@deck.gl/widgets 9.2.0-beta.2 → 9.2.0-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/dist/compass-widget.d.ts +1 -1
  2. package/dist/compass-widget.d.ts.map +1 -1
  3. package/dist/compass-widget.js +0 -1
  4. package/dist/compass-widget.js.map +1 -1
  5. package/dist/context-menu-widget.d.ts +2 -2
  6. package/dist/context-menu-widget.d.ts.map +1 -1
  7. package/dist/context-menu-widget.js +4 -1
  8. package/dist/context-menu-widget.js.map +1 -1
  9. package/dist/dist.dev.js +965 -900
  10. package/dist/fps-widget.d.ts +5 -6
  11. package/dist/fps-widget.d.ts.map +1 -1
  12. package/dist/fps-widget.js +13 -14
  13. package/dist/fps-widget.js.map +1 -1
  14. package/dist/fullscreen-widget.d.ts +2 -0
  15. package/dist/fullscreen-widget.d.ts.map +1 -1
  16. package/dist/fullscreen-widget.js +7 -3
  17. package/dist/fullscreen-widget.js.map +1 -1
  18. package/dist/geocoder-widget.d.ts +4 -3
  19. package/dist/geocoder-widget.d.ts.map +1 -1
  20. package/dist/geocoder-widget.js +3 -4
  21. package/dist/geocoder-widget.js.map +1 -1
  22. package/dist/gimbal-widget.d.ts +7 -5
  23. package/dist/gimbal-widget.d.ts.map +1 -1
  24. package/dist/gimbal-widget.js +15 -10
  25. package/dist/gimbal-widget.js.map +1 -1
  26. package/dist/index.cjs +684 -668
  27. package/dist/index.cjs.map +4 -4
  28. package/dist/index.d.ts +7 -7
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +12 -9
  31. package/dist/index.js.map +1 -1
  32. package/dist/info-widget.d.ts +9 -9
  33. package/dist/info-widget.d.ts.map +1 -1
  34. package/dist/info-widget.js +7 -9
  35. package/dist/info-widget.js.map +1 -1
  36. package/dist/lib/components/button-group.d.ts +1 -1
  37. package/dist/lib/components/button-group.d.ts.map +1 -1
  38. package/dist/lib/components/button-group.js +1 -1
  39. package/dist/lib/components/button-group.js.map +1 -1
  40. package/dist/lib/components/grouped-icon-button.d.ts +5 -3
  41. package/dist/lib/components/grouped-icon-button.d.ts.map +1 -1
  42. package/dist/lib/components/grouped-icon-button.js +3 -3
  43. package/dist/lib/components/grouped-icon-button.js.map +1 -1
  44. package/dist/lib/components/icon-button.d.ts +5 -6
  45. package/dist/lib/components/icon-button.d.ts.map +1 -1
  46. package/dist/lib/components/icon-button.js +1 -1
  47. package/dist/lib/components/icon-button.js.map +1 -1
  48. package/dist/lib/components/icon-menu.d.ts +2 -2
  49. package/dist/lib/components/icon-menu.d.ts.map +1 -1
  50. package/dist/lib/components/icon-menu.js +4 -19
  51. package/dist/lib/components/icon-menu.js.map +1 -1
  52. package/dist/lib/components/simple-menu.js +1 -1
  53. package/dist/lib/components/simple-menu.js.map +1 -1
  54. package/dist/loading-widget.d.ts +4 -2
  55. package/dist/loading-widget.d.ts.map +1 -1
  56. package/dist/loading-widget.js +5 -3
  57. package/dist/loading-widget.js.map +1 -1
  58. package/dist/reset-view-widget.d.ts +9 -11
  59. package/dist/reset-view-widget.d.ts.map +1 -1
  60. package/dist/reset-view-widget.js +5 -4
  61. package/dist/reset-view-widget.js.map +1 -1
  62. package/dist/scale-widget.d.ts +6 -3
  63. package/dist/scale-widget.d.ts.map +1 -1
  64. package/dist/scale-widget.js +3 -2
  65. package/dist/scale-widget.js.map +1 -1
  66. package/dist/screenshot-widget.d.ts +4 -2
  67. package/dist/screenshot-widget.d.ts.map +1 -1
  68. package/dist/screenshot-widget.js +3 -1
  69. package/dist/screenshot-widget.js.map +1 -1
  70. package/dist/splitter-widget.d.ts +1 -1
  71. package/dist/splitter-widget.d.ts.map +1 -1
  72. package/dist/splitter-widget.js +0 -2
  73. package/dist/splitter-widget.js.map +1 -1
  74. package/dist/stats-widget.d.ts +6 -1
  75. package/dist/stats-widget.d.ts.map +1 -1
  76. package/dist/stats-widget.js +11 -4
  77. package/dist/stats-widget.js.map +1 -1
  78. package/dist/stylesheet.css +53 -35
  79. package/dist/theme-widget.d.ts +3 -1
  80. package/dist/theme-widget.d.ts.map +1 -1
  81. package/dist/theme-widget.js +6 -3
  82. package/dist/theme-widget.js.map +1 -1
  83. package/dist/themes.d.ts +10 -0
  84. package/dist/themes.d.ts.map +1 -1
  85. package/dist/themes.js +12 -4
  86. package/dist/themes.js.map +1 -1
  87. package/dist/timeline-widget.d.ts +10 -32
  88. package/dist/timeline-widget.d.ts.map +1 -1
  89. package/dist/timeline-widget.js +6 -2
  90. package/dist/timeline-widget.js.map +1 -1
  91. package/dist/view-selector-widget.d.ts +2 -0
  92. package/dist/view-selector-widget.d.ts.map +1 -1
  93. package/dist/view-selector-widget.js +14 -13
  94. package/dist/view-selector-widget.js.map +1 -1
  95. package/dist/zoom-widget.d.ts +1 -2
  96. package/dist/zoom-widget.d.ts.map +1 -1
  97. package/dist/zoom-widget.js +7 -5
  98. package/dist/zoom-widget.js.map +1 -1
  99. package/dist.min.js +2 -3
  100. package/package.json +2 -2
  101. package/src/compass-widget.tsx +1 -1
  102. package/src/context-menu-widget.tsx +7 -3
  103. package/src/fps-widget.tsx +25 -16
  104. package/src/fullscreen-widget.tsx +9 -3
  105. package/src/geocoder-widget.tsx +7 -7
  106. package/src/gimbal-widget.tsx +16 -11
  107. package/src/index.ts +15 -10
  108. package/src/info-widget.tsx +17 -17
  109. package/src/lib/components/button-group.tsx +2 -2
  110. package/src/lib/components/grouped-icon-button.tsx +9 -6
  111. package/src/lib/components/icon-button.tsx +5 -6
  112. package/src/lib/components/icon-menu.tsx +12 -30
  113. package/src/lib/components/simple-menu.tsx +1 -1
  114. package/src/loading-widget.tsx +9 -5
  115. package/src/reset-view-widget.tsx +18 -16
  116. package/src/scale-widget.tsx +9 -5
  117. package/src/screenshot-widget.tsx +7 -3
  118. package/src/splitter-widget.tsx +1 -3
  119. package/src/stats-widget.tsx +18 -5
  120. package/src/stylesheet.css +53 -35
  121. package/src/theme-widget.tsx +9 -4
  122. package/src/themes.ts +15 -4
  123. package/src/timeline-widget.tsx +19 -42
  124. package/src/view-selector-widget.tsx +58 -15
  125. package/src/zoom-widget.tsx +8 -6
@@ -7,6 +7,7 @@ import type {Viewport, WidgetPlacement, WidgetProps} from '@deck.gl/core';
7
7
  import {render} from 'preact';
8
8
 
9
9
  export type CompassWidgetProps = WidgetProps & {
10
+ /** Widget positioning within the view. Default 'top-left'. */
10
11
  placement?: WidgetPlacement;
11
12
  /** View to attach to and interact with. Required when using multiple views. */
12
13
  viewId?: string | null;
@@ -28,7 +29,6 @@ export class CompassWidget extends Widget<CompassWidgetProps> {
28
29
 
29
30
  className = 'deck-widget-compass';
30
31
  placement: WidgetPlacement = 'top-left';
31
- viewId?: string | null = null;
32
32
  viewports: {[id: string]: Viewport} = {};
33
33
 
34
34
  constructor(props: CompassWidgetProps = {}) {
@@ -1,6 +1,10 @@
1
+ // deck.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
1
5
  /* global document */
2
- import {Widget, WidgetProps} from '@deck.gl/core';
3
- import type {Deck, PickingInfo} from '@deck.gl/core';
6
+ import {Widget} from '@deck.gl/core';
7
+ import type {Deck, PickingInfo, WidgetProps} from '@deck.gl/core';
4
8
  import {render} from 'preact';
5
9
  import {SimpleMenu} from './lib/components/simple-menu';
6
10
 
@@ -50,7 +54,7 @@ export class ContextMenuWidget extends Widget<ContextMenuWidgetProps> {
50
54
  constructor(props: ContextMenuWidgetProps) {
51
55
  super(props, ContextMenuWidget.defaultProps);
52
56
  this.pickInfo = null;
53
- this.setProps(props);
57
+ this.setProps(this.props);
54
58
  }
55
59
 
56
60
  onAdd({deck}: {deck: Deck<any>}): HTMLDivElement {
@@ -2,13 +2,17 @@
2
2
  // SPDX-License-Identifier: MIT
3
3
  // Copyright (c) vis.gl contributors
4
4
 
5
- import {Widget, WidgetProps} from '@deck.gl/core';
6
- import type {WidgetPlacement, Deck} from '@deck.gl/core';
5
+ import {Widget} from '@deck.gl/core';
6
+ import {render} from 'preact';
7
+ import type {WidgetPlacement, Deck, WidgetProps} from '@deck.gl/core';
8
+ import {IconButton} from './lib/components/icon-button';
7
9
 
8
10
  /** Properties for the FpsWidget. */
9
11
  export type FpsWidgetProps = WidgetProps & {
10
12
  /** Widget positioning within the view. Default 'top-left'. */
11
13
  placement?: WidgetPlacement;
14
+ /** View to attach to and interact with. Required when using multiple views. */
15
+ viewId?: string | null;
12
16
  };
13
17
 
14
18
  /**
@@ -18,7 +22,8 @@ export class FpsWidget extends Widget<FpsWidgetProps> {
18
22
  static defaultProps: Required<FpsWidgetProps> = {
19
23
  ...Widget.defaultProps,
20
24
  id: 'fps',
21
- placement: 'top-left'
25
+ placement: 'top-left',
26
+ viewId: null
22
27
  };
23
28
 
24
29
  className = 'deck-widget-fps';
@@ -28,37 +33,41 @@ export class FpsWidget extends Widget<FpsWidgetProps> {
28
33
 
29
34
  constructor(props: FpsWidgetProps = {}) {
30
35
  super(props, FpsWidget.defaultProps);
31
- this.placement = props.placement ?? this.placement;
36
+ this.setProps(this.props);
32
37
  }
33
38
 
34
39
  setProps(props: Partial<FpsWidgetProps>): void {
35
- if (props.placement) {
36
- this.placement = props.placement;
37
- }
40
+ this.placement = props.placement ?? this.placement;
41
+ this.viewId = props.viewId ?? this.viewId;
38
42
  super.setProps(props);
39
43
  }
40
44
 
41
45
  onAdd({}: {deck: Deck<any>; viewId: string | null}): void {
42
46
  this._lastFps = this._getFps();
43
- this.updateHTML();
47
+ requestAnimationFrame(() => this._animate());
44
48
  }
45
49
 
46
50
  onRenderHTML(rootElement: HTMLElement): void {
47
51
  const fps = this._getFps();
48
- // TODO - avoid changing the root element, instead create a child for better styling.
49
- rootElement.innerText = `FPS:\n${fps}`;
50
- rootElement.style.backgroundColor = 'white';
51
- rootElement.style.fontFamily = 'monospace';
52
- rootElement.style.fontSize = '8px';
53
- rootElement.style.fontWeight = '700'; // Make font bolder on click
52
+ render(
53
+ <IconButton>
54
+ <div className="text">
55
+ FPS
56
+ <br />
57
+ {fps}
58
+ </div>
59
+ </IconButton>,
60
+ rootElement
61
+ );
54
62
  }
55
63
 
56
- onRedraw({}: {viewports: any[]; layers: any[]}): void {
64
+ _animate(): void {
57
65
  const fps = this._getFps();
58
- if (fps !== this._lastFps) {
66
+ if (this._lastFps !== fps) {
59
67
  this._lastFps = fps;
60
68
  this.updateHTML();
61
69
  }
70
+ requestAnimationFrame(() => this._animate());
62
71
  }
63
72
 
64
73
  _getFps(): number {
@@ -3,7 +3,7 @@
3
3
  // Copyright (c) vis.gl contributors
4
4
 
5
5
  /* global document */
6
- import {Widget, type WidgetProps, type WidgetPlacement} from '@deck.gl/core';
6
+ import {log, Widget, type WidgetProps, type WidgetPlacement} from '@deck.gl/core';
7
7
  import {render} from 'preact';
8
8
  import {IconButton} from './lib/components/icon-button';
9
9
 
@@ -13,6 +13,8 @@ export type FullscreenWidgetProps = WidgetProps & {
13
13
  id?: string;
14
14
  /** Widget positioning within the view. Default 'top-left'. */
15
15
  placement?: WidgetPlacement;
16
+ /** View to attach to and interact with. Required when using multiple views. */
17
+ viewId?: string | null;
16
18
  /** Tooltip message when out of fullscreen. */
17
19
  enterLabel?: string;
18
20
  /** Tooltip message when fullscreen. */
@@ -29,6 +31,7 @@ export class FullscreenWidget extends Widget<FullscreenWidgetProps> {
29
31
  ...Widget.defaultProps,
30
32
  id: 'fullscreen',
31
33
  placement: 'top-left',
34
+ viewId: null,
32
35
  enterLabel: 'Enter Fullscreen',
33
36
  exitLabel: 'Exit Fullscreen',
34
37
  container: undefined!
@@ -40,7 +43,7 @@ export class FullscreenWidget extends Widget<FullscreenWidgetProps> {
40
43
 
41
44
  constructor(props: FullscreenWidgetProps = {}) {
42
45
  super(props, FullscreenWidget.defaultProps);
43
- this.placement = props.placement ?? this.placement;
46
+ this.setProps(this.props);
44
47
  }
45
48
 
46
49
  onAdd(): void {
@@ -54,7 +57,9 @@ export class FullscreenWidget extends Widget<FullscreenWidgetProps> {
54
57
  onRenderHTML(rootElement: HTMLElement): void {
55
58
  render(
56
59
  <IconButton
57
- onClick={this.handleClick.bind(this)}
60
+ onClick={() => {
61
+ this.handleClick().catch(err => log.error(err)());
62
+ }}
58
63
  label={this.fullscreen ? this.props.exitLabel : this.props.enterLabel}
59
64
  className={this.fullscreen ? 'deck-widget-fullscreen-exit' : 'deck-widget-fullscreen-enter'}
60
65
  />,
@@ -64,6 +69,7 @@ export class FullscreenWidget extends Widget<FullscreenWidgetProps> {
64
69
 
65
70
  setProps(props: Partial<FullscreenWidgetProps>) {
66
71
  this.placement = props.placement ?? this.placement;
72
+ this.viewId = props.viewId ?? this.viewId;
67
73
  super.setProps(props);
68
74
  }
69
75
 
@@ -2,8 +2,8 @@
2
2
  // SPDX-License-Identifier: MIT
3
3
  // Copyright (c) vis.gl contributors
4
4
 
5
- import {Widget, WidgetProps} from '@deck.gl/core';
6
- import type {WidgetPlacement, Viewport} from '@deck.gl/core';
5
+ import {Widget} from '@deck.gl/core';
6
+ import type {WidgetPlacement, Viewport, WidgetProps} from '@deck.gl/core';
7
7
  import {FlyToInterpolator, LinearInterpolator} from '@deck.gl/core';
8
8
  import {render} from 'preact';
9
9
  import {DropdownMenu} from './lib/components/dropdown-menu';
@@ -24,11 +24,12 @@ const CURRENT_LOCATION = 'current';
24
24
 
25
25
  /** Properties for the GeocoderWidget */
26
26
  export type GeocoderWidgetProps = WidgetProps & {
27
- viewId?: string;
27
+ viewId?: string | null;
28
28
  /** Widget positioning within the view. Default 'top-left'. */
29
29
  placement?: WidgetPlacement;
30
30
  /** Tooltip message */
31
31
  label?: string;
32
+ /** View state reset transition duration in ms. 0 disables the transition */
32
33
  transitionDuration?: number;
33
34
  /** Geocoding service selector, for declarative usage */
34
35
  geocoder?: 'google' | 'mapbox' | 'opencage' | 'coordinates' | 'custom';
@@ -49,7 +50,7 @@ export class GeocoderWidget extends Widget<GeocoderWidgetProps> {
49
50
  static defaultProps: Required<GeocoderWidgetProps> = {
50
51
  ...Widget.defaultProps,
51
52
  id: 'geocoder',
52
- viewId: undefined!,
53
+ viewId: null,
53
54
  placement: 'top-left',
54
55
  label: 'Geocoder',
55
56
  transitionDuration: 200,
@@ -68,18 +69,17 @@ export class GeocoderWidget extends Widget<GeocoderWidgetProps> {
68
69
 
69
70
  constructor(props: GeocoderWidgetProps = {}) {
70
71
  super(props, GeocoderWidget.defaultProps);
71
- this.placement = this.props.placement ?? this.placement;
72
72
  this.setProps(this.props);
73
- this.geocoder = getGeocoder(this.props);
74
73
  }
75
74
 
76
75
  setProps(props: Partial<GeocoderWidgetProps>): void {
77
- super.setProps(props);
78
76
  this.placement = props.placement ?? this.placement;
77
+ this.viewId = props.viewId ?? this.viewId;
79
78
  this.geocoder = getGeocoder(this.props);
80
79
  if (this.geocoder.requiresApiKey && !this.props.apiKey) {
81
80
  throw new Error(`API key is required for the ${this.geocoder.name} geocoder`);
82
81
  }
82
+ super.setProps(props);
83
83
  }
84
84
 
85
85
  onRenderHTML(rootElement: HTMLElement): void {
@@ -12,7 +12,7 @@ export type GimbalWidgetProps = WidgetProps & {
12
12
  viewId?: string | null;
13
13
  /** Tooltip message. */
14
14
  label?: string;
15
- /** Width of gimbal lines */
15
+ /** Width of gimbal lines. */
16
16
  strokeWidth?: number;
17
17
  /** Transition duration in ms when resetting rotation. */
18
18
  transitionDuration?: number;
@@ -23,7 +23,7 @@ export class GimbalWidget extends Widget<GimbalWidgetProps> {
23
23
  ...Widget.defaultProps,
24
24
  id: 'gimbal',
25
25
  placement: 'top-left',
26
- viewId: undefined!,
26
+ viewId: null,
27
27
  label: 'Gimbal',
28
28
  strokeWidth: 1.5,
29
29
  transitionDuration: 200
@@ -31,7 +31,7 @@ export class GimbalWidget extends Widget<GimbalWidgetProps> {
31
31
 
32
32
  className = 'deck-widget-gimbal';
33
33
  placement: WidgetPlacement = 'top-left';
34
- viewId?: string | null = null;
34
+ viewports: {[id: string]: Viewport} = {};
35
35
 
36
36
  constructor(props: GimbalWidgetProps = {}) {
37
37
  super(props, GimbalWidget.defaultProps);
@@ -45,14 +45,18 @@ export class GimbalWidget extends Widget<GimbalWidgetProps> {
45
45
  }
46
46
 
47
47
  onRenderHTML(rootElement: HTMLElement): void {
48
- const {rotationOrbit, rotationX} = this.getNormalizedRotation();
48
+ const viewId = this.viewId || Object.values(this.viewports)[0]?.id || 'default-view';
49
+ const widgetViewport = this.viewports[viewId];
50
+ const {rotationOrbit, rotationX} = this.getNormalizedRotation(widgetViewport);
49
51
  // Note - we use CSS 3D transforms instead of SVG 2D transforms
50
52
  const ui = (
51
53
  <div className="deck-widget-button" style={{perspective: 100, pointerEvents: 'auto'}}>
52
54
  <button
53
55
  type="button"
54
56
  onClick={() => {
55
- this.resetOrbitView();
57
+ for (const viewport of Object.values(this.viewports)) {
58
+ this.resetOrbitView(viewport);
59
+ }
56
60
  }}
57
61
  title={this.props.label}
58
62
  style={{position: 'relative', width: 26, height: 26}}
@@ -110,11 +114,12 @@ export class GimbalWidget extends Widget<GimbalWidgetProps> {
110
114
  }
111
115
 
112
116
  onViewportChange(viewport: Viewport) {
117
+ this.viewports[viewport.id] = viewport;
113
118
  this.updateHTML();
114
119
  }
115
120
 
116
- resetOrbitView() {
117
- const viewId = this.getViewId();
121
+ resetOrbitView(viewport?: Viewport) {
122
+ const viewId = this.getViewId(viewport);
118
123
  const viewState = this.getViewState(viewId);
119
124
  if ('rotationOrbit' in viewState || 'rotationX' in viewState) {
120
125
  const nextViewState = {
@@ -131,8 +136,8 @@ export class GimbalWidget extends Widget<GimbalWidgetProps> {
131
136
  }
132
137
  }
133
138
 
134
- getNormalizedRotation() {
135
- const viewState = this.getViewState(this.getViewId());
139
+ getNormalizedRotation(viewport?: Viewport): {rotationOrbit: number; rotationX: number} {
140
+ const viewState = this.getViewState(this.getViewId(viewport));
136
141
  const [rz, rx] = this.getRotation(viewState);
137
142
  const rotationOrbit = normalizeAndClampAngle(rz);
138
143
  const rotationX = normalizeAndClampAngle(rx);
@@ -148,8 +153,8 @@ export class GimbalWidget extends Widget<GimbalWidgetProps> {
148
153
 
149
154
  // Move to Widget/WidgetManager?
150
155
 
151
- getViewId() {
152
- const viewId = this.viewId || 'OrbitView';
156
+ getViewId(viewport?: Viewport) {
157
+ const viewId = this.viewId || viewport?.id || 'OrbitView';
153
158
  return viewId;
154
159
  }
155
160
 
package/src/index.ts CHANGED
@@ -5,25 +5,31 @@
5
5
  // Navigation widgets
6
6
  export {ZoomWidget} from './zoom-widget';
7
7
  export {ResetViewWidget} from './reset-view-widget';
8
+ export {GimbalWidget} from './gimbal-widget';
8
9
 
9
10
  // Geospatial widgets
10
11
  export {CompassWidget} from './compass-widget';
11
- export {GimbalWidget} from './gimbal-widget';
12
12
  export {ScaleWidget as _ScaleWidget} from './scale-widget';
13
13
  export {GeocoderWidget as _GeocoderWidget} from './geocoder-widget';
14
14
 
15
- // Utility widgets
15
+ // View widgets
16
16
  export {FullscreenWidget} from './fullscreen-widget';
17
+ export {SplitterWidget as _SplitterWidget} from './splitter-widget';
18
+ export {ViewSelectorWidget as _ViewSelectorWidget} from './view-selector-widget';
19
+
20
+ // Information widgets
21
+ export {InfoWidget as _InfoWidget} from './info-widget';
22
+ export {ContextMenuWidget as _ContextMenuWidget} from './context-menu-widget';
23
+
24
+ // Control widgets
25
+ export {TimelineWidget as _TimelineWidget} from './timeline-widget';
26
+
27
+ // Utility widgets
17
28
  export {ScreenshotWidget} from './screenshot-widget';
29
+ export {ThemeWidget as _ThemeWidget} from './theme-widget';
18
30
  export {LoadingWidget as _LoadingWidget} from './loading-widget';
19
31
  export {FpsWidget as _FpsWidget} from './fps-widget';
20
- export {ThemeWidget as _ThemeWidget} from './theme-widget';
21
- export {InfoWidget as _InfoWidget} from './info-widget';
22
32
  export {StatsWidget as _StatsWidget} from './stats-widget';
23
- export {ContextMenuWidget as _ContextMenuWidget} from './context-menu-widget';
24
- export {SplitterWidget as _SplitterWidget} from './splitter-widget';
25
- export {TimelineWidget as _TimelineWidget} from './timeline-widget';
26
- export {ViewSelectorWidget as _ViewSelectorWidget} from './view-selector-widget';
27
33
 
28
34
  export type {FullscreenWidgetProps} from './fullscreen-widget';
29
35
  export type {CompassWidgetProps} from './compass-widget';
@@ -46,8 +52,7 @@ export type {GimbalWidgetProps} from './gimbal-widget';
46
52
  export {LightTheme, DarkTheme, LightGlassTheme, DarkGlassTheme} from './themes';
47
53
  export type {DeckWidgetTheme} from './themes';
48
54
 
49
- // Experimental exports
50
-
55
+ // Experimental preact components
51
56
  export {ButtonGroup as _ButtonGroup, type ButtonGroupProps} from './lib/components/button-group';
52
57
  export {IconButton as _IconButton, type IconButtonProps} from './lib/components/icon-button';
53
58
  export {
@@ -1,33 +1,37 @@
1
- /* global document */
2
- import {Widget, WidgetProps} from '@deck.gl/core';
3
- import type {Deck, PickingInfo, Viewport} from '@deck.gl/core';
1
+ // deck.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ import {Widget} from '@deck.gl/core';
6
+ import type {Deck, PickingInfo, Viewport, WidgetProps} from '@deck.gl/core';
4
7
  import {render, JSX} from 'preact';
5
8
 
6
9
  export type InfoWidgetProps = WidgetProps & {
7
- /** View to attach to and interact with. Required when using multiple views. */
10
+ /** View to attach to and interact with. Required when using multiple views */
8
11
  viewId?: string | null;
9
- /** InfoWidget mode */
12
+ /** Determines the interaction mode of the widget */
10
13
  mode: 'click' | 'hover' | 'static';
11
- /** Get the popup contents from the selected element */
12
- getTooltip?: (info: PickingInfo, widget: InfoWidget) => any;
13
- /** Position at which to place popup (clicked point: [longitude, latitude]). */
14
+ /** Function to generate the popup contents from the selected element */
15
+ getTooltip?: (info: PickingInfo, widget: InfoWidget) => InfoWidgetProps | null;
16
+ /** Position at which to place popup (clicked point: [longitude, latitude]) */
14
17
  position: [number, number];
15
- /** Text of popup */
18
+ /** Text content of popup */
16
19
  text?: string;
17
20
  /** Visibility of info widget */
18
21
  visible?: boolean;
19
22
  /** Minimum offset (in pixels) to keep the popup away from the canvas edges. */
20
23
  minOffset?: number;
24
+ /** Callback triggered when the widget is clicked. */
21
25
  onClick?: (widget: InfoWidget, info: PickingInfo) => boolean;
22
26
  };
23
27
 
24
28
  export class InfoWidget extends Widget<InfoWidgetProps> {
25
29
  static defaultProps: Required<InfoWidgetProps> = {
26
30
  ...Widget.defaultProps,
31
+ id: 'info',
27
32
  position: [0, 0],
28
33
  text: '',
29
34
  visible: false,
30
- // Set default minOffset if not provided
31
35
  minOffset: 0,
32
36
  viewId: null,
33
37
  mode: 'hover',
@@ -37,19 +41,15 @@ export class InfoWidget extends Widget<InfoWidgetProps> {
37
41
 
38
42
  className = 'deck-widget-info';
39
43
  placement = 'fill' as const;
40
- viewId?: string | null = null;
41
44
  viewport?: Viewport;
42
45
 
43
46
  constructor(props: InfoWidgetProps) {
44
47
  super(props, InfoWidget.defaultProps);
45
- props.position = props.position || [0, 0];
46
- props.text = props.text || '';
47
- props.visible = props.visible || false;
48
- // Set default minOffset if not provided
49
- props.minOffset = props.minOffset ?? 0;
48
+ this.setProps(this.props);
50
49
  }
51
50
 
52
51
  setProps(props: Partial<InfoWidgetProps>) {
52
+ this.viewId = props.viewId ?? this.viewId;
53
53
  super.setProps(props);
54
54
  }
55
55
 
@@ -72,7 +72,7 @@ export class InfoWidget extends Widget<InfoWidgetProps> {
72
72
  this.setProps({
73
73
  visible: tooltip !== null,
74
74
  ...tooltip,
75
- style: {zIndex: 1, ...tooltip?.style}
75
+ style: {zIndex: '1', ...tooltip?.style}
76
76
  });
77
77
  }
78
78
  }
@@ -6,11 +6,11 @@ import type {ComponentChildren} from 'preact';
6
6
 
7
7
  export type ButtonGroupProps = {
8
8
  children: ComponentChildren;
9
- orientation;
9
+ orientation: 'vertical' | 'horizontal';
10
10
  };
11
11
 
12
12
  /** Renders a group of buttons with Widget CSS */
13
13
  export const ButtonGroup = (props: ButtonGroupProps) => {
14
- const {children, orientation} = props;
14
+ const {children, orientation = 'horizontal'} = props;
15
15
  return <div className={`deck-widget-button-group ${orientation}`}>{children}</div>;
16
16
  };
@@ -2,23 +2,26 @@
2
2
  // SPDX-License-Identifier: MIT
3
3
  // Copyright (c) vis.gl contributors
4
4
 
5
+ import type {ComponentChildren, JSX} from 'preact';
6
+
5
7
  export type GroupedIconButtonProps = {
6
8
  className?: string;
7
- label: string;
8
- onClick: () => void;
9
+ label?: string;
10
+ onClick?: JSX.MouseEventHandler<HTMLButtonElement>;
11
+ children?: ComponentChildren;
9
12
  };
10
13
 
11
14
  /** Renders an icon button as part of a ButtonGroup */
12
- export const GroupedIconButton = props => {
13
- const {className, label, onClick} = props;
15
+ export const GroupedIconButton = (props: GroupedIconButtonProps) => {
16
+ const {className = '', label, onClick, children} = props;
14
17
  return (
15
18
  <button
16
- className={`deck-widget-icon-button ${className || ''}`}
19
+ className={`deck-widget-icon-button ${className}`}
17
20
  type="button"
18
21
  onClick={onClick}
19
22
  title={label}
20
23
  >
21
- <div className="deck-widget-icon" />
24
+ {children ? children : <div className="deck-widget-icon" />}
22
25
  </button>
23
26
  );
24
27
  };
@@ -2,19 +2,18 @@
2
2
  // SPDX-License-Identifier: MIT
3
3
  // Copyright (c) vis.gl contributors
4
4
 
5
- import type {ComponentChildren} from 'preact';
5
+ import type {ComponentChildren, JSX} from 'preact';
6
6
 
7
7
  export type IconButtonProps = {
8
- className: string;
9
- label: string;
10
- onClick: (event?) => unknown;
11
- /** Optional icon or element to render inside the button */
8
+ className?: string;
9
+ label?: string;
10
+ onClick?: JSX.MouseEventHandler<HTMLButtonElement>;
12
11
  children?: ComponentChildren;
13
12
  };
14
13
 
15
14
  /** Renders a button component with widget CSS */
16
15
  export const IconButton = (props: IconButtonProps) => {
17
- const {className, label, onClick, children} = props;
16
+ const {className = '', label, onClick, children} = props;
18
17
  return (
19
18
  <div className="deck-widget-button">
20
19
  <button
@@ -1,31 +1,14 @@
1
1
  import type {JSX} from 'preact';
2
2
  import {useState, useRef, useEffect} from 'preact/hooks';
3
3
  import {IconButton} from './icon-button';
4
-
5
- const MENU_STYLE: JSX.CSSProperties = {
6
- position: 'absolute',
7
- top: '100%',
8
- left: 0,
9
- background: 'white',
10
- border: '1px solid #ccc',
11
- borderRadius: '4px',
12
- marginTop: '4px',
13
- zIndex: 100
14
- };
15
-
16
- const MENU_ITEM_STYLE: JSX.CSSProperties = {
17
- background: 'white',
18
- border: 'none',
19
- padding: '4px',
20
- cursor: 'pointer',
21
- pointerEvents: 'auto'
22
- };
4
+ import {ButtonGroup} from './button-group';
5
+ import {GroupedIconButton} from './grouped-icon-button';
23
6
 
24
7
  export type IconMenuProps<KeyType = string> = {
25
8
  className: string;
26
- icon?: () => JSX.Element;
9
+ icon?: JSX.Element;
27
10
  label?: string;
28
- menuItems: {value: KeyType; icon: () => JSX.Element; label: string}[];
11
+ menuItems: {value: KeyType; icon: JSX.Element; label: string}[];
29
12
  initialItem: KeyType;
30
13
  onItemSelected: (item: KeyType) => void;
31
14
  };
@@ -61,27 +44,26 @@ export function IconMenu<KeyType extends string>(props: IconMenuProps<KeyType>)
61
44
 
62
45
  const selectedMenuItem = props.menuItems.find(item => item.value === selectedItem);
63
46
  const label = props.label || selectedMenuItem?.label || '';
64
- const Icon = (props.icon || selectedMenuItem?.icon)!;
47
+ const icon = (props.icon || selectedMenuItem?.icon)!;
65
48
 
66
49
  return (
67
50
  <div style={{position: 'relative', display: 'inline-block'}} ref={containerRef}>
68
51
  <IconButton className={props.className} label={label} onClick={handleButtonClick}>
69
- <Icon />
52
+ {icon}
70
53
  </IconButton>
71
54
  {menuOpen && (
72
- <div style={MENU_STYLE}>
73
- <div style={{display: 'flex', flexDirection: 'column'}}>
55
+ <div className="deck-widget-icon-menu">
56
+ <ButtonGroup orientation="vertical">
74
57
  {props.menuItems.map(item => (
75
- <button
58
+ <GroupedIconButton
76
59
  key={item.value}
77
- style={MENU_ITEM_STYLE}
78
- title={item.label}
60
+ label={item.label}
79
61
  onClick={() => handleSelectItem(item.value)}
80
62
  >
81
63
  {item.icon}
82
- </button>
64
+ </GroupedIconButton>
83
65
  ))}
84
- </div>
66
+ </ButtonGroup>
85
67
  </div>
86
68
  )}
87
69
  </div>
@@ -7,7 +7,7 @@ const MENU_STYLE: JSX.CSSProperties = {
7
7
  background: 'white',
8
8
  border: '1px solid #ccc',
9
9
  borderRadius: '4px',
10
- marginTop: '4px',
10
+ marginTop: 'var(--menu-gap, 4px)',
11
11
  zIndex: 100
12
12
  };
13
13
 
@@ -2,15 +2,17 @@
2
2
  // SPDX-License-Identifier: MIT
3
3
  // Copyright (c) vis.gl contributors
4
4
 
5
- import type {WidgetPlacement, Layer} from '@deck.gl/core';
5
+ import type {WidgetPlacement, Layer, WidgetProps} from '@deck.gl/core';
6
6
  import {render} from 'preact';
7
- import {Widget, WidgetProps} from '@deck.gl/core';
7
+ import {Widget} from '@deck.gl/core';
8
8
  import {IconButton} from './lib/components/icon-button';
9
9
 
10
10
  /** Properties for the LoadingWidget */
11
11
  export type LoadingWidgetProps = WidgetProps & {
12
12
  /** Widget positioning within the view. Default 'top-left'. */
13
13
  placement?: WidgetPlacement;
14
+ /** View to attach to and interact with. Required when using multiple views */
15
+ viewId?: string | null;
14
16
  /** Tooltip message when loading */
15
17
  label?: string;
16
18
  };
@@ -23,6 +25,7 @@ export class LoadingWidget extends Widget<LoadingWidgetProps> {
23
25
  ...Widget.defaultProps,
24
26
  id: 'loading',
25
27
  placement: 'top-left',
28
+ viewId: null,
26
29
  label: 'Loading layer data'
27
30
  };
28
31
 
@@ -32,11 +35,12 @@ export class LoadingWidget extends Widget<LoadingWidgetProps> {
32
35
 
33
36
  constructor(props: LoadingWidgetProps = {}) {
34
37
  super(props, LoadingWidget.defaultProps);
35
- this.placement = props.placement ?? this.placement;
38
+ this.setProps(this.props);
36
39
  }
37
40
 
38
41
  setProps(props: Partial<LoadingWidgetProps>) {
39
42
  this.placement = props.placement ?? this.placement;
43
+ this.viewId = props.viewId ?? this.viewId;
40
44
  super.setProps(props);
41
45
  }
42
46
 
@@ -45,7 +49,7 @@ export class LoadingWidget extends Widget<LoadingWidgetProps> {
45
49
  // TODO(ibgreen) - this should not be a button, but styling is so nested that it is easier to reuse this component.
46
50
  this.loading && (
47
51
  <IconButton
48
- className="deck-widget-spinner-icon"
52
+ className="deck-widget-spinner"
49
53
  label={this.props.label}
50
54
  onClick={this.handleClick.bind(this)}
51
55
  />
@@ -55,7 +59,7 @@ export class LoadingWidget extends Widget<LoadingWidgetProps> {
55
59
  }
56
60
 
57
61
  onRedraw({layers}: {layers: Layer[]}): void {
58
- const loading = !layers.some(layer => !layer.isLoaded);
62
+ const loading = layers.some(layer => !layer.isLoaded);
59
63
  if (loading !== this.loading) {
60
64
  this.loading = loading;
61
65
  this.updateHTML();