@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.
@@ -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: Record<string, unknown>;
23
+ itemProps: ModelMenuItemProps;
24
24
  }
25
25
 
26
26
  const { itemProps } = defineProps<Props>();
27
27
 
28
- const modelId = computed<string>(() => itemProps.meta_data.modelId || itemProps.id);
29
- const componentId = computed<string | undefined>(() => itemProps.meta_data.pickedComponentId);
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
- <ViewerOptionsVisibilitySwitch
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 };