From 75921839e5a0878916d8ea721a8ac27cccbc5e17 Mon Sep 17 00:00:00 2001 From: Tao Schiro Date: Wed, 26 Aug 2026 16:29:02 +0200 Subject: [PATCH 1/4] fix(QuickScalarRange and MinValue): closes https://github.com/Geode-solutions/Vease/issues/576 and https://github.com/Geode-solutions/Vease/issues/627 --- .../Viewer/Options/AttributeColorBar.vue | 44 +---- .../Viewer/Options/AttributeRangeSelector.vue | 46 +++++ .../Viewer/Options/AttributeSelector.vue | 13 +- .../Viewer/Options/ColorMapList.vue | 1 + .../Viewer/Options/ColormapQuickPicker.vue | 115 +++-------- app/composables/use_global_attribute_style.js | 181 ++++++++++++++++++ app/utils/attributes.js | 23 +++ 7 files changed, 291 insertions(+), 132 deletions(-) create mode 100644 app/components/Viewer/Options/AttributeRangeSelector.vue create mode 100644 app/composables/use_global_attribute_style.js create mode 100644 app/utils/attributes.js diff --git a/app/components/Viewer/Options/AttributeColorBar.vue b/app/components/Viewer/Options/AttributeColorBar.vue index 15e010f5..3df6f085 100644 --- a/app/components/Viewer/Options/AttributeColorBar.vue +++ b/app/components/Viewer/Options/AttributeColorBar.vue @@ -1,4 +1,5 @@ + + diff --git a/app/components/Viewer/Options/AttributeSelector.vue b/app/components/Viewer/Options/AttributeSelector.vue index 4a88c78a..7791ccc8 100644 --- a/app/components/Viewer/Options/AttributeSelector.vue +++ b/app/components/Viewer/Options/AttributeSelector.vue @@ -17,6 +17,9 @@ const { id, componentIds, schema } = defineProps({ const attributes = ref([]); +const currentAttribute = computed(() => + attributes.value.find((attr) => attr.attribute_name === attributeName.value), +); const rangeMin = computed({ get: () => (attributeRange.value ? attributeRange.value[0] : undefined), set: (val) => { @@ -40,10 +43,6 @@ const rangeMax = computed({ }, }); -const currentAttribute = computed(() => - attributes.value.find((attr) => attr.attribute_name === attributeName.value), -); - const componentItems = computed(() => { if (!currentAttribute.value) { return []; @@ -57,10 +56,8 @@ const componentItems = computed(() => { function resetRange() { if (currentAttribute.value) { const comp = attributeItem.value ?? 0; - attributeRange.value = [ - currentAttribute.value.min_values[comp], - currentAttribute.value.max_values[comp], - ]; + const { min, max } = getAttributeRange(currentAttribute.value, comp); + attributeRange.value = [min, max]; } } diff --git a/app/components/Viewer/Options/ColorMapList.vue b/app/components/Viewer/Options/ColorMapList.vue index 19eb899c..bad60472 100644 --- a/app/components/Viewer/Options/ColorMapList.vue +++ b/app/components/Viewer/Options/ColorMapList.vue @@ -168,6 +168,7 @@ watch(filteredPresets, drawAllCanvases); + diff --git a/app/components/Viewer/Options/ColormapQuickPicker.vue b/app/components/Viewer/Options/ColormapQuickPicker.vue index a15bf137..f2b21a38 100644 --- a/app/components/Viewer/Options/ColormapQuickPicker.vue +++ b/app/components/Viewer/Options/ColormapQuickPicker.vue @@ -1,9 +1,9 @@ @@ -114,8 +48,15 @@ async function onQuickColormapSelect(preset) { > + > + + + diff --git a/app/composables/use_global_attribute_style.js b/app/composables/use_global_attribute_style.js new file mode 100644 index 00000000..ecb457bf --- /dev/null +++ b/app/composables/use_global_attribute_style.js @@ -0,0 +1,181 @@ +import back_schemas from "@geode/opengeodeweb-back/opengeodeweb_back_schemas.json"; +import { computed } from "vue"; + +import { getAttributeRange } from "@ogw_front/utils/attributes"; +import { useBackStore } from "@ogw_front/stores/back"; +import { useDataStyleStore } from "@ogw_front/stores/data_style"; +import { useHybridViewerStore } from "@ogw_front/stores/hybrid_viewer"; + +export function useGlobalAttributeStyle(dataIdRef) { + const dataStyleStore = useDataStyleStore(); + const hybridViewerStore = useHybridViewerStore(); + const backStore = useBackStore(); + + const componentNames = [ + { getterKey: "meshPoints", setterKey: "MeshPoints", key: "points" }, + { getterKey: "meshEdges", setterKey: "MeshEdges", key: "edges" }, + { getterKey: "meshPolygons", setterKey: "MeshPolygons", key: "polygons" }, + { getterKey: "meshCells", setterKey: "MeshCells", key: "cells" }, + { getterKey: "meshPolyhedra", setterKey: "MeshPolyhedra", key: "polyhedra" }, + ]; + + function getActiveComponents(targetId) { + const style = dataStyleStore.getStyle(targetId); + const activeComponents = []; + if (!style) { + return activeComponents; + } + for (const { key, getterKey, setterKey } of componentNames) { + if (!style[key] || !style[key].coloring) { + continue; + } + + const activeColoring = style[key].coloring.active; + if (!["vertex", "edge", "polygon", "cell", "polyhedron"].includes(activeColoring)) { + continue; + } + + const attributeType = `${activeColoring.charAt(0).toUpperCase()}${activeColoring.slice(1)}Attribute`; + activeComponents.push({ activeColoring, attributeType, getterKey, setterKey }); + } + return activeComponents; + } + + const currentColormap = computed(() => { + const targetId = dataIdRef.value; + if (!targetId) { + return "batlow"; + } + + for (const comp of getActiveComponents(targetId)) { + const getterName = `${comp.getterKey}${comp.attributeType}ColorMap`; + const getter = dataStyleStore[getterName]; + if (getter) { + const colorMap = getter(targetId); + if (colorMap) { + return colorMap; + } + } + } + + return "batlow"; + }); + + const currentRange = computed({ + get() { + const targetId = dataIdRef.value; + if (!targetId) { + return [0, 1]; + } + + for (const comp of getActiveComponents(targetId)) { + const getterName = `${comp.getterKey}${comp.attributeType}Range`; + const getter = dataStyleStore[getterName]; + if (getter) { + const range = getter(targetId); + if (range && range.length === 2) { + return range; + } + } + } + return [0, 1]; + }, + set(newValue) { + const targetId = dataIdRef.value; + if (!targetId) { + return; + } + + let updated = false; + for (const comp of getActiveComponents(targetId)) { + const setterName = `set${comp.setterKey}${comp.attributeType}Range`; + const setter = dataStyleStore[setterName]; + if (setter) { + setter(targetId, newValue[0], newValue[1]); + updated = true; + } + } + if (updated) { + hybridViewerStore.remoteRender(); + } + } + }); + + async function applyGlobalColormap(newMap) { + const targetId = dataIdRef.value; + if (!targetId) { + return; + } + + const promises = []; + + for (const comp of getActiveComponents(targetId)) { + const setterName = `set${comp.setterKey}${comp.attributeType}ColorMap`; + const setter = dataStyleStore[setterName]; + + if (setter) { + promises.push(setter(targetId, newMap)); + } + } + + await Promise.all(promises); + hybridViewerStore.remoteRender(); + } + + function resetGlobalRange() { + const targetId = dataIdRef.value; + if (!targetId) { + return; + } + + for (const comp of getActiveComponents(targetId)) { + const { activeColoring, attributeType, getterKey, setterKey } = comp; + + const nameGetter = dataStyleStore[`${getterKey}${attributeType}Name`]; + const itemGetter = dataStyleStore[`${getterKey}${attributeType}Item`]; + if (!nameGetter || !itemGetter) { + continue; + } + + const attrName = nameGetter(targetId); + const attrItem = itemGetter(targetId) ?? 0; + + if (!attrName) { + continue; + } + + const schemaName = `${activeColoring}_attribute_names`; + const schema = back_schemas.opengeodeweb_back[schemaName]; + if (!schema) { + continue; + } + + backStore.request( + { schema, params: { id: targetId } }, + { + response_function: (response) => { + const attributes = response.attributes || []; + const currentAttribute = attributes.find((attr) => attr.attribute_name === attrName); + if (currentAttribute) { + const { min, max } = getAttributeRange(currentAttribute, attrItem); + + const setterName = `set${setterKey}${attributeType}Range`; + const setter = dataStyleStore[setterName]; + if (setter) { + setter(targetId, min, max); + hybridViewerStore.remoteRender(); + } + } + }, + }, + ); + } + } + + return { + currentColormap, + currentRange, + applyGlobalColormap, + resetGlobalRange, + }; +} diff --git a/app/utils/attributes.js b/app/utils/attributes.js new file mode 100644 index 00000000..20a34de2 --- /dev/null +++ b/app/utils/attributes.js @@ -0,0 +1,23 @@ +export function getAttributeRange(currentAttribute, compIndex = 0) { + if (!currentAttribute) { + return { min: 0, max: 1 }; + } + + const { min_values, max_values, min_value, max_value } = currentAttribute; + let min = 0; + let max = 1; + + if (min_values && min_values[compIndex] !== undefined) { + min = min_values[compIndex]; + } else if (compIndex === 0 && min_value !== undefined) { + min = min_value; + } + + if (max_values && max_values[compIndex] !== undefined) { + max = max_values[compIndex]; + } else if (compIndex === 0 && max_value !== undefined) { + max = max_value; + } + + return { min, max }; +} From b3c47060593d35014c387a262abd6404d744828c Mon Sep 17 00:00:00 2001 From: SpliiT <106495600+SpliiT@users.noreply.github.com> Date: Wed, 26 Aug 2026 14:30:38 +0000 Subject: [PATCH 2/4] Apply prepare changes --- app/composables/use_global_attribute_style.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/composables/use_global_attribute_style.js b/app/composables/use_global_attribute_style.js index ecb457bf..e384590f 100644 --- a/app/composables/use_global_attribute_style.js +++ b/app/composables/use_global_attribute_style.js @@ -67,7 +67,7 @@ export function useGlobalAttributeStyle(dataIdRef) { if (!targetId) { return [0, 1]; } - + for (const comp of getActiveComponents(targetId)) { const getterName = `${comp.getterKey}${comp.attributeType}Range`; const getter = dataStyleStore[getterName]; @@ -85,7 +85,7 @@ export function useGlobalAttributeStyle(dataIdRef) { if (!targetId) { return; } - + let updated = false; for (const comp of getActiveComponents(targetId)) { const setterName = `set${comp.setterKey}${comp.attributeType}Range`; @@ -98,7 +98,7 @@ export function useGlobalAttributeStyle(dataIdRef) { if (updated) { hybridViewerStore.remoteRender(); } - } + }, }); async function applyGlobalColormap(newMap) { From 057dec8e6ed0f240e99dce5fcaface78b6502d49 Mon Sep 17 00:00:00 2001 From: Tao Schiro Date: Wed, 26 Aug 2026 16:36:55 +0200 Subject: [PATCH 3/4] remove use prefix --- app/components/Viewer/Options/ColormapQuickPicker.vue | 2 +- ...{use_global_attribute_style.js => global_attribute_style.js} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename app/composables/{use_global_attribute_style.js => global_attribute_style.js} (100%) diff --git a/app/components/Viewer/Options/ColormapQuickPicker.vue b/app/components/Viewer/Options/ColormapQuickPicker.vue index f2b21a38..7c2221df 100644 --- a/app/components/Viewer/Options/ColormapQuickPicker.vue +++ b/app/components/Viewer/Options/ColormapQuickPicker.vue @@ -3,7 +3,7 @@ import AttributeRangeSelector from "@ogw_front/components/Viewer/Options/Attribu import ColorMapList from "@ogw_front/components/Viewer/Options/ColorMapList.vue"; import { getPresetsWithCurrentAtTop } from "@ogw_front/utils/colormap"; -import { useGlobalAttributeStyle } from "@ogw_front/composables/use_global_attribute_style"; +import { useGlobalAttributeStyle } from "@ogw_front/composables/global_attribute_style"; const { dataId, x, y } = defineProps({ dataId: { required: false, type: String, default: undefined }, diff --git a/app/composables/use_global_attribute_style.js b/app/composables/global_attribute_style.js similarity index 100% rename from app/composables/use_global_attribute_style.js rename to app/composables/global_attribute_style.js From da0bc742fa885300b3bca367153e463f0b0aae3d Mon Sep 17 00:00:00 2001 From: Tao Schiro Date: Thu, 27 Aug 2026 12:03:30 +0200 Subject: [PATCH 4/4] data test id --- app/components/Viewer/Options/AttributeRangeSelector.vue | 2 ++ app/components/Viewer/Options/AttributeSelector.vue | 1 + 2 files changed, 3 insertions(+) diff --git a/app/components/Viewer/Options/AttributeRangeSelector.vue b/app/components/Viewer/Options/AttributeRangeSelector.vue index d7d6427c..32a51928 100644 --- a/app/components/Viewer/Options/AttributeRangeSelector.vue +++ b/app/components/Viewer/Options/AttributeRangeSelector.vue @@ -22,6 +22,8 @@ const maximum = defineModel("maximum", { type: Number }); import ViewerOptionsAttributeColorBar from "@ogw_front/components/Viewer/Options/AttributeColorBar.vue"; +import { getAttributeRange } from "@ogw_front/utils/attributes"; import { useBackStore } from "@ogw_front/stores/back"; const backStore = useBackStore();