UNPKG

@tldraw/editor

Version:

tldraw infinite canvas SDK (editor).

8 lines (7 loc) • 8.39 kB
{ "version": 3, "sources": ["../../../../../src/lib/editor/managers/ScribbleManager/ScribbleManager.ts"], "sourcesContent": ["import { TLScribble, VecModel } from '@tldraw/tlschema'\nimport { uniqueId } from '@tldraw/utils'\nimport { Vec } from '../../../primitives/Vec'\nimport { Editor } from '../../Editor'\n\n/** @public */\nexport interface ScribbleItem {\n\tid: string\n\tscribble: TLScribble\n\ttimeoutMs: number\n\tdelayRemaining: number\n\tprev: null | VecModel\n\tnext: null | VecModel\n}\n\n/** @public */\nexport class ScribbleManager {\n\tscribbleItems = new Map<string, ScribbleItem>()\n\tstate = 'paused' as 'paused' | 'running'\n\n\tconstructor(private editor: Editor) {}\n\n\taddScribble(scribble: Partial<TLScribble>, id = uniqueId()) {\n\t\tconst item: ScribbleItem = {\n\t\t\tid,\n\t\t\tscribble: {\n\t\t\t\tid,\n\t\t\t\tsize: 20,\n\t\t\t\tcolor: 'accent',\n\t\t\t\topacity: 0.8,\n\t\t\t\tdelay: 0,\n\t\t\t\tpoints: [],\n\t\t\t\tshrink: 0.1,\n\t\t\t\ttaper: true,\n\t\t\t\t...scribble,\n\t\t\t\tstate: 'starting',\n\t\t\t},\n\t\t\ttimeoutMs: 0,\n\t\t\tdelayRemaining: scribble.delay ?? 0,\n\t\t\tprev: null,\n\t\t\tnext: null,\n\t\t}\n\t\tthis.scribbleItems.set(id, item)\n\t\treturn item\n\t}\n\n\treset() {\n\t\tthis.editor.updateInstanceState({ scribbles: [] })\n\t\tthis.scribbleItems.clear()\n\t}\n\n\t/**\n\t * Start stopping the scribble. The scribble won't be removed until its last point is cleared.\n\t *\n\t * @public\n\t */\n\tstop(id: ScribbleItem['id']) {\n\t\tconst item = this.scribbleItems.get(id)\n\t\tif (!item) throw Error(`Scribble with id ${id} not found`)\n\t\titem.delayRemaining = Math.min(item.delayRemaining, 200)\n\t\titem.scribble.state = 'stopping'\n\t\treturn item\n\t}\n\n\t/**\n\t * Set the scribble's next point.\n\t *\n\t * @param id - The id of the scribble to add a point to.\n\t * @param x - The x coordinate of the point.\n\t * @param y - The y coordinate of the point.\n\t * @param z - The z coordinate of the point.\n\t * @public\n\t */\n\taddPoint(id: ScribbleItem['id'], x: number, y: number, z = 0.5) {\n\t\tconst item = this.scribbleItems.get(id)\n\t\tif (!item) throw Error(`Scribble with id ${id} not found`)\n\t\tconst { prev } = item\n\t\tconst point = { x, y, z }\n\t\tif (!prev || Vec.Dist(prev, point) >= 1) {\n\t\t\titem.next = point\n\t\t}\n\t\treturn item\n\t}\n\n\t/**\n\t * Update on each animation frame.\n\t *\n\t * @param elapsed - The number of milliseconds since the last tick.\n\t * @public\n\t */\n\ttick(elapsed: number) {\n\t\tif (this.scribbleItems.size === 0) return\n\t\tthis.editor.run(() => {\n\t\t\tthis.scribbleItems.forEach((item) => {\n\t\t\t\t// let the item get at least eight points before\n\t\t\t\t// switching from starting to active\n\t\t\t\tif (item.scribble.state === 'starting') {\n\t\t\t\t\tconst { next, prev } = item\n\t\t\t\t\tif (next && next !== prev) {\n\t\t\t\t\t\titem.prev = next\n\t\t\t\t\t\titem.scribble.points.push(next)\n\t\t\t\t\t}\n\n\t\t\t\t\tif (item.scribble.points.length > 8) {\n\t\t\t\t\t\titem.scribble.state = 'active'\n\t\t\t\t\t}\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tif (item.delayRemaining > 0) {\n\t\t\t\t\titem.delayRemaining = Math.max(0, item.delayRemaining - elapsed)\n\t\t\t\t}\n\n\t\t\t\titem.timeoutMs += elapsed\n\t\t\t\tif (item.timeoutMs >= 16) {\n\t\t\t\t\titem.timeoutMs = 0\n\t\t\t\t}\n\n\t\t\t\tconst { delayRemaining, timeoutMs, prev, next, scribble } = item\n\n\t\t\t\tswitch (scribble.state) {\n\t\t\t\t\tcase 'active': {\n\t\t\t\t\t\tif (next && next !== prev) {\n\t\t\t\t\t\t\titem.prev = next\n\t\t\t\t\t\t\tscribble.points.push(next)\n\n\t\t\t\t\t\t\t// If we've run out of delay, then shrink the scribble from the start\n\t\t\t\t\t\t\tif (delayRemaining === 0) {\n\t\t\t\t\t\t\t\tif (scribble.points.length > 8) {\n\t\t\t\t\t\t\t\t\tscribble.points.shift()\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// While not moving, shrink the scribble from the start\n\t\t\t\t\t\t\tif (timeoutMs === 0) {\n\t\t\t\t\t\t\t\tif (scribble.points.length > 1) {\n\t\t\t\t\t\t\t\t\tscribble.points.shift()\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t// Reset the item's delay\n\t\t\t\t\t\t\t\t\titem.delayRemaining = scribble.delay\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\tcase 'stopping': {\n\t\t\t\t\t\tif (item.delayRemaining === 0) {\n\t\t\t\t\t\t\tif (timeoutMs === 0) {\n\t\t\t\t\t\t\t\t// If the scribble is down to one point, we're done!\n\t\t\t\t\t\t\t\tif (scribble.points.length === 1) {\n\t\t\t\t\t\t\t\t\tthis.scribbleItems.delete(item.id) // Remove the scribble\n\t\t\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tif (scribble.shrink) {\n\t\t\t\t\t\t\t\t\t// Drop the scribble's size as it shrinks\n\t\t\t\t\t\t\t\t\tscribble.size = Math.max(1, scribble.size * (1 - scribble.shrink))\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// Drop the scribble's first point (its tail)\n\t\t\t\t\t\t\t\tscribble.points.shift()\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t\tcase 'paused': {\n\t\t\t\t\t\t// Nothing to do while paused.\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t})\n\n\t\t\t// The object here will get frozen into the record, so we need to\n\t\t\t// create a copies of the parts that what we'll be mutating later.\n\t\t\tthis.editor.updateInstanceState({\n\t\t\t\tscribbles: Array.from(this.scribbleItems.values())\n\t\t\t\t\t.map(({ scribble }) => ({\n\t\t\t\t\t\t...scribble,\n\t\t\t\t\t\tpoints: [...scribble.points],\n\t\t\t\t\t}))\n\t\t\t\t\t.slice(-5), // limit to three as a minor sanity check\n\t\t\t})\n\t\t})\n\t}\n}\n"], "mappings": "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", "names": ["next", "prev"] }