From ebdd9905fdd6a6f65140bfa9cc871bc05d58311a Mon Sep 17 00:00:00 2001 From: MaxNumerique Date: Fri, 14 Aug 2026 14:56:33 +0200 Subject: [PATCH 1/7] feat(ruler): Add ruler tool --- app/components/HybridRenderingView.vue | 8 ++ app/components/Ruler.vue | 144 ++++++++++++++++++++++++ app/components/ViewToolbar.vue | 12 ++ app/components/Viewer/Ui.vue | 28 ++++- app/stores/hybrid_viewer.js | 24 ++-- internal/stores/hybrid_viewer/camera.js | 70 ++++++++++++ internal/stores/hybrid_viewer/ruler.js | 129 +++++++++++++++++++++ 7 files changed, 405 insertions(+), 10 deletions(-) create mode 100644 app/components/Ruler.vue create mode 100644 internal/stores/hybrid_viewer/ruler.js diff --git a/app/components/HybridRenderingView.vue b/app/components/HybridRenderingView.vue index 5100f4d7..d019b0e3 100644 --- a/app/components/HybridRenderingView.vue +++ b/app/components/HybridRenderingView.vue @@ -55,6 +55,14 @@ function debounce(func, wait) { async function handleClick(event) { const { offsetX, offsetY, clientX, clientY } = event; + if (hybridViewerStore.is_ruler_active) { + const rect = container.value.$el.getBoundingClientRect(); + const x = event.clientX - rect.left; + const y = elementHeight.value - (event.clientY - rect.top); + await hybridViewerStore.handleRulerClick(x, y); + return; + } + if (viewerStore.picking_mode) { const rect = container.value.$el.getBoundingClientRect(); const x = event.clientX - rect.left; diff --git a/app/components/Ruler.vue b/app/components/Ruler.vue new file mode 100644 index 00000000..365f222e --- /dev/null +++ b/app/components/Ruler.vue @@ -0,0 +1,144 @@ + + + diff --git a/app/components/ViewToolbar.vue b/app/components/ViewToolbar.vue index c6065cfd..c8178901 100644 --- a/app/components/ViewToolbar.vue +++ b/app/components/ViewToolbar.vue @@ -4,6 +4,7 @@ import CameraBookmarkIcon from "@ogw_front/assets/viewer_svgs/camera-bookmark.sv import CameraManager from "@ogw_front/components/CameraManager"; import CameraOrientation from "@ogw_front/components/CameraOrientation"; import ClippingPlanes from "@ogw_front/components/ClippingPlanes"; +import Ruler from "@ogw_front/components/Ruler"; import Screenshot from "@ogw_front/components/Screenshot"; import ShrinkFilter from "@ogw_front/components/ShrinkFilter"; import ZScaling from "@ogw_front/components/ZScaling"; @@ -19,6 +20,7 @@ const showCameraOrientation = ref(false); const showZScaling = ref(false); const showClippingPlanes = ref(false); const showShrinkFilter = ref(false); +const showRuler = ref(false); const grid_scale = ref(false); const zScale = ref(hybridViewerStore.zScale); @@ -173,6 +175,15 @@ const camera_options = computed(() => [ showShrinkFilter.value = !showShrinkFilter.value; }, }, + { + testId: "rulerButton", + tooltip: "Ruler", + icon: "mdi-ruler", + color: showRuler.value ? "primary" : undefined, + action: () => { + showRuler.value = !showRuler.value; + }, + }, ]); @@ -247,6 +258,7 @@ const camera_options = computed(() => [ /> +