fix: 修复ipad双指缩放问题
This commit is contained in:
@@ -250,8 +250,33 @@ export class CanvasEventManager {
|
||||
initialDistance: 0,
|
||||
initialZoom: 1,
|
||||
lastTouchTime: 0,
|
||||
lastZoomTime: 0,
|
||||
zoomThrottle: 16, // 约60fps的节流
|
||||
};
|
||||
|
||||
// iPad特殊处理:禁用默认的触摸行为
|
||||
if (this.deviceInfo.isTablet) {
|
||||
document.addEventListener(
|
||||
"touchstart",
|
||||
(e) => {
|
||||
if (e.target.closest("canvas")) {
|
||||
e.preventDefault();
|
||||
}
|
||||
},
|
||||
{ passive: false }
|
||||
);
|
||||
|
||||
document.addEventListener(
|
||||
"touchmove",
|
||||
(e) => {
|
||||
if (e.target.closest("canvas")) {
|
||||
e.preventDefault();
|
||||
}
|
||||
},
|
||||
{ passive: false }
|
||||
);
|
||||
}
|
||||
|
||||
// 使用标准的mouse事件,Fabric.js会自动处理触摸转换
|
||||
this.canvas.on("mouse:down", (opt) => {
|
||||
// 只在PAN模式下处理触摸事件
|
||||
@@ -325,9 +350,21 @@ export class CanvasEventManager {
|
||||
touches.length === 2 &&
|
||||
this.touchState.isZooming
|
||||
) {
|
||||
// 双指缩放处理
|
||||
// 双指缩放处理 - 修复抖动问题
|
||||
const currentDistance = this.getTouchDistance(touches[0], touches[1]);
|
||||
|
||||
// 防止除零和异常值
|
||||
if (this.touchState.initialDistance === 0 || currentDistance === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const scale = currentDistance / this.touchState.initialDistance;
|
||||
|
||||
// 防止抖动:忽略微小的变化
|
||||
if (Math.abs(scale - 1) < 0.01) {
|
||||
return;
|
||||
}
|
||||
|
||||
const newZoom = this.touchState.initialZoom * scale;
|
||||
|
||||
// 限制缩放范围
|
||||
@@ -424,7 +461,7 @@ export class CanvasEventManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置原生触摸事件监听器(备用方案)- 优化性能
|
||||
* 设置原生触摸事件监听器(备用方案)- 专门处理iPad双指缩放
|
||||
*/
|
||||
setupNativeTouchEvents() {
|
||||
const canvasElement = this.canvas.upperCanvasEl;
|
||||
@@ -432,38 +469,126 @@ export class CanvasEventManager {
|
||||
// 确保canvas元素支持触摸
|
||||
canvasElement.style.touchAction = "none";
|
||||
|
||||
// 原生touchstart事件 - 简化处理
|
||||
let lastTouchDistance = 0;
|
||||
let lastZoom = 1;
|
||||
|
||||
// 原生touchstart事件 - 处理双指缩放初始化
|
||||
canvasElement.addEventListener(
|
||||
"touchstart",
|
||||
(e) => {
|
||||
// 只在PAN模式下处理
|
||||
if (this.editorMode === OperationType.PAN) {
|
||||
if (this.editorMode !== OperationType.PAN) return;
|
||||
|
||||
// 调试信息
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
console.log("iPad touchstart:", e.touches.length, "fingers");
|
||||
}
|
||||
|
||||
if (e.touches.length === 2) {
|
||||
// 双指触摸开始
|
||||
this.touchState.isZooming = true;
|
||||
lastTouchDistance = this.getTouchDistance(e.touches[0], e.touches[1]);
|
||||
lastZoom = this.canvas.getZoom();
|
||||
|
||||
// 计算缩放中心点
|
||||
const centerX = (e.touches[0].clientX + e.touches[1].clientX) / 2;
|
||||
const centerY = (e.touches[0].clientY + e.touches[1].clientY) / 2;
|
||||
this.touchState.zoomCenter = { x: centerX, y: centerY };
|
||||
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
console.log("iPad双指缩放开始:", {
|
||||
distance: lastTouchDistance,
|
||||
zoom: lastZoom,
|
||||
center: this.touchState.zoomCenter,
|
||||
});
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
}
|
||||
},
|
||||
{ passive: false }
|
||||
);
|
||||
|
||||
// 原生touchmove事件 - 简化处理
|
||||
// 原生touchmove事件 - 处理双指缩放(修复抖动问题)
|
||||
canvasElement.addEventListener(
|
||||
"touchmove",
|
||||
(e) => {
|
||||
// 只在PAN模式下处理
|
||||
if (this.editorMode === OperationType.PAN) {
|
||||
if (this.editorMode !== OperationType.PAN) return;
|
||||
|
||||
if (e.touches.length === 2 && this.touchState.isZooming) {
|
||||
// 节流处理,避免过于频繁的缩放操作
|
||||
const now = Date.now();
|
||||
if (
|
||||
now - this.touchState.lastZoomTime <
|
||||
this.touchState.zoomThrottle
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const currentDistance = this.getTouchDistance(
|
||||
e.touches[0],
|
||||
e.touches[1]
|
||||
);
|
||||
|
||||
// 防止除零和异常值
|
||||
if (lastTouchDistance === 0 || currentDistance === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const scale = currentDistance / lastTouchDistance;
|
||||
|
||||
// 防止抖动:忽略微小的变化
|
||||
if (Math.abs(scale - 1) < 0.02) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 使用当前缩放值而不是初始缩放值,避免累积误差
|
||||
const currentZoom = this.canvas.getZoom();
|
||||
const newZoom = currentZoom * scale;
|
||||
|
||||
// 限制缩放范围
|
||||
const clampedZoom = Math.max(0.1, Math.min(5, newZoom));
|
||||
|
||||
if (process.env.NODE_ENV === "development") {
|
||||
console.log("iPad双指缩放中:", {
|
||||
currentDistance,
|
||||
lastTouchDistance,
|
||||
scale,
|
||||
currentZoom,
|
||||
newZoom,
|
||||
clampedZoom,
|
||||
});
|
||||
}
|
||||
|
||||
// 使用缩放中心点进行缩放
|
||||
const point = new fabric.Point(
|
||||
this.touchState.zoomCenter.x,
|
||||
this.touchState.zoomCenter.y
|
||||
);
|
||||
|
||||
this.canvas.zoomToPoint(point, clampedZoom);
|
||||
|
||||
// 更新基准距离和时间,避免累积误差
|
||||
lastTouchDistance = currentDistance;
|
||||
this.touchState.lastZoomTime = now;
|
||||
|
||||
e.preventDefault();
|
||||
}
|
||||
},
|
||||
{ passive: false }
|
||||
);
|
||||
|
||||
// 原生touchend事件 - 简化处理
|
||||
// 原生touchend事件 - 重置缩放状态
|
||||
canvasElement.addEventListener(
|
||||
"touchend",
|
||||
(e) => {
|
||||
// 只在PAN模式下处理
|
||||
if (this.editorMode === OperationType.PAN) {
|
||||
e.preventDefault();
|
||||
if (this.editorMode !== OperationType.PAN) return;
|
||||
|
||||
if (e.touches.length < 2) {
|
||||
this.touchState.isZooming = false;
|
||||
lastTouchDistance = 0;
|
||||
}
|
||||
|
||||
e.preventDefault();
|
||||
},
|
||||
{ passive: false }
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user