@geode/opengeodeweb-front 10.10.2-rc.2 → 10.11.0-rc.4
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/ContextMenuItem.vue +1 -1
- package/app/components/Viewer/Generic/Model/ModelStyleCard.vue +96 -0
- package/app/components/Viewer/Generic/Model/ModelStyleOptions.vue +22 -0
- package/app/components/Viewer/Ui.vue +24 -15
- package/app/stores/data.js +29 -11
- package/app/stores/menu.js +8 -8
- package/internal/database/tables/model_components.js +1 -1
- package/internal/stores/data_style/mesh/edges/edge.js +1 -0
- package/package.json +1 -1
- package/tests/vitest.config.js +6 -0
- package/app/components/Viewer/Generic/Model/ModelComponentsOptions.vue +0 -38
|
@@ -29,7 +29,7 @@ const optionsStyle = computed(() => {
|
|
|
29
29
|
if (!is_active.value || !optionsHeight.value) {
|
|
30
30
|
return {};
|
|
31
31
|
}
|
|
32
|
-
const angle = (index / itemProps.totalItems) * 2 * Math.PI;
|
|
32
|
+
const angle = (itemProps.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;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import ViewerOptionsColorPicker from "@ogw_front/components/Viewer/Options/ColorPicker.vue";
|
|
3
|
+
import VisibilitySwitch from "@ogw_front/components/Viewer/Options/VisibilitySwitch.vue";
|
|
4
|
+
import { useDataStyleStore } from "@ogw_front/stores/data_style";
|
|
5
|
+
import { useHybridViewerStore } from "@ogw_front/stores/hybrid_viewer";
|
|
6
|
+
|
|
7
|
+
const dataStyleStore = useDataStyleStore();
|
|
8
|
+
const hybridViewerStore = useHybridViewerStore();
|
|
9
|
+
|
|
10
|
+
const { itemProps } = defineProps({
|
|
11
|
+
itemProps: { type: Object, required: true },
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
const modelId = computed(() => itemProps.meta_data.modelId || itemProps.id);
|
|
15
|
+
const componentId = computed(() => itemProps.meta_data.pickedComponentId);
|
|
16
|
+
|
|
17
|
+
const modelVisibility = computed({
|
|
18
|
+
get: () => dataStyleStore.modelVisibility(modelId.value),
|
|
19
|
+
set: (value) => {
|
|
20
|
+
dataStyleStore.setModelVisibility(modelId.value, value);
|
|
21
|
+
hybridViewerStore.remoteRender();
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const componentColor = computed({
|
|
26
|
+
get: () =>
|
|
27
|
+
componentId.value
|
|
28
|
+
? dataStyleStore.getModelComponentColor(modelId.value, componentId.value)
|
|
29
|
+
: undefined,
|
|
30
|
+
set: async (newValue) => {
|
|
31
|
+
if (componentId.value) {
|
|
32
|
+
await dataStyleStore.setModelComponentsColor(modelId.value, [componentId.value], newValue);
|
|
33
|
+
hybridViewerStore.remoteRender();
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
</script>
|
|
38
|
+
|
|
39
|
+
<template>
|
|
40
|
+
<div class="model-style-card">
|
|
41
|
+
<div class="options-section">
|
|
42
|
+
<div class="section-badge">Model Options</div>
|
|
43
|
+
<v-container class="pa-2">
|
|
44
|
+
<VisibilitySwitch v-model="modelVisibility" />
|
|
45
|
+
</v-container>
|
|
46
|
+
</div>
|
|
47
|
+
|
|
48
|
+
<div v-if="componentId" class="options-section mt-6">
|
|
49
|
+
<div class="section-badge">Component Options</div>
|
|
50
|
+
<v-container class="pa-2">
|
|
51
|
+
<div class="text-caption mb-1">Color</div>
|
|
52
|
+
<ViewerOptionsColorPicker v-model="componentColor" />
|
|
53
|
+
</v-container>
|
|
54
|
+
</div>
|
|
55
|
+
</div>
|
|
56
|
+
</template>
|
|
57
|
+
|
|
58
|
+
<style scoped>
|
|
59
|
+
.model-style-card {
|
|
60
|
+
min-width: 280px;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.options-section {
|
|
64
|
+
position: relative;
|
|
65
|
+
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
66
|
+
border-radius: 12px;
|
|
67
|
+
padding: 12px 8px 8px 8px;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.section-badge {
|
|
71
|
+
position: absolute;
|
|
72
|
+
top: -12px;
|
|
73
|
+
left: 16px;
|
|
74
|
+
background-color: rgba(255, 255, 255, 0.1);
|
|
75
|
+
backdrop-filter: blur(8px);
|
|
76
|
+
padding: 2px 12px;
|
|
77
|
+
font-size: 0.7rem;
|
|
78
|
+
font-weight: 700;
|
|
79
|
+
text-transform: uppercase;
|
|
80
|
+
letter-spacing: 0.5px;
|
|
81
|
+
color: white;
|
|
82
|
+
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
83
|
+
border-radius: 20px;
|
|
84
|
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.v-theme--light .options-section {
|
|
88
|
+
border-color: rgba(0, 0, 0, 0.12);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.v-theme--light .section-badge {
|
|
92
|
+
background-color: white;
|
|
93
|
+
color: #444;
|
|
94
|
+
border-color: rgba(0, 0, 0, 0.12);
|
|
95
|
+
}
|
|
96
|
+
</style>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import ModelColor from "@ogw_front/assets/viewer_svgs/model_component_color.svg";
|
|
3
|
+
import ModelStyleCard from "./ModelStyleCard.vue";
|
|
4
|
+
import ViewerContextMenuItem from "@ogw_front/components/Viewer/ContextMenuItem";
|
|
5
|
+
|
|
6
|
+
const { itemProps } = defineProps({
|
|
7
|
+
itemProps: { type: Object, required: true },
|
|
8
|
+
});
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
<template>
|
|
12
|
+
<ViewerContextMenuItem
|
|
13
|
+
:index="itemProps.index"
|
|
14
|
+
:itemProps="itemProps"
|
|
15
|
+
tooltip="Style options"
|
|
16
|
+
:btn_image="ModelColor"
|
|
17
|
+
>
|
|
18
|
+
<template #options>
|
|
19
|
+
<ModelStyleCard :itemProps="itemProps" />
|
|
20
|
+
</template>
|
|
21
|
+
</ViewerContextMenuItem>
|
|
22
|
+
</template>
|
|
@@ -1,34 +1,43 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import ViewerContextMenu from "@ogw_front/components/Viewer/ContextMenu";
|
|
3
3
|
import ViewerTreeObjectTree from "@ogw_front/components/Viewer/Tree/ObjectTree";
|
|
4
|
+
import { useDataStore } from "@ogw_front/stores/data";
|
|
5
|
+
import { useDataStyleStore } from "@ogw_front/stores/data_style";
|
|
6
|
+
import { useMenuStore } from "@ogw_front/stores/menu";
|
|
7
|
+
import { useViewerStore } from "@ogw_front/stores/viewer";
|
|
4
8
|
import viewer_schemas from "@geode/opengeodeweb-viewer/opengeodeweb_viewer_schemas.json";
|
|
5
9
|
|
|
6
|
-
const {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
containerWidth: { type: Number, required: true },
|
|
12
|
-
containerHeight: { type: Number, required: true },
|
|
13
|
-
dataStyleStore: { type: Object, required: true },
|
|
14
|
-
viewerStore: { type: Object, required: true },
|
|
15
|
-
});
|
|
10
|
+
const { displayMenu, containerWidth, containerHeight } = defineProps({
|
|
11
|
+
displayMenu: { type: Boolean, required: true },
|
|
12
|
+
containerWidth: { type: Number, required: true },
|
|
13
|
+
containerHeight: { type: Number, required: true },
|
|
14
|
+
});
|
|
16
15
|
|
|
17
|
-
const emit = defineEmits(["show-menu"
|
|
16
|
+
const emit = defineEmits(["show-menu"]);
|
|
17
|
+
|
|
18
|
+
const dataStore = useDataStore();
|
|
19
|
+
const dataStyleStore = useDataStyleStore();
|
|
20
|
+
const viewerStore = useViewerStore();
|
|
21
|
+
const menuStore = useMenuStore();
|
|
22
|
+
const dataItems = dataStore.refAllItems();
|
|
18
23
|
|
|
19
24
|
async function get_viewer_id(x, y) {
|
|
20
|
-
const
|
|
25
|
+
const activeIds = new Set(dataItems.value.map((item) => item.id));
|
|
26
|
+
const ids = Object.keys(dataStyleStore.styles).filter((styleId) => activeIds.has(styleId));
|
|
27
|
+
|
|
28
|
+
let result = { id: undefined, viewer_id: undefined };
|
|
21
29
|
await viewerStore.request(
|
|
22
30
|
viewer_schemas.opengeodeweb_viewer.viewer.picked_ids,
|
|
23
31
|
{ x, y, ids },
|
|
24
32
|
{
|
|
25
33
|
response_function: (response) => {
|
|
26
|
-
const { array_ids } = response;
|
|
34
|
+
const { array_ids, viewer_id } = response;
|
|
27
35
|
const [first_id] = array_ids;
|
|
28
|
-
|
|
36
|
+
result = { id: first_id, viewer_id };
|
|
29
37
|
},
|
|
30
38
|
},
|
|
31
39
|
);
|
|
40
|
+
return result;
|
|
32
41
|
}
|
|
33
42
|
|
|
34
43
|
defineExpose({ get_viewer_id });
|
|
@@ -38,7 +47,7 @@ defineExpose({ get_viewer_id });
|
|
|
38
47
|
<ViewerTreeObjectTree @show-menu="(args) => emit('show-menu', args)" />
|
|
39
48
|
<ViewerContextMenu
|
|
40
49
|
v-if="displayMenu"
|
|
41
|
-
:id="menuStore.current_id
|
|
50
|
+
:id="menuStore.current_id"
|
|
42
51
|
:x="menuStore.menuX"
|
|
43
52
|
:y="menuStore.menuY"
|
|
44
53
|
:container-width="containerWidth"
|
package/app/stores/data.js
CHANGED
|
@@ -120,8 +120,12 @@ export const useDataStore = defineStore("data", () => {
|
|
|
120
120
|
});
|
|
121
121
|
}
|
|
122
122
|
}
|
|
123
|
-
|
|
124
|
-
|
|
123
|
+
if (new_item.mesh_components) {
|
|
124
|
+
addModelComponents(new_item.mesh_components);
|
|
125
|
+
}
|
|
126
|
+
if (new_item.collection_components) {
|
|
127
|
+
addModelComponents(new_item.collection_components);
|
|
128
|
+
}
|
|
125
129
|
return database.model_components.bulkPut(allComponents);
|
|
126
130
|
}
|
|
127
131
|
|
|
@@ -137,22 +141,35 @@ export const useDataStore = defineStore("data", () => {
|
|
|
137
141
|
});
|
|
138
142
|
}
|
|
139
143
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
144
|
+
if (new_item.mesh_components) {
|
|
145
|
+
for (const component of new_item.mesh_components) {
|
|
146
|
+
if (component.boundaries) {
|
|
147
|
+
addModelComponentRelations(component.boundaries, component.geode_id, "boundary");
|
|
148
|
+
}
|
|
149
|
+
if (component.internals) {
|
|
150
|
+
addModelComponentRelations(component.internals, component.geode_id, "internal");
|
|
151
|
+
}
|
|
146
152
|
}
|
|
147
153
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
154
|
+
if (new_item.collection_components) {
|
|
155
|
+
for (const component of new_item.collection_components) {
|
|
156
|
+
if (component.items) {
|
|
157
|
+
addModelComponentRelations(component.items, component.geode_id, "collection");
|
|
158
|
+
}
|
|
151
159
|
}
|
|
152
160
|
}
|
|
153
161
|
return database.model_components_relation.bulkPut(relations);
|
|
154
162
|
}
|
|
155
163
|
|
|
164
|
+
async function getComponentByViewerId(modelId, viewer_id) {
|
|
165
|
+
const component = await database.model_components
|
|
166
|
+
.where("viewer_id")
|
|
167
|
+
.equals(Number(viewer_id))
|
|
168
|
+
.and((model_component) => model_component.id === modelId)
|
|
169
|
+
.first();
|
|
170
|
+
return component;
|
|
171
|
+
}
|
|
172
|
+
|
|
156
173
|
async function deleteItem(id) {
|
|
157
174
|
await database.data.delete(id);
|
|
158
175
|
await deleteModelComponents(id);
|
|
@@ -232,6 +249,7 @@ export const useDataStore = defineStore("data", () => {
|
|
|
232
249
|
getBlocksGeodeIds,
|
|
233
250
|
getMeshComponentGeodeIds,
|
|
234
251
|
getMeshComponentsViewerIds,
|
|
252
|
+
getComponentByViewerId,
|
|
235
253
|
|
|
236
254
|
exportStores,
|
|
237
255
|
importStores,
|
package/app/stores/menu.js
CHANGED
|
@@ -36,9 +36,9 @@ import TetrahedralSolidTetrahedraOptions from "@ogw_front/components/Viewer/Tetr
|
|
|
36
36
|
import TetrahedralSolidTrianglesOptions from "@ogw_front/components/Viewer/TetrahedralSolid/TrianglesOptions";
|
|
37
37
|
|
|
38
38
|
// Model components
|
|
39
|
-
import ModelComponentsOptions from "@ogw_front/components/Viewer/Generic/Model/ModelComponentsOptions";
|
|
40
39
|
import ModelEdgesOptions from "@ogw_front/components/Viewer/Generic/Model/EdgesOptions";
|
|
41
40
|
import ModelPointsOptions from "@ogw_front/components/Viewer/Generic/Model/PointsOptions";
|
|
41
|
+
import ModelStyleOptions from "@ogw_front/components/Viewer/Generic/Model/ModelStyleOptions";
|
|
42
42
|
|
|
43
43
|
const PointSet_menu = [PointSetPointsOptions];
|
|
44
44
|
|
|
@@ -78,18 +78,18 @@ const TetrahedralSolid_menu = [
|
|
|
78
78
|
TetrahedralSolidTetrahedraOptions,
|
|
79
79
|
];
|
|
80
80
|
|
|
81
|
-
const BRep_menu = [ModelEdgesOptions, ModelPointsOptions];
|
|
81
|
+
const BRep_menu = [ModelEdgesOptions, ModelPointsOptions, ModelStyleOptions];
|
|
82
82
|
|
|
83
|
-
const CrossSection_menu = [ModelEdgesOptions, ModelPointsOptions];
|
|
83
|
+
const CrossSection_menu = [ModelEdgesOptions, ModelPointsOptions, ModelStyleOptions];
|
|
84
84
|
|
|
85
|
-
const ImplicitCrossSection_menu = [ModelEdgesOptions, ModelPointsOptions];
|
|
86
|
-
const ImplicitStructuralModel_menu = [ModelEdgesOptions, ModelPointsOptions];
|
|
85
|
+
const ImplicitCrossSection_menu = [ModelEdgesOptions, ModelPointsOptions, ModelStyleOptions];
|
|
86
|
+
const ImplicitStructuralModel_menu = [ModelEdgesOptions, ModelPointsOptions, ModelStyleOptions];
|
|
87
87
|
|
|
88
|
-
const Section_menu = [ModelEdgesOptions, ModelPointsOptions];
|
|
88
|
+
const Section_menu = [ModelEdgesOptions, ModelPointsOptions, ModelStyleOptions];
|
|
89
89
|
|
|
90
|
-
const StructuralModel_menu = [ModelEdgesOptions, ModelPointsOptions];
|
|
90
|
+
const StructuralModel_menu = [ModelEdgesOptions, ModelPointsOptions, ModelStyleOptions];
|
|
91
91
|
|
|
92
|
-
const ModelComponent_menu = [
|
|
92
|
+
const ModelComponent_menu = [ModelStyleOptions];
|
|
93
93
|
|
|
94
94
|
const menusData = {
|
|
95
95
|
mesh: {
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import viewer_schemas from "@geode/opengeodeweb-viewer/opengeodeweb_viewer_schemas.json";
|
|
3
3
|
|
|
4
4
|
// Local imports
|
|
5
|
+
import { getRGBPointsFromPreset } from "@ogw_front/utils/colormap";
|
|
5
6
|
import { useMeshEdgesCommonStyle } from "./common";
|
|
6
7
|
import { useViewerStore } from "@ogw_front/stores/viewer";
|
|
7
8
|
|
package/package.json
CHANGED
package/tests/vitest.config.js
CHANGED
|
@@ -7,6 +7,10 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
|
7
7
|
|
|
8
8
|
const RETRIES = 3;
|
|
9
9
|
const DEFAULT_RETRY = 0;
|
|
10
|
+
const TIMEOUTS = {
|
|
11
|
+
unit: 5000,
|
|
12
|
+
integration: 15_000,
|
|
13
|
+
};
|
|
10
14
|
|
|
11
15
|
const globalRetry = process.env.CI ? RETRIES : DEFAULT_RETRY;
|
|
12
16
|
|
|
@@ -27,6 +31,7 @@ export default defineConfig({
|
|
|
27
31
|
globals: false,
|
|
28
32
|
include: ["tests/unit/**/*.test.js"],
|
|
29
33
|
environment: "nuxt",
|
|
34
|
+
testTimeout: TIMEOUTS.unit,
|
|
30
35
|
setupFiles: [path.resolve(__dirname, "./setup_indexeddb.js")],
|
|
31
36
|
server: {
|
|
32
37
|
deps: {
|
|
@@ -43,6 +48,7 @@ export default defineConfig({
|
|
|
43
48
|
include: ["tests/integration/**/*.test.js"],
|
|
44
49
|
environment: "nuxt",
|
|
45
50
|
fileParallelism: false,
|
|
51
|
+
testTimeout: TIMEOUTS.integration,
|
|
46
52
|
setupFiles: [path.resolve(__dirname, "./setup_indexeddb.js")],
|
|
47
53
|
server: {
|
|
48
54
|
deps: {
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
<script setup>
|
|
2
|
-
import ModelColor from "@ogw_front/assets/viewer_svgs/model_component_color.svg";
|
|
3
|
-
import ViewerContextMenuItem from "@ogw_front/components/Viewer/ContextMenuItem";
|
|
4
|
-
import ViewerOptionsColorPicker from "@ogw_front/components/Viewer/Options/ColorPicker.vue";
|
|
5
|
-
|
|
6
|
-
import { useDataStyleStore } from "@ogw_front/stores/data_style";
|
|
7
|
-
import { useHybridViewerStore } from "@ogw_front/stores/hybrid_viewer";
|
|
8
|
-
|
|
9
|
-
const dataStyleStore = useDataStyleStore();
|
|
10
|
-
const hybridViewerStore = useHybridViewerStore();
|
|
11
|
-
|
|
12
|
-
const { itemProps } = defineProps({
|
|
13
|
-
itemProps: { type: Object, required: true },
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
const modelId = computed(() => itemProps.meta_data.modelId);
|
|
17
|
-
const componentId = computed(() => itemProps.id);
|
|
18
|
-
|
|
19
|
-
const color = computed({
|
|
20
|
-
get: () => dataStyleStore.getModelComponentColor(modelId.value, componentId.value),
|
|
21
|
-
set: async (newValue) => {
|
|
22
|
-
await dataStyleStore.setModelComponentsColor(modelId.value, [componentId.value], newValue);
|
|
23
|
-
hybridViewerStore.remoteRender();
|
|
24
|
-
},
|
|
25
|
-
});
|
|
26
|
-
</script>
|
|
27
|
-
|
|
28
|
-
<template>
|
|
29
|
-
<ViewerContextMenuItem :itemProps="itemProps" tooltip="Components color" :btn_image="ModelColor">
|
|
30
|
-
<template #options>
|
|
31
|
-
<v-row class="pa-0" align="center">
|
|
32
|
-
<v-col>
|
|
33
|
-
<ViewerOptionsColorPicker v-model="color" />
|
|
34
|
-
</v-col>
|
|
35
|
-
</v-row>
|
|
36
|
-
</template>
|
|
37
|
-
</ViewerContextMenuItem>
|
|
38
|
-
</template>
|