Skip to content

Commit

Permalink
fix(lib-classifier): canvas context for SVG drawing tools (#6491)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
eatyourgreens authored Jan 6, 2025
1 parent 51f064e commit c8e3241
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 46 deletions.
Original file line number Diff line number Diff line change
@@ -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'
Expand Down Expand Up @@ -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)
Expand All @@ -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({
Expand All @@ -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)
Expand All @@ -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
}
Expand All @@ -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)
}
}

Expand All @@ -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)
}
}
Expand All @@ -165,7 +134,7 @@ function InteractionLayer({
return (
<>
<DrawingCanvas
ref={canvas}
ref={canvasRef}
disabled={disabled || move}
pointerEvents={move ? 'none' : 'all'}
width={width}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,14 @@ function createPoint(event) {

function getEventOffset(event, canvas) {
const svgPoint = createPoint(event)
const svgEventOffset = svgPoint.matrixTransform
? svgPoint.matrixTransform(canvas.getScreenCTM().inverse())
const ctm = canvas?.getScreenCTM()
const svgEventOffset = ctm && svgPoint.matrixTransform
? svgPoint.matrixTransform(ctm.inverse())
: svgPoint
return svgEventOffset
}

function convertEvent(event, canvas) {
export function convertEvent(event, canvas) {
const svgEventOffset = getEventOffset(event, canvas)
const svgCoordinateEvent = {
type: event.type,
Expand Down

0 comments on commit c8e3241

Please sign in to comment.