@webviz/subsurface-viewer 0.11.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.
- package/dist/components/Map.d.ts +26 -21
- package/dist/components/Map.js +563 -455
- package/dist/components/Map.js.map +1 -1
- package/dist/layers/utils/layerTools.d.ts +1 -1
- package/dist/layers/utils/layerTools.js +4 -2
- package/dist/layers/utils/layerTools.js.map +1 -1
- package/dist/utils/BoundingBox3D.d.ts +18 -0
- package/dist/utils/BoundingBox3D.js +41 -0
- package/dist/utils/BoundingBox3D.js.map +1 -0
- package/dist/utils/BoundingBox3D.test.d.ts +1 -0
- package/dist/utils/BoundingBox3D.test.js +33 -0
- package/dist/utils/BoundingBox3D.test.js.map +1 -0
- package/package.json +2 -1
package/dist/components/Map.js
CHANGED
|
@@ -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 {
|
|
4
|
-
import
|
|
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
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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
|
-
|
|
34
|
-
|
|
45
|
+
if (arrowEvent.shiftModifier) {
|
|
46
|
+
scaleFactor /= 5;
|
|
35
47
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
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
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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.
|
|
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 (
|
|
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 (
|
|
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 (
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
251
|
-
|
|
252
|
-
if (
|
|
253
|
-
((
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
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
|
-
|
|
262
|
-
|
|
263
|
-
|
|
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 [
|
|
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.
|
|
277
|
-
}, [
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
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
|
-
//
|
|
334
|
-
|
|
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
|
-
|
|
425
|
-
|
|
426
|
-
|
|
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,
|
|
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 (
|
|
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(
|
|
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,
|
|
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 (
|
|
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
|
-
(
|
|
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 ||
|
|
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
|
-
|
|
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
|
-
|
|
582
|
-
}, [getCameraPosition, viewStates, views === null || views === void 0 ? void 0 : views.viewports]);
|
|
399
|
+
}, [getCameraPosition, viewController]);
|
|
583
400
|
const effects = parseLights(lights);
|
|
584
|
-
|
|
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:
|
|
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: (
|
|
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) =>
|
|
504
|
+
const filtered_data = data.filter((value) => !isEmpty(value));
|
|
664
505
|
return jsonConverter.convert(filtered_data);
|
|
665
506
|
}
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
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
|
-
|
|
674
|
-
|
|
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 =
|
|
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
|
|
698
|
-
if (
|
|
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:
|
|
744
|
-
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
|
-
|
|
754
|
-
|
|
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
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
797
|
+
return [
|
|
798
|
+
viewport.id === "intersection_view"
|
|
799
|
+
? IntersectionView
|
|
800
|
+
: OrthographicView,
|
|
801
|
+
OrthographicController,
|
|
771
802
|
];
|
|
772
|
-
|
|
773
|
-
|
|
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
|
-
|
|
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
|
-
|
|
789
|
-
|
|
790
|
-
|
|
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
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
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
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
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
|
|
996
|
+
return result;
|
|
889
997
|
}
|
|
890
998
|
function handleMouseEvent(type, infos, event) {
|
|
891
999
|
var _a;
|