1
0
فهرست منبع

移动端双指缩放

tangning 4 ماه پیش
والد
کامیت
00077bf1ab
1فایلهای تغییر یافته به همراه149 افزوده شده و 1 حذف شده
  1. 149 1
      src/view/case/photos/canvas-photo-editor.js

+ 149 - 1
src/view/case/photos/canvas-photo-editor.js

@@ -94,6 +94,19 @@ export class CanvasPhotoEditor {
     this.history = []
     this.isHistory = false
     this.currentIndex = -1;   // 当前在第几步
+    // 新增:触摸状态
+    this.touchState = {
+      isTouching: false,       // 是否触摸中
+      isPinching: false,       // 是否双指缩放中
+      startDistance: 0,        // 双指初始距离
+      startScale: 0,           // 缩放初始值
+      startX: 0,               // 单指初始X
+      startY: 0,               // 单指初始Y
+      lastTouchOffsetX: 0,     // 触摸初始偏移X
+      lastTouchOffsetY: 0,     // 触摸初始偏移Y
+      touchStartTime: 0        // 触摸开始时间(防点击穿透)
+    }
+
     // 绑定事件
     this.handleMouseDown = this.handleMouseDown.bind(this)
     this.handleMouseMove = this.handleMouseMove.bind(this)
@@ -158,7 +171,12 @@ export class CanvasPhotoEditor {
     document.addEventListener('mousemove', this.handleMouseMove)//移动鼠标时触发
     document.addEventListener('mouseup', this.handleMouseUp)//释放鼠标按键时触发
     document.addEventListener('mouseleave', this.handleMouseLeave)//离开触发
-
+    
+    // 新增:移动端触摸事件
+    this.canvas.addEventListener('touchstart', this.handleTouchStart.bind(this), { passive: false })
+    this.canvas.addEventListener('touchmove', this.handleTouchMove.bind(this), { passive: false })
+    this.canvas.addEventListener('touchend', this.handleTouchEnd.bind(this))
+    this.canvas.addEventListener('touchcancel', this.handleTouchEnd.bind(this))
     // 初始化画布
     this.resizeCanvas()
     this.resetPosition()
@@ -182,6 +200,11 @@ export class CanvasPhotoEditor {
     document.removeEventListener('mousemove', this.handleMouseMove)//移动鼠标时触发
     document.removeEventListener('mouseup', this.handleMouseUp)//释放鼠标按键时触发
     document.removeEventListener('mouseleave', this.handleMouseLeave)//离开触发
+    // 新增:解绑触摸事件
+    this.canvas.removeEventListener('touchstart', this.handleTouchStart)
+    this.canvas.removeEventListener('touchmove', this.handleTouchMove)
+    this.canvas.removeEventListener('touchend', this.handleTouchEnd)
+    this.canvas.removeEventListener('touchcancel', this.handleTouchEnd)
     this.imgCache.clear()
   }
 
@@ -536,6 +559,131 @@ export class CanvasPhotoEditor {
     this.drawAllPages()
     console.log('tempArrow', this.indexing, this.tempArrow)
   }
+
+  /**
+ * 计算双指之间的距离
+ * @param {TouchList} touches - 触摸点列表
+ * @returns {number} 双指距离
+ */
+getTouchDistance(touches) {
+  if (touches.length < 2) return 0
+  const touch1 = touches[0]
+  const touch2 = touches[1]
+  const dx = touch2.clientX - touch1.clientX
+  const dy = touch2.clientY - touch1.clientY
+  return Math.sqrt(dx * dx + dy * dy)
+}
+
+/**
+ * 计算双指中点坐标
+ * @param {TouchList} touches - 触摸点列表
+ * @returns {Object} 中点坐标 {x, y}
+ */
+getTouchCenter(touches) {
+  if (touches.length < 2) return { x: 0, y: 0 }
+  const touch1 = touches[0]
+  const touch2 = touches[1]
+  return {
+    x: (touch1.clientX + touch2.clientX) / 2,
+    y: (touch1.clientY + touch2.clientY) / 2
+  }
+}
+
+/**
+ * 触摸开始事件
+ * @param {TouchEvent} e - 触摸事件
+ */
+handleTouchStart(e) {
+  e.preventDefault() // 阻止默认滚动行为
+  const rect = this.canvas.getBoundingClientRect()
+  this.touchState.isTouching = true
+  this.touchState.touchStartTime = Date.now()
+
+  // 双指缩放开始
+  if (e.touches.length === 2) {
+    this.touchState.isPinching = true
+    this.touchState.startDistance = this.getTouchDistance(e.touches)
+    this.touchState.startScale = this._scale // 记录初始缩放值
+    
+    // 计算双指中点作为缩放中心
+    const center = this.getTouchCenter(e.touches)
+    this.touchState.lastTouchOffsetX = this.drawOffsetX
+    this.touchState.lastTouchOffsetY = this.drawOffsetY
+    this.touchState.scaleCenterX = center.x - rect.left
+    this.touchState.scaleCenterY = center.y - rect.top
+  } 
+  // 单指拖拽开始
+  else if (e.touches.length === 1) {
+    const touch = e.touches[0]
+    this.touchState.startX = touch.clientX
+    this.touchState.startY = touch.clientY
+    this.touchState.lastTouchOffsetX = this.drawOffsetX
+    this.touchState.lastTouchOffsetY = this.drawOffsetY
+  }
+}
+
+/**
+ * 触摸移动事件
+ * @param {TouchEvent} e - 触摸事件
+ */
+handleTouchMove(e) {
+  if (!this.touchState.isTouching) return
+  e.preventDefault()
+  const rect = this.canvas.getBoundingClientRect()
+
+  // 双指缩放逻辑
+  if (e.touches.length === 2 && this.touchState.isPinching) {
+    const currentDistance = this.getTouchDistance(e.touches)
+    const scaleRatio = currentDistance / this.touchState.startDistance
+    const newScale = Math.max(this._scaleMin, Math.min(this._scaleMax, this.touchState.startScale * scaleRatio))
+    
+    // 计算缩放偏移(保证缩放中心在双指中点)
+    const scaleDiff = newScale / this._scale
+    this.drawOffsetX = (this.touchState.scaleCenterX - (this.touchState.scaleCenterX - this.touchState.lastTouchOffsetX) * scaleDiff)
+    this.drawOffsetY = (this.touchState.scaleCenterY - (this.touchState.scaleCenterY - this.touchState.lastTouchOffsetY) * scaleDiff)
+    
+    this.scale = newScale // 触发重绘
+  } 
+  // 单指拖拽逻辑
+  else if (e.touches.length === 1 && !this.touchState.isPinching) {
+    const touch = e.touches[0]
+    const deltaX = touch.clientX - this.touchState.startX
+    const deltaY = touch.clientY - this.touchState.startY
+    
+    // 更新拖拽偏移(和鼠标拖拽逻辑一致)
+    this.drawOffsetX = this.touchState.lastTouchOffsetX + deltaX
+    this.drawOffsetY = this.touchState.lastTouchOffsetY + deltaY
+    
+    // 实时重绘(保持拖拽流畅)
+    this.drawAllPages()
+  }
+}
+
+/**
+ * 触摸结束事件
+ * @param {TouchEvent} e - 触摸事件
+ */
+handleTouchEnd(e) {
+  // 过滤快速点击(防止点击穿透)
+  const touchDuration = Date.now() - this.touchState.touchStartTime
+  if (touchDuration < 300 && e.touches.length === 0) {
+    // 模拟点击事件(可选:需要点击逻辑的话)
+    const touch = e.changedTouches[0]
+    const clickEvent = new MouseEvent('mousedown', {
+      clientX: touch.clientX,
+      clientY: touch.clientY,
+      button: 0
+    })
+    this.canvas.dispatchEvent(clickEvent)
+  }
+
+  // 重置触摸状态
+  this.touchState.isTouching = false
+  this.touchState.isPinching = false
+  this.touchState.startDistance = 0
+  this.touchState.startScale = 0
+}
+
   // --- 拖拽预览:轻量级绘制,仅更新偏移(替代全量重绘)---
   drawDragPreview() {
     // 快速绘制当前状态(跳过照片,提升流畅度)