@antv/s2
Version:
effective spreadsheet render core lib
118 lines • 5.48 kB
JavaScript
import EE from '@antv/event-emitter';
import { easeCubicIn as easeFunc } from '@antv/vendor/d3-ease';
import { OriginEventType } from '../../common';
/** 获取执行时间戳 */
const now = () => { var _a; return (_a = performance === null || performance === void 0 ? void 0 : performance.now()) !== null && _a !== void 0 ? _a : Date.now(); };
/** 动画总时间 */
const TOTAL_MS = 800;
/** swipe 手势判断阈值 */
const SWIPE_TIME_GAP = 100;
/**
* 判断是否是多点触控 (用于检测缩放手势)
* @param evt FederatedPointerEvent
* @returns boolean - true 表示是多点触控 (>= 2 个触摸点)
*/
const isMultiTouch = (evt) => {
var _a;
const nativeEvent = evt.nativeEvent;
// 检查是否是触摸事件且有多个触摸点
return ((_a = nativeEvent === null || nativeEvent === void 0 ? void 0 : nativeEvent.touches) === null || _a === void 0 ? void 0 : _a.length) >= 2;
};
/**
* 移动端滚动事件
* @see https://github.com/antvis/g-gesture/blob/next/src/event/wheel.ts
*/
export class WheelEvent extends EE {
constructor(canvas, shouldPreventDefault) {
super();
this.bindPointerDown = (evt) => {
// 多点触控时 (如缩放手势), 不开始滚动, 让浏览器处理原生缩放行为
// When multi-touch is detected (e.g., pinch-to-zoom), don't start panning
// to allow native browser zoom behavior
if (isMultiTouch(evt)) {
return;
}
window.cancelAnimationFrame(this.raf);
this.panning = true;
this.preX = evt.x;
this.preY = evt.y;
this.speedX = 0;
this.speedY = 0;
this.lastMoveMS = now();
};
this.bindPointerMove = (evt) => {
var _a, _b, _c, _d;
// 多点触控时 (如缩放手势), 停止滚动, 让浏览器处理原生缩放行为
// When multi-touch is detected (e.g., pinch-to-zoom), stop panning
// to allow native browser zoom behavior
if (isMultiTouch(evt)) {
this.panning = false;
window.cancelAnimationFrame(this.raf);
return;
}
if (this.panning) {
const nativeEvent = evt.nativeEvent;
const ms = now();
const deltaMS = ms - this.lastMoveMS;
const deltaX = this.preX - evt.x;
const deltaY = this.preY - evt.y;
// https://github.com/antvis/S2/issues/3249
// 根据回调判断是否阻止默认滚动行为
// 必须在事件链早期调用,否则浏览器的 passive 事件监听器会接管滚动
if (nativeEvent === null || nativeEvent === void 0 ? void 0 : nativeEvent.cancelable) {
const shouldPrevent = (_b = (_a = this.shouldPreventDefault) === null || _a === void 0 ? void 0 : _a.call(this, deltaX, deltaY, evt.x, evt.y)) !== null && _b !== void 0 ? _b : true;
if (shouldPrevent) {
(_d = (_c = nativeEvent).preventDefault) === null || _d === void 0 ? void 0 : _d.call(_c);
}
}
this.speedX = deltaX / deltaMS;
this.speedY = deltaY / deltaMS;
this.preX = evt.x;
this.preY = evt.y;
this.lastMoveMS = ms;
this.emit('wheel', Object.assign(Object.assign({}, evt.clone()), { x: evt.x, y: evt.y, deltaX,
deltaY,
// 传递原生事件用于移动端 preventDefault
nativeEvent }));
}
};
this.bindPointerUp = (evt) => {
this.panning = false;
const pointerUpMS = now();
if (!this.speedX ||
!this.speedY ||
pointerUpMS - this.lastMoveMS >= SWIPE_TIME_GAP) {
return;
}
const moveLoop = () => {
const loopStartMS = now();
this.raf = window.requestAnimationFrame(() => {
const ms = now();
const ratio = (ms - pointerUpMS) / TOTAL_MS;
if (ratio < 1) {
const currentRatio = easeFunc(1 - ratio);
const t = ms - loopStartMS;
this.emit('wheel', Object.assign(Object.assign({}, evt.clone()), { x: evt.x, y: evt.y, deltaX: this.speedX * currentRatio * t, deltaY: this.speedY * currentRatio * t }));
moveLoop();
}
});
};
moveLoop();
};
this.canvas = canvas;
this.panning = false;
this.shouldPreventDefault = shouldPreventDefault;
this.init();
}
init() {
this.canvas.addEventListener(OriginEventType.POINTER_DOWN, this.bindPointerDown);
this.canvas.addEventListener(OriginEventType.POINTER_MOVE, this.bindPointerMove);
this.canvas.addEventListener(OriginEventType.POINTER_UP, this.bindPointerUp);
}
destroy() {
this.canvas.removeEventListener(OriginEventType.POINTER_DOWN, this.bindPointerDown);
this.canvas.removeEventListener(OriginEventType.POINTER_MOVE, this.bindPointerMove);
this.canvas.removeEventListener(OriginEventType.POINTER_UP, this.bindPointerUp);
}
}
//# sourceMappingURL=wheelEvent.js.map