Forráskód Böngészése

fix(框架代码): 修复触摸手势坐标及手指提示定位偏移

- Gesture.ts:getX/getY 改用 clientX/Y - rect.left/top,替代 pageX/Y,
  修正 canvas 非全屏布局时触摸坐标相对 canvas 的偏移错误
- tap 回调同步修正,统一用 getBoundingClientRect() 计算相对坐标
- FingerHint.ts:contentToScreen 加上 canvas.getBoundingClientRect() 偏移,
  将 canvas 内坐标正确转换为 position:fixed 视口坐标系
guoziyun 3 hete
szülő
commit
2677d01d6f
2 módosított fájl, 87 hozzáadás és 104 törlés
  1. 78 102
      src/base/Gesture.ts
  2. 9 2
      src/filler/FingerHint.ts

+ 78 - 102
src/base/Gesture.ts

@@ -1,38 +1,35 @@
-
-type DragCallback = (dx: number, dy: number) => void
-type ZoomCallback = (scale: number, focusX: number, focusY: number) => void
-type TapCallback = (dx: number, dy: number) => void
+type DragCallback = (dx: number, dy: number) => void;
+type ZoomCallback = (scale: number, focusX: number, focusY: number) => void;
+type TapCallback = (dx: number, dy: number) => void;
 
 
 export interface Callbacks {
 export interface Callbacks {
-  drag?: DragCallback,
-  zoom?: ZoomCallback,
-  tap?: TapCallback,
+  drag?: DragCallback;
+  zoom?: ZoomCallback;
+  tap?: TapCallback;
 }
 }
 
 
-
-
 interface MyTouch {
 interface MyTouch {
-  identifier: number,
-  lastX: number,
-  lastY: number,
-  dx: number,
-  dy: number,
+  identifier: number;
+  lastX: number;
+  lastY: number;
+  dx: number;
+  dy: number;
 }
 }
 
 
 interface ScaleTracker {
 interface ScaleTracker {
-  focusX: number,
-  focusY: number,
-  distance: number,
+  focusX: number;
+  focusY: number;
+  distance: number;
 }
 }
 
 
 export class TouchTracker {
 export class TouchTracker {
-  touches: Array<MyTouch> = []
+  touches: Array<MyTouch> = [];
   callbacks: Callbacks;
   callbacks: Callbacks;
   el: HTMLElement;
   el: HTMLElement;
 
 
-  scaleTracker?: ScaleTracker
+  scaleTracker?: ScaleTracker;
 
 
-  distance = 0
+  distance = 0;
 
 
   constructor(el: HTMLElement, callbacks: Callbacks) {
   constructor(el: HTMLElement, callbacks: Callbacks) {
     this.callbacks = callbacks;
     this.callbacks = callbacks;
@@ -40,28 +37,27 @@ export class TouchTracker {
   }
   }
 
 
   private removeTouch(identifier: number) {
   private removeTouch(identifier: number) {
-    let index = this.touches.findIndex(t => t.identifier == identifier)
+    let index = this.touches.findIndex((t) => t.identifier == identifier);
     if (index >= 0) {
     if (index >= 0) {
-      this.touches.splice(index, 1)
+      this.touches.splice(index, 1);
     }
     }
   }
   }
 
 
   private getTouch(identifier: number): MyTouch | null {
   private getTouch(identifier: number): MyTouch | null {
-    let index = this.touches.findIndex(t => t.identifier == identifier)
-    if (index >= 0) return this.touches[index]
-    else return null
+    let index = this.touches.findIndex((t) => t.identifier == identifier);
+    if (index >= 0) return this.touches[index];
+    else return null;
   }
   }
 
 
   private getX(touch: Touch) {
   private getX(touch: Touch) {
-    //return touch.pageX - this.el.offsetLeft
-    return touch.pageX 
+    const rect = this.el.getBoundingClientRect();
+    return touch.clientX - rect.left;
   }
   }
   private getY(touch: Touch) {
   private getY(touch: Touch) {
-    //return touch.pageY - this.el.offsetTop
-    return touch.pageY 
+    const rect = this.el.getBoundingClientRect();
+    return touch.clientY - rect.top;
   }
   }
 
 
-
   start(list: TouchList) {
   start(list: TouchList) {
     for (var i = 0; i < list.length; i++) {
     for (var i = 0; i < list.length; i++) {
       let touch = list[i];
       let touch = list[i];
@@ -71,8 +67,8 @@ export class TouchTracker {
         lastY: this.getY(touch),
         lastY: this.getY(touch),
         dx: 0,
         dx: 0,
         dy: 0,
         dy: 0,
-        identifier: touch.identifier
-      })
+        identifier: touch.identifier,
+      });
     }
     }
 
 
     if (this.touches.length == 1) {
     if (this.touches.length == 1) {
@@ -80,13 +76,12 @@ export class TouchTracker {
     }
     }
 
 
     this.updateFocus();
     this.updateFocus();
-
   }
   }
 
 
   updateFocus() {
   updateFocus() {
     if (this.touches.length < 2) {
     if (this.touches.length < 2) {
       this.scaleTracker = undefined;
       this.scaleTracker = undefined;
-      return
+      return;
     }
     }
 
 
     let t1 = this.touches[0];
     let t1 = this.touches[0];
@@ -94,13 +89,14 @@ export class TouchTracker {
 
 
     let focusX = (t1.lastX + t2.lastX) / 2;
     let focusX = (t1.lastX + t2.lastX) / 2;
     let focusY = (t1.lastY + t2.lastY) / 2;
     let focusY = (t1.lastY + t2.lastY) / 2;
-    let distance = Math.sqrt(Math.pow(t2.lastX - t1.lastX, 2) + Math.pow(t2.lastY - t1.lastY, 2));
-    this.scaleTracker = { focusX, focusY, distance }
+    let distance = Math.sqrt(
+      Math.pow(t2.lastX - t1.lastX, 2) + Math.pow(t2.lastY - t1.lastY, 2),
+    );
+    this.scaleTracker = { focusX, focusY, distance };
   }
   }
 
 
-
   end(list: TouchList) {
   end(list: TouchList) {
-    console.log('end')
+    console.log("end");
     for (var i = 0; i < list.length; i++) {
     for (var i = 0; i < list.length; i++) {
       this.removeTouch(list[i].identifier);
       this.removeTouch(list[i].identifier);
     }
     }
@@ -108,32 +104,34 @@ export class TouchTracker {
 
 
     if (this.touches.length <= 0 && this.distance == 0) {
     if (this.touches.length <= 0 && this.distance == 0) {
       let touch = list[0];
       let touch = list[0];
-      let el = touch.target as HTMLElement
+      const rect = this.el.getBoundingClientRect();
       //console.log('kkkkkk', el.offsetLeft, el.offsetTop)
       //console.log('kkkkkk', el.offsetLeft, el.offsetTop)
-      //this.callbacks?.tap?.(touch.clientX - el.offsetLeft, touch.clientY - el.offsetTop)
-      this.callbacks?.tap?.(touch.clientX , touch.clientY)
+      this.callbacks?.tap?.(
+        touch.clientX - rect.left,
+        touch.clientY - rect.top,
+      );
     }
     }
   }
   }
 
 
-
   move(list: TouchList) {
   move(list: TouchList) {
     for (var i = 0; i < list.length; i++) {
     for (var i = 0; i < list.length; i++) {
       let touch = list[i];
       let touch = list[i];
       let mytouch = this.getTouch(touch.identifier);
       let mytouch = this.getTouch(touch.identifier);
       if (mytouch == null) continue;
       if (mytouch == null) continue;
-      mytouch.dx = this.getX(touch) - mytouch.lastX
-      mytouch.dy = this.getY(touch) - mytouch.lastY
-      mytouch.lastX = this.getX(touch)
-      mytouch.lastY = this.getY(touch)
+      mytouch.dx = this.getX(touch) - mytouch.lastX;
+      mytouch.dy = this.getY(touch) - mytouch.lastY;
+      mytouch.lastX = this.getX(touch);
+      mytouch.lastY = this.getY(touch);
 
 
       if (this.scaleTracker) {
       if (this.scaleTracker) {
-
         let t1 = this.touches[0];
         let t1 = this.touches[0];
         let t2 = this.touches[1];
         let t2 = this.touches[1];
 
 
         let focusX = (t1.lastX + t2.lastX) / 2;
         let focusX = (t1.lastX + t2.lastX) / 2;
         let focusY = (t1.lastY + t2.lastY) / 2;
         let focusY = (t1.lastY + t2.lastY) / 2;
-        let distance = Math.sqrt(Math.pow(t2.lastX - t1.lastX, 2) + Math.pow(t2.lastY - t1.lastY, 2));
+        let distance = Math.sqrt(
+          Math.pow(t2.lastX - t1.lastX, 2) + Math.pow(t2.lastY - t1.lastY, 2),
+        );
         let dx = focusX - this.scaleTracker.focusX;
         let dx = focusX - this.scaleTracker.focusX;
         let dy = focusY - this.scaleTracker.focusY;
         let dy = focusY - this.scaleTracker.focusY;
 
 
@@ -148,100 +146,78 @@ export class TouchTracker {
         this.scaleTracker.focusY = focusY;
         this.scaleTracker.focusY = focusY;
         this.scaleTracker.distance = distance;
         this.scaleTracker.distance = distance;
 
 
-        this.distance += Math.abs(dx) + Math.abs(dy)
-
-
+        this.distance += Math.abs(dx) + Math.abs(dy);
       } else {
       } else {
         //if(mytouch.dx > 0 || mytouch.dy >0) {
         //if(mytouch.dx > 0 || mytouch.dy >0) {
-        this.callbacks.drag?.(mytouch.dx, mytouch.dy)
+        this.callbacks.drag?.(mytouch.dx, mytouch.dy);
         // }
         // }
-        this.distance += Math.abs(mytouch.dx) + Math.abs(mytouch.dy)
+        this.distance += Math.abs(mytouch.dx) + Math.abs(mytouch.dy);
       }
       }
     }
     }
   }
   }
-
-
-
-
-
 }
 }
 
 
-
 export class Gesture {
 export class Gesture {
-
-
   constructor(el: HTMLElement, callbacks: Callbacks) {
   constructor(el: HTMLElement, callbacks: Callbacks) {
-
-
-
     var dx, dy;
     var dx, dy;
     var isDown = false;
     var isDown = false;
     var lastX: number = 0;
     var lastX: number = 0;
     var lastY: number = 0;
     var lastY: number = 0;
     var distance = 0;
     var distance = 0;
 
 
-    el.addEventListener('mousedown', e => {
+    el.addEventListener("mousedown", (e) => {
       isDown = true;
       isDown = true;
       lastX = e.clientX;
       lastX = e.clientX;
       lastY = e.clientY;
       lastY = e.clientY;
       distance = 0;
       distance = 0;
-    })
+    });
 
 
-    document.addEventListener('mouseup', e => {
+    document.addEventListener("mouseup", (e) => {
       isDown = false;
       isDown = false;
       if (distance == 0 && e.target == el) {
       if (distance == 0 && e.target == el) {
-        callbacks.tap?.(e.offsetX, e.offsetY)
+        callbacks.tap?.(e.offsetX, e.offsetY);
       }
       }
-    })
-
+    });
 
 
-    document.addEventListener('mousemove', e => {
+    document.addEventListener("mousemove", (e) => {
       if (isDown) {
       if (isDown) {
-        e.preventDefault()
+        e.preventDefault();
         dx = e.clientX - lastX;
         dx = e.clientX - lastX;
         dy = e.clientY - lastY;
         dy = e.clientY - lastY;
         lastX = e.clientX;
         lastX = e.clientX;
         lastY = e.clientY;
         lastY = e.clientY;
-        distance += Math.abs(dx) + Math.abs(dy)
+        distance += Math.abs(dx) + Math.abs(dy);
         callbacks?.drag?.(dx, dy);
         callbacks?.drag?.(dx, dy);
       }
       }
-    })
+    });
 
 
-    el.addEventListener('wheel', e => {
-      e.preventDefault()
+    el.addEventListener("wheel", (e) => {
+      e.preventDefault();
       let scale = e.deltaY * -0.01 + 1;
       let scale = e.deltaY * -0.01 + 1;
-      callbacks.zoom?.(scale, e.offsetX, e.offsetY)
-    })
+      callbacks.zoom?.(scale, e.offsetX, e.offsetY);
+    });
 
 
-    el.addEventListener('click', e => {
-      e.preventDefault()
+    el.addEventListener("click", (e) => {
+      e.preventDefault();
       //callbacks.tap?.(e.offsetX, e.offsetY)
       //callbacks.tap?.(e.offsetX, e.offsetY)
-    })
-
-
-
+    });
 
 
     const tracker = new TouchTracker(el, callbacks);
     const tracker = new TouchTracker(el, callbacks);
 
 
-
-
-    el.addEventListener('touchstart', e => {
+    el.addEventListener("touchstart", (e) => {
       e.preventDefault();
       e.preventDefault();
       tracker.start(e.changedTouches);
       tracker.start(e.changedTouches);
-    })
-
-    el.addEventListener('touchmove', e => {
-      tracker.move(e.changedTouches)
-    })
-
-    el.addEventListener('touchend', e => {
-      tracker.end(e.changedTouches)
-    })
-    el.addEventListener('touchcancel', e => {
-      tracker.end(e.changedTouches)
-    })
-
-
+    });
+
+    el.addEventListener("touchmove", (e) => {
+      tracker.move(e.changedTouches);
+    });
+
+    el.addEventListener("touchend", (e) => {
+      tracker.end(e.changedTouches);
+    });
+    el.addEventListener("touchcancel", (e) => {
+      tracker.end(e.changedTouches);
+    });
   }
   }
 }
 }
-

+ 9 - 2
src/filler/FingerHint.ts

@@ -81,14 +81,21 @@ export class FingerHint {
    * Scene 的 userMat 是列主序矩阵,对简单 scale+translate 变换:
    * Scene 的 userMat 是列主序矩阵,对简单 scale+translate 变换:
    *   physX = cx * mat[0] + cy * mat[4] + mat[12]
    *   physX = cx * mat[0] + cy * mat[4] + mat[12]
    *   physY = cx * mat[1] + cy * mat[5] + mat[13]
    *   physY = cx * mat[1] + cy * mat[5] + mat[13]
-   * 再除以 devicePixelRatio 得到 CSS px。
+   * 再除以 devicePixelRatio 得到 canvas 内 CSS px;
+   * 最后加上 canvas 元素的视口偏移,以匹配 position:fixed 坐标系。
    */
    */
   private contentToScreen(cx: number, cy: number): [number, number] {
   private contentToScreen(cx: number, cy: number): [number, number] {
     const mat = this.scene.userMat;
     const mat = this.scene.userMat;
     const ratio = this.scene.ratio;
     const ratio = this.scene.ratio;
     const physX = cx * mat[0] + cy * mat[4] + mat[12];
     const physX = cx * mat[0] + cy * mat[4] + mat[12];
     const physY = cx * mat[1] + cy * mat[5] + mat[13];
     const physY = cx * mat[1] + cy * mat[5] + mat[13];
-    return [physX / ratio, physY / ratio];
+    // canvas 内 CSS 像素
+    const canvasCssX = physX / ratio;
+    const canvasCssY = physY / ratio;
+    // 加上 canvas 在视口中的偏移,转换为 position:fixed 坐标
+    const canvas = this.scene.gl.canvas as HTMLElement;
+    const rect = canvas.getBoundingClientRect();
+    return [canvasCssX + rect.left, canvasCssY + rect.top];
   }
   }
 
 
   private show(cssX: number, cssY: number) {
   private show(cssX: number, cssY: number) {