canvas/pages/index/gesture-handler.js

225 lines
6.4 KiB
JavaScript

import AnyTouch from 'any-touch'
class GestureHandler {
constructor(context, transformMatrix, { container }) {
this.transformMatrix = transformMatrix;
this.containerRect = container;
this.panThreshold = 5; // 移动5像素以上才认为是拖动
this.panStarted = false;
// 小程序环境兼容处理
const atOptions = {
getPoint: touch => ({
x: touch.clientX - this.containerRect.left,
y: touch.clientY - this.containerRect.top
}),
preventDefault: false
};
// 小程序特化处理 - 跳过DOM相关操作
if (typeof window === 'undefined' || typeof HTMLElement === 'undefined') {
// 小程序环境下不需要设置DOM属性
atOptions._element = {
style: {},
addEventListener: () => {},
removeEventListener: () => {}
};
}
try {
this.at = new AnyTouch(atOptions);
} catch (e) {
console.error('AnyTouch初始化失败:', e);
// 降级方案:在小程序环境实现基本手势
this.handleGesture = this.createSimpleGestureHandler();
}
if (this.at) {
this.setupGestures();
console.log('AnyTouch手势处理器已初始化');
} else {
console.warn('使用简化手势处理器');
}
}
// 创建小程序专用的简化手势处理器
createSimpleGestureHandler() {
return {
run: (event) => {
// 小程序环境下的基本手势实现
const touches = event.touches || [];
if (touches.length === 1) {
// 单指移动
this._handlePan(touches[0]);
} else if (touches.length > 1) {
// 双指缩放
this._handlePinch(touches);
}
}
};
}
setupGestures() {
// 平移手势 - 修复版本
this.at.on('pan', (event) => {
if (event.type === 'panstart') {
console.log('panstart', event);
// 重置移动开始状态
this.panStarted = false;
}
else if (event.type === 'panmove') {
// 检查是否超过阈值
const distance = Math.sqrt(event.deltaX**2 + event.deltaY**2);
if (!this.panStarted && distance < this.panThreshold) {
return; // 小于阈值不处理
}
if (!this.panStarted) {
console.log('拖动手势开始');
this.panStarted = true;
}
// 基于当前缩放比例修正移动量
const currentScale = Math.sqrt(
this.transformMatrix.a * this.transformMatrix.a +
this.transformMatrix.b * this.transformMatrix.b
);
// 逆缩放移动量
const dx = event.deltaX / currentScale;
const dy = event.deltaY / currentScale;
console.log(`平移: deltaX=${event.deltaX}, deltaY=${event.deltaY} | 修正后: dx=${dx}, dy=${dy}`);
this.transformMatrix.translate(dx, dy);
} else if (event.type === 'panend') {
this.panStarted = false;
}
});
// 缩放手势 - 修复版本
this.at.on('pinch', (event) => {
if (event.type === 'pinchstart') {
this.lastScale = 1;
}
else if (event.type === 'pinchmove') {
// 计算缩放变化量
const scaleChange = event.scale / this.lastScale;
this.lastScale = event.scale;
// 使用两指中心点
const centerX = event.center.x;
const centerY = event.center.y;
console.log(`缩放: scale=${event.scale} | 变化=${scaleChange} | 中心点: (${centerX}, ${centerY})`);
// 应用缩放
this.transformMatrix.scale(scaleChange, scaleChange, centerX, centerY);
}
});
// 点击手势
this.at.on('tap', (event) => {
console.log('点击事件', event);
});
// 长按手势
this.at.on('press', (event) => {
console.log('长按事件', event);
});
}
// 公共接口保持不变
catchEvent(event) {
try {
if (this.at) {
this.at.run(event);
} else {
// 内部处理降级方案
const touches = event.touches || [];
const eventType = event.type;
// 在事件开始时重置状态
if (eventType === 'touchstart') {
this.lastPoint = null;
this.lastPoints = null;
this.lastDistance = null;
}
// 处理不同数量的手指
if (touches.length === 1) {
this._handlePan(touches[0]);
} else if (touches.length > 1) {
this._handlePinch(touches);
}
}
} catch (e) {
console.error('手势处理错误:', e);
}
}
// 基础平移手势处理
_handlePan(touch) {
const pointX = touch.x || (touch.clientX - this.containerRect.left);
const pointY = touch.y || (touch.clientY - this.containerRect.top);
if (this.lastPoint) {
// 基于容器坐标系的增量计算
const dx = pointX - this.lastPoint.x;
const dy = pointY - this.lastPoint.y;
// 使用真实增量,不需要缩放修正
this.transformMatrix.translate(dx, dy);
}
// 存储当前点 (容器坐标系)
this.lastPoint = {x: pointX, y: pointY};
}
// 基础缩放手势处理
_handlePinch(touches) {
const point1 = touches[0];
const point2 = touches[1];
// 获取容器坐标系坐标
const getPoint = (touch) => ({
x: touch.x || (touch.clientX - this.containerRect.left),
y: touch.y || (touch.clientY - this.containerRect.top)
});
const currentPoints = [getPoint(point1), getPoint(point2)];
if (this.lastPoints) {
// 计算当前距离 (容器坐标系)
const currentDistance = Math.sqrt(
Math.pow(currentPoints[1].x - currentPoints[0].x, 2) +
Math.pow(currentPoints[1].y - currentPoints[0].y, 2)
);
// 上次距离 (容器坐标系)
const prevDistance = Math.sqrt(
Math.pow(this.lastPoints[1].x - this.lastPoints[0].x, 2) +
Math.pow(this.lastPoints[1].y - this.lastPoints[0].y, 2)
);
// 缩放比例
if (prevDistance > 0 && currentDistance > 0) {
const scaleChange = currentDistance / prevDistance;
// 计算中心点 (容器坐标系)
const centerX = (currentPoints[0].x + currentPoints[1].x) / 2;
const centerY = (currentPoints[0].y + currentPoints[1].y) / 2;
this.transformMatrix.scale(scaleChange, scaleChange, centerX, centerY);
}
}
// 存储当前点
this.lastPoints = currentPoints;
}
}
export default GestureHandler;