From 3f7b73ee8a3f75cd688ee7ddc7b54d90b00bee67 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 3 Jan 2024 13:23:14 -0500
Subject: fixed marquee annotator for lightbox with pdf and rotated documents.

---
 src/client/views/MarqueeAnnotator.tsx | 29 +++++++++++++++++++----------
 1 file changed, 19 insertions(+), 10 deletions(-)

(limited to 'src/client/views/MarqueeAnnotator.tsx')

diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx
index 3eb43dacf..9f3786d8e 100644
--- a/src/client/views/MarqueeAnnotator.tsx
+++ b/src/client/views/MarqueeAnnotator.tsx
@@ -22,11 +22,12 @@ export interface MarqueeAnnotatorProps {
     Document: Doc;
     down?: number[];
     scrollTop: number;
+    isNativeScaled?: boolean;
     scaling?: () => number;
     annotationLayerScaling?: () => number;
     annotationLayerScrollTop: number;
     containerOffset?: () => number[];
-    mainCont: HTMLDivElement;
+    marqueeContainer: HTMLDivElement;
     docView: () => DocumentView;
     savedAnnotations: () => ObservableMap<number, HTMLDivElement[]>;
     selectionText: () => string;
@@ -147,20 +148,28 @@ export class MarqueeAnnotator extends ObservableReactComponent<MarqueeAnnotatorP
         savedAnnotations.set(page, savedPage ?? [div]);
     });
 
+    // this transforms a screen point into a local coordinate subject.  It's complicated by documents that are rotated
+    // since the DOM's bounding rectangle is not rotated and Dash's ScreenToLocalTransform carries along a rotation value, but doesn't
+    // use it when transforming points.
+    // So the idea here is to reconstruct a local point by unrotating the screen point about the center of the bounding box. The approach is:
+    //    1) Get vector from the screen point to the center of the rotated bounding box in screens space
+    //    2) unrotate that vector in screen space
+    //    3) localize the unrotated vector by scaling into the marquee container's coordinates
+    //    4) reattach the vector to the center of the bounding box
     getTransformedScreenPt = (down: number[]) => {
-        const boundingRect = this.props.mainCont.getBoundingClientRect();
+        const marqueeContainer = this.props.marqueeContainer;
+        const containerXf = this.props.isNativeScaled ? this.props.docView().screenToNativeLocalTransform() : this.props.docView().props.ScreenToLocalTransform();
+        const boundingRect = marqueeContainer.getBoundingClientRect();
         const center = { x: boundingRect.x + boundingRect.width / 2, y: boundingRect.y + boundingRect.height / 2 };
-        const downPt = Utils.rotPt(down[0] - center.x, down[1] - center.y, NumCast(this.props.docView().screenToLocalTransform().Rotate));
-        const scale = this.props.docView().props.ScreenToLocalTransform().Scale;
-        const scalex = this.props.mainCont.offsetWidth / NumCast(this.props.Document.width);
-        const scaley = this.props.mainCont.offsetHeight / NumCast(this.props.Document.height);
-        // set marquee x and y positions to the spatially transformed position
-        return { x: scalex * (downPt.x + NumCast(this.props.Document.width) / scale / 2) * scale, 
-                 y: scaley * (downPt.y + NumCast(this.props.Document.height) / scale / 2) * scale + this.props.annotationLayerScrollTop }; // prettier-ignore
+        const downVec = Utils.rotPt(down[0] - center.x,  
+                                    down[1] - center.y, NumCast(containerXf.Rotate)); // prettier-ignore
+        return { x: downVec.x * containerXf.Scale + marqueeContainer.offsetWidth /2,
+                 y: downVec.y * containerXf.Scale + marqueeContainer.offsetHeight/2 + this.props.annotationLayerScrollTop }; // prettier-ignore
     };
 
     @action
     public onInitiateSelection(down: number[]) {
+        console.log('DOWN = ' + down[0] + ' ' + down[1]);
         this._width = this._height = 0;
         this._start = this.getTransformedScreenPt(down);
 
@@ -242,7 +251,7 @@ export class MarqueeAnnotator extends ObservableReactComponent<MarqueeAnnotatorP
     @action
     onSelectEnd = (e: PointerEvent) => {
         e.stopPropagation();
-        const marquees = this.props.mainCont.getElementsByClassName('marqueeAnnotator-dragBox');
+        const marquees = this.props.marqueeContainer.getElementsByClassName('marqueeAnnotator-dragBox');
         const marqueeStyle = (Array.from(marquees).lastElement() as HTMLDivElement)?.style;
         if (!this.isEmpty && marqueeStyle) {
             // configure and show the annotation/link menu if a the drag region is big enough
-- 
cgit v1.2.3-70-g09d2

