@deck.gl/core 9.3.0-alpha.1 → 9.3.0-alpha.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 (134) hide show
  1. package/debug.min.js +1 -1
  2. package/dist/controllers/controller.d.ts +5 -4
  3. package/dist/controllers/controller.d.ts.map +1 -1
  4. package/dist/controllers/controller.js +18 -7
  5. package/dist/controllers/controller.js.map +1 -1
  6. package/dist/controllers/first-person-controller.d.ts +3 -2
  7. package/dist/controllers/first-person-controller.d.ts.map +1 -1
  8. package/dist/controllers/first-person-controller.js +13 -5
  9. package/dist/controllers/first-person-controller.js.map +1 -1
  10. package/dist/controllers/globe-controller.d.ts +1 -0
  11. package/dist/controllers/globe-controller.d.ts.map +1 -1
  12. package/dist/controllers/globe-controller.js +66 -5
  13. package/dist/controllers/globe-controller.js.map +1 -1
  14. package/dist/controllers/map-controller.d.ts +7 -18
  15. package/dist/controllers/map-controller.d.ts.map +1 -1
  16. package/dist/controllers/map-controller.js +94 -50
  17. package/dist/controllers/map-controller.js.map +1 -1
  18. package/dist/controllers/orbit-controller.d.ts +12 -4
  19. package/dist/controllers/orbit-controller.d.ts.map +1 -1
  20. package/dist/controllers/orbit-controller.js +118 -10
  21. package/dist/controllers/orbit-controller.js.map +1 -1
  22. package/dist/controllers/orthographic-controller.d.ts +117 -9
  23. package/dist/controllers/orthographic-controller.d.ts.map +1 -1
  24. package/dist/controllers/orthographic-controller.js +302 -37
  25. package/dist/controllers/orthographic-controller.js.map +1 -1
  26. package/dist/controllers/terrain-controller.d.ts +29 -0
  27. package/dist/controllers/terrain-controller.d.ts.map +1 -0
  28. package/dist/controllers/terrain-controller.js +108 -0
  29. package/dist/controllers/terrain-controller.js.map +1 -0
  30. package/dist/controllers/view-state.d.ts +2 -1
  31. package/dist/controllers/view-state.d.ts.map +1 -1
  32. package/dist/controllers/view-state.js +2 -1
  33. package/dist/controllers/view-state.js.map +1 -1
  34. package/dist/debug/loggers.d.ts.map +1 -1
  35. package/dist/debug/loggers.js +1 -4
  36. package/dist/debug/loggers.js.map +1 -1
  37. package/dist/dist.dev.js +3800 -1675
  38. package/dist/effects/lighting/lighting-effect.d.ts +1 -0
  39. package/dist/effects/lighting/lighting-effect.d.ts.map +1 -1
  40. package/dist/effects/lighting/lighting-effect.js +14 -5
  41. package/dist/effects/lighting/lighting-effect.js.map +1 -1
  42. package/dist/index.cjs +775 -123
  43. package/dist/index.cjs.map +4 -4
  44. package/dist/index.d.ts +1 -0
  45. package/dist/index.d.ts.map +1 -1
  46. package/dist/index.js +1 -0
  47. package/dist/index.js.map +1 -1
  48. package/dist/lib/attribute/attribute-manager.d.ts.map +1 -1
  49. package/dist/lib/attribute/attribute-manager.js +2 -0
  50. package/dist/lib/attribute/attribute-manager.js.map +1 -1
  51. package/dist/lib/deck-picker.d.ts +6 -1
  52. package/dist/lib/deck-picker.d.ts.map +1 -1
  53. package/dist/lib/deck-picker.js +15 -3
  54. package/dist/lib/deck-picker.js.map +1 -1
  55. package/dist/lib/deck-renderer.d.ts +6 -1
  56. package/dist/lib/deck-renderer.d.ts.map +1 -1
  57. package/dist/lib/deck-renderer.js +14 -2
  58. package/dist/lib/deck-renderer.js.map +1 -1
  59. package/dist/lib/deck.d.ts +5 -0
  60. package/dist/lib/deck.d.ts.map +1 -1
  61. package/dist/lib/deck.js +13 -3
  62. package/dist/lib/deck.js.map +1 -1
  63. package/dist/lib/init.js +2 -2
  64. package/dist/lib/layer.d.ts.map +1 -1
  65. package/dist/lib/layer.js +1 -0
  66. package/dist/lib/layer.js.map +1 -1
  67. package/dist/passes/draw-layers-pass.d.ts +2 -0
  68. package/dist/passes/draw-layers-pass.d.ts.map +1 -1
  69. package/dist/passes/draw-layers-pass.js +3 -0
  70. package/dist/passes/draw-layers-pass.js.map +1 -1
  71. package/dist/passes/layers-pass.d.ts +2 -1
  72. package/dist/passes/layers-pass.d.ts.map +1 -1
  73. package/dist/passes/layers-pass.js +3 -0
  74. package/dist/passes/layers-pass.js.map +1 -1
  75. package/dist/passes/pick-layers-pass.d.ts +5 -2
  76. package/dist/passes/pick-layers-pass.d.ts.map +1 -1
  77. package/dist/passes/pick-layers-pass.js +3 -2
  78. package/dist/passes/pick-layers-pass.js.map +1 -1
  79. package/dist/shaderlib/project/project.glsl.d.ts.map +1 -1
  80. package/dist/shaderlib/project/project.glsl.js +3 -0
  81. package/dist/shaderlib/project/project.glsl.js.map +1 -1
  82. package/dist/utils/deep-merge.d.ts +5 -0
  83. package/dist/utils/deep-merge.d.ts.map +1 -0
  84. package/dist/utils/deep-merge.js +31 -0
  85. package/dist/utils/deep-merge.js.map +1 -0
  86. package/dist/utils/math-utils.d.ts +4 -0
  87. package/dist/utils/math-utils.d.ts.map +1 -1
  88. package/dist/utils/math-utils.js +8 -0
  89. package/dist/utils/math-utils.js.map +1 -1
  90. package/dist/viewports/globe-viewport.d.ts +1 -0
  91. package/dist/viewports/globe-viewport.d.ts.map +1 -1
  92. package/dist/viewports/globe-viewport.js +1 -1
  93. package/dist/viewports/globe-viewport.js.map +1 -1
  94. package/dist/viewports/orbit-viewport.d.ts.map +1 -1
  95. package/dist/viewports/orbit-viewport.js +7 -2
  96. package/dist/viewports/orbit-viewport.js.map +1 -1
  97. package/dist/viewports/orthographic-viewport.d.ts +8 -2
  98. package/dist/viewports/orthographic-viewport.d.ts.map +1 -1
  99. package/dist/viewports/orthographic-viewport.js.map +1 -1
  100. package/dist/views/orthographic-view.d.ts +38 -4
  101. package/dist/views/orthographic-view.d.ts.map +1 -1
  102. package/dist/views/orthographic-view.js.map +1 -1
  103. package/dist/views/view.d.ts.map +1 -1
  104. package/dist/views/view.js +2 -8
  105. package/dist/views/view.js.map +1 -1
  106. package/dist.min.js +220 -144
  107. package/package.json +9 -9
  108. package/src/controllers/controller.ts +23 -9
  109. package/src/controllers/first-person-controller.ts +18 -8
  110. package/src/controllers/globe-controller.ts +89 -5
  111. package/src/controllers/map-controller.ts +105 -56
  112. package/src/controllers/orbit-controller.ts +147 -13
  113. package/src/controllers/orthographic-controller.ts +417 -41
  114. package/src/controllers/terrain-controller.ts +146 -0
  115. package/src/controllers/view-state.ts +8 -1
  116. package/src/debug/loggers.ts +1 -5
  117. package/src/effects/lighting/lighting-effect.ts +20 -8
  118. package/src/index.ts +1 -0
  119. package/src/lib/attribute/attribute-manager.ts +1 -0
  120. package/src/lib/deck-picker.ts +18 -4
  121. package/src/lib/deck-renderer.ts +17 -3
  122. package/src/lib/deck.ts +19 -3
  123. package/src/lib/layer.ts +1 -0
  124. package/src/passes/draw-layers-pass.ts +5 -0
  125. package/src/passes/layers-pass.ts +5 -1
  126. package/src/passes/pick-layers-pass.ts +8 -4
  127. package/src/shaderlib/project/project.glsl.ts +3 -0
  128. package/src/utils/deep-merge.ts +33 -0
  129. package/src/utils/math-utils.ts +12 -0
  130. package/src/viewports/globe-viewport.ts +1 -1
  131. package/src/viewports/orbit-viewport.ts +8 -2
  132. package/src/viewports/orthographic-viewport.ts +8 -2
  133. package/src/views/orthographic-view.ts +38 -4
  134. package/src/views/view.ts +2 -8
@@ -11,7 +11,7 @@ import {Matrix4, Vector3} from '@math.gl/core';
11
11
  import ShadowPass from '../../passes/shadow-pass';
12
12
  import shadow from '../../shaderlib/shadow/shadow';
13
13
 
14
- import type {LightingProps} from '@luma.gl/shadertools';
14
+ import type {Light, LightingProps} from '@luma.gl/shadertools';
15
15
  import type {ShadowModuleProps} from '../../shaderlib/shadow/shadow';
16
16
  import type Layer from '../../lib/layer';
17
17
  import type {Effect, EffectContext, PreRenderOptions} from '../../lib/effect';
@@ -140,15 +140,9 @@ export default class LightingEffect implements Effect {
140
140
  } satisfies ShadowModuleProps)
141
141
  : {};
142
142
 
143
- // when not rendering to screen, turn off lighting by adding empty light source object
144
- // lights shader module relies on the `lightSources` to turn on/off lighting
145
143
  const lightingProps: LightingProps = {
146
144
  enabled: true,
147
- ambientLight: this.ambientLight,
148
- directionalLights: this.directionalLights.map(directionalLight =>
149
- directionalLight.getProjectedLight({layer})
150
- ),
151
- pointLights: this.pointLights.map(pointLight => pointLight.getProjectedLight({layer}))
145
+ lights: this._getLights(layer)
152
146
  };
153
147
  // @ts-expect-error material is not a Layer prop
154
148
  const materialProps = layer.props.material;
@@ -203,4 +197,22 @@ export default class LightingEffect implements Effect {
203
197
  );
204
198
  }
205
199
  }
200
+
201
+ private _getLights(layer: Layer): Light[] {
202
+ const lights: Light[] = [];
203
+
204
+ if (this.ambientLight) {
205
+ lights.push(this.ambientLight);
206
+ }
207
+
208
+ for (const pointLight of this.pointLights) {
209
+ lights.push(pointLight.getProjectedLight({layer}));
210
+ }
211
+
212
+ for (const directionalLight of this.directionalLights) {
213
+ lights.push(directionalLight.getProjectedLight({layer}));
214
+ }
215
+
216
+ return lights;
217
+ }
206
218
  }
package/src/index.ts CHANGED
@@ -65,6 +65,7 @@ export {default as _GlobeView} from './views/globe-view';
65
65
  // Controllers
66
66
  export {default as Controller} from './controllers/controller';
67
67
  export {default as MapController} from './controllers/map-controller';
68
+ export {default as TerrainController} from './controllers/terrain-controller';
68
69
  export {default as _GlobeController} from './controllers/globe-controller';
69
70
  export {default as FirstPersonController} from './controllers/first-person-controller';
70
71
  export {default as OrbitController} from './controllers/orbit-controller';
@@ -235,6 +235,7 @@ export default class AttributeManager {
235
235
 
236
236
  if (this.stats) {
237
237
  this.stats.get('Update Attributes').timeEnd();
238
+ if (updated) this.stats.get('Attributes updated').incrementCount();
238
239
  }
239
240
 
240
241
  this.attributeTransitionManager.update({
@@ -11,7 +11,8 @@ import {
11
11
  getEmptyPickingInfo,
12
12
  PickingInfo
13
13
  } from './picking/pick-info';
14
-
14
+ import type {RenderStats} from '../passes/layers-pass';
15
+ import type {Stats} from '@probe.gl/stats';
15
16
  import type {Framebuffer} from '@luma.gl/core';
16
17
  import type {FilterContext, Rect} from '../passes/layers-pass';
17
18
  import type Layer from './layer';
@@ -52,6 +53,7 @@ export default class DeckPicker {
52
53
  depthFBO?: Framebuffer;
53
54
  pickLayersPass: PickLayersPass;
54
55
  layerFilter?: (context: FilterContext) => boolean;
56
+ stats?: Stats;
55
57
 
56
58
  /** Identifiers of the previously picked object, for callback tracking and auto highlight */
57
59
  lastPickedInfo: {
@@ -62,8 +64,9 @@ export default class DeckPicker {
62
64
 
63
65
  _pickable: boolean = true;
64
66
 
65
- constructor(device: Device) {
67
+ constructor(device: Device, opts: {stats?: Stats} = {}) {
66
68
  this.device = device;
69
+ this.stats = opts.stats;
67
70
  this.pickLayersPass = new PickLayersPass(device);
68
71
  this.lastPickedInfo = {
69
72
  index: -1,
@@ -808,7 +811,8 @@ export default class DeckPicker {
808
811
  }
809
812
  }
810
813
 
811
- const {decodePickingColor} = this.pickLayersPass.render(opts);
814
+ const {decodePickingColor, stats} = this.pickLayersPass.render(opts);
815
+ this._updateStats(stats);
812
816
 
813
817
  // Read from an already rendered picking buffer
814
818
  // Returns an Uint8ClampedArray of picked pixels
@@ -913,7 +917,8 @@ export default class DeckPicker {
913
917
  }
914
918
  }
915
919
 
916
- const {decodePickingColor} = this.pickLayersPass.render(opts);
920
+ const {decodePickingColor, stats} = this.pickLayersPass.render(opts);
921
+ this._updateStats(stats);
917
922
 
918
923
  // Read from an already rendered picking buffer
919
924
  // Returns an Uint8ClampedArray of picked pixels
@@ -930,6 +935,15 @@ export default class DeckPicker {
930
935
  return {pickedColors, decodePickingColor};
931
936
  }
932
937
 
938
+ private _updateStats(source: RenderStats[]) {
939
+ if (!this.stats) return;
940
+ let layersCount = 0;
941
+ for (const {visibleCount} of source) {
942
+ layersCount += visibleCount;
943
+ }
944
+ this.stats.get('Layers picked').addCount(layersCount);
945
+ }
946
+
933
947
  /**
934
948
  * Determine which layers to use for the depth (pickZ) pass.
935
949
  * - If a non-draped layer was picked, use just that layer.
@@ -7,7 +7,8 @@ import {Framebuffer} from '@luma.gl/core';
7
7
  import debug from '../debug/index';
8
8
  import DrawLayersPass from '../passes/draw-layers-pass';
9
9
  import PickLayersPass from '../passes/pick-layers-pass';
10
-
10
+ import type {RenderStats} from '../passes/layers-pass';
11
+ import type {Stats} from '@probe.gl/stats';
11
12
  import type Layer from './layer';
12
13
  import type Viewport from '../viewports/viewport';
13
14
  import type View from '../views/view';
@@ -24,14 +25,16 @@ export default class DeckRenderer {
24
25
  drawPickingColors: boolean;
25
26
  drawLayersPass: DrawLayersPass;
26
27
  pickLayersPass: PickLayersPass;
28
+ stats?: Stats;
27
29
 
28
30
  private renderCount: number;
29
31
  private _needsRedraw: string | false;
30
32
  private renderBuffers: Framebuffer[];
31
33
  private lastPostProcessEffect: string | null;
32
34
 
33
- constructor(device: Device) {
35
+ constructor(device: Device, opts: {stats?: Stats} = {}) {
34
36
  this.device = device;
37
+ this.stats = opts.stats;
35
38
  this.layerFilter = null;
36
39
  this.drawPickingColors = false;
37
40
  this.drawLayersPass = new DrawLayersPass(device);
@@ -88,7 +91,8 @@ export default class DeckRenderer {
88
91
  renderOpts.clearColor = [0, 0, 0, 0];
89
92
  renderOpts.clearCanvas = true;
90
93
  }
91
- const renderStats = layerPass.render({...renderOpts, target: outputBuffer});
94
+ const renderResult = layerPass.render({...renderOpts, target: outputBuffer});
95
+ const renderStats = 'stats' in renderResult ? renderResult.stats : renderResult;
92
96
 
93
97
  if (renderOpts.effects) {
94
98
  if (this.lastPostProcessEffect) {
@@ -102,6 +106,7 @@ export default class DeckRenderer {
102
106
  this.renderCount++;
103
107
 
104
108
  debug(TRACE_RENDER_LAYERS, this, renderStats, opts);
109
+ this._updateStats(renderStats);
105
110
  }
106
111
 
107
112
  needsRedraw(opts: {clearRedrawFlags: boolean} = {clearRedrawFlags: false}): string | false {
@@ -120,6 +125,15 @@ export default class DeckRenderer {
120
125
  renderBuffers.length = 0;
121
126
  }
122
127
 
128
+ private _updateStats(source: RenderStats[]) {
129
+ if (!this.stats) return;
130
+ let layersCount = 0;
131
+ for (const {visibleCount} of source) {
132
+ layersCount += visibleCount;
133
+ }
134
+ this.stats.get('Layers rendered').addCount(layersCount);
135
+ }
136
+
123
137
  private _preRender(effects: Effect[], opts: LayersPassRenderOptions) {
124
138
  this.lastPostProcessEffect = null;
125
139
  opts.preRenderStats = opts.preRenderStats || {};
package/src/lib/deck.ts CHANGED
@@ -55,10 +55,15 @@ const getCursor = ({isDragging}) => (isDragging ? 'grabbing' : 'grab');
55
55
  export type DeckMetrics = {
56
56
  fps: number;
57
57
  setPropsTime: number;
58
+ layersCount: number;
59
+ drawLayersCount: number;
60
+ updateLayersCount: number;
58
61
  updateAttributesTime: number;
62
+ updateAttributesCount: number;
59
63
  framesRedrawn: number;
60
64
  pickTime: number;
61
65
  pickCount: number;
66
+ pickLayersCount: number;
62
67
  gpuTime: number;
63
68
  gpuTimePerFrame: number;
64
69
  cpuTime: number;
@@ -309,10 +314,15 @@ export default class Deck<ViewsT extends ViewOrViews = null> {
309
314
  protected metrics: DeckMetrics = {
310
315
  fps: 0,
311
316
  setPropsTime: 0,
317
+ layersCount: 0,
318
+ drawLayersCount: 0,
319
+ updateLayersCount: 0,
320
+ updateAttributesCount: 0,
312
321
  updateAttributesTime: 0,
313
322
  framesRedrawn: 0,
314
323
  pickTime: 0,
315
324
  pickCount: 0,
325
+ pickLayersCount: 0,
316
326
  gpuTime: 0,
317
327
  gpuTimePerFrame: 0,
318
328
  cpuTime: 0,
@@ -1132,9 +1142,9 @@ export default class Deck<ViewsT extends ViewOrViews = null> {
1132
1142
  device: this.device
1133
1143
  });
1134
1144
 
1135
- this.deckRenderer = new DeckRenderer(this.device);
1145
+ this.deckRenderer = new DeckRenderer(this.device, {stats: this.stats});
1136
1146
 
1137
- this.deckPicker = new DeckPicker(this.device);
1147
+ this.deckPicker = new DeckPicker(this.device, {stats: this.stats});
1138
1148
 
1139
1149
  const widgetParent =
1140
1150
  this.props.parent?.querySelector<HTMLDivElement>('.deck-widgets-root') ||
@@ -1349,13 +1359,19 @@ export default class Deck<ViewsT extends ViewOrViews = null> {
1349
1359
  stats.get('pickObjects Time').time;
1350
1360
  metrics.pickCount = stats.get('Pick Count').count;
1351
1361
 
1362
+ metrics.layersCount = this.layerManager?.layers.length ?? 0;
1363
+ metrics.drawLayersCount = stats.get('Layers rendered').lastSampleCount;
1364
+ metrics.pickLayersCount = stats.get('Layers picked').lastSampleCount;
1365
+ metrics.updateAttributesCount = stats.get('Layers updated').count;
1366
+ metrics.updateAttributesCount = stats.get('Attributes updated').count;
1367
+
1352
1368
  // Luma stats
1353
1369
  metrics.gpuTime = stats.get('GPU Time').time;
1354
1370
  metrics.cpuTime = stats.get('CPU Time').time;
1355
1371
  metrics.gpuTimePerFrame = stats.get('GPU Time').getAverageTime();
1356
1372
  metrics.cpuTimePerFrame = stats.get('CPU Time').getAverageTime();
1357
1373
 
1358
- const memoryStats = luma.stats.get('Memory Usage');
1374
+ const memoryStats = luma.stats.get('GPU Time and Memory');
1359
1375
  metrics.bufferMemory = memoryStats.get('Buffer Memory').count;
1360
1376
  metrics.textureMemory = memoryStats.get('Texture Memory').count;
1361
1377
  metrics.renderbufferMemory = memoryStats.get('Renderbuffer Memory').count;
package/src/lib/layer.ts CHANGED
@@ -969,6 +969,7 @@ export default abstract class Layer<PropsT extends {} = {}> extends Component<
969
969
  if (!stateNeedsUpdate) {
970
970
  return;
971
971
  }
972
+ this.context.stats.get('Layer updates').incrementCount();
972
973
 
973
974
  const currentProps = this.props;
974
975
  const context = this.context;
@@ -3,10 +3,15 @@
3
3
  // Copyright (c) vis.gl contributors
4
4
 
5
5
  import LayersPass from './layers-pass';
6
+ import type {LayersPassRenderOptions, RenderStats} from './layers-pass';
6
7
 
7
8
  export default class DrawLayersPass extends LayersPass {
8
9
  shouldDrawLayer(layer) {
9
10
  const {operation} = layer.props;
10
11
  return operation.includes('draw') || operation.includes('terrain');
11
12
  }
13
+
14
+ render(options: LayersPassRenderOptions): RenderStats[] {
15
+ return this._render(options);
16
+ }
12
17
  }
@@ -65,7 +65,11 @@ export type RenderStats = {
65
65
  export default class LayersPass extends Pass {
66
66
  _lastRenderIndex: number = -1;
67
67
 
68
- render(options: LayersPassRenderOptions): any {
68
+ render(options: LayersPassRenderOptions): void {
69
+ this._render(options);
70
+ }
71
+
72
+ protected _render(options: LayersPassRenderOptions): RenderStats[] {
69
73
  const canvasContext = this.device.canvasContext!;
70
74
  const framebuffer = options.target ?? canvasContext.getCurrentFramebuffer();
71
75
  const [width, height] = canvasContext.getDrawingBufferSize();
@@ -46,13 +46,17 @@ export default class PickLayersPass extends LayersPass {
46
46
  byAlpha: EncodedPickingColors[];
47
47
  } | null = null;
48
48
 
49
- render(props: LayersPassRenderOptions | PickLayersPassRenderOptions) {
49
+ render(props: LayersPassRenderOptions | PickLayersPassRenderOptions): {
50
+ decodePickingColor: PickingColorDecoder | null;
51
+ stats: RenderStats[];
52
+ } {
50
53
  if ('pickingFBO' in props) {
51
54
  // When drawing into an off-screen buffer, use the alpha channel to encode layer index
52
55
  return this._drawPickingBuffer(props);
53
56
  }
54
57
  // When drawing to screen (debug mode), do not use the alpha channel so that result is always visible
55
- return super.render(props);
58
+ const stats = super._render(props);
59
+ return {decodePickingColor: null, stats};
56
60
  }
57
61
 
58
62
  // Private
@@ -74,7 +78,7 @@ export default class PickLayersPass extends LayersPass {
74
78
  clearColor
75
79
  }: PickLayersPassRenderOptions): {
76
80
  decodePickingColor: PickingColorDecoder | null;
77
- stats: RenderStats;
81
+ stats: RenderStats[];
78
82
  } {
79
83
  this.pickZ = pickZ;
80
84
  const colorEncoderState = this._resetColorEncoder(pickZ);
@@ -85,7 +89,7 @@ export default class PickLayersPass extends LayersPass {
85
89
  // Note that the callback here is called synchronously.
86
90
  // Set blend mode for picking
87
91
  // always overwrite existing pixel with [r,g,b,layerIndex]
88
- const renderStatus = super.render({
92
+ const renderStatus = super._render({
89
93
  target: pickingFBO,
90
94
  layers,
91
95
  layerFilter,
@@ -265,6 +265,9 @@ vec2 project_pixel_size_to_clipspace(vec2 pixels) {
265
265
  float project_size_to_pixel(float meters) {
266
266
  return project_size(meters) * project.scale;
267
267
  }
268
+ vec2 project_size_to_pixel(vec2 meters) {
269
+ return project_size(meters) * project.scale;
270
+ }
268
271
  float project_size_to_pixel(float size, int unit) {
269
272
  if (unit == UNIT_METERS) return project_size_to_pixel(size);
270
273
  if (unit == UNIT_COMMON) return size * project.scale;
@@ -0,0 +1,33 @@
1
+ // deck.gl
2
+ // SPDX-License-Identifier: MIT
3
+ // Copyright (c) vis.gl contributors
4
+
5
+ /** Merge two viewstates, except `id`
6
+ * For position arrays such as `target`, only override the components that are defined.
7
+ */
8
+ export function deepMergeViewState<ViewStateT extends Record<string, any>>(
9
+ a: ViewStateT,
10
+ b: ViewStateT
11
+ ): ViewStateT {
12
+ const result = {...a};
13
+ for (const key in b) {
14
+ if (key === 'id') continue;
15
+ if (Array.isArray(result[key]) && Array.isArray(b[key])) {
16
+ result[key] = mergeNumericArray(result[key], b[key]) as any;
17
+ } else {
18
+ result[key] = b[key];
19
+ }
20
+ }
21
+ return result;
22
+ }
23
+
24
+ function mergeNumericArray(target: number[], source: number[]): number[] {
25
+ target = target.slice();
26
+ for (let i = 0; i < source.length; i++) {
27
+ const v = source[i];
28
+ if (Number.isFinite(v)) {
29
+ target[i] = v;
30
+ }
31
+ }
32
+ return target;
33
+ }
@@ -26,6 +26,18 @@ export function getCameraPosition(
26
26
  return [viewMatrixInverse[12], viewMatrixInverse[13], viewMatrixInverse[14]];
27
27
  }
28
28
 
29
+ export function getProjectionParameters(projectionMatrix: Matrix4 | NumericArray): {
30
+ near: number;
31
+ far: number;
32
+ } {
33
+ const m22 = projectionMatrix[10];
34
+ const m23 = projectionMatrix[14];
35
+ return {
36
+ near: m23 / (m22 - 1),
37
+ far: m23 / (m22 + 1)
38
+ };
39
+ }
40
+
29
41
  export type FrustumPlane = {
30
42
  distance: number;
31
43
  normal: Vector3;
@@ -13,7 +13,7 @@ import {vec3, vec4} from '@math.gl/core';
13
13
  const DEGREES_TO_RADIANS = Math.PI / 180;
14
14
  const RADIANS_TO_DEGREES = 180 / Math.PI;
15
15
  const EARTH_RADIUS = 6370972;
16
- const GLOBE_RADIUS = 256;
16
+ export const GLOBE_RADIUS = 256;
17
17
 
18
18
  function getDistanceScales() {
19
19
  const unitsPerMeter = GLOBE_RADIUS / EARTH_RADIUS;
@@ -6,6 +6,7 @@ import Viewport from '../viewports/viewport';
6
6
 
7
7
  import {Matrix4} from '@math.gl/core';
8
8
  import {pixelsToWorld, fovyToAltitude} from '@math.gl/web-mercator';
9
+ import {getProjectionParameters} from '../utils/math-utils';
9
10
 
10
11
  const DEGREES_TO_RADIANS = Math.PI / 180;
11
12
 
@@ -150,9 +151,14 @@ export default class OrbitViewport extends Viewport {
150
151
 
151
152
  panByPosition(coords: number[], pixel: number[], startPixel?: number[]): OrbitViewportOptions {
152
153
  const p0 = this.project(coords);
154
+ const {near, far} = getProjectionParameters(this.projectionMatrix);
155
+ const pz = (near * far) / (far - p0[2] * (far - near));
156
+ const centerZ = (near * far) / (far - this.projectedCenter[2] * (far - near));
157
+ const shiftScale = pz / centerZ;
158
+
153
159
  const nextCenter = [
154
- this.width / 2 + p0[0] - pixel[0],
155
- this.height / 2 + p0[1] - pixel[1],
160
+ this.width / 2 + (p0[0] - pixel[0]) * shiftScale,
161
+ this.height / 2 + (p0[1] - pixel[1]) * shiftScale,
156
162
  this.projectedCenter[2]
157
163
  ];
158
164
  return {
@@ -48,6 +48,10 @@ function getProjectionMatrix({
48
48
  });
49
49
  }
50
50
 
51
+ /** independent zoom levels for X and Y axes
52
+ * @deprecated use `zoomX` and `zoomY` instead */
53
+ type Deprecated2DZoom = [number, number];
54
+
51
55
  export type OrthographicViewportOptions = {
52
56
  /** Name of the viewport */
53
57
  id?: string;
@@ -62,8 +66,10 @@ export type OrthographicViewportOptions = {
62
66
  /** The world position at the center of the viewport. Default `[0, 0, 0]`. */
63
67
  target?: [number, number, number] | [number, number];
64
68
  /** The zoom level of the viewport. `zoom: 0` maps one unit distance to one pixel on screen, and increasing `zoom` by `1` scales the same object to twice as large.
65
- * To apply independent zoom levels to the X and Y axes, supply an array `[zoomX, zoomY]`. Default `0`. */
66
- zoom?: number | [number, number];
69
+ * To apply independent zoom levels to the X and Y axes, use `zoomX` and `zoomY`.
70
+ * @default 0
71
+ */
72
+ zoom?: number | Deprecated2DZoom;
67
73
  /** Independent zoom along the X axis. Overrides `zoom`. */
68
74
  zoomX?: number;
69
75
  /** Independent zoom along the Y axis. Overrides `zoom`. */
@@ -6,16 +6,50 @@ import View, {CommonViewState, CommonViewProps} from './view';
6
6
  import OrthographicViewport from '../viewports/orthographic-viewport';
7
7
  import OrthographicController from '../controllers/orthographic-controller';
8
8
 
9
+ /** independent zoom levels for X and Y axes
10
+ * @deprecated use `zoomX` and `zoomY` instead */
11
+ type Deprecated2DZoom = [number, number];
12
+
9
13
  export type OrthographicViewState = {
10
14
  /** The world position at the center of the viewport. Default `[0, 0, 0]`. */
11
15
  target?: [number, number, number] | [number, number];
12
16
  /** The zoom level of the viewport. `zoom: 0` maps one unit distance to one pixel on screen, and increasing `zoom` by `1` scales the same object to twice as large.
13
- * To apply independent zoom levels to the X and Y axes, supply an array `[zoomX, zoomY]`. Default `0`. */
14
- zoom?: number | [number, number];
15
- /** The min zoom level of the viewport. Default `-Infinity`. */
17
+ * To apply independent zoom levels to the X and Y axes, use `zoomX` and `zoomY`.
18
+ * @default 0
19
+ */
20
+ zoom?: number | Deprecated2DZoom;
21
+ /** Which axes to apply zoom to. One of 'X', 'Y' or 'all'
22
+ * @default 'all'
23
+ */
24
+ zoomAxis?: 'X' | 'Y' | 'all';
25
+ /** The zoom level along X axis. Overrides `zoom` if supplied. */
26
+ zoomX?: number;
27
+ /** The zoom level along Y axis. Overrides `zoom` if supplied. */
28
+ zoomY?: number;
29
+ /** The min zoom level of the viewport.
30
+ * @default -Infinity
31
+ */
16
32
  minZoom?: number;
17
- /** The max zoom level of the viewport. Default `Infinity`. */
33
+ /** The max zoom level of the viewport.
34
+ * @default Infinity
35
+ */
18
36
  maxZoom?: number;
37
+ /** The min zoom level along X axis.
38
+ * @default `minZoom`
39
+ */
40
+ maxZoomX?: number;
41
+ /** The max zoom level along X axis.
42
+ * @default `maxZoom`
43
+ */
44
+ minZoomX?: number;
45
+ /** The min zoom level along Y axis.
46
+ * @default `minZoom`
47
+ */
48
+ maxZoomY?: number;
49
+ /** The max zoom level along Y axis.
50
+ * @default `maxZoom`
51
+ */
52
+ minZoomY?: number;
19
53
  } & CommonViewState;
20
54
 
21
55
  export type OrthographicViewProps = {
package/src/views/view.ts CHANGED
@@ -5,6 +5,7 @@
5
5
  import Viewport from '../viewports/viewport';
6
6
  import {parsePosition, getPosition, LayoutExpression} from '../utils/positions';
7
7
  import {deepEqual} from '../utils/deep-equal';
8
+ import {deepMergeViewState} from '../utils/deep-merge';
8
9
  import type Controller from '../controllers/controller';
9
10
  import type {ControllerOptions} from '../controllers/controller';
10
11
  import type {TransitionProps} from '../controllers/transition-manager';
@@ -148,14 +149,7 @@ export default abstract class View<
148
149
  return this.props.viewState as ViewState;
149
150
  }
150
151
 
151
- // Merge in all props from View's viewState, except id
152
- const newViewState = {...viewState};
153
- for (const key in this.props.viewState) {
154
- if (key !== 'id') {
155
- newViewState[key] = this.props.viewState[key];
156
- }
157
- }
158
- return newViewState;
152
+ return deepMergeViewState<ViewState>(viewState, this.props.viewState as ViewState);
159
153
  }
160
154
 
161
155
  return viewState;