Skip to content

Commit

Permalink
refactor: refactor code of PinchHandler, support binding multiple typ…
Browse files Browse the repository at this point in the history
…es of callback
  • Loading branch information
zhongyunWan committed Feb 19, 2025
1 parent d56ad5a commit 75aa7f8
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 7 deletions.
70 changes: 65 additions & 5 deletions packages/g6/src/utils/pinch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,22 @@ export interface PinchEventOptions {
scale: number;
}

/**
* <zh/> 捏合手势阶段类型
* <en/> Pinch gesture phase type
* @remarks
* <zh/> 包含三个手势阶段:
* - start: 手势开始
* - move: 手势移动中
* - end: 手势结束
*
* <en/> Contains three gesture phases:
* - start: Gesture started
* - move: Gesture in progress
* - end: Gesture ended
*/
export type PinchPhase = 'start' | 'move' | 'end';

/**
* <zh/> 捏合手势回调函数类型
*
Expand Down Expand Up @@ -74,18 +90,28 @@ export class PinchHandler {

private emitter: EventEmitter;
private static instance: PinchHandler | null = null;
private static callbacks: {
start: PinchCallback[];
move: PinchCallback[];
end: PinchCallback[];
} = { start: [], move: [], end: [] };

constructor(
emitter: EventEmitter,
private callback: PinchCallback,
private phase: PinchPhase,
callback: PinchCallback,
) {
this.emitter = emitter;
if (PinchHandler.instance) return PinchHandler.instance;
if (PinchHandler.instance) {
PinchHandler.callbacks[this.phase].push(callback);
return PinchHandler.instance;
}
this.onPointerDown = this.onPointerDown.bind(this);
this.onPointerMove = this.onPointerMove.bind(this);
this.onPointerUp = this.onPointerUp.bind(this);
this.bindEvents();
PinchHandler.instance = this;
PinchHandler.callbacks[this.phase].push(callback);
}

private bindEvents() {
Expand Down Expand Up @@ -130,6 +156,7 @@ export class PinchHandler {
const dx = this.pointerByTouch[0].x - this.pointerByTouch[1].x;
const dy = this.pointerByTouch[0].y - this.pointerByTouch[1].y;
this.initialDistance = Math.sqrt(dx * dx + dy * dy);
PinchHandler.callbacks.start.forEach((cb) => cb(event, { scale: 0 }));
}
}

Expand All @@ -153,22 +180,25 @@ export class PinchHandler {
const currentDistance = Math.sqrt(dx * dx + dy * dy);
const ratio = currentDistance / this.initialDistance;

this.callback(event, { scale: (ratio - 1) * 5 });
PinchHandler.callbacks.move.forEach((cb) => cb(event, { scale: (ratio - 1) * 5 }));
}

/**
* <zh/> 处理指针抬起事件
*
* <en/> Handle pointer up event
* @param event
* @remarks
* <zh/> 重置触摸状态和初始距离
*
* <en/> Reset touch state and initial distance
*/
onPointerUp() {
onPointerUp(event: IPointerEvent) {
PinchHandler.callbacks.end.forEach((cb) => cb(event, { scale: 0 }));
PinchHandler.isPinchStage = false;
this.initialDistance = null;
this.pointerByTouch = [];
PinchHandler.instance?.tryDestroy();
}

/**
Expand All @@ -180,10 +210,40 @@ export class PinchHandler {
*
* <en/> Remove listeners for pointer down, move, and up events
*/
destroy() {
public destroy() {
this.emitter.off(CommonEvent.POINTER_DOWN, this.onPointerDown);
this.emitter.off(CommonEvent.POINTER_MOVE, this.onPointerMove);
this.emitter.off(CommonEvent.POINTER_UP, this.onPointerUp);
PinchHandler.instance = null;
}

/**
* <zh/> 解绑指定阶段的手势回调
* <en/> Unregister gesture callback for specific phase
* @param phase - <zh/> 手势阶段:开始(start)/移动(move)/结束(end) | <en/> Gesture phase: start/move/end
* @param callback - <zh/> 要解绑的回调函数 | <en/> Callback function to unregister
* @remarks
* <zh/> 从指定阶段的回调列表中移除特定回调,当所有回调都解绑后自动销毁事件监听
* <en/> Remove specific callback from the phase's callback list, auto-destroy event listeners when all callbacks are unregistered
*/
public unregister(phase: PinchPhase, callback: PinchCallback) {
const index = PinchHandler.callbacks[phase].indexOf(callback);
if (index > -1) PinchHandler.callbacks[phase].splice(index, 1);
this.tryDestroy();
}

/**
* <zh/> 尝试销毁手势处理器
* <en/> Attempt to destroy the gesture handler
* @remarks
* <zh/> 当所有阶段(开始/移动/结束)的回调列表都为空时,执行实际销毁操作
* <en/> Perform actual destruction when all phase (start/move/end) callback lists are empty
* <zh/> 自动解除事件监听并重置单例实例
* <en/> Automatically remove event listeners and reset singleton instance
*/
private tryDestroy() {
if (Object.values(PinchHandler.callbacks).every((arr) => arr.length === 0)) {
this.destroy();
}
}
}
4 changes: 2 additions & 2 deletions packages/g6/src/utils/shortcut.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export class Shortcut {
public bind(key: ShortcutKey, handler: Handler) {
if (key.length === 0) return;
if (key.includes(CommonEvent.PINCH) && !this.pinchHandler) {
this.pinchHandler = new PinchHandler(this.emitter, this.handlePinch.bind(this));
this.pinchHandler = new PinchHandler(this.emitter, 'move', this.handlePinch.bind(this));
}
this.map.set(key, handler);
}
Expand Down Expand Up @@ -127,7 +127,7 @@ export class Shortcut {
this.emitter.off(CommonEvent.KEY_UP, this.onKeyUp);
this.emitter.off(CommonEvent.WHEEL, this.onWheel);
this.emitter.off(CommonEvent.DRAG, this.onDrag);
this.pinchHandler?.destroy();
this.pinchHandler?.unregister('move', this.handlePinch.bind(this));
globalThis.removeEventListener?.('blur', this.onFocus);
}
}

0 comments on commit 75aa7f8

Please sign in to comment.