diff --git a/modules/core/src/lib/widget.ts b/modules/core/src/lib/widget.ts index 4adad3f80dd..eaf5e9774a3 100644 --- a/modules/core/src/lib/widget.ts +++ b/modules/core/src/lib/widget.ts @@ -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; + export type WidgetProps = { id?: string; @@ -84,8 +90,6 @@ export abstract class Widget { // 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 @@ -122,7 +126,7 @@ export abstract class Widget { /** 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 {} @@ -138,4 +142,38 @@ export abstract class Widget { 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({ + 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: {}}); + } } diff --git a/modules/widgets/src/geolocate-widget.tsx b/modules/widgets/src/geolocate-widget.tsx index 793e74b6008..094cf0cede4 100644 --- a/modules/widgets/src/geolocate-widget.tsx +++ b/modules/widgets/src/geolocate-widget.tsx @@ -4,12 +4,8 @@ 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; - /** Properties for the GeolocateWidget */ export type GeolocateWidgetProps = WidgetProps & { viewId?: string; @@ -17,7 +13,8 @@ export type GeolocateWidgetProps = WidgetProps & { placement?: WidgetPlacement; /** Tooltip message */ label?: string; - transitionDuration?: number; + /** Animated transition duration. Set to 0 to disable transitions */ + transitionDurationMs?: number; }; /** @@ -32,7 +29,7 @@ export class GeolocateWidget extends Widget { viewId: undefined!, placement: 'top-left', label: 'Geolocate', - transitionDuration: 200 + transitionDurationMs: 200 }; className = 'deck-widget-geolocate'; @@ -95,31 +92,6 @@ export class GeolocateWidget extends Widget { handleCoordinates = coordinates => { this.setViewState(coordinates); }; - - // TODO - MOVE TO WIDGETIMPL? - - setViewState(viewState: ViewState) { - const viewId = this.props.viewId || (viewState?.id as string) || 'default-view'; - const viewport = this.viewports[viewId] || {}; - 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 = {}; } /** diff --git a/modules/widgets/src/reset-view-widget.tsx b/modules/widgets/src/reset-view-widget.tsx index 91acbb18a6c..a32c2491bc1 100644 --- a/modules/widgets/src/reset-view-widget.tsx +++ b/modules/widgets/src/reset-view-widget.tsx @@ -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; }; /** @@ -32,7 +34,8 @@ export class ResetViewWidget extends Widget { placement: 'top-left', label: 'Reset View', initialViewState: undefined!, - viewId: undefined! + viewId: undefined!, + transitionDurationMs: 200, }; className = 'deck-widget-reset-view'; @@ -61,18 +64,10 @@ export class ResetViewWidget extends Widget { handleClick() { const initialViewState = this.props.initialViewState || this.deck?.props.initialViewState; - 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 + }); } }