From 7dc882341b7c49e5151ec4419728e76faba4a998 Mon Sep 17 00:00:00 2001 From: Paul Elliott Date: Thu, 2 May 2024 18:51:22 -0400 Subject: [PATCH] feat(polygon): only show handles on hover --- src/components/tools/polygon/PolygonSVG2D.vue | 38 +++++++++++++++++-- .../tools/polygon/PolygonWidget2D.vue | 27 ++++++++++++- src/vtk/PolygonWidget/behavior.ts | 23 +++++------ src/vtk/PolygonWidget/index.d.ts | 1 + 4 files changed, 72 insertions(+), 17 deletions(-) diff --git a/src/components/tools/polygon/PolygonSVG2D.vue b/src/components/tools/polygon/PolygonSVG2D.vue index 89f1e7e5..fe50614a 100644 --- a/src/components/tools/polygon/PolygonSVG2D.vue +++ b/src/components/tools/polygon/PolygonSVG2D.vue @@ -9,6 +9,7 @@ :stroke-width="strokeWidth" fill="transparent" :r="radius" + :visibility="index === 0 ? firstHandleVisibility : handleVisibility" /> { + return points.value.length > 0 && placing.value && finishable.value; + }); + + const handleVisibility = computed(() => { + return showHandles.value ? 'visible' : 'hidden'; + }); + const firstHandleVisibility = computed(() => { + if (finishPossible.value) { + return 'visible'; + } + return handleVisibility.value; + }); + type SVGPoint = { point: Vector2; radius: number }; const handlePoints = ref>([]); const linePoints = ref(''); @@ -74,7 +102,7 @@ export default defineComponent({ }); // Indicate finishable - if (svgPoints.length > 0 && finishable.value && placing.value) { + if (finishPossible.value) { svgPoints[0].radius = FINISHABLE_POINT_RADIUS; } @@ -117,6 +145,8 @@ export default defineComponent({ devicePixelRatio, handlePoints, linePoints, + firstHandleVisibility, + handleVisibility, }; }, }); diff --git a/src/components/tools/polygon/PolygonWidget2D.vue b/src/components/tools/polygon/PolygonWidget2D.vue index 8bb82c6a..6c151f6e 100644 --- a/src/components/tools/polygon/PolygonWidget2D.vue +++ b/src/components/tools/polygon/PolygonWidget2D.vue @@ -9,6 +9,7 @@ import { watchEffect, inject, onUnmounted, + ref, } from 'vue'; import vtkPlaneManipulator from '@kitware/vtk.js/Widgets/Manipulators/PlaneManipulator'; import { useImage } from '@/src/composables/useCurrentImage'; @@ -16,10 +17,10 @@ import { updatePlaneManipulatorFor2DView } from '@/src/utils/manipulators'; import { LPSAxisDir } from '@/src/types/lps'; import { onVTKEvent } from '@/src/composables/onVTKEvent'; import { - useHoverEvent, useRightClickContextMenu, useWidgetVisibility, } from '@/src/composables/annotationTool'; +import { getCSSCoordinatesFromEvent } from '@/src/utils/vtk-helpers'; import { usePolygonStore as useStore } from '@/src/store/tools/polygons'; import vtkWidgetFactory, { vtkPolygonViewWidget as WidgetView, @@ -92,7 +93,27 @@ export default defineComponent({ emit('placed'); }); - useHoverEvent(emit, widget); + const lastHoverEventData = ref(null); + onVTKEvent(widget, 'onHoverEvent', (eventData: any) => { + lastHoverEventData.value = eventData; + }); + const dragging = ref(false); + onVTKEvent(widget, 'onDraggingEvent', (eventData: any) => { + dragging.value = eventData.dragging; + }); + const showHandles = computed(() => { + return lastHoverEventData.value?.hovering && !dragging.value; + }); + watchEffect(() => { + if (!lastHoverEventData.value) return; + const displayXY = getCSSCoordinatesFromEvent(lastHoverEventData.value); + if (displayXY) { + emit('widgetHover', { + displayXY, + hovering: lastHoverEventData.value?.hovering && !dragging.value, + }); + } + }); // --- right click handling --- // @@ -134,6 +155,7 @@ export default defineComponent({ slice, tool, editState, + showHandles, }; }, }); @@ -148,5 +170,6 @@ export default defineComponent({ :move-point="editState.movePoint" :placing="tool.placing" :finishable="editState.finishable" + :show-handles="showHandles" /> diff --git a/src/vtk/PolygonWidget/behavior.ts b/src/vtk/PolygonWidget/behavior.ts index fd3b1e24..b2f63b13 100644 --- a/src/vtk/PolygonWidget/behavior.ts +++ b/src/vtk/PolygonWidget/behavior.ts @@ -22,7 +22,13 @@ const DOUBLE_CLICK_SLIP_DISTANCE_MAX_SQUARED = export default function widgetBehavior(publicAPI: any, model: any) { model.classHierarchy.push('vtkPolygonWidgetBehavior'); - model._isDragging = false; + + const setDragging = (isDragging: boolean) => { + model._dragging = isDragging; + publicAPI.invokeDraggingEvent({ + dragging: isDragging, + }); + }; // overUnselectedHandle is true if mouse is over handle that was created before a mouse move event. // That happens if creating new handle and immediately dragging. @@ -52,6 +58,7 @@ export default function widgetBehavior(publicAPI: any, model: any) { macro.event(publicAPI, model, 'RightClickEvent'); macro.event(publicAPI, model, 'PlacedEvent'); macro.event(publicAPI, model, 'HoverEvent'); + macro.event(publicAPI, model, 'DraggingEvent'); publicAPI.resetInteractions = () => { model._interactor.cancelAnimation(publicAPI, true); @@ -123,7 +130,7 @@ export default function widgetBehavior(publicAPI: any, model: any) { if ( worldCoords?.length && (model.activeState === model.widgetState.getMoveHandle() || - model._isDragging) + model._dragging) ) { model.activeState.setOrigin(worldCoords); @@ -155,12 +162,6 @@ export default function widgetBehavior(publicAPI: any, model: any) { publicAPI.handleLeftButtonPress = (event: vtkMouseEvent) => { const activeWidget = model._widgetManager.getActiveWidget(); - // turns off hover while dragging - publicAPI.invokeHoverEvent({ - ...event, - hovering: false, - }); - if ( !model.manipulator || ignoreKey(event) || @@ -199,7 +200,7 @@ export default function widgetBehavior(publicAPI: any, model: any) { } if (model.activeState?.getActive() && model.pickable && model.dragable) { - model._isDragging = true; + setDragging(true); model._apiSpecificRenderWindow.setCursor('grabbing'); model._interactor.requestAnimation(publicAPI); publicAPI.invokeStartInteractionEvent(); @@ -287,10 +288,10 @@ export default function widgetBehavior(publicAPI: any, model: any) { freeHanding = false; - if (model._isDragging) { + if (model._dragging) { model._apiSpecificRenderWindow.setCursor('pointer'); model._interactor.cancelAnimation(publicAPI); - model._isDragging = false; + setDragging(false); model._widgetManager.enablePicking(); // So a following left click without moving the mouse can immediately grab the handle, // we don't call model.widgetState.deactivate() here. diff --git a/src/vtk/PolygonWidget/index.d.ts b/src/vtk/PolygonWidget/index.d.ts index 0c793a84..513a82c6 100644 --- a/src/vtk/PolygonWidget/index.d.ts +++ b/src/vtk/PolygonWidget/index.d.ts @@ -25,6 +25,7 @@ export interface vtkPolygonWidgetState extends vtkAnnotationWidgetState { export interface vtkPolygonViewWidget extends vtkAnnotationToolWidget { getWidgetState(): vtkPolygonWidgetState; + onDraggingEvent(callback: (e: any) => void): vtkSubscription; } export interface IPolygonWidgetInitialValues