UNPKG

tldraw

Version:

A tiny little drawing editor.

153 lines (152 loc) 4.62 kB
import { StateNode, applyRotationToSnapshotShapes, degreesToRadians, getRotationSnapshot, kickoutOccludedShapes, shortAngleDist, snapAngle } from "@tldraw/editor"; import { CursorTypeMap } from "./PointingResizeHandle.mjs"; const ONE_DEGREE = Math.PI / 180; class Rotating extends StateNode { static id = "rotating"; snapshot = {}; info = {}; markId = ""; onEnter(info) { this.info = info; if (typeof info.onInteractionEnd === "string") { this.parent.setCurrentToolIdMask(info.onInteractionEnd); } this.markId = this.editor.markHistoryStoppingPoint("rotate start"); const snapshot = getRotationSnapshot({ editor: this.editor, ids: this.editor.getSelectedShapeIds() }); if (!snapshot) { this.parent.transition("idle", this.info); return; } this.snapshot = snapshot; const newSelectionRotation = this._getRotationFromPointerPosition({ snapToNearestDegree: false }); applyRotationToSnapshotShapes({ editor: this.editor, delta: this._getRotationFromPointerPosition({ snapToNearestDegree: false }), snapshot: this.snapshot, stage: "start" }); this.editor.setCursor({ type: CursorTypeMap[this.info.handle], rotation: newSelectionRotation + this.snapshot.initialShapesRotation }); } onExit() { this.editor.setCursor({ type: "default", rotation: 0 }); this.parent.setCurrentToolIdMask(void 0); this.snapshot = {}; } onPointerMove() { this.update(); } onKeyDown() { this.update(); } onKeyUp() { this.update(); } onPointerUp() { this.complete(); } onComplete() { this.complete(); } onCancel() { this.cancel(); } // --- update() { const newSelectionRotation = this._getRotationFromPointerPosition({ snapToNearestDegree: false }); applyRotationToSnapshotShapes({ editor: this.editor, delta: newSelectionRotation, snapshot: this.snapshot, stage: "update" }); this.editor.setCursor({ type: CursorTypeMap[this.info.handle], rotation: newSelectionRotation + this.snapshot.initialShapesRotation }); } cancel() { const { shapeSnapshots } = this.snapshot; shapeSnapshots.forEach(({ shape }) => { const current = this.editor.getShape(shape.id); if (current) { const util = this.editor.getShapeUtil(shape); util.onRotateCancel?.(shape, current); } }); this.editor.bailToMark(this.markId); const { onInteractionEnd } = this.info; if (onInteractionEnd) { if (typeof onInteractionEnd === "string") { this.editor.setCurrentTool(onInteractionEnd, this.info); } else { onInteractionEnd(); } return; } this.parent.transition("idle", this.info); } complete() { applyRotationToSnapshotShapes({ editor: this.editor, delta: this._getRotationFromPointerPosition({ snapToNearestDegree: true }), snapshot: this.snapshot, stage: "end" }); kickoutOccludedShapes( this.editor, this.snapshot.shapeSnapshots.map((s) => s.shape.id) ); const { onInteractionEnd } = this.info; if (onInteractionEnd) { if (typeof onInteractionEnd === "string") { this.editor.setCurrentTool(onInteractionEnd, this.info); } else { onInteractionEnd(); } return; } this.parent.transition("idle", this.info); } _getRotationFromPointerPosition({ snapToNearestDegree }) { const shiftKey = this.editor.inputs.getShiftKey(); const currentPagePoint = this.editor.inputs.getCurrentPagePoint(); const { initialCursorAngle, initialShapesRotation, initialPageCenter } = this.snapshot; const preSnapRotationDelta = initialPageCenter.angle(currentPagePoint) - initialCursorAngle; let newSelectionRotation = initialShapesRotation + preSnapRotationDelta; if (shiftKey) { newSelectionRotation = snapAngle(newSelectionRotation, 24); } else if (snapToNearestDegree) { newSelectionRotation = Math.round(newSelectionRotation / ONE_DEGREE) * ONE_DEGREE; if (this.editor.getInstanceState().isCoarsePointer) { const snappedToRightAngle = snapAngle(newSelectionRotation, 4); const angleToRightAngle = shortAngleDist(newSelectionRotation, snappedToRightAngle); if (Math.abs(angleToRightAngle) < degreesToRadians(5)) { newSelectionRotation = snappedToRightAngle; } } } return newSelectionRotation - initialShapesRotation; } } export { Rotating }; //# sourceMappingURL=Rotating.mjs.map