@geode/opengeodeweb-front 10.41.0-rc.1 → 10.41.0-rc.2
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/Viewer/Generic/Mesh/PointsOptions.vue +0 -1
- package/app/components/Viewer/Generic/Model/ComponentPointsOptions.vue +245 -0
- package/app/components/Viewer/Generic/Model/ModelPointsCard.vue +141 -0
- package/app/components/Viewer/Generic/Model/ModelStyleCard.vue +7 -67
- package/app/components/Viewer/Generic/Model/PointsOptions.vue +2 -40
- package/app/composables/model_menu_context.ts +101 -0
- package/internal/stores/data_style/model/blocks/index.ts +4 -0
- package/internal/stores/data_style/model/blocks/points.ts +51 -0
- package/internal/stores/data_style/model/index.ts +6 -0
- package/internal/stores/data_style/model/lines/index.ts +4 -0
- package/internal/stores/data_style/model/lines/points.ts +51 -0
- package/internal/stores/data_style/model/points/component.ts +423 -0
- package/internal/stores/data_style/model/points/size.ts +13 -1
- package/internal/stores/data_style/model/points/visibility.ts +13 -3
- package/internal/stores/data_style/model/surfaces/index.ts +4 -0
- package/internal/stores/data_style/model/surfaces/points.ts +51 -0
- package/package.json +1 -1
|
@@ -172,7 +172,6 @@ async function setVertexAttributeRangesPerData(ranges: RangesPerData): Promise<v
|
|
|
172
172
|
v-model:vertex_attribute_color_map="vertex_attribute_color_map"
|
|
173
173
|
v-model:vertex_attribute_no_data_color="vertex_attribute_no_data_color"
|
|
174
174
|
v-model:vertex_attribute_time_step="vertex_attribute_time_step"
|
|
175
|
-
:capabilities="{ vertex: { available: false } }"
|
|
176
175
|
/>
|
|
177
176
|
</template>
|
|
178
177
|
</template>
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { RGBAColor } from "@ogw_front/utils/default_styles/constants";
|
|
3
|
+
import ViewerOptionsColoringTypeSelector from "@ogw_front/components/Viewer/Options/ColoringTypeSelector.vue";
|
|
4
|
+
import ViewerOptionsSizeSlider from "@ogw_front/components/Viewer/Options/Sliders/Size.vue";
|
|
5
|
+
import VisibilitySwitch from "@ogw_front/components/Viewer/Options/VisibilitySwitch.vue";
|
|
6
|
+
import back_schemas from "@geode/opengeodeweb-back/opengeodeweb_back_typed_schemas.js";
|
|
7
|
+
import { useDataStyleStore } from "@ogw_front/stores/data_style";
|
|
8
|
+
import { useHybridViewerStore } from "@ogw_front/stores/hybrid_viewer";
|
|
9
|
+
|
|
10
|
+
interface PointsTarget {
|
|
11
|
+
componentType: "Surface" | "Line" | "Block";
|
|
12
|
+
componentIds: string[];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface Props {
|
|
16
|
+
modelId: string;
|
|
17
|
+
targets: PointsTarget[];
|
|
18
|
+
referenceComponentId?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const { modelId, targets, referenceComponentId = undefined } = defineProps<Props>();
|
|
22
|
+
|
|
23
|
+
const dataStyleStore = useDataStyleStore();
|
|
24
|
+
const hybridViewerStore = useHybridViewerStore();
|
|
25
|
+
|
|
26
|
+
// Each component type exposes its own points functions in the data style store
|
|
27
|
+
const POINTS_STYLES = {
|
|
28
|
+
Surface: {
|
|
29
|
+
visibility: dataStyleStore.modelSurfacePointsVisibility,
|
|
30
|
+
size: dataStyleStore.modelSurfacePointsSize,
|
|
31
|
+
color: dataStyleStore.modelSurfacePointsColor,
|
|
32
|
+
activeColoring: dataStyleStore.modelSurfacePointsActiveColoring,
|
|
33
|
+
vertexAttributeName: dataStyleStore.modelSurfacePointsVertexAttributeName,
|
|
34
|
+
vertexAttributeItem: dataStyleStore.modelSurfacePointsVertexAttributeItem,
|
|
35
|
+
vertexAttributeRange: dataStyleStore.modelSurfacePointsVertexAttributeRange,
|
|
36
|
+
vertexAttributeColorMap: dataStyleStore.modelSurfacePointsVertexAttributeColorMap,
|
|
37
|
+
vertexAttributeNoDataColor: dataStyleStore.modelSurfacePointsVertexAttributeNoDataColor,
|
|
38
|
+
setVisibility: dataStyleStore.setModelSurfacesPointsVisibility,
|
|
39
|
+
setSize: dataStyleStore.setModelSurfacesPointsSize,
|
|
40
|
+
setColor: dataStyleStore.setModelSurfacesPointsColor,
|
|
41
|
+
setActiveColoring: dataStyleStore.setModelSurfacesPointsActiveColoring,
|
|
42
|
+
setVertexAttributeName: dataStyleStore.setModelSurfacesPointsVertexAttributeName,
|
|
43
|
+
setVertexAttributeItem: dataStyleStore.setModelSurfacesPointsVertexAttributeItem,
|
|
44
|
+
setVertexAttributeRange: dataStyleStore.setModelSurfacesPointsVertexAttributeRange,
|
|
45
|
+
setVertexAttributeColorMap: dataStyleStore.setModelSurfacesPointsVertexAttributeColorMap,
|
|
46
|
+
setVertexAttributeNoDataColor: dataStyleStore.setModelSurfacesPointsVertexAttributeNoDataColor,
|
|
47
|
+
},
|
|
48
|
+
Line: {
|
|
49
|
+
visibility: dataStyleStore.modelLinePointsVisibility,
|
|
50
|
+
size: dataStyleStore.modelLinePointsSize,
|
|
51
|
+
color: dataStyleStore.modelLinePointsColor,
|
|
52
|
+
activeColoring: dataStyleStore.modelLinePointsActiveColoring,
|
|
53
|
+
vertexAttributeName: dataStyleStore.modelLinePointsVertexAttributeName,
|
|
54
|
+
vertexAttributeItem: dataStyleStore.modelLinePointsVertexAttributeItem,
|
|
55
|
+
vertexAttributeRange: dataStyleStore.modelLinePointsVertexAttributeRange,
|
|
56
|
+
vertexAttributeColorMap: dataStyleStore.modelLinePointsVertexAttributeColorMap,
|
|
57
|
+
vertexAttributeNoDataColor: dataStyleStore.modelLinePointsVertexAttributeNoDataColor,
|
|
58
|
+
setVisibility: dataStyleStore.setModelLinesPointsVisibility,
|
|
59
|
+
setSize: dataStyleStore.setModelLinesPointsSize,
|
|
60
|
+
setColor: dataStyleStore.setModelLinesPointsColor,
|
|
61
|
+
setActiveColoring: dataStyleStore.setModelLinesPointsActiveColoring,
|
|
62
|
+
setVertexAttributeName: dataStyleStore.setModelLinesPointsVertexAttributeName,
|
|
63
|
+
setVertexAttributeItem: dataStyleStore.setModelLinesPointsVertexAttributeItem,
|
|
64
|
+
setVertexAttributeRange: dataStyleStore.setModelLinesPointsVertexAttributeRange,
|
|
65
|
+
setVertexAttributeColorMap: dataStyleStore.setModelLinesPointsVertexAttributeColorMap,
|
|
66
|
+
setVertexAttributeNoDataColor: dataStyleStore.setModelLinesPointsVertexAttributeNoDataColor,
|
|
67
|
+
},
|
|
68
|
+
Block: {
|
|
69
|
+
visibility: dataStyleStore.modelBlockPointsVisibility,
|
|
70
|
+
size: dataStyleStore.modelBlockPointsSize,
|
|
71
|
+
color: dataStyleStore.modelBlockPointsColor,
|
|
72
|
+
activeColoring: dataStyleStore.modelBlockPointsActiveColoring,
|
|
73
|
+
vertexAttributeName: dataStyleStore.modelBlockPointsVertexAttributeName,
|
|
74
|
+
vertexAttributeItem: dataStyleStore.modelBlockPointsVertexAttributeItem,
|
|
75
|
+
vertexAttributeRange: dataStyleStore.modelBlockPointsVertexAttributeRange,
|
|
76
|
+
vertexAttributeColorMap: dataStyleStore.modelBlockPointsVertexAttributeColorMap,
|
|
77
|
+
vertexAttributeNoDataColor: dataStyleStore.modelBlockPointsVertexAttributeNoDataColor,
|
|
78
|
+
setVisibility: dataStyleStore.setModelBlocksPointsVisibility,
|
|
79
|
+
setSize: dataStyleStore.setModelBlocksPointsSize,
|
|
80
|
+
setColor: dataStyleStore.setModelBlocksPointsColor,
|
|
81
|
+
setActiveColoring: dataStyleStore.setModelBlocksPointsActiveColoring,
|
|
82
|
+
setVertexAttributeName: dataStyleStore.setModelBlocksPointsVertexAttributeName,
|
|
83
|
+
setVertexAttributeItem: dataStyleStore.setModelBlocksPointsVertexAttributeItem,
|
|
84
|
+
setVertexAttributeRange: dataStyleStore.setModelBlocksPointsVertexAttributeRange,
|
|
85
|
+
setVertexAttributeColorMap: dataStyleStore.setModelBlocksPointsVertexAttributeColorMap,
|
|
86
|
+
setVertexAttributeNoDataColor: dataStyleStore.setModelBlocksPointsVertexAttributeNoDataColor,
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
type PointsStyle = (typeof POINTS_STYLES)[PointsTarget["componentType"]];
|
|
90
|
+
|
|
91
|
+
// Values are read from the first target, changes are applied to every target
|
|
92
|
+
const pointsStyle = computed<PointsStyle | undefined>(() => {
|
|
93
|
+
const [reference] = targets;
|
|
94
|
+
return reference === undefined ? undefined : POINTS_STYLES[reference.componentType];
|
|
95
|
+
});
|
|
96
|
+
const allComponentIds = computed<string[]>(() => targets.flatMap((target) => target.componentIds));
|
|
97
|
+
|
|
98
|
+
async function applyPointsStyle(
|
|
99
|
+
setter: (style: PointsStyle, componentIds: string[]) => Promise<unknown>,
|
|
100
|
+
): Promise<void> {
|
|
101
|
+
await Promise.all(
|
|
102
|
+
targets.map(async (target) => {
|
|
103
|
+
await setter(POINTS_STYLES[target.componentType], target.componentIds);
|
|
104
|
+
}),
|
|
105
|
+
);
|
|
106
|
+
hybridViewerStore.remoteRender();
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const visibility = computed<boolean | undefined>({
|
|
110
|
+
get: () => pointsStyle.value?.visibility(modelId, referenceComponentId),
|
|
111
|
+
set: async (newValue) => {
|
|
112
|
+
if (newValue === undefined) {
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
await applyPointsStyle((style, ids) => style.setVisibility(modelId, ids, newValue));
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
const size = computed<number | undefined>({
|
|
120
|
+
get: () => pointsStyle.value?.size(modelId, referenceComponentId),
|
|
121
|
+
set: async (newValue) => {
|
|
122
|
+
if (newValue === undefined) {
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
await applyPointsStyle((style, ids) => style.setSize(modelId, ids, newValue));
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
const activeColoring = computed<string | undefined>({
|
|
130
|
+
get: () => pointsStyle.value?.activeColoring(modelId, referenceComponentId),
|
|
131
|
+
set: async (newValue) => {
|
|
132
|
+
if (newValue === undefined) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
await applyPointsStyle((style, ids) => style.setActiveColoring(modelId, ids, newValue));
|
|
136
|
+
},
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
const color = computed<RGBAColor | undefined>({
|
|
140
|
+
get: () => pointsStyle.value?.color(modelId, referenceComponentId),
|
|
141
|
+
set: async (newValue) => {
|
|
142
|
+
if (newValue === undefined) {
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
await applyPointsStyle((style, ids) => style.setColor(modelId, ids, newValue));
|
|
146
|
+
},
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
const vertexAttributeName = computed<string | undefined>({
|
|
150
|
+
get: () => pointsStyle.value?.vertexAttributeName(modelId, referenceComponentId),
|
|
151
|
+
set: async (newValue) => {
|
|
152
|
+
if (newValue === undefined) {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
await applyPointsStyle((style, ids) => style.setVertexAttributeName(modelId, ids, newValue));
|
|
156
|
+
},
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
const vertexAttributeItem = computed<number | undefined>({
|
|
160
|
+
get: () => pointsStyle.value?.vertexAttributeItem(modelId, referenceComponentId),
|
|
161
|
+
set: async (newValue) => {
|
|
162
|
+
if (newValue === undefined) {
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
await applyPointsStyle((style, ids) => style.setVertexAttributeItem(modelId, ids, newValue));
|
|
166
|
+
},
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
const vertexAttributeRange = computed<(number | undefined)[] | undefined>({
|
|
170
|
+
get: () => pointsStyle.value?.vertexAttributeRange(modelId, referenceComponentId),
|
|
171
|
+
set: async (newValue) => {
|
|
172
|
+
if (newValue === undefined) {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
const [minimum, maximum] = newValue;
|
|
176
|
+
if (minimum === undefined || maximum === undefined) {
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
await applyPointsStyle((style, ids) =>
|
|
180
|
+
style.setVertexAttributeRange(modelId, ids, minimum, maximum),
|
|
181
|
+
);
|
|
182
|
+
},
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
const vertexAttributeColorMap = computed<string | undefined>({
|
|
186
|
+
get: () => pointsStyle.value?.vertexAttributeColorMap(modelId, referenceComponentId),
|
|
187
|
+
set: async (newValue) => {
|
|
188
|
+
await applyPointsStyle((style, ids) =>
|
|
189
|
+
style.setVertexAttributeColorMap(modelId, ids, newValue),
|
|
190
|
+
);
|
|
191
|
+
},
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
const vertexAttributeNoDataColor = computed<RGBAColor | undefined>({
|
|
195
|
+
get: () => pointsStyle.value?.vertexAttributeNoDataColor(modelId, referenceComponentId),
|
|
196
|
+
set: async (newValue) => {
|
|
197
|
+
if (newValue === undefined) {
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
await applyPointsStyle((style, ids) =>
|
|
201
|
+
style.setVertexAttributeNoDataColor(modelId, ids, newValue),
|
|
202
|
+
);
|
|
203
|
+
},
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
const capabilities = {
|
|
207
|
+
color: { available: true },
|
|
208
|
+
textures: { available: false },
|
|
209
|
+
vertex: { available: true },
|
|
210
|
+
edge: { available: false },
|
|
211
|
+
cell: { available: false },
|
|
212
|
+
polygon: { available: false },
|
|
213
|
+
polyhedron: { available: false },
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
const backSchemas = back_schemas.opengeodeweb_back;
|
|
217
|
+
const attributeSchemas = {
|
|
218
|
+
vertex: {
|
|
219
|
+
names: backSchemas.model_component_vertex_attribute_names,
|
|
220
|
+
range: backSchemas.model_component_vertex_attribute_range,
|
|
221
|
+
},
|
|
222
|
+
};
|
|
223
|
+
</script>
|
|
224
|
+
|
|
225
|
+
<template>
|
|
226
|
+
<div class="mt-2" data-testid="modelComponentPointsOptions">
|
|
227
|
+
<VisibilitySwitch data-testid="modelComponentPointsVisibilitySwitch" v-model="visibility" />
|
|
228
|
+
<template v-if="visibility">
|
|
229
|
+
<ViewerOptionsSizeSlider data-testid="modelComponentPointsSizeSlider" v-model="size" />
|
|
230
|
+
<ViewerOptionsColoringTypeSelector
|
|
231
|
+
:id="modelId"
|
|
232
|
+
:componentIds="allComponentIds"
|
|
233
|
+
v-model:coloring_style_key="activeColoring"
|
|
234
|
+
v-model:color="color"
|
|
235
|
+
v-model:vertex_attribute_name="vertexAttributeName"
|
|
236
|
+
v-model:vertex_attribute_item="vertexAttributeItem"
|
|
237
|
+
v-model:vertex_attribute_range="vertexAttributeRange"
|
|
238
|
+
v-model:vertex_attribute_color_map="vertexAttributeColorMap"
|
|
239
|
+
v-model:vertex_attribute_no_data_color="vertexAttributeNoDataColor"
|
|
240
|
+
:capabilities="capabilities"
|
|
241
|
+
:schemas="attributeSchemas"
|
|
242
|
+
/>
|
|
243
|
+
</template>
|
|
244
|
+
</div>
|
|
245
|
+
</template>
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import {
|
|
3
|
+
type ModelMenuItemProps,
|
|
4
|
+
useModelMenuContext,
|
|
5
|
+
} from "@ogw_front/composables/model_menu_context";
|
|
6
|
+
import OptionsSection from "@ogw_front/components/Viewer/Options/OptionsSection.vue";
|
|
7
|
+
import ViewerGenericModelComponentPointsOptions from "@ogw_front/components/Viewer/Generic/Model/ComponentPointsOptions.vue";
|
|
8
|
+
import VisibilitySwitch from "@ogw_front/components/Viewer/Options/VisibilitySwitch.vue";
|
|
9
|
+
import { useBatchStyle } from "@ogw_front/composables/batch_style";
|
|
10
|
+
import { useDataStore } from "@ogw_front/stores/data";
|
|
11
|
+
import { useDataStyleStore } from "@ogw_front/stores/data_style";
|
|
12
|
+
import { useHybridViewerStore } from "@ogw_front/stores/hybrid_viewer";
|
|
13
|
+
|
|
14
|
+
// Corners have no points options: their points are the corners themselves
|
|
15
|
+
const POINTS_TYPE_TITLES = {
|
|
16
|
+
Surface: "Surfaces Points Options",
|
|
17
|
+
Line: "Lines Points Options",
|
|
18
|
+
Block: "Blocks Points Options",
|
|
19
|
+
} as const;
|
|
20
|
+
type PointsComponentType = keyof typeof POINTS_TYPE_TITLES;
|
|
21
|
+
const POINTS_COMPONENT_TYPES: PointsComponentType[] = ["Surface", "Line", "Block"];
|
|
22
|
+
|
|
23
|
+
function isPointsComponentType(type: string | undefined): type is PointsComponentType {
|
|
24
|
+
return type !== undefined && type in POINTS_TYPE_TITLES;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
interface Props {
|
|
28
|
+
itemProps: ModelMenuItemProps;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const { itemProps } = defineProps<Props>();
|
|
32
|
+
|
|
33
|
+
const dataStore = useDataStore();
|
|
34
|
+
const dataStyleStore = useDataStyleStore();
|
|
35
|
+
const hybridViewerStore = useHybridViewerStore();
|
|
36
|
+
const { applyBatchStyle } = useBatchStyle();
|
|
37
|
+
|
|
38
|
+
const { modelId, componentId, componentType, collections, targetComponentIds } =
|
|
39
|
+
useModelMenuContext(() => itemProps);
|
|
40
|
+
|
|
41
|
+
const modelPointsVisibility = computed<boolean>({
|
|
42
|
+
get: () => dataStyleStore.modelPointsVisibility(modelId.value),
|
|
43
|
+
set: async (newValue) => {
|
|
44
|
+
await applyBatchStyle(modelId.value, (targetId: string) =>
|
|
45
|
+
dataStyleStore.setModelPointsVisibility(targetId, newValue),
|
|
46
|
+
);
|
|
47
|
+
hybridViewerStore.remoteRender();
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
const pointsComponentType = computed<PointsComponentType | undefined>(() =>
|
|
52
|
+
isPointsComponentType(componentType.value) ? componentType.value : undefined,
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
const allComponentsTargets = ref<{ componentType: PointsComponentType; componentIds: string[] }[]>(
|
|
56
|
+
[],
|
|
57
|
+
);
|
|
58
|
+
watch(
|
|
59
|
+
modelId,
|
|
60
|
+
async (currentModelId) => {
|
|
61
|
+
const targets = await Promise.all(
|
|
62
|
+
POINTS_COMPONENT_TYPES.map(async (type) => ({
|
|
63
|
+
componentType: type,
|
|
64
|
+
componentIds: await dataStore.getMeshComponentGeodeIds(currentModelId, type),
|
|
65
|
+
})),
|
|
66
|
+
);
|
|
67
|
+
if (modelId.value === currentModelId) {
|
|
68
|
+
allComponentsTargets.value = targets.filter((target) => target.componentIds.length > 0);
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
{ immediate: true },
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
const typeTargets = computed(() =>
|
|
75
|
+
pointsComponentType.value === undefined
|
|
76
|
+
? []
|
|
77
|
+
: [{ componentType: pointsComponentType.value, componentIds: targetComponentIds.value }],
|
|
78
|
+
);
|
|
79
|
+
const typeReferenceId = computed<string | undefined>(() =>
|
|
80
|
+
collections.value ? targetComponentIds.value[0] : undefined,
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
const componentTargets = computed(() =>
|
|
84
|
+
pointsComponentType.value === undefined || componentId.value === undefined
|
|
85
|
+
? []
|
|
86
|
+
: [{ componentType: pointsComponentType.value, componentIds: [componentId.value] }],
|
|
87
|
+
);
|
|
88
|
+
</script>
|
|
89
|
+
|
|
90
|
+
<template>
|
|
91
|
+
<v-sheet class="model-points-card" color="transparent">
|
|
92
|
+
<OptionsSection title="Model Points Options">
|
|
93
|
+
<VisibilitySwitch data-testid="modelPointsVisibilitySwitch" v-model="modelPointsVisibility" />
|
|
94
|
+
</OptionsSection>
|
|
95
|
+
|
|
96
|
+
<OptionsSection
|
|
97
|
+
v-if="!componentType && !componentId && allComponentsTargets.length > 0"
|
|
98
|
+
title="Components Points Options"
|
|
99
|
+
data-testid="modelPointsComponentsOptions"
|
|
100
|
+
class="mt-4"
|
|
101
|
+
>
|
|
102
|
+
<ViewerGenericModelComponentPointsOptions
|
|
103
|
+
:modelId="modelId"
|
|
104
|
+
:targets="allComponentsTargets"
|
|
105
|
+
/>
|
|
106
|
+
</OptionsSection>
|
|
107
|
+
|
|
108
|
+
<OptionsSection
|
|
109
|
+
v-if="pointsComponentType"
|
|
110
|
+
:title="POINTS_TYPE_TITLES[pointsComponentType]"
|
|
111
|
+
data-testid="modelPointsComponentTypeOptions"
|
|
112
|
+
class="mt-4"
|
|
113
|
+
>
|
|
114
|
+
<ViewerGenericModelComponentPointsOptions
|
|
115
|
+
:modelId="modelId"
|
|
116
|
+
:targets="typeTargets"
|
|
117
|
+
:referenceComponentId="typeReferenceId"
|
|
118
|
+
/>
|
|
119
|
+
</OptionsSection>
|
|
120
|
+
|
|
121
|
+
<OptionsSection
|
|
122
|
+
v-if="pointsComponentType && componentId"
|
|
123
|
+
title="Component Points Options"
|
|
124
|
+
data-testid="modelPointsComponentOptions"
|
|
125
|
+
class="mt-4"
|
|
126
|
+
>
|
|
127
|
+
<ViewerGenericModelComponentPointsOptions
|
|
128
|
+
:modelId="modelId"
|
|
129
|
+
:targets="componentTargets"
|
|
130
|
+
:referenceComponentId="componentId"
|
|
131
|
+
/>
|
|
132
|
+
</OptionsSection>
|
|
133
|
+
</v-sheet>
|
|
134
|
+
</template>
|
|
135
|
+
|
|
136
|
+
<style scoped>
|
|
137
|
+
.model-points-card {
|
|
138
|
+
padding-top: 12px;
|
|
139
|
+
overflow-x: hidden;
|
|
140
|
+
}
|
|
141
|
+
</style>
|
|
@@ -1,95 +1,35 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
+
import {
|
|
3
|
+
type ModelMenuItemProps,
|
|
4
|
+
useModelMenuContext,
|
|
5
|
+
} from "@ogw_front/composables/model_menu_context";
|
|
2
6
|
import BlocksOptions from "./BlocksOptions.vue";
|
|
3
|
-
import type { CollectionComponent } from "@ogw_front/stores/data_helpers/collections";
|
|
4
7
|
import CornersOptions from "./CornersOptions.vue";
|
|
5
8
|
import LinesOptions from "./LinesOptions.vue";
|
|
6
|
-
import { MESH_COMPONENT_TYPES } from "@ogw_front/utils/default_styles";
|
|
7
9
|
import OptionsSection from "@ogw_front/components/Viewer/Options/OptionsSection.vue";
|
|
8
10
|
import type { RGBAColor } from "@ogw_front/utils/default_styles/constants";
|
|
9
11
|
import SurfacesOptions from "./SurfacesOptions.vue";
|
|
10
12
|
import ViewerOptionsColoringTypeSelector from "@ogw_front/components/Viewer/Options/ColoringTypeSelector.vue";
|
|
11
13
|
import VisibilitySwitch from "@ogw_front/components/Viewer/Options/VisibilitySwitch.vue";
|
|
12
14
|
import { useBatchStyle } from "@ogw_front/composables/batch_style";
|
|
13
|
-
import { useDataStore } from "@ogw_front/stores/data";
|
|
14
15
|
import { useDataStyleStore } from "@ogw_front/stores/data_style";
|
|
15
16
|
import { useHybridViewerStore } from "@ogw_front/stores/hybrid_viewer";
|
|
16
17
|
|
|
17
18
|
const dataStyleStore = useDataStyleStore();
|
|
18
19
|
const hybridViewerStore = useHybridViewerStore();
|
|
19
|
-
const dataStore = useDataStore();
|
|
20
20
|
const { applyBatchStyle } = useBatchStyle();
|
|
21
21
|
|
|
22
22
|
interface Props {
|
|
23
|
-
itemProps:
|
|
23
|
+
itemProps: ModelMenuItemProps;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
const { itemProps } = defineProps<Props>();
|
|
27
27
|
|
|
28
|
-
const modelId
|
|
29
|
-
|
|
28
|
+
const { modelId, componentId, componentType, collections, targetComponentIds } =
|
|
29
|
+
useModelMenuContext(() => itemProps);
|
|
30
30
|
function visibleComponents(targetId: string): string[] {
|
|
31
31
|
return dataStyleStore.visibleMeshComponents(targetId).value || [];
|
|
32
32
|
}
|
|
33
|
-
const componentType = ref<string | undefined>(undefined);
|
|
34
|
-
const collections = ref<CollectionComponent[] | undefined>(undefined);
|
|
35
|
-
|
|
36
|
-
watch(
|
|
37
|
-
() => [
|
|
38
|
-
modelId.value,
|
|
39
|
-
componentId.value,
|
|
40
|
-
itemProps.meta_data.viewer_type,
|
|
41
|
-
itemProps.meta_data.modelComponentType,
|
|
42
|
-
],
|
|
43
|
-
async () => {
|
|
44
|
-
componentType.value = undefined;
|
|
45
|
-
collections.value = undefined;
|
|
46
|
-
if (itemProps.meta_data.viewer_type === "model_component_type") {
|
|
47
|
-
const { modelComponentType, targetComponentIds: ids } = itemProps.meta_data;
|
|
48
|
-
if (MESH_COMPONENT_TYPES.includes(modelComponentType)) {
|
|
49
|
-
componentType.value = modelComponentType;
|
|
50
|
-
} else {
|
|
51
|
-
const collectionsByType = await dataStore.fetchAllCollectionComponents(modelId.value);
|
|
52
|
-
collections.value = collectionsByType[modelComponentType].filter((collection) =>
|
|
53
|
-
collection.children.every((child) => ids.includes(child.id)),
|
|
54
|
-
);
|
|
55
|
-
componentType.value = collections.value[0].children[0].category;
|
|
56
|
-
}
|
|
57
|
-
} else if (componentId.value && modelId.value) {
|
|
58
|
-
const currentModelId = modelId.value;
|
|
59
|
-
const currentCompId = componentId.value;
|
|
60
|
-
const type = await dataStore.meshComponentType(currentModelId, currentCompId);
|
|
61
|
-
if (
|
|
62
|
-
modelId.value === currentModelId &&
|
|
63
|
-
componentId.value === currentCompId &&
|
|
64
|
-
itemProps.meta_data.viewer_type !== "model_component_type"
|
|
65
|
-
) {
|
|
66
|
-
componentType.value = type;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
},
|
|
70
|
-
{ immediate: true },
|
|
71
|
-
);
|
|
72
|
-
|
|
73
|
-
const targetComponentIds = ref<string[]>([]);
|
|
74
|
-
watch(
|
|
75
|
-
() => [modelId.value, componentType.value, itemProps.meta_data.targetComponentIds],
|
|
76
|
-
async () => {
|
|
77
|
-
targetComponentIds.value = [];
|
|
78
|
-
if (itemProps.meta_data.targetComponentIds) {
|
|
79
|
-
targetComponentIds.value = itemProps.meta_data.targetComponentIds;
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
if (componentType.value && modelId.value) {
|
|
83
|
-
const currentModelId = modelId.value;
|
|
84
|
-
const currentType = componentType.value;
|
|
85
|
-
const ids = await dataStore.getMeshComponentGeodeIds(currentModelId, currentType);
|
|
86
|
-
if (modelId.value === currentModelId && componentType.value === currentType) {
|
|
87
|
-
targetComponentIds.value = ids;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
},
|
|
91
|
-
{ immediate: true },
|
|
92
|
-
);
|
|
93
33
|
|
|
94
34
|
const modelVisibility = computed<boolean | undefined>({
|
|
95
35
|
get: () => dataStyleStore.modelVisibility(modelId.value),
|
|
@@ -2,45 +2,14 @@
|
|
|
2
2
|
import ViewerContextMenuItem, {
|
|
3
3
|
type ItemProps,
|
|
4
4
|
} from "@ogw_front/components/Viewer/ContextMenu/ContextMenuItem.vue";
|
|
5
|
+
import ModelPointsCard from "./ModelPointsCard.vue";
|
|
5
6
|
import SurfacePoints from "@ogw_front/assets/viewer_svgs/surface_points.svg";
|
|
6
|
-
import ViewerOptionsSizeSlider from "@ogw_front/components/Viewer/Options/Sliders/Size.vue";
|
|
7
|
-
import ViewerOptionsVisibilitySwitch from "@ogw_front/components/Viewer/Options/VisibilitySwitch.vue";
|
|
8
|
-
import { useBatchStyle } from "@ogw_front/composables/batch_style";
|
|
9
|
-
import { useDataStyleStore } from "@ogw_front/stores/data_style";
|
|
10
|
-
import { useHybridViewerStore } from "@ogw_front/stores/hybrid_viewer";
|
|
11
|
-
|
|
12
|
-
const dataStyleStore = useDataStyleStore();
|
|
13
|
-
const hybridViewerStore = useHybridViewerStore();
|
|
14
|
-
const { applyBatchStyle } = useBatchStyle();
|
|
15
7
|
|
|
16
8
|
interface Props {
|
|
17
9
|
itemProps: ItemProps & { index: number };
|
|
18
10
|
}
|
|
19
11
|
|
|
20
12
|
const { itemProps } = defineProps<Props>();
|
|
21
|
-
|
|
22
|
-
const id = computed<string>(
|
|
23
|
-
() => (itemProps.meta_data.modelId as string | undefined) || itemProps.id,
|
|
24
|
-
);
|
|
25
|
-
|
|
26
|
-
const visibility = computed<boolean>({
|
|
27
|
-
get: () => dataStyleStore.modelPointsVisibility(id.value),
|
|
28
|
-
set: async (newValue) => {
|
|
29
|
-
await applyBatchStyle(id.value, (targetId: string) =>
|
|
30
|
-
dataStyleStore.setModelPointsVisibility(targetId, newValue),
|
|
31
|
-
);
|
|
32
|
-
hybridViewerStore.remoteRender();
|
|
33
|
-
},
|
|
34
|
-
});
|
|
35
|
-
const size = computed<number>({
|
|
36
|
-
get: () => dataStyleStore.modelPointsSize(id.value),
|
|
37
|
-
set: async (newValue) => {
|
|
38
|
-
await applyBatchStyle(id.value, (targetId: string) =>
|
|
39
|
-
dataStyleStore.setModelPointsSize(targetId, newValue),
|
|
40
|
-
);
|
|
41
|
-
hybridViewerStore.remoteRender();
|
|
42
|
-
},
|
|
43
|
-
});
|
|
44
13
|
</script>
|
|
45
14
|
|
|
46
15
|
<template>
|
|
@@ -52,14 +21,7 @@ const size = computed<number>({
|
|
|
52
21
|
:btnImage="SurfacePoints"
|
|
53
22
|
>
|
|
54
23
|
<template #options>
|
|
55
|
-
<
|
|
56
|
-
data-testid="modelPointsVisibilitySwitch"
|
|
57
|
-
v-model="visibility"
|
|
58
|
-
/>
|
|
59
|
-
<template v-if="visibility">
|
|
60
|
-
<v-divider class="my-2" />
|
|
61
|
-
<ViewerOptionsSizeSlider data-testid="modelPointsSizeSlider" v-model="size" />
|
|
62
|
-
</template>
|
|
24
|
+
<ModelPointsCard :itemProps="itemProps" />
|
|
63
25
|
</template>
|
|
64
26
|
</ViewerContextMenuItem>
|
|
65
27
|
</template>
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { type ComputedRef, type Ref, computed, ref, watch } from "vue";
|
|
2
|
+
import type { CollectionComponent } from "@ogw_front/stores/data_helpers/collections";
|
|
3
|
+
import { MESH_COMPONENT_TYPES } from "@ogw_front/utils/default_styles";
|
|
4
|
+
import { useDataStore } from "@ogw_front/stores/data";
|
|
5
|
+
|
|
6
|
+
interface ModelMenuMetaData {
|
|
7
|
+
modelId?: string;
|
|
8
|
+
pickedComponentId?: string;
|
|
9
|
+
viewer_type?: string;
|
|
10
|
+
modelComponentType?: string;
|
|
11
|
+
targetComponentIds?: string[];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
interface ModelMenuItemProps {
|
|
15
|
+
id: string;
|
|
16
|
+
meta_data: Record<string, unknown>;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface ModelMenuContext {
|
|
20
|
+
modelId: ComputedRef<string>;
|
|
21
|
+
componentId: ComputedRef<string | undefined>;
|
|
22
|
+
componentType: Ref<string | undefined>;
|
|
23
|
+
collections: Ref<CollectionComponent[] | undefined>;
|
|
24
|
+
targetComponentIds: Ref<string[]>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// Resolves what a model context menu targets: the whole model, a component type, a collection or one component
|
|
28
|
+
// oxlint-disable-next-line max-lines-per-function
|
|
29
|
+
function useModelMenuContext(getItemProps: () => ModelMenuItemProps): ModelMenuContext {
|
|
30
|
+
const dataStore = useDataStore();
|
|
31
|
+
// oxlint-disable-next-line no-unsafe-type-assertion -- meta_data is filled by the viewer context menu with these keys.
|
|
32
|
+
const metaData = computed(() => getItemProps().meta_data as ModelMenuMetaData);
|
|
33
|
+
|
|
34
|
+
const modelId = computed<string>(() => metaData.value.modelId ?? getItemProps().id);
|
|
35
|
+
const componentId = computed<string | undefined>(() => metaData.value.pickedComponentId);
|
|
36
|
+
const componentType = ref<string | undefined>(undefined);
|
|
37
|
+
const collections = ref<CollectionComponent[] | undefined>(undefined);
|
|
38
|
+
|
|
39
|
+
watch(
|
|
40
|
+
() => [
|
|
41
|
+
modelId.value,
|
|
42
|
+
componentId.value,
|
|
43
|
+
metaData.value.viewer_type,
|
|
44
|
+
metaData.value.modelComponentType,
|
|
45
|
+
],
|
|
46
|
+
async () => {
|
|
47
|
+
componentType.value = undefined;
|
|
48
|
+
collections.value = undefined;
|
|
49
|
+
if (metaData.value.viewer_type === "model_component_type") {
|
|
50
|
+
const { modelComponentType = "", targetComponentIds: ids = [] } = metaData.value;
|
|
51
|
+
if (MESH_COMPONENT_TYPES.includes(modelComponentType)) {
|
|
52
|
+
componentType.value = modelComponentType;
|
|
53
|
+
} else {
|
|
54
|
+
const collectionsByType = await dataStore.fetchAllCollectionComponents(modelId.value);
|
|
55
|
+
collections.value = (collectionsByType[modelComponentType] ?? []).filter((collection) =>
|
|
56
|
+
collection.children.every((child) => ids.includes(child.id)),
|
|
57
|
+
);
|
|
58
|
+
componentType.value = collections.value[0]?.children[0]?.category;
|
|
59
|
+
}
|
|
60
|
+
} else if (componentId.value !== undefined && modelId.value !== "") {
|
|
61
|
+
const currentModelId = modelId.value;
|
|
62
|
+
const currentCompId = componentId.value;
|
|
63
|
+
const type = await dataStore.meshComponentType(currentModelId, currentCompId);
|
|
64
|
+
if (
|
|
65
|
+
modelId.value === currentModelId &&
|
|
66
|
+
componentId.value === currentCompId &&
|
|
67
|
+
metaData.value.viewer_type !== "model_component_type"
|
|
68
|
+
) {
|
|
69
|
+
componentType.value = type;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
{ immediate: true },
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
const targetComponentIds = ref<string[]>([]);
|
|
77
|
+
watch(
|
|
78
|
+
() => [modelId.value, componentType.value, metaData.value.targetComponentIds],
|
|
79
|
+
async () => {
|
|
80
|
+
targetComponentIds.value = [];
|
|
81
|
+
if (metaData.value.targetComponentIds !== undefined) {
|
|
82
|
+
targetComponentIds.value = metaData.value.targetComponentIds;
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
if (componentType.value !== undefined && modelId.value !== "") {
|
|
86
|
+
const currentModelId = modelId.value;
|
|
87
|
+
const currentType = componentType.value;
|
|
88
|
+
const ids = await dataStore.getMeshComponentGeodeIds(currentModelId, currentType);
|
|
89
|
+
if (modelId.value === currentModelId && componentType.value === currentType) {
|
|
90
|
+
targetComponentIds.value = ids;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
{ immediate: true },
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
return { modelId, componentId, componentType, collections, targetComponentIds };
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export { useModelMenuContext };
|
|
101
|
+
export type { ModelMenuItemProps };
|