From a932804fb58f01a2cf794d02aad5a36a33b38cec Mon Sep 17 00:00:00 2001 From: legraina Date: Tue, 2 Sep 2025 21:11:04 -0400 Subject: [PATCH] A new CurrentPointers class to store current pointers used by the editor Move current pointer field of DrawingEditor to CurrentPointer class in tools.js: The pointer types fields have been moved to a CurrentPointer object in tools.js. This object is used by eraser.js and ink.js. Only reset pointer type when user select a new mode: Clear the pointer type when changing mode, instead of at the end of the session. It seems more stable, as the method is not called this way when the user changes pages. Also, clear the pointer type when the mode is changed by an event (the user changes the editor type), otherwise, the same pointer type is kept (the document is changed for example) --- src/display/editor/draw.js | 56 +++++++++---------------- src/display/editor/tools.js | 82 +++++++++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 37 deletions(-) diff --git a/src/display/editor/draw.js b/src/display/editor/draw.js index bcff3f228..3ca7dfcfa 100644 --- a/src/display/editor/draw.js +++ b/src/display/editor/draw.js @@ -16,6 +16,7 @@ import { AnnotationEditorParamsType, unreachable } from "../../shared/util.js"; import { noContextMenu, stopEvent } from "../display_utils.js"; import { AnnotationEditor } from "./editor.js"; +import { CurrentPointers } from "./tools.js"; class DrawingOptions { #svgProperties = Object.create(null); @@ -81,14 +82,6 @@ class DrawingEditor extends AnnotationEditor { static #currentDrawingOptions = null; - static #currentPointerId = NaN; - - static #currentPointerType = null; - - static #currentPointerIds = null; - - static #currentMoveTimestamp = NaN; - static _INNER_MARGIN = 3; constructor(params) { @@ -678,20 +671,15 @@ class DrawingEditor extends AnnotationEditor { } static startDrawing(parent, uiManager, _isLTR, event) { - // The _currentPointerType is set when the user starts an empty drawing - // session. If, in the same drawing session, the user starts using a + // The pointerType of CurrentPointer is set when the user starts an empty + // drawing session. If, in the same drawing session, the user starts using a // different type of pointer (e.g. a pen and then a finger), we just return. // - // The _currentPointerId and _currentPointerIds are used to keep track of - // the pointers with a same type (e.g. two fingers). If the user starts to - // draw with a finger and then uses a second finger, we just stop the - // current drawing and let the user zoom the document. + // If the user starts to draw with a finger and then uses a second finger, + // we just stop the current drawing and let the user zoom the document. const { target, offsetX: x, offsetY: y, pointerId, pointerType } = event; - if ( - DrawingEditor.#currentPointerType && - DrawingEditor.#currentPointerType !== pointerType - ) { + if (CurrentPointers.isInitializedAndDifferentPointerType(pointerType)) { return; } @@ -704,16 +692,13 @@ class DrawingEditor extends AnnotationEditor { const ac = (DrawingEditor.#currentDrawingAC = new AbortController()); const signal = parent.combinedSignal(ac); - DrawingEditor.#currentPointerId ||= pointerId; - DrawingEditor.#currentPointerType ??= pointerType; + CurrentPointers.setPointer(pointerType, pointerId); window.addEventListener( "pointerup", e => { - if (DrawingEditor.#currentPointerId === e.pointerId) { + if (CurrentPointers.isSamePointerIdOrRemove(e.pointerId)) { this._endDraw(e); - } else { - DrawingEditor.#currentPointerIds?.delete(e.pointerId); } }, { signal } @@ -721,10 +706,8 @@ class DrawingEditor extends AnnotationEditor { window.addEventListener( "pointercancel", e => { - if (DrawingEditor.#currentPointerId === e.pointerId) { + if (CurrentPointers.isSamePointerIdOrRemove(e.pointerId)) { this._currentParent.endDrawingSession(); - } else { - DrawingEditor.#currentPointerIds?.delete(e.pointerId); } }, { signal } @@ -732,14 +715,14 @@ class DrawingEditor extends AnnotationEditor { window.addEventListener( "pointerdown", e => { - if (DrawingEditor.#currentPointerType !== e.pointerType) { + if (!CurrentPointers.isSamePointerType(e.pointerType)) { // For example, we started with a pen and the user // is now using a finger. return; } // For example, the user is using a second finger. - (DrawingEditor.#currentPointerIds ||= new Set()).add(e.pointerId); + CurrentPointers.initializeAndAddPointerId(e.pointerId); // The first finger created a first point and a second finger just // started, so we stop the drawing and remove this only point. @@ -765,7 +748,7 @@ class DrawingEditor extends AnnotationEditor { target.addEventListener( "touchmove", e => { - if (e.timeStamp === DrawingEditor.#currentMoveTimestamp) { + if (CurrentPointers.isSameTimeStamp(e.timeStamp)) { // This move event is used to draw so we don't want to scroll. stopEvent(e); } @@ -812,16 +795,16 @@ class DrawingEditor extends AnnotationEditor { } static _drawMove(event) { - DrawingEditor.#currentMoveTimestamp = -1; + CurrentPointers.isSameTimeStamp(event.timeStamp); if (!DrawingEditor.#currentDraw) { return; } const { offsetX, offsetY, pointerId } = event; - if (DrawingEditor.#currentPointerId !== pointerId) { + if (!CurrentPointers.isSamePointerId(pointerId)) { return; } - if (DrawingEditor.#currentPointerIds?.size >= 1) { + if (CurrentPointers.isUsingMultiplePointers()) { // The user is using multiple fingers and the first one is moving. this._endDraw(event); return; @@ -831,7 +814,7 @@ class DrawingEditor extends AnnotationEditor { DrawingEditor.#currentDraw.add(offsetX, offsetY) ); // We track the timestamp to know if the touchmove event is used to draw. - DrawingEditor.#currentMoveTimestamp = event.timeStamp; + CurrentPointers.setTimeStamp(event.timeStamp); stopEvent(event); } @@ -841,15 +824,14 @@ class DrawingEditor extends AnnotationEditor { this._currentParent = null; DrawingEditor.#currentDraw = null; DrawingEditor.#currentDrawingOptions = null; - DrawingEditor.#currentPointerType = null; - DrawingEditor.#currentMoveTimestamp = NaN; + CurrentPointers.clearPointerType(); + CurrentPointers.clearTimeStamp(); } if (DrawingEditor.#currentDrawingAC) { DrawingEditor.#currentDrawingAC.abort(); DrawingEditor.#currentDrawingAC = null; - DrawingEditor.#currentPointerId = NaN; - DrawingEditor.#currentPointerIds = null; + CurrentPointers.clearPointerIds(); } } diff --git a/src/display/editor/tools.js b/src/display/editor/tools.js index 1d1212a53..3fcb1f84b 100644 --- a/src/display/editor/tools.js +++ b/src/display/editor/tools.js @@ -42,6 +42,87 @@ function bindEvents(obj, element, names) { } } +/** + * Class to store current pointers used by the editor to be able to handle + * multiple pointers (e.g. two fingers, a pen, a mouse, ...). + */ +class CurrentPointers { + // To manage the pointer events. + + // The pointerId and pointerIds are used to keep track of + // the pointers with a same type (e.g. two fingers). + static #pointerId = NaN; + + static #pointerIds = null; + + // Track the timestamp to know if the touchmove event is used. + static #moveTimestamp = NaN; + + // The pointerType is used to know if we are using a mouse, a pen or a touch. + static #pointerType = null; + + static initializeAndAddPointerId(pointerId) { + // Store pointer ids. For example, the user is using a second finger. + (CurrentPointers.#pointerIds ||= new Set()).add(pointerId); + } + + static setPointer(pointerType, pointerId) { + CurrentPointers.#pointerId ||= pointerId; + CurrentPointers.#pointerType ??= pointerType; + } + + static setTimeStamp(timeStamp) { + CurrentPointers.#moveTimestamp = timeStamp; + } + + static isSamePointerId(pointerId) { + return CurrentPointers.#pointerId === pointerId; + } + + // Check if it's the same pointer id, otherwise remove it from the set. + static isSamePointerIdOrRemove(pointerId) { + if (CurrentPointers.#pointerId === pointerId) { + return true; + } + + CurrentPointers.#pointerIds?.delete(pointerId); + return false; + } + + static isSamePointerType(pointerType) { + return CurrentPointers.#pointerType === pointerType; + } + + static isInitializedAndDifferentPointerType(pointerType) { + return ( + CurrentPointers.#pointerType !== null && + !CurrentPointers.isSamePointerType(pointerType) + ); + } + + static isSameTimeStamp(timeStamp) { + return CurrentPointers.#moveTimestamp === timeStamp; + } + + static isUsingMultiplePointers() { + // Check if the user is using multiple fingers + return CurrentPointers.#pointerIds?.size >= 1; + } + + static clearPointerType() { + CurrentPointers.#pointerType = null; + } + + static clearPointerIds() { + CurrentPointers.#pointerId = NaN; + CurrentPointers.#pointerIds = null; + } + + static clearTimeStamp() { + CurrentPointers.#moveTimestamp = NaN; + } +} + /** * Class to create some unique ids for the different editors. */ @@ -2801,5 +2882,6 @@ export { bindEvents, ColorManager, CommandManager, + CurrentPointers, KeyboardManager, };