From eb1f31d1c84c20b453be708949a73ceef3ab5044 Mon Sep 17 00:00:00 2001 From: Milan Pilipovic Date: Tue, 18 Jun 2024 17:27:35 +0200 Subject: [PATCH] Fixed annotation getting rotated when moving between pages --- src/display/editor/annotation_editor_layer.js | 22 ++++++ src/display/editor/editor.js | 78 ++++++++++++++++++- 2 files changed, 96 insertions(+), 4 deletions(-) diff --git a/src/display/editor/annotation_editor_layer.js b/src/display/editor/annotation_editor_layer.js index 1e95423d09f15..62a0d2e78ad9d 100644 --- a/src/display/editor/annotation_editor_layer.js +++ b/src/display/editor/annotation_editor_layer.js @@ -488,6 +488,7 @@ class AnnotationEditorLayer { this.attach(editor); editor.parent?.detach(editor); + this.resetRotation(editor); editor.setParent(this); if (editor.div && editor.isAttachedToDOM) { editor.div.remove(); @@ -495,6 +496,27 @@ class AnnotationEditorLayer { } } + /** + * When a page is rotated, the editor must be rotated as well + * to maintain the same orientation. + * @param {AnnotationEditor} editor + */ + resetRotation(editor) { + if (this.viewport.rotation === editor.parent.viewport.rotation) { + return; + } + const rotationOfThisPage = this.viewport.rotation; + const currentRotation = + 360 - Number(this.div.getAttribute("data-main-rotation")); + + const pageRotation = + (360 + rotationOfThisPage - editor._uiManager.viewParameters.rotation) % + 360; + editor.pageRotation = pageRotation; + editor.rotation = rotationOfThisPage; + editor.div.setAttribute("data-editor-rotation", currentRotation); + } + /** * Add a new editor in the current view. * @param {AnnotationEditor} editor diff --git a/src/display/editor/editor.js b/src/display/editor/editor.js index 3a42786d3374a..92bb777e09291 100644 --- a/src/display/editor/editor.js +++ b/src/display/editor/editor.js @@ -259,6 +259,42 @@ class AnnotationEditor { return false; } + /** + * Rotate a point about 0.5 0.5 origin + * @param {number} x + * @param {number} y + * @param {number} angle + * @returns {any} The rotated point + */ + static rotatePointByMidPoint(x, y, angle) { + const originX = 0.5; + const originY = 0.5; + // Translate the point to the origin (originX, originY) + const translatedX = x - originX; + const translatedY = y - originY; + let rotatedX, rotatedY; + + // Perform the rotation based on the given angle + switch (angle) { + case 90: + rotatedX = -translatedY; + rotatedY = translatedX; + break; + case 270: + rotatedX = translatedY; + rotatedY = -translatedX; + break; + default: + throw new Error("Invalid angle. Valid angles are 90 and 270 degrees."); + } + + // Translate the point back + const finalX = rotatedX + originX; + const finalY = rotatedY + originY; + + return { x: finalX, y: finalY }; + } + /** * Extract the data from the clipboard item and delegate the creation of the * editor to the parent. @@ -469,6 +505,9 @@ class AnnotationEditor { const [parentWidth, parentHeight] = this.parentDimensions; this.x += tx / parentWidth; this.y += ty / parentHeight; + + const oldRotation = this.rotation; + if (this.parent && (this.x < 0 || this.x > 1 || this.y < 0 || this.y > 1)) { // It's possible to not have a parent: for example, when the user is // dragging all the selected editors but this one on a page which has been @@ -476,12 +515,43 @@ class AnnotationEditor { // It's why we need to check for it. In such a situation, it isn't really // a problem to not find a new parent: it's something which is related to // what the user is seeing, hence it depends on how pages are layed out. - - // The element will be outside of its parent so change the parent. const { x, y } = this.div.getBoundingClientRect(); if (this.parent.findNewParent(this, x, y)) { - this.x -= Math.floor(this.x); - this.y -= Math.floor(this.y); + const newRotation = this.rotation; + if (oldRotation !== newRotation) { + const { + x: layerX, + y: layerY, + width, + height, + } = this.parent.div.getBoundingClientRect(); + this.x = (x - layerX) / width; + this.y = (y - layerY) / height; + + if (newRotation === 90) { + const points = AnnotationEditor.rotatePointByMidPoint( + this.x, + this.y, + 270 + ); + this.x = points.x; + this.y = points.y; + } else if (newRotation === 270) { + const points = AnnotationEditor.rotatePointByMidPoint( + this.x, + this.y, + 90 + ); + this.x = points.x; + this.y = points.y; + } else if (newRotation === 180) { + this.x = 1 - this.x; + this.y = 1 - this.y; + } + } else { + this.x -= Math.floor(this.x); + this.y -= Math.floor(this.y); + } } }