@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
package/.oxlintrc.json
CHANGED
|
@@ -92,6 +92,12 @@
|
|
|
92
92
|
"ignore": [-1, 0, 1, 2, 3, 4],
|
|
93
93
|
"ignoreArrayIndexes": true
|
|
94
94
|
}
|
|
95
|
+
],
|
|
96
|
+
"eslint/no-underscore-dangle": [
|
|
97
|
+
"error",
|
|
98
|
+
{
|
|
99
|
+
"allow": ["_data", "__dirname", "__VEASE_UTILS__", "__VEASE_STORES__", "__VEASE_SCHEMAS__"]
|
|
100
|
+
}
|
|
95
101
|
]
|
|
96
102
|
},
|
|
97
103
|
"overrides": [
|
|
@@ -117,6 +123,7 @@
|
|
|
117
123
|
"rules": {
|
|
118
124
|
"vitest/require-hook": "off",
|
|
119
125
|
"vitest/no-hooks": "off",
|
|
126
|
+
"jest/no-hooks": "off",
|
|
120
127
|
"vitest/no-importing-vitest-globals": "off",
|
|
121
128
|
"max-lines-per-function": "off",
|
|
122
129
|
"max-statements": "off",
|
|
@@ -124,8 +131,11 @@
|
|
|
124
131
|
"vitest/prefer-to-be-falsy": "off",
|
|
125
132
|
"vitest/require-test-timeout": "warn",
|
|
126
133
|
"vitest/prefer-importing-vitest-globals": "off",
|
|
127
|
-
"jest/consistent-test-it":
|
|
128
|
-
"vitest/
|
|
134
|
+
"jest/consistent-test-it": "off",
|
|
135
|
+
"vitest/consistent-test-it": ["error", { "fn": "test", "withinDescribe": "test" }],
|
|
136
|
+
"vitest/prefer-spy-on": "off",
|
|
137
|
+
"vitest/prefer-expect-assertions": "off",
|
|
138
|
+
"jest/prefer-expect-assertions": "off"
|
|
129
139
|
}
|
|
130
140
|
},
|
|
131
141
|
{
|
|
@@ -46,7 +46,7 @@ function debounce(func, wait) {
|
|
|
46
46
|
|
|
47
47
|
<template>
|
|
48
48
|
<ClientOnly>
|
|
49
|
-
<div class="fill-height" style="position: relative; height: 100%">
|
|
49
|
+
<div data-testid="hybridViewer" class="fill-height" style="position: relative; height: 100%">
|
|
50
50
|
<VeaseViewToolbar />
|
|
51
51
|
<slot name="ui"></slot>
|
|
52
52
|
<v-col
|
|
@@ -4,7 +4,6 @@ import { useMenuStore } from "@ogw_front/stores/menu";
|
|
|
4
4
|
|
|
5
5
|
const RADIUS = 80;
|
|
6
6
|
const MARGIN_OFFSET = 40;
|
|
7
|
-
const Z_INDEX_MENU = 1000;
|
|
8
7
|
const Z_INDEX_ACTIVE_ITEM = 10;
|
|
9
8
|
const Z_INDEX_BASE_ITEM = 1;
|
|
10
9
|
const FULL_ANGLE = 360;
|
|
@@ -34,7 +33,7 @@ const menuX = ref(x);
|
|
|
34
33
|
const menuY = ref(y);
|
|
35
34
|
|
|
36
35
|
watch(
|
|
37
|
-
() => [x, y],
|
|
36
|
+
() => [x, y, containerWidth, containerHeight],
|
|
38
37
|
([newX, newY]) => {
|
|
39
38
|
const { x: clampedX, y: clampedY } = clampPosition(newX, newY);
|
|
40
39
|
menuX.value = clampedX;
|
|
@@ -110,7 +109,6 @@ function getMenuStyle() {
|
|
|
110
109
|
position: "fixed",
|
|
111
110
|
left: `${menuStore.containerLeft + menuX.value - RADIUS}px`,
|
|
112
111
|
top: `${menuStore.containerTop + menuY.value - RADIUS}px`,
|
|
113
|
-
zIndex: Z_INDEX_MENU,
|
|
114
112
|
};
|
|
115
113
|
}
|
|
116
114
|
|
|
@@ -29,7 +29,7 @@ const optionsStyle = computed(() => {
|
|
|
29
29
|
if (!is_active.value || !optionsHeight.value) {
|
|
30
30
|
return {};
|
|
31
31
|
}
|
|
32
|
-
const angle = (
|
|
32
|
+
const angle = (index / itemProps.totalItems) * 2 * Math.PI;
|
|
33
33
|
const radius = RADIUS;
|
|
34
34
|
const absoluteButtonY = menuStore.menuY + Math.sin(angle) * radius;
|
|
35
35
|
const height = optionsHeight.value;
|
|
@@ -89,7 +89,6 @@ function toggleOptions() {
|
|
|
89
89
|
>
|
|
90
90
|
<GlassCard
|
|
91
91
|
@click.stop
|
|
92
|
-
:title="tooltip"
|
|
93
92
|
width="320"
|
|
94
93
|
:max-height="maxCardHeight"
|
|
95
94
|
:ripple="false"
|
|
@@ -98,6 +97,7 @@ function toggleOptions() {
|
|
|
98
97
|
class="elevation-24"
|
|
99
98
|
style="overflow: hidden; display: flex; flex-direction: column"
|
|
100
99
|
>
|
|
100
|
+
<v-card-title>{{ tooltip }}</v-card-title>
|
|
101
101
|
<v-card-text class="pa-5" style="overflow-y: auto; flex: 1; min-height: 0">
|
|
102
102
|
<slot name="options" />
|
|
103
103
|
</v-card-text>
|
|
@@ -3,6 +3,7 @@ import EdgedCurveEdges from "@ogw_front/assets/viewer_svgs/edged_curve_edges.svg
|
|
|
3
3
|
import ViewerContextMenuItem from "@ogw_front/components/Viewer/ContextMenuItem";
|
|
4
4
|
import ViewerOptionsColoringTypeSelector from "@ogw_front/components/Viewer/Options/ColoringTypeSelector";
|
|
5
5
|
import ViewerOptionsVisibilitySwitch from "@ogw_front/components/Viewer/Options/VisibilitySwitch";
|
|
6
|
+
import ViewerOptionsWidthSlider from "@ogw_front/components/Viewer/Options/Sliders/Width";
|
|
6
7
|
|
|
7
8
|
import { useDataStyleStore } from "@ogw_front/stores/data_style";
|
|
8
9
|
import { useHybridViewerStore } from "@ogw_front/stores/hybrid_viewer";
|
|
@@ -23,7 +24,7 @@ const visibility = computed({
|
|
|
23
24
|
hybridViewerStore.remoteRender();
|
|
24
25
|
},
|
|
25
26
|
});
|
|
26
|
-
const
|
|
27
|
+
const width = computed({
|
|
27
28
|
get: () => dataStyleStore.meshEdgesWidth(id.value),
|
|
28
29
|
set: async (newValue) => {
|
|
29
30
|
await dataStyleStore.setMeshEdgesWidth(id.value, newValue);
|
|
@@ -90,20 +91,15 @@ const edge_attribute_color_map = computed({
|
|
|
90
91
|
<template>
|
|
91
92
|
<ViewerContextMenuItem
|
|
92
93
|
:itemProps="itemProps"
|
|
93
|
-
tooltip="Edges options"
|
|
94
94
|
:btn_image="EdgedCurveEdges"
|
|
95
|
+
tooltip="Edges options"
|
|
95
96
|
>
|
|
96
97
|
<template #options>
|
|
97
|
-
<ViewerOptionsVisibilitySwitch v-model="visibility" />
|
|
98
|
+
<ViewerOptionsVisibilitySwitch data-testid="meshEdgesVisibilitySwitch" v-model="visibility" />
|
|
98
99
|
<template v-if="visibility">
|
|
99
100
|
<v-row class="pa-0" align="center">
|
|
100
101
|
<v-divider />
|
|
101
|
-
<v-
|
|
102
|
-
<v-icon size="30" icon="mdi-ruler" v-tooltip:left="'Width'" />
|
|
103
|
-
</v-col>
|
|
104
|
-
<v-col justify="center">
|
|
105
|
-
<v-slider v-model="size" hide-details min="0" max="20" step="2" />
|
|
106
|
-
</v-col>
|
|
102
|
+
<ViewerOptionsWidthSlider v-model="width" />
|
|
107
103
|
</v-row>
|
|
108
104
|
<v-row>
|
|
109
105
|
<v-col>
|
|
@@ -90,9 +90,14 @@ const cell_attribute_color_map = computed({
|
|
|
90
90
|
</script>
|
|
91
91
|
|
|
92
92
|
<template>
|
|
93
|
-
<ViewerContextMenuItem
|
|
93
|
+
<ViewerContextMenuItem
|
|
94
|
+
data-testid="meshCellsMenu"
|
|
95
|
+
:itemProps="itemProps"
|
|
96
|
+
:tooltip="tooltip"
|
|
97
|
+
:btn_image="btn_image"
|
|
98
|
+
>
|
|
94
99
|
<template #options>
|
|
95
|
-
<ViewerOptionsVisibilitySwitch v-model="visibility" />
|
|
100
|
+
<ViewerOptionsVisibilitySwitch data-testid="meshCellsVisibilitySwitch" v-model="visibility" />
|
|
96
101
|
<template v-if="visibility">
|
|
97
102
|
<ViewerOptionsColoringTypeSelector
|
|
98
103
|
:id="id"
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import ViewerContextMenuItem from "@ogw_front/components/Viewer/ContextMenuItem";
|
|
3
3
|
import ViewerOptionsColoringTypeSelector from "@ogw_front/components/Viewer/Options/ColoringTypeSelector";
|
|
4
4
|
import ViewerOptionsVisibilitySwitch from "@ogw_front/components/Viewer/Options/VisibilitySwitch";
|
|
5
|
+
import ViewerOptionsWidthSlider from "@ogw_front/components/Viewer/Options/Sliders/Width";
|
|
5
6
|
|
|
6
7
|
import { useDataStyleStore } from "@ogw_front/stores/data_style";
|
|
7
8
|
import { useHybridViewerStore } from "@ogw_front/stores/hybrid_viewer";
|
|
@@ -9,9 +10,10 @@ import { useHybridViewerStore } from "@ogw_front/stores/hybrid_viewer";
|
|
|
9
10
|
const dataStyleStore = useDataStyleStore();
|
|
10
11
|
const hybridViewerStore = useHybridViewerStore();
|
|
11
12
|
|
|
12
|
-
const { itemProps, btn_image } = defineProps({
|
|
13
|
+
const { itemProps, btn_image, tooltip } = defineProps({
|
|
13
14
|
itemProps: { type: Object, required: true },
|
|
14
15
|
btn_image: { type: String, required: true },
|
|
16
|
+
tooltip: { type: String, required: false, default: "Edges options" },
|
|
15
17
|
});
|
|
16
18
|
|
|
17
19
|
const id = toRef(() => itemProps.id);
|
|
@@ -89,18 +91,18 @@ const edge_attribute_color_map = computed({
|
|
|
89
91
|
</script>
|
|
90
92
|
|
|
91
93
|
<template>
|
|
92
|
-
<ViewerContextMenuItem
|
|
94
|
+
<ViewerContextMenuItem
|
|
95
|
+
data-testid="meshEdgesMenu"
|
|
96
|
+
:itemProps="itemProps"
|
|
97
|
+
:tooltip="tooltip"
|
|
98
|
+
:btn_image="btn_image"
|
|
99
|
+
>
|
|
93
100
|
<template #options>
|
|
94
|
-
<ViewerOptionsVisibilitySwitch v-model="visibility" />
|
|
101
|
+
<ViewerOptionsVisibilitySwitch data-testid="meshEdgesVisibilitySwitch" v-model="visibility" />
|
|
95
102
|
<template v-if="visibility">
|
|
96
103
|
<v-row class="pa-0" align="center">
|
|
97
104
|
<v-divider />
|
|
98
|
-
<
|
|
99
|
-
<v-icon size="30" icon="mdi-ruler" v-tooltip:left="'Width'" />
|
|
100
|
-
</v-col>
|
|
101
|
-
<v-col justify="center">
|
|
102
|
-
<v-slider v-model="size" hide-details min="0" max="20" step="2" />
|
|
103
|
-
</v-col>
|
|
105
|
+
<ViewerOptionsWidthSlider data-testid="meshEdgesWidthSlider" v-model="size" />
|
|
104
106
|
</v-row>
|
|
105
107
|
<v-row>
|
|
106
108
|
<v-col>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import ViewerContextMenuItem from "@ogw_front/components/Viewer/ContextMenuItem";
|
|
3
3
|
import ViewerOptionsColoringTypeSelector from "@ogw_front/components/Viewer/Options/ColoringTypeSelector";
|
|
4
|
+
import ViewerOptionsSizeSlider from "@ogw_front/components/Viewer/Options/Sliders/Size";
|
|
4
5
|
import ViewerOptionsVisibilitySwitch from "@ogw_front/components/Viewer/Options/VisibilitySwitch";
|
|
5
6
|
|
|
6
7
|
import { useDataStyleStore } from "@ogw_front/stores/data_style";
|
|
@@ -9,9 +10,10 @@ import { useHybridViewerStore } from "@ogw_front/stores/hybrid_viewer";
|
|
|
9
10
|
const dataStyleStore = useDataStyleStore();
|
|
10
11
|
const hybridViewerStore = useHybridViewerStore();
|
|
11
12
|
|
|
12
|
-
const { itemProps, btn_image } = defineProps({
|
|
13
|
+
const { itemProps, btn_image, tooltip } = defineProps({
|
|
13
14
|
itemProps: { type: Object, required: true },
|
|
14
15
|
btn_image: { type: String, required: true },
|
|
16
|
+
tooltip: { type: String, required: false, default: "Points options" },
|
|
15
17
|
});
|
|
16
18
|
|
|
17
19
|
const id = toRef(() => itemProps.id);
|
|
@@ -68,18 +70,21 @@ const vertex_attribute_color_map = computed({
|
|
|
68
70
|
</script>
|
|
69
71
|
|
|
70
72
|
<template>
|
|
71
|
-
<ViewerContextMenuItem
|
|
73
|
+
<ViewerContextMenuItem
|
|
74
|
+
data-testid="meshPointsMenu"
|
|
75
|
+
:itemProps="itemProps"
|
|
76
|
+
:tooltip="tooltip"
|
|
77
|
+
:btn_image="btn_image"
|
|
78
|
+
>
|
|
72
79
|
<template #options>
|
|
73
|
-
<ViewerOptionsVisibilitySwitch
|
|
80
|
+
<ViewerOptionsVisibilitySwitch
|
|
81
|
+
data-testid="meshPointsVisibilitySwitch"
|
|
82
|
+
v-model="visibility"
|
|
83
|
+
/>
|
|
74
84
|
<template v-if="visibility">
|
|
75
85
|
<v-row class="pa-0" align="center">
|
|
76
86
|
<v-divider />
|
|
77
|
-
<
|
|
78
|
-
<v-icon size="30" icon="mdi-ruler" v-tooltip:left="'Size'" />
|
|
79
|
-
</v-col>
|
|
80
|
-
<v-col justify="center">
|
|
81
|
-
<v-slider v-model="size" hide-details min="0" max="20" step="2" />
|
|
82
|
-
</v-col>
|
|
87
|
+
<ViewerOptionsSizeSlider data-testid="meshPointsSizeSlider" v-model="size" />
|
|
83
88
|
</v-row>
|
|
84
89
|
<v-row>
|
|
85
90
|
<v-col>
|
|
@@ -90,9 +90,17 @@ const polygon_attribute_color_map = computed({
|
|
|
90
90
|
</script>
|
|
91
91
|
|
|
92
92
|
<template>
|
|
93
|
-
<ViewerContextMenuItem
|
|
93
|
+
<ViewerContextMenuItem
|
|
94
|
+
data-testid="meshPolygonsMenu"
|
|
95
|
+
:itemProps="itemProps"
|
|
96
|
+
:tooltip="tooltip"
|
|
97
|
+
:btn_image="btn_image"
|
|
98
|
+
>
|
|
94
99
|
<template #options>
|
|
95
|
-
<ViewerOptionsVisibilitySwitch
|
|
100
|
+
<ViewerOptionsVisibilitySwitch
|
|
101
|
+
data-testid="meshPolygonsVisibilitySwitch"
|
|
102
|
+
v-model="visibility"
|
|
103
|
+
/>
|
|
96
104
|
<template v-if="visibility">
|
|
97
105
|
<ViewerOptionsColoringTypeSelector
|
|
98
106
|
:id="id"
|
|
@@ -87,9 +87,17 @@ const polyhedron_attribute_color_map = computed({
|
|
|
87
87
|
</script>
|
|
88
88
|
|
|
89
89
|
<template>
|
|
90
|
-
<ViewerContextMenuItem
|
|
90
|
+
<ViewerContextMenuItem
|
|
91
|
+
data-testid="meshPolyhedraMenu"
|
|
92
|
+
:itemProps="itemProps"
|
|
93
|
+
:tooltip="tooltip"
|
|
94
|
+
:btn_image="btn_image"
|
|
95
|
+
>
|
|
91
96
|
<template #options>
|
|
92
|
-
<ViewerOptionsVisibilitySwitch
|
|
97
|
+
<ViewerOptionsVisibilitySwitch
|
|
98
|
+
data-testid="meshPolyhedraVisibilitySwitch"
|
|
99
|
+
v-model="visibility"
|
|
100
|
+
/>
|
|
93
101
|
<template v-if="visibility">
|
|
94
102
|
<ViewerOptionsColoringTypeSelector
|
|
95
103
|
:id="id"
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import SurfacePoints from "@ogw_front/assets/viewer_svgs/surface_points.svg";
|
|
3
3
|
import ViewerContextMenuItem from "@ogw_front/components/Viewer/ContextMenuItem";
|
|
4
|
+
import ViewerOptionsSizeSlider from "@ogw_front/components/Viewer/Options/Sliders/Size";
|
|
4
5
|
import ViewerOptionsVisibilitySwitch from "@ogw_front/components/Viewer/Options/VisibilitySwitch";
|
|
5
6
|
|
|
6
7
|
import { useDataStyleStore } from "@ogw_front/stores/data_style";
|
|
@@ -46,20 +47,7 @@ const size = computed({
|
|
|
46
47
|
<template v-if="visibility">
|
|
47
48
|
<v-row class="pa-0" align="center">
|
|
48
49
|
<v-divider />
|
|
49
|
-
<
|
|
50
|
-
<v-icon size="30" icon="mdi-ruler" v-tooltip:left="'Size'" />
|
|
51
|
-
</v-col>
|
|
52
|
-
<v-col justify="center">
|
|
53
|
-
<v-slider
|
|
54
|
-
v-model="size"
|
|
55
|
-
hide-details
|
|
56
|
-
min="0"
|
|
57
|
-
max="20"
|
|
58
|
-
step="2"
|
|
59
|
-
thumb-color="black"
|
|
60
|
-
ticks
|
|
61
|
-
/>
|
|
62
|
-
</v-col>
|
|
50
|
+
<ViewerOptionsSizeSlider data-testid="modelPointsSizeSlider" v-model="size" />
|
|
63
51
|
</v-row>
|
|
64
52
|
</template>
|
|
65
53
|
</template>
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import StickyHeader from "@ogw_front/components/Viewer/ObjectTree/Base/StickyHeader.vue";
|
|
3
|
+
import TreeRow from "@ogw_front/components/Viewer/ObjectTree/Base/TreeRow.vue";
|
|
4
|
+
import { useTreeKeyboardNav } from "@ogw_front/composables/tree_keyboard_nav";
|
|
5
|
+
import { useTreeScroll } from "@ogw_front/composables/tree_scroll";
|
|
6
|
+
import { useVirtualTree } from "@ogw_front/composables/virtual_tree";
|
|
7
|
+
|
|
8
|
+
const { items, opened, selected, scrollTop, options } = defineProps({
|
|
9
|
+
items: { type: Array, required: true },
|
|
10
|
+
opened: { type: Array, required: false, default: () => [] },
|
|
11
|
+
selected: { type: Array, required: false, default: () => [] },
|
|
12
|
+
scrollTop: { type: Number, required: false, default: 0 },
|
|
13
|
+
options: { type: Object, required: false, default: () => ({}) },
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
const treeWrapper = ref(undefined);
|
|
17
|
+
|
|
18
|
+
const emit = defineEmits([
|
|
19
|
+
"update:opened",
|
|
20
|
+
"update:selected",
|
|
21
|
+
"click:item",
|
|
22
|
+
"update:scrollTop",
|
|
23
|
+
"hover:enter",
|
|
24
|
+
"hover:leave",
|
|
25
|
+
]);
|
|
26
|
+
|
|
27
|
+
const {
|
|
28
|
+
actualItemProps,
|
|
29
|
+
actualSelection,
|
|
30
|
+
displayItems,
|
|
31
|
+
toggleOpen,
|
|
32
|
+
toggleSelect,
|
|
33
|
+
isSelected,
|
|
34
|
+
getIndeterminate,
|
|
35
|
+
} = useVirtualTree(
|
|
36
|
+
computed(() => ({
|
|
37
|
+
items,
|
|
38
|
+
opened,
|
|
39
|
+
selected,
|
|
40
|
+
...options,
|
|
41
|
+
})),
|
|
42
|
+
emit,
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
const { virtualScrollRef, stickyHeader, handleScroll, scrollToIndex } = useTreeScroll(
|
|
46
|
+
computed(() => ({ scrollTop })),
|
|
47
|
+
emit,
|
|
48
|
+
displayItems,
|
|
49
|
+
actualItemProps,
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
function handleItemClick(item, index) {
|
|
53
|
+
if (index !== undefined) {
|
|
54
|
+
focusedIndex.value = index;
|
|
55
|
+
}
|
|
56
|
+
if (item.isLeaf) {
|
|
57
|
+
toggleSelect(item.raw);
|
|
58
|
+
emit("click:item", item.raw);
|
|
59
|
+
} else {
|
|
60
|
+
toggleOpen(item.raw);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const { focusedIndex, handleKeyDown } = useTreeKeyboardNav(
|
|
65
|
+
displayItems,
|
|
66
|
+
emit,
|
|
67
|
+
scrollToIndex,
|
|
68
|
+
toggleOpen,
|
|
69
|
+
handleItemClick,
|
|
70
|
+
);
|
|
71
|
+
</script>
|
|
72
|
+
|
|
73
|
+
<template>
|
|
74
|
+
<div
|
|
75
|
+
ref="treeWrapper"
|
|
76
|
+
class="common-tree-view-wrapper"
|
|
77
|
+
tabindex="0"
|
|
78
|
+
@keydown="handleKeyDown"
|
|
79
|
+
@mousedown="treeWrapper.focus()"
|
|
80
|
+
>
|
|
81
|
+
<StickyHeader
|
|
82
|
+
v-if="stickyHeader"
|
|
83
|
+
:item="stickyHeader"
|
|
84
|
+
:item-props="actualItemProps"
|
|
85
|
+
:selection="actualSelection"
|
|
86
|
+
:is-selected="isSelected"
|
|
87
|
+
:get-indeterminate="getIndeterminate"
|
|
88
|
+
@toggle-open="toggleOpen"
|
|
89
|
+
@toggle-select="toggleSelect"
|
|
90
|
+
>
|
|
91
|
+
<template #title="slotProps">
|
|
92
|
+
<slot name="title" v-bind="slotProps" />
|
|
93
|
+
</template>
|
|
94
|
+
</StickyHeader>
|
|
95
|
+
|
|
96
|
+
<v-virtual-scroll
|
|
97
|
+
ref="virtualScrollRef"
|
|
98
|
+
:items="displayItems"
|
|
99
|
+
:item-height="actualItemProps.height"
|
|
100
|
+
class="common-tree-view"
|
|
101
|
+
@scroll="handleScroll"
|
|
102
|
+
>
|
|
103
|
+
<template #default="{ item, index }">
|
|
104
|
+
<v-list-item
|
|
105
|
+
:class="[
|
|
106
|
+
'tree-row-wrapper',
|
|
107
|
+
{ 'leaf-row': item.isLeaf, 'is-focused': focusedIndex === index },
|
|
108
|
+
]"
|
|
109
|
+
class="pa-0"
|
|
110
|
+
tabindex="-1"
|
|
111
|
+
@mousedown.prevent
|
|
112
|
+
@click="
|
|
113
|
+
handleItemClick(item, index);
|
|
114
|
+
treeWrapper.focus();
|
|
115
|
+
"
|
|
116
|
+
@mouseenter="emit('hover:enter', { item })"
|
|
117
|
+
@mouseleave="emit('hover:leave', { item })"
|
|
118
|
+
>
|
|
119
|
+
<TreeRow
|
|
120
|
+
:item="item"
|
|
121
|
+
:item-props="actualItemProps"
|
|
122
|
+
:selection="actualSelection"
|
|
123
|
+
:is-selected="isSelected"
|
|
124
|
+
:get-indeterminate="getIndeterminate"
|
|
125
|
+
@toggle-open="toggleOpen"
|
|
126
|
+
@toggle-select="toggleSelect"
|
|
127
|
+
>
|
|
128
|
+
<template #title="slotProps">
|
|
129
|
+
<slot name="title" v-bind="slotProps" />
|
|
130
|
+
</template>
|
|
131
|
+
<template #append="slotProps">
|
|
132
|
+
<slot name="append" v-bind="slotProps" />
|
|
133
|
+
</template>
|
|
134
|
+
</TreeRow>
|
|
135
|
+
</v-list-item>
|
|
136
|
+
</template>
|
|
137
|
+
</v-virtual-scroll>
|
|
138
|
+
</div>
|
|
139
|
+
</template>
|
|
140
|
+
|
|
141
|
+
<style scoped>
|
|
142
|
+
.common-tree-view-wrapper {
|
|
143
|
+
height: 100%;
|
|
144
|
+
position: relative;
|
|
145
|
+
display: flex;
|
|
146
|
+
flex-direction: column;
|
|
147
|
+
min-height: 0;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.common-tree-view-wrapper:focus {
|
|
151
|
+
outline: none;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.common-tree-view {
|
|
155
|
+
flex-grow: 1;
|
|
156
|
+
min-height: 0;
|
|
157
|
+
overflow-y: auto !important;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
.v-list-item {
|
|
161
|
+
background-color: transparent !important;
|
|
162
|
+
transition: none !important;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.tree-row-wrapper {
|
|
166
|
+
min-height: 44px !important;
|
|
167
|
+
cursor: pointer;
|
|
168
|
+
border-radius: 8px;
|
|
169
|
+
margin: 1px 4px;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
.tree-row-wrapper.is-focused {
|
|
173
|
+
background-color: rgba(0, 0, 0, 0.08) !important;
|
|
174
|
+
box-shadow: inset 0 0 0 2px rgba(0, 0, 0, 0.15);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
.tree-row-wrapper:hover:not(.is-focused) {
|
|
178
|
+
background-color: rgba(0, 0, 0, 0.04) !important;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
:deep(.v-list-item__content) {
|
|
182
|
+
padding: 0 !important;
|
|
183
|
+
display: block !important;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
:deep(.v-list-item__overlay) {
|
|
187
|
+
display: none !important;
|
|
188
|
+
}
|
|
189
|
+
</style>
|