Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
5af6fc6
temp
MaxNumerique May 13, 2026
f002da1
Merge branch 'next' of https://github.com/Geode-solutions/OpenGeodeWe…
MaxNumerique May 13, 2026
f0e4548
Apply prepare changes
MaxNumerique May 13, 2026
fe7eedb
Merge branch 'next' of https://github.com/Geode-solutions/OpenGeodeWe…
MaxNumerique May 13, 2026
f1fc4c7
Merge branch 'feat/highlightVertex' of https://github.com/Geode-solut…
MaxNumerique May 13, 2026
45a718c
Merge branch 'next' of https://github.com/Geode-solutions/OpenGeodeWe…
MaxNumerique May 15, 2026
7cb8aaa
Merge branch 'next' of https://github.com/Geode-solutions/OpenGeodeWe…
MaxNumerique May 15, 2026
c19b4c5
Merge branch 'feat/highlightVertex' of https://github.com/Geode-solut…
MaxNumerique May 15, 2026
bf8b503
refacto
MaxNumerique May 15, 2026
566687f
Merge branch 'feat/highlightVertex' of https://github.com/Geode-solut…
MaxNumerique May 15, 2026
f4e7e37
refacto
MaxNumerique May 15, 2026
be80859
refacto
MaxNumerique May 15, 2026
2446fe3
Apply prepare changes
MaxNumerique May 15, 2026
2ce2882
refacto ?
MaxNumerique May 15, 2026
6244978
Merge branch 'next' of https://github.com/Geode-solutions/OpenGeodeWe…
MaxNumerique May 15, 2026
acee510
Apply prepare changes
MaxNumerique May 15, 2026
2735630
refacto + new file
MaxNumerique May 15, 2026
6310946
Apply prepare changes
MaxNumerique May 15, 2026
f741af3
oxlint
MaxNumerique May 15, 2026
f178607
Merge branch 'feat/highlightVertex' of https://github.com/Geode-solut…
MaxNumerique May 15, 2026
b2ef83e
sub tools
MaxNumerique May 15, 2026
2f2a606
Apply prepare changes
MaxNumerique May 15, 2026
6d10e6a
icons
MaxNumerique May 15, 2026
b5078c3
Merge branch 'feat/highlightVertex' of https://github.com/Geode-solut…
MaxNumerique May 15, 2026
983c9e5
Merge branch 'next' of https://github.com/Geode-solutions/OpenGeodeWe…
MaxNumerique May 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/components/CameraOrientation.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script setup>
import ToolPanel from "@ogw_front/components/ToolPanel";
import { applyCameraOptions } from "@ogw_internal/stores/hybrid_viewer";
import { applyCameraOptions } from "@ogw_internal/stores/hybrid_viewer_camera";
import { useHybridViewerStore } from "@ogw_front/stores/hybrid_viewer";
import { newInstance as vtkAnnotatedCubeActor } from "@kitware/vtk.js/Rendering/Core/AnnotatedCubeActor";
import { newInstance as vtkGenericRenderWindow } from "@kitware/vtk.js/Rendering/Misc/GenericRenderWindow";
Expand Down
82 changes: 79 additions & 3 deletions app/components/ViewToolbar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ async function handleZScalingClose() {
showZScaling.value = false;
}

const camera_options = [
const camera_options = computed(() => [
{
tooltip: "Reset camera",
icon: "mdi-cube-scan",
Expand All @@ -41,10 +41,50 @@ const camera_options = [
{
tooltip: "Center on click",
icon: "mdi-crosshairs-question",
color: hybridViewerStore.is_picking ? "primary" : undefined,
action: () => {
hybridViewerStore.is_picking = !hybridViewerStore.is_picking;
},
},
{
tooltip: "Highlight on hover",
icon: "mdi-cursor-default-click",
color: hybridViewerStore.is_hover_highlight ? "primary" : undefined,
menu: [
{
title: "Cells",
icon: "mdi-select-all",
action: () => {
if (
hybridViewerStore.is_hover_highlight &&
hybridViewerStore.hover_highlight_field_type === "CELL"
) {
hybridViewerStore.is_hover_highlight = false;
hybridViewerStore.clearHoverHighlight();
} else {
hybridViewerStore.is_hover_highlight = true;
hybridViewerStore.hover_highlight_field_type = "CELL";
}
},
},
{
title: "Points",
icon: "mdi-select-drag",
action: () => {
if (
hybridViewerStore.is_hover_highlight &&
hybridViewerStore.hover_highlight_field_type === "POINT"
) {
hybridViewerStore.is_hover_highlight = false;
hybridViewerStore.clearHoverHighlight();
} else {
hybridViewerStore.is_hover_highlight = true;
hybridViewerStore.hover_highlight_field_type = "POINT";
}
},
},
],
},
{
tooltip: "Camera orientation",
icon: "mdi-rotate-3d",
Expand All @@ -70,6 +110,7 @@ const camera_options = [
{
tooltip: "Toggle grid scale",
icon: "mdi-ruler-square",
color: grid_scale.value ? "primary" : undefined,
action: () => {
viewerStore.request(
schemas.opengeodeweb_viewer.viewer.grid_scale,
Expand All @@ -90,19 +131,54 @@ const camera_options = [
showZScaling.value = !showZScaling.value;
},
},
];
]);
</script>

<template>
<v-container :class="[$style.floatToolbar, 'pa-0']" width="auto">
<v-row v-for="camera_option in camera_options" :key="camera_option.icon" dense>
<v-col>
<v-menu v-if="camera_option.menu" location="start" :close-on-content-click="false">
<template #activator="{ props }">
<ActionButton
v-bind="props"
:icon="
typeof camera_option.icon === 'function' ? camera_option.icon() : camera_option.icon
"
:tooltip="camera_option.tooltip"
:color="camera_option.color"
:icon-size="camera_option.iconSize"
tooltip-location="left"
/>
</template>
<v-card class="pa-1 mr-2" elevation="4" rounded="pill">
<v-row dense>
<v-col v-for="item in camera_option.menu" :key="item.title">
<ActionButton
:icon="item.icon"
:tooltip="item.title"
:color="
hybridViewerStore.is_hover_highlight &&
hybridViewerStore.hover_highlight_field_type ===
item.title.toUpperCase().slice(0, -1)
? 'primary'
: undefined
"
tooltip-location="top"
@click="item.action"
/>
</v-col>
</v-row>
</v-card>
</v-menu>
<ActionButton
v-else
:icon="camera_option.icon"
:tooltip="camera_option.tooltip"
:color="camera_option.color"
:icon-size="camera_option.iconSize"
tooltip-location="left"
@click.stop="camera_option.action"
@click.stop="camera_option.action?.()"
/>
</v-col>
</v-row>
Expand Down
180 changes: 80 additions & 100 deletions app/stores/hybrid_viewer.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,24 @@
import {
ACTOR_COLOR,
BACKGROUND_COLOR,
HOVER_THROTTLE_MS,
WHEEL_TIME_OUT_MS,
applySnapshot,
computeAverageBrightness,
performAddItem,
performClearHoverHighlight,
performClickPicking,
performHoverHighlight,
performSetContainer,
performSetZScaling,
} from "@ogw_internal/stores/hybrid_viewer";
import {
applySnapshot,
getCameraOptions,
performCameraOrientation,
performClickPicking,
performFocusCameraOnObject,
performSetCamera,
} from "@ogw_internal/stores/hybrid_viewer";
performSyncRemoteCamera,
} from "@ogw_internal/stores/hybrid_viewer_camera";
import { newInstance as vtkActor } from "@kitware/vtk.js/Rendering/Core/Actor";
import { newInstance as vtkGenericRenderWindow } from "@kitware/vtk.js/Rendering/Misc/GenericRenderWindow";
import { newInstance as vtkMapper } from "@kitware/vtk.js/Rendering/Core/Mapper";
Expand All @@ -30,6 +39,8 @@ export const useHybridViewerStore = defineStore("hybridViewer", () => {
const status = ref(Status.NOT_CREATED);
const is_moving = ref(false);
const is_picking = ref(false);
const is_hover_highlight = ref(false);
const hover_highlight_field_type = ref("CELL");
const zScale = ref(1);
let imageStyle = undefined;
let viewStream = undefined;
Expand Down Expand Up @@ -83,25 +94,15 @@ export const useHybridViewerStore = defineStore("hybridViewer", () => {
}

async function addItem(id) {
if (!genericRenderWindow.value) {
return;
}
const reader = vtkXMLPolyDataReader();
const value = await dataStore.item(id);
await reader.parseAsArrayBuffer(new TextEncoder().encode(value.binary_light_viewable));
const actor = vtkActor();
const mapper = vtkMapper();
const polydata = reader.getOutputData(0);
mapper.setInputData(polydata);
actor.getProperty().setColor(ACTOR_COLOR);
actor.setMapper(mapper);
const renderer = genericRenderWindow.value.getRenderer();
const isFirst = renderer.getActors().length === 0;
renderer.addActor(actor);
if (isFirst) {
renderer.resetCamera();
}
hybridDb[id] = { actor, polydata, mapper };
await performAddItem(id, {
genericRenderWindow: genericRenderWindow.value,
dataStore,
vtkXMLPolyDataReader,
vtkActor,
vtkMapper,
actorColor: ACTOR_COLOR,
hybridDb,
});
}

function removeItem(id) {
Expand All @@ -122,21 +123,14 @@ export const useHybridViewerStore = defineStore("hybridViewer", () => {
}

async function setZScaling(z_scale) {
zScale.value = z_scale;
const renderer = genericRenderWindow.value.getRenderer();
for (const actor of renderer.getActors()) {
if (actor !== gridActor) {
const scale = actor.getScale();
actor.setScale(scale[0], scale[1], z_scale);
}
}
renderer.resetCamera();
genericRenderWindow.value.getRenderWindow().render();
const schema = viewer_schemas?.opengeodeweb_viewer?.viewer?.set_z_scaling;
if (schema) {
await viewerStore.request(schema, { z_scale });
}
remoteRender();
await performSetZScaling(z_scale, {
zScale,
genericRenderWindow: genericRenderWindow.value,
gridActor,
viewerStore,
viewer_schemas,
remoteRender,
});
}

function resetCamera() {
Expand Down Expand Up @@ -177,76 +171,59 @@ export const useHybridViewerStore = defineStore("hybridViewer", () => {
}

function syncRemoteCamera() {
const camera = genericRenderWindow.value.getRenderer().getActiveCamera();
const options = getCameraOptions(camera);
viewerStore.request(
viewer_schemas.opengeodeweb_viewer.viewer.update_camera,
{ camera_options: options },
{
response_function: () => {
remoteRender();
Object.assign(camera_options, options);
},
},
);
performSyncRemoteCamera({
genericRenderWindow: genericRenderWindow.value,
viewerStore,
viewer_schemas,
remoteRender,
camera_options,
});
}

function remoteRender() {
return viewerStore.request(viewer_schemas.opengeodeweb_viewer.viewer.render);
}

function setContainer(container) {
if (!container.value) {
return;
}
genericRenderWindow.value.setContainer(container.value.$el);
const webGLRenderWindow = genericRenderWindow.value.getApiSpecificRenderWindow();
webGLRenderWindow.setUseBackgroundImage(true);
imageStyle = webGLRenderWindow.getReferenceByName("bgImage").style;
Object.assign(imageStyle, { transition: "opacity 0.1s ease-in", zIndex: 1 });
resize(container.value.$el.offsetWidth, container.value.$el.offsetHeight);
useMousePressed({
target: container,
onPressed: (event) => {
if (event.button !== 0) {
return;
}
if (is_picking.value) {
performClickPicking(event, {
container: container.value.$el,
viewerStore,
viewer_schemas,
genericRenderWindow: genericRenderWindow.value,
syncRemoteCamera,
});
is_picking.value = false;
return;
}
is_moving.value = true;
event.stopPropagation();
imageStyle.opacity = 0;
},
onReleased: () => {
if (is_moving.value) {
is_moving.value = false;
syncRemoteCamera();
}
is_moving.value = false;
genericRenderWindow.value.getRenderer().resetCameraClippingRange();
syncRemoteCamera();
},
const throttledHoverHighlight = useThrottleFn(
(event) =>
performHoverHighlight(event, {
is_hover_highlight,
genericRenderWindow: genericRenderWindow.value,
viewerStore,
viewer_schemas,
hover_highlight_field_type,
hybridDb,
}),
HOVER_THROTTLE_MS,
);

function clearHoverHighlight() {
performClearHoverHighlight({
viewerStore,
viewer_schemas,
hover_highlight_field_type,
hybridDb,
});
useEventListener(container, "wheel", () => {
is_moving.value = true;
if (imageStyle) {
imageStyle.opacity = 0;
}
clearTimeout(wheelEventEndTimeout);
wheelEventEndTimeout = setTimeout(() => {
is_moving.value = false;
genericRenderWindow.value.getRenderer().resetCameraClippingRange();
syncRemoteCamera();
}, WHEEL_TIME_OUT_MS);
}

function setContainer(container) {
performSetContainer({
container,
genericRenderWindow: genericRenderWindow.value,
imageStyleSetter: (style) => (imageStyle = style),
resize,
useMousePressed,
useEventListener,
is_picking,
is_moving,
clickPickingCallback: performClickPicking,
viewerStore,
viewer_schemas,
syncRemoteCamera,
throttledHoverHighlight,
wheelTimeoutMs: WHEEL_TIME_OUT_MS,
wheelEventEndTimeout,
wheelTimeoutSetter: (timeout) => (wheelEventEndTimeout = timeout),
});
}

Expand Down Expand Up @@ -317,6 +294,9 @@ export const useHybridViewerStore = defineStore("hybridViewer", () => {
setContainer,
zScale,
is_picking,
is_hover_highlight,
hover_highlight_field_type,
clearHoverHighlight,
clear,
exportStores,
importStores,
Expand Down
Loading
Loading