js-draw
Version:
Draw pictures using a pen, touchscreen, or mouse! JS-draw is a drawing library for JavaScript and TypeScript.
82 lines (81 loc) • 3.34 kB
JavaScript
import { InputEvtType } from '../../inputEvents.mjs';
import InputMapper from './InputMapper.mjs';
import { lineLockKeyboardShortcutId, snapToGridKeyboardShortcutId } from '../keybindings.mjs';
/**
* Provides keyboard shortcuts that provide some amount of control over
* drawing (e.g. snap to grid, plane lock).
*/
export default class StrokeKeyboardControl extends InputMapper {
constructor(shortcuts, viewport) {
super();
this.shortcuts = shortcuts;
this.viewport = viewport;
this.snapToGridEnabled = false;
this.angleLockEnabled = false;
// The point at which the last pointerDown event happened (or null if
// no such event has occurred).
this.startPointCanvas = null;
}
// Snap the given pointer to the nearer of the x/y axes.
xyAxesSnap(pointer) {
if (!this.startPointCanvas) {
return pointer;
}
// Convert this.startPointCanvas here because the viewport might change
// while drawing a stroke.
const screenPos = this.viewport.canvasToScreen(this.startPointCanvas);
return pointer.lockedToXYAxesScreen(screenPos, this.viewport);
}
mapPointerEvent(event) {
const mapPointer = (pointer) => {
// Only map if there's exactly one pointer.
if (event.allPointers.length > 1) {
return pointer;
}
if (this.snapToGridEnabled) {
return pointer.snappedToGrid(this.viewport);
}
if (this.angleLockEnabled && this.startPointCanvas) {
return this.xyAxesSnap(pointer);
}
return pointer;
};
return {
kind: event.kind,
current: mapPointer(event.current),
allPointers: event.allPointers.map(mapPointer),
};
}
onEvent(event) {
const shortcuts = this.shortcuts;
if (event.kind === InputEvtType.PointerDownEvt ||
event.kind === InputEvtType.PointerMoveEvt ||
event.kind === InputEvtType.PointerUpEvt) {
if (event.kind === InputEvtType.PointerDownEvt) {
this.startPointCanvas = event.current.canvasPos;
}
event = this.mapPointerEvent(event);
}
let handled = this.emit(event);
if (
// Always check keyUpEvents (in case we handled the corresponding keyDown event)
event.kind === InputEvtType.KeyUpEvent ||
// Only handle key press events if another tool isn't handling it. We don't want
// snap to grid/angle lock to conflict with selection/another tool's shortcuts.
(!handled && event.kind === InputEvtType.KeyPressEvent)) {
const isKeyPress = event.kind === InputEvtType.KeyPressEvent;
if (shortcuts.matchesShortcut(snapToGridKeyboardShortcutId, event)) {
this.snapToGridEnabled = isKeyPress;
handled = true;
}
if (shortcuts.matchesShortcut(lineLockKeyboardShortcutId, event)) {
this.angleLockEnabled = isKeyPress;
handled = true;
}
}
return handled;
}
static fromEditor(editor) {
return new StrokeKeyboardControl(editor.shortcuts, editor.viewport);
}
}