From 412aedc8c671d3187d7d900a385e5701b9156f6e Mon Sep 17 00:00:00 2001 From: gary-Shen Date: Wed, 30 Oct 2024 16:12:44 +0800 Subject: [PATCH] fix(image-annotator-react): accurate redo undo stack if the label attributes is configured --- .../src/ImageAnnotator.tsx | 128 ++++++++++++------ .../src/LabelSection/index.tsx | 4 +- 2 files changed, 87 insertions(+), 45 deletions(-) diff --git a/packages/image-annotator-react/src/ImageAnnotator.tsx b/packages/image-annotator-react/src/ImageAnnotator.tsx index fb71de45..9bce8190 100644 --- a/packages/image-annotator-react/src/ImageAnnotator.tsx +++ b/packages/image-annotator-react/src/ImageAnnotator.tsx @@ -501,13 +501,13 @@ function ForwardAnnotator( ); const onAnnotationChange = useCallback( - (_annotation: AnnotationWithTool) => { + (_annotation: AnnotationWithTool, skipHistory?: boolean) => { updateAnnotationsWithGlobal((pre) => { return { ...pre!, [_annotation.id]: _annotation, }; - }); + }, skipHistory); }, [updateAnnotationsWithGlobal], ); @@ -520,11 +520,14 @@ function ForwardAnnotator( const annotation = sortedImageAnnotations.find((item) => item.id === selectedId); // 按住shift键时,调起属性框 - if (engine?.keyboard?.Shift) { + if (engine?.keyboard?.Shift && annotation) { + e.preventDefault(); + e.stopPropagation(); const labelConfig = labels.find((item) => item.value === annotation?.label); openAttributeModal({ labelValue: annotation.label, e, + openModalAnyway: true, engine, labelConfig, }); @@ -538,28 +541,6 @@ function ForwardAnnotator( }; }, [engine, labels, sortedImageAnnotations]); - useEffect(() => { - const handleSelectAnnotation = (annotation: AnnotationData, toolName: ToolName) => { - // 选中了隐藏的标记,需要显示 - engine?.toggleAnnotationsVisibility(toolName, [annotation.id], true); - engine?.setLabel(annotation.label!); - const newAnnotation = { - ...annotation, - tool: toolName, - visible: true, - }; - setSelectedAnnotation(newAnnotation); - onAnnotationChange(newAnnotation); - selectedIndexRef.current = sortedImageAnnotations.findIndex((item) => item.id === annotation.id); - }; - - engine?.on('select', handleSelectAnnotation); - - return () => { - engine?.off('select', handleSelectAnnotation); - }; - }, [engine, labels, onAnnotationChange, sortedImageAnnotations]); - useEffect(() => { const handleUnSelect = () => { setSelectedAnnotation(undefined); @@ -628,36 +609,97 @@ function ForwardAnnotator( }, [engine, onAnnotationDelete]); useEffect(() => { - const _onAnnotationsChange = () => { - onAnnotationsChange(addToolNameToAnnotationData(engine!.getDataByTool())); - }; - // 添加标记 - engine?.on('add', (annotations: AnnotationData[]) => { - _onAnnotationsChange(); + const handleAttributesChange = (annotation: AnnotationData) => { + if (!engine) { + return; + } + setSelectedAnnotation({ - // 默认选中第一个 - ...annotations[0], + ...annotation, tool: engine.activeToolName!, }); - }); + }; - // 改变标签 - engine?.on('labelChange', (label) => { - _onAnnotationsChange(); + engine?.on('attributesChange', handleAttributesChange); - setSelectedLabel(engine.activeToolName ? labelMappingByTool[engine.activeToolName][label] : undefined); - }); + return () => { + engine?.off('attributesChange', handleAttributesChange); + }; + }, [engine, labelMappingByTool, onAnnotationsChange]); + + useEffect(() => { + const handleAnnotationAdded = (annotations: AnnotationData[]) => { + if (!engine) { + return; + } - engine?.on('attributesChange', (annotation: AnnotationData) => { + onAnnotationsChange(addToolNameToAnnotationData(engine!.getDataByTool())); setSelectedAnnotation({ - ...annotation, + // 默认选中第一个 + ...annotations[0], tool: engine.activeToolName!, }); - }); + }; + // 添加标记 + engine?.on('add', handleAnnotationAdded); + + return () => { + engine?.off('add', handleAnnotationAdded); + }; + }, [engine, onAnnotationsChange]); + + useEffect(() => { + const _onAnnotationsChange = () => { + onAnnotationsChange(addToolNameToAnnotationData(engine!.getDataByTool())); + }; // 标记变更,如移动,编辑等 engine?.on('change', _onAnnotationsChange); - }, [engine, labelMappingByTool, onAnnotationsChange]); + + return () => { + engine?.off('change', _onAnnotationsChange); + }; + }, [engine, onAnnotationsChange]); + + useEffect(() => { + const handleLabelChange = (label: string) => { + if (label === selectedLabel?.value && engine?.activeToolName === currentTool) { + return; + } + + onAnnotationsChange(addToolNameToAnnotationData(engine!.getDataByTool())); + + setSelectedLabel(engine?.activeToolName ? labelMappingByTool[engine.activeToolName][label] : undefined); + }; + // 改变标签 + engine?.on('labelChange', handleLabelChange); + + return () => { + engine?.off('labelChange', handleLabelChange); + }; + }, [currentTool, engine, labelMappingByTool, onAnnotationsChange, selectedLabel?.value]); + + useEffect(() => { + const handleSelectAnnotation = (annotation: AnnotationData, toolName: ToolName) => { + // 选中了隐藏的标记,需要显示 + engine?.toggleAnnotationsVisibility(toolName, [annotation.id], true); + engine?.setLabel(annotation.label!); + const newAnnotation = { + ...annotation, + tool: toolName, + visible: true, + }; + setSelectedAnnotation(newAnnotation); + onAnnotationChange(newAnnotation, true); + selectedIndexRef.current = sortedImageAnnotations.findIndex((item) => item.id === annotation.id); + }; + + engine?.on('select', handleSelectAnnotation); + + return () => { + engine?.off('select', handleSelectAnnotation); + }; + }, [engine, labels, onAnnotationChange, sortedImageAnnotations]); useEffect(() => { if (!onError) { diff --git a/packages/image-annotator-react/src/LabelSection/index.tsx b/packages/image-annotator-react/src/LabelSection/index.tsx index 17299c27..ebdb519e 100644 --- a/packages/image-annotator-react/src/LabelSection/index.tsx +++ b/packages/image-annotator-react/src/LabelSection/index.tsx @@ -233,7 +233,7 @@ export function LabelSection() { (values: any) => { const { attributes, label } = values; - if (label) { + if (label && label !== selectedLabel?.value) { // 清除上一个标签的属性 engine?.setAttributes({}); engine?.setLabel(label); @@ -243,7 +243,7 @@ export function LabelSection() { engine?.setAttributes(attributes); } }, - [engine], + [engine, selectedLabel?.value], ); // 标记完后打开标签属性编辑框