From 11f70648698a76ec6cc389b6138a0c747cd8ad3b Mon Sep 17 00:00:00 2001 From: Bryon Lewis Date: Thu, 3 Sep 2026 14:50:52 -0400 Subject: [PATCH 1/4] add editing/new track icons --- client/src/components/LayerManager.vue | 8 ++- .../annotators/AnnotatorImageCursor.vue | 65 +++++++++++++++++++ .../components/annotators/ImageAnnotator.vue | 21 +++++- .../components/annotators/VideoAnnotator.vue | 25 +++++-- .../src/components/annotators/annotator.scss | 4 ++ .../annotators/mediaControllerType.ts | 4 +- .../annotators/useAnnotatorImageCursor.ts | 23 +++++++ .../annotators/useMediaController.ts | 7 +- client/src/components/index.ts | 3 + client/src/layers/EditAnnotationLayer.ts | 10 ++- .../src/layers/MediaLayers/maskEditorLayer.ts | 17 +++++ client/src/layers/UILayers/ToolTipLayer.ts | 33 +++++++--- client/src/layers/UILayers/ToolTipWidget.vue | 13 ++-- .../src/layers/UILayers/mountGeoJsWidget.ts | 16 +++++ 14 files changed, 219 insertions(+), 30 deletions(-) create mode 100644 client/src/components/annotators/AnnotatorImageCursor.vue create mode 100644 client/src/components/annotators/useAnnotatorImageCursor.ts create mode 100644 client/src/layers/UILayers/mountGeoJsWidget.ts diff --git a/client/src/components/LayerManager.vue b/client/src/components/LayerManager.vue index efad9d75..09d2f4be 100644 --- a/client/src/components/LayerManager.vue +++ b/client/src/components/LayerManager.vue @@ -478,7 +478,7 @@ export default defineComponent({ visualMaskEditLayer.setType('rectangle'); visualMaskEditLayer.setKey(''); visualMaskEditLayer.changeData([visualMaskFrame]); - annotator.setImageCursor('mdi-vector-rectangle'); + annotator.setImageCursor('mdi-vector-rectangle', true); rectAnnotationLayer.setDisableClicking(false); } else if (selectedTrackId !== null) { if ((editingTrack) && !(currentFrameIds || []).includes(selectedTrackId) @@ -500,13 +500,15 @@ export default defineComponent({ editingTracks.push(trackFrame); } if (editingTracks.length && editingTrack !== 'Mask') { + // These layers share the annotator cursor. Disable them before the + // active edit layer sets its cursor so they cannot clear it afterward. + visualMaskEditLayer.disable(); + maskEditorLayer.disable(); if (editingTrack) { editAnnotationLayer.setType(editingTrack); editAnnotationLayer.setKey(selectedKey); editAnnotationLayer.changeData(editingTracks); } - visualMaskEditLayer.disable(); - maskEditorLayer.disable(); } else if (editingTracks.length && editingTrack === 'Mask') { maskLayer.disable(); visualMaskEditLayer.disable(); diff --git a/client/src/components/annotators/AnnotatorImageCursor.vue b/client/src/components/annotators/AnnotatorImageCursor.vue new file mode 100644 index 00000000..b4e879a3 --- /dev/null +++ b/client/src/components/annotators/AnnotatorImageCursor.vue @@ -0,0 +1,65 @@ + + + + + diff --git a/client/src/components/annotators/ImageAnnotator.vue b/client/src/components/annotators/ImageAnnotator.vue index 5c17ea68..2ddbafcd 100644 --- a/client/src/components/annotators/ImageAnnotator.vue +++ b/client/src/components/annotators/ImageAnnotator.vue @@ -4,6 +4,8 @@ import { } from 'vue'; import { SetTimeFunc } from '../../use/useTimeObserver'; import { injectCameraInitializer } from './useMediaController'; +import AnnotatorImageCursor from './AnnotatorImageCursor.vue'; +import useAnnotatorImageCursor from './useAnnotatorImageCursor'; export interface ImageDataItem { url: string; @@ -21,6 +23,7 @@ function loadImageFunc(imageDataItem: ImageDataItem, img: HTMLImageElement) { } export default defineComponent({ name: 'ImageAnnotator', + components: { AnnotatorImageCursor }, props: { imageData: { type: Array as PropType, @@ -69,6 +72,13 @@ export default defineComponent({ // eslint-disable-next-line @typescript-eslint/no-use-before-define seek, pause, play, setVolume: unimplemented, setSpeed: unimplemented, }); + const { playbackCursor } = useAnnotatorImageCursor( + toRef(data, 'imageCursor'), + toRef(data, 'cursor'), + toRef(data, 'imageCursorEditing'), + ); + const imageCursorIcon = toRef(data, 'imageCursor'); + const imageCursorEditing = toRef(data, 'imageCursorEditing'); data.maxFrame = props.imageData.length - 1; // Below are configuration settings we can set until we decide on good numbers to utilize. let local = { @@ -374,6 +384,9 @@ export default defineComponent({ imageCursorRef: imageCursor, containerRef: container, cursorHandler, + playbackCursor, + imageCursorIcon, + imageCursorEditing, }; }, }); @@ -412,12 +425,16 @@ export default defineComponent({ ref="imageCursorRef" class="imageCursor" > - {{ data.imageCursor }} +