UNPKG

tldraw

Version:

A tiny little drawing editor.

8 lines (7 loc) 8.67 kB
{ "version": 3, "sources": ["../../../../../src/lib/tools/SelectTool/childStates/Rotating.ts"], "sourcesContent": ["import {\n\tRotateCorner,\n\tStateNode,\n\tTLPointerEventInfo,\n\tTLRotationSnapshot,\n\tapplyRotationToSnapshotShapes,\n\tdegreesToRadians,\n\tgetRotationSnapshot,\n\tkickoutOccludedShapes,\n\tshortAngleDist,\n\tsnapAngle,\n} from '@tldraw/editor'\nimport { CursorTypeMap } from './PointingResizeHandle'\n\nconst ONE_DEGREE = Math.PI / 180\n\nexport class Rotating extends StateNode {\n\tstatic override id = 'rotating'\n\n\tsnapshot = {} as TLRotationSnapshot\n\n\tinfo = {} as Extract<TLPointerEventInfo, { target: 'selection' }> & {\n\t\tonInteractionEnd?: string | (() => void)\n\t}\n\n\tmarkId = ''\n\n\toverride onEnter(\n\t\tinfo: TLPointerEventInfo & { target: 'selection'; onInteractionEnd?: string | (() => void) }\n\t) {\n\t\t// Store the event information\n\t\tthis.info = info\n\t\tif (typeof info.onInteractionEnd === 'string') {\n\t\t\tthis.parent.setCurrentToolIdMask(info.onInteractionEnd)\n\t\t}\n\n\t\tthis.markId = this.editor.markHistoryStoppingPoint('rotate start')\n\n\t\tconst snapshot = getRotationSnapshot({\n\t\t\teditor: this.editor,\n\t\t\tids: this.editor.getSelectedShapeIds(),\n\t\t})\n\t\tif (!snapshot) {\n\t\t\tthis.parent.transition('idle', this.info)\n\t\t\treturn\n\t\t}\n\t\tthis.snapshot = snapshot\n\n\t\t// Trigger a pointer move\n\t\tconst newSelectionRotation = this._getRotationFromPointerPosition({\n\t\t\tsnapToNearestDegree: false,\n\t\t})\n\n\t\tapplyRotationToSnapshotShapes({\n\t\t\teditor: this.editor,\n\t\t\tdelta: this._getRotationFromPointerPosition({ snapToNearestDegree: false }),\n\t\t\tsnapshot: this.snapshot,\n\t\t\tstage: 'start',\n\t\t})\n\n\t\t// Update cursor\n\t\tthis.editor.setCursor({\n\t\t\ttype: CursorTypeMap[this.info.handle as RotateCorner],\n\t\t\trotation: newSelectionRotation + this.snapshot.initialShapesRotation,\n\t\t})\n\t}\n\n\toverride onExit() {\n\t\tthis.editor.setCursor({ type: 'default', rotation: 0 })\n\t\tthis.parent.setCurrentToolIdMask(undefined)\n\n\t\tthis.snapshot = {} as TLRotationSnapshot\n\t}\n\n\toverride onPointerMove() {\n\t\tthis.update()\n\t}\n\n\toverride onKeyDown() {\n\t\tthis.update()\n\t}\n\n\toverride onKeyUp() {\n\t\tthis.update()\n\t}\n\n\toverride onPointerUp() {\n\t\tthis.complete()\n\t}\n\n\toverride onComplete() {\n\t\tthis.complete()\n\t}\n\n\toverride onCancel() {\n\t\tthis.cancel()\n\t}\n\n\t// ---\n\n\tprivate update() {\n\t\tconst newSelectionRotation = this._getRotationFromPointerPosition({\n\t\t\tsnapToNearestDegree: false,\n\t\t})\n\n\t\tapplyRotationToSnapshotShapes({\n\t\t\teditor: this.editor,\n\t\t\tdelta: newSelectionRotation,\n\t\t\tsnapshot: this.snapshot,\n\t\t\tstage: 'update',\n\t\t})\n\n\t\t// Update cursor\n\t\tthis.editor.setCursor({\n\t\t\ttype: CursorTypeMap[this.info.handle as RotateCorner],\n\t\t\trotation: newSelectionRotation + this.snapshot.initialShapesRotation,\n\t\t})\n\t}\n\n\tprivate cancel() {\n\t\t// Call onRotateCancel callback before bailing to mark\n\t\tconst { shapeSnapshots } = this.snapshot\n\n\t\tshapeSnapshots.forEach(({ shape }) => {\n\t\t\tconst current = this.editor.getShape(shape.id)\n\t\t\tif (current) {\n\t\t\t\tconst util = this.editor.getShapeUtil(shape)\n\t\t\t\tutil.onRotateCancel?.(shape, current)\n\t\t\t}\n\t\t})\n\n\t\tthis.editor.bailToMark(this.markId)\n\t\tconst { onInteractionEnd } = this.info\n\t\tif (onInteractionEnd) {\n\t\t\tif (typeof onInteractionEnd === 'string') {\n\t\t\t\tthis.editor.setCurrentTool(onInteractionEnd, this.info)\n\t\t\t} else {\n\t\t\t\tonInteractionEnd()\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t\tthis.parent.transition('idle', this.info)\n\t}\n\n\tprivate complete() {\n\t\tapplyRotationToSnapshotShapes({\n\t\t\teditor: this.editor,\n\t\t\tdelta: this._getRotationFromPointerPosition({ snapToNearestDegree: true }),\n\t\t\tsnapshot: this.snapshot,\n\t\t\tstage: 'end',\n\t\t})\n\t\tkickoutOccludedShapes(\n\t\t\tthis.editor,\n\t\t\tthis.snapshot.shapeSnapshots.map((s) => s.shape.id)\n\t\t)\n\t\tconst { onInteractionEnd } = this.info\n\t\tif (onInteractionEnd) {\n\t\t\tif (typeof onInteractionEnd === 'string') {\n\t\t\t\tthis.editor.setCurrentTool(onInteractionEnd, this.info)\n\t\t\t} else {\n\t\t\t\tonInteractionEnd()\n\t\t\t}\n\t\t\treturn\n\t\t}\n\t\tthis.parent.transition('idle', this.info)\n\t}\n\n\t_getRotationFromPointerPosition({ snapToNearestDegree }: { snapToNearestDegree: boolean }) {\n\t\tconst shiftKey = this.editor.inputs.getShiftKey()\n\t\tconst currentPagePoint = this.editor.inputs.getCurrentPagePoint()\n\t\tconst { initialCursorAngle, initialShapesRotation, initialPageCenter } = this.snapshot\n\n\t\t// The delta is the difference between the current angle and the initial angle\n\t\tconst preSnapRotationDelta = initialPageCenter.angle(currentPagePoint) - initialCursorAngle\n\t\tlet newSelectionRotation = initialShapesRotation + preSnapRotationDelta\n\n\t\tif (shiftKey) {\n\t\t\tnewSelectionRotation = snapAngle(newSelectionRotation, 24)\n\t\t} else if (snapToNearestDegree) {\n\t\t\tnewSelectionRotation = Math.round(newSelectionRotation / ONE_DEGREE) * ONE_DEGREE\n\n\t\t\tif (this.editor.getInstanceState().isCoarsePointer) {\n\t\t\t\tconst snappedToRightAngle = snapAngle(newSelectionRotation, 4)\n\t\t\t\tconst angleToRightAngle = shortAngleDist(newSelectionRotation, snappedToRightAngle)\n\t\t\t\tif (Math.abs(angleToRightAngle) < degreesToRadians(5)) {\n\t\t\t\t\tnewSelectionRotation = snappedToRightAngle\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn newSelectionRotation - initialShapesRotation\n\t}\n}\n"], "mappings": "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", "names": [] }