@geode/opengeodeweb-front 10.31.0 → 10.32.0-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.
@@ -3,8 +3,11 @@ import {
3
3
  SHORT_ANIMATION_DURATION,
4
4
  animateCamera,
5
5
  computeAnimationDuration,
6
- } from "@ogw_internal/stores/hybrid_viewer_camera_animation";
6
+ } from "./camera_animation";
7
7
  import { dot } from "@kitware/vtk.js/Common/Core/Math";
8
+ import { useHybridViewerStore } from "@ogw_front/stores/hybrid_viewer";
9
+ import { useViewerStore } from "@ogw_front/stores/viewer";
10
+ import viewer_schemas from "@geode/opengeodeweb-viewer/opengeodeweb_viewer_schemas.json";
8
11
 
9
12
  const BUMP_MULTIPLIER = 0.2;
10
13
  const ALIGNMENT_THRESHOLD = 0.9;
@@ -19,8 +22,59 @@ const ORIENTATIONS = {
19
22
  xminus: { position: [-1, 0, 0], view_up: [0, 0, 1] },
20
23
  };
21
24
 
25
+ function getImageStyle() {
26
+ const { genericRenderWindow } = useHybridViewerStore();
27
+ if (!genericRenderWindow.value) {
28
+ return undefined;
29
+ }
30
+ const webGLRenderWindow = genericRenderWindow.value.getApiSpecificRenderWindow();
31
+ if (!webGLRenderWindow) {
32
+ return undefined;
33
+ }
34
+ const bgImage = webGLRenderWindow.getReferenceByName("bgImage");
35
+ return bgImage ? bgImage.style : undefined;
36
+ }
37
+
38
+ function useHybridViewerCamera() {
39
+ const camera_options = reactive({});
40
+
41
+ function syncRemoteCamera() {
42
+ performSyncRemoteCamera();
43
+ }
44
+
45
+ function setCamera(targetCameraOptions) {
46
+ performSetCamera(targetCameraOptions);
47
+ }
48
+
49
+ function resetCamera() {
50
+ const { genericRenderWindow } = useHybridViewerStore();
51
+ const renderer = genericRenderWindow.value.getRenderer();
52
+ renderer.resetCamera();
53
+ const renderWindow = genericRenderWindow.value.getRenderWindow();
54
+ renderWindow.render();
55
+ syncRemoteCamera();
56
+ }
57
+
58
+ async function focusCameraOnObject(id, block_ids = []) {
59
+ await performFocusCameraOnObject(id, block_ids);
60
+ }
61
+
62
+ function setCameraOrientation(orientation) {
63
+ performCameraOrientation(orientation);
64
+ }
65
+
66
+ return {
67
+ camera_options,
68
+ syncRemoteCamera,
69
+ setCamera,
70
+ resetCamera,
71
+ focusCameraOnObject,
72
+ setCameraOrientation,
73
+ };
74
+ }
75
+
22
76
  function getCameraOptions(camera) {
23
- if (!camera?.getFocalPoint) {
77
+ if (!camera || !camera.getFocalPoint) {
24
78
  return camera;
25
79
  }
26
80
  return {
@@ -34,7 +88,7 @@ function getCameraOptions(camera) {
34
88
  }
35
89
 
36
90
  function applyCameraOptions(camera, options) {
37
- if (camera?.set && options) {
91
+ if (camera && camera.set && options) {
38
92
  camera.set({
39
93
  focalPoint: options.focal_point,
40
94
  viewUp: options.view_up,
@@ -59,9 +113,13 @@ function centerCameraOnPosition(camera, pickedPosition) {
59
113
  );
60
114
  }
61
115
 
62
- function performSetCamera(targetCameraOptions, options) {
63
- const { genericRenderWindow, is_moving, imageStyle, syncRemoteCamera } = options;
64
- const camera = genericRenderWindow.getRenderer().getActiveCamera();
116
+ function performSetCamera(targetCameraOptions) {
117
+ const hybridViewerStore = useHybridViewerStore();
118
+ const { genericRenderWindow, syncRemoteCamera } = hybridViewerStore;
119
+ const { is_moving } = storeToRefs(hybridViewerStore);
120
+ const imageStyle = getImageStyle();
121
+ const renderer = genericRenderWindow.value.getRenderer();
122
+ const camera = renderer.getActiveCamera();
65
123
  const startState = getCameraOptions(camera);
66
124
  const duration = computeAnimationDuration(startState, targetCameraOptions);
67
125
  is_moving.value = true;
@@ -75,20 +133,27 @@ function performSetCamera(targetCameraOptions, options) {
75
133
  duration,
76
134
  bumpMultiplier: 0,
77
135
  easeExponent: EASE_EXPONENT,
78
- onUpdate: () => genericRenderWindow.getRenderWindow().render(),
136
+ onUpdate: () => {
137
+ const renderWindow = genericRenderWindow.value.getRenderWindow();
138
+ renderWindow.render();
139
+ },
79
140
  onEnd: () => {
80
141
  applyCameraOptions(camera, targetCameraOptions);
81
- genericRenderWindow.getRenderWindow().render();
142
+ const renderWindow = genericRenderWindow.value.getRenderWindow();
143
+ renderWindow.render();
82
144
  is_moving.value = false;
83
145
  syncRemoteCamera();
84
146
  },
85
147
  });
86
148
  }
87
149
 
88
- function performCameraOrientation(orientation, options) {
89
- const { genericRenderWindow, is_moving, imageStyle, syncRemoteCamera } = options;
150
+ function performCameraOrientation(orientation) {
151
+ const hybridViewerStore = useHybridViewerStore();
152
+ const { genericRenderWindow, syncRemoteCamera } = hybridViewerStore;
153
+ const { is_moving } = storeToRefs(hybridViewerStore);
154
+ const imageStyle = getImageStyle();
90
155
  const config = ORIENTATIONS[orientation.toLowerCase()];
91
- const renderer = genericRenderWindow.getRenderer();
156
+ const renderer = genericRenderWindow.value.getRenderer();
92
157
  const camera = renderer.getActiveCamera();
93
158
  const startState = getCameraOptions(camera);
94
159
 
@@ -105,7 +170,9 @@ function performCameraOrientation(orientation, options) {
105
170
  const duration =
106
171
  alignment > ALIGNMENT_THRESHOLD ? LONG_ANIMATION_DURATION : SHORT_ANIMATION_DURATION;
107
172
  is_moving.value = true;
108
- imageStyle.opacity = 0;
173
+ if (imageStyle) {
174
+ imageStyle.opacity = 0;
175
+ }
109
176
 
110
177
  animateCamera({
111
178
  camera,
@@ -114,7 +181,10 @@ function performCameraOrientation(orientation, options) {
114
181
  duration,
115
182
  bumpMultiplier: BUMP_MULTIPLIER,
116
183
  easeExponent: EASE_EXPONENT,
117
- onUpdate: () => genericRenderWindow.getRenderWindow().render(),
184
+ onUpdate: () => {
185
+ const renderWindow = genericRenderWindow.value.getRenderWindow();
186
+ renderWindow.render();
187
+ },
118
188
  onEnd: () => {
119
189
  is_moving.value = false;
120
190
  syncRemoteCamera();
@@ -122,22 +192,14 @@ function performCameraOrientation(orientation, options) {
122
192
  });
123
193
  }
124
194
 
125
- async function performFocusCameraOnObject(id, options) {
126
- const {
127
- hybridDb,
128
- viewerStore,
129
- viewer_schemas,
130
- genericRenderWindow,
131
- block_ids = [],
132
- is_moving,
133
- imageStyle,
134
- syncRemoteCamera,
135
- } = options;
195
+ async function performFocusCameraOnObject(id, block_ids = []) {
196
+ const { genericRenderWindow, hybridDb } = useHybridViewerStore();
136
197
 
137
198
  if (!hybridDb[id]) {
138
199
  return;
139
200
  }
140
201
 
202
+ const viewerStore = useViewerStore();
141
203
  let bounds = [];
142
204
  if (block_ids.length > 0) {
143
205
  const schema = viewer_schemas.opengeodeweb_viewer.model.get_blocks_bounds;
@@ -147,25 +209,21 @@ async function performFocusCameraOnObject(id, options) {
147
209
  bounds = hybridDb[id].actor.getBounds();
148
210
  }
149
211
 
150
- const renderer = genericRenderWindow.getRenderer();
212
+ const renderer = genericRenderWindow.value.getRenderer();
151
213
  const camera = renderer.getActiveCamera();
152
214
  const startOptions = getCameraOptions(camera);
153
215
  renderer.resetCamera(bounds);
154
216
  const targetOptions = getCameraOptions(camera);
155
217
  applyCameraOptions(camera, startOptions);
156
218
 
157
- performSetCamera(targetOptions, {
158
- genericRenderWindow,
159
- is_moving,
160
- imageStyle,
161
- syncRemoteCamera,
162
- });
219
+ performSetCamera(targetOptions);
163
220
  }
164
221
 
165
- function performSyncRemoteCamera(options) {
166
- const { genericRenderWindow, viewerStore, viewer_schemas, remoteRender, camera_options } =
167
- options;
168
- const camera = genericRenderWindow.getRenderer().getActiveCamera();
222
+ function performSyncRemoteCamera() {
223
+ const { genericRenderWindow, camera_options, remoteRender } = useHybridViewerStore();
224
+ const viewerStore = useViewerStore();
225
+ const renderer = genericRenderWindow.value.getRenderer();
226
+ const camera = renderer.getActiveCamera();
169
227
  const options_camera = getCameraOptions(camera);
170
228
  const schema = viewer_schemas.opengeodeweb_viewer.viewer.update_camera;
171
229
  const params = { camera_options: options_camera };
@@ -177,39 +235,30 @@ function performSyncRemoteCamera(options) {
177
235
  {
178
236
  response_function: () => {
179
237
  remoteRender();
180
- Object.assign(camera_options, options_camera);
238
+ if (camera_options) {
239
+ Object.assign(camera_options, options_camera);
240
+ }
181
241
  },
182
242
  },
183
243
  );
184
244
  }
185
245
 
186
- async function applySnapshot(snapshot, options) {
187
- const { genericRenderWindow, setZScaling, syncRemoteCamera, setCamera } = options;
246
+ async function applySnapshot(snapshot) {
188
247
  if (!snapshot) {
189
248
  return;
190
249
  }
191
- const z_scale = snapshot.zScale;
192
- if (typeof z_scale === "number") {
193
- await setZScaling(z_scale);
194
- }
195
- const { camera_options: snapshot_camera_options } = snapshot;
196
- if (snapshot_camera_options) {
197
- if (setCamera) {
198
- setCamera(snapshot_camera_options);
199
- } else {
200
- applyCameraOptions(
201
- genericRenderWindow.getRenderer().getActiveCamera(),
202
- snapshot_camera_options,
203
- );
204
- genericRenderWindow.getRenderWindow().render();
205
- syncRemoteCamera();
206
- }
250
+ const { setZScaling, setCamera } = useHybridViewerStore();
251
+ if (typeof snapshot.zScale === "number") {
252
+ await setZScaling(snapshot.zScale);
253
+ }
254
+ if (snapshot.camera_options) {
255
+ setCamera(snapshot.camera_options);
207
256
  }
208
257
  }
209
258
 
210
259
  export {
211
- BUMP_MULTIPLIER,
212
260
  ALIGNMENT_THRESHOLD,
261
+ BUMP_MULTIPLIER,
213
262
  EASE_EXPONENT,
214
263
  ORIENTATIONS,
215
264
  applyCameraOptions,
@@ -220,4 +269,5 @@ export {
220
269
  performFocusCameraOnObject,
221
270
  performSetCamera,
222
271
  performSyncRemoteCamera,
272
+ useHybridViewerCamera,
223
273
  };
@@ -0,0 +1,38 @@
1
+ import { useHybridViewerStore } from "@ogw_front/stores/hybrid_viewer";
2
+ import { useViewerStore } from "@ogw_front/stores/viewer";
3
+ import viewer_schemas from "@geode/opengeodeweb-viewer/opengeodeweb_viewer_schemas.json";
4
+
5
+ function useHybridViewerFilters() {
6
+ async function setClippingPlanes(ids, planes) {
7
+ await performSetClippingPlanes(ids, planes);
8
+ }
9
+
10
+ async function setShrink(ids, shrink_factor) {
11
+ await performSetShrink(ids, shrink_factor);
12
+ }
13
+
14
+ return {
15
+ setClippingPlanes,
16
+ setShrink,
17
+ };
18
+ }
19
+
20
+ async function performSetClippingPlanes(ids, planes) {
21
+ const viewerStore = useViewerStore();
22
+ const { remoteRender } = useHybridViewerStore();
23
+ const schema = viewer_schemas.opengeodeweb_viewer.viewer.clipping_planes;
24
+ const params = { ids, planes };
25
+ await viewerStore.request({ schema, params });
26
+ await remoteRender();
27
+ }
28
+
29
+ async function performSetShrink(ids, shrink_factor) {
30
+ const viewerStore = useViewerStore();
31
+ const { remoteRender } = useHybridViewerStore();
32
+ const schema = viewer_schemas.opengeodeweb_viewer.viewer.shrink;
33
+ const params = { ids, shrink_factor };
34
+ await viewerStore.request({ schema, params });
35
+ await remoteRender();
36
+ }
37
+
38
+ export { performSetClippingPlanes, performSetShrink, useHybridViewerFilters };
@@ -0,0 +1,162 @@
1
+ import { HOVER_DEBOUNCE_MS, HOVER_TIMEOUT_MS } from "./constants";
2
+ import { database } from "@ogw_internal/database/database.js";
3
+ import { useHybridViewerStore } from "@ogw_front/stores/hybrid_viewer";
4
+ import { useViewerStore } from "@ogw_front/stores/viewer";
5
+ import viewer_schemas from "@geode/opengeodeweb-viewer/opengeodeweb_viewer_schemas.json";
6
+
7
+ function useHybridViewerHighlight() {
8
+ const is_hover_highlight = ref(false);
9
+ const hover_highlight_field_type = ref("CELL");
10
+ const hoverData = ref(undefined);
11
+ const hoverPosition = ref({ x: 0, y: 0 });
12
+ const hoverTimeoutRef = ref(undefined);
13
+ const currentHoverId = ref(undefined);
14
+
15
+ const clearHoverData = createClearHoverData(hoverTimeoutRef, hoverData, currentHoverId);
16
+
17
+ const hoverHighlight = createHoverHighlight({ hoverTimeoutRef, currentHoverId, clearHoverData });
18
+
19
+ function clearHoverHighlight() {
20
+ clearHoverData();
21
+ performClearHoverHighlight();
22
+ }
23
+
24
+ return {
25
+ is_hover_highlight,
26
+ hover_highlight_field_type,
27
+ hoverData,
28
+ hoverPosition,
29
+ clearHoverHighlight,
30
+ hoverHighlight,
31
+ };
32
+ }
33
+
34
+ function performHoverHighlight(event, onResponse) {
35
+ const hybridViewerStore = useHybridViewerStore();
36
+ const { genericRenderWindow, hybridDb } = hybridViewerStore;
37
+ const { is_hover_highlight, hover_highlight_field_type } = storeToRefs(hybridViewerStore);
38
+ if (!is_hover_highlight.value) {
39
+ return;
40
+ }
41
+ const container = genericRenderWindow.value?.getContainer();
42
+ if (!container) {
43
+ return;
44
+ }
45
+ const viewerStore = useViewerStore();
46
+ const rect = container.getBoundingClientRect();
47
+ const schema = viewer_schemas.opengeodeweb_viewer.viewer.highlight;
48
+ const params = {
49
+ x: Math.round(event.clientX - rect.left),
50
+ y: Math.round(rect.height - (event.clientY - rect.top)),
51
+ field_type: hover_highlight_field_type.value,
52
+ ids: Object.keys(hybridDb),
53
+ };
54
+ viewerStore.request({ schema, params }, { response_function: onResponse });
55
+ }
56
+
57
+ function performClearHoverHighlight() {
58
+ const { hybridDb } = useHybridViewerStore();
59
+ const { hover_highlight_field_type } = storeToRefs(useHybridViewerStore());
60
+ const viewerStore = useViewerStore();
61
+ const schema = viewer_schemas.opengeodeweb_viewer.viewer.highlight;
62
+ const params = {
63
+ x: -1,
64
+ y: -1,
65
+ field_type: hover_highlight_field_type.value,
66
+ ids: Object.keys(hybridDb),
67
+ };
68
+ viewerStore.request({ schema, params });
69
+ }
70
+
71
+ function createClearHoverData(hoverTimeoutRef, hoverData, currentHoverId) {
72
+ return function clearHoverData() {
73
+ if (hoverTimeoutRef.value) {
74
+ clearTimeout(hoverTimeoutRef.value);
75
+ hoverTimeoutRef.value = undefined;
76
+ }
77
+ hoverData.value = undefined;
78
+ currentHoverId.value = undefined;
79
+ };
80
+ }
81
+
82
+ function createHoverHighlight({ hoverTimeoutRef, currentHoverId, clearHoverData }) {
83
+ return useDebounceFn((event) => {
84
+ const hybridViewerStore = useHybridViewerStore();
85
+ const { genericRenderWindow } = hybridViewerStore;
86
+ const { is_hover_highlight, hoverData, hoverPosition } = storeToRefs(hybridViewerStore);
87
+ const containerElement = genericRenderWindow.value?.getContainer();
88
+ const relativeMousePosition = containerElement
89
+ ? {
90
+ x: event.clientX - containerElement.getBoundingClientRect().left,
91
+ y: event.clientY - containerElement.getBoundingClientRect().top,
92
+ }
93
+ : { x: event.clientX, y: event.clientY };
94
+
95
+ performHoverHighlight(event, async (response) => {
96
+ const isResponseValid =
97
+ response && response.id && response.picked_id !== undefined && response.picked_id !== -1;
98
+ if (!is_hover_highlight.value || !isResponseValid) {
99
+ clearHoverData();
100
+ return;
101
+ }
102
+
103
+ const hoverKey = `${response.id}_${response.field_type}_${response.picked_id}`;
104
+ if (currentHoverId.value === hoverKey) {
105
+ return;
106
+ }
107
+
108
+ if (hoverTimeoutRef.value) {
109
+ clearTimeout(hoverTimeoutRef.value);
110
+ hoverTimeoutRef.value = undefined;
111
+ }
112
+
113
+ hoverData.value = undefined;
114
+ currentHoverId.value = hoverKey;
115
+
116
+ let componentInfo = undefined;
117
+ let modelName = undefined;
118
+
119
+ const modelRecord = await database.data.get(response.id);
120
+ if (modelRecord) {
121
+ modelName = modelRecord.name;
122
+ }
123
+
124
+ if (response.geode_id) {
125
+ const components = database.model_components.where("[id+geode_id]");
126
+ const query = components.equals([response.id, response.geode_id]);
127
+ const component = await query.first();
128
+ if (component) {
129
+ componentInfo = {
130
+ name: component.name,
131
+ id: component.geode_id,
132
+ type: component.type,
133
+ };
134
+ }
135
+ }
136
+
137
+ const newHoverData = {
138
+ modelId: response.id,
139
+ modelName,
140
+ blockName: response.geode_id,
141
+ pickedId: response.picked_id,
142
+ fieldType: response.field_type,
143
+ component: componentInfo,
144
+ attributes: response.attributes || {},
145
+ };
146
+
147
+ hoverTimeoutRef.value = setTimeout(() => {
148
+ hoverPosition.value = relativeMousePosition;
149
+ hoverData.value = newHoverData;
150
+ hoverTimeoutRef.value = undefined;
151
+ }, HOVER_TIMEOUT_MS);
152
+ });
153
+ }, HOVER_DEBOUNCE_MS);
154
+ }
155
+
156
+ export {
157
+ createClearHoverData,
158
+ createHoverHighlight,
159
+ performClearHoverHighlight,
160
+ performHoverHighlight,
161
+ useHybridViewerHighlight,
162
+ };
@@ -0,0 +1,121 @@
1
+ import { useHybridViewerStore } from "@ogw_front/stores/hybrid_viewer";
2
+ import { useViewerStore } from "@ogw_front/stores/viewer";
3
+ import viewer_schemas from "@geode/opengeodeweb-viewer/opengeodeweb_viewer_schemas.json";
4
+
5
+ function useHybridViewerRuler() {
6
+ const is_ruler_active = ref(false);
7
+ const ruler_snap = ref(false);
8
+ const ruler_point1 = ref(undefined);
9
+ const ruler_point2 = ref(undefined);
10
+ const ruler_distance = ref(undefined);
11
+ const ruler_awaiting_point = ref(1);
12
+ const ruler_previous_hover_state = ref({ active: false, fieldType: "CELL" });
13
+
14
+ function updateRulerSnapHighlight() {
15
+ const hybridViewerStore = useHybridViewerStore();
16
+ const { is_hover_highlight, hover_highlight_field_type } = storeToRefs(hybridViewerStore);
17
+ const { clearHoverHighlight } = hybridViewerStore;
18
+
19
+ if (is_ruler_active.value && ruler_snap.value) {
20
+ ruler_previous_hover_state.value = {
21
+ active: is_hover_highlight.value,
22
+ fieldType: hover_highlight_field_type.value,
23
+ };
24
+ is_hover_highlight.value = true;
25
+ hover_highlight_field_type.value = "POINT";
26
+ } else {
27
+ is_hover_highlight.value = ruler_previous_hover_state.value.active;
28
+ hover_highlight_field_type.value = ruler_previous_hover_state.value.fieldType;
29
+ if (!is_hover_highlight.value) {
30
+ clearHoverHighlight();
31
+ }
32
+ }
33
+ }
34
+
35
+ watch([is_ruler_active, ruler_snap], updateRulerSnapHighlight);
36
+
37
+ async function applyRuler() {
38
+ if (!ruler_point1.value) {
39
+ return;
40
+ }
41
+ const points = ruler_point2.value
42
+ ? [ruler_point1.value, ruler_point2.value]
43
+ : [ruler_point1.value];
44
+ const { remoteRender } = useHybridViewerStore();
45
+ const viewerStore = useViewerStore();
46
+ const schema = viewer_schemas.opengeodeweb_viewer.viewer.ruler;
47
+ const response = await viewerStore.request({ schema, params: { points } });
48
+ ruler_distance.value = response.distance;
49
+ await remoteRender();
50
+ }
51
+
52
+ async function handleRulerClick(x, y) {
53
+ const { hybridDb } = useHybridViewerStore();
54
+ const viewerStore = useViewerStore();
55
+ let coords = undefined;
56
+ if (ruler_snap.value) {
57
+ const schema = viewer_schemas.opengeodeweb_viewer.viewer.highlight;
58
+ const params = {
59
+ x: Math.round(x),
60
+ y: Math.round(y),
61
+ field_type: "POINT",
62
+ ids: Object.keys(hybridDb),
63
+ };
64
+ const response = await viewerStore.request({ schema, params });
65
+ coords = response.attributes?.coordinates;
66
+ } else {
67
+ const schema = viewer_schemas.opengeodeweb_viewer.viewer.get_point_position;
68
+ const params = { x: Math.round(x), y: Math.round(y) };
69
+ const response = await viewerStore.request({ schema, params });
70
+ coords = [response.x, response.y, response.z];
71
+ }
72
+ if (!coords) {
73
+ return;
74
+ }
75
+
76
+ if (ruler_awaiting_point.value === 1) {
77
+ ruler_point1.value = coords;
78
+ ruler_point2.value = undefined;
79
+ ruler_distance.value = undefined;
80
+ ruler_awaiting_point.value = 2;
81
+ } else {
82
+ ruler_point2.value = coords;
83
+ ruler_awaiting_point.value = 1;
84
+ }
85
+ await applyRuler();
86
+ }
87
+
88
+ function deactivateRuler() {
89
+ const { clearHoverHighlight } = useHybridViewerStore();
90
+ is_ruler_active.value = false;
91
+ clearHoverHighlight();
92
+ }
93
+
94
+ async function clearRuler() {
95
+ ruler_point1.value = undefined;
96
+ ruler_point2.value = undefined;
97
+ ruler_distance.value = undefined;
98
+ ruler_awaiting_point.value = 1;
99
+ deactivateRuler();
100
+ const { remoteRender } = useHybridViewerStore();
101
+ const viewerStore = useViewerStore();
102
+ const schema = viewer_schemas.opengeodeweb_viewer.viewer.reset_ruler;
103
+ await viewerStore.request({ schema });
104
+ await remoteRender();
105
+ }
106
+
107
+ return {
108
+ is_ruler_active,
109
+ ruler_snap,
110
+ ruler_point1,
111
+ ruler_point2,
112
+ ruler_distance,
113
+ ruler_awaiting_point,
114
+ handleRulerClick,
115
+ applyRuler,
116
+ clearRuler,
117
+ deactivateRuler,
118
+ };
119
+ }
120
+
121
+ export { useHybridViewerRuler };