Skip to content

Commit

Permalink
feat: mouse event manager
Browse files Browse the repository at this point in the history
  • Loading branch information
F-star committed Jul 16, 2024
1 parent 4b71c63 commit eda1f2a
Show file tree
Hide file tree
Showing 7 changed files with 257 additions and 101 deletions.
77 changes: 37 additions & 40 deletions packages/core/src/canvas_dragger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { EventEmitter } from '@suika/common';
import { type IPoint } from '@suika/geo';

import { type SuikaEditor } from './editor';
import { type IMouseEvent, type IMousemoveEvent } from './host_event_manager';

interface Events {
activeChange(active: boolean): void;
Expand All @@ -17,8 +18,7 @@ export class CanvasDragger {
private isEnableDragCanvasBySpace = true;

private _isPressing = false;
private isDragging = false;
private startPoint: IPoint = { x: 0, y: 0 };
private startVwPos: IPoint = { x: 0, y: 0 };
private startViewportPos: IPoint = { x: 0, y: 0 };

private eventEmitter = new EventEmitter<Events>();
Expand Down Expand Up @@ -47,7 +47,7 @@ export class CanvasDragger {

constructor(private editor: SuikaEditor) {
this.editor.hostEventManager.on('spaceToggle', this.handleSpaceToggle);
this.editor.hostEventManager.on(
this.editor.mouseEventManager.on(
'wheelBtnToggle',
this.handleWheelBtnToggle,
);
Expand All @@ -69,20 +69,18 @@ export class CanvasDragger {
this.eventEmitter.emit('activeChange', true);
this._active = true;
this.editor.setCursor('grab');
this.bindEvent();
this.bindEventWhenActive();
if (event) {
this.editor.setCursor('grabbing');
this.handlePointerDown(event);
const vwPos = this.editor.getCursorXY(event);
this.onStart({
pos: this.editor.viewportCoordsToScene(vwPos.x, vwPos.y),
vwPos,
nativeEvent: event,
});
}
}

private bindEvent() {
const canvas = this.editor.canvasElement;
canvas.addEventListener('pointerdown', this.handlePointerDown);
window.addEventListener('pointermove', this.handlePointerMove);
window.addEventListener('pointerup', this.handlePointerUp);
}

inactive() {
if (this._isPressing) {
this.inactiveAfterPointerUp = true;
Expand All @@ -93,74 +91,73 @@ export class CanvasDragger {
}
this.eventEmitter.emit('activeChange', false);
this._active = false;
this.unbindEvent();
this.unbindEventWhenInactive();
this.editor.toolManager.setCursorWhenActive();
}
}

private unbindEvent() {
const canvas = this.editor.canvasElement;
canvas.removeEventListener('pointerdown', this.handlePointerDown);
window.removeEventListener('pointermove', this.handlePointerMove);
window.removeEventListener('pointerup', this.handlePointerUp);
this.editor.toolManager.setCursorWhenActive();
}

enableDragBySpace() {
this.isEnableDragCanvasBySpace = true;
}
disableDragBySpace() {
this.isEnableDragCanvasBySpace = false;
}

private handlePointerDown = (e: PointerEvent) => {
if (!(e.button === 0 || e.button === 1)) return;
private onStart = (event: IMouseEvent) => {
if (event.nativeEvent.button !== 0 && event.nativeEvent.button !== 1) {
return;
}
this.editor.cursorManager.setCursor('grabbing');

this._isPressing = true;
this.startPoint = this.editor.getCursorXY(e);
this.startVwPos = { ...event.vwPos };
this.startViewportPos = this.editor.viewportManager.getViewport();
};

private handlePointerMove = (e: PointerEvent) => {
private onDrag = (event: IMousemoveEvent) => {
if (!this._isPressing) return;
const point: IPoint = this.editor.getCursorXY(e);
const dx = point.x - this.startPoint.x;
const dy = point.y - this.startPoint.y;
const dx = event.vwPos.x - this.startVwPos.x;
const dy = event.vwPos.y - this.startVwPos.y;

const zoom = this.editor.zoomManager.getZoom();
const dragBlockStep = this.editor.setting.get('dragBlockStep');
if (
!this.isDragging &&
(Math.abs(dx) > dragBlockStep || Math.abs(dy) > dragBlockStep)
) {
this.isDragging = true;
}

if (this.isDragging) {
const zoom = this.editor.zoomManager.getZoom();
if (event.maxDragDistance > dragBlockStep / zoom) {
const viewportX = this.startViewportPos.x - dx / zoom;
const viewportY = this.startViewportPos.y - dy / zoom;
this.editor.viewportManager.setViewport({ x: viewportX, y: viewportY });
this.editor.render();
}
};

private handlePointerUp = () => {
private onEnd = () => {
this.editor.cursorManager.setCursor('grab');
this.isDragging = false;
this._isPressing = false;
if (this.inactiveAfterPointerUp) {
this.inactiveAfterPointerUp = false;
this.inactive();
}
};

private bindEventWhenActive() {
this.editor.mouseEventManager.on('start', this.onStart);
this.editor.mouseEventManager.on('drag', this.onDrag);
this.editor.mouseEventManager.on('end', this.onEnd);
}

private unbindEventWhenInactive() {
this.editor.mouseEventManager.off('start', this.onStart);
this.editor.mouseEventManager.off('drag', this.onDrag);
this.editor.mouseEventManager.off('end', this.onEnd);
}

destroy() {
this.editor.hostEventManager.off('spaceToggle', this.handleSpaceToggle);
this.editor.hostEventManager.off(
this.editor.mouseEventManager.off(
'wheelBtnToggle',
this.handleWheelBtnToggle,
);
this.unbindEvent();
this.unbindEventWhenInactive();
}

on<K extends keyof Events>(eventName: K, handler: Events[K]) {
Expand Down
4 changes: 3 additions & 1 deletion packages/core/src/editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { CursorManger, type ICursor } from './cursor_manager';
import { type GraphicsAttrs } from './graphs';
import { SuikaCanvas } from './graphs/canvas';
import { SuikaDocument } from './graphs/document';
import { HostEventManager } from './host_event_manager';
import { HostEventManager, MouseEventManager } from './host_event_manager';
import { ImgManager } from './Img_manager';
import { KeyBindingManager } from './key_binding_manager';
import { PathEditor } from './path_editor';
Expand Down Expand Up @@ -69,6 +69,7 @@ export class SuikaEditor {
imgManager: ImgManager;

cursorManager: CursorManger;
mouseEventManager: MouseEventManager;
keybindingManager: KeyBindingManager;
hostEventManager: HostEventManager;
clipboard: ClipboardManager;
Expand Down Expand Up @@ -96,6 +97,7 @@ export class SuikaEditor {
this.setting.set('offsetY', options.offsetY);
}

this.mouseEventManager = new MouseEventManager(this);
this.keybindingManager = new KeyBindingManager(this);
this.keybindingManager.bindEvent();

Expand Down
55 changes: 1 addition & 54 deletions packages/core/src/host_event_manager/host_event_manager.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { EventEmitter } from '@suika/common';
import { distance, type IPoint } from '@suika/geo';
import { type IPoint } from '@suika/geo';

import { type SuikaEditor } from '../editor';
import { CommandKeyBinding } from './command_key_binding';
Expand All @@ -9,9 +9,7 @@ interface Events {
shiftToggle(press: boolean): void;
altToggle(press: boolean): void;
spaceToggle(press: boolean): void;
wheelBtnToggle(press: boolean, event: PointerEvent): void;
contextmenu(point: IPoint): void;
continueClick(): void;
}

/**
Expand Down Expand Up @@ -43,7 +41,6 @@ export class HostEventManager {
bindHotkeys() {
this.bindModifiersRecordEvent(); // 记录 isShiftPressing 等值
this.bindWheelEvent();
this.bindMouseRecordEvent();
this.bindContextMenu();

this.moveGraphsKeyBinding.bindKey();
Expand Down Expand Up @@ -84,56 +81,6 @@ export class HostEventManager {
});
}

private bindMouseRecordEvent() {
let pointerDownTimeStamp = -Infinity;
let lastPointerDownPos: IPoint = { x: -99, y: -99 };

const handlePointerEvent = (event: PointerEvent) => {
// mouse left
if (event.button === 0 && event.type === 'pointerdown') {
const now = new Date().getTime();
const newPos = {
x: event.pageX,
y: event.pageY,
};

const interval = now - pointerDownTimeStamp;
const clickDistanceDiff = distance(newPos, lastPointerDownPos);
if (
interval < this.editor.setting.get('continueClickMaxGap') &&
clickDistanceDiff <
this.editor.setting.get('continueClickDistanceTol')
) {
pointerDownTimeStamp = now;
this.eventEmitter.emit('continueClick');
}
pointerDownTimeStamp = now;
lastPointerDownPos = newPos;
}

// mouse middle
if (event.button === 1) {
const prevWheelBtnPressing = this.isWheelBtnPressing;
this.isWheelBtnPressing = event.type === 'pointerdown';
if (prevWheelBtnPressing !== this.isWheelBtnPressing) {
this.eventEmitter.emit(
'wheelBtnToggle',
this.isWheelBtnPressing,
event,
);
}
}
};

document.addEventListener('pointerdown', handlePointerEvent);
document.addEventListener('pointerup', handlePointerEvent);

this.unbindHandlers.push(() => {
document.removeEventListener('pointerdown', handlePointerEvent);
document.removeEventListener('pointerup', handlePointerEvent);
});
}

/**
* shiftToggle 会在切换时触发。按住 shift 不放,只会触发一次
*/
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/host_event_manager/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './host_event_manager';
export * from './mouse_event_manager';
Loading

0 comments on commit eda1f2a

Please sign in to comment.