@geode/opengeodeweb-front 10.14.1 → 10.14.2-rc.1
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/.oxlintrc.json +12 -2
- package/app/components/SearchBar.vue +1 -1
- package/app/components/Viewer/ContextMenu.vue +1 -3
- package/app/components/Viewer/ContextMenuItem.vue +2 -2
- package/app/components/Viewer/ObjectTree/Base/CommonTreeView.vue +189 -0
- package/app/components/Viewer/ObjectTree/Base/Controls.vue +124 -38
- package/app/components/Viewer/ObjectTree/Base/ItemLabel.vue +43 -18
- package/app/components/Viewer/ObjectTree/Base/StickyHeader.vue +46 -0
- package/app/components/Viewer/ObjectTree/Base/TreeRow.vue +77 -0
- package/app/components/Viewer/ObjectTree/Box.vue +106 -15
- package/app/components/Viewer/ObjectTree/Layout.vue +14 -12
- package/app/components/Viewer/ObjectTree/Views/GlobalObjects.vue +48 -33
- package/app/components/Viewer/ObjectTree/Views/ModelComponents.vue +102 -66
- package/app/composables/hover_highlight.js +85 -0
- package/app/composables/model_components.js +68 -0
- package/app/composables/{use_tree_filter.js → tree_filter.js} +49 -31
- package/app/composables/tree_keyboard_nav.js +81 -0
- package/app/composables/tree_scroll.js +91 -0
- package/app/composables/virtual_tree.js +164 -0
- package/app/stores/data.js +41 -1
- package/app/stores/hybrid_viewer.js +30 -38
- package/app/utils/hybrid_viewer.js +101 -0
- package/package.json +3 -3
- package/app/composables/use_hover_highlight.js +0 -48
|
@@ -1,13 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
applyCameraOptions,
|
|
3
|
+
computeAverageBrightness,
|
|
4
|
+
getCameraOptions,
|
|
5
|
+
} from "@ogw_front/utils/hybrid_viewer";
|
|
3
6
|
import { newInstance as vtkActor } from "@kitware/vtk.js/Rendering/Core/Actor";
|
|
4
7
|
import { newInstance as vtkGenericRenderWindow } from "@kitware/vtk.js/Rendering/Misc/GenericRenderWindow";
|
|
5
8
|
import { newInstance as vtkMapper } from "@kitware/vtk.js/Rendering/Core/Mapper";
|
|
6
9
|
import { newInstance as vtkXMLPolyDataReader } from "@kitware/vtk.js/IO/XML/XMLPolyDataReader";
|
|
7
10
|
|
|
8
|
-
import { Status } from "@ogw_front/utils/status";
|
|
9
11
|
import { useDataStore } from "@ogw_front/stores/data";
|
|
10
12
|
import { useViewerStore } from "@ogw_front/stores/viewer";
|
|
13
|
+
|
|
14
|
+
import { Status } from "@ogw_front/utils/status";
|
|
11
15
|
import viewer_schemas from "@geode/opengeodeweb-viewer/opengeodeweb_viewer_schemas.json";
|
|
12
16
|
|
|
13
17
|
const RGB_MAX = 255;
|
|
@@ -37,6 +41,13 @@ export const useHybridViewerStore = defineStore("hybridViewer", () => {
|
|
|
37
41
|
let viewStream = undefined;
|
|
38
42
|
const gridActor = undefined;
|
|
39
43
|
|
|
44
|
+
const latestImage = ref(undefined);
|
|
45
|
+
const offscreenCanvas =
|
|
46
|
+
typeof document === "undefined" ? undefined : document.createElement("canvas");
|
|
47
|
+
const offscreenCtx = offscreenCanvas
|
|
48
|
+
? offscreenCanvas.getContext("2d", { willReadFrequently: true })
|
|
49
|
+
: undefined;
|
|
50
|
+
|
|
40
51
|
async function initHybridViewer() {
|
|
41
52
|
if (status.value !== Status.NOT_CREATED) {
|
|
42
53
|
return;
|
|
@@ -58,6 +69,7 @@ export const useHybridViewerStore = defineStore("hybridViewer", () => {
|
|
|
58
69
|
if (is_moving.value) {
|
|
59
70
|
return;
|
|
60
71
|
}
|
|
72
|
+
latestImage.value = event.image;
|
|
61
73
|
webGLRenderWindow.setBackgroundImage(event.image);
|
|
62
74
|
imageStyle.opacity = 1;
|
|
63
75
|
});
|
|
@@ -136,18 +148,10 @@ export const useHybridViewerStore = defineStore("hybridViewer", () => {
|
|
|
136
148
|
}
|
|
137
149
|
|
|
138
150
|
function syncRemoteCamera() {
|
|
139
|
-
console.log("syncRemoteCamera");
|
|
140
151
|
const renderer = genericRenderWindow.value.getRenderer();
|
|
141
152
|
const camera = renderer.getActiveCamera();
|
|
142
153
|
const params = {
|
|
143
|
-
camera_options:
|
|
144
|
-
focal_point: [...camera.getFocalPoint()],
|
|
145
|
-
view_up: [...camera.getViewUp()],
|
|
146
|
-
position: [...camera.getPosition()],
|
|
147
|
-
view_angle: camera.getViewAngle(),
|
|
148
|
-
clipping_range: [...camera.getClippingRange()],
|
|
149
|
-
distance: camera.getDistance(),
|
|
150
|
-
},
|
|
154
|
+
camera_options: getCameraOptions(camera),
|
|
151
155
|
};
|
|
152
156
|
viewerStore.request(viewer_schemas.opengeodeweb_viewer.viewer.update_camera, params, {
|
|
153
157
|
response_function: () => {
|
|
@@ -173,12 +177,10 @@ export const useHybridViewerStore = defineStore("hybridViewer", () => {
|
|
|
173
177
|
imageStyle.transition = "opacity 0.1s ease-in";
|
|
174
178
|
imageStyle.zIndex = 1;
|
|
175
179
|
resize(container.value.$el.offsetWidth, container.value.$el.offsetHeight);
|
|
176
|
-
console.log("setContainer", container.value.$el);
|
|
177
180
|
|
|
178
181
|
useMousePressed({
|
|
179
182
|
target: container,
|
|
180
183
|
onPressed: (event) => {
|
|
181
|
-
console.log("onPressed");
|
|
182
184
|
if (event.button === 0) {
|
|
183
185
|
is_moving.value = true;
|
|
184
186
|
event.stopPropagation();
|
|
@@ -190,7 +192,6 @@ export const useHybridViewerStore = defineStore("hybridViewer", () => {
|
|
|
190
192
|
return;
|
|
191
193
|
}
|
|
192
194
|
is_moving.value = false;
|
|
193
|
-
console.log("onReleased");
|
|
194
195
|
syncRemoteCamera();
|
|
195
196
|
},
|
|
196
197
|
});
|
|
@@ -223,25 +224,24 @@ export const useHybridViewerStore = defineStore("hybridViewer", () => {
|
|
|
223
224
|
remoteRender();
|
|
224
225
|
}
|
|
225
226
|
|
|
227
|
+
function getAverageBrightness(rect) {
|
|
228
|
+
return computeAverageBrightness(rect, {
|
|
229
|
+
latestImage: latestImage.value,
|
|
230
|
+
offscreenCtx,
|
|
231
|
+
offscreenCanvas,
|
|
232
|
+
genericRenderWindow: genericRenderWindow.value,
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
|
|
226
236
|
function exportStores() {
|
|
227
237
|
const renderer = genericRenderWindow.value.getRenderer();
|
|
228
238
|
const camera = renderer.getActiveCamera();
|
|
229
|
-
const cameraSnapshot = camera
|
|
230
|
-
? {
|
|
231
|
-
focal_point: [...camera.getFocalPoint()],
|
|
232
|
-
view_up: [...camera.getViewUp()],
|
|
233
|
-
position: [...camera.getPosition()],
|
|
234
|
-
view_angle: camera.getViewAngle(),
|
|
235
|
-
clipping_range: [...camera.getClippingRange()],
|
|
236
|
-
distance: camera.getDistance(),
|
|
237
|
-
}
|
|
238
|
-
: camera_options;
|
|
239
|
+
const cameraSnapshot = getCameraOptions(camera) || camera_options;
|
|
239
240
|
return { zScale: zScale.value, camera_options: cameraSnapshot };
|
|
240
241
|
}
|
|
241
242
|
|
|
242
243
|
async function importStores(snapshot) {
|
|
243
244
|
if (!snapshot) {
|
|
244
|
-
console.warn("importStores called with undefined snapshot");
|
|
245
245
|
return;
|
|
246
246
|
}
|
|
247
247
|
const z_scale = snapshot.zScale;
|
|
@@ -255,22 +255,12 @@ export const useHybridViewerStore = defineStore("hybridViewer", () => {
|
|
|
255
255
|
const renderer = genericRenderWindow.value.getRenderer();
|
|
256
256
|
const camera = renderer.getActiveCamera();
|
|
257
257
|
|
|
258
|
-
camera
|
|
259
|
-
camera.setViewUp(...snapshot_camera_options.view_up);
|
|
260
|
-
camera.setPosition(...snapshot_camera_options.position);
|
|
261
|
-
camera.setViewAngle(snapshot_camera_options.view_angle);
|
|
262
|
-
camera.setClippingRange(...snapshot_camera_options.clipping_range);
|
|
258
|
+
applyCameraOptions(camera, snapshot_camera_options);
|
|
263
259
|
|
|
264
260
|
genericRenderWindow.value.getRenderWindow().render();
|
|
265
261
|
|
|
266
262
|
const payload = {
|
|
267
|
-
camera_options:
|
|
268
|
-
focal_point: [...snapshot_camera_options.focal_point],
|
|
269
|
-
view_up: [...snapshot_camera_options.view_up],
|
|
270
|
-
position: [...snapshot_camera_options.position],
|
|
271
|
-
view_angle: snapshot_camera_options.view_angle,
|
|
272
|
-
clipping_range: [...snapshot_camera_options.clipping_range],
|
|
273
|
-
},
|
|
263
|
+
camera_options: getCameraOptions(snapshot_camera_options),
|
|
274
264
|
};
|
|
275
265
|
return viewerStore.request(viewer_schemas.opengeodeweb_viewer.viewer.update_camera, payload, {
|
|
276
266
|
response_function: () => {
|
|
@@ -316,5 +306,7 @@ export const useHybridViewerStore = defineStore("hybridViewer", () => {
|
|
|
316
306
|
clear,
|
|
317
307
|
exportStores,
|
|
318
308
|
importStores,
|
|
309
|
+
latestImage,
|
|
310
|
+
getAverageBrightness,
|
|
319
311
|
};
|
|
320
312
|
});
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
const RGB_MAX = 255;
|
|
2
|
+
const BACKGROUND_GREY_VALUE = 180;
|
|
3
|
+
const SAMPLE_SIZE = 10;
|
|
4
|
+
const TOTAL_CHANNELS = 400;
|
|
5
|
+
const RGBA_CHANNELS = 4;
|
|
6
|
+
|
|
7
|
+
function getCameraOptions(camera) {
|
|
8
|
+
if (!camera) {
|
|
9
|
+
return undefined;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
if (typeof camera.getFocalPoint !== "function") {
|
|
13
|
+
return { ...camera };
|
|
14
|
+
}
|
|
15
|
+
return {
|
|
16
|
+
focal_point: [...camera.getFocalPoint()],
|
|
17
|
+
view_up: [...camera.getViewUp()],
|
|
18
|
+
position: [...camera.getPosition()],
|
|
19
|
+
view_angle: camera.getViewAngle(),
|
|
20
|
+
clipping_range: [...camera.getClippingRange()],
|
|
21
|
+
distance: camera.getDistance(),
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function applyCameraOptions(camera, options) {
|
|
26
|
+
if (!camera || !options) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
if (options.focal_point) {
|
|
30
|
+
camera.setFocalPoint(...options.focal_point);
|
|
31
|
+
}
|
|
32
|
+
if (options.view_up) {
|
|
33
|
+
camera.setViewUp(...options.view_up);
|
|
34
|
+
}
|
|
35
|
+
if (options.position) {
|
|
36
|
+
camera.setPosition(...options.position);
|
|
37
|
+
}
|
|
38
|
+
if (options.view_angle) {
|
|
39
|
+
camera.setViewAngle(options.view_angle);
|
|
40
|
+
}
|
|
41
|
+
if (options.clipping_range) {
|
|
42
|
+
camera.setClippingRange(...options.clipping_range);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function mapRect(rect, latestImage, canvasRect) {
|
|
47
|
+
const scaleX = latestImage.width / canvasRect.width;
|
|
48
|
+
const scaleY = latestImage.height / canvasRect.height;
|
|
49
|
+
return {
|
|
50
|
+
relX: (rect.x - canvasRect.left) * scaleX,
|
|
51
|
+
relY: (rect.y - canvasRect.top) * scaleY,
|
|
52
|
+
relW: rect.width * scaleX,
|
|
53
|
+
relH: rect.height * scaleY,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function computeAverageBrightness(rect, options) {
|
|
58
|
+
const { latestImage, offscreenCtx, offscreenCanvas, genericRenderWindow } = options;
|
|
59
|
+
if (!latestImage || !offscreenCtx || !offscreenCanvas || !genericRenderWindow) {
|
|
60
|
+
return BACKGROUND_GREY_VALUE / RGB_MAX;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const canvas = genericRenderWindow.getApiSpecificRenderWindow().getCanvas();
|
|
64
|
+
if (!canvas) {
|
|
65
|
+
return BACKGROUND_GREY_VALUE / RGB_MAX;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const { relX, relY, relW, relH } = mapRect(rect, latestImage, canvas.getBoundingClientRect());
|
|
69
|
+
|
|
70
|
+
offscreenCanvas.width = SAMPLE_SIZE;
|
|
71
|
+
offscreenCanvas.height = SAMPLE_SIZE;
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
offscreenCtx.drawImage(
|
|
75
|
+
latestImage,
|
|
76
|
+
Math.max(0, relX),
|
|
77
|
+
Math.max(0, relY),
|
|
78
|
+
Math.min(latestImage.width, relW),
|
|
79
|
+
Math.min(latestImage.height, relH),
|
|
80
|
+
0,
|
|
81
|
+
0,
|
|
82
|
+
SAMPLE_SIZE,
|
|
83
|
+
SAMPLE_SIZE,
|
|
84
|
+
);
|
|
85
|
+
const { data } = offscreenCtx.getImageData(0, 0, SAMPLE_SIZE, SAMPLE_SIZE);
|
|
86
|
+
|
|
87
|
+
let minBrightness = 1;
|
|
88
|
+
for (let i = 0; i < TOTAL_CHANNELS; i += RGBA_CHANNELS) {
|
|
89
|
+
const brightness = (data[i] + data[i + 1] + data[i + 2]) / (3 * RGB_MAX);
|
|
90
|
+
if (brightness < minBrightness) {
|
|
91
|
+
minBrightness = brightness;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return minBrightness;
|
|
96
|
+
} catch {
|
|
97
|
+
return BACKGROUND_GREY_VALUE / RGB_MAX;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export { applyCameraOptions, computeAverageBrightness, getCameraOptions };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@geode/opengeodeweb-front",
|
|
3
|
-
"version": "10.14.1",
|
|
3
|
+
"version": "10.14.2-rc.1",
|
|
4
4
|
"description": "OpenSource Vue/Nuxt/Pinia/Vuetify framework for web applications",
|
|
5
5
|
"homepage": "https://github.com/Geode-solutions/OpenGeodeWeb-Front",
|
|
6
6
|
"bugs": {
|
|
@@ -34,8 +34,8 @@
|
|
|
34
34
|
"build": ""
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@geode/opengeodeweb-back": "
|
|
38
|
-
"@geode/opengeodeweb-viewer": "
|
|
37
|
+
"@geode/opengeodeweb-back": "next",
|
|
38
|
+
"@geode/opengeodeweb-viewer": "next",
|
|
39
39
|
"@google-cloud/run": "3.2.0",
|
|
40
40
|
"@kitware/vtk.js": "33.3.0",
|
|
41
41
|
"@mdi/font": "7.4.47",
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { useViewerStore } from "@ogw_front/stores/viewer";
|
|
2
|
-
import vtk_schemas from "@geode/opengeodeweb-viewer/opengeodeweb_viewer_schemas.json";
|
|
3
|
-
|
|
4
|
-
const HOVER_DELAY = 1000;
|
|
5
|
-
|
|
6
|
-
export function useHoverhighlight() {
|
|
7
|
-
const viewerStore = useViewerStore();
|
|
8
|
-
let timer = undefined;
|
|
9
|
-
let currentId = undefined;
|
|
10
|
-
let currentType = undefined;
|
|
11
|
-
|
|
12
|
-
function onHoverEnter(id, block_ids = [], type = "model") {
|
|
13
|
-
if (timer) {
|
|
14
|
-
clearTimeout(timer);
|
|
15
|
-
}
|
|
16
|
-
const schema = vtk_schemas.opengeodeweb_viewer[type].highlight;
|
|
17
|
-
timer = setTimeout(async () => {
|
|
18
|
-
currentId = id;
|
|
19
|
-
currentType = type;
|
|
20
|
-
const params = {
|
|
21
|
-
id,
|
|
22
|
-
visibility: true,
|
|
23
|
-
...(type === "model" && { block_ids }),
|
|
24
|
-
};
|
|
25
|
-
await viewerStore.request(schema, params);
|
|
26
|
-
}, HOVER_DELAY);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function onHoverLeave(id) {
|
|
30
|
-
if (timer) {
|
|
31
|
-
clearTimeout(timer);
|
|
32
|
-
timer = undefined;
|
|
33
|
-
}
|
|
34
|
-
if (currentId === id) {
|
|
35
|
-
const schema = vtk_schemas.opengeodeweb_viewer[currentType].highlight;
|
|
36
|
-
const params = {
|
|
37
|
-
id,
|
|
38
|
-
visibility: false,
|
|
39
|
-
...(currentType === "model" && { block_ids: [] }),
|
|
40
|
-
};
|
|
41
|
-
viewerStore.request(schema, params);
|
|
42
|
-
currentId = undefined;
|
|
43
|
-
currentType = undefined;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
return { onHoverEnter, onHoverLeave };
|
|
48
|
-
}
|