@geode/opengeodeweb-front 10.40.0-rc.2 → 10.40.1-rc.1
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/ThresholdFilter.vue +25 -17
- package/app/components/Viewer/Generic/Model/BlocksOptions.vue +92 -29
- package/app/components/Viewer/Generic/Model/CornersOptions.vue +12 -4
- package/app/components/Viewer/Generic/Model/LinesOptions.vue +16 -5
- package/app/components/Viewer/Generic/Model/SurfacesOptions.vue +16 -5
- package/app/components/Viewer/Options/AttributeRangeSelector.vue +42 -8
- package/app/components/Viewer/Options/AttributeSelector.vue +101 -47
- package/app/components/Viewer/Options/ColoringTypeSelector.vue +32 -17
- package/app/composables/global_attribute_style.ts +20 -33
- package/app/utils/attribute_range.ts +56 -0
- package/internal/stores/data_style/model/blocks/polyhedron.ts +23 -20
- package/package.json +1 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
+
import { type AttributeSchemas, fetchAttributeRange } from "@ogw_front/utils/attribute_range";
|
|
2
3
|
import {
|
|
3
4
|
MESH_ELEMENT_KINDS,
|
|
4
5
|
MODEL_COMPONENT_ATTRIBUTE_SCHEMAS,
|
|
@@ -26,9 +27,9 @@ const { escapeFunction = undefined } = defineProps<Props>();
|
|
|
26
27
|
|
|
27
28
|
interface AttributeSource {
|
|
28
29
|
title: string;
|
|
29
|
-
|
|
30
|
+
schemas: AttributeSchemas;
|
|
30
31
|
timeStepKey: string;
|
|
31
|
-
params:
|
|
32
|
+
params: { id: string; component_ids?: string[] };
|
|
32
33
|
location: "point" | "cell";
|
|
33
34
|
}
|
|
34
35
|
|
|
@@ -86,23 +87,24 @@ const itemOptions = computed<{ title: string; value: number }[]>(() =>
|
|
|
86
87
|
})),
|
|
87
88
|
);
|
|
88
89
|
|
|
89
|
-
function attributeSchema(kind: string, isModel: boolean): JsonRpcSchema {
|
|
90
|
+
function attributeSchema(kind: string, isModel: boolean, route: "names" | "range"): JsonRpcSchema {
|
|
90
91
|
const prefix = isModel ? "model_component_" : "";
|
|
91
92
|
return back_schemas.opengeodeweb_back[
|
|
92
|
-
`${prefix}${kind}
|
|
93
|
+
`${prefix}${kind}_attribute_${route}` as keyof typeof back_schemas.opengeodeweb_back
|
|
93
94
|
] as JsonRpcSchema;
|
|
94
95
|
}
|
|
95
96
|
|
|
96
97
|
function attributeSource(
|
|
97
98
|
kind: string,
|
|
98
99
|
title: string,
|
|
99
|
-
params:
|
|
100
|
+
params: { id: string; component_ids?: string[] },
|
|
100
101
|
modelType?: string,
|
|
101
102
|
): AttributeSource {
|
|
102
|
-
const
|
|
103
|
+
const isModel = modelType !== undefined;
|
|
104
|
+
const schema = attributeSchema(kind, isModel, "names");
|
|
103
105
|
return {
|
|
104
106
|
title: `${title}${kind} attribute`,
|
|
105
|
-
schema,
|
|
107
|
+
schemas: { names: schema, range: attributeSchema(kind, isModel, "range") },
|
|
106
108
|
timeStepKey:
|
|
107
109
|
modelType === undefined
|
|
108
110
|
? schema.$id
|
|
@@ -154,11 +156,17 @@ async function applyThreshold(): Promise<void> {
|
|
|
154
156
|
|
|
155
157
|
const debouncedApply = useDebounceFn(() => applyThreshold(), DEBOUNCE_DELAY);
|
|
156
158
|
|
|
157
|
-
function resetRange(): void {
|
|
158
|
-
const
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
159
|
+
async function resetRange(): Promise<void> {
|
|
160
|
+
const source = sources.value[selectedSourceIndex.value ?? -1];
|
|
161
|
+
const name = attributeName.value;
|
|
162
|
+
if (!source || name === undefined) {
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
const range = await fetchAttributeRange(source.schemas.range, source.params, name);
|
|
166
|
+
if (name !== attributeName.value) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
const { min, max } = getAttributeRange(range, attributeItem.value);
|
|
162
170
|
minimum.value = min;
|
|
163
171
|
maximum.value = max;
|
|
164
172
|
}
|
|
@@ -186,19 +194,19 @@ watch(selectedSourceIndex, async (index) => {
|
|
|
186
194
|
return;
|
|
187
195
|
}
|
|
188
196
|
const response = (await backStore.request({
|
|
189
|
-
schema: source.
|
|
197
|
+
schema: source.schemas.names,
|
|
190
198
|
params: source.params,
|
|
191
199
|
})) as { attributes: AttributeInfo[] };
|
|
192
200
|
attributes.value = response.attributes;
|
|
193
201
|
});
|
|
194
202
|
|
|
195
|
-
watch(attributeName, () => {
|
|
203
|
+
watch(attributeName, async () => {
|
|
196
204
|
attributeItem.value = 0;
|
|
197
|
-
resetRange();
|
|
205
|
+
await resetRange();
|
|
198
206
|
});
|
|
199
207
|
|
|
200
|
-
watch(attributeItem, () => {
|
|
201
|
-
resetRange();
|
|
208
|
+
watch(attributeItem, async () => {
|
|
209
|
+
await resetRange();
|
|
202
210
|
});
|
|
203
211
|
|
|
204
212
|
watch(currentTimeStep, () => {
|
|
@@ -30,6 +30,8 @@ const referenceBlockId = computed<string | undefined>(() =>
|
|
|
30
30
|
collections ? targetBlockIds[0] : undefined,
|
|
31
31
|
);
|
|
32
32
|
|
|
33
|
+
const blockComponentIds = computed<string[]>(() => (blockId === undefined ? [] : [blockId]));
|
|
34
|
+
|
|
33
35
|
// Visibility
|
|
34
36
|
const blocksVisibility = computed<boolean>({
|
|
35
37
|
get: () =>
|
|
@@ -184,8 +186,14 @@ const blocksPolyhedronAttributeName = computed<string | undefined>({
|
|
|
184
186
|
if (newValue === undefined) {
|
|
185
187
|
return;
|
|
186
188
|
}
|
|
187
|
-
await dataStyleStore.setModelBlocksPolyhedronAttributeName(
|
|
188
|
-
|
|
189
|
+
const applied = await dataStyleStore.setModelBlocksPolyhedronAttributeName(
|
|
190
|
+
modelId,
|
|
191
|
+
targetBlockIds,
|
|
192
|
+
newValue,
|
|
193
|
+
);
|
|
194
|
+
if (applied) {
|
|
195
|
+
hybridViewerStore.remoteRender();
|
|
196
|
+
}
|
|
189
197
|
},
|
|
190
198
|
});
|
|
191
199
|
|
|
@@ -195,20 +203,28 @@ const blocksPolyhedronAttributeTimeStep = computed<number | undefined>({
|
|
|
195
203
|
if (newValue === undefined) {
|
|
196
204
|
return;
|
|
197
205
|
}
|
|
198
|
-
await dataStyleStore.setModelBlocksPolyhedronAttributeTimeStep(
|
|
206
|
+
const applied = await dataStyleStore.setModelBlocksPolyhedronAttributeTimeStep(
|
|
199
207
|
modelId,
|
|
200
208
|
targetBlockIds,
|
|
201
209
|
newValue,
|
|
202
210
|
);
|
|
203
|
-
|
|
211
|
+
if (applied) {
|
|
212
|
+
hybridViewerStore.remoteRender();
|
|
213
|
+
}
|
|
204
214
|
},
|
|
205
215
|
});
|
|
206
216
|
|
|
207
217
|
const blocksPolyhedronAttributeItem = computed<string | undefined>({
|
|
208
218
|
get: () => dataStyleStore.modelBlocksPolyhedronAttributeItem(modelId, referenceBlockId.value),
|
|
209
219
|
set: async (newValue) => {
|
|
210
|
-
await dataStyleStore.setModelBlocksPolyhedronAttributeItem(
|
|
211
|
-
|
|
220
|
+
const applied = await dataStyleStore.setModelBlocksPolyhedronAttributeItem(
|
|
221
|
+
modelId,
|
|
222
|
+
targetBlockIds,
|
|
223
|
+
newValue,
|
|
224
|
+
);
|
|
225
|
+
if (applied) {
|
|
226
|
+
hybridViewerStore.remoteRender();
|
|
227
|
+
}
|
|
212
228
|
},
|
|
213
229
|
});
|
|
214
230
|
|
|
@@ -219,25 +235,29 @@ const blocksPolyhedronAttributeRange = computed<[number, number] | undefined>({
|
|
|
219
235
|
if (minimum === undefined || maximum === undefined) {
|
|
220
236
|
return;
|
|
221
237
|
}
|
|
222
|
-
await dataStyleStore.setModelBlocksPolyhedronAttributeRange(
|
|
238
|
+
const applied = await dataStyleStore.setModelBlocksPolyhedronAttributeRange(
|
|
223
239
|
modelId,
|
|
224
240
|
targetBlockIds,
|
|
225
241
|
minimum,
|
|
226
242
|
maximum,
|
|
227
243
|
);
|
|
228
|
-
|
|
244
|
+
if (applied) {
|
|
245
|
+
hybridViewerStore.remoteRender();
|
|
246
|
+
}
|
|
229
247
|
},
|
|
230
248
|
});
|
|
231
249
|
|
|
232
250
|
const blocksPolyhedronAttributeColorMap = computed<Map<string, RGBAColor> | undefined>({
|
|
233
251
|
get: () => dataStyleStore.modelBlocksPolyhedronAttributeColorMap(modelId, referenceBlockId.value),
|
|
234
252
|
set: async (newValue) => {
|
|
235
|
-
await dataStyleStore.setModelBlocksPolyhedronAttributeColorMap(
|
|
253
|
+
const applied = await dataStyleStore.setModelBlocksPolyhedronAttributeColorMap(
|
|
236
254
|
modelId,
|
|
237
255
|
targetBlockIds,
|
|
238
256
|
newValue,
|
|
239
257
|
);
|
|
240
|
-
|
|
258
|
+
if (applied) {
|
|
259
|
+
hybridViewerStore.remoteRender();
|
|
260
|
+
}
|
|
241
261
|
},
|
|
242
262
|
});
|
|
243
263
|
|
|
@@ -245,12 +265,14 @@ const blocksPolyhedronAttributeNoDataColor = computed<RGBAColor>({
|
|
|
245
265
|
get: () =>
|
|
246
266
|
dataStyleStore.modelBlocksPolyhedronAttributeNoDataColor(modelId, referenceBlockId.value),
|
|
247
267
|
set: async (newValue) => {
|
|
248
|
-
await dataStyleStore.setModelBlocksPolyhedronAttributeNoDataColor(
|
|
268
|
+
const applied = await dataStyleStore.setModelBlocksPolyhedronAttributeNoDataColor(
|
|
249
269
|
modelId,
|
|
250
270
|
targetBlockIds,
|
|
251
271
|
newValue,
|
|
252
272
|
);
|
|
253
|
-
|
|
273
|
+
if (applied) {
|
|
274
|
+
hybridViewerStore.remoteRender();
|
|
275
|
+
}
|
|
254
276
|
},
|
|
255
277
|
});
|
|
256
278
|
|
|
@@ -328,8 +350,14 @@ const polyhedronAttributeName = computed<string | undefined>({
|
|
|
328
350
|
if (blockId === undefined || newValue === undefined) {
|
|
329
351
|
return;
|
|
330
352
|
}
|
|
331
|
-
await dataStyleStore.setModelBlocksPolyhedronAttributeName(
|
|
332
|
-
|
|
353
|
+
const applied = await dataStyleStore.setModelBlocksPolyhedronAttributeName(
|
|
354
|
+
modelId,
|
|
355
|
+
[blockId],
|
|
356
|
+
newValue,
|
|
357
|
+
);
|
|
358
|
+
if (applied) {
|
|
359
|
+
hybridViewerStore.remoteRender();
|
|
360
|
+
}
|
|
333
361
|
},
|
|
334
362
|
});
|
|
335
363
|
|
|
@@ -339,8 +367,14 @@ const polyhedronAttributeTimeStep = computed<number | undefined>({
|
|
|
339
367
|
if (blockId === undefined || newValue === undefined) {
|
|
340
368
|
return;
|
|
341
369
|
}
|
|
342
|
-
await dataStyleStore.setModelBlocksPolyhedronAttributeTimeStep(
|
|
343
|
-
|
|
370
|
+
const applied = await dataStyleStore.setModelBlocksPolyhedronAttributeTimeStep(
|
|
371
|
+
modelId,
|
|
372
|
+
[blockId],
|
|
373
|
+
newValue,
|
|
374
|
+
);
|
|
375
|
+
if (applied) {
|
|
376
|
+
hybridViewerStore.remoteRender();
|
|
377
|
+
}
|
|
344
378
|
},
|
|
345
379
|
});
|
|
346
380
|
|
|
@@ -350,8 +384,14 @@ const polyhedronAttributeItem = computed<string | undefined>({
|
|
|
350
384
|
if (blockId === undefined) {
|
|
351
385
|
return;
|
|
352
386
|
}
|
|
353
|
-
await dataStyleStore.setModelBlocksPolyhedronAttributeItem(
|
|
354
|
-
|
|
387
|
+
const applied = await dataStyleStore.setModelBlocksPolyhedronAttributeItem(
|
|
388
|
+
modelId,
|
|
389
|
+
[blockId],
|
|
390
|
+
newValue,
|
|
391
|
+
);
|
|
392
|
+
if (applied) {
|
|
393
|
+
hybridViewerStore.remoteRender();
|
|
394
|
+
}
|
|
355
395
|
},
|
|
356
396
|
});
|
|
357
397
|
|
|
@@ -362,13 +402,15 @@ const polyhedronAttributeRange = computed<[number, number] | undefined>({
|
|
|
362
402
|
if (blockId === undefined || minimum === undefined || maximum === undefined) {
|
|
363
403
|
return;
|
|
364
404
|
}
|
|
365
|
-
await dataStyleStore.setModelBlocksPolyhedronAttributeRange(
|
|
405
|
+
const applied = await dataStyleStore.setModelBlocksPolyhedronAttributeRange(
|
|
366
406
|
modelId,
|
|
367
407
|
[blockId],
|
|
368
408
|
minimum,
|
|
369
409
|
maximum,
|
|
370
410
|
);
|
|
371
|
-
|
|
411
|
+
if (applied) {
|
|
412
|
+
hybridViewerStore.remoteRender();
|
|
413
|
+
}
|
|
372
414
|
},
|
|
373
415
|
});
|
|
374
416
|
|
|
@@ -378,8 +420,14 @@ const polyhedronAttributeColorMap = computed<Map<string, RGBAColor> | undefined>
|
|
|
378
420
|
if (blockId === undefined) {
|
|
379
421
|
return;
|
|
380
422
|
}
|
|
381
|
-
await dataStyleStore.setModelBlocksPolyhedronAttributeColorMap(
|
|
382
|
-
|
|
423
|
+
const applied = await dataStyleStore.setModelBlocksPolyhedronAttributeColorMap(
|
|
424
|
+
modelId,
|
|
425
|
+
[blockId],
|
|
426
|
+
newValue,
|
|
427
|
+
);
|
|
428
|
+
if (applied) {
|
|
429
|
+
hybridViewerStore.remoteRender();
|
|
430
|
+
}
|
|
383
431
|
},
|
|
384
432
|
});
|
|
385
433
|
|
|
@@ -389,8 +437,14 @@ const polyhedronAttributeNoDataColor = computed<RGBAColor>({
|
|
|
389
437
|
if (blockId === undefined) {
|
|
390
438
|
return;
|
|
391
439
|
}
|
|
392
|
-
await dataStyleStore.setModelBlocksPolyhedronAttributeNoDataColor(
|
|
393
|
-
|
|
440
|
+
const applied = await dataStyleStore.setModelBlocksPolyhedronAttributeNoDataColor(
|
|
441
|
+
modelId,
|
|
442
|
+
[blockId],
|
|
443
|
+
newValue,
|
|
444
|
+
);
|
|
445
|
+
if (applied) {
|
|
446
|
+
hybridViewerStore.remoteRender();
|
|
447
|
+
}
|
|
394
448
|
},
|
|
395
449
|
});
|
|
396
450
|
|
|
@@ -404,8 +458,17 @@ const capabilities = {
|
|
|
404
458
|
polyhedron: { available: true },
|
|
405
459
|
};
|
|
406
460
|
|
|
407
|
-
const
|
|
408
|
-
const
|
|
461
|
+
const backSchemas = back_schemas.opengeodeweb_back;
|
|
462
|
+
const attributeSchemas = {
|
|
463
|
+
vertex: {
|
|
464
|
+
names: backSchemas.model_component_vertex_attribute_names,
|
|
465
|
+
range: backSchemas.model_component_vertex_attribute_range,
|
|
466
|
+
},
|
|
467
|
+
polyhedron: {
|
|
468
|
+
names: backSchemas.model_component_polyhedron_attribute_names,
|
|
469
|
+
range: backSchemas.model_component_polyhedron_attribute_range,
|
|
470
|
+
},
|
|
471
|
+
};
|
|
409
472
|
</script>
|
|
410
473
|
|
|
411
474
|
<template>
|
|
@@ -429,7 +492,7 @@ const polyhedronSchema = back_schemas.opengeodeweb_back.model_component_polyhedr
|
|
|
429
492
|
v-model:polyhedron_attribute_no_data_color="blocksPolyhedronAttributeNoDataColor"
|
|
430
493
|
v-model:polyhedron_attribute_time_step="blocksPolyhedronAttributeTimeStep"
|
|
431
494
|
:capabilities="capabilities"
|
|
432
|
-
:schemas="
|
|
495
|
+
:schemas="attributeSchemas"
|
|
433
496
|
:allowRandom="true"
|
|
434
497
|
/>
|
|
435
498
|
</OptionsSection>
|
|
@@ -443,7 +506,7 @@ const polyhedronSchema = back_schemas.opengeodeweb_back.model_component_polyhedr
|
|
|
443
506
|
<VisibilitySwitch v-model="blockVisibility" />
|
|
444
507
|
<ViewerOptionsColoringTypeSelector
|
|
445
508
|
:id="modelId"
|
|
446
|
-
:componentIds="
|
|
509
|
+
:componentIds="blockComponentIds"
|
|
447
510
|
v-model:coloring_style_key="blockActiveColoring"
|
|
448
511
|
v-model:color="blockColor"
|
|
449
512
|
v-model:vertex_attribute_name="vertexAttributeName"
|
|
@@ -459,7 +522,7 @@ const polyhedronSchema = back_schemas.opengeodeweb_back.model_component_polyhedr
|
|
|
459
522
|
v-model:polyhedron_attribute_no_data_color="polyhedronAttributeNoDataColor"
|
|
460
523
|
v-model:polyhedron_attribute_time_step="polyhedronAttributeTimeStep"
|
|
461
524
|
:capabilities="capabilities"
|
|
462
|
-
:schemas="
|
|
525
|
+
:schemas="attributeSchemas"
|
|
463
526
|
:allowRandom="true"
|
|
464
527
|
/>
|
|
465
528
|
</OptionsSection>
|
|
@@ -29,6 +29,8 @@ const referenceCornerId = computed<string | undefined>(() =>
|
|
|
29
29
|
collections ? targetCornerIds[0] : undefined,
|
|
30
30
|
);
|
|
31
31
|
|
|
32
|
+
const cornerComponentIds = computed<string[]>(() => (cornerId === undefined ? [] : [cornerId]));
|
|
33
|
+
|
|
32
34
|
// Visibility
|
|
33
35
|
const cornersVisibility = computed<boolean>({
|
|
34
36
|
get: () =>
|
|
@@ -258,7 +260,13 @@ const capabilities = {
|
|
|
258
260
|
polyhedron: { available: false },
|
|
259
261
|
};
|
|
260
262
|
|
|
261
|
-
const
|
|
263
|
+
const backSchemas = back_schemas.opengeodeweb_back;
|
|
264
|
+
const attributeSchemas = {
|
|
265
|
+
vertex: {
|
|
266
|
+
names: backSchemas.model_component_vertex_attribute_names,
|
|
267
|
+
range: backSchemas.model_component_vertex_attribute_range,
|
|
268
|
+
},
|
|
269
|
+
};
|
|
262
270
|
</script>
|
|
263
271
|
|
|
264
272
|
<template>
|
|
@@ -276,7 +284,7 @@ const vertexSchema = back_schemas.opengeodeweb_back.model_component_vertex_attri
|
|
|
276
284
|
v-model:vertex_attribute_no_data_color="cornersVertexAttributeNoDataColor"
|
|
277
285
|
v-model:vertex_attribute_time_step="cornersVertexAttributeTimeStep"
|
|
278
286
|
:capabilities="capabilities"
|
|
279
|
-
:schemas="
|
|
287
|
+
:schemas="attributeSchemas"
|
|
280
288
|
:allowRandom="true"
|
|
281
289
|
/>
|
|
282
290
|
</OptionsSection>
|
|
@@ -290,7 +298,7 @@ const vertexSchema = back_schemas.opengeodeweb_back.model_component_vertex_attri
|
|
|
290
298
|
<VisibilitySwitch v-model="cornerVisibility" />
|
|
291
299
|
<ViewerOptionsColoringTypeSelector
|
|
292
300
|
:id="modelId"
|
|
293
|
-
:componentIds="
|
|
301
|
+
:componentIds="cornerComponentIds"
|
|
294
302
|
v-model:coloring_style_key="cornerActiveColoring"
|
|
295
303
|
v-model:color="cornerColor"
|
|
296
304
|
v-model:vertex_attribute_name="vertexAttributeName"
|
|
@@ -300,7 +308,7 @@ const vertexSchema = back_schemas.opengeodeweb_back.model_component_vertex_attri
|
|
|
300
308
|
v-model:vertex_attribute_no_data_color="vertexAttributeNoDataColor"
|
|
301
309
|
v-model:vertex_attribute_time_step="vertexAttributeTimeStep"
|
|
302
310
|
:capabilities="capabilities"
|
|
303
|
-
:schemas="
|
|
311
|
+
:schemas="attributeSchemas"
|
|
304
312
|
:allowRandom="true"
|
|
305
313
|
/>
|
|
306
314
|
</OptionsSection>
|
|
@@ -29,6 +29,8 @@ const referenceLineId = computed<string | undefined>(() =>
|
|
|
29
29
|
collections ? targetLineIds[0] : undefined,
|
|
30
30
|
);
|
|
31
31
|
|
|
32
|
+
const lineComponentIds = computed<string[]>(() => (lineId === undefined ? [] : [lineId]));
|
|
33
|
+
|
|
32
34
|
// Visibility
|
|
33
35
|
const linesVisibility = computed<boolean>({
|
|
34
36
|
get: () =>
|
|
@@ -375,8 +377,17 @@ const capabilities = {
|
|
|
375
377
|
polyhedron: { available: false },
|
|
376
378
|
};
|
|
377
379
|
|
|
378
|
-
const
|
|
379
|
-
const
|
|
380
|
+
const backSchemas = back_schemas.opengeodeweb_back;
|
|
381
|
+
const attributeSchemas = {
|
|
382
|
+
vertex: {
|
|
383
|
+
names: backSchemas.model_component_vertex_attribute_names,
|
|
384
|
+
range: backSchemas.model_component_vertex_attribute_range,
|
|
385
|
+
},
|
|
386
|
+
edge: {
|
|
387
|
+
names: backSchemas.model_component_edge_attribute_names,
|
|
388
|
+
range: backSchemas.model_component_edge_attribute_range,
|
|
389
|
+
},
|
|
390
|
+
};
|
|
380
391
|
</script>
|
|
381
392
|
|
|
382
393
|
<template>
|
|
@@ -400,7 +411,7 @@ const edgeSchema = back_schemas.opengeodeweb_back.model_component_edge_attribute
|
|
|
400
411
|
v-model:edge_attribute_no_data_color="linesEdgeAttributeNoDataColor"
|
|
401
412
|
v-model:edge_attribute_time_step="linesEdgeAttributeTimeStep"
|
|
402
413
|
:capabilities="capabilities"
|
|
403
|
-
:schemas="
|
|
414
|
+
:schemas="attributeSchemas"
|
|
404
415
|
:allowRandom="true"
|
|
405
416
|
/>
|
|
406
417
|
</OptionsSection>
|
|
@@ -414,7 +425,7 @@ const edgeSchema = back_schemas.opengeodeweb_back.model_component_edge_attribute
|
|
|
414
425
|
<VisibilitySwitch v-model="lineVisibility" />
|
|
415
426
|
<ViewerOptionsColoringTypeSelector
|
|
416
427
|
:id="modelId"
|
|
417
|
-
:componentIds="
|
|
428
|
+
:componentIds="lineComponentIds"
|
|
418
429
|
v-model:coloring_style_key="lineActiveColoring"
|
|
419
430
|
v-model:color="lineColor"
|
|
420
431
|
v-model:vertex_attribute_name="vertexAttributeName"
|
|
@@ -430,7 +441,7 @@ const edgeSchema = back_schemas.opengeodeweb_back.model_component_edge_attribute
|
|
|
430
441
|
v-model:edge_attribute_no_data_color="edgeAttributeNoDataColor"
|
|
431
442
|
v-model:edge_attribute_time_step="edgeAttributeTimeStep"
|
|
432
443
|
:capabilities="capabilities"
|
|
433
|
-
:schemas="
|
|
444
|
+
:schemas="attributeSchemas"
|
|
434
445
|
:allowRandom="true"
|
|
435
446
|
/>
|
|
436
447
|
</OptionsSection>
|
|
@@ -30,6 +30,8 @@ const referenceSurfaceId = computed<string | undefined>(() =>
|
|
|
30
30
|
collections ? targetSurfaceIds[0] : undefined,
|
|
31
31
|
);
|
|
32
32
|
|
|
33
|
+
const surfaceComponentIds = computed<string[]>(() => (surfaceId === undefined ? [] : [surfaceId]));
|
|
34
|
+
|
|
33
35
|
// Visibility
|
|
34
36
|
const surfacesVisibility = computed<boolean>({
|
|
35
37
|
get: () =>
|
|
@@ -426,8 +428,17 @@ const capabilities = {
|
|
|
426
428
|
polyhedron: { available: false },
|
|
427
429
|
};
|
|
428
430
|
|
|
429
|
-
const
|
|
430
|
-
const
|
|
431
|
+
const backSchemas = back_schemas.opengeodeweb_back;
|
|
432
|
+
const attributeSchemas = {
|
|
433
|
+
vertex: {
|
|
434
|
+
names: backSchemas.model_component_vertex_attribute_names,
|
|
435
|
+
range: backSchemas.model_component_vertex_attribute_range,
|
|
436
|
+
},
|
|
437
|
+
polygon: {
|
|
438
|
+
names: backSchemas.model_component_polygon_attribute_names,
|
|
439
|
+
range: backSchemas.model_component_polygon_attribute_range,
|
|
440
|
+
},
|
|
441
|
+
};
|
|
431
442
|
</script>
|
|
432
443
|
|
|
433
444
|
<template>
|
|
@@ -451,7 +462,7 @@ const polygonSchema = back_schemas.opengeodeweb_back.model_component_polygon_att
|
|
|
451
462
|
v-model:polygon_attribute_no_data_color="surfacesPolygonAttributeNoDataColor"
|
|
452
463
|
v-model:polygon_attribute_time_step="surfacesPolygonAttributeTimeStep"
|
|
453
464
|
:capabilities="capabilities"
|
|
454
|
-
:schemas="
|
|
465
|
+
:schemas="attributeSchemas"
|
|
455
466
|
:allowRandom="true"
|
|
456
467
|
/>
|
|
457
468
|
</OptionsSection>
|
|
@@ -465,7 +476,7 @@ const polygonSchema = back_schemas.opengeodeweb_back.model_component_polygon_att
|
|
|
465
476
|
<VisibilitySwitch v-model="surfaceVisibility" />
|
|
466
477
|
<ViewerOptionsColoringTypeSelector
|
|
467
478
|
:id="modelId"
|
|
468
|
-
:componentIds="
|
|
479
|
+
:componentIds="surfaceComponentIds"
|
|
469
480
|
v-model:coloring_style_key="surfaceActiveColoring"
|
|
470
481
|
v-model:color="surfaceColor"
|
|
471
482
|
v-model:vertex_attribute_name="vertexAttributeName"
|
|
@@ -481,7 +492,7 @@ const polygonSchema = back_schemas.opengeodeweb_back.model_component_polygon_att
|
|
|
481
492
|
v-model:polygon_attribute_no_data_color="polygonAttributeNoDataColor"
|
|
482
493
|
v-model:polygon_attribute_time_step="polygonAttributeTimeStep"
|
|
483
494
|
:capabilities="capabilities"
|
|
484
|
-
:schemas="
|
|
495
|
+
:schemas="attributeSchemas"
|
|
485
496
|
:allowRandom="true"
|
|
486
497
|
/>
|
|
487
498
|
</OptionsSection>
|
|
@@ -7,6 +7,40 @@ const emit = defineEmits<Emits>();
|
|
|
7
7
|
|
|
8
8
|
const minimum = defineModel<number>("minimum");
|
|
9
9
|
const maximum = defineModel<number>("maximum");
|
|
10
|
+
|
|
11
|
+
const minimumText = ref<string>("");
|
|
12
|
+
const maximumText = ref<string>("");
|
|
13
|
+
|
|
14
|
+
watch(minimum, (value) => (minimumText.value = value === undefined ? "" : String(value)), {
|
|
15
|
+
immediate: true,
|
|
16
|
+
});
|
|
17
|
+
watch(maximum, (value) => (maximumText.value = value === undefined ? "" : String(value)), {
|
|
18
|
+
immediate: true,
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
// Text inputs (not type="number") so scientific notation like 1.5e7 can be typed, committed on enter or blur.
|
|
22
|
+
function parseValue(text: string): number | undefined {
|
|
23
|
+
const value = Number(text.trim());
|
|
24
|
+
return text.trim() === "" || !Number.isFinite(value) ? undefined : value;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function commitMinimum(): void {
|
|
28
|
+
const value = parseValue(minimumText.value);
|
|
29
|
+
if (value === undefined) {
|
|
30
|
+
minimumText.value = minimum.value === undefined ? "" : String(minimum.value);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
minimum.value = value;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function commitMaximum(): void {
|
|
37
|
+
const value = parseValue(maximumText.value);
|
|
38
|
+
if (value === undefined) {
|
|
39
|
+
maximumText.value = maximum.value === undefined ? "" : String(maximum.value);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
maximum.value = value;
|
|
43
|
+
}
|
|
10
44
|
</script>
|
|
11
45
|
|
|
12
46
|
<template>
|
|
@@ -14,11 +48,11 @@ const maximum = defineModel<number>("maximum");
|
|
|
14
48
|
<v-col cols="5" class="pe-1">
|
|
15
49
|
<v-text-field
|
|
16
50
|
data-testid="attributeMinInput"
|
|
17
|
-
|
|
18
|
-
@
|
|
51
|
+
v-model="minimumText"
|
|
52
|
+
@keydown.enter="commitMinimum"
|
|
53
|
+
@blur="commitMinimum"
|
|
19
54
|
label="Min"
|
|
20
|
-
|
|
21
|
-
:max="maximum"
|
|
55
|
+
inputmode="decimal"
|
|
22
56
|
density="compact"
|
|
23
57
|
hide-details
|
|
24
58
|
variant="outlined"
|
|
@@ -38,11 +72,11 @@ const maximum = defineModel<number>("maximum");
|
|
|
38
72
|
<v-col cols="5" class="ps-1">
|
|
39
73
|
<v-text-field
|
|
40
74
|
data-testid="attributeMaxInput"
|
|
41
|
-
|
|
42
|
-
@
|
|
75
|
+
v-model="maximumText"
|
|
76
|
+
@keydown.enter="commitMaximum"
|
|
77
|
+
@blur="commitMaximum"
|
|
43
78
|
label="Max"
|
|
44
|
-
|
|
45
|
-
:min="minimum"
|
|
79
|
+
inputmode="decimal"
|
|
46
80
|
density="compact"
|
|
47
81
|
hide-details
|
|
48
82
|
variant="outlined"
|
|
@@ -4,9 +4,13 @@ import {
|
|
|
4
4
|
type RangesPerData,
|
|
5
5
|
useBatchGroup,
|
|
6
6
|
} from "@ogw_front/composables/batch_style";
|
|
7
|
+
import {
|
|
8
|
+
type AttributeRangeInfo,
|
|
9
|
+
type AttributeSchemas,
|
|
10
|
+
fetchAttributeRange,
|
|
11
|
+
} from "@ogw_front/utils/attribute_range";
|
|
7
12
|
import { getAttributeRange, intersectAttributes } from "@ogw_front/utils/attributes";
|
|
8
13
|
import { DEFAULT_NO_DATA_COLOR } from "@ogw_front/utils/default_styles/constants";
|
|
9
|
-
import type { JsonRpcSchema } from "@ogw_shared/utils/types.js";
|
|
10
14
|
import ViewerOptionsAttributeColorBar from "@ogw_front/components/Viewer/Options/AttributeColorBar.vue";
|
|
11
15
|
import ViewerOptionsColorPicker from "@ogw_front/components/Viewer/Options/ColorPicker.vue";
|
|
12
16
|
import ViewerOptionsTimeStepSlider from "@ogw_front/components/Viewer/Options/TimeStepSlider.vue";
|
|
@@ -27,10 +31,10 @@ const attributeTimeStep = defineModel<number>("attributeTimeStep");
|
|
|
27
31
|
interface Props {
|
|
28
32
|
id: string;
|
|
29
33
|
componentIds?: string[];
|
|
30
|
-
|
|
34
|
+
schemas: AttributeSchemas;
|
|
31
35
|
}
|
|
32
36
|
|
|
33
|
-
const { id, componentIds = undefined,
|
|
37
|
+
const { id, componentIds = undefined, schemas } = defineProps<Props>();
|
|
34
38
|
|
|
35
39
|
interface Emits {
|
|
36
40
|
"update:attributeColorMap": [colorMap: string];
|
|
@@ -43,13 +47,15 @@ const emit = defineEmits<Emits>();
|
|
|
43
47
|
interface AttributeInfo {
|
|
44
48
|
attribute_name: string;
|
|
45
49
|
nb_items: number;
|
|
46
|
-
no_data?: boolean;
|
|
47
50
|
time_steps?: number[];
|
|
48
51
|
[key: string]: unknown;
|
|
49
52
|
}
|
|
50
53
|
|
|
51
54
|
const attributes = ref<AttributeInfo[]>([]);
|
|
52
55
|
let attributesPerTarget = new Map<string, AttributeInfo[]>();
|
|
56
|
+
const rangesPerTarget = ref(new Map<string, AttributeRangeInfo>());
|
|
57
|
+
let rangesName: string | undefined = undefined;
|
|
58
|
+
let rangesLoading: Promise<void> = Promise.resolve();
|
|
53
59
|
|
|
54
60
|
const groupTargetIds = useBatchGroup(() => id);
|
|
55
61
|
|
|
@@ -57,6 +63,9 @@ const currentAttribute = computed<AttributeInfo | undefined>(() =>
|
|
|
57
63
|
attributes.value.find((attr) => attr.attribute_name === attributeName.value),
|
|
58
64
|
);
|
|
59
65
|
const timeSteps = computed<number[]>(() => currentAttribute.value?.time_steps ?? []);
|
|
66
|
+
const noData = computed<boolean>(() =>
|
|
67
|
+
[...rangesPerTarget.value.values()].some((range) => range.no_data),
|
|
68
|
+
);
|
|
60
69
|
|
|
61
70
|
let committedSeries: string | undefined = undefined;
|
|
62
71
|
|
|
@@ -72,7 +81,10 @@ function commitSeriesTimeStep(): void {
|
|
|
72
81
|
committedSeries = name;
|
|
73
82
|
const current = attributeTimeStep.value;
|
|
74
83
|
const valid = current !== undefined && current >= 0 && current < timeSteps.value.length;
|
|
75
|
-
|
|
84
|
+
// A valid step is already stored and applied with the series: emitting it again re-applies the attribute
|
|
85
|
+
if (!valid) {
|
|
86
|
+
emit("update:attributeTimeStep", 0);
|
|
87
|
+
}
|
|
76
88
|
}
|
|
77
89
|
|
|
78
90
|
const cssNoDataColor = computed<string>(() => {
|
|
@@ -118,68 +130,105 @@ const componentItems = computed<{ title: string; value: number }[]>(() => {
|
|
|
118
130
|
}));
|
|
119
131
|
});
|
|
120
132
|
|
|
121
|
-
function
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
comp,
|
|
130
|
-
);
|
|
131
|
-
attributeRange.value = [min, max];
|
|
133
|
+
function hasSelectedComponent(components: unknown): boolean {
|
|
134
|
+
return Array.isArray(components) && components.length > 0;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function requestParams(): { id: string; component_ids?: string[] } | undefined {
|
|
138
|
+
const schemaProperties = schemas.names.properties as Record<string, unknown> | undefined;
|
|
139
|
+
if (schemaProperties?.component_ids === undefined) {
|
|
140
|
+
return { id };
|
|
132
141
|
}
|
|
142
|
+
return hasSelectedComponent(componentIds) ? { id, component_ids: componentIds } : undefined;
|
|
133
143
|
}
|
|
134
144
|
|
|
135
|
-
|
|
136
|
-
|
|
145
|
+
// Ranges are computed by the back for the selected attribute only, as scanning every step of every series is slow
|
|
146
|
+
async function requestRanges(name: string): Promise<void> {
|
|
147
|
+
const targets: [string, { id: string; component_ids?: string[] } | undefined][] =
|
|
148
|
+
groupTargetIds.value
|
|
149
|
+
? [...attributesPerTarget]
|
|
150
|
+
.filter(([, targetAttributes]) =>
|
|
151
|
+
targetAttributes.some((attribute) => attribute.attribute_name === name),
|
|
152
|
+
)
|
|
153
|
+
.map(([targetId]) => [targetId, { id: targetId }])
|
|
154
|
+
: [[id, requestParams()]];
|
|
155
|
+
const entries = await Promise.all(
|
|
156
|
+
targets.map(async ([targetId, params]): Promise<[string, AttributeRangeInfo | undefined]> => [
|
|
157
|
+
targetId,
|
|
158
|
+
params ? await fetchAttributeRange(schemas.range, params, name) : undefined,
|
|
159
|
+
]),
|
|
160
|
+
);
|
|
161
|
+
if (rangesName !== name) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
rangesPerTarget.value = new Map(
|
|
165
|
+
entries.filter((entry): entry is [string, AttributeRangeInfo] => entry[1] !== undefined),
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
async function loadRanges(name: string): Promise<void> {
|
|
170
|
+
if (name !== rangesName) {
|
|
171
|
+
rangesName = name;
|
|
172
|
+
rangesPerTarget.value = new Map();
|
|
173
|
+
rangesLoading = requestRanges(name);
|
|
174
|
+
}
|
|
175
|
+
await rangesLoading;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function applyRange(): void {
|
|
179
|
+
const { min, max } = getAttributeRange(rangesPerTarget.value.get(id), attributeItem.value ?? 0);
|
|
180
|
+
attributeRange.value = [min, max];
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
async function resetRange(): Promise<void> {
|
|
184
|
+
if (currentAttribute.value) {
|
|
185
|
+
await loadRanges(currentAttribute.value.attribute_name);
|
|
186
|
+
applyRange();
|
|
187
|
+
}
|
|
137
188
|
}
|
|
138
189
|
|
|
139
190
|
async function getGroupAttributes(targetIds: string[]): Promise<void> {
|
|
140
|
-
const responses = await requestForTargets<{ attributes: AttributeInfo[] }>(
|
|
141
|
-
|
|
142
|
-
|
|
191
|
+
const responses = await requestForTargets<{ attributes: AttributeInfo[] }>(
|
|
192
|
+
schemas.names,
|
|
193
|
+
targetIds,
|
|
194
|
+
{
|
|
195
|
+
attributes: [],
|
|
196
|
+
},
|
|
197
|
+
);
|
|
143
198
|
attributesPerTarget = new Map(
|
|
144
199
|
responses.map(([targetId, response]) => [targetId, response.attributes]),
|
|
145
200
|
);
|
|
146
201
|
attributes.value = intersectAttributes([...attributesPerTarget.values()]);
|
|
147
202
|
}
|
|
148
203
|
|
|
149
|
-
function initGroupAttribute(name: string, item: number): void {
|
|
204
|
+
async function initGroupAttribute(name: string, item: number): Promise<void> {
|
|
205
|
+
await loadRanges(name);
|
|
206
|
+
if (attributeName.value !== name) {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
150
209
|
const ranges = new Map<string, AttributeRange>();
|
|
151
|
-
for (const [targetId,
|
|
152
|
-
const
|
|
153
|
-
|
|
154
|
-
const { min, max } = getAttributeRange(
|
|
155
|
-
attribute as unknown as Parameters<typeof getAttributeRange>[0],
|
|
156
|
-
item,
|
|
157
|
-
);
|
|
158
|
-
ranges.set(targetId, [min, max]);
|
|
159
|
-
}
|
|
210
|
+
for (const [targetId, range] of rangesPerTarget.value) {
|
|
211
|
+
const { min, max } = getAttributeRange(range, item);
|
|
212
|
+
ranges.set(targetId, [min, max]);
|
|
160
213
|
}
|
|
161
214
|
emit("update:attributeColorMap", attributeColorMap.value ?? "batlow");
|
|
162
215
|
emit("ranges_per_data", ranges);
|
|
163
216
|
}
|
|
164
217
|
|
|
165
218
|
async function getAttributes(): Promise<void> {
|
|
219
|
+
rangesName = undefined;
|
|
220
|
+
rangesPerTarget.value = new Map();
|
|
166
221
|
if (groupTargetIds.value) {
|
|
167
222
|
await getGroupAttributes(groupTargetIds.value);
|
|
168
223
|
return;
|
|
169
224
|
}
|
|
170
|
-
const
|
|
171
|
-
|
|
172
|
-
if (requiresComponent && !hasSelectedComponent(componentIds)) {
|
|
225
|
+
const params = requestParams();
|
|
226
|
+
if (!params) {
|
|
173
227
|
return;
|
|
174
228
|
}
|
|
175
229
|
|
|
176
|
-
const params: { id: string; component_ids?: unknown } = { id };
|
|
177
|
-
if (requiresComponent) {
|
|
178
|
-
params.component_ids = componentIds;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
230
|
await backStore.request(
|
|
182
|
-
{ schema, params },
|
|
231
|
+
{ schema: schemas.names, params },
|
|
183
232
|
{
|
|
184
233
|
response_function: (response: unknown) => {
|
|
185
234
|
attributes.value = (response as { attributes: AttributeInfo[] }).attributes;
|
|
@@ -193,19 +242,19 @@ onMounted(async () => {
|
|
|
193
242
|
});
|
|
194
243
|
|
|
195
244
|
watch(
|
|
196
|
-
() =>
|
|
245
|
+
[(): string => id, (): string[] | undefined => componentIds, (): AttributeSchemas => schemas],
|
|
197
246
|
async () => {
|
|
198
247
|
await getAttributes();
|
|
199
248
|
},
|
|
200
249
|
);
|
|
201
250
|
|
|
202
|
-
watch([attributeName, attributeItem], ([name, item]) => {
|
|
251
|
+
watch([attributeName, attributeItem], async ([name, item]) => {
|
|
203
252
|
if (groupTargetIds.value && name !== undefined) {
|
|
204
|
-
initGroupAttribute(name, item ?? 0);
|
|
253
|
+
await initGroupAttribute(name, item ?? 0);
|
|
205
254
|
}
|
|
206
255
|
});
|
|
207
256
|
|
|
208
|
-
watch([attributeName, attributeItem, currentAttribute], () => {
|
|
257
|
+
watch([attributeName, attributeItem, currentAttribute], async () => {
|
|
209
258
|
commitSeriesTimeStep();
|
|
210
259
|
if (groupTargetIds.value) {
|
|
211
260
|
return;
|
|
@@ -216,8 +265,13 @@ watch([attributeName, attributeItem, currentAttribute], () => {
|
|
|
216
265
|
if (attributeNoDataColor.value === undefined) {
|
|
217
266
|
attributeNoDataColor.value = DEFAULT_NO_DATA_COLOR;
|
|
218
267
|
}
|
|
219
|
-
|
|
220
|
-
|
|
268
|
+
const name = currentAttribute.value?.attribute_name;
|
|
269
|
+
if (name === undefined) {
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
await loadRanges(name);
|
|
273
|
+
if (name === currentAttribute.value?.attribute_name && attributeRange.value[0] === undefined) {
|
|
274
|
+
applyRange();
|
|
221
275
|
}
|
|
222
276
|
});
|
|
223
277
|
</script>
|
|
@@ -247,7 +301,7 @@ watch([attributeName, attributeItem, currentAttribute], () => {
|
|
|
247
301
|
/>
|
|
248
302
|
<ViewerOptionsTimeStepSlider v-model="attributeTimeStep" :time-steps="timeSteps" />
|
|
249
303
|
<div
|
|
250
|
-
v-if="currentAttribute &&
|
|
304
|
+
v-if="currentAttribute && noData"
|
|
251
305
|
class="text-caption text-high-emphasis mt-1 d-flex align-center ga-1"
|
|
252
306
|
data-testid="noDataInfo"
|
|
253
307
|
>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import type {
|
|
2
|
+
import type { AttributeSchemas } from "@ogw_front/utils/attribute_range";
|
|
3
3
|
import type { RGBAColor } from "@ogw_front/utils/default_styles/constants";
|
|
4
4
|
import type { RangesPerData } from "@ogw_front/composables/batch_style";
|
|
5
5
|
import ViewerOptionsAttributeSelector from "@ogw_front/components/Viewer/Options/AttributeSelector.vue";
|
|
@@ -18,11 +18,11 @@ interface CapabilityConfig {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
interface Schemas {
|
|
21
|
-
vertex?:
|
|
22
|
-
edge?:
|
|
23
|
-
cell?:
|
|
24
|
-
polygon?:
|
|
25
|
-
polyhedron?:
|
|
21
|
+
vertex?: AttributeSchemas;
|
|
22
|
+
edge?: AttributeSchemas;
|
|
23
|
+
cell?: AttributeSchemas;
|
|
24
|
+
polygon?: AttributeSchemas;
|
|
25
|
+
polyhedron?: AttributeSchemas;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
const coloring_style_key = defineModel<string>("coloring_style_key");
|
|
@@ -95,12 +95,27 @@ const {
|
|
|
95
95
|
allowRandom = false,
|
|
96
96
|
} = defineProps<Props>();
|
|
97
97
|
|
|
98
|
-
const
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
98
|
+
const backSchemas = back_schemas.opengeodeweb_back;
|
|
99
|
+
const vertexSchemas = schemas.vertex ?? {
|
|
100
|
+
names: backSchemas.vertex_attribute_names,
|
|
101
|
+
range: backSchemas.vertex_attribute_range,
|
|
102
|
+
};
|
|
103
|
+
const edgeSchemas = schemas.edge ?? {
|
|
104
|
+
names: backSchemas.edge_attribute_names,
|
|
105
|
+
range: backSchemas.edge_attribute_range,
|
|
106
|
+
};
|
|
107
|
+
const cellSchemas = schemas.cell ?? {
|
|
108
|
+
names: backSchemas.cell_attribute_names,
|
|
109
|
+
range: backSchemas.cell_attribute_range,
|
|
110
|
+
};
|
|
111
|
+
const polygonSchemas = schemas.polygon ?? {
|
|
112
|
+
names: backSchemas.polygon_attribute_names,
|
|
113
|
+
range: backSchemas.polygon_attribute_range,
|
|
114
|
+
};
|
|
115
|
+
const polyhedronSchemas = schemas.polyhedron ?? {
|
|
116
|
+
names: backSchemas.polyhedron_attribute_names,
|
|
117
|
+
range: backSchemas.polyhedron_attribute_range,
|
|
118
|
+
};
|
|
104
119
|
|
|
105
120
|
function isAvailable(key: string): boolean {
|
|
106
121
|
if (capabilities[key] && capabilities[key].available === false) {
|
|
@@ -266,7 +281,7 @@ watch(
|
|
|
266
281
|
@ranges_per_data="emit('vertex_attribute_ranges_per_data', $event)"
|
|
267
282
|
:id="id"
|
|
268
283
|
:componentIds="componentIds"
|
|
269
|
-
:
|
|
284
|
+
:schemas="vertexSchemas"
|
|
270
285
|
/>
|
|
271
286
|
</template>
|
|
272
287
|
<template v-if="active_key === edge_dict['value'] && hasColorMap('edge')">
|
|
@@ -280,7 +295,7 @@ watch(
|
|
|
280
295
|
@ranges_per_data="emit('edge_attribute_ranges_per_data', $event)"
|
|
281
296
|
:id="id"
|
|
282
297
|
:componentIds="componentIds"
|
|
283
|
-
:
|
|
298
|
+
:schemas="edgeSchemas"
|
|
284
299
|
/>
|
|
285
300
|
</template>
|
|
286
301
|
<template v-if="active_key === cell_dict['value'] && hasColorMap('cell')">
|
|
@@ -294,7 +309,7 @@ watch(
|
|
|
294
309
|
@ranges_per_data="emit('cell_attribute_ranges_per_data', $event)"
|
|
295
310
|
:id="id"
|
|
296
311
|
:componentIds="componentIds"
|
|
297
|
-
:
|
|
312
|
+
:schemas="cellSchemas"
|
|
298
313
|
/>
|
|
299
314
|
</template>
|
|
300
315
|
<template v-if="active_key === polygon_dict['value'] && hasColorMap('polygon')">
|
|
@@ -308,7 +323,7 @@ watch(
|
|
|
308
323
|
@ranges_per_data="emit('polygon_attribute_ranges_per_data', $event)"
|
|
309
324
|
:id="id"
|
|
310
325
|
:componentIds="componentIds"
|
|
311
|
-
:
|
|
326
|
+
:schemas="polygonSchemas"
|
|
312
327
|
/>
|
|
313
328
|
</template>
|
|
314
329
|
<template v-if="active_key === polyhedron_dict['value'] && hasColorMap('polyhedron')">
|
|
@@ -322,7 +337,7 @@ watch(
|
|
|
322
337
|
@ranges_per_data="emit('polyhedron_attribute_ranges_per_data', $event)"
|
|
323
338
|
:id="id"
|
|
324
339
|
:componentIds="componentIds"
|
|
325
|
-
:
|
|
340
|
+
:schemas="polyhedronSchemas"
|
|
326
341
|
/>
|
|
327
342
|
</template>
|
|
328
343
|
</v-col>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { JsonRpcSchema } from "@ogw_shared/utils/types";
|
|
2
2
|
import back_schemas from "@geode/opengeodeweb-back/opengeodeweb_back_typed_schemas.js";
|
|
3
|
+
import { fetchAttributeRange } from "@ogw_front/utils/attribute_range";
|
|
3
4
|
import { getAttributeRange } from "@ogw_front/utils/attributes";
|
|
4
5
|
import { useBackStore } from "@ogw_front/stores/back";
|
|
5
6
|
import { useDataStyleStore } from "@ogw_front/stores/data_style";
|
|
@@ -35,10 +36,6 @@ interface AttributeStyleComponent {
|
|
|
35
36
|
interface AttributeResponse {
|
|
36
37
|
readonly attributes?: readonly {
|
|
37
38
|
readonly attribute_name?: string;
|
|
38
|
-
readonly min_values?: readonly number[];
|
|
39
|
-
readonly max_values?: readonly number[];
|
|
40
|
-
readonly min_value?: number;
|
|
41
|
-
readonly max_value?: number;
|
|
42
39
|
readonly time_steps?: readonly number[];
|
|
43
40
|
}[];
|
|
44
41
|
}
|
|
@@ -259,39 +256,29 @@ export function useGlobalAttributeStyle(dataIdRef: Ref<string | undefined>): {
|
|
|
259
256
|
continue;
|
|
260
257
|
}
|
|
261
258
|
|
|
262
|
-
const
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
if (
|
|
259
|
+
const rangeSchema = (back_schemas.opengeodeweb_back as Record<string, unknown>)[
|
|
260
|
+
`${activeColoring}_attribute_range`
|
|
261
|
+
];
|
|
262
|
+
if (!isJsonRpcSchema(rangeSchema)) {
|
|
266
263
|
continue;
|
|
267
264
|
}
|
|
268
265
|
|
|
269
266
|
requestPromises.push(
|
|
270
|
-
|
|
271
|
-
{
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
}
|
|
275
|
-
{
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
const setterName = `set${setterKey}${attributeType}Range`;
|
|
286
|
-
const setter = getDynamicStoreMethod(dataStyleStore, setterName);
|
|
287
|
-
if (setter) {
|
|
288
|
-
setter(targetId, min, max);
|
|
289
|
-
await hybridViewerStore.remoteRender();
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
},
|
|
293
|
-
},
|
|
294
|
-
),
|
|
267
|
+
(async (): Promise<void> => {
|
|
268
|
+
const range = await fetchAttributeRange(rangeSchema, { id: targetId }, attrName);
|
|
269
|
+
if (!range) {
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
const { min, max } = getAttributeRange(range, attrItem);
|
|
273
|
+
const setter = getDynamicStoreMethod(
|
|
274
|
+
dataStyleStore,
|
|
275
|
+
`set${setterKey}${attributeType}Range`,
|
|
276
|
+
);
|
|
277
|
+
if (setter) {
|
|
278
|
+
setter(targetId, min, max);
|
|
279
|
+
await hybridViewerStore.remoteRender();
|
|
280
|
+
}
|
|
281
|
+
})(),
|
|
295
282
|
);
|
|
296
283
|
}
|
|
297
284
|
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { JsonRpcSchema } from "@ogw_shared/utils/types.js";
|
|
2
|
+
import { useBackStore } from "@ogw_front/stores/back";
|
|
3
|
+
|
|
4
|
+
interface AttributeRangeInfo {
|
|
5
|
+
min_values: number[];
|
|
6
|
+
max_values: number[];
|
|
7
|
+
no_data: boolean;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// The *_attribute_names route listing the attributes, and its *_attribute_range route
|
|
11
|
+
interface AttributeSchemas {
|
|
12
|
+
names: JsonRpcSchema;
|
|
13
|
+
range: JsonRpcSchema;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
interface AttributeRangeTarget {
|
|
17
|
+
id: string;
|
|
18
|
+
component_ids?: string[];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// A data never changes once imported: selectors showing the same attribute share one request
|
|
22
|
+
const rangeRequests = new Map<string, Promise<AttributeRangeInfo | undefined>>();
|
|
23
|
+
|
|
24
|
+
async function requestAttributeRange(
|
|
25
|
+
rangeSchema: JsonRpcSchema,
|
|
26
|
+
params: Record<string, unknown>,
|
|
27
|
+
key: string,
|
|
28
|
+
): Promise<AttributeRangeInfo | undefined> {
|
|
29
|
+
const backStore = useBackStore();
|
|
30
|
+
try {
|
|
31
|
+
const range = await backStore.request({ schema: rangeSchema, params });
|
|
32
|
+
// oxlint-disable-next-line no-unsafe-type-assertion -- every *_attribute_range schema shares this response.
|
|
33
|
+
return range as AttributeRangeInfo;
|
|
34
|
+
} catch {
|
|
35
|
+
rangeRequests.delete(key);
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function fetchAttributeRange(
|
|
41
|
+
rangeSchema: JsonRpcSchema,
|
|
42
|
+
target: AttributeRangeTarget,
|
|
43
|
+
attributeName: string,
|
|
44
|
+
): Promise<AttributeRangeInfo | undefined> {
|
|
45
|
+
const params = { ...target, attribute_name: attributeName };
|
|
46
|
+
const key = JSON.stringify([rangeSchema.$id, params]);
|
|
47
|
+
let request = rangeRequests.get(key);
|
|
48
|
+
if (request === undefined) {
|
|
49
|
+
request = requestAttributeRange(rangeSchema, params, key);
|
|
50
|
+
rangeRequests.set(key, request);
|
|
51
|
+
}
|
|
52
|
+
const range = await request;
|
|
53
|
+
return range;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export { type AttributeRangeInfo, type AttributeSchemas, fetchAttributeRange };
|
|
@@ -72,7 +72,7 @@ interface UseModelBlocksPolyhedronAttributeReturn {
|
|
|
72
72
|
modelId: string,
|
|
73
73
|
blockIds: string[],
|
|
74
74
|
timeStep: number,
|
|
75
|
-
) => Promise<
|
|
75
|
+
) => Promise<boolean>;
|
|
76
76
|
modelBlocksPolyhedronAttributeColorMap: (modelId: string, blockId?: string) => string | undefined;
|
|
77
77
|
modelBlocksPolyhedronAttributeStoredConfig: (
|
|
78
78
|
modelId: string,
|
|
@@ -89,29 +89,29 @@ interface UseModelBlocksPolyhedronAttributeReturn {
|
|
|
89
89
|
modelId: string,
|
|
90
90
|
blockIds: string[],
|
|
91
91
|
name: string,
|
|
92
|
-
) => Promise<
|
|
92
|
+
) => Promise<boolean>;
|
|
93
93
|
setModelBlocksPolyhedronAttributeItem: (
|
|
94
94
|
modelId: string,
|
|
95
95
|
blockIds: string[],
|
|
96
96
|
item: number,
|
|
97
|
-
) => Promise<
|
|
97
|
+
) => Promise<boolean>;
|
|
98
98
|
setModelBlocksPolyhedronAttributeRange: (
|
|
99
99
|
modelId: string,
|
|
100
100
|
blockIds: string[],
|
|
101
101
|
minimum: number,
|
|
102
102
|
maximum: number,
|
|
103
|
-
) => Promise<
|
|
103
|
+
) => Promise<boolean>;
|
|
104
104
|
setModelBlocksPolyhedronAttributeColorMap: (
|
|
105
105
|
modelId: string,
|
|
106
106
|
blockIds: string[],
|
|
107
107
|
colorMap: string | undefined,
|
|
108
|
-
) => Promise<
|
|
108
|
+
) => Promise<boolean>;
|
|
109
109
|
modelBlocksPolyhedronAttributeNoDataColor: (modelId: string, blockId?: string) => RGBAColor;
|
|
110
110
|
setModelBlocksPolyhedronAttributeNoDataColor: (
|
|
111
111
|
modelId: string,
|
|
112
112
|
blockIds: string[],
|
|
113
113
|
no_data_color: RGBAColor,
|
|
114
|
-
) => Promise<
|
|
114
|
+
) => Promise<boolean>;
|
|
115
115
|
}
|
|
116
116
|
|
|
117
117
|
// oxlint-disable-next-line max-lines-per-function
|
|
@@ -281,7 +281,8 @@ function useModelBlocksPolyhedronAttribute(): UseModelBlocksPolyhedronAttributeR
|
|
|
281
281
|
params,
|
|
282
282
|
});
|
|
283
283
|
}
|
|
284
|
-
|
|
284
|
+
// True when the attribute was sent to the viewer, so the caller knows a render is needed
|
|
285
|
+
async function applyPolyhedronAttribute(modelId: string, blockIds: string[]): Promise<boolean> {
|
|
285
286
|
const name = modelBlocksPolyhedronAttributeName(modelId, blockIds[0]);
|
|
286
287
|
const item = modelBlocksPolyhedronAttributeItem(modelId, blockIds[0]);
|
|
287
288
|
const storedConfig = modelBlocksPolyhedronAttributeStoredConfig(
|
|
@@ -298,17 +299,17 @@ function useModelBlocksPolyhedronAttribute(): UseModelBlocksPolyhedronAttributeR
|
|
|
298
299
|
colorMap: storedConfig.colorMap,
|
|
299
300
|
no_data_color: storedConfig.no_data_color,
|
|
300
301
|
};
|
|
301
|
-
if (isModelBlocksPolyhedronAttributeValid(attribute)) {
|
|
302
|
-
|
|
303
|
-
return result;
|
|
302
|
+
if (!isModelBlocksPolyhedronAttributeValid(attribute)) {
|
|
303
|
+
return false;
|
|
304
304
|
}
|
|
305
|
-
|
|
305
|
+
await setModelBlocksPolyhedronAttribute(modelId, blockIds, attribute);
|
|
306
|
+
return true;
|
|
306
307
|
}
|
|
307
308
|
async function setModelBlocksPolyhedronAttributeName(
|
|
308
309
|
modelId: string,
|
|
309
310
|
blockIds: string[],
|
|
310
311
|
name: string,
|
|
311
|
-
): Promise<
|
|
312
|
+
): Promise<boolean> {
|
|
312
313
|
const item = modelBlocksPolyhedronAttributeLastItem(modelId, blockIds[0], name);
|
|
313
314
|
await mutateModelBlocksPolyhedronStyle(modelId, blockIds, {
|
|
314
315
|
name,
|
|
@@ -320,7 +321,7 @@ function useModelBlocksPolyhedronAttribute(): UseModelBlocksPolyhedronAttributeR
|
|
|
320
321
|
modelId: string,
|
|
321
322
|
blockIds: string[],
|
|
322
323
|
item: number,
|
|
323
|
-
): Promise<
|
|
324
|
+
): Promise<boolean> {
|
|
324
325
|
await mutateModelBlocksPolyhedronStyle(modelId, blockIds, {
|
|
325
326
|
item,
|
|
326
327
|
});
|
|
@@ -330,13 +331,14 @@ function useModelBlocksPolyhedronAttribute(): UseModelBlocksPolyhedronAttributeR
|
|
|
330
331
|
modelId: string,
|
|
331
332
|
blockIds: string[],
|
|
332
333
|
timeStep: number,
|
|
333
|
-
): Promise<
|
|
334
|
+
): Promise<boolean> {
|
|
334
335
|
const name = modelBlocksPolyhedronAttributeName(modelId, blockIds[0]);
|
|
335
336
|
if (name === undefined) {
|
|
336
|
-
return;
|
|
337
|
+
return false;
|
|
337
338
|
}
|
|
338
339
|
await setAttributeTimeStep(modelId, modelBlockPolyhedronAttributeSchema.$id, name, timeStep);
|
|
339
|
-
|
|
340
|
+
let reapplied = false;
|
|
341
|
+
const [applied] = await Promise.all([
|
|
340
342
|
applyPolyhedronAttribute(modelId, blockIds),
|
|
341
343
|
reapplySameSeries(
|
|
342
344
|
await dataStore.getBlocksGeodeIds(modelId),
|
|
@@ -352,17 +354,18 @@ function useModelBlocksPolyhedronAttribute(): UseModelBlocksPolyhedronAttributeR
|
|
|
352
354
|
].join("|")
|
|
353
355
|
: undefined,
|
|
354
356
|
async (ids) => {
|
|
355
|
-
await applyPolyhedronAttribute(modelId, ids);
|
|
357
|
+
reapplied = (await applyPolyhedronAttribute(modelId, ids)) || reapplied;
|
|
356
358
|
},
|
|
357
359
|
),
|
|
358
360
|
]);
|
|
361
|
+
return applied || reapplied;
|
|
359
362
|
}
|
|
360
363
|
async function setModelBlocksPolyhedronAttributeRange(
|
|
361
364
|
modelId: string,
|
|
362
365
|
blockIds: string[],
|
|
363
366
|
minimum: number,
|
|
364
367
|
maximum: number,
|
|
365
|
-
): Promise<
|
|
368
|
+
): Promise<boolean> {
|
|
366
369
|
const name = modelBlocksPolyhedronAttributeName(modelId, blockIds[0]);
|
|
367
370
|
const item = modelBlocksPolyhedronAttributeItem(modelId, blockIds[0]);
|
|
368
371
|
await setModelBlocksPolyhedronAttributeStoredConfig(modelId, blockIds, name, item, {
|
|
@@ -375,7 +378,7 @@ function useModelBlocksPolyhedronAttribute(): UseModelBlocksPolyhedronAttributeR
|
|
|
375
378
|
modelId: string,
|
|
376
379
|
blockIds: string[],
|
|
377
380
|
colorMap: string | undefined,
|
|
378
|
-
): Promise<
|
|
381
|
+
): Promise<boolean> {
|
|
379
382
|
const name = modelBlocksPolyhedronAttributeName(modelId, blockIds[0]);
|
|
380
383
|
const item = modelBlocksPolyhedronAttributeItem(modelId, blockIds[0]);
|
|
381
384
|
await setModelBlocksPolyhedronAttributeStoredConfig(modelId, blockIds, name, item, {
|
|
@@ -387,7 +390,7 @@ function useModelBlocksPolyhedronAttribute(): UseModelBlocksPolyhedronAttributeR
|
|
|
387
390
|
modelId: string,
|
|
388
391
|
blockIds: string[],
|
|
389
392
|
no_data_color: RGBAColor,
|
|
390
|
-
): Promise<
|
|
393
|
+
): Promise<boolean> {
|
|
391
394
|
const name = modelBlocksPolyhedronAttributeName(modelId, blockIds[0]);
|
|
392
395
|
const item = modelBlocksPolyhedronAttributeItem(modelId, blockIds[0]);
|
|
393
396
|
const storedConfig = modelBlocksPolyhedronAttributeStoredConfig(
|
package/package.json
CHANGED