Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 41 additions & 3 deletions modules/core/src/lib/widget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ import type Layer from './layer';
import type {WidgetManager, WidgetPlacement} from './widget-manager';
import {deepEqual} from '../utils/deep-equal';
import {applyStyles, removeStyles} from '../utils/apply-styles';
import {default as LinearInterpolator} from '../transitions/linear-interpolator';
import {default as FlyToInterpolator} from '../transitions/fly-to-interpolator';

/** @todo - is the the best we can do? deck.gl does not seem to export a union type */
type ViewState = Record<string, unknown>;


export type WidgetProps = {
id?: string;
Expand Down Expand Up @@ -84,8 +90,6 @@ export abstract class Widget<PropsT extends WidgetProps = WidgetProps> {

// WIDGET LIFECYCLE

// @note empty method calls have an overhead in V8 but it is very low, ~1ns

/**
* Called to create the root DOM element for this widget
* Configures the top-level styles and adds basic class names for theming
Expand Down Expand Up @@ -122,7 +126,7 @@ export abstract class Widget<PropsT extends WidgetProps = WidgetProps> {
/** Called when the widget is removed */
onRemove(): void {}

// deck integration - Event hooks
// DECK INTEGRATION - EVENT HOOKS

/** Called when the containing view is changed */
onViewportChange(viewport: Viewport): void {}
Expand All @@ -138,4 +142,38 @@ export abstract class Widget<PropsT extends WidgetProps = WidgetProps> {
onDragStart(info: PickingInfo, event: MjolnirGestureEvent): void {}
/** Called when a dragend event occurs */
onDragEnd(info: PickingInfo, event: MjolnirGestureEvent): void {}

// DECK INTEGRATION - OPERATIONS

/**
* Lets the widget update viewState for a view, optionally with transitions
* @note this code abuses protected methods and should be refactored,
* but does work for now until we have a cleaner solutions.
*/
setViewState({
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make protected?

viewState,
viewId = (viewState?.id as string) || 'default-view',
transitionDuration = 0,
}: {
viewState: ViewState,
viewId?: string,
transitionDuration?: number
}) {
// @ts-expect-error viewManager is protected
const viewport = this.deck?.viewManager?.getViewport(viewId) || {};

// HACK - mising viewport and view state
const nextViewState: ViewState = {
...viewport,
...viewState
};
if (transitionDuration > 0) {
nextViewState.transitionDuration = transitionDuration;
nextViewState.transitionInterpolator =
'latitude' in nextViewState ? new FlyToInterpolator() : new LinearInterpolator();
}

// @ts-expect-error Using private method temporary until there's a public one
this.deck._onViewStateChange({viewId, viewState: nextViewState, interactionState: {}});
}
}
34 changes: 3 additions & 31 deletions modules/widgets/src/geolocate-widget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,17 @@

import {Widget, WidgetProps} from '@deck.gl/core';
import type {WidgetPlacement, Viewport} from '@deck.gl/core';
import {FlyToInterpolator, LinearInterpolator} from '@deck.gl/core';
import {render} from 'preact';

/** @todo - is the the best we can do? */
type ViewState = Record<string, unknown>;

/** Properties for the GeolocateWidget */
export type GeolocateWidgetProps = WidgetProps & {
viewId?: string;
/** Widget positioning within the view. Default 'top-left'. */
placement?: WidgetPlacement;
/** Tooltip message */
label?: string;
transitionDuration?: number;
/** Animated transition duration. Set to 0 to disable transitions */
transitionDurationMs?: number;
};

/**
Expand All @@ -32,7 +29,7 @@ export class GeolocateWidget extends Widget<GeolocateWidgetProps> {
viewId: undefined!,
placement: 'top-left',
label: 'Geolocate',
transitionDuration: 200
transitionDurationMs: 200
};

className = 'deck-widget-geolocate';
Expand Down Expand Up @@ -95,31 +92,6 @@ export class GeolocateWidget extends Widget<GeolocateWidgetProps> {
handleCoordinates = coordinates => {
this.setViewState(coordinates);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is broken

};

// TODO - MOVE TO WIDGETIMPL?

setViewState(viewState: ViewState) {
const viewId = this.props.viewId || (viewState?.id as string) || 'default-view';
const viewport = this.viewports[viewId] || {};
Comment on lines -102 to -103
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is necessary in widget that set view state

const nextViewState: ViewState = {
...viewport,
...viewState
};
if (this.props.transitionDuration > 0) {
nextViewState.transitionDuration = this.props.transitionDuration;
nextViewState.transitionInterpolator =
'latitude' in nextViewState ? new FlyToInterpolator() : new LinearInterpolator();
}

// @ts-ignore Using private method temporary until there's a public one
this.deck._onViewStateChange({viewId, viewState: nextViewState, interactionState: {}});
}

onViewportChange(viewport: Viewport) {
this.viewports[viewport.id] = viewport;
}

viewports: Record<string, Viewport> = {};
Comment on lines -118 to -122
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keep

}

/**
Expand Down
25 changes: 10 additions & 15 deletions modules/widgets/src/reset-view-widget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ export type ResetViewWidgetProps = WidgetProps & {
/** The initial view state to reset the view to. Defaults to deck.props.initialViewState */
initialViewState?: ViewState;
/** View to interact with. Required when using multiple views. */
viewId?: string | null;
viewId?: string;
/** Set to 0 to disable transitions */
transitionDurationMs?: number;
};

/**
Expand All @@ -32,7 +34,8 @@ export class ResetViewWidget extends Widget<ResetViewWidgetProps> {
placement: 'top-left',
label: 'Reset View',
initialViewState: undefined!,
viewId: undefined!
viewId: undefined!,
transitionDurationMs: 200,
};

className = 'deck-widget-reset-view';
Expand Down Expand Up @@ -61,18 +64,10 @@ export class ResetViewWidget extends Widget<ResetViewWidgetProps> {

handleClick() {
const initialViewState = this.props.initialViewState || this.deck?.props.initialViewState;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We really ought to combine what this widget does and what compass widget does so that they can be used in either mode (initialViewState/viewState)

A user managing viewState would be able to use this widget too if we made homeViewState a widget prop, and stored viewports in the widget like the others.

In compass, we don't need to expose a prop but just check if initialViewState is in use.

this.setViewState(initialViewState);
}

setViewState(viewState: ViewState) {
const viewId = this.props.viewId || viewState?.id || 'default-view';
const nextViewState = {
...viewState
// only works for geospatial?
// transitionDuration: this.props.transitionDuration,
// transitionInterpolator: new FlyToInterpolator()
};
// @ts-ignore Using private method temporary until there's a public one
this.deck._onViewStateChange({viewId, viewState: nextViewState, interactionState: {}});
this.setViewState({
viewState: initialViewState,
viewId: this.props.viewId,
transitionDurationMs: this.props.transitionDurationMs
});
}
}
Loading