@geode/opengeodeweb-front 10.14.1 → 10.14.2-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/.oxlintrc.json +12 -2
- package/app/components/Basic/Slider.vue +7 -0
- package/app/components/Basic/Switch.vue +7 -0
- package/app/components/HybridRenderingView.vue +1 -1
- 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/EdgedCurve/SpecificEdgesOptions.vue +5 -9
- package/app/components/Viewer/Generic/Mesh/CellsOptions.vue +7 -2
- package/app/components/Viewer/Generic/Mesh/EdgesOptions.vue +11 -9
- package/app/components/Viewer/Generic/Mesh/PointsOptions.vue +14 -9
- package/app/components/Viewer/Generic/Mesh/PolygonsOptions.vue +10 -2
- package/app/components/Viewer/Generic/Mesh/PolyhedraOptions.vue +10 -2
- package/app/components/Viewer/Generic/Model/PointsOptions.vue +2 -14
- 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/components/Viewer/Options/Sliders/Size.vue +8 -0
- package/app/components/Viewer/Options/Sliders/Slider.vue +17 -0
- package/app/components/Viewer/Options/Sliders/Width.vue +8 -0
- package/app/components/Viewer/Options/VisibilitySwitch.vue +3 -1
- package/app/components/Viewer/PointSet/SpecificPointsOptions.vue +1 -5
- package/app/components/Viewer/Surface/Triangulated/TrianglesOptions.vue +11 -0
- 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/stores/menu.js +8 -14
- package/app/utils/hybrid_viewer.js +101 -0
- package/package.json +3 -3
- package/tests/integration/setup.js +2 -1
- package/tests/integration/stores/data_style/mesh/cells.nuxt.test.js +2 -3
- package/tests/integration/stores/data_style/mesh/edges.nuxt.test.js +2 -3
- package/tests/integration/stores/data_style/mesh/index.nuxt.test.js +2 -3
- package/tests/integration/stores/data_style/mesh/points.nuxt.test.js +2 -3
- package/tests/integration/stores/data_style/mesh/polygons.nuxt.test.js +2 -3
- package/tests/integration/stores/data_style/mesh/polyhedra.nuxt.test.js +2 -3
- package/tests/integration/stores/data_style/model/blocks.nuxt.test.js +2 -3
- package/tests/integration/stores/data_style/model/corners.nuxt.test.js +2 -3
- package/tests/integration/stores/data_style/model/edges.nuxt.test.js +2 -3
- package/tests/integration/stores/data_style/model/index.nuxt.test.js +2 -3
- package/tests/integration/stores/data_style/model/lines.nuxt.test.js +2 -3
- package/tests/integration/stores/data_style/model/points.nuxt.test.js +2 -3
- package/tests/integration/stores/data_style/model/surfaces.nuxt.test.js +2 -3
- package/tests/integration/stores/viewer.nuxt.test.js +2 -2
- package/app/components/Viewer/HybridSolid/EdgesOptions.vue +0 -12
- package/app/components/Viewer/HybridSolid/PointsOptions.vue +0 -12
- package/app/components/Viewer/HybridSolid/PolygonsOptions.vue +0 -12
- package/app/components/Viewer/HybridSolid/PolyhedraOptions.vue +0 -12
- package/app/components/Viewer/PolygonalSurface/EdgesOptions.vue +0 -12
- package/app/components/Viewer/PolygonalSurface/PointsOptions.vue +0 -12
- package/app/components/Viewer/TriangulatedSurface/TrianglesOptions.vue +0 -16
- package/app/composables/use_hover_highlight.js +0 -48
- package/tests/integration/microservices/back/requirements.txt +0 -7
- package/tests/integration/microservices/viewer/requirements.txt +0 -7
- /package/app/components/Viewer/{TriangulatedSurface → Surface}/EdgesOptions.vue +0 -0
- /package/app/components/Viewer/{TriangulatedSurface → Surface}/PointsOptions.vue +0 -0
- /package/app/components/Viewer/{PolygonalSurface/SpecificPolygonsOptions.vue → Surface/PolygonsOptions.vue} +0 -0
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
+
import CommonTreeView from "@ogw_front/components/Viewer/ObjectTree/Base/CommonTreeView.vue";
|
|
2
3
|
import ObjectTreeControls from "@ogw_front/components/Viewer/ObjectTree/Base/Controls.vue";
|
|
3
4
|
import ObjectTreeItemLabel from "@ogw_front/components/Viewer/ObjectTree/Base/ItemLabel.vue";
|
|
4
5
|
import { compareSelections } from "@ogw_front/utils/treeview";
|
|
5
6
|
import { useDataStore } from "@ogw_front/stores/data";
|
|
6
7
|
import { useDataStyleStore } from "@ogw_front/stores/data_style";
|
|
7
|
-
import { useHoverhighlight } from "@ogw_front/composables/
|
|
8
|
+
import { useHoverhighlight } from "@ogw_front/composables/hover_highlight";
|
|
8
9
|
import { useHybridViewerStore } from "@ogw_front/stores/hybrid_viewer";
|
|
9
|
-
import { useTreeFilter } from "@ogw_front/composables/
|
|
10
|
+
import { useTreeFilter } from "@ogw_front/composables/tree_filter";
|
|
10
11
|
import { useTreeviewStore } from "@ogw_front/stores/treeview";
|
|
11
12
|
|
|
12
13
|
const treeviewStore = useTreeviewStore();
|
|
@@ -32,7 +33,7 @@ const {
|
|
|
32
33
|
toggleSort,
|
|
33
34
|
customFilter,
|
|
34
35
|
applySearchFilter,
|
|
35
|
-
} = useTreeFilter(
|
|
36
|
+
} = useTreeFilter(() => treeviewStore.items, { recursiveSort: true });
|
|
36
37
|
|
|
37
38
|
function onUpdateSelection(val) {
|
|
38
39
|
treeviewStore.selection = applySearchFilter(val, treeviewStore.selection);
|
|
@@ -74,18 +75,28 @@ function isModel(item) {
|
|
|
74
75
|
);
|
|
75
76
|
}
|
|
76
77
|
|
|
77
|
-
|
|
78
|
+
function handleHoverEnter({ item, immediate = false }) {
|
|
78
79
|
const actualItem = item.raw || item;
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
block_ids = await dataStore.getAllModelComponentsViewerIds(actualItem.id);
|
|
80
|
+
|
|
81
|
+
if (!actualItem.viewer_type) {
|
|
82
|
+
return;
|
|
83
83
|
}
|
|
84
|
-
|
|
84
|
+
|
|
85
|
+
const is_model = isModel(item);
|
|
86
|
+
|
|
87
|
+
onHoverEnter(
|
|
88
|
+
actualItem.id,
|
|
89
|
+
async () => (is_model ? await dataStore.getAllModelComponentsViewerIds(actualItem.id) : []),
|
|
90
|
+
is_model ? "model" : "mesh",
|
|
91
|
+
immediate,
|
|
92
|
+
);
|
|
85
93
|
}
|
|
86
94
|
|
|
87
|
-
function handleHoverLeave(item) {
|
|
95
|
+
function handleHoverLeave({ item }) {
|
|
88
96
|
const actualItem = item.raw || item;
|
|
97
|
+
if (!actualItem.viewer_type) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
89
100
|
onHoverLeave(actualItem.id);
|
|
90
101
|
}
|
|
91
102
|
</script>
|
|
@@ -98,26 +109,29 @@ function handleHoverLeave(item) {
|
|
|
98
109
|
:filter-options="filterOptions"
|
|
99
110
|
:available-filter-options="availableFilterOptions"
|
|
100
111
|
@toggle-sort="toggleSort"
|
|
112
|
+
@collapse-all="opened = []"
|
|
101
113
|
/>
|
|
102
114
|
|
|
103
|
-
<
|
|
115
|
+
<CommonTreeView
|
|
104
116
|
:selected="visibleSelection"
|
|
105
117
|
v-model:opened="opened"
|
|
106
118
|
:items="processedItems"
|
|
107
|
-
:
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
119
|
+
:options="{
|
|
120
|
+
selection: { selectable: true },
|
|
121
|
+
search,
|
|
122
|
+
customFilter,
|
|
123
|
+
}"
|
|
124
|
+
:scroll-top="mainView?.scrollTop || 0"
|
|
125
|
+
class="transparent-treeview virtual-tree-height"
|
|
114
126
|
@update:selected="onUpdateSelection"
|
|
127
|
+
@update:scroll-top="treeviewStore.setScrollTop(mainView.id, $event)"
|
|
128
|
+
@hover:enter="handleHoverEnter"
|
|
129
|
+
@hover:leave="handleHoverLeave"
|
|
115
130
|
>
|
|
116
|
-
<template #title="{ item }">
|
|
131
|
+
<template #title="{ item, isLeaf }">
|
|
117
132
|
<ObjectTreeItemLabel
|
|
118
133
|
:item="item"
|
|
119
|
-
|
|
120
|
-
@mouseleave="handleHoverLeave(item)"
|
|
134
|
+
:is-leaf="isLeaf"
|
|
121
135
|
@contextmenu="emit('show-menu', { event: $event, itemId: item.id })"
|
|
122
136
|
/>
|
|
123
137
|
</template>
|
|
@@ -135,25 +149,26 @@ function handleHoverLeave(item) {
|
|
|
135
149
|
"
|
|
136
150
|
/>
|
|
137
151
|
</template>
|
|
138
|
-
</
|
|
152
|
+
</CommonTreeView>
|
|
139
153
|
</div>
|
|
140
154
|
</template>
|
|
141
155
|
|
|
142
156
|
<style scoped>
|
|
143
|
-
.
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
:
|
|
149
|
-
transition: background-color 0.2s ease;
|
|
157
|
+
.tree-view-container {
|
|
158
|
+
height: 100%;
|
|
159
|
+
display: flex;
|
|
160
|
+
flex-direction: column;
|
|
161
|
+
overflow: hidden;
|
|
162
|
+
min-height: 0;
|
|
150
163
|
}
|
|
151
164
|
|
|
152
|
-
|
|
153
|
-
|
|
165
|
+
.virtual-tree-height {
|
|
166
|
+
flex-grow: 1;
|
|
167
|
+
min-height: 0;
|
|
154
168
|
}
|
|
155
169
|
|
|
156
|
-
|
|
157
|
-
|
|
170
|
+
.transparent-treeview {
|
|
171
|
+
background-color: transparent;
|
|
172
|
+
margin: 4px 0;
|
|
158
173
|
}
|
|
159
174
|
</style>
|
|
@@ -1,85 +1,113 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
+
import { sortAndFormatItems, useTreeFilter } from "@ogw_front/composables/tree_filter";
|
|
3
|
+
import CommonTreeView from "@ogw_front/components/Viewer/ObjectTree/Base/CommonTreeView.vue";
|
|
2
4
|
import FetchingData from "@ogw_front/components/FetchingData.vue";
|
|
3
5
|
import ObjectTreeControls from "@ogw_front/components/Viewer/ObjectTree/Base/Controls.vue";
|
|
4
6
|
import ObjectTreeItemLabel from "@ogw_front/components/Viewer/ObjectTree/Base/ItemLabel.vue";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { useDataStyleStore } from "@ogw_front/stores/data_style";
|
|
8
|
-
import { useHoverhighlight } from "@ogw_front/composables/use_hover_highlight";
|
|
9
|
-
import { useHybridViewerStore } from "@ogw_front/stores/hybrid_viewer";
|
|
10
|
-
import { useTreeFilter } from "@ogw_front/composables/use_tree_filter";
|
|
7
|
+
import { useHoverhighlight } from "@ogw_front/composables/hover_highlight";
|
|
8
|
+
import { useModelComponents } from "@ogw_front/composables/model_components";
|
|
11
9
|
import { useTreeviewStore } from "@ogw_front/stores/treeview";
|
|
12
10
|
|
|
13
|
-
const { id
|
|
11
|
+
const { id } = defineProps({ id: { type: String, required: true } });
|
|
14
12
|
const { onHoverEnter, onHoverLeave } = useHoverhighlight();
|
|
15
13
|
const emit = defineEmits(["show-menu"]);
|
|
16
14
|
|
|
17
|
-
const dataStore = useDataStore();
|
|
18
|
-
const dataStyleStore = useDataStyleStore();
|
|
19
|
-
const hybridViewerStore = useHybridViewerStore();
|
|
20
15
|
const treeviewStore = useTreeviewStore();
|
|
16
|
+
const {
|
|
17
|
+
items: rawItems,
|
|
18
|
+
componentsCache,
|
|
19
|
+
localCategories,
|
|
20
|
+
selection: visibleComponents,
|
|
21
|
+
updateVisibility,
|
|
22
|
+
} = useModelComponents(id);
|
|
23
|
+
|
|
24
|
+
const currentView = computed(() => treeviewStore.opened_views.find((view) => view.id === id));
|
|
21
25
|
|
|
22
|
-
const currentView = computed(() => treeviewStore.opened_views.find((view) => view.id === viewId));
|
|
23
26
|
const opened = computed({
|
|
24
27
|
get: () => currentView.value?.opened || [],
|
|
25
|
-
set: (val) => treeviewStore.setOpened(
|
|
28
|
+
set: (val) => treeviewStore.setOpened(id, val),
|
|
26
29
|
});
|
|
27
30
|
|
|
28
|
-
const items = dataStore.refFormatedMeshComponents(viewId);
|
|
29
|
-
const mesh_components_selection = dataStyleStore.visibleMeshComponents(viewId);
|
|
30
|
-
|
|
31
31
|
const {
|
|
32
32
|
search,
|
|
33
33
|
sortType,
|
|
34
34
|
filterOptions,
|
|
35
|
-
processedItems,
|
|
35
|
+
processedItems: filteredCategories,
|
|
36
36
|
availableFilterOptions,
|
|
37
37
|
toggleSort,
|
|
38
38
|
customFilter,
|
|
39
39
|
applySearchFilter,
|
|
40
|
-
} = useTreeFilter(
|
|
40
|
+
} = useTreeFilter(localCategories);
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
function onUpdateSelection(newSelection) {
|
|
43
|
+
const finalSelection = applySearchFilter(newSelection, visibleComponents.value);
|
|
44
|
+
updateVisibility(finalSelection);
|
|
45
|
+
}
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
const visibleSelection = computed(() => applySearchFilter(visibleComponents.value, []));
|
|
48
|
+
|
|
49
|
+
const itemsForTreeView = computed(() => {
|
|
50
|
+
if (search.value && componentsCache.value) {
|
|
51
|
+
const query = search.value.toLowerCase();
|
|
52
|
+
const result = [];
|
|
53
|
+
for (const type of Object.keys(componentsCache.value)) {
|
|
54
|
+
const matches = componentsCache.value[type].filter(
|
|
55
|
+
(component) =>
|
|
56
|
+
component.title.toLowerCase().includes(query) ||
|
|
57
|
+
component.id.toLowerCase().includes(query),
|
|
58
|
+
);
|
|
59
|
+
if (matches.length > 0) {
|
|
60
|
+
result.push({
|
|
61
|
+
id: type,
|
|
62
|
+
title: `${type}s (${matches.length})`,
|
|
63
|
+
children: sortAndFormatItems(matches, sortType.value),
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return result;
|
|
49
68
|
}
|
|
50
69
|
|
|
51
|
-
|
|
52
|
-
|
|
70
|
+
const result = [];
|
|
71
|
+
for (const category of filteredCategories.value) {
|
|
72
|
+
result.push({
|
|
73
|
+
...category,
|
|
74
|
+
children: sortAndFormatItems(componentsCache.value?.[category.id], sortType.value),
|
|
75
|
+
});
|
|
53
76
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
hybridViewerStore.remoteRender();
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const visibleSelection = computed(() => applySearchFilter(mesh_components_selection.value, []));
|
|
77
|
+
return result;
|
|
78
|
+
});
|
|
61
79
|
|
|
62
80
|
function showContextMenu(event, item) {
|
|
63
81
|
const actualItem = item.raw || item;
|
|
64
82
|
emit("show-menu", {
|
|
65
83
|
event,
|
|
66
|
-
itemId: actualItem.category ? actualItem.id :
|
|
84
|
+
itemId: actualItem.category ? actualItem.id : id,
|
|
67
85
|
context_type: actualItem.category ? "model_component" : "model_component_type",
|
|
68
|
-
modelId:
|
|
86
|
+
modelId: id,
|
|
69
87
|
modelComponentType: actualItem.category ? undefined : actualItem.id,
|
|
70
88
|
});
|
|
71
89
|
}
|
|
72
90
|
|
|
73
|
-
function handleHoverEnter(item) {
|
|
91
|
+
function handleHoverEnter({ item, immediate = false }) {
|
|
74
92
|
const actualItem = item.raw || item;
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
93
|
+
|
|
94
|
+
if (!actualItem.category && (!actualItem.children || actualItem.children.length === 0)) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
onHoverEnter(
|
|
99
|
+
id,
|
|
100
|
+
() =>
|
|
101
|
+
actualItem.category
|
|
102
|
+
? [actualItem.viewer_id]
|
|
103
|
+
: actualItem.children?.map((child) => child.viewer_id) || [],
|
|
104
|
+
"model",
|
|
105
|
+
immediate,
|
|
106
|
+
);
|
|
79
107
|
}
|
|
80
108
|
|
|
81
109
|
function handleHoverLeave() {
|
|
82
|
-
onHoverLeave(
|
|
110
|
+
onHoverLeave(id);
|
|
83
111
|
}
|
|
84
112
|
</script>
|
|
85
113
|
|
|
@@ -91,52 +119,60 @@ function handleHoverLeave() {
|
|
|
91
119
|
:filter-options="filterOptions"
|
|
92
120
|
:available-filter-options="availableFilterOptions"
|
|
93
121
|
@toggle-sort="toggleSort"
|
|
122
|
+
@collapse-all="opened = []"
|
|
94
123
|
/>
|
|
95
124
|
|
|
96
|
-
<FetchingData v-if="
|
|
125
|
+
<FetchingData v-if="rawItems === undefined" :size="48" :width="4" text="" />
|
|
97
126
|
|
|
98
|
-
<
|
|
99
|
-
v-else
|
|
127
|
+
<CommonTreeView
|
|
100
128
|
:selected="visibleSelection"
|
|
101
129
|
v-model:opened="opened"
|
|
102
|
-
:items="
|
|
103
|
-
:
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
@update:selected="
|
|
130
|
+
:items="itemsForTreeView"
|
|
131
|
+
:options="{
|
|
132
|
+
selection: { selectable: true, strategy: 'classic' },
|
|
133
|
+
search,
|
|
134
|
+
customFilter,
|
|
135
|
+
}"
|
|
136
|
+
:scroll-top="currentView?.scrollTop || 0"
|
|
137
|
+
class="transparent-treeview virtual-tree-height"
|
|
138
|
+
@update:selected="onUpdateSelection"
|
|
139
|
+
@click:item="onUpdateSelection([$event.id, ...visibleComponents])"
|
|
140
|
+
@update:scroll-top="treeviewStore.setScrollTop(id, $event)"
|
|
141
|
+
@hover:enter="handleHoverEnter"
|
|
142
|
+
@hover:leave="handleHoverLeave"
|
|
111
143
|
>
|
|
112
|
-
<template #title="{ item }">
|
|
144
|
+
<template #title="{ item, isLeaf }">
|
|
113
145
|
<ObjectTreeItemLabel
|
|
114
146
|
:item="item"
|
|
147
|
+
:is-leaf="isLeaf"
|
|
115
148
|
show-tooltip
|
|
116
|
-
|
|
117
|
-
@
|
|
118
|
-
@contextmenu="showContextMenu($event, item)"
|
|
149
|
+
class="text-body-1"
|
|
150
|
+
@contextmenu.prevent.stop="showContextMenu($event, item)"
|
|
119
151
|
/>
|
|
120
152
|
</template>
|
|
121
|
-
</
|
|
153
|
+
</CommonTreeView>
|
|
122
154
|
</div>
|
|
123
155
|
</template>
|
|
124
156
|
|
|
125
157
|
<style scoped>
|
|
126
|
-
.
|
|
127
|
-
|
|
128
|
-
|
|
158
|
+
.tree-view-container {
|
|
159
|
+
height: 100%;
|
|
160
|
+
display: flex;
|
|
161
|
+
flex-direction: column;
|
|
162
|
+
overflow: hidden;
|
|
163
|
+
min-height: 0;
|
|
129
164
|
}
|
|
130
165
|
|
|
131
|
-
|
|
132
|
-
|
|
166
|
+
.virtual-tree-height {
|
|
167
|
+
flex-grow: 1;
|
|
168
|
+
min-height: 0;
|
|
133
169
|
}
|
|
134
170
|
|
|
135
|
-
|
|
136
|
-
|
|
171
|
+
.transparent-treeview {
|
|
172
|
+
background-color: transparent;
|
|
137
173
|
}
|
|
138
174
|
|
|
139
|
-
:deep(.v-list-
|
|
140
|
-
|
|
175
|
+
:deep(.v-list-item__overlay) {
|
|
176
|
+
display: none !important;
|
|
141
177
|
}
|
|
142
178
|
</style>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import BasicSlider from "@ogw_front/components/Basic/Slider";
|
|
3
|
+
|
|
4
|
+
const model = defineModel();
|
|
5
|
+
const { tooltip } = defineProps({
|
|
6
|
+
tooltip: { type: String, required: true },
|
|
7
|
+
});
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<template>
|
|
11
|
+
<v-col cols="auto" justify="center">
|
|
12
|
+
<v-icon size="30" icon="mdi-ruler" v-tooltip:left="tooltip" />
|
|
13
|
+
</v-col>
|
|
14
|
+
<v-col justify="center">
|
|
15
|
+
<BasicSlider v-model="model" />
|
|
16
|
+
</v-col>
|
|
17
|
+
</template>
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
<script setup>
|
|
2
|
+
import BasicSwitch from "@ogw_front/components/Basic/Switch";
|
|
3
|
+
|
|
2
4
|
const visibility = defineModel();
|
|
3
5
|
</script>
|
|
4
6
|
|
|
@@ -8,7 +10,7 @@ const visibility = defineModel();
|
|
|
8
10
|
<v-icon size="30" icon="mdi-eye" v-tooltip:left="'Visibility'" />
|
|
9
11
|
</v-col>
|
|
10
12
|
<v-col cols="auto" justify="center">
|
|
11
|
-
<
|
|
13
|
+
<BasicSwitch v-model="visibility" />
|
|
12
14
|
</v-col>
|
|
13
15
|
</v-row>
|
|
14
16
|
</template>
|
|
@@ -67,11 +67,7 @@ const vertex_attribute_color_map = computed({
|
|
|
67
67
|
});
|
|
68
68
|
</script>
|
|
69
69
|
<template>
|
|
70
|
-
<ViewerContextMenuItem
|
|
71
|
-
:itemProps="itemProps"
|
|
72
|
-
tooltip="Points options"
|
|
73
|
-
:btn_image="PointSetPoints"
|
|
74
|
-
>
|
|
70
|
+
<ViewerContextMenuItem :itemProps="itemProps" :btn_image="PointSetPoints">
|
|
75
71
|
<template #options>
|
|
76
72
|
<ViewerOptionsVisibilitySwitch v-model="visibility" />
|
|
77
73
|
<template v-if="visibility">
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import ViewerSpecificPolygonsOptions from "@ogw_front/components/Viewer/Surface/PolygonsOptions";
|
|
3
|
+
|
|
4
|
+
const { itemProps } = defineProps({
|
|
5
|
+
itemProps: { type: Object, required: true },
|
|
6
|
+
});
|
|
7
|
+
</script>
|
|
8
|
+
|
|
9
|
+
<template>
|
|
10
|
+
<ViewerSpecificPolygonsOptions :itemProps="itemProps" tooltip="Triangles options" />
|
|
11
|
+
</template>
|
|
@@ -0,0 +1,85 @@
|
|
|
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 = 200;
|
|
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_provider = [], type = "model", immediate = false) {
|
|
13
|
+
if (timer) {
|
|
14
|
+
clearTimeout(timer);
|
|
15
|
+
timer = undefined;
|
|
16
|
+
}
|
|
17
|
+
const schema = vtk_schemas.opengeodeweb_viewer[type].highlight;
|
|
18
|
+
|
|
19
|
+
async function highlightAction() {
|
|
20
|
+
currentId = id;
|
|
21
|
+
currentType = type;
|
|
22
|
+
|
|
23
|
+
let block_ids = [];
|
|
24
|
+
if (typeof block_ids_provider === "function") {
|
|
25
|
+
block_ids = await block_ids_provider();
|
|
26
|
+
} else {
|
|
27
|
+
block_ids = block_ids_provider;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
block_ids = (Array.isArray(block_ids) ? block_ids : [])
|
|
31
|
+
.map((blockId) => Number.parseInt(blockId, 10))
|
|
32
|
+
.filter((blockId) => !Number.isNaN(blockId));
|
|
33
|
+
|
|
34
|
+
if (currentId !== id) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const params = {
|
|
39
|
+
id,
|
|
40
|
+
visibility: true,
|
|
41
|
+
...(type === "model" && { block_ids }),
|
|
42
|
+
};
|
|
43
|
+
try {
|
|
44
|
+
await viewerStore.request(schema, params);
|
|
45
|
+
} catch (error) {
|
|
46
|
+
console.error(`Highlight failed for ${type} ${id}:`, error);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (immediate) {
|
|
51
|
+
highlightAction();
|
|
52
|
+
} else {
|
|
53
|
+
timer = setTimeout(highlightAction, HOVER_DELAY);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function onHoverLeave(id) {
|
|
58
|
+
if (timer) {
|
|
59
|
+
clearTimeout(timer);
|
|
60
|
+
timer = undefined;
|
|
61
|
+
}
|
|
62
|
+
if (currentId === id) {
|
|
63
|
+
const schema = vtk_schemas.opengeodeweb_viewer[currentType].highlight;
|
|
64
|
+
const params = {
|
|
65
|
+
id,
|
|
66
|
+
visibility: false,
|
|
67
|
+
...(currentType === "model" && { block_ids: [] }),
|
|
68
|
+
};
|
|
69
|
+
try {
|
|
70
|
+
viewerStore.request(schema, params);
|
|
71
|
+
} catch (error) {
|
|
72
|
+
console.error(`Unhighlight failed for ${currentType} ${id}:`, error);
|
|
73
|
+
}
|
|
74
|
+
currentId = undefined;
|
|
75
|
+
currentType = undefined;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (!currentId) {
|
|
79
|
+
currentId = undefined;
|
|
80
|
+
currentType = undefined;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return { onHoverEnter, onHoverLeave };
|
|
85
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { compareSelections } from "@ogw_front/utils/treeview";
|
|
2
|
+
import { useDataStore } from "@ogw_front/stores/data";
|
|
3
|
+
import { useDataStyleStore } from "@ogw_front/stores/data_style";
|
|
4
|
+
import { useHybridViewerStore } from "@ogw_front/stores/hybrid_viewer";
|
|
5
|
+
|
|
6
|
+
export function useModelComponents(viewId) {
|
|
7
|
+
const dataStore = useDataStore();
|
|
8
|
+
const dataStyleStore = useDataStyleStore();
|
|
9
|
+
const hybridViewerStore = useHybridViewerStore();
|
|
10
|
+
|
|
11
|
+
const items = dataStore.refFormatedMeshComponents(viewId);
|
|
12
|
+
const componentsCache = ref(undefined);
|
|
13
|
+
const localCategories = ref([]);
|
|
14
|
+
|
|
15
|
+
onMounted(async () => {
|
|
16
|
+
const data = await dataStore.fetchAllMeshComponents(viewId);
|
|
17
|
+
componentsCache.value = markRaw(data);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
watch(
|
|
21
|
+
items,
|
|
22
|
+
(newItems) => {
|
|
23
|
+
if (!newItems) {
|
|
24
|
+
localCategories.value = [];
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
localCategories.value = newItems.map((newCategory) => {
|
|
28
|
+
const existing = localCategories.value.find((category) => category.id === newCategory.id);
|
|
29
|
+
if (existing) {
|
|
30
|
+
existing.title = newCategory.title || newCategory.id;
|
|
31
|
+
return existing;
|
|
32
|
+
}
|
|
33
|
+
return reactive({
|
|
34
|
+
...newCategory,
|
|
35
|
+
title: newCategory.title || newCategory.id,
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
},
|
|
39
|
+
{ immediate: true },
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
const selection = dataStyleStore.visibleMeshComponents(viewId);
|
|
43
|
+
|
|
44
|
+
async function updateVisibility(current) {
|
|
45
|
+
const previous = selection.value;
|
|
46
|
+
const { added, removed } = compareSelections(current, previous);
|
|
47
|
+
|
|
48
|
+
if (added.length === 0 && removed.length === 0) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (added.length > 0) {
|
|
53
|
+
await dataStyleStore.setModelComponentsVisibility(viewId, added, true);
|
|
54
|
+
}
|
|
55
|
+
if (removed.length > 0) {
|
|
56
|
+
await dataStyleStore.setModelComponentsVisibility(viewId, removed, false);
|
|
57
|
+
}
|
|
58
|
+
hybridViewerStore.remoteRender();
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return {
|
|
62
|
+
items,
|
|
63
|
+
componentsCache,
|
|
64
|
+
localCategories,
|
|
65
|
+
selection,
|
|
66
|
+
updateVisibility,
|
|
67
|
+
};
|
|
68
|
+
}
|