@webviz/subsurface-viewer 0.10.0 → 0.12.0

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.
@@ -1,59 +1,86 @@
1
+ import React, { useEffect, useState, useCallback, useMemo } from "react";
2
+ import { cloneDeep, isEmpty } from "lodash";
1
3
  import { JSONConfiguration, JSONConverter } from "@deck.gl/json/typed";
2
4
  import DeckGL from "@deck.gl/react/typed";
3
- import { OrthographicView, OrbitView, PointLight } from "@deck.gl/core/typed";
4
- import React, { useEffect, useState, useCallback, useMemo } from "react";
5
+ import { _CameraLight as CameraLight, AmbientLight, DirectionalLight, LightingEffect, OrbitController, OrbitView, OrthographicController, OrthographicView, PointLight, } from "@deck.gl/core/typed";
6
+ import { LineLayer } from "@deck.gl/layers/typed";
7
+ import { Matrix4 } from "@math.gl/core";
8
+ import { fovyToAltitude } from "@math.gl/web-mercator";
9
+ import { colorTables } from "@emerson-eps/color-tables";
10
+ import { boxCenter, boxUnion } from "../utils/BoundingBox3D";
5
11
  import JSON_CONVERTER_CONFIG from "../utils/configuration";
6
12
  import InfoCard from "./InfoCard";
7
13
  import DistanceScale from "./DistanceScale";
8
14
  import StatusIndicator from "./StatusIndicator";
9
15
  import fitBounds from "../utils/fit-bounds";
10
16
  import { validateColorTables, validateLayers } from "@webviz/wsc-common";
11
- import { getLayersByType } from "../layers/utils/layerTools";
12
- import { getWellLayerByTypeAndSelectedWells } from "../layers/utils/layerTools";
17
+ import { getModelMatrixScale, getLayersByType, getWellLayerByTypeAndSelectedWells, } from "../layers/utils/layerTools";
13
18
  import { WellsLayer, Axes2DLayer, NorthArrow3DLayer } from "../layers";
14
- import { isEmpty, isEqual } from "lodash";
15
- import { cloneDeep } from "lodash";
16
- import { colorTables } from "@emerson-eps/color-tables";
17
- import { getModelMatrixScale } from "../layers/utils/layerTools";
18
- import { OrbitController, OrthographicController } from "@deck.gl/core/typed";
19
19
  import IntersectionView from "../views/intersectionView";
20
- import { _CameraLight as CameraLight, AmbientLight, DirectionalLight, } from "@deck.gl/core/typed";
21
- import { LightingEffect } from "@deck.gl/core/typed";
22
- import { LineLayer } from "@deck.gl/layers/typed";
23
- import { Matrix4 } from "@math.gl/core";
24
- import { fovyToAltitude } from "@math.gl/web-mercator";
25
20
  const minZoom3D = -12;
26
21
  const maxZoom3D = 12;
27
22
  const minZoom2D = -12;
28
23
  const maxZoom2D = 4;
29
- class ZScaleOrbitController extends OrbitController {
30
- static setZScaleUpReference(setZScaleUp) {
31
- ZScaleOrbitController.setZScaleUp = setZScaleUp;
24
+ function updateZScaleReducer(zScale, action) {
25
+ return zScale * getZScaleModifier(action);
26
+ }
27
+ function getZScaleModifier(arrowEvent) {
28
+ let scaleFactor = 0;
29
+ switch (arrowEvent.key) {
30
+ case "ArrowUp":
31
+ scaleFactor = 0.05;
32
+ break;
33
+ case "ArrowDown":
34
+ scaleFactor = -0.05;
35
+ break;
36
+ case "PageUp":
37
+ scaleFactor = 0.25;
38
+ break;
39
+ case "PageDown":
40
+ scaleFactor = -0.25;
41
+ break;
42
+ default:
43
+ break;
32
44
  }
33
- static setZScaleDownReference(setZScaleDown) {
34
- ZScaleOrbitController.setZScaleDown = setZScaleDown;
45
+ if (arrowEvent.shiftModifier) {
46
+ scaleFactor /= 5;
35
47
  }
36
- handleEvent(event) {
37
- if (ZScaleOrbitController.setZScaleUp === null) {
38
- return super.handleEvent(event);
39
- }
40
- if (ZScaleOrbitController.setZScaleUp &&
41
- event.type === "keydown" &&
42
- event.key === "ArrowUp") {
43
- ZScaleOrbitController.setZScaleUp(Math.random());
44
- return true;
48
+ return 1 + scaleFactor;
49
+ }
50
+ function convertToArrowEvent(event) {
51
+ if (event.type === "keydown") {
52
+ const keyEvent = event;
53
+ switch (keyEvent.key) {
54
+ case "ArrowUp":
55
+ case "ArrowDown":
56
+ case "PageUp":
57
+ case "PageDown":
58
+ return {
59
+ key: keyEvent.key,
60
+ shiftModifier: keyEvent.srcEvent.shiftKey,
61
+ };
62
+ default:
63
+ return null;
45
64
  }
46
- else if (ZScaleOrbitController.setZScaleDown &&
47
- event.type === "keydown" &&
48
- event.key === "ArrowDown") {
49
- ZScaleOrbitController.setZScaleDown(Math.random());
50
- return true;
65
+ }
66
+ return null;
67
+ }
68
+ class ZScaleOrbitController extends OrbitController {
69
+ static setUpdateZScaleAction(updateZScaleAction) {
70
+ ZScaleOrbitController.updateZScaleAction = updateZScaleAction;
71
+ }
72
+ handleEvent(event) {
73
+ if (ZScaleOrbitController.updateZScaleAction) {
74
+ const arrowEvent = convertToArrowEvent(event);
75
+ if (arrowEvent) {
76
+ ZScaleOrbitController.updateZScaleAction(arrowEvent);
77
+ return true;
78
+ }
51
79
  }
52
80
  return super.handleEvent(event);
53
81
  }
54
82
  }
55
- ZScaleOrbitController.setZScaleUp = null;
56
- ZScaleOrbitController.setZScaleDown = null;
83
+ ZScaleOrbitController.updateZScaleAction = null;
57
84
  class ZScaleOrbitView extends OrbitView {
58
85
  get ControllerType() {
59
86
  return ZScaleOrbitController;
@@ -61,7 +88,7 @@ class ZScaleOrbitView extends OrbitView {
61
88
  }
62
89
  function parseLights(lights) {
63
90
  var _a, _b, _c, _d;
64
- if (typeof lights === "undefined") {
91
+ if (!lights) {
65
92
  return undefined;
66
93
  }
67
94
  const effects = [];
@@ -80,13 +107,13 @@ function parseLights(lights) {
80
107
  });
81
108
  lightsObj = Object.assign(Object.assign({}, lightsObj), { ambientLight });
82
109
  }
83
- if (typeof lights.pointLights !== "undefined") {
110
+ if (lights.pointLights) {
84
111
  for (const light of lights.pointLights) {
85
112
  const pointLight = new PointLight(Object.assign(Object.assign({}, light), { color: (_c = light.color) !== null && _c !== void 0 ? _c : [255, 255, 255] }));
86
113
  lightsObj = Object.assign(Object.assign({}, lightsObj), { pointLight });
87
114
  }
88
115
  }
89
- if (typeof lights.directionalLights !== "undefined") {
116
+ if (lights.directionalLights) {
90
117
  for (const light of lights.directionalLights) {
91
118
  const directionalLight = new DirectionalLight(Object.assign(Object.assign({}, light), { color: (_d = light.color) !== null && _d !== void 0 ? _d : [255, 255, 255] }));
92
119
  lightsObj = Object.assign(Object.assign({}, lightsObj), { directionalLight });
@@ -96,51 +123,8 @@ function parseLights(lights) {
96
123
  effects.push(lightingEffect);
97
124
  return effects;
98
125
  }
99
- function addBoundingBoxes(b1, b2) {
100
- const boxDefault = [0, 0, 0, 1, 1, 1];
101
- if (typeof b1 === "undefined" || typeof b2 === "undefined") {
102
- return boxDefault;
103
- }
104
- if (isEqual(b1, boxDefault)) {
105
- return b2;
106
- }
107
- const xmin = Math.min(b1[0], b2[0]);
108
- const ymin = Math.min(b1[1], b2[1]);
109
- const zmin = Math.min(b1[2], b2[2]);
110
- const xmax = Math.max(b1[3], b2[3]);
111
- const ymax = Math.max(b1[4], b2[4]);
112
- const zmax = Math.max(b1[5], b2[5]);
113
- return [xmin, ymin, zmin, xmax, ymax, zmax];
114
- }
115
126
  function mapBoundingBoxReducer(mapBoundingBox, action) {
116
- return addBoundingBoxes(mapBoundingBox, action.layerBoundingBox);
117
- }
118
- function boundingBoxCenter(box) {
119
- const xmin = box[0];
120
- const ymin = box[1];
121
- const zmin = box[2];
122
- const xmax = box[3];
123
- const ymax = box[4];
124
- const zmax = box[5];
125
- return [
126
- xmin + 0.5 * (xmax - xmin),
127
- ymin + 0.5 * (ymax - ymin),
128
- zmin + 0.5 * (zmax - zmin),
129
- ];
130
- }
131
- // Exclude "layerIds" when monitoring changes to "view" prop as we do not
132
- // want to recalculate views when the layers change.
133
- function compareViewsProp(views) {
134
- if (typeof views === "undefined" || Object.keys(views).length === 0) {
135
- return undefined;
136
- }
137
- const copy = cloneDeep(views);
138
- const viewports = copy.viewports.map((e) => {
139
- delete e.layerIds;
140
- return e;
141
- });
142
- copy.viewports = viewports;
143
- return JSON.stringify(copy);
127
+ return boxUnion(mapBoundingBox, action.layerBoundingBox);
144
128
  }
145
129
  export function useHoverInfo() {
146
130
  const [hoverInfo, setHoverInfo] = useState([]);
@@ -160,178 +144,56 @@ function defaultTooltip(info) {
160
144
  const feat = info.object;
161
145
  return (_c = feat === null || feat === void 0 ? void 0 : feat.properties) === null || _c === void 0 ? void 0 : _c["name"];
162
146
  }
163
- function adjustCameraTarget(viewStates, scale, newScale) {
164
- const vs = cloneDeep(viewStates);
165
- for (const key in vs) {
166
- if (typeof vs[key].target !== "undefined") {
167
- const t = vs[key].target;
168
- const z = newScale * (t[2] / scale);
169
- vs[key].target = [t[0], t[1], z];
170
- }
171
- }
172
- return vs;
173
- }
174
- function calculateZoomFromBBox3D(camera, size) {
175
- const DEGREES_TO_RADIANS = Math.PI / 180;
176
- const RADIANS_TO_DEGREES = 180 / Math.PI;
177
- const IDENTITY = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
178
- const camera_ = cloneDeep(camera);
179
- if (typeof camera_ === "undefined" || !Array.isArray(camera_.zoom)) {
180
- return camera;
181
- }
182
- if (size.width === 0 || size.height === 0) {
183
- camera_.zoom = 0;
184
- camera_.target = [0, 0, 0];
185
- return camera_;
186
- }
187
- // camera fov eye position. see deck.gl file orbit-viewports.ts
188
- const fovy = 50; // default in deck.gl. May also be set construction OrbitView
189
- const fD = fovyToAltitude(fovy);
190
- const bbox = camera_.zoom;
191
- const xMin = bbox[0];
192
- const yMin = bbox[1];
193
- const zMin = bbox[2];
194
- const xMax = bbox[3];
195
- const yMax = bbox[4];
196
- const zMax = bbox[5];
197
- const target = [
198
- xMin + (xMax - xMin) / 2,
199
- yMin + (yMax - yMin) / 2,
200
- zMin + (zMax - zMin) / 2,
201
- ];
202
- const cameraFovVertical = 50;
203
- const angle_ver = (cameraFovVertical / 2) * DEGREES_TO_RADIANS;
204
- const L = size.height / 2 / Math.sin(angle_ver);
205
- const r = L * Math.cos(angle_ver);
206
- const cameraFov = 2 * Math.atan(size.width / 2 / r) * RADIANS_TO_DEGREES;
207
- const angle_hor = (cameraFov / 2) * DEGREES_TO_RADIANS;
208
- const points = [];
209
- points.push([xMin, yMin, zMin]);
210
- points.push([xMin, yMax, zMin]);
211
- points.push([xMax, yMax, zMin]);
212
- points.push([xMax, yMin, zMin]);
213
- points.push([xMin, yMin, zMax]);
214
- points.push([xMin, yMax, zMax]);
215
- points.push([xMax, yMax, zMax]);
216
- points.push([xMax, yMin, zMax]);
217
- let zoom = 999;
218
- for (const point of points) {
219
- const x_ = (point[0] - target[0]) / size.height;
220
- const y_ = (point[1] - target[1]) / size.height;
221
- const z_ = (point[2] - target[2]) / size.height;
222
- const m = new Matrix4(IDENTITY);
223
- m.rotateX(camera_.rotationX * DEGREES_TO_RADIANS);
224
- m.rotateZ(camera_.rotationOrbit * DEGREES_TO_RADIANS);
225
- const [x, y, z] = m.transformAsVector([x_, y_, z_]);
226
- if (y >= 0) {
227
- // These points will actually appear further away when zooming in.
228
- continue;
229
- }
230
- const fwX = fD * Math.tan(angle_hor);
231
- let y_new = fwX / (Math.abs(x) / y - fwX / fD);
232
- const zoom_x = Math.log2(y_new / y);
233
- const fwY = fD * Math.tan(angle_ver);
234
- y_new = fwY / (Math.abs(z) / y - fwY / fD);
235
- const zoom_z = Math.log2(y_new / y);
236
- // it needs to be inside view volume in both directions.
237
- zoom = zoom_x < zoom ? zoom_x : zoom;
238
- zoom = zoom_z < zoom ? zoom_z : zoom;
239
- }
240
- camera_.zoom = zoom;
241
- camera_.target = target;
242
- return camera_;
243
- }
244
147
  const Map = ({ id, layers, bounds, cameraPosition, triggerHome, views, coords, scale, coordinateUnit, colorTables, setEditedData, checkDatafileSchema, onMouseEvent, selection, children, getTooltip = defaultTooltip, getCameraPosition, isRenderedCallback, onDragStart, onDragEnd, lights, triggerResetMultipleWells, }) => {
245
- var _a, _b, _c, _d, _e, _f, _g, _h, _j;
246
- const deckRef = React.useRef(null);
148
+ var _a, _b, _c, _d, _e;
247
149
  // From react doc, ref should not be read nor modified during rendering.
248
- // Extract the needed size in an effect to respect this rule (which proved true)
150
+ const deckRef = React.useRef(null);
151
+ const [applyViewController, forceUpdate] = React.useReducer((x) => x + 1, 0);
152
+ const viewController = useMemo(() => new ViewController(forceUpdate), []);
153
+ // Extract the needed size from onResize function
249
154
  const [deckSize, setDeckSize] = useState({ width: 0, height: 0 });
250
- useEffect(() => {
251
- var _a, _b, _c, _d;
252
- if (((_b = (_a = deckRef.current) === null || _a === void 0 ? void 0 : _a.deck) === null || _b === void 0 ? void 0 : _b.width) &&
253
- ((_d = (_c = deckRef.current) === null || _c === void 0 ? void 0 : _c.deck) === null || _d === void 0 ? void 0 : _d.height) &&
254
- deckRef.current.deck.width !== deckSize.width &&
255
- deckRef.current.deck.height !== deckSize.height) {
256
- setDeckSize({
257
- width: deckRef.current.deck.width,
258
- height: deckRef.current.deck.height,
155
+ const onResize = useCallback((size) => {
156
+ // exclude {0, 0} size (when rendered hidden pages)
157
+ if (size.width > 0 && size.height > 0) {
158
+ setDeckSize((prevSize) => {
159
+ if ((prevSize === null || prevSize === void 0 ? void 0 : prevSize.width) !== size.width ||
160
+ (prevSize === null || prevSize === void 0 ? void 0 : prevSize.height) !== size.height) {
161
+ return size;
162
+ }
163
+ return prevSize;
259
164
  });
260
165
  }
261
- // eslint-disable-next-line react-hooks/exhaustive-deps
262
- }, [(_b = (_a = deckRef.current) === null || _a === void 0 ? void 0 : _a.deck) === null || _b === void 0 ? void 0 : _b.width, (_d = (_c = deckRef.current) === null || _c === void 0 ? void 0 : _c.deck) === null || _d === void 0 ? void 0 : _d.height]);
263
- // Deck.gl View's and viewStates as input to Deck.gl
264
- const [deckGLViews, setDeckGLViews] = useState([]);
265
- const [viewStates, setViewStates] = useState({});
266
- const [dataBoundingBox3d, dispatchBoundingBox] = React.useReducer(mapBoundingBoxReducer, [0, 0, 0, 1, 1, 1]);
267
- const [viewStateChanged, setViewStateChanged] = useState(false);
268
- const camera = useMemo(() => {
269
- return calculateZoomFromBBox3D(cameraPosition, deckSize);
270
- }, [cameraPosition, deckSize]);
166
+ }, []);
167
+ // 3d bounding box computed from the layers
168
+ const [dataBoundingBox3d, dispatchBoundingBox] = React.useReducer(mapBoundingBoxReducer, undefined);
271
169
  // Used for scaling in z direction using arrow keys.
272
- const [scaleZ, setScaleZ] = useState(1);
273
- const [scaleZUp, setScaleZUp] = useState(Number.MAX_VALUE);
274
- const [scaleZDown, setScaleZDown] = useState(Number.MAX_VALUE);
170
+ const [zScale, updateZScale] = React.useReducer(updateZScaleReducer, 1);
275
171
  React.useEffect(() => {
276
- ZScaleOrbitController.setZScaleUpReference(setScaleZUp);
277
- }, [setScaleZUp]);
278
- React.useEffect(() => {
279
- ZScaleOrbitController.setZScaleDownReference(setScaleZDown);
280
- }, [setScaleZDown]);
281
- useEffect(() => {
282
- const [Views, viewStates] = createViewsAndViewStates(views, viewPortMargins, bounds, undefined, // Use bounds not cameraPosition,
283
- dataBoundingBox3d, deckSize);
284
- setDeckGLViews(Views);
285
- setViewStates(viewStates);
286
- // eslint-disable-next-line react-hooks/exhaustive-deps
287
- }, [triggerHome]);
288
- useEffect(() => {
289
- const isBoundsDefined = typeof bounds !== "undefined";
290
- const isCameraPositionDefined = typeof cameraPosition !== "undefined" &&
291
- Object.keys(cameraPosition).length !== 0;
292
- if (viewStateChanged || isBoundsDefined || isCameraPositionDefined) {
293
- // User has changed viewState or camera is defined, do not recalculate.
294
- return;
295
- }
296
- const [Views, viewStates] = createViewsAndViewStates(views, viewPortMargins, bounds, camera, dataBoundingBox3d, deckSize);
297
- setDeckGLViews(Views);
298
- setViewStates(viewStates);
299
- setViewStateChanged(false);
300
- // eslint-disable-next-line react-hooks/exhaustive-deps
301
- }, [dataBoundingBox3d]);
302
- useEffect(() => {
303
- const [Views, viewStates] = createViewsAndViewStates(views, viewPortMargins, bounds, camera, dataBoundingBox3d, deckSize);
304
- setDeckGLViews(Views);
305
- setViewStates(viewStates);
306
- setViewStateChanged(false);
307
- // eslint-disable-next-line react-hooks/exhaustive-deps
308
- }, [
309
- bounds,
310
- camera,
311
- deckSize,
312
- // eslint-disable-next-line react-hooks/exhaustive-deps
313
- compareViewsProp(views),
314
- ]);
315
- useEffect(() => {
316
- if (scaleZUp !== Number.MAX_VALUE) {
317
- const newScaleZ = scaleZ * 1.05;
318
- setScaleZ(newScaleZ);
319
- // Make camera target follow the scaling.
320
- const vs = adjustCameraTarget(viewStates, scaleZ, newScaleZ);
321
- setViewStates(vs);
322
- }
323
- // eslint-disable-next-line react-hooks/exhaustive-deps
324
- }, [scaleZUp]);
325
- useEffect(() => {
326
- if (scaleZUp !== Number.MAX_VALUE) {
327
- const newScaleZ = scaleZ * 0.95;
328
- setScaleZ(newScaleZ);
329
- // Make camera target follow the scaling.
330
- const vs = adjustCameraTarget(viewStates, scaleZ, newScaleZ);
331
- setViewStates(vs);
172
+ ZScaleOrbitController.setUpdateZScaleAction(updateZScale);
173
+ }, [updateZScale]);
174
+ // compute the viewport margins
175
+ const viewPortMargins = React.useMemo(() => {
176
+ if (!(layers === null || layers === void 0 ? void 0 : layers.length)) {
177
+ return {
178
+ left: 0,
179
+ right: 0,
180
+ top: 0,
181
+ bottom: 0,
182
+ };
332
183
  }
333
- // eslint-disable-next-line react-hooks/exhaustive-deps
334
- }, [scaleZDown]);
184
+ // Margins on the viewport are extracted from a potential axes2D layer.
185
+ const axes2DLayer = layers === null || layers === void 0 ? void 0 : layers.find((e) => {
186
+ return (e === null || e === void 0 ? void 0 : e.constructor) === Axes2DLayer;
187
+ });
188
+ const axes2DProps = axes2DLayer === null || axes2DLayer === void 0 ? void 0 : axes2DLayer.props;
189
+ return {
190
+ left: (axes2DProps === null || axes2DProps === void 0 ? void 0 : axes2DProps.isLeftRuler) ? axes2DProps.marginH : 0,
191
+ right: (axes2DProps === null || axes2DProps === void 0 ? void 0 : axes2DProps.isRightRuler) ? axes2DProps.marginH : 0,
192
+ top: (axes2DProps === null || axes2DProps === void 0 ? void 0 : axes2DProps.isTopRuler) ? axes2DProps.marginV : 0,
193
+ bottom: (axes2DProps === null || axes2DProps === void 0 ? void 0 : axes2DProps.isBottomRuler) ? axes2DProps.marginV : 0,
194
+ };
195
+ }, [layers]);
196
+ // selection
335
197
  useEffect(() => {
336
198
  var _a, _b, _c;
337
199
  const layers = (_b = (_a = deckRef.current) === null || _a === void 0 ? void 0 : _a.deck) === null || _b === void 0 ? void 0 : _b.props.layers;
@@ -421,17 +283,9 @@ const Map = ({ id, layers, bounds, cameraPosition, triggerHome, views, coords, s
421
283
  event.tapCount == 2 // Note. Detect double click.
422
284
  ) {
423
285
  // Left button click identifies new camera rotation anchor.
424
- const viewstateKeys = Object.keys(viewStates);
425
- if (infos.length >= 1 && viewstateKeys.length === 1) {
426
- const info = infos[0];
427
- if (info.coordinate) {
428
- const x = info.coordinate[0];
429
- const y = info.coordinate[1];
430
- const z = info.coordinate[2];
431
- const vs = cloneDeep(viewStates);
432
- vs[viewstateKeys[0]].target = [x, y, z];
433
- vs[viewstateKeys[0]].transitionDuration = 1000;
434
- setViewStates(vs);
286
+ if (infos.length >= 1) {
287
+ if (infos[0].coordinate) {
288
+ viewController.setTarget(infos[0].coordinate);
435
289
  }
436
290
  }
437
291
  }
@@ -439,7 +293,7 @@ const Map = ({ id, layers, bounds, cameraPosition, triggerHome, views, coords, s
439
293
  return;
440
294
  const ev = handleMouseEvent(type, infos, event);
441
295
  onMouseEvent(ev);
442
- }, [onMouseEvent, viewStates]);
296
+ }, [onMouseEvent, viewController]);
443
297
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
444
298
  const [hoverInfo, setHoverInfo] = useState([]);
445
299
  const onHover = useCallback((pickInfo, event) => {
@@ -451,30 +305,8 @@ const Map = ({ id, layers, bounds, cameraPosition, triggerHome, views, coords, s
451
305
  const infos = getPickingInfos(pickInfo, event);
452
306
  callOnMouseEvent === null || callOnMouseEvent === void 0 ? void 0 : callOnMouseEvent("click", infos, event);
453
307
  }, [callOnMouseEvent, getPickingInfos]);
454
- // compute the viewport margins
455
- const viewPortMargins = React.useMemo(() => {
456
- if (typeof layers === "undefined") {
457
- return {
458
- left: 0,
459
- right: 0,
460
- top: 0,
461
- bottom: 0,
462
- };
463
- }
464
- // Margins on the viewport are extracted from a potential axes2D layer.
465
- const axes2DLayer = layers === null || layers === void 0 ? void 0 : layers.find((e) => {
466
- return (e === null || e === void 0 ? void 0 : e.constructor) === Axes2DLayer;
467
- });
468
- const axes2DProps = axes2DLayer === null || axes2DLayer === void 0 ? void 0 : axes2DLayer.props;
469
- return {
470
- left: (axes2DProps === null || axes2DProps === void 0 ? void 0 : axes2DProps.isLeftRuler) ? axes2DProps.marginH : 0,
471
- right: (axes2DProps === null || axes2DProps === void 0 ? void 0 : axes2DProps.isRightRuler) ? axes2DProps.marginH : 0,
472
- top: (axes2DProps === null || axes2DProps === void 0 ? void 0 : axes2DProps.isTopRuler) ? axes2DProps.marginV : 0,
473
- bottom: (axes2DProps === null || axes2DProps === void 0 ? void 0 : axes2DProps.isBottomRuler) ? axes2DProps.marginV : 0,
474
- };
475
- }, [layers]);
476
308
  const deckGLLayers = React.useMemo(() => {
477
- if (typeof layers === "undefined") {
309
+ if (!layers) {
478
310
  return [];
479
311
  }
480
312
  if (layers.length === 0) {
@@ -486,7 +318,7 @@ const Map = ({ id, layers, bounds, cameraPosition, triggerHome, views, coords, s
486
318
  });
487
319
  layers.push(dummy_layer);
488
320
  }
489
- const m = getModelMatrixScale(scaleZ);
321
+ const m = getModelMatrixScale(zScale);
490
322
  return layers.map((item) => {
491
323
  if ((item === null || item === void 0 ? void 0 : item.constructor.name) === NorthArrow3DLayer.name) {
492
324
  return item;
@@ -500,7 +332,7 @@ const Map = ({ id, layers, bounds, cameraPosition, triggerHome, views, coords, s
500
332
  modelMatrix: m,
501
333
  });
502
334
  });
503
- }, [layers, scaleZ]);
335
+ }, [layers, zScale]);
504
336
  const [isLoaded, setIsLoaded] = useState(false);
505
337
  const onAfterRender = useCallback(() => {
506
338
  if (deckGLLayers) {
@@ -512,7 +344,7 @@ const Map = ({ id, layers, bounds, cameraPosition, triggerHome, views, coords, s
512
344
  deckGLLayers[0].id ===
513
345
  "webviz_internal_dummy_layer";
514
346
  setIsLoaded(loadedState || emptyLayers);
515
- if (typeof isRenderedCallback !== "undefined") {
347
+ if (isRenderedCallback) {
516
348
  isRenderedCallback(loadedState);
517
349
  }
518
350
  }
@@ -537,13 +369,14 @@ const Map = ({ id, layers, bounds, cameraPosition, triggerHome, views, coords, s
537
369
  }, [
538
370
  checkDatafileSchema,
539
371
  colorTables,
540
- (_f = (_e = deckRef === null || deckRef === void 0 ? void 0 : deckRef.current) === null || _e === void 0 ? void 0 : _e.deck) === null || _f === void 0 ? void 0 : _f.props.layers,
372
+ (_b = (_a = deckRef === null || deckRef === void 0 ? void 0 : deckRef.current) === null || _a === void 0 ? void 0 : _a.deck) === null || _b === void 0 ? void 0 : _b.props.layers,
541
373
  isLoaded,
542
374
  ]);
543
375
  const layerFilter = useCallback((args) => {
544
376
  // display all the layers if views are not specified correctly
545
- if (!views || !views.viewports || !views.layout)
377
+ if (!(views === null || views === void 0 ? void 0 : views.viewports) || !(views === null || views === void 0 ? void 0 : views.layout)) {
546
378
  return true;
379
+ }
547
380
  const cur_view = views.viewports.find(({ id }) => args.viewport.id && id === args.viewport.id);
548
381
  if ((cur_view === null || cur_view === void 0 ? void 0 : cur_view.layerIds) && cur_view.layerIds.length > 0) {
549
382
  const layer_ids = cur_view.layerIds;
@@ -559,32 +392,40 @@ const Map = ({ id, layers, bounds, cameraPosition, triggerHome, views, coords, s
559
392
  const onViewStateChange = useCallback(
560
393
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
561
394
  ({ viewId, viewState }) => {
562
- const viewports = (views === null || views === void 0 ? void 0 : views.viewports) || [];
563
- if (viewState.target.length === 2) {
564
- // In orthographic mode viewState.target contains only x and y. Add existing z value.
565
- viewState.target.push(viewStates[viewId].target[2]);
566
- }
567
- const isSyncIds = viewports
568
- .filter((item) => item.isSync)
569
- .map((item) => item.id);
570
- if (isSyncIds === null || isSyncIds === void 0 ? void 0 : isSyncIds.includes(viewId)) {
571
- const viewStateTable = views === null || views === void 0 ? void 0 : views.viewports.filter((item) => item.isSync).map((item) => [item.id, viewState]);
572
- const tempViewStates = Object.fromEntries(viewStateTable !== null && viewStateTable !== void 0 ? viewStateTable : []);
573
- setViewStates((currentViewStates) => (Object.assign(Object.assign({}, currentViewStates), tempViewStates)));
574
- }
575
- else {
576
- setViewStates((currentViewStates) => (Object.assign(Object.assign({}, currentViewStates), { [viewId]: viewState })));
577
- }
395
+ viewController.onViewStateChange(viewId, viewState);
578
396
  if (getCameraPosition) {
579
397
  getCameraPosition(viewState);
580
398
  }
581
- setViewStateChanged(true);
582
- }, [getCameraPosition, viewStates, views === null || views === void 0 ? void 0 : views.viewports]);
399
+ }, [getCameraPosition, viewController]);
583
400
  const effects = parseLights(lights);
584
- if (!deckGLViews || isEmpty(deckGLViews) || isEmpty(deckGLLayers))
401
+ const [deckGlViews, deckGlViewState] = useMemo(() => {
402
+ const state = {
403
+ triggerHome,
404
+ camera: cameraPosition,
405
+ bounds,
406
+ boundingBox3d: dataBoundingBox3d,
407
+ viewPortMargins,
408
+ deckSize,
409
+ zScale,
410
+ };
411
+ return viewController.getViews(views, state);
412
+ // eslint-disable-next-line react-hooks/exhaustive-deps
413
+ }, [
414
+ triggerHome,
415
+ cameraPosition,
416
+ bounds,
417
+ dataBoundingBox3d,
418
+ viewPortMargins,
419
+ deckSize,
420
+ views,
421
+ zScale,
422
+ applyViewController,
423
+ viewController,
424
+ ]);
425
+ if (!deckGlViews || isEmpty(deckGlViews) || isEmpty(deckGLLayers))
585
426
  return null;
586
427
  return (React.createElement("div", { onContextMenu: (event) => event.preventDefault() },
587
- React.createElement(DeckGL, { id: id, viewState: viewStates, views: deckGLViews, layerFilter: layerFilter, layers: deckGLLayers,
428
+ React.createElement(DeckGL, { id: id, viewState: deckGlViewState, views: deckGlViews, layerFilter: layerFilter, layers: deckGLLayers,
588
429
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
589
430
  // @ts-expect-error
590
431
  userData: {
@@ -609,8 +450,8 @@ const Map = ({ id, layers, bounds, cameraPosition, triggerHome, views, coords, s
609
450
  setEditedData === null || setEditedData === void 0 ? void 0 : setEditedData(updated_prop);
610
451
  },
611
452
  colorTables: colorTables,
612
- }, getCursor: ({ isDragging }) => isDragging ? "grabbing" : "default", getTooltip: getTooltip, ref: deckRef, onViewStateChange: onViewStateChange, onHover: onHover, onClick: onClick, onAfterRender: onAfterRender, effects: effects, onDragStart: onDragStart, onDragEnd: onDragEnd }, children),
613
- (scale === null || scale === void 0 ? void 0 : scale.visible) ? (React.createElement(DistanceScale, Object.assign({}, scale, { zoom: (_h = (_g = viewStates[Object.keys(viewStates)[0]]) === null || _g === void 0 ? void 0 : _g.zoom) !== null && _h !== void 0 ? _h : -5, scaleUnit: coordinateUnit, style: (_j = scale.cssStyle) !== null && _j !== void 0 ? _j : {} }))) : null,
453
+ }, getCursor: ({ isDragging }) => isDragging ? "grabbing" : "default", getTooltip: getTooltip, ref: deckRef, onViewStateChange: onViewStateChange, onHover: onHover, onClick: onClick, onAfterRender: onAfterRender, effects: effects, onDragStart: onDragStart, onDragEnd: onDragEnd, onResize: onResize }, children),
454
+ (scale === null || scale === void 0 ? void 0 : scale.visible) ? (React.createElement(DistanceScale, Object.assign({}, scale, { zoom: (_d = (_c = deckGlViewState[Object.keys(deckGlViewState)[0]]) === null || _c === void 0 ? void 0 : _c.zoom) !== null && _d !== void 0 ? _d : -5, scaleUnit: coordinateUnit, style: (_e = scale.cssStyle) !== null && _e !== void 0 ? _e : {} }))) : null,
614
455
  React.createElement(StatusIndicator, { layers: deckGLLayers, isLoaded: isLoaded }),
615
456
  (coords === null || coords === void 0 ? void 0 : coords.visible) ? React.createElement(InfoCard, { pickInfos: hoverInfo }) : null,
616
457
  errorText && (React.createElement("pre", { style: {
@@ -660,22 +501,228 @@ export function jsonToObject(data, enums = undefined) {
660
501
  });
661
502
  const jsonConverter = new JSONConverter({ configuration });
662
503
  // remove empty data/layer object
663
- const filtered_data = data.filter((value) => Object.keys(value).length !== 0);
504
+ const filtered_data = data.filter((value) => !isEmpty(value));
664
505
  return jsonConverter.convert(filtered_data);
665
506
  }
666
- // return viewstate with computed bounds to fit the data in viewport
667
- function getViewState(viewPortMargins, bounds_accessor, centerOfData, views, viewPort, size) {
668
- var _a;
669
- let bounds = [0, 0, 1, 1];
670
- if (typeof bounds_accessor == "function") {
671
- bounds = bounds_accessor();
507
+ class ViewController {
508
+ constructor(rerender) {
509
+ this.state_ = {
510
+ triggerHome: undefined,
511
+ camera: undefined,
512
+ bounds: undefined,
513
+ boundingBox3d: undefined,
514
+ deckSize: { width: 0, height: 0 },
515
+ zScale: 1,
516
+ viewPortMargins: {
517
+ left: 0,
518
+ right: 0,
519
+ top: 0,
520
+ bottom: 0,
521
+ },
522
+ // Derived state
523
+ target: undefined,
524
+ viewStateChanged: false,
525
+ };
526
+ this.derivedState_ = {
527
+ target: undefined,
528
+ viewStateChanged: false,
529
+ };
530
+ this.views_ = undefined;
531
+ this.result_ = {
532
+ views: [],
533
+ viewState: {},
534
+ };
535
+ this.setTarget = (target) => {
536
+ this.derivedState_.target = [target[0], target[1], target[2]];
537
+ this.rerender_();
538
+ };
539
+ this.getViews = (views, state) => {
540
+ const fullState = this.consolidateState(state);
541
+ const newViews = this.getDeckGlViews(views, fullState);
542
+ const newViewState = this.getDeckGlViewState(views, fullState);
543
+ if (this.result_.views !== newViews ||
544
+ this.result_.viewState !== newViewState) {
545
+ const viewsMsg = this.result_.views !== newViews ? " views" : "";
546
+ const stateMsg = this.result_.viewState !== newViewState ? " state" : "";
547
+ const linkMsg = viewsMsg && stateMsg ? " and" : "";
548
+ console.log(`ViewController returns new${viewsMsg}${linkMsg}${stateMsg}`);
549
+ }
550
+ this.state_ = fullState;
551
+ this.views_ = views;
552
+ this.result_.views = newViews;
553
+ this.result_.viewState = newViewState;
554
+ return [newViews, newViewState];
555
+ };
556
+ // consolidate "controlled" state (ie. set by parent) with "uncontrolled" state
557
+ this.consolidateState = (state) => {
558
+ return Object.assign(Object.assign({}, state), this.derivedState_);
559
+ };
560
+ // returns the DeckGL views (ie. view position and viewport)
561
+ this.getDeckGlViews = (views, state) => {
562
+ const needUpdate = views != this.views_ || state.deckSize != this.state_.deckSize;
563
+ if (!needUpdate) {
564
+ return this.result_.views;
565
+ }
566
+ return buildDeckGlViews(views, state.deckSize);
567
+ };
568
+ // returns the DeckGL views state(s) (ie. camera settings applied to individual views)
569
+ this.getDeckGlViewState = (views, state) => {
570
+ var _a, _b;
571
+ const viewsChanged = views != this.views_;
572
+ const triggerHome = state.triggerHome !== this.state_.triggerHome;
573
+ const updateTarget = (viewsChanged || state.target !== ((_a = this.state_) === null || _a === void 0 ? void 0 : _a.target)) &&
574
+ state.target !== undefined;
575
+ const updateZScale = viewsChanged || state.zScale !== ((_b = this.state_) === null || _b === void 0 ? void 0 : _b.zScale) || triggerHome;
576
+ const updateViewState = viewsChanged ||
577
+ triggerHome ||
578
+ (!state.viewStateChanged &&
579
+ state.boundingBox3d !== this.state_.boundingBox3d);
580
+ const needUpdate = updateZScale || updateTarget || updateViewState;
581
+ const isCacheEmpty = isEmpty(this.result_.viewState);
582
+ if (!isCacheEmpty && !needUpdate) {
583
+ return this.result_.viewState;
584
+ }
585
+ // initialize with last result
586
+ const prevViewState = this.result_.viewState;
587
+ let viewState = prevViewState;
588
+ if (updateViewState || isCacheEmpty) {
589
+ viewState = buildDeckGlViewStates(views, state.viewPortMargins, state.camera, state.boundingBox3d, state.bounds, state.deckSize);
590
+ // reset state
591
+ this.derivedState_.viewStateChanged = false;
592
+ }
593
+ // check if view state could be computed
594
+ if (isEmpty(viewState)) {
595
+ return viewState;
596
+ }
597
+ const viewStateKeys = Object.keys(viewState);
598
+ if (updateTarget &&
599
+ this.derivedState_.target &&
600
+ (viewStateKeys === null || viewStateKeys === void 0 ? void 0 : viewStateKeys.length) === 1) {
601
+ // deep clone to notify change (memo checks object address)
602
+ if (viewState === prevViewState) {
603
+ viewState = cloneDeep(prevViewState);
604
+ }
605
+ // update target
606
+ viewState[viewStateKeys[0]].target = this.derivedState_.target;
607
+ viewState[viewStateKeys[0]].transitionDuration = 1000;
608
+ // reset
609
+ this.derivedState_.target = undefined;
610
+ }
611
+ if (updateZScale) {
612
+ // deep clone to notify change (memo checks object address)
613
+ if (viewState === prevViewState) {
614
+ viewState = cloneDeep(prevViewState);
615
+ }
616
+ // Z scale to apply to target.
617
+ // - if triggerHome: the target was recomputed from the input data (ie. without any scale applied)
618
+ // - otherwise: previous scale (ie. this.state_.zScale) was already applied, and must be "reverted"
619
+ const targetScale = state.zScale / (triggerHome ? 1 : this.state_.zScale);
620
+ // update target
621
+ for (const key in viewState) {
622
+ const t = viewState[key].target;
623
+ if (t) {
624
+ viewState[key].target = [t[0], t[1], t[2] * targetScale];
625
+ }
626
+ }
627
+ }
628
+ return viewState;
629
+ };
630
+ this.onViewStateChange = (viewId, viewState) => {
631
+ var _a, _b, _c;
632
+ const viewports = (_b = (_a = this.views_) === null || _a === void 0 ? void 0 : _a.viewports) !== null && _b !== void 0 ? _b : [];
633
+ if (viewState.target.length === 2) {
634
+ // In orthographic mode viewState.target contains only x and y. Add existing z value.
635
+ viewState.target.push(this.result_.viewState[viewId].target[2]);
636
+ }
637
+ const isSyncIds = viewports
638
+ .filter((item) => item.isSync)
639
+ .map((item) => item.id);
640
+ if (isSyncIds === null || isSyncIds === void 0 ? void 0 : isSyncIds.includes(viewId)) {
641
+ const viewStateTable = (_c = this.views_) === null || _c === void 0 ? void 0 : _c.viewports.filter((item) => item.isSync).map((item) => [item.id, viewState]);
642
+ const tempViewStates = Object.fromEntries(viewStateTable !== null && viewStateTable !== void 0 ? viewStateTable : []);
643
+ this.result_.viewState = Object.assign(Object.assign({}, this.result_.viewState), tempViewStates);
644
+ }
645
+ else {
646
+ this.result_.viewState = Object.assign(Object.assign({}, this.result_.viewState), { [viewId]: viewState });
647
+ }
648
+ this.derivedState_.viewStateChanged = true;
649
+ this.rerender_();
650
+ };
651
+ this.rerender_ = rerender;
672
652
  }
673
- else {
674
- bounds = bounds_accessor;
653
+ }
654
+ /**
655
+ * Returns the zoom factor allowing to view the complete boundingBox.
656
+ * @param camera camera defining the view orientation.
657
+ * @param boundingBox 3D bounding box to visualize.
658
+ * @param fov field of view (see deck.gl file orbit-viewports.ts).
659
+ */
660
+ function computeCameraZoom(camera, boundingBox, size, fovy = 50) {
661
+ const DEGREES_TO_RADIANS = Math.PI / 180;
662
+ const RADIANS_TO_DEGREES = 180 / Math.PI;
663
+ const IDENTITY = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
664
+ const fD = fovyToAltitude(fovy);
665
+ const xMin = boundingBox[0];
666
+ const yMin = boundingBox[1];
667
+ const zMin = boundingBox[2];
668
+ const xMax = boundingBox[3];
669
+ const yMax = boundingBox[4];
670
+ const zMax = boundingBox[5];
671
+ const target = [
672
+ xMin + (xMax - xMin) / 2,
673
+ yMin + (yMax - yMin) / 2,
674
+ zMin + (zMax - zMin) / 2,
675
+ ];
676
+ const cameraFovVertical = 50;
677
+ const angle_ver = (cameraFovVertical / 2) * DEGREES_TO_RADIANS;
678
+ const L = size.height / 2 / Math.sin(angle_ver);
679
+ const r = L * Math.cos(angle_ver);
680
+ const cameraFov = 2 * Math.atan(size.width / 2 / r) * RADIANS_TO_DEGREES;
681
+ const angle_hor = (cameraFov / 2) * DEGREES_TO_RADIANS;
682
+ const points = [];
683
+ points.push([xMin, yMin, zMin]);
684
+ points.push([xMin, yMax, zMin]);
685
+ points.push([xMax, yMax, zMin]);
686
+ points.push([xMax, yMin, zMin]);
687
+ points.push([xMin, yMin, zMax]);
688
+ points.push([xMin, yMax, zMax]);
689
+ points.push([xMax, yMax, zMax]);
690
+ points.push([xMax, yMin, zMax]);
691
+ let zoom = 999;
692
+ for (const point of points) {
693
+ const x_ = (point[0] - target[0]) / size.height;
694
+ const y_ = (point[1] - target[1]) / size.height;
695
+ const z_ = (point[2] - target[2]) / size.height;
696
+ const m = new Matrix4(IDENTITY);
697
+ m.rotateX(camera.rotationX * DEGREES_TO_RADIANS);
698
+ m.rotateZ(camera.rotationOrbit * DEGREES_TO_RADIANS);
699
+ const [x, y, z] = m.transformAsVector([x_, y_, z_]);
700
+ if (y >= 0) {
701
+ // These points will actually appear further away when zooming in.
702
+ continue;
703
+ }
704
+ const fwX = fD * Math.tan(angle_hor);
705
+ let y_new = fwX / (Math.abs(x) / y - fwX / fD);
706
+ const zoom_x = Math.log2(y_new / y);
707
+ const fwY = fD * Math.tan(angle_ver);
708
+ y_new = fwY / (Math.abs(z) / y - fwY / fD);
709
+ const zoom_z = Math.log2(y_new / y);
710
+ // it needs to be inside view volume in both directions.
711
+ zoom = zoom_x < zoom ? zoom_x : zoom;
712
+ zoom = zoom_z < zoom ? zoom_z : zoom;
675
713
  }
714
+ return zoom;
715
+ }
716
+ ///////////////////////////////////////////////////////////////////////////////////////////
717
+ // return viewstate with computed bounds to fit the data in viewport
718
+ function getViewStateFromBounds(viewPortMargins, bounds_accessor, target, views, viewPort, size) {
719
+ var _a, _b, _c;
720
+ const bounds = typeof bounds_accessor == "function"
721
+ ? bounds_accessor()
722
+ : bounds_accessor;
676
723
  let w = bounds[2] - bounds[0]; // right - left
677
724
  let h = bounds[3] - bounds[1]; // top - bottom
678
- const z = centerOfData[2];
725
+ const z = target[2];
679
726
  const fb = fitBounds({ width: w, height: h, bounds });
680
727
  let fb_target = [fb.x, fb.y, z];
681
728
  let fb_zoom = fb.zoom;
@@ -694,8 +741,8 @@ function getViewState(viewPortMargins, bounds_accessor, centerOfData, views, vie
694
741
  w = size.width - marginH; // width of the viewport minus margin.
695
742
  h = size.height - marginV;
696
743
  // Special case if matrix views.
697
- // Use width and heigt for a subview instead of full viewport.
698
- if (typeof (views === null || views === void 0 ? void 0 : views.layout) !== "undefined") {
744
+ // Use width and height for a sub-view instead of full viewport.
745
+ if (views === null || views === void 0 ? void 0 : views.layout) {
699
746
  const [nY, nX] = views.layout;
700
747
  const isMatrixViews = nX !== 1 || nY !== 1;
701
748
  if (isMatrixViews) {
@@ -733,159 +780,220 @@ function getViewState(viewPortMargins, bounds_accessor, centerOfData, views, vie
733
780
  fb_target = [fb.x - translate_x, fb.y - translate_y, z];
734
781
  fb_zoom = fb.zoom;
735
782
  }
736
- const target = viewPort.target;
737
- const zoom = viewPort.zoom;
738
- const target_ = target !== null && target !== void 0 ? target : fb_target;
739
- const zoom_ = zoom !== null && zoom !== void 0 ? zoom : fb_zoom;
740
- const minZoom = minZoom3D;
741
- const maxZoom = viewPort.show3D ? maxZoom3D : maxZoom2D;
742
783
  const view_state = {
743
- target: target_,
744
- zoom: zoom_,
784
+ target: (_b = viewPort.target) !== null && _b !== void 0 ? _b : fb_target,
785
+ zoom: (_c = viewPort.zoom) !== null && _c !== void 0 ? _c : fb_zoom,
745
786
  rotationX: 90,
746
787
  rotationOrbit: 0,
747
- minZoom,
748
- maxZoom,
788
+ minZoom: viewPort.show3D ? minZoom3D : minZoom2D,
789
+ maxZoom: viewPort.show3D ? maxZoom3D : maxZoom2D,
749
790
  };
750
791
  return view_state;
751
792
  }
752
- ///////////////////////////////////////////////////////////////////////////////////////////
753
- // return viewstate with computed bounds to fit the data in viewport
754
- function getViewState3D(is3D, bounds, zoom, size) {
755
- const xMin = bounds[0];
756
- const yMin = bounds[1];
757
- const zMin = bounds[2];
758
- const xMax = bounds[3];
759
- const yMax = bounds[4];
760
- const zMax = bounds[5];
761
- let width = xMax - xMin;
762
- let height = yMax - yMin;
763
- if (size.width > 0 && size.height > 0) {
764
- width = size.width;
765
- height = size.height;
793
+ function getVT(viewport) {
794
+ if (viewport.show3D) {
795
+ return [ZScaleOrbitView, ZScaleOrbitController];
766
796
  }
767
- const target = [
768
- xMin + (xMax - xMin) / 2,
769
- yMin + (yMax - yMin) / 2,
770
- is3D ? zMin + (zMax - zMin) / 2 : 0,
797
+ return [
798
+ viewport.id === "intersection_view"
799
+ ? IntersectionView
800
+ : OrthographicView,
801
+ OrthographicController,
771
802
  ];
772
- const bounds2D = [xMin, yMin, xMax, yMax];
773
- const fitted_bound = fitBounds({
803
+ }
804
+ function areViewsValid(views, size) {
805
+ var _a, _b;
806
+ const isInvalid = (views === null || views === void 0 ? void 0 : views.viewports) === undefined ||
807
+ (views === null || views === void 0 ? void 0 : views.layout) === undefined ||
808
+ !((_a = views === null || views === void 0 ? void 0 : views.layout) === null || _a === void 0 ? void 0 : _a[0]) ||
809
+ !((_b = views === null || views === void 0 ? void 0 : views.layout) === null || _b === void 0 ? void 0 : _b[1]) ||
810
+ !size.width ||
811
+ !size.height;
812
+ return !isInvalid;
813
+ }
814
+ /** returns a new View instance. */
815
+ function newView(viewport, x, y, width, height) {
816
+ const far = 9999;
817
+ const near = viewport.show3D ? 0.1 : -9999;
818
+ const [ViewType, Controller] = getVT(viewport);
819
+ return new ViewType({
820
+ id: viewport.id,
821
+ controller: {
822
+ type: Controller,
823
+ doubleClickZoom: false,
824
+ },
825
+ x,
826
+ y,
774
827
  width,
775
828
  height,
776
- bounds: bounds2D,
829
+ flipY: false,
830
+ far,
831
+ near,
777
832
  });
778
- const view_state = {
779
- target,
780
- zoom: zoom !== null && zoom !== void 0 ? zoom : fitted_bound.zoom * 1.2,
781
- rotationX: 45,
782
- rotationOrbit: 0,
783
- minZoom: minZoom3D,
784
- maxZoom: maxZoom3D,
785
- };
786
- return view_state;
787
833
  }
788
- // construct views and viewStates for DeckGL component
789
- function createViewsAndViewStates(views, viewPortMargins, bounds, cameraPosition, boundingBox, size) {
790
- var _a, _b, _c, _d;
791
- const deckgl_views = [];
792
- let viewStates = {};
793
- const centerOfData = boundingBoxCenter(boundingBox);
794
- const widthViewPort = size.width;
795
- const heightViewPort = size.height;
796
- const mPixels = (_a = views === null || views === void 0 ? void 0 : views.marginPixels) !== null && _a !== void 0 ? _a : 0;
797
- const isOk = (views === null || views === void 0 ? void 0 : views.layout) !== undefined &&
798
- ((_b = views === null || views === void 0 ? void 0 : views.layout) === null || _b === void 0 ? void 0 : _b[0]) >= 1 &&
799
- ((_c = views === null || views === void 0 ? void 0 : views.layout) === null || _c === void 0 ? void 0 : _c[1]) >= 1 &&
800
- widthViewPort > 0 &&
801
- heightViewPort > 0;
802
- // if props for multiple viewport are not proper, or deck size is not yet initialized, return 2d view
803
- // add redundant check on views to please lint
834
+ function buildDeckGlViews(views, size) {
835
+ var _a;
836
+ const isOk = areViewsValid(views, size);
804
837
  if (!views || !isOk) {
805
- deckgl_views.push(new OrthographicView({
806
- id: "main",
807
- controller: { doubleClickZoom: false },
808
- x: "0%",
809
- y: "0%",
810
- width: "100%",
811
- height: "100%",
812
- flipY: false,
813
- far: +99999,
814
- near: -99999,
815
- }));
816
- viewStates["dummy"] =
817
- cameraPosition !== null && cameraPosition !== void 0 ? cameraPosition : {
818
- target: [0, 0],
819
- zoom: 0,
820
- rotationX: 0,
821
- rotationOrbit: 0,
822
- minZoom: minZoom2D,
823
- maxZoom: maxZoom2D,
824
- };
838
+ return [
839
+ new OrthographicView({
840
+ id: "main",
841
+ controller: { doubleClickZoom: false },
842
+ x: "0%",
843
+ y: "0%",
844
+ width: "100%",
845
+ height: "100%",
846
+ flipY: false,
847
+ far: +99999,
848
+ near: -99999,
849
+ }),
850
+ ];
851
+ }
852
+ // compute
853
+ const [nY, nX] = views.layout;
854
+ // compute for single view (code is more readable)
855
+ const singleView = nX === 1 && nY === 1;
856
+ if (singleView) {
857
+ // Using 99.5% of viewport to avoid flickering of deckgl canvas
858
+ return [newView(views.viewports[0], 0, 0, "95%", "95%")];
859
+ }
860
+ // compute for matrix
861
+ const result = [];
862
+ const w = 99.5 / nX; // Using 99.5% of viewport to avoid flickering of deckgl canvas
863
+ const h = 99.5 / nY;
864
+ const marginPixels = (_a = views.marginPixels) !== null && _a !== void 0 ? _a : 0;
865
+ const marginHorPercentage = 100 * 100 * (marginPixels / (w * size.width));
866
+ const marginVerPercentage = 100 * 100 * (marginPixels / (h * size.height));
867
+ let yPos = 0;
868
+ for (let y = 1; y <= nY; y++) {
869
+ let xPos = 0;
870
+ for (let x = 1; x <= nX; x++) {
871
+ if (result.length >= views.viewports.length) {
872
+ // stop when all the viewports are filled
873
+ return result;
874
+ }
875
+ const currentViewport = views.viewports[result.length];
876
+ const viewX = xPos + marginHorPercentage / nX + "%";
877
+ const viewY = yPos + marginVerPercentage / nY + "%";
878
+ const viewWidth = w * (1 - 2 * (marginHorPercentage / 100)) + "%";
879
+ const viewHeight = h * (1 - 2 * (marginVerPercentage / 100)) + "%";
880
+ result.push(newView(currentViewport, viewX, viewY, viewWidth, viewHeight));
881
+ xPos = xPos + w;
882
+ }
883
+ yPos = yPos + h;
884
+ }
885
+ return result;
886
+ }
887
+ /**
888
+ * Returns the camera if it is fully specified (ie. the zoom is a valid number), otherwise computes
889
+ * the zoom to visualize the complete camera boundingBox if set, the provided boundingBox otherwise.
890
+ * @param camera input camera
891
+ * @param boundingBox fallback bounding box, if the camera zoom is not zoom a value nor a bounding box
892
+ */
893
+ function updateViewState(camera, boundingBox, size) {
894
+ var _a, _b;
895
+ if (typeof camera.zoom === "number" && !Number.isNaN(camera.zoom)) {
896
+ return camera;
897
+ }
898
+ // update the camera to see the whole boundingBox
899
+ if (Array.isArray(camera.zoom)) {
900
+ boundingBox = camera.zoom;
901
+ }
902
+ // return the camera if the bounding box is undefined
903
+ if (boundingBox === undefined) {
904
+ return camera;
905
+ }
906
+ // clone the camera in case of triggerHome
907
+ const camera_ = cloneDeep(camera);
908
+ camera_.zoom = computeCameraZoom(camera, boundingBox, size);
909
+ camera_.target = boxCenter(boundingBox);
910
+ camera_.minZoom = (_a = camera_.minZoom) !== null && _a !== void 0 ? _a : minZoom3D;
911
+ camera_.maxZoom = (_b = camera_.maxZoom) !== null && _b !== void 0 ? _b : maxZoom3D;
912
+ return camera_;
913
+ }
914
+ /**
915
+ *
916
+ * @returns Computes the view state
917
+ */
918
+ function computeViewState(viewPort, cameraPosition, boundingBox, bounds, viewportMargins, views, size) {
919
+ var _a;
920
+ // If the camera is defined, use it
921
+ const isCameraPositionDefined = cameraPosition !== undefined;
922
+ const isBoundsDefined = bounds !== undefined;
923
+ if ((_a = viewPort.show3D) !== null && _a !== void 0 ? _a : false) {
924
+ // If the camera is defined, use it
925
+ if (isCameraPositionDefined) {
926
+ return updateViewState(cameraPosition, boundingBox, size);
927
+ }
928
+ // deprecated in 3D, kept for backward compatibility
929
+ if (isBoundsDefined) {
930
+ const centerOfData = boundingBox
931
+ ? boxCenter(boundingBox)
932
+ : [0, 0, 0];
933
+ return getViewStateFromBounds(viewportMargins, bounds, centerOfData, views, viewPort, size);
934
+ }
935
+ const defaultCamera = {
936
+ target: [],
937
+ zoom: NaN,
938
+ rotationX: 45,
939
+ rotationOrbit: 0,
940
+ };
941
+ return updateViewState(defaultCamera, boundingBox, size);
825
942
  }
826
943
  else {
827
- let yPos = 0;
828
- const [nY, nX] = views.layout;
829
- const w = 99.5 / nX; // Using 99.5% of viewport to avoid flickering of deckgl canvas
830
- const h = 99.5 / nY;
831
- const singleView = nX === 1 && nY === 1;
832
- const marginHorPercentage = singleView // percentage of sub view
833
- ? 0
834
- : 100 * 100 * (mPixels / (w * widthViewPort));
835
- const marginVerPercentage = singleView
836
- ? 0
837
- : 100 * 100 * (mPixels / (h * heightViewPort));
838
- for (let y = 1; y <= nY; y++) {
839
- let xPos = 0;
840
- for (let x = 1; x <= nX; x++) {
841
- if (views.viewports == undefined ||
842
- deckgl_views.length >= views.viewports.length) {
843
- return [deckgl_views, viewStates];
844
- }
845
- const currentViewport = views.viewports[deckgl_views.length];
846
- let ViewType = ZScaleOrbitView;
847
- if (!currentViewport.show3D) {
848
- ViewType =
849
- currentViewport.id === "intersection_view"
850
- ? IntersectionView
851
- : OrthographicView;
852
- }
853
- const far = 9999;
854
- const near = currentViewport.show3D ? 0.1 : -9999;
855
- const Controller = currentViewport.show3D
856
- ? ZScaleOrbitController
857
- : OrthographicController;
858
- const controller = {
859
- type: Controller,
860
- doubleClickZoom: false,
861
- };
862
- deckgl_views.push(new ViewType({
863
- id: currentViewport.id,
864
- controller: controller,
865
- x: xPos + marginHorPercentage / nX + "%",
866
- y: yPos + marginVerPercentage / nY + "%",
867
- width: w * (1 - 2 * (marginHorPercentage / 100)) + "%",
868
- height: h * (1 - 2 * (marginVerPercentage / 100)) + "%",
869
- flipY: false,
870
- far,
871
- near,
872
- }));
873
- const isBoundsDefined = typeof bounds !== "undefined";
874
- const isCameraPositionDefined = typeof cameraPosition !== "undefined" &&
875
- Object.keys(cameraPosition).length !== 0;
876
- let viewState = cameraPosition;
877
- if (!isCameraPositionDefined) {
878
- viewState = isBoundsDefined
879
- ? getViewState(viewPortMargins, bounds !== null && bounds !== void 0 ? bounds : [0, 0, 1, 1], centerOfData, views, currentViewport, size)
880
- : getViewState3D((_d = currentViewport.show3D) !== null && _d !== void 0 ? _d : false, boundingBox, currentViewport.zoom, size);
881
- }
882
- viewStates = Object.assign(Object.assign({}, viewStates), { [currentViewport.id]: viewState });
883
- xPos = xPos + w;
944
+ const centerOfData = boundingBox
945
+ ? boxCenter(boundingBox)
946
+ : [0, 0, 0];
947
+ // if bounds are defined, use them
948
+ if (isBoundsDefined) {
949
+ return getViewStateFromBounds(viewportMargins, bounds, centerOfData, views, viewPort, size);
950
+ }
951
+ // deprecated in 2D, kept for backward compatibility
952
+ if (isCameraPositionDefined) {
953
+ return cameraPosition;
954
+ }
955
+ return boundingBox
956
+ ? getViewStateFromBounds(viewportMargins,
957
+ // use the bounding box to extract the 2D bounds
958
+ [
959
+ boundingBox[0],
960
+ boundingBox[1],
961
+ boundingBox[3],
962
+ boundingBox[4],
963
+ ], centerOfData, views, viewPort, size)
964
+ : undefined;
965
+ }
966
+ }
967
+ function buildDeckGlViewStates(views, viewPortMargins, cameraPosition, boundingBox, bounds, size) {
968
+ const isOk = areViewsValid(views, size);
969
+ if (!views || !isOk) {
970
+ return {};
971
+ }
972
+ // compute
973
+ const [nY, nX] = views.layout;
974
+ // compute for single view (code is more readable)
975
+ const singleView = nX === 1 && nY === 1;
976
+ if (singleView) {
977
+ const viewState = computeViewState(views.viewports[0], cameraPosition, boundingBox, bounds, viewPortMargins, views, size);
978
+ return viewState ? { [views.viewports[0].id]: viewState } : {};
979
+ }
980
+ // compute for matrix
981
+ let result = {};
982
+ for (let y = 1; y <= nY; y++) {
983
+ for (let x = 1; x <= nX; x++) {
984
+ const resultLength = Object.keys(result).length;
985
+ if (resultLength >= views.viewports.length) {
986
+ // stop when all the viewports are filled
987
+ return result;
988
+ }
989
+ const currentViewport = views.viewports[resultLength];
990
+ const currentViewState = computeViewState(currentViewport, cameraPosition, boundingBox, bounds, viewPortMargins, views, size);
991
+ if (currentViewState) {
992
+ result = Object.assign(Object.assign({}, result), { [currentViewport.id]: currentViewState });
884
993
  }
885
- yPos = yPos + h;
886
994
  }
887
995
  }
888
- return [deckgl_views, viewStates];
996
+ return result;
889
997
  }
890
998
  function handleMouseEvent(type, infos, event) {
891
999
  var _a;