From c8e3241bc48e190fccd715d5bda5bd158e08f2c5 Mon Sep 17 00:00:00 2001 From: Jim O'Donnell Date: Mon, 6 Jan 2025 17:06:34 +0000 Subject: [PATCH] fix(lib-classifier): canvas context for SVG drawing tools (#6491) * fix(lib-classifier): canvas context for SVG drawing tools Make sure that `SVGContext.canvas` is a reference to the SVG `rect` element that's used as a drawing canvas, so that creating new drawing marks and editing existing marks both use the same screen CTM when calculating the pointer position. This fixes a bug in Firefox where the `draggable` decorator doesn't correctly track the active pointer, in the context of a zoomed SVG image. * DRY up SVG event-handling functions * revert changes to SingleImageViewer --- .../InteractionLayer/InteractionLayer.js | 55 ++++--------------- .../components/draggable/draggable.js | 7 ++- 2 files changed, 16 insertions(+), 46 deletions(-) diff --git a/packages/lib-classifier/src/components/Classifier/components/SubjectViewer/components/InteractionLayer/InteractionLayer.js b/packages/lib-classifier/src/components/Classifier/components/SubjectViewer/components/InteractionLayer/InteractionLayer.js index 1ec9ee978b..0fbc578b18 100644 --- a/packages/lib-classifier/src/components/Classifier/components/SubjectViewer/components/InteractionLayer/InteractionLayer.js +++ b/packages/lib-classifier/src/components/Classifier/components/SubjectViewer/components/InteractionLayer/InteractionLayer.js @@ -1,7 +1,10 @@ import cuid from 'cuid' import PropTypes from 'prop-types' -import { useRef, useState } from 'react'; +import { useContext, useRef, useState } from 'react'; import styled, { css } from 'styled-components' + +import SVGContext from '@plugins/drawingTools/shared/SVGContext' +import { convertEvent } from '@plugins/drawingTools/components/draggable/draggable' import DrawingToolMarks from './components/DrawingToolMarks' import TranscribedLines from './components/TranscribedLines' import SubTaskPopup from './components/SubTaskPopup' @@ -43,7 +46,9 @@ function InteractionLayer({ duration }) { const [creating, setCreating] = useState(false) - const canvas = useRef() + const svgContext = useContext(SVGContext) + const canvasRef = useRef() + svgContext.canvas = canvasRef.current if (creating && !activeMark) { setCreating(false) @@ -54,42 +59,6 @@ function InteractionLayer({ setActiveMark(undefined) } - function convertEvent(event) { - const type = event.type - - const svgEventOffset = getEventOffset(event) - - const svgCoordinateEvent = { - pointerId: event.pointerId, - type, - x: svgEventOffset.x, - y: svgEventOffset.y - } - - return svgCoordinateEvent - } - - function createPoint(event) { - const { clientX, clientY } = event - // SVG 2 uses DOMPoint - if (window.DOMPointReadOnly) { - return new DOMPointReadOnly(clientX, clientY) - } - // jsdom doesn't support SVG - return { - x: clientX, - y: clientY - } - } - - function getEventOffset(event) { - const svgPoint = createPoint(event) - const svgEventOffset = svgPoint.matrixTransform - ? svgPoint.matrixTransform(canvas.current?.getScreenCTM().inverse()) - : svgPoint - return svgEventOffset - } - function createMark(event) { const timeStamp = getFixedNumber(played, 5) const mark = activeTool.createMark({ @@ -99,7 +68,7 @@ function InteractionLayer({ toolIndex: activeToolIndex }) - mark.initialPosition(convertEvent(event)) + mark.initialPosition(convertEvent(event, canvasRef.current)) setActiveMark(mark) setCreating(true) mark.setSubTaskVisibility(false) @@ -124,7 +93,7 @@ function InteractionLayer({ } if (creating) { - activeTool?.handlePointerDown?.(convertEvent(event), activeMark) + activeTool?.handlePointerDown?.(convertEvent(event, canvasRef.current), activeMark) if (activeMark.finished) onFinish(event) return true } @@ -136,7 +105,7 @@ function InteractionLayer({ function onPointerMove(event) { cancelEvent(event) if (creating) { - activeTool?.handlePointerMove?.(convertEvent(event), activeMark) + activeTool?.handlePointerMove?.(convertEvent(event, canvasRef.current), activeMark) } } @@ -149,7 +118,7 @@ function InteractionLayer({ function onPointerUp(event) { cancelEvent(event) if (creating) { - activeTool?.handlePointerUp?.(convertEvent(event), activeMark) + activeTool?.handlePointerUp?.(convertEvent(event, canvasRef.current), activeMark) if (activeMark.finished) onFinish(event) } } @@ -165,7 +134,7 @@ function InteractionLayer({ return ( <>