@geode/opengeodeweb-front 10.23.0-rc.2 → 10.23.0-rc.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app/components/HybridRenderingView.vue +23 -1
- package/app/components/RemoteRenderingView.vue +23 -5
- package/app/components/Viewer/Options/ColorMapList.vue +5 -57
- package/app/components/Viewer/Options/ColorMapPicker.vue +9 -72
- package/app/components/Viewer/Options/ColormapQuickPicker.vue +120 -0
- package/app/composables/use_quick_colormap.js +32 -0
- package/app/stores/data.js +2 -2
- package/app/utils/colormap.js +62 -5
- package/app/utils/import_workflow.js +1 -1
- package/internal/stores/data_style/mesh/edges/vertex.js +1 -0
- package/package.json +1 -1
- package/tests/unit/composables/project_manager.nuxt.test.js +1 -1
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
+
import ColormapQuickPicker from "@ogw_front/components/Viewer/Options/ColormapQuickPicker.vue";
|
|
2
3
|
import HybridViewerTooltip from "@ogw_front/components/HybridViewerTooltip";
|
|
3
4
|
import ViewToolbar from "@ogw_front/components/ViewToolbar";
|
|
5
|
+
|
|
6
|
+
import { useDataStore } from "@ogw_front/stores/data";
|
|
4
7
|
import { useHybridViewerStore } from "@ogw_front/stores/hybrid_viewer";
|
|
8
|
+
import { useMenuStore } from "@ogw_front/stores/menu";
|
|
9
|
+
import { useQuickColormap } from "@ogw_front/composables/use_quick_colormap";
|
|
5
10
|
import { useViewerStore } from "@ogw_front/stores/viewer";
|
|
6
11
|
|
|
7
12
|
const DEFAULT_ELEMENT_HEIGHT = 100;
|
|
@@ -11,6 +16,8 @@ const emit = defineEmits(["click"]);
|
|
|
11
16
|
const container = useTemplateRef("viewer");
|
|
12
17
|
const hybridViewerStore = useHybridViewerStore();
|
|
13
18
|
const viewerStore = useViewerStore();
|
|
19
|
+
const menuStore = useMenuStore();
|
|
20
|
+
const dataStore = useDataStore();
|
|
14
21
|
|
|
15
22
|
const { width: elementWidth, height: elementHeight } = useElementSize(container);
|
|
16
23
|
const { width: windowWidth, height: windowHeight } = useWindowSize();
|
|
@@ -32,6 +39,8 @@ onMounted(async () => {
|
|
|
32
39
|
}
|
|
33
40
|
});
|
|
34
41
|
|
|
42
|
+
const { pickColormap, quickColormap } = useQuickColormap();
|
|
43
|
+
|
|
35
44
|
function debounce(func, wait) {
|
|
36
45
|
let timeout = undefined;
|
|
37
46
|
return function executedFunction(...args) {
|
|
@@ -45,6 +54,7 @@ function debounce(func, wait) {
|
|
|
45
54
|
}
|
|
46
55
|
|
|
47
56
|
async function handleClick(event) {
|
|
57
|
+
const { offsetX, offsetY, clientX, clientY } = event;
|
|
48
58
|
if (viewerStore.picking_mode) {
|
|
49
59
|
const rect = container.value.$el.getBoundingClientRect();
|
|
50
60
|
const x = event.clientX - rect.left;
|
|
@@ -52,6 +62,12 @@ async function handleClick(event) {
|
|
|
52
62
|
await viewerStore.set_picked_point(x, y);
|
|
53
63
|
return;
|
|
54
64
|
}
|
|
65
|
+
|
|
66
|
+
const picked = await pickColormap(offsetX, offsetY, clientX, clientY);
|
|
67
|
+
if (picked) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
55
71
|
emit("click", event);
|
|
56
72
|
}
|
|
57
73
|
</script>
|
|
@@ -59,6 +75,12 @@ async function handleClick(event) {
|
|
|
59
75
|
<template>
|
|
60
76
|
<ClientOnly>
|
|
61
77
|
<div data-testid="hybridViewer" class="fill-height" style="position: relative; height: 100%">
|
|
78
|
+
<ColormapQuickPicker
|
|
79
|
+
v-model:show="quickColormap.show"
|
|
80
|
+
:x="quickColormap.x"
|
|
81
|
+
:y="quickColormap.y"
|
|
82
|
+
:data-id="quickColormap.data_id"
|
|
83
|
+
/>
|
|
62
84
|
<ViewToolbar />
|
|
63
85
|
<slot name="ui"></slot>
|
|
64
86
|
<HybridViewerTooltip :container-width="elementWidth" :container-height="elementHeight" />
|
|
@@ -67,7 +89,7 @@ async function handleClick(event) {
|
|
|
67
89
|
ref="viewer"
|
|
68
90
|
:class="{ 'picking-cursor': viewerStore.picking_mode }"
|
|
69
91
|
style="height: 100%; overflow: hidden; position: relative; z-index: 0"
|
|
70
|
-
@
|
|
92
|
+
@pointerup.capture="handleClick"
|
|
71
93
|
/>
|
|
72
94
|
</div>
|
|
73
95
|
</ClientOnly>
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { useElementSize, useWindowSize } from "@vueuse/core";
|
|
3
|
+
|
|
3
4
|
import { Status } from "@ogw_front/utils/status";
|
|
4
|
-
import
|
|
5
|
+
import { useDataStore } from "@ogw_front/stores/data";
|
|
6
|
+
import { useMenuStore } from "@ogw_front/stores/menu";
|
|
7
|
+
import { useQuickColormap } from "@ogw_front/composables/use_quick_colormap";
|
|
5
8
|
import { useViewerStore } from "@ogw_front/stores/viewer";
|
|
9
|
+
|
|
10
|
+
import ColormapQuickPicker from "@ogw_front/components/Viewer/Options/ColormapQuickPicker.vue";
|
|
11
|
+
import ViewToolbar from "@ogw_front/components/ViewToolbar";
|
|
6
12
|
import viewer_schemas from "@geode/opengeodeweb-viewer/opengeodeweb_viewer_schemas.json";
|
|
7
13
|
import vtkRemoteView from "@kitware/vtk.js/Rendering/Misc/RemoteView";
|
|
8
14
|
|
|
@@ -11,18 +17,24 @@ const { viewId } = defineProps({
|
|
|
11
17
|
});
|
|
12
18
|
|
|
13
19
|
const viewerStore = useViewerStore();
|
|
20
|
+
const menuStore = useMenuStore();
|
|
21
|
+
const dataStore = useDataStore();
|
|
14
22
|
const viewer = useTemplateRef("viewer");
|
|
15
23
|
const { width, height } = useElementSize(viewer);
|
|
16
24
|
|
|
17
25
|
const { width: windowWidth, height: windowHeight } = useWindowSize();
|
|
18
26
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
27
|
+
const { pickColormap, quickColormap } = useQuickColormap();
|
|
28
|
+
|
|
29
|
+
async function get_x_y(event) {
|
|
30
|
+
const { offsetX, offsetY, clientX, clientY } = event;
|
|
31
|
+
if (viewerStore.picking_mode === true) {
|
|
22
32
|
viewerStore.set_picked_point(offsetX, offsetY);
|
|
23
33
|
const schema = viewer_schemas.opengeodeweb_viewer.viewer.get_point_position;
|
|
24
34
|
const params = { x: offsetX, y: offsetY };
|
|
25
35
|
viewerStore.request({ schema, params });
|
|
36
|
+
} else {
|
|
37
|
+
await pickColormap(offsetX, offsetY, clientX, clientY);
|
|
26
38
|
}
|
|
27
39
|
}
|
|
28
40
|
|
|
@@ -101,13 +113,19 @@ onMounted(async () => {
|
|
|
101
113
|
<template>
|
|
102
114
|
<ClientOnly>
|
|
103
115
|
<div style="position: relative; width: 100%; height: 100%">
|
|
116
|
+
<ColormapQuickPicker
|
|
117
|
+
v-model:show="quickColormap.show"
|
|
118
|
+
:x="quickColormap.x"
|
|
119
|
+
:y="quickColormap.y"
|
|
120
|
+
:data-id="quickColormap.data_id"
|
|
121
|
+
/>
|
|
104
122
|
<ViewToolbar />
|
|
105
123
|
<slot name="ui"></slot>
|
|
106
124
|
<v-col
|
|
107
125
|
ref="viewer"
|
|
108
126
|
style="overflow: hidden; position: relative; z-index: 0; height: 100%; width: 100%"
|
|
109
127
|
class="pa-0"
|
|
110
|
-
@
|
|
128
|
+
@pointerup.capture="get_x_y"
|
|
111
129
|
@keydown.esc="viewerStore.toggle_picking_mode(false)"
|
|
112
130
|
/>
|
|
113
131
|
</div>
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
2
|
+
import GlassCard from "@ogw_front/components/GlassCard.vue";
|
|
3
|
+
import { drawCanvasForPreset } from "@ogw_front/utils/colormap";
|
|
4
4
|
|
|
5
|
-
const LAST_POINT_OFFSET = 4;
|
|
6
|
-
const THREE = 3;
|
|
7
5
|
const CHUNK_SIZE = 5;
|
|
8
6
|
|
|
9
7
|
const { presets, selectedPresetName } = defineProps({
|
|
@@ -46,43 +44,6 @@ const filteredPresets = computed(() => {
|
|
|
46
44
|
return result;
|
|
47
45
|
});
|
|
48
46
|
|
|
49
|
-
function drawPresetCanvas(presetName, canvas) {
|
|
50
|
-
if (!canvas) {
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
const rgbPoints = getRGBPointsFromPreset(presetName);
|
|
54
|
-
if (!rgbPoints || rgbPoints.length === 0) {
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
const ctx = canvas.getContext("2d");
|
|
58
|
-
const { height, width } = canvas;
|
|
59
|
-
const lut = vtkColorTransferFunction();
|
|
60
|
-
for (let pointIdx = 0; pointIdx < rgbPoints.length; pointIdx += 4) {
|
|
61
|
-
lut.addRGBPoint(
|
|
62
|
-
rgbPoints[pointIdx],
|
|
63
|
-
rgbPoints[pointIdx + 1],
|
|
64
|
-
rgbPoints[pointIdx + 2],
|
|
65
|
-
rgbPoints[pointIdx + THREE],
|
|
66
|
-
);
|
|
67
|
-
}
|
|
68
|
-
const table = lut.getUint8Table(rgbPoints[0], rgbPoints.at(-LAST_POINT_OFFSET), width, true);
|
|
69
|
-
const imageData = ctx.createImageData(width, height);
|
|
70
|
-
for (let xCoord = 0; xCoord < width; xCoord += 1) {
|
|
71
|
-
const alpha = table[xCoord * 4 + THREE],
|
|
72
|
-
blue = table[xCoord * 4 + 2],
|
|
73
|
-
green = table[xCoord * 4 + 1],
|
|
74
|
-
red = table[xCoord * 4];
|
|
75
|
-
for (let yCoord = 0; yCoord < height; yCoord += 1) {
|
|
76
|
-
const pixelIdx = (yCoord * width + xCoord) * 4;
|
|
77
|
-
imageData.data[pixelIdx] = red;
|
|
78
|
-
imageData.data[pixelIdx + 1] = green;
|
|
79
|
-
imageData.data[pixelIdx + 2] = blue;
|
|
80
|
-
imageData.data[pixelIdx + THREE] = alpha;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
ctx.putImageData(imageData, 0, 0);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
47
|
function processChunk(entries, index, jobId) {
|
|
87
48
|
if (jobId !== renderJobId.value || index >= entries.length) {
|
|
88
49
|
if (jobId === renderJobId.value) {
|
|
@@ -94,7 +55,7 @@ function processChunk(entries, index, jobId) {
|
|
|
94
55
|
const end = Math.min(index + CHUNK_SIZE, entries.length);
|
|
95
56
|
for (let i = index; i < end; i += 1) {
|
|
96
57
|
const [unusedKey, refValue] = entries[i];
|
|
97
|
-
|
|
58
|
+
drawCanvasForPreset(refValue.presetName, refValue.element);
|
|
98
59
|
}
|
|
99
60
|
const ZERO = 0;
|
|
100
61
|
setTimeout(() => processChunk(entries, end, jobId), ZERO);
|
|
@@ -115,13 +76,7 @@ watch(filteredPresets, drawAllCanvases);
|
|
|
115
76
|
</script>
|
|
116
77
|
|
|
117
78
|
<template>
|
|
118
|
-
<
|
|
119
|
-
width="320"
|
|
120
|
-
class="pa-3 blur-card overflow-hidden"
|
|
121
|
-
theme="dark"
|
|
122
|
-
variant="outlined"
|
|
123
|
-
rounded="lg"
|
|
124
|
-
>
|
|
79
|
+
<GlassCard width="320" variant="panel" padding="pa-3" rounded="lg" class="overflow-hidden">
|
|
125
80
|
<v-overlay
|
|
126
81
|
v-model="loading"
|
|
127
82
|
contained
|
|
@@ -199,17 +154,10 @@ watch(filteredPresets, drawAllCanvases);
|
|
|
199
154
|
</v-list-item>
|
|
200
155
|
</template>
|
|
201
156
|
</v-list>
|
|
202
|
-
</
|
|
157
|
+
</GlassCard>
|
|
203
158
|
</template>
|
|
204
159
|
|
|
205
160
|
<style scoped>
|
|
206
|
-
.blur-card {
|
|
207
|
-
background-color: rgba(35, 35, 35, 0.8) !important;
|
|
208
|
-
backdrop-filter: blur(16px);
|
|
209
|
-
-webkit-backdrop-filter: blur(16px);
|
|
210
|
-
border-color: rgba(255, 255, 255, 0.1) !important;
|
|
211
|
-
}
|
|
212
|
-
|
|
213
161
|
.border-thin {
|
|
214
162
|
border: 1px solid rgba(255, 255, 255, 0.15) !important;
|
|
215
163
|
}
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
-
import {
|
|
2
|
+
import { drawCanvasForPreset, getPresetsWithCurrentAtTop } from "@ogw_front/utils/colormap";
|
|
3
3
|
import ColorMapList from "./ColorMapList.vue";
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
const LAST_POINT_OFFSET = 4;
|
|
7
|
-
const THREE = 3;
|
|
4
|
+
import GlassCard from "@ogw_front/components/GlassCard.vue";
|
|
8
5
|
|
|
9
6
|
const { max, min } = defineProps({
|
|
10
7
|
min: { type: Number, required: true },
|
|
@@ -16,58 +13,10 @@ const selectedPresetName = defineModel("selectedPresetName", { default: "batlow"
|
|
|
16
13
|
const menuOpen = ref(false);
|
|
17
14
|
const lutCanvas = ref();
|
|
18
15
|
|
|
19
|
-
const presets = computed(() =>
|
|
20
|
-
let currentPreset = undefined;
|
|
21
|
-
for (const category of colormaps) {
|
|
22
|
-
currentPreset = category.Children.find((preset) => preset.Name === selectedPresetName.value);
|
|
23
|
-
if (currentPreset) {
|
|
24
|
-
break;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
return [currentPreset, ...colormaps].filter(Boolean);
|
|
28
|
-
});
|
|
16
|
+
const presets = computed(() => getPresetsWithCurrentAtTop(selectedPresetName.value));
|
|
29
17
|
|
|
30
18
|
function drawLutCanvas() {
|
|
31
|
-
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
const rgbPoints = getRGBPointsFromPreset(selectedPresetName.value);
|
|
35
|
-
if (!rgbPoints || rgbPoints.length === 0) {
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const canvas = lutCanvas.value;
|
|
40
|
-
const ctx = canvas.getContext("2d");
|
|
41
|
-
const { height, width } = canvas;
|
|
42
|
-
|
|
43
|
-
const lut = newInstance();
|
|
44
|
-
|
|
45
|
-
for (let pointIdx = 0; pointIdx < rgbPoints.length; pointIdx += 4) {
|
|
46
|
-
lut.addRGBPoint(
|
|
47
|
-
rgbPoints[pointIdx],
|
|
48
|
-
rgbPoints[pointIdx + 1],
|
|
49
|
-
rgbPoints[pointIdx + 2],
|
|
50
|
-
rgbPoints[pointIdx + THREE],
|
|
51
|
-
);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const table = lut.getUint8Table(rgbPoints[0], rgbPoints.at(-LAST_POINT_OFFSET), width, true);
|
|
55
|
-
const imageData = ctx.createImageData(width, height);
|
|
56
|
-
|
|
57
|
-
for (let xCoord = 0; xCoord < width; xCoord += 1) {
|
|
58
|
-
const red = table[xCoord * 4];
|
|
59
|
-
const green = table[xCoord * 4 + 1];
|
|
60
|
-
const blue = table[xCoord * 4 + 2];
|
|
61
|
-
const alpha = table[xCoord * 4 + THREE];
|
|
62
|
-
for (let yCoord = 0; yCoord < height; yCoord += 1) {
|
|
63
|
-
const pixelIdx = (yCoord * width + xCoord) * 4;
|
|
64
|
-
imageData.data[pixelIdx] = red;
|
|
65
|
-
imageData.data[pixelIdx + 1] = green;
|
|
66
|
-
imageData.data[pixelIdx + 2] = blue;
|
|
67
|
-
imageData.data[pixelIdx + THREE] = alpha;
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
ctx.putImageData(imageData, 0, 0);
|
|
19
|
+
drawCanvasForPreset(selectedPresetName.value, lutCanvas.value);
|
|
71
20
|
}
|
|
72
21
|
|
|
73
22
|
function onSelectPreset(preset) {
|
|
@@ -82,19 +31,19 @@ watch([lutCanvas, selectedPresetName, () => min, () => max], drawLutCanvas);
|
|
|
82
31
|
<template>
|
|
83
32
|
<v-menu v-model="menuOpen" :close-on-content-click="false" location="bottom">
|
|
84
33
|
<template #activator="{ props: menuProps }">
|
|
85
|
-
<
|
|
34
|
+
<GlassCard
|
|
86
35
|
v-bind="menuProps"
|
|
87
|
-
|
|
88
|
-
|
|
36
|
+
variant="ui"
|
|
37
|
+
padding="pa-2"
|
|
89
38
|
rounded="sm"
|
|
90
|
-
class="
|
|
39
|
+
class="d-flex flex-column"
|
|
91
40
|
style="gap: 4px; cursor: pointer"
|
|
92
41
|
>
|
|
93
42
|
<span class="text-caption text-white font-weight-medium">
|
|
94
43
|
{{ selectedPresetName }}
|
|
95
44
|
</span>
|
|
96
45
|
<canvas ref="lutCanvas" width="200" height="18" class="w-100 rounded-xs border-thin" />
|
|
97
|
-
</
|
|
46
|
+
</GlassCard>
|
|
98
47
|
</template>
|
|
99
48
|
|
|
100
49
|
<ColorMapList
|
|
@@ -106,18 +55,6 @@ watch([lutCanvas, selectedPresetName, () => min, () => max], drawLutCanvas);
|
|
|
106
55
|
</template>
|
|
107
56
|
|
|
108
57
|
<style scoped>
|
|
109
|
-
.blur-picker {
|
|
110
|
-
background-color: rgba(40, 40, 40, 0.7) !important;
|
|
111
|
-
backdrop-filter: blur(12px);
|
|
112
|
-
-webkit-backdrop-filter: blur(12px);
|
|
113
|
-
border-color: rgba(255, 255, 255, 0.2) !important;
|
|
114
|
-
transition: background-color 0.2s;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
.blur-picker {
|
|
118
|
-
background-color: rgba(60, 60, 60, 0.9) !important;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
58
|
.border-thin {
|
|
122
59
|
border: 1px solid rgba(255, 255, 255, 0.15) !important;
|
|
123
60
|
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import ColorMapList from "@ogw_front/components/Viewer/Options/ColorMapList.vue";
|
|
3
|
+
import { getPresetsWithCurrentAtTop } from "@ogw_front/utils/colormap";
|
|
4
|
+
import { useDataStyleStore } from "@ogw_front/stores/data_style";
|
|
5
|
+
import { useHybridViewerStore } from "@ogw_front/stores/hybrid_viewer";
|
|
6
|
+
|
|
7
|
+
const { dataId, x, y } = defineProps({
|
|
8
|
+
dataId: { required: false, type: String },
|
|
9
|
+
x: { required: true, type: Number },
|
|
10
|
+
y: { required: true, type: Number },
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
const show = defineModel("show", { type: Boolean, default: false });
|
|
14
|
+
|
|
15
|
+
const dataStyleStore = useDataStyleStore();
|
|
16
|
+
const hybridViewerStore = useHybridViewerStore();
|
|
17
|
+
|
|
18
|
+
const componentNames = [
|
|
19
|
+
{ getterKey: "meshPoints", setterKey: "MeshPoints", key: "points" },
|
|
20
|
+
{ getterKey: "meshEdges", setterKey: "MeshEdges", key: "edges" },
|
|
21
|
+
{ getterKey: "meshPolygons", setterKey: "MeshPolygons", key: "polygons" },
|
|
22
|
+
{ getterKey: "meshCells", setterKey: "MeshCells", key: "cells" },
|
|
23
|
+
{ getterKey: "meshPolyhedra", setterKey: "MeshPolyhedra", key: "polyhedra" },
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
const current = computed(() => {
|
|
27
|
+
const targetId = dataId;
|
|
28
|
+
if (!targetId) {
|
|
29
|
+
return "batlow";
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const style = dataStyleStore.getStyle(targetId);
|
|
33
|
+
if (!style) {
|
|
34
|
+
return "batlow";
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
for (const { key, getterKey } of componentNames) {
|
|
38
|
+
if (!style[key] || !style[key].coloring) {
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const activeColoring = style[key].coloring.active;
|
|
43
|
+
if (!["vertex", "edge", "polygon", "cell", "polyhedron"].includes(activeColoring)) {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const attributeType = `${activeColoring.charAt(0).toUpperCase()}${activeColoring.slice(1)}Attribute`;
|
|
48
|
+
const getterName = `${getterKey}${attributeType}ColorMap`;
|
|
49
|
+
const getter = dataStyleStore[getterName];
|
|
50
|
+
|
|
51
|
+
if (!getter) {
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const colorMap = getter(targetId);
|
|
56
|
+
if (colorMap) {
|
|
57
|
+
return colorMap;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return "batlow";
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const quickColormapPresets = computed(() => getPresetsWithCurrentAtTop(current.value));
|
|
65
|
+
|
|
66
|
+
async function onQuickColormapSelect(preset) {
|
|
67
|
+
show.value = false;
|
|
68
|
+
const newMap = preset.Name;
|
|
69
|
+
const targetId = dataId;
|
|
70
|
+
if (!targetId) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const style = dataStyleStore.getStyle(targetId);
|
|
75
|
+
if (!style) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const promises = [];
|
|
80
|
+
|
|
81
|
+
for (const { key, setterKey } of componentNames) {
|
|
82
|
+
if (!style[key] || !style[key].coloring) {
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const activeColoring = style[key].coloring.active;
|
|
87
|
+
if (!["vertex", "edge", "polygon", "cell", "polyhedron"].includes(activeColoring)) {
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const attributeType = `${activeColoring.charAt(0).toUpperCase() + activeColoring.slice(1)}Attribute`;
|
|
92
|
+
const setterName = `set${setterKey}${attributeType}ColorMap`;
|
|
93
|
+
const setter = dataStyleStore[setterName];
|
|
94
|
+
|
|
95
|
+
if (setter) {
|
|
96
|
+
promises.push(setter(targetId, newMap));
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
await Promise.all(promises);
|
|
101
|
+
|
|
102
|
+
hybridViewerStore.remoteRender();
|
|
103
|
+
}
|
|
104
|
+
</script>
|
|
105
|
+
|
|
106
|
+
<template>
|
|
107
|
+
<v-menu
|
|
108
|
+
v-model="show"
|
|
109
|
+
:target="[x, y - 80]"
|
|
110
|
+
location="top center"
|
|
111
|
+
:close-on-content-click="false"
|
|
112
|
+
eager
|
|
113
|
+
>
|
|
114
|
+
<ColorMapList
|
|
115
|
+
:presets="quickColormapPresets"
|
|
116
|
+
:selected-preset-name="current"
|
|
117
|
+
@select="onQuickColormapSelect"
|
|
118
|
+
/>
|
|
119
|
+
</v-menu>
|
|
120
|
+
</template>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { useViewerStore } from "@ogw_front/stores/viewer";
|
|
2
|
+
import viewer_schemas from "@geode/opengeodeweb-viewer/opengeodeweb_viewer_schemas.json";
|
|
3
|
+
|
|
4
|
+
export function useQuickColormap() {
|
|
5
|
+
const viewerStore = useViewerStore();
|
|
6
|
+
const quickColormap = reactive({
|
|
7
|
+
data_id: undefined,
|
|
8
|
+
show: false,
|
|
9
|
+
x: 0,
|
|
10
|
+
y: 0,
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
async function pickColormap(offsetX, offsetY, clientX, clientY) {
|
|
14
|
+
try {
|
|
15
|
+
const schema = viewer_schemas.opengeodeweb_viewer.viewer.pick_colormap;
|
|
16
|
+
const params = { x: offsetX, y: offsetY };
|
|
17
|
+
const result = await viewerStore.request({ schema, params });
|
|
18
|
+
if (result && result.data_id) {
|
|
19
|
+
quickColormap.data_id = result.data_id;
|
|
20
|
+
quickColormap.x = clientX;
|
|
21
|
+
quickColormap.y = clientY;
|
|
22
|
+
quickColormap.show = true;
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
} catch (error) {
|
|
26
|
+
console.error("Error picking colormap:", error);
|
|
27
|
+
}
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return { pickColormap, quickColormap };
|
|
32
|
+
}
|
package/app/stores/data.js
CHANGED
|
@@ -73,9 +73,9 @@ export const useDataStore = defineStore("data", () => {
|
|
|
73
73
|
return component?.type;
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
async function registerObject(id) {
|
|
76
|
+
async function registerObject(id, name) {
|
|
77
77
|
const schema = viewer_generic_schemas.register;
|
|
78
|
-
const params = { id };
|
|
78
|
+
const params = { id, name };
|
|
79
79
|
return await viewerStore.request({ schema, params });
|
|
80
80
|
}
|
|
81
81
|
|
package/app/utils/colormap.js
CHANGED
|
@@ -1,10 +1,67 @@
|
|
|
1
1
|
import colormaps from "@ogw_front/assets/colormaps.json";
|
|
2
2
|
|
|
3
|
+
import { newInstance as vtkColorTransferFunction } from "@kitware/vtk.js/Rendering/Core/ColorTransferFunction";
|
|
4
|
+
|
|
5
|
+
function getPresetByName(presetName) {
|
|
6
|
+
return colormaps
|
|
7
|
+
.flatMap((category) => category.Children)
|
|
8
|
+
.find((preset) => preset.Name === presetName);
|
|
9
|
+
}
|
|
10
|
+
|
|
3
11
|
function getRGBPointsFromPreset(presetName) {
|
|
4
|
-
return (
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
12
|
+
return getPresetByName(presetName)?.RGBPoints ?? [];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function getPresetsWithCurrentAtTop(presetName) {
|
|
16
|
+
const currentPreset = getPresetByName(presetName);
|
|
17
|
+
return [currentPreset, ...colormaps].filter(Boolean);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function drawCanvasForPreset(presetName, canvas) {
|
|
21
|
+
if (!canvas) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const rgbPoints = getRGBPointsFromPreset(presetName);
|
|
25
|
+
if (!rgbPoints || rgbPoints.length === 0) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const ctx = canvas.getContext("2d");
|
|
29
|
+
const { height, width } = canvas;
|
|
30
|
+
const lut = vtkColorTransferFunction();
|
|
31
|
+
|
|
32
|
+
const LAST_POINT_OFFSET = 4;
|
|
33
|
+
const THREE = 3;
|
|
34
|
+
|
|
35
|
+
for (let pointIdx = 0; pointIdx < rgbPoints.length; pointIdx += 4) {
|
|
36
|
+
lut.addRGBPoint(
|
|
37
|
+
rgbPoints[pointIdx],
|
|
38
|
+
rgbPoints[pointIdx + 1],
|
|
39
|
+
rgbPoints[pointIdx + 2],
|
|
40
|
+
rgbPoints[pointIdx + THREE],
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
const table = lut.getUint8Table(rgbPoints[0], rgbPoints.at(-LAST_POINT_OFFSET), width, true);
|
|
44
|
+
const imageData = ctx.createImageData(width, height);
|
|
45
|
+
for (let xCoord = 0; xCoord < width; xCoord += 1) {
|
|
46
|
+
const alpha = table[xCoord * 4 + THREE],
|
|
47
|
+
blue = table[xCoord * 4 + 2],
|
|
48
|
+
green = table[xCoord * 4 + 1],
|
|
49
|
+
red = table[xCoord * 4];
|
|
50
|
+
for (let yCoord = 0; yCoord < height; yCoord += 1) {
|
|
51
|
+
const pixelIdx = (yCoord * width + xCoord) * 4;
|
|
52
|
+
imageData.data[pixelIdx] = red;
|
|
53
|
+
imageData.data[pixelIdx + 1] = green;
|
|
54
|
+
imageData.data[pixelIdx + 2] = blue;
|
|
55
|
+
imageData.data[pixelIdx + THREE] = alpha;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
ctx.putImageData(imageData, 0, 0);
|
|
8
59
|
}
|
|
9
60
|
|
|
10
|
-
export {
|
|
61
|
+
export {
|
|
62
|
+
drawCanvasForPreset,
|
|
63
|
+
getRGBPointsFromPreset,
|
|
64
|
+
getPresetByName,
|
|
65
|
+
getPresetsWithCurrentAtTop,
|
|
66
|
+
colormaps,
|
|
67
|
+
};
|
|
@@ -53,7 +53,7 @@ async function importItem(item) {
|
|
|
53
53
|
feedbackStore.add_warning(`Pointset "${item.name}" is empty`);
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
const registerTask = dataStore.registerObject(item.id);
|
|
56
|
+
const registerTask = dataStore.registerObject(item.id, item.name);
|
|
57
57
|
const addDataTask = dataStore.addItem(item);
|
|
58
58
|
const addDataComponentsTask =
|
|
59
59
|
item.viewer_type === "model" ? dataStore.addComponents(item) : Promise.resolve();
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import viewer_schemas from "@geode/opengeodeweb-viewer/opengeodeweb_viewer_schemas.json";
|
|
3
3
|
|
|
4
4
|
// Local imports
|
|
5
|
+
import { getRGBPointsFromPreset } from "@ogw_front/utils/colormap";
|
|
5
6
|
import { useMeshEdgesCommonStyle } from "./common";
|
|
6
7
|
import { useViewerStore } from "@ogw_front/stores/viewer";
|
|
7
8
|
|
package/package.json
CHANGED
|
@@ -210,7 +210,7 @@ function verifyStoreImports() {
|
|
|
210
210
|
function verifyDataManagement() {
|
|
211
211
|
expect(dataStyleStoreMock.importStores).toHaveBeenCalledWith(snapshotMock.dataStyle);
|
|
212
212
|
expect(dataStyleStoreMock.applyAllStylesFromState).toHaveBeenCalledWith();
|
|
213
|
-
expect(dataStoreMock.registerObject).toHaveBeenCalledWith("abc123");
|
|
213
|
+
expect(dataStoreMock.registerObject).toHaveBeenCalledWith("abc123", "My Data");
|
|
214
214
|
expect(dataStoreMock.addItem).toHaveBeenCalledWith(snapshotMock.data.items[0]);
|
|
215
215
|
expect(treeviewStoreMock.addItem).toHaveBeenCalledWith("PointSet2D", "My Data", "abc123", "mesh");
|
|
216
216
|
}
|