@fieldnotes/core 0.61.0 → 0.62.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/core/snap.ts","../src/elements/note-sanitizer.ts","../src/core/state-serializer.ts","../src/core/storage/local-storage-adapter.ts","../src/core/auto-save.ts","../src/core/storage/memory-adapter.ts","../src/core/storage/indexeddb-adapter.ts","../src/canvas/camera.ts","../src/canvas/input-filter.ts","../src/elements/create-id.ts","../src/core/geometry.ts","../src/elements/arrow-geometry.ts","../src/elements/element-bounds.ts","../src/elements/bounds.ts","../src/canvas/keyboard-actions.ts","../src/canvas/shortcut-map.ts","../src/canvas/keyboard-handler.ts","../src/canvas/pan-inertia.ts","../src/canvas/input-handler.ts","../src/canvas/background.ts","../src/core/event-bus.ts","../src/core/quadtree.ts","../src/elements/stroke-smoothing.ts","../src/elements/stroke-cache.ts","../src/elements/element-store.ts","../src/elements/rotate-canvas.ts","../src/elements/renderers/stroke-renderer.ts","../src/elements/shape-geometry.ts","../src/elements/renderers/shape-renderer.ts","../src/elements/arrow-render-cache.ts","../src/elements/arrow-binding.ts","../src/elements/renderers/arrow-renderer.ts","../src/elements/renderers/image-renderer.ts","../src/elements/hex-fill.ts","../src/elements/renderers/template-measure.ts","../src/elements/renderers/template-renderer.ts","../src/elements/grid-renderer.ts","../src/elements/element-renderer.ts","../src/elements/element-factory.ts","../src/elements/note-formatting.ts","../src/elements/note-toolbar.ts","../src/elements/note-editor.ts","../src/canvas/context-menu.ts","../src/canvas/minimap-transform.ts","../src/canvas/minimap-controller.ts","../src/canvas/minimap.ts","../src/canvas/viewport-dom.ts","../src/canvas/hybrid-render-surface.ts","../src/elements/arrow-label-editor.ts","../src/tools/tool-manager.ts","../src/history/history-stack.ts","../src/history/commands.ts","../src/history/layer-commands.ts","../src/history/history-recorder.ts","../src/canvas/note-canvas-renderer.ts","../src/canvas/text-canvas-renderer.ts","../src/canvas/html-export.ts","../src/canvas/export-image.ts","../src/canvas/export-svg.ts","../src/layers/layer-manager.ts","../src/canvas/interact-mode.ts","../src/canvas/double-tap-detector.ts","../src/canvas/dom-node-manager.ts","../src/canvas/render-stats.ts","../src/canvas/render-loop.ts","../src/canvas/layer-cache.ts","../src/canvas/margin-viewport.ts","../src/elements/translate.ts","../src/elements/element-style.ts","../src/canvas/selection-rotate.ts","../src/canvas/selection-ops.ts","../src/canvas/grid-controller.ts","../src/canvas/viewport-interactions.ts","../src/canvas/viewport.ts","../src/canvas/remote-laser-overlay.ts","../src/canvas/ping-pulse.ts","../src/canvas/remote-ping-overlay.ts","../src/canvas/measure-render.ts","../src/canvas/remote-measure-overlay.ts","../src/canvas/ping-input.ts","../src/canvas/camera-view.ts","../src/canvas/camera-animator.ts","../src/canvas/focus-presence.ts","../src/canvas/remote-focus-receiver.ts","../src/tools/hand-tool.ts","../src/tools/pencil-tool.ts","../src/elements/stroke-hit.ts","../src/elements/stroke-erase.ts","../src/tools/eraser-tool.ts","../src/elements/group.ts","../src/tools/arrow-handles.ts","../src/elements/snap-guides.ts","../src/tools/select-overlay.ts","../src/tools/select-hit.ts","../src/tools/select-resize.ts","../src/tools/select-tool.ts","../src/tools/arrow-tool.ts","../src/tools/note-tool.ts","../src/tools/text-tool.ts","../src/tools/image-tool.ts","../src/tools/shape-tool.ts","../src/tools/measure-tool.ts","../src/tools/template-tool.ts","../src/tools/laser-tool.ts","../src/tools/ping-tool.ts"],"sourcesContent":["export const VERSION = '0.61.0';\n\nexport type { Point, StrokePoint, Size, Bounds } from './core/types';\nexport { snapPoint, smartSnap, snapToHexCenter } from './core/snap';\nexport type { CanvasState } from './core/state-serializer';\nexport { AutoSave } from './core/auto-save';\nexport type { AutoSaveOptions } from './core/auto-save';\nexport { MemoryAdapter } from './core/storage/memory-adapter';\nexport { LocalStorageAdapter } from './core/storage/local-storage-adapter';\nexport { IndexedDBAdapter } from './core/storage/indexeddb-adapter';\nexport type { StorageAdapter } from './core/storage/storage-adapter';\nexport type { IndexedDBAdapterOptions } from './core/storage/indexeddb-adapter';\n\nexport { Camera } from './canvas/camera';\nexport type { CameraOptions, CameraChangeInfo } from './canvas/camera';\nexport type { BackgroundOptions, BackgroundPattern } from './canvas/background';\nexport type { ShortcutOptions, ShortcutBindings, ShortcutsApi } from './canvas/shortcut-map';\nexport { Viewport } from './canvas/viewport';\nexport type {\n ViewportOptions,\n GridInfo,\n AlignEdge,\n DistributeAxis,\n RotateDirection,\n} from './canvas/viewport';\nexport { exportImage } from './canvas/export-image';\nexport type {\n ExportAssetError,\n ExportAssetErrorReason,\n ExportImageOptions,\n ExportResourceOptions,\n} from './canvas/export-image';\nexport { exportSvg } from './canvas/export-svg';\nexport type { ExportSvgOptions } from './canvas/export-svg';\nexport type {\n HtmlExportError,\n HtmlExportErrorReason,\n HtmlExportOptions,\n HtmlExportRenderer,\n} from './canvas/html-export';\nexport type { RenderStatsSnapshot } from './canvas/render-stats';\nexport type { OverlayRenderer } from './canvas/render-loop';\nexport {\n RemoteLaserOverlay,\n isLaserTrailPresence,\n toLaserTrailPresence,\n LASER_TRAIL_PRESENCE_KIND,\n} from './canvas/remote-laser-overlay';\nexport type {\n LaserTrailPresence,\n RemoteLaserOverlayHost,\n RemoteLaserOverlayOptions,\n} from './canvas/remote-laser-overlay';\nexport {\n RemotePingOverlay,\n isPingPresence,\n toPingPresence,\n PING_PRESENCE_KIND,\n} from './canvas/remote-ping-overlay';\nexport type {\n PingPresence,\n RemotePingOverlayHost,\n RemotePingOverlayOptions,\n} from './canvas/remote-ping-overlay';\nexport {\n RemoteMeasureOverlay,\n isMeasurePresence,\n toMeasurePresence,\n MEASURE_PRESENCE_KIND,\n} from './canvas/remote-measure-overlay';\nexport type {\n MeasurePresence,\n RemoteMeasureOverlayHost,\n RemoteMeasureOverlayOptions,\n} from './canvas/remote-measure-overlay';\nexport { PingInput } from './canvas/ping-input';\nexport type { PingInputHost, PingInputOptions } from './canvas/ping-input';\nexport { MinimapController } from './canvas/minimap-controller';\nexport type { MinimapControllerOptions } from './canvas/minimap-controller';\nexport {\n captureCameraView,\n fitZoomForView,\n cameraOriginForView,\n applyCameraView,\n} from './canvas/camera-view';\nexport type { CameraView } from './canvas/camera-view';\nexport { CameraAnimator } from './canvas/camera-animator';\nexport type {\n CameraAnimatorOptions,\n CameraAnimationEndReason,\n FrameScheduler,\n} from './canvas/camera-animator';\nexport { isFocusPresence, toFocusPresence, FOCUS_PRESENCE_KIND } from './canvas/focus-presence';\nexport type { FocusPresence, FocusAudience } from './canvas/focus-presence';\nexport { RemoteFocusReceiver } from './canvas/remote-focus-receiver';\nexport type {\n FocusRole,\n RemoteFocusReceiverHost,\n RemoteFocusReceiverOptions,\n} from './canvas/remote-focus-receiver';\n\nexport { ElementStore } from './elements/element-store';\nexport type { ElementUpdateEvent } from './elements/element-store';\nexport type { ElementChangeMeta } from './elements/element-store';\nexport type { FontSizePreset } from './elements/note-toolbar';\nexport {\n toggleBold,\n toggleItalic,\n toggleUnderline,\n toggleStrikethrough,\n setFontSize,\n getActiveFormats,\n} from './elements/note-formatting';\nexport type { ActiveFormats } from './elements/note-formatting';\nexport {\n createStroke,\n createNote,\n createArrow,\n createImage,\n createHtmlElement,\n createText,\n createShape,\n createGrid,\n createTemplate,\n DEFAULT_NOTE_FONT_SIZE,\n} from './elements/element-factory';\nexport {\n getArrowControlPoint,\n getArrowMidpoint,\n getBendFromPoint,\n getArrowTangentAngle,\n isNearBezier,\n getArrowBounds,\n} from './elements/arrow-geometry';\nexport { getElementBounds, boundsIntersect } from './elements/element-bounds';\nexport { styleToPatch, getElementStyle } from './elements/element-style';\nexport type { ElementStyle } from './elements/element-style';\nexport type { SelectionStyleDetails } from './canvas/selection-ops';\nexport { getElementsBoundingBox } from './elements/bounds';\nexport {\n getHexDistance,\n getHexCellsInRadius,\n getHexCellsInCone,\n getHexCellsInLine,\n getHexCellsInSquare,\n getHexCellsInRectangle,\n drawHexPath,\n} from './elements/hex-fill';\nexport type {\n Binding,\n CanvasElement,\n ElementType,\n StrokeElement,\n NoteElement,\n ArrowElement,\n ArrowStrokeStyle,\n ImageElement,\n HtmlElement,\n TextElement,\n ShapeElement,\n ShapeKind,\n GridElement,\n HexOrientation,\n TemplateElement,\n TemplateShape,\n TemplateRenderStyle,\n} from './elements/types';\n\nexport type { Command } from './history/types';\nexport { HistoryStack } from './history/history-stack';\nexport type { HistoryStackOptions } from './history/history-stack';\n\nexport { ToolManager } from './tools/tool-manager';\nexport { HandTool } from './tools/hand-tool';\nexport { PencilTool } from './tools/pencil-tool';\nexport type { PencilToolOptions } from './tools/pencil-tool';\nexport { EraserTool } from './tools/eraser-tool';\nexport type { EraserToolOptions } from './tools/eraser-tool';\nexport { SelectTool } from './tools/select-tool';\nexport { ArrowTool } from './tools/arrow-tool';\nexport type { ArrowToolOptions } from './tools/arrow-tool';\nexport { NoteTool } from './tools/note-tool';\nexport type { NoteToolOptions } from './tools/note-tool';\nexport { TextTool } from './tools/text-tool';\nexport type { TextToolOptions } from './tools/text-tool';\nexport { ImageTool } from './tools/image-tool';\nexport type { ImageToolOptions } from './tools/image-tool';\nexport { ShapeTool } from './tools/shape-tool';\nexport type { ShapeToolOptions } from './tools/shape-tool';\nexport { MeasureTool } from './tools/measure-tool';\nexport type { MeasureToolOptions, Measurement, MeasureEmission } from './tools/measure-tool';\nexport { TemplateTool } from './tools/template-tool';\nexport type { TemplateToolOptions } from './tools/template-tool';\nexport { LaserTool } from './tools/laser-tool';\nexport type { LaserToolOptions, LaserTrailEmission } from './tools/laser-tool';\nexport { PingTool } from './tools/ping-tool';\nexport type { PingToolOptions, PingEmission } from './tools/ping-tool';\nexport type { Tool, ToolContext, PointerState, ToolName } from './tools/types';\n\nexport { LayerManager } from './layers/layer-manager';\nexport type { Layer } from './layers/types';\n","import type { Point } from './types';\r\nimport type { HexOrientation } from '../elements/types';\r\nimport type { ToolContext } from '../tools/types';\r\n\r\nexport function snapPoint(point: Point, gridSize: number): Point {\r\n return {\r\n x: Math.round(point.x / gridSize) * gridSize || 0,\r\n y: Math.round(point.y / gridSize) * gridSize || 0,\r\n };\r\n}\r\n\r\nexport function snapToHexCenter(\r\n point: Point,\r\n cellSize: number,\r\n orientation: HexOrientation,\r\n): Point {\r\n if (orientation === 'pointy') {\r\n const hexW = Math.sqrt(3) * cellSize;\r\n const rowH = 1.5 * cellSize;\r\n const row = Math.round(point.y / rowH);\r\n const offsetX = row % 2 !== 0 ? hexW / 2 : 0;\r\n const col = Math.round((point.x - offsetX) / hexW);\r\n return { x: col * hexW + offsetX || 0, y: row * rowH || 0 };\r\n } else {\r\n const hexH = Math.sqrt(3) * cellSize;\r\n const colW = 1.5 * cellSize;\r\n const col = Math.round(point.x / colW);\r\n const offsetY = col % 2 !== 0 ? hexH / 2 : 0;\r\n const row = Math.round((point.y - offsetY) / hexH);\r\n return { x: col * colW || 0, y: row * hexH + offsetY || 0 };\r\n }\r\n}\r\n\r\nexport function smartSnap(point: Point, ctx: ToolContext): Point {\r\n if (!ctx.snapToGrid || !ctx.gridSize) return point;\r\n if (ctx.gridType === 'hex' && ctx.hexOrientation) {\r\n return snapToHexCenter(point, ctx.gridSize, ctx.hexOrientation);\r\n }\r\n return snapPoint(point, ctx.gridSize);\r\n}\r\n","interface RunStyle {\r\n bold: boolean;\r\n italic: boolean;\r\n underline: boolean;\r\n strikethrough: boolean;\r\n fontSize: number;\r\n}\r\n\r\nexport interface StyledRun extends RunStyle {\r\n text: string;\r\n}\r\n\r\nconst BOLD_TAGS = new Set(['b', 'strong']);\r\nconst ITALIC_TAGS = new Set(['i', 'em']);\r\nconst UNDERLINE_TAGS = new Set(['u']);\r\nconst STRIKE_TAGS = new Set(['s', 'strike', 'del']);\r\nconst BLOCK_TAGS = new Set(['div']);\r\n\r\nexport function parseStyledRuns(html: string, baseFontSize: number): StyledRun[] {\r\n if (!html) return [];\r\n\r\n const doc = new DOMParser().parseFromString(html, 'text/html');\r\n const runs: StyledRun[] = [];\r\n const baseStyle: RunStyle = {\r\n bold: false,\r\n italic: false,\r\n underline: false,\r\n strikethrough: false,\r\n fontSize: baseFontSize,\r\n };\r\n\r\n walkNodes(doc.body, baseStyle, runs);\r\n return runs;\r\n}\r\n\r\nfunction walkNodes(node: Node, style: RunStyle, runs: StyledRun[]): void {\r\n for (const child of Array.from(node.childNodes)) {\r\n if (child.nodeType === Node.TEXT_NODE) {\r\n const text = child.textContent ?? '';\r\n if (text) {\r\n runs.push({ text, ...style });\r\n }\r\n continue;\r\n }\r\n\r\n if (child.nodeType !== Node.ELEMENT_NODE) continue;\r\n\r\n const el = child as Element;\r\n const tag = el.tagName.toLowerCase();\r\n\r\n if (tag === 'br') {\r\n runs.push({ text: '\\n', ...style });\r\n continue;\r\n }\r\n\r\n if (BLOCK_TAGS.has(tag) && runs.length > 0) {\r\n const lastRun = runs[runs.length - 1];\r\n if (lastRun && !lastRun.text.endsWith('\\n')) {\r\n runs.push({ text: '\\n', ...style });\r\n }\r\n }\r\n\r\n const childStyle = { ...style };\r\n if (BOLD_TAGS.has(tag)) childStyle.bold = true;\r\n if (ITALIC_TAGS.has(tag)) childStyle.italic = true;\r\n if (UNDERLINE_TAGS.has(tag)) childStyle.underline = true;\r\n if (STRIKE_TAGS.has(tag)) childStyle.strikethrough = true;\r\n\r\n if (tag === 'span') {\r\n const fontSize = (el as HTMLElement).style.fontSize;\r\n if (fontSize) {\r\n childStyle.fontSize = parseInt(fontSize, 10) || style.fontSize;\r\n }\r\n }\r\n\r\n walkNodes(el, childStyle, runs);\r\n }\r\n}\r\n\r\nconst ALLOWED_TAGS = new Set([\r\n 'b',\r\n 'strong',\r\n 'i',\r\n 'em',\r\n 'u',\r\n 's',\r\n 'strike',\r\n 'del',\r\n 'span',\r\n 'br',\r\n 'div',\r\n]);\r\n\r\nexport function sanitizeNoteHtml(html: string): string {\r\n if (!html) return '';\r\n\r\n const doc = new DOMParser().parseFromString(html, 'text/html');\r\n sanitizeNode(doc.body);\r\n return doc.body.innerHTML;\r\n}\r\n\r\nfunction sanitizeNode(node: Node): void {\r\n const children = Array.from(node.childNodes);\r\n\r\n for (const child of children) {\r\n if (child.nodeType === Node.TEXT_NODE) continue;\r\n\r\n if (child.nodeType !== Node.ELEMENT_NODE) {\r\n child.remove();\r\n continue;\r\n }\r\n\r\n const el = child as Element;\r\n const tag = el.tagName.toLowerCase();\r\n\r\n if (!ALLOWED_TAGS.has(tag)) {\r\n const fragment = document.createDocumentFragment();\r\n while (el.firstChild) {\r\n fragment.appendChild(el.firstChild);\r\n }\r\n node.replaceChild(fragment, el);\r\n sanitizeNode(node);\r\n return;\r\n }\r\n\r\n sanitizeAttributes(el, tag);\r\n sanitizeNode(el);\r\n }\r\n}\r\n\r\nexport function isNoteContentEmpty(html: string): boolean {\r\n if (!html) return true;\r\n const doc = new DOMParser().parseFromString(html, 'text/html');\r\n const text = doc.body.textContent ?? '';\r\n return text.replace(/\\u00a0/g, ' ').trim().length === 0;\r\n}\r\n\r\nfunction sanitizeAttributes(el: Element, tag: string): void {\r\n const attrs = Array.from(el.attributes);\r\n for (const attr of attrs) {\r\n if (tag === 'span' && attr.name === 'style') {\r\n const fontSize = (el as HTMLElement).style.fontSize;\r\n if (fontSize) {\r\n el.setAttribute('style', `font-size: ${fontSize};`);\r\n } else {\r\n el.removeAttribute('style');\r\n }\r\n continue;\r\n }\r\n el.removeAttribute(attr.name);\r\n }\r\n}\r\n","import type { CanvasElement } from '../elements/types';\r\nimport type { Point } from './types';\r\nimport type { Layer } from '../layers/types';\r\nimport { sanitizeNoteHtml } from '../elements/note-sanitizer';\r\n\r\nexport interface CanvasState {\r\n version: number;\r\n camera: {\r\n position: Point;\r\n zoom: number;\r\n };\r\n elements: CanvasElement[];\r\n layers?: Layer[];\r\n activeLayerId?: string;\r\n}\r\n\r\nconst CURRENT_VERSION = 2;\r\nconst ELEMENT_TYPES = [\r\n 'stroke',\r\n 'note',\r\n 'arrow',\r\n 'image',\r\n 'html',\r\n 'text',\r\n 'shape',\r\n 'grid',\r\n 'template',\r\n] as const satisfies readonly CanvasElement['type'][];\r\ntype _ElementTypesAreExhaustive = CanvasElement['type'] extends (typeof ELEMENT_TYPES)[number]\r\n ? true\r\n : never;\r\nconst _elementTypesAreExhaustive: _ElementTypesAreExhaustive = true;\r\nvoid _elementTypesAreExhaustive;\r\n\r\nexport function exportState(\r\n elements: CanvasElement[],\r\n camera: { position: Point; zoom: number },\r\n layers: Layer[] = [],\r\n activeLayerId?: string,\r\n): CanvasState {\r\n const state: CanvasState = {\r\n version: CURRENT_VERSION,\r\n camera: {\r\n position: { ...camera.position },\r\n zoom: camera.zoom,\r\n },\r\n elements: elements.map((el) => {\r\n const clone = structuredClone(el);\r\n if (clone.type === 'arrow') {\r\n delete clone.cachedControlPoint;\r\n }\r\n return clone;\r\n }),\r\n layers: layers.map((l) => ({ ...l })),\r\n };\r\n if (activeLayerId) state.activeLayerId = activeLayerId;\r\n return state;\r\n}\r\n\r\nexport function parseState(json: string): CanvasState {\r\n const data: unknown = JSON.parse(json);\r\n validateState(data);\r\n return data;\r\n}\r\n\r\nfunction validateState(data: unknown): asserts data is CanvasState {\r\n if (!isRecord(data)) {\r\n throw new Error('Invalid state: expected an object');\r\n }\r\n\r\n const obj = data;\r\n\r\n if (!Number.isInteger(obj['version']) || (obj['version'] as number) < 1) {\r\n throw new Error('Invalid state: missing or invalid version');\r\n }\r\n if ((obj['version'] as number) > CURRENT_VERSION) {\r\n throw new Error(`Invalid state: unsupported version ${String(obj['version'])}`);\r\n }\r\n\r\n if (!isRecord(obj['camera'])) {\r\n throw new Error('Invalid state: missing camera');\r\n }\r\n\r\n const cam = obj['camera'];\r\n if (!isRecord(cam['position'])) {\r\n throw new Error('Invalid state: missing camera.position');\r\n }\r\n\r\n if (!isPoint(cam['position'])) {\r\n throw new Error('Invalid state: camera.position must have finite x and y numbers');\r\n }\r\n\r\n if (!isFiniteNumber(cam['zoom']) || cam['zoom'] <= 0) {\r\n throw new Error('Invalid state: camera.zoom must be a positive finite number');\r\n }\r\n\r\n if (!Array.isArray(obj['elements'])) {\r\n throw new Error('Invalid state: elements must be an array');\r\n }\r\n if (obj['layers'] !== undefined && !Array.isArray(obj['layers'])) {\r\n throw new Error('Invalid state: layers must be an array');\r\n }\r\n\r\n const elements = obj['elements'] as unknown[];\r\n const hasLayers = Array.isArray(obj['layers']) && obj['layers'].length > 0;\r\n for (const el of elements) {\r\n if (!isRecord(el)) throw new Error('Invalid element: expected an object');\r\n migrateElement(el, !hasLayers);\r\n }\r\n\r\n if (!hasLayers) {\r\n obj['layers'] = [\r\n {\r\n id: 'default-layer',\r\n name: 'Layer 1',\r\n visible: true,\r\n locked: false,\r\n order: 0,\r\n opacity: 1.0,\r\n },\r\n ];\r\n }\r\n\r\n const layers = obj['layers'] as unknown[];\r\n const layerIds = new Set<string>();\r\n for (const layer of layers) {\r\n validateLayer(layer);\r\n if (layerIds.has(layer.id)) throw new Error(`Invalid state: duplicate layer id \"${layer.id}\"`);\r\n layerIds.add(layer.id);\r\n }\r\n\r\n const elementIds = new Set<string>();\r\n for (const el of elements) {\r\n validateElement(el);\r\n if (elementIds.has(el.id)) throw new Error(`Invalid state: duplicate element id \"${el.id}\"`);\r\n elementIds.add(el.id);\r\n if (!layerIds.has(el.layerId)) {\r\n throw new Error(`Invalid element \"${el.id}\": unknown layerId \"${el.layerId}\"`);\r\n }\r\n }\r\n\r\n if (obj['activeLayerId'] !== undefined) {\r\n if (typeof obj['activeLayerId'] !== 'string' || !layerIds.has(obj['activeLayerId'])) {\r\n throw new Error('Invalid state: activeLayerId must reference an existing layer');\r\n }\r\n }\r\n\r\n cleanBindings(elements as Record<string, unknown>[]);\r\n}\r\n\r\nfunction validateElement(el: unknown): asserts el is CanvasElement {\r\n if (!isRecord(el)) {\r\n throw new Error('Invalid element: expected an object');\r\n }\r\n\r\n if (typeof el['id'] !== 'string' || el['id'].length === 0) {\r\n throw new Error('Invalid element: missing id');\r\n }\r\n if (!isEnum(el['type'], ELEMENT_TYPES)) {\r\n throw new Error(`Invalid element: unknown type \"${String(el['type'])}\"`);\r\n }\r\n if (!isFiniteNumber(el['zIndex'])) {\r\n throw new Error(`Invalid element \"${el['id']}\": missing or invalid zIndex`);\r\n }\r\n if (\r\n !isPoint(el['position']) ||\r\n typeof el['locked'] !== 'boolean' ||\r\n typeof el['layerId'] !== 'string' ||\r\n !isOptional(el['groupId'], isString) ||\r\n !isOptional(el['rotation'], isFiniteNumber)\r\n ) {\r\n throw new Error(`Invalid element \"${el['id']}\": invalid base fields or geometry`);\r\n }\r\n\r\n const valid = validateTypeFields(el, el['type']);\r\n if (!valid) throw new Error(`Invalid element \"${el['id']}\": malformed ${el['type']} data`);\r\n}\r\n\r\nfunction validateTypeFields(el: Record<string, unknown>, type: CanvasElement['type']): boolean {\r\n switch (type) {\r\n case 'stroke':\r\n return (\r\n Array.isArray(el['points']) &&\r\n el['points'].every(isStrokePoint) &&\r\n isString(el['color']) &&\r\n isFiniteNumber(el['width']) &&\r\n isFiniteNumber(el['opacity']) &&\r\n isOptionalEnum(el['blendMode'], ['multiply'])\r\n );\r\n case 'note':\r\n return (\r\n isSize(el['size']) &&\r\n isString(el['text']) &&\r\n isString(el['backgroundColor']) &&\r\n isString(el['textColor']) &&\r\n isOptional(el['fontSize'], isFiniteNumber)\r\n );\r\n case 'arrow':\r\n return (\r\n isPoint(el['from']) &&\r\n isPoint(el['to']) &&\r\n isFiniteNumber(el['bend']) &&\r\n isString(el['color']) &&\r\n isFiniteNumber(el['width']) &&\r\n isOptional(el['fromBinding'], isBinding) &&\r\n isOptional(el['toBinding'], isBinding) &&\r\n isOptional(el['cachedControlPoint'], isPoint) &&\r\n isOptional(el['label'], isString) &&\r\n isOptionalEnum(el['strokeStyle'], ['solid', 'dashed', 'dotted'])\r\n );\r\n case 'image':\r\n return isSize(el['size']) && isString(el['src']);\r\n case 'html':\r\n return (\r\n isSize(el['size']) &&\r\n isOptional(el['domId'], isString) &&\r\n isOptional(el['interactive'], isBoolean) &&\r\n isOptional(el['htmlType'], isString) &&\r\n isOptional(el['data'], isRecord)\r\n );\r\n case 'text':\r\n return (\r\n isSize(el['size']) &&\r\n isString(el['text']) &&\r\n isFiniteNumber(el['fontSize']) &&\r\n isString(el['color']) &&\r\n isEnum(el['textAlign'], ['left', 'center', 'right'])\r\n );\r\n case 'shape':\r\n return (\r\n isEnum(el['shape'], ['rectangle', 'ellipse', 'line']) &&\r\n isSize(el['size']) &&\r\n isString(el['strokeColor']) &&\r\n isFiniteNumber(el['strokeWidth']) &&\r\n isString(el['fillColor']) &&\r\n isOptional(el['flip'], isBoolean)\r\n );\r\n case 'grid':\r\n return (\r\n isEnum(el['gridType'], ['square', 'hex']) &&\r\n isEnum(el['hexOrientation'], ['pointy', 'flat']) &&\r\n isFiniteNumber(el['cellSize']) &&\r\n isString(el['strokeColor']) &&\r\n isFiniteNumber(el['strokeWidth']) &&\r\n isFiniteNumber(el['opacity'])\r\n );\r\n case 'template':\r\n return (\r\n isEnum(el['templateShape'], ['circle', 'cone', 'line', 'square', 'rectangle']) &&\r\n isFiniteNumber(el['radius']) &&\r\n isFiniteNumber(el['angle']) &&\r\n isOptional(el['width'], isFiniteNumber) &&\r\n isString(el['fillColor']) &&\r\n isString(el['strokeColor']) &&\r\n isFiniteNumber(el['strokeWidth']) &&\r\n isFiniteNumber(el['opacity']) &&\r\n isOptional(el['feetPerCell'], isFiniteNumber) &&\r\n isOptional(el['radiusFeet'], isFiniteNumber) &&\r\n isOptionalEnum(el['renderStyle'], ['cells', 'geometric'])\r\n );\r\n }\r\n}\r\n\r\nfunction validateLayer(layer: unknown): asserts layer is Layer {\r\n if (\r\n !isRecord(layer) ||\r\n typeof layer['id'] !== 'string' ||\r\n layer['id'].length === 0 ||\r\n typeof layer['name'] !== 'string' ||\r\n typeof layer['visible'] !== 'boolean' ||\r\n typeof layer['locked'] !== 'boolean' ||\r\n !isFiniteNumber(layer['order']) ||\r\n !isFiniteNumber(layer['opacity']) ||\r\n layer['opacity'] < 0 ||\r\n layer['opacity'] > 1\r\n ) {\r\n throw new Error('Invalid state: malformed layer');\r\n }\r\n}\r\n\r\nfunction cleanBindings(elements: Record<string, unknown>[]): void {\r\n const ids = new Set(elements.map((el) => el['id'] as string));\r\n\r\n for (const el of elements) {\r\n if (el['type'] !== 'arrow') continue;\r\n\r\n const fromBinding = el['fromBinding'] as Record<string, unknown> | undefined;\r\n if (fromBinding && !ids.has(fromBinding['elementId'] as string)) {\r\n el['fromBinding'] = undefined;\r\n }\r\n\r\n const toBinding = el['toBinding'] as Record<string, unknown> | undefined;\r\n if (toBinding && !ids.has(toBinding['elementId'] as string)) {\r\n el['toBinding'] = undefined;\r\n }\r\n }\r\n}\r\n\r\nfunction migrateElement(obj: Record<string, unknown>, useDefaultLayer: boolean): void {\r\n if (obj['layerId'] === undefined || (useDefaultLayer && obj['layerId'] === '')) {\r\n obj['layerId'] = 'default-layer';\r\n }\r\n\r\n if (obj['type'] === 'arrow' && obj['bend'] === undefined) {\r\n obj['bend'] = 0;\r\n }\r\n\r\n if (obj['type'] === 'stroke' && Array.isArray(obj['points'])) {\r\n for (const pt of obj['points'] as Record<string, unknown>[]) {\r\n if (pt['pressure'] === undefined) {\r\n pt['pressure'] = 0.5;\r\n }\r\n }\r\n }\r\n\r\n if (obj['type'] === 'shape' && obj['shape'] === undefined) {\r\n obj['shape'] = 'rectangle';\r\n }\r\n\r\n if (obj['type'] === 'note' && obj['textColor'] === undefined) {\r\n obj['textColor'] = '#000000';\r\n }\r\n\r\n if ((obj['type'] === 'note' || obj['type'] === 'text') && typeof obj['text'] === 'string') {\r\n obj['text'] = sanitizeNoteHtml(obj['text']);\r\n }\r\n}\r\n\r\ntype Validator = (value: unknown) => boolean;\r\n\r\nfunction isRecord(value: unknown): value is Record<string, unknown> {\r\n return typeof value === 'object' && value !== null && !Array.isArray(value);\r\n}\r\n\r\nfunction isFiniteNumber(value: unknown): value is number {\r\n return typeof value === 'number' && Number.isFinite(value);\r\n}\r\n\r\nfunction isString(value: unknown): value is string {\r\n return typeof value === 'string';\r\n}\r\n\r\nfunction isBoolean(value: unknown): value is boolean {\r\n return typeof value === 'boolean';\r\n}\r\n\r\nfunction isOptional(value: unknown, validate: Validator): boolean {\r\n return value === undefined || validate(value);\r\n}\r\n\r\nfunction isEnum<const T extends readonly string[]>(value: unknown, values: T): value is T[number] {\r\n return typeof value === 'string' && (values as readonly string[]).includes(value);\r\n}\r\n\r\nfunction isOptionalEnum<const T extends readonly string[]>(value: unknown, values: T): boolean {\r\n return value === undefined || isEnum(value, values);\r\n}\r\n\r\nfunction isPoint(value: unknown): boolean {\r\n return isRecord(value) && isFiniteNumber(value['x']) && isFiniteNumber(value['y']);\r\n}\r\n\r\nfunction isSize(value: unknown): boolean {\r\n return isRecord(value) && isFiniteNumber(value['w']) && isFiniteNumber(value['h']);\r\n}\r\n\r\nfunction isStrokePoint(value: unknown): boolean {\r\n return isRecord(value) && isPoint(value) && isFiniteNumber(value['pressure']);\r\n}\r\n\r\nfunction isBinding(value: unknown): boolean {\r\n return isRecord(value) && typeof value['elementId'] === 'string';\r\n}\r\n","import type { StorageAdapter } from './storage-adapter';\r\n\r\nexport class LocalStorageAdapter implements StorageAdapter {\r\n async load(key: string): Promise<string | null> {\r\n if (typeof localStorage === 'undefined') return null;\r\n return localStorage.getItem(key);\r\n }\r\n async save(key: string, value: string): Promise<void> {\r\n if (typeof localStorage === 'undefined') return;\r\n localStorage.setItem(key, value);\r\n }\r\n async clear(key: string): Promise<void> {\r\n if (typeof localStorage === 'undefined') return;\r\n localStorage.removeItem(key);\r\n }\r\n}\r\n","import type { ElementStore } from '../elements/element-store';\r\nimport type { Camera } from '../canvas/camera';\r\nimport type { LayerManager } from '../layers/layer-manager';\r\nimport { exportState, parseState } from './state-serializer';\r\nimport type { CanvasState } from './state-serializer';\r\nimport { LocalStorageAdapter } from './storage/local-storage-adapter';\r\nimport type { StorageAdapter } from './storage/storage-adapter';\r\n\r\nexport interface AutoSaveOptions {\r\n key?: string;\r\n debounceMs?: number;\r\n layerManager?: LayerManager;\r\n adapter?: StorageAdapter;\r\n onError?: (error: Error) => void;\r\n}\r\n\r\nconst DEFAULT_KEY = 'fieldnotes-autosave';\r\nconst DEFAULT_DEBOUNCE_MS = 1000;\r\n\r\nexport class AutoSave {\r\n private readonly key: string;\r\n private readonly debounceMs: number;\r\n private readonly layerManager?: LayerManager;\r\n private readonly adapter: StorageAdapter;\r\n private timerId: ReturnType<typeof setTimeout> | null = null;\r\n private unsubscribers: (() => void)[] = [];\r\n private readonly onError?: (error: Error) => void;\r\n private saving = false;\r\n private pendingSave = false;\r\n\r\n constructor(\r\n private readonly store: ElementStore,\r\n private readonly camera: Camera,\r\n options: AutoSaveOptions = {},\r\n ) {\r\n this.key = options.key ?? DEFAULT_KEY;\r\n this.debounceMs = options.debounceMs ?? DEFAULT_DEBOUNCE_MS;\r\n this.layerManager = options.layerManager;\r\n this.adapter = options.adapter ?? new LocalStorageAdapter();\r\n this.onError = options.onError;\r\n }\r\n\r\n start(): void {\r\n const schedule = () => this.scheduleSave();\r\n\r\n this.unsubscribers = [\r\n this.store.on('add', schedule),\r\n this.store.on('remove', schedule),\r\n this.store.on('update', schedule),\r\n this.camera.onChange(schedule),\r\n ];\r\n if (this.layerManager) {\r\n this.unsubscribers.push(this.layerManager.on('change', schedule));\r\n }\r\n }\r\n\r\n stop(): void {\r\n this.cancelPending();\r\n this.unsubscribers.forEach((fn) => fn());\r\n this.unsubscribers = [];\r\n }\r\n\r\n async load(): Promise<CanvasState | null> {\r\n const json = await this.adapter.load(this.key);\r\n if (!json) return null;\r\n\r\n try {\r\n return parseState(json);\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n async clear(): Promise<void> {\r\n await this.adapter.clear(this.key);\r\n }\r\n\r\n private scheduleSave(): void {\r\n this.cancelPending();\r\n this.timerId = setTimeout(() => void this.save(), this.debounceMs);\r\n }\r\n\r\n private cancelPending(): void {\r\n if (this.timerId !== null) {\r\n clearTimeout(this.timerId);\r\n this.timerId = null;\r\n }\r\n }\r\n\r\n private async save(): Promise<void> {\r\n if (this.saving) {\r\n this.pendingSave = true;\r\n return;\r\n }\r\n this.saving = true;\r\n try {\r\n const layers = this.layerManager?.snapshot() ?? [];\r\n const state = exportState(this.store.snapshot(), this.camera, layers);\r\n await this.adapter.save(this.key, JSON.stringify(state));\r\n } catch (e) {\r\n this.onError?.(e instanceof Error ? e : new Error(String(e)));\r\n } finally {\r\n this.saving = false;\r\n if (this.pendingSave) {\r\n this.pendingSave = false;\r\n void this.save();\r\n }\r\n }\r\n }\r\n}\r\n","import type { StorageAdapter } from './storage-adapter';\r\n\r\nexport class MemoryAdapter implements StorageAdapter {\r\n private store = new Map<string, string>();\r\n async load(key: string): Promise<string | null> {\r\n return this.store.get(key) ?? null;\r\n }\r\n async save(key: string, value: string): Promise<void> {\r\n this.store.set(key, value);\r\n }\r\n async clear(key: string): Promise<void> {\r\n this.store.delete(key);\r\n }\r\n}\r\n","import type { StorageAdapter } from './storage-adapter';\r\n\r\nexport interface IndexedDBAdapterOptions {\r\n dbName?: string;\r\n storeName?: string;\r\n indexedDB?: IDBFactory;\r\n}\r\n\r\nconst DEFAULT_DB = 'fieldnotes';\r\nconst DEFAULT_STORE = 'state';\r\n\r\nexport class IndexedDBAdapter implements StorageAdapter {\r\n private readonly dbName: string;\r\n private readonly storeName: string;\r\n private readonly idb: IDBFactory | null;\r\n private dbPromise: Promise<IDBDatabase> | null = null;\r\n\r\n constructor(options: IndexedDBAdapterOptions = {}) {\r\n this.dbName = options.dbName ?? DEFAULT_DB;\r\n this.storeName = options.storeName ?? DEFAULT_STORE;\r\n this.idb = options.indexedDB ?? (typeof indexedDB !== 'undefined' ? indexedDB : null);\r\n }\r\n\r\n private open(): Promise<IDBDatabase> {\r\n const idb = this.idb;\r\n if (!idb) return Promise.reject(new Error('IndexedDB unavailable'));\r\n if (!this.dbPromise) {\r\n const storeName = this.storeName;\r\n this.dbPromise = new Promise((resolve, reject) => {\r\n const req = idb.open(this.dbName, 1);\r\n req.onupgradeneeded = () => {\r\n const db = req.result;\r\n if (!db.objectStoreNames.contains(storeName)) db.createObjectStore(storeName);\r\n };\r\n req.onsuccess = () => resolve(req.result);\r\n req.onerror = () => reject(req.error ?? new Error('IndexedDB open failed'));\r\n });\r\n }\r\n return this.dbPromise;\r\n }\r\n\r\n async load(key: string): Promise<string | null> {\r\n if (!this.idb) return null;\r\n const db = await this.open();\r\n return new Promise((resolve, reject) => {\r\n const req = db.transaction(this.storeName, 'readonly').objectStore(this.storeName).get(key);\r\n req.onsuccess = () => {\r\n const v = req.result;\r\n resolve(typeof v === 'string' ? v : null);\r\n };\r\n req.onerror = () => reject(req.error ?? new Error('IndexedDB read failed'));\r\n });\r\n }\r\n\r\n async save(key: string, value: string): Promise<void> {\r\n if (!this.idb) return;\r\n const db = await this.open();\r\n return new Promise((resolve, reject) => {\r\n const tx = db.transaction(this.storeName, 'readwrite');\r\n tx.objectStore(this.storeName).put(value, key);\r\n tx.oncomplete = () => resolve();\r\n tx.onerror = () => reject(tx.error ?? new Error('IndexedDB write failed'));\r\n tx.onabort = () => reject(tx.error ?? new Error('IndexedDB write aborted'));\r\n });\r\n }\r\n\r\n async clear(key: string): Promise<void> {\r\n if (!this.idb) return;\r\n const db = await this.open();\r\n return new Promise((resolve, reject) => {\r\n const tx = db.transaction(this.storeName, 'readwrite');\r\n tx.objectStore(this.storeName).delete(key);\r\n tx.oncomplete = () => resolve();\r\n tx.onerror = () => reject(tx.error ?? new Error('IndexedDB delete failed'));\r\n tx.onabort = () => reject(tx.error ?? new Error('IndexedDB delete aborted'));\r\n });\r\n }\r\n}\r\n","import type { Bounds, Point } from '../core/types';\r\n\r\nexport interface CameraOptions {\r\n minZoom?: number;\r\n maxZoom?: number;\r\n}\r\n\r\nexport interface CameraChangeInfo {\r\n panned: boolean;\r\n zoomed: boolean;\r\n}\r\n\r\nconst DEFAULT_MIN_ZOOM = 0.1;\r\nconst DEFAULT_MAX_ZOOM = 10;\r\n\r\nexport class Camera {\r\n private x = 0;\r\n private y = 0;\r\n private z = 1;\r\n private readonly minZoom: number;\r\n private readonly maxZoom: number;\r\n private changeListeners = new Set<(info: CameraChangeInfo) => void>();\r\n\r\n constructor(options: CameraOptions = {}) {\r\n this.minZoom = options.minZoom ?? DEFAULT_MIN_ZOOM;\r\n this.maxZoom = options.maxZoom ?? DEFAULT_MAX_ZOOM;\r\n }\r\n\r\n get position(): Point {\r\n return { x: this.x, y: this.y };\r\n }\r\n\r\n get zoom(): number {\r\n return this.z;\r\n }\r\n\r\n pan(dx: number, dy: number): void {\r\n this.x += dx;\r\n this.y += dy;\r\n this.notifyPan();\r\n }\r\n\r\n moveTo(x: number, y: number): void {\r\n this.x = x;\r\n this.y = y;\r\n this.notifyPan();\r\n }\r\n\r\n setZoom(level: number): void {\r\n this.z = Math.min(this.maxZoom, Math.max(this.minZoom, level));\r\n this.notifyZoom();\r\n }\r\n\r\n zoomAt(level: number, screenPoint: Point): void {\r\n const before = this.screenToWorld(screenPoint);\r\n this.z = Math.min(this.maxZoom, Math.max(this.minZoom, level));\r\n const after = this.screenToWorld(screenPoint);\r\n this.x += (after.x - before.x) * this.z;\r\n this.y += (after.y - before.y) * this.z;\r\n this.notifyPanAndZoom();\r\n }\r\n\r\n screenToWorld(screen: Point): Point {\r\n return {\r\n x: (screen.x - this.x) / this.z,\r\n y: (screen.y - this.y) / this.z,\r\n };\r\n }\r\n\r\n worldToScreen(world: Point): Point {\r\n return {\r\n x: world.x * this.z + this.x,\r\n y: world.y * this.z + this.y,\r\n };\r\n }\r\n\r\n getVisibleRect(canvasWidth: number, canvasHeight: number): Bounds {\r\n const topLeft = this.screenToWorld({ x: 0, y: 0 });\r\n const bottomRight = this.screenToWorld({ x: canvasWidth, y: canvasHeight });\r\n return {\r\n x: topLeft.x,\r\n y: topLeft.y,\r\n w: bottomRight.x - topLeft.x,\r\n h: bottomRight.y - topLeft.y,\r\n };\r\n }\r\n\r\n fitToContent(boundingBox: Bounds, canvasWidth: number, canvasHeight: number, padding = 40): void {\r\n if (boundingBox.w === 0 && boundingBox.h === 0) return;\r\n\r\n const scaleX = canvasWidth / (boundingBox.w + 2 * padding);\r\n const scaleY = canvasHeight / (boundingBox.h + 2 * padding);\r\n this.z = Math.min(this.maxZoom, Math.max(this.minZoom, Math.min(scaleX, scaleY)));\r\n this.x = (canvasWidth - boundingBox.w * this.z) / 2 - boundingBox.x * this.z;\r\n this.y = (canvasHeight - boundingBox.h * this.z) / 2 - boundingBox.y * this.z;\r\n this.notifyPanAndZoom();\r\n }\r\n\r\n toCSSTransform(): string {\r\n return `translate3d(${this.x}px, ${this.y}px, 0) scale(${this.z})`;\r\n }\r\n\r\n onChange(listener: (info: CameraChangeInfo) => void): () => void {\r\n this.changeListeners.add(listener);\r\n return () => this.changeListeners.delete(listener);\r\n }\r\n\r\n private notifyPan(): void {\r\n this.changeListeners.forEach((fn) => fn({ panned: true, zoomed: false }));\r\n }\r\n\r\n private notifyZoom(): void {\r\n this.changeListeners.forEach((fn) => fn({ panned: false, zoomed: true }));\r\n }\r\n\r\n private notifyPanAndZoom(): void {\r\n this.changeListeners.forEach((fn) => fn({ panned: true, zoomed: true }));\r\n }\r\n}\r\n","export type FilterAction = 'dispatch' | 'suppress' | 'defer';\r\n\r\nexport interface FilteredEvent {\r\n event: PointerEvent;\r\n action: FilterAction;\r\n}\r\n\r\nexport interface FilteredUpEvent extends FilteredEvent {\r\n pendingTap?: { x: number; y: number };\r\n}\r\n\r\nexport class InputFilter {\r\n private activePenId: number | null = null;\r\n private pendingTap: { pointerId: number; x: number; y: number } | null = null;\r\n\r\n static readonly MIN_MOVE_DISTANCE = 3;\r\n\r\n filterDown(e: PointerEvent): FilteredEvent {\r\n if (e.pointerType === 'pen') {\r\n this.activePenId = e.pointerId;\r\n return { event: e, action: 'dispatch' };\r\n }\r\n\r\n if (e.pointerType === 'touch' && this.activePenId !== null) {\r\n return { event: e, action: 'suppress' };\r\n }\r\n\r\n if (e.pointerType === 'touch') {\r\n this.pendingTap = { pointerId: e.pointerId, x: e.clientX, y: e.clientY };\r\n return { event: e, action: 'defer' };\r\n }\r\n\r\n return { event: e, action: 'dispatch' };\r\n }\r\n\r\n filterMove(e: PointerEvent): FilteredEvent {\r\n if (e.pointerType === 'touch' && this.activePenId !== null) {\r\n return { event: e, action: 'suppress' };\r\n }\r\n\r\n if (this.pendingTap && e.pointerId === this.pendingTap.pointerId) {\r\n const dx = e.clientX - this.pendingTap.x;\r\n const dy = e.clientY - this.pendingTap.y;\r\n if (dx * dx + dy * dy > InputFilter.MIN_MOVE_DISTANCE * InputFilter.MIN_MOVE_DISTANCE) {\r\n this.pendingTap = null;\r\n return { event: e, action: 'dispatch' };\r\n }\r\n return { event: e, action: 'suppress' };\r\n }\r\n\r\n return { event: e, action: 'dispatch' };\r\n }\r\n\r\n filterUp(e: PointerEvent): FilteredUpEvent {\r\n if (e.pointerId === this.activePenId) {\r\n this.activePenId = null;\r\n return { event: e, action: 'dispatch' };\r\n }\r\n\r\n if (e.pointerType === 'touch' && this.activePenId !== null) {\r\n return { event: e, action: 'suppress' };\r\n }\r\n\r\n if (this.pendingTap && e.pointerId === this.pendingTap.pointerId) {\r\n const tap = { x: this.pendingTap.x, y: this.pendingTap.y };\r\n this.pendingTap = null;\r\n return { event: e, action: 'dispatch', pendingTap: tap };\r\n }\r\n\r\n return { event: e, action: 'dispatch' };\r\n }\r\n\r\n reset(): void {\r\n this.activePenId = null;\r\n this.pendingTap = null;\r\n }\r\n}\r\n","let counter = 0;\r\n\r\nexport function randomClientComponent(): string {\r\n // getRandomValues works in NON-secure contexts (an iPad on http://LAN) — unlike crypto.randomUUID, which\r\n // is secure-context-gated in browsers. Uniqueness, not security.\r\n if (typeof crypto !== 'undefined' && typeof crypto.getRandomValues === 'function') {\r\n const bytes = new Uint8Array(8);\r\n crypto.getRandomValues(bytes);\r\n return Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join(''); // 16 hex = 64 bits\r\n }\r\n return Math.random().toString(36).slice(2, 14); // last resort — no crypto at all\r\n}\r\n\r\n// Per-process (per tab/worker) client component — generated ONCE at module load so two clients never collide\r\n// even at counter 0 in the same millisecond.\r\nconst CLIENT = randomClientComponent();\r\n\r\n// Internal (module-exported for tests; NOT in the package barrel — see index.ts / index.test.ts `removed`).\r\nexport function formatId(prefix: string, time: string, counter: string, client: string): string {\r\n return `${prefix}_${time}_${counter}_${client}`;\r\n}\r\n\r\nexport function createId(prefix: string): string {\r\n return formatId(prefix, Date.now().toString(36), (counter++).toString(36), CLIENT);\r\n}\r\n","import type { Point, Bounds } from './types';\r\n\r\nexport function distSqToSegment(p: Point, a: Point, b: Point): number {\r\n const abx = b.x - a.x;\r\n const aby = b.y - a.y;\r\n const apx = p.x - a.x;\r\n const apy = p.y - a.y;\r\n const lenSq = abx * abx + aby * aby;\r\n if (lenSq === 0) {\r\n return apx * apx + apy * apy;\r\n }\r\n const t = Math.max(0, Math.min(1, (apx * abx + apy * aby) / lenSq));\r\n const dx = p.x - (a.x + t * abx);\r\n const dy = p.y - (a.y + t * aby);\r\n return dx * dx + dy * dy;\r\n}\r\n\r\nexport function rotatePoint(p: Point, center: Point, angle: number): Point {\r\n if (angle === 0) return p;\r\n const cos = Math.cos(angle);\r\n const sin = Math.sin(angle);\r\n const dx = p.x - center.x;\r\n const dy = p.y - center.y;\r\n return { x: center.x + dx * cos - dy * sin, y: center.y + dx * sin + dy * cos };\r\n}\r\n\r\nexport function rotatedAABB(bounds: Bounds, angle: number): Bounds {\r\n if (angle === 0) return bounds;\r\n const c = { x: bounds.x + bounds.w / 2, y: bounds.y + bounds.h / 2 };\r\n const corners = [\r\n { x: bounds.x, y: bounds.y },\r\n { x: bounds.x + bounds.w, y: bounds.y },\r\n { x: bounds.x + bounds.w, y: bounds.y + bounds.h },\r\n { x: bounds.x, y: bounds.y + bounds.h },\r\n ].map((p) => rotatePoint(p, c, angle));\r\n const xs = corners.map((p) => p.x);\r\n const ys = corners.map((p) => p.y);\r\n const minX = Math.min(...xs);\r\n const minY = Math.min(...ys);\r\n return { x: minX, y: minY, w: Math.max(...xs) - minX, h: Math.max(...ys) - minY };\r\n}\r\n\r\nexport function normalizeAngle(angle: number): number {\r\n const twoPi = Math.PI * 2;\r\n let a = angle % twoPi;\r\n if (a <= -Math.PI) a += twoPi;\r\n else if (a > Math.PI) a -= twoPi;\r\n return a;\r\n}\r\n","import type { Bounds, Point } from '../core/types';\r\nimport { distSqToSegment } from '../core/geometry';\r\n\r\nexport function getArrowControlPoint(from: Point, to: Point, bend: number): Point {\r\n const midX = (from.x + to.x) / 2;\r\n const midY = (from.y + to.y) / 2;\r\n\r\n if (bend === 0) return { x: midX, y: midY };\r\n\r\n const dx = to.x - from.x;\r\n const dy = to.y - from.y;\r\n const len = Math.sqrt(dx * dx + dy * dy);\r\n\r\n if (len === 0) return { x: midX, y: midY };\r\n\r\n const perpX = -dy / len;\r\n const perpY = dx / len;\r\n\r\n return {\r\n x: midX + perpX * bend,\r\n y: midY + perpY * bend,\r\n };\r\n}\r\n\r\nexport function getArrowMidpoint(from: Point, to: Point, bend: number): Point {\r\n const cp = getArrowControlPoint(from, to, bend);\r\n return {\r\n x: 0.25 * from.x + 0.5 * cp.x + 0.25 * to.x,\r\n y: 0.25 * from.y + 0.5 * cp.y + 0.25 * to.y,\r\n };\r\n}\r\n\r\nexport function getBendFromPoint(from: Point, to: Point, dragPoint: Point): number {\r\n const midX = (from.x + to.x) / 2;\r\n const midY = (from.y + to.y) / 2;\r\n\r\n const dx = to.x - from.x;\r\n const dy = to.y - from.y;\r\n const len = Math.sqrt(dx * dx + dy * dy);\r\n\r\n if (len === 0) return 0;\r\n\r\n const perpX = -dy / len;\r\n const perpY = dx / len;\r\n\r\n // The bend handle sits at the curve midpoint (getArrowMidpoint), which is HALF the control-point\r\n // offset. Double the projection so the handle tracks the pointer 1:1 (bend is the control-point offset).\r\n return 2 * ((dragPoint.x - midX) * perpX + (dragPoint.y - midY) * perpY);\r\n}\r\n\r\nexport function getArrowTangentAngle(from: Point, to: Point, bend: number, t: number): number {\r\n const cp = getArrowControlPoint(from, to, bend);\r\n\r\n const tangentX = 2 * (1 - t) * (cp.x - from.x) + 2 * t * (to.x - cp.x);\r\n const tangentY = 2 * (1 - t) * (cp.y - from.y) + 2 * t * (to.y - cp.y);\r\n\r\n return Math.atan2(tangentY, tangentX);\r\n}\r\n\r\nexport function isNearBezier(\r\n point: Point,\r\n from: Point,\r\n to: Point,\r\n bend: number,\r\n threshold: number,\r\n): boolean {\r\n if (bend === 0) return isNearLine(point, from, to, threshold);\r\n\r\n const cp = getArrowControlPoint(from, to, bend);\r\n const segments = 20;\r\n\r\n for (let i = 0; i < segments; i++) {\r\n const t0 = i / segments;\r\n const t1 = (i + 1) / segments;\r\n const a = bezierPoint(from, cp, to, t0);\r\n const b = bezierPoint(from, cp, to, t1);\r\n if (isNearLine(point, a, b, threshold)) return true;\r\n }\r\n\r\n return false;\r\n}\r\n\r\nexport function getArrowBounds(from: Point, to: Point, bend: number): Bounds {\r\n if (bend === 0) {\r\n const minX = Math.min(from.x, to.x);\r\n const minY = Math.min(from.y, to.y);\r\n return {\r\n x: minX,\r\n y: minY,\r\n w: Math.abs(to.x - from.x),\r\n h: Math.abs(to.y - from.y),\r\n };\r\n }\r\n\r\n const cp = getArrowControlPoint(from, to, bend);\r\n const steps = 20;\r\n let minX = Math.min(from.x, to.x);\r\n let minY = Math.min(from.y, to.y);\r\n let maxX = Math.max(from.x, to.x);\r\n let maxY = Math.max(from.y, to.y);\r\n\r\n for (let i = 1; i < steps; i++) {\r\n const t = i / steps;\r\n const p = bezierPoint(from, cp, to, t);\r\n if (p.x < minX) minX = p.x;\r\n if (p.y < minY) minY = p.y;\r\n if (p.x > maxX) maxX = p.x;\r\n if (p.y > maxY) maxY = p.y;\r\n }\r\n\r\n return { x: minX, y: minY, w: maxX - minX, h: maxY - minY };\r\n}\r\n\r\nfunction bezierPoint(from: Point, cp: Point, to: Point, t: number): Point {\r\n const mt = 1 - t;\r\n return {\r\n x: mt * mt * from.x + 2 * mt * t * cp.x + t * t * to.x,\r\n y: mt * mt * from.y + 2 * mt * t * cp.y + t * t * to.y,\r\n };\r\n}\r\n\r\nfunction isNearLine(point: Point, a: Point, b: Point, threshold: number): boolean {\r\n return distSqToSegment(point, a, b) <= threshold * threshold;\r\n}\r\n","import type { Bounds } from '../core/types';\r\nimport { rotatedAABB } from '../core/geometry';\r\nimport type { CanvasElement, TemplateElement } from './types';\r\nimport { getArrowControlPoint } from './arrow-geometry';\r\n\r\n// Cache stroke bounds via WeakMap.\r\n// May miss after ElementStore.update() creates new object via spread,\r\n// acceptable since stroke points never change after commit.\r\nconst strokeBoundsCache = new WeakMap<CanvasElement, Bounds>();\r\n\r\nexport function getElementBounds(element: CanvasElement): Bounds | null {\r\n if (element.type === 'grid') return null;\r\n\r\n if ('size' in element) {\r\n return {\r\n x: element.position.x,\r\n y: element.position.y,\r\n w: element.size.w,\r\n h: element.size.h,\r\n };\r\n }\r\n\r\n if (element.type === 'stroke') {\r\n if (element.points.length === 0) return null;\r\n\r\n const cached = strokeBoundsCache.get(element);\r\n if (cached) return cached;\r\n\r\n let minX = Infinity;\r\n let minY = Infinity;\r\n let maxX = -Infinity;\r\n let maxY = -Infinity;\r\n\r\n for (const p of element.points) {\r\n const px = p.x + element.position.x;\r\n const py = p.y + element.position.y;\r\n if (px < minX) minX = px;\r\n if (py < minY) minY = py;\r\n if (px > maxX) maxX = px;\r\n if (py > maxY) maxY = py;\r\n }\r\n\r\n const bounds: Bounds = { x: minX, y: minY, w: maxX - minX, h: maxY - minY };\r\n strokeBoundsCache.set(element, bounds);\r\n return bounds;\r\n }\r\n\r\n if (element.type === 'arrow') {\r\n return getArrowBoundsAnalytical(element.from, element.to, element.bend);\r\n }\r\n\r\n if (element.type === 'template') {\r\n return getTemplateBounds(element);\r\n }\r\n\r\n return null;\r\n}\r\n\r\n/** Axis-aligned world bounds covering the element's complete rotated visual footprint. */\r\nexport function getElementVisualBounds(element: CanvasElement): Bounds | null {\r\n const bounds = getElementBounds(element);\r\n if (!bounds) return null;\r\n const rotation = element.rotation ?? 0;\r\n return rotation === 0 ? bounds : rotatedAABB(bounds, rotation);\r\n}\r\n\r\nfunction getArrowBoundsAnalytical(\r\n from: { x: number; y: number },\r\n to: { x: number; y: number },\r\n bend: number,\r\n): Bounds {\r\n if (bend === 0) {\r\n const minX = Math.min(from.x, to.x);\r\n const minY = Math.min(from.y, to.y);\r\n return {\r\n x: minX,\r\n y: minY,\r\n w: Math.abs(to.x - from.x),\r\n h: Math.abs(to.y - from.y),\r\n };\r\n }\r\n\r\n const cp = getArrowControlPoint(from, to, bend);\r\n\r\n let minX = Math.min(from.x, to.x);\r\n let maxX = Math.max(from.x, to.x);\r\n let minY = Math.min(from.y, to.y);\r\n let maxY = Math.max(from.y, to.y);\r\n\r\n // Analytical extrema for quadratic bezier: t = (P0 - P1) / (P0 - 2*P1 + P2)\r\n const tx = from.x - 2 * cp.x + to.x;\r\n if (tx !== 0) {\r\n const t = (from.x - cp.x) / tx;\r\n if (t > 0 && t < 1) {\r\n const mt = 1 - t;\r\n const x = mt * mt * from.x + 2 * mt * t * cp.x + t * t * to.x;\r\n if (x < minX) minX = x;\r\n if (x > maxX) maxX = x;\r\n }\r\n }\r\n\r\n const ty = from.y - 2 * cp.y + to.y;\r\n if (ty !== 0) {\r\n const t = (from.y - cp.y) / ty;\r\n if (t > 0 && t < 1) {\r\n const mt = 1 - t;\r\n const y = mt * mt * from.y + 2 * mt * t * cp.y + t * t * to.y;\r\n if (y < minY) minY = y;\r\n if (y > maxY) maxY = y;\r\n }\r\n }\r\n\r\n return { x: minX, y: minY, w: maxX - minX, h: maxY - minY };\r\n}\r\n\r\nfunction getTemplateBounds(el: TemplateElement): Bounds {\r\n const { x: cx, y: cy } = el.position;\r\n const r = el.radius;\r\n\r\n switch (el.templateShape) {\r\n case 'circle':\r\n return { x: cx - r, y: cy - r, w: 2 * r, h: 2 * r };\r\n\r\n case 'square':\r\n return { x: cx - r / 2, y: cy - r / 2, w: r, h: r };\r\n\r\n case 'cone': {\r\n const halfAngle = Math.atan(0.5);\r\n const tipX = cx;\r\n const tipY = cy;\r\n const leftX = cx + r * Math.cos(el.angle - halfAngle);\r\n const leftY = cy + r * Math.sin(el.angle - halfAngle);\r\n const rightX = cx + r * Math.cos(el.angle + halfAngle);\r\n const rightY = cy + r * Math.sin(el.angle + halfAngle);\r\n const farX = cx + r * Math.cos(el.angle);\r\n const farY = cy + r * Math.sin(el.angle);\r\n\r\n const xs = [tipX, leftX, rightX, farX];\r\n const ys = [tipY, leftY, rightY, farY];\r\n\r\n let minX = Infinity;\r\n let minY = Infinity;\r\n let maxX = -Infinity;\r\n let maxY = -Infinity;\r\n\r\n for (let i = 0; i < xs.length; i++) {\r\n const px = xs[i];\r\n const py = ys[i];\r\n if (px !== undefined && px < minX) minX = px;\r\n if (px !== undefined && px > maxX) maxX = px;\r\n if (py !== undefined && py < minY) minY = py;\r\n if (py !== undefined && py > maxY) maxY = py;\r\n }\r\n\r\n return { x: minX, y: minY, w: maxX - minX, h: maxY - minY };\r\n }\r\n\r\n case 'line': {\r\n const halfW = r / 12;\r\n const cos = Math.cos(el.angle);\r\n const sin = Math.sin(el.angle);\r\n const perpX = -sin * halfW;\r\n const perpY = cos * halfW;\r\n\r\n const x0 = cx + perpX;\r\n const y0 = cy + perpY;\r\n const x1 = cx + r * cos + perpX;\r\n const y1 = cy + r * sin + perpY;\r\n const x2 = cx + r * cos - perpX;\r\n const y2 = cy + r * sin - perpY;\r\n const x3 = cx - perpX;\r\n const y3 = cy - perpY;\r\n\r\n const minX = Math.min(x0, x1, x2, x3);\r\n const minY = Math.min(y0, y1, y2, y3);\r\n const maxX = Math.max(x0, x1, x2, x3);\r\n const maxY = Math.max(y0, y1, y2, y3);\r\n\r\n return { x: minX, y: minY, w: maxX - minX, h: maxY - minY };\r\n }\r\n\r\n case 'rectangle': {\r\n const halfW = (el.width ?? 0) / 2;\r\n const cos = Math.cos(el.angle);\r\n const sin = Math.sin(el.angle);\r\n const perpX = -sin * halfW;\r\n const perpY = cos * halfW;\r\n const x0 = cx + perpX;\r\n const y0 = cy + perpY;\r\n const x1 = cx + r * cos + perpX;\r\n const y1 = cy + r * sin + perpY;\r\n const x2 = cx + r * cos - perpX;\r\n const y2 = cy + r * sin - perpY;\r\n const x3 = cx - perpX;\r\n const y3 = cy - perpY;\r\n const minX = Math.min(x0, x1, x2, x3);\r\n const minY = Math.min(y0, y1, y2, y3);\r\n const maxX = Math.max(x0, x1, x2, x3);\r\n const maxY = Math.max(y0, y1, y2, y3);\r\n return { x: minX, y: minY, w: maxX - minX, h: maxY - minY };\r\n }\r\n }\r\n}\r\n\r\nexport function transferStrokeBounds(prev: CanvasElement, next: CanvasElement): void {\r\n if (prev.type !== 'stroke' || next.type !== 'stroke') return;\r\n if (prev.points !== next.points) return;\r\n if (prev.position.x !== next.position.x || prev.position.y !== next.position.y) return;\r\n const bounds = strokeBoundsCache.get(prev);\r\n if (bounds) strokeBoundsCache.set(next, bounds);\r\n}\r\n\r\nexport function boundsIntersect(a: Bounds, b: Bounds): boolean {\r\n return a.x <= b.x + b.w && a.x + a.w >= b.x && a.y <= b.y + b.h && a.y + a.h >= b.y;\r\n}\r\n","import type { Bounds } from '../core/types';\r\nimport type { CanvasElement } from './types';\r\nimport { getElementBounds } from './element-bounds';\r\n\r\nexport function getElementsBoundingBox(elements: CanvasElement[]): Bounds | null {\r\n let minX = Infinity;\r\n let minY = Infinity;\r\n let maxX = -Infinity;\r\n let maxY = -Infinity;\r\n let found = false;\r\n\r\n for (const el of elements) {\r\n const b = getElementBounds(el);\r\n if (!b) continue;\r\n found = true;\r\n if (b.x < minX) minX = b.x;\r\n if (b.y < minY) minY = b.y;\r\n if (b.x + b.w > maxX) maxX = b.x + b.w;\r\n if (b.y + b.h > maxY) maxY = b.y + b.h;\r\n }\r\n\r\n if (!found) return null;\r\n return { x: minX, y: minY, w: maxX - minX, h: maxY - minY };\r\n}\r\n","import type { ToolManager } from '../tools/tool-manager';\r\nimport type { ToolContext } from '../tools/types';\r\nimport type { SelectTool } from '../tools/select-tool';\r\nimport type { HistoryRecorder } from '../history/history-recorder';\r\nimport type { HistoryStack } from '../history/history-stack';\r\nimport type { CanvasElement } from '../elements/types';\r\nimport type { Point } from '../core/types';\r\nimport { createId } from '../elements/create-id';\r\nimport { getElementsBoundingBox } from '../elements/bounds';\r\nimport type { RotateDirection } from './selection-rotate';\r\n\r\nexport interface KeyboardActionsDeps {\r\n getToolManager: () => ToolManager | null;\r\n getToolContext: () => ToolContext | null;\r\n getHistoryRecorder: () => HistoryRecorder | null;\r\n getHistoryStack: () => HistoryStack | null;\r\n isToolActive: () => boolean;\r\n fitToContent?: () => void;\r\n group?: () => void;\r\n ungroup?: () => void;\r\n toggleLock?: () => void;\r\n rotate?: (direction: RotateDirection) => void;\r\n getLastPointerWorld?: () => Point | null;\r\n}\r\n\r\nexport class KeyboardActions {\r\n private clipboard: CanvasElement[] = [];\r\n private pasteCount = 0;\r\n private nudgeTimer: ReturnType<typeof setTimeout> | null = null;\r\n private nudgeTxId: number | null = null;\r\n\r\n constructor(private readonly deps: KeyboardActionsDeps) {}\r\n\r\n dispose(): void {\r\n this.flushPendingNudge();\r\n }\r\n\r\n private selectTool(): { tool: SelectTool; ctx: ToolContext } | null {\r\n const tm = this.deps.getToolManager();\r\n const ctx = this.deps.getToolContext();\r\n if (!tm || !ctx) return null;\r\n const tool = tm.activeTool;\r\n if (tool?.name !== 'select') return null;\r\n return { tool: tool as SelectTool, ctx };\r\n }\r\n\r\n private selectableElements(ctx: ToolContext): CanvasElement[] {\r\n return ctx.store\r\n .getAll()\r\n .filter(\r\n (el) =>\r\n !el.locked &&\r\n (ctx.isLayerVisible?.(el.layerId) ?? true) &&\r\n !(ctx.isLayerLocked?.(el.layerId) ?? false),\r\n );\r\n }\r\n\r\n nudge(dx: number, dy: number, byCell: boolean): boolean {\r\n if (this.deps.isToolActive()) return false;\r\n const sel = this.selectTool();\r\n if (!sel) return false;\r\n if (sel.tool.selectedIds.length === 0) return false;\r\n\r\n const step = byCell ? (sel.ctx.gridSize ?? 10) : 1;\r\n if (this.nudgeTimer === null) {\r\n const recorder = this.deps.getHistoryRecorder();\r\n recorder?.begin();\r\n this.nudgeTxId = recorder?.currentTransactionId ?? null;\r\n } else {\r\n clearTimeout(this.nudgeTimer);\r\n const recorder = this.deps.getHistoryRecorder();\r\n if (recorder?.currentTransactionId !== this.nudgeTxId) {\r\n recorder?.begin();\r\n this.nudgeTxId = recorder?.currentTransactionId ?? null;\r\n }\r\n }\r\n const moved = sel.tool.nudgeSelection(dx * step, dy * step, sel.ctx);\r\n this.nudgeTimer = setTimeout(() => this.flushPendingNudge(), 400);\r\n return moved;\r\n }\r\n\r\n flushPendingNudge(): void {\r\n if (this.nudgeTimer === null) return;\r\n clearTimeout(this.nudgeTimer);\r\n this.nudgeTimer = null;\r\n const recorder = this.deps.getHistoryRecorder();\r\n if (recorder?.currentTransactionId === this.nudgeTxId) {\r\n recorder?.commit();\r\n }\r\n this.nudgeTxId = null;\r\n }\r\n\r\n deleteSelected(): void {\r\n if (this.deps.isToolActive()) return;\r\n this.flushPendingNudge();\r\n const sel = this.selectTool();\r\n if (!sel) return;\r\n const ids = sel.tool.selectedIds;\r\n if (ids.length === 0) return;\r\n const recorder = this.deps.getHistoryRecorder();\r\n recorder?.begin();\r\n for (const id of ids) {\r\n sel.ctx.store.remove(id);\r\n }\r\n recorder?.commit();\r\n sel.ctx.requestRender();\r\n }\r\n\r\n undo(): void {\r\n if (this.deps.isToolActive()) return;\r\n this.flushPendingNudge();\r\n const ctx = this.deps.getToolContext();\r\n const stack = this.deps.getHistoryStack();\r\n if (!stack || !ctx) return;\r\n const recorder = this.deps.getHistoryRecorder();\r\n recorder?.pause();\r\n stack.undo(ctx.store);\r\n recorder?.resume();\r\n ctx.requestRender();\r\n }\r\n\r\n redo(): void {\r\n if (this.deps.isToolActive()) return;\r\n this.flushPendingNudge();\r\n const ctx = this.deps.getToolContext();\r\n const stack = this.deps.getHistoryStack();\r\n if (!stack || !ctx) return;\r\n const recorder = this.deps.getHistoryRecorder();\r\n recorder?.pause();\r\n stack.redo(ctx.store);\r\n recorder?.resume();\r\n ctx.requestRender();\r\n }\r\n\r\n copy(): void {\r\n if (this.deps.isToolActive()) return;\r\n const sel = this.selectTool();\r\n if (!sel) return;\r\n const ids = sel.tool.selectedIds;\r\n if (ids.length === 0) return;\r\n this.clipboard = [];\r\n for (const id of ids) {\r\n const el = sel.ctx.store.getById(id);\r\n if (el) this.clipboard.push(structuredClone(el));\r\n }\r\n this.pasteCount = 0;\r\n }\r\n\r\n cut(): void {\r\n if (this.deps.isToolActive()) return;\r\n this.copy();\r\n this.deleteSelected();\r\n }\r\n\r\n hasClipboard(): boolean {\r\n return this.clipboard.length > 0;\r\n }\r\n\r\n paste(): void {\r\n if (this.deps.isToolActive()) return;\r\n this.flushPendingNudge();\r\n if (this.clipboard.length === 0) return;\r\n const sel = this.selectTool();\r\n if (!sel) return;\r\n\r\n const cursor = this.deps.getLastPointerWorld?.() ?? null;\r\n if (cursor) {\r\n const bbox = getElementsBoundingBox(this.clipboard);\r\n if (bbox) {\r\n const centerX = bbox.x + bbox.w / 2;\r\n const centerY = bbox.y + bbox.h / 2;\r\n this.insertClones(this.clipboard, { x: cursor.x - centerX, y: cursor.y - centerY }, sel);\r\n return;\r\n }\r\n }\r\n\r\n this.pasteCount++;\r\n this.insertClones(this.clipboard, { x: this.pasteCount * 20, y: this.pasteCount * 20 }, sel);\r\n }\r\n\r\n duplicate(): void {\r\n if (this.deps.isToolActive()) return;\r\n this.flushPendingNudge();\r\n const sel = this.selectTool();\r\n if (!sel) return;\r\n const source: CanvasElement[] = [];\r\n for (const id of sel.tool.selectedIds) {\r\n const el = sel.ctx.store.getById(id);\r\n if (el) source.push(el);\r\n }\r\n if (source.length === 0) return;\r\n this.insertClones(source, { x: 20, y: 20 }, sel);\r\n }\r\n\r\n deselect(): void {\r\n if (this.deps.isToolActive()) return;\r\n const sel = this.selectTool();\r\n if (!sel) return;\r\n if (sel.tool.selectedIds.length === 0) return;\r\n sel.tool.setSelection([]);\r\n sel.ctx.requestRender();\r\n }\r\n\r\n selectAll(): void {\r\n if (this.deps.isToolActive()) return;\r\n const tm = this.deps.getToolManager();\r\n const ctx = this.deps.getToolContext();\r\n if (!tm || !ctx) return;\r\n if (tm.activeTool?.name !== 'select') {\r\n ctx.switchTool?.('select');\r\n }\r\n const sel = this.selectTool();\r\n if (!sel) return;\r\n const ids = this.selectableElements(sel.ctx).map((el) => el.id);\r\n sel.tool.setSelection(ids);\r\n sel.ctx.requestRender();\r\n }\r\n\r\n cycleSelection(direction: 1 | -1): void {\r\n if (this.deps.isToolActive()) return;\r\n const tm = this.deps.getToolManager();\r\n const ctx = this.deps.getToolContext();\r\n if (!tm || !ctx) return;\r\n if (tm.activeTool?.name !== 'select') ctx.switchTool?.('select');\r\n const sel = this.selectTool();\r\n if (!sel) return;\r\n const eligible = this.selectableElements(sel.ctx).filter((el) => el.type !== 'grid');\r\n if (eligible.length === 0) return;\r\n const idxs = sel.tool.selectedIds\r\n .map((id) => eligible.findIndex((e) => e.id === id))\r\n .filter((i) => i >= 0);\r\n const anchor =\r\n idxs.length === 0\r\n ? direction > 0\r\n ? -1\r\n : 0\r\n : direction > 0\r\n ? Math.max(...idxs)\r\n : Math.min(...idxs);\r\n const next = (anchor + direction + eligible.length) % eligible.length;\r\n const target = eligible[next];\r\n if (!target) return;\r\n sel.tool.setSelection([target.id]);\r\n sel.ctx.requestRender();\r\n }\r\n\r\n zoomToFit(): void {\r\n if (this.deps.isToolActive()) return;\r\n this.deps.fitToContent?.();\r\n }\r\n\r\n group(): void {\r\n if (this.deps.isToolActive()) return;\r\n this.deps.group?.();\r\n }\r\n\r\n ungroup(): void {\r\n if (this.deps.isToolActive()) return;\r\n this.deps.ungroup?.();\r\n }\r\n\r\n toggleLock(): void {\r\n if (this.deps.isToolActive()) return;\r\n this.deps.toggleLock?.();\r\n }\r\n\r\n rotate(direction: RotateDirection): void {\r\n if (this.deps.isToolActive()) return;\r\n this.flushPendingNudge();\r\n const sel = this.selectTool();\r\n if (!sel) return;\r\n if (sel.tool.selectedIds.length === 0) return;\r\n this.deps.rotate?.(direction);\r\n }\r\n\r\n zOrder(operation: 'forward' | 'backward' | 'front' | 'back'): void {\r\n if (this.deps.isToolActive()) return;\r\n this.flushPendingNudge();\r\n const sel = this.selectTool();\r\n if (!sel) return;\r\n const ids = sel.tool.selectedIds;\r\n if (ids.length === 0) return;\r\n const recorder = this.deps.getHistoryRecorder();\r\n recorder?.begin();\r\n for (const id of ids) {\r\n switch (operation) {\r\n case 'forward':\r\n sel.ctx.store.bringForward(id);\r\n break;\r\n case 'backward':\r\n sel.ctx.store.sendBackward(id);\r\n break;\r\n case 'front':\r\n sel.ctx.store.bringToFront(id);\r\n break;\r\n case 'back':\r\n sel.ctx.store.sendToBack(id);\r\n break;\r\n }\r\n }\r\n recorder?.commit();\r\n sel.ctx.requestRender();\r\n }\r\n\r\n private insertClones(\r\n source: CanvasElement[],\r\n offset: Point,\r\n sel: { tool: SelectTool; ctx: ToolContext },\r\n ): void {\r\n const idMap = new Map<string, string>();\r\n for (const el of source) {\r\n idMap.set(el.id, createId(el.type));\r\n }\r\n\r\n const groupIdMap = new Map<string, string>();\r\n for (const el of source) {\r\n if (el.groupId && !groupIdMap.has(el.groupId)) groupIdMap.set(el.groupId, createId('group'));\r\n }\r\n\r\n const newIds: string[] = [];\r\n const recorder = this.deps.getHistoryRecorder();\r\n recorder?.begin();\r\n\r\n for (const el of source) {\r\n const clone = structuredClone(el);\r\n const newId = idMap.get(el.id);\r\n if (!newId) continue;\r\n clone.id = newId;\r\n if (clone.groupId) clone.groupId = groupIdMap.get(clone.groupId) ?? clone.groupId;\r\n clone.position = { x: clone.position.x + offset.x, y: clone.position.y + offset.y };\r\n\r\n if (clone.type === 'arrow') {\r\n const arrow = clone;\r\n arrow.from = { x: arrow.from.x + offset.x, y: arrow.from.y + offset.y };\r\n arrow.to = { x: arrow.to.x + offset.x, y: arrow.to.y + offset.y };\r\n delete arrow.cachedControlPoint;\r\n\r\n if (arrow.fromBinding) {\r\n const newTarget = idMap.get(arrow.fromBinding.elementId);\r\n if (newTarget) {\r\n arrow.fromBinding = { elementId: newTarget };\r\n } else {\r\n delete arrow.fromBinding;\r\n }\r\n }\r\n if (arrow.toBinding) {\r\n const newTarget = idMap.get(arrow.toBinding.elementId);\r\n if (newTarget) {\r\n arrow.toBinding = { elementId: newTarget };\r\n } else {\r\n delete arrow.toBinding;\r\n }\r\n }\r\n }\r\n\r\n if (sel.ctx.activeLayerId) {\r\n clone.layerId = sel.ctx.activeLayerId;\r\n }\r\n\r\n sel.ctx.store.add(clone);\r\n newIds.push(clone.id);\r\n }\r\n\r\n recorder?.commit();\r\n sel.tool.setSelection(newIds);\r\n sel.ctx.requestRender();\r\n }\r\n}\r\n","export type ShortcutBindings = Record<string, string | string[] | null>;\r\n\r\nexport interface ShortcutOptions {\r\n scope?: 'focus' | 'window';\r\n bindings?: ShortcutBindings;\r\n}\r\n\r\nexport interface ShortcutsApi {\r\n rebind(action: string, bindings: string | string[] | null): void;\r\n disable(action: string): void;\r\n reset(action?: string): void;\r\n getBindings(): Record<string, string[]>;\r\n}\r\n\r\ninterface ParsedBinding {\r\n mod: boolean;\r\n ctrl: boolean;\r\n meta: boolean;\r\n shift: boolean;\r\n alt: boolean;\r\n key: string;\r\n digit: boolean;\r\n}\r\n\r\nconst DEFAULT_BINDINGS: readonly (readonly [string, readonly string[]])[] = [\r\n ['delete', ['delete', 'backspace']],\r\n ['deselect', ['escape']],\r\n ['undo', ['mod+z']],\r\n ['redo', ['mod+y', 'mod+shift+z']],\r\n ['select-all', ['mod+a']],\r\n ['cycle-selection', ['tab']],\r\n ['cycle-selection-reverse', ['shift+tab']],\r\n ['copy', ['mod+c']],\r\n ['duplicate', ['mod+d']],\r\n ['z-forward', [']']],\r\n ['z-backward', ['[']],\r\n ['z-front', ['mod+]']],\r\n ['z-back', ['mod+[']],\r\n ['zoom-fit', ['shift+1']],\r\n ['zoom-in', ['mod+=']],\r\n ['zoom-out', ['mod+-']],\r\n ['zoom-reset', ['mod+0']],\r\n ['group', ['mod+g']],\r\n ['ungroup', ['mod+shift+g']],\r\n ['cut', ['mod+x']],\r\n ['toggle-lock', ['mod+shift+l']],\r\n ['rotate-cw', ['r']],\r\n ['rotate-ccw', ['shift+r']],\r\n ['nudge-left', ['arrowleft']],\r\n ['nudge-right', ['arrowright']],\r\n ['nudge-up', ['arrowup']],\r\n ['nudge-down', ['arrowdown']],\r\n ['tool:select', ['v']],\r\n ['tool:hand', ['h']],\r\n ['tool:pencil', ['p']],\r\n ['tool:eraser', ['e']],\r\n ['tool:arrow', ['a']],\r\n ['tool:note', ['n']],\r\n ['tool:text', ['t']],\r\n ['tool:shape', ['s']],\r\n ['tool:measure', ['m']],\r\n ['tool:template', ['g']],\r\n];\r\n\r\nconst ALLOW_SHIFT = new Set(['nudge-left', 'nudge-right', 'nudge-up', 'nudge-down']);\r\nconst MODIFIERS = new Set(['mod', 'ctrl', 'meta', 'shift', 'alt']);\r\n\r\nfunction parseBinding(binding: string): ParsedBinding {\r\n const parts = binding.toLowerCase().split('+');\r\n const key = parts.pop();\r\n if (key === undefined || key.length === 0 || MODIFIERS.has(key)) {\r\n throw new Error(`Invalid shortcut binding \"${binding}\": missing key`);\r\n }\r\n const normalizedKey = key === 'space' ? ' ' : key;\r\n const parsed: ParsedBinding = {\r\n mod: false,\r\n ctrl: false,\r\n meta: false,\r\n shift: false,\r\n alt: false,\r\n key: normalizedKey,\r\n digit: /^[0-9]$/.test(normalizedKey),\r\n };\r\n for (const part of parts) {\r\n switch (part) {\r\n case 'mod':\r\n parsed.mod = true;\r\n break;\r\n case 'ctrl':\r\n parsed.ctrl = true;\r\n break;\r\n case 'meta':\r\n parsed.meta = true;\r\n break;\r\n case 'shift':\r\n parsed.shift = true;\r\n break;\r\n case 'alt':\r\n parsed.alt = true;\r\n break;\r\n default:\r\n throw new Error(`Invalid shortcut binding \"${binding}\": unknown modifier \"${part}\"`);\r\n }\r\n }\r\n if (parsed.mod && (parsed.ctrl || parsed.meta)) {\r\n throw new Error(\r\n `Invalid shortcut binding \"${binding}\": \"mod\" already means Ctrl or Cmd; don't combine it with ctrl/meta`,\r\n );\r\n }\r\n return parsed;\r\n}\r\n\r\nfunction bindingMatches(p: ParsedBinding, e: KeyboardEvent, allowShift: boolean): boolean {\r\n if (p.mod) {\r\n if (!e.ctrlKey && !e.metaKey) return false;\r\n } else if (e.ctrlKey !== p.ctrl || e.metaKey !== p.meta) {\r\n return false;\r\n }\r\n if (!allowShift && e.shiftKey !== p.shift) return false;\r\n if (e.altKey !== p.alt) return false;\r\n return p.digit ? e.code === `Digit${p.key}` : e.key.toLowerCase() === p.key;\r\n}\r\n\r\nfunction sameBinding(a: ParsedBinding, b: ParsedBinding): boolean {\r\n return (\r\n a.key === b.key &&\r\n a.mod === b.mod &&\r\n a.ctrl === b.ctrl &&\r\n a.meta === b.meta &&\r\n a.shift === b.shift &&\r\n a.alt === b.alt\r\n );\r\n}\r\n\r\nfunction toArray(bindings: string | string[] | null): string[] {\r\n if (bindings === null) return [];\r\n return Array.isArray(bindings) ? [...bindings] : [bindings];\r\n}\r\n\r\nexport class ShortcutMap implements ShortcutsApi {\r\n private raw = new Map<string, string[]>();\r\n private parsed = new Map<string, ParsedBinding[]>();\r\n\r\n constructor(overrides?: ShortcutBindings) {\r\n this.applyDefaults();\r\n if (overrides) {\r\n for (const [action, bindings] of Object.entries(overrides)) {\r\n this.rebind(action, bindings);\r\n }\r\n }\r\n }\r\n\r\n /** First matching action in registration order wins when bindings conflict. */\r\n match(e: KeyboardEvent): string | null {\r\n for (const [action, parsedList] of this.parsed) {\r\n const allowShift = ALLOW_SHIFT.has(action);\r\n for (const p of parsedList) {\r\n if (bindingMatches(p, e, allowShift)) return action;\r\n }\r\n }\r\n return null;\r\n }\r\n\r\n rebind(action: string, bindings: string | string[] | null): void {\r\n const list = toArray(bindings);\r\n const parsedList = list.map(parseBinding);\r\n for (const p of parsedList) {\r\n for (const [otherAction, otherList] of this.parsed) {\r\n if (otherAction === action) continue;\r\n if (otherList.some((q) => sameBinding(p, q))) {\r\n console.warn(\r\n `[fieldnotes] shortcut binding for \"${action}\" conflicts with \"${otherAction}\"; first registered wins`,\r\n );\r\n }\r\n }\r\n }\r\n this.raw.set(action, list);\r\n this.parsed.set(action, parsedList);\r\n }\r\n\r\n disable(action: string): void {\r\n this.rebind(action, null);\r\n }\r\n\r\n reset(action?: string): void {\r\n if (action === undefined) {\r\n this.raw.clear();\r\n this.parsed.clear();\r\n this.applyDefaults();\r\n return;\r\n }\r\n const def = DEFAULT_BINDINGS.find(([name]) => name === action);\r\n if (def) {\r\n this.rebind(action, [...def[1]]);\r\n } else if (this.raw.has(action)) {\r\n this.raw.delete(action);\r\n this.parsed.delete(action);\r\n }\r\n }\r\n\r\n getBindings(): Record<string, string[]> {\r\n const out: Record<string, string[]> = {};\r\n for (const [action, list] of this.raw) {\r\n out[action] = [...list];\r\n }\r\n return out;\r\n }\r\n\r\n private applyDefaults(): void {\r\n for (const [action, bindings] of DEFAULT_BINDINGS) {\r\n this.rebind(action, [...bindings]);\r\n }\r\n }\r\n}\r\n","import type { Camera } from './camera';\r\nimport type { ToolContext } from '../tools/types';\r\nimport type { ShortcutOptions, ShortcutsApi } from './shortcut-map';\r\nimport { ShortcutMap } from './shortcut-map';\r\nimport type { KeyboardActions } from './keyboard-actions';\r\n\r\nconst ZOOM_STEP = 1.2;\r\n\r\nconst NUDGE_DELTAS: Record<string, readonly [number, number]> = {\r\n 'nudge-left': [-1, 0],\r\n 'nudge-right': [1, 0],\r\n 'nudge-up': [0, -1],\r\n 'nudge-down': [0, 1],\r\n};\r\n\r\nexport interface KeyboardHandlerDeps {\r\n element: HTMLElement;\r\n camera: Camera;\r\n actions: KeyboardActions;\r\n scope: 'focus' | 'window';\r\n shortcuts?: ShortcutOptions;\r\n abortSignal: AbortSignal;\r\n getToolContext: () => ToolContext | null;\r\n getIsToolActive: () => boolean;\r\n getLastPointerEvent: () => PointerEvent | null;\r\n setSpaceHeld: (v: boolean) => void;\r\n getActivePointerCount: () => number;\r\n dispatchToolHover: (e: PointerEvent) => void;\r\n addImage: (src: string, world: { x: number; y: number }) => string;\r\n getLastPointerWorld: () => { x: number; y: number } | null;\r\n getCenteredWorld: () => { x: number; y: number };\r\n onPaste?: (e: ClipboardEvent, world: { x: number; y: number }) => void;\r\n}\r\n\r\nexport class KeyboardHandler {\r\n private readonly shortcutMap: ShortcutMap;\r\n\r\n constructor(private readonly deps: KeyboardHandlerDeps) {\r\n this.shortcutMap = new ShortcutMap(deps.shortcuts?.bindings);\r\n window.addEventListener('keydown', this.onKeyDown, { signal: deps.abortSignal });\r\n window.addEventListener('keyup', this.onKeyUp, { signal: deps.abortSignal });\r\n window.addEventListener('paste', this.onPaste, { signal: deps.abortSignal });\r\n }\r\n\r\n get shortcuts(): ShortcutsApi {\r\n return this.shortcutMap;\r\n }\r\n\r\n private viewportCenter(): { x: number; y: number } {\r\n const rect = this.deps.element.getBoundingClientRect();\r\n return { x: rect.width / 2, y: rect.height / 2 };\r\n }\r\n\r\n private zoomByFactor(factor: number): void {\r\n this.deps.camera.zoomAt(this.deps.camera.zoom * factor, this.viewportCenter());\r\n }\r\n\r\n private zoomToLevel(level: number): void {\r\n this.deps.camera.zoomAt(level, this.viewportCenter());\r\n }\r\n\r\n private shouldHandle(target: EventTarget | null): boolean {\r\n const el = target as HTMLElement | null;\r\n if (el?.isContentEditable) return false;\r\n const tag = el?.tagName;\r\n if (tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT') return false;\r\n return this.isInScope();\r\n }\r\n\r\n onKeyDown = (e: KeyboardEvent): void => {\r\n if (!this.shouldHandle(e.target)) return;\r\n\r\n if (e.key === ' ') {\r\n this.deps.setSpaceHeld(true);\r\n }\r\n const action = this.shortcutMap.match(e);\r\n if (action !== null) {\r\n this.runAction(action, e);\r\n }\r\n };\r\n\r\n onKeyUp = (e: KeyboardEvent): void => {\r\n if (e.key === ' ') {\r\n this.deps.setSpaceHeld(false);\r\n if (this.deps.getActivePointerCount() === 0) {\r\n const lastPointerEvent = this.deps.getLastPointerEvent();\r\n if (lastPointerEvent) {\r\n this.deps.dispatchToolHover(lastPointerEvent);\r\n } else {\r\n this.deps.getToolContext()?.setCursor?.('default');\r\n }\r\n }\r\n }\r\n };\r\n\r\n onPaste = (e: ClipboardEvent): void => {\r\n if (!this.shouldHandle(e.target)) return;\r\n const items = e.clipboardData?.items;\r\n let file: File | null = null;\r\n if (items) {\r\n for (const it of items) {\r\n if (it.kind === 'file' && it.type.startsWith('image/')) {\r\n file = it.getAsFile();\r\n break;\r\n }\r\n }\r\n }\r\n if (file) {\r\n e.preventDefault();\r\n const world = this.deps.getLastPointerWorld() ?? this.deps.getCenteredWorld();\r\n if (this.deps.onPaste) {\r\n this.deps.onPaste(e, world);\r\n return;\r\n }\r\n const reader = new FileReader();\r\n reader.onload = () => {\r\n if (typeof reader.result === 'string') this.deps.addImage(reader.result, world);\r\n };\r\n reader.readAsDataURL(file);\r\n return;\r\n }\r\n this.deps.actions.paste();\r\n };\r\n\r\n runAction(action: string, e?: KeyboardEvent): void {\r\n switch (action) {\r\n case 'delete':\r\n e?.preventDefault();\r\n this.deps.actions.deleteSelected();\r\n return;\r\n case 'deselect':\r\n this.deps.actions.deselect();\r\n return;\r\n case 'undo':\r\n e?.preventDefault();\r\n this.deps.actions.undo();\r\n return;\r\n case 'redo':\r\n e?.preventDefault();\r\n this.deps.actions.redo();\r\n return;\r\n case 'select-all':\r\n e?.preventDefault();\r\n this.deps.actions.selectAll();\r\n return;\r\n case 'cycle-selection':\r\n e?.preventDefault();\r\n this.deps.actions.cycleSelection(1);\r\n return;\r\n case 'cycle-selection-reverse':\r\n e?.preventDefault();\r\n this.deps.actions.cycleSelection(-1);\r\n return;\r\n case 'copy':\r\n e?.preventDefault();\r\n this.deps.actions.copy();\r\n return;\r\n case 'paste':\r\n e?.preventDefault();\r\n this.deps.actions.paste();\r\n return;\r\n case 'duplicate':\r\n e?.preventDefault();\r\n this.deps.actions.duplicate();\r\n return;\r\n case 'z-forward':\r\n e?.preventDefault();\r\n this.deps.actions.zOrder('forward');\r\n return;\r\n case 'z-backward':\r\n e?.preventDefault();\r\n this.deps.actions.zOrder('backward');\r\n return;\r\n case 'z-front':\r\n e?.preventDefault();\r\n this.deps.actions.zOrder('front');\r\n return;\r\n case 'z-back':\r\n e?.preventDefault();\r\n this.deps.actions.zOrder('back');\r\n return;\r\n case 'zoom-fit':\r\n e?.preventDefault();\r\n this.deps.actions.zoomToFit();\r\n return;\r\n case 'group':\r\n e?.preventDefault();\r\n this.deps.actions.group();\r\n return;\r\n case 'ungroup':\r\n e?.preventDefault();\r\n this.deps.actions.ungroup();\r\n return;\r\n case 'cut':\r\n e?.preventDefault();\r\n this.deps.actions.cut();\r\n return;\r\n case 'toggle-lock':\r\n e?.preventDefault();\r\n this.deps.actions.toggleLock();\r\n return;\r\n case 'rotate-cw':\r\n e?.preventDefault();\r\n this.deps.actions.rotate('cw');\r\n return;\r\n case 'rotate-ccw':\r\n e?.preventDefault();\r\n this.deps.actions.rotate('ccw');\r\n return;\r\n case 'zoom-in':\r\n e?.preventDefault();\r\n this.zoomByFactor(ZOOM_STEP);\r\n return;\r\n case 'zoom-out':\r\n e?.preventDefault();\r\n this.zoomByFactor(1 / ZOOM_STEP);\r\n return;\r\n case 'zoom-reset':\r\n e?.preventDefault();\r\n this.zoomToLevel(1);\r\n return;\r\n case 'nudge-left':\r\n case 'nudge-right':\r\n case 'nudge-up':\r\n case 'nudge-down': {\r\n const delta = NUDGE_DELTAS[action];\r\n if (delta && this.deps.actions.nudge(delta[0], delta[1], e?.shiftKey ?? false)) {\r\n e?.preventDefault();\r\n }\r\n return;\r\n }\r\n default:\r\n if (action.startsWith('tool:')) {\r\n if (this.deps.getIsToolActive()) return;\r\n e?.preventDefault();\r\n this.deps.getToolContext()?.switchTool?.(action.slice('tool:'.length));\r\n return;\r\n }\r\n console.warn(`[fieldnotes] unknown shortcut action \"${action}\"`);\r\n }\r\n }\r\n\r\n private isInScope(): boolean {\r\n if (this.deps.scope === 'window') return true;\r\n const active = document.activeElement;\r\n return active === this.deps.element || this.deps.element.contains(active);\r\n }\r\n}\r\n","export interface PanInertiaDeps {\r\n pan: (dx: number, dy: number) => void;\r\n now: () => number;\r\n requestFrame: (cb: () => void) => number;\r\n cancelFrame: (id: number) => void;\r\n enabled: () => boolean;\r\n}\r\n\r\n// Only the last VELOCITY_WINDOW_MS of drag samples count toward release velocity,\r\n// so a paused or slow finger at release does not produce a coast.\r\nconst VELOCITY_WINDOW_MS = 60;\r\nconst FRICTION = 0.92;\r\nconst MIN_START_SPEED = 2;\r\nconst MIN_STOP_SPEED = 0.3;\r\n\r\ninterface Sample {\r\n dx: number;\r\n dy: number;\r\n t: number;\r\n}\r\n\r\nexport class PanInertia {\r\n private samples: Sample[] = [];\r\n private vx = 0;\r\n private vy = 0;\r\n private rafId: number | null = null;\r\n\r\n constructor(private readonly deps: PanInertiaDeps) {}\r\n\r\n sample(dx: number, dy: number): void {\r\n const t = this.deps.now();\r\n this.samples.push({ dx, dy, t });\r\n this.prune(t);\r\n }\r\n\r\n release(): void {\r\n if (!this.deps.enabled()) {\r\n this.reset();\r\n return;\r\n }\r\n const t = this.deps.now();\r\n this.prune(t);\r\n const recent = this.samples;\r\n if (recent.length === 0) {\r\n this.reset();\r\n return;\r\n }\r\n let sx = 0;\r\n let sy = 0;\r\n for (const s of recent) {\r\n sx += s.dx;\r\n sy += s.dy;\r\n }\r\n this.vx = sx / recent.length;\r\n this.vy = sy / recent.length;\r\n this.samples = [];\r\n if (Math.hypot(this.vx, this.vy) < MIN_START_SPEED) {\r\n this.vx = 0;\r\n this.vy = 0;\r\n return;\r\n }\r\n this.rafId = this.deps.requestFrame(this.step);\r\n }\r\n\r\n cancel(): void {\r\n this.reset();\r\n }\r\n\r\n private step = (): void => {\r\n if (this.rafId === null) return;\r\n this.deps.pan(this.vx, this.vy);\r\n this.vx *= FRICTION;\r\n this.vy *= FRICTION;\r\n if (Math.hypot(this.vx, this.vy) >= MIN_STOP_SPEED) {\r\n this.rafId = this.deps.requestFrame(this.step);\r\n } else {\r\n this.reset();\r\n }\r\n };\r\n\r\n private prune(now: number): void {\r\n const cutoff = now - VELOCITY_WINDOW_MS;\r\n this.samples = this.samples.filter((s) => s.t >= cutoff);\r\n }\r\n\r\n private reset(): void {\r\n if (this.rafId !== null) {\r\n this.deps.cancelFrame(this.rafId);\r\n this.rafId = null;\r\n }\r\n this.samples = [];\r\n this.vx = 0;\r\n this.vy = 0;\r\n }\r\n}\r\n","import type { Point } from '../core/types';\r\nimport type { Camera } from './camera';\r\nimport type { ToolManager } from '../tools/tool-manager';\r\nimport type { ToolContext, PointerState } from '../tools/types';\r\nimport type { HistoryRecorder } from '../history/history-recorder';\r\nimport type { HistoryStack } from '../history/history-stack';\r\nimport type { ShortcutOptions, ShortcutsApi } from './shortcut-map';\r\nimport type { RotateDirection } from './selection-rotate';\r\nimport { InputFilter } from './input-filter';\r\nimport { KeyboardActions } from './keyboard-actions';\r\nimport { KeyboardHandler } from './keyboard-handler';\r\nimport { PanInertia } from './pan-inertia';\r\n\r\nconst ZOOM_SENSITIVITY = 0.001;\r\nconst MIDDLE_BUTTON = 1;\r\nconst LONG_PRESS_MS = 500;\r\n\r\nexport interface InputHandlerOptions {\r\n toolManager?: ToolManager;\r\n toolContext?: ToolContext;\r\n historyRecorder?: HistoryRecorder;\r\n historyStack?: HistoryStack;\r\n fitToContent?: () => void;\r\n group?: () => void;\r\n ungroup?: () => void;\r\n toggleLock?: () => void;\r\n rotate?: (direction: RotateDirection) => void;\r\n openContextMenu?: (screenPos: Point, world: Point) => void;\r\n shortcuts?: ShortcutOptions;\r\n addImage?: (src: string, world: { x: number; y: number }) => string;\r\n getCenteredWorld?: () => { x: number; y: number };\r\n onPaste?: (event: ClipboardEvent, worldPosition: { x: number; y: number }) => void;\r\n panInertia?: boolean;\r\n}\r\n\r\nexport class InputHandler {\r\n private isPanning = false;\r\n private lastPointer = { x: 0, y: 0 };\r\n private spaceHeld = false;\r\n private activePointers = new Map<number, { x: number; y: number }>();\r\n private lastPinchDistance = 0;\r\n private lastPinchCenter = { x: 0, y: 0 };\r\n private toolManager: ToolManager | null;\r\n private toolContext: ToolContext | null;\r\n private historyRecorder: HistoryRecorder | null;\r\n private historyStack: HistoryStack | null;\r\n private isToolActive = false;\r\n private lastPointerEvent: PointerEvent | null = null;\r\n private readonly inputFilter = new InputFilter();\r\n private deferredDown: PointerEvent | null = null;\r\n private longPressTimer: ReturnType<typeof setTimeout> | null = null;\r\n private longPressStart: { x: number; y: number } | null = null;\r\n private readonly abortController = new AbortController();\r\n private readonly actions: KeyboardActions;\r\n private readonly keyboard: KeyboardHandler;\r\n private readonly scope: 'focus' | 'window';\r\n private readonly openContextMenu?: (screenPos: Point, world: Point) => void;\r\n private readonly panInertia: PanInertia;\r\n private readonly panInertiaEnabled: boolean;\r\n\r\n constructor(\r\n private readonly element: HTMLElement,\r\n private readonly camera: Camera,\r\n options: InputHandlerOptions = {},\r\n ) {\r\n this.toolManager = options.toolManager ?? null;\r\n this.toolContext = options.toolContext ?? null;\r\n this.historyRecorder = options.historyRecorder ?? null;\r\n this.historyStack = options.historyStack ?? null;\r\n this.actions = new KeyboardActions({\r\n getToolManager: () => this.toolManager,\r\n getToolContext: () => this.toolContext,\r\n getHistoryRecorder: () => this.historyRecorder,\r\n getHistoryStack: () => this.historyStack,\r\n isToolActive: () => this.isToolActive,\r\n fitToContent: options.fitToContent,\r\n group: options.group,\r\n ungroup: options.ungroup,\r\n toggleLock: options.toggleLock,\r\n rotate: options.rotate,\r\n getLastPointerWorld: () => this.lastPointerWorld(),\r\n });\r\n this.openContextMenu = options.openContextMenu;\r\n this.panInertiaEnabled = options.panInertia ?? true;\r\n this.panInertia = new PanInertia({\r\n pan: (dx, dy) => this.camera.pan(dx, dy),\r\n now: () => (typeof performance !== 'undefined' ? performance.now() : Date.now()),\r\n requestFrame: (cb) =>\r\n typeof requestAnimationFrame !== 'undefined' ? requestAnimationFrame(cb) : 0,\r\n cancelFrame: (id) => {\r\n if (typeof cancelAnimationFrame !== 'undefined') cancelAnimationFrame(id);\r\n },\r\n enabled: () => this.panInertiaEnabled,\r\n });\r\n this.scope = options.shortcuts?.scope ?? 'focus';\r\n this.keyboard = new KeyboardHandler({\r\n element: this.element,\r\n camera: this.camera,\r\n actions: this.actions,\r\n scope: this.scope,\r\n shortcuts: options.shortcuts,\r\n abortSignal: this.abortController.signal,\r\n getToolContext: () => this.toolContext,\r\n getIsToolActive: () => this.isToolActive,\r\n getLastPointerEvent: () => this.lastPointerEvent,\r\n setSpaceHeld: (v) => {\r\n this.spaceHeld = v;\r\n },\r\n getActivePointerCount: () => this.activePointers.size,\r\n dispatchToolHover: (e) => this.dispatchToolHover(e),\r\n addImage: options.addImage ?? (() => ''),\r\n getLastPointerWorld: () => this.lastPointerWorld(),\r\n getCenteredWorld: options.getCenteredWorld ?? (() => ({ x: 0, y: 0 })),\r\n onPaste: options.onPaste,\r\n });\r\n this.element.style.touchAction = 'none';\r\n if (this.scope === 'focus') {\r\n this.element.tabIndex = 0;\r\n // Suppressed like other canvas SDKs; consumers needing a focus ring style their container.\r\n this.element.style.outline = 'none';\r\n }\r\n this.bind();\r\n }\r\n\r\n setToolManager(toolManager: ToolManager, toolContext: ToolContext): void {\r\n this.toolManager = toolManager;\r\n this.toolContext = toolContext;\r\n }\r\n\r\n flushPendingHistory(): void {\r\n this.actions.flushPendingNudge();\r\n }\r\n\r\n get shortcuts(): ShortcutsApi {\r\n return this.keyboard.shortcuts;\r\n }\r\n\r\n destroy(): void {\r\n this.panInertia.cancel();\r\n this.actions.dispose();\r\n this.abortController.abort();\r\n this.inputFilter.reset();\r\n this.cancelLongPress();\r\n this.deferredDown = null;\r\n this.lastPointerEvent = null;\r\n if (this.scope === 'focus') {\r\n this.element.removeAttribute('tabindex');\r\n this.element.style.outline = '';\r\n }\r\n }\r\n\r\n private bind(): void {\r\n const opts = { signal: this.abortController.signal };\r\n\r\n this.element.addEventListener('wheel', this.onWheel, { ...opts, passive: false });\r\n this.element.addEventListener('pointerdown', this.onPointerDown, opts);\r\n this.element.addEventListener('pointermove', this.onPointerMove, opts);\r\n this.element.addEventListener('pointerup', this.onPointerUp, opts);\r\n this.element.addEventListener('pointerleave', this.onPointerLeave, opts);\r\n this.element.addEventListener('pointercancel', this.onPointerUp, opts);\r\n this.element.addEventListener('contextmenu', this.onContextMenu, opts);\r\n }\r\n\r\n private onWheel = (e: WheelEvent): void => {\r\n e.preventDefault();\r\n this.panInertia.cancel();\r\n const rect = this.element.getBoundingClientRect();\r\n const zoomFactor = 1 - e.deltaY * ZOOM_SENSITIVITY;\r\n const newZoom = this.camera.zoom * zoomFactor;\r\n this.camera.zoomAt(newZoom, {\r\n x: e.clientX - rect.left,\r\n y: e.clientY - rect.top,\r\n });\r\n };\r\n\r\n private onPointerDown = (e: PointerEvent): void => {\r\n this.panInertia.cancel();\r\n this.focusSelf();\r\n this.activePointers.set(e.pointerId, { x: e.clientX, y: e.clientY });\r\n\r\n this.element.setPointerCapture?.(e.pointerId);\r\n\r\n if (this.activePointers.size === 2) {\r\n this.cancelLongPress();\r\n this.startPinch();\r\n this.cancelToolIfActive(e);\r\n return;\r\n }\r\n\r\n if (e.button === MIDDLE_BUTTON || (e.button === 0 && this.spaceHeld)) {\r\n this.cancelLongPress();\r\n this.isPanning = true;\r\n this.lastPointer = { x: e.clientX, y: e.clientY };\r\n return;\r\n }\r\n\r\n if (\r\n this.activePointers.size === 1 &&\r\n (e.button === 0 || e.pointerType === 'touch' || e.pointerType === 'pen')\r\n ) {\r\n const result = this.inputFilter.filterDown(e);\r\n if (result.action === 'suppress') return;\r\n if (result.action === 'defer') {\r\n this.deferredDown = e;\r\n this.startLongPress(e);\r\n return;\r\n }\r\n this.dispatchToolDown(e);\r\n }\r\n };\r\n\r\n private onPointerMove = (e: PointerEvent): void => {\r\n this.lastPointerEvent = e;\r\n\r\n if (this.activePointers.has(e.pointerId)) {\r\n this.activePointers.set(e.pointerId, { x: e.clientX, y: e.clientY });\r\n }\r\n\r\n if (this.activePointers.size >= 2) {\r\n this.handlePinchMove();\r\n return;\r\n }\r\n\r\n if (this.isPanning) {\r\n const dx = e.clientX - this.lastPointer.x;\r\n const dy = e.clientY - this.lastPointer.y;\r\n this.lastPointer = { x: e.clientX, y: e.clientY };\r\n this.camera.pan(dx, dy);\r\n this.panInertia.sample(dx, dy);\r\n return;\r\n }\r\n\r\n if (e.pointerType === 'pen' && !this.activePointers.has(e.pointerId)) {\r\n this.dispatchToolHover(e);\r\n } else if (this.isToolActive) {\r\n this.dispatchToolMove(e);\r\n } else if (this.deferredDown) {\r\n const result = this.inputFilter.filterMove(e);\r\n if (result.action === 'dispatch') {\r\n this.cancelLongPress();\r\n this.dispatchToolDown(this.deferredDown);\r\n this.deferredDown = null;\r\n this.dispatchToolMove(e);\r\n }\r\n } else if (this.activePointers.size === 0) {\r\n this.dispatchToolHover(e);\r\n }\r\n };\r\n\r\n private onPointerUp = (e: PointerEvent): void => {\r\n this.cancelLongPress();\r\n try {\r\n this.element.releasePointerCapture(e.pointerId);\r\n } catch {\r\n // Already released (e.g., pointercancel fired first)\r\n }\r\n const removedActivePointer = this.activePointers.delete(e.pointerId);\r\n\r\n if (removedActivePointer && this.activePointers.size >= 2) {\r\n // Pointer membership may have changed the first-two navigation pair. Rebaseline before the\r\n // next move so the replacement pointer cannot produce a discontinuous pan or zoom.\r\n this.startPinch();\r\n } else if (this.activePointers.size < 2) {\r\n this.lastPinchDistance = 0;\r\n const remainingPointer = this.activePointers.values().next().value;\r\n if (remainingPointer && this.isPanning) {\r\n this.lastPointer = { ...remainingPointer };\r\n }\r\n }\r\n\r\n if (this.isPanning && this.activePointers.size === 0) {\r\n this.isPanning = false;\r\n this.panInertia.release();\r\n }\r\n\r\n const upResult = this.inputFilter.filterUp(e);\r\n\r\n if (this.isToolActive) {\r\n this.dispatchToolUp(e);\r\n this.isToolActive = false;\r\n } else if (this.deferredDown && upResult.pendingTap) {\r\n this.dispatchToolDown(this.deferredDown);\r\n this.dispatchToolUp(e);\r\n this.deferredDown = null;\r\n } else {\r\n this.deferredDown = null;\r\n }\r\n };\r\n\r\n runAction(action: string, e?: KeyboardEvent): void {\r\n this.keyboard.runAction(action, e);\r\n }\r\n\r\n hasClipboard(): boolean {\r\n return this.actions.hasClipboard();\r\n }\r\n\r\n private startPinch(): void {\r\n this.panInertia.cancel();\r\n this.cancelLongPress();\r\n this.inputFilter.reset();\r\n this.deferredDown = null;\r\n this.isPanning = true;\r\n const [a, b] = this.getPinchPoints();\r\n this.lastPinchDistance = this.distance(a, b);\r\n this.lastPinchCenter = this.midpoint(a, b);\r\n this.lastPointer = { ...this.lastPinchCenter };\r\n }\r\n\r\n private handlePinchMove(): void {\r\n const [a, b] = this.getPinchPoints();\r\n const dist = this.distance(a, b);\r\n const center = this.midpoint(a, b);\r\n\r\n if (this.lastPinchDistance > 0) {\r\n const scale = dist / this.lastPinchDistance;\r\n const newZoom = this.camera.zoom * scale;\r\n const rect = this.element.getBoundingClientRect();\r\n this.camera.zoomAt(newZoom, {\r\n x: center.x - rect.left,\r\n y: center.y - rect.top,\r\n });\r\n }\r\n\r\n const dx = center.x - this.lastPointer.x;\r\n const dy = center.y - this.lastPointer.y;\r\n this.camera.pan(dx, dy);\r\n this.panInertia.sample(dx, dy);\r\n\r\n this.lastPinchDistance = dist;\r\n this.lastPinchCenter = center;\r\n this.lastPointer = { ...center };\r\n }\r\n\r\n private getPinchPoints(): [{ x: number; y: number }, { x: number; y: number }] {\r\n const pts = [...this.activePointers.values()];\r\n return [pts[0] ?? { x: 0, y: 0 }, pts[1] ?? { x: 0, y: 0 }];\r\n }\r\n\r\n private distance(a: { x: number; y: number }, b: { x: number; y: number }): number {\r\n const dx = a.x - b.x;\r\n const dy = a.y - b.y;\r\n return Math.sqrt(dx * dx + dy * dy);\r\n }\r\n\r\n private midpoint(\r\n a: { x: number; y: number },\r\n b: { x: number; y: number },\r\n ): { x: number; y: number } {\r\n return { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 };\r\n }\r\n\r\n private lastPointerWorld(): { x: number; y: number } | null {\r\n const e = this.lastPointerEvent;\r\n if (!e) return null;\r\n const rect = this.element.getBoundingClientRect();\r\n return this.camera.screenToWorld({ x: e.clientX - rect.left, y: e.clientY - rect.top });\r\n }\r\n\r\n private onContextMenu = (e: MouseEvent): void => {\r\n e.preventDefault();\r\n if (this.toolManager?.activeTool?.name !== 'select') return;\r\n const rect = this.element.getBoundingClientRect();\r\n const world = this.camera.screenToWorld({ x: e.clientX - rect.left, y: e.clientY - rect.top });\r\n this.openContextMenu?.({ x: e.clientX, y: e.clientY }, world);\r\n };\r\n\r\n private onPointerLeave = (e: PointerEvent): void => {\r\n this.lastPointerEvent = null;\r\n this.onPointerUp(e);\r\n };\r\n\r\n private toPointerState(e: PointerEvent): PointerState {\r\n const rect = this.element.getBoundingClientRect();\r\n return {\r\n x: e.clientX - rect.left,\r\n y: e.clientY - rect.top,\r\n pressure: e.pressure,\r\n pointerType: e.pointerType === 'touch' || e.pointerType === 'pen' ? e.pointerType : 'mouse',\r\n shiftKey: e.shiftKey,\r\n };\r\n }\r\n\r\n private dispatchToolDown(e: PointerEvent): void {\r\n if (!this.toolManager || !this.toolContext) return;\r\n this.actions.flushPendingNudge();\r\n this.historyRecorder?.begin();\r\n this.isToolActive = true;\r\n this.toolManager.handlePointerDown(this.toPointerState(e), this.toolContext);\r\n }\r\n\r\n private dispatchToolMove(e: PointerEvent): void {\r\n if (!this.toolManager || !this.toolContext) return;\r\n this.toolManager.handlePointerMove(this.toPointerState(e), this.toolContext);\r\n }\r\n\r\n private dispatchToolHover(e: PointerEvent): void {\r\n if (!this.toolManager?.activeTool || !this.toolContext) return;\r\n const tool = this.toolManager.activeTool;\r\n if (tool.onHover) {\r\n tool.onHover(this.toPointerState(e), this.toolContext);\r\n }\r\n }\r\n\r\n private dispatchToolUp(e: PointerEvent): void {\r\n if (!this.toolManager || !this.toolContext) return;\r\n this.toolManager.handlePointerUp(this.toPointerState(e), this.toolContext);\r\n this.historyRecorder?.commit();\r\n }\r\n\r\n private isInScope(): boolean {\r\n if (this.scope === 'window') return true;\r\n const active = document.activeElement;\r\n return active === this.element || this.element.contains(active);\r\n }\r\n\r\n private focusSelf(): void {\r\n if (this.scope !== 'focus' || this.isInScope()) return;\r\n this.element.focus({ preventScroll: true });\r\n }\r\n\r\n private cancelToolIfActive(e: PointerEvent): void {\r\n this.cancelLongPress();\r\n if (this.isToolActive) {\r\n this.dispatchToolUp(e);\r\n this.isToolActive = false;\r\n }\r\n this.deferredDown = null;\r\n }\r\n\r\n private startLongPress(e: PointerEvent): void {\r\n if (e.pointerType !== 'touch') return;\r\n if (this.toolManager?.activeTool?.name !== 'select') return;\r\n this.longPressStart = { x: e.clientX, y: e.clientY };\r\n this.longPressTimer = setTimeout(() => this.fireLongPress(), LONG_PRESS_MS);\r\n }\r\n\r\n private cancelLongPress(): void {\r\n if (this.longPressTimer !== null) {\r\n clearTimeout(this.longPressTimer);\r\n this.longPressTimer = null;\r\n }\r\n this.longPressStart = null;\r\n }\r\n\r\n private fireLongPress(): void {\r\n this.longPressTimer = null;\r\n if (!this.deferredDown || this.activePointers.size !== 1 || this.isPanning) return;\r\n const start = this.longPressStart;\r\n if (!start) return;\r\n const rect = this.element.getBoundingClientRect();\r\n const world = this.camera.screenToWorld({ x: start.x - rect.left, y: start.y - rect.top });\r\n this.deferredDown = null;\r\n this.openContextMenu?.({ x: start.x, y: start.y }, world);\r\n }\r\n}\r\n","import type { Camera } from './camera';\r\n\r\nexport type BackgroundPattern = 'dots' | 'grid' | 'none';\r\n\r\nexport interface BackgroundOptions {\r\n pattern?: BackgroundPattern;\r\n spacing?: number;\r\n color?: string;\r\n dotRadius?: number;\r\n lineWidth?: number;\r\n}\r\n\r\nconst MIN_PATTERN_SPACING = 16;\r\n\r\nconst DEFAULTS = {\r\n pattern: 'dots' as BackgroundPattern,\r\n spacing: 24,\r\n color: '#d0d0d0',\r\n dotRadius: 1,\r\n lineWidth: 0.5,\r\n};\r\n\r\nexport class Background {\r\n private readonly pattern: BackgroundPattern;\r\n private readonly spacing: number;\r\n private readonly color: string;\r\n private readonly dotRadius: number;\r\n private readonly lineWidth: number;\r\n private cachedCanvas: OffscreenCanvas | HTMLCanvasElement | null = null;\r\n private cachedCtx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D | null = null;\r\n private lastZoom = -1;\r\n private lastOffsetX = -Infinity;\r\n private lastOffsetY = -Infinity;\r\n private lastWidth = 0;\r\n private lastHeight = 0;\r\n\r\n constructor(options: BackgroundOptions = {}) {\r\n this.pattern = options.pattern ?? DEFAULTS.pattern;\r\n this.spacing = options.spacing ?? DEFAULTS.spacing;\r\n this.color = options.color ?? DEFAULTS.color;\r\n this.dotRadius = options.dotRadius ?? DEFAULTS.dotRadius;\r\n this.lineWidth = options.lineWidth ?? DEFAULTS.lineWidth;\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, camera: Camera): void {\r\n const { width, height } = ctx.canvas;\r\n const dpr = typeof devicePixelRatio !== 'undefined' ? devicePixelRatio : 1;\r\n const cssWidth = width / dpr;\r\n const cssHeight = height / dpr;\r\n\r\n ctx.save();\r\n ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\r\n ctx.clearRect(0, 0, cssWidth, cssHeight);\r\n\r\n if (this.pattern === 'none') {\r\n ctx.restore();\r\n return;\r\n }\r\n\r\n const spacing = this.adaptSpacing(this.spacing, camera.zoom);\r\n const keyZoom = camera.zoom;\r\n const keyX = Math.floor(camera.position.x % spacing);\r\n const keyY = Math.floor(camera.position.y % spacing);\r\n\r\n if (\r\n this.cachedCanvas !== null &&\r\n keyZoom === this.lastZoom &&\r\n keyX === this.lastOffsetX &&\r\n keyY === this.lastOffsetY &&\r\n cssWidth === this.lastWidth &&\r\n cssHeight === this.lastHeight\r\n ) {\r\n ctx.drawImage(this.cachedCanvas as CanvasImageSource, 0, 0);\r\n ctx.restore();\r\n return;\r\n }\r\n\r\n this.ensureCachedCanvas(cssWidth, cssHeight, dpr);\r\n\r\n if (this.cachedCtx === null) {\r\n // Fallback: render directly when offscreen canvas is unavailable (e.g. jsdom)\r\n if (this.pattern === 'dots') {\r\n this.renderDots(ctx, camera, cssWidth, cssHeight);\r\n } else if (this.pattern === 'grid') {\r\n this.renderGrid(ctx, camera, cssWidth, cssHeight);\r\n }\r\n ctx.restore();\r\n return;\r\n }\r\n\r\n const offCtx = this.cachedCtx as CanvasRenderingContext2D;\r\n offCtx.clearRect(0, 0, cssWidth, cssHeight);\r\n if (this.pattern === 'dots') {\r\n this.renderDots(offCtx, camera, cssWidth, cssHeight);\r\n } else if (this.pattern === 'grid') {\r\n this.renderGrid(offCtx, camera, cssWidth, cssHeight);\r\n }\r\n\r\n this.lastZoom = keyZoom;\r\n this.lastOffsetX = keyX;\r\n this.lastOffsetY = keyY;\r\n this.lastWidth = cssWidth;\r\n this.lastHeight = cssHeight;\r\n\r\n ctx.drawImage(this.cachedCanvas as CanvasImageSource, 0, 0);\r\n ctx.restore();\r\n }\r\n\r\n private ensureCachedCanvas(cssWidth: number, cssHeight: number, dpr: number): void {\r\n if (\r\n this.cachedCanvas !== null &&\r\n this.lastWidth === cssWidth &&\r\n this.lastHeight === cssHeight\r\n ) {\r\n return;\r\n }\r\n\r\n const physWidth = Math.round(cssWidth * dpr);\r\n const physHeight = Math.round(cssHeight * dpr);\r\n\r\n if (typeof OffscreenCanvas !== 'undefined') {\r\n this.cachedCanvas = new OffscreenCanvas(physWidth, physHeight);\r\n } else if (typeof document !== 'undefined') {\r\n const el = document.createElement('canvas');\r\n el.width = physWidth;\r\n el.height = physHeight;\r\n this.cachedCanvas = el;\r\n } else {\r\n // No offscreen canvas support available; fall back to direct rendering\r\n this.cachedCanvas = null;\r\n this.cachedCtx = null;\r\n return;\r\n }\r\n\r\n const offCtx = this.cachedCanvas.getContext('2d');\r\n if (offCtx !== null) {\r\n (offCtx as CanvasRenderingContext2D).scale(dpr, dpr);\r\n }\r\n this.cachedCtx = offCtx as CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D | null;\r\n\r\n // Force re-render on next frame since canvas was recreated\r\n this.lastZoom = -1;\r\n }\r\n\r\n private adaptSpacing(baseSpacing: number, zoom: number): number {\r\n let spacing = baseSpacing * zoom;\r\n while (spacing < MIN_PATTERN_SPACING) {\r\n spacing *= 2;\r\n }\r\n return spacing;\r\n }\r\n\r\n private renderDots(\r\n ctx: CanvasRenderingContext2D,\r\n camera: Camera,\r\n width: number,\r\n height: number,\r\n ): void {\r\n const spacing = this.adaptSpacing(this.spacing, camera.zoom);\r\n const offsetX = camera.position.x % spacing;\r\n const offsetY = camera.position.y % spacing;\r\n const radius = this.dotRadius * Math.min(camera.zoom, 2);\r\n\r\n ctx.fillStyle = this.color;\r\n ctx.beginPath();\r\n\r\n for (let x = offsetX; x < width; x += spacing) {\r\n for (let y = offsetY; y < height; y += spacing) {\r\n ctx.moveTo(x + radius, y);\r\n ctx.arc(x, y, radius, 0, Math.PI * 2);\r\n }\r\n }\r\n\r\n ctx.fill();\r\n }\r\n\r\n private renderGrid(\r\n ctx: CanvasRenderingContext2D,\r\n camera: Camera,\r\n width: number,\r\n height: number,\r\n ): void {\r\n const spacing = this.adaptSpacing(this.spacing, camera.zoom);\r\n const offsetX = camera.position.x % spacing;\r\n const offsetY = camera.position.y % spacing;\r\n const lineW = this.lineWidth * Math.min(camera.zoom, 2);\r\n\r\n ctx.fillStyle = this.color;\r\n\r\n for (let x = offsetX; x < width; x += spacing) {\r\n ctx.fillRect(x, 0, lineW, height);\r\n }\r\n\r\n for (let y = offsetY; y < height; y += spacing) {\r\n ctx.fillRect(0, y, width, lineW);\r\n }\r\n }\r\n}\r\n","export interface EventMeta {\r\n origin?: string;\r\n}\r\n\r\nconst EMPTY_META: EventMeta = Object.freeze({});\r\n\r\ntype Listener<T> = (data: T, meta: EventMeta) => void;\r\n\r\nexport class EventBus<TEvents extends { [K in keyof TEvents]: TEvents[K] }> {\r\n private listeners = new Map<keyof TEvents, Set<Listener<never>>>();\r\n\r\n on<K extends keyof TEvents>(event: K, listener: Listener<TEvents[K]>): () => void {\r\n const existing = this.listeners.get(event);\r\n if (existing) {\r\n existing.add(listener as Listener<never>);\r\n } else {\r\n const set = new Set<Listener<never>>([listener as Listener<never>]);\r\n this.listeners.set(event, set);\r\n }\r\n return () => this.off(event, listener);\r\n }\r\n\r\n off<K extends keyof TEvents>(event: K, listener: Listener<TEvents[K]>): void {\r\n this.listeners.get(event)?.delete(listener as Listener<never>);\r\n }\r\n\r\n emit<K extends keyof TEvents>(event: K, data: TEvents[K], meta: EventMeta = EMPTY_META): void {\r\n this.listeners.get(event)?.forEach((listener) => {\r\n try {\r\n listener(data as never, meta);\r\n } catch (err) {\r\n console.error(`[fieldnotes] listener error for \"${String(event)}\"`, err);\r\n }\r\n });\r\n }\r\n\r\n clear(): void {\r\n this.listeners.clear();\r\n }\r\n}\r\n","import type { Bounds, Point } from './types';\r\n\r\ninterface Entry {\r\n id: string;\r\n bounds: Bounds;\r\n}\r\n\r\nconst MAX_ITEMS = 8;\r\nconst MAX_DEPTH = 8;\r\n\r\nfunction intersects(a: Bounds, b: Bounds): boolean {\r\n return a.x <= b.x + b.w && a.x + a.w >= b.x && a.y <= b.y + b.h && a.y + a.h >= b.y;\r\n}\r\n\r\nfunction contains(outer: Bounds, inner: Bounds): boolean {\r\n return (\r\n inner.x >= outer.x &&\r\n inner.x + inner.w <= outer.x + outer.w &&\r\n inner.y >= outer.y &&\r\n inner.y + inner.h <= outer.y + outer.h\r\n );\r\n}\r\n\r\nclass QuadNode {\r\n items: Entry[] = [];\r\n children: QuadNode[] | null = null;\r\n\r\n constructor(\r\n readonly bounds: Bounds,\r\n readonly depth: number,\r\n ) {}\r\n\r\n insert(entry: Entry): void {\r\n if (this.children) {\r\n const idx = this.getChildIndex(entry.bounds);\r\n if (idx !== -1) {\r\n const child = this.children[idx];\r\n if (child) child.insert(entry);\r\n return;\r\n }\r\n this.items.push(entry);\r\n return;\r\n }\r\n\r\n this.items.push(entry);\r\n\r\n if (this.items.length > MAX_ITEMS && this.depth < MAX_DEPTH) {\r\n this.split();\r\n }\r\n }\r\n\r\n remove(id: string): boolean {\r\n const idx = this.items.findIndex((e) => e.id === id);\r\n if (idx !== -1) {\r\n this.items.splice(idx, 1);\r\n return true;\r\n }\r\n\r\n if (this.children) {\r\n for (const child of this.children) {\r\n if (child.remove(id)) {\r\n this.collapseIfEmpty();\r\n return true;\r\n }\r\n }\r\n }\r\n\r\n return false;\r\n }\r\n\r\n query(rect: Bounds, result: string[]): void {\r\n if (!intersects(this.bounds, rect)) return;\r\n\r\n for (const item of this.items) {\r\n if (intersects(item.bounds, rect)) {\r\n result.push(item.id);\r\n }\r\n }\r\n\r\n if (this.children) {\r\n for (const child of this.children) {\r\n child.query(rect, result);\r\n }\r\n }\r\n }\r\n\r\n collect(result: Entry[]): void {\r\n result.push(...this.items);\r\n if (this.children) {\r\n for (const child of this.children) {\r\n child.collect(result);\r\n }\r\n }\r\n }\r\n\r\n private getChildIndex(itemBounds: Bounds): number {\r\n const midX = this.bounds.x + this.bounds.w / 2;\r\n const midY = this.bounds.y + this.bounds.h / 2;\r\n\r\n const left = itemBounds.x >= this.bounds.x && itemBounds.x + itemBounds.w <= midX;\r\n const right =\r\n itemBounds.x >= midX && itemBounds.x + itemBounds.w <= this.bounds.x + this.bounds.w;\r\n const top = itemBounds.y >= this.bounds.y && itemBounds.y + itemBounds.h <= midY;\r\n const bottom =\r\n itemBounds.y >= midY && itemBounds.y + itemBounds.h <= this.bounds.y + this.bounds.h;\r\n\r\n if (left && top) return 0;\r\n if (right && top) return 1;\r\n if (left && bottom) return 2;\r\n if (right && bottom) return 3;\r\n\r\n return -1;\r\n }\r\n\r\n private split(): void {\r\n const { x, y, w, h } = this.bounds;\r\n const halfW = w / 2;\r\n const halfH = h / 2;\r\n const d = this.depth + 1;\r\n\r\n this.children = [\r\n new QuadNode({ x, y, w: halfW, h: halfH }, d),\r\n new QuadNode({ x: x + halfW, y, w: halfW, h: halfH }, d),\r\n new QuadNode({ x, y: y + halfH, w: halfW, h: halfH }, d),\r\n new QuadNode({ x: x + halfW, y: y + halfH, w: halfW, h: halfH }, d),\r\n ];\r\n\r\n const remaining: Entry[] = [];\r\n for (const item of this.items) {\r\n const idx = this.getChildIndex(item.bounds);\r\n if (idx !== -1) {\r\n const target = this.children[idx];\r\n if (target) target.insert(item);\r\n } else {\r\n remaining.push(item);\r\n }\r\n }\r\n this.items = remaining;\r\n }\r\n\r\n private collapseIfEmpty(): void {\r\n if (!this.children) return;\r\n let totalItems = this.items.length;\r\n for (const child of this.children) {\r\n if (child.children) return;\r\n totalItems += child.items.length;\r\n }\r\n if (totalItems <= MAX_ITEMS) {\r\n for (const child of this.children) {\r\n this.items.push(...child.items);\r\n }\r\n this.children = null;\r\n }\r\n }\r\n}\r\n\r\nexport class Quadtree {\r\n private root: QuadNode;\r\n private _size = 0;\r\n private readonly worldBounds: Bounds;\r\n\r\n constructor(worldBounds: Bounds) {\r\n this.worldBounds = worldBounds;\r\n this.root = new QuadNode(worldBounds, 0);\r\n }\r\n\r\n get size(): number {\r\n return this._size;\r\n }\r\n\r\n insert(id: string, bounds: Bounds): void {\r\n this.expandToFit(bounds);\r\n this.root.insert({ id, bounds });\r\n this._size++;\r\n }\r\n\r\n remove(id: string): void {\r\n if (this.root.remove(id)) {\r\n this._size--;\r\n }\r\n }\r\n\r\n update(id: string, newBounds: Bounds): void {\r\n this.remove(id);\r\n this.insert(id, newBounds);\r\n }\r\n\r\n query(rect: Bounds): string[] {\r\n const result: string[] = [];\r\n this.root.query(rect, result);\r\n return result;\r\n }\r\n\r\n queryPoint(point: Point): string[] {\r\n return this.query({ x: point.x, y: point.y, w: 0, h: 0 });\r\n }\r\n\r\n clear(): void {\r\n this.root = new QuadNode(this.worldBounds, 0);\r\n this._size = 0;\r\n }\r\n\r\n private expandToFit(bounds: Bounds): void {\r\n const current = this.root.bounds;\r\n if (contains(current, bounds)) return;\r\n\r\n const currentRight = current.x + current.w;\r\n const currentBottom = current.y + current.h;\r\n const requiredWidth =\r\n Math.max(currentRight, bounds.x + bounds.w) - Math.min(current.x, bounds.x);\r\n const requiredHeight =\r\n Math.max(currentBottom, bounds.y + bounds.h) - Math.min(current.y, bounds.y);\r\n const width = Math.max(current.w * 2, requiredWidth);\r\n const height = Math.max(current.h * 2, requiredHeight);\r\n const x = bounds.x < current.x ? currentRight - width : current.x;\r\n const y = bounds.y < current.y ? currentBottom - height : current.y;\r\n\r\n const entries: Entry[] = [];\r\n this.root.collect(entries);\r\n this.root = new QuadNode({ x, y, w: width, h: height }, 0);\r\n for (const entry of entries) {\r\n this.root.insert(entry);\r\n }\r\n }\r\n}\r\n","import type { Point, StrokePoint } from '../core/types';\r\n\r\nexport interface CurveSegment {\r\n start: StrokePoint;\r\n cp1: Point;\r\n cp2: Point;\r\n end: StrokePoint;\r\n}\r\n\r\nconst MIN_PRESSURE_SCALE = 0.4;\r\nconst MAX_PRESSURE_SCALE = 1.8;\r\n\r\nexport function pressureToWidth(pressure: number, baseWidth: number): number {\r\n return baseWidth * (MIN_PRESSURE_SCALE + (MAX_PRESSURE_SCALE - MIN_PRESSURE_SCALE) * pressure);\r\n}\r\n\r\nexport function simplifyPoints(points: StrokePoint[], tolerance: number): StrokePoint[] {\r\n if (points.length <= 2) return points.slice();\r\n return rdp(points, 0, points.length - 1, tolerance);\r\n}\r\n\r\nfunction rdp(points: StrokePoint[], start: number, end: number, tolerance: number): StrokePoint[] {\r\n const first = points[start];\r\n const last = points[end];\r\n if (!first || !last) return [];\r\n\r\n if (end - start <= 1) return [first, last];\r\n\r\n let maxDist = 0;\r\n let maxIndex = start;\r\n\r\n for (let i = start + 1; i < end; i++) {\r\n const pt = points[i];\r\n if (!pt) continue;\r\n const dist = perpendicularDistance(pt, first, last);\r\n if (dist > maxDist) {\r\n maxDist = dist;\r\n maxIndex = i;\r\n }\r\n }\r\n\r\n if (maxDist <= tolerance) return [first, last];\r\n\r\n const left = rdp(points, start, maxIndex, tolerance);\r\n const right = rdp(points, maxIndex, end, tolerance);\r\n\r\n return left.concat(right.slice(1));\r\n}\r\n\r\nfunction perpendicularDistance(pt: Point, lineStart: Point, lineEnd: Point): number {\r\n const dx = lineEnd.x - lineStart.x;\r\n const dy = lineEnd.y - lineStart.y;\r\n const lenSq = dx * dx + dy * dy;\r\n\r\n if (lenSq === 0) {\r\n const ex = pt.x - lineStart.x;\r\n const ey = pt.y - lineStart.y;\r\n return Math.sqrt(ex * ex + ey * ey);\r\n }\r\n\r\n const num = Math.abs(dy * pt.x - dx * pt.y + lineEnd.x * lineStart.y - lineEnd.y * lineStart.x);\r\n return num / Math.sqrt(lenSq);\r\n}\r\n\r\nexport function smoothToSegments(points: StrokePoint[]): CurveSegment[] {\r\n if (points.length < 2) return [];\r\n\r\n if (points.length === 2) {\r\n const p0 = points[0];\r\n const p1 = points[1];\r\n if (!p0 || !p1) return [];\r\n const mx = (p0.x + p1.x) / 2;\r\n const my = (p0.y + p1.y) / 2;\r\n return [{ start: p0, cp1: { x: mx, y: my }, cp2: { x: mx, y: my }, end: p1 }];\r\n }\r\n\r\n const segments: CurveSegment[] = [];\r\n const n = points.length;\r\n\r\n for (let i = 0; i < n - 1; i++) {\r\n const p0 = points[Math.max(0, i - 1)];\r\n const p1 = points[i];\r\n const p2 = points[i + 1];\r\n const p3 = points[Math.min(n - 1, i + 2)];\r\n if (!p0 || !p1 || !p2 || !p3) continue;\r\n\r\n const cp1: Point = {\r\n x: p1.x + (p2.x - p0.x) / 6,\r\n y: p1.y + (p2.y - p0.y) / 6,\r\n };\r\n const cp2: Point = {\r\n x: p2.x - (p3.x - p1.x) / 6,\r\n y: p2.y - (p3.y - p1.y) / 6,\r\n };\r\n\r\n segments.push({ start: p1, cp1, cp2, end: p2 });\r\n }\r\n\r\n return segments;\r\n}\r\n","import type { CanvasElement, StrokeElement } from './types';\r\nimport type { CurveSegment } from './stroke-smoothing';\r\nimport { smoothToSegments, pressureToWidth } from './stroke-smoothing';\r\n\r\nexport interface StrokeWidthBucket {\r\n width: number;\r\n path: Path2D;\r\n}\r\n\r\nexport interface StrokeRenderData {\r\n segments: CurveSegment[]; // always populated; used by hit-testing and the no-Path2D fallback\r\n widths: number[];\r\n buckets: StrokeWidthBucket[] | null; // null when Path2D is unavailable (jsdom / old browsers)\r\n}\r\n\r\n// Strokes are immutable after commit. If points ever become mutable,\r\n// this cache must be invalidated on store.update().\r\nconst cache = new WeakMap<StrokeElement, StrokeRenderData>();\r\n\r\nconst WIDTH_QUANTUM = 0.25;\r\n\r\nfunction buildWidthBuckets(segments: CurveSegment[], widths: number[]): StrokeWidthBucket[] | null {\r\n if (typeof Path2D === 'undefined') return null;\r\n const byWidth = new Map<number, Path2D>();\r\n for (let i = 0; i < segments.length; i++) {\r\n const seg = segments[i];\r\n const w = widths[i];\r\n if (!seg || w === undefined) continue;\r\n const q = Math.max(WIDTH_QUANTUM, Math.round(w / WIDTH_QUANTUM) * WIDTH_QUANTUM);\r\n let path = byWidth.get(q);\r\n if (!path) {\r\n path = new Path2D();\r\n byWidth.set(q, path);\r\n }\r\n // Each segment is an independent open sub-path; moveTo resets the pen between them.\r\n path.moveTo(seg.start.x, seg.start.y);\r\n path.bezierCurveTo(seg.cp1.x, seg.cp1.y, seg.cp2.x, seg.cp2.y, seg.end.x, seg.end.y);\r\n }\r\n return [...byWidth.entries()].map(([width, path]) => ({ width, path }));\r\n}\r\n\r\nexport function computeStrokeSegments(stroke: StrokeElement): StrokeRenderData {\r\n const segments = smoothToSegments(stroke.points);\r\n const widths: number[] = [];\r\n\r\n for (const seg of segments) {\r\n const w =\r\n (pressureToWidth(seg.start.pressure, stroke.width) +\r\n pressureToWidth(seg.end.pressure, stroke.width)) /\r\n 2;\r\n widths.push(w);\r\n }\r\n\r\n const data: StrokeRenderData = { segments, widths, buckets: buildWidthBuckets(segments, widths) };\r\n cache.set(stroke, data);\r\n return data;\r\n}\r\n\r\nexport function getStrokeRenderData(stroke: StrokeElement): StrokeRenderData {\r\n const cached = cache.get(stroke);\r\n if (cached) return cached;\r\n return computeStrokeSegments(stroke);\r\n}\r\n\r\nexport function transferStrokeRenderData(prev: CanvasElement, next: CanvasElement): void {\r\n if (prev.type !== 'stroke' || next.type !== 'stroke') return;\r\n if (prev.points !== next.points) return;\r\n const data = cache.get(prev);\r\n if (data) cache.set(next, data);\r\n}\r\n","import { EventBus } from '../core/event-bus';\r\nimport type { Bounds, Point } from '../core/types';\r\nimport { Quadtree } from '../core/quadtree';\r\nimport { getElementVisualBounds, transferStrokeBounds } from './element-bounds';\r\nimport { getArrowControlPoint } from './arrow-geometry';\r\nimport { sanitizeNoteHtml } from './note-sanitizer';\r\nimport { computeStrokeSegments, transferStrokeRenderData } from './stroke-cache';\r\nimport type { CanvasElement, ElementType } from './types';\r\n\r\nfunction sanitizeRichText(element: CanvasElement): CanvasElement {\r\n if (element.type !== 'note' && element.type !== 'text') return element;\r\n const text = sanitizeNoteHtml(element.text);\r\n return text === element.text ? element : { ...element, text };\r\n}\r\n\r\nexport interface ElementUpdateEvent {\r\n previous: CanvasElement;\r\n current: CanvasElement;\r\n}\r\n\r\nexport interface ElementChangeMeta {\r\n /**\r\n * Identifies what caused the change. `undefined` or `'local'` = a local change (recorded to undo\r\n * history and observed as local). Any other value (e.g. `'remote'`) marks an externally-applied\r\n * change: it is NOT recorded to undo history, and is tagged so observers can avoid re-broadcasting it.\r\n */\r\n origin?: string;\r\n}\r\n\r\ninterface ElementStoreEvents {\r\n add: CanvasElement;\r\n remove: CanvasElement;\r\n update: ElementUpdateEvent;\r\n clear: null;\r\n}\r\n\r\nexport class ElementStore {\r\n private elements = new Map<string, CanvasElement>();\r\n private bus = new EventBus<ElementStoreEvents>();\r\n private layerOrderMap = new Map<string, number>();\r\n private spatialIndex = new Quadtree({ x: -100000, y: -100000, w: 200000, h: 200000 });\r\n private sortedCache: CanvasElement[] | null = null;\r\n private _versions = new Map<string, number>();\r\n\r\n get count(): number {\r\n return this.elements.size;\r\n }\r\n\r\n getVersion(id: string): number {\r\n return this._versions.get(id) ?? -1;\r\n }\r\n\r\n setLayerOrder(order: Map<string, number>): void {\r\n this.layerOrderMap = new Map(order);\r\n this.sortedCache = null;\r\n }\r\n\r\n getAll(): CanvasElement[] {\r\n if (this.sortedCache) return this.sortedCache;\r\n this.sortedCache = [...this.elements.values()].sort((a, b) => {\r\n const layerA = this.layerOrderMap.get(a.layerId) ?? 0;\r\n const layerB = this.layerOrderMap.get(b.layerId) ?? 0;\r\n if (layerA !== layerB) return layerA - layerB;\r\n return a.zIndex - b.zIndex;\r\n });\r\n return this.sortedCache;\r\n }\r\n\r\n getById(id: string): CanvasElement | undefined {\r\n return this.elements.get(id);\r\n }\r\n\r\n getElementsByType<T extends ElementType>(type: T): Extract<CanvasElement, { type: T }>[] {\r\n return this.getAll().filter(\r\n (el): el is Extract<CanvasElement, { type: T }> => el.type === type,\r\n );\r\n }\r\n\r\n // Spatial index stores the rotation-expanded AABB so rotated elements remain\r\n // broad-phase hit-test/marquee candidates; precise tests run against local bounds.\r\n private indexBounds(element: CanvasElement): Bounds | null {\r\n return getElementVisualBounds(element);\r\n }\r\n\r\n add(element: CanvasElement, meta?: ElementChangeMeta): void {\r\n element = sanitizeRichText(element);\r\n this.sortedCache = null;\r\n this._versions.set(element.id, 0);\r\n this.elements.set(element.id, element);\r\n const bounds = this.indexBounds(element);\r\n if (bounds) this.spatialIndex.insert(element.id, bounds);\r\n this.bus.emit('add', element, meta);\r\n }\r\n\r\n update(id: string, partial: Partial<CanvasElement>, meta?: ElementChangeMeta): void {\r\n const existing = this.elements.get(id);\r\n if (!existing) return;\r\n this.sortedCache = null;\r\n this._versions.set(id, (this._versions.get(id) ?? 0) + 1);\r\n\r\n // Shallow spread preserves the points array identity when `partial` omits points;\r\n // transferStrokeRenderData/transferStrokeBounds rely on that reference equality.\r\n const updated = {\r\n ...existing,\r\n ...partial,\r\n id: existing.id,\r\n type: existing.type,\r\n } as CanvasElement;\r\n\r\n if (updated.type === 'stroke' && existing.type === 'stroke') {\r\n transferStrokeRenderData(existing, updated);\r\n transferStrokeBounds(existing, updated);\r\n }\r\n\r\n if (updated.type === 'arrow') {\r\n const arrow = updated;\r\n arrow.cachedControlPoint = getArrowControlPoint(arrow.from, arrow.to, arrow.bend);\r\n }\r\n\r\n if ((updated.type === 'note' || updated.type === 'text') && 'text' in partial) {\r\n updated.text = sanitizeNoteHtml(updated.text);\r\n }\r\n\r\n this.elements.set(id, updated);\r\n\r\n const newBounds = this.indexBounds(updated);\r\n if (newBounds) {\r\n this.spatialIndex.update(id, newBounds);\r\n }\r\n\r\n this.bus.emit('update', { previous: existing, current: updated }, meta);\r\n }\r\n\r\n remove(id: string, meta?: ElementChangeMeta): void {\r\n const element = this.elements.get(id);\r\n if (!element) return;\r\n this.sortedCache = null;\r\n this._versions.delete(id);\r\n\r\n this.elements.delete(id);\r\n this.spatialIndex.remove(id);\r\n this.bus.emit('remove', element, meta);\r\n }\r\n\r\n clear(meta?: ElementChangeMeta): void {\r\n this.sortedCache = null;\r\n this._versions.clear();\r\n this.elements.clear();\r\n this.spatialIndex.clear();\r\n this.bus.emit('clear', null, meta);\r\n }\r\n\r\n snapshot(): CanvasElement[] {\r\n return this.getAll().map((el) => ({ ...el }));\r\n }\r\n\r\n loadSnapshot(elements: CanvasElement[], meta?: ElementChangeMeta): void {\r\n const sanitizedElements = elements.map(sanitizeRichText);\r\n this.sortedCache = null;\r\n this._versions.clear();\r\n this.elements.clear();\r\n this.spatialIndex.clear();\r\n for (const el of sanitizedElements) {\r\n this.elements.set(el.id, el);\r\n this._versions.set(el.id, 0);\r\n const bounds = this.indexBounds(el);\r\n if (bounds) this.spatialIndex.insert(el.id, bounds);\r\n if (el.type === 'stroke') {\r\n computeStrokeSegments(el);\r\n }\r\n if (el.type === 'arrow' && el.bend !== 0 && !el.cachedControlPoint) {\r\n el.cachedControlPoint = getArrowControlPoint(el.from, el.to, el.bend);\r\n }\r\n }\r\n this.bus.emit('clear', null, meta);\r\n for (const el of sanitizedElements) {\r\n this.bus.emit('add', el, meta);\r\n }\r\n }\r\n\r\n bringToFront(id: string): void {\r\n const el = this.elements.get(id);\r\n if (!el) return;\r\n const siblings = [...this.elements.values()].filter(\r\n (e) => e.layerId === el.layerId && e.id !== id,\r\n );\r\n if (siblings.length === 0) return;\r\n const maxZ = Math.max(...siblings.map((e) => e.zIndex));\r\n if (el.zIndex >= maxZ) return;\r\n this.update(id, { zIndex: maxZ + 1 });\r\n }\r\n\r\n sendToBack(id: string): void {\r\n const el = this.elements.get(id);\r\n if (!el) return;\r\n const siblings = [...this.elements.values()].filter(\r\n (e) => e.layerId === el.layerId && e.id !== id,\r\n );\r\n if (siblings.length === 0) return;\r\n const minZ = Math.min(...siblings.map((e) => e.zIndex));\r\n if (el.zIndex <= minZ) return;\r\n this.update(id, { zIndex: minZ - 1 });\r\n }\r\n\r\n bringForward(id: string): void {\r\n const el = this.elements.get(id);\r\n if (!el) return;\r\n const sorted = [...this.elements.values()]\r\n .filter((e) => e.layerId === el.layerId)\r\n .sort((a, b) => a.zIndex - b.zIndex);\r\n const idx = sorted.findIndex((e) => e.id === id);\r\n if (idx < 0 || idx >= sorted.length - 1) return;\r\n const next = sorted[idx + 1];\r\n if (!next) return;\r\n const myZ = el.zIndex;\r\n const nextZ = next.zIndex;\r\n this.update(id, { zIndex: nextZ });\r\n this.update(next.id, { zIndex: myZ });\r\n }\r\n\r\n sendBackward(id: string): void {\r\n const el = this.elements.get(id);\r\n if (!el) return;\r\n const sorted = [...this.elements.values()]\r\n .filter((e) => e.layerId === el.layerId)\r\n .sort((a, b) => a.zIndex - b.zIndex);\r\n const idx = sorted.findIndex((e) => e.id === id);\r\n if (idx <= 0) return;\r\n const prev = sorted[idx - 1];\r\n if (!prev) return;\r\n const myZ = el.zIndex;\r\n const prevZ = prev.zIndex;\r\n this.update(id, { zIndex: prevZ });\r\n this.update(prev.id, { zIndex: myZ });\r\n }\r\n\r\n queryRect(rect: Bounds): CanvasElement[] {\r\n const ids = this.spatialIndex.query(rect);\r\n const elements: CanvasElement[] = [];\r\n for (const id of ids) {\r\n const el = this.elements.get(id);\r\n if (el) elements.push(el);\r\n }\r\n return elements.sort((a, b) => {\r\n const layerA = this.layerOrderMap.get(a.layerId) ?? 0;\r\n const layerB = this.layerOrderMap.get(b.layerId) ?? 0;\r\n if (layerA !== layerB) return layerA - layerB;\r\n return a.zIndex - b.zIndex;\r\n });\r\n }\r\n\r\n queryPoint(point: Point): CanvasElement[] {\r\n return this.queryRect({ x: point.x, y: point.y, w: 0, h: 0 });\r\n }\r\n\r\n on<K extends keyof ElementStoreEvents>(\r\n event: K,\r\n listener: (data: ElementStoreEvents[K], meta: ElementChangeMeta) => void,\r\n ): () => void {\r\n return this.bus.on(event, listener);\r\n }\r\n\r\n onChange(listener: () => void): () => void {\r\n const unsubs = [\r\n this.bus.on('add', listener),\r\n this.bus.on('remove', listener),\r\n this.bus.on('update', listener),\r\n this.bus.on('clear', listener),\r\n ];\r\n return () => unsubs.forEach((fn) => fn());\r\n }\r\n}\r\n","import type { Point } from '../core/types';\r\n\r\nexport function withRotation(\r\n ctx: CanvasRenderingContext2D,\r\n el: { rotation?: number },\r\n center: Point,\r\n draw: () => void,\r\n): void {\r\n const angle = el.rotation ?? 0;\r\n if (angle === 0) {\r\n draw();\r\n return;\r\n }\r\n ctx.save();\r\n ctx.translate(center.x, center.y);\r\n ctx.rotate(angle);\r\n ctx.translate(-center.x, -center.y);\r\n draw();\r\n ctx.restore();\r\n}\r\n","import type { StrokeElement } from '../types';\r\nimport { getStrokeRenderData } from '../stroke-cache';\r\n\r\nexport function renderStroke(ctx: CanvasRenderingContext2D, stroke: StrokeElement): void {\r\n if (stroke.points.length < 2) return;\r\n\r\n ctx.save();\r\n if (stroke.blendMode) ctx.globalCompositeOperation = stroke.blendMode;\r\n ctx.translate(stroke.position.x, stroke.position.y);\r\n ctx.strokeStyle = stroke.color;\r\n ctx.lineCap = 'round';\r\n ctx.lineJoin = 'round';\r\n ctx.globalAlpha = stroke.opacity;\r\n\r\n const data = getStrokeRenderData(stroke);\r\n if (data.buckets) {\r\n for (const bucket of data.buckets) {\r\n ctx.lineWidth = bucket.width;\r\n ctx.stroke(bucket.path);\r\n }\r\n } else {\r\n for (let i = 0; i < data.segments.length; i++) {\r\n const seg = data.segments[i];\r\n const w = data.widths[i];\r\n if (!seg || w === undefined) continue;\r\n ctx.lineWidth = w;\r\n ctx.beginPath();\r\n ctx.moveTo(seg.start.x, seg.start.y);\r\n ctx.bezierCurveTo(seg.cp1.x, seg.cp1.y, seg.cp2.x, seg.cp2.y, seg.end.x, seg.end.y);\r\n ctx.stroke();\r\n }\r\n }\r\n\r\n ctx.restore();\r\n}\r\n","import type { Point, Size } from '../core/types';\r\nimport type { ShapeElement } from './types';\r\n\r\n/** Inverse of lineEndpoints: two endpoints → a line shape's bbox + flip. */\r\nexport function lineFromEndpoints(a: Point, b: Point): { position: Point; size: Size; flip: boolean } {\r\n return {\r\n position: { x: Math.min(a.x, b.x), y: Math.min(a.y, b.y) },\r\n size: { w: Math.abs(b.x - a.x), h: Math.abs(b.y - a.y) },\r\n flip: (b.x > a.x) !== (b.y > a.y),\r\n };\r\n}\r\n\r\n/** The two segment endpoints of a 'line' shape, from its bbox + flip. */\r\nexport function lineEndpoints(shape: ShapeElement): [Point, Point] {\r\n const { x, y } = shape.position;\r\n const { w, h } = shape.size;\r\n return shape.flip\r\n ? [\r\n { x, y: y + h },\r\n { x: x + w, y },\r\n ]\r\n : [\r\n { x, y },\r\n { x: x + w, y: y + h },\r\n ];\r\n}\r\n","import type { ShapeElement } from '../types';\r\nimport { lineEndpoints } from '../shape-geometry';\r\n\r\nexport function renderShape(ctx: CanvasRenderingContext2D, shape: ShapeElement): void {\r\n ctx.save();\r\n\r\n if (shape.fillColor !== 'none' && shape.shape !== 'line') {\r\n ctx.fillStyle = shape.fillColor;\r\n fillShapePath(ctx, shape);\r\n }\r\n\r\n if (shape.strokeWidth > 0) {\r\n ctx.strokeStyle = shape.strokeColor;\r\n ctx.lineWidth = shape.strokeWidth;\r\n strokeShapePath(ctx, shape);\r\n }\r\n\r\n ctx.restore();\r\n}\r\n\r\nfunction fillShapePath(ctx: CanvasRenderingContext2D, shape: ShapeElement): void {\r\n switch (shape.shape) {\r\n case 'rectangle':\r\n ctx.fillRect(shape.position.x, shape.position.y, shape.size.w, shape.size.h);\r\n break;\r\n case 'ellipse': {\r\n const cx = shape.position.x + shape.size.w / 2;\r\n const cy = shape.position.y + shape.size.h / 2;\r\n ctx.beginPath();\r\n ctx.ellipse(cx, cy, shape.size.w / 2, shape.size.h / 2, 0, 0, Math.PI * 2);\r\n ctx.fill();\r\n break;\r\n }\r\n }\r\n}\r\n\r\nfunction strokeShapePath(ctx: CanvasRenderingContext2D, shape: ShapeElement): void {\r\n switch (shape.shape) {\r\n case 'rectangle':\r\n ctx.strokeRect(shape.position.x, shape.position.y, shape.size.w, shape.size.h);\r\n break;\r\n case 'ellipse': {\r\n const cx = shape.position.x + shape.size.w / 2;\r\n const cy = shape.position.y + shape.size.h / 2;\r\n ctx.beginPath();\r\n ctx.ellipse(cx, cy, shape.size.w / 2, shape.size.h / 2, 0, 0, Math.PI * 2);\r\n ctx.stroke();\r\n break;\r\n }\r\n case 'line': {\r\n const [a, b] = lineEndpoints(shape);\r\n ctx.lineCap = 'round';\r\n ctx.beginPath();\r\n ctx.moveTo(a.x, a.y);\r\n ctx.lineTo(b.x, b.y);\r\n ctx.stroke();\r\n break;\r\n }\r\n }\r\n}\r\n","import type { Point } from '../core/types';\r\nimport type { ArrowElement } from './types';\r\nimport { getArrowControlPoint, getArrowTangentAngle } from './arrow-geometry';\r\n\r\nexport interface ArrowRenderGeometry {\r\n controlPoint: Point | null;\r\n tangentStart: number;\r\n tangentEnd: number;\r\n}\r\n\r\n// Intrinsic geometry only (from/to/bend). Binding-resolved endpoints are deliberately\r\n// NOT cached: bound targets can move without the arrow object being replaced.\r\nconst cache = new WeakMap<ArrowElement, ArrowRenderGeometry>();\r\n\r\nexport function getArrowRenderGeometry(arrow: ArrowElement): ArrowRenderGeometry {\r\n const hit = cache.get(arrow);\r\n if (hit) return hit;\r\n const geometry: ArrowRenderGeometry = {\r\n controlPoint:\r\n arrow.bend !== 0\r\n ? (arrow.cachedControlPoint ?? getArrowControlPoint(arrow.from, arrow.to, arrow.bend))\r\n : null,\r\n tangentStart: getArrowTangentAngle(arrow.from, arrow.to, arrow.bend, 0),\r\n tangentEnd: getArrowTangentAngle(arrow.from, arrow.to, arrow.bend, 1),\r\n };\r\n cache.set(arrow, geometry);\r\n return geometry;\r\n}\r\n","import type { Bounds, Point } from '../core/types';\r\nimport type { ArrowElement, CanvasElement } from './types';\r\nimport type { ElementStore } from './element-store';\r\nimport { getArrowTangentAngle } from './arrow-geometry';\r\nimport { getElementBounds } from './element-bounds';\r\n\r\nconst BINDABLE_TYPES = new Set(['note', 'text', 'image', 'html', 'shape']);\r\n\r\nexport function isBindable(element: CanvasElement): boolean {\r\n return BINDABLE_TYPES.has(element.type);\r\n}\r\n\r\nexport function getElementCenter(element: CanvasElement): Point {\r\n if (!('size' in element)) {\r\n throw new Error(`getElementCenter: element type \"${element.type}\" has no size`);\r\n }\r\n return {\r\n x: element.position.x + element.size.w / 2,\r\n y: element.position.y + element.size.h / 2,\r\n };\r\n}\r\n\r\nexport function getEdgeIntersection(bounds: Bounds, outsidePoint: Point): Point {\r\n const cx = bounds.x + bounds.w / 2;\r\n const cy = bounds.y + bounds.h / 2;\r\n const dx = outsidePoint.x - cx;\r\n const dy = outsidePoint.y - cy;\r\n\r\n if (dx === 0 && dy === 0) return { x: cx, y: cy };\r\n\r\n const halfW = bounds.w / 2;\r\n const halfH = bounds.h / 2;\r\n\r\n const scaleX = dx !== 0 ? halfW / Math.abs(dx) : Infinity;\r\n const scaleY = dy !== 0 ? halfH / Math.abs(dy) : Infinity;\r\n const scale = Math.min(scaleX, scaleY);\r\n\r\n return {\r\n x: cx + dx * scale,\r\n y: cy + dy * scale,\r\n };\r\n}\r\n\r\nexport function findBindTarget(\r\n point: Point,\r\n store: ElementStore,\r\n threshold: number,\r\n excludeId?: string,\r\n filter?: (el: CanvasElement) => boolean,\r\n): CanvasElement | null {\r\n let closest: CanvasElement | null = null;\r\n let closestDist = Infinity;\r\n\r\n for (const el of store.getAll()) {\r\n if (!isBindable(el)) continue;\r\n if (excludeId && el.id === excludeId) continue;\r\n if (filter && !filter(el)) continue;\r\n\r\n const bounds = getElementBounds(el);\r\n if (!bounds) continue;\r\n\r\n const dist = distToBounds(point, bounds);\r\n if (dist <= threshold && dist < closestDist) {\r\n closest = el;\r\n closestDist = dist;\r\n }\r\n }\r\n\r\n return closest;\r\n}\r\n\r\nfunction distToBounds(point: Point, bounds: Bounds): number {\r\n const clampedX = Math.max(bounds.x, Math.min(point.x, bounds.x + bounds.w));\r\n const clampedY = Math.max(bounds.y, Math.min(point.y, bounds.y + bounds.h));\r\n return Math.hypot(point.x - clampedX, point.y - clampedY);\r\n}\r\n\r\nexport function findBoundArrows(elementId: string, store: ElementStore): ArrowElement[] {\r\n return store\r\n .getElementsByType('arrow')\r\n .filter((a) => a.fromBinding?.elementId === elementId || a.toBinding?.elementId === elementId);\r\n}\r\n\r\n/** Re-anchor every arrow bound to any of the moved non-arrow elements (each updated once). */\r\nexport function updateArrowsBoundToElements(movedIds: Iterable<string>, store: ElementStore): void {\r\n const movedNonArrowIds = new Set<string>();\r\n for (const id of movedIds) {\r\n const el = store.getById(id);\r\n if (el && el.type !== 'arrow') movedNonArrowIds.add(id);\r\n }\r\n if (movedNonArrowIds.size === 0) return;\r\n const updated = new Set<string>();\r\n for (const id of movedNonArrowIds) {\r\n for (const ba of findBoundArrows(id, store)) {\r\n if (updated.has(ba.id)) continue;\r\n updated.add(ba.id);\r\n const updates = updateBoundArrow(ba, store);\r\n if (updates) store.update(ba.id, updates);\r\n }\r\n }\r\n}\r\n\r\nexport function updateBoundArrow(\r\n arrow: ArrowElement,\r\n store: ElementStore,\r\n): Partial<ArrowElement> | null {\r\n if (!arrow.fromBinding && !arrow.toBinding) return null;\r\n\r\n const updates: Partial<ArrowElement> = {};\r\n\r\n if (arrow.fromBinding) {\r\n const el = store.getById(arrow.fromBinding.elementId);\r\n if (el) {\r\n const center = getElementCenter(el);\r\n updates.from = center;\r\n updates.position = center;\r\n }\r\n }\r\n\r\n if (arrow.toBinding) {\r\n const el = store.getById(arrow.toBinding.elementId);\r\n if (el) {\r\n updates.to = getElementCenter(el);\r\n }\r\n }\r\n\r\n return Object.keys(updates).length > 0 ? updates : null;\r\n}\r\n\r\nexport function clearStaleBindings(\r\n arrow: ArrowElement,\r\n store: ElementStore,\r\n): Partial<ArrowElement> | null {\r\n const updates: Partial<ArrowElement> = {};\r\n let hasUpdates = false;\r\n\r\n if (arrow.fromBinding && !store.getById(arrow.fromBinding.elementId)) {\r\n updates.fromBinding = undefined;\r\n hasUpdates = true;\r\n }\r\n\r\n if (arrow.toBinding && !store.getById(arrow.toBinding.elementId)) {\r\n updates.toBinding = undefined;\r\n hasUpdates = true;\r\n }\r\n\r\n return hasUpdates ? updates : null;\r\n}\r\n\r\nexport function unbindArrow(arrow: ArrowElement, store: ElementStore): Partial<ArrowElement> {\r\n const updates: Partial<ArrowElement> = {};\r\n\r\n if (arrow.fromBinding) {\r\n const el = store.getById(arrow.fromBinding.elementId);\r\n const bounds = el ? getElementBounds(el) : null;\r\n if (bounds) {\r\n const angle = getArrowTangentAngle(arrow.from, arrow.to, arrow.bend, 0);\r\n const rayTarget = {\r\n x: arrow.from.x + Math.cos(angle) * 1000,\r\n y: arrow.from.y + Math.sin(angle) * 1000,\r\n };\r\n const edge = getEdgeIntersection(bounds, rayTarget);\r\n updates.from = edge;\r\n updates.position = edge;\r\n }\r\n updates.fromBinding = undefined;\r\n }\r\n\r\n if (arrow.toBinding) {\r\n const el = store.getById(arrow.toBinding.elementId);\r\n const bounds = el ? getElementBounds(el) : null;\r\n if (bounds) {\r\n const angle = getArrowTangentAngle(arrow.from, arrow.to, arrow.bend, 1);\r\n // Reverse tangent direction — tangent at t=1 points away from curve body\r\n const rayTarget = {\r\n x: arrow.to.x - Math.cos(angle) * 1000,\r\n y: arrow.to.y - Math.sin(angle) * 1000,\r\n };\r\n updates.to = getEdgeIntersection(bounds, rayTarget);\r\n }\r\n updates.toBinding = undefined;\r\n }\r\n\r\n return updates;\r\n}\r\n","import type { ArrowElement, ArrowStrokeStyle } from '../types';\r\nimport type { ElementStore } from '../element-store';\r\nimport { getArrowRenderGeometry } from '../arrow-render-cache';\r\nimport { getArrowMidpoint } from '../arrow-geometry';\r\nimport { getEdgeIntersection } from '../arrow-binding';\r\nimport { getElementBounds } from '../element-bounds';\r\n\r\nconst ARROWHEAD_LENGTH = 12;\r\nconst ARROWHEAD_ANGLE = Math.PI / 6;\r\nconst ARROW_LABEL_FONT_SIZE = 14;\r\n\r\nexport function getArrowDashPattern(strokeStyle: ArrowStrokeStyle | undefined): number[] {\r\n switch (strokeStyle) {\r\n case 'dashed':\r\n return [8, 4];\r\n case 'dotted':\r\n return [2, 4];\r\n default:\r\n return [];\r\n }\r\n}\r\n\r\nexport function renderArrow(\r\n ctx: CanvasRenderingContext2D,\r\n arrow: ArrowElement,\r\n store: ElementStore | null,\r\n labelEditingId: string | null,\r\n): void {\r\n const geometry = getArrowRenderGeometry(arrow);\r\n const { visualFrom, visualTo } = getVisualEndpoints(arrow, geometry, store);\r\n\r\n ctx.save();\r\n ctx.strokeStyle = arrow.color;\r\n ctx.lineWidth = arrow.width;\r\n ctx.lineCap = 'round';\r\n\r\n const dash = getArrowDashPattern(arrow.strokeStyle);\r\n if (dash.length > 0) ctx.setLineDash(dash);\r\n\r\n ctx.beginPath();\r\n ctx.moveTo(visualFrom.x, visualFrom.y);\r\n\r\n if (arrow.bend !== 0) {\r\n const cp = geometry.controlPoint;\r\n if (cp) {\r\n ctx.quadraticCurveTo(cp.x, cp.y, visualTo.x, visualTo.y);\r\n }\r\n } else {\r\n ctx.lineTo(visualTo.x, visualTo.y);\r\n }\r\n ctx.stroke();\r\n\r\n renderArrowhead(ctx, arrow, visualTo, geometry.tangentEnd);\r\n ctx.restore();\r\n renderArrowLabel(ctx, arrow, labelEditingId);\r\n}\r\n\r\nfunction renderArrowLabel(\r\n ctx: CanvasRenderingContext2D,\r\n arrow: ArrowElement,\r\n labelEditingId: string | null,\r\n): void {\r\n if (!arrow.label || arrow.label.length === 0) return;\r\n if (arrow.id === labelEditingId) return;\r\n const mid = getArrowMidpoint(arrow.from, arrow.to, arrow.bend);\r\n ctx.save();\r\n ctx.font = `${ARROW_LABEL_FONT_SIZE}px system-ui, sans-serif`;\r\n const metrics = ctx.measureText(arrow.label);\r\n const padX = 6;\r\n const padY = 4;\r\n const w = metrics.width + padX * 2;\r\n const h = ARROW_LABEL_FONT_SIZE + padY * 2;\r\n ctx.fillStyle = 'rgba(255, 255, 255, 0.9)';\r\n ctx.beginPath();\r\n ctx.roundRect(mid.x - w / 2, mid.y - h / 2, w, h, 4);\r\n ctx.fill();\r\n ctx.fillStyle = '#1a1a1a';\r\n ctx.textAlign = 'center';\r\n ctx.textBaseline = 'middle';\r\n ctx.fillText(arrow.label, mid.x, mid.y);\r\n ctx.restore();\r\n}\r\n\r\nfunction renderArrowhead(\r\n ctx: CanvasRenderingContext2D,\r\n arrow: ArrowElement,\r\n tip: { x: number; y: number },\r\n angle: number,\r\n): void {\r\n ctx.beginPath();\r\n ctx.moveTo(tip.x, tip.y);\r\n ctx.lineTo(\r\n tip.x - ARROWHEAD_LENGTH * Math.cos(angle - ARROWHEAD_ANGLE),\r\n tip.y - ARROWHEAD_LENGTH * Math.sin(angle - ARROWHEAD_ANGLE),\r\n );\r\n ctx.lineTo(\r\n tip.x - ARROWHEAD_LENGTH * Math.cos(angle + ARROWHEAD_ANGLE),\r\n tip.y - ARROWHEAD_LENGTH * Math.sin(angle + ARROWHEAD_ANGLE),\r\n );\r\n ctx.closePath();\r\n ctx.fillStyle = arrow.color;\r\n ctx.fill();\r\n}\r\n\r\nexport function getVisualEndpoints(\r\n arrow: ArrowElement,\r\n geometry: ReturnType<typeof getArrowRenderGeometry>,\r\n store: ElementStore | null,\r\n): {\r\n visualFrom: { x: number; y: number };\r\n visualTo: { x: number; y: number };\r\n} {\r\n let visualFrom = arrow.from;\r\n let visualTo = arrow.to;\r\n\r\n if (!store) return { visualFrom, visualTo };\r\n\r\n if (arrow.fromBinding) {\r\n const el = store.getById(arrow.fromBinding.elementId);\r\n if (el) {\r\n const bounds = getElementBounds(el);\r\n if (bounds) {\r\n const tangentAngle = geometry.tangentStart;\r\n const rayTarget = {\r\n x: arrow.from.x + Math.cos(tangentAngle) * 1000,\r\n y: arrow.from.y + Math.sin(tangentAngle) * 1000,\r\n };\r\n visualFrom = getEdgeIntersection(bounds, rayTarget);\r\n }\r\n }\r\n }\r\n\r\n if (arrow.toBinding) {\r\n const el = store.getById(arrow.toBinding.elementId);\r\n if (el) {\r\n const bounds = getElementBounds(el);\r\n if (bounds) {\r\n const tangentAngle = geometry.tangentEnd;\r\n // Reverse tangent — at t=1 tangent points away from curve body,\r\n // but we need the ray from center back toward the curve\r\n const rayTarget = {\r\n x: arrow.to.x - Math.cos(tangentAngle) * 1000,\r\n y: arrow.to.y - Math.sin(tangentAngle) * 1000,\r\n };\r\n visualTo = getEdgeIntersection(bounds, rayTarget);\r\n }\r\n }\r\n }\r\n\r\n return { visualFrom, visualTo };\r\n}\r\n","import type { ImageElement } from '../types';\r\n\r\nexport function renderImage(\r\n ctx: CanvasRenderingContext2D,\r\n image: ImageElement,\r\n imageCache: Map<string, ImageBitmap | HTMLImageElement | 'failed'>,\r\n onImageLoad: (() => void) | null,\r\n onImageError: ((src: string, cause?: unknown) => void) | null,\r\n): void {\r\n if (imageCache.get(image.src) === 'failed') {\r\n renderImagePlaceholder(ctx, image);\r\n return;\r\n }\r\n const img = getImage(image.src, imageCache, onImageLoad, onImageError);\r\n if (!img) return;\r\n ctx.drawImage(\r\n img as CanvasImageSource,\r\n image.position.x,\r\n image.position.y,\r\n image.size.w,\r\n image.size.h,\r\n );\r\n}\r\n\r\nfunction renderImagePlaceholder(ctx: CanvasRenderingContext2D, image: ImageElement): void {\r\n const { x, y } = image.position;\r\n const { w, h } = image.size;\r\n ctx.save();\r\n ctx.fillStyle = '#eeeeee';\r\n ctx.fillRect(x, y, w, h);\r\n ctx.strokeStyle = '#bdbdbd';\r\n ctx.lineWidth = 1;\r\n ctx.strokeRect(x, y, w, h);\r\n\r\n const glyph = Math.min(24, w / 2, h / 2);\r\n const cx = x + w / 2;\r\n const cy = y + h / 2;\r\n ctx.strokeStyle = '#9e9e9e';\r\n ctx.lineWidth = 2;\r\n ctx.beginPath();\r\n ctx.arc(cx, cy, glyph / 2, 0, Math.PI * 2);\r\n ctx.moveTo(cx - glyph / 2, cy + glyph / 2);\r\n ctx.lineTo(cx + glyph / 2, cy - glyph / 2);\r\n ctx.stroke();\r\n ctx.restore();\r\n}\r\n\r\nfunction getImage(\r\n src: string,\r\n imageCache: Map<string, ImageBitmap | HTMLImageElement | 'failed'>,\r\n onImageLoad: (() => void) | null,\r\n onImageError: ((src: string, cause?: unknown) => void) | null,\r\n): ImageBitmap | HTMLImageElement | null {\r\n const cached = imageCache.get(src);\r\n if (cached) {\r\n if (cached === 'failed') return null;\r\n if (cached instanceof HTMLImageElement) return cached.complete ? cached : null;\r\n return cached;\r\n }\r\n\r\n const img = new Image();\r\n img.src = src;\r\n imageCache.set(src, img);\r\n img.onload = () => {\r\n onImageLoad?.();\r\n // Decode from already-loaded image in memory, not a re-fetch\r\n if (typeof createImageBitmap !== 'undefined') {\r\n createImageBitmap(img)\r\n .then((bitmap) => {\r\n imageCache.set(src, bitmap);\r\n onImageLoad?.();\r\n })\r\n .catch(() => {\r\n /* keep HTMLImageElement fallback — handles CORS rejection */\r\n });\r\n }\r\n };\r\n img.onerror = (event) => {\r\n // failed srcs stay failed for the session; pointing the element at a new src loads fresh\r\n imageCache.set(src, 'failed');\r\n onImageError?.(src, event);\r\n onImageLoad?.();\r\n };\r\n return null;\r\n}\r\n","import type { Point } from '../core/types';\r\nimport type { HexOrientation } from './types';\r\n\r\ninterface HexCoord {\r\n col: number;\r\n row: number;\r\n}\r\n\r\nfunction offsetToCube(\r\n col: number,\r\n row: number,\r\n orientation: HexOrientation,\r\n): { q: number; r: number } {\r\n if (orientation === 'pointy') {\r\n return { q: col - (row - (row & 1)) / 2, r: row };\r\n }\r\n return { q: col, r: row - (col - (col & 1)) / 2 };\r\n}\r\n\r\nfunction cubeToOffset(q: number, r: number, orientation: HexOrientation): HexCoord {\r\n if (orientation === 'pointy') {\r\n return { col: q + (r - (r & 1)) / 2, row: r };\r\n }\r\n return { col: q, row: r + (q - (q & 1)) / 2 };\r\n}\r\n\r\nfunction offsetToPixel(\r\n col: number,\r\n row: number,\r\n cellSize: number,\r\n orientation: HexOrientation,\r\n): Point {\r\n if (orientation === 'pointy') {\r\n const hexW = Math.sqrt(3) * cellSize;\r\n const rowH = 1.5 * cellSize;\r\n const offsetX = row % 2 !== 0 ? hexW / 2 : 0;\r\n return { x: col * hexW + offsetX, y: row * rowH };\r\n }\r\n const hexH = Math.sqrt(3) * cellSize;\r\n const colW = 1.5 * cellSize;\r\n const offsetY = col % 2 !== 0 ? hexH / 2 : 0;\r\n return { x: col * colW, y: row * hexH + offsetY };\r\n}\r\n\r\nfunction pixelToOffset(\r\n x: number,\r\n y: number,\r\n cellSize: number,\r\n orientation: HexOrientation,\r\n): HexCoord {\r\n if (orientation === 'pointy') {\r\n const hexW = Math.sqrt(3) * cellSize;\r\n const rowH = 1.5 * cellSize;\r\n const row = Math.round(y / rowH);\r\n const offsetX = row % 2 !== 0 ? hexW / 2 : 0;\r\n return { col: Math.round((x - offsetX) / hexW), row };\r\n }\r\n const hexH = Math.sqrt(3) * cellSize;\r\n const colW = 1.5 * cellSize;\r\n const col = Math.round(x / colW);\r\n const offsetY = col % 2 !== 0 ? hexH / 2 : 0;\r\n return { col, row: Math.round((y - offsetY) / hexH) };\r\n}\r\n\r\nfunction enumerateHexRing(\r\n centerQ: number,\r\n centerR: number,\r\n n: number,\r\n orientation: HexOrientation,\r\n cellSize: number,\r\n): Point[] {\r\n const cells: Point[] = [];\r\n for (let dq = -n; dq <= n; dq++) {\r\n const rMin = Math.max(-n, -dq - n);\r\n const rMax = Math.min(n, -dq + n);\r\n for (let dr = rMin; dr <= rMax; dr++) {\r\n const absQ = centerQ + dq;\r\n const absR = centerR + dr;\r\n const off = cubeToOffset(absQ, absR, orientation);\r\n cells.push(offsetToPixel(off.col, off.row, cellSize, orientation));\r\n }\r\n }\r\n return cells;\r\n}\r\n\r\nexport function getHexDistance(\r\n a: Point,\r\n b: Point,\r\n cellSize: number,\r\n orientation: HexOrientation,\r\n): number {\r\n const offA = pixelToOffset(a.x, a.y, cellSize, orientation);\r\n const offB = pixelToOffset(b.x, b.y, cellSize, orientation);\r\n const cubeA = offsetToCube(offA.col, offA.row, orientation);\r\n const cubeB = offsetToCube(offB.col, offB.row, orientation);\r\n const dq = cubeA.q - cubeB.q;\r\n const dr = cubeA.r - cubeB.r;\r\n const ds = -dq - dr;\r\n return Math.max(Math.abs(dq), Math.abs(dr), Math.abs(ds));\r\n}\r\n\r\nexport function getHexCellsInRadius(\r\n center: Point,\r\n radiusCells: number,\r\n cellSize: number,\r\n orientation: HexOrientation,\r\n): Point[] {\r\n const n = Math.round(radiusCells);\r\n const off = pixelToOffset(center.x, center.y, cellSize, orientation);\r\n const cube = offsetToCube(off.col, off.row, orientation);\r\n if (n <= 0) {\r\n return [offsetToPixel(off.col, off.row, cellSize, orientation)];\r\n }\r\n return enumerateHexRing(cube.q, cube.r, n, orientation, cellSize);\r\n}\r\n\r\nexport function getHexCellsInCone(\r\n center: Point,\r\n angle: number,\r\n radiusCells: number,\r\n cellSize: number,\r\n orientation: HexOrientation,\r\n): Point[] {\r\n const n = Math.round(radiusCells);\r\n const off = pixelToOffset(center.x, center.y, cellSize, orientation);\r\n const cube = offsetToCube(off.col, off.row, orientation);\r\n const centerPixel = offsetToPixel(off.col, off.row, cellSize, orientation);\r\n\r\n if (n <= 0) return [centerPixel];\r\n\r\n const vertexOffset = orientation === 'pointy' ? Math.PI / 6 : 0;\r\n const step = Math.PI / 3;\r\n const snappedAngle = Math.round((angle - vertexOffset) / step) * step + vertexOffset;\r\n\r\n const halfAngle = Math.PI / 6 + 1e-6;\r\n const cells: Point[] = [centerPixel];\r\n\r\n for (let dq = -n; dq <= n; dq++) {\r\n const rMin = Math.max(-n, -dq - n);\r\n const rMax = Math.min(n, -dq + n);\r\n for (let dr = rMin; dr <= rMax; dr++) {\r\n if (dq === 0 && dr === 0) continue;\r\n const absQ = cube.q + dq;\r\n const absR = cube.r + dr;\r\n const pixel = offsetToPixel(\r\n cubeToOffset(absQ, absR, orientation).col,\r\n cubeToOffset(absQ, absR, orientation).row,\r\n cellSize,\r\n orientation,\r\n );\r\n\r\n const dx = pixel.x - centerPixel.x;\r\n const dy = pixel.y - centerPixel.y;\r\n let diff = Math.atan2(dy, dx) - snappedAngle;\r\n if (diff > Math.PI) diff -= 2 * Math.PI;\r\n if (diff < -Math.PI) diff += 2 * Math.PI;\r\n\r\n if (Math.abs(diff) <= halfAngle) {\r\n cells.push(pixel);\r\n }\r\n }\r\n }\r\n return cells;\r\n}\r\n\r\nexport function getHexCellsInLine(\r\n center: Point,\r\n angle: number,\r\n radiusCells: number,\r\n cellSize: number,\r\n orientation: HexOrientation,\r\n): Point[] {\r\n const n = Math.round(radiusCells);\r\n const off = pixelToOffset(center.x, center.y, cellSize, orientation);\r\n const cube = offsetToCube(off.col, off.row, orientation);\r\n const centerPixel = offsetToPixel(off.col, off.row, cellSize, orientation);\r\n\r\n if (n <= 0) return [centerPixel];\r\n\r\n const vertexOffset = orientation === 'pointy' ? Math.PI / 6 : 0;\r\n const step = Math.PI / 3;\r\n const snappedAngle = Math.round((angle - vertexOffset) / step) * step + vertexOffset;\r\n\r\n const cos = Math.cos(snappedAngle);\r\n const sin = Math.sin(snappedAngle);\r\n const snapUnit = Math.sqrt(3) * cellSize;\r\n const lineLength = n * snapUnit;\r\n const halfWidth = snapUnit * 0.5 + 1e-6;\r\n const cells: Point[] = [];\r\n\r\n for (let dq = -n; dq <= n; dq++) {\r\n const rMin = Math.max(-n, -dq - n);\r\n const rMax = Math.min(n, -dq + n);\r\n for (let dr = rMin; dr <= rMax; dr++) {\r\n const absQ = cube.q + dq;\r\n const absR = cube.r + dr;\r\n const pixel = offsetToPixel(\r\n cubeToOffset(absQ, absR, orientation).col,\r\n cubeToOffset(absQ, absR, orientation).row,\r\n cellSize,\r\n orientation,\r\n );\r\n\r\n const dx = pixel.x - centerPixel.x;\r\n const dy = pixel.y - centerPixel.y;\r\n const along = dx * cos + dy * sin;\r\n const perp = Math.abs(-dx * sin + dy * cos);\r\n\r\n if (along >= -snapUnit * 0.1 && along <= lineLength + snapUnit * 0.1 && perp <= halfWidth) {\r\n cells.push(pixel);\r\n }\r\n }\r\n }\r\n return cells;\r\n}\r\n\r\nexport function getHexCellsInRectangle(\r\n center: Point,\r\n angle: number,\r\n lengthCells: number,\r\n widthCells: number,\r\n cellSize: number,\r\n orientation: HexOrientation,\r\n): Point[] {\r\n const nLen = Math.round(lengthCells);\r\n const wCells = Math.max(1, Math.round(widthCells));\r\n const off = pixelToOffset(center.x, center.y, cellSize, orientation);\r\n const cube = offsetToCube(off.col, off.row, orientation);\r\n const centerPixel = offsetToPixel(off.col, off.row, cellSize, orientation);\r\n\r\n if (nLen <= 0) return [centerPixel];\r\n\r\n const vertexOffset = orientation === 'pointy' ? Math.PI / 6 : 0;\r\n const step = Math.PI / 3;\r\n const snappedAngle = Math.round((angle - vertexOffset) / step) * step + vertexOffset;\r\n\r\n const cos = Math.cos(snappedAngle);\r\n const sin = Math.sin(snappedAngle);\r\n const snapUnit = Math.sqrt(3) * cellSize;\r\n const lineLength = nLen * snapUnit;\r\n const halfWidth = (wCells * snapUnit) / 2 + 1e-6;\r\n const iterM = nLen + Math.ceil(wCells / 2) + 1;\r\n const cells: Point[] = [];\r\n\r\n for (let dq = -iterM; dq <= iterM; dq++) {\r\n const rMin = Math.max(-iterM, -dq - iterM);\r\n const rMax = Math.min(iterM, -dq + iterM);\r\n for (let dr = rMin; dr <= rMax; dr++) {\r\n const absQ = cube.q + dq;\r\n const absR = cube.r + dr;\r\n const pixel = offsetToPixel(\r\n cubeToOffset(absQ, absR, orientation).col,\r\n cubeToOffset(absQ, absR, orientation).row,\r\n cellSize,\r\n orientation,\r\n );\r\n const dx = pixel.x - centerPixel.x;\r\n const dy = pixel.y - centerPixel.y;\r\n const along = dx * cos + dy * sin;\r\n const perp = Math.abs(-dx * sin + dy * cos);\r\n if (along >= -snapUnit * 0.1 && along <= lineLength + snapUnit * 0.1 && perp <= halfWidth) {\r\n cells.push(pixel);\r\n }\r\n }\r\n }\r\n return cells;\r\n}\r\n\r\nexport function getHexCellsInSquare(\r\n center: Point,\r\n radiusCells: number,\r\n cellSize: number,\r\n orientation: HexOrientation,\r\n): Point[] {\r\n const n = Math.round(radiusCells);\r\n const off = pixelToOffset(center.x, center.y, cellSize, orientation);\r\n const cube = offsetToCube(off.col, off.row, orientation);\r\n const centerPixel = offsetToPixel(off.col, off.row, cellSize, orientation);\r\n\r\n if (n <= 0) return [centerPixel];\r\n\r\n const snapUnit = Math.sqrt(3) * cellSize;\r\n const halfSide = (n * snapUnit) / 2;\r\n const cells: Point[] = [];\r\n\r\n for (let dq = -n; dq <= n; dq++) {\r\n const rMin = Math.max(-n, -dq - n);\r\n const rMax = Math.min(n, -dq + n);\r\n for (let dr = rMin; dr <= rMax; dr++) {\r\n const absQ = cube.q + dq;\r\n const absR = cube.r + dr;\r\n const pixel = offsetToPixel(\r\n cubeToOffset(absQ, absR, orientation).col,\r\n cubeToOffset(absQ, absR, orientation).row,\r\n cellSize,\r\n orientation,\r\n );\r\n\r\n if (\r\n Math.abs(pixel.x - centerPixel.x) <= halfSide &&\r\n Math.abs(pixel.y - centerPixel.y) <= halfSide\r\n ) {\r\n cells.push(pixel);\r\n }\r\n }\r\n }\r\n return cells;\r\n}\r\n\r\nexport function drawHexPath(\r\n ctx: CanvasRenderingContext2D,\r\n cx: number,\r\n cy: number,\r\n cellSize: number,\r\n orientation: HexOrientation,\r\n): void {\r\n const angleOffset = orientation === 'pointy' ? Math.PI / 6 : 0;\r\n ctx.moveTo(cx + cellSize * Math.cos(angleOffset), cy + cellSize * Math.sin(angleOffset));\r\n for (let i = 1; i < 6; i++) {\r\n const a = angleOffset + (Math.PI / 3) * i;\r\n ctx.lineTo(cx + cellSize * Math.cos(a), cy + cellSize * Math.sin(a));\r\n }\r\n ctx.closePath();\r\n}\r\n","import type { Point } from '../../core/types';\r\nimport type { TemplateShape } from '../types';\r\n\r\nexport interface TemplateFeetLabelParams {\r\n position: Point;\r\n radius: number;\r\n angle: number;\r\n templateShape: TemplateShape;\r\n feet: number;\r\n color: string;\r\n}\r\n\r\nexport function renderTemplateFeetLabel(\r\n ctx: CanvasRenderingContext2D,\r\n p: TemplateFeetLabelParams,\r\n): void {\r\n if (p.feet <= 0) return;\r\n\r\n const directional =\r\n p.templateShape === 'cone' || p.templateShape === 'line' || p.templateShape === 'rectangle';\r\n const dir = directional ? p.angle : 0;\r\n const length = p.templateShape === 'square' ? p.radius / 2 : p.radius;\r\n const cos = Math.cos(dir);\r\n const sin = Math.sin(dir);\r\n const start = p.position;\r\n const end = { x: start.x + length * cos, y: start.y + length * sin };\r\n const midX = start.x + (length / 2) * cos;\r\n const midY = start.y + (length / 2) * sin;\r\n\r\n ctx.save();\r\n ctx.globalAlpha = 1;\r\n\r\n ctx.beginPath();\r\n ctx.setLineDash([4, 4]);\r\n ctx.strokeStyle = p.color;\r\n ctx.lineWidth = 1.5;\r\n ctx.moveTo(start.x, start.y);\r\n ctx.lineTo(end.x, end.y);\r\n ctx.stroke();\r\n ctx.setLineDash([]);\r\n\r\n const label = `${Math.round(p.feet)} ft`;\r\n const fontSize = Math.max(10, Math.min(14, p.radius * 0.15));\r\n ctx.font = `bold ${fontSize}px system-ui, sans-serif`;\r\n ctx.textAlign = 'center';\r\n ctx.textBaseline = 'bottom';\r\n const textY = midY - 4;\r\n\r\n const metrics = ctx.measureText(label);\r\n const padX = 4;\r\n const padY = 2;\r\n const textW = metrics.width + padX * 2;\r\n const textH = fontSize + padY * 2;\r\n\r\n ctx.fillStyle = 'rgba(255, 255, 255, 0.85)';\r\n ctx.beginPath();\r\n ctx.roundRect(midX - textW / 2, textY - textH, textW, textH, 3);\r\n ctx.fill();\r\n\r\n ctx.fillStyle = p.color;\r\n ctx.fillText(label, midX, textY - padY);\r\n\r\n ctx.restore();\r\n}\r\n","import type { TemplateElement, HexOrientation } from '../types';\r\nimport type { ElementStore } from '../element-store';\r\nimport {\r\n getHexCellsInRadius,\r\n getHexCellsInCone,\r\n getHexCellsInLine,\r\n getHexCellsInSquare,\r\n getHexCellsInRectangle,\r\n drawHexPath,\r\n} from '../hex-fill';\r\nimport { renderTemplateFeetLabel } from './template-measure';\r\n\r\nexport function renderTemplate(\r\n ctx: CanvasRenderingContext2D,\r\n template: TemplateElement,\r\n store: ElementStore | null,\r\n): void {\r\n const grid = store?.getElementsByType('grid')[0];\r\n if (grid && grid.gridType === 'hex' && template.renderStyle !== 'geometric') {\r\n renderHexTemplate(ctx, template, grid.cellSize, grid.hexOrientation);\r\n return;\r\n }\r\n\r\n renderGeometricTemplate(ctx, template);\r\n}\r\n\r\nfunction renderGeometricTemplate(ctx: CanvasRenderingContext2D, template: TemplateElement): void {\r\n const { x: cx, y: cy } = template.position;\r\n const r = template.radius;\r\n\r\n ctx.save();\r\n ctx.globalAlpha = template.opacity;\r\n ctx.fillStyle = template.fillColor;\r\n ctx.strokeStyle = template.strokeColor;\r\n ctx.lineWidth = template.strokeWidth;\r\n\r\n switch (template.templateShape) {\r\n case 'circle':\r\n ctx.beginPath();\r\n ctx.arc(cx, cy, r, 0, Math.PI * 2);\r\n ctx.fill();\r\n ctx.stroke();\r\n break;\r\n\r\n case 'square':\r\n ctx.fillRect(cx - r / 2, cy - r / 2, r, r);\r\n ctx.strokeRect(cx - r / 2, cy - r / 2, r, r);\r\n break;\r\n\r\n case 'cone': {\r\n const halfAngle = Math.atan(0.5);\r\n ctx.beginPath();\r\n ctx.moveTo(cx, cy);\r\n ctx.arc(cx, cy, r, template.angle - halfAngle, template.angle + halfAngle);\r\n ctx.closePath();\r\n ctx.fill();\r\n ctx.stroke();\r\n break;\r\n }\r\n\r\n case 'line': {\r\n const halfW = r / 12;\r\n const cos = Math.cos(template.angle);\r\n const sin = Math.sin(template.angle);\r\n const perpX = -sin * halfW;\r\n const perpY = cos * halfW;\r\n\r\n ctx.beginPath();\r\n ctx.moveTo(cx + perpX, cy + perpY);\r\n ctx.lineTo(cx + r * cos + perpX, cy + r * sin + perpY);\r\n ctx.lineTo(cx + r * cos - perpX, cy + r * sin - perpY);\r\n ctx.lineTo(cx - perpX, cy - perpY);\r\n ctx.closePath();\r\n ctx.fill();\r\n ctx.stroke();\r\n break;\r\n }\r\n\r\n case 'rectangle': {\r\n const halfW = (template.width ?? 0) / 2;\r\n const cos = Math.cos(template.angle);\r\n const sin = Math.sin(template.angle);\r\n const perpX = -sin * halfW;\r\n const perpY = cos * halfW;\r\n ctx.beginPath();\r\n ctx.moveTo(cx + perpX, cy + perpY);\r\n ctx.lineTo(cx + r * cos + perpX, cy + r * sin + perpY);\r\n ctx.lineTo(cx + r * cos - perpX, cy + r * sin - perpY);\r\n ctx.lineTo(cx - perpX, cy - perpY);\r\n ctx.closePath();\r\n ctx.fill();\r\n ctx.stroke();\r\n break;\r\n }\r\n }\r\n\r\n if (template.radiusFeet != null && template.radiusFeet > 0) {\r\n renderTemplateFeetLabel(ctx, {\r\n position: template.position,\r\n radius: template.radius,\r\n angle: template.angle,\r\n templateShape: template.templateShape,\r\n feet: template.radiusFeet,\r\n color: template.strokeColor,\r\n });\r\n }\r\n\r\n ctx.restore();\r\n}\r\n\r\nfunction renderHexTemplate(\r\n ctx: CanvasRenderingContext2D,\r\n template: TemplateElement,\r\n cellSize: number,\r\n orientation: HexOrientation,\r\n): void {\r\n const snapUnit = Math.sqrt(3) * cellSize;\r\n const radiusCells = template.radius / snapUnit;\r\n const center = template.position;\r\n\r\n let cells: { x: number; y: number }[];\r\n switch (template.templateShape) {\r\n case 'circle':\r\n cells = getHexCellsInRadius(center, radiusCells, cellSize, orientation);\r\n break;\r\n case 'cone':\r\n cells = getHexCellsInCone(center, template.angle, radiusCells, cellSize, orientation);\r\n break;\r\n case 'line':\r\n cells = getHexCellsInLine(center, template.angle, radiusCells, cellSize, orientation);\r\n break;\r\n case 'square':\r\n cells = getHexCellsInSquare(center, radiusCells, cellSize, orientation);\r\n break;\r\n case 'rectangle': {\r\n const widthCells = (template.width ?? 0) / snapUnit;\r\n cells = getHexCellsInRectangle(\r\n center,\r\n template.angle,\r\n radiusCells,\r\n widthCells,\r\n cellSize,\r\n orientation,\r\n );\r\n break;\r\n }\r\n }\r\n\r\n ctx.save();\r\n ctx.globalAlpha = template.opacity;\r\n\r\n ctx.beginPath();\r\n for (const cell of cells) {\r\n drawHexPath(ctx, cell.x, cell.y, cellSize, orientation);\r\n }\r\n ctx.fillStyle = template.fillColor;\r\n ctx.fill();\r\n\r\n ctx.beginPath();\r\n for (const cell of cells) {\r\n drawHexPath(ctx, cell.x, cell.y, cellSize, orientation);\r\n }\r\n ctx.strokeStyle = template.strokeColor;\r\n ctx.lineWidth = template.strokeWidth;\r\n ctx.stroke();\r\n\r\n {\r\n ctx.globalAlpha = Math.min(template.opacity + 0.1, 1);\r\n ctx.beginPath();\r\n drawHexPath(ctx, center.x, center.y, cellSize, orientation);\r\n ctx.fillStyle = template.strokeColor;\r\n ctx.fill();\r\n ctx.strokeStyle = template.strokeColor;\r\n ctx.lineWidth = template.strokeWidth;\r\n ctx.stroke();\r\n }\r\n\r\n if (template.radiusFeet != null && template.radiusFeet > 0) {\r\n renderTemplateFeetLabel(ctx, {\r\n position: template.position,\r\n radius: template.radius,\r\n angle: template.angle,\r\n templateShape: template.templateShape,\r\n feet: template.radiusFeet,\r\n color: template.strokeColor,\r\n });\r\n }\r\n\r\n ctx.restore();\r\n}\r\n","import type { HexOrientation } from './types';\r\n\r\nexport interface VisibleBounds {\r\n minX: number;\r\n minY: number;\r\n maxX: number;\r\n maxY: number;\r\n}\r\n\r\nexport interface SquareGridLines {\r\n verticals: number[];\r\n horizontals: number[];\r\n}\r\n\r\nexport function getSquareGridLines(bounds: VisibleBounds, cellSize: number): SquareGridLines {\r\n if (cellSize <= 0) return { verticals: [], horizontals: [] };\r\n\r\n const verticals: number[] = [];\r\n const startX = Math.floor(bounds.minX / cellSize) * cellSize;\r\n const endX = Math.ceil(bounds.maxX / cellSize) * cellSize;\r\n for (let x = startX; x <= endX; x += cellSize) {\r\n verticals.push(x);\r\n }\r\n\r\n const horizontals: number[] = [];\r\n const startY = Math.floor(bounds.minY / cellSize) * cellSize;\r\n const endY = Math.ceil(bounds.maxY / cellSize) * cellSize;\r\n for (let y = startY; y <= endY; y += cellSize) {\r\n horizontals.push(y);\r\n }\r\n\r\n return { verticals, horizontals };\r\n}\r\n\r\nexport interface HexVertex {\r\n x: number;\r\n y: number;\r\n}\r\n\r\nexport function getHexVertices(\r\n cx: number,\r\n cy: number,\r\n circumradius: number,\r\n orientation: HexOrientation,\r\n): HexVertex[] {\r\n const vertices: HexVertex[] = [];\r\n const angleOffset = orientation === 'pointy' ? -Math.PI / 2 : 0;\r\n for (let i = 0; i < 6; i++) {\r\n const angle = (Math.PI / 3) * i + angleOffset;\r\n vertices.push({\r\n x: cx + circumradius * Math.cos(angle),\r\n y: cy + circumradius * Math.sin(angle),\r\n });\r\n }\r\n return vertices;\r\n}\r\n\r\nexport function getHexCenters(\r\n bounds: VisibleBounds,\r\n circumradius: number,\r\n orientation: HexOrientation,\r\n): HexVertex[] {\r\n if (circumradius <= 0) return [];\r\n\r\n const centers: HexVertex[] = [];\r\n\r\n if (orientation === 'pointy') {\r\n const hexW = Math.sqrt(3) * circumradius;\r\n const hexH = 2 * circumradius;\r\n const rowH = hexH * 0.75;\r\n\r\n const startRow = Math.floor((bounds.minY - circumradius) / rowH);\r\n const endRow = Math.ceil((bounds.maxY + circumradius) / rowH);\r\n const startCol = Math.floor((bounds.minX - hexW) / hexW);\r\n const endCol = Math.ceil((bounds.maxX + hexW) / hexW);\r\n\r\n for (let row = startRow; row <= endRow; row++) {\r\n const offsetX = row % 2 !== 0 ? hexW / 2 : 0;\r\n for (let col = startCol; col <= endCol; col++) {\r\n centers.push({\r\n x: col * hexW + offsetX,\r\n y: row * rowH,\r\n });\r\n }\r\n }\r\n } else {\r\n const hexW = 2 * circumradius;\r\n const hexH = Math.sqrt(3) * circumradius;\r\n const colW = hexW * 0.75;\r\n\r\n const startCol = Math.floor((bounds.minX - circumradius) / colW);\r\n const endCol = Math.ceil((bounds.maxX + circumradius) / colW);\r\n const startRow = Math.floor((bounds.minY - hexH) / hexH);\r\n const endRow = Math.ceil((bounds.maxY + hexH) / hexH);\r\n\r\n for (let col = startCol; col <= endCol; col++) {\r\n const offsetY = col % 2 !== 0 ? hexH / 2 : 0;\r\n for (let row = startRow; row <= endRow; row++) {\r\n centers.push({\r\n x: col * colW,\r\n y: row * hexH + offsetY,\r\n });\r\n }\r\n }\r\n }\r\n\r\n return centers;\r\n}\r\n\r\nexport function renderSquareGrid(\r\n ctx: CanvasRenderingContext2D,\r\n bounds: VisibleBounds,\r\n cellSize: number,\r\n strokeColor: string,\r\n strokeWidth: number,\r\n opacity: number,\r\n): void {\r\n if (cellSize <= 0) return;\r\n\r\n const { verticals, horizontals } = getSquareGridLines(bounds, cellSize);\r\n\r\n ctx.save();\r\n ctx.strokeStyle = strokeColor;\r\n ctx.lineWidth = strokeWidth;\r\n ctx.globalAlpha *= opacity;\r\n ctx.beginPath();\r\n\r\n for (const x of verticals) {\r\n ctx.moveTo(x, bounds.minY);\r\n ctx.lineTo(x, bounds.maxY);\r\n }\r\n for (const y of horizontals) {\r\n ctx.moveTo(bounds.minX, y);\r\n ctx.lineTo(bounds.maxX, y);\r\n }\r\n\r\n ctx.stroke();\r\n ctx.restore();\r\n}\r\n\r\nexport function renderHexGrid(\r\n ctx: CanvasRenderingContext2D,\r\n bounds: VisibleBounds,\r\n cellSize: number,\r\n orientation: HexOrientation,\r\n strokeColor: string,\r\n strokeWidth: number,\r\n opacity: number,\r\n): void {\r\n if (cellSize <= 0) return;\r\n\r\n // Precompute 6 vertex offsets once (12 trig calls total, not 12 per hex)\r\n const angleOffset = orientation === 'pointy' ? -Math.PI / 2 : 0;\r\n const ox0 = cellSize * Math.cos(angleOffset);\r\n const oy0 = cellSize * Math.sin(angleOffset);\r\n const ox1 = cellSize * Math.cos(Math.PI / 3 + angleOffset);\r\n const oy1 = cellSize * Math.sin(Math.PI / 3 + angleOffset);\r\n const ox2 = cellSize * Math.cos((2 * Math.PI) / 3 + angleOffset);\r\n const oy2 = cellSize * Math.sin((2 * Math.PI) / 3 + angleOffset);\r\n const ox3 = cellSize * Math.cos(Math.PI + angleOffset);\r\n const oy3 = cellSize * Math.sin(Math.PI + angleOffset);\r\n const ox4 = cellSize * Math.cos((4 * Math.PI) / 3 + angleOffset);\r\n const oy4 = cellSize * Math.sin((4 * Math.PI) / 3 + angleOffset);\r\n const ox5 = cellSize * Math.cos((5 * Math.PI) / 3 + angleOffset);\r\n const oy5 = cellSize * Math.sin((5 * Math.PI) / 3 + angleOffset);\r\n\r\n ctx.save();\r\n ctx.strokeStyle = strokeColor;\r\n ctx.lineWidth = strokeWidth;\r\n ctx.globalAlpha *= opacity;\r\n ctx.beginPath();\r\n\r\n // Inline center iteration — zero allocations per hex\r\n if (orientation === 'pointy') {\r\n const hexW = Math.sqrt(3) * cellSize;\r\n const rowH = 1.5 * cellSize;\r\n\r\n const startRow = Math.floor((bounds.minY - cellSize) / rowH);\r\n const endRow = Math.ceil((bounds.maxY + cellSize) / rowH);\r\n const startCol = Math.floor((bounds.minX - hexW) / hexW);\r\n const endCol = Math.ceil((bounds.maxX + hexW) / hexW);\r\n\r\n for (let row = startRow; row <= endRow; row++) {\r\n const offX = row % 2 !== 0 ? hexW / 2 : 0;\r\n for (let col = startCol; col <= endCol; col++) {\r\n const cx = col * hexW + offX;\r\n const cy = row * rowH;\r\n ctx.moveTo(cx + ox0, cy + oy0);\r\n ctx.lineTo(cx + ox1, cy + oy1);\r\n ctx.lineTo(cx + ox2, cy + oy2);\r\n ctx.lineTo(cx + ox3, cy + oy3);\r\n ctx.lineTo(cx + ox4, cy + oy4);\r\n ctx.lineTo(cx + ox5, cy + oy5);\r\n ctx.closePath();\r\n }\r\n }\r\n } else {\r\n const hexH = Math.sqrt(3) * cellSize;\r\n const colW = 1.5 * cellSize;\r\n\r\n const startCol = Math.floor((bounds.minX - cellSize) / colW);\r\n const endCol = Math.ceil((bounds.maxX + cellSize) / colW);\r\n const startRow = Math.floor((bounds.minY - hexH) / hexH);\r\n const endRow = Math.ceil((bounds.maxY + hexH) / hexH);\r\n\r\n for (let col = startCol; col <= endCol; col++) {\r\n const offY = col % 2 !== 0 ? hexH / 2 : 0;\r\n for (let row = startRow; row <= endRow; row++) {\r\n const cx = col * colW;\r\n const cy = row * hexH + offY;\r\n ctx.moveTo(cx + ox0, cy + oy0);\r\n ctx.lineTo(cx + ox1, cy + oy1);\r\n ctx.lineTo(cx + ox2, cy + oy2);\r\n ctx.lineTo(cx + ox3, cy + oy3);\r\n ctx.lineTo(cx + ox4, cy + oy4);\r\n ctx.lineTo(cx + ox5, cy + oy5);\r\n ctx.closePath();\r\n }\r\n }\r\n }\r\n\r\n ctx.stroke();\r\n ctx.restore();\r\n}\r\n\r\nexport interface HexGridTile {\r\n canvas: HTMLCanvasElement | OffscreenCanvas;\r\n tileW: number;\r\n tileH: number;\r\n}\r\n\r\nexport function createHexGridTile(\r\n cellSize: number,\r\n orientation: HexOrientation,\r\n strokeColor: string,\r\n strokeWidth: number,\r\n opacity: number,\r\n scale: number,\r\n): HexGridTile | null {\r\n let tileW: number;\r\n let tileH: number;\r\n if (orientation === 'pointy') {\r\n tileW = Math.sqrt(3) * cellSize;\r\n tileH = 3 * cellSize;\r\n } else {\r\n tileW = 3 * cellSize;\r\n tileH = Math.sqrt(3) * cellSize;\r\n }\r\n\r\n const pxW = Math.ceil(tileW * scale);\r\n const pxH = Math.ceil(tileH * scale);\r\n if (pxW <= 0 || pxH <= 0) return null;\r\n\r\n let canvas: HTMLCanvasElement | OffscreenCanvas;\r\n if (typeof OffscreenCanvas !== 'undefined') {\r\n canvas = new OffscreenCanvas(pxW, pxH);\r\n } else if (typeof document !== 'undefined') {\r\n const el = document.createElement('canvas');\r\n el.width = pxW;\r\n el.height = pxH;\r\n canvas = el;\r\n } else {\r\n return null;\r\n }\r\n\r\n const tc = canvas.getContext('2d') as CanvasRenderingContext2D | null;\r\n if (!tc) return null;\r\n\r\n tc.scale(scale, scale);\r\n tc.beginPath();\r\n tc.rect(0, 0, tileW, tileH);\r\n tc.clip();\r\n\r\n const angleOffset = orientation === 'pointy' ? -Math.PI / 2 : 0;\r\n const ox0 = cellSize * Math.cos(angleOffset);\r\n const oy0 = cellSize * Math.sin(angleOffset);\r\n const ox1 = cellSize * Math.cos(Math.PI / 3 + angleOffset);\r\n const oy1 = cellSize * Math.sin(Math.PI / 3 + angleOffset);\r\n const ox2 = cellSize * Math.cos((2 * Math.PI) / 3 + angleOffset);\r\n const oy2 = cellSize * Math.sin((2 * Math.PI) / 3 + angleOffset);\r\n const ox3 = cellSize * Math.cos(Math.PI + angleOffset);\r\n const oy3 = cellSize * Math.sin(Math.PI + angleOffset);\r\n const ox4 = cellSize * Math.cos((4 * Math.PI) / 3 + angleOffset);\r\n const oy4 = cellSize * Math.sin((4 * Math.PI) / 3 + angleOffset);\r\n const ox5 = cellSize * Math.cos((5 * Math.PI) / 3 + angleOffset);\r\n const oy5 = cellSize * Math.sin((5 * Math.PI) / 3 + angleOffset);\r\n\r\n tc.strokeStyle = strokeColor;\r\n tc.lineWidth = strokeWidth;\r\n tc.globalAlpha = opacity;\r\n tc.beginPath();\r\n\r\n if (orientation === 'pointy') {\r\n const hexW = tileW;\r\n const rowH = 1.5 * cellSize;\r\n for (let row = -1; row <= 3; row++) {\r\n const offX = row % 2 !== 0 ? hexW / 2 : 0;\r\n for (let col = -1; col <= 1; col++) {\r\n const cx = col * hexW + offX;\r\n const cy = row * rowH;\r\n tc.moveTo(cx + ox0, cy + oy0);\r\n tc.lineTo(cx + ox1, cy + oy1);\r\n tc.lineTo(cx + ox2, cy + oy2);\r\n tc.lineTo(cx + ox3, cy + oy3);\r\n tc.lineTo(cx + ox4, cy + oy4);\r\n tc.lineTo(cx + ox5, cy + oy5);\r\n tc.closePath();\r\n }\r\n }\r\n } else {\r\n const hexH = tileH;\r\n const colW = 1.5 * cellSize;\r\n for (let col = -1; col <= 3; col++) {\r\n const offY = col % 2 !== 0 ? hexH / 2 : 0;\r\n for (let row = -1; row <= 1; row++) {\r\n const cx = col * colW;\r\n const cy = row * hexH + offY;\r\n tc.moveTo(cx + ox0, cy + oy0);\r\n tc.lineTo(cx + ox1, cy + oy1);\r\n tc.lineTo(cx + ox2, cy + oy2);\r\n tc.lineTo(cx + ox3, cy + oy3);\r\n tc.lineTo(cx + ox4, cy + oy4);\r\n tc.lineTo(cx + ox5, cy + oy5);\r\n tc.closePath();\r\n }\r\n }\r\n }\r\n\r\n tc.stroke();\r\n return { canvas, tileW, tileH };\r\n}\r\n\r\nexport function renderHexGridTiled(\r\n ctx: CanvasRenderingContext2D,\r\n bounds: VisibleBounds,\r\n cellSize: number,\r\n tile: HexGridTile,\r\n): void {\r\n const { tileW, tileH } = tile;\r\n\r\n const startCol = Math.floor(bounds.minX / tileW) - 1;\r\n const endCol = Math.ceil(bounds.maxX / tileW) + 1;\r\n const startRow = Math.floor(bounds.minY / tileH) - 1;\r\n const endRow = Math.ceil(bounds.maxY / tileH) + 1;\r\n\r\n for (let row = startRow; row <= endRow; row++) {\r\n for (let col = startCol; col <= endCol; col++) {\r\n ctx.drawImage(tile.canvas as CanvasImageSource, col * tileW, row * tileH, tileW, tileH);\r\n }\r\n }\r\n}\r\n","import type { CanvasElement, GridElement } from './types';\r\nimport { getElementBounds } from './element-bounds';\r\nimport { withRotation } from './rotate-canvas';\r\nimport { renderStroke } from './renderers/stroke-renderer';\r\nimport { renderShape } from './renderers/shape-renderer';\r\nimport { renderArrow } from './renderers/arrow-renderer';\r\nimport { renderImage } from './renderers/image-renderer';\r\nimport { renderTemplate } from './renderers/template-renderer';\r\nimport type { ElementStore } from './element-store';\r\nimport {\r\n renderSquareGrid,\r\n renderHexGrid,\r\n createHexGridTile,\r\n renderHexGridTiled,\r\n} from './grid-renderer';\r\nimport type { HexGridTile } from './grid-renderer';\r\nimport type { HexOrientation } from './types';\r\nimport type { Camera } from '../canvas/camera';\r\n\r\nconst DOM_ELEMENT_TYPES = new Set(['note', 'html', 'text']);\r\n\r\nexport class ElementRenderer {\r\n private store: ElementStore | null = null;\r\n private imageCache = new Map<string, ImageBitmap | HTMLImageElement | 'failed'>();\r\n private onImageLoad: (() => void) | null = null;\r\n private onImageError: ((src: string, cause?: unknown) => void) | null = null;\r\n private camera: Camera | null = null;\r\n private canvasSize: { w: number; h: number } | null = null;\r\n private hexTileCache: HexGridTile | null = null;\r\n private hexTileCacheKey = '';\r\n private gridBoundsOverride: { minX: number; minY: number; maxX: number; maxY: number } | null =\r\n null;\r\n private labelEditingId: string | null = null;\r\n\r\n setStore(store: ElementStore): void {\r\n this.store = store;\r\n }\r\n\r\n setOnImageLoad(callback: () => void): void {\r\n this.onImageLoad = callback;\r\n }\r\n\r\n setOnImageError(callback: (src: string, cause?: unknown) => void): void {\r\n this.onImageError = callback;\r\n }\r\n\r\n setCamera(camera: Camera): void {\r\n this.camera = camera;\r\n }\r\n\r\n setCanvasSize(w: number, h: number): void {\r\n this.canvasSize = { w, h };\r\n }\r\n\r\n setGridBoundsOverride(\r\n bounds: { minX: number; minY: number; maxX: number; maxY: number } | null,\r\n ): void {\r\n this.gridBoundsOverride = bounds;\r\n }\r\n\r\n setLabelEditingId(id: string | null): void {\r\n this.labelEditingId = id;\r\n }\r\n\r\n isDomElement(element: CanvasElement): boolean {\r\n return DOM_ELEMENT_TYPES.has(element.type);\r\n }\r\n\r\n renderCanvasElement(ctx: CanvasRenderingContext2D, element: CanvasElement): void {\r\n switch (element.type) {\r\n case 'stroke': {\r\n const b = getElementBounds(element);\r\n const c = b ? { x: b.x + b.w / 2, y: b.y + b.h / 2 } : element.position;\r\n withRotation(ctx, element, c, () => renderStroke(ctx, element));\r\n break;\r\n }\r\n case 'arrow':\r\n renderArrow(ctx, element, this.store, this.labelEditingId);\r\n break;\r\n case 'shape': {\r\n const b = getElementBounds(element);\r\n const c = b ? { x: b.x + b.w / 2, y: b.y + b.h / 2 } : element.position;\r\n withRotation(ctx, element, c, () => renderShape(ctx, element));\r\n break;\r\n }\r\n case 'image': {\r\n const b = getElementBounds(element);\r\n const c = b ? { x: b.x + b.w / 2, y: b.y + b.h / 2 } : element.position;\r\n withRotation(ctx, element, c, () =>\r\n renderImage(ctx, element, this.imageCache, this.onImageLoad, this.onImageError),\r\n );\r\n break;\r\n }\r\n case 'grid':\r\n this.renderGrid(ctx, element);\r\n break;\r\n case 'template':\r\n renderTemplate(ctx, element, this.store);\r\n break;\r\n }\r\n }\r\n\r\n private renderGrid(ctx: CanvasRenderingContext2D, grid: GridElement): void {\r\n const canvasSize = this.canvasSize;\r\n if (!canvasSize) return;\r\n\r\n const cam = this.camera;\r\n if (!cam) return;\r\n\r\n const bounds =\r\n this.gridBoundsOverride ??\r\n (() => {\r\n const topLeft = cam.screenToWorld({ x: 0, y: 0 });\r\n const bottomRight = cam.screenToWorld({ x: canvasSize.w, y: canvasSize.h });\r\n return {\r\n minX: topLeft.x,\r\n minY: topLeft.y,\r\n maxX: bottomRight.x,\r\n maxY: bottomRight.y,\r\n };\r\n })();\r\n\r\n if (grid.gridType === 'hex') {\r\n const dpr = typeof devicePixelRatio !== 'undefined' ? devicePixelRatio : 1;\r\n const scale = cam.zoom * dpr;\r\n const tile = this.getHexTile(\r\n grid.cellSize,\r\n grid.hexOrientation,\r\n grid.strokeColor,\r\n grid.strokeWidth,\r\n grid.opacity,\r\n scale,\r\n );\r\n if (tile) {\r\n renderHexGridTiled(ctx, bounds, grid.cellSize, tile);\r\n } else {\r\n renderHexGrid(\r\n ctx,\r\n bounds,\r\n grid.cellSize,\r\n grid.hexOrientation,\r\n grid.strokeColor,\r\n grid.strokeWidth,\r\n grid.opacity,\r\n );\r\n }\r\n } else {\r\n renderSquareGrid(\r\n ctx,\r\n bounds,\r\n grid.cellSize,\r\n grid.strokeColor,\r\n grid.strokeWidth,\r\n grid.opacity,\r\n );\r\n }\r\n }\r\n\r\n private getHexTile(\r\n cellSize: number,\r\n orientation: HexOrientation,\r\n strokeColor: string,\r\n strokeWidth: number,\r\n opacity: number,\r\n scale: number,\r\n ): HexGridTile | null {\r\n const key = `${cellSize}:${orientation}:${strokeColor}:${strokeWidth}:${opacity}:${scale}`;\r\n if (this.hexTileCacheKey === key && this.hexTileCache) {\r\n return this.hexTileCache;\r\n }\r\n const tile = createHexGridTile(cellSize, orientation, strokeColor, strokeWidth, opacity, scale);\r\n if (tile) {\r\n this.hexTileCache = tile;\r\n this.hexTileCacheKey = key;\r\n }\r\n return tile;\r\n }\r\n}\r\n","import type { Point, Size, StrokePoint } from '../core/types';\r\nimport type {\r\n Binding,\r\n StrokeElement,\r\n NoteElement,\r\n ArrowElement,\r\n ArrowStrokeStyle,\r\n ImageElement,\r\n HtmlElement,\r\n TextElement,\r\n ShapeElement,\r\n ShapeKind,\r\n GridElement,\r\n HexOrientation,\r\n TemplateElement,\r\n TemplateShape,\r\n TemplateRenderStyle,\r\n} from './types';\r\nimport { createId } from './create-id';\r\nimport { getArrowControlPoint } from './arrow-geometry';\r\nimport { sanitizeNoteHtml } from './note-sanitizer';\r\n\r\nexport const DEFAULT_NOTE_FONT_SIZE = 18;\r\n\r\ninterface BaseDefaults {\r\n position?: Point;\r\n zIndex?: number;\r\n locked?: boolean;\r\n layerId?: string;\r\n}\r\n\r\ninterface StrokeInput extends BaseDefaults {\r\n points: StrokePoint[];\r\n color?: string;\r\n width?: number;\r\n opacity?: number;\r\n blendMode?: 'multiply';\r\n}\r\n\r\ninterface NoteInput extends BaseDefaults {\r\n position: Point;\r\n size?: Size;\r\n text?: string;\r\n backgroundColor?: string;\r\n textColor?: string;\r\n fontSize?: number;\r\n}\r\n\r\ninterface ArrowInput extends BaseDefaults {\r\n from: Point;\r\n to: Point;\r\n bend?: number;\r\n color?: string;\r\n width?: number;\r\n fromBinding?: Binding;\r\n toBinding?: Binding;\r\n label?: string;\r\n strokeStyle?: ArrowStrokeStyle;\r\n}\r\n\r\ninterface ImageInput extends BaseDefaults {\r\n position: Point;\r\n size: Size;\r\n src: string;\r\n}\r\n\r\ninterface HtmlInput extends BaseDefaults {\r\n position: Point;\r\n size: Size;\r\n domId?: string;\r\n interactive?: boolean;\r\n htmlType?: string;\r\n data?: Record<string, unknown>;\r\n}\r\n\r\ninterface TextInput extends BaseDefaults {\r\n position: Point;\r\n size?: Size;\r\n text?: string;\r\n fontSize?: number;\r\n color?: string;\r\n textAlign?: 'left' | 'center' | 'right';\r\n}\r\n\r\nexport function createStroke(input: StrokeInput): StrokeElement {\r\n const result: StrokeElement = {\r\n id: createId('stroke'),\r\n type: 'stroke',\r\n position: input.position ?? { x: 0, y: 0 },\r\n zIndex: input.zIndex ?? 0,\r\n locked: input.locked ?? false,\r\n layerId: input.layerId ?? '',\r\n points: input.points,\r\n color: input.color ?? '#000000',\r\n width: input.width ?? 2,\r\n opacity: input.opacity ?? 1,\r\n };\r\n if (input.blendMode) result.blendMode = input.blendMode;\r\n return result;\r\n}\r\n\r\nexport function createNote(input: NoteInput): NoteElement {\r\n return {\r\n id: createId('note'),\r\n type: 'note',\r\n position: input.position,\r\n zIndex: input.zIndex ?? 0,\r\n locked: input.locked ?? false,\r\n layerId: input.layerId ?? '',\r\n size: input.size ?? { w: 200, h: 100 },\r\n text: sanitizeNoteHtml(input.text ?? ''),\r\n backgroundColor: input.backgroundColor ?? '#ffeb3b',\r\n textColor: input.textColor ?? '#000000',\r\n fontSize: input.fontSize ?? DEFAULT_NOTE_FONT_SIZE,\r\n };\r\n}\r\n\r\nexport function createArrow(input: ArrowInput): ArrowElement {\r\n const bend = input.bend ?? 0;\r\n const result: ArrowElement = {\r\n id: createId('arrow'),\r\n type: 'arrow',\r\n position: input.position ?? { x: 0, y: 0 },\r\n zIndex: input.zIndex ?? 0,\r\n locked: input.locked ?? false,\r\n layerId: input.layerId ?? '',\r\n from: input.from,\r\n to: input.to,\r\n bend,\r\n color: input.color ?? '#000000',\r\n width: input.width ?? 2,\r\n cachedControlPoint: getArrowControlPoint(input.from, input.to, bend),\r\n };\r\n if (input.fromBinding) result.fromBinding = input.fromBinding;\r\n if (input.toBinding) result.toBinding = input.toBinding;\r\n if (input.label !== undefined) result.label = input.label;\r\n if (input.strokeStyle !== undefined) result.strokeStyle = input.strokeStyle;\r\n return result;\r\n}\r\n\r\nexport function createImage(input: ImageInput): ImageElement {\r\n return {\r\n id: createId('image'),\r\n type: 'image',\r\n position: input.position,\r\n zIndex: input.zIndex ?? 0,\r\n locked: input.locked ?? false,\r\n layerId: input.layerId ?? '',\r\n size: input.size,\r\n src: input.src,\r\n };\r\n}\r\n\r\nexport function createHtmlElement(input: HtmlInput): HtmlElement {\r\n const el: HtmlElement = {\r\n id: createId('html'),\r\n type: 'html',\r\n position: input.position,\r\n zIndex: input.zIndex ?? 0,\r\n locked: input.locked ?? false,\r\n layerId: input.layerId ?? '',\r\n size: input.size,\r\n };\r\n if (input.domId) el.domId = input.domId;\r\n if (input.interactive) el.interactive = input.interactive;\r\n if (input.htmlType) el.htmlType = input.htmlType;\r\n if (input.data) el.data = input.data;\r\n return el;\r\n}\r\n\r\ninterface ShapeInput extends BaseDefaults {\r\n position: Point;\r\n size: Size;\r\n shape?: ShapeKind;\r\n strokeColor?: string;\r\n strokeWidth?: number;\r\n fillColor?: string;\r\n flip?: boolean;\r\n}\r\n\r\nexport function createShape(input: ShapeInput): ShapeElement {\r\n const result: ShapeElement = {\r\n id: createId('shape'),\r\n type: 'shape',\r\n position: input.position,\r\n zIndex: input.zIndex ?? 0,\r\n locked: input.locked ?? false,\r\n layerId: input.layerId ?? '',\r\n shape: input.shape ?? 'rectangle',\r\n size: input.size,\r\n strokeColor: input.strokeColor ?? '#000000',\r\n strokeWidth: input.strokeWidth ?? 2,\r\n fillColor: input.fillColor ?? 'none',\r\n };\r\n if (input.flip) result.flip = input.flip;\r\n return result;\r\n}\r\n\r\ninterface GridInput extends BaseDefaults {\r\n gridType?: 'square' | 'hex';\r\n hexOrientation?: HexOrientation;\r\n cellSize?: number;\r\n strokeColor?: string;\r\n strokeWidth?: number;\r\n opacity?: number;\r\n}\r\n\r\nexport function createGrid(input: GridInput): GridElement {\r\n return {\r\n id: createId('grid'),\r\n type: 'grid',\r\n position: input.position ?? { x: 0, y: 0 },\r\n zIndex: input.zIndex ?? 0,\r\n locked: input.locked ?? false,\r\n layerId: input.layerId ?? '',\r\n gridType: input.gridType ?? 'square',\r\n hexOrientation: input.hexOrientation ?? 'pointy',\r\n cellSize: input.cellSize ?? 40,\r\n strokeColor: input.strokeColor ?? '#000000',\r\n strokeWidth: input.strokeWidth ?? 1,\r\n opacity: input.opacity ?? 1,\r\n };\r\n}\r\n\r\nexport function createText(input: TextInput): TextElement {\r\n return {\r\n id: createId('text'),\r\n type: 'text',\r\n position: input.position,\r\n zIndex: input.zIndex ?? 0,\r\n locked: input.locked ?? false,\r\n layerId: input.layerId ?? '',\r\n size: input.size ?? { w: 200, h: 28 },\r\n text: sanitizeNoteHtml(input.text ?? ''),\r\n fontSize: input.fontSize ?? 16,\r\n color: input.color ?? '#1a1a1a',\r\n textAlign: input.textAlign ?? 'left',\r\n };\r\n}\r\n\r\ninterface TemplateInput extends BaseDefaults {\r\n position: Point;\r\n templateShape: TemplateShape;\r\n radius: number;\r\n angle?: number;\r\n width?: number;\r\n fillColor?: string;\r\n strokeColor?: string;\r\n strokeWidth?: number;\r\n opacity?: number;\r\n feetPerCell?: number;\r\n radiusFeet?: number;\r\n renderStyle?: TemplateRenderStyle;\r\n}\r\n\r\nexport function createTemplate(input: TemplateInput): TemplateElement {\r\n return {\r\n id: createId('template'),\r\n type: 'template',\r\n position: input.position,\r\n zIndex: input.zIndex ?? 0,\r\n locked: input.locked ?? false,\r\n layerId: input.layerId ?? '',\r\n templateShape: input.templateShape,\r\n radius: input.radius,\r\n angle: input.angle ?? 0,\r\n fillColor: input.fillColor ?? 'rgba(255, 87, 34, 0.2)',\r\n strokeColor: input.strokeColor ?? '#FF5722',\r\n strokeWidth: input.strokeWidth ?? 2,\r\n opacity: input.opacity ?? 0.6,\r\n feetPerCell: input.feetPerCell,\r\n radiusFeet: input.radiusFeet,\r\n ...(input.renderStyle !== undefined ? { renderStyle: input.renderStyle } : {}),\r\n ...(input.width !== undefined ? { width: input.width } : {}),\r\n };\r\n}\r\n","export interface ActiveFormats {\r\n bold: boolean;\r\n italic: boolean;\r\n underline: boolean;\r\n strikethrough: boolean;\r\n}\r\n\r\nexport function toggleBold(): void {\r\n document.execCommand('bold');\r\n}\r\n\r\nexport function toggleItalic(): void {\r\n document.execCommand('italic');\r\n}\r\n\r\nexport function toggleUnderline(): void {\r\n document.execCommand('underline');\r\n}\r\n\r\nexport function toggleStrikethrough(): void {\r\n document.execCommand('strikeThrough');\r\n}\r\n\r\nexport function setFontSize(size: number): void {\r\n const sel = window.getSelection();\r\n if (!sel || sel.rangeCount === 0) return;\r\n\r\n const range = sel.getRangeAt(0);\r\n if (range.collapsed) return;\r\n\r\n const span = document.createElement('span');\r\n span.style.fontSize = `${size}px`;\r\n try {\r\n range.surroundContents(span);\r\n } catch {\r\n span.appendChild(range.extractContents());\r\n range.insertNode(span);\r\n }\r\n}\r\n\r\nexport function getActiveFormats(): ActiveFormats {\r\n const query = (cmd: string): boolean => {\r\n try {\r\n return document.queryCommandState(cmd);\r\n } catch {\r\n return false;\r\n }\r\n };\r\n\r\n return {\r\n bold: query('bold'),\r\n italic: query('italic'),\r\n underline: query('underline'),\r\n strikethrough: query('strikeThrough'),\r\n };\r\n}\r\n","import { DEFAULT_NOTE_FONT_SIZE } from './element-factory';\r\nimport { setFontSize, getActiveFormats } from './note-formatting';\r\n\r\nconst TOOLBAR_HEIGHT = 52;\r\nconst TOOLBAR_GAP = 4;\r\n\r\ninterface FormatButton {\r\n label: string;\r\n format: string;\r\n command: string;\r\n}\r\n\r\nconst FORMAT_BUTTONS: FormatButton[] = [\r\n { label: 'B', format: 'bold', command: 'bold' },\r\n { label: 'I', format: 'italic', command: 'italic' },\r\n { label: 'U', format: 'underline', command: 'underline' },\r\n { label: 'S', format: 'strikethrough', command: 'strikeThrough' },\r\n];\r\n\r\nexport interface FontSizePreset {\r\n label: string;\r\n size: number;\r\n}\r\n\r\nexport const DEFAULT_FONT_SIZE_PRESETS: FontSizePreset[] = [\r\n { label: 'Small', size: 14 },\r\n { label: 'Normal', size: 18 },\r\n { label: 'Large', size: 24 },\r\n { label: 'Heading', size: 32 },\r\n];\r\n\r\nexport class NoteToolbar {\r\n private el: HTMLDivElement | null = null;\r\n private anchor: HTMLElement | null = null;\r\n private selectionListener: (() => void) | null = null;\r\n private readonly fontSizePresets: FontSizePreset[];\r\n\r\n constructor(fontSizePresets?: FontSizePreset[]) {\r\n this.fontSizePresets = fontSizePresets ?? DEFAULT_FONT_SIZE_PRESETS;\r\n }\r\n\r\n show(anchor: HTMLElement): void {\r\n this.hide();\r\n this.anchor = anchor;\r\n this.el = this.createToolbarElement();\r\n document.body.appendChild(this.el);\r\n this.positionToolbar(anchor);\r\n this.selectionListener = () => this.updateActiveStates();\r\n document.addEventListener('selectionchange', this.selectionListener);\r\n }\r\n\r\n hide(): void {\r\n if (this.selectionListener) {\r\n document.removeEventListener('selectionchange', this.selectionListener);\r\n this.selectionListener = null;\r\n }\r\n if (this.el) {\r\n this.el.remove();\r\n this.el = null;\r\n }\r\n this.anchor = null;\r\n }\r\n\r\n getElement(): HTMLDivElement | null {\r\n return this.el;\r\n }\r\n\r\n updatePosition(anchor: HTMLElement): void {\r\n if (this.el) {\r\n this.positionToolbar(anchor);\r\n }\r\n }\r\n\r\n private createToolbarElement(): HTMLDivElement {\r\n const toolbar = document.createElement('div');\r\n toolbar.dataset['noteToolbar'] = '';\r\n Object.assign(toolbar.style, {\r\n position: 'fixed',\r\n display: 'flex',\r\n alignItems: 'center',\r\n gap: '2px',\r\n padding: '2px 4px',\r\n background: '#fff',\r\n border: '1px solid #ccc',\r\n borderRadius: '4px',\r\n boxShadow: '0 2px 8px rgba(0,0,0,0.15)',\r\n zIndex: '10000',\r\n height: `${TOOLBAR_HEIGHT}px`,\r\n userSelect: 'none',\r\n });\r\n\r\n for (const btn of FORMAT_BUTTONS) {\r\n toolbar.appendChild(this.createFormatButton(btn));\r\n }\r\n\r\n toolbar.appendChild(this.createFontSizeSelect());\r\n\r\n return toolbar;\r\n }\r\n\r\n private createFormatButton(config: FormatButton): HTMLButtonElement {\r\n const btn = document.createElement('button');\r\n btn.dataset['format'] = config.format;\r\n btn.textContent = config.label;\r\n Object.assign(btn.style, {\r\n border: '1px solid transparent',\r\n borderRadius: '3px',\r\n background: 'none',\r\n cursor: 'pointer',\r\n padding: '2px 6px',\r\n fontSize: '13px',\r\n fontWeight: config.format === 'bold' ? 'bold' : 'normal',\r\n fontStyle: config.format === 'italic' ? 'italic' : 'normal',\r\n textDecoration:\r\n config.format === 'underline'\r\n ? 'underline'\r\n : config.format === 'strikethrough'\r\n ? 'line-through'\r\n : 'none',\r\n minWidth: '44px',\r\n height: '44px',\r\n lineHeight: '44px',\r\n });\r\n\r\n btn.addEventListener('pointerdown', (e) => {\r\n e.preventDefault();\r\n document.execCommand(config.command);\r\n this.updateActiveStates();\r\n });\r\n\r\n return btn;\r\n }\r\n\r\n private createFontSizeSelect(): HTMLSelectElement {\r\n const select = document.createElement('select');\r\n Object.assign(select.style, {\r\n border: '1px solid #ccc',\r\n borderRadius: '3px',\r\n background: '#fff',\r\n cursor: 'pointer',\r\n padding: '2px',\r\n fontSize: '12px',\r\n height: '44px',\r\n marginLeft: '4px',\r\n });\r\n\r\n for (const preset of this.fontSizePresets) {\r\n const option = document.createElement('option');\r\n option.value = String(preset.size);\r\n option.textContent = preset.label;\r\n select.appendChild(option);\r\n }\r\n\r\n select.value = String(DEFAULT_NOTE_FONT_SIZE);\r\n\r\n select.addEventListener('pointerdown', (e) => {\r\n e.stopPropagation();\r\n });\r\n\r\n select.addEventListener('change', () => {\r\n this.applyFontSize(Number(select.value));\r\n this.updateActiveStates();\r\n this.anchor?.focus();\r\n });\r\n\r\n return select;\r\n }\r\n\r\n private applyFontSize(size: number): void {\r\n const sel = window.getSelection();\r\n const collapsed = !sel || sel.rangeCount === 0 || sel.getRangeAt(0).collapsed;\r\n if (collapsed && this.anchor) {\r\n const range = document.createRange();\r\n range.selectNodeContents(this.anchor);\r\n sel?.removeAllRanges();\r\n sel?.addRange(range);\r\n setFontSize(size);\r\n const after = window.getSelection();\r\n if (after) {\r\n const caret = document.createRange();\r\n caret.selectNodeContents(this.anchor);\r\n caret.collapse(false);\r\n after.removeAllRanges();\r\n after.addRange(caret);\r\n }\r\n return;\r\n }\r\n setFontSize(size);\r\n }\r\n\r\n private positionToolbar(anchor: HTMLElement): void {\r\n if (!this.el) return;\r\n\r\n const rect = anchor.getBoundingClientRect();\r\n const toolbarWidth = this.el.offsetWidth || 200;\r\n\r\n let top = rect.top - TOOLBAR_HEIGHT - TOOLBAR_GAP;\r\n if (top < 0) {\r\n top = rect.bottom + TOOLBAR_GAP;\r\n }\r\n\r\n let left = rect.left + (rect.width - toolbarWidth) / 2;\r\n left = Math.max(4, left);\r\n\r\n Object.assign(this.el.style, {\r\n top: `${top}px`,\r\n left: `${left}px`,\r\n });\r\n }\r\n\r\n private updateActiveStates(): void {\r\n if (!this.el) return;\r\n\r\n const active = getActiveFormats();\r\n for (const config of FORMAT_BUTTONS) {\r\n const btn = this.el.querySelector(`[data-format=\"${config.format}\"]`) as HTMLElement | null;\r\n if (!btn) continue;\r\n\r\n const isActive = active[config.format as keyof typeof active] ?? false;\r\n btn.style.background = isActive ? '#e0e0e0' : 'none';\r\n btn.style.borderColor = isActive ? '#bbb' : 'transparent';\r\n }\r\n }\r\n}\r\n","import type { ElementStore } from './element-store';\r\nimport { NoteToolbar } from './note-toolbar';\r\nimport type { FontSizePreset } from './note-toolbar';\r\nimport { sanitizeNoteHtml } from './note-sanitizer';\r\nimport { toggleBold, toggleItalic, toggleUnderline } from './note-formatting';\r\n\r\nconst FORMAT_SHORTCUTS: Record<string, () => void> = {\r\n b: toggleBold,\r\n i: toggleItalic,\r\n u: toggleUnderline,\r\n};\r\n\r\nexport interface NoteEditorOptions {\r\n fontSizePresets?: FontSizePreset[];\r\n toolbar?: boolean;\r\n placeholder?: string;\r\n}\r\n\r\nfunction ensureEditorStyles(): void {\r\n if (document.querySelector('style[data-fieldnotes-editor]')) return;\r\n const style = document.createElement('style');\r\n style.setAttribute('data-fieldnotes-editor', '');\r\n style.textContent = `[data-fn-placeholder][data-fn-empty='true']::before {\r\n content: attr(data-fn-placeholder);\r\n color: #9e9e9e;\r\n position: absolute;\r\n pointer-events: none;\r\n}`;\r\n document.head.appendChild(style);\r\n}\r\n\r\nfunction isNodeEmpty(node: HTMLElement): boolean {\r\n const text = node.textContent ?? '';\r\n return text.replace(/\\u00a0/g, ' ').trim().length === 0;\r\n}\r\n\r\nexport class NoteEditor {\r\n private editingId: string | null = null;\r\n private editingNode: HTMLDivElement | null = null;\r\n private blurHandler: ((e: FocusEvent) => void) | null = null;\r\n private keyHandler: ((e: KeyboardEvent) => void) | null = null;\r\n private pointerHandler: ((e: PointerEvent) => void) | null = null;\r\n private inputHandler: (() => void) | null = null;\r\n private pendingEditId: string | null = null;\r\n private onStopCallback: ((elementId: string) => void) | null = null;\r\n private onInputCallback: ((elementId: string) => void) | null = null;\r\n private beginHistory: (() => void) | null = null;\r\n private commitHistory: (() => void) | null = null;\r\n private toolbar: NoteToolbar | null;\r\n private readonly placeholder: string;\r\n\r\n constructor(options?: NoteEditorOptions) {\r\n this.toolbar = options?.toolbar === false ? null : new NoteToolbar(options?.fontSizePresets);\r\n this.placeholder = options?.placeholder ?? 'Type…';\r\n }\r\n\r\n get isEditing(): boolean {\r\n return this.editingId !== null;\r\n }\r\n\r\n get editingElementId(): string | null {\r\n return this.editingId;\r\n }\r\n\r\n setOnStop(callback: (elementId: string) => void): void {\r\n this.onStopCallback = callback;\r\n }\r\n\r\n setOnInput(callback: (elementId: string) => void): void {\r\n this.onInputCallback = callback;\r\n }\r\n\r\n setHistoryHooks(begin: () => void, commit: () => void): void {\r\n this.beginHistory = begin;\r\n this.commitHistory = commit;\r\n }\r\n\r\n startEditing(node: HTMLDivElement, elementId: string, store: ElementStore): void {\r\n if (this.editingId === elementId) return;\r\n\r\n if (this.editingId) {\r\n this.stopEditing(store);\r\n }\r\n\r\n this.pendingEditId = elementId;\r\n\r\n requestAnimationFrame(() => {\r\n if (this.pendingEditId !== elementId) return;\r\n this.pendingEditId = null;\r\n this.activateEditing(node, elementId, store);\r\n });\r\n }\r\n\r\n stopEditing(store: ElementStore): void {\r\n this.pendingEditId = null;\r\n\r\n if (!this.editingId || !this.editingNode) return;\r\n\r\n if (this.blurHandler) {\r\n this.editingNode.removeEventListener('blur', this.blurHandler);\r\n }\r\n if (this.keyHandler) {\r\n this.editingNode.removeEventListener('keydown', this.keyHandler);\r\n }\r\n if (this.pointerHandler) {\r\n this.editingNode.removeEventListener('pointerdown', this.pointerHandler);\r\n }\r\n if (this.inputHandler) {\r\n this.editingNode.removeEventListener('input', this.inputHandler);\r\n }\r\n this.editingNode.removeAttribute('data-fn-placeholder');\r\n this.editingNode.removeAttribute('data-fn-empty');\r\n\r\n const text = sanitizeNoteHtml(this.editingNode.innerHTML);\r\n const current = store.getById(this.editingId);\r\n const textChanged =\r\n !!current && (current.type === 'note' || current.type === 'text') && current.text !== text;\r\n\r\n this.editingNode.contentEditable = 'false';\r\n Object.assign(this.editingNode.style, {\r\n userSelect: 'none',\r\n cursor: 'default',\r\n });\r\n\r\n this.toolbar?.hide();\r\n\r\n // The history transaction spans the whole edit session: opened at activate, committed\r\n // here at stop. Live height fits during editing plus the final text write all touch the\r\n // same element, so the recorder coalesces them into one undo step.\r\n if (textChanged) {\r\n store.update(this.editingId, { text });\r\n }\r\n if (this.editingId && this.onStopCallback) {\r\n this.onStopCallback(this.editingId);\r\n }\r\n this.commitHistory?.();\r\n\r\n this.editingId = null;\r\n this.editingNode = null;\r\n this.blurHandler = null;\r\n this.keyHandler = null;\r\n this.pointerHandler = null;\r\n this.inputHandler = null;\r\n }\r\n\r\n destroy(store: ElementStore): void {\r\n this.pendingEditId = null;\r\n if (this.isEditing) {\r\n this.stopEditing(store);\r\n }\r\n }\r\n\r\n updateToolbarPosition(): void {\r\n if (this.editingNode) {\r\n this.toolbar?.updatePosition(this.editingNode);\r\n }\r\n }\r\n\r\n private activateEditing(node: HTMLDivElement, elementId: string, store: ElementStore): void {\r\n this.editingId = elementId;\r\n this.editingNode = node;\r\n this.beginHistory?.();\r\n\r\n node.contentEditable = 'true';\r\n Object.assign(node.style, {\r\n userSelect: 'text',\r\n cursor: 'text',\r\n outline: 'none',\r\n });\r\n node.focus();\r\n\r\n const selection = window.getSelection?.();\r\n if (selection) {\r\n const range = document.createRange();\r\n range.selectNodeContents(node);\r\n range.collapse(false);\r\n selection.removeAllRanges();\r\n selection.addRange(range);\r\n }\r\n\r\n ensureEditorStyles();\r\n node.setAttribute('data-fn-placeholder', this.placeholder);\r\n node.setAttribute('data-fn-empty', String(isNodeEmpty(node)));\r\n this.inputHandler = () => {\r\n node.setAttribute('data-fn-empty', String(isNodeEmpty(node)));\r\n this.onInputCallback?.(elementId);\r\n };\r\n node.addEventListener('input', this.inputHandler);\r\n\r\n this.toolbar?.show(node);\r\n\r\n this.blurHandler = (e: FocusEvent) => {\r\n const related = e.relatedTarget as Node | null;\r\n if (related && this.toolbar?.getElement()?.contains(related)) return;\r\n this.stopEditing(store);\r\n };\r\n this.keyHandler = (e: KeyboardEvent) => {\r\n if ((e.ctrlKey || e.metaKey) && !e.shiftKey && !e.altKey) {\r\n const action = FORMAT_SHORTCUTS[e.key.toLowerCase()];\r\n if (action) {\r\n e.preventDefault();\r\n action();\r\n return;\r\n }\r\n }\r\n if (e.key === 'Escape') {\r\n node.blur();\r\n }\r\n e.stopPropagation();\r\n };\r\n this.pointerHandler = (e: PointerEvent) => {\r\n e.stopPropagation();\r\n };\r\n\r\n node.addEventListener('blur', this.blurHandler);\r\n node.addEventListener('keydown', this.keyHandler);\r\n node.addEventListener('pointerdown', this.pointerHandler);\r\n }\r\n}\r\n","import type { Point } from '../core/types';\r\n\r\nexport interface ContextMenuItem {\r\n label: string;\r\n action: string;\r\n disabled?: boolean;\r\n}\r\n\r\nexport interface ContextMenuOptions {\r\n onCommand: (action: string) => void;\r\n onClose: () => void;\r\n}\r\n\r\nexport class ContextMenu {\r\n private el: HTMLDivElement | null = null;\r\n private outsideListener: ((e: PointerEvent) => void) | null = null;\r\n private keyListener: ((e: KeyboardEvent) => void) | null = null;\r\n\r\n constructor(private readonly options: ContextMenuOptions) {}\r\n\r\n isOpen(): boolean {\r\n return this.el !== null;\r\n }\r\n\r\n open(items: ContextMenuItem[], screenPos: Point): void {\r\n this.close();\r\n const el = document.createElement('div');\r\n el.className = 'fieldnotes-context-menu';\r\n Object.assign(el.style, {\r\n position: 'fixed',\r\n left: `${screenPos.x}px`,\r\n top: `${screenPos.y}px`,\r\n zIndex: '10000',\r\n display: 'flex',\r\n flexDirection: 'column',\r\n });\r\n for (const item of items) {\r\n const btn = document.createElement('button');\r\n btn.type = 'button';\r\n btn.className =\r\n 'fieldnotes-context-menu-item' +\r\n (item.disabled ? ' fieldnotes-context-menu-item--disabled' : '');\r\n btn.textContent = item.label;\r\n if (item.disabled) {\r\n btn.disabled = true;\r\n } else {\r\n btn.addEventListener('click', () => {\r\n this.options.onCommand(item.action);\r\n this.close();\r\n });\r\n }\r\n el.appendChild(btn);\r\n }\r\n document.body.appendChild(el);\r\n this.el = el;\r\n this.clampToViewport(el, screenPos);\r\n\r\n this.keyListener = (e: KeyboardEvent) => {\r\n if (e.key === 'Escape') this.close();\r\n };\r\n document.addEventListener('keydown', this.keyListener);\r\n\r\n this.outsideListener = (e: PointerEvent) => {\r\n if (this.el && !this.el.contains(e.target as Node)) this.close();\r\n };\r\n // Defer attaching so the opening gesture's own pointerdown doesn't immediately close it.\r\n setTimeout(() => {\r\n if (this.outsideListener) document.addEventListener('pointerdown', this.outsideListener);\r\n }, 0);\r\n }\r\n\r\n close(): void {\r\n if (this.keyListener) {\r\n document.removeEventListener('keydown', this.keyListener);\r\n this.keyListener = null;\r\n }\r\n if (this.outsideListener) {\r\n document.removeEventListener('pointerdown', this.outsideListener);\r\n this.outsideListener = null;\r\n }\r\n if (this.el) {\r\n this.el.remove();\r\n this.el = null;\r\n this.options.onClose();\r\n }\r\n }\r\n\r\n dispose(): void {\r\n this.close();\r\n }\r\n\r\n private clampToViewport(el: HTMLElement, screenPos: Point): void {\r\n const rect = el.getBoundingClientRect();\r\n if (rect.width > 0 && screenPos.x + rect.width > window.innerWidth) {\r\n el.style.left = `${Math.max(0, screenPos.x - rect.width)}px`;\r\n }\r\n if (rect.height > 0 && screenPos.y + rect.height > window.innerHeight) {\r\n el.style.top = `${Math.max(0, screenPos.y - rect.height)}px`;\r\n }\r\n }\r\n}\r\n","import type { Bounds, Point } from '../core/types';\r\n\r\nexport interface MinimapTransform {\r\n scale: number;\r\n offsetX: number;\r\n offsetY: number;\r\n}\r\n\r\nexport function unionBounds(a: Bounds, b: Bounds): Bounds {\r\n const minX = Math.min(a.x, b.x);\r\n const minY = Math.min(a.y, b.y);\r\n const maxX = Math.max(a.x + a.w, b.x + b.w);\r\n const maxY = Math.max(a.y + a.h, b.y + b.h);\r\n return { x: minX, y: minY, w: maxX - minX, h: maxY - minY };\r\n}\r\n\r\n// `mapping` is the union of the content bounds and the visible viewport, so the\r\n// minimap always frames both what exists and where the camera is looking.\r\nexport function computeMinimapTransform(\r\n mapping: Bounds,\r\n miniW: number,\r\n miniH: number,\r\n padding: number,\r\n): MinimapTransform {\r\n const availW = Math.max(1, miniW - 2 * padding);\r\n const availH = Math.max(1, miniH - 2 * padding);\r\n const w = Math.max(mapping.w, 1);\r\n const h = Math.max(mapping.h, 1);\r\n const scale = Math.min(availW / w, availH / h);\r\n const offsetX = (miniW - mapping.w * scale) / 2 - mapping.x * scale;\r\n const offsetY = (miniH - mapping.h * scale) / 2 - mapping.y * scale;\r\n return { scale, offsetX, offsetY };\r\n}\r\n\r\nexport function worldToMini(t: MinimapTransform, p: Point): Point {\r\n return { x: p.x * t.scale + t.offsetX, y: p.y * t.scale + t.offsetY };\r\n}\r\n\r\nexport function miniToWorld(t: MinimapTransform, p: Point): Point {\r\n return { x: (p.x - t.offsetX) / t.scale, y: (p.y - t.offsetY) / t.scale };\r\n}\r\n","import type { Bounds, Point } from '../core/types';\r\nimport type { CanvasElement } from '../elements/types';\r\nimport type { Viewport } from './viewport';\r\nimport { ElementRenderer } from '../elements/element-renderer';\r\nimport { getElementBounds } from '../elements/element-bounds';\r\nimport { getElementsBoundingBox } from '../elements/bounds';\r\nimport {\r\n computeMinimapTransform,\r\n miniToWorld,\r\n unionBounds,\r\n worldToMini,\r\n type MinimapTransform,\r\n} from './minimap-transform';\r\n\r\nexport interface MinimapControllerOptions {\r\n /** Minimap width in CSS pixels. Default `200`. */\r\n width?: number;\r\n /** Minimap height in CSS pixels. Default `140`. */\r\n height?: number;\r\n /** Content inset inside the minimap, in minimap pixels. Default `8`. */\r\n padding?: number;\r\n /** Backdrop fill behind the thumbnail. Default: none (transparent). */\r\n background?: string;\r\n /** Stroke color of the viewport rectangle. Default `'#3b82f6'`. */\r\n viewportStroke?: string;\r\n /** Trailing debounce for scene bitmap re-renders. Default `200`. */\r\n debounceMs?: number;\r\n /** Tap/drag-to-center navigation on the canvas. Default `true`. */\r\n interactive?: boolean;\r\n /** Frame scheduler; default `requestAnimationFrame`. Injected by tests. */\r\n requestFrame?: (cb: () => void) => number;\r\n /** Frame canceller; default `cancelAnimationFrame`. Injected by tests. */\r\n cancelFrame?: (id: number) => void;\r\n}\r\n\r\nconst DEFAULT_WIDTH = 200;\r\nconst DEFAULT_HEIGHT = 140;\r\nconst DEFAULT_PADDING = 8;\r\nconst DEFAULT_DEBOUNCE_MS = 200;\r\nconst DEFAULT_VIEWPORT_STROKE = '#3b82f6';\r\nconst NEUTRAL = 'rgba(100,116,139,0.6)';\r\nconst DOM_FALLBACK_TYPES = new Set(['note', 'text', 'html']);\r\n\r\nfunction elementColor(el: CanvasElement): string {\r\n return 'color' in el && typeof el.color === 'string' ? el.color : NEUTRAL;\r\n}\r\n\r\ninterface SceneCache {\r\n canvas: HTMLCanvasElement;\r\n transform: MinimapTransform;\r\n mapping: Bounds;\r\n}\r\n\r\nfunction sameBounds(a: Bounds, b: Bounds): boolean {\r\n return a.x === b.x && a.y === b.y && a.w === b.w && a.h === b.h;\r\n}\r\n\r\n/**\r\n * Thumbnail overview navigator: renders the scene (real element shapes,\r\n * downscaled images, per-layer opacity compositing) into a cached offscreen\r\n * bitmap, composites it with the live viewport rectangle each frame, and\r\n * centers the camera on tap/drag. The cached bitmap and its transform swap\r\n * atomically: camera motion never renders the scene, only re-composites.\r\n */\r\nexport class MinimapController {\r\n private width: number;\r\n private height: number;\r\n private readonly padding: number;\r\n private readonly background: string | null;\r\n private readonly viewportStroke: string;\r\n private readonly debounceMs: number;\r\n private readonly interactive: boolean;\r\n private readonly requestFrame: (cb: () => void) => number;\r\n private readonly cancelFrame: (id: number) => void;\r\n private readonly renderer = new ElementRenderer();\r\n private scene: SceneCache | null = null;\r\n private frameId: number | null = null;\r\n private debounceTimer: ReturnType<typeof setTimeout> | null = null;\r\n private dragging = false;\r\n private disposed = false;\r\n private readonly unsubs: (() => void)[] = [];\r\n\r\n constructor(\r\n private readonly viewport: Viewport,\r\n private readonly canvas: HTMLCanvasElement,\r\n options: MinimapControllerOptions = {},\r\n ) {\r\n this.width = options.width ?? DEFAULT_WIDTH;\r\n this.height = options.height ?? DEFAULT_HEIGHT;\r\n this.padding = options.padding ?? DEFAULT_PADDING;\r\n this.background = options.background ?? null;\r\n this.viewportStroke = options.viewportStroke ?? DEFAULT_VIEWPORT_STROKE;\r\n this.debounceMs = options.debounceMs ?? DEFAULT_DEBOUNCE_MS;\r\n this.interactive = options.interactive !== false;\r\n this.requestFrame =\r\n options.requestFrame ??\r\n ((cb) => (typeof requestAnimationFrame !== 'undefined' ? requestAnimationFrame(cb) : 0));\r\n this.cancelFrame =\r\n options.cancelFrame ??\r\n ((id) => {\r\n if (typeof cancelAnimationFrame !== 'undefined') cancelAnimationFrame(id);\r\n });\r\n\r\n this.renderer.setStore(viewport.store);\r\n this.renderer.setOnImageLoad(() => this.markSceneDirty());\r\n this.applyCanvasSize();\r\n\r\n const onScene = () => this.markSceneDirty();\r\n this.unsubs.push(\r\n viewport.store.on('add', onScene),\r\n viewport.store.on('remove', onScene),\r\n viewport.store.on('update', onScene),\r\n viewport.store.on('clear', onScene),\r\n viewport.layerManager.on('change', onScene),\r\n viewport.camera.onChange(() => this.onViewChanged()),\r\n viewport.onResize(() => this.onViewChanged()),\r\n );\r\n\r\n if (this.interactive) {\r\n canvas.style.touchAction = 'none';\r\n canvas.style.cursor = 'pointer';\r\n canvas.addEventListener('pointerdown', this.onPointerDown);\r\n canvas.addEventListener('pointermove', this.onPointerMove);\r\n canvas.addEventListener('pointerup', this.onPointerUp);\r\n canvas.addEventListener('pointercancel', this.onPointerEnd);\r\n canvas.addEventListener('lostpointercapture', this.onPointerEnd);\r\n }\r\n\r\n this.renderScene();\r\n this.requestDraw();\r\n }\r\n\r\n setSize(width: number, height: number): void {\r\n if (this.disposed) return;\r\n this.width = width;\r\n this.height = height;\r\n this.applyCanvasSize();\r\n this.clearDebounce();\r\n this.renderScene();\r\n this.requestDraw();\r\n }\r\n\r\n requestDraw(): void {\r\n if (this.disposed || this.frameId !== null) return;\r\n this.frameId = this.requestFrame(this.draw);\r\n }\r\n\r\n dispose(): void {\r\n if (this.disposed) return;\r\n this.disposed = true;\r\n this.clearDebounce();\r\n if (this.frameId !== null) {\r\n this.cancelFrame(this.frameId);\r\n this.frameId = null;\r\n }\r\n for (const unsub of this.unsubs.splice(0)) unsub();\r\n if (this.interactive) {\r\n this.canvas.removeEventListener('pointerdown', this.onPointerDown);\r\n this.canvas.removeEventListener('pointermove', this.onPointerMove);\r\n this.canvas.removeEventListener('pointerup', this.onPointerUp);\r\n this.canvas.removeEventListener('pointercancel', this.onPointerEnd);\r\n this.canvas.removeEventListener('lostpointercapture', this.onPointerEnd);\r\n }\r\n }\r\n\r\n private clearDebounce(): void {\r\n if (this.debounceTimer !== null) {\r\n clearTimeout(this.debounceTimer);\r\n this.debounceTimer = null;\r\n }\r\n }\r\n\r\n private dpr(): number {\r\n return typeof devicePixelRatio !== 'undefined' ? devicePixelRatio : 1;\r\n }\r\n\r\n private applyCanvasSize(): void {\r\n const dpr = this.dpr();\r\n this.canvas.width = Math.max(1, Math.round(this.width * dpr));\r\n this.canvas.height = Math.max(1, Math.round(this.height * dpr));\r\n }\r\n\r\n // Single source for both mapping bounds and rendering: layer-visible,\r\n // grids excluded. (getElementBounds already returns null for grids, so they\r\n // cannot extend the bounding box today — this filter makes the invariant\r\n // structural instead of relying on that special case.)\r\n private sceneElements(): CanvasElement[] {\r\n return this.viewport.store\r\n .getAll()\r\n .filter((el) => el.type !== 'grid' && this.viewport.layerManager.isLayerVisible(el.layerId));\r\n }\r\n\r\n private currentMapping(): Bounds {\r\n const viewportRect = this.viewport.getVisibleRect();\r\n const content = getElementsBoundingBox(this.sceneElements());\r\n return content ? unionBounds(content, viewportRect) : viewportRect;\r\n }\r\n\r\n private onViewChanged(): void {\r\n if (this.disposed) return;\r\n const mapping = this.currentMapping();\r\n if (!this.scene || !sameBounds(mapping, this.scene.mapping)) {\r\n this.markSceneDirty();\r\n }\r\n this.requestDraw();\r\n }\r\n\r\n private markSceneDirty(): void {\r\n if (this.disposed) return;\r\n this.clearDebounce();\r\n this.debounceTimer = setTimeout(() => {\r\n this.debounceTimer = null;\r\n this.renderScene();\r\n this.requestDraw();\r\n }, this.debounceMs);\r\n }\r\n\r\n private renderScene(): void {\r\n if (this.disposed) return;\r\n const dpr = this.dpr();\r\n const mapping = this.currentMapping();\r\n const transform = computeMinimapTransform(mapping, this.width, this.height, this.padding);\r\n const sceneCanvas = document.createElement('canvas');\r\n sceneCanvas.width = Math.max(1, Math.round(this.width * dpr));\r\n sceneCanvas.height = Math.max(1, Math.round(this.height * dpr));\r\n const ctx = sceneCanvas.getContext('2d');\r\n if (!ctx) return;\r\n\r\n const byLayer = new Map<string, CanvasElement[]>();\r\n for (const el of this.sceneElements()) {\r\n let list = byLayer.get(el.layerId);\r\n if (!list) {\r\n list = [];\r\n byLayer.set(el.layerId, list);\r\n }\r\n list.push(el);\r\n }\r\n\r\n for (const layer of this.viewport.layerManager.getLayers()) {\r\n const els = byLayer.get(layer.id);\r\n if (!els || els.length === 0) continue;\r\n const opacity = layer.opacity;\r\n if (opacity >= 1) {\r\n this.renderLayerElements(ctx, els, transform, dpr);\r\n continue;\r\n }\r\n // Translucent layers composite ONCE so overlapping elements within the\r\n // layer do not darken each other (main-renderer semantics).\r\n const layerCanvas = document.createElement('canvas');\r\n layerCanvas.width = sceneCanvas.width;\r\n layerCanvas.height = sceneCanvas.height;\r\n const layerCtx = layerCanvas.getContext('2d');\r\n if (!layerCtx) continue;\r\n this.renderLayerElements(layerCtx, els, transform, dpr);\r\n ctx.save();\r\n ctx.globalAlpha = opacity;\r\n ctx.drawImage(layerCanvas, 0, 0);\r\n ctx.restore();\r\n }\r\n\r\n // Atomic swap: bitmap, transform, and mapping replace together.\r\n this.scene = { canvas: sceneCanvas, transform, mapping };\r\n }\r\n\r\n private renderLayerElements(\r\n ctx: CanvasRenderingContext2D,\r\n elements: CanvasElement[],\r\n t: MinimapTransform,\r\n dpr: number,\r\n ): void {\r\n for (const el of elements) {\r\n if (DOM_FALLBACK_TYPES.has(el.type)) {\r\n const b = getElementBounds(el);\r\n if (!b) continue;\r\n const tl = worldToMini(t, { x: b.x, y: b.y });\r\n ctx.save();\r\n ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\r\n ctx.fillStyle = elementColor(el);\r\n ctx.fillRect(tl.x, tl.y, Math.max(1, b.w * t.scale), Math.max(1, b.h * t.scale));\r\n ctx.restore();\r\n continue;\r\n }\r\n ctx.save();\r\n ctx.setTransform(dpr * t.scale, 0, 0, dpr * t.scale, dpr * t.offsetX, dpr * t.offsetY);\r\n this.renderer.renderCanvasElement(ctx, el);\r\n ctx.restore();\r\n }\r\n }\r\n\r\n private draw = (): void => {\r\n this.frameId = null;\r\n if (this.disposed) return;\r\n const ctx = this.canvas.getContext('2d');\r\n if (!ctx) return;\r\n const dpr = this.dpr();\r\n ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\r\n ctx.clearRect(0, 0, this.width, this.height);\r\n if (this.background) {\r\n ctx.fillStyle = this.background;\r\n ctx.fillRect(0, 0, this.width, this.height);\r\n }\r\n const scene = this.scene;\r\n if (!scene) return;\r\n ctx.drawImage(scene.canvas, 0, 0, this.width, this.height);\r\n // The rect projects through the SAME transform the bitmap was rendered\r\n // with (atomic-swap invariant) — never a fresher transform.\r\n const viewportRect = this.viewport.getVisibleRect();\r\n const tl = worldToMini(scene.transform, { x: viewportRect.x, y: viewportRect.y });\r\n ctx.strokeStyle = this.viewportStroke;\r\n ctx.lineWidth = 1.5;\r\n ctx.strokeRect(\r\n tl.x,\r\n tl.y,\r\n viewportRect.w * scene.transform.scale,\r\n viewportRect.h * scene.transform.scale,\r\n );\r\n };\r\n\r\n private navTransform(): MinimapTransform {\r\n return (\r\n this.scene?.transform ??\r\n computeMinimapTransform(this.currentMapping(), this.width, this.height, this.padding)\r\n );\r\n }\r\n\r\n private navigateFromEvent(e: PointerEvent): void {\r\n const rect = this.canvas.getBoundingClientRect();\r\n // The canvas's DISPLAYED CSS size (rect.width/height) can differ from the\r\n // logical width/height the minimap transform is built for — applyCanvasSize\r\n // only sets the backing-store pixel attributes, never canvas.style\r\n // width/height, so a consumer that doesn't explicitly style the canvas (or\r\n // that CSS-scales it responsively) can display it at a different CSS size.\r\n // Normalize the pointer position from displayed to logical space first.\r\n // A zero-size rect (unmeasured/unlaid-out canvas) carries no scaling\r\n // information, so it falls back to an identity ratio rather than\r\n // dividing by zero.\r\n const scaleX = rect.width > 0 ? this.width / rect.width : 1;\r\n const scaleY = rect.height > 0 ? this.height / rect.height : 1;\r\n const point = {\r\n x: (e.clientX - rect.left) * scaleX,\r\n y: (e.clientY - rect.top) * scaleY,\r\n };\r\n const world: Point = miniToWorld(this.navTransform(), point);\r\n this.viewport.centerCameraAt(world);\r\n }\r\n\r\n private onPointerDown = (e: PointerEvent): void => {\r\n e.stopPropagation();\r\n e.preventDefault();\r\n this.dragging = true;\r\n this.canvas.setPointerCapture?.(e.pointerId);\r\n this.navigateFromEvent(e);\r\n };\r\n\r\n private onPointerMove = (e: PointerEvent): void => {\r\n if (!this.dragging) return;\r\n e.stopPropagation();\r\n this.navigateFromEvent(e);\r\n };\r\n\r\n private onPointerUp = (e: PointerEvent): void => {\r\n this.dragging = false;\r\n try {\r\n this.canvas.releasePointerCapture(e.pointerId);\r\n } catch {\r\n // already released\r\n }\r\n };\r\n\r\n // pointercancel / lostpointercapture: a browser gesture or interrupted touch\r\n // can end the interaction without a pointerup — the drag must not stick.\r\n private onPointerEnd = (): void => {\r\n this.dragging = false;\r\n };\r\n}\r\n","import type { Viewport } from './viewport';\r\nimport { MinimapController } from './minimap-controller';\r\n\r\nconst WIDTH = 200;\r\nconst HEIGHT = 140;\r\nconst MARGIN = 16;\r\n\r\n/**\r\n * Built-in bottom-right minimap for `ViewportOptions.minimap: true`. Thin DOM\r\n * wrapper over `MinimapController`, which owns rendering, invalidation, and\r\n * tap/drag navigation.\r\n */\r\nexport class Minimap {\r\n private readonly canvas: HTMLCanvasElement;\r\n private readonly controller: MinimapController;\r\n\r\n constructor(container: HTMLElement, viewport: Viewport) {\r\n const canvas = document.createElement('canvas');\r\n Object.assign(canvas.style, {\r\n position: 'absolute',\r\n right: `${MARGIN}px`,\r\n bottom: `${MARGIN}px`,\r\n width: `${WIDTH}px`,\r\n height: `${HEIGHT}px`,\r\n background: 'rgba(255,255,255,0.85)',\r\n border: '1px solid rgba(0,0,0,0.15)',\r\n borderRadius: '4px',\r\n zIndex: '10',\r\n });\r\n canvas.dataset.fieldnotesMinimap = 'true';\r\n container.appendChild(canvas);\r\n this.canvas = canvas;\r\n this.controller = new MinimapController(viewport, canvas, { width: WIDTH, height: HEIGHT });\r\n }\r\n\r\n scheduleDraw(): void {\r\n this.controller.requestDraw();\r\n }\r\n\r\n destroy(): void {\r\n this.controller.dispose();\r\n this.canvas.remove();\r\n }\r\n}\r\n","export function createWrapper(): HTMLDivElement {\r\n const el = document.createElement('div');\r\n Object.assign(el.style, {\r\n position: 'relative',\r\n width: '100%',\r\n height: '100%',\r\n overflow: 'hidden',\r\n overscrollBehavior: 'none',\r\n userSelect: 'none',\r\n webkitUserSelect: 'none',\r\n });\r\n return el;\r\n}\r\n\r\nexport function createCanvas(): HTMLCanvasElement {\r\n const el = document.createElement('canvas');\r\n Object.assign(el.style, {\r\n position: 'absolute',\r\n top: '0',\r\n left: '0',\r\n width: '100%',\r\n height: '100%',\r\n });\r\n return el;\r\n}\r\n\r\nexport function createDomLayer(): HTMLDivElement {\r\n const el = document.createElement('div');\r\n Object.assign(el.style, {\r\n position: 'absolute',\r\n top: '0',\r\n left: '0',\r\n width: '100%',\r\n height: '100%',\r\n pointerEvents: 'none',\r\n transformOrigin: '0 0',\r\n });\r\n return el;\r\n}\r\n\r\nexport function createPaintStack(): HTMLDivElement {\r\n const el = createDomLayer();\r\n el.dataset['fieldnotesPaintStack'] = '';\r\n el.style.transformOrigin = '';\r\n return el;\r\n}\r\n","export class HybridRenderSurface {\r\n private readonly canvases = new Map<number, HTMLCanvasElement>();\r\n\r\n constructor(private readonly root: HTMLDivElement) {}\r\n\r\n beginFrame(activeOrders: ReadonlySet<number>, width: number, height: number): void {\r\n for (const [order, canvas] of this.canvases) {\r\n if (!activeOrders.has(order)) {\r\n canvas.remove();\r\n this.canvases.delete(order);\r\n }\r\n }\r\n\r\n for (const order of activeOrders) {\r\n const canvas = this.getCanvas(order);\r\n if (canvas.width !== width) canvas.width = width;\r\n if (canvas.height !== height) canvas.height = height;\r\n canvas.style.zIndex = String(order);\r\n }\r\n }\r\n\r\n getContext(order: number): CanvasRenderingContext2D | null {\r\n return this.getCanvas(order).getContext('2d');\r\n }\r\n\r\n clear(): void {\r\n for (const canvas of this.canvases.values()) canvas.remove();\r\n this.canvases.clear();\r\n }\r\n\r\n private getCanvas(order: number): HTMLCanvasElement {\r\n let canvas = this.canvases.get(order);\r\n if (canvas) return canvas;\r\n\r\n canvas = document.createElement('canvas');\r\n canvas.dataset['paintOrder'] = String(order);\r\n Object.assign(canvas.style, {\r\n position: 'absolute',\r\n inset: '0',\r\n width: '100%',\r\n height: '100%',\r\n pointerEvents: 'none',\r\n });\r\n this.root.appendChild(canvas);\r\n this.canvases.set(order, canvas);\r\n return canvas;\r\n }\r\n}\r\n","import type { ArrowElement } from './types';\r\nimport type { ElementStore } from './element-store';\r\nimport type { HistoryRecorder } from '../history/history-recorder';\r\nimport { getArrowMidpoint } from './arrow-geometry';\r\n\r\nexport interface ArrowLabelEditStart {\r\n arrow: ArrowElement;\r\n layer: HTMLElement;\r\n store: ElementStore;\r\n recorder: HistoryRecorder;\r\n onDone: () => void;\r\n}\r\n\r\nexport class ArrowLabelEditor {\r\n private input: HTMLInputElement | null = null;\r\n private done = false;\r\n\r\n get isEditing(): boolean {\r\n return this.input !== null;\r\n }\r\n\r\n startEditing(start: ArrowLabelEditStart): void {\r\n if (this.input) this.cleanup();\r\n const { arrow, layer, store, recorder, onDone } = start;\r\n const mid = getArrowMidpoint(arrow.from, arrow.to, arrow.bend);\r\n\r\n const input = document.createElement('input');\r\n input.type = 'text';\r\n input.value = arrow.label ?? '';\r\n Object.assign(input.style, {\r\n position: 'absolute',\r\n left: `${mid.x}px`,\r\n top: `${mid.y}px`,\r\n transform: 'translate(-50%, -50%)',\r\n // domLayer is pointer-events:none; the input must opt back in to receive taps/clicks.\r\n pointerEvents: 'auto',\r\n font: '14px system-ui, sans-serif',\r\n padding: '2px 6px',\r\n border: '1px solid #2196F3',\r\n borderRadius: '4px',\r\n background: '#ffffff',\r\n color: '#1a1a1a',\r\n outline: 'none',\r\n minWidth: '40px',\r\n });\r\n\r\n this.done = false;\r\n\r\n const commit = (): void => {\r\n if (this.done) return;\r\n this.done = true;\r\n const next = input.value.trim() || undefined;\r\n if (next !== arrow.label) {\r\n recorder.begin();\r\n store.update(arrow.id, { label: next });\r\n recorder.commit();\r\n }\r\n this.cleanup();\r\n onDone();\r\n };\r\n\r\n const cancel = (): void => {\r\n if (this.done) return;\r\n this.done = true;\r\n this.cleanup();\r\n onDone();\r\n };\r\n\r\n input.addEventListener('keydown', (e) => {\r\n if (e.key === 'Enter') {\r\n e.preventDefault();\r\n commit();\r\n } else if (e.key === 'Escape') {\r\n e.preventDefault();\r\n cancel();\r\n }\r\n e.stopPropagation();\r\n });\r\n input.addEventListener('blur', commit);\r\n\r\n layer.appendChild(input);\r\n this.input = input;\r\n input.focus();\r\n input.select();\r\n }\r\n\r\n /** Abort any in-progress edit without committing (e.g. on viewport teardown). */\r\n cancel(): void {\r\n this.done = true;\r\n this.cleanup();\r\n }\r\n\r\n private cleanup(): void {\r\n if (this.input) {\r\n this.input.remove();\r\n this.input = null;\r\n }\r\n }\r\n}\r\n","import type { Tool, ToolContext, PointerState } from './types';\r\n\r\nexport class ToolManager {\r\n private tools = new Map<string, Tool>();\r\n private current: Tool | null = null;\r\n private changeListeners = new Set<(name: string) => void>();\r\n private registerListeners = new Set<(tool: Tool) => void>();\r\n\r\n get activeTool(): Tool | null {\r\n return this.current;\r\n }\r\n\r\n get toolNames(): string[] {\r\n return [...this.tools.keys()];\r\n }\r\n\r\n register(tool: Tool): void {\r\n this.tools.set(tool.name, tool);\r\n this.registerListeners.forEach((fn) => fn(tool));\r\n }\r\n\r\n getTool<T extends Tool = Tool>(name: string): T | undefined {\r\n return this.tools.get(name) as T | undefined;\r\n }\r\n\r\n setTool(name: string, ctx: ToolContext): void {\r\n const tool = this.tools.get(name);\r\n if (!tool) return;\r\n\r\n this.current?.onDeactivate?.(ctx);\r\n this.current = tool;\r\n this.current.onActivate?.(ctx);\r\n this.changeListeners.forEach((fn) => fn(name));\r\n }\r\n\r\n handlePointerDown(state: PointerState, ctx: ToolContext): void {\r\n this.current?.onPointerDown(state, ctx);\r\n }\r\n\r\n handlePointerMove(state: PointerState, ctx: ToolContext): void {\r\n this.current?.onPointerMove(state, ctx);\r\n }\r\n\r\n handlePointerUp(state: PointerState, ctx: ToolContext): void {\r\n this.current?.onPointerUp(state, ctx);\r\n }\r\n\r\n onChange(listener: (name: string) => void): () => void {\r\n this.changeListeners.add(listener);\r\n return () => this.changeListeners.delete(listener);\r\n }\r\n\r\n onRegister(listener: (tool: Tool) => void): () => void {\r\n this.registerListeners.add(listener);\r\n return () => this.registerListeners.delete(listener);\r\n }\r\n}\r\n","import type { ElementStore } from '../elements/element-store';\nimport type { Command } from './types';\n\nexport interface HistoryStackOptions {\n maxSize?: number;\n}\n\nconst DEFAULT_MAX_SIZE = 100;\n\nexport class HistoryStack {\n private undoStack: Command[] = [];\n private redoStack: Command[] = [];\n private readonly maxSize: number;\n private changeListeners = new Set<() => void>();\n\n constructor(options: HistoryStackOptions = {}) {\n this.maxSize = options.maxSize ?? DEFAULT_MAX_SIZE;\n }\n\n get canUndo(): boolean {\n return this.undoStack.length > 0;\n }\n\n get canRedo(): boolean {\n return this.redoStack.length > 0;\n }\n\n get undoCount(): number {\n return this.undoStack.length;\n }\n\n get redoCount(): number {\n return this.redoStack.length;\n }\n\n push(command: Command): void {\n this.undoStack.push(command);\n this.redoStack = [];\n\n if (this.undoStack.length > this.maxSize) {\n this.undoStack.shift();\n }\n\n this.notifyChange();\n }\n\n undo(store: ElementStore): boolean {\n const command = this.undoStack.pop();\n if (!command) return false;\n\n command.undo(store);\n this.redoStack.push(command);\n this.notifyChange();\n return true;\n }\n\n redo(store: ElementStore): boolean {\n const command = this.redoStack.pop();\n if (!command) return false;\n\n command.execute(store);\n this.undoStack.push(command);\n this.notifyChange();\n return true;\n }\n\n clear(): void {\n this.undoStack = [];\n this.redoStack = [];\n this.notifyChange();\n }\n\n onChange(listener: () => void): () => void {\n this.changeListeners.add(listener);\n return () => this.changeListeners.delete(listener);\n }\n\n private notifyChange(): void {\n this.changeListeners.forEach((fn) => fn());\n }\n}\n","import type { CanvasElement } from '../elements/types';\r\nimport type { ElementStore } from '../elements/element-store';\r\nimport type { Command } from './types';\r\n\r\nexport class AddElementCommand implements Command {\r\n private readonly element: CanvasElement;\r\n\r\n constructor(element: CanvasElement) {\r\n this.element = { ...element };\r\n }\r\n\r\n execute(store: ElementStore): void {\r\n store.add(this.element);\r\n }\r\n\r\n undo(store: ElementStore): void {\r\n store.remove(this.element.id);\r\n }\r\n}\r\n\r\nexport class RemoveElementCommand implements Command {\r\n private readonly element: CanvasElement;\r\n\r\n constructor(element: CanvasElement) {\r\n this.element = { ...element };\r\n }\r\n\r\n execute(store: ElementStore): void {\r\n store.remove(this.element.id);\r\n }\r\n\r\n undo(store: ElementStore): void {\r\n store.add(this.element);\r\n }\r\n}\r\n\r\nexport class UpdateElementCommand implements Command {\r\n constructor(\r\n private readonly id: string,\r\n private readonly previous: CanvasElement,\r\n private readonly current: CanvasElement,\r\n ) {}\r\n\r\n execute(store: ElementStore): void {\r\n store.update(this.id, diffPatch(this.previous, this.current));\r\n }\r\n\r\n undo(store: ElementStore): void {\r\n store.update(this.id, diffPatch(this.current, this.previous));\r\n }\r\n}\r\n\r\n// Patch turning `from` into `to`, explicitly setting keys that exist on `from`\r\n// but not `to` to `undefined` so a merge-based `update` clears them.\r\nfunction diffPatch(from: CanvasElement, to: CanvasElement): Partial<CanvasElement> {\r\n const patch: Record<string, unknown> = { ...to };\r\n for (const key of Object.keys(from)) {\r\n if (!(key in to)) patch[key] = undefined;\r\n }\r\n return patch as Partial<CanvasElement>;\r\n}\r\n\r\nexport class BatchCommand implements Command {\r\n readonly commands: readonly Command[];\r\n\r\n constructor(commands: Command[]) {\r\n this.commands = [...commands];\r\n }\r\n\r\n execute(store: ElementStore): void {\r\n for (const cmd of this.commands) {\r\n cmd.execute(store);\r\n }\r\n }\r\n\r\n undo(store: ElementStore): void {\r\n for (let i = this.commands.length - 1; i >= 0; i--) {\r\n this.commands[i]?.undo(store);\r\n }\r\n }\r\n}\r\n","import type { ElementStore } from '../elements/element-store';\r\nimport type { Command } from './types';\r\nimport type { LayerManager } from '../layers/layer-manager';\r\nimport type { Layer } from '../layers/types';\r\n\r\nexport class CreateLayerCommand implements Command {\r\n constructor(\r\n private readonly manager: LayerManager,\r\n private readonly layer: Layer,\r\n ) {}\r\n\r\n execute(_store: ElementStore): void {\r\n this.manager.addLayerDirect(this.layer);\r\n }\r\n\r\n undo(_store: ElementStore): void {\r\n this.manager.removeLayerDirect(this.layer.id);\r\n }\r\n}\r\n\r\nexport class RemoveLayerCommand implements Command {\r\n constructor(\r\n private readonly manager: LayerManager,\r\n private readonly layer: Layer,\r\n ) {}\r\n\r\n execute(_store: ElementStore): void {\r\n this.manager.removeLayerDirect(this.layer.id);\r\n }\r\n\r\n undo(_store: ElementStore): void {\r\n this.manager.addLayerDirect(this.layer);\r\n }\r\n}\r\n\r\nexport class UpdateLayerCommand implements Command {\r\n constructor(\r\n private readonly manager: LayerManager,\r\n private readonly layerId: string,\r\n private readonly previous: Layer,\r\n private readonly current: Layer,\r\n ) {}\r\n\r\n execute(_store: ElementStore): void {\r\n this.manager.updateLayerDirect(this.layerId, { ...this.current });\r\n }\r\n\r\n undo(_store: ElementStore): void {\r\n this.manager.updateLayerDirect(this.layerId, { ...this.previous });\r\n }\r\n}\r\n","import type { ElementStore } from '../elements/element-store';\r\nimport type { EventMeta } from '../core/event-bus';\r\nimport type { CanvasElement } from '../elements/types';\r\nimport type { Command } from './types';\r\nimport type { HistoryStack } from './history-stack';\r\nimport type { LayerManager } from '../layers/layer-manager';\r\nimport type { Layer } from '../layers/types';\r\nimport {\r\n AddElementCommand,\r\n RemoveElementCommand,\r\n UpdateElementCommand,\r\n BatchCommand,\r\n} from './commands';\r\nimport { CreateLayerCommand, RemoveLayerCommand, UpdateLayerCommand } from './layer-commands';\r\n\r\nfunction isExternalChange(meta: EventMeta): boolean {\r\n return meta.origin !== undefined && meta.origin !== 'local';\r\n}\r\n\r\nexport class HistoryRecorder {\r\n private recording = true;\r\n private transaction: Command[] | null = null;\r\n private generation = 0;\r\n private updateSnapshots = new Map<string, CanvasElement>();\r\n private unsubscribers: (() => void)[];\r\n private transactionEndListeners = new Set<() => void>();\r\n\r\n constructor(\r\n private readonly store: ElementStore,\r\n private readonly stack: HistoryStack,\r\n private readonly layerManager?: LayerManager,\r\n ) {\r\n this.unsubscribers = [\r\n store.on('add', (el, meta) => this.onAdd(el, meta)),\r\n store.on('remove', (el, meta) => this.onRemove(el, meta)),\r\n store.on('update', ({ previous, current }, meta) => this.onUpdate(previous, current, meta)),\r\n ];\r\n\r\n if (layerManager) {\r\n this.unsubscribers.push(\r\n layerManager.on('create', (layer) => this.onLayerCreate(layer)),\r\n layerManager.on('remove', (layer) => this.onLayerRemove(layer)),\r\n layerManager.on('update', ({ previous, current }) => this.onLayerUpdate(previous, current)),\r\n );\r\n }\r\n }\r\n\r\n pause(): void {\r\n this.recording = false;\r\n }\r\n\r\n resume(): void {\r\n this.recording = true;\r\n }\r\n\r\n begin(): void {\r\n if (this.transaction !== null) {\r\n this.commit();\r\n }\r\n this.transaction = [];\r\n this.updateSnapshots.clear();\r\n this.generation += 1;\r\n }\r\n\r\n get currentTransactionId(): number | null {\r\n return this.transaction !== null ? this.generation : null;\r\n }\r\n\r\n onTransactionEnd(listener: () => void): () => void {\r\n this.transactionEndListeners.add(listener);\r\n return () => this.transactionEndListeners.delete(listener);\r\n }\r\n\r\n private notifyTransactionEnd(): void {\r\n for (const listener of this.transactionEndListeners) {\r\n try {\r\n listener();\r\n } catch {\r\n // Listeners must not interrupt history commit.\r\n }\r\n }\r\n }\r\n\r\n commit(): void {\r\n if (!this.transaction) return;\r\n\r\n const finalCommands = this.flushUpdateSnapshots();\r\n const all = [...this.transaction, ...finalCommands];\r\n this.transaction = null;\r\n this.updateSnapshots.clear();\r\n\r\n if (all.length > 0) {\r\n const first = all[0];\r\n this.stack.push(all.length === 1 && first ? first : new BatchCommand(all));\r\n }\r\n this.notifyTransactionEnd();\r\n }\r\n\r\n rollback(): void {\r\n const wasOpen = this.transaction !== null;\r\n this.transaction = null;\r\n this.updateSnapshots.clear();\r\n if (wasOpen) this.notifyTransactionEnd();\r\n }\r\n\r\n destroy(): void {\r\n this.unsubscribers.forEach((fn) => fn());\r\n }\r\n\r\n private record(command: Command): void {\r\n if (this.transaction) {\r\n this.transaction.push(command);\r\n } else {\r\n this.stack.push(command);\r\n }\r\n }\r\n\r\n private onAdd(element: CanvasElement, meta: EventMeta): void {\r\n if (isExternalChange(meta)) return;\r\n if (!this.recording) return;\r\n this.record(new AddElementCommand(element));\r\n }\r\n\r\n private onRemove(element: CanvasElement, meta: EventMeta): void {\r\n if (isExternalChange(meta)) return;\r\n if (!this.recording) return;\r\n\r\n if (this.transaction && this.updateSnapshots.has(element.id)) {\r\n this.updateSnapshots.delete(element.id);\r\n }\r\n\r\n this.record(new RemoveElementCommand(element));\r\n }\r\n\r\n private onUpdate(previous: CanvasElement, current: CanvasElement, meta: EventMeta): void {\r\n if (isExternalChange(meta)) return;\r\n if (!this.recording) return;\r\n\r\n if (this.transaction) {\r\n if (!this.updateSnapshots.has(current.id)) {\r\n this.updateSnapshots.set(current.id, { ...previous });\r\n }\r\n } else {\r\n this.stack.push(new UpdateElementCommand(current.id, previous, current));\r\n }\r\n }\r\n\r\n private onLayerCreate(layer: Layer): void {\r\n if (!this.recording) return;\r\n if (!this.layerManager) return;\r\n this.record(new CreateLayerCommand(this.layerManager, layer));\r\n }\r\n\r\n private onLayerRemove(layer: Layer): void {\r\n if (!this.recording) return;\r\n if (!this.layerManager) return;\r\n this.record(new RemoveLayerCommand(this.layerManager, layer));\r\n }\r\n\r\n private onLayerUpdate(previous: Layer, current: Layer): void {\r\n if (!this.recording) return;\r\n if (!this.layerManager) return;\r\n this.record(new UpdateLayerCommand(this.layerManager, current.id, previous, current));\r\n }\r\n\r\n private flushUpdateSnapshots(): Command[] {\r\n const commands: Command[] = [];\r\n for (const [id, previous] of this.updateSnapshots) {\r\n const current = this.store.getById(id);\r\n if (current) {\r\n commands.push(new UpdateElementCommand(id, previous, current));\r\n }\r\n }\r\n return commands;\r\n }\r\n}\r\n","import type { NoteElement } from '../elements/types';\r\nimport { DEFAULT_NOTE_FONT_SIZE } from '../elements/element-factory';\r\nimport { parseStyledRuns } from '../elements/note-sanitizer';\r\nimport type { StyledRun } from '../elements/note-sanitizer';\r\n\r\nexport { parseStyledRuns };\r\nexport type { StyledRun };\r\n\r\nexport function renderNoteOnCanvas(ctx: CanvasRenderingContext2D, note: NoteElement): void {\r\n const { x, y } = note.position;\r\n const { w, h } = note.size;\r\n const r = 4;\r\n const pad = 8;\r\n const baseFontSize = note.fontSize ?? DEFAULT_NOTE_FONT_SIZE;\r\n\r\n ctx.save();\r\n ctx.fillStyle = note.backgroundColor;\r\n ctx.beginPath();\r\n ctx.moveTo(x + r, y);\r\n ctx.lineTo(x + w - r, y);\r\n ctx.arcTo(x + w, y, x + w, y + r, r);\r\n ctx.lineTo(x + w, y + h - r);\r\n ctx.arcTo(x + w, y + h, x + w - r, y + h, r);\r\n ctx.lineTo(x + r, y + h);\r\n ctx.arcTo(x, y + h, x, y + h - r, r);\r\n ctx.lineTo(x, y + r);\r\n ctx.arcTo(x, y, x + r, y, r);\r\n ctx.closePath();\r\n ctx.fill();\r\n\r\n if (note.text) {\r\n ctx.fillStyle = note.textColor;\r\n const runs = parseStyledRuns(note.text, baseFontSize);\r\n renderStyledRuns(ctx, runs, x + pad, y + pad, w - pad * 2);\r\n }\r\n\r\n ctx.restore();\r\n}\r\n\r\nfunction buildFontString(run: StyledRun): string {\r\n const style = run.italic ? 'italic' : 'normal';\r\n const weight = run.bold ? 'bold' : 'normal';\r\n return `${style} ${weight} ${run.fontSize}px system-ui, sans-serif`;\r\n}\r\n\r\ninterface LineFragment {\r\n text: string;\r\n font: string;\r\n x: number;\r\n width: number;\r\n fontSize: number;\r\n underline: boolean;\r\n strikethrough: boolean;\r\n}\r\n\r\ninterface LaidOutLine {\r\n y: number;\r\n width: number;\r\n fragments: LineFragment[];\r\n}\r\n\r\nexport function renderStyledRuns(\r\n ctx: CanvasRenderingContext2D,\r\n runs: StyledRun[],\r\n startX: number,\r\n startY: number,\r\n maxWidth: number,\r\n opts: { align?: 'left' | 'center' | 'right'; lineHeight?: number } = {},\r\n): void {\r\n const align = opts.align ?? 'left';\r\n const lhMul = opts.lineHeight ?? 1.3;\r\n ctx.textBaseline = 'top';\r\n\r\n // PASS 1 — lay runs out into lines (no drawing). Wrap behaviour mirrors the\r\n // original single-pass renderer exactly so wrap points are alignment-agnostic.\r\n const lines: LaidOutLine[] = [];\r\n let cursorX = startX;\r\n let lineY = startY;\r\n let lineHeight = 0;\r\n let fragments: LineFragment[] = [];\r\n\r\n const finalizeLine = (): void => {\r\n const last = fragments[fragments.length - 1];\r\n const width = last ? last.x + last.width : 0;\r\n lines.push({ y: lineY, width, fragments });\r\n };\r\n\r\n const breakLine = (runLineHeight: number): void => {\r\n finalizeLine();\r\n lineY += lineHeight;\r\n lineHeight = runLineHeight;\r\n fragments = [];\r\n cursorX = startX;\r\n };\r\n\r\n for (const run of runs) {\r\n const font = buildFontString(run);\r\n ctx.font = font;\r\n const runLineHeight = run.fontSize * lhMul;\r\n lineHeight = Math.max(lineHeight, runLineHeight);\r\n\r\n const words = run.text.split(/(\\n| )/);\r\n for (const word of words) {\r\n if (word === '\\n') {\r\n breakLine(runLineHeight);\r\n continue;\r\n }\r\n if (word === ' ') {\r\n const spaceWidth = ctx.measureText(' ').width;\r\n if (cursorX + spaceWidth > startX + maxWidth && cursorX > startX) {\r\n breakLine(runLineHeight);\r\n } else {\r\n cursorX += spaceWidth;\r\n }\r\n continue;\r\n }\r\n if (!word) continue;\r\n\r\n const metrics = ctx.measureText(word);\r\n if (cursorX + metrics.width > startX + maxWidth && cursorX > startX) {\r\n breakLine(runLineHeight);\r\n }\r\n\r\n fragments.push({\r\n text: word,\r\n font,\r\n x: cursorX - startX,\r\n width: metrics.width,\r\n fontSize: run.fontSize,\r\n underline: run.underline,\r\n strikethrough: run.strikethrough,\r\n });\r\n cursorX += metrics.width;\r\n }\r\n }\r\n finalizeLine();\r\n\r\n // PASS 2 — draw each line at its alignment offset. For align 'left' the\r\n // offset is 0, so the absolute x equals the original streaming cursorX.\r\n for (const line of lines) {\r\n const offset =\r\n align === 'center'\r\n ? (maxWidth - line.width) / 2\r\n : align === 'right'\r\n ? maxWidth - line.width\r\n : 0;\r\n for (const fragment of line.fragments) {\r\n ctx.font = fragment.font;\r\n const fx = startX + offset + fragment.x;\r\n ctx.fillText(fragment.text, fx, line.y);\r\n\r\n if (fragment.underline) {\r\n ctx.fillRect(fx, line.y + fragment.fontSize + 1, fragment.width, 1);\r\n }\r\n\r\n if (fragment.strikethrough) {\r\n ctx.fillRect(fx, line.y + fragment.fontSize * 0.55, fragment.width, 1);\r\n }\r\n }\r\n }\r\n}\r\n","import type { TextElement } from '../elements/types';\r\nimport { parseStyledRuns, renderStyledRuns } from './note-canvas-renderer';\r\n\r\nexport function renderTextOnCanvas(ctx: CanvasRenderingContext2D, text: TextElement): void {\r\n const pad = 2; // matches the DOM text padding\r\n ctx.save();\r\n ctx.fillStyle = text.color;\r\n const runs = parseStyledRuns(text.text ?? '', text.fontSize);\r\n renderStyledRuns(ctx, runs, text.position.x + pad, text.position.y + pad, text.size.w - pad * 2, {\r\n align: text.textAlign,\r\n lineHeight: 1.4,\r\n });\r\n ctx.restore();\r\n}\r\n","import type { HtmlElement } from '../elements/types';\r\n\r\nexport type HtmlExportRenderer = (\r\n element: HtmlElement,\r\n) => CanvasImageSource | null | Promise<CanvasImageSource | null>;\r\n\r\nexport type HtmlExportErrorReason = 'unsupported' | 'timeout' | 'render' | 'encode';\r\n\r\nexport interface HtmlExportError {\r\n elementId: string;\r\n htmlType?: string;\r\n reason: HtmlExportErrorReason;\r\n cause?: unknown;\r\n}\r\n\r\nexport interface HtmlExportOptions {\r\n /** Converts an application-owned HTML embed into a ready canvas image source. */\r\n renderHtml?: HtmlExportRenderer;\r\n /** Maximum wait for each HTML renderer. Defaults to 10 seconds. */\r\n htmlTimeoutMs?: number;\r\n /** Called when an HTML embed cannot be rendered or encoded. The export continues. */\r\n onHtmlError?: (error: HtmlExportError) => void;\r\n}\r\n\r\nconst DEFAULT_HTML_TIMEOUT_MS = 10_000;\r\nconst TIMEOUT = Symbol('html-export-timeout');\r\n\r\nexport function validateHtmlExportOptions(options: HtmlExportOptions): number {\r\n const timeoutMs = options.htmlTimeoutMs ?? DEFAULT_HTML_TIMEOUT_MS;\r\n if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {\r\n throw new RangeError('htmlTimeoutMs must be a finite number greater than 0');\r\n }\r\n return timeoutMs;\r\n}\r\n\r\nexport async function renderHtmlElements(\r\n elements: HtmlElement[],\r\n options: HtmlExportOptions,\r\n): Promise<Map<string, CanvasImageSource>> {\r\n const timeoutMs = validateHtmlExportOptions(options);\r\n const sources = new Map<string, CanvasImageSource>();\r\n\r\n await Promise.all(\r\n elements.map(async (element) => {\r\n if (!options.renderHtml) {\r\n options.onHtmlError?.({\r\n elementId: element.id,\r\n htmlType: element.htmlType,\r\n reason: 'unsupported',\r\n });\r\n return;\r\n }\r\n\r\n let timer: ReturnType<typeof setTimeout> | undefined;\r\n try {\r\n const timeout = new Promise<typeof TIMEOUT>((resolve) => {\r\n timer = setTimeout(() => resolve(TIMEOUT), timeoutMs);\r\n });\r\n const result = await Promise.race([Promise.resolve(options.renderHtml(element)), timeout]);\r\n if (result === TIMEOUT) {\r\n options.onHtmlError?.({\r\n elementId: element.id,\r\n htmlType: element.htmlType,\r\n reason: 'timeout',\r\n });\r\n return;\r\n }\r\n if (!result) {\r\n options.onHtmlError?.({\r\n elementId: element.id,\r\n htmlType: element.htmlType,\r\n reason: 'render',\r\n });\r\n return;\r\n }\r\n sources.set(element.id, result);\r\n } catch (cause) {\r\n options.onHtmlError?.({\r\n elementId: element.id,\r\n htmlType: element.htmlType,\r\n reason: 'render',\r\n cause,\r\n });\r\n } finally {\r\n if (timer !== undefined) clearTimeout(timer);\r\n }\r\n }),\r\n );\r\n\r\n return sources;\r\n}\r\n","import type { CanvasElement, GridElement, HtmlElement } from '../elements/types';\r\nimport type { ElementStore } from '../elements/element-store';\r\nimport { ElementRenderer } from '../elements/element-renderer';\r\nimport { getArrowBounds } from '../elements/arrow-geometry';\r\nimport { getElementBounds } from '../elements/element-bounds';\r\nimport { renderSquareGrid, renderHexGrid } from '../elements/grid-renderer';\r\nimport { withRotation } from '../elements/rotate-canvas';\r\nimport { rotatedAABB } from '../core/geometry';\r\nimport type { LayerManager } from '../layers/layer-manager';\r\nimport { renderNoteOnCanvas } from './note-canvas-renderer';\r\nimport { renderTextOnCanvas } from './text-canvas-renderer';\r\nimport { renderHtmlElements, validateHtmlExportOptions } from './html-export';\r\nimport type { HtmlExportOptions } from './html-export';\r\n\r\nexport interface ExportImageOptions extends ExportResourceOptions, HtmlExportOptions {\r\n scale?: number;\r\n padding?: number;\r\n background?: string;\r\n filter?: (element: CanvasElement) => boolean;\r\n /**\r\n * Optional world-space crop. When set it replaces the computed content\r\n * bounds; `padding` still applies around it. Elements outside the region\r\n * clip naturally. A region export with no intersecting elements still\r\n * produces a background-filled image.\r\n */\r\n region?: { x: number; y: number; w: number; h: number };\r\n /**\r\n * Output encoding. Defaults to 'png'. JPEG output is opaque — a transparent\r\n * `background` renders as black; keep the default `#ffffff` (or any opaque color)\r\n * for JPEG exports.\r\n */\r\n format?: 'png' | 'jpeg';\r\n /** Encoder quality in (0, 1]. Only meaningful for 'jpeg'. */\r\n quality?: number;\r\n /**\r\n * 'exact' (default) throws when scale × bounds exceeds maxDimension/maxPixels.\r\n * 'fit' reduces the effective scale to the largest value that satisfies both\r\n * caps (never above the requested scale).\r\n */\r\n scaleMode?: 'exact' | 'fit';\r\n}\r\n\r\nexport type ExportAssetErrorReason = 'load' | 'timeout' | 'encode';\r\n\r\nexport interface ExportAssetError {\r\n elementId: string;\r\n src: string;\r\n reason: ExportAssetErrorReason;\r\n cause?: unknown;\r\n}\r\n\r\nexport interface ExportResourceOptions {\r\n /** Maximum wait for each image asset. Defaults to 10 seconds. */\r\n imageTimeoutMs?: number;\r\n /** Maximum width or height of any allocated export canvas. Defaults to 16,384. */\r\n maxDimension?: number;\r\n /** Maximum pixel count of any allocated export canvas. Defaults to 67,108,864. */\r\n maxPixels?: number;\r\n /** Called when an image cannot be loaded or embedded. The export continues. */\r\n onAssetError?: (error: ExportAssetError) => void;\r\n}\r\n\r\nconst DEFAULT_IMAGE_TIMEOUT_MS = 10_000;\r\nconst DEFAULT_MAX_DIMENSION = 16_384;\r\nconst DEFAULT_MAX_PIXELS = 67_108_864;\r\n\r\ninterface Rect {\r\n x: number;\r\n y: number;\r\n w: number;\r\n h: number;\r\n}\r\n\r\nconst center = (b: Rect): { x: number; y: number } => ({ x: b.x + b.w / 2, y: b.y + b.h / 2 });\r\n\r\nfunction getStrokeBounds(el: CanvasElement): Rect | null {\r\n if (el.type !== 'stroke') return null;\r\n if (el.points.length === 0) return null;\r\n\r\n let minX = Infinity;\r\n let minY = Infinity;\r\n let maxX = -Infinity;\r\n let maxY = -Infinity;\r\n\r\n for (const p of el.points) {\r\n const px = el.position.x + p.x;\r\n const py = el.position.y + p.y;\r\n minX = Math.min(minX, px);\r\n minY = Math.min(minY, py);\r\n maxX = Math.max(maxX, px);\r\n maxY = Math.max(maxY, py);\r\n }\r\n\r\n const pad = el.width / 2;\r\n return {\r\n x: minX - pad,\r\n y: minY - pad,\r\n w: maxX - minX + el.width,\r\n h: maxY - minY + el.width,\r\n };\r\n}\r\n\r\nfunction getElementRect(el: CanvasElement): Rect | null {\r\n switch (el.type) {\r\n case 'stroke': {\r\n const r = getStrokeBounds(el);\r\n return r ? rotatedAABB(r, el.rotation ?? 0) : r;\r\n }\r\n case 'arrow': {\r\n const b = getArrowBounds(el.from, el.to, el.bend);\r\n const pad = el.width / 2 + 14;\r\n return { x: b.x - pad, y: b.y - pad, w: b.w + pad * 2, h: b.h + pad * 2 };\r\n }\r\n case 'grid':\r\n return null;\r\n case 'template': {\r\n const bounds = getElementBounds(el);\r\n if (!bounds) return null;\r\n return bounds;\r\n }\r\n case 'note':\r\n case 'image':\r\n case 'html':\r\n case 'text':\r\n case 'shape':\r\n if ('size' in el) {\r\n return rotatedAABB(\r\n { x: el.position.x, y: el.position.y, w: el.size.w, h: el.size.h },\r\n el.rotation ?? 0,\r\n );\r\n }\r\n return null;\r\n default:\r\n return null;\r\n }\r\n}\r\n\r\nfunction computeBounds(\r\n elements: CanvasElement[],\r\n padding: number,\r\n): { x: number; y: number; w: number; h: number } | null {\r\n let minX = Infinity;\r\n let minY = Infinity;\r\n let maxX = -Infinity;\r\n let maxY = -Infinity;\r\n let found = false;\r\n\r\n for (const el of elements) {\r\n const rect = getElementRect(el);\r\n if (!rect) continue;\r\n found = true;\r\n minX = Math.min(minX, rect.x);\r\n minY = Math.min(minY, rect.y);\r\n maxX = Math.max(maxX, rect.x + rect.w);\r\n maxY = Math.max(maxY, rect.y + rect.h);\r\n }\r\n\r\n if (!found) return null;\r\n\r\n return {\r\n x: minX - padding,\r\n y: minY - padding,\r\n w: maxX - minX + padding * 2,\r\n h: maxY - minY + padding * 2,\r\n };\r\n}\r\n\r\nfunction resolveExportBounds(\r\n region: { x: number; y: number; w: number; h: number } | undefined,\r\n elements: CanvasElement[],\r\n padding: number,\r\n): Rect | null {\r\n if (!region) return computeBounds(elements, padding);\r\n const finite =\r\n Number.isFinite(region.x) &&\r\n Number.isFinite(region.y) &&\r\n Number.isFinite(region.w) &&\r\n Number.isFinite(region.h);\r\n if (!finite || region.w <= 0 || region.h <= 0) {\r\n throw new RangeError('region must have finite coordinates and positive w/h');\r\n }\r\n return {\r\n x: region.x - padding,\r\n y: region.y - padding,\r\n w: region.w + padding * 2,\r\n h: region.h + padding * 2,\r\n };\r\n}\r\n\r\nfunction renderGridForBounds(\r\n ctx: CanvasRenderingContext2D,\r\n grid: GridElement,\r\n bounds: { x: number; y: number; w: number; h: number },\r\n): void {\r\n const visibleBounds = {\r\n minX: bounds.x,\r\n minY: bounds.y,\r\n maxX: bounds.x + bounds.w,\r\n maxY: bounds.y + bounds.h,\r\n };\r\n\r\n if (grid.gridType === 'hex') {\r\n renderHexGrid(\r\n ctx,\r\n visibleBounds,\r\n grid.cellSize,\r\n grid.hexOrientation,\r\n grid.strokeColor,\r\n grid.strokeWidth,\r\n grid.opacity,\r\n );\r\n } else {\r\n renderSquareGrid(\r\n ctx,\r\n visibleBounds,\r\n grid.cellSize,\r\n grid.strokeColor,\r\n grid.strokeWidth,\r\n grid.opacity,\r\n );\r\n }\r\n}\r\n\r\nfunction positiveOption(value: number | undefined, fallback: number, name: string): number {\r\n const resolved = value ?? fallback;\r\n if (!Number.isFinite(resolved) || resolved <= 0) {\r\n throw new RangeError(`${name} must be a finite number greater than 0`);\r\n }\r\n return resolved;\r\n}\r\n\r\nfunction nonNegativeOption(value: number | undefined, fallback: number, name: string): number {\r\n const resolved = value ?? fallback;\r\n if (!Number.isFinite(resolved) || resolved < 0) {\r\n throw new RangeError(`${name} must be a finite number greater than or equal to 0`);\r\n }\r\n return resolved;\r\n}\r\n\r\nfunction fitExportScale(\r\n bounds: { w: number; h: number },\r\n requestedScale: number,\r\n options: Pick<ExportResourceOptions, 'maxDimension' | 'maxPixels'>,\r\n): number {\r\n const maxDimension = positiveOption(options.maxDimension, DEFAULT_MAX_DIMENSION, 'maxDimension');\r\n const maxPixels = positiveOption(options.maxPixels, DEFAULT_MAX_PIXELS, 'maxPixels');\r\n const fits = (scale: number): boolean => {\r\n const w = Math.ceil(bounds.w * scale);\r\n const h = Math.ceil(bounds.h * scale);\r\n return w <= maxDimension && h <= maxDimension && w * h <= maxPixels;\r\n };\r\n if (fits(requestedScale)) return requestedScale;\r\n // Every fitting scale satisfies w·s ≤ maxDimension and (w·s)(h·s) ≤ maxPixels\r\n // (ceil(x) ≤ n ⟹ x ≤ n), so the analytical candidate is a true upper bound —\r\n // this keeps the search interval tight even for astronomically large bounds.\r\n // ceil rounding makes the candidate itself unreliable, so binary-search the\r\n // narrow rounding-sensitive interval below it; the predicate is monotonic.\r\n // Divide by each sqrt separately: forming bounds.w * bounds.h first can\r\n // overflow to Infinity for large finite bounds, collapsing the candidate to 0.\r\n const analytical = Math.min(\r\n maxDimension / Math.max(bounds.w, bounds.h),\r\n Math.sqrt(maxPixels) / Math.sqrt(bounds.w) / Math.sqrt(bounds.h),\r\n );\r\n let hi = Math.min(requestedScale, analytical);\r\n if (fits(hi)) return hi;\r\n let lo = 0;\r\n for (let i = 0; i < 40; i++) {\r\n const mid = (lo + hi) / 2;\r\n if (fits(mid)) lo = mid;\r\n else hi = mid;\r\n }\r\n return lo;\r\n}\r\n\r\nfunction assertExportSize(\r\n width: number,\r\n height: number,\r\n options: Pick<ExportResourceOptions, 'maxDimension' | 'maxPixels'>,\r\n): void {\r\n const maxDimension = positiveOption(options.maxDimension, DEFAULT_MAX_DIMENSION, 'maxDimension');\r\n const maxPixels = positiveOption(options.maxPixels, DEFAULT_MAX_PIXELS, 'maxPixels');\r\n if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) {\r\n throw new RangeError('Export dimensions must be finite numbers greater than 0');\r\n }\r\n if (width > maxDimension || height > maxDimension) {\r\n throw new RangeError(\r\n `Export dimensions ${width}x${height} exceed the maximum dimension of ${maxDimension}`,\r\n );\r\n }\r\n if (width * height > maxPixels) {\r\n throw new RangeError(\r\n `Export size ${width}x${height} exceeds the maximum of ${maxPixels} pixels`,\r\n );\r\n }\r\n}\r\n\r\nfunction validateExportResourceOptions(options: ExportResourceOptions): void {\r\n positiveOption(options.imageTimeoutMs, DEFAULT_IMAGE_TIMEOUT_MS, 'imageTimeoutMs');\r\n positiveOption(options.maxDimension, DEFAULT_MAX_DIMENSION, 'maxDimension');\r\n positiveOption(options.maxPixels, DEFAULT_MAX_PIXELS, 'maxPixels');\r\n}\r\n\r\nfunction loadImages(\r\n elements: CanvasElement[],\r\n options: Pick<ExportResourceOptions, 'imageTimeoutMs' | 'onAssetError'> = {},\r\n): Promise<Map<string, HTMLImageElement>> {\r\n const imageElements = elements.filter(\r\n (el): el is CanvasElement & { src: string } => el.type === 'image' && 'src' in el,\r\n );\r\n\r\n const cache = new Map<string, HTMLImageElement>();\r\n if (imageElements.length === 0) return Promise.resolve(cache);\r\n\r\n const timeoutMs = positiveOption(\r\n options.imageTimeoutMs,\r\n DEFAULT_IMAGE_TIMEOUT_MS,\r\n 'imageTimeoutMs',\r\n );\r\n\r\n return new Promise((resolve) => {\r\n let remaining = imageElements.length;\r\n const done = () => {\r\n remaining--;\r\n if (remaining <= 0) resolve(cache);\r\n };\r\n\r\n for (const el of imageElements) {\r\n const img = new Image();\r\n img.crossOrigin = 'anonymous';\r\n let settled = false;\r\n const timer = setTimeout(() => {\r\n if (settled) return;\r\n settled = true;\r\n img.onload = null;\r\n img.onerror = null;\r\n options.onAssetError?.({ elementId: el.id, src: el.src, reason: 'timeout' });\r\n done();\r\n }, timeoutMs);\r\n const settle = (): boolean => {\r\n if (settled) return false;\r\n settled = true;\r\n clearTimeout(timer);\r\n img.onload = null;\r\n img.onerror = null;\r\n return true;\r\n };\r\n img.onload = () => {\r\n if (!settle()) return;\r\n cache.set(el.id, img);\r\n done();\r\n };\r\n img.onerror = (cause) => {\r\n if (!settle()) return;\r\n options.onAssetError?.({ elementId: el.id, src: el.src, reason: 'load', cause });\r\n done();\r\n };\r\n img.src = el.src;\r\n }\r\n });\r\n}\r\n\r\nexport async function exportImage(\r\n store: ElementStore,\r\n options: ExportImageOptions = {},\r\n layerManager?: LayerManager,\r\n): Promise<Blob | null> {\r\n const requestedScale = positiveOption(options.scale, 2, 'scale');\r\n const scaleMode = options.scaleMode ?? 'exact';\r\n if (scaleMode !== 'exact' && scaleMode !== 'fit') {\r\n throw new RangeError(`scaleMode must be 'exact' or 'fit'`);\r\n }\r\n const padding = nonNegativeOption(options.padding, 0, 'padding');\r\n validateExportResourceOptions(options);\r\n validateHtmlExportOptions(options);\r\n const format = options.format ?? 'png';\r\n if (format !== 'png' && format !== 'jpeg') {\r\n throw new RangeError(`format must be 'png' or 'jpeg'`);\r\n }\r\n if (options.quality !== undefined) {\r\n if (!Number.isFinite(options.quality) || options.quality <= 0 || options.quality > 1) {\r\n throw new RangeError('quality must be a finite number in (0, 1]');\r\n }\r\n }\r\n const background = options.background ?? '#ffffff';\r\n const filter = options.filter;\r\n\r\n const allElements = store.getAll();\r\n let visibleElements = layerManager\r\n ? allElements.filter((el) => layerManager.isLayerVisible(el.layerId))\r\n : allElements;\r\n\r\n if (filter) {\r\n visibleElements = visibleElements.filter(filter);\r\n }\r\n\r\n const bounds = resolveExportBounds(options.region, visibleElements, padding);\r\n if (!bounds) return null;\r\n\r\n const scale =\r\n scaleMode === 'fit' ? fitExportScale(bounds, requestedScale, options) : requestedScale;\r\n const width = Math.ceil(bounds.w * scale);\r\n const height = Math.ceil(bounds.h * scale);\r\n assertExportSize(width, height, options);\r\n const imageCache = await loadImages(visibleElements, options);\r\n const htmlElements = visibleElements.filter((el): el is HtmlElement => el.type === 'html');\r\n const htmlSources = await renderHtmlElements(htmlElements, options);\r\n\r\n const canvas = document.createElement('canvas');\r\n canvas.width = width;\r\n canvas.height = height;\r\n\r\n const ctx = canvas.getContext('2d');\r\n if (!ctx) return null;\r\n\r\n ctx.scale(scale, scale);\r\n ctx.translate(-bounds.x, -bounds.y);\r\n\r\n ctx.fillStyle = background;\r\n ctx.fillRect(bounds.x, bounds.y, bounds.w, bounds.h);\r\n\r\n const renderer = new ElementRenderer();\r\n renderer.setStore(store);\r\n\r\n const grids: GridElement[] = [];\r\n const renderElement = (target: CanvasRenderingContext2D, el: CanvasElement): void => {\r\n if (el.type === 'note') {\r\n const b = getElementBounds(el);\r\n withRotation(target, el, b ? center(b) : el.position, () => renderNoteOnCanvas(target, el));\r\n return;\r\n }\r\n\r\n if (el.type === 'text') {\r\n const b = getElementBounds(el);\r\n withRotation(target, el, b ? center(b) : el.position, () => renderTextOnCanvas(target, el));\r\n return;\r\n }\r\n\r\n if (el.type === 'html') {\r\n const source = htmlSources.get(el.id);\r\n if (!source) return;\r\n const b = getElementBounds(el);\r\n try {\r\n withRotation(target, el, b ? center(b) : el.position, () =>\r\n target.drawImage(source, el.position.x, el.position.y, el.size.w, el.size.h),\r\n );\r\n } catch (cause) {\r\n options.onHtmlError?.({\r\n elementId: el.id,\r\n htmlType: el.htmlType,\r\n reason: 'render',\r\n cause,\r\n });\r\n }\r\n return;\r\n }\r\n\r\n if (el.type === 'image') {\r\n const img = imageCache.get(el.id);\r\n if (img) {\r\n const b = getElementBounds(el);\r\n withRotation(target, el, b ? center(b) : el.position, () =>\r\n target.drawImage(img, el.position.x, el.position.y, el.size.w, el.size.h),\r\n );\r\n }\r\n return;\r\n }\r\n\r\n renderer.renderCanvasElement(target, el);\r\n };\r\n\r\n const layerGroups = new Map<string, CanvasElement[]>();\r\n for (const el of visibleElements) {\r\n if (el.type === 'grid') {\r\n grids.push(el);\r\n continue;\r\n }\r\n const group = layerGroups.get(el.layerId) ?? [];\r\n group.push(el);\r\n layerGroups.set(el.layerId, group);\r\n }\r\n\r\n for (const [layerId, elements] of layerGroups) {\r\n const opacity = layerManager?.getLayer?.(layerId)?.opacity ?? 1;\r\n if (opacity === 1) {\r\n for (const el of elements) renderElement(ctx, el);\r\n continue;\r\n }\r\n\r\n const layerCanvas = document.createElement('canvas');\r\n layerCanvas.width = canvas.width;\r\n layerCanvas.height = canvas.height;\r\n const layerCtx = layerCanvas.getContext('2d');\r\n if (!layerCtx) continue;\r\n layerCtx.scale(scale, scale);\r\n layerCtx.translate(-bounds.x, -bounds.y);\r\n for (const el of elements) renderElement(layerCtx, el);\r\n\r\n ctx.save();\r\n ctx.setTransform(1, 0, 0, 1, 0, 0);\r\n ctx.globalAlpha = opacity;\r\n ctx.drawImage(layerCanvas, 0, 0);\r\n ctx.restore();\r\n }\r\n\r\n for (const grid of grids) {\r\n ctx.save();\r\n ctx.globalAlpha = layerManager?.getLayer?.(grid.layerId)?.opacity ?? 1;\r\n renderGridForBounds(ctx, grid, bounds);\r\n ctx.restore();\r\n }\r\n\r\n const mimeType = format === 'jpeg' ? 'image/jpeg' : 'image/png';\r\n return new Promise((resolve) => {\r\n canvas.toBlob((blob) => resolve(blob), mimeType, options.quality);\r\n });\r\n}\r\n\r\nexport {\r\n assertExportSize,\r\n computeBounds,\r\n fitExportScale,\r\n getElementRect,\r\n loadImages,\r\n nonNegativeOption,\r\n positiveOption,\r\n validateExportResourceOptions,\r\n};\r\n","import type {\r\n CanvasElement,\r\n StrokeElement,\r\n ShapeElement,\r\n ArrowElement,\r\n ImageElement,\r\n TextElement,\r\n NoteElement,\r\n GridElement,\r\n TemplateElement,\r\n HtmlElement,\r\n} from '../elements/types';\r\nimport type { ElementStore } from '../elements/element-store';\r\nimport type { LayerManager } from '../layers/layer-manager';\r\nimport { getStrokeRenderData } from '../elements/stroke-cache';\r\nimport { lineEndpoints } from '../elements/shape-geometry';\r\nimport { getArrowControlPoint, getArrowMidpoint } from '../elements/arrow-geometry';\r\nimport { getArrowRenderGeometry } from '../elements/arrow-render-cache';\r\nimport { getVisualEndpoints, getArrowDashPattern } from '../elements/renderers/arrow-renderer';\r\nimport { getSquareGridLines, getHexVertices, getHexCenters } from '../elements/grid-renderer';\r\nimport {\r\n getHexCellsInRadius,\r\n getHexCellsInCone,\r\n getHexCellsInLine,\r\n getHexCellsInSquare,\r\n getHexCellsInRectangle,\r\n} from '../elements/hex-fill';\r\nimport { getElementBounds } from '../elements/element-bounds';\r\nimport { renderNoteOnCanvas } from './note-canvas-renderer';\r\nimport { renderTextOnCanvas } from './text-canvas-renderer';\r\nimport {\r\n assertExportSize,\r\n loadImages,\r\n computeBounds,\r\n nonNegativeOption,\r\n positiveOption,\r\n validateExportResourceOptions,\r\n} from './export-image';\r\nimport type { ExportResourceOptions } from './export-image';\r\nimport { renderHtmlElements, validateHtmlExportOptions } from './html-export';\r\nimport type { HtmlExportOptions } from './html-export';\r\n\r\nexport interface ExportSvgOptions extends ExportResourceOptions, HtmlExportOptions {\r\n padding?: number;\r\n background?: string;\r\n filter?: (el: CanvasElement) => boolean;\r\n rasterScale?: number;\r\n}\r\n\r\ninterface Bounds {\r\n x: number;\r\n y: number;\r\n w: number;\r\n h: number;\r\n}\r\n\r\nconst ARROWHEAD_LENGTH = 12;\r\nconst ARROWHEAD_ANGLE = Math.PI / 6;\r\nconst ARROW_LABEL_FONT_SIZE = 14;\r\n\r\nfunction esc(s: string): string {\r\n return s\r\n .replace(/&/g, '&amp;')\r\n .replace(/</g, '&lt;')\r\n .replace(/>/g, '&gt;')\r\n .replace(/\"/g, '&quot;')\r\n .replace(/'/g, '&#39;');\r\n}\r\n\r\nconst n = (v: number): string => (Number.isFinite(v) ? `${Math.round(v * 1000) / 1000}` : '0');\r\n\r\nfunction elementCenter(el: CanvasElement): { x: number; y: number } | null {\r\n const b = getElementBounds(el);\r\n if (!b) return null;\r\n return { x: b.x + b.w / 2, y: b.y + b.h / 2 };\r\n}\r\n\r\n/** Wrap a fragment in a rotation group matching withRotation (radians → degrees). */\r\nfunction withRotationSvg(el: CanvasElement, fragment: string): string {\r\n const angle = el.rotation ?? 0;\r\n if (!angle || !fragment) return fragment;\r\n const c = elementCenter(el);\r\n if (!c) return fragment;\r\n const deg = (angle * 180) / Math.PI;\r\n return `<g transform=\"rotate(${n(deg)} ${n(c.x)} ${n(c.y)})\">${fragment}</g>`;\r\n}\r\n\r\n// Strokes use variable per-point width on the canvas; SVG <path> takes a single\r\n// stroke-width, so we mirror the canvas width-bucketing: segments are grouped by\r\n// quantized width and each bucket becomes one <path> of bezier sub-paths. This\r\n// reproduces the canvas geometry exactly. We rebuild buckets from segments+widths\r\n// (always populated) rather than the Path2D buckets, which are absent under jsdom.\r\nconst WIDTH_QUANTUM = 0.25;\r\n\r\nfunction emitStroke(stroke: StrokeElement): string {\r\n if (stroke.points.length < 2) return '';\r\n const data = getStrokeRenderData(stroke);\r\n const { x: ox, y: oy } = stroke.position;\r\n\r\n const byWidth = new Map<number, string[]>();\r\n for (let i = 0; i < data.segments.length; i++) {\r\n const seg = data.segments[i];\r\n const w = data.widths[i];\r\n if (!seg || w === undefined) continue;\r\n const q = Math.max(WIDTH_QUANTUM, Math.round(w / WIDTH_QUANTUM) * WIDTH_QUANTUM);\r\n let parts = byWidth.get(q);\r\n if (!parts) {\r\n parts = [];\r\n byWidth.set(q, parts);\r\n }\r\n parts.push(\r\n `M${n(ox + seg.start.x)} ${n(oy + seg.start.y)} C${n(ox + seg.cp1.x)} ${n(oy + seg.cp1.y)} ${n(ox + seg.cp2.x)} ${n(oy + seg.cp2.y)} ${n(ox + seg.end.x)} ${n(oy + seg.end.y)}`,\r\n );\r\n }\r\n\r\n const blend = stroke.blendMode === 'multiply' ? ' style=\"mix-blend-mode:multiply\"' : '';\r\n let out = '';\r\n for (const [width, parts] of byWidth) {\r\n out += `<path d=\"${parts.join(' ')}\" fill=\"none\" stroke=\"${esc(stroke.color)}\" stroke-width=\"${n(width)}\" stroke-linecap=\"round\" stroke-linejoin=\"round\" opacity=\"${n(stroke.opacity)}\"${blend} />`;\r\n }\r\n return out;\r\n}\r\n\r\nfunction emitShape(shape: ShapeElement): string {\r\n const { x, y } = shape.position;\r\n const { w, h } = shape.size;\r\n const fill = shape.fillColor !== 'none' && shape.shape !== 'line' ? esc(shape.fillColor) : 'none';\r\n const stroke = shape.strokeWidth > 0 ? esc(shape.strokeColor) : 'none';\r\n const sw = shape.strokeWidth > 0 ? ` stroke-width=\"${n(shape.strokeWidth)}\"` : '';\r\n\r\n switch (shape.shape) {\r\n case 'rectangle':\r\n return `<rect x=\"${n(x)}\" y=\"${n(y)}\" width=\"${n(w)}\" height=\"${n(h)}\" fill=\"${fill}\" stroke=\"${stroke}\"${sw} />`;\r\n case 'ellipse':\r\n return `<ellipse cx=\"${n(x + w / 2)}\" cy=\"${n(y + h / 2)}\" rx=\"${n(w / 2)}\" ry=\"${n(h / 2)}\" fill=\"${fill}\" stroke=\"${stroke}\"${sw} />`;\r\n case 'line': {\r\n const [a, b] = lineEndpoints(shape);\r\n return `<line x1=\"${n(a.x)}\" y1=\"${n(a.y)}\" x2=\"${n(b.x)}\" y2=\"${n(b.y)}\" stroke=\"${stroke}\"${sw} stroke-linecap=\"round\" />`;\r\n }\r\n }\r\n}\r\n\r\nfunction emitArrow(arrow: ArrowElement, store: ElementStore): string {\r\n const geometry = getArrowRenderGeometry(arrow);\r\n // Bound arrows store from/to at the bound element's CENTER; the canvas renderer\r\n // snaps them to the element EDGE at draw time. Mirror that for PNG/canvas parity.\r\n const { visualFrom: from, visualTo: to } = getVisualEndpoints(arrow, geometry, store);\r\n\r\n let d: string;\r\n if (arrow.bend !== 0) {\r\n const cp = geometry.controlPoint ?? getArrowControlPoint(from, to, arrow.bend);\r\n d = `M${n(from.x)} ${n(from.y)} Q${n(cp.x)} ${n(cp.y)} ${n(to.x)} ${n(to.y)}`;\r\n } else {\r\n d = `M${n(from.x)} ${n(from.y)} L${n(to.x)} ${n(to.y)}`;\r\n }\r\n\r\n const pattern = getArrowDashPattern(arrow.strokeStyle);\r\n const dash = pattern.length > 0 ? ` stroke-dasharray=\"${pattern.join(' ')}\"` : '';\r\n let out = `<path d=\"${d}\" fill=\"none\" stroke=\"${esc(arrow.color)}\" stroke-width=\"${n(arrow.width)}\" stroke-linecap=\"round\"${dash} />`;\r\n\r\n // Arrowhead — mirror arrow-renderer's polygon math (tip at the visual endpoint).\r\n const angle = geometry.tangentEnd;\r\n const p1x = to.x - ARROWHEAD_LENGTH * Math.cos(angle - ARROWHEAD_ANGLE);\r\n const p1y = to.y - ARROWHEAD_LENGTH * Math.sin(angle - ARROWHEAD_ANGLE);\r\n const p2x = to.x - ARROWHEAD_LENGTH * Math.cos(angle + ARROWHEAD_ANGLE);\r\n const p2y = to.y - ARROWHEAD_LENGTH * Math.sin(angle + ARROWHEAD_ANGLE);\r\n out += `<polygon points=\"${n(to.x)},${n(to.y)} ${n(p1x)},${n(p1y)} ${n(p2x)},${n(p2y)}\" fill=\"${esc(arrow.color)}\" />`;\r\n\r\n if (arrow.label && arrow.label.length > 0) {\r\n // Canvas renderer places the label at the raw-endpoint midpoint, not the visual one.\r\n const mid = getArrowMidpoint(arrow.from, arrow.to, arrow.bend);\r\n const approxW = arrow.label.length * ARROW_LABEL_FONT_SIZE * 0.6;\r\n const padX = 6;\r\n const padY = 4;\r\n const lw = approxW + padX * 2;\r\n const lh = ARROW_LABEL_FONT_SIZE + padY * 2;\r\n out += `<rect x=\"${n(mid.x - lw / 2)}\" y=\"${n(mid.y - lh / 2)}\" width=\"${n(lw)}\" height=\"${n(lh)}\" rx=\"4\" fill=\"rgba(255,255,255,0.9)\" />`;\r\n out += `<text x=\"${n(mid.x)}\" y=\"${n(mid.y)}\" font-family=\"system-ui, sans-serif\" font-size=\"${ARROW_LABEL_FONT_SIZE}\" fill=\"#1a1a1a\" text-anchor=\"middle\" dominant-baseline=\"central\">${esc(arrow.label)}</text>`;\r\n }\r\n\r\n return out;\r\n}\r\n\r\nfunction emitImage(image: ImageElement | HtmlElement, dataUri: string | undefined): string {\r\n const href = dataUri ?? ('src' in image ? image.src : '');\r\n if (!href) return '';\r\n const { x, y } = image.position;\r\n const { w, h } = image.size;\r\n return `<image href=\"${esc(href)}\" x=\"${n(x)}\" y=\"${n(y)}\" width=\"${n(w)}\" height=\"${n(h)}\" />`;\r\n}\r\n\r\nfunction emitText(\r\n text: TextElement,\r\n rasterScale: number,\r\n resourceOptions: ExportResourceOptions,\r\n): string {\r\n if (!text.text) return '';\r\n const { x, y } = text.position;\r\n const { w, h } = text.size;\r\n if (typeof document === 'undefined') return '';\r\n\r\n const width = Math.max(1, Math.ceil(w * rasterScale));\r\n const height = Math.max(1, Math.ceil(h * rasterScale));\r\n assertExportSize(width, height, resourceOptions);\r\n const canvas = document.createElement('canvas');\r\n canvas.width = width;\r\n canvas.height = height;\r\n const ctx = canvas.getContext('2d');\r\n if (!ctx) return '';\r\n\r\n ctx.scale(rasterScale, rasterScale);\r\n ctx.translate(-x, -y);\r\n renderTextOnCanvas(ctx, text);\r\n\r\n let dataUri: string;\r\n try {\r\n dataUri = canvas.toDataURL();\r\n } catch {\r\n return '';\r\n }\r\n if (!dataUri || !dataUri.startsWith('data:')) return '';\r\n\r\n return `<image href=\"${esc(dataUri)}\" x=\"${n(x)}\" y=\"${n(y)}\" width=\"${n(w)}\" height=\"${n(h)}\" />`;\r\n}\r\n\r\nfunction emitNote(\r\n note: NoteElement,\r\n rasterScale: number,\r\n resourceOptions: ExportResourceOptions,\r\n): string {\r\n const { x, y } = note.position;\r\n const { w, h } = note.size;\r\n if (typeof document === 'undefined') return emitNotePlaceholder(note);\r\n\r\n const width = Math.max(1, Math.ceil(w * rasterScale));\r\n const height = Math.max(1, Math.ceil(h * rasterScale));\r\n assertExportSize(width, height, resourceOptions);\r\n const canvas = document.createElement('canvas');\r\n canvas.width = width;\r\n canvas.height = height;\r\n const ctx = canvas.getContext('2d');\r\n if (!ctx) return emitNotePlaceholder(note);\r\n\r\n ctx.scale(rasterScale, rasterScale);\r\n ctx.translate(-x, -y);\r\n renderNoteOnCanvas(ctx, note);\r\n\r\n let dataUri: string;\r\n try {\r\n dataUri = canvas.toDataURL();\r\n } catch {\r\n return emitNotePlaceholder(note);\r\n }\r\n if (!dataUri || !dataUri.startsWith('data:')) return emitNotePlaceholder(note);\r\n\r\n return `<image href=\"${esc(dataUri)}\" x=\"${n(x)}\" y=\"${n(y)}\" width=\"${n(w)}\" height=\"${n(h)}\" />`;\r\n}\r\n\r\nfunction emitNotePlaceholder(note: NoteElement): string {\r\n const { x, y } = note.position;\r\n const { w, h } = note.size;\r\n return `<rect x=\"${n(x)}\" y=\"${n(y)}\" width=\"${n(w)}\" height=\"${n(h)}\" rx=\"4\" fill=\"${esc(note.backgroundColor)}\" />`;\r\n}\r\n\r\nfunction emitGrid(grid: GridElement, bounds: Bounds): string {\r\n if (grid.cellSize <= 0) return '';\r\n const vb = {\r\n minX: bounds.x,\r\n minY: bounds.y,\r\n maxX: bounds.x + bounds.w,\r\n maxY: bounds.y + bounds.h,\r\n };\r\n const stroke = esc(grid.strokeColor);\r\n const sw = n(grid.strokeWidth);\r\n const op = n(grid.opacity);\r\n\r\n if (grid.gridType === 'hex') {\r\n const centers = getHexCenters(vb, grid.cellSize, grid.hexOrientation);\r\n let d = '';\r\n for (const c of centers) {\r\n const verts = getHexVertices(c.x, c.y, grid.cellSize, grid.hexOrientation);\r\n const first = verts[0];\r\n if (!first) continue;\r\n d += `M${n(first.x)} ${n(first.y)}`;\r\n for (let i = 1; i < verts.length; i++) {\r\n const v = verts[i];\r\n if (v) d += `L${n(v.x)} ${n(v.y)}`;\r\n }\r\n d += 'Z';\r\n }\r\n return `<path d=\"${d}\" fill=\"none\" stroke=\"${stroke}\" stroke-width=\"${sw}\" opacity=\"${op}\" />`;\r\n }\r\n\r\n const { verticals, horizontals } = getSquareGridLines(vb, grid.cellSize);\r\n let d = '';\r\n for (const gx of verticals) d += `M${n(gx)} ${n(vb.minY)}L${n(gx)} ${n(vb.maxY)}`;\r\n for (const gy of horizontals) d += `M${n(vb.minX)} ${n(gy)}L${n(vb.maxX)} ${n(gy)}`;\r\n return `<path d=\"${d}\" fill=\"none\" stroke=\"${stroke}\" stroke-width=\"${sw}\" opacity=\"${op}\" />`;\r\n}\r\n\r\n// Geometric template only (square-grid context). Hex-grid templates fill snapped\r\n// hex cells; we approximate by emitting the cell hex outlines.\r\nfunction emitTemplate(template: TemplateElement, grid: GridElement | undefined): string {\r\n if (grid && grid.gridType === 'hex') {\r\n return emitHexTemplate(template, grid);\r\n }\r\n return emitGeometricTemplate(template);\r\n}\r\n\r\nfunction emitGeometricTemplate(t: TemplateElement): string {\r\n const { x: cx, y: cy } = t.position;\r\n const r = t.radius;\r\n const fill = esc(t.fillColor);\r\n const stroke = esc(t.strokeColor);\r\n const sw = n(t.strokeWidth);\r\n const op = n(t.opacity);\r\n const attrs = `fill=\"${fill}\" stroke=\"${stroke}\" stroke-width=\"${sw}\" opacity=\"${op}\"`;\r\n\r\n switch (t.templateShape) {\r\n case 'circle':\r\n return `<circle cx=\"${n(cx)}\" cy=\"${n(cy)}\" r=\"${n(r)}\" ${attrs} />`;\r\n case 'square':\r\n return `<rect x=\"${n(cx - r / 2)}\" y=\"${n(cy - r / 2)}\" width=\"${n(r)}\" height=\"${n(r)}\" ${attrs} />`;\r\n case 'cone': {\r\n const halfAngle = Math.atan(0.5);\r\n const a0 = t.angle - halfAngle;\r\n const a1 = t.angle + halfAngle;\r\n const p0x = cx + r * Math.cos(a0);\r\n const p0y = cy + r * Math.sin(a0);\r\n const p1x = cx + r * Math.cos(a1);\r\n const p1y = cy + r * Math.sin(a1);\r\n const large = a1 - a0 > Math.PI ? 1 : 0;\r\n return `<path d=\"M${n(cx)} ${n(cy)} L${n(p0x)} ${n(p0y)} A${n(r)} ${n(r)} 0 ${large} 1 ${n(p1x)} ${n(p1y)} Z\" ${attrs} />`;\r\n }\r\n case 'line': {\r\n const halfW = r / 12;\r\n const cos = Math.cos(t.angle);\r\n const sin = Math.sin(t.angle);\r\n const perpX = -sin * halfW;\r\n const perpY = cos * halfW;\r\n const pts = [\r\n [cx + perpX, cy + perpY],\r\n [cx + r * cos + perpX, cy + r * sin + perpY],\r\n [cx + r * cos - perpX, cy + r * sin - perpY],\r\n [cx - perpX, cy - perpY],\r\n ]\r\n .map(([px, py]) => `${n(px ?? 0)},${n(py ?? 0)}`)\r\n .join(' ');\r\n return `<polygon points=\"${pts}\" ${attrs} />`;\r\n }\r\n case 'rectangle': {\r\n const halfW = (t.width ?? 0) / 2;\r\n const cos = Math.cos(t.angle);\r\n const sin = Math.sin(t.angle);\r\n const perpX = -sin * halfW;\r\n const perpY = cos * halfW;\r\n const pts = [\r\n [cx + perpX, cy + perpY],\r\n [cx + r * cos + perpX, cy + r * sin + perpY],\r\n [cx + r * cos - perpX, cy + r * sin - perpY],\r\n [cx - perpX, cy - perpY],\r\n ]\r\n .map(([px, py]) => `${n(px ?? 0)},${n(py ?? 0)}`)\r\n .join(' ');\r\n return `<polygon points=\"${pts}\" ${attrs} />`;\r\n }\r\n }\r\n}\r\n\r\nfunction emitHexTemplate(t: TemplateElement, grid: GridElement): string {\r\n const cellSize = grid.cellSize;\r\n const orientation = grid.hexOrientation;\r\n const snapUnit = Math.sqrt(3) * cellSize;\r\n const radiusCells = t.radius / snapUnit;\r\n const center = t.position;\r\n\r\n let cells: { x: number; y: number }[];\r\n switch (t.templateShape) {\r\n case 'circle':\r\n cells = getHexCellsInRadius(center, radiusCells, cellSize, orientation);\r\n break;\r\n case 'cone':\r\n cells = getHexCellsInCone(center, t.angle, radiusCells, cellSize, orientation);\r\n break;\r\n case 'line':\r\n cells = getHexCellsInLine(center, t.angle, radiusCells, cellSize, orientation);\r\n break;\r\n case 'square':\r\n cells = getHexCellsInSquare(center, radiusCells, cellSize, orientation);\r\n break;\r\n case 'rectangle': {\r\n const widthCells = (t.width ?? 0) / snapUnit;\r\n cells = getHexCellsInRectangle(\r\n center,\r\n t.angle,\r\n radiusCells,\r\n widthCells,\r\n cellSize,\r\n orientation,\r\n );\r\n break;\r\n }\r\n }\r\n\r\n let d = '';\r\n for (const cell of cells) {\r\n const verts = getHexVertices(cell.x, cell.y, cellSize, orientation);\r\n const first = verts[0];\r\n if (!first) continue;\r\n d += `M${n(first.x)} ${n(first.y)}`;\r\n for (let i = 1; i < verts.length; i++) {\r\n const v = verts[i];\r\n if (v) d += `L${n(v.x)} ${n(v.y)}`;\r\n }\r\n d += 'Z';\r\n }\r\n return `<path d=\"${d}\" fill=\"${esc(t.fillColor)}\" stroke=\"${esc(t.strokeColor)}\" stroke-width=\"${n(t.strokeWidth)}\" opacity=\"${n(t.opacity)}\" />`;\r\n}\r\n\r\nexport async function exportSvg(\r\n store: ElementStore,\r\n options: ExportSvgOptions = {},\r\n layerManager?: LayerManager,\r\n): Promise<string> {\r\n const padding = nonNegativeOption(options.padding, 0, 'padding');\r\n const rasterScale = positiveOption(options.rasterScale, 2, 'rasterScale');\r\n validateExportResourceOptions(options);\r\n validateHtmlExportOptions(options);\r\n const filter = options.filter;\r\n\r\n const allElements = store.getAll();\r\n let visibleElements = layerManager\r\n ? allElements.filter((el) => layerManager.isLayerVisible(el.layerId))\r\n : allElements;\r\n if (filter) visibleElements = visibleElements.filter(filter);\r\n\r\n const bounds = computeBounds(visibleElements, padding);\r\n if (!bounds) {\r\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"0\" height=\"0\" viewBox=\"0 0 0 0\"></svg>`;\r\n }\r\n assertExportSize(Math.ceil(bounds.w), Math.ceil(bounds.h), options);\r\n\r\n // Only remote/blob image srcs need network loading; data: srcs pass through.\r\n const remoteImages = visibleElements.filter(\r\n (el) => el.type === 'image' && !el.src.startsWith('data:'),\r\n );\r\n const imageCache = await loadImages(remoteImages, options);\r\n const imageDataUris = encodeImages(visibleElements, imageCache, rasterScale, options);\r\n const htmlElements = visibleElements.filter((el): el is HtmlElement => el.type === 'html');\r\n const htmlSources = await renderHtmlElements(htmlElements, options);\r\n const htmlDataUris = encodeHtmlElements(htmlElements, htmlSources, rasterScale, options);\r\n\r\n const grids = visibleElements.filter((el): el is GridElement => el.type === 'grid');\r\n const firstGrid = grids[0];\r\n\r\n let body = '';\r\n if (options.background) {\r\n body += `<rect x=\"${n(bounds.x)}\" y=\"${n(bounds.y)}\" width=\"${n(bounds.w)}\" height=\"${n(bounds.h)}\" fill=\"${esc(options.background)}\" />`;\r\n }\r\n\r\n const layerBodies = new Map<string, string>();\r\n for (const el of visibleElements) {\r\n const emitted = emitElement(\r\n el,\r\n imageDataUris,\r\n htmlDataUris,\r\n rasterScale,\r\n firstGrid,\r\n store,\r\n options,\r\n );\r\n layerBodies.set(el.layerId, (layerBodies.get(el.layerId) ?? '') + emitted);\r\n }\r\n for (const [layerId, emitted] of layerBodies) {\r\n const opacity = layerManager?.getLayer?.(layerId)?.opacity ?? 1;\r\n body += opacity === 1 || emitted === '' ? emitted : `<g opacity=\"${n(opacity)}\">${emitted}</g>`;\r\n }\r\n for (const grid of grids) {\r\n const emitted = emitGrid(grid, bounds);\r\n const opacity = layerManager?.getLayer?.(grid.layerId)?.opacity ?? 1;\r\n body += opacity === 1 ? emitted : `<g opacity=\"${n(opacity)}\">${emitted}</g>`;\r\n }\r\n\r\n return (\r\n `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${n(bounds.w)}\" height=\"${n(bounds.h)}\" ` +\r\n `viewBox=\"${n(bounds.x)} ${n(bounds.y)} ${n(bounds.w)} ${n(bounds.h)}\">${body}</svg>`\r\n );\r\n}\r\n\r\nfunction emitElement(\r\n el: CanvasElement,\r\n imageDataUris: Map<string, string>,\r\n htmlDataUris: Map<string, string>,\r\n rasterScale: number,\r\n firstGrid: GridElement | undefined,\r\n store: ElementStore,\r\n resourceOptions: ExportResourceOptions,\r\n): string {\r\n switch (el.type) {\r\n case 'stroke':\r\n return withRotationSvg(el, emitStroke(el));\r\n case 'shape':\r\n return withRotationSvg(el, emitShape(el));\r\n case 'arrow':\r\n return emitArrow(el, store);\r\n case 'image':\r\n return withRotationSvg(el, emitImage(el, imageDataUris.get(el.id)));\r\n case 'text':\r\n return withRotationSvg(el, emitText(el, rasterScale, resourceOptions));\r\n case 'note':\r\n return withRotationSvg(el, emitNote(el, rasterScale, resourceOptions));\r\n case 'template':\r\n return emitTemplate(el, firstGrid);\r\n case 'grid':\r\n return '';\r\n case 'html':\r\n return withRotationSvg(el, emitImage(el, htmlDataUris.get(el.id)));\r\n default:\r\n return '';\r\n }\r\n}\r\n\r\nfunction encodeHtmlElements(\r\n elements: HtmlElement[],\r\n sources: Map<string, CanvasImageSource>,\r\n rasterScale: number,\r\n options: ExportSvgOptions,\r\n): Map<string, string> {\r\n const encoded = new Map<string, string>();\r\n for (const element of elements) {\r\n const source = sources.get(element.id);\r\n if (!source) continue;\r\n const width = Math.max(1, Math.ceil(element.size.w * rasterScale));\r\n const height = Math.max(1, Math.ceil(element.size.h * rasterScale));\r\n assertExportSize(width, height, options);\r\n if (typeof document === 'undefined') {\r\n options.onHtmlError?.({\r\n elementId: element.id,\r\n htmlType: element.htmlType,\r\n reason: 'encode',\r\n });\r\n continue;\r\n }\r\n const canvas = document.createElement('canvas');\r\n canvas.width = width;\r\n canvas.height = height;\r\n const ctx = canvas.getContext('2d');\r\n if (!ctx) {\r\n options.onHtmlError?.({\r\n elementId: element.id,\r\n htmlType: element.htmlType,\r\n reason: 'encode',\r\n });\r\n continue;\r\n }\r\n try {\r\n ctx.drawImage(source, 0, 0, width, height);\r\n const dataUri = canvas.toDataURL();\r\n if (dataUri.startsWith('data:')) {\r\n encoded.set(element.id, dataUri);\r\n } else {\r\n options.onHtmlError?.({\r\n elementId: element.id,\r\n htmlType: element.htmlType,\r\n reason: 'encode',\r\n });\r\n }\r\n } catch (cause) {\r\n options.onHtmlError?.({\r\n elementId: element.id,\r\n htmlType: element.htmlType,\r\n reason: 'encode',\r\n cause,\r\n });\r\n }\r\n }\r\n return encoded;\r\n}\r\n\r\n/** data: srcs pass through; remote/blob srcs are rasterized to data-URIs via the loaded image. */\r\nfunction encodeImages(\r\n elements: CanvasElement[],\r\n imageCache: Map<string, HTMLImageElement>,\r\n rasterScale: number,\r\n resourceOptions: ExportResourceOptions,\r\n): Map<string, string> {\r\n const out = new Map<string, string>();\r\n for (const el of elements) {\r\n if (el.type !== 'image') continue;\r\n if (el.src.startsWith('data:')) {\r\n out.set(el.id, el.src);\r\n continue;\r\n }\r\n const img = imageCache.get(el.id);\r\n if (!img || typeof document === 'undefined') continue;\r\n const width = Math.max(1, Math.ceil(el.size.w * rasterScale));\r\n const height = Math.max(1, Math.ceil(el.size.h * rasterScale));\r\n assertExportSize(width, height, resourceOptions);\r\n const canvas = document.createElement('canvas');\r\n canvas.width = width;\r\n canvas.height = height;\r\n const ctx = canvas.getContext('2d');\r\n if (!ctx) {\r\n resourceOptions.onAssetError?.({ elementId: el.id, src: el.src, reason: 'encode' });\r\n continue;\r\n }\r\n try {\r\n ctx.drawImage(img, 0, 0, canvas.width, canvas.height);\r\n const uri = canvas.toDataURL();\r\n if (uri.startsWith('data:')) out.set(el.id, uri);\r\n else resourceOptions.onAssetError?.({ elementId: el.id, src: el.src, reason: 'encode' });\r\n } catch (cause) {\r\n resourceOptions.onAssetError?.({ elementId: el.id, src: el.src, reason: 'encode', cause });\r\n }\r\n }\r\n return out;\r\n}\r\n","import { EventBus } from '../core/event-bus';\r\nimport type { ElementStore } from '../elements/element-store';\r\nimport type { Layer } from './types';\r\nimport { createId } from '../elements/create-id';\r\n\r\ninterface LayerManagerEvents {\r\n change: null;\r\n create: Layer;\r\n remove: Layer;\r\n update: { previous: Layer; current: Layer };\r\n}\r\n\r\nexport class LayerManager {\r\n private layers = new Map<string, Layer>();\r\n private _activeLayerId: string;\r\n private bus = new EventBus<LayerManagerEvents>();\r\n\r\n constructor(private readonly store: ElementStore) {\r\n const defaultLayer: Layer = {\r\n id: createId('layer'),\r\n name: 'Layer 1',\r\n visible: true,\r\n locked: false,\r\n order: 0,\r\n opacity: 1.0,\r\n };\r\n this.layers.set(defaultLayer.id, defaultLayer);\r\n this._activeLayerId = defaultLayer.id;\r\n this.syncLayerOrder();\r\n }\r\n\r\n get activeLayer(): Layer {\r\n const layer = this.layers.get(this._activeLayerId);\r\n if (!layer) throw new Error('Active layer not found');\r\n return { ...layer };\r\n }\r\n\r\n get activeLayerId(): string {\r\n return this._activeLayerId;\r\n }\r\n\r\n getLayers(): Layer[] {\r\n return [...this.layers.values()].sort((a, b) => a.order - b.order).map((l) => ({ ...l }));\r\n }\r\n\r\n getLayer(id: string): Layer | undefined {\r\n const layer = this.layers.get(id);\r\n return layer ? { ...layer } : undefined;\r\n }\r\n\r\n isLayerVisible(id: string): boolean {\r\n return this.layers.get(id)?.visible ?? true;\r\n }\r\n\r\n isLayerLocked(id: string): boolean {\r\n return this.layers.get(id)?.locked ?? false;\r\n }\r\n\r\n createLayer(name?: string): Layer {\r\n const maxOrder = Math.max(...[...this.layers.values()].map((l) => l.order), -1);\r\n const autoName = name ?? `Layer ${this.layers.size + 1}`;\r\n const layer: Layer = {\r\n id: createId('layer'),\r\n name: autoName,\r\n visible: true,\r\n locked: false,\r\n order: maxOrder + 1,\r\n opacity: 1.0,\r\n };\r\n this.addLayerDirect(layer);\r\n return { ...layer };\r\n }\r\n\r\n removeLayer(id: string): void {\r\n if (this.layers.size <= 1) {\r\n throw new Error('Cannot remove the last layer');\r\n }\r\n if (this._activeLayerId === id) {\r\n const remaining = [...this.layers.values()]\r\n .filter((l) => l.id !== id)\r\n .sort((a, b) => b.order - a.order);\r\n const fallback = remaining[0];\r\n if (fallback) this._activeLayerId = fallback.id;\r\n }\r\n const elements = this.store.getAll().filter((el) => el.layerId === id);\r\n for (const el of elements) {\r\n this.store.update(el.id, { layerId: this._activeLayerId });\r\n }\r\n this.removeLayerDirect(id);\r\n }\r\n\r\n renameLayer(id: string, name: string): void {\r\n this.updateLayerDirect(id, { name });\r\n }\r\n\r\n reorderLayer(id: string, newOrder: number): void {\r\n if (!this.layers.has(id)) return;\r\n this.updateLayerDirect(id, { order: newOrder });\r\n }\r\n\r\n setLayerVisible(id: string, visible: boolean): boolean {\r\n if (!visible && id === this._activeLayerId) {\r\n const fallback = this.findFallbackLayer(id);\r\n if (!fallback) return false;\r\n this._activeLayerId = fallback.id;\r\n }\r\n this.updateLayerDirect(id, { visible });\r\n return true;\r\n }\r\n\r\n setLayerLocked(id: string, locked: boolean): boolean {\r\n if (locked && id === this._activeLayerId) {\r\n const fallback = this.findFallbackLayer(id);\r\n if (!fallback) return false;\r\n this._activeLayerId = fallback.id;\r\n }\r\n this.updateLayerDirect(id, { locked });\r\n return true;\r\n }\r\n\r\n setLayerOpacity(id: string, opacity: number): void {\r\n if (!this.layers.has(id)) return;\r\n this.updateLayerDirect(id, { opacity: Math.max(0, Math.min(1, opacity)) });\r\n }\r\n\r\n setActiveLayer(id: string): void {\r\n if (!this.layers.has(id)) return;\r\n this._activeLayerId = id;\r\n this.bus.emit('change', null);\r\n }\r\n\r\n moveElementToLayer(elementId: string, layerId: string): void {\r\n if (!this.layers.has(layerId)) return;\r\n this.store.update(elementId, { layerId });\r\n this.bus.emit('change', null);\r\n }\r\n\r\n snapshot(): Layer[] {\r\n return this.getLayers();\r\n }\r\n\r\n loadSnapshot(layers: Layer[]): void {\r\n this.layers.clear();\r\n for (const layer of layers) {\r\n this.layers.set(layer.id, { ...layer });\r\n }\r\n const first = this.getLayers()[0];\r\n if (first) this._activeLayerId = first.id;\r\n this.syncLayerOrder();\r\n this.bus.emit('change', null);\r\n }\r\n\r\n on<K extends keyof LayerManagerEvents>(\r\n event: K,\r\n callback: (data: LayerManagerEvents[K]) => void,\r\n ): () => void {\r\n return this.bus.on(event, callback);\r\n }\r\n\r\n addLayerDirect(layer: Layer): void {\r\n this.layers.set(layer.id, { ...layer });\r\n this.syncLayerOrder();\r\n this.bus.emit('create', { ...layer });\r\n this.bus.emit('change', null);\r\n }\r\n\r\n removeLayerDirect(id: string): void {\r\n const layer = this.layers.get(id);\r\n this.layers.delete(id);\r\n this.syncLayerOrder();\r\n if (layer) this.bus.emit('remove', { ...layer });\r\n this.bus.emit('change', null);\r\n }\r\n\r\n updateLayerDirect(id: string, props: Omit<Partial<Layer>, 'id'>): void {\r\n const layer = this.layers.get(id);\r\n if (!layer) return;\r\n const previous = { ...layer };\r\n Object.assign(layer, props);\r\n if ('order' in props) this.syncLayerOrder();\r\n this.bus.emit('update', { previous, current: { ...layer } });\r\n this.bus.emit('change', null);\r\n }\r\n\r\n private syncLayerOrder(): void {\r\n const order = new Map<string, number>();\r\n for (const layer of this.layers.values()) {\r\n order.set(layer.id, layer.order);\r\n }\r\n this.store.setLayerOrder(order);\r\n }\r\n\r\n private findFallbackLayer(excludeId: string): Layer | undefined {\r\n return [...this.layers.values()]\r\n .filter((l) => l.id !== excludeId && l.visible && !l.locked)\r\n .sort((a, b) => b.order - a.order)[0];\r\n }\r\n}\r\n","export interface InteractModeDeps {\r\n getNode: (id: string) => HTMLDivElement | undefined;\r\n}\r\n\r\nexport class InteractMode {\r\n private interactingElementId: string | null = null;\r\n private readonly getNode: (id: string) => HTMLDivElement | undefined;\r\n\r\n constructor(deps: InteractModeDeps) {\r\n this.getNode = deps.getNode;\r\n }\r\n\r\n startInteracting(id: string): void {\r\n this.stopInteracting();\r\n const node = this.getNode(id);\r\n if (!node) return;\r\n\r\n this.interactingElementId = id;\r\n node.style.pointerEvents = 'auto';\r\n node.addEventListener('pointerdown', this.onNodePointerDown);\r\n\r\n window.addEventListener('keydown', this.onKeyDown);\r\n window.addEventListener('pointerdown', this.onPointerDown);\r\n }\r\n\r\n stopInteracting(): void {\r\n if (!this.interactingElementId) return;\r\n\r\n const node = this.getNode(this.interactingElementId);\r\n if (node) {\r\n node.style.pointerEvents = 'none';\r\n node.removeEventListener('pointerdown', this.onNodePointerDown);\r\n }\r\n\r\n this.interactingElementId = null;\r\n window.removeEventListener('keydown', this.onKeyDown);\r\n window.removeEventListener('pointerdown', this.onPointerDown);\r\n }\r\n\r\n isInteracting(): boolean {\r\n return this.interactingElementId !== null;\r\n }\r\n\r\n destroy(): void {\r\n this.stopInteracting();\r\n }\r\n\r\n private onNodePointerDown = (e: PointerEvent): void => {\r\n e.stopPropagation();\r\n };\r\n\r\n private onKeyDown = (e: KeyboardEvent): void => {\r\n if (e.key === 'Escape') {\r\n this.stopInteracting();\r\n }\r\n };\r\n\r\n private onPointerDown = (e: PointerEvent): void => {\r\n if (!this.interactingElementId) return;\r\n const target = e.target;\r\n if (!(target instanceof Element)) {\r\n this.stopInteracting();\r\n return;\r\n }\r\n\r\n const node = this.getNode(this.interactingElementId);\r\n if (node && !node.contains(target)) {\r\n this.stopInteracting();\r\n }\r\n };\r\n}\r\n","export interface DoubleTapDetectorOptions {\r\n timeout?: number;\r\n maxDistance?: number;\r\n}\r\n\r\nconst DEFAULT_TIMEOUT = 300;\r\nconst DEFAULT_MAX_DISTANCE = 20;\r\n\r\nexport class DoubleTapDetector {\r\n private readonly timeout: number;\r\n private readonly maxDistance: number;\r\n private lastTapTime = 0;\r\n private lastTapX = 0;\r\n private lastTapY = 0;\r\n private hasPendingTap = false;\r\n\r\n constructor(options?: DoubleTapDetectorOptions) {\r\n this.timeout = options?.timeout ?? DEFAULT_TIMEOUT;\r\n this.maxDistance = options?.maxDistance ?? DEFAULT_MAX_DISTANCE;\r\n }\r\n\r\n feed(e: PointerEvent): boolean {\r\n const now = Date.now();\r\n const x = e.clientX;\r\n const y = e.clientY;\r\n\r\n if (this.hasPendingTap) {\r\n const elapsed = now - this.lastTapTime;\r\n const dx = x - this.lastTapX;\r\n const dy = y - this.lastTapY;\r\n const dist = Math.sqrt(dx * dx + dy * dy);\r\n\r\n if (elapsed <= this.timeout && dist <= this.maxDistance) {\r\n this.reset();\r\n return true;\r\n }\r\n }\r\n\r\n this.lastTapTime = now;\r\n this.lastTapX = x;\r\n this.lastTapY = y;\r\n this.hasPendingTap = true;\r\n return false;\r\n }\r\n\r\n reset(): void {\r\n this.hasPendingTap = false;\r\n this.lastTapTime = 0;\r\n this.lastTapX = 0;\r\n this.lastTapY = 0;\r\n }\r\n}\r\n","import type { CanvasElement } from '../elements/types';\r\nimport type { ElementStore } from '../elements/element-store';\r\nimport { DEFAULT_NOTE_FONT_SIZE } from '../elements/element-factory';\r\nimport { DoubleTapDetector } from './double-tap-detector';\r\nexport interface DomNodeManagerDeps {\r\n domLayer: HTMLDivElement;\r\n onEditRequest: (id: string) => void;\r\n isEditingElement: (id: string) => boolean;\r\n getVersion?: (id: string) => number;\r\n}\r\n\r\nexport class DomNodeManager {\r\n private domNodes = new Map<string, HTMLDivElement>();\r\n private strata = new Map<number, HTMLDivElement>();\r\n private htmlContent = new Map<string, HTMLElement>();\r\n private readonly domLayer: HTMLDivElement;\r\n private readonly onEditRequest: (id: string) => void;\r\n private readonly isEditingElement: (id: string) => boolean;\r\n private readonly getVersion: ((id: string) => number) | null;\r\n private lastSyncedVersion = new Map<string, number>();\r\n private lastSyncedZIndex = new Map<string, number>();\r\n private lastSyncedOpacity = new Map<string, number>();\r\n private cameraTransform = '';\r\n\r\n constructor(deps: DomNodeManagerDeps) {\r\n this.domLayer = deps.domLayer;\r\n this.onEditRequest = deps.onEditRequest;\r\n this.isEditingElement = deps.isEditingElement;\r\n this.getVersion = deps.getVersion ?? null;\r\n }\r\n\r\n getNode(id: string): HTMLDivElement | undefined {\r\n return this.domNodes.get(id);\r\n }\r\n\r\n setCameraTransform(transform: string): void {\r\n if (transform === this.cameraTransform) return;\r\n this.cameraTransform = transform;\r\n for (const stratum of this.strata.values()) stratum.style.transform = transform;\r\n }\r\n\r\n storeHtmlContent(elementId: string, dom: HTMLElement): void {\r\n this.htmlContent.set(elementId, dom);\r\n }\r\n\r\n hasContent(elementId: string): boolean {\r\n return this.htmlContent.has(elementId);\r\n }\r\n\r\n resetHtmlContent(elementId: string): void {\r\n this.htmlContent.delete(elementId);\r\n this.lastSyncedVersion.delete(elementId);\r\n this.lastSyncedZIndex.delete(elementId);\r\n this.lastSyncedOpacity.delete(elementId);\r\n const node = this.domNodes.get(elementId);\r\n if (!node) return;\r\n while (node.firstChild) {\r\n node.removeChild(node.firstChild);\r\n }\r\n delete node.dataset['initialized'];\r\n }\r\n\r\n syncDomNode(element: CanvasElement, zIndex = 0, opacity = 1): void {\r\n let node = this.domNodes.get(element.id);\r\n if (!node) {\r\n node = document.createElement('div');\r\n node.dataset['elementId'] = element.id;\r\n Object.assign(node.style, {\r\n position: 'absolute',\r\n pointerEvents: 'auto',\r\n });\r\n this.getStratum(zIndex).appendChild(node);\r\n this.domNodes.set(element.id, node);\r\n } else if (this.getVersion) {\r\n const currentVersion = this.getVersion(element.id);\r\n const lastVersion = this.lastSyncedVersion.get(element.id);\r\n const lastZ = this.lastSyncedZIndex.get(element.id);\r\n const lastOpacity = this.lastSyncedOpacity.get(element.id);\r\n if (lastVersion === currentVersion && lastZ === zIndex && lastOpacity === opacity) {\r\n return;\r\n }\r\n }\r\n\r\n if (node.parentElement !== this.getStratum(zIndex)) {\r\n const previousStratum = node.parentElement;\r\n this.getStratum(zIndex).appendChild(node);\r\n if (previousStratum?.childElementCount === 0) {\r\n const previousOrder = Number(previousStratum.dataset['paintOrder']);\r\n previousStratum.remove();\r\n this.strata.delete(previousOrder);\r\n }\r\n }\r\n\r\n if (this.getVersion) {\r\n this.lastSyncedVersion.set(element.id, this.getVersion(element.id));\r\n this.lastSyncedZIndex.set(element.id, zIndex);\r\n this.lastSyncedOpacity.set(element.id, opacity);\r\n }\r\n\r\n const size = 'size' in element ? element.size : null;\r\n Object.assign(node.style, {\r\n display: 'block',\r\n left: `${element.position.x}px`,\r\n top: `${element.position.y}px`,\r\n width: size ? `${size.w}px` : 'auto',\r\n height: size ? `${size.h}px` : 'auto',\r\n zIndex: String(zIndex),\r\n opacity: String(opacity),\r\n transform: element.rotation ? `rotate(${element.rotation}rad)` : '',\r\n transformOrigin: '50% 50%',\r\n });\r\n\r\n this.renderDomContent(node, element);\r\n }\r\n\r\n hideDomNode(id: string): void {\r\n const node = this.domNodes.get(id);\r\n if (node) {\r\n node.style.display = 'none';\r\n this.lastSyncedVersion.delete(id);\r\n }\r\n }\r\n\r\n removeDomNode(id: string): void {\r\n this.htmlContent.delete(id);\r\n this.lastSyncedVersion.delete(id);\r\n this.lastSyncedZIndex.delete(id);\r\n this.lastSyncedOpacity.delete(id);\r\n const node = this.domNodes.get(id);\r\n if (node) {\r\n const stratum = node.parentElement;\r\n node.remove();\r\n this.domNodes.delete(id);\r\n if (stratum?.childElementCount === 0) {\r\n const order = Number(stratum.dataset['paintOrder']);\r\n stratum.remove();\r\n this.strata.delete(order);\r\n }\r\n }\r\n }\r\n\r\n clearDomNodes(): void {\r\n this.domNodes.forEach((node) => node.remove());\r\n this.domNodes.clear();\r\n this.htmlContent.clear();\r\n this.lastSyncedVersion.clear();\r\n this.lastSyncedZIndex.clear();\r\n this.lastSyncedOpacity.clear();\r\n for (const stratum of this.strata.values()) stratum.remove();\r\n this.strata.clear();\r\n }\r\n\r\n private getStratum(order: number): HTMLDivElement {\r\n let stratum = this.strata.get(order);\r\n if (stratum) return stratum;\r\n stratum = document.createElement('div');\r\n stratum.dataset['paintOrder'] = String(order);\r\n Object.assign(stratum.style, {\r\n position: 'absolute',\r\n inset: '0',\r\n width: '100%',\r\n height: '100%',\r\n pointerEvents: 'none',\r\n transformOrigin: '0 0',\r\n transform: this.cameraTransform,\r\n zIndex: String(order),\r\n });\r\n this.domLayer.appendChild(stratum);\r\n this.strata.set(order, stratum);\r\n return stratum;\r\n }\r\n\r\n reattachHtmlContent(store: ElementStore): void {\r\n for (const el of store.getElementsByType('html')) {\r\n if (el.domId) {\r\n const dom = document.getElementById(el.domId);\r\n if (dom) {\r\n this.htmlContent.set(el.id, dom);\r\n }\r\n }\r\n }\r\n }\r\n\r\n private renderDomContent(node: HTMLDivElement, element: CanvasElement): void {\r\n if (element.type === 'note') {\r\n if (!node.dataset['initialized']) {\r\n node.dataset['initialized'] = 'true';\r\n Object.assign(node.style, {\r\n backgroundColor: element.backgroundColor,\r\n color: element.textColor,\r\n padding: '8px',\r\n borderRadius: '4px',\r\n boxShadow: '0 2px 8px rgba(0,0,0,0.15)',\r\n fontSize: `${element.fontSize ?? DEFAULT_NOTE_FONT_SIZE}px`,\r\n overflow: 'hidden',\r\n cursor: 'default',\r\n userSelect: 'none',\r\n wordWrap: 'break-word',\r\n });\r\n node.innerHTML = element.text || '';\r\n\r\n // One-time per node: this pointerup/double-tap listener is attached once (guarded by\r\n // `initialized`) for note/text nodes and is GC'd with the node — no teardown.\r\n // `resetHtmlContent()` (the only path clearing `initialized`) is html-only, and the html\r\n // init branch attaches no listener, so re-init is safe. INVARIANT: never call\r\n // resetHtmlContent on a note/text node, and if you add a listener to the html init branch,\r\n // add matching teardown in resetHtmlContent — else a second listener would stack.\r\n const detector = new DoubleTapDetector();\r\n node.addEventListener('pointerup', (e) => {\r\n if (detector.feed(e)) {\r\n e.stopPropagation();\r\n const id = node.dataset['elementId'];\r\n if (id) this.onEditRequest(id);\r\n }\r\n });\r\n }\r\n\r\n if (!this.isEditingElement(element.id)) {\r\n const text = element.text || '';\r\n if (node.innerHTML !== text) {\r\n node.innerHTML = text;\r\n }\r\n node.style.backgroundColor = element.backgroundColor;\r\n node.style.color = element.textColor;\r\n node.style.fontSize = `${element.fontSize ?? DEFAULT_NOTE_FONT_SIZE}px`;\r\n }\r\n }\r\n\r\n if (element.type === 'html') {\r\n if (!node.dataset['initialized']) {\r\n const content = this.htmlContent.get(element.id);\r\n if (content) {\r\n node.dataset['initialized'] = 'true';\r\n Object.assign(node.style, {\r\n overflow: 'hidden',\r\n pointerEvents: element.interactive ? 'auto' : 'none',\r\n });\r\n node.appendChild(content);\r\n }\r\n } else {\r\n node.style.pointerEvents = element.interactive ? 'auto' : 'none';\r\n }\r\n }\r\n\r\n if (element.type === 'text') {\r\n if (!node.dataset['initialized']) {\r\n node.dataset['initialized'] = 'true';\r\n Object.assign(node.style, {\r\n padding: '2px',\r\n fontSize: `${element.fontSize}px`,\r\n color: element.color,\r\n textAlign: element.textAlign,\r\n background: 'none',\r\n border: 'none',\r\n boxShadow: 'none',\r\n overflow: 'visible',\r\n cursor: 'default',\r\n userSelect: 'none',\r\n wordWrap: 'break-word',\r\n lineHeight: '1.4',\r\n });\r\n node.innerHTML = element.text || '';\r\n\r\n // One-time per node; see the note branch above for the one-listener-per-node invariant.\r\n const detector = new DoubleTapDetector();\r\n node.addEventListener('pointerup', (e) => {\r\n if (detector.feed(e)) {\r\n e.stopPropagation();\r\n const id = node.dataset['elementId'];\r\n if (id) this.onEditRequest(id);\r\n }\r\n });\r\n }\r\n\r\n if (!this.isEditingElement(element.id)) {\r\n const text = element.text || '';\r\n if (node.innerHTML !== text) {\r\n node.innerHTML = text;\r\n }\r\n Object.assign(node.style, {\r\n fontSize: `${element.fontSize}px`,\r\n color: element.color,\r\n textAlign: element.textAlign,\r\n });\r\n }\r\n }\r\n }\r\n}\r\n","const SAMPLE_SIZE = 60;\r\n\r\nexport interface RenderStatsSnapshot {\r\n fps: number;\r\n avgFrameMs: number;\r\n p95FrameMs: number;\r\n lastFrameMs: number;\r\n lastGridMs: number;\r\n layersMs: number;\r\n backgroundMs: number;\r\n compositeMs: number;\r\n overlayMs: number;\r\n frameCount: number;\r\n}\r\n\r\ninterface FrameBreakdown {\r\n gridMs?: number;\r\n layersMs?: number;\r\n backgroundMs?: number;\r\n compositeMs?: number;\r\n overlayMs?: number;\r\n}\r\n\r\nexport class RenderStats {\r\n private frameTimes: number[] = [];\r\n private frameCount = 0;\r\n private _lastGridMs = 0;\r\n private _lastLayersMs = 0;\r\n private _lastBackgroundMs = 0;\r\n private _lastCompositeMs = 0;\r\n private _lastOverlayMs = 0;\r\n\r\n recordFrame(durationMs: number, breakdown?: FrameBreakdown): void {\r\n this.frameCount++;\r\n this.frameTimes.push(durationMs);\r\n if (this.frameTimes.length > SAMPLE_SIZE) {\r\n this.frameTimes.shift();\r\n }\r\n if (breakdown !== undefined) {\r\n if (breakdown.gridMs !== undefined) this._lastGridMs = breakdown.gridMs;\r\n if (breakdown.layersMs !== undefined) this._lastLayersMs = breakdown.layersMs;\r\n if (breakdown.backgroundMs !== undefined) this._lastBackgroundMs = breakdown.backgroundMs;\r\n if (breakdown.compositeMs !== undefined) this._lastCompositeMs = breakdown.compositeMs;\r\n if (breakdown.overlayMs !== undefined) this._lastOverlayMs = breakdown.overlayMs;\r\n }\r\n }\r\n\r\n getSnapshot(): RenderStatsSnapshot {\r\n const times = this.frameTimes;\r\n if (times.length === 0) {\r\n return {\r\n fps: 0,\r\n avgFrameMs: 0,\r\n p95FrameMs: 0,\r\n lastFrameMs: 0,\r\n lastGridMs: 0,\r\n layersMs: 0,\r\n backgroundMs: 0,\r\n compositeMs: 0,\r\n overlayMs: 0,\r\n frameCount: 0,\r\n };\r\n }\r\n\r\n const avg = times.reduce((a, b) => a + b, 0) / times.length;\r\n const sorted = [...times].sort((a, b) => a - b);\r\n const p95Index = Math.min(Math.floor(sorted.length * 0.95), sorted.length - 1);\r\n const lastFrame = times[times.length - 1] ?? 0;\r\n\r\n return {\r\n fps: avg > 0 ? Math.round(1000 / avg) : 0,\r\n avgFrameMs: Math.round(avg * 100) / 100,\r\n p95FrameMs: Math.round((sorted[p95Index] ?? 0) * 100) / 100,\r\n lastFrameMs: Math.round(lastFrame * 100) / 100,\r\n lastGridMs: Math.round(this._lastGridMs * 100) / 100,\r\n layersMs: Math.round(this._lastLayersMs * 100) / 100,\r\n backgroundMs: Math.round(this._lastBackgroundMs * 100) / 100,\r\n compositeMs: Math.round(this._lastCompositeMs * 100) / 100,\r\n overlayMs: Math.round(this._lastOverlayMs * 100) / 100,\r\n frameCount: this.frameCount,\r\n };\r\n }\r\n\r\n reset(): void {\r\n this.frameTimes = [];\r\n this.frameCount = 0;\r\n }\r\n}\r\n","import type { Camera } from './camera';\r\nimport type { Background } from './background';\r\nimport type { ElementStore } from '../elements/element-store';\r\nimport type { ElementRenderer } from '../elements/element-renderer';\r\nimport type { ToolManager } from '../tools/tool-manager';\r\nimport type { LayerManager } from '../layers/layer-manager';\r\nimport type { DomNodeManager } from './dom-node-manager';\r\nimport type { LayerCache } from './layer-cache';\r\nimport type { MarginViewport } from './margin-viewport';\r\nimport type { Bounds } from '../core/types';\r\nimport type { CanvasElement } from '../elements/types';\r\nimport { getElementVisualBounds, boundsIntersect } from '../elements/element-bounds';\r\nimport { RenderStats } from './render-stats';\r\nimport type { RenderStatsSnapshot } from './render-stats';\r\nimport type { HybridRenderSurface } from './hybrid-render-surface';\r\n\r\n/**\r\n * A world-space draw callback rendered above elements on every frame,\r\n * regardless of which tool is active. The context arrives with the camera\r\n * transform applied; implementations must not assume exclusive context state\r\n * (each renderer is wrapped in save/restore). A throwing renderer is isolated\r\n * per frame and must not break the render loop.\r\n */\r\nexport type OverlayRenderer = (ctx: CanvasRenderingContext2D) => void;\r\n\r\nexport interface RenderLoopDeps {\r\n canvasEl: HTMLCanvasElement;\r\n camera: Camera;\r\n background: Background;\r\n store: ElementStore;\r\n renderer: ElementRenderer;\r\n toolManager: ToolManager;\r\n layerManager: LayerManager;\r\n domNodeManager: DomNodeManager;\r\n layerCache: LayerCache;\r\n marginViewport: MarginViewport;\r\n hybridSurface: HybridRenderSurface;\r\n}\r\n\r\nexport class RenderLoop {\r\n private needsRender = false;\r\n private animFrameId = 0;\r\n private readonly canvasEl: HTMLCanvasElement;\r\n private readonly camera: Camera;\r\n private readonly background: Background;\r\n private readonly store: ElementStore;\r\n private readonly renderer: ElementRenderer;\r\n private readonly toolManager: ToolManager;\r\n private readonly layerManager: LayerManager;\r\n private readonly domNodeManager: DomNodeManager;\r\n private readonly layerCache: LayerCache;\r\n private readonly marginViewport: MarginViewport;\r\n private readonly hybridSurface: HybridRenderSurface;\r\n private activeDrawingLayerId: string | null = null;\r\n private gridCacheDirty = true; // set on recenter/viewport-change; consumed by the grid block\r\n private readonly stats = new RenderStats();\r\n private layerGroups = new Map<string, CanvasElement[]>();\r\n private readonly overlays = new Set<OverlayRenderer>();\r\n private gridCacheCanvas: HTMLCanvasElement | null = null;\r\n private gridCacheCtx: CanvasRenderingContext2D | null = null;\r\n private lastGridRefs: CanvasElement[] = [];\r\n\r\n constructor(deps: RenderLoopDeps) {\r\n this.canvasEl = deps.canvasEl;\r\n this.camera = deps.camera;\r\n this.background = deps.background;\r\n this.store = deps.store;\r\n this.renderer = deps.renderer;\r\n this.toolManager = deps.toolManager;\r\n this.layerManager = deps.layerManager;\r\n this.domNodeManager = deps.domNodeManager;\r\n this.layerCache = deps.layerCache;\r\n this.marginViewport = deps.marginViewport;\r\n this.hybridSurface = deps.hybridSurface;\r\n }\r\n\r\n requestRender(): void {\r\n this.needsRender = true;\r\n }\r\n\r\n flush(): void {\r\n if (this.needsRender) {\r\n this.render();\r\n this.needsRender = false;\r\n }\r\n }\r\n\r\n start(): void {\r\n const loop = (): void => {\r\n if (this.needsRender) {\r\n this.render();\r\n this.needsRender = false;\r\n }\r\n this.animFrameId = requestAnimationFrame(loop);\r\n };\r\n this.animFrameId = requestAnimationFrame(loop);\r\n }\r\n\r\n stop(): void {\r\n cancelAnimationFrame(this.animFrameId);\r\n }\r\n\r\n setCanvasSize(width: number, height: number): void {\r\n this.canvasEl.width = width;\r\n this.canvasEl.height = height;\r\n const dpr = typeof devicePixelRatio !== 'undefined' ? devicePixelRatio : 1;\r\n this.marginViewport.setViewport(width / dpr, height / dpr, dpr);\r\n this.layerCache.resize();\r\n }\r\n\r\n setActiveDrawingLayer(layerId: string | null): void {\r\n this.activeDrawingLayerId = layerId;\r\n }\r\n\r\n markLayerDirty(layerId: string): void {\r\n this.layerCache.markDirty(layerId);\r\n }\r\n\r\n markAllLayersDirty(): void {\r\n this.layerCache.markAllDirty();\r\n this.gridCacheDirty = true;\r\n }\r\n\r\n getStats(): RenderStatsSnapshot {\r\n return this.stats.getSnapshot();\r\n }\r\n\r\n /**\r\n * Registers a viewport overlay drawn beneath the active tool's own overlay.\r\n * Returns an idempotent unsubscribe that also erases the overlay's last\r\n * frame.\r\n */\r\n registerOverlay(draw: OverlayRenderer): () => void {\r\n this.overlays.add(draw);\r\n this.requestRender();\r\n return () => {\r\n if (this.overlays.delete(draw)) this.requestRender();\r\n };\r\n }\r\n\r\n private drawRegisteredOverlays(ctx: CanvasRenderingContext2D): void {\r\n for (const draw of this.overlays) {\r\n ctx.save();\r\n try {\r\n draw(ctx);\r\n } catch {\r\n // One faulty overlay must not take down the frame or its siblings.\r\n } finally {\r\n ctx.restore();\r\n }\r\n }\r\n }\r\n\r\n private compositeLayerCache(\r\n ctx: CanvasRenderingContext2D,\r\n layerId: string,\r\n opacity: number,\r\n ): void {\r\n const cached = this.layerCache.getCanvas(layerId);\r\n const offset = this.marginViewport.compositeOffset(\r\n this.camera.position.x,\r\n this.camera.position.y,\r\n );\r\n ctx.save();\r\n ctx.setTransform(1, 0, 0, 1, 0, 0);\r\n ctx.globalAlpha = opacity;\r\n ctx.drawImage(cached as CanvasImageSource, offset.x, offset.y);\r\n ctx.restore();\r\n }\r\n\r\n private ensureGridCache(): void {\r\n const w = this.marginViewport.physicalWidth();\r\n const h = this.marginViewport.physicalHeight();\r\n if (\r\n this.gridCacheCanvas !== null &&\r\n this.gridCacheCanvas.width === w &&\r\n this.gridCacheCanvas.height === h\r\n ) {\r\n return;\r\n }\r\n\r\n if (typeof OffscreenCanvas !== 'undefined') {\r\n this.gridCacheCanvas = new OffscreenCanvas(w, h) as unknown as HTMLCanvasElement;\r\n } else if (typeof document !== 'undefined') {\r\n const el = document.createElement('canvas');\r\n el.width = w;\r\n el.height = h;\r\n this.gridCacheCanvas = el;\r\n } else {\r\n this.gridCacheCanvas = null;\r\n this.gridCacheCtx = null;\r\n return;\r\n }\r\n\r\n this.gridCacheCtx = this.gridCacheCanvas.getContext('2d') as CanvasRenderingContext2D | null;\r\n }\r\n\r\n private render(): void {\r\n const t0 = performance.now();\r\n const ctx = this.canvasEl.getContext('2d');\r\n if (!ctx) return;\r\n\r\n let layersMs = 0;\r\n let compositeMs = 0;\r\n let gridMs = 0;\r\n\r\n const dpr = typeof devicePixelRatio !== 'undefined' ? devicePixelRatio : 1;\r\n const cssWidth = this.canvasEl.clientWidth;\r\n const cssHeight = this.canvasEl.clientHeight;\r\n\r\n // idempotent; catches resizes that bypass setCanvasSize\r\n this.marginViewport.setViewport(cssWidth, cssHeight, dpr);\r\n\r\n const currentZoom = this.camera.zoom;\r\n const currentCamX = this.camera.position.x;\r\n const currentCamY = this.camera.position.y;\r\n if (this.marginViewport.needsRecenter(currentCamX, currentCamY, currentZoom)) {\r\n this.marginViewport.recenter(currentCamX, currentCamY, currentZoom);\r\n this.layerCache.markAllDirty();\r\n this.gridCacheDirty = true;\r\n }\r\n\r\n ctx.save();\r\n ctx.scale(dpr, dpr);\r\n\r\n this.renderer.setCanvasSize(cssWidth, cssHeight);\r\n const hasGridElement = this.store.getElementsByType('grid').length > 0;\r\n const bgT0 = performance.now();\r\n if (hasGridElement) {\r\n ctx.save();\r\n ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\r\n ctx.clearRect(0, 0, cssWidth, cssHeight);\r\n ctx.restore();\r\n } else {\r\n this.background.render(ctx, this.camera);\r\n }\r\n const backgroundMs = performance.now() - bgT0;\r\n\r\n ctx.save();\r\n ctx.translate(this.camera.position.x, this.camera.position.y);\r\n ctx.scale(this.camera.zoom, this.camera.zoom);\r\n\r\n const cullBounds = this.marginViewport.cachedWorldBounds();\r\n const cullPad = Math.max(cullBounds.w, cullBounds.h) * 0.05;\r\n const cullingRect: Bounds = {\r\n x: cullBounds.x - cullPad,\r\n y: cullBounds.y - cullPad,\r\n w: cullBounds.w + cullPad * 2,\r\n h: cullBounds.h + cullPad * 2,\r\n };\r\n\r\n const allElements = this.store.getAll();\r\n const visibleElements = allElements.filter((element) =>\r\n this.layerManager.isLayerVisible(element.layerId),\r\n );\r\n const firstDomIndex = visibleElements.findIndex((element) =>\r\n this.renderer.isDomElement(element),\r\n );\r\n const hybridActive =\r\n firstDomIndex >= 0 &&\r\n visibleElements\r\n .slice(firstDomIndex + 1)\r\n .some((element) => !this.renderer.isDomElement(element));\r\n const hybridCanvasRuns = new Map<number, CanvasElement[]>();\r\n const hybridOrders = new Set<number>();\r\n let activeHybridOrder: number | null = null;\r\n this.layerGroups.clear();\r\n const gridElements: CanvasElement[] = [];\r\n let paintOrder = 0;\r\n\r\n for (const element of allElements) {\r\n if (!this.layerManager.isLayerVisible(element.layerId)) {\r\n if (this.renderer.isDomElement(element)) {\r\n this.domNodeManager.hideDomNode(element.id);\r\n }\r\n continue;\r\n }\r\n\r\n const order = ++paintOrder;\r\n\r\n if (this.renderer.isDomElement(element)) {\r\n activeHybridOrder = null;\r\n const layerOpacity = this.layerManager.getLayer?.(element.layerId)?.opacity ?? 1;\r\n const elBounds = getElementVisualBounds(element);\r\n if (elBounds && !boundsIntersect(elBounds, cullingRect)) {\r\n this.domNodeManager.hideDomNode(element.id);\r\n } else {\r\n this.domNodeManager.syncDomNode(element, order, layerOpacity);\r\n }\r\n continue;\r\n }\r\n\r\n if (hybridActive && paintOrder > firstDomIndex + 1 && element.type !== 'grid') {\r\n activeHybridOrder ??= order;\r\n let run = hybridCanvasRuns.get(activeHybridOrder);\r\n if (!run) {\r\n run = [];\r\n hybridCanvasRuns.set(activeHybridOrder, run);\r\n hybridOrders.add(activeHybridOrder);\r\n }\r\n run.push(element);\r\n continue;\r\n }\r\n\r\n // Grids are viewport-filling; handled via anchored cache below\r\n if (element.type === 'grid') {\r\n gridElements.push(element);\r\n continue;\r\n }\r\n\r\n let group = this.layerGroups.get(element.layerId);\r\n if (!group) {\r\n group = [];\r\n this.layerGroups.set(element.layerId, group);\r\n }\r\n group.push(element);\r\n }\r\n\r\n const activeTool = this.toolManager.activeTool;\r\n const overlayOrder = visibleElements.length + 1;\r\n const hasOverlay = activeTool?.renderOverlay !== undefined || this.overlays.size > 0;\r\n if (hybridActive && hasOverlay) hybridOrders.add(overlayOrder);\r\n this.hybridSurface.beginFrame(hybridOrders, this.canvasEl.width, this.canvasEl.height);\r\n\r\n for (const [layerId, elements] of this.layerGroups) {\r\n const isActiveDrawingLayer = layerId === this.activeDrawingLayerId;\r\n const layerOpacity = this.layerManager.getLayer?.(layerId)?.opacity ?? 1;\r\n\r\n if (!this.layerCache.isDirty(layerId)) {\r\n const compT0 = performance.now();\r\n this.compositeLayerCache(ctx, layerId, layerOpacity);\r\n compositeMs += performance.now() - compT0;\r\n continue;\r\n }\r\n\r\n if (isActiveDrawingLayer) {\r\n const compT0 = performance.now();\r\n this.compositeLayerCache(ctx, layerId, layerOpacity);\r\n compositeMs += performance.now() - compT0;\r\n continue;\r\n }\r\n\r\n const offCtx = this.layerCache.getContext(layerId);\r\n if (offCtx) {\r\n const layerT0 = performance.now();\r\n const offCanvas = this.layerCache.getCanvas(layerId);\r\n offCtx.clearRect(0, 0, offCanvas.width, offCanvas.height);\r\n offCtx.save();\r\n this.marginViewport.applyRenderTransform(offCtx);\r\n for (const element of elements) {\r\n const elBounds = getElementVisualBounds(element);\r\n if (elBounds && !boundsIntersect(elBounds, cullingRect)) continue;\r\n this.renderer.renderCanvasElement(offCtx as CanvasRenderingContext2D, element);\r\n }\r\n offCtx.restore();\r\n this.layerCache.markClean(layerId);\r\n layersMs += performance.now() - layerT0;\r\n\r\n const compT0 = performance.now();\r\n this.compositeLayerCache(ctx, layerId, layerOpacity);\r\n compositeMs += performance.now() - compT0;\r\n }\r\n }\r\n\r\n // Render grids on top of layer elements\r\n if (gridElements.length > 0) {\r\n const gridT0 = performance.now();\r\n const gridsChanged =\r\n gridElements.length !== this.lastGridRefs.length ||\r\n gridElements.some((grid, index) => grid !== this.lastGridRefs[index]);\r\n const gridDirty = this.gridCacheDirty || gridsChanged;\r\n\r\n if (gridDirty) {\r\n this.ensureGridCache();\r\n if (this.gridCacheCtx && this.gridCacheCanvas) {\r\n const cb = this.marginViewport.cachedWorldBounds();\r\n this.renderer.setGridBoundsOverride({\r\n minX: cb.x,\r\n minY: cb.y,\r\n maxX: cb.x + cb.w,\r\n maxY: cb.y + cb.h,\r\n });\r\n const gc = this.gridCacheCtx;\r\n gc.clearRect(0, 0, this.gridCacheCanvas.width, this.gridCacheCanvas.height);\r\n gc.save();\r\n this.marginViewport.applyRenderTransform(gc);\r\n try {\r\n for (const grid of gridElements) {\r\n gc.save();\r\n gc.globalAlpha = this.layerManager.getLayer?.(grid.layerId)?.opacity ?? 1;\r\n this.renderer.renderCanvasElement(gc as CanvasRenderingContext2D, grid);\r\n gc.restore();\r\n }\r\n } finally {\r\n gc.restore();\r\n this.renderer.setGridBoundsOverride(null);\r\n }\r\n }\r\n this.gridCacheDirty = false;\r\n this.lastGridRefs = [...gridElements];\r\n }\r\n\r\n if (this.gridCacheCanvas) {\r\n const offset = this.marginViewport.compositeOffset(\r\n this.camera.position.x,\r\n this.camera.position.y,\r\n );\r\n ctx.save();\r\n ctx.setTransform(1, 0, 0, 1, 0, 0);\r\n ctx.drawImage(this.gridCacheCanvas as CanvasImageSource, offset.x, offset.y);\r\n ctx.restore();\r\n } else {\r\n for (const grid of gridElements) {\r\n ctx.save();\r\n ctx.globalAlpha = this.layerManager.getLayer?.(grid.layerId)?.opacity ?? 1;\r\n this.renderer.renderCanvasElement(ctx, grid);\r\n ctx.restore();\r\n }\r\n }\r\n gridMs = performance.now() - gridT0;\r\n } else {\r\n this.lastGridRefs = [];\r\n }\r\n\r\n for (const [order, elements] of hybridCanvasRuns) {\r\n const hybridCtx = this.hybridSurface.getContext(order);\r\n if (!hybridCtx) continue;\r\n hybridCtx.clearRect(0, 0, this.canvasEl.width, this.canvasEl.height);\r\n hybridCtx.save();\r\n hybridCtx.scale(dpr, dpr);\r\n hybridCtx.translate(this.camera.position.x, this.camera.position.y);\r\n hybridCtx.scale(this.camera.zoom, this.camera.zoom);\r\n for (const element of elements) {\r\n const elBounds = getElementVisualBounds(element);\r\n if (elBounds && !boundsIntersect(elBounds, cullingRect)) continue;\r\n hybridCtx.save();\r\n hybridCtx.globalAlpha = this.layerManager.getLayer?.(element.layerId)?.opacity ?? 1;\r\n this.renderer.renderCanvasElement(hybridCtx, element);\r\n hybridCtx.restore();\r\n }\r\n hybridCtx.restore();\r\n }\r\n\r\n const overlayT0 = performance.now();\r\n if (hybridActive && hasOverlay) {\r\n const overlayCtx = this.hybridSurface.getContext(overlayOrder);\r\n if (overlayCtx) {\r\n overlayCtx.clearRect(0, 0, this.canvasEl.width, this.canvasEl.height);\r\n overlayCtx.save();\r\n overlayCtx.scale(dpr, dpr);\r\n overlayCtx.translate(this.camera.position.x, this.camera.position.y);\r\n overlayCtx.scale(this.camera.zoom, this.camera.zoom);\r\n this.drawRegisteredOverlays(overlayCtx);\r\n if (activeTool?.renderOverlay) activeTool.renderOverlay(overlayCtx);\r\n overlayCtx.restore();\r\n }\r\n } else if (hasOverlay) {\r\n this.drawRegisteredOverlays(ctx);\r\n if (activeTool?.renderOverlay) activeTool.renderOverlay(ctx);\r\n }\r\n const overlayMs = performance.now() - overlayT0;\r\n\r\n ctx.restore();\r\n ctx.restore();\r\n\r\n this.stats.recordFrame(performance.now() - t0, {\r\n gridMs,\r\n layersMs,\r\n backgroundMs,\r\n compositeMs,\r\n overlayMs,\r\n });\r\n }\r\n}\r\n","import type { MarginViewport } from './margin-viewport';\r\n\r\nfunction createOffscreenCanvas(width: number, height: number): HTMLCanvasElement | OffscreenCanvas {\r\n if (typeof OffscreenCanvas !== 'undefined') {\r\n return new OffscreenCanvas(width, height);\r\n }\r\n const canvas = document.createElement('canvas');\r\n canvas.width = width;\r\n canvas.height = height;\r\n return canvas;\r\n}\r\n\r\nexport class LayerCache {\r\n private canvases = new Map<string, HTMLCanvasElement | OffscreenCanvas>();\r\n private dirtyFlags = new Map<string, boolean>();\r\n\r\n constructor(private readonly viewport: MarginViewport) {}\r\n\r\n isDirty(layerId: string): boolean {\r\n return this.dirtyFlags.get(layerId) !== false;\r\n }\r\n\r\n markDirty(layerId: string): void {\r\n this.dirtyFlags.set(layerId, true);\r\n }\r\n\r\n markClean(layerId: string): void {\r\n this.dirtyFlags.set(layerId, false);\r\n }\r\n\r\n markAllDirty(): void {\r\n for (const [id] of this.dirtyFlags) {\r\n this.dirtyFlags.set(id, true);\r\n }\r\n }\r\n\r\n getCanvas(layerId: string): HTMLCanvasElement | OffscreenCanvas {\r\n let canvas = this.canvases.get(layerId);\r\n if (!canvas) {\r\n canvas = createOffscreenCanvas(this.viewport.physicalWidth(), this.viewport.physicalHeight());\r\n this.canvases.set(layerId, canvas);\r\n this.dirtyFlags.set(layerId, true);\r\n }\r\n return canvas;\r\n }\r\n\r\n getContext(layerId: string): CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D | null {\r\n const canvas = this.getCanvas(layerId);\r\n return canvas.getContext('2d') as\r\n | CanvasRenderingContext2D\r\n | OffscreenCanvasRenderingContext2D\r\n | null;\r\n }\r\n\r\n resize(): void {\r\n const w = this.viewport.physicalWidth();\r\n const h = this.viewport.physicalHeight();\r\n for (const [id, canvas] of this.canvases) {\r\n canvas.width = w;\r\n canvas.height = h;\r\n this.dirtyFlags.set(id, true);\r\n }\r\n }\r\n\r\n clear(): void {\r\n this.canvases.clear();\r\n this.dirtyFlags.clear();\r\n }\r\n}\r\n","import type { Bounds } from '../core/types';\r\n\r\n/**\r\n * Owns the cache anchor (the camera state the screen-space caches were last rendered at)\r\n * and the margin geometry. Pure — holds no canvas. Caches render a region inflated by\r\n * `marginPx` on every side, so a pan within the margin is an offset-blit, not a re-raster.\r\n *\r\n * Call setViewport(cssW, cssH, dpr) before physicalWidth/Height, applyRenderTransform, or compositeOffset — they read the stored dpr.\r\n */\r\nexport class MarginViewport {\r\n private cssW = 0;\r\n private cssH = 0;\r\n private dpr = 1;\r\n private anchorCamX = 0;\r\n private anchorCamY = 0;\r\n private anchorZoom = Number.NaN; // sentinel → first needsRecenter is true\r\n private viewportDirty = true;\r\n\r\n constructor(private marginPx: number) {}\r\n\r\n setMargin(marginPx: number): void {\r\n if (marginPx !== this.marginPx) {\r\n this.marginPx = marginPx;\r\n this.viewportDirty = true;\r\n }\r\n }\r\n\r\n setViewport(cssW: number, cssH: number, dpr: number): void {\r\n if (cssW !== this.cssW || cssH !== this.cssH || dpr !== this.dpr) {\r\n this.cssW = cssW;\r\n this.cssH = cssH;\r\n this.dpr = dpr;\r\n this.viewportDirty = true;\r\n }\r\n }\r\n\r\n physicalWidth(): number {\r\n return Math.round((this.cssW + 2 * this.marginPx) * this.dpr);\r\n }\r\n\r\n physicalHeight(): number {\r\n return Math.round((this.cssH + 2 * this.marginPx) * this.dpr);\r\n }\r\n\r\n needsRecenter(camX: number, camY: number, zoom: number): boolean {\r\n return (\r\n this.viewportDirty ||\r\n zoom !== this.anchorZoom ||\r\n Math.abs(camX - this.anchorCamX) > this.marginPx ||\r\n Math.abs(camY - this.anchorCamY) > this.marginPx\r\n );\r\n }\r\n\r\n recenter(camX: number, camY: number, zoom: number): void {\r\n this.anchorCamX = camX;\r\n this.anchorCamY = camY;\r\n this.anchorZoom = zoom;\r\n this.viewportDirty = false;\r\n }\r\n\r\n /** Applies dpr scale + anchor-relative world transform. setViewport must have been called first. */\r\n applyRenderTransform(ctx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D): void {\r\n ctx.scale(this.dpr, this.dpr);\r\n ctx.translate(this.marginPx + this.anchorCamX, this.marginPx + this.anchorCamY);\r\n ctx.scale(this.anchorZoom, this.anchorZoom);\r\n }\r\n\r\n // Device-px destination for drawImage(cache, x, y).\r\n // A world point P sits in the cache at CSS x `margin + anchorCamX + P*zoom`; it must land on\r\n // screen at `camX + P*zoom`; so the blit offset is `camX - anchorCamX - margin` (CSS) * dpr.\r\n compositeOffset(camX: number, camY: number): { x: number; y: number } {\r\n return {\r\n x: (camX - this.anchorCamX - this.marginPx) * this.dpr,\r\n y: (camY - this.anchorCamY - this.marginPx) * this.dpr,\r\n };\r\n }\r\n\r\n // World-space bounds of the whole cached region at the anchor (cull rect for re-renders).\r\n cachedWorldBounds(): Bounds {\r\n const z = this.anchorZoom;\r\n return {\r\n x: (-this.marginPx - this.anchorCamX) / z,\r\n y: (-this.marginPx - this.anchorCamY) / z,\r\n w: (this.cssW + 2 * this.marginPx) / z,\r\n h: (this.cssH + 2 * this.marginPx) / z,\r\n };\r\n }\r\n}\r\n","import type { CanvasElement } from './types';\r\n\r\n/** Patch that translates an element by (dx, dy). Arrows move position + from + to;\r\n * every other type moves position only (strokes carry points relative to position). */\r\nexport function translateElementPatch(\r\n el: CanvasElement,\r\n dx: number,\r\n dy: number,\r\n): Partial<CanvasElement> {\r\n const position = { x: el.position.x + dx, y: el.position.y + dy };\r\n if (el.type === 'arrow') {\r\n return {\r\n position,\r\n from: { x: el.from.x + dx, y: el.from.y + dy },\r\n to: { x: el.to.x + dx, y: el.to.y + dy },\r\n };\r\n }\r\n return { position };\r\n}\r\n","import type { ArrowStrokeStyle, CanvasElement } from './types';\r\n\r\nexport interface ElementStyle {\r\n color?: string;\r\n fillColor?: string;\r\n strokeWidth?: number;\r\n opacity?: number;\r\n fontSize?: number;\r\n strokeStyle?: ArrowStrokeStyle;\r\n}\r\n\r\nexport function styleToPatch(element: CanvasElement, style: ElementStyle): Partial<CanvasElement> {\r\n const { color, fillColor, strokeWidth, opacity, fontSize, strokeStyle } = style;\r\n switch (element.type) {\r\n case 'stroke':\r\n return {\r\n ...(color !== undefined ? { color } : {}),\r\n ...(strokeWidth !== undefined ? { width: strokeWidth } : {}),\r\n ...(opacity !== undefined ? { opacity } : {}),\r\n };\r\n case 'arrow':\r\n return {\r\n ...(color !== undefined ? { color } : {}),\r\n ...(strokeWidth !== undefined ? { width: strokeWidth } : {}),\r\n ...(strokeStyle !== undefined ? { strokeStyle } : {}),\r\n };\r\n case 'shape':\r\n return {\r\n ...(color !== undefined ? { strokeColor: color } : {}),\r\n ...(fillColor !== undefined ? { fillColor } : {}),\r\n ...(strokeWidth !== undefined ? { strokeWidth } : {}),\r\n };\r\n case 'text':\r\n return {\r\n ...(color !== undefined ? { color } : {}),\r\n ...(fontSize !== undefined ? { fontSize } : {}),\r\n };\r\n case 'note':\r\n return {\r\n ...(color !== undefined ? { textColor: color } : {}),\r\n ...(fillColor !== undefined ? { backgroundColor: fillColor } : {}),\r\n ...(fontSize !== undefined ? { fontSize } : {}),\r\n };\r\n case 'grid':\r\n return {\r\n ...(color !== undefined ? { strokeColor: color } : {}),\r\n ...(strokeWidth !== undefined ? { strokeWidth } : {}),\r\n ...(opacity !== undefined ? { opacity } : {}),\r\n };\r\n case 'template':\r\n return {\r\n ...(color !== undefined ? { strokeColor: color } : {}),\r\n ...(fillColor !== undefined ? { fillColor } : {}),\r\n ...(strokeWidth !== undefined ? { strokeWidth } : {}),\r\n ...(opacity !== undefined ? { opacity } : {}),\r\n };\r\n default:\r\n return {};\r\n }\r\n}\r\n\r\nexport function getElementStyle(element: CanvasElement): ElementStyle {\r\n switch (element.type) {\r\n case 'stroke':\r\n return { color: element.color, strokeWidth: element.width, opacity: element.opacity };\r\n case 'arrow':\r\n return {\r\n color: element.color,\r\n strokeWidth: element.width,\r\n ...(element.strokeStyle !== undefined ? { strokeStyle: element.strokeStyle } : {}),\r\n };\r\n case 'shape':\r\n return {\r\n color: element.strokeColor,\r\n fillColor: element.fillColor,\r\n strokeWidth: element.strokeWidth,\r\n };\r\n case 'text':\r\n return { color: element.color, fontSize: element.fontSize };\r\n case 'note':\r\n return {\r\n color: element.textColor,\r\n fillColor: element.backgroundColor,\r\n ...(element.fontSize !== undefined ? { fontSize: element.fontSize } : {}),\r\n };\r\n case 'grid':\r\n return {\r\n color: element.strokeColor,\r\n strokeWidth: element.strokeWidth,\r\n opacity: element.opacity,\r\n };\r\n case 'template':\r\n return {\r\n color: element.strokeColor,\r\n fillColor: element.fillColor,\r\n strokeWidth: element.strokeWidth,\r\n opacity: element.opacity,\r\n };\r\n default:\r\n return {};\r\n }\r\n}\r\n","import type { Bounds, Point } from '../core/types';\r\nimport type { CanvasElement } from '../elements/types';\r\nimport { normalizeAngle, rotatePoint, rotatedAABB } from '../core/geometry';\r\n\r\nexport type RotateDirection = 'cw' | 'ccw';\r\n\r\nexport interface BoundedElement {\r\n id: string;\r\n el: CanvasElement;\r\n bounds: Bounds;\r\n}\r\n\r\nexport function unionBounds(list: Bounds[]): Bounds {\r\n let minX = Infinity,\r\n minY = Infinity,\r\n maxX = -Infinity,\r\n maxY = -Infinity;\r\n for (const b of list) {\r\n minX = Math.min(minX, b.x);\r\n minY = Math.min(minY, b.y);\r\n maxX = Math.max(maxX, b.x + b.w);\r\n maxY = Math.max(maxY, b.y + b.h);\r\n }\r\n return { x: minX, y: minY, w: maxX - minX, h: maxY - minY };\r\n}\r\n\r\nexport function rotationPivot(items: readonly BoundedElement[]): Point {\r\n const first = items[0];\r\n if (items.length === 1 && first) {\r\n return { x: first.bounds.x + first.bounds.w / 2, y: first.bounds.y + first.bounds.h / 2 };\r\n }\r\n const u = unionBounds(items.map((it) => rotatedAABB(it.bounds, it.el.rotation ?? 0)));\r\n return { x: u.x + u.w / 2, y: u.y + u.h / 2 };\r\n}\r\n\r\nexport function rotateElementPatch(\r\n el: CanvasElement,\r\n bounds: Bounds,\r\n pivot: Point,\r\n delta: number,\r\n): Partial<CanvasElement> {\r\n if (el.type === 'arrow') {\r\n const center = { x: bounds.x + bounds.w / 2, y: bounds.y + bounds.h / 2 };\r\n const moved = rotatePoint(center, pivot, delta);\r\n return {\r\n position: { x: el.position.x + moved.x - center.x, y: el.position.y + moved.y - center.y },\r\n from: rotatePoint(el.from, pivot, delta),\r\n to: rotatePoint(el.to, pivot, delta),\r\n };\r\n }\r\n if (el.type === 'template') {\r\n return {\r\n position: rotatePoint(el.position, pivot, delta),\r\n angle: normalizeAngle(el.angle + delta),\r\n };\r\n }\r\n const center = { x: bounds.x + bounds.w / 2, y: bounds.y + bounds.h / 2 };\r\n const moved = rotatePoint(center, pivot, delta);\r\n return {\r\n position: { x: el.position.x + moved.x - center.x, y: el.position.y + moved.y - center.y },\r\n rotation: normalizeAngle((el.rotation ?? 0) + delta),\r\n };\r\n}\r\n","import type { ElementStore } from '../elements/element-store';\r\nimport type { HistoryRecorder } from '../history/history-recorder';\r\nimport { updateArrowsBoundToElements } from '../elements/arrow-binding';\r\nimport { translateElementPatch } from '../elements/translate';\r\nimport { getElementBounds } from '../elements/element-bounds';\r\nimport { createId } from '../elements/create-id';\r\nimport { styleToPatch, getElementStyle } from '../elements/element-style';\r\nimport type { ElementStyle } from '../elements/element-style';\r\nimport type { CanvasElement } from '../elements/types';\r\nimport type { Bounds } from '../core/types';\r\nimport { rotationPivot, rotateElementPatch, unionBounds } from './selection-rotate';\r\nimport type { RotateDirection } from './selection-rotate';\r\n\r\nconst STYLE_FIELDS = [\r\n 'color',\r\n 'fillColor',\r\n 'strokeWidth',\r\n 'opacity',\r\n 'fontSize',\r\n 'strokeStyle',\r\n] as const;\r\n\r\nexport interface SelectionStyleDetails {\r\n common: ElementStyle;\r\n applicable: readonly (keyof ElementStyle)[];\r\n mixed: readonly (keyof ElementStyle)[];\r\n}\r\n\r\nexport type AlignEdge = 'left' | 'center-x' | 'right' | 'top' | 'middle' | 'bottom';\r\nexport type DistributeAxis = 'horizontal' | 'vertical';\r\n\r\nfunction sharedValue<T>(values: (T | undefined)[]): T | undefined {\r\n const present = values.filter((v): v is T => v !== undefined);\r\n if (present.length === 0) return undefined;\r\n const first = present[0];\r\n return present.every((v) => v === first) ? first : undefined;\r\n}\r\n\r\nexport interface SelectionOpsDeps {\r\n store: ElementStore;\r\n recorder: HistoryRecorder;\r\n getSelectedIds: () => string[];\r\n requestRender: () => void;\r\n}\r\n\r\nexport class SelectionOps {\r\n constructor(private readonly deps: SelectionOpsDeps) {}\r\n\r\n getStyle(): ElementStyle | null {\r\n const ids = this.deps.getSelectedIds();\r\n if (ids.length === 0) return null;\r\n const styles: ElementStyle[] = [];\r\n for (const id of ids) {\r\n const el = this.deps.store.getById(id);\r\n if (el) styles.push(getElementStyle(el));\r\n }\r\n if (styles.length === 0) return null;\r\n const result: ElementStyle = {};\r\n const color = sharedValue(styles.map((s) => s.color));\r\n if (color !== undefined) result.color = color;\r\n const fillColor = sharedValue(styles.map((s) => s.fillColor));\r\n if (fillColor !== undefined) result.fillColor = fillColor;\r\n const strokeWidth = sharedValue(styles.map((s) => s.strokeWidth));\r\n if (strokeWidth !== undefined) result.strokeWidth = strokeWidth;\r\n const opacity = sharedValue(styles.map((s) => s.opacity));\r\n if (opacity !== undefined) result.opacity = opacity;\r\n const fontSize = sharedValue(styles.map((s) => s.fontSize));\r\n if (fontSize !== undefined) result.fontSize = fontSize;\r\n const strokeStyle = sharedValue(styles.map((s) => s.strokeStyle));\r\n if (strokeStyle !== undefined) result.strokeStyle = strokeStyle;\r\n return result;\r\n }\r\n\r\n /**\r\n * Unlike `getStyle()` — which returns `{}` for a selection whose elements\r\n * have no applicable style fields (e.g. images) — this returns `null` when\r\n * no field is applicable, so callers can distinguish \"nothing to show\" from\r\n * \"everything shared but empty\".\r\n */\r\n getStyleDetails(): SelectionStyleDetails | null {\r\n const ids = this.deps.getSelectedIds();\r\n if (ids.length === 0) return null;\r\n const styles: ElementStyle[] = [];\r\n for (const id of ids) {\r\n const el = this.deps.store.getById(id);\r\n if (el) styles.push(getElementStyle(el));\r\n }\r\n if (styles.length === 0) return null;\r\n const common: ElementStyle = {};\r\n const applicable: (keyof ElementStyle)[] = [];\r\n const mixed: (keyof ElementStyle)[] = [];\r\n for (const field of STYLE_FIELDS) {\r\n const allValues = styles.map((s) => s[field]);\r\n // Filter out undefined values without requiring a type predicate\r\n const values: NonNullable<(typeof allValues)[0]>[] = [];\r\n for (const v of allValues) {\r\n if (v !== undefined) values.push(v);\r\n }\r\n if (values.length === 0) continue;\r\n applicable.push(field);\r\n const distinct = new Set(values);\r\n if (distinct.size > 1) {\r\n mixed.push(field);\r\n } else {\r\n (common as Record<string, unknown>)[field] = values[0];\r\n }\r\n }\r\n if (applicable.length === 0) return null;\r\n return { common, applicable, mixed };\r\n }\r\n\r\n applyStyle(style: ElementStyle): void {\r\n const ids = this.deps.getSelectedIds();\r\n if (ids.length === 0) return;\r\n this.deps.recorder.begin();\r\n for (const id of ids) {\r\n const el = this.deps.store.getById(id);\r\n if (!el) continue;\r\n const patch = styleToPatch(el, style);\r\n if (Object.keys(patch).length > 0) {\r\n this.deps.store.update(id, patch);\r\n }\r\n }\r\n this.deps.recorder.commit();\r\n }\r\n\r\n group(): void {\r\n const ids = this.deps.getSelectedIds();\r\n if (ids.length < 2) return;\r\n const groupId = createId('group');\r\n this.deps.recorder.begin();\r\n for (const id of ids) {\r\n if (this.deps.store.getById(id)) this.deps.store.update(id, { groupId });\r\n }\r\n this.deps.recorder.commit();\r\n }\r\n\r\n ungroup(): void {\r\n const ids = this.deps.getSelectedIds();\r\n if (ids.length === 0) return;\r\n this.deps.recorder.begin();\r\n for (const id of ids) {\r\n const el = this.deps.store.getById(id);\r\n if (el && el.groupId !== undefined) this.deps.store.update(id, { groupId: undefined });\r\n }\r\n this.deps.recorder.commit();\r\n }\r\n\r\n toggleLock(): void {\r\n const ids = this.deps.getSelectedIds();\r\n if (ids.length === 0) return;\r\n const anyUnlocked = ids.some((id) => {\r\n const el = this.deps.store.getById(id);\r\n return el ? !el.locked : false;\r\n });\r\n this.deps.recorder.begin();\r\n for (const id of ids) {\r\n const el = this.deps.store.getById(id);\r\n if (el && el.locked !== anyUnlocked) this.deps.store.update(id, { locked: anyUnlocked });\r\n }\r\n this.deps.recorder.commit();\r\n }\r\n\r\n align(edge: AlignEdge): void {\r\n const bounded = this.boundedSelection();\r\n if (bounded.length < 2) return;\r\n const B = unionBounds(bounded.map((e) => e.bounds));\r\n this.deps.recorder.begin();\r\n const moved: string[] = [];\r\n for (const { id, el, bounds: b } of bounded) {\r\n if (!this.isMovable(el)) continue;\r\n let dx = 0;\r\n let dy = 0;\r\n switch (edge) {\r\n case 'left':\r\n dx = B.x - b.x;\r\n break;\r\n case 'right':\r\n dx = B.x + B.w - (b.x + b.w);\r\n break;\r\n case 'center-x':\r\n dx = B.x + B.w / 2 - (b.x + b.w / 2);\r\n break;\r\n case 'top':\r\n dy = B.y - b.y;\r\n break;\r\n case 'bottom':\r\n dy = B.y + B.h - (b.y + b.h);\r\n break;\r\n case 'middle':\r\n dy = B.y + B.h / 2 - (b.y + b.h / 2);\r\n break;\r\n }\r\n if (dx === 0 && dy === 0) continue;\r\n this.deps.store.update(id, translateElementPatch(el, dx, dy));\r\n moved.push(id);\r\n }\r\n updateArrowsBoundToElements(moved, this.deps.store);\r\n this.deps.recorder.commit();\r\n this.deps.requestRender();\r\n }\r\n\r\n distribute(axis: DistributeAxis): void {\r\n const bounded = this.boundedSelection();\r\n if (bounded.length < 3) return;\r\n const center = (b: Bounds) => (axis === 'horizontal' ? b.x + b.w / 2 : b.y + b.h / 2);\r\n const sorted = [...bounded].sort((p, q) => center(p.bounds) - center(q.bounds));\r\n const first = sorted[0];\r\n const last = sorted[sorted.length - 1];\r\n if (!first || !last) return;\r\n const c0 = center(first.bounds);\r\n const cN = center(last.bounds);\r\n const n = sorted.length;\r\n this.deps.recorder.begin();\r\n const moved: string[] = [];\r\n for (let i = 1; i < n - 1; i++) {\r\n const item = sorted[i];\r\n if (!item || !this.isMovable(item.el)) continue;\r\n const target = c0 + (i * (cN - c0)) / (n - 1);\r\n const delta = target - center(item.bounds);\r\n if (delta === 0) continue;\r\n const [dx, dy] = axis === 'horizontal' ? [delta, 0] : [0, delta];\r\n this.deps.store.update(item.id, translateElementPatch(item.el, dx, dy));\r\n moved.push(item.id);\r\n }\r\n updateArrowsBoundToElements(moved, this.deps.store);\r\n this.deps.recorder.commit();\r\n this.deps.requestRender();\r\n }\r\n\r\n rotateSelection(direction: RotateDirection): void {\r\n const eligible = this.boundedSelection().filter(({ el }) => this.isMovable(el));\r\n if (eligible.length === 0) return;\r\n const delta = direction === 'cw' ? Math.PI / 2 : -Math.PI / 2;\r\n const pivot = rotationPivot(eligible);\r\n this.deps.recorder.begin();\r\n const moved: string[] = [];\r\n for (const { id, el, bounds } of eligible) {\r\n this.deps.store.update(id, rotateElementPatch(el, bounds, pivot, delta));\r\n moved.push(id);\r\n }\r\n updateArrowsBoundToElements(moved, this.deps.store);\r\n this.deps.recorder.commit();\r\n this.deps.requestRender();\r\n }\r\n\r\n private boundedSelection(): { id: string; el: CanvasElement; bounds: Bounds }[] {\r\n const out: { id: string; el: CanvasElement; bounds: Bounds }[] = [];\r\n for (const id of this.deps.getSelectedIds()) {\r\n const el = this.deps.store.getById(id);\r\n if (!el) continue;\r\n const bounds = getElementBounds(el);\r\n if (bounds) out.push({ id, el, bounds });\r\n }\r\n return out;\r\n }\r\n\r\n private isMovable(el: CanvasElement): boolean {\r\n if (el.locked) return false;\r\n if (el.type === 'arrow' && (el.fromBinding ?? el.toBinding)) return false;\r\n return true;\r\n }\r\n}\r\n","import type { ElementStore } from '../elements/element-store';\r\nimport type { HistoryRecorder } from '../history/history-recorder';\r\nimport type { ToolContext } from '../tools/types';\r\nimport type { GridElement } from '../elements/types';\r\nimport { createGrid } from '../elements/element-factory';\r\n\r\nexport interface GridInfo {\r\n gridType: 'square' | 'hex';\r\n hexOrientation: 'pointy' | 'flat';\r\n cellSize: number;\r\n cellRadius: number;\r\n}\r\n\r\nexport interface GridControllerDeps {\r\n store: ElementStore;\r\n recorder: HistoryRecorder;\r\n requestRender: () => void;\r\n getActiveLayerId: () => string;\r\n toolContext: ToolContext;\r\n defaultGridSize: number;\r\n}\r\n\r\nexport class GridController {\r\n private readonly listeners = new Set<(info: GridInfo | null) => void>();\r\n\r\n constructor(private readonly deps: GridControllerDeps) {}\r\n\r\n add(input: {\r\n gridType?: 'square' | 'hex';\r\n hexOrientation?: 'pointy' | 'flat';\r\n cellSize?: number;\r\n strokeColor?: string;\r\n strokeWidth?: number;\r\n opacity?: number;\r\n }): string {\r\n const existing = this.deps.store.getElementsByType('grid')[0];\r\n this.deps.recorder.begin();\r\n if (existing) {\r\n this.deps.store.remove(existing.id);\r\n }\r\n const grid = createGrid({ ...input, layerId: this.deps.getActiveLayerId() });\r\n this.deps.store.add(grid);\r\n this.deps.recorder.commit();\r\n this.deps.requestRender();\r\n return grid.id;\r\n }\r\n\r\n update(\r\n updates: Partial<\r\n Pick<\r\n GridElement,\r\n 'gridType' | 'hexOrientation' | 'cellSize' | 'strokeColor' | 'strokeWidth' | 'opacity'\r\n >\r\n >,\r\n ): void {\r\n const grid = this.deps.store.getElementsByType('grid')[0];\r\n if (!grid) return;\r\n this.deps.recorder.begin();\r\n this.deps.store.update(grid.id, updates);\r\n this.deps.recorder.commit();\r\n this.deps.requestRender();\r\n }\r\n\r\n remove(): void {\r\n const grid = this.deps.store.getElementsByType('grid')[0];\r\n if (!grid) return;\r\n this.deps.recorder.begin();\r\n this.deps.store.remove(grid.id);\r\n this.deps.recorder.commit();\r\n this.deps.requestRender();\r\n }\r\n\r\n getInfo(): GridInfo | null {\r\n const grid = this.deps.store.getElementsByType('grid')[0];\r\n if (!grid) return null;\r\n return {\r\n gridType: grid.gridType,\r\n hexOrientation: grid.hexOrientation,\r\n cellSize: grid.cellSize,\r\n cellRadius: grid.gridType === 'hex' ? grid.cellSize : grid.cellSize / 2,\r\n };\r\n }\r\n\r\n onChange(listener: (info: GridInfo | null) => void): () => void {\r\n this.listeners.add(listener);\r\n return () => {\r\n this.listeners.delete(listener);\r\n };\r\n }\r\n\r\n syncContext(): void {\r\n const grid = this.deps.store.getElementsByType('grid')[0];\r\n if (grid) {\r\n this.deps.toolContext.gridSize = grid.cellSize;\r\n this.deps.toolContext.gridType = grid.gridType;\r\n this.deps.toolContext.hexOrientation = grid.hexOrientation;\r\n } else {\r\n this.deps.toolContext.gridSize = this.deps.defaultGridSize;\r\n this.deps.toolContext.gridType = undefined;\r\n this.deps.toolContext.hexOrientation = undefined;\r\n }\r\n this.notify();\r\n }\r\n\r\n private notify(): void {\r\n const info = this.getInfo();\r\n for (const listener of this.listeners) {\r\n listener(info);\r\n }\r\n }\r\n}\r\n","import type { Camera } from './camera';\nimport type { ElementStore } from '../elements/element-store';\nimport type { ElementRenderer } from '../elements/element-renderer';\nimport type { NoteEditor } from '../elements/note-editor';\nimport type { ArrowLabelEditor } from '../elements/arrow-label-editor';\nimport type { InteractMode } from './interact-mode';\nimport type { DomNodeManager } from './dom-node-manager';\nimport type { RenderLoop } from './render-loop';\nimport type { HistoryRecorder } from '../history/history-recorder';\nimport type { CanvasElement, ArrowElement } from '../elements/types';\nimport { DoubleTapDetector } from './double-tap-detector';\nimport { isNearBezier } from '../elements/arrow-geometry';\nimport { isNoteContentEmpty } from '../elements/note-sanitizer';\n\nconst ARROW_HIT_THRESHOLD = 10;\n\nexport interface ViewportInteractionsDeps {\n store: ElementStore;\n camera: Camera;\n wrapper: HTMLDivElement;\n domLayer: HTMLDivElement;\n renderLoop: RenderLoop;\n domNodeManager: DomNodeManager;\n noteEditor: NoteEditor;\n arrowLabelEditor: ArrowLabelEditor;\n interactMode: InteractMode;\n renderer: ElementRenderer;\n recorder: HistoryRecorder;\n requestRender: () => void;\n addImage: (src: string, position: { x: number; y: number }) => string;\n dropHandler?: (event: DragEvent, worldPosition: { x: number; y: number }) => void;\n}\n\nexport class ViewportInteractions {\n private readonly doubleTapDetector = new DoubleTapDetector();\n private tapDownX = 0;\n private tapDownY = 0;\n\n constructor(private readonly deps: ViewportInteractionsDeps) {}\n\n startEditingElement(id: string): void {\n const element = this.deps.store.getById(id);\n if (!element || (element.type !== 'note' && element.type !== 'text')) return;\n\n this.deps.renderLoop.flush();\n\n const node = this.deps.domNodeManager.getNode(id);\n if (node) {\n this.deps.noteEditor.startEditing(node, id, this.deps.store);\n }\n }\n\n liveFitHeight(elementId: string): void {\n const element = this.deps.store.getById(elementId);\n if (!element || (element.type !== 'note' && element.type !== 'text')) return;\n const node = this.deps.domNodeManager.getNode(elementId);\n if (!node) return;\n const measured = node.scrollHeight;\n if (measured > 0 && measured !== element.size.h) {\n this.deps.store.update(elementId, { size: { w: element.size.w, h: measured } });\n }\n }\n\n fitNoteHeight(elementId: string): void {\n const element = this.deps.store.getById(elementId);\n if (!element || element.type !== 'note') return;\n if (isNoteContentEmpty(element.text)) return;\n const node = this.deps.domNodeManager.getNode(elementId);\n if (!node) return;\n const measured = node.scrollHeight;\n if (measured > element.size.h) {\n this.deps.store.update(elementId, { size: { w: element.size.w, h: measured } });\n }\n }\n\n onTextEditStop(elementId: string): void {\n const element = this.deps.store.getById(elementId);\n if (!element) return;\n\n if (element.type === 'note') {\n if (isNoteContentEmpty(element.text)) {\n this.deps.store.remove(elementId);\n return;\n }\n this.liveFitHeight(elementId);\n return;\n }\n\n if (element.type !== 'text') return;\n\n if (!element.text || element.text.trim() === '') {\n this.deps.store.remove(elementId);\n return;\n }\n\n this.liveFitHeight(elementId);\n }\n\n onTapDown = (e: PointerEvent): void => {\n this.tapDownX = e.clientX;\n this.tapDownY = e.clientY;\n };\n\n onDoubleTap = (e: PointerEvent): void => {\n const dx = e.clientX - this.tapDownX;\n const dy = e.clientY - this.tapDownY;\n const moved = Math.sqrt(dx * dx + dy * dy);\n if (moved > 10) return;\n\n if (!this.doubleTapDetector.feed(e)) return;\n if (typeof document.elementFromPoint !== 'function') return;\n\n const el = document.elementFromPoint(e.clientX, e.clientY);\n\n const nodeEl = (el as HTMLElement | null)?.closest<HTMLDivElement>('[data-element-id]');\n if (nodeEl) {\n const elementId = nodeEl.dataset['elementId'];\n if (elementId) {\n const element = this.deps.store.getById(elementId);\n if (element?.type === 'note' || element?.type === 'text') {\n this.startEditingElement(elementId);\n return;\n }\n }\n }\n\n const rect = this.deps.wrapper.getBoundingClientRect();\n const screen = { x: e.clientX - rect.left, y: e.clientY - rect.top };\n const world = this.deps.camera.screenToWorld(screen);\n\n // HTML embeds keep double-tap priority: you double-tapped inside the embed even if an\n // arrow's curve passes nearby. Arrow-label editing only when no embed is hit.\n const hit = this.hitTestWorld(world);\n if (hit?.type === 'html') {\n this.deps.interactMode.startInteracting(hit.id);\n return;\n }\n\n const arrow = this.findArrowAt(world);\n if (arrow) {\n this.startArrowLabelEdit(arrow);\n }\n };\n\n findArrowAt(world: { x: number; y: number }): ArrowElement | undefined {\n const candidates = this.deps.store.queryPoint(world).reverse();\n for (const el of candidates) {\n if (\n el.type === 'arrow' &&\n isNearBezier(world, el.from, el.to, el.bend, ARROW_HIT_THRESHOLD)\n ) {\n return el;\n }\n }\n return undefined;\n }\n\n startArrowLabelEdit(arrow: ArrowElement): void {\n this.deps.arrowLabelEditor.startEditing({\n arrow,\n layer: this.deps.domLayer,\n store: this.deps.store,\n recorder: this.deps.recorder,\n onDone: () => {\n this.deps.renderer.setLabelEditingId(null);\n this.deps.requestRender();\n },\n });\n // Set AFTER startEditing: starting a new edit cleans up any prior session, whose onDone\n // synchronously clears the editing id — so claim suppression for this arrow last.\n this.deps.renderer.setLabelEditingId(arrow.id);\n }\n\n private hitTestWorld(world: { x: number; y: number }): CanvasElement | null {\n const candidates = this.deps.store.queryPoint(world).reverse();\n for (const el of candidates) {\n if (!('size' in el)) continue;\n const { x, y } = el.position;\n const { w, h } = el.size;\n if (world.x >= x && world.x <= x + w && world.y >= y && world.y <= y + h) {\n return el;\n }\n }\n return null;\n }\n\n onDragOver = (e: DragEvent): void => {\n e.preventDefault();\n };\n\n onDrop = (e: DragEvent): void => {\n e.preventDefault();\n const rect = this.deps.wrapper.getBoundingClientRect();\n const screenPos = { x: e.clientX - rect.left, y: e.clientY - rect.top };\n const worldPos = this.deps.camera.screenToWorld(screenPos);\n\n if (this.deps.dropHandler) {\n this.deps.dropHandler(e, worldPos);\n return;\n }\n\n const files = e.dataTransfer?.files;\n if (!files) return;\n\n for (const file of files) {\n if (!file.type.startsWith('image/')) continue;\n\n const reader = new FileReader();\n reader.onload = () => {\n const src = reader.result;\n if (typeof src !== 'string') return;\n this.deps.addImage(src, worldPos);\n };\n reader.readAsDataURL(file);\n }\n };\n}\n","import { Camera } from './camera';\nimport type { CameraOptions } from './camera';\nimport { InputHandler } from './input-handler';\nimport type { ShortcutOptions, ShortcutsApi } from './shortcut-map';\nimport { Background } from './background';\nimport type { BackgroundOptions } from './background';\nimport { ElementStore } from '../elements/element-store';\nimport { ElementRenderer } from '../elements/element-renderer';\nimport { NoteEditor } from '../elements/note-editor';\nimport type { FontSizePreset } from '../elements/note-toolbar';\nimport type {\n CanvasElement,\n ArrowElement,\n GridElement,\n HtmlElement,\n ShapeKind,\n} from '../elements/types';\nimport type { Point, Bounds } from '../core/types';\nimport { ContextMenu } from './context-menu';\nimport type { ContextMenuItem } from './context-menu';\nimport { Minimap } from './minimap';\nimport { createWrapper, createCanvas, createDomLayer, createPaintStack } from './viewport-dom';\nimport { HybridRenderSurface } from './hybrid-render-surface';\nimport { findBoundArrows, getEdgeIntersection } from '../elements/arrow-binding';\nimport { getElementBounds } from '../elements/element-bounds';\nimport { getElementsBoundingBox } from '../elements/bounds';\nimport { getArrowTangentAngle } from '../elements/arrow-geometry';\nimport { ArrowLabelEditor } from '../elements/arrow-label-editor';\nimport { ToolManager } from '../tools/tool-manager';\nimport type { ToolContext, Tool } from '../tools/types';\nimport type { SelectTool } from '../tools/select-tool';\nimport { HistoryStack } from '../history/history-stack';\nimport { HistoryRecorder } from '../history/history-recorder';\nimport { createImage, createHtmlElement, createShape } from '../elements/element-factory';\nimport { exportState as exportCanvasState, parseState } from '../core/state-serializer';\nimport { exportImage } from './export-image';\nimport type { ExportImageOptions } from './export-image';\nimport { exportSvg } from './export-svg';\nimport type { ExportSvgOptions } from './export-svg';\nimport type { CanvasState } from '../core/state-serializer';\nimport { LayerManager } from '../layers/layer-manager';\nimport { InteractMode } from './interact-mode';\nimport { DomNodeManager } from './dom-node-manager';\nimport { RenderLoop } from './render-loop';\nimport type { OverlayRenderer } from './render-loop';\nimport type { RenderStatsSnapshot } from './render-stats';\nimport { LayerCache } from './layer-cache';\nimport { MarginViewport } from './margin-viewport';\nimport type { ElementStyle } from '../elements/element-style';\nimport { SelectionOps } from './selection-ops';\nimport type { SelectionStyleDetails } from './selection-ops';\nimport type { AlignEdge, DistributeAxis } from './selection-ops';\nimport { GridController } from './grid-controller';\nimport type { GridInfo } from './grid-controller';\nimport { ViewportInteractions } from './viewport-interactions';\nimport type { RotateDirection } from './selection-rotate';\n\nexport type { AlignEdge, DistributeAxis } from './selection-ops';\nexport type { GridInfo } from './grid-controller';\nexport type { RotateDirection } from './selection-rotate';\n\nconst EMPTY_IDS: string[] = [];\n\nfunction noop(): void {\n // Stable unsubscribe handle returned when no select tool is registered.\n}\n\nexport interface ViewportOptions {\n camera?: CameraOptions;\n background?: BackgroundOptions;\n fontSizePresets?: FontSizePreset[];\n toolbar?: boolean;\n placeholder?: string;\n shortcuts?: ShortcutOptions;\n onHtmlElementMount?: (\n elementId: string,\n domId: string | undefined,\n container: HTMLDivElement,\n ) => void;\n onDrop?: (event: DragEvent, worldPosition: { x: number; y: number }) => void;\n onPaste?: (event: ClipboardEvent, worldPosition: { x: number; y: number }) => void;\n onImageError?: (info: { src: string; elementIds: string[]; cause?: unknown }) => void;\n /** CSS-pixel margin cached beyond the viewport. Default `256`. Set `0` to disable. */\n panBufferMargin?: number;\n /** Enable the built-in context menu. Default `true`. */\n contextMenu?: boolean;\n /** Coast (inertial glide) after a pan flick. Default `true`. */\n panInertia?: boolean;\n /** Show an overview minimap (bottom-right) with tap/drag-to-navigate. Default `false`. */\n minimap?: boolean;\n}\n\nexport class Viewport {\n readonly camera: Camera;\n readonly store: ElementStore;\n readonly layerManager: LayerManager;\n readonly toolManager: ToolManager;\n readonly history: HistoryStack;\n readonly domLayer: HTMLDivElement;\n private readonly canvasEl: HTMLCanvasElement;\n private readonly paintStack: HTMLDivElement;\n private readonly wrapper: HTMLDivElement;\n private readonly unsubCamera: () => void;\n private readonly unsubToolChange: () => void;\n private readonly unsubStore: (() => void)[];\n private readonly inputHandler: InputHandler;\n private readonly background: Background;\n private readonly renderer: ElementRenderer;\n private readonly noteEditor: NoteEditor;\n private readonly arrowLabelEditor: ArrowLabelEditor;\n private readonly historyRecorder: HistoryRecorder;\n private transactionDepth = 0;\n private readonly selectionOps: SelectionOps;\n readonly toolContext: ToolContext;\n private readonly marginViewport: MarginViewport;\n private resizeObserver: ResizeObserver | null = null;\n private _snapToGrid = false;\n private _smartGuides = false;\n private readonly _gridSize: number;\n private readonly renderLoop: RenderLoop;\n private readonly domNodeManager: DomNodeManager;\n private readonly interactMode: InteractMode;\n private readonly onHtmlElementMount?: (\n elementId: string,\n domId: string | undefined,\n container: HTMLDivElement,\n ) => void;\n private readonly dropHandler?: (\n event: DragEvent,\n worldPosition: { x: number; y: number },\n ) => void;\n private readonly gridController: GridController;\n private readonly interactions: ViewportInteractions;\n private contextMenu: ContextMenu | null = null;\n private minimap: Minimap | null = null;\n private readonly htmlRenderers = new Map<string, (el: HtmlElement) => HTMLElement>();\n private readonly resizeListeners = new Set<() => void>();\n private readonly selectionListeners = new Set<() => void>();\n private detachSelectionSource: (() => void) | null = null;\n private unsubToolRegister: () => void = () => {\n // Replaced synchronously in the constructor below.\n };\n private pendingSelectionPrune = false;\n private unsubRecorderEnd: () => void = () => {\n // Replaced synchronously in the constructor below.\n };\n\n constructor(\n private readonly container: HTMLElement,\n options: ViewportOptions = {},\n ) {\n this.camera = new Camera(options.camera);\n this.background = new Background(options.background);\n this._gridSize = options.background?.spacing ?? 24;\n this.store = new ElementStore();\n this.layerManager = new LayerManager(this.store);\n this.toolManager = new ToolManager();\n this.unsubToolRegister = this.toolManager.onRegister((tool) => {\n if (Viewport.isSelectionSource(tool)) this.attachSelectionSource(tool);\n });\n const existingSelect = this.getSelectTool();\n if (existingSelect && Viewport.isSelectionSource(existingSelect)) {\n this.attachSelectionSource(existingSelect);\n }\n this.renderer = new ElementRenderer();\n this.renderer.setStore(this.store);\n this.renderer.setCamera(this.camera);\n this.renderer.setOnImageLoad(() => {\n this.renderLoop.markAllLayersDirty();\n this.requestRender();\n });\n this.renderer.setOnImageError((src, cause) => {\n const elementIds: string[] = [];\n for (const el of this.store.getAll()) {\n if (el.type === 'image' && el.src === src) elementIds.push(el.id);\n }\n if (options.onImageError) {\n options.onImageError({ src, elementIds, cause });\n } else {\n console.warn(`[fieldnotes] image failed to load: ${src}`);\n }\n });\n this.noteEditor = new NoteEditor({\n fontSizePresets: options.fontSizePresets,\n toolbar: options.toolbar,\n placeholder: options.placeholder,\n });\n this.noteEditor.setOnStop((id) => this.interactions.onTextEditStop(id));\n this.noteEditor.setOnInput((id) => this.interactions.liveFitHeight(id));\n this.arrowLabelEditor = new ArrowLabelEditor();\n this.noteEditor.setHistoryHooks(\n () => this.historyRecorder.begin(),\n () => this.historyRecorder.commit(),\n );\n this.onHtmlElementMount = options.onHtmlElementMount;\n this.dropHandler = options.onDrop;\n this.history = new HistoryStack();\n this.historyRecorder = new HistoryRecorder(this.store, this.history, this.layerManager);\n this.unsubRecorderEnd = this.historyRecorder.onTransactionEnd(() => {\n if (!this.pendingSelectionPrune) return;\n this.pendingSelectionPrune = false;\n this.pruneSelection();\n });\n this.selectionOps = new SelectionOps({\n store: this.store,\n recorder: this.historyRecorder,\n getSelectedIds: () => this.getSelectedIds(),\n requestRender: () => this.requestRender(),\n });\n\n this.wrapper = createWrapper();\n this.canvasEl = createCanvas();\n this.paintStack = createPaintStack();\n this.domLayer = createDomLayer();\n this.domLayer.style.zIndex = '2147483647';\n\n this.wrapper.appendChild(this.canvasEl);\n this.wrapper.appendChild(this.paintStack);\n this.wrapper.appendChild(this.domLayer);\n this.container.appendChild(this.wrapper);\n\n this.toolContext = {\n camera: this.camera,\n store: this.store,\n requestRender: () => this.requestRender(),\n switchTool: (name: string) => this.toolManager.setTool(name, this.toolContext),\n editElement: (id: string) => this.interactions.startEditingElement(id),\n fitNoteHeight: (id: string) => this.interactions.fitNoteHeight(id),\n setCursor: (cursor: string) => {\n this.wrapper.style.cursor = cursor;\n },\n snapToGrid: false,\n gridSize: this._gridSize,\n activeLayerId: this.layerManager.activeLayerId,\n isLayerVisible: (id: string) => this.layerManager.isLayerVisible(id),\n isLayerLocked: (id: string) => this.layerManager.isLayerLocked(id),\n smartGuides: false,\n getVisibleRect: () =>\n this.camera.getVisibleRect(this.canvasEl.clientWidth, this.canvasEl.clientHeight),\n };\n\n this.inputHandler = new InputHandler(this.wrapper, this.camera, {\n toolManager: this.toolManager,\n toolContext: this.toolContext,\n historyRecorder: this.historyRecorder,\n historyStack: this.history,\n fitToContent: () => this.fitToContent(),\n group: () => this.groupSelection(),\n ungroup: () => this.ungroupSelection(),\n toggleLock: () => this.toggleLockSelection(),\n rotate: (direction) => this.rotateSelection(direction),\n openContextMenu: (screenPos, world) => {\n this.getSelectTool()?.selectAtPoint(world, this.toolContext);\n this.openContextMenu(screenPos);\n },\n shortcuts: options.shortcuts,\n addImage: (src, world) => this.addImage(src, world),\n getCenteredWorld: () => this.centeredPosition({ w: 300, h: 200 }),\n onPaste: options.onPaste,\n panInertia: options.panInertia,\n });\n\n if (options.contextMenu !== false) {\n this.contextMenu = new ContextMenu({\n onCommand: (action) => this.runAction(action),\n onClose: noop,\n });\n }\n this.unsubToolChange = this.toolManager.onChange(() => this.contextMenu?.close());\n\n if (options.minimap) {\n this.minimap = new Minimap(this.wrapper, this);\n }\n\n this.domNodeManager = new DomNodeManager({\n domLayer: this.paintStack,\n onEditRequest: (id) => this.interactions.startEditingElement(id),\n isEditingElement: (id) =>\n this.noteEditor.isEditing && this.noteEditor.editingElementId === id,\n getVersion: (id) => this.store.getVersion(id),\n });\n this.domNodeManager.setCameraTransform(this.camera.toCSSTransform());\n\n this.interactMode = new InteractMode({\n getNode: (id) => this.domNodeManager.getNode(id),\n });\n\n this.marginViewport = new MarginViewport(options.panBufferMargin ?? 256);\n this.marginViewport.setViewport(\n this.canvasEl.clientWidth || 800,\n this.canvasEl.clientHeight || 600,\n typeof devicePixelRatio !== 'undefined' ? devicePixelRatio : 1,\n );\n const layerCache = new LayerCache(this.marginViewport);\n\n this.renderLoop = new RenderLoop({\n canvasEl: this.canvasEl,\n camera: this.camera,\n background: this.background,\n store: this.store,\n renderer: this.renderer,\n toolManager: this.toolManager,\n layerManager: this.layerManager,\n domNodeManager: this.domNodeManager,\n layerCache,\n marginViewport: this.marginViewport,\n hybridSurface: new HybridRenderSurface(this.paintStack),\n });\n\n this.unsubCamera = this.camera.onChange(() => {\n this.applyCameraTransform();\n this.noteEditor.updateToolbarPosition();\n this.contextMenu?.close();\n this.requestRender();\n });\n\n this.gridController = new GridController({\n store: this.store,\n recorder: this.historyRecorder,\n requestRender: () => this.requestRender(),\n getActiveLayerId: () => this.layerManager.activeLayerId,\n toolContext: this.toolContext,\n defaultGridSize: this._gridSize,\n });\n\n this.unsubStore = [\n this.store.on('add', (el) => {\n if (el.type === 'grid') this.gridController.syncContext();\n this.renderLoop.markLayerDirty(el.layerId);\n this.requestRender();\n }),\n this.store.on('remove', (el) => {\n if (el.type === 'grid') this.gridController.syncContext();\n this.unbindArrowsFrom(el);\n this.domNodeManager.removeDomNode(el.id);\n this.renderLoop.markLayerDirty(el.layerId);\n this.requestRender();\n this.handleRemovedElement(el.id);\n }),\n this.store.on('update', ({ previous, current }) => {\n if (current.type === 'grid') this.gridController.syncContext();\n this.renderLoop.markLayerDirty(current.layerId);\n if (previous.layerId !== current.layerId) {\n this.renderLoop.markLayerDirty(previous.layerId);\n }\n this.requestRender();\n }),\n this.store.on('clear', () => {\n this.domNodeManager.clearDomNodes();\n this.renderLoop.markAllLayersDirty();\n this.gridController.syncContext();\n this.requestRender();\n this.pruneSelection();\n }),\n ];\n\n this.layerManager.on('change', () => {\n this.toolContext.activeLayerId = this.layerManager.activeLayerId;\n this.renderLoop.markAllLayersDirty();\n this.requestRender();\n });\n\n this.interactions = new ViewportInteractions({\n store: this.store,\n camera: this.camera,\n wrapper: this.wrapper,\n domLayer: this.domLayer,\n renderLoop: this.renderLoop,\n domNodeManager: this.domNodeManager,\n noteEditor: this.noteEditor,\n arrowLabelEditor: this.arrowLabelEditor,\n interactMode: this.interactMode,\n renderer: this.renderer,\n recorder: this.historyRecorder,\n requestRender: () => this.requestRender(),\n addImage: (src, position) => this.addImage(src, position),\n dropHandler: this.dropHandler,\n });\n\n this.wrapper.addEventListener('pointerdown', this.interactions.onTapDown);\n this.wrapper.addEventListener('pointerup', this.interactions.onDoubleTap);\n this.wrapper.addEventListener('dragover', this.interactions.onDragOver);\n this.wrapper.addEventListener('drop', this.interactions.onDrop);\n this.observeResize();\n this.syncCanvasSize();\n this.renderLoop.start();\n this.gridController.syncContext();\n }\n\n get ctx(): CanvasRenderingContext2D | null {\n return this.canvasEl.getContext('2d');\n }\n\n get snapToGrid(): boolean {\n return this._snapToGrid;\n }\n\n setSnapToGrid(enabled: boolean): void {\n this._snapToGrid = enabled;\n this.toolContext.snapToGrid = enabled;\n }\n\n get smartGuides(): boolean {\n return this._smartGuides;\n }\n\n setSmartGuides(enabled: boolean): void {\n this._smartGuides = enabled;\n this.toolContext.smartGuides = enabled;\n }\n\n fitToContent(padding = 40): void {\n if (this.wrapper.clientWidth === 0 || this.wrapper.clientHeight === 0) return;\n const visibleElements = this.store\n .getAll()\n .filter((el) => this.layerManager.isLayerVisible(el.layerId));\n const bbox = getElementsBoundingBox(visibleElements);\n if (!bbox) return;\n this.camera.fitToContent(bbox, this.wrapper.clientWidth, this.wrapper.clientHeight, padding);\n }\n\n /** World-space rectangle currently visible through the canvas. */\n getVisibleRect(): Bounds {\n return this.camera.getVisibleRect(this.canvasEl.clientWidth, this.canvasEl.clientHeight);\n }\n\n /**\n * Size in CSS pixels of the canvas that `getVisibleRect()` measures.\n * Exposed because `canvasEl` is private: consumers can only reach the\n * wrapper (via `domLayer.parentElement`), so without this accessor the\n * canonical size behind `getVisibleRect()` is unreachable and callers\n * resort to `getVisibleRect().w * camera.zoom`. Capture and restore must\n * measure the same element or saved views do not round-trip.\n */\n getCanvasSize(): { w: number; h: number } {\n return { w: this.canvasEl.clientWidth, h: this.canvasEl.clientHeight };\n }\n\n /** Centers the camera on a world point without changing zoom. */\n centerCameraAt(world: Point): void {\n const z = this.camera.zoom;\n this.camera.moveTo(\n this.canvasEl.clientWidth / 2 - world.x * z,\n this.canvasEl.clientHeight / 2 - world.y * z,\n );\n }\n\n /**\n * Notifies after the host container resizes (ResizeObserver-driven). A resize\n * changes the visible world rect without a camera event; overlays such as the\n * minimap subscribe to stay current. Returns an idempotent unsubscribe.\n */\n onResize(listener: () => void): () => void {\n this.resizeListeners.add(listener);\n return () => this.resizeListeners.delete(listener);\n }\n\n requestRender(): void {\n this.renderLoop.requestRender();\n }\n\n /**\n * Registers a world-space overlay drawn above elements on every frame,\n * regardless of the active tool — the surface for remote presence visuals\n * such as laser trails, cursors, pings, and shared rulers. Overlays draw\n * beneath the active tool's own `renderOverlay` and never touch elements,\n * history, or persisted state. Returns an idempotent unsubscribe that also\n * erases the overlay's last frame.\n */\n registerOverlay(draw: OverlayRenderer): () => void {\n return this.renderLoop.registerOverlay(draw);\n }\n\n exportState(): CanvasState {\n return exportCanvasState(\n this.store.snapshot(),\n this.camera,\n this.layerManager.snapshot(),\n this.layerManager.activeLayerId,\n );\n }\n\n exportJSON(): string {\n return JSON.stringify(this.exportState());\n }\n\n async exportImage(options?: ExportImageOptions): Promise<Blob | null> {\n return exportImage(this.store, options, this.layerManager);\n }\n\n async exportSVG(options?: ExportSvgOptions): Promise<string> {\n return exportSvg(this.store, options, this.layerManager);\n }\n\n loadState(state: CanvasState): void {\n this.inputHandler.flushPendingHistory();\n this.historyRecorder.pause();\n this.noteEditor.destroy(this.store);\n this.domNodeManager.clearDomNodes();\n this.store.loadSnapshot(state.elements);\n if (state.layers && state.layers.length > 0) {\n this.layerManager.loadSnapshot(state.layers);\n }\n if (state.activeLayerId) {\n this.layerManager.setActiveLayer(state.activeLayerId);\n }\n this.domNodeManager.reattachHtmlContent(this.store);\n for (const el of this.store.getElementsByType('html')) {\n if (this.domNodeManager.hasContent(el.id)) continue;\n\n // Registry first: rebuild the embed from serialized data and mount it via the html branch\n // of renderDomContent. This stores content BEFORE the onHtmlElementMount path's hasContent\n // check, so a factory-rebuilt element never also gets an empty node from the callback path.\n const factory = el.htmlType ? this.htmlRenderers.get(el.htmlType) : undefined;\n const rebuilt = factory ? factory(el) : null;\n if (rebuilt) {\n this.domNodeManager.storeHtmlContent(el.id, rebuilt);\n this.domNodeManager.syncDomNode(el);\n }\n\n // Callback still fires for wiring (both fire; registry produces the node, callback wires it).\n if (this.onHtmlElementMount) {\n if (!rebuilt) this.domNodeManager.syncDomNode(el);\n const node = this.domNodeManager.getNode(el.id);\n if (node) {\n this.onHtmlElementMount(el.id, el.domId, node);\n node.dataset['initialized'] = 'true';\n Object.assign(node.style, {\n overflow: 'hidden',\n pointerEvents: el.interactive ? 'auto' : 'none',\n });\n }\n }\n }\n this.history.clear();\n this.historyRecorder.resume();\n this.camera.moveTo(state.camera.position.x, state.camera.position.y);\n this.camera.setZoom(state.camera.zoom);\n }\n\n loadJSON(json: string): void {\n this.loadState(parseState(json));\n }\n\n setTool(name: string): void {\n if (!this.toolManager.getTool(name)) {\n console.warn(`[fieldnotes] setTool: no tool registered as \"${name}\"`);\n return;\n }\n this.toolManager.setTool(name, this.toolContext);\n }\n\n get shortcuts(): ShortcutsApi {\n return this.inputHandler.shortcuts;\n }\n\n /**\n * Groups synchronous local store and layer mutations into one undo step.\n * Nested calls join the outer transaction. If the callback throws, mutations\n * already applied remain undoable and the original error is rethrown.\n */\n transaction<T>(operation: () => T): T {\n const isOuterTransaction = this.transactionDepth === 0;\n if (isOuterTransaction) {\n this.inputHandler.flushPendingHistory();\n this.historyRecorder.begin();\n }\n this.transactionDepth += 1;\n try {\n return operation();\n } finally {\n this.transactionDepth -= 1;\n if (isOuterTransaction) this.historyRecorder.commit();\n }\n }\n\n /** Removes existing elements as one undoable operation and returns the number removed. */\n removeElements(ids: Iterable<string>): number {\n const existingIds = [...new Set(ids)].filter((id) => this.store.getById(id) !== undefined);\n if (existingIds.length === 0) return 0;\n this.transaction(() => {\n for (const id of existingIds) this.store.remove(id);\n });\n this.requestRender();\n return existingIds.length;\n }\n\n undo(): boolean {\n this.inputHandler.flushPendingHistory();\n this.historyRecorder.pause();\n const result = this.history.undo(this.store);\n this.historyRecorder.resume();\n if (result) this.requestRender();\n return result;\n }\n\n redo(): boolean {\n this.inputHandler.flushPendingHistory();\n this.historyRecorder.pause();\n const result = this.history.redo(this.store);\n this.historyRecorder.resume();\n if (result) this.requestRender();\n return result;\n }\n\n addImage(src: string, position: { x: number; y: number }, size = { w: 300, h: 200 }): string {\n const image = createImage({ position, size, src, layerId: this.layerManager.activeLayerId });\n this.historyRecorder.begin();\n this.store.add(image);\n this.historyRecorder.commit();\n this.requestRender();\n return image.id;\n }\n\n addHtmlElement(\n dom: HTMLElement,\n position: { x: number; y: number },\n size = { w: 200, h: 150 },\n opts?: { htmlType?: string; data?: Record<string, unknown> },\n ): string {\n const domId = dom.id || undefined;\n const el = createHtmlElement({\n position,\n size,\n domId,\n htmlType: opts?.htmlType,\n data: opts?.data,\n layerId: this.layerManager.activeLayerId,\n });\n this.domNodeManager.storeHtmlContent(el.id, dom);\n this.historyRecorder.begin();\n this.store.add(el);\n this.historyRecorder.commit();\n this.requestRender();\n return el.id;\n }\n\n addShape(\n opts: {\n shape?: ShapeKind;\n size?: { w: number; h: number };\n position?: { x: number; y: number };\n strokeColor?: string;\n fillColor?: string;\n strokeWidth?: number;\n } = {},\n ): string {\n const size = opts.size ?? { w: 100, h: 100 };\n const position = opts.position ?? this.centeredPosition(size);\n const shape = createShape({\n position,\n size,\n shape: opts.shape,\n strokeColor: opts.strokeColor,\n strokeWidth: opts.strokeWidth,\n fillColor: opts.fillColor,\n layerId: this.layerManager.activeLayerId,\n });\n this.historyRecorder.begin();\n this.store.add(shape);\n this.historyRecorder.commit();\n this.getSelectTool()?.setSelection([shape.id]);\n this.requestRender();\n return shape.id;\n }\n\n private centeredPosition(size: { w: number; h: number }): { x: number; y: number } {\n const c = this.camera.screenToWorld({\n x: this.wrapper.clientWidth / 2,\n y: this.wrapper.clientHeight / 2,\n });\n return { x: c.x - size.w / 2, y: c.y - size.h / 2 };\n }\n\n removeLayer(id: string): void {\n this.historyRecorder.begin();\n this.layerManager.removeLayer(id);\n this.historyRecorder.commit();\n }\n\n registerHtmlRenderer(htmlType: string, factory: (el: HtmlElement) => HTMLElement): void {\n this.htmlRenderers.set(htmlType, factory);\n }\n\n updateHtmlElement(id: string, newContent: HTMLElement): void {\n const el = this.store.getById(id);\n if (!el) throw new Error(`Element not found: ${id}`);\n if (el.type !== 'html') throw new Error(`Element ${id} is not an HTML element`);\n this.domNodeManager.resetHtmlContent(id);\n this.domNodeManager.storeHtmlContent(id, newContent);\n this.requestRender();\n }\n\n addGrid(input: {\n gridType?: 'square' | 'hex';\n hexOrientation?: 'pointy' | 'flat';\n cellSize?: number;\n strokeColor?: string;\n strokeWidth?: number;\n opacity?: number;\n }): string {\n return this.gridController.add(input);\n }\n\n updateGrid(\n updates: Partial<\n Pick<\n GridElement,\n 'gridType' | 'hexOrientation' | 'cellSize' | 'strokeColor' | 'strokeWidth' | 'opacity'\n >\n >,\n ): void {\n this.gridController.update(updates);\n }\n\n removeGrid(): void {\n this.gridController.remove();\n }\n\n getGridInfo(): GridInfo | null {\n return this.gridController.getInfo();\n }\n\n onGridChange(listener: (info: GridInfo | null) => void): () => void {\n return this.gridController.onChange(listener);\n }\n\n private getSelectTool(): SelectTool | undefined {\n return this.toolManager.getTool<SelectTool>('select');\n }\n\n private pruneSelection(): void {\n const tool = this.getSelectTool();\n if (!tool) return;\n const ids = tool.selectedIds;\n const filtered = ids.filter((id) => this.store.getById(id) !== undefined);\n if (filtered.length !== ids.length) tool.setSelection(filtered);\n }\n\n private handleRemovedElement(id: string): void {\n if (!this.getSelectedIds().includes(id)) return;\n if (this.historyRecorder.currentTransactionId !== null) {\n this.pendingSelectionPrune = true;\n return;\n }\n this.pruneSelection();\n }\n\n private static isSelectionSource(tool: Tool): tool is SelectTool {\n const candidate = tool as Partial<SelectTool>;\n return (\n tool.name === 'select' &&\n typeof candidate.onSelectionChange === 'function' &&\n typeof candidate.setSelection === 'function'\n );\n }\n\n private emitSelectionChange(): void {\n for (const listener of this.selectionListeners) {\n try {\n listener();\n } catch {\n // Selection listeners must not break each other or the caller.\n }\n }\n }\n\n private attachSelectionSource(tool: SelectTool): void {\n this.detachSelectionSource?.();\n this.detachSelectionSource = tool.onSelectionChange(() => this.emitSelectionChange());\n }\n\n /**\n * getSelectedIds() and the onSelectionChange emitter never surface stale ids:\n * once the enclosing history transaction completes, both reflect\n * the current selection.\n */\n getSelectedIds(): string[] {\n return this.getSelectTool()?.selectedIds ?? EMPTY_IDS;\n }\n\n runAction(action: string): void {\n this.inputHandler.runAction(action);\n }\n\n canPaste(): boolean {\n return this.inputHandler.hasClipboard();\n }\n\n openContextMenu(screenPos: Point): void {\n if (!this.contextMenu) return;\n const ids = this.getSelectedIds();\n const items: ContextMenuItem[] = [];\n if (ids.length > 0) {\n items.push({ label: 'Cut', action: 'cut' });\n items.push({ label: 'Copy', action: 'copy' });\n if (this.canPaste()) items.push({ label: 'Paste', action: 'paste' });\n items.push({ label: 'Duplicate', action: 'duplicate' });\n items.push({ label: 'Delete', action: 'delete' });\n items.push({ label: 'Bring to Front', action: 'z-front' });\n items.push({ label: 'Bring Forward', action: 'z-forward' });\n items.push({ label: 'Send Backward', action: 'z-backward' });\n items.push({ label: 'Send to Back', action: 'z-back' });\n items.push({ label: 'Rotate 90° CW', action: 'rotate-cw' });\n items.push({ label: 'Rotate 90° CCW', action: 'rotate-ccw' });\n const allLocked = ids.every((id) => this.store.getById(id)?.locked);\n items.push({ label: allLocked ? 'Unlock' : 'Lock', action: 'toggle-lock' });\n } else if (this.canPaste()) {\n items.push({ label: 'Paste', action: 'paste' });\n }\n if (items.length === 0) return;\n this.contextMenu.open(items, screenPos);\n }\n\n /**\n * Persistent, viewport-owned selection-change emitter. Subscribing works\n * regardless of whether a select tool is registered yet; it forwards\n * events from whichever select tool is currently attached via\n * `toolManager.onRegister`. Never delivers stale ids once the enclosing\n * history transaction completes.\n */\n onSelectionChange(listener: () => void): () => void {\n this.selectionListeners.add(listener);\n return () => {\n this.selectionListeners.delete(listener);\n };\n }\n\n getSelectionStyle(): ElementStyle | null {\n return this.selectionOps.getStyle();\n }\n\n /**\n * Unlike `getSelectionStyle()` — which returns `{}` for a style-less\n * selection — this returns `null` when no style field is applicable.\n */\n getSelectionStyleDetails(): SelectionStyleDetails | null {\n return this.selectionOps.getStyleDetails();\n }\n\n applyStyleToSelection(style: ElementStyle): void {\n this.selectionOps.applyStyle(style);\n }\n\n groupSelection(): void {\n this.selectionOps.group();\n }\n\n ungroupSelection(): void {\n this.selectionOps.ungroup();\n }\n\n toggleLockSelection(): void {\n this.selectionOps.toggleLock();\n }\n\n alignSelection(edge: AlignEdge): void {\n this.selectionOps.align(edge);\n }\n\n distributeSelection(axis: DistributeAxis): void {\n this.selectionOps.distribute(axis);\n }\n\n rotateSelection(direction: RotateDirection): void {\n this.selectionOps.rotateSelection(direction);\n }\n\n getRenderStats(): RenderStatsSnapshot {\n return this.renderLoop.getStats();\n }\n\n logPerformance(intervalMs = 2000): () => void {\n const id = setInterval(() => {\n const s = this.getRenderStats();\n console.log(\n `[FieldNotes] fps=${s.fps} frame=${s.avgFrameMs}ms p95=${s.p95FrameMs}ms grid=${s.lastGridMs}ms layers=${s.layersMs}ms comp=${s.compositeMs}ms bg=${s.backgroundMs}ms overlay=${s.overlayMs}ms`,\n );\n }, intervalMs);\n return () => clearInterval(id);\n }\n\n destroy(): void {\n this.renderLoop.stop();\n this.interactMode.destroy();\n this.noteEditor.destroy(this.store);\n this.arrowLabelEditor.cancel();\n this.historyRecorder.destroy();\n this.contextMenu?.dispose();\n this.minimap?.destroy();\n this.wrapper.removeEventListener('pointerdown', this.interactions.onTapDown);\n this.wrapper.removeEventListener('pointerup', this.interactions.onDoubleTap);\n this.wrapper.removeEventListener('dragover', this.interactions.onDragOver);\n this.wrapper.removeEventListener('drop', this.interactions.onDrop);\n this.inputHandler.destroy();\n this.unsubCamera();\n this.unsubToolChange();\n this.unsubToolRegister();\n this.unsubRecorderEnd();\n this.detachSelectionSource?.();\n this.detachSelectionSource = null;\n this.selectionListeners.clear();\n this.unsubStore.forEach((fn) => fn());\n this.resizeObserver?.disconnect();\n this.resizeObserver = null;\n this.resizeListeners.clear();\n this.wrapper.remove();\n }\n\n stopInteracting(): void {\n this.interactMode.stopInteracting();\n }\n\n private unbindArrowsFrom(removedElement: CanvasElement): void {\n const boundArrows = findBoundArrows(removedElement.id, this.store);\n const bounds = getElementBounds(removedElement);\n\n for (const arrow of boundArrows) {\n const updates: Partial<ArrowElement> = {};\n\n if (arrow.fromBinding?.elementId === removedElement.id) {\n updates.fromBinding = undefined;\n if (bounds) {\n const angle = getArrowTangentAngle(arrow.from, arrow.to, arrow.bend, 0);\n const rayTarget = {\n x: arrow.from.x + Math.cos(angle) * 1000,\n y: arrow.from.y + Math.sin(angle) * 1000,\n };\n const edge = getEdgeIntersection(bounds, rayTarget);\n updates.from = edge;\n updates.position = edge;\n }\n }\n\n if (arrow.toBinding?.elementId === removedElement.id) {\n updates.toBinding = undefined;\n if (bounds) {\n const angle = getArrowTangentAngle(arrow.from, arrow.to, arrow.bend, 1);\n const rayTarget = {\n x: arrow.to.x - Math.cos(angle) * 1000,\n y: arrow.to.y - Math.sin(angle) * 1000,\n };\n updates.to = getEdgeIntersection(bounds, rayTarget);\n }\n }\n\n if (Object.keys(updates).length > 0) {\n this.store.update(arrow.id, updates);\n }\n }\n }\n\n private applyCameraTransform(): void {\n const transform = this.camera.toCSSTransform();\n this.domLayer.style.transform = transform;\n this.domNodeManager.setCameraTransform(transform);\n }\n\n private syncCanvasSize(): void {\n const rect = this.container.getBoundingClientRect();\n const dpr = typeof devicePixelRatio !== 'undefined' ? devicePixelRatio : 1;\n this.renderLoop.setCanvasSize(rect.width * dpr, rect.height * dpr);\n this.requestRender();\n this.resizeListeners.forEach((fn) => fn());\n }\n\n private observeResize(): void {\n if (typeof ResizeObserver === 'undefined') return;\n this.resizeObserver = new ResizeObserver(() => this.syncCanvasSize());\n this.resizeObserver.observe(this.container);\n }\n}\n","import type { Point } from '../core/types';\r\nimport type { OverlayRenderer } from './render-loop';\r\nimport type { LaserTrailEmission } from '../tools/laser-tool';\r\n\r\n/**\r\n * The wire shape of a laser-trail presence payload. Presence data is untyped\r\n * on the wire, so hosts discriminate on `kind`; `isLaserTrailPresence`\r\n * validates a received payload before it reaches the overlay. Trails are\r\n * ephemeral by contract: they must travel as presence only — never as\r\n * elements, undo history, persisted canvas state, or durable operations.\r\n */\r\nexport interface LaserTrailPresence {\r\n readonly kind: 'laser';\r\n /** World-space points, oldest first. */\r\n readonly points: readonly Point[];\r\n readonly color?: string;\r\n readonly width?: number;\r\n readonly fadeMs?: number;\r\n}\r\n\r\nexport const LASER_TRAIL_PRESENCE_KIND = 'laser';\r\n\r\nfunction isFinitePoint(value: unknown): value is Point {\r\n if (typeof value !== 'object' || value === null) return false;\r\n const point = value as { x?: unknown; y?: unknown };\r\n return (\r\n typeof point.x === 'number' &&\r\n Number.isFinite(point.x) &&\r\n typeof point.y === 'number' &&\r\n Number.isFinite(point.y)\r\n );\r\n}\r\n\r\nexport function isLaserTrailPresence(data: unknown): data is LaserTrailPresence {\r\n if (typeof data !== 'object' || data === null) return false;\r\n const payload = data as {\r\n kind?: unknown;\r\n points?: unknown;\r\n color?: unknown;\r\n width?: unknown;\r\n fadeMs?: unknown;\r\n };\r\n if (payload.kind !== LASER_TRAIL_PRESENCE_KIND) return false;\r\n if (!Array.isArray(payload.points) || !payload.points.every(isFinitePoint)) return false;\r\n if (payload.color !== undefined && typeof payload.color !== 'string') return false;\r\n if (payload.width !== undefined && !(typeof payload.width === 'number' && payload.width > 0)) {\r\n return false;\r\n }\r\n if (payload.fadeMs !== undefined && !(typeof payload.fadeMs === 'number' && payload.fadeMs > 0)) {\r\n return false;\r\n }\r\n return true;\r\n}\r\n\r\n/** Builds the presence payload for one local `LaserTool` emission. */\r\nexport function toLaserTrailPresence(emission: LaserTrailEmission): LaserTrailPresence {\r\n return {\r\n kind: LASER_TRAIL_PRESENCE_KIND,\r\n points: emission.points.map((point) => ({ x: point.x, y: point.y })),\r\n color: emission.color,\r\n width: emission.width,\r\n fadeMs: emission.fadeMs,\r\n };\r\n}\r\n\r\n/**\r\n * The two viewport capabilities the overlay needs; `Viewport` satisfies it.\r\n */\r\nexport interface RemoteLaserOverlayHost {\r\n registerOverlay(draw: OverlayRenderer): () => void;\r\n requestRender(): void;\r\n}\r\n\r\nexport interface RemoteLaserOverlayOptions {\r\n /** Style fallbacks when a payload omits them. */\r\n color?: string;\r\n width?: number;\r\n fadeMs?: number;\r\n /** Per-sender point cap; oldest points drop first. Default `512`. */\r\n maxPointsPerSender?: number;\r\n}\r\n\r\ninterface RemoteTrailPoint {\r\n x: number;\r\n y: number;\r\n t: number;\r\n}\r\n\r\ninterface RemoteTrail {\r\n points: RemoteTrailPoint[];\r\n color: string;\r\n width: number;\r\n fadeMs: number;\r\n}\r\n\r\nconst DEFAULT_COLOR = '#ff3b30';\r\nconst DEFAULT_WIDTH = 4;\r\nconst DEFAULT_FADE_MS = 1200;\r\nconst DEFAULT_MAX_POINTS = 512;\r\n\r\n/**\r\n * Renders fading laser trails for remote senders through the viewport overlay\r\n * registration, independent of the viewer's active tool. Points are stamped\r\n * with local receive time (remote clocks are never trusted), fade like the\r\n * local `LaserTool`, and a sender's trail disappears immediately on\r\n * `remove()` — wire that to `presence-leave`/disconnect. The controller never\r\n * touches elements, history, or persisted state.\r\n */\r\nexport class RemoteLaserOverlay {\r\n private readonly host: RemoteLaserOverlayHost;\r\n private readonly color: string;\r\n private readonly width: number;\r\n private readonly fadeMs: number;\r\n private readonly maxPointsPerSender: number;\r\n private readonly trails = new Map<string, RemoteTrail>();\r\n private unregister: (() => void) | null;\r\n private rafId: number | null = null;\r\n private disposed = false;\r\n\r\n constructor(host: RemoteLaserOverlayHost, options: RemoteLaserOverlayOptions = {}) {\r\n this.host = host;\r\n this.color = options.color ?? DEFAULT_COLOR;\r\n this.width = options.width ?? DEFAULT_WIDTH;\r\n this.fadeMs = options.fadeMs ?? DEFAULT_FADE_MS;\r\n this.maxPointsPerSender = options.maxPointsPerSender ?? DEFAULT_MAX_POINTS;\r\n this.unregister = host.registerOverlay((ctx) => this.renderTrails(ctx));\r\n }\r\n\r\n private now(): number {\r\n return performance.now();\r\n }\r\n\r\n /**\r\n * Applies a presence payload from `sender` (any opaque per-sender key, e.g.\r\n * the envelope `from`). Non-laser or malformed payloads are ignored and\r\n * reported as `false`, so hosts can feed every presence frame through.\r\n */\r\n apply(sender: string, data: unknown): boolean {\r\n if (this.disposed || !isLaserTrailPresence(data)) return false;\r\n let trail = this.trails.get(sender);\r\n if (!trail) {\r\n trail = { points: [], color: this.color, width: this.width, fadeMs: this.fadeMs };\r\n this.trails.set(sender, trail);\r\n }\r\n trail.color = data.color ?? this.color;\r\n trail.width = data.width ?? this.width;\r\n trail.fadeMs = data.fadeMs ?? this.fadeMs;\r\n const t = this.now();\r\n for (const point of data.points) {\r\n trail.points.push({ x: point.x, y: point.y, t });\r\n }\r\n const excess = trail.points.length - this.maxPointsPerSender;\r\n if (excess > 0) trail.points.splice(0, excess);\r\n this.ensureAnimating();\r\n this.host.requestRender();\r\n return true;\r\n }\r\n\r\n /** Removes a sender's trail immediately (presence-leave/disconnect). */\r\n remove(sender: string): void {\r\n if (this.trails.delete(sender)) this.host.requestRender();\r\n }\r\n\r\n /** Removes every trail immediately. */\r\n clear(): void {\r\n if (this.trails.size === 0) return;\r\n this.trails.clear();\r\n this.host.requestRender();\r\n }\r\n\r\n /** Number of senders with a live (unfaded) trail. */\r\n get activeSenderCount(): number {\r\n return this.trails.size;\r\n }\r\n\r\n /** Unregisters the overlay and stops the fade loop. Idempotent. */\r\n dispose(): void {\r\n if (this.disposed) return;\r\n this.disposed = true;\r\n if (this.rafId !== null) {\r\n cancelAnimationFrame(this.rafId);\r\n this.rafId = null;\r\n }\r\n this.trails.clear();\r\n this.unregister?.();\r\n this.unregister = null;\r\n }\r\n\r\n private ensureAnimating(): void {\r\n if (this.rafId === null) {\r\n this.rafId = requestAnimationFrame(() => this.tick());\r\n }\r\n }\r\n\r\n private tick(): void {\r\n if (this.disposed) return;\r\n const now = this.now();\r\n for (const [sender, trail] of this.trails) {\r\n const cutoff = now - trail.fadeMs;\r\n trail.points = trail.points.filter((point) => point.t >= cutoff);\r\n if (trail.points.length === 0) this.trails.delete(sender);\r\n }\r\n this.host.requestRender();\r\n this.rafId = this.trails.size > 0 ? requestAnimationFrame(() => this.tick()) : null;\r\n }\r\n\r\n private renderTrails(ctx: CanvasRenderingContext2D): void {\r\n if (this.trails.size === 0) return;\r\n const now = this.now();\r\n for (const trail of this.trails.values()) {\r\n if (trail.points.length < 2) continue;\r\n ctx.save();\r\n ctx.strokeStyle = trail.color;\r\n ctx.lineWidth = trail.width;\r\n ctx.lineCap = 'round';\r\n ctx.lineJoin = 'round';\r\n for (let i = 0; i < trail.points.length - 1; i++) {\r\n const a = trail.points[i];\r\n const b = trail.points[i + 1];\r\n if (!a || !b) continue;\r\n const age = now - b.t;\r\n ctx.globalAlpha = Math.max(0, 1 - age / trail.fadeMs);\r\n ctx.beginPath();\r\n ctx.moveTo(a.x, a.y);\r\n ctx.lineTo(b.x, b.y);\r\n ctx.stroke();\r\n }\r\n ctx.restore();\r\n }\r\n }\r\n}\r\n","/**\r\n * Shared expanding-pulse rendering for map pings. Internal helper used by the\r\n * local `PingTool` overlay and the `RemotePingOverlay` so a viewer sees the\r\n * same animation for local and remote pings. Not part of the public API.\r\n */\r\n\r\nexport interface PingPulseStyle {\r\n color: string;\r\n /** Total animation length in milliseconds. */\r\n durationMs: number;\r\n /** Maximum ripple radius in world units. */\r\n radius: number;\r\n}\r\n\r\n/** Ripple start offsets as fractions of the total duration. */\r\nconst RIPPLE_OFFSETS = [0, 0.25] as const;\r\n\r\nfunction easeOutCubic(t: number): number {\r\n const inv = 1 - t;\r\n return 1 - inv * inv * inv;\r\n}\r\n\r\n/**\r\n * Draws one ping at world position (`x`, `y`) given its age. The context is\r\n * already in world space. Draws nothing once `ageMs >= durationMs`.\r\n */\r\nexport function renderPingPulse(\r\n ctx: CanvasRenderingContext2D,\r\n x: number,\r\n y: number,\r\n ageMs: number,\r\n style: PingPulseStyle,\r\n): void {\r\n if (ageMs < 0 || ageMs >= style.durationMs) return;\r\n\r\n ctx.save();\r\n ctx.strokeStyle = style.color;\r\n ctx.fillStyle = style.color;\r\n\r\n for (const offset of RIPPLE_OFFSETS) {\r\n const rippleSpan = style.durationMs * (1 - offset);\r\n const rippleAge = ageMs - style.durationMs * offset;\r\n if (rippleAge < 0) continue;\r\n const progress = Math.min(1, rippleAge / rippleSpan);\r\n const rippleRadius = style.radius * easeOutCubic(progress);\r\n if (rippleRadius <= 0) continue;\r\n ctx.globalAlpha = Math.max(0, 1 - progress);\r\n ctx.lineWidth = Math.max(1.5, style.radius / 12);\r\n ctx.beginPath();\r\n ctx.arc(x, y, rippleRadius, 0, Math.PI * 2);\r\n ctx.stroke();\r\n }\r\n\r\n // Center dot: solid for the first half, then fades with the ripples.\r\n const dotProgress = ageMs / style.durationMs;\r\n ctx.globalAlpha = Math.max(0, 1 - Math.max(0, dotProgress - 0.5) * 2);\r\n ctx.beginPath();\r\n ctx.arc(x, y, Math.max(2, style.radius / 8), 0, Math.PI * 2);\r\n ctx.fill();\r\n\r\n ctx.restore();\r\n}\r\n","import type { OverlayRenderer } from './render-loop';\r\nimport { renderPingPulse } from './ping-pulse';\r\nimport type { PingEmission } from '../tools/ping-tool';\r\n\r\n/**\r\n * The wire shape of a map-ping presence payload. Presence data is untyped on\r\n * the wire, so hosts discriminate on `kind`; `isPingPresence` validates a\r\n * received payload before it reaches the overlay. Pings are ephemeral by\r\n * contract: they must travel as presence only — never as elements, undo\r\n * history, persisted canvas state, or durable operations.\r\n */\r\nexport interface PingPresence {\r\n readonly kind: 'ping';\r\n /** World-space ping position. */\r\n readonly x: number;\r\n readonly y: number;\r\n readonly color?: string;\r\n readonly durationMs?: number;\r\n readonly radius?: number;\r\n}\r\n\r\nexport const PING_PRESENCE_KIND = 'ping';\r\n\r\nexport function isPingPresence(data: unknown): data is PingPresence {\r\n if (typeof data !== 'object' || data === null) return false;\r\n const payload = data as {\r\n kind?: unknown;\r\n x?: unknown;\r\n y?: unknown;\r\n color?: unknown;\r\n durationMs?: unknown;\r\n radius?: unknown;\r\n };\r\n if (payload.kind !== PING_PRESENCE_KIND) return false;\r\n if (typeof payload.x !== 'number' || !Number.isFinite(payload.x)) return false;\r\n if (typeof payload.y !== 'number' || !Number.isFinite(payload.y)) return false;\r\n if (payload.color !== undefined && typeof payload.color !== 'string') return false;\r\n if (\r\n payload.durationMs !== undefined &&\r\n !(\r\n typeof payload.durationMs === 'number' &&\r\n Number.isFinite(payload.durationMs) &&\r\n payload.durationMs > 0\r\n )\r\n ) {\r\n return false;\r\n }\r\n if (\r\n payload.radius !== undefined &&\r\n !(typeof payload.radius === 'number' && Number.isFinite(payload.radius) && payload.radius > 0)\r\n ) {\r\n return false;\r\n }\r\n return true;\r\n}\r\n\r\n/** Builds the presence payload for one local `PingTool` emission. */\r\nexport function toPingPresence(emission: PingEmission): PingPresence {\r\n return {\r\n kind: PING_PRESENCE_KIND,\r\n x: emission.x,\r\n y: emission.y,\r\n color: emission.color,\r\n durationMs: emission.durationMs,\r\n radius: emission.radius,\r\n };\r\n}\r\n\r\n/**\r\n * The two viewport capabilities the overlay needs; `Viewport` satisfies it.\r\n */\r\nexport interface RemotePingOverlayHost {\r\n registerOverlay(draw: OverlayRenderer): () => void;\r\n requestRender(): void;\r\n}\r\n\r\nexport interface RemotePingOverlayOptions {\r\n /** Style fallbacks when a payload omits them. */\r\n color?: string;\r\n durationMs?: number;\r\n radius?: number;\r\n /** Per-sender live-ping cap; oldest pings drop first. Default `8`. */\r\n maxPingsPerSender?: number;\r\n}\r\n\r\ninterface RemotePing {\r\n x: number;\r\n y: number;\r\n t: number;\r\n color: string;\r\n durationMs: number;\r\n radius: number;\r\n}\r\n\r\nconst DEFAULT_COLOR = '#ff3b30';\r\nconst DEFAULT_DURATION_MS = 1800;\r\nconst DEFAULT_RADIUS = 48;\r\nconst DEFAULT_MAX_PINGS = 8;\r\n\r\n/**\r\n * Renders expanding-pulse pings for remote senders through the viewport\r\n * overlay registration, independent of the viewer's active tool. Pings are\r\n * stamped with local receive time (remote clocks are never trusted),\r\n * self-expire when their animation ends, and a sender's pings disappear\r\n * immediately on `remove()` — wire that to `presence-leave`/disconnect. The\r\n * controller never touches elements, history, or persisted state, and it\r\n * never moves the viewer's camera: pings are visual only.\r\n */\r\nexport class RemotePingOverlay {\r\n private readonly host: RemotePingOverlayHost;\r\n private readonly color: string;\r\n private readonly durationMs: number;\r\n private readonly radius: number;\r\n private readonly maxPingsPerSender: number;\r\n private readonly pings = new Map<string, RemotePing[]>();\r\n private unregister: (() => void) | null;\r\n private rafId: number | null = null;\r\n private disposed = false;\r\n\r\n constructor(host: RemotePingOverlayHost, options: RemotePingOverlayOptions = {}) {\r\n this.host = host;\r\n this.color = options.color ?? DEFAULT_COLOR;\r\n this.durationMs = options.durationMs ?? DEFAULT_DURATION_MS;\r\n this.radius = options.radius ?? DEFAULT_RADIUS;\r\n this.maxPingsPerSender = options.maxPingsPerSender ?? DEFAULT_MAX_PINGS;\r\n this.unregister = host.registerOverlay((ctx) => this.renderPings(ctx));\r\n }\r\n\r\n private now(): number {\r\n return performance.now();\r\n }\r\n\r\n /**\r\n * Applies a presence payload from `sender` (any opaque per-sender key, e.g.\r\n * the envelope `from`). Non-ping or malformed payloads are ignored and\r\n * reported as `false`, so hosts can feed every presence frame through.\r\n */\r\n apply(sender: string, data: unknown): boolean {\r\n if (this.disposed || !isPingPresence(data)) return false;\r\n let senderPings = this.pings.get(sender);\r\n if (!senderPings) {\r\n senderPings = [];\r\n this.pings.set(sender, senderPings);\r\n }\r\n senderPings.push({\r\n x: data.x,\r\n y: data.y,\r\n t: this.now(),\r\n color: data.color ?? this.color,\r\n durationMs: data.durationMs ?? this.durationMs,\r\n radius: data.radius ?? this.radius,\r\n });\r\n const excess = senderPings.length - this.maxPingsPerSender;\r\n if (excess > 0) senderPings.splice(0, excess);\r\n this.ensureAnimating();\r\n this.host.requestRender();\r\n return true;\r\n }\r\n\r\n /** Removes a sender's pings immediately (presence-leave/disconnect). */\r\n remove(sender: string): void {\r\n if (this.pings.delete(sender)) this.host.requestRender();\r\n }\r\n\r\n /** Removes every ping immediately. */\r\n clear(): void {\r\n if (this.pings.size === 0) return;\r\n this.pings.clear();\r\n this.host.requestRender();\r\n }\r\n\r\n /** Number of senders with a live (unexpired) ping. */\r\n get activeSenderCount(): number {\r\n return this.pings.size;\r\n }\r\n\r\n /** Unregisters the overlay and stops the animation loop. Idempotent. */\r\n dispose(): void {\r\n if (this.disposed) return;\r\n this.disposed = true;\r\n if (this.rafId !== null) {\r\n cancelAnimationFrame(this.rafId);\r\n this.rafId = null;\r\n }\r\n this.pings.clear();\r\n this.unregister?.();\r\n this.unregister = null;\r\n }\r\n\r\n private ensureAnimating(): void {\r\n if (this.rafId === null) {\r\n this.rafId = requestAnimationFrame(() => this.tick());\r\n }\r\n }\r\n\r\n private tick(): void {\r\n if (this.disposed) return;\r\n const now = this.now();\r\n for (const [sender, senderPings] of this.pings) {\r\n const live = senderPings.filter((ping) => now - ping.t < ping.durationMs);\r\n if (live.length === 0) {\r\n this.pings.delete(sender);\r\n } else {\r\n this.pings.set(sender, live);\r\n }\r\n }\r\n this.host.requestRender();\r\n this.rafId = this.pings.size > 0 ? requestAnimationFrame(() => this.tick()) : null;\r\n }\r\n\r\n private renderPings(ctx: CanvasRenderingContext2D): void {\r\n if (this.pings.size === 0) return;\r\n const now = this.now();\r\n for (const senderPings of this.pings.values()) {\r\n for (const ping of senderPings) {\r\n renderPingPulse(ctx, ping.x, ping.y, now - ping.t, {\r\n color: ping.color,\r\n durationMs: ping.durationMs,\r\n radius: ping.radius,\r\n });\r\n }\r\n }\r\n }\r\n}\r\n","import type { Point } from '../core/types';\r\n\r\n/** Label parity contract: local tool and remote overlay must format identically. */\r\nexport function formatMeasureLabel(feet: number): string {\r\n return `${Math.round(feet)} ft`;\r\n}\r\n\r\nexport interface MeasureRenderModel {\r\n readonly start: Point;\r\n readonly end: Point;\r\n readonly feet: number;\r\n readonly color: string;\r\n}\r\n\r\n/**\r\n * Draws one measurement — dashed segment, endpoint dots, rounded-pill distance\r\n * label — in world space. Shared by `MeasureTool.renderOverlay` and\r\n * `RemoteMeasureOverlay` so local and remote rulers stay pixel-identical.\r\n */\r\nexport function drawMeasurement(\r\n ctx: CanvasRenderingContext2D,\r\n m: MeasureRenderModel,\r\n opts: { alpha?: number } = {},\r\n): void {\r\n ctx.save();\r\n if (opts.alpha !== undefined) ctx.globalAlpha = opts.alpha;\r\n\r\n ctx.strokeStyle = m.color;\r\n ctx.setLineDash([8, 4]);\r\n ctx.lineWidth = 2;\r\n ctx.beginPath();\r\n ctx.moveTo(m.start.x, m.start.y);\r\n ctx.lineTo(m.end.x, m.end.y);\r\n ctx.stroke();\r\n\r\n ctx.setLineDash([]);\r\n ctx.fillStyle = m.color;\r\n const dotRadius = 4;\r\n ctx.beginPath();\r\n ctx.arc(m.start.x, m.start.y, dotRadius, 0, Math.PI * 2);\r\n ctx.fill();\r\n ctx.beginPath();\r\n ctx.arc(m.end.x, m.end.y, dotRadius, 0, Math.PI * 2);\r\n ctx.fill();\r\n\r\n const label = formatMeasureLabel(m.feet);\r\n const midX = (m.start.x + m.end.x) / 2;\r\n const midY = (m.start.y + m.end.y) / 2;\r\n ctx.font = '14px sans-serif';\r\n const metrics = ctx.measureText(label);\r\n const padX = 6;\r\n const padY = 4;\r\n const textH = 14;\r\n\r\n ctx.fillStyle = 'rgba(0, 0, 0, 0.75)';\r\n ctx.beginPath();\r\n ctx.roundRect(\r\n midX - metrics.width / 2 - padX,\r\n midY - textH / 2 - padY,\r\n metrics.width + padX * 2,\r\n textH + padY * 2,\r\n 4,\r\n );\r\n ctx.fill();\r\n\r\n ctx.fillStyle = '#FFFFFF';\r\n ctx.textAlign = 'center';\r\n ctx.textBaseline = 'middle';\r\n ctx.fillText(label, midX, midY);\r\n\r\n ctx.restore();\r\n}\r\n","import type { Point } from '../core/types';\r\nimport type { MeasureEmission } from '../tools/measure-tool';\r\nimport type { OverlayRenderer } from './render-loop';\r\nimport { drawMeasurement } from './measure-render';\r\n\r\n/**\r\n * The wire shape of a shared-ruler presence payload. Presence data is untyped\r\n * on the wire, so hosts discriminate on `kind`; `isMeasurePresence` validates\r\n * a received payload before it reaches the overlay. Distance is\r\n * sender-authoritative: receivers render the payload's `feet`/`cells` and\r\n * never recompute from their own grid. Measurements are ephemeral by\r\n * contract: presence only — never elements, undo history, persisted canvas\r\n * state, or durable operations.\r\n */\r\nexport type MeasurePresence =\r\n | {\r\n readonly kind: 'measure';\r\n readonly start: Point;\r\n readonly end: Point;\r\n readonly cells: number;\r\n readonly feet: number;\r\n readonly color?: string;\r\n }\r\n | { readonly kind: 'measure'; readonly cleared: true };\r\n\r\nexport const MEASURE_PRESENCE_KIND = 'measure';\r\n\r\nfunction isFinitePoint(value: unknown): value is Point {\r\n if (typeof value !== 'object' || value === null) return false;\r\n const point = value as { x?: unknown; y?: unknown };\r\n return (\r\n typeof point.x === 'number' &&\r\n Number.isFinite(point.x) &&\r\n typeof point.y === 'number' &&\r\n Number.isFinite(point.y)\r\n );\r\n}\r\n\r\nexport function isMeasurePresence(data: unknown): data is MeasurePresence {\r\n if (typeof data !== 'object' || data === null) return false;\r\n const payload = data as {\r\n kind?: unknown;\r\n cleared?: unknown;\r\n start?: unknown;\r\n end?: unknown;\r\n cells?: unknown;\r\n feet?: unknown;\r\n color?: unknown;\r\n };\r\n if (payload.kind !== MEASURE_PRESENCE_KIND) return false;\r\n if ('cleared' in payload) return payload.cleared === true;\r\n if (!isFinitePoint(payload.start) || !isFinitePoint(payload.end)) return false;\r\n if (typeof payload.cells !== 'number' || !Number.isFinite(payload.cells)) return false;\r\n if (typeof payload.feet !== 'number' || !Number.isFinite(payload.feet)) return false;\r\n if (payload.color !== undefined && typeof payload.color !== 'string') return false;\r\n return true;\r\n}\r\n\r\n/** Builds the presence payload for one local `MeasureTool` emission. */\r\nexport function toMeasurePresence(emission: MeasureEmission | null): MeasurePresence {\r\n if (emission === null) return { kind: MEASURE_PRESENCE_KIND, cleared: true };\r\n return {\r\n kind: MEASURE_PRESENCE_KIND,\r\n start: emission.start,\r\n end: emission.end,\r\n cells: emission.cells,\r\n feet: emission.feet,\r\n color: emission.color,\r\n };\r\n}\r\n\r\n/** The two viewport capabilities the overlay needs; `Viewport` satisfies it. */\r\nexport interface RemoteMeasureOverlayHost {\r\n registerOverlay(draw: OverlayRenderer): () => void;\r\n requestRender(): void;\r\n}\r\n\r\nexport interface RemoteMeasureOverlayOptions {\r\n /** Style fallback when a payload omits `color`. Default `'#FF5722'`. */\r\n color?: string;\r\n /** Full-opacity hold after a cleared payload. Default `1500`. */\r\n holdMs?: number;\r\n /** Linear fade to 0 after the hold. Default `400`. */\r\n fadeMs?: number;\r\n /** Stale active entries are treated as cleared after this. Default `30000`. */\r\n maxAgeMs?: number;\r\n}\r\n\r\ninterface RemoteMeasurement {\r\n start: Point;\r\n end: Point;\r\n feet: number;\r\n color: string;\r\n /** Local receive time of the linger start; `null` while active. */\r\n clearedAt: number | null;\r\n expiryTimer: ReturnType<typeof setTimeout> | null;\r\n}\r\n\r\nconst DEFAULT_COLOR = '#FF5722';\r\nconst DEFAULT_HOLD_MS = 1500;\r\nconst DEFAULT_FADE_MS = 400;\r\nconst DEFAULT_MAX_AGE_MS = 30_000;\r\n\r\n/**\r\n * Renders remote shared-ruler measurements through the viewport overlay\r\n * registration, independent of the viewer's active tool. Entries are stamped\r\n * with local receive time (remote clocks are never trusted). A cleared\r\n * payload holds the final measurement for `holdMs`, fades over `fadeMs`, and\r\n * deletes; presence-leave (`remove`) deletes immediately. An active entry not\r\n * updated for `maxAgeMs` is expired by a timer — an idle map never renders,\r\n * so expiry cannot ride on the draw path. The overlay never touches elements,\r\n * history, or persisted state, and never moves the viewer's camera.\r\n */\r\nexport class RemoteMeasureOverlay {\r\n private readonly host: RemoteMeasureOverlayHost;\r\n private readonly color: string;\r\n private readonly holdMs: number;\r\n private readonly fadeMs: number;\r\n private readonly maxAgeMs: number;\r\n private readonly measurements = new Map<string, RemoteMeasurement>();\r\n private unregister: (() => void) | null;\r\n private rafId: number | null = null;\r\n private disposed = false;\r\n\r\n constructor(host: RemoteMeasureOverlayHost, options: RemoteMeasureOverlayOptions = {}) {\r\n this.host = host;\r\n this.color = options.color ?? DEFAULT_COLOR;\r\n this.holdMs = options.holdMs ?? DEFAULT_HOLD_MS;\r\n this.fadeMs = options.fadeMs ?? DEFAULT_FADE_MS;\r\n this.maxAgeMs = options.maxAgeMs ?? DEFAULT_MAX_AGE_MS;\r\n this.unregister = host.registerOverlay((ctx) => this.renderMeasurements(ctx));\r\n }\r\n\r\n private now(): number {\r\n return performance.now();\r\n }\r\n\r\n /**\r\n * Applies a presence payload from `sender` (any opaque per-sender key, e.g.\r\n * the envelope `from`). Non-measure or malformed payloads are ignored and\r\n * reported as `false`, so hosts can feed every presence frame through.\r\n */\r\n apply(sender: string, data: unknown): boolean {\r\n if (this.disposed || !isMeasurePresence(data)) return false;\r\n if ('cleared' in data) {\r\n this.beginLinger(sender);\r\n return true;\r\n }\r\n const existing = this.measurements.get(sender);\r\n if (existing?.expiryTimer != null) clearTimeout(existing.expiryTimer);\r\n this.measurements.set(sender, {\r\n start: data.start,\r\n end: data.end,\r\n feet: data.feet,\r\n color: data.color ?? this.color,\r\n clearedAt: null,\r\n expiryTimer: setTimeout(() => this.beginLinger(sender), this.maxAgeMs),\r\n });\r\n this.host.requestRender();\r\n return true;\r\n }\r\n\r\n /** Removes a sender's ruler immediately (presence-leave/disconnect). */\r\n remove(sender: string): void {\r\n const entry = this.measurements.get(sender);\r\n if (!entry) return;\r\n if (entry.expiryTimer != null) clearTimeout(entry.expiryTimer);\r\n this.measurements.delete(sender);\r\n this.host.requestRender();\r\n }\r\n\r\n /** Removes every ruler immediately. */\r\n clear(): void {\r\n if (this.measurements.size === 0) return;\r\n for (const entry of this.measurements.values()) {\r\n if (entry.expiryTimer != null) clearTimeout(entry.expiryTimer);\r\n }\r\n this.measurements.clear();\r\n this.host.requestRender();\r\n }\r\n\r\n /** Number of senders with a visible (active or lingering) ruler. */\r\n get activeSenderCount(): number {\r\n return this.measurements.size;\r\n }\r\n\r\n /** Unregisters the overlay, cancels timers, stops animating. Idempotent. */\r\n dispose(): void {\r\n if (this.disposed) return;\r\n this.disposed = true;\r\n if (this.rafId !== null) {\r\n cancelAnimationFrame(this.rafId);\r\n this.rafId = null;\r\n }\r\n for (const entry of this.measurements.values()) {\r\n if (entry.expiryTimer != null) clearTimeout(entry.expiryTimer);\r\n }\r\n this.measurements.clear();\r\n this.unregister?.();\r\n this.unregister = null;\r\n this.host.requestRender();\r\n }\r\n\r\n private beginLinger(sender: string): void {\r\n const entry = this.measurements.get(sender);\r\n if (!entry || entry.clearedAt !== null) return;\r\n if (entry.expiryTimer != null) {\r\n clearTimeout(entry.expiryTimer);\r\n entry.expiryTimer = null;\r\n }\r\n entry.clearedAt = this.now();\r\n this.ensureAnimating();\r\n this.host.requestRender();\r\n }\r\n\r\n private ensureAnimating(): void {\r\n if (this.rafId === null) {\r\n this.rafId = requestAnimationFrame(() => this.tick());\r\n }\r\n }\r\n\r\n private tick(): void {\r\n if (this.disposed) return;\r\n const now = this.now();\r\n let lingering = 0;\r\n for (const [sender, entry] of this.measurements) {\r\n if (entry.clearedAt === null) continue;\r\n if (now - entry.clearedAt >= this.holdMs + this.fadeMs) {\r\n this.measurements.delete(sender);\r\n } else {\r\n lingering += 1;\r\n }\r\n }\r\n this.host.requestRender();\r\n this.rafId = lingering > 0 ? requestAnimationFrame(() => this.tick()) : null;\r\n }\r\n\r\n private renderMeasurements(ctx: CanvasRenderingContext2D): void {\r\n if (this.measurements.size === 0) return;\r\n const now = this.now();\r\n for (const entry of this.measurements.values()) {\r\n let alpha = 1;\r\n if (entry.clearedAt !== null) {\r\n const fadeAge = now - entry.clearedAt - this.holdMs;\r\n if (fadeAge > 0) alpha = Math.max(0, 1 - fadeAge / this.fadeMs);\r\n }\r\n drawMeasurement(ctx, entry, { alpha });\r\n }\r\n }\r\n}\r\n","import type { Point } from '../core/types';\r\nimport type { PingEmission } from '../tools/ping-tool';\r\n\r\n/**\r\n * The one camera capability `PingInput` needs; `Camera` satisfies it. Screen\r\n * coordinates are element-local (the same space `Camera.screenToWorld`\r\n * expects).\r\n */\r\nexport interface PingInputHost {\r\n screenToWorld(screen: Point): Point;\r\n}\r\n\r\nexport interface PingInputOptions {\r\n /**\r\n * Opt-in for the long-press gesture. Off by default: a hidden hold-to-ping\r\n * gesture surprises users outside shared-canvas products, so hosts enable\r\n * it deliberately. The keyboard/programmatic paths (`pingAtPointer`,\r\n * `pingAt`) are always available. Default `false`.\r\n */\r\n longPressEnabled?: boolean;\r\n /** Hold duration before a still press pings. Default `600`. */\r\n longPressMs?: number;\r\n /** Maximum pointer travel while holding; moving further cancels. Default `8`. */\r\n slopPx?: number;\r\n /** Emission style forwarded to hosts; matches `PingTool` defaults. */\r\n color?: string;\r\n durationMs?: number;\r\n radius?: number;\r\n /**\r\n * Minimum interval between emitted pings, shared across the long-press and\r\n * keyboard/programmatic paths. Faster pings are dropped entirely. Default\r\n * `300`.\r\n */\r\n minIntervalMs?: number;\r\n /**\r\n * Host veto consulted at fire time on every path (e.g. return `false` while\r\n * a ping tool is active to avoid double pings). A veto does not consume the\r\n * rate-limit interval.\r\n */\r\n shouldPing?: () => boolean;\r\n}\r\n\r\ninterface PressState {\r\n pointerId: number;\r\n /** Element-local press position; the ping fires here, not where the pointer drifted. */\r\n x: number;\r\n y: number;\r\n timer: ReturnType<typeof setTimeout>;\r\n}\r\n\r\nconst DEFAULT_LONG_PRESS_MS = 600;\r\nconst DEFAULT_SLOP_PX = 8;\r\nconst DEFAULT_COLOR = '#ff3b30';\r\nconst DEFAULT_DURATION_MS = 1800;\r\nconst DEFAULT_RADIUS = 48;\r\nconst DEFAULT_MIN_INTERVAL_MS = 300;\r\n\r\n/**\r\n * Always-available ping input alongside the active tool: long-press-to-ping\r\n * plus keyboard/programmatic pings, independent of `PingTool`.\r\n *\r\n * `PingInput` is a passive observer by contract. Its DOM pointer listeners are\r\n * registered `passive: true` and it never calls `preventDefault`,\r\n * `stopPropagation`, or captures pointers, so the active tool, panning, and\r\n * pinch navigation behave exactly as if it were absent (with a pencil active,\r\n * a still hold pings AND the pencil still draws its dot). It also never\r\n * renders: hosts feed emissions into their own `RemotePingOverlay` under a\r\n * `'self'` sender key. Pings are ephemeral — no elements, no undo history, no\r\n * persisted state, no camera movement.\r\n *\r\n * The long-press gesture is opt-in via `longPressEnabled` (hosts whose users\r\n * would not expect hold-to-ping simply leave it off and keep the keyboard\r\n * paths). When enabled, a long-press arms on the first pointer down (mouse\r\n * primary button, touch, or pen), fires after `longPressMs` at the original\r\n * press position, and\r\n * cancels on movement past `slopPx`, a second pointer (two-finger\r\n * navigation), or pointer up/cancel/leave. Keyboard support is a capability,\r\n * not a binding: hosts call `pingAtPointer()` (last tracked hover position,\r\n * world-converted at call time) or `pingAt(world)` from their own shortcut\r\n * handling.\r\n */\r\nexport class PingInput {\r\n private readonly element: HTMLElement;\r\n private readonly host: PingInputHost;\r\n private longPressEnabled: boolean;\r\n private longPressMs: number;\r\n private slopPx: number;\r\n private color: string;\r\n private durationMs: number;\r\n private radius: number;\r\n private minIntervalMs: number;\r\n private shouldPing: (() => boolean) | undefined;\r\n\r\n private press: PressState | null = null;\r\n private readonly downPointers = new Set<number>();\r\n private lastPointerScreen: Point | null = null;\r\n private lastEmitAt = -Infinity;\r\n private disposed = false;\r\n private optionListeners = new Set<() => void>();\r\n private pingListeners = new Set<(emission: PingEmission) => void>();\r\n\r\n private readonly handlePointerDown = (e: PointerEvent): void => this.onPointerDown(e);\r\n private readonly handlePointerMove = (e: PointerEvent): void => this.onPointerMove(e);\r\n private readonly handlePointerUp = (e: PointerEvent): void => this.onPointerEnd(e);\r\n private readonly handlePointerCancel = (e: PointerEvent): void => this.onPointerEnd(e);\r\n private readonly handlePointerLeave = (e: PointerEvent): void => this.onPointerEnd(e);\r\n\r\n constructor(element: HTMLElement, host: PingInputHost, options: PingInputOptions = {}) {\r\n this.element = element;\r\n this.host = host;\r\n this.longPressEnabled = options.longPressEnabled ?? false;\r\n this.longPressMs = options.longPressMs ?? DEFAULT_LONG_PRESS_MS;\r\n this.slopPx = options.slopPx ?? DEFAULT_SLOP_PX;\r\n this.color = options.color ?? DEFAULT_COLOR;\r\n this.durationMs = options.durationMs ?? DEFAULT_DURATION_MS;\r\n this.radius = options.radius ?? DEFAULT_RADIUS;\r\n this.minIntervalMs = options.minIntervalMs ?? DEFAULT_MIN_INTERVAL_MS;\r\n this.shouldPing = options.shouldPing;\r\n\r\n const opts: AddEventListenerOptions = { passive: true };\r\n element.addEventListener('pointerdown', this.handlePointerDown, opts);\r\n element.addEventListener('pointermove', this.handlePointerMove, opts);\r\n element.addEventListener('pointerup', this.handlePointerUp, opts);\r\n element.addEventListener('pointercancel', this.handlePointerCancel, opts);\r\n element.addEventListener('pointerleave', this.handlePointerLeave, opts);\r\n }\r\n\r\n private now(): number {\r\n return performance.now();\r\n }\r\n\r\n getOptions(): PingInputOptions {\r\n return {\r\n longPressEnabled: this.longPressEnabled,\r\n longPressMs: this.longPressMs,\r\n slopPx: this.slopPx,\r\n color: this.color,\r\n durationMs: this.durationMs,\r\n radius: this.radius,\r\n minIntervalMs: this.minIntervalMs,\r\n ...(this.shouldPing ? { shouldPing: this.shouldPing } : {}),\r\n };\r\n }\r\n\r\n setOptions(options: PingInputOptions): void {\r\n if (options.longPressEnabled !== undefined) {\r\n this.longPressEnabled = options.longPressEnabled;\r\n if (!this.longPressEnabled) this.cancelPress();\r\n }\r\n if (options.longPressMs !== undefined) this.longPressMs = options.longPressMs;\r\n if (options.slopPx !== undefined) this.slopPx = options.slopPx;\r\n if (options.color !== undefined) this.color = options.color;\r\n if (options.durationMs !== undefined) this.durationMs = options.durationMs;\r\n if (options.radius !== undefined) this.radius = options.radius;\r\n if (options.minIntervalMs !== undefined) this.minIntervalMs = options.minIntervalMs;\r\n if (options.shouldPing !== undefined) this.shouldPing = options.shouldPing;\r\n for (const listener of this.optionListeners) listener();\r\n }\r\n\r\n onOptionsChange(listener: () => void): () => void {\r\n this.optionListeners.add(listener);\r\n return () => this.optionListeners.delete(listener);\r\n }\r\n\r\n /**\r\n * Subscribes to emitted pings. Listeners must not throw; a throwing\r\n * listener is isolated so it cannot break input handling or other\r\n * listeners.\r\n */\r\n onPing(listener: (emission: PingEmission) => void): () => void {\r\n this.pingListeners.add(listener);\r\n return () => this.pingListeners.delete(listener);\r\n }\r\n\r\n /**\r\n * Pings at the last tracked pointer position (hover moves and presses),\r\n * world-converted at call time. Returns `false` when no pointer has been\r\n * seen yet, the host vetoes, or the rate limit drops the ping.\r\n */\r\n pingAtPointer(): boolean {\r\n if (this.disposed || this.lastPointerScreen === null) return false;\r\n return this.emit(this.host.screenToWorld(this.lastPointerScreen));\r\n }\r\n\r\n /** Pings a world position directly. Same veto and rate limit as every path. */\r\n pingAt(world: Point): boolean {\r\n if (this.disposed) return false;\r\n return this.emit(world);\r\n }\r\n\r\n /** Removes all DOM listeners and cancels any pending press. Idempotent. */\r\n dispose(): void {\r\n if (this.disposed) return;\r\n this.disposed = true;\r\n this.cancelPress();\r\n this.downPointers.clear();\r\n this.element.removeEventListener('pointerdown', this.handlePointerDown);\r\n this.element.removeEventListener('pointermove', this.handlePointerMove);\r\n this.element.removeEventListener('pointerup', this.handlePointerUp);\r\n this.element.removeEventListener('pointercancel', this.handlePointerCancel);\r\n this.element.removeEventListener('pointerleave', this.handlePointerLeave);\r\n this.optionListeners.clear();\r\n this.pingListeners.clear();\r\n }\r\n\r\n private toLocal(e: PointerEvent): Point {\r\n const rect = this.element.getBoundingClientRect();\r\n return { x: e.clientX - rect.left, y: e.clientY - rect.top };\r\n }\r\n\r\n private onPointerDown(e: PointerEvent): void {\r\n const local = this.toLocal(e);\r\n this.lastPointerScreen = local;\r\n\r\n const hadPointers = this.downPointers.size > 0;\r\n this.downPointers.add(e.pointerId);\r\n if (hadPointers) {\r\n // A second pointer means navigation, not a press — and the new pointer\r\n // must not arm its own press while others are down.\r\n this.cancelPress();\r\n return;\r\n }\r\n if (!this.longPressEnabled) return;\r\n if (e.pointerType === 'mouse' && e.button !== 0) return;\r\n\r\n this.press = {\r\n pointerId: e.pointerId,\r\n x: local.x,\r\n y: local.y,\r\n timer: setTimeout(() => this.firePress(), this.longPressMs),\r\n };\r\n }\r\n\r\n private onPointerMove(e: PointerEvent): void {\r\n const local = this.toLocal(e);\r\n this.lastPointerScreen = local;\r\n if (this.press === null || e.pointerId !== this.press.pointerId) return;\r\n const dx = local.x - this.press.x;\r\n const dy = local.y - this.press.y;\r\n if (Math.hypot(dx, dy) > this.slopPx) this.cancelPress();\r\n }\r\n\r\n private onPointerEnd(e: PointerEvent): void {\r\n this.downPointers.delete(e.pointerId);\r\n if (this.press !== null && e.pointerId === this.press.pointerId) this.cancelPress();\r\n }\r\n\r\n private cancelPress(): void {\r\n if (this.press === null) return;\r\n clearTimeout(this.press.timer);\r\n this.press = null;\r\n }\r\n\r\n private firePress(): void {\r\n if (this.press === null) return;\r\n const screen = { x: this.press.x, y: this.press.y };\r\n this.press = null;\r\n // Convert at fire time so the ping lands where the held pointer points now.\r\n this.emit(this.host.screenToWorld(screen));\r\n }\r\n\r\n private emit(world: Point): boolean {\r\n if (this.shouldPing && !this.shouldPing()) return false;\r\n const t = this.now();\r\n if (t - this.lastEmitAt < this.minIntervalMs) return false;\r\n this.lastEmitAt = t;\r\n const emission: PingEmission = {\r\n x: world.x,\r\n y: world.y,\r\n color: this.color,\r\n durationMs: this.durationMs,\r\n radius: this.radius,\r\n };\r\n for (const listener of this.pingListeners) {\r\n try {\r\n listener(emission);\r\n } catch {\r\n // A throwing host listener must not break input handling.\r\n }\r\n }\r\n return true;\r\n }\r\n}\r\n","import type { Point } from '../core/types';\nimport type { Camera } from './camera';\n\n/**\n * A viewport-size-independent camera view: the world rectangle to frame.\n * Restored by contain-fit, so the same view frames the same world content on\n * any screen size or aspect — a DM's saved zone looks right on a phone and a\n * TV. Center+zoom would NOT have this property.\n */\nexport interface CameraView {\n x: number;\n y: number;\n w: number;\n h: number;\n}\n\nexport function assertValidView(view: CameraView): void {\n const { x, y, w, h } = view;\n if (!Number.isFinite(x) || !Number.isFinite(y) || !Number.isFinite(w) || !Number.isFinite(h)) {\n throw new Error('[fieldnotes] CameraView requires finite x, y, w, and h');\n }\n if (w <= 0 || h <= 0) {\n throw new Error('[fieldnotes] CameraView requires positive w and h');\n }\n}\n\n/**\n * Rejects dimensions that would poison the camera. Zero is NOT rejected here:\n * callers decide, because a zero-size canvas is a legitimate transient (an\n * unmounted or `display: none` host reports 0) while a negative or non-finite\n * dimension is always a bug or a poisoned measurement.\n */\nexport function assertCanvasDims(canvasW: number, canvasH: number): void {\n if (!Number.isFinite(canvasW) || !Number.isFinite(canvasH)) {\n throw new Error('[fieldnotes] canvas dimensions must be finite');\n }\n if (canvasW < 0 || canvasH < 0) {\n throw new Error('[fieldnotes] canvas dimensions must not be negative');\n }\n}\n\n/**\n * Non-throwing companion to `assertCanvasDims`, for call sites that cannot\n * throw (the per-frame animation path) and must instead resolve a zero-size\n * canvas into a clean lifecycle outcome. Zero IS accepted here — see\n * `assertCanvasDims` for why zero is a legitimate transient rather than a bug.\n */\nexport function canvasDimsUsable(canvasW: number, canvasH: number): boolean {\n return Number.isFinite(canvasW) && Number.isFinite(canvasH) && canvasW >= 0 && canvasH >= 0;\n}\n\n/** Captures the currently visible world rect. */\nexport function captureCameraView(viewport: {\n getVisibleRect(): { x: number; y: number; w: number; h: number };\n}): CameraView {\n const rect = viewport.getVisibleRect();\n return { x: rect.x, y: rect.y, w: rect.w, h: rect.h };\n}\n\n/**\n * Unclamped contain-fit zoom: the largest zoom at which the whole rect fits.\n * Contain, never crop — a view whose aspect differs from the canvas shows\n * extra world content on the short axis.\n */\nexport function fitZoomForView(view: CameraView, canvasW: number, canvasH: number): number {\n assertValidView(view);\n assertCanvasDims(canvasW, canvasH);\n if (canvasW === 0 || canvasH === 0) {\n throw new Error('[fieldnotes] fitZoomForView requires a non-zero canvas size');\n }\n return Math.min(canvasW / view.w, canvasH / view.h);\n}\n\n/** Camera origin that centers `view` on the canvas at an already-decided zoom. */\nexport function cameraOriginForView(\n view: CameraView,\n zoom: number,\n canvasW: number,\n canvasH: number,\n): Point {\n return {\n x: canvasW / 2 - (view.x + view.w / 2) * zoom,\n y: canvasH / 2 - (view.y + view.h / 2) * zoom,\n };\n}\n\n/**\n * Writes `view` to `camera`. No-ops on a zero canvas dimension (mount and\n * visibility races are legitimate); throws on an invalid view or on negative\n * or non-finite dimensions.\n */\nexport function applyCameraView(\n camera: Camera,\n view: CameraView,\n canvasW: number,\n canvasH: number,\n): void {\n assertValidView(view);\n assertCanvasDims(canvasW, canvasH);\n if (canvasW === 0 || canvasH === 0) return;\n\n camera.setZoom(fitZoomForView(view, canvasW, canvasH));\n // Read the zoom BACK: when the fit zoom exceeds the camera's private clamp,\n // centering must use the value the camera accepted or the view lands\n // off-center. `Camera.moveTo` takes two numbers, not a Point.\n const origin = cameraOriginForView(view, camera.zoom, canvasW, canvasH);\n camera.moveTo(origin.x, origin.y);\n}\n","import type { Camera } from './camera';\nimport {\n applyCameraView,\n assertCanvasDims,\n assertValidView,\n canvasDimsUsable,\n type CameraView,\n} from './camera-view';\n\n/** A scheduler and its matching canceller. Inseparable by construction. */\nexport interface FrameScheduler {\n requestFrame: (cb: () => void) => number;\n cancelFrame: (id: number) => void;\n}\n\nexport interface CameraAnimatorOptions {\n /** REQUIRED. `element` is used for input listeners only, never measurement. */\n getCanvasSize: () => { w: number; h: number };\n durationMs?: number;\n easing?: (t: number) => number;\n interactive?: boolean;\n frames?: FrameScheduler;\n now?: () => number;\n}\n\nexport type CameraAnimationEndReason = 'complete' | 'cancelled' | 'superseded';\n\nconst DEFAULT_DURATION_MS = 400;\nconst FRAMED_EPSILON = 1e-6;\n\nconst easeOutCubic = (t: number): number => 1 - Math.pow(1 - t, 3);\n\nfunction lerp(a: number, b: number, k: number): number {\n return a + (b - a) * k;\n}\n\nfunction lerpView(from: CameraView, to: CameraView, k: number): CameraView {\n return {\n x: lerp(from.x, to.x, k),\n y: lerp(from.y, to.y, k),\n w: lerp(from.w, to.w, k),\n h: lerp(from.h, to.h, k),\n };\n}\n\nfunction viewsClose(a: CameraView, b: CameraView): boolean {\n return (\n Math.abs(a.x - b.x) < FRAMED_EPSILON &&\n Math.abs(a.y - b.y) < FRAMED_EPSILON &&\n Math.abs(a.w - b.w) < FRAMED_EPSILON &&\n Math.abs(a.h - b.h) < FRAMED_EPSILON\n );\n}\n\n/**\n * Animates a camera to a `CameraView`. Standalone controller in the\n * `PingInput`/`MinimapController` shape: the host owns construction and\n * disposal, and every timing dependency is injectable for deterministic tests.\n */\nexport class CameraAnimator {\n private readonly camera: Camera;\n private readonly getCanvasSize: () => { w: number; h: number };\n private readonly frames: FrameScheduler;\n private readonly now: () => number;\n private readonly durationMs: number;\n private readonly easing: (t: number) => number;\n\n private rafId: number | null = null;\n private from: CameraView | null = null;\n private to: CameraView | null = null;\n private startedAt = 0;\n private endListeners = new Set<(reason: CameraAnimationEndReason) => void>();\n /**\n * Monotonic operation counter. `animateTo`/`jumpTo` claim a generation\n * before emitting 'superseded'; if an onEnd listener starts a newer\n * operation during that emit, the outer call sees a bumped counter and\n * bails instead of overwriting the nested animation's state. Without this,\n * the nested animation would run to completion having never reported an end\n * reason, breaking the exactly-one guarantee the spec makes.\n */\n private generation = 0;\n\n private lastWrite: { x: number; y: number; zoom: number } | null = null;\n private disposed = false;\n private detachListeners: (() => void) | null = null;\n\n constructor(element: HTMLElement, camera: Camera, options: CameraAnimatorOptions) {\n if (options.frames !== undefined) {\n const { requestFrame, cancelFrame } = options.frames;\n if (typeof requestFrame !== 'function' || typeof cancelFrame !== 'function') {\n throw new Error(\n '[fieldnotes] CameraAnimator: `frames` must supply both requestFrame and cancelFrame',\n );\n }\n }\n this.camera = camera;\n this.getCanvasSize = options.getCanvasSize;\n this.frames = options.frames ?? {\n requestFrame: (cb) => requestAnimationFrame(cb),\n cancelFrame: (id) => cancelAnimationFrame(id),\n };\n this.now = options.now ?? (() => performance.now());\n this.durationMs = options.durationMs ?? DEFAULT_DURATION_MS;\n this.easing = options.easing ?? easeOutCubic;\n\n if (options.interactive ?? true) {\n const onUserInput = (): void => {\n this.end('cancelled');\n };\n const types = ['pointerdown', 'wheel', 'keydown'] as const;\n for (const type of types) {\n element.addEventListener(type, onUserInput, { passive: true });\n }\n this.detachListeners = () => {\n for (const type of types) {\n element.removeEventListener(type, onUserInput);\n }\n };\n }\n }\n\n get animating(): boolean {\n return this.to !== null;\n }\n\n onEnd(listener: (reason: CameraAnimationEndReason) => void): () => void {\n this.endListeners.add(listener);\n return () => this.endListeners.delete(listener);\n }\n\n animateTo(view: CameraView): void {\n const size = this.validateAndMeasure(view);\n if (size === null) return;\n\n const current = this.camera.getVisibleRect(size.w, size.h);\n const generation = ++this.generation;\n this.end('superseded');\n // An onEnd listener may have started a newer operation during that\n // 'superseded' emit. It now owns the animator; overwriting its state here\n // would leave it running with no end reason ever reported.\n if (this.generation !== generation) return;\n\n if (viewsClose(current, view)) {\n applyCameraView(this.camera, view, size.w, size.h);\n this.emit('complete');\n return;\n }\n\n this.from = current;\n this.to = view;\n this.startedAt = this.now();\n this.lastWrite = null;\n this.rafId = this.frames.requestFrame(this.step);\n }\n\n jumpTo(view: CameraView): void {\n const size = this.validateAndMeasure(view);\n if (size === null) return;\n const generation = ++this.generation;\n this.end('superseded');\n if (this.generation !== generation) return; // nested operation owns us now\n applyCameraView(this.camera, view, size.w, size.h);\n this.lastWrite = null;\n }\n\n cancel(): void {\n if (this.disposed) return;\n this.end('cancelled');\n }\n\n /**\n * Terminal. Order is load-bearing: the flag is set BEFORE any listener runs,\n * because an onEnd listener can call animateTo during the disposal callback.\n * With the flag set last, that call would start a real animation which the\n * listener clear then silently discards — a second animation with no end\n * reason, breaking the exactly-one guarantee.\n */\n dispose(): void {\n if (this.disposed) return;\n this.disposed = true;\n // Bump the generation so an animateTo/jumpTo call whose 'superseded' emit\n // reached this dispose() (nested inside its own emit) sees its claimed\n // generation go stale, just like nested animateTo/jumpTo re-entrancy. Without\n // this, the outer call's generation guard passes and it writes state (or\n // schedules a frame) onto a disposed animator.\n this.generation++;\n\n const wasAnimating = this.to !== null;\n this.clearFrame();\n this.from = null;\n this.to = null;\n this.lastWrite = null;\n\n if (wasAnimating) this.emit('cancelled');\n\n this.endListeners.clear();\n this.detachListeners?.();\n this.detachListeners = null;\n }\n\n /**\n * Steps 1-3 of the public-call contract. Returns null when the caller must\n * stop, having already handled termination.\n *\n * The disposed check precedes validation deliberately: ordering it after\n * would make `disposed.animateTo(invalidView)` both required to throw and\n * required to stay silent. Disposal wins — a terminal animator is inert for\n * every input, and post-disposal calls are exactly the racy teardown paths\n * where a throw is least useful.\n */\n private validateAndMeasure(view: CameraView): { w: number; h: number } | null {\n if (this.disposed) return null;\n assertValidView(view);\n const size = this.getCanvasSize();\n // Validate the MEASUREMENT too, not just the target. A negative or\n // non-finite dimension would otherwise reach camera.getVisibleRect()\n // before applyCameraView could reject it, and NaN propagates through\n // Camera.setZoom's Math.min/Math.max clamp to poison the camera\n // permanently. Throws synchronously here, where the caller can catch it.\n assertCanvasDims(size.w, size.h);\n if (size.w === 0 || size.h === 0) {\n // A valid target meeting a zero size cancels any running animation\n // synchronously within this call, so `animating` is false the instant it\n // returns. 'cancelled', never 'superseded': the animation was ended by\n // the host becoming unmeasurable, not replaced by a running successor.\n this.end('cancelled');\n return null;\n }\n return size;\n }\n\n private step = (): void => {\n if (this.disposed || this.to === null || this.from === null) return;\n\n // Foreign-write guard: if the camera no longer matches what this animator\n // last wrote, another writer moved it — drag, pinch, wheel, keyboard zoom,\n // a PanInertia coast frame, a minimap tap, fitToContent, or loadState.\n if (this.foreignWrite()) {\n this.end('cancelled');\n return;\n }\n\n const size = this.getCanvasSize();\n if (!canvasDimsUsable(size.w, size.h)) {\n // A poisoned measurement mid-flight TERMINATES rather than throws.\n // Throwing from inside a frame callback has no catcher and would strand\n // the animation state with its lifecycle unresolved — the exact orphan\n // this contract exists to prevent. Public calls still throw, because\n // there a caller can handle it.\n this.end('cancelled');\n return;\n }\n if (size.w === 0 || size.h === 0) {\n // The clock keeps advancing while a host is hidden, so without this the\n // animation would reach t=1, write nothing, and report a false 'complete'.\n this.end('cancelled');\n return;\n }\n\n const elapsed = this.now() - this.startedAt;\n const t = this.durationMs <= 0 ? 1 : Math.min(1, elapsed / this.durationMs);\n const view = lerpView(this.from, this.to, this.easing(t));\n applyCameraView(this.camera, view, size.w, size.h);\n this.recordWrite();\n\n if (t >= 1) {\n this.end('complete');\n return;\n }\n this.rafId = this.frames.requestFrame(this.step);\n };\n\n private recordWrite(): void {\n this.lastWrite = {\n x: this.camera.position.x,\n y: this.camera.position.y,\n zoom: this.camera.zoom,\n };\n }\n\n private foreignWrite(): boolean {\n if (this.lastWrite === null) return false;\n const eps = 1e-6;\n return (\n Math.abs(this.camera.position.x - this.lastWrite.x) > eps ||\n Math.abs(this.camera.position.y - this.lastWrite.y) > eps ||\n Math.abs(this.camera.zoom - this.lastWrite.zoom) > eps\n );\n }\n\n /** Terminates an in-flight animation with `reason`. No-op when idle. */\n private end(reason: CameraAnimationEndReason): void {\n if (this.disposed || this.to === null) return;\n this.clearFrame();\n this.from = null;\n this.to = null;\n this.lastWrite = null;\n this.emit(reason);\n }\n\n private clearFrame(): void {\n if (this.rafId !== null) {\n this.frames.cancelFrame(this.rafId);\n this.rafId = null;\n }\n }\n\n private emit(reason: CameraAnimationEndReason): void {\n for (const listener of [...this.endListeners]) {\n try {\n listener(reason);\n } catch {\n // Listener faults must never wedge the animator.\n }\n }\n }\n}\n","import type { CameraView } from './camera-view';\n\n/**\n * The wire shape of a focus-request presence payload. Focus is ephemeral by\n * contract: presence frames only — never elements, undo history, persisted\n * canvas state, or durable operations. A frame that arrives while a client is\n * offline is dropped, never queued, and late joiners are never retro-focused.\n *\n * `audience` is a delivery hint, NOT a security boundary: the relay broadcasts\n * presence room-wide and receivers filter by their own role. The payload is a\n * map rectangle, not secret data; hidden elements stay behind relay `canRead`.\n */\nexport interface FocusPresence {\n readonly kind: 'focus';\n readonly x: number;\n readonly y: number;\n readonly w: number;\n readonly h: number;\n readonly audience: FocusAudience;\n readonly color?: string;\n}\n\nexport type FocusAudience = 'all' | 'players' | 'display';\n\nexport const FOCUS_PRESENCE_KIND = 'focus';\n\nconst AUDIENCES: readonly FocusAudience[] = ['all', 'players', 'display'];\n\nfunction isPositiveFinite(value: unknown): value is number {\n return typeof value === 'number' && Number.isFinite(value) && value > 0;\n}\n\nfunction isFiniteNumber(value: unknown): value is number {\n return typeof value === 'number' && Number.isFinite(value);\n}\n\n/**\n * The only trust boundary between untyped wire data and the canvas. Mirrors\n * `isPingPresence`: every field is validated, and `color` is rejected when\n * defined but not a string, because it flows into canvas styling.\n *\n * These rules deliberately match `CameraView` validation, so a payload that\n * passes here can never make the animator's synchronous target validation\n * throw on the receive path.\n */\nexport function isFocusPresence(data: unknown): data is FocusPresence {\n if (typeof data !== 'object' || data === null) return false;\n const payload = data as {\n kind?: unknown;\n x?: unknown;\n y?: unknown;\n w?: unknown;\n h?: unknown;\n audience?: unknown;\n color?: unknown;\n };\n if (payload.kind !== FOCUS_PRESENCE_KIND) return false;\n if (!isFiniteNumber(payload.x) || !isFiniteNumber(payload.y)) return false;\n if (!isPositiveFinite(payload.w) || !isPositiveFinite(payload.h)) return false;\n if (typeof payload.audience !== 'string' || !AUDIENCES.some((a) => a === payload.audience)) {\n return false;\n }\n if (payload.color !== undefined && typeof payload.color !== 'string') return false;\n return true;\n}\n\n/** Builds the presence payload for one local focus request. */\nexport function toFocusPresence(\n view: CameraView,\n audience: FocusAudience,\n color?: string,\n): FocusPresence {\n return {\n kind: FOCUS_PRESENCE_KIND,\n x: view.x,\n y: view.y,\n w: view.w,\n h: view.h,\n audience,\n ...(color === undefined ? {} : { color }),\n };\n}\n","import type { CameraAnimator } from './camera-animator';\nimport { isFocusPresence, type FocusAudience } from './focus-presence';\nimport { RemotePingOverlay, type RemotePingOverlayHost } from './remote-ping-overlay';\n\nexport type FocusRole = 'dm' | 'player' | 'display';\n\n/** The two viewport capabilities the receiver needs; `Viewport` satisfies it. */\nexport type RemoteFocusReceiverHost = RemotePingOverlayHost;\n\nexport interface RemoteFocusReceiverOptions {\n role: FocusRole;\n animator: CameraAnimator;\n /** Draw an arrival pulse at the focus target. Default `true`. */\n pulse?: boolean;\n pulseColor?: string;\n pulseDurationMs?: number;\n pulseRadius?: number;\n /** Animate the camera (default) or jump instantly. */\n animate?: boolean;\n}\n\nfunction audienceIncludes(audience: FocusAudience, role: FocusRole): boolean {\n if (role === 'dm') return false; // a DM device is never moved by a focus frame\n if (audience === 'all') return true;\n if (audience === 'players') return role === 'player';\n return role === 'display';\n}\n\n/**\n * Applies remote focus requests addressed to this client's role: moves the\n * camera and marks the target with one pulse.\n *\n * The pulse is DELEGATED to a private `RemotePingOverlay` rather than\n * reimplemented. `renderPingPulse` draws a single frame from an elapsed time,\n * so an animated pulse needs a rAF loop that re-requests renders, expires the\n * pulse, and cancels on disposal — machinery that already exists and is tested\n * there. `maxPingsPerSender: 1` makes a rapid second focus REPLACE the older\n * pulse instead of leaving two competing markers; different senders keep\n * separate keys and coexist, which is correct when two DMs share a table.\n */\nexport class RemoteFocusReceiver {\n private readonly role: FocusRole;\n private readonly animator: CameraAnimator;\n private readonly animate: boolean;\n private readonly pulseColor: string | undefined;\n private readonly overlay: RemotePingOverlay | null;\n private disposed = false;\n\n constructor(host: RemoteFocusReceiverHost, options: RemoteFocusReceiverOptions) {\n this.role = options.role;\n this.animator = options.animator;\n this.animate = options.animate ?? true;\n this.pulseColor = options.pulseColor;\n this.overlay =\n (options.pulse ?? true)\n ? new RemotePingOverlay(host, {\n ...(options.pulseColor === undefined ? {} : { color: options.pulseColor }),\n ...(options.pulseDurationMs === undefined\n ? {}\n : { durationMs: options.pulseDurationMs }),\n ...(options.pulseRadius === undefined ? {} : { radius: options.pulseRadius }),\n maxPingsPerSender: 1,\n })\n : null;\n }\n\n /**\n * Applies a presence payload from `sender`. Returns `false` for payloads\n * that are not focus frames, or are addressed to a different role, so hosts\n * can feed every presence frame through without disturbing other handlers.\n */\n apply(from: string, data: unknown): boolean {\n if (this.disposed || !isFocusPresence(data)) return false;\n if (!audienceIncludes(data.audience, this.role)) return false;\n\n const view = { x: data.x, y: data.y, w: data.w, h: data.h };\n // `isFocusPresence` enforces the same rules as CameraView validation, so\n // wire data cannot make the animator's synchronous validation throw here.\n if (this.animate) {\n this.animator.animateTo(view);\n } else {\n this.animator.jumpTo(view);\n }\n\n this.overlay?.apply(from, {\n kind: 'ping',\n x: view.x + view.w / 2,\n y: view.y + view.h / 2,\n color: data.color ?? this.pulseColor,\n });\n return true;\n }\n\n /** Idempotent. Does NOT dispose the animator — the host owns that. */\n dispose(): void {\n if (this.disposed) return;\n this.disposed = true;\n this.overlay?.dispose();\n }\n}\n","import type { Tool, ToolContext, PointerState } from './types';\n\nexport class HandTool implements Tool {\n readonly name = 'hand';\n private panning = false;\n private lastScreen = { x: 0, y: 0 };\n\n onActivate(ctx: ToolContext): void {\n ctx.setCursor?.('grab');\n }\n\n onDeactivate(ctx: ToolContext): void {\n ctx.setCursor?.('default');\n }\n\n onPointerDown(state: PointerState, ctx: ToolContext): void {\n this.panning = true;\n this.lastScreen = { x: state.x, y: state.y };\n ctx.setCursor?.('grabbing');\n }\n\n onPointerMove(state: PointerState, ctx: ToolContext): void {\n if (!this.panning) return;\n const dx = state.x - this.lastScreen.x;\n const dy = state.y - this.lastScreen.y;\n this.lastScreen = { x: state.x, y: state.y };\n ctx.camera.pan(dx, dy);\n }\n\n onPointerUp(_state: PointerState, ctx: ToolContext): void {\n this.panning = false;\n ctx.setCursor?.('grab');\n }\n}\n","import type { StrokePoint } from '../core/types';\r\nimport type { Tool, ToolContext, PointerState } from './types';\r\nimport { createStroke } from '../elements/element-factory';\r\nimport { simplifyPoints, smoothToSegments, pressureToWidth } from '../elements/stroke-smoothing';\r\nimport { computeStrokeSegments } from '../elements/stroke-cache';\r\n\r\nexport interface PencilToolOptions {\r\n name?: string;\r\n color?: string;\r\n width?: number;\r\n smoothing?: number;\r\n minPointDistance?: number;\r\n progressiveSimplifyThreshold?: number;\r\n opacity?: number;\r\n blendMode?: 'multiply';\r\n}\r\n\r\nconst MIN_POINTS_FOR_STROKE = 2;\r\nconst DEFAULT_SMOOTHING = 1.5;\r\nconst DEFAULT_PRESSURE = 0.5;\r\nconst DEFAULT_MIN_POINT_DISTANCE = 3;\r\nconst DEFAULT_PROGRESSIVE_THRESHOLD = 200;\r\nconst PROGRESSIVE_HOT_ZONE = 30;\r\n\r\nexport class PencilTool implements Tool {\r\n readonly name: string;\r\n private drawing = false;\r\n private points: StrokePoint[] = [];\r\n private color: string;\r\n private width: number;\r\n private smoothing: number;\r\n private minPointDistance: number;\r\n private progressiveThreshold: number;\r\n private nextSimplifyAt: number;\r\n private opacity: number;\r\n private blendMode: 'multiply' | undefined;\r\n private optionListeners = new Set<() => void>();\r\n\r\n constructor(options: PencilToolOptions = {}) {\r\n this.name = options.name ?? 'pencil';\r\n this.color = options.color ?? '#000000';\r\n this.width = options.width ?? 2;\r\n this.smoothing = options.smoothing ?? DEFAULT_SMOOTHING;\r\n this.minPointDistance = options.minPointDistance ?? DEFAULT_MIN_POINT_DISTANCE;\r\n this.progressiveThreshold =\r\n options.progressiveSimplifyThreshold ?? DEFAULT_PROGRESSIVE_THRESHOLD;\r\n this.nextSimplifyAt = this.progressiveThreshold;\r\n this.opacity = options.opacity ?? 1;\r\n this.blendMode = options.blendMode;\r\n }\r\n\r\n onActivate(ctx: ToolContext): void {\r\n ctx.setCursor?.('crosshair');\r\n }\r\n\r\n onDeactivate(ctx: ToolContext): void {\r\n ctx.setCursor?.('default');\r\n }\r\n\r\n getOptions(): PencilToolOptions {\r\n return {\r\n color: this.color,\r\n width: this.width,\r\n smoothing: this.smoothing,\r\n minPointDistance: this.minPointDistance,\r\n progressiveSimplifyThreshold: this.progressiveThreshold,\r\n opacity: this.opacity,\r\n blendMode: this.blendMode,\r\n };\r\n }\r\n\r\n onOptionsChange(listener: () => void): () => void {\r\n this.optionListeners.add(listener);\r\n return () => this.optionListeners.delete(listener);\r\n }\r\n\r\n setOptions(options: PencilToolOptions): void {\r\n if (options.color !== undefined) this.color = options.color;\r\n if (options.width !== undefined) this.width = options.width;\r\n if (options.smoothing !== undefined) this.smoothing = options.smoothing;\r\n if (options.minPointDistance !== undefined) this.minPointDistance = options.minPointDistance;\r\n if (options.progressiveSimplifyThreshold !== undefined)\r\n this.progressiveThreshold = options.progressiveSimplifyThreshold;\r\n if (options.opacity !== undefined) this.opacity = options.opacity;\r\n if (options.blendMode !== undefined) this.blendMode = options.blendMode;\r\n this.notifyOptionsChange();\r\n }\r\n\r\n onPointerDown(state: PointerState, ctx: ToolContext): void {\r\n this.drawing = true;\r\n const world = ctx.camera.screenToWorld({ x: state.x, y: state.y });\r\n const pressure = state.pressure === 0 ? DEFAULT_PRESSURE : state.pressure;\r\n this.points = [{ x: world.x, y: world.y, pressure }];\r\n this.nextSimplifyAt = this.progressiveThreshold;\r\n }\r\n\r\n onPointerMove(state: PointerState, ctx: ToolContext): void {\r\n if (!this.drawing) return;\r\n const world = ctx.camera.screenToWorld({ x: state.x, y: state.y });\r\n const pressure = state.pressure === 0 ? DEFAULT_PRESSURE : state.pressure;\r\n\r\n const last = this.points[this.points.length - 1];\r\n if (last) {\r\n const dx = world.x - last.x;\r\n const dy = world.y - last.y;\r\n if (dx * dx + dy * dy < this.minPointDistance * this.minPointDistance) return;\r\n }\r\n\r\n this.points.push({ x: world.x, y: world.y, pressure });\r\n\r\n // Progressively simplify the cold zone to bound memory on very long strokes.\r\n // nextSimplifyAt doubles after each pass to avoid compounding data loss.\r\n if (this.points.length > this.nextSimplifyAt) {\r\n const hotZone = this.points.slice(-PROGRESSIVE_HOT_ZONE);\r\n const coldZone = this.points.slice(0, -PROGRESSIVE_HOT_ZONE);\r\n const simplified = simplifyPoints(coldZone, this.smoothing * 2);\r\n this.points = [...simplified, ...hotZone];\r\n this.nextSimplifyAt = this.points.length + this.progressiveThreshold;\r\n }\r\n\r\n ctx.requestRender();\r\n }\r\n\r\n onPointerUp(_state: PointerState, ctx: ToolContext): void {\r\n if (!this.drawing) return;\r\n this.drawing = false;\r\n\r\n if (this.points.length < MIN_POINTS_FOR_STROKE) {\r\n this.points = [];\r\n return;\r\n }\r\n\r\n const simplified = simplifyPoints(this.points, this.smoothing);\r\n const stroke = createStroke({\r\n points: simplified,\r\n color: this.color,\r\n width: this.width,\r\n layerId: ctx.activeLayerId ?? '',\r\n opacity: this.opacity,\r\n blendMode: this.blendMode,\r\n });\r\n ctx.store.add(stroke);\r\n computeStrokeSegments(stroke);\r\n this.points = [];\r\n ctx.requestRender();\r\n }\r\n\r\n private notifyOptionsChange(): void {\r\n for (const listener of this.optionListeners) listener();\r\n }\r\n\r\n renderOverlay(ctx: CanvasRenderingContext2D): void {\r\n if (!this.drawing || this.points.length < 2) return;\r\n\r\n ctx.save();\r\n ctx.strokeStyle = this.color;\r\n ctx.lineCap = 'round';\r\n ctx.lineJoin = 'round';\r\n // Preview a highlighter at its real opacity + blend so it doesn't snap on commit;\r\n // a normal pencil keeps the lighter 0.8 in-progress affordance.\r\n ctx.globalAlpha = this.blendMode ? this.opacity : 0.8;\r\n if (this.blendMode) ctx.globalCompositeOperation = this.blendMode;\r\n\r\n const segments = smoothToSegments(this.points);\r\n for (const seg of segments) {\r\n const w =\r\n (pressureToWidth(seg.start.pressure, this.width) +\r\n pressureToWidth(seg.end.pressure, this.width)) /\r\n 2;\r\n ctx.lineWidth = w;\r\n ctx.beginPath();\r\n ctx.moveTo(seg.start.x, seg.start.y);\r\n ctx.bezierCurveTo(seg.cp1.x, seg.cp1.y, seg.cp2.x, seg.cp2.y, seg.end.x, seg.end.y);\r\n ctx.stroke();\r\n }\r\n\r\n ctx.restore();\r\n }\r\n}\r\n","import type { Point } from '../core/types';\r\nimport type { StrokeElement } from './types';\r\nimport { getElementBounds } from './element-bounds';\r\nimport { getStrokeRenderData } from './stroke-cache';\r\nimport { distSqToSegment } from '../core/geometry';\r\n\r\nexport function hitTestStroke(stroke: StrokeElement, point: Point, radius: number): boolean {\r\n const bounds = getElementBounds(stroke);\r\n if (!bounds) return false;\r\n if (\r\n point.x < bounds.x - radius ||\r\n point.x > bounds.x + bounds.w + radius ||\r\n point.y < bounds.y - radius ||\r\n point.y > bounds.y + bounds.h + radius\r\n ) {\r\n return false;\r\n }\r\n\r\n const radiusSq = radius * radius;\r\n const local: Point = { x: point.x - stroke.position.x, y: point.y - stroke.position.y };\r\n const { segments } = getStrokeRenderData(stroke);\r\n\r\n if (segments.length === 0) {\r\n const p = stroke.points[0];\r\n if (!p) return false;\r\n const dx = p.x - local.x;\r\n const dy = p.y - local.y;\r\n return dx * dx + dy * dy <= radiusSq;\r\n }\r\n\r\n for (const seg of segments) {\r\n if (distSqToSegment(local, seg.start, seg.end) <= radiusSq) return true;\r\n }\r\n return false;\r\n}\r\n","import type { Point, StrokePoint } from '../core/types';\r\n\r\nfunction lerp(a: StrokePoint, b: StrokePoint, t: number): StrokePoint {\r\n return {\r\n x: a.x + (b.x - a.x) * t,\r\n y: a.y + (b.y - a.y) * t,\r\n pressure: a.pressure + (b.pressure - a.pressure) * t,\r\n };\r\n}\r\n\r\n/**\r\n * Split a stroke's points by an eraser circle (all in the stroke's local space).\r\n * Returns surviving runs (each ≥2 points), `[]` if fully erased, or `null` if nothing\r\n * was within the radius (no change).\r\n */\r\nexport function erasePoints(\r\n points: StrokePoint[],\r\n eraser: Point,\r\n radius: number,\r\n): StrokePoint[][] | null {\r\n const r2 = radius * radius;\r\n\r\n if (points.length < 2) {\r\n const p = points[0];\r\n if (p && (p.x - eraser.x) ** 2 + (p.y - eraser.y) ** 2 <= r2) return [];\r\n return null;\r\n }\r\n\r\n const runs: StrokePoint[][] = [];\r\n let current: StrokePoint[] = [];\r\n let erased = false;\r\n\r\n const flush = (): void => {\r\n if (current.length >= 2) runs.push(current);\r\n current = [];\r\n };\r\n\r\n for (let i = 0; i < points.length - 1; i++) {\r\n const a = points[i];\r\n const b = points[i + 1];\r\n if (!a || !b) continue;\r\n\r\n const dx = b.x - a.x;\r\n const dy = b.y - a.y;\r\n const fx = a.x - eraser.x;\r\n const fy = a.y - eraser.y;\r\n const A = dx * dx + dy * dy;\r\n const B = 2 * (fx * dx + fy * dy);\r\n const C = fx * fx + fy * fy - r2;\r\n\r\n let tLo = 1;\r\n let tHi = 0;\r\n if (A === 0) {\r\n if (C <= 0) {\r\n tLo = 0;\r\n tHi = 1;\r\n }\r\n } else {\r\n const disc = B * B - 4 * A * C;\r\n if (disc >= 0) {\r\n const sq = Math.sqrt(disc);\r\n const lo = Math.max(0, (-B - sq) / (2 * A));\r\n const hi = Math.min(1, (-B + sq) / (2 * A));\r\n // Strict `<`: a tangent graze (lo === hi, zero-width overlap) is not an erase —\r\n // it would otherwise split a stroke in two at a single duplicated point.\r\n if (lo < hi) {\r\n tLo = lo;\r\n tHi = hi;\r\n }\r\n }\r\n }\r\n\r\n if (tLo > tHi) {\r\n if (current.length === 0) current.push(a);\r\n current.push(b);\r\n continue;\r\n }\r\n\r\n erased = true;\r\n if (tLo > 0) {\r\n if (current.length === 0) current.push(a);\r\n current.push(lerp(a, b, tLo));\r\n flush();\r\n } else {\r\n flush();\r\n }\r\n if (tHi < 1) {\r\n current = [lerp(a, b, tHi), b];\r\n }\r\n }\r\n\r\n flush();\r\n return erased ? runs : null;\r\n}\r\n","import type { Bounds, Point } from '../core/types';\r\nimport type { Tool, ToolContext, PointerState } from './types';\r\nimport type { StrokeElement } from '../elements/types';\r\nimport { hitTestStroke } from '../elements/stroke-hit';\r\nimport { createStroke } from '../elements/element-factory';\r\nimport { erasePoints } from '../elements/stroke-erase';\r\n\r\nexport interface EraserToolOptions {\r\n /** Eraser radius in SCREEN pixels (matches the cursor circle; converted to world units per zoom). */\r\n radius?: number;\r\n mode?: 'partial' | 'stroke';\r\n}\r\n\r\nconst DEFAULT_RADIUS = 20;\r\n\r\nfunction makeEraserCursor(radius: number): string {\r\n const size = radius * 2;\r\n const svg = `<svg xmlns='http://www.w3.org/2000/svg' width='${size}' height='${size}'><circle cx='${radius}' cy='${radius}' r='${radius - 1}' fill='none' stroke='%23666' stroke-width='1.5'/></svg>`;\r\n return `url(\"data:image/svg+xml,${svg}\") ${radius} ${radius}, crosshair`;\r\n}\r\n\r\nexport class EraserTool implements Tool {\r\n readonly name = 'eraser';\r\n private erasing = false;\r\n private radius: number;\r\n private cursor: string;\r\n private mode: 'partial' | 'stroke';\r\n\r\n constructor(options: EraserToolOptions = {}) {\r\n this.radius = options.radius ?? DEFAULT_RADIUS;\r\n this.cursor = makeEraserCursor(this.radius);\r\n this.mode = options.mode ?? 'partial';\r\n }\r\n\r\n getOptions(): EraserToolOptions {\r\n return { radius: this.radius, mode: this.mode };\r\n }\r\n\r\n setOptions(options: EraserToolOptions): void {\r\n if (options.mode !== undefined) this.mode = options.mode;\r\n if (options.radius !== undefined) {\r\n this.radius = options.radius;\r\n this.cursor = makeEraserCursor(this.radius); // applied on next activate\r\n }\r\n }\r\n\r\n onActivate(ctx: ToolContext): void {\r\n ctx.setCursor?.(this.cursor);\r\n }\r\n\r\n onDeactivate(ctx: ToolContext): void {\r\n ctx.setCursor?.('default');\r\n }\r\n\r\n onPointerDown(state: PointerState, ctx: ToolContext): void {\r\n this.erasing = true;\r\n this.eraseAt(state, ctx);\r\n }\r\n\r\n onPointerMove(state: PointerState, ctx: ToolContext): void {\r\n if (!this.erasing) return;\r\n this.eraseAt(state, ctx);\r\n }\r\n\r\n onPointerUp(_state: PointerState, _ctx: ToolContext): void {\r\n this.erasing = false;\r\n }\r\n\r\n private eraseAt(state: PointerState, ctx: ToolContext): void {\r\n const world = ctx.camera.screenToWorld({ x: state.x, y: state.y });\r\n const worldRadius = this.radius / ctx.camera.zoom;\r\n const queryBounds: Bounds = {\r\n x: world.x - worldRadius,\r\n y: world.y - worldRadius,\r\n w: worldRadius * 2,\r\n h: worldRadius * 2,\r\n };\r\n const candidates = ctx.store.queryRect(queryBounds);\r\n let erased = false;\r\n\r\n for (const el of candidates) {\r\n if (el.type !== 'stroke') continue;\r\n if (ctx.isLayerVisible && !ctx.isLayerVisible(el.layerId)) continue;\r\n if (ctx.isLayerLocked && ctx.isLayerLocked(el.layerId)) continue;\r\n if (!this.strokeIntersects(el, world, worldRadius)) continue;\r\n if (this.mode === 'stroke') {\r\n ctx.store.remove(el.id);\r\n erased = true;\r\n continue;\r\n }\r\n const localEraser = { x: world.x - el.position.x, y: world.y - el.position.y };\r\n const runs = erasePoints(el.points, localEraser, worldRadius);\r\n if (runs === null) continue;\r\n ctx.store.remove(el.id);\r\n for (const run of runs) {\r\n ctx.store.add(\r\n createStroke({\r\n points: run,\r\n color: el.color,\r\n width: el.width,\r\n opacity: el.opacity,\r\n layerId: el.layerId,\r\n zIndex: el.zIndex,\r\n position: el.position,\r\n }),\r\n );\r\n }\r\n erased = true;\r\n }\r\n\r\n if (erased) ctx.requestRender();\r\n }\r\n\r\n private strokeIntersects(stroke: StrokeElement, point: Point, worldRadius: number): boolean {\r\n return hitTestStroke(stroke, point, worldRadius);\r\n }\r\n}\r\n","import type { CanvasElement } from './types';\r\n\r\n/** Expand a selection to include every co-member of any group it touches. Returns `ids`\r\n * unchanged (same reference) when no selected element is grouped. */\r\nexport function expandToGroups(ids: string[], elements: CanvasElement[]): string[] {\r\n const byId = new Map(elements.map((e) => [e.id, e]));\r\n const groupIds = new Set<string>();\r\n for (const id of ids) {\r\n const g = byId.get(id)?.groupId;\r\n if (g) groupIds.add(g);\r\n }\r\n if (groupIds.size === 0) return ids;\r\n const idSet = new Set(ids);\r\n const result = [...ids];\r\n for (const el of elements) {\r\n if (el.groupId && groupIds.has(el.groupId) && !idSet.has(el.id)) {\r\n result.push(el.id);\r\n idSet.add(el.id);\r\n }\r\n }\r\n return result;\r\n}\r\n","import type { Point } from '../core/types';\r\nimport type { ArrowElement, CanvasElement } from '../elements/types';\r\nimport type { ToolContext } from './types';\r\nimport { getArrowMidpoint, getBendFromPoint } from '../elements/arrow-geometry';\r\nimport { findBindTarget, getElementCenter } from '../elements/arrow-binding';\r\nimport { getElementBounds } from '../elements/element-bounds';\r\n\r\nconst BIND_THRESHOLD = 20;\r\n\r\nexport type ArrowHandle = 'start' | 'mid' | 'end';\r\n\r\nconst HANDLE_RADIUS = 5;\r\nconst HANDLE_HIT_PADDING = 4;\r\n\r\nconst ARROW_HANDLE_CURSORS: Record<ArrowHandle, string> = {\r\n start: 'crosshair',\r\n end: 'crosshair',\r\n mid: 'grab',\r\n};\r\n\r\nexport function getArrowHandleCursor(handle: ArrowHandle, active: boolean): string {\r\n if (handle === 'mid' && active) return 'grabbing';\r\n return ARROW_HANDLE_CURSORS[handle];\r\n}\r\n\r\nexport function getArrowHandlePositions(arrow: ArrowElement): [ArrowHandle, Point][] {\r\n const mid = getArrowMidpoint(arrow.from, arrow.to, arrow.bend);\r\n return [\r\n ['start', arrow.from],\r\n ['mid', mid],\r\n ['end', arrow.to],\r\n ];\r\n}\r\n\r\nexport function hitTestArrowHandles(\r\n world: Point,\r\n selectedIds: string[],\r\n ctx: ToolContext,\r\n): { elementId: string; handle: ArrowHandle } | null {\r\n if (selectedIds.length === 0) return null;\r\n\r\n const zoom = ctx.camera.zoom;\r\n const hitRadius = (HANDLE_RADIUS + HANDLE_HIT_PADDING) / zoom;\r\n\r\n for (const id of selectedIds) {\r\n const el = ctx.store.getById(id);\r\n if (!el || el.type !== 'arrow' || el.locked || (ctx.isLayerLocked?.(el.layerId) ?? false))\r\n continue;\r\n\r\n const handles = getArrowHandlePositions(el);\r\n for (const [handle, pos] of handles) {\r\n const dx = world.x - pos.x;\r\n const dy = world.y - pos.y;\r\n if (dx * dx + dy * dy <= hitRadius * hitRadius) {\r\n return { elementId: id, handle };\r\n }\r\n }\r\n }\r\n\r\n return null;\r\n}\r\n\r\nexport function applyArrowHandleDrag(\r\n handle: ArrowHandle,\r\n elementId: string,\r\n world: Point,\r\n ctx: ToolContext,\r\n): void {\r\n const el = ctx.store.getById(elementId);\r\n if (!el || el.type !== 'arrow' || el.locked || (ctx.isLayerLocked?.(el.layerId) ?? false)) return;\r\n\r\n const threshold = BIND_THRESHOLD / ctx.camera.zoom;\r\n\r\n const layerFilter = (candidate: CanvasElement) => candidate.layerId === el.layerId;\r\n\r\n switch (handle) {\r\n case 'start': {\r\n const excludeId = el.toBinding?.elementId;\r\n const target = findBindTarget(world, ctx.store, threshold, excludeId, layerFilter);\r\n if (target) {\r\n const center = getElementCenter(target);\r\n ctx.store.update(elementId, {\r\n from: center,\r\n position: center,\r\n fromBinding: { elementId: target.id },\r\n });\r\n } else {\r\n ctx.store.update(elementId, {\r\n from: { x: world.x, y: world.y },\r\n position: { x: world.x, y: world.y },\r\n fromBinding: undefined,\r\n });\r\n }\r\n break;\r\n }\r\n case 'end': {\r\n const excludeId = el.fromBinding?.elementId;\r\n const target = findBindTarget(world, ctx.store, threshold, excludeId, layerFilter);\r\n if (target) {\r\n const center = getElementCenter(target);\r\n ctx.store.update(elementId, {\r\n to: center,\r\n toBinding: { elementId: target.id },\r\n });\r\n } else {\r\n ctx.store.update(elementId, {\r\n to: { x: world.x, y: world.y },\r\n toBinding: undefined,\r\n });\r\n }\r\n break;\r\n }\r\n case 'mid': {\r\n const bend = getBendFromPoint(el.from, el.to, world);\r\n ctx.store.update(elementId, { bend });\r\n break;\r\n }\r\n }\r\n\r\n ctx.requestRender();\r\n}\r\n\r\nexport function getArrowHandleDragTarget(\r\n handle: ArrowHandle,\r\n elementId: string,\r\n world: Point,\r\n ctx: ToolContext,\r\n): { x: number; y: number; w: number; h: number } | null {\r\n if (handle === 'mid') return null;\r\n\r\n const el = ctx.store.getById(elementId);\r\n if (!el || el.type !== 'arrow' || el.locked || (ctx.isLayerLocked?.(el.layerId) ?? false)) {\r\n return null;\r\n }\r\n\r\n const threshold = BIND_THRESHOLD / ctx.camera.zoom;\r\n const excludeId = handle === 'start' ? el.toBinding?.elementId : el.fromBinding?.elementId;\r\n const layerFilter = (candidate: CanvasElement) => candidate.layerId === el.layerId;\r\n const target = findBindTarget(world, ctx.store, threshold, excludeId, layerFilter);\r\n if (!target) return null;\r\n\r\n return getElementBounds(target);\r\n}\r\n\r\nexport function renderArrowHandles(\r\n canvasCtx: CanvasRenderingContext2D,\r\n arrow: ArrowElement,\r\n zoom: number,\r\n): void {\r\n const radius = HANDLE_RADIUS / zoom;\r\n const handles = getArrowHandlePositions(arrow);\r\n\r\n canvasCtx.setLineDash([]);\r\n canvasCtx.lineWidth = 1.5 / zoom;\r\n\r\n for (const [handle, pos] of handles) {\r\n canvasCtx.fillStyle = handle === 'mid' ? '#2196F3' : '#ffffff';\r\n canvasCtx.strokeStyle = '#2196F3';\r\n\r\n canvasCtx.beginPath();\r\n canvasCtx.arc(pos.x, pos.y, radius, 0, Math.PI * 2);\r\n canvasCtx.fill();\r\n canvasCtx.stroke();\r\n }\r\n}\r\n\r\nexport function renderArrowHoverHandle(\r\n canvasCtx: CanvasRenderingContext2D,\r\n arrow: ArrowElement,\r\n zoom: number,\r\n): void {\r\n const mid = getArrowMidpoint(arrow.from, arrow.to, arrow.bend);\r\n const radius = HANDLE_RADIUS / zoom;\r\n canvasCtx.fillStyle = '#2196F3';\r\n canvasCtx.strokeStyle = '#2196F3';\r\n canvasCtx.lineWidth = 1.5 / zoom;\r\n canvasCtx.beginPath();\r\n canvasCtx.arc(mid.x, mid.y, radius, 0, Math.PI * 2);\r\n canvasCtx.fill();\r\n canvasCtx.stroke();\r\n}\r\n","import type { Bounds } from '../core/types';\r\n\r\nexport interface SnapGuide {\r\n axis: 'x' | 'y';\r\n position: number;\r\n}\r\nexport interface SnapResult {\r\n dx: number;\r\n dy: number;\r\n guides: SnapGuide[];\r\n}\r\n\r\ninterface AxisAnchors {\r\n lo: number;\r\n mid: number;\r\n hi: number;\r\n}\r\n\r\nfunction xAnchors(b: Bounds): AxisAnchors {\r\n return { lo: b.x, mid: b.x + b.w / 2, hi: b.x + b.w };\r\n}\r\n\r\nfunction yAnchors(b: Bounds): AxisAnchors {\r\n return { lo: b.y, mid: b.y + b.h / 2, hi: b.y + b.h };\r\n}\r\n\r\nfunction bestAxisSnap(\r\n moving: AxisAnchors,\r\n targets: Bounds[],\r\n anchorsFn: (b: Bounds) => AxisAnchors,\r\n threshold: number,\r\n): { delta: number; position: number } | null {\r\n let best: { delta: number; position: number } | null = null;\r\n\r\n for (const t of targets) {\r\n const ta = anchorsFn(t);\r\n const pairs: [number, number][] = [\r\n // colinear alignment: same-type edges/centers line up\r\n [ta.lo - moving.lo, ta.lo],\r\n [ta.mid - moving.mid, ta.mid],\r\n [ta.hi - moving.hi, ta.hi],\r\n // abutment: the moving box sits flush against the target's opposite edge\r\n [ta.lo - moving.hi, ta.lo],\r\n [ta.hi - moving.lo, ta.hi],\r\n ];\r\n\r\n for (const [delta, position] of pairs) {\r\n const abs = Math.abs(delta);\r\n if (abs <= threshold && (best === null || abs < Math.abs(best.delta))) {\r\n best = { delta, position };\r\n }\r\n }\r\n }\r\n\r\n return best;\r\n}\r\n\r\nexport function computeSnapGuides(\r\n moving: Bounds,\r\n targets: Bounds[],\r\n threshold: number,\r\n): SnapResult {\r\n const xSnap = bestAxisSnap(xAnchors(moving), targets, xAnchors, threshold);\r\n const ySnap = bestAxisSnap(yAnchors(moving), targets, yAnchors, threshold);\r\n\r\n const guides: SnapGuide[] = [];\r\n if (xSnap) guides.push({ axis: 'x', position: xSnap.position });\r\n if (ySnap) guides.push({ axis: 'y', position: ySnap.position });\r\n\r\n return { dx: xSnap?.delta ?? 0, dy: ySnap?.delta ?? 0, guides };\r\n}\r\n","import type { Bounds, Point } from '../core/types';\r\nimport type { CanvasElement, ArrowElement } from '../elements/types';\r\nimport type { ElementStore } from '../elements/element-store';\r\nimport type { SnapGuide } from '../elements/snap-guides';\r\nimport { getElementBounds } from '../elements/element-bounds';\r\nimport { rotatePoint } from '../core/geometry';\r\nimport { lineEndpoints } from '../elements/shape-geometry';\r\nimport { renderArrowHandles } from './arrow-handles';\r\n\r\nexport type HandlePosition = 'nw' | 'ne' | 'sw' | 'se';\r\n\r\nexport const HANDLE_SIZE = 8;\r\nexport const HANDLE_HIT_PADDING = 4;\r\nexport const SELECTION_PAD = 4;\r\nexport const ROTATE_HANDLE_OFFSET = 24;\r\nexport const ROTATABLE_TYPES = new Set(['note', 'text', 'image', 'html', 'shape', 'stroke']);\r\n\r\nexport const HANDLE_CURSORS: Record<HandlePosition, string> = {\r\n nw: 'nwse-resize',\r\n se: 'nwse-resize',\r\n ne: 'nesw-resize',\r\n sw: 'nesw-resize',\r\n};\r\n\r\nexport interface OverlayLayout {\r\n center: Point;\r\n corners: [HandlePosition, Point][];\r\n rotateHandle: Point;\r\n angle: number;\r\n}\r\n\r\nexport function getOverlayLayout(el: CanvasElement, zoom: number): OverlayLayout | null {\r\n const bounds = getElementBounds(el);\r\n if (!bounds) return null;\r\n const angle = el.rotation ?? 0;\r\n const pad = SELECTION_PAD / zoom;\r\n const center = { x: bounds.x + bounds.w / 2, y: bounds.y + bounds.h / 2 };\r\n const raw: [HandlePosition, Point][] = [\r\n ['nw', { x: bounds.x - pad, y: bounds.y - pad }],\r\n ['ne', { x: bounds.x + bounds.w + pad, y: bounds.y - pad }],\r\n ['sw', { x: bounds.x - pad, y: bounds.y + bounds.h + pad }],\r\n ['se', { x: bounds.x + bounds.w + pad, y: bounds.y + bounds.h + pad }],\r\n ];\r\n const corners = raw.map(\r\n ([h, p]) => [h, rotatePoint(p, center, angle)] as [HandlePosition, Point],\r\n );\r\n const topMid = { x: center.x, y: bounds.y - pad - ROTATE_HANDLE_OFFSET / zoom };\r\n const rotateHandle = rotatePoint(topMid, center, angle);\r\n return { center, corners, rotateHandle, angle };\r\n}\r\n\r\nexport function templateAimKnob(\r\n el: CanvasElement,\r\n zoom: number,\r\n): { origin: Point; knob: Point } | null {\r\n if (el.type !== 'template') return null;\r\n if (\r\n el.templateShape !== 'cone' &&\r\n el.templateShape !== 'line' &&\r\n el.templateShape !== 'rectangle'\r\n )\r\n return null;\r\n const gap = ROTATE_HANDLE_OFFSET / zoom;\r\n const dist = el.radius + gap;\r\n const origin = el.position;\r\n return {\r\n origin,\r\n knob: {\r\n x: origin.x + dist * Math.cos(el.angle),\r\n y: origin.y + dist * Math.sin(el.angle),\r\n },\r\n };\r\n}\r\n\r\nexport function getHandlePositions(bounds: Bounds): [HandlePosition, Point][] {\r\n return [\r\n ['nw', { x: bounds.x, y: bounds.y }],\r\n ['ne', { x: bounds.x + bounds.w, y: bounds.y }],\r\n ['sw', { x: bounds.x, y: bounds.y + bounds.h }],\r\n ['se', { x: bounds.x + bounds.w, y: bounds.y + bounds.h }],\r\n ];\r\n}\r\n\r\nexport function topMidpoint(layout: { corners: [HandlePosition, Point][] }): Point {\r\n const nw = layout.corners.find(([h]) => h === 'nw')?.[1] ?? { x: 0, y: 0 };\r\n const ne = layout.corners.find(([h]) => h === 'ne')?.[1] ?? { x: 0, y: 0 };\r\n return { x: (nw.x + ne.x) / 2, y: (nw.y + ne.y) / 2 };\r\n}\r\n\r\nexport function drawLockBadge(ctx: CanvasRenderingContext2D, at: Point, zoom: number): void {\r\n const r = 9 / zoom;\r\n ctx.save();\r\n ctx.setLineDash([]);\r\n ctx.beginPath();\r\n ctx.arc(at.x, at.y, r, 0, Math.PI * 2);\r\n ctx.fillStyle = '#ffffff';\r\n ctx.fill();\r\n ctx.strokeStyle = '#2196F3';\r\n ctx.lineWidth = 1.5 / zoom;\r\n ctx.stroke();\r\n const bw = 8 / zoom;\r\n const bh = 6 / zoom;\r\n ctx.fillStyle = '#2196F3';\r\n ctx.fillRect(at.x - bw / 2, at.y - bh / 2 + 1 / zoom, bw, bh);\r\n ctx.beginPath();\r\n ctx.arc(at.x, at.y - bh / 2 + 1 / zoom, 2.5 / zoom, Math.PI, 0);\r\n ctx.lineWidth = 1.4 / zoom;\r\n ctx.stroke();\r\n ctx.restore();\r\n}\r\n\r\nexport function renderMarquee(ctx: CanvasRenderingContext2D, rect: Bounds): void {\r\n ctx.save();\r\n ctx.strokeStyle = '#2196F3';\r\n ctx.fillStyle = 'rgba(33, 150, 243, 0.08)';\r\n ctx.lineWidth = 1;\r\n ctx.setLineDash([4, 4]);\r\n ctx.strokeRect(rect.x, rect.y, rect.w, rect.h);\r\n ctx.fillRect(rect.x, rect.y, rect.w, rect.h);\r\n ctx.restore();\r\n}\r\n\r\nexport function renderBindingHighlights(\r\n ctx: CanvasRenderingContext2D,\r\n arrow: ArrowElement,\r\n zoom: number,\r\n store: ElementStore,\r\n): void {\r\n if (!arrow.fromBinding && !arrow.toBinding) return;\r\n\r\n const pad = SELECTION_PAD / zoom;\r\n\r\n ctx.save();\r\n ctx.strokeStyle = '#2196F3';\r\n ctx.lineWidth = 2 / zoom;\r\n ctx.setLineDash([]);\r\n\r\n const drawn = new Set<string>();\r\n for (const binding of [arrow.fromBinding, arrow.toBinding]) {\r\n if (!binding || drawn.has(binding.elementId)) continue;\r\n drawn.add(binding.elementId);\r\n\r\n const target = store.getById(binding.elementId);\r\n if (!target) continue;\r\n\r\n const bounds = getElementBounds(target);\r\n if (!bounds) continue;\r\n\r\n ctx.strokeRect(bounds.x - pad, bounds.y - pad, bounds.w + pad * 2, bounds.h + pad * 2);\r\n }\r\n\r\n ctx.restore();\r\n}\r\n\r\nexport function renderSelectionBoxes(\r\n ctx: CanvasRenderingContext2D,\r\n p: {\r\n selectedIds: string[];\r\n store: ElementStore;\r\n zoom: number;\r\n isLayerLocked?: (layerId: string) => boolean;\r\n },\r\n): void {\r\n if (p.selectedIds.length === 0) return;\r\n\r\n const zoom = p.zoom;\r\n const handleWorldSize = HANDLE_SIZE / zoom;\r\n\r\n ctx.save();\r\n ctx.strokeStyle = '#2196F3';\r\n ctx.lineWidth = 1.5 / zoom;\r\n ctx.setLineDash([4 / zoom, 4 / zoom]);\r\n\r\n for (const id of p.selectedIds) {\r\n const el = p.store.getById(id);\r\n if (!el) continue;\r\n const locked = el.locked || (p.isLayerLocked?.(el.layerId) ?? false);\r\n\r\n if (el.type === 'arrow') {\r\n if (!locked) renderArrowHandles(ctx, el, zoom);\r\n renderBindingHighlights(ctx, el, zoom, p.store);\r\n continue;\r\n }\r\n\r\n if (el.type === 'shape' && el.shape === 'line') {\r\n if (!locked) {\r\n ctx.setLineDash([]);\r\n ctx.fillStyle = '#ffffff';\r\n const r = handleWorldSize / 2;\r\n for (const pt of lineEndpoints(el)) {\r\n ctx.beginPath();\r\n ctx.arc(pt.x, pt.y, r, 0, Math.PI * 2);\r\n ctx.fill();\r\n ctx.stroke();\r\n }\r\n ctx.setLineDash([4 / zoom, 4 / zoom]);\r\n }\r\n continue;\r\n }\r\n\r\n const bounds = getElementBounds(el);\r\n if (!bounds) continue;\r\n\r\n const layout = getOverlayLayout(el, zoom);\r\n if (!layout) continue;\r\n\r\n const pad = SELECTION_PAD / zoom;\r\n if (layout.angle === 0) {\r\n ctx.strokeRect(bounds.x - pad, bounds.y - pad, bounds.w + pad * 2, bounds.h + pad * 2);\r\n } else {\r\n const ordered = (['nw', 'ne', 'se', 'sw'] as HandlePosition[])\r\n .map((h) => layout.corners.find(([c]) => c === h)?.[1])\r\n .filter((pp): pp is Point => !!pp);\r\n const [p0, ...others] = ordered;\r\n if (p0) {\r\n ctx.beginPath();\r\n ctx.moveTo(p0.x, p0.y);\r\n for (const pp of others) ctx.lineTo(pp.x, pp.y);\r\n ctx.closePath();\r\n ctx.stroke();\r\n }\r\n }\r\n\r\n if (!el.locked) {\r\n if ('size' in el) {\r\n ctx.setLineDash([]);\r\n ctx.fillStyle = '#ffffff';\r\n const corners = layout.angle === 0 ? getHandlePositions(bounds) : layout.corners;\r\n for (const [, pos] of corners) {\r\n ctx.fillRect(\r\n pos.x - handleWorldSize / 2,\r\n pos.y - handleWorldSize / 2,\r\n handleWorldSize,\r\n handleWorldSize,\r\n );\r\n ctx.strokeRect(\r\n pos.x - handleWorldSize / 2,\r\n pos.y - handleWorldSize / 2,\r\n handleWorldSize,\r\n handleWorldSize,\r\n );\r\n }\r\n ctx.setLineDash([4 / zoom, 4 / zoom]);\r\n } else if (el.type === 'template') {\r\n ctx.setLineDash([]);\r\n ctx.fillStyle = '#ffffff';\r\n if (el.templateShape === 'rectangle') {\r\n if (p.selectedIds.length === 1) {\r\n const cos = Math.cos(el.angle);\r\n const sin = Math.sin(el.angle);\r\n const halfW = (el.width ?? 0) / 2;\r\n const pts: [number, number][] = [\r\n [el.position.x + el.radius * cos, el.position.y + el.radius * sin],\r\n [\r\n el.position.x + (el.radius / 2) * cos + halfW * -sin,\r\n el.position.y + (el.radius / 2) * sin + halfW * cos,\r\n ],\r\n ];\r\n for (const [hx, hy] of pts) {\r\n ctx.fillRect(\r\n hx - handleWorldSize / 2,\r\n hy - handleWorldSize / 2,\r\n handleWorldSize,\r\n handleWorldSize,\r\n );\r\n ctx.strokeRect(\r\n hx - handleWorldSize / 2,\r\n hy - handleWorldSize / 2,\r\n handleWorldSize,\r\n handleWorldSize,\r\n );\r\n }\r\n }\r\n } else {\r\n const hx = bounds.x + bounds.w;\r\n const hy = bounds.y + bounds.h;\r\n ctx.fillRect(\r\n hx - handleWorldSize / 2,\r\n hy - handleWorldSize / 2,\r\n handleWorldSize,\r\n handleWorldSize,\r\n );\r\n ctx.strokeRect(\r\n hx - handleWorldSize / 2,\r\n hy - handleWorldSize / 2,\r\n handleWorldSize,\r\n handleWorldSize,\r\n );\r\n }\r\n ctx.setLineDash([4 / zoom, 4 / zoom]);\r\n\r\n if (\r\n p.selectedIds.length === 1 &&\r\n (el.templateShape === 'cone' ||\r\n el.templateShape === 'line' ||\r\n el.templateShape === 'rectangle')\r\n ) {\r\n const aim = templateAimKnob(el, zoom);\r\n if (aim) {\r\n ctx.beginPath();\r\n ctx.moveTo(aim.origin.x, aim.origin.y);\r\n ctx.lineTo(aim.knob.x, aim.knob.y);\r\n ctx.stroke();\r\n\r\n ctx.setLineDash([]);\r\n ctx.fillStyle = '#ffffff';\r\n ctx.beginPath();\r\n ctx.arc(aim.knob.x, aim.knob.y, handleWorldSize / 2, 0, Math.PI * 2);\r\n ctx.fill();\r\n ctx.stroke();\r\n ctx.setLineDash([4 / zoom, 4 / zoom]);\r\n }\r\n }\r\n }\r\n\r\n if (p.selectedIds.length === 1 && ROTATABLE_TYPES.has(el.type)) {\r\n const stemStart = topMidpoint(layout);\r\n const stemEnd = layout.rotateHandle;\r\n ctx.beginPath();\r\n ctx.moveTo(stemStart.x, stemStart.y);\r\n ctx.lineTo(stemEnd.x, stemEnd.y);\r\n ctx.stroke();\r\n\r\n ctx.setLineDash([]);\r\n ctx.fillStyle = '#ffffff';\r\n ctx.beginPath();\r\n ctx.arc(stemEnd.x, stemEnd.y, handleWorldSize / 2, 0, Math.PI * 2);\r\n ctx.fill();\r\n ctx.stroke();\r\n ctx.setLineDash([4 / zoom, 4 / zoom]);\r\n }\r\n }\r\n\r\n if (el.locked) {\r\n const ne = layout.corners.find(([h]) => h === 'ne')?.[1];\r\n if (ne) drawLockBadge(ctx, ne, zoom);\r\n }\r\n }\r\n\r\n ctx.restore();\r\n}\r\n\r\nexport function renderGuideLines(\r\n ctx: CanvasRenderingContext2D,\r\n p: { guides: SnapGuide[]; rect: Bounds | null; currentWorld: Point; zoom: number },\r\n): void {\r\n const zoom = p.zoom;\r\n const rect = p.rect; // cached at drag start (same source as the candidate query)\r\n ctx.save();\r\n ctx.strokeStyle = '#FF4081';\r\n ctx.lineWidth = 1 / zoom;\r\n ctx.setLineDash([]);\r\n for (const g of p.guides) {\r\n ctx.beginPath();\r\n if (g.axis === 'x') {\r\n const y0 = rect ? rect.y : p.currentWorld.y - 1e5;\r\n const y1 = rect ? rect.y + rect.h : p.currentWorld.y + 1e5;\r\n ctx.moveTo(g.position, y0);\r\n ctx.lineTo(g.position, y1);\r\n } else {\r\n const x0 = rect ? rect.x : p.currentWorld.x - 1e5;\r\n const x1 = rect ? rect.x + rect.w : p.currentWorld.x + 1e5;\r\n ctx.moveTo(x0, g.position);\r\n ctx.lineTo(x1, g.position);\r\n }\r\n ctx.stroke();\r\n }\r\n ctx.restore();\r\n}\r\n","import type { Bounds, Point } from '../core/types';\r\nimport type { ToolContext } from './types';\r\nimport { distSqToSegment, rotatePoint, rotatedAABB } from '../core/geometry';\r\nimport type { CanvasElement } from '../elements/types';\r\nimport { isNearBezier } from '../elements/arrow-geometry';\r\nimport { getElementBounds } from '../elements/element-bounds';\r\nimport { hitTestStroke } from '../elements/stroke-hit';\r\nimport { lineEndpoints } from '../elements/shape-geometry';\r\nimport type { HandlePosition } from './select-overlay';\r\nimport {\r\n HANDLE_SIZE,\r\n HANDLE_HIT_PADDING,\r\n ROTATABLE_TYPES,\r\n getOverlayLayout,\r\n templateAimKnob,\r\n} from './select-overlay';\r\n\r\nexport function hitTest(world: Point, ctx: ToolContext): CanvasElement | null {\r\n // Inflate query by hit radius so strokes/arrows near the point are included\r\n const r = 10;\r\n const candidates = ctx.store\r\n .queryRect({ x: world.x - r, y: world.y - r, w: r * 2, h: r * 2 })\r\n .reverse();\r\n for (const el of candidates) {\r\n if (ctx.isLayerVisible && !ctx.isLayerVisible(el.layerId)) continue;\r\n if (ctx.isLayerLocked && ctx.isLayerLocked(el.layerId)) continue;\r\n if (el.type === 'grid') continue;\r\n if (isInsideBounds(world, el)) return el;\r\n }\r\n return null;\r\n}\r\n\r\nexport function isInsideBounds(point: Point, el: CanvasElement): boolean {\r\n if (el.type === 'grid') return false;\r\n const angle = el.rotation ?? 0;\r\n if (angle !== 0) {\r\n const b = getElementBounds(el);\r\n if (b) {\r\n point = rotatePoint(point, { x: b.x + b.w / 2, y: b.y + b.h / 2 }, -angle);\r\n }\r\n }\r\n if (el.type === 'shape' && el.shape === 'line') {\r\n const [a, b] = lineEndpoints(el);\r\n const threshold = Math.max(el.strokeWidth / 2, 6);\r\n return distSqToSegment(point, a, b) <= threshold * threshold;\r\n }\r\n if ('size' in el) {\r\n const s = el.size;\r\n return (\r\n point.x >= el.position.x &&\r\n point.x <= el.position.x + s.w &&\r\n point.y >= el.position.y &&\r\n point.y <= el.position.y + s.h\r\n );\r\n }\r\n\r\n if (el.type === 'stroke') {\r\n return hitTestStroke(el, point, 10);\r\n }\r\n\r\n if (el.type === 'arrow') {\r\n return isNearBezier(point, el.from, el.to, el.bend, 10);\r\n }\r\n\r\n if (el.type === 'template') {\r\n const bounds = getElementBounds(el);\r\n if (!bounds) return false;\r\n return (\r\n point.x >= bounds.x &&\r\n point.x <= bounds.x + bounds.w &&\r\n point.y >= bounds.y &&\r\n point.y <= bounds.y + bounds.h\r\n );\r\n }\r\n\r\n return false;\r\n}\r\n\r\nexport function hitTestResizeHandle(\r\n world: Point,\r\n ctx: ToolContext,\r\n selectedIds: string[],\r\n): { elementId: string; handle: HandlePosition } | null {\r\n if (selectedIds.length === 0) return null;\r\n\r\n const zoom = ctx.camera.zoom;\r\n const handleHalf = (HANDLE_SIZE / 2 + HANDLE_HIT_PADDING) / zoom;\r\n\r\n for (const id of selectedIds) {\r\n const el = ctx.store.getById(id);\r\n if (!el || !('size' in el)) continue;\r\n if (el.locked) continue;\r\n if (el.type === 'shape' && el.shape === 'line') continue;\r\n\r\n const layout = getOverlayLayout(el, zoom);\r\n if (!layout) continue;\r\n for (const [handle, pos] of layout.corners) {\r\n if (Math.abs(world.x - pos.x) <= handleHalf && Math.abs(world.y - pos.y) <= handleHalf) {\r\n return { elementId: id, handle };\r\n }\r\n }\r\n }\r\n\r\n return null;\r\n}\r\n\r\nexport function hitTestRotateHandle(\r\n world: Point,\r\n ctx: ToolContext,\r\n selectedIds: string[],\r\n): { elementId: string } | null {\r\n if (selectedIds.length !== 1) return null;\r\n const id = selectedIds[0];\r\n if (!id) return null;\r\n const el = ctx.store.getById(id);\r\n if (!el || el.locked || !ROTATABLE_TYPES.has(el.type)) return null;\r\n const layout = getOverlayLayout(el, ctx.camera.zoom);\r\n if (!layout) return null;\r\n const r = (HANDLE_SIZE / 2 + HANDLE_HIT_PADDING) / ctx.camera.zoom;\r\n const dx = world.x - layout.rotateHandle.x;\r\n const dy = world.y - layout.rotateHandle.y;\r\n return dx * dx + dy * dy <= r * r ? { elementId: id } : null;\r\n}\r\n\r\nexport function hitTestLineHandles(\r\n world: Point,\r\n ctx: ToolContext,\r\n selectedIds: string[],\r\n): { elementId: string; fixed: Point } | null {\r\n if (selectedIds.length === 0) return null;\r\n const zoom = ctx.camera.zoom;\r\n const r = (HANDLE_SIZE / 2 + HANDLE_HIT_PADDING) / zoom;\r\n const r2 = r * r;\r\n for (const id of selectedIds) {\r\n const el = ctx.store.getById(id);\r\n if (\r\n !el ||\r\n el.type !== 'shape' ||\r\n el.shape !== 'line' ||\r\n el.locked ||\r\n (ctx.isLayerLocked?.(el.layerId) ?? false)\r\n )\r\n continue;\r\n const [a, b] = lineEndpoints(el);\r\n if ((world.x - a.x) ** 2 + (world.y - a.y) ** 2 <= r2) return { elementId: id, fixed: b };\r\n if ((world.x - b.x) ** 2 + (world.y - b.y) ** 2 <= r2) return { elementId: id, fixed: a };\r\n }\r\n return null;\r\n}\r\n\r\nexport function hitTestTemplateResizeHandle(\r\n world: Point,\r\n ctx: ToolContext,\r\n selectedIds: string[],\r\n): string | null {\r\n if (selectedIds.length === 0) return null;\r\n\r\n const zoom = ctx.camera.zoom;\r\n const handleHalf = (HANDLE_SIZE / 2 + HANDLE_HIT_PADDING) / zoom;\r\n\r\n for (const id of selectedIds) {\r\n const el = ctx.store.getById(id);\r\n if (!el || el.type !== 'template') continue;\r\n if (el.templateShape === 'rectangle') continue;\r\n\r\n const bounds = getElementBounds(el);\r\n if (!bounds) continue;\r\n\r\n const hx = bounds.x + bounds.w;\r\n const hy = bounds.y + bounds.h;\r\n if (Math.abs(world.x - hx) <= handleHalf && Math.abs(world.y - hy) <= handleHalf) {\r\n return id;\r\n }\r\n }\r\n\r\n return null;\r\n}\r\n\r\nexport function hitTestTemplateAimHandle(\r\n world: Point,\r\n ctx: ToolContext,\r\n selectedIds: string[],\r\n): { elementId: string } | null {\r\n if (selectedIds.length !== 1) return null;\r\n const id = selectedIds[0];\r\n if (!id) return null;\r\n const el = ctx.store.getById(id);\r\n if (!el || el.locked) return null;\r\n const knob = templateAimKnob(el, ctx.camera.zoom);\r\n if (!knob) return null;\r\n const r = (HANDLE_SIZE / 2 + HANDLE_HIT_PADDING) / ctx.camera.zoom;\r\n const dx = world.x - knob.knob.x;\r\n const dy = world.y - knob.knob.y;\r\n return dx * dx + dy * dy <= r * r ? { elementId: id } : null;\r\n}\r\n\r\nexport function hitTestRectangleLengthHandle(\r\n world: Point,\r\n ctx: ToolContext,\r\n selectedIds: string[],\r\n): { elementId: string } | null {\r\n if (selectedIds.length !== 1) return null;\r\n const id = selectedIds[0];\r\n if (!id) return null;\r\n const el = ctx.store.getById(id);\r\n if (!el || el.locked || el.type !== 'template' || el.templateShape !== 'rectangle') return null;\r\n const zoom = ctx.camera.zoom;\r\n const r = (HANDLE_SIZE / 2 + HANDLE_HIT_PADDING) / zoom;\r\n const hx = el.position.x + el.radius * Math.cos(el.angle);\r\n const hy = el.position.y + el.radius * Math.sin(el.angle);\r\n const dx = world.x - hx;\r\n const dy = world.y - hy;\r\n return dx * dx + dy * dy <= r * r ? { elementId: id } : null;\r\n}\r\n\r\nexport function hitTestRectangleWidthHandle(\r\n world: Point,\r\n ctx: ToolContext,\r\n selectedIds: string[],\r\n): { elementId: string } | null {\r\n if (selectedIds.length !== 1) return null;\r\n const id = selectedIds[0];\r\n if (!id) return null;\r\n const el = ctx.store.getById(id);\r\n if (!el || el.locked || el.type !== 'template' || el.templateShape !== 'rectangle') return null;\r\n const zoom = ctx.camera.zoom;\r\n const r = (HANDLE_SIZE / 2 + HANDLE_HIT_PADDING) / zoom;\r\n const cos = Math.cos(el.angle);\r\n const sin = Math.sin(el.angle);\r\n const halfW = (el.width ?? 0) / 2;\r\n const hx = el.position.x + (el.radius / 2) * cos + halfW * -sin;\r\n const hy = el.position.y + (el.radius / 2) * sin + halfW * cos;\r\n const dx = world.x - hx;\r\n const dy = world.y - hy;\r\n return dx * dx + dy * dy <= r * r ? { elementId: id } : null;\r\n}\r\n\r\nexport function findElementsInRect(marquee: Bounds, ctx: ToolContext): string[] {\r\n const candidates = ctx.store.queryRect(marquee);\r\n const ids: string[] = [];\r\n for (const el of candidates) {\r\n if (ctx.isLayerVisible && !ctx.isLayerVisible(el.layerId)) continue;\r\n if (ctx.isLayerLocked && ctx.isLayerLocked(el.layerId)) continue;\r\n if (el.type === 'grid') continue;\r\n const bounds = getElementBounds(el);\r\n if (bounds && rectsOverlap(marquee, rotatedAABB(bounds, el.rotation ?? 0))) {\r\n ids.push(el.id);\r\n }\r\n }\r\n return ids;\r\n}\r\n\r\nexport function rectsOverlap(a: Bounds, b: Bounds): boolean {\r\n return a.x <= b.x + b.w && a.x + a.w >= b.x && a.y <= b.y + b.h && a.y + a.h >= b.y;\r\n}\r\n","import type { Point } from '../core/types';\r\nimport type { CanvasElement, TemplateElement } from '../elements/types';\r\nimport { rotatePoint } from '../core/geometry';\r\nimport type { HandlePosition } from './select-overlay';\r\n\r\nexport const MIN_ELEMENT_SIZE = 20;\r\n\r\nexport function anchorOffset(handle: HandlePosition, w: number, h: number): Point {\r\n switch (handle) {\r\n case 'se':\r\n return { x: -w / 2, y: -h / 2 };\r\n case 'sw':\r\n return { x: w / 2, y: -h / 2 };\r\n case 'ne':\r\n return { x: -w / 2, y: h / 2 };\r\n case 'nw':\r\n return { x: w / 2, y: h / 2 };\r\n default:\r\n return { x: 0, y: 0 };\r\n }\r\n}\r\n\r\nexport function computeResize(\r\n el: CanvasElement & { size: { w: number; h: number } },\r\n handle: HandlePosition,\r\n world: Point,\r\n lastWorld: Point,\r\n aspectRatio: number,\r\n lockAspect: boolean,\r\n): { position: { x: number; y: number }; size: { w: number; h: number } } {\r\n const dx = world.x - lastWorld.x;\r\n const dy = world.y - lastWorld.y;\r\n\r\n let { x, y, w, h } = { x: el.position.x, y: el.position.y, w: el.size.w, h: el.size.h };\r\n\r\n switch (handle) {\r\n case 'se':\r\n w += dx;\r\n h += dy;\r\n break;\r\n case 'sw':\r\n x += dx;\r\n w -= dx;\r\n h += dy;\r\n break;\r\n case 'ne':\r\n y += dy;\r\n w += dx;\r\n h -= dy;\r\n break;\r\n case 'nw':\r\n x += dx;\r\n y += dy;\r\n w -= dx;\r\n h -= dy;\r\n break;\r\n }\r\n\r\n if (lockAspect && aspectRatio > 0) {\r\n const absDw = Math.abs(w - el.size.w);\r\n const absDh = Math.abs(h - el.size.h);\r\n if (absDw >= absDh) {\r\n h = w / aspectRatio;\r\n } else {\r\n w = h * aspectRatio;\r\n }\r\n if (handle === 'nw' || handle === 'sw') {\r\n x = el.position.x + el.size.w - w;\r\n }\r\n if (handle === 'nw' || handle === 'ne') {\r\n y = el.position.y + el.size.h - h;\r\n }\r\n }\r\n\r\n if (w < MIN_ELEMENT_SIZE) {\r\n if (handle === 'nw' || handle === 'sw') x = el.position.x + el.size.w - MIN_ELEMENT_SIZE;\r\n w = MIN_ELEMENT_SIZE;\r\n }\r\n if (h < MIN_ELEMENT_SIZE) {\r\n if (handle === 'nw' || handle === 'ne') y = el.position.y + el.size.h - MIN_ELEMENT_SIZE;\r\n h = MIN_ELEMENT_SIZE;\r\n }\r\n\r\n return { position: { x, y }, size: { w, h } };\r\n}\r\n\r\nexport function computeRotatedResize(\r\n el: CanvasElement & { size: { w: number; h: number } },\r\n handle: HandlePosition,\r\n angle: number,\r\n world: Point,\r\n lastWorld: Point,\r\n aspectRatio: number,\r\n lockAspect: boolean,\r\n): { position: { x: number; y: number }; size: { w: number; h: number } } {\r\n const wdx = world.x - lastWorld.x;\r\n const wdy = world.y - lastWorld.y;\r\n\r\n // world delta → element local frame (inverse rotation of the vector)\r\n const cosN = Math.cos(-angle);\r\n const sinN = Math.sin(-angle);\r\n const ldx = wdx * cosN - wdy * sinN;\r\n const ldy = wdx * sinN + wdy * cosN;\r\n\r\n let w = el.size.w;\r\n let h = el.size.h;\r\n switch (handle) {\r\n case 'se':\r\n w += ldx;\r\n h += ldy;\r\n break;\r\n case 'sw':\r\n w -= ldx;\r\n h += ldy;\r\n break;\r\n case 'ne':\r\n w += ldx;\r\n h -= ldy;\r\n break;\r\n case 'nw':\r\n w -= ldx;\r\n h -= ldy;\r\n break;\r\n }\r\n\r\n if (lockAspect && aspectRatio > 0) {\r\n const absDw = Math.abs(w - el.size.w);\r\n const absDh = Math.abs(h - el.size.h);\r\n if (absDw >= absDh) h = w / aspectRatio;\r\n else w = h * aspectRatio;\r\n }\r\n w = Math.max(w, MIN_ELEMENT_SIZE);\r\n h = Math.max(h, MIN_ELEMENT_SIZE);\r\n\r\n // anchor (opposite corner) fixed in world space, computed from OLD geometry\r\n const oldCenter = { x: el.position.x + el.size.w / 2, y: el.position.y + el.size.h / 2 };\r\n const oldAnchorLocal = anchorOffset(handle, el.size.w, el.size.h);\r\n const anchorWorld = rotatePoint(\r\n { x: oldCenter.x + oldAnchorLocal.x, y: oldCenter.y + oldAnchorLocal.y },\r\n oldCenter,\r\n angle,\r\n );\r\n\r\n // new center so the anchor stays put: anchorWorld = newCenter + R(angle)·newAnchorLocal\r\n const newAnchorLocal = anchorOffset(handle, w, h);\r\n const cos = Math.cos(angle);\r\n const sin = Math.sin(angle);\r\n const rotatedAnchor = {\r\n x: newAnchorLocal.x * cos - newAnchorLocal.y * sin,\r\n y: newAnchorLocal.x * sin + newAnchorLocal.y * cos,\r\n };\r\n const newCenter = { x: anchorWorld.x - rotatedAnchor.x, y: anchorWorld.y - rotatedAnchor.y };\r\n const position = { x: newCenter.x - w / 2, y: newCenter.y - h / 2 };\r\n\r\n return { position, size: { w, h } };\r\n}\r\n\r\nexport interface TemplateResizeOptions {\r\n snapToGrid?: boolean;\r\n gridSize?: number;\r\n gridType?: 'square' | 'hex';\r\n}\r\n\r\nexport function computeTemplateResize(\r\n el: TemplateElement,\r\n world: Point,\r\n opts: TemplateResizeOptions,\r\n): Record<string, unknown> | null {\r\n const dx = world.x - el.position.x;\r\n const dy = world.y - el.position.y;\r\n let newRadius = Math.sqrt(dx * dx + dy * dy);\r\n\r\n if (opts.snapToGrid && opts.gridSize && opts.gridSize > 0) {\r\n const snapUnit = opts.gridType === 'hex' ? Math.sqrt(3) * opts.gridSize : opts.gridSize;\r\n newRadius = Math.max(snapUnit, Math.round(newRadius / snapUnit) * snapUnit);\r\n }\r\n newRadius = Math.max(MIN_ELEMENT_SIZE, newRadius);\r\n\r\n const updates: Record<string, unknown> = { radius: newRadius };\r\n if (el.feetPerCell != null && opts.gridSize && opts.gridSize > 0) {\r\n const snapUnit = opts.gridType === 'hex' ? Math.sqrt(3) * opts.gridSize : opts.gridSize;\r\n updates.radiusFeet = (newRadius / snapUnit) * el.feetPerCell;\r\n }\r\n\r\n return updates;\r\n}\r\n\r\nexport function computeRectangleLengthResize(\r\n el: TemplateElement,\r\n world: Point,\r\n opts: TemplateResizeOptions,\r\n): Record<string, unknown> | null {\r\n const cos = Math.cos(el.angle);\r\n const sin = Math.sin(el.angle);\r\n let len = (world.x - el.position.x) * cos + (world.y - el.position.y) * sin;\r\n if (opts.snapToGrid && opts.gridSize && opts.gridSize > 0) {\r\n const snapUnit = opts.gridType === 'hex' ? Math.sqrt(3) * opts.gridSize : opts.gridSize;\r\n len = Math.max(snapUnit, Math.round(len / snapUnit) * snapUnit);\r\n }\r\n len = Math.max(MIN_ELEMENT_SIZE, len);\r\n const updates: Record<string, unknown> = { radius: len };\r\n if (el.feetPerCell != null && opts.gridSize && opts.gridSize > 0) {\r\n const snapUnit = opts.gridType === 'hex' ? Math.sqrt(3) * opts.gridSize : opts.gridSize;\r\n updates.radiusFeet = (len / snapUnit) * el.feetPerCell;\r\n }\r\n return updates;\r\n}\r\n\r\nexport function computeRectangleWidthResize(\r\n el: TemplateElement,\r\n world: Point,\r\n opts: TemplateResizeOptions,\r\n): Record<string, unknown> | null {\r\n const cos = Math.cos(el.angle);\r\n const sin = Math.sin(el.angle);\r\n const perp = Math.abs(-(world.x - el.position.x) * sin + (world.y - el.position.y) * cos);\r\n let width = perp * 2;\r\n if (opts.snapToGrid && opts.gridSize && opts.gridSize > 0) {\r\n const snapUnit = opts.gridType === 'hex' ? Math.sqrt(3) * opts.gridSize : opts.gridSize;\r\n width = Math.max(snapUnit, Math.round(width / snapUnit) * snapUnit);\r\n }\r\n width = Math.max(MIN_ELEMENT_SIZE, width);\r\n return { width };\r\n}\r\n","import type { Bounds, Point } from '../core/types';\r\nimport type { Tool, ToolContext, PointerState } from './types';\r\nimport { smartSnap } from '../core/snap';\r\nimport { normalizeAngle } from '../core/geometry';\r\nimport type { CanvasElement } from '../elements/types';\r\nimport { updateArrowsBoundToElements } from '../elements/arrow-binding';\r\nimport { getElementBounds } from '../elements/element-bounds';\r\nimport { expandToGroups } from '../elements/group';\r\nimport { getElementsBoundingBox } from '../elements/bounds';\r\nimport { lineFromEndpoints } from '../elements/shape-geometry';\r\nimport { translateElementPatch } from '../elements/translate';\r\nimport {\r\n type ArrowHandle,\r\n hitTestArrowHandles,\r\n applyArrowHandleDrag,\r\n getArrowHandleCursor,\r\n getArrowHandleDragTarget,\r\n renderArrowHoverHandle,\r\n} from './arrow-handles';\r\nimport { computeSnapGuides } from '../elements/snap-guides';\r\nimport type { SnapGuide } from '../elements/snap-guides';\r\nimport {\r\n hitTest,\r\n hitTestResizeHandle,\r\n hitTestRotateHandle,\r\n hitTestLineHandles,\r\n hitTestTemplateResizeHandle,\r\n hitTestTemplateAimHandle,\r\n hitTestRectangleLengthHandle,\r\n hitTestRectangleWidthHandle,\r\n findElementsInRect,\r\n} from './select-hit';\r\nimport type { HandlePosition, OverlayLayout } from './select-overlay';\r\nimport {\r\n HANDLE_CURSORS,\r\n getOverlayLayout,\r\n renderMarquee,\r\n renderSelectionBoxes,\r\n renderGuideLines,\r\n} from './select-overlay';\r\nimport {\r\n computeResize,\r\n computeRotatedResize,\r\n computeTemplateResize,\r\n computeRectangleLengthResize,\r\n computeRectangleWidthResize,\r\n} from './select-resize';\r\n\r\nconst SNAP_PX = 6;\r\nconst ROTATE_SNAP = Math.PI / 12; // 15°\r\n\r\ntype Mode =\r\n | { type: 'idle' }\r\n | { type: 'dragging' }\r\n | { type: 'marquee'; start: Point }\r\n | { type: 'resizing'; elementId: string; handle: HandlePosition }\r\n | { type: 'resizing-template'; elementId: string }\r\n | { type: 'aiming-template'; elementId: string }\r\n | { type: 'resizing-rect-length'; elementId: string }\r\n | { type: 'resizing-rect-width'; elementId: string }\r\n | { type: 'arrow-handle'; elementId: string; handle: ArrowHandle }\r\n | { type: 'line-handle'; elementId: string; fixed: Point }\r\n | {\r\n type: 'rotating';\r\n elementId: string;\r\n center: Point;\r\n startPointerAngle: number;\r\n startRotation: number;\r\n };\r\n\r\nexport class SelectTool implements Tool {\r\n readonly name = 'select';\r\n private _selectedIds: string[] = [];\r\n private selectionListeners = new Set<() => void>();\r\n private mode: Mode = { type: 'idle' };\r\n private lastWorld: Point = { x: 0, y: 0 };\r\n private currentWorld: Point = { x: 0, y: 0 };\r\n private ctx: ToolContext | null = null;\r\n private pendingSingleSelectId: string | null = null;\r\n private hasDragged = false;\r\n private activeGuides: SnapGuide[] = [];\r\n private dragSnapTargets: Bounds[] | null = null;\r\n private dragVisibleRect: Bounds | null = null;\r\n private resizeAspectRatio = 0;\r\n private hoveredId: string | null = null;\r\n\r\n get selectedIds(): string[] {\r\n return this._selectedIds;\r\n }\r\n\r\n onSelectionChange(listener: () => void): () => void {\r\n this.selectionListeners.add(listener);\r\n return () => {\r\n this.selectionListeners.delete(listener);\r\n };\r\n }\r\n\r\n private setSelectedIds(ids: string[]): void {\r\n const prev = this._selectedIds;\r\n if (prev.length === ids.length && prev.every((id, i) => id === ids[i])) return;\r\n this._selectedIds = ids;\r\n for (const listener of this.selectionListeners) listener();\r\n }\r\n\r\n setSelection(ids: string[]): void {\r\n this.setSelectedIds(ids);\r\n this.ctx?.requestRender();\r\n }\r\n\r\n selectAtPoint(world: Point, ctx: ToolContext): void {\r\n const hit = hitTest(world, ctx);\r\n if (!hit) {\r\n this.setSelectedIds([]);\r\n return;\r\n }\r\n if (this._selectedIds.includes(hit.id)) return;\r\n this.setSelectedIds(expandToGroups([hit.id], ctx.store.getAll()));\r\n }\r\n\r\n get isMarqueeActive(): boolean {\r\n return this.mode.type === 'marquee';\r\n }\r\n\r\n onActivate(ctx: ToolContext): void {\r\n this.ctx = ctx;\r\n }\r\n\r\n onDeactivate(ctx: ToolContext): void {\r\n this.setSelectedIds([]);\r\n this.mode = { type: 'idle' };\r\n this.hoveredId = null;\r\n this.activeGuides = [];\r\n this.dragSnapTargets = null;\r\n this.dragVisibleRect = null;\r\n ctx.setCursor?.('default');\r\n }\r\n\r\n private snap(point: Point, ctx: ToolContext): Point {\r\n return smartSnap(point, ctx);\r\n }\r\n\r\n onPointerDown(state: PointerState, ctx: ToolContext): void {\r\n this.ctx = ctx;\r\n this.setHovered(null, ctx);\r\n this.dragSnapTargets = null;\r\n this.dragVisibleRect = null;\r\n const world = ctx.camera.screenToWorld({ x: state.x, y: state.y });\r\n this.lastWorld = this.snap(world, ctx);\r\n this.currentWorld = world;\r\n\r\n const arrowHit = hitTestArrowHandles(world, this._selectedIds, ctx);\r\n if (arrowHit) {\r\n this.mode = {\r\n type: 'arrow-handle',\r\n elementId: arrowHit.elementId,\r\n handle: arrowHit.handle,\r\n };\r\n ctx.requestRender();\r\n return;\r\n }\r\n\r\n const lineHit = hitTestLineHandles(world, ctx, this._selectedIds);\r\n if (lineHit) {\r\n this.mode = { type: 'line-handle', elementId: lineHit.elementId, fixed: lineHit.fixed };\r\n ctx.requestRender();\r\n return;\r\n }\r\n\r\n const templateResizeHit = hitTestTemplateResizeHandle(world, ctx, this._selectedIds);\r\n if (templateResizeHit) {\r\n this.mode = { type: 'resizing-template', elementId: templateResizeHit };\r\n ctx.requestRender();\r\n return;\r\n }\r\n\r\n const rectLengthHit = hitTestRectangleLengthHandle(world, ctx, this._selectedIds);\r\n if (rectLengthHit) {\r\n this.mode = { type: 'resizing-rect-length', elementId: rectLengthHit.elementId };\r\n ctx.requestRender();\r\n return;\r\n }\r\n\r\n const rectWidthHit = hitTestRectangleWidthHandle(world, ctx, this._selectedIds);\r\n if (rectWidthHit) {\r\n this.mode = { type: 'resizing-rect-width', elementId: rectWidthHit.elementId };\r\n ctx.requestRender();\r\n return;\r\n }\r\n\r\n const aimHit = hitTestTemplateAimHandle(world, ctx, this._selectedIds);\r\n if (aimHit) {\r\n this.mode = { type: 'aiming-template', elementId: aimHit.elementId };\r\n ctx.requestRender();\r\n return;\r\n }\r\n\r\n const rotateHit = hitTestRotateHandle(world, ctx, this._selectedIds);\r\n if (rotateHit) {\r\n const el = ctx.store.getById(rotateHit.elementId);\r\n const layout = el ? this.getOverlayLayout(el, ctx.camera.zoom) : null;\r\n if (el && layout) {\r\n this.mode = {\r\n type: 'rotating',\r\n elementId: rotateHit.elementId,\r\n center: layout.center,\r\n startPointerAngle: Math.atan2(world.y - layout.center.y, world.x - layout.center.x),\r\n startRotation: el.rotation ?? 0,\r\n };\r\n ctx.requestRender();\r\n return;\r\n }\r\n }\r\n\r\n const resizeHit = hitTestResizeHandle(world, ctx, this._selectedIds);\r\n if (resizeHit) {\r\n const el = ctx.store.getById(resizeHit.elementId);\r\n if (el && 'size' in el) {\r\n this.resizeAspectRatio = el.size.h > 0 ? el.size.w / el.size.h : 0;\r\n this.mode = {\r\n type: 'resizing',\r\n elementId: resizeHit.elementId,\r\n handle: resizeHit.handle,\r\n };\r\n ctx.requestRender();\r\n return;\r\n }\r\n }\r\n\r\n this.pendingSingleSelectId = null;\r\n this.hasDragged = false;\r\n const hit = hitTest(world, ctx);\r\n if (hit) {\r\n const all = ctx.store.getAll();\r\n const alreadySelected = this._selectedIds.includes(hit.id);\r\n if (state.shiftKey) {\r\n if (alreadySelected) {\r\n const grp = new Set(expandToGroups([hit.id], all));\r\n this.setSelectedIds(this._selectedIds.filter((id) => !grp.has(id)));\r\n this.mode = { type: 'idle' };\r\n } else {\r\n this.setSelectedIds(expandToGroups([...this._selectedIds, hit.id], all));\r\n this.mode = hit.locked ? { type: 'idle' } : { type: 'dragging' };\r\n }\r\n } else {\r\n if (!alreadySelected) {\r\n this.setSelectedIds(expandToGroups([hit.id], all));\r\n } else if (this._selectedIds.length > 1) {\r\n this.pendingSingleSelectId = hit.id;\r\n }\r\n this.mode = hit.locked ? { type: 'idle' } : { type: 'dragging' };\r\n }\r\n } else {\r\n this.setSelectedIds([]);\r\n this.mode = { type: 'marquee', start: world };\r\n }\r\n\r\n ctx.requestRender();\r\n }\r\n\r\n onPointerMove(state: PointerState, ctx: ToolContext): void {\r\n const world = ctx.camera.screenToWorld({ x: state.x, y: state.y });\r\n this.currentWorld = world;\r\n\r\n if (this.mode.type === 'arrow-handle') {\r\n ctx.setCursor?.(getArrowHandleCursor(this.mode.handle, true));\r\n applyArrowHandleDrag(this.mode.handle, this.mode.elementId, world, ctx);\r\n return;\r\n }\r\n\r\n if (this.mode.type === 'line-handle') {\r\n ctx.setCursor?.('grabbing');\r\n const el = ctx.store.getById(this.mode.elementId);\r\n if (\r\n el &&\r\n el.type === 'shape' &&\r\n el.shape === 'line' &&\r\n !el.locked &&\r\n !(ctx.isLayerLocked?.(el.layerId) ?? false)\r\n ) {\r\n ctx.store.update(el.id, lineFromEndpoints(this.mode.fixed, world));\r\n ctx.requestRender();\r\n }\r\n return;\r\n }\r\n\r\n if (this.mode.type === 'resizing-template') {\r\n ctx.setCursor?.('nwse-resize');\r\n this.handleTemplateResize(world, ctx);\r\n return;\r\n }\r\n\r\n if (this.mode.type === 'aiming-template') {\r\n const el = ctx.store.getById(this.mode.elementId);\r\n if (el && el.type === 'template' && !el.locked) {\r\n let a = Math.atan2(world.y - el.position.y, world.x - el.position.x);\r\n if (state.shiftKey) {\r\n const snap = ctx.gridType === 'hex' ? Math.PI / 3 : ROTATE_SNAP;\r\n a = Math.round(a / snap) * snap;\r\n }\r\n ctx.store.update(this.mode.elementId, { angle: normalizeAngle(a) });\r\n ctx.requestRender();\r\n }\r\n return;\r\n }\r\n\r\n if (this.mode.type === 'resizing-rect-length' || this.mode.type === 'resizing-rect-width') {\r\n ctx.setCursor?.(this.mode.type === 'resizing-rect-length' ? 'ew-resize' : 'ns-resize');\r\n const el = ctx.store.getById(this.mode.elementId);\r\n if (el && el.type === 'template' && !el.locked) {\r\n const opts = { snapToGrid: ctx.snapToGrid, gridSize: ctx.gridSize, gridType: ctx.gridType };\r\n const patch =\r\n this.mode.type === 'resizing-rect-length'\r\n ? computeRectangleLengthResize(el, world, opts)\r\n : computeRectangleWidthResize(el, world, opts);\r\n if (patch) {\r\n ctx.store.update(this.mode.elementId, patch);\r\n ctx.requestRender();\r\n }\r\n }\r\n return;\r\n }\r\n\r\n if (this.mode.type === 'rotating') {\r\n const { elementId, center, startPointerAngle, startRotation } = this.mode;\r\n const a = Math.atan2(world.y - center.y, world.x - center.x);\r\n let next = startRotation + (a - startPointerAngle);\r\n if (state.shiftKey) next = Math.round(next / ROTATE_SNAP) * ROTATE_SNAP;\r\n ctx.store.update(elementId, { rotation: normalizeAngle(next) });\r\n ctx.requestRender();\r\n return;\r\n }\r\n\r\n if (this.mode.type === 'resizing') {\r\n ctx.setCursor?.(HANDLE_CURSORS[this.mode.handle]);\r\n this.handleResize(world, ctx, state.shiftKey);\r\n return;\r\n }\r\n\r\n if (this.mode.type === 'dragging' && this._selectedIds.length > 0) {\r\n this.hasDragged = true;\r\n ctx.setCursor?.('move');\r\n const snapped = this.snap(world, ctx);\r\n const dx = snapped.x - this.lastWorld.x;\r\n const dy = snapped.y - this.lastWorld.y;\r\n this.lastWorld = snapped;\r\n\r\n let adjDx = dx;\r\n let adjDy = dy;\r\n this.activeGuides = [];\r\n if (ctx.smartGuides) {\r\n // Candidates (non-selected visible elements) and the viewport rect don't change\r\n // during a single-pointer drag, so compute them once per drag and reuse each frame.\r\n if (this.dragSnapTargets === null) {\r\n const selSet = new Set(this._selectedIds);\r\n this.dragVisibleRect = ctx.getVisibleRect?.() ?? null;\r\n const candidates = (\r\n this.dragVisibleRect ? ctx.store.queryRect(this.dragVisibleRect) : ctx.store.getAll()\r\n ).filter((el) => !selSet.has(el.id) && el.type !== 'grid');\r\n const targets: Bounds[] = [];\r\n for (const el of candidates) {\r\n const b = getElementBounds(el);\r\n if (b) targets.push(b);\r\n }\r\n this.dragSnapTargets = targets;\r\n }\r\n const selectedEls = this._selectedIds\r\n .map((id) => ctx.store.getById(id))\r\n .filter((el): el is CanvasElement => !!el && !el.locked);\r\n const base = getElementsBoundingBox(selectedEls);\r\n if (base) {\r\n const moving: Bounds = { x: base.x + dx, y: base.y + dy, w: base.w, h: base.h };\r\n const res = computeSnapGuides(moving, this.dragSnapTargets, SNAP_PX / ctx.camera.zoom);\r\n adjDx = dx + res.dx;\r\n adjDy = dy + res.dy;\r\n this.activeGuides = res.guides;\r\n }\r\n }\r\n\r\n for (const id of this._selectedIds) {\r\n const el = ctx.store.getById(id);\r\n if (!el || el.locked) continue;\r\n\r\n if (el.type === 'arrow') {\r\n if (el.fromBinding || el.toBinding) {\r\n continue;\r\n }\r\n\r\n ctx.store.update(id, {\r\n position: { x: el.position.x + adjDx, y: el.position.y + adjDy },\r\n from: { x: el.from.x + adjDx, y: el.from.y + adjDy },\r\n to: { x: el.to.x + adjDx, y: el.to.y + adjDy },\r\n });\r\n } else if (!ctx.smartGuides && ctx.gridType && 'size' in el) {\r\n const centerX = el.position.x + el.size.w / 2 + adjDx;\r\n const centerY = el.position.y + el.size.h / 2 + adjDy;\r\n const snappedCenter = this.snap({ x: centerX, y: centerY }, ctx);\r\n ctx.store.update(id, {\r\n position: {\r\n x: snappedCenter.x - el.size.w / 2,\r\n y: snappedCenter.y - el.size.h / 2,\r\n },\r\n });\r\n } else {\r\n ctx.store.update(id, {\r\n position: { x: el.position.x + adjDx, y: el.position.y + adjDy },\r\n });\r\n }\r\n }\r\n\r\n this.updateArrowsBoundTo(this._selectedIds, ctx);\r\n\r\n ctx.requestRender();\r\n return;\r\n }\r\n\r\n if (this.mode.type === 'marquee') {\r\n ctx.setCursor?.('crosshair');\r\n ctx.requestRender();\r\n return;\r\n }\r\n\r\n this.updateHoverCursor(world, ctx);\r\n }\r\n\r\n onPointerUp(_state: PointerState, ctx: ToolContext): void {\r\n if (this.mode.type === 'marquee') {\r\n const rect = this.getMarqueeRect();\r\n if (rect) {\r\n this.setSelectedIds(expandToGroups(findElementsInRect(rect, ctx), ctx.store.getAll()));\r\n }\r\n ctx.requestRender();\r\n }\r\n\r\n if (!this.hasDragged && this.pendingSingleSelectId !== null) {\r\n this.setSelectedIds(expandToGroups([this.pendingSingleSelectId], ctx.store.getAll()));\r\n }\r\n this.pendingSingleSelectId = null;\r\n this.hasDragged = false;\r\n\r\n const resizedNoteId = this.mode.type === 'resizing' ? this.mode.elementId : null;\r\n\r\n this.mode = { type: 'idle' };\r\n this.activeGuides = [];\r\n this.dragSnapTargets = null;\r\n this.dragVisibleRect = null;\r\n ctx.requestRender();\r\n ctx.setCursor?.('default');\r\n\r\n if (resizedNoteId !== null) {\r\n const el = ctx.store.getById(resizedNoteId);\r\n // Runs during tool pointer-up, inside the InputHandler resize transaction, so the\r\n // height fit coalesces into the same undo step as the resize.\r\n if (el?.type === 'note') ctx.fitNoteHeight?.(resizedNoteId);\r\n }\r\n }\r\n\r\n onHover(state: PointerState, ctx: ToolContext): void {\r\n const world = ctx.camera.screenToWorld({ x: state.x, y: state.y });\r\n const hoverId = this.updateHoverCursor(world, ctx);\r\n this.setHovered(hoverId, ctx);\r\n }\r\n\r\n renderOverlay(canvasCtx: CanvasRenderingContext2D): void {\r\n if (this.mode.type === 'marquee') {\r\n const rect = this.getMarqueeRect();\r\n if (rect) renderMarquee(canvasCtx, rect);\r\n }\r\n if (this.ctx)\r\n renderSelectionBoxes(canvasCtx, {\r\n selectedIds: this._selectedIds,\r\n store: this.ctx.store,\r\n zoom: this.ctx.camera.zoom,\r\n isLayerLocked: this.ctx.isLayerLocked,\r\n });\r\n\r\n if (this.mode.type === 'arrow-handle' && this.ctx) {\r\n const target = getArrowHandleDragTarget(\r\n this.mode.handle,\r\n this.mode.elementId,\r\n this.currentWorld,\r\n this.ctx,\r\n );\r\n if (target) {\r\n canvasCtx.save();\r\n canvasCtx.strokeStyle = '#2196F3';\r\n canvasCtx.lineWidth = 2 / this.ctx.camera.zoom;\r\n canvasCtx.setLineDash([]);\r\n canvasCtx.strokeRect(target.x, target.y, target.w, target.h);\r\n canvasCtx.restore();\r\n }\r\n }\r\n\r\n if (this.hoveredId && this.ctx && this.mode.type === 'idle') {\r\n if (!this._selectedIds.includes(this.hoveredId)) {\r\n const el = this.ctx.store.getById(this.hoveredId);\r\n if (el?.type === 'arrow') {\r\n canvasCtx.save();\r\n canvasCtx.globalAlpha = 0.35;\r\n canvasCtx.setLineDash([]);\r\n renderArrowHoverHandle(canvasCtx, el, this.ctx.camera.zoom);\r\n canvasCtx.restore();\r\n } else if (el) {\r\n const b = getElementBounds(el);\r\n if (b) {\r\n canvasCtx.save();\r\n canvasCtx.strokeStyle = '#2196F3';\r\n canvasCtx.globalAlpha = 0.35;\r\n canvasCtx.lineWidth = 1.5 / this.ctx.camera.zoom;\r\n canvasCtx.setLineDash([]);\r\n canvasCtx.strokeRect(b.x, b.y, b.w, b.h);\r\n canvasCtx.restore();\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (this.mode.type === 'dragging' && this.ctx && this.activeGuides.length)\r\n renderGuideLines(canvasCtx, {\r\n guides: this.activeGuides,\r\n rect: this.dragVisibleRect,\r\n currentWorld: this.currentWorld,\r\n zoom: this.ctx.camera.zoom,\r\n });\r\n }\r\n\r\n private updateArrowsBoundTo(ids: Iterable<string>, ctx: ToolContext): void {\r\n updateArrowsBoundToElements(ids, ctx.store);\r\n }\r\n\r\n nudgeSelection(dx: number, dy: number, ctx: ToolContext): boolean {\r\n let moved = false;\r\n for (const id of this._selectedIds) {\r\n const el = ctx.store.getById(id);\r\n if (!el || el.locked) continue;\r\n if (el.type === 'arrow' && (el.fromBinding || el.toBinding)) continue;\r\n ctx.store.update(id, translateElementPatch(el, dx, dy));\r\n moved = true;\r\n }\r\n\r\n if (moved) {\r\n this.updateArrowsBoundTo(this._selectedIds, ctx);\r\n ctx.requestRender();\r\n }\r\n return moved;\r\n }\r\n\r\n private updateHoverCursor(world: Point, ctx: ToolContext): string | null {\r\n const arrowHit = hitTestArrowHandles(world, this._selectedIds, ctx);\r\n if (arrowHit) {\r\n ctx.setCursor?.(getArrowHandleCursor(arrowHit.handle, false));\r\n return null;\r\n }\r\n\r\n if (hitTestLineHandles(world, ctx, this._selectedIds)) {\r\n ctx.setCursor?.('grab');\r\n return null;\r\n }\r\n\r\n const templateResizeHit = hitTestTemplateResizeHandle(world, ctx, this._selectedIds);\r\n if (templateResizeHit) {\r\n ctx.setCursor?.('nwse-resize');\r\n return null;\r\n }\r\n\r\n if (hitTestRectangleLengthHandle(world, ctx, this._selectedIds)) {\r\n ctx.setCursor?.('ew-resize');\r\n return null;\r\n }\r\n if (hitTestRectangleWidthHandle(world, ctx, this._selectedIds)) {\r\n ctx.setCursor?.('ns-resize');\r\n return null;\r\n }\r\n\r\n if (hitTestTemplateAimHandle(world, ctx, this._selectedIds)) {\r\n ctx.setCursor?.('grab');\r\n return null;\r\n }\r\n\r\n if (hitTestRotateHandle(world, ctx, this._selectedIds)) {\r\n ctx.setCursor?.('grab');\r\n return null;\r\n }\r\n\r\n const resizeHit = hitTestResizeHandle(world, ctx, this._selectedIds);\r\n if (resizeHit) {\r\n ctx.setCursor?.(HANDLE_CURSORS[resizeHit.handle]);\r\n return null;\r\n }\r\n\r\n const hit = hitTest(world, ctx);\r\n ctx.setCursor?.(hit ? 'move' : 'default');\r\n return hit ? hit.id : null;\r\n }\r\n\r\n private setHovered(id: string | null, ctx: ToolContext): void {\r\n if (this.hoveredId === id) return;\r\n this.hoveredId = id;\r\n ctx.requestRender();\r\n }\r\n\r\n private handleResize(world: Point, ctx: ToolContext, shiftKey = false): void {\r\n if (this.mode.type !== 'resizing') return;\r\n\r\n const el = ctx.store.getById(this.mode.elementId);\r\n if (!el || !('size' in el) || el.locked) return;\r\n\r\n const lockAspect = shiftKey !== (el.type === 'image');\r\n\r\n const angle = el.rotation ?? 0;\r\n const patch =\r\n angle !== 0\r\n ? computeRotatedResize(\r\n el,\r\n this.mode.handle,\r\n angle,\r\n world,\r\n this.lastWorld,\r\n this.resizeAspectRatio,\r\n lockAspect,\r\n )\r\n : computeResize(\r\n el,\r\n this.mode.handle,\r\n world,\r\n this.lastWorld,\r\n this.resizeAspectRatio,\r\n lockAspect,\r\n );\r\n\r\n this.lastWorld = world;\r\n ctx.store.update(this.mode.elementId, patch);\r\n this.updateArrowsBoundTo([this.mode.elementId], ctx);\r\n ctx.requestRender();\r\n }\r\n\r\n private getOverlayLayout(el: CanvasElement, zoom: number): OverlayLayout | null {\r\n return getOverlayLayout(el, zoom);\r\n }\r\n\r\n private handleTemplateResize(world: Point, ctx: ToolContext): void {\r\n if (this.mode.type !== 'resizing-template') return;\r\n\r\n const el = ctx.store.getById(this.mode.elementId);\r\n if (!el || el.type !== 'template' || el.locked) return;\r\n\r\n const patch = computeTemplateResize(el, world, {\r\n snapToGrid: ctx.snapToGrid,\r\n gridSize: ctx.gridSize,\r\n gridType: ctx.gridType,\r\n });\r\n if (patch) {\r\n ctx.store.update(this.mode.elementId, patch);\r\n ctx.requestRender();\r\n }\r\n }\r\n\r\n private getMarqueeRect(): Bounds | null {\r\n if (this.mode.type !== 'marquee') return null;\r\n\r\n const { start } = this.mode;\r\n const end = this.currentWorld;\r\n const x = Math.min(start.x, end.x);\r\n const y = Math.min(start.y, end.y);\r\n const w = Math.abs(end.x - start.x);\r\n const h = Math.abs(end.y - start.y);\r\n\r\n if (w === 0 && h === 0) return null;\r\n return { x, y, w, h };\r\n }\r\n}\r\n","import type { Point } from '../core/types';\r\nimport type { ArrowStrokeStyle, Binding, CanvasElement } from '../elements/types';\r\nimport type { Tool, ToolContext, PointerState } from './types';\r\nimport { createArrow } from '../elements/element-factory';\r\nimport { findBindTarget, getElementCenter } from '../elements/arrow-binding';\r\nimport { getElementBounds } from '../elements/element-bounds';\r\nimport { smartSnap } from '../core/snap';\r\n\r\nconst BIND_THRESHOLD = 20;\r\n\r\nexport interface ArrowToolOptions {\r\n color?: string;\r\n width?: number;\r\n strokeStyle?: ArrowStrokeStyle;\r\n}\r\n\r\nexport class ArrowTool implements Tool {\r\n readonly name = 'arrow';\r\n private drawing = false;\r\n private start: Point = { x: 0, y: 0 };\r\n private end: Point = { x: 0, y: 0 };\r\n private color: string;\r\n private width: number;\r\n private strokeStyle: ArrowStrokeStyle;\r\n private fromBinding: Binding | undefined;\r\n private fromTarget: CanvasElement | null = null;\r\n private toTarget: CanvasElement | null = null;\r\n private optionListeners = new Set<() => void>();\r\n\r\n constructor(options: ArrowToolOptions = {}) {\r\n this.color = options.color ?? '#000000';\r\n this.width = options.width ?? 2;\r\n this.strokeStyle = options.strokeStyle ?? 'solid';\r\n }\r\n\r\n getOptions(): ArrowToolOptions {\r\n return { color: this.color, width: this.width, strokeStyle: this.strokeStyle };\r\n }\r\n\r\n onOptionsChange(listener: () => void): () => void {\r\n this.optionListeners.add(listener);\r\n return () => this.optionListeners.delete(listener);\r\n }\r\n\r\n setOptions(options: ArrowToolOptions): void {\r\n if (options.color !== undefined) this.color = options.color;\r\n if (options.width !== undefined) this.width = options.width;\r\n if (options.strokeStyle !== undefined) this.strokeStyle = options.strokeStyle;\r\n this.notifyOptionsChange();\r\n }\r\n\r\n private notifyOptionsChange(): void {\r\n for (const listener of this.optionListeners) listener();\r\n }\r\n\r\n private layerFilter(ctx: ToolContext): ((el: CanvasElement) => boolean) | undefined {\r\n const activeLayerId = ctx.activeLayerId;\r\n if (!activeLayerId && !ctx.isLayerVisible && !ctx.isLayerLocked) return undefined;\r\n return (el: CanvasElement) => {\r\n if (activeLayerId && el.layerId !== activeLayerId) return false;\r\n if (ctx.isLayerVisible && !ctx.isLayerVisible(el.layerId)) return false;\r\n if (ctx.isLayerLocked && ctx.isLayerLocked(el.layerId)) return false;\r\n return true;\r\n };\r\n }\r\n\r\n onPointerDown(state: PointerState, ctx: ToolContext): void {\r\n this.drawing = true;\r\n const world = ctx.camera.screenToWorld({ x: state.x, y: state.y });\r\n const threshold = BIND_THRESHOLD / ctx.camera.zoom;\r\n const filter = this.layerFilter(ctx);\r\n\r\n const target = findBindTarget(world, ctx.store, threshold, undefined, filter);\r\n if (target) {\r\n this.start = getElementCenter(target);\r\n this.fromBinding = { elementId: target.id };\r\n this.fromTarget = target;\r\n } else {\r\n this.start = smartSnap(world, ctx);\r\n this.fromBinding = undefined;\r\n this.fromTarget = null;\r\n }\r\n this.end = { ...this.start };\r\n this.toTarget = null;\r\n }\r\n\r\n onPointerMove(state: PointerState, ctx: ToolContext): void {\r\n if (!this.drawing) return;\r\n const world = ctx.camera.screenToWorld({ x: state.x, y: state.y });\r\n const threshold = BIND_THRESHOLD / ctx.camera.zoom;\r\n const excludeId = this.fromBinding?.elementId;\r\n const filter = this.layerFilter(ctx);\r\n\r\n const target = findBindTarget(world, ctx.store, threshold, excludeId, filter);\r\n if (target) {\r\n this.end = getElementCenter(target);\r\n this.toTarget = target;\r\n } else {\r\n this.end = smartSnap(world, ctx);\r\n this.toTarget = null;\r\n }\r\n ctx.requestRender();\r\n }\r\n\r\n onPointerUp(_state: PointerState, ctx: ToolContext): void {\r\n if (!this.drawing) return;\r\n this.drawing = false;\r\n\r\n if (this.start.x === this.end.x && this.start.y === this.end.y) return;\r\n\r\n const arrow = createArrow({\r\n from: this.start,\r\n to: this.end,\r\n position: this.start,\r\n color: this.color,\r\n width: this.width,\r\n strokeStyle: this.strokeStyle,\r\n fromBinding: this.fromBinding,\r\n toBinding: this.toTarget ? { elementId: this.toTarget.id } : undefined,\r\n layerId: ctx.activeLayerId ?? '',\r\n });\r\n ctx.store.add(arrow);\r\n this.fromTarget = null;\r\n this.toTarget = null;\r\n ctx.requestRender();\r\n ctx.switchTool?.('select');\r\n }\r\n\r\n renderOverlay(ctx: CanvasRenderingContext2D): void {\r\n if (!this.drawing) return;\r\n if (this.start.x === this.end.x && this.start.y === this.end.y) return;\r\n\r\n ctx.save();\r\n\r\n if (this.fromTarget) {\r\n const bounds = getElementBounds(this.fromTarget);\r\n if (bounds) {\r\n ctx.strokeStyle = '#2196F3';\r\n ctx.lineWidth = 2;\r\n ctx.setLineDash([]);\r\n ctx.strokeRect(bounds.x, bounds.y, bounds.w, bounds.h);\r\n }\r\n }\r\n\r\n if (this.toTarget) {\r\n const bounds = getElementBounds(this.toTarget);\r\n if (bounds) {\r\n ctx.strokeStyle = '#2196F3';\r\n ctx.lineWidth = 2;\r\n ctx.setLineDash([]);\r\n ctx.strokeRect(bounds.x, bounds.y, bounds.w, bounds.h);\r\n }\r\n }\r\n\r\n ctx.strokeStyle = this.color;\r\n ctx.lineWidth = this.width;\r\n ctx.lineCap = 'round';\r\n ctx.globalAlpha = 0.6;\r\n\r\n ctx.beginPath();\r\n ctx.moveTo(this.start.x, this.start.y);\r\n ctx.lineTo(this.end.x, this.end.y);\r\n ctx.stroke();\r\n\r\n const angle = Math.atan2(this.end.y - this.start.y, this.end.x - this.start.x);\r\n const headLen = 12;\r\n const headAngle = Math.PI / 6;\r\n\r\n ctx.fillStyle = this.color;\r\n ctx.beginPath();\r\n ctx.moveTo(this.end.x, this.end.y);\r\n ctx.lineTo(\r\n this.end.x - headLen * Math.cos(angle - headAngle),\r\n this.end.y - headLen * Math.sin(angle - headAngle),\r\n );\r\n ctx.lineTo(\r\n this.end.x - headLen * Math.cos(angle + headAngle),\r\n this.end.y - headLen * Math.sin(angle + headAngle),\r\n );\r\n ctx.closePath();\r\n ctx.fill();\r\n ctx.restore();\r\n }\r\n}\r\n","import type { Size } from '../core/types';\r\nimport type { Tool, ToolContext, PointerState } from './types';\r\nimport { createNote, DEFAULT_NOTE_FONT_SIZE } from '../elements/element-factory';\r\nimport { smartSnap } from '../core/snap';\r\n\r\nexport interface NoteToolOptions {\r\n backgroundColor?: string;\r\n textColor?: string;\r\n size?: Size;\r\n fontSize?: number;\r\n}\r\n\r\nexport class NoteTool implements Tool {\r\n readonly name = 'note';\r\n private backgroundColor: string;\r\n private textColor: string;\r\n private size: Size;\r\n private fontSize: number;\r\n private optionListeners = new Set<() => void>();\r\n\r\n constructor(options: NoteToolOptions = {}) {\r\n this.backgroundColor = options.backgroundColor ?? '#ffeb3b';\r\n this.textColor = options.textColor ?? '#000000';\r\n this.size = options.size ?? { w: 200, h: 100 };\r\n this.fontSize = options.fontSize ?? DEFAULT_NOTE_FONT_SIZE;\r\n }\r\n\r\n getOptions(): NoteToolOptions {\r\n return {\r\n backgroundColor: this.backgroundColor,\r\n textColor: this.textColor,\r\n size: { ...this.size },\r\n fontSize: this.fontSize,\r\n };\r\n }\r\n\r\n onOptionsChange(listener: () => void): () => void {\r\n this.optionListeners.add(listener);\r\n return () => this.optionListeners.delete(listener);\r\n }\r\n\r\n setOptions(options: NoteToolOptions): void {\r\n if (options.backgroundColor !== undefined) this.backgroundColor = options.backgroundColor;\r\n if (options.textColor !== undefined) this.textColor = options.textColor;\r\n if (options.size !== undefined) this.size = options.size;\r\n if (options.fontSize !== undefined) this.fontSize = options.fontSize;\r\n this.notifyOptionsChange();\r\n }\r\n\r\n private notifyOptionsChange(): void {\r\n for (const listener of this.optionListeners) listener();\r\n }\r\n\r\n onPointerDown(_state: PointerState, _ctx: ToolContext): void {\r\n // Note is placed on pointer up\r\n }\r\n\r\n onPointerMove(_state: PointerState, _ctx: ToolContext): void {\r\n // No drag behavior for note placement\r\n }\r\n\r\n onPointerUp(state: PointerState, ctx: ToolContext): void {\r\n let world = ctx.camera.screenToWorld({ x: state.x, y: state.y });\r\n world = smartSnap(world, ctx);\r\n const note = createNote({\r\n position: world,\r\n size: { ...this.size },\r\n backgroundColor: this.backgroundColor,\r\n textColor: this.textColor,\r\n fontSize: this.fontSize,\r\n layerId: ctx.activeLayerId ?? '',\r\n });\r\n ctx.store.add(note);\r\n ctx.requestRender();\r\n\r\n ctx.switchTool?.('select');\r\n ctx.editElement?.(note.id);\r\n }\r\n}\r\n","import type { Tool, ToolContext, PointerState } from './types';\r\nimport { createText } from '../elements/element-factory';\r\nimport { smartSnap } from '../core/snap';\r\n\r\nexport interface TextToolOptions {\r\n fontSize?: number;\r\n color?: string;\r\n textAlign?: 'left' | 'center' | 'right';\r\n}\r\n\r\nexport class TextTool implements Tool {\r\n readonly name = 'text';\r\n private fontSize: number;\r\n private color: string;\r\n private textAlign: 'left' | 'center' | 'right';\r\n private optionListeners = new Set<() => void>();\r\n\r\n constructor(options: TextToolOptions = {}) {\r\n this.fontSize = options.fontSize ?? 16;\r\n this.color = options.color ?? '#1a1a1a';\r\n this.textAlign = options.textAlign ?? 'left';\r\n }\r\n\r\n getOptions(): TextToolOptions {\r\n return { fontSize: this.fontSize, color: this.color, textAlign: this.textAlign };\r\n }\r\n\r\n onOptionsChange(listener: () => void): () => void {\r\n this.optionListeners.add(listener);\r\n return () => this.optionListeners.delete(listener);\r\n }\r\n\r\n setOptions(options: TextToolOptions): void {\r\n if (options.fontSize !== undefined) this.fontSize = options.fontSize;\r\n if (options.color !== undefined) this.color = options.color;\r\n if (options.textAlign !== undefined) this.textAlign = options.textAlign;\r\n this.notifyOptionsChange();\r\n }\r\n\r\n private notifyOptionsChange(): void {\r\n for (const listener of this.optionListeners) listener();\r\n }\r\n\r\n onActivate(ctx: ToolContext): void {\r\n ctx.setCursor?.('text');\r\n }\r\n\r\n onDeactivate(ctx: ToolContext): void {\r\n ctx.setCursor?.('default');\r\n }\r\n\r\n onPointerDown(_state: PointerState, _ctx: ToolContext): void {\r\n // Text is placed on pointer up\r\n }\r\n\r\n onPointerMove(_state: PointerState, _ctx: ToolContext): void {\r\n // No drag behavior for text placement\r\n }\r\n\r\n onPointerUp(state: PointerState, ctx: ToolContext): void {\r\n let world = ctx.camera.screenToWorld({ x: state.x, y: state.y });\r\n world = smartSnap(world, ctx);\r\n const textEl = createText({\r\n position: world,\r\n fontSize: this.fontSize,\r\n color: this.color,\r\n textAlign: this.textAlign,\r\n layerId: ctx.activeLayerId ?? '',\r\n });\r\n ctx.store.add(textEl);\r\n ctx.requestRender();\r\n\r\n ctx.switchTool?.('select');\r\n ctx.editElement?.(textEl.id);\r\n }\r\n}\r\n","import type { Size } from '../core/types';\r\nimport type { Tool, ToolContext, PointerState } from './types';\r\nimport { createImage } from '../elements/element-factory';\r\nimport { smartSnap } from '../core/snap';\r\n\r\nexport interface ImageToolOptions {\r\n size?: Size;\r\n}\r\n\r\nexport class ImageTool implements Tool {\r\n readonly name = 'image';\r\n private size: Size;\r\n private src: string | null = null;\r\n\r\n constructor(options: ImageToolOptions = {}) {\r\n this.size = options.size ?? { w: 300, h: 200 };\r\n }\r\n\r\n setSrc(src: string): void {\r\n this.src = src;\r\n }\r\n\r\n onPointerDown(_state: PointerState, _ctx: ToolContext): void {\r\n // No action on pointer down — image is placed on pointer up\r\n }\r\n\r\n onPointerMove(_state: PointerState, _ctx: ToolContext): void {\r\n // No action on pointer move\r\n }\r\n\r\n onPointerUp(state: PointerState, ctx: ToolContext): void {\r\n if (!this.src) return;\r\n\r\n const world = ctx.camera.screenToWorld({ x: state.x, y: state.y });\r\n const snapped = smartSnap(world, ctx);\r\n const image = createImage({\r\n position: {\r\n x: snapped.x - this.size.w / 2,\r\n y: snapped.y - this.size.h / 2,\r\n },\r\n size: { ...this.size },\r\n src: this.src,\r\n });\r\n ctx.store.add(image);\r\n ctx.requestRender();\r\n\r\n this.src = null;\r\n ctx.switchTool?.('select');\r\n }\r\n}\r\n","import type { Point } from '../core/types';\r\nimport type { ShapeKind } from '../elements/types';\r\nimport type { Tool, ToolContext, PointerState } from './types';\r\nimport { createShape } from '../elements/element-factory';\r\nimport { smartSnap } from '../core/snap';\r\n\r\nfunction snapTo45(start: Point, end: Point): Point {\r\n const dx = end.x - start.x;\r\n const dy = end.y - start.y;\r\n const len = Math.hypot(dx, dy);\r\n if (len === 0) return { ...end };\r\n const step = Math.PI / 4;\r\n const angle = Math.round(Math.atan2(dy, dx) / step) * step;\r\n return { x: start.x + Math.cos(angle) * len, y: start.y + Math.sin(angle) * len };\r\n}\r\n\r\nexport interface ShapeToolOptions {\r\n shape?: ShapeKind;\r\n strokeColor?: string;\r\n strokeWidth?: number;\r\n fillColor?: string;\r\n}\r\n\r\nexport class ShapeTool implements Tool {\r\n readonly name = 'shape';\r\n private drawing = false;\r\n private start: Point = { x: 0, y: 0 };\r\n private end: Point = { x: 0, y: 0 };\r\n private shiftHeld = false;\r\n private shape: ShapeKind;\r\n private strokeColor: string;\r\n private strokeWidth: number;\r\n private fillColor: string;\r\n private optionListeners = new Set<() => void>();\r\n\r\n constructor(options: ShapeToolOptions = {}) {\r\n this.shape = options.shape ?? 'rectangle';\r\n this.strokeColor = options.strokeColor ?? '#000000';\r\n this.strokeWidth = options.strokeWidth ?? 2;\r\n this.fillColor = options.fillColor ?? 'none';\r\n }\r\n\r\n getOptions(): ShapeToolOptions {\r\n return {\r\n shape: this.shape,\r\n strokeColor: this.strokeColor,\r\n strokeWidth: this.strokeWidth,\r\n fillColor: this.fillColor,\r\n };\r\n }\r\n\r\n onOptionsChange(listener: () => void): () => void {\r\n this.optionListeners.add(listener);\r\n return () => this.optionListeners.delete(listener);\r\n }\r\n\r\n setOptions(options: ShapeToolOptions): void {\r\n if (options.shape !== undefined) this.shape = options.shape;\r\n if (options.strokeColor !== undefined) this.strokeColor = options.strokeColor;\r\n if (options.strokeWidth !== undefined) this.strokeWidth = options.strokeWidth;\r\n if (options.fillColor !== undefined) this.fillColor = options.fillColor;\r\n this.notifyOptionsChange();\r\n }\r\n\r\n onActivate(_ctx: ToolContext): void {\r\n if (typeof window !== 'undefined') {\r\n window.addEventListener('keydown', this.onKeyDown);\r\n window.addEventListener('keyup', this.onKeyUp);\r\n }\r\n }\r\n\r\n onDeactivate(_ctx: ToolContext): void {\r\n this.shiftHeld = false;\r\n if (typeof window !== 'undefined') {\r\n window.removeEventListener('keydown', this.onKeyDown);\r\n window.removeEventListener('keyup', this.onKeyUp);\r\n }\r\n }\r\n\r\n onPointerDown(state: PointerState, ctx: ToolContext): void {\r\n this.drawing = true;\r\n this.start = this.snap(ctx.camera.screenToWorld({ x: state.x, y: state.y }), ctx);\r\n this.end = { ...this.start };\r\n }\r\n\r\n onPointerMove(state: PointerState, ctx: ToolContext): void {\r\n if (!this.drawing) return;\r\n this.end = this.snap(ctx.camera.screenToWorld({ x: state.x, y: state.y }), ctx);\r\n if (this.shape === 'line' && this.shiftHeld) {\r\n this.end = snapTo45(this.start, this.end);\r\n }\r\n ctx.requestRender();\r\n }\r\n\r\n onPointerUp(_state: PointerState, ctx: ToolContext): void {\r\n if (!this.drawing) return;\r\n this.drawing = false;\r\n\r\n const { position, size } = this.computeRect();\r\n const isLine = this.shape === 'line';\r\n if (isLine ? size.w === 0 && size.h === 0 : size.w === 0 || size.h === 0) return;\r\n\r\n const shape = createShape({\r\n position,\r\n size,\r\n shape: this.shape,\r\n strokeColor: this.strokeColor,\r\n strokeWidth: this.strokeWidth,\r\n fillColor: this.fillColor,\r\n ...(isLine ? { flip: this.end.x > this.start.x !== this.end.y > this.start.y } : {}),\r\n layerId: ctx.activeLayerId ?? '',\r\n });\r\n ctx.store.add(shape);\r\n ctx.requestRender();\r\n ctx.switchTool?.('select');\r\n }\r\n\r\n renderOverlay(ctx: CanvasRenderingContext2D): void {\r\n if (!this.drawing) return;\r\n\r\n const { position, size } = this.computeRect();\r\n if (size.w === 0 && size.h === 0) return;\r\n\r\n ctx.save();\r\n ctx.globalAlpha = 0.5;\r\n ctx.strokeStyle = this.strokeColor;\r\n ctx.lineWidth = this.strokeWidth;\r\n\r\n if (this.fillColor !== 'none') {\r\n ctx.fillStyle = this.fillColor;\r\n }\r\n\r\n switch (this.shape) {\r\n case 'rectangle':\r\n if (this.fillColor !== 'none') {\r\n ctx.fillRect(position.x, position.y, size.w, size.h);\r\n }\r\n ctx.strokeRect(position.x, position.y, size.w, size.h);\r\n break;\r\n case 'ellipse': {\r\n const cx = position.x + size.w / 2;\r\n const cy = position.y + size.h / 2;\r\n ctx.beginPath();\r\n ctx.ellipse(cx, cy, size.w / 2, size.h / 2, 0, 0, Math.PI * 2);\r\n if (this.fillColor !== 'none') ctx.fill();\r\n ctx.stroke();\r\n break;\r\n }\r\n case 'line':\r\n ctx.lineCap = 'round';\r\n ctx.beginPath();\r\n ctx.moveTo(this.start.x, this.start.y);\r\n ctx.lineTo(this.end.x, this.end.y);\r\n ctx.stroke();\r\n break;\r\n }\r\n\r\n ctx.restore();\r\n }\r\n\r\n private computeRect(): { position: Point; size: { w: number; h: number } } {\r\n let x = Math.min(this.start.x, this.end.x);\r\n let y = Math.min(this.start.y, this.end.y);\r\n let w = Math.abs(this.end.x - this.start.x);\r\n let h = Math.abs(this.end.y - this.start.y);\r\n\r\n if (this.shiftHeld && this.shape !== 'line') {\r\n const side = Math.max(w, h);\r\n w = side;\r\n h = side;\r\n x = this.end.x >= this.start.x ? this.start.x : this.start.x - side;\r\n y = this.end.y >= this.start.y ? this.start.y : this.start.y - side;\r\n }\r\n\r\n return { position: { x, y }, size: { w, h } };\r\n }\r\n\r\n private notifyOptionsChange(): void {\r\n for (const listener of this.optionListeners) listener();\r\n }\r\n\r\n private snap(point: Point, ctx: ToolContext): Point {\r\n return smartSnap(point, ctx);\r\n }\r\n\r\n private onKeyDown = (e: KeyboardEvent): void => {\r\n if (e.key === 'Shift') this.shiftHeld = true;\r\n };\r\n\r\n private onKeyUp = (e: KeyboardEvent): void => {\r\n if (e.key === 'Shift') this.shiftHeld = false;\r\n };\r\n}\r\n","import type { Point } from '../core/types';\r\nimport type { HexOrientation } from '../elements/types';\r\nimport type { Tool, ToolContext, PointerState } from './types';\r\nimport { snapPoint, snapToHexCenter } from '../core/snap';\r\nimport { getHexDistance } from '../elements/hex-fill';\r\nimport { drawMeasurement } from '../canvas/measure-render';\r\n\r\nexport interface MeasureToolOptions {\r\n feetPerCell?: number;\r\n color?: string;\r\n}\r\n\r\nexport interface Measurement {\r\n start: Point;\r\n end: Point;\r\n worldDistance: number;\r\n cells: number;\r\n feet: number;\r\n}\r\n\r\n/**\r\n * A raf-coalesced snapshot of the in-progress measurement — the outgoing\r\n * side of a shared live ruler. Emissions carry world coordinates, derived\r\n * distance, and the tool's current color so a host can forward them as\r\n * ephemeral presence without duplicating the tool's input handling.\r\n * Ephemeral by contract: presence only — never elements, history, or\r\n * persisted state.\r\n */\r\nexport interface MeasureEmission {\r\n readonly start: Point;\r\n readonly end: Point;\r\n readonly worldDistance: number;\r\n readonly cells: number;\r\n readonly feet: number;\r\n readonly color: string;\r\n}\r\n\r\nexport class MeasureTool implements Tool {\r\n readonly name = 'measure';\r\n private start: Point | null = null;\r\n private end: Point | null = null;\r\n private gridSize = 1;\r\n private gridType: 'square' | 'hex' | undefined;\r\n private hexOrientation: HexOrientation | undefined;\r\n private feetPerCell: number;\r\n private color: string;\r\n private optionListeners = new Set<() => void>();\r\n private measurementListeners = new Set<(emission: MeasureEmission | null) => void>();\r\n private emissionRafId: number | null = null;\r\n\r\n constructor(options: MeasureToolOptions = {}) {\r\n this.feetPerCell = options.feetPerCell ?? 5;\r\n this.color = options.color ?? '#FF5722';\r\n }\r\n\r\n getOptions(): MeasureToolOptions {\r\n return { feetPerCell: this.feetPerCell, color: this.color };\r\n }\r\n\r\n setOptions(options: MeasureToolOptions): void {\r\n if (options.feetPerCell !== undefined) this.feetPerCell = options.feetPerCell;\r\n if (options.color !== undefined) this.color = options.color;\r\n this.notifyOptionsChange();\r\n }\r\n\r\n onOptionsChange(listener: () => void): () => void {\r\n this.optionListeners.add(listener);\r\n return () => this.optionListeners.delete(listener);\r\n }\r\n\r\n /**\r\n * Subscribes to raf-coalesced measurement snapshots. While a measurement is\r\n * in progress, listeners receive at most one snapshot per animation frame\r\n * carrying the latest state; `null` is delivered synchronously when the\r\n * measurement clears (pointer-up or deactivate). Emissions are ephemeral by\r\n * contract: presence only — never elements, history, or persisted state.\r\n */\r\n onMeasurement(listener: (emission: MeasureEmission | null) => void): () => void {\r\n this.measurementListeners.add(listener);\r\n return () => this.measurementListeners.delete(listener);\r\n }\r\n\r\n onPointerDown(state: PointerState, ctx: ToolContext): void {\r\n this.gridSize = ctx.gridSize ?? 1;\r\n this.gridType = ctx.gridType;\r\n this.hexOrientation = ctx.hexOrientation;\r\n const world = ctx.camera.screenToWorld({ x: state.x, y: state.y });\r\n this.start = this.snapToGrid(world, ctx);\r\n this.end = { ...this.start };\r\n this.scheduleEmission();\r\n }\r\n\r\n onPointerMove(state: PointerState, ctx: ToolContext): void {\r\n if (!this.start) return;\r\n const world = ctx.camera.screenToWorld({ x: state.x, y: state.y });\r\n this.end = this.snapToGrid(world, ctx);\r\n ctx.requestRender();\r\n this.scheduleEmission();\r\n }\r\n\r\n onPointerUp(_state: PointerState, ctx: ToolContext): void {\r\n if (!this.start) return;\r\n this.start = null;\r\n this.end = null;\r\n ctx.requestRender();\r\n this.emitClear();\r\n }\r\n\r\n onDeactivate(_ctx: ToolContext): void {\r\n const wasActive = this.start !== null;\r\n this.start = null;\r\n this.end = null;\r\n if (wasActive) this.emitClear();\r\n }\r\n\r\n getMeasurement(): Measurement | null {\r\n if (!this.start || !this.end) return null;\r\n const dx = this.end.x - this.start.x;\r\n const dy = this.end.y - this.start.y;\r\n const worldDistance = Math.sqrt(dx * dx + dy * dy);\r\n\r\n let cells: number;\r\n if (this.gridType === 'hex' && this.hexOrientation) {\r\n cells = getHexDistance(this.start, this.end, this.gridSize, this.hexOrientation);\r\n } else {\r\n const snapUnit = this.gridSize;\r\n cells = worldDistance / snapUnit;\r\n }\r\n\r\n const feet = cells * this.feetPerCell;\r\n return {\r\n start: { ...this.start },\r\n end: { ...this.end },\r\n worldDistance,\r\n cells,\r\n feet,\r\n };\r\n }\r\n\r\n renderOverlay(ctx: CanvasRenderingContext2D): void {\r\n const m = this.getMeasurement();\r\n if (!m) return;\r\n drawMeasurement(ctx, { start: m.start, end: m.end, feet: m.feet, color: this.color });\r\n }\r\n\r\n private snapToGrid(point: Point, ctx: ToolContext): Point {\r\n if (!ctx.gridSize) return point;\r\n if (ctx.gridType === 'hex' && ctx.hexOrientation) {\r\n return snapToHexCenter(point, ctx.gridSize, ctx.hexOrientation);\r\n }\r\n if (ctx.gridType === 'square') {\r\n return snapPoint(point, ctx.gridSize);\r\n }\r\n if (ctx.snapToGrid) {\r\n return snapPoint(point, ctx.gridSize);\r\n }\r\n return point;\r\n }\r\n\r\n private notifyOptionsChange(): void {\r\n for (const listener of this.optionListeners) listener();\r\n }\r\n\r\n private scheduleEmission(): void {\r\n if (this.measurementListeners.size === 0) return;\r\n if (this.emissionRafId !== null) return;\r\n this.emissionRafId = requestAnimationFrame(() => {\r\n this.emissionRafId = null;\r\n const m = this.getMeasurement();\r\n if (!m) return; // cleared before the frame; the sync null already went out\r\n this.emit({ ...m, color: this.color });\r\n });\r\n }\r\n\r\n private emitClear(): void {\r\n if (this.emissionRafId !== null) {\r\n cancelAnimationFrame(this.emissionRafId);\r\n this.emissionRafId = null;\r\n }\r\n if (this.measurementListeners.size === 0) return;\r\n this.emit(null);\r\n }\r\n\r\n private emit(emission: MeasureEmission | null): void {\r\n for (const listener of this.measurementListeners) {\r\n try {\r\n listener(emission);\r\n } catch {\r\n // A throwing host listener must not break measurement input.\r\n }\r\n }\r\n }\r\n}\r\n","import type { Point } from '../core/types';\r\nimport type { TemplateShape, HexOrientation, TemplateRenderStyle } from '../elements/types';\r\nimport type { Tool, ToolContext, PointerState } from './types';\r\nimport { createTemplate } from '../elements/element-factory';\r\nimport { snapPoint, snapToHexCenter } from '../core/snap';\r\nimport {\r\n getHexCellsInRadius,\r\n getHexCellsInCone,\r\n getHexCellsInLine,\r\n getHexCellsInSquare,\r\n getHexCellsInRectangle,\r\n drawHexPath,\r\n} from '../elements/hex-fill';\r\nimport { renderTemplateFeetLabel } from '../elements/renderers/template-measure';\r\n\r\nconst MIN_RECT_WIDTH = 20;\r\n\r\nexport function defaultRectWidth(radius: number, scaleUnit: number): number {\r\n if (scaleUnit > 0) return scaleUnit; // one grid cell\r\n return Math.max(MIN_RECT_WIDTH, radius * 0.25);\r\n}\r\n\r\nexport interface TemplateToolOptions {\r\n templateShape?: TemplateShape;\r\n fillColor?: string;\r\n strokeColor?: string;\r\n strokeWidth?: number;\r\n opacity?: number;\r\n feetPerCell?: number;\r\n renderStyle?: TemplateRenderStyle;\r\n}\r\n\r\nexport class TemplateTool implements Tool {\r\n readonly name = 'template';\r\n private drawing = false;\r\n private origin: Point = { x: 0, y: 0 };\r\n private current: Point = { x: 0, y: 0 };\r\n private gridSize = 1;\r\n private gridType: 'square' | 'hex' | undefined;\r\n private hexOrientation: HexOrientation | undefined;\r\n private snapEnabled = false;\r\n private feetScaleUnit = 0;\r\n private templateShape: TemplateShape;\r\n private fillColor: string;\r\n private strokeColor: string;\r\n private strokeWidth: number;\r\n private opacity: number;\r\n private feetPerCell: number;\r\n private renderStyle: TemplateRenderStyle;\r\n private optionListeners = new Set<() => void>();\r\n\r\n constructor(options: TemplateToolOptions = {}) {\r\n this.templateShape = options.templateShape ?? 'circle';\r\n this.fillColor = options.fillColor ?? 'rgba(255, 87, 34, 0.2)';\r\n this.strokeColor = options.strokeColor ?? '#FF5722';\r\n this.strokeWidth = options.strokeWidth ?? 2;\r\n this.opacity = options.opacity ?? 0.6;\r\n this.feetPerCell = options.feetPerCell ?? 5;\r\n this.renderStyle = options.renderStyle ?? 'cells';\r\n }\r\n\r\n getOptions(): TemplateToolOptions {\r\n return {\r\n templateShape: this.templateShape,\r\n fillColor: this.fillColor,\r\n strokeColor: this.strokeColor,\r\n strokeWidth: this.strokeWidth,\r\n opacity: this.opacity,\r\n feetPerCell: this.feetPerCell,\r\n renderStyle: this.renderStyle,\r\n };\r\n }\r\n\r\n setOptions(options: TemplateToolOptions): void {\r\n if (options.templateShape !== undefined) this.templateShape = options.templateShape;\r\n if (options.fillColor !== undefined) this.fillColor = options.fillColor;\r\n if (options.strokeColor !== undefined) this.strokeColor = options.strokeColor;\r\n if (options.strokeWidth !== undefined) this.strokeWidth = options.strokeWidth;\r\n if (options.opacity !== undefined) this.opacity = options.opacity;\r\n if (options.feetPerCell !== undefined) this.feetPerCell = options.feetPerCell;\r\n if (options.renderStyle !== undefined) this.renderStyle = options.renderStyle;\r\n this.notifyOptionsChange();\r\n }\r\n\r\n onOptionsChange(listener: () => void): () => void {\r\n this.optionListeners.add(listener);\r\n return () => this.optionListeners.delete(listener);\r\n }\r\n\r\n onPointerDown(state: PointerState, ctx: ToolContext): void {\r\n this.drawing = true;\r\n this.gridSize = ctx.gridSize ?? 1;\r\n this.gridType = ctx.gridType;\r\n this.hexOrientation = ctx.hexOrientation;\r\n this.snapEnabled = !!ctx.gridType || (ctx.snapToGrid ?? false);\r\n this.feetScaleUnit =\r\n ctx.gridSize && ctx.gridSize > 0\r\n ? ctx.gridType === 'hex'\r\n ? Math.sqrt(3) * ctx.gridSize\r\n : ctx.gridSize\r\n : 0;\r\n const world = ctx.camera.screenToWorld({ x: state.x, y: state.y });\r\n this.origin = this.snapToGrid(world, ctx);\r\n this.current = { ...this.origin };\r\n }\r\n\r\n onPointerMove(state: PointerState, ctx: ToolContext): void {\r\n if (!this.drawing) return;\r\n this.current = ctx.camera.screenToWorld({ x: state.x, y: state.y });\r\n ctx.requestRender();\r\n }\r\n\r\n onPointerUp(_state: PointerState, ctx: ToolContext): void {\r\n if (!this.drawing) return;\r\n this.drawing = false;\r\n\r\n const radius = this.computeRadius();\r\n if (radius <= 0) return;\r\n\r\n const angle = this.computeAngle();\r\n const gridSize = ctx.gridSize;\r\n const snapUnit =\r\n gridSize && gridSize > 0 ? (ctx.gridType === 'hex' ? Math.sqrt(3) * gridSize : gridSize) : 0;\r\n const cells = snapUnit > 0 ? radius / snapUnit : 0;\r\n const radiusFeet = cells * this.feetPerCell;\r\n const width =\r\n this.templateShape === 'rectangle' ? defaultRectWidth(radius, this.feetScaleUnit) : undefined;\r\n\r\n const element = createTemplate({\r\n position: { ...this.origin },\r\n templateShape: this.templateShape,\r\n radius,\r\n angle,\r\n width,\r\n fillColor: this.fillColor,\r\n strokeColor: this.strokeColor,\r\n strokeWidth: this.strokeWidth,\r\n opacity: this.opacity,\r\n feetPerCell: this.feetPerCell,\r\n radiusFeet: radiusFeet > 0 ? radiusFeet : undefined,\r\n renderStyle: this.renderStyle,\r\n layerId: ctx.activeLayerId ?? '',\r\n });\r\n ctx.store.add(element);\r\n ctx.requestRender();\r\n ctx.switchTool?.('select');\r\n }\r\n\r\n onDeactivate(_ctx: ToolContext): void {\r\n this.drawing = false;\r\n this.origin = { x: 0, y: 0 };\r\n this.current = { x: 0, y: 0 };\r\n }\r\n\r\n renderOverlay(ctx: CanvasRenderingContext2D): void {\r\n if (!this.drawing) return;\r\n\r\n const radius = this.computeRadius();\r\n if (radius <= 0) return;\r\n\r\n if (this.gridType === 'hex' && this.hexOrientation && this.renderStyle !== 'geometric') {\r\n this.renderHexOverlay(ctx, radius);\r\n return;\r\n }\r\n\r\n this.renderGeometricOverlay(ctx, radius);\r\n }\r\n\r\n private renderGeometricOverlay(ctx: CanvasRenderingContext2D, radius: number): void {\r\n const cx = this.origin.x;\r\n const cy = this.origin.y;\r\n const angle = this.computeAngle();\r\n\r\n ctx.save();\r\n ctx.globalAlpha = 0.4;\r\n ctx.fillStyle = this.fillColor;\r\n ctx.strokeStyle = this.strokeColor;\r\n ctx.lineWidth = this.strokeWidth;\r\n\r\n switch (this.templateShape) {\r\n case 'circle':\r\n ctx.beginPath();\r\n ctx.arc(cx, cy, radius, 0, Math.PI * 2);\r\n ctx.fill();\r\n ctx.stroke();\r\n break;\r\n\r\n case 'square':\r\n ctx.fillRect(cx - radius / 2, cy - radius / 2, radius, radius);\r\n ctx.strokeRect(cx - radius / 2, cy - radius / 2, radius, radius);\r\n break;\r\n\r\n case 'cone': {\r\n const halfAngle = Math.atan(0.5);\r\n ctx.beginPath();\r\n ctx.moveTo(cx, cy);\r\n ctx.arc(cx, cy, radius, angle - halfAngle, angle + halfAngle);\r\n ctx.closePath();\r\n ctx.fill();\r\n ctx.stroke();\r\n break;\r\n }\r\n\r\n case 'line': {\r\n const halfW = radius / 12;\r\n const cos = Math.cos(angle);\r\n const sin = Math.sin(angle);\r\n const perpX = -sin * halfW;\r\n const perpY = cos * halfW;\r\n\r\n ctx.beginPath();\r\n ctx.moveTo(cx + perpX, cy + perpY);\r\n ctx.lineTo(cx + radius * cos + perpX, cy + radius * sin + perpY);\r\n ctx.lineTo(cx + radius * cos - perpX, cy + radius * sin - perpY);\r\n ctx.lineTo(cx - perpX, cy - perpY);\r\n ctx.closePath();\r\n ctx.fill();\r\n ctx.stroke();\r\n break;\r\n }\r\n\r\n case 'rectangle': {\r\n const halfW = defaultRectWidth(radius, this.feetScaleUnit) / 2;\r\n const cos = Math.cos(angle);\r\n const sin = Math.sin(angle);\r\n const perpX = -sin * halfW;\r\n const perpY = cos * halfW;\r\n ctx.beginPath();\r\n ctx.moveTo(cx + perpX, cy + perpY);\r\n ctx.lineTo(cx + radius * cos + perpX, cy + radius * sin + perpY);\r\n ctx.lineTo(cx + radius * cos - perpX, cy + radius * sin - perpY);\r\n ctx.lineTo(cx - perpX, cy - perpY);\r\n ctx.closePath();\r\n ctx.fill();\r\n ctx.stroke();\r\n break;\r\n }\r\n }\r\n\r\n this.drawFeetLabel(ctx, radius);\r\n ctx.restore();\r\n }\r\n\r\n private renderHexOverlay(ctx: CanvasRenderingContext2D, radius: number): void {\r\n const orientation = this.hexOrientation;\r\n if (!orientation) return;\r\n const cellSize = this.gridSize;\r\n const snapUnit = Math.sqrt(3) * cellSize;\r\n const radiusCells = radius / snapUnit;\r\n const angle = this.computeAngle();\r\n const center = this.origin;\r\n\r\n let hexCells: Point[];\r\n switch (this.templateShape) {\r\n case 'circle':\r\n hexCells = getHexCellsInRadius(center, radiusCells, cellSize, orientation);\r\n break;\r\n case 'cone':\r\n hexCells = getHexCellsInCone(center, angle, radiusCells, cellSize, orientation);\r\n break;\r\n case 'line':\r\n hexCells = getHexCellsInLine(center, angle, radiusCells, cellSize, orientation);\r\n break;\r\n case 'square':\r\n hexCells = getHexCellsInSquare(center, radiusCells, cellSize, orientation);\r\n break;\r\n case 'rectangle': {\r\n const widthCells = defaultRectWidth(radius, this.feetScaleUnit) / snapUnit;\r\n hexCells = getHexCellsInRectangle(\r\n center,\r\n angle,\r\n radiusCells,\r\n widthCells,\r\n cellSize,\r\n orientation,\r\n );\r\n break;\r\n }\r\n }\r\n\r\n ctx.save();\r\n ctx.globalAlpha = 0.4;\r\n\r\n ctx.beginPath();\r\n for (const cell of hexCells) {\r\n drawHexPath(ctx, cell.x, cell.y, cellSize, orientation);\r\n }\r\n ctx.fillStyle = this.fillColor;\r\n ctx.fill();\r\n\r\n ctx.beginPath();\r\n for (const cell of hexCells) {\r\n drawHexPath(ctx, cell.x, cell.y, cellSize, orientation);\r\n }\r\n ctx.strokeStyle = this.strokeColor;\r\n ctx.lineWidth = this.strokeWidth;\r\n ctx.stroke();\r\n\r\n if (\r\n this.templateShape === 'cone' ||\r\n this.templateShape === 'line' ||\r\n this.templateShape === 'circle' ||\r\n this.templateShape === 'square' ||\r\n this.templateShape === 'rectangle'\r\n ) {\r\n ctx.globalAlpha = 0.5;\r\n ctx.beginPath();\r\n drawHexPath(ctx, center.x, center.y, cellSize, orientation);\r\n ctx.fillStyle = this.strokeColor;\r\n ctx.fill();\r\n ctx.strokeStyle = this.strokeColor;\r\n ctx.lineWidth = this.strokeWidth;\r\n ctx.stroke();\r\n }\r\n\r\n this.drawFeetLabel(ctx, radius);\r\n ctx.restore();\r\n }\r\n\r\n private computeRadius(): number {\r\n const dx = this.current.x - this.origin.x;\r\n const dy = this.current.y - this.origin.y;\r\n const raw = Math.sqrt(dx * dx + dy * dy);\r\n if (this.snapEnabled && this.gridSize > 0) {\r\n const snapUnit = this.gridType === 'hex' ? Math.sqrt(3) * this.gridSize : this.gridSize;\r\n return Math.max(snapUnit, Math.round(raw / snapUnit) * snapUnit);\r\n }\r\n return raw;\r\n }\r\n\r\n private computeAngle(): number {\r\n const dx = this.current.x - this.origin.x;\r\n const dy = this.current.y - this.origin.y;\r\n return Math.atan2(dy, dx);\r\n }\r\n\r\n private drawFeetLabel(ctx: CanvasRenderingContext2D, radius: number): void {\r\n const feet = this.feetScaleUnit > 0 ? (radius / this.feetScaleUnit) * this.feetPerCell : 0;\r\n renderTemplateFeetLabel(ctx, {\r\n position: this.origin,\r\n radius,\r\n angle: this.computeAngle(),\r\n templateShape: this.templateShape,\r\n feet,\r\n color: this.strokeColor,\r\n });\r\n }\r\n\r\n private snapToGrid(point: Point, ctx: ToolContext): Point {\r\n if (!ctx.gridSize) return point;\r\n if (ctx.gridType === 'hex' && ctx.hexOrientation) {\r\n return snapToHexCenter(point, ctx.gridSize, ctx.hexOrientation);\r\n }\r\n if (ctx.gridType === 'square') {\r\n return snapPoint(point, ctx.gridSize);\r\n }\r\n if (ctx.snapToGrid) {\r\n return snapPoint(point, ctx.gridSize);\r\n }\r\n return point;\r\n }\r\n\r\n private notifyOptionsChange(): void {\r\n for (const listener of this.optionListeners) listener();\r\n }\r\n}\r\n","import type { Tool, ToolContext, PointerState } from './types';\r\nimport type { Point } from '../core/types';\r\n\r\nexport interface LaserToolOptions {\r\n name?: string;\r\n color?: string;\r\n width?: number;\r\n fadeMs?: number;\r\n}\r\n\r\n/**\r\n * A coalesced batch of locally drawn trail points, flushed at most once per\r\n * animation frame — the outgoing side of a shared laser pointer. Emissions\r\n * carry world coordinates and the tool's current style so a host can forward\r\n * them as ephemeral presence without duplicating the tool's input handling.\r\n */\r\nexport interface LaserTrailEmission {\r\n /** World-space points recorded since the previous emission, oldest first. */\r\n readonly points: readonly Point[];\r\n readonly color: string;\r\n readonly width: number;\r\n readonly fadeMs: number;\r\n}\r\n\r\ninterface TrailPoint {\r\n x: number;\r\n y: number;\r\n t: number;\r\n}\r\n\r\nconst DEFAULT_COLOR = '#ff3b30';\r\nconst DEFAULT_WIDTH = 4;\r\nconst DEFAULT_FADE_MS = 1200;\r\n\r\nexport class LaserTool implements Tool {\r\n readonly name: string;\r\n private color: string;\r\n private width: number;\r\n private fadeMs: number;\r\n private trail: TrailPoint[] = [];\r\n private rafId: number | null = null;\r\n private drawing = false;\r\n private optionListeners = new Set<() => void>();\r\n private trailListeners = new Set<(emission: LaserTrailEmission) => void>();\r\n private pendingEmission: Point[] = [];\r\n\r\n constructor(options: LaserToolOptions = {}) {\r\n this.name = options.name ?? 'laser';\r\n this.color = options.color ?? DEFAULT_COLOR;\r\n this.width = options.width ?? DEFAULT_WIDTH;\r\n this.fadeMs = options.fadeMs ?? DEFAULT_FADE_MS;\r\n }\r\n\r\n private now(): number {\r\n return performance.now();\r\n }\r\n\r\n onActivate(ctx: ToolContext): void {\r\n ctx.setCursor?.('crosshair');\r\n }\r\n\r\n onDeactivate(ctx: ToolContext): void {\r\n if (this.rafId !== null) {\r\n cancelAnimationFrame(this.rafId);\r\n this.rafId = null;\r\n }\r\n this.trail = [];\r\n this.drawing = false;\r\n this.pendingEmission = [];\r\n ctx.setCursor?.('default');\r\n ctx.requestRender();\r\n }\r\n\r\n getOptions(): LaserToolOptions {\r\n return {\r\n name: this.name,\r\n color: this.color,\r\n width: this.width,\r\n fadeMs: this.fadeMs,\r\n };\r\n }\r\n\r\n onOptionsChange(listener: () => void): () => void {\r\n this.optionListeners.add(listener);\r\n return () => this.optionListeners.delete(listener);\r\n }\r\n\r\n /**\r\n * Subscribes to coalesced trail emissions. Points recorded by pointer input\r\n * are batched and delivered at most once per animation frame, keeping\r\n * outgoing presence packets small. Listeners must not throw; a throwing\r\n * listener is isolated so it cannot stall the fade loop.\r\n */\r\n onTrail(listener: (emission: LaserTrailEmission) => void): () => void {\r\n this.trailListeners.add(listener);\r\n return () => this.trailListeners.delete(listener);\r\n }\r\n\r\n setOptions(options: LaserToolOptions): void {\r\n if (options.color !== undefined) this.color = options.color;\r\n if (options.width !== undefined) this.width = options.width;\r\n if (options.fadeMs !== undefined) this.fadeMs = options.fadeMs;\r\n this.notifyOptionsChange();\r\n }\r\n\r\n onPointerDown(state: PointerState, ctx: ToolContext): void {\r\n this.drawing = true;\r\n this.recordPoint(state, ctx);\r\n }\r\n\r\n onPointerMove(state: PointerState, ctx: ToolContext): void {\r\n if (!this.drawing) return;\r\n this.recordPoint(state, ctx);\r\n }\r\n\r\n private recordPoint(state: PointerState, ctx: ToolContext): void {\r\n const world = ctx.camera.screenToWorld({ x: state.x, y: state.y });\r\n this.trail.push({ x: world.x, y: world.y, t: this.now() });\r\n if (this.trailListeners.size > 0) {\r\n this.pendingEmission.push({ x: world.x, y: world.y });\r\n }\r\n this.ensureAnimating(ctx);\r\n }\r\n\r\n onPointerUp(_state: PointerState, _ctx: ToolContext): void {\r\n this.drawing = false;\r\n }\r\n\r\n renderOverlay(ctx: CanvasRenderingContext2D): void {\r\n if (this.trail.length < 2) return;\r\n\r\n ctx.save();\r\n ctx.strokeStyle = this.color;\r\n ctx.lineWidth = this.width;\r\n ctx.lineCap = 'round';\r\n ctx.lineJoin = 'round';\r\n\r\n const now = this.now();\r\n for (let i = 0; i < this.trail.length - 1; i++) {\r\n const a = this.trail[i];\r\n const b = this.trail[i + 1];\r\n if (!a || !b) continue;\r\n const age = now - b.t;\r\n ctx.globalAlpha = Math.max(0, 1 - age / this.fadeMs);\r\n ctx.beginPath();\r\n ctx.moveTo(a.x, a.y);\r\n ctx.lineTo(b.x, b.y);\r\n ctx.stroke();\r\n }\r\n\r\n ctx.restore();\r\n }\r\n\r\n private ensureAnimating(ctx: ToolContext): void {\r\n if (this.rafId === null) {\r\n this.rafId = requestAnimationFrame(() => this.tick(ctx));\r\n }\r\n }\r\n\r\n private flushEmission(): void {\r\n if (this.pendingEmission.length === 0) return;\r\n const emission: LaserTrailEmission = {\r\n points: this.pendingEmission,\r\n color: this.color,\r\n width: this.width,\r\n fadeMs: this.fadeMs,\r\n };\r\n this.pendingEmission = [];\r\n for (const listener of this.trailListeners) {\r\n try {\r\n listener(emission);\r\n } catch {\r\n // A throwing host listener must not stall the fade/emission loop.\r\n }\r\n }\r\n }\r\n\r\n private tick(ctx: ToolContext): void {\r\n this.flushEmission();\r\n const cutoff = this.now() - this.fadeMs;\r\n this.trail = this.trail.filter((p) => p.t >= cutoff);\r\n if (this.trail.length > 0) {\r\n ctx.requestRender();\r\n this.rafId = requestAnimationFrame(() => this.tick(ctx));\r\n } else {\r\n ctx.requestRender();\r\n this.rafId = null;\r\n }\r\n }\r\n\r\n private notifyOptionsChange(): void {\r\n for (const listener of this.optionListeners) listener();\r\n }\r\n}\r\n","import type { Tool, ToolContext, PointerState } from './types';\r\nimport { renderPingPulse } from '../canvas/ping-pulse';\r\n\r\nexport interface PingToolOptions {\r\n name?: string;\r\n color?: string;\r\n /** Total pulse animation length in milliseconds. */\r\n durationMs?: number;\r\n /** Maximum ripple radius in world units. */\r\n radius?: number;\r\n /**\r\n * Minimum interval between emitted pings. Taps arriving faster are ignored\r\n * entirely (no local pulse, no emission), so rapid-fire pings cannot starve\r\n * durable sync traffic.\r\n */\r\n minIntervalMs?: number;\r\n}\r\n\r\n/**\r\n * One emitted ping — the outgoing side of a shared \"look here\" marker.\r\n * Emissions carry the world position and the tool's current style so a host\r\n * can forward them as ephemeral presence without duplicating input handling.\r\n */\r\nexport interface PingEmission {\r\n /** World-space ping position. */\r\n readonly x: number;\r\n readonly y: number;\r\n readonly color: string;\r\n readonly durationMs: number;\r\n readonly radius: number;\r\n}\r\n\r\ninterface LocalPing {\r\n x: number;\r\n y: number;\r\n t: number;\r\n}\r\n\r\nconst DEFAULT_COLOR = '#ff3b30';\r\nconst DEFAULT_DURATION_MS = 1800;\r\nconst DEFAULT_RADIUS = 48;\r\nconst DEFAULT_MIN_INTERVAL_MS = 300;\r\n\r\n/**\r\n * Tap or click to ping a world position: a short expanding-pulse animation is\r\n * rendered locally and one `PingEmission` is delivered to `onPing` listeners\r\n * per accepted tap. Pings are ephemeral by contract: they never create\r\n * elements, enter undo history, or touch persisted canvas state — hosts\r\n * forward emissions as presence only.\r\n */\r\nexport class PingTool implements Tool {\r\n readonly name: string;\r\n private color: string;\r\n private durationMs: number;\r\n private radius: number;\r\n private minIntervalMs: number;\r\n private pings: LocalPing[] = [];\r\n private lastEmitAt = -Infinity;\r\n private rafId: number | null = null;\r\n private optionListeners = new Set<() => void>();\r\n private pingListeners = new Set<(emission: PingEmission) => void>();\r\n\r\n constructor(options: PingToolOptions = {}) {\r\n this.name = options.name ?? 'ping';\r\n this.color = options.color ?? DEFAULT_COLOR;\r\n this.durationMs = options.durationMs ?? DEFAULT_DURATION_MS;\r\n this.radius = options.radius ?? DEFAULT_RADIUS;\r\n this.minIntervalMs = options.minIntervalMs ?? DEFAULT_MIN_INTERVAL_MS;\r\n }\r\n\r\n private now(): number {\r\n return performance.now();\r\n }\r\n\r\n onActivate(ctx: ToolContext): void {\r\n ctx.setCursor?.('crosshair');\r\n }\r\n\r\n onDeactivate(ctx: ToolContext): void {\r\n if (this.rafId !== null) {\r\n cancelAnimationFrame(this.rafId);\r\n this.rafId = null;\r\n }\r\n this.pings = [];\r\n ctx.setCursor?.('default');\r\n ctx.requestRender();\r\n }\r\n\r\n getOptions(): PingToolOptions {\r\n return {\r\n name: this.name,\r\n color: this.color,\r\n durationMs: this.durationMs,\r\n radius: this.radius,\r\n minIntervalMs: this.minIntervalMs,\r\n };\r\n }\r\n\r\n setOptions(options: PingToolOptions): void {\r\n if (options.color !== undefined) this.color = options.color;\r\n if (options.durationMs !== undefined) this.durationMs = options.durationMs;\r\n if (options.radius !== undefined) this.radius = options.radius;\r\n if (options.minIntervalMs !== undefined) this.minIntervalMs = options.minIntervalMs;\r\n this.notifyOptionsChange();\r\n }\r\n\r\n onOptionsChange(listener: () => void): () => void {\r\n this.optionListeners.add(listener);\r\n return () => this.optionListeners.delete(listener);\r\n }\r\n\r\n /**\r\n * Subscribes to accepted pings. Listeners must not throw; a throwing\r\n * listener is isolated so it cannot break the tap handling or other\r\n * listeners.\r\n */\r\n onPing(listener: (emission: PingEmission) => void): () => void {\r\n this.pingListeners.add(listener);\r\n return () => this.pingListeners.delete(listener);\r\n }\r\n\r\n onPointerDown(state: PointerState, ctx: ToolContext): void {\r\n const t = this.now();\r\n if (t - this.lastEmitAt < this.minIntervalMs) return;\r\n this.lastEmitAt = t;\r\n\r\n const world = ctx.camera.screenToWorld({ x: state.x, y: state.y });\r\n this.pings.push({ x: world.x, y: world.y, t });\r\n const emission: PingEmission = {\r\n x: world.x,\r\n y: world.y,\r\n color: this.color,\r\n durationMs: this.durationMs,\r\n radius: this.radius,\r\n };\r\n for (const listener of this.pingListeners) {\r\n try {\r\n listener(emission);\r\n } catch {\r\n // A throwing host listener must not break tap handling.\r\n }\r\n }\r\n this.ensureAnimating(ctx);\r\n ctx.requestRender();\r\n }\r\n\r\n onPointerMove(_state: PointerState, _ctx: ToolContext): void {\r\n // Pings are discrete taps; dragging does nothing.\r\n }\r\n\r\n onPointerUp(_state: PointerState, _ctx: ToolContext): void {\r\n // Nothing to finish; the ping fired on pointer down.\r\n }\r\n\r\n renderOverlay(ctx: CanvasRenderingContext2D): void {\r\n if (this.pings.length === 0) return;\r\n const now = this.now();\r\n for (const ping of this.pings) {\r\n renderPingPulse(ctx, ping.x, ping.y, now - ping.t, {\r\n color: this.color,\r\n durationMs: this.durationMs,\r\n radius: this.radius,\r\n });\r\n }\r\n }\r\n\r\n private ensureAnimating(ctx: ToolContext): void {\r\n if (this.rafId === null) {\r\n this.rafId = requestAnimationFrame(() => this.tick(ctx));\r\n }\r\n }\r\n\r\n private tick(ctx: ToolContext): void {\r\n const cutoff = this.now() - this.durationMs;\r\n this.pings = this.pings.filter((ping) => ping.t > cutoff);\r\n ctx.requestRender();\r\n this.rafId = this.pings.length > 0 ? requestAnimationFrame(() => this.tick(ctx)) : null;\r\n }\r\n\r\n private notifyOptionsChange(): void {\r\n for (const listener of this.optionListeners) listener();\r\n }\r\n}\r\n"],"mappings":"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","names":["counter","center","minX","minY","minX","minY","center","n","center","cache","center","n","center","center","DEFAULT_DEBOUNCE_MS","cache","ARROWHEAD_LENGTH","ARROWHEAD_ANGLE","ARROW_LABEL_FONT_SIZE","WIDTH_QUANTUM","d","center","unionBounds","center","moved","unionBounds","center","n","DEFAULT_WIDTH","DEFAULT_COLOR","isFinitePoint","DEFAULT_COLOR","DEFAULT_FADE_MS","DEFAULT_COLOR","DEFAULT_DURATION_MS","DEFAULT_RADIUS","DEFAULT_DURATION_MS","easeOutCubic","isFiniteNumber","lerp","DEFAULT_RADIUS","center","HANDLE_HIT_PADDING","center","HANDLE_HIT_PADDING","center","BIND_THRESHOLD","center","DEFAULT_COLOR","DEFAULT_WIDTH","DEFAULT_FADE_MS","DEFAULT_COLOR","DEFAULT_DURATION_MS","DEFAULT_RADIUS","DEFAULT_MIN_INTERVAL_MS"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/core/snap.ts","../src/elements/note-sanitizer.ts","../src/core/state-serializer.ts","../src/core/storage/local-storage-adapter.ts","../src/core/auto-save.ts","../src/core/storage/memory-adapter.ts","../src/core/storage/indexeddb-adapter.ts","../src/canvas/camera.ts","../src/canvas/input-filter.ts","../src/elements/create-id.ts","../src/core/geometry.ts","../src/elements/arrow-geometry.ts","../src/elements/element-bounds.ts","../src/elements/bounds.ts","../src/canvas/keyboard-actions.ts","../src/canvas/shortcut-map.ts","../src/canvas/keyboard-handler.ts","../src/canvas/pan-inertia.ts","../src/canvas/input-handler.ts","../src/canvas/background.ts","../src/core/event-bus.ts","../src/core/quadtree.ts","../src/elements/stroke-smoothing.ts","../src/elements/stroke-cache.ts","../src/elements/element-store.ts","../src/elements/rotate-canvas.ts","../src/elements/renderers/stroke-renderer.ts","../src/elements/shape-geometry.ts","../src/elements/renderers/shape-renderer.ts","../src/elements/arrow-render-cache.ts","../src/elements/arrow-binding.ts","../src/elements/renderers/arrow-renderer.ts","../src/elements/renderers/image-renderer.ts","../src/elements/hex-fill.ts","../src/elements/renderers/template-measure.ts","../src/elements/renderers/template-renderer.ts","../src/elements/grid-renderer.ts","../src/canvas/html-painter-registry.ts","../src/canvas/html-paint.ts","../src/elements/element-renderer.ts","../src/elements/element-factory.ts","../src/elements/note-formatting.ts","../src/elements/note-toolbar.ts","../src/elements/note-editor.ts","../src/canvas/context-menu.ts","../src/canvas/minimap-transform.ts","../src/canvas/minimap-controller.ts","../src/canvas/minimap.ts","../src/canvas/viewport-dom.ts","../src/canvas/hybrid-render-surface.ts","../src/elements/arrow-label-editor.ts","../src/tools/tool-manager.ts","../src/history/history-stack.ts","../src/history/commands.ts","../src/history/layer-commands.ts","../src/history/history-recorder.ts","../src/canvas/note-canvas-renderer.ts","../src/canvas/text-canvas-renderer.ts","../src/canvas/html-export.ts","../src/canvas/export-image.ts","../src/canvas/export-svg.ts","../src/layers/layer-manager.ts","../src/canvas/interact-mode.ts","../src/canvas/double-tap-detector.ts","../src/canvas/dom-node-manager.ts","../src/canvas/render-stats.ts","../src/canvas/render-loop.ts","../src/canvas/html-paint-diagnostics.ts","../src/canvas/layer-cache.ts","../src/canvas/margin-viewport.ts","../src/elements/translate.ts","../src/elements/element-style.ts","../src/canvas/selection-rotate.ts","../src/canvas/selection-ops.ts","../src/canvas/grid-controller.ts","../src/canvas/viewport-interactions.ts","../src/elements/stroke-hit.ts","../src/tools/arrow-handles.ts","../src/tools/select-overlay.ts","../src/tools/select-hit.ts","../src/canvas/element-activation.ts","../src/canvas/viewport.ts","../src/canvas/remote-laser-overlay.ts","../src/canvas/ping-pulse.ts","../src/canvas/remote-ping-overlay.ts","../src/canvas/measure-render.ts","../src/canvas/remote-measure-overlay.ts","../src/canvas/ping-input.ts","../src/canvas/camera-view.ts","../src/canvas/camera-animator.ts","../src/canvas/focus-presence.ts","../src/canvas/remote-focus-receiver.ts","../src/tools/hand-tool.ts","../src/tools/pencil-tool.ts","../src/elements/stroke-erase.ts","../src/tools/eraser-tool.ts","../src/elements/group.ts","../src/elements/snap-guides.ts","../src/tools/select-resize.ts","../src/tools/select-tool.ts","../src/tools/arrow-tool.ts","../src/tools/note-tool.ts","../src/tools/text-tool.ts","../src/tools/image-tool.ts","../src/tools/shape-tool.ts","../src/tools/measure-tool.ts","../src/tools/template-tool.ts","../src/tools/laser-tool.ts","../src/tools/ping-tool.ts"],"sourcesContent":["export const VERSION = '0.62.0';\n\nexport type { Point, StrokePoint, Size, Bounds } from './core/types';\nexport { snapPoint, smartSnap, snapToHexCenter } from './core/snap';\nexport type { CanvasState } from './core/state-serializer';\nexport { AutoSave } from './core/auto-save';\nexport type { AutoSaveOptions } from './core/auto-save';\nexport { MemoryAdapter } from './core/storage/memory-adapter';\nexport { LocalStorageAdapter } from './core/storage/local-storage-adapter';\nexport { IndexedDBAdapter } from './core/storage/indexeddb-adapter';\nexport type { StorageAdapter } from './core/storage/storage-adapter';\nexport type { IndexedDBAdapterOptions } from './core/storage/indexeddb-adapter';\n\nexport { Camera } from './canvas/camera';\nexport type { CameraOptions, CameraChangeInfo } from './canvas/camera';\nexport type { BackgroundOptions, BackgroundPattern } from './canvas/background';\nexport type { ShortcutOptions, ShortcutBindings, ShortcutsApi } from './canvas/shortcut-map';\nexport { Viewport } from './canvas/viewport';\nexport type {\n ViewportOptions,\n GridInfo,\n AlignEdge,\n DistributeAxis,\n RotateDirection,\n} from './canvas/viewport';\nexport { exportImage } from './canvas/export-image';\nexport type {\n ExportAssetError,\n ExportAssetErrorReason,\n ExportImageOptions,\n ExportResourceOptions,\n} from './canvas/export-image';\nexport { exportSvg } from './canvas/export-svg';\nexport type { ExportSvgOptions } from './canvas/export-svg';\nexport type {\n HtmlExportError,\n HtmlExportErrorReason,\n HtmlExportOptions,\n HtmlExportRenderer,\n} from './canvas/html-export';\nexport type { RenderStatsSnapshot } from './canvas/render-stats';\nexport type { OverlayRenderer } from './canvas/render-loop';\nexport {\n RemoteLaserOverlay,\n isLaserTrailPresence,\n toLaserTrailPresence,\n LASER_TRAIL_PRESENCE_KIND,\n} from './canvas/remote-laser-overlay';\nexport type {\n LaserTrailPresence,\n RemoteLaserOverlayHost,\n RemoteLaserOverlayOptions,\n} from './canvas/remote-laser-overlay';\nexport {\n RemotePingOverlay,\n isPingPresence,\n toPingPresence,\n PING_PRESENCE_KIND,\n} from './canvas/remote-ping-overlay';\nexport type {\n PingPresence,\n RemotePingOverlayHost,\n RemotePingOverlayOptions,\n} from './canvas/remote-ping-overlay';\nexport {\n RemoteMeasureOverlay,\n isMeasurePresence,\n toMeasurePresence,\n MEASURE_PRESENCE_KIND,\n} from './canvas/remote-measure-overlay';\nexport type {\n MeasurePresence,\n RemoteMeasureOverlayHost,\n RemoteMeasureOverlayOptions,\n} from './canvas/remote-measure-overlay';\nexport { PingInput } from './canvas/ping-input';\nexport type { PingInputHost, PingInputOptions } from './canvas/ping-input';\nexport { MinimapController } from './canvas/minimap-controller';\nexport type { MinimapControllerOptions } from './canvas/minimap-controller';\nexport {\n captureCameraView,\n fitZoomForView,\n cameraOriginForView,\n applyCameraView,\n} from './canvas/camera-view';\nexport type { CameraView } from './canvas/camera-view';\nexport { CameraAnimator } from './canvas/camera-animator';\nexport type {\n CameraAnimatorOptions,\n CameraAnimationEndReason,\n FrameScheduler,\n} from './canvas/camera-animator';\nexport { isFocusPresence, toFocusPresence, FOCUS_PRESENCE_KIND } from './canvas/focus-presence';\nexport type { FocusPresence, FocusAudience } from './canvas/focus-presence';\nexport { RemoteFocusReceiver } from './canvas/remote-focus-receiver';\nexport type {\n FocusRole,\n RemoteFocusReceiverHost,\n RemoteFocusReceiverOptions,\n} from './canvas/remote-focus-receiver';\nexport {\n HtmlPainterRegistry,\n HtmlPainterMissingError,\n resolveHtmlRouting,\n} from './canvas/html-painter-registry';\nexport type { HtmlPaintContext, HtmlPainter, HtmlRouting } from './canvas/html-painter-registry';\nexport type { HtmlPaintDiagnostic, HtmlRenderTarget } from './canvas/html-paint-diagnostics';\nexport type { ElementActivationEvent, ActivationOptions } from './canvas/element-activation';\n\nexport { ElementStore } from './elements/element-store';\nexport type { ElementUpdateEvent } from './elements/element-store';\nexport type { ElementChangeMeta } from './elements/element-store';\nexport type { FontSizePreset } from './elements/note-toolbar';\nexport {\n toggleBold,\n toggleItalic,\n toggleUnderline,\n toggleStrikethrough,\n setFontSize,\n getActiveFormats,\n} from './elements/note-formatting';\nexport type { ActiveFormats } from './elements/note-formatting';\nexport {\n createStroke,\n createNote,\n createArrow,\n createImage,\n createHtmlElement,\n createText,\n createShape,\n createGrid,\n createTemplate,\n DEFAULT_NOTE_FONT_SIZE,\n} from './elements/element-factory';\nexport {\n getArrowControlPoint,\n getArrowMidpoint,\n getBendFromPoint,\n getArrowTangentAngle,\n isNearBezier,\n getArrowBounds,\n} from './elements/arrow-geometry';\nexport { getElementBounds, boundsIntersect } from './elements/element-bounds';\nexport { styleToPatch, getElementStyle } from './elements/element-style';\nexport type { ElementStyle } from './elements/element-style';\nexport type { SelectionStyleDetails } from './canvas/selection-ops';\nexport { getElementsBoundingBox } from './elements/bounds';\nexport {\n getHexDistance,\n getHexCellsInRadius,\n getHexCellsInCone,\n getHexCellsInLine,\n getHexCellsInSquare,\n getHexCellsInRectangle,\n drawHexPath,\n} from './elements/hex-fill';\nexport type {\n Binding,\n CanvasElement,\n ElementType,\n StrokeElement,\n NoteElement,\n ArrowElement,\n ArrowStrokeStyle,\n ImageElement,\n HtmlElement,\n TextElement,\n ShapeElement,\n ShapeKind,\n GridElement,\n HexOrientation,\n TemplateElement,\n TemplateShape,\n TemplateRenderStyle,\n} from './elements/types';\n\nexport type { Command } from './history/types';\nexport { HistoryStack } from './history/history-stack';\nexport type { HistoryStackOptions } from './history/history-stack';\n\nexport { ToolManager } from './tools/tool-manager';\nexport { HandTool } from './tools/hand-tool';\nexport { PencilTool } from './tools/pencil-tool';\nexport type { PencilToolOptions } from './tools/pencil-tool';\nexport { EraserTool } from './tools/eraser-tool';\nexport type { EraserToolOptions } from './tools/eraser-tool';\nexport { SelectTool } from './tools/select-tool';\nexport { ArrowTool } from './tools/arrow-tool';\nexport type { ArrowToolOptions } from './tools/arrow-tool';\nexport { NoteTool } from './tools/note-tool';\nexport type { NoteToolOptions } from './tools/note-tool';\nexport { TextTool } from './tools/text-tool';\nexport type { TextToolOptions } from './tools/text-tool';\nexport { ImageTool } from './tools/image-tool';\nexport type { ImageToolOptions } from './tools/image-tool';\nexport { ShapeTool } from './tools/shape-tool';\nexport type { ShapeToolOptions } from './tools/shape-tool';\nexport { MeasureTool } from './tools/measure-tool';\nexport type { MeasureToolOptions, Measurement, MeasureEmission } from './tools/measure-tool';\nexport { TemplateTool } from './tools/template-tool';\nexport type { TemplateToolOptions } from './tools/template-tool';\nexport { LaserTool } from './tools/laser-tool';\nexport type { LaserToolOptions, LaserTrailEmission } from './tools/laser-tool';\nexport { PingTool } from './tools/ping-tool';\nexport type { PingToolOptions, PingEmission } from './tools/ping-tool';\nexport type { Tool, ToolContext, PointerState, ToolName } from './tools/types';\n\nexport { LayerManager } from './layers/layer-manager';\nexport type { Layer } from './layers/types';\n","import type { Point } from './types';\r\nimport type { HexOrientation } from '../elements/types';\r\nimport type { ToolContext } from '../tools/types';\r\n\r\nexport function snapPoint(point: Point, gridSize: number): Point {\r\n return {\r\n x: Math.round(point.x / gridSize) * gridSize || 0,\r\n y: Math.round(point.y / gridSize) * gridSize || 0,\r\n };\r\n}\r\n\r\nexport function snapToHexCenter(\r\n point: Point,\r\n cellSize: number,\r\n orientation: HexOrientation,\r\n): Point {\r\n if (orientation === 'pointy') {\r\n const hexW = Math.sqrt(3) * cellSize;\r\n const rowH = 1.5 * cellSize;\r\n const row = Math.round(point.y / rowH);\r\n const offsetX = row % 2 !== 0 ? hexW / 2 : 0;\r\n const col = Math.round((point.x - offsetX) / hexW);\r\n return { x: col * hexW + offsetX || 0, y: row * rowH || 0 };\r\n } else {\r\n const hexH = Math.sqrt(3) * cellSize;\r\n const colW = 1.5 * cellSize;\r\n const col = Math.round(point.x / colW);\r\n const offsetY = col % 2 !== 0 ? hexH / 2 : 0;\r\n const row = Math.round((point.y - offsetY) / hexH);\r\n return { x: col * colW || 0, y: row * hexH + offsetY || 0 };\r\n }\r\n}\r\n\r\nexport function smartSnap(point: Point, ctx: ToolContext): Point {\r\n if (!ctx.snapToGrid || !ctx.gridSize) return point;\r\n if (ctx.gridType === 'hex' && ctx.hexOrientation) {\r\n return snapToHexCenter(point, ctx.gridSize, ctx.hexOrientation);\r\n }\r\n return snapPoint(point, ctx.gridSize);\r\n}\r\n","interface RunStyle {\r\n bold: boolean;\r\n italic: boolean;\r\n underline: boolean;\r\n strikethrough: boolean;\r\n fontSize: number;\r\n}\r\n\r\nexport interface StyledRun extends RunStyle {\r\n text: string;\r\n}\r\n\r\nconst BOLD_TAGS = new Set(['b', 'strong']);\r\nconst ITALIC_TAGS = new Set(['i', 'em']);\r\nconst UNDERLINE_TAGS = new Set(['u']);\r\nconst STRIKE_TAGS = new Set(['s', 'strike', 'del']);\r\nconst BLOCK_TAGS = new Set(['div']);\r\n\r\nexport function parseStyledRuns(html: string, baseFontSize: number): StyledRun[] {\r\n if (!html) return [];\r\n\r\n const doc = new DOMParser().parseFromString(html, 'text/html');\r\n const runs: StyledRun[] = [];\r\n const baseStyle: RunStyle = {\r\n bold: false,\r\n italic: false,\r\n underline: false,\r\n strikethrough: false,\r\n fontSize: baseFontSize,\r\n };\r\n\r\n walkNodes(doc.body, baseStyle, runs);\r\n return runs;\r\n}\r\n\r\nfunction walkNodes(node: Node, style: RunStyle, runs: StyledRun[]): void {\r\n for (const child of Array.from(node.childNodes)) {\r\n if (child.nodeType === Node.TEXT_NODE) {\r\n const text = child.textContent ?? '';\r\n if (text) {\r\n runs.push({ text, ...style });\r\n }\r\n continue;\r\n }\r\n\r\n if (child.nodeType !== Node.ELEMENT_NODE) continue;\r\n\r\n const el = child as Element;\r\n const tag = el.tagName.toLowerCase();\r\n\r\n if (tag === 'br') {\r\n runs.push({ text: '\\n', ...style });\r\n continue;\r\n }\r\n\r\n if (BLOCK_TAGS.has(tag) && runs.length > 0) {\r\n const lastRun = runs[runs.length - 1];\r\n if (lastRun && !lastRun.text.endsWith('\\n')) {\r\n runs.push({ text: '\\n', ...style });\r\n }\r\n }\r\n\r\n const childStyle = { ...style };\r\n if (BOLD_TAGS.has(tag)) childStyle.bold = true;\r\n if (ITALIC_TAGS.has(tag)) childStyle.italic = true;\r\n if (UNDERLINE_TAGS.has(tag)) childStyle.underline = true;\r\n if (STRIKE_TAGS.has(tag)) childStyle.strikethrough = true;\r\n\r\n if (tag === 'span') {\r\n const fontSize = (el as HTMLElement).style.fontSize;\r\n if (fontSize) {\r\n childStyle.fontSize = parseInt(fontSize, 10) || style.fontSize;\r\n }\r\n }\r\n\r\n walkNodes(el, childStyle, runs);\r\n }\r\n}\r\n\r\nconst ALLOWED_TAGS = new Set([\r\n 'b',\r\n 'strong',\r\n 'i',\r\n 'em',\r\n 'u',\r\n 's',\r\n 'strike',\r\n 'del',\r\n 'span',\r\n 'br',\r\n 'div',\r\n]);\r\n\r\nexport function sanitizeNoteHtml(html: string): string {\r\n if (!html) return '';\r\n\r\n const doc = new DOMParser().parseFromString(html, 'text/html');\r\n sanitizeNode(doc.body);\r\n return doc.body.innerHTML;\r\n}\r\n\r\nfunction sanitizeNode(node: Node): void {\r\n const children = Array.from(node.childNodes);\r\n\r\n for (const child of children) {\r\n if (child.nodeType === Node.TEXT_NODE) continue;\r\n\r\n if (child.nodeType !== Node.ELEMENT_NODE) {\r\n child.remove();\r\n continue;\r\n }\r\n\r\n const el = child as Element;\r\n const tag = el.tagName.toLowerCase();\r\n\r\n if (!ALLOWED_TAGS.has(tag)) {\r\n const fragment = document.createDocumentFragment();\r\n while (el.firstChild) {\r\n fragment.appendChild(el.firstChild);\r\n }\r\n node.replaceChild(fragment, el);\r\n sanitizeNode(node);\r\n return;\r\n }\r\n\r\n sanitizeAttributes(el, tag);\r\n sanitizeNode(el);\r\n }\r\n}\r\n\r\nexport function isNoteContentEmpty(html: string): boolean {\r\n if (!html) return true;\r\n const doc = new DOMParser().parseFromString(html, 'text/html');\r\n const text = doc.body.textContent ?? '';\r\n return text.replace(/\\u00a0/g, ' ').trim().length === 0;\r\n}\r\n\r\nfunction sanitizeAttributes(el: Element, tag: string): void {\r\n const attrs = Array.from(el.attributes);\r\n for (const attr of attrs) {\r\n if (tag === 'span' && attr.name === 'style') {\r\n const fontSize = (el as HTMLElement).style.fontSize;\r\n if (fontSize) {\r\n el.setAttribute('style', `font-size: ${fontSize};`);\r\n } else {\r\n el.removeAttribute('style');\r\n }\r\n continue;\r\n }\r\n el.removeAttribute(attr.name);\r\n }\r\n}\r\n","import type { CanvasElement } from '../elements/types';\r\nimport type { Point } from './types';\r\nimport type { Layer } from '../layers/types';\r\nimport { sanitizeNoteHtml } from '../elements/note-sanitizer';\r\n\r\nexport interface CanvasState {\r\n version: number;\r\n camera: {\r\n position: Point;\r\n zoom: number;\r\n };\r\n elements: CanvasElement[];\r\n layers?: Layer[];\r\n activeLayerId?: string;\r\n}\r\n\r\nconst CURRENT_VERSION = 2;\r\nconst ELEMENT_TYPES = [\r\n 'stroke',\r\n 'note',\r\n 'arrow',\r\n 'image',\r\n 'html',\r\n 'text',\r\n 'shape',\r\n 'grid',\r\n 'template',\r\n] as const satisfies readonly CanvasElement['type'][];\r\ntype _ElementTypesAreExhaustive = CanvasElement['type'] extends (typeof ELEMENT_TYPES)[number]\r\n ? true\r\n : never;\r\nconst _elementTypesAreExhaustive: _ElementTypesAreExhaustive = true;\r\nvoid _elementTypesAreExhaustive;\r\n\r\nexport function exportState(\r\n elements: CanvasElement[],\r\n camera: { position: Point; zoom: number },\r\n layers: Layer[] = [],\r\n activeLayerId?: string,\r\n): CanvasState {\r\n const state: CanvasState = {\r\n version: CURRENT_VERSION,\r\n camera: {\r\n position: { ...camera.position },\r\n zoom: camera.zoom,\r\n },\r\n elements: elements.map((el) => {\r\n const clone = structuredClone(el);\r\n if (clone.type === 'arrow') {\r\n delete clone.cachedControlPoint;\r\n }\r\n return clone;\r\n }),\r\n layers: layers.map((l) => ({ ...l })),\r\n };\r\n if (activeLayerId) state.activeLayerId = activeLayerId;\r\n return state;\r\n}\r\n\r\nexport function parseState(json: string): CanvasState {\r\n const data: unknown = JSON.parse(json);\r\n validateState(data);\r\n return data;\r\n}\r\n\r\nfunction validateState(data: unknown): asserts data is CanvasState {\r\n if (!isRecord(data)) {\r\n throw new Error('Invalid state: expected an object');\r\n }\r\n\r\n const obj = data;\r\n\r\n if (!Number.isInteger(obj['version']) || (obj['version'] as number) < 1) {\r\n throw new Error('Invalid state: missing or invalid version');\r\n }\r\n if ((obj['version'] as number) > CURRENT_VERSION) {\r\n throw new Error(`Invalid state: unsupported version ${String(obj['version'])}`);\r\n }\r\n\r\n if (!isRecord(obj['camera'])) {\r\n throw new Error('Invalid state: missing camera');\r\n }\r\n\r\n const cam = obj['camera'];\r\n if (!isRecord(cam['position'])) {\r\n throw new Error('Invalid state: missing camera.position');\r\n }\r\n\r\n if (!isPoint(cam['position'])) {\r\n throw new Error('Invalid state: camera.position must have finite x and y numbers');\r\n }\r\n\r\n if (!isFiniteNumber(cam['zoom']) || cam['zoom'] <= 0) {\r\n throw new Error('Invalid state: camera.zoom must be a positive finite number');\r\n }\r\n\r\n if (!Array.isArray(obj['elements'])) {\r\n throw new Error('Invalid state: elements must be an array');\r\n }\r\n if (obj['layers'] !== undefined && !Array.isArray(obj['layers'])) {\r\n throw new Error('Invalid state: layers must be an array');\r\n }\r\n\r\n const elements = obj['elements'] as unknown[];\r\n const hasLayers = Array.isArray(obj['layers']) && obj['layers'].length > 0;\r\n for (const el of elements) {\r\n if (!isRecord(el)) throw new Error('Invalid element: expected an object');\r\n migrateElement(el, !hasLayers);\r\n }\r\n\r\n if (!hasLayers) {\r\n obj['layers'] = [\r\n {\r\n id: 'default-layer',\r\n name: 'Layer 1',\r\n visible: true,\r\n locked: false,\r\n order: 0,\r\n opacity: 1.0,\r\n },\r\n ];\r\n }\r\n\r\n const layers = obj['layers'] as unknown[];\r\n const layerIds = new Set<string>();\r\n for (const layer of layers) {\r\n validateLayer(layer);\r\n if (layerIds.has(layer.id)) throw new Error(`Invalid state: duplicate layer id \"${layer.id}\"`);\r\n layerIds.add(layer.id);\r\n }\r\n\r\n const elementIds = new Set<string>();\r\n for (const el of elements) {\r\n validateElement(el);\r\n if (elementIds.has(el.id)) throw new Error(`Invalid state: duplicate element id \"${el.id}\"`);\r\n elementIds.add(el.id);\r\n if (!layerIds.has(el.layerId)) {\r\n throw new Error(`Invalid element \"${el.id}\": unknown layerId \"${el.layerId}\"`);\r\n }\r\n }\r\n\r\n if (obj['activeLayerId'] !== undefined) {\r\n if (typeof obj['activeLayerId'] !== 'string' || !layerIds.has(obj['activeLayerId'])) {\r\n throw new Error('Invalid state: activeLayerId must reference an existing layer');\r\n }\r\n }\r\n\r\n cleanBindings(elements as Record<string, unknown>[]);\r\n}\r\n\r\nfunction validateElement(el: unknown): asserts el is CanvasElement {\r\n if (!isRecord(el)) {\r\n throw new Error('Invalid element: expected an object');\r\n }\r\n\r\n if (typeof el['id'] !== 'string' || el['id'].length === 0) {\r\n throw new Error('Invalid element: missing id');\r\n }\r\n if (!isEnum(el['type'], ELEMENT_TYPES)) {\r\n throw new Error(`Invalid element: unknown type \"${String(el['type'])}\"`);\r\n }\r\n if (!isFiniteNumber(el['zIndex'])) {\r\n throw new Error(`Invalid element \"${el['id']}\": missing or invalid zIndex`);\r\n }\r\n if (\r\n !isPoint(el['position']) ||\r\n typeof el['locked'] !== 'boolean' ||\r\n typeof el['layerId'] !== 'string' ||\r\n !isOptional(el['groupId'], isString) ||\r\n !isOptional(el['rotation'], isFiniteNumber)\r\n ) {\r\n throw new Error(`Invalid element \"${el['id']}\": invalid base fields or geometry`);\r\n }\r\n\r\n const valid = validateTypeFields(el, el['type']);\r\n if (!valid) throw new Error(`Invalid element \"${el['id']}\": malformed ${el['type']} data`);\r\n}\r\n\r\nfunction validateTypeFields(el: Record<string, unknown>, type: CanvasElement['type']): boolean {\r\n switch (type) {\r\n case 'stroke':\r\n return (\r\n Array.isArray(el['points']) &&\r\n el['points'].every(isStrokePoint) &&\r\n isString(el['color']) &&\r\n isFiniteNumber(el['width']) &&\r\n isFiniteNumber(el['opacity']) &&\r\n isOptionalEnum(el['blendMode'], ['multiply'])\r\n );\r\n case 'note':\r\n return (\r\n isSize(el['size']) &&\r\n isString(el['text']) &&\r\n isString(el['backgroundColor']) &&\r\n isString(el['textColor']) &&\r\n isOptional(el['fontSize'], isFiniteNumber)\r\n );\r\n case 'arrow':\r\n return (\r\n isPoint(el['from']) &&\r\n isPoint(el['to']) &&\r\n isFiniteNumber(el['bend']) &&\r\n isString(el['color']) &&\r\n isFiniteNumber(el['width']) &&\r\n isOptional(el['fromBinding'], isBinding) &&\r\n isOptional(el['toBinding'], isBinding) &&\r\n isOptional(el['cachedControlPoint'], isPoint) &&\r\n isOptional(el['label'], isString) &&\r\n isOptionalEnum(el['strokeStyle'], ['solid', 'dashed', 'dotted'])\r\n );\r\n case 'image':\r\n return isSize(el['size']) && isString(el['src']);\r\n case 'html':\r\n return (\r\n isSize(el['size']) &&\r\n isOptional(el['domId'], isString) &&\r\n isOptional(el['interactive'], isBoolean) &&\r\n isOptional(el['htmlType'], isString) &&\r\n isOptional(el['data'], isRecord)\r\n );\r\n case 'text':\r\n return (\r\n isSize(el['size']) &&\r\n isString(el['text']) &&\r\n isFiniteNumber(el['fontSize']) &&\r\n isString(el['color']) &&\r\n isEnum(el['textAlign'], ['left', 'center', 'right'])\r\n );\r\n case 'shape':\r\n return (\r\n isEnum(el['shape'], ['rectangle', 'ellipse', 'line']) &&\r\n isSize(el['size']) &&\r\n isString(el['strokeColor']) &&\r\n isFiniteNumber(el['strokeWidth']) &&\r\n isString(el['fillColor']) &&\r\n isOptional(el['flip'], isBoolean)\r\n );\r\n case 'grid':\r\n return (\r\n isEnum(el['gridType'], ['square', 'hex']) &&\r\n isEnum(el['hexOrientation'], ['pointy', 'flat']) &&\r\n isFiniteNumber(el['cellSize']) &&\r\n isString(el['strokeColor']) &&\r\n isFiniteNumber(el['strokeWidth']) &&\r\n isFiniteNumber(el['opacity'])\r\n );\r\n case 'template':\r\n return (\r\n isEnum(el['templateShape'], ['circle', 'cone', 'line', 'square', 'rectangle']) &&\r\n isFiniteNumber(el['radius']) &&\r\n isFiniteNumber(el['angle']) &&\r\n isOptional(el['width'], isFiniteNumber) &&\r\n isString(el['fillColor']) &&\r\n isString(el['strokeColor']) &&\r\n isFiniteNumber(el['strokeWidth']) &&\r\n isFiniteNumber(el['opacity']) &&\r\n isOptional(el['feetPerCell'], isFiniteNumber) &&\r\n isOptional(el['radiusFeet'], isFiniteNumber) &&\r\n isOptionalEnum(el['renderStyle'], ['cells', 'geometric'])\r\n );\r\n }\r\n}\r\n\r\nfunction validateLayer(layer: unknown): asserts layer is Layer {\r\n if (\r\n !isRecord(layer) ||\r\n typeof layer['id'] !== 'string' ||\r\n layer['id'].length === 0 ||\r\n typeof layer['name'] !== 'string' ||\r\n typeof layer['visible'] !== 'boolean' ||\r\n typeof layer['locked'] !== 'boolean' ||\r\n !isFiniteNumber(layer['order']) ||\r\n !isFiniteNumber(layer['opacity']) ||\r\n layer['opacity'] < 0 ||\r\n layer['opacity'] > 1\r\n ) {\r\n throw new Error('Invalid state: malformed layer');\r\n }\r\n}\r\n\r\nfunction cleanBindings(elements: Record<string, unknown>[]): void {\r\n const ids = new Set(elements.map((el) => el['id'] as string));\r\n\r\n for (const el of elements) {\r\n if (el['type'] !== 'arrow') continue;\r\n\r\n const fromBinding = el['fromBinding'] as Record<string, unknown> | undefined;\r\n if (fromBinding && !ids.has(fromBinding['elementId'] as string)) {\r\n el['fromBinding'] = undefined;\r\n }\r\n\r\n const toBinding = el['toBinding'] as Record<string, unknown> | undefined;\r\n if (toBinding && !ids.has(toBinding['elementId'] as string)) {\r\n el['toBinding'] = undefined;\r\n }\r\n }\r\n}\r\n\r\nfunction migrateElement(obj: Record<string, unknown>, useDefaultLayer: boolean): void {\r\n if (obj['layerId'] === undefined || (useDefaultLayer && obj['layerId'] === '')) {\r\n obj['layerId'] = 'default-layer';\r\n }\r\n\r\n if (obj['type'] === 'arrow' && obj['bend'] === undefined) {\r\n obj['bend'] = 0;\r\n }\r\n\r\n if (obj['type'] === 'stroke' && Array.isArray(obj['points'])) {\r\n for (const pt of obj['points'] as Record<string, unknown>[]) {\r\n if (pt['pressure'] === undefined) {\r\n pt['pressure'] = 0.5;\r\n }\r\n }\r\n }\r\n\r\n if (obj['type'] === 'shape' && obj['shape'] === undefined) {\r\n obj['shape'] = 'rectangle';\r\n }\r\n\r\n if (obj['type'] === 'note' && obj['textColor'] === undefined) {\r\n obj['textColor'] = '#000000';\r\n }\r\n\r\n if ((obj['type'] === 'note' || obj['type'] === 'text') && typeof obj['text'] === 'string') {\r\n obj['text'] = sanitizeNoteHtml(obj['text']);\r\n }\r\n}\r\n\r\ntype Validator = (value: unknown) => boolean;\r\n\r\nfunction isRecord(value: unknown): value is Record<string, unknown> {\r\n return typeof value === 'object' && value !== null && !Array.isArray(value);\r\n}\r\n\r\nfunction isFiniteNumber(value: unknown): value is number {\r\n return typeof value === 'number' && Number.isFinite(value);\r\n}\r\n\r\nfunction isString(value: unknown): value is string {\r\n return typeof value === 'string';\r\n}\r\n\r\nfunction isBoolean(value: unknown): value is boolean {\r\n return typeof value === 'boolean';\r\n}\r\n\r\nfunction isOptional(value: unknown, validate: Validator): boolean {\r\n return value === undefined || validate(value);\r\n}\r\n\r\nfunction isEnum<const T extends readonly string[]>(value: unknown, values: T): value is T[number] {\r\n return typeof value === 'string' && (values as readonly string[]).includes(value);\r\n}\r\n\r\nfunction isOptionalEnum<const T extends readonly string[]>(value: unknown, values: T): boolean {\r\n return value === undefined || isEnum(value, values);\r\n}\r\n\r\nfunction isPoint(value: unknown): boolean {\r\n return isRecord(value) && isFiniteNumber(value['x']) && isFiniteNumber(value['y']);\r\n}\r\n\r\nfunction isSize(value: unknown): boolean {\r\n return isRecord(value) && isFiniteNumber(value['w']) && isFiniteNumber(value['h']);\r\n}\r\n\r\nfunction isStrokePoint(value: unknown): boolean {\r\n return isRecord(value) && isPoint(value) && isFiniteNumber(value['pressure']);\r\n}\r\n\r\nfunction isBinding(value: unknown): boolean {\r\n return isRecord(value) && typeof value['elementId'] === 'string';\r\n}\r\n","import type { StorageAdapter } from './storage-adapter';\r\n\r\nexport class LocalStorageAdapter implements StorageAdapter {\r\n async load(key: string): Promise<string | null> {\r\n if (typeof localStorage === 'undefined') return null;\r\n return localStorage.getItem(key);\r\n }\r\n async save(key: string, value: string): Promise<void> {\r\n if (typeof localStorage === 'undefined') return;\r\n localStorage.setItem(key, value);\r\n }\r\n async clear(key: string): Promise<void> {\r\n if (typeof localStorage === 'undefined') return;\r\n localStorage.removeItem(key);\r\n }\r\n}\r\n","import type { ElementStore } from '../elements/element-store';\r\nimport type { Camera } from '../canvas/camera';\r\nimport type { LayerManager } from '../layers/layer-manager';\r\nimport { exportState, parseState } from './state-serializer';\r\nimport type { CanvasState } from './state-serializer';\r\nimport { LocalStorageAdapter } from './storage/local-storage-adapter';\r\nimport type { StorageAdapter } from './storage/storage-adapter';\r\n\r\nexport interface AutoSaveOptions {\r\n key?: string;\r\n debounceMs?: number;\r\n layerManager?: LayerManager;\r\n adapter?: StorageAdapter;\r\n onError?: (error: Error) => void;\r\n}\r\n\r\nconst DEFAULT_KEY = 'fieldnotes-autosave';\r\nconst DEFAULT_DEBOUNCE_MS = 1000;\r\n\r\nexport class AutoSave {\r\n private readonly key: string;\r\n private readonly debounceMs: number;\r\n private readonly layerManager?: LayerManager;\r\n private readonly adapter: StorageAdapter;\r\n private timerId: ReturnType<typeof setTimeout> | null = null;\r\n private unsubscribers: (() => void)[] = [];\r\n private readonly onError?: (error: Error) => void;\r\n private saving = false;\r\n private pendingSave = false;\r\n\r\n constructor(\r\n private readonly store: ElementStore,\r\n private readonly camera: Camera,\r\n options: AutoSaveOptions = {},\r\n ) {\r\n this.key = options.key ?? DEFAULT_KEY;\r\n this.debounceMs = options.debounceMs ?? DEFAULT_DEBOUNCE_MS;\r\n this.layerManager = options.layerManager;\r\n this.adapter = options.adapter ?? new LocalStorageAdapter();\r\n this.onError = options.onError;\r\n }\r\n\r\n start(): void {\r\n const schedule = () => this.scheduleSave();\r\n\r\n this.unsubscribers = [\r\n this.store.on('add', schedule),\r\n this.store.on('remove', schedule),\r\n this.store.on('update', schedule),\r\n this.camera.onChange(schedule),\r\n ];\r\n if (this.layerManager) {\r\n this.unsubscribers.push(this.layerManager.on('change', schedule));\r\n }\r\n }\r\n\r\n stop(): void {\r\n this.cancelPending();\r\n this.unsubscribers.forEach((fn) => fn());\r\n this.unsubscribers = [];\r\n }\r\n\r\n async load(): Promise<CanvasState | null> {\r\n const json = await this.adapter.load(this.key);\r\n if (!json) return null;\r\n\r\n try {\r\n return parseState(json);\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n async clear(): Promise<void> {\r\n await this.adapter.clear(this.key);\r\n }\r\n\r\n private scheduleSave(): void {\r\n this.cancelPending();\r\n this.timerId = setTimeout(() => void this.save(), this.debounceMs);\r\n }\r\n\r\n private cancelPending(): void {\r\n if (this.timerId !== null) {\r\n clearTimeout(this.timerId);\r\n this.timerId = null;\r\n }\r\n }\r\n\r\n private async save(): Promise<void> {\r\n if (this.saving) {\r\n this.pendingSave = true;\r\n return;\r\n }\r\n this.saving = true;\r\n try {\r\n const layers = this.layerManager?.snapshot() ?? [];\r\n const state = exportState(this.store.snapshot(), this.camera, layers);\r\n await this.adapter.save(this.key, JSON.stringify(state));\r\n } catch (e) {\r\n this.onError?.(e instanceof Error ? e : new Error(String(e)));\r\n } finally {\r\n this.saving = false;\r\n if (this.pendingSave) {\r\n this.pendingSave = false;\r\n void this.save();\r\n }\r\n }\r\n }\r\n}\r\n","import type { StorageAdapter } from './storage-adapter';\r\n\r\nexport class MemoryAdapter implements StorageAdapter {\r\n private store = new Map<string, string>();\r\n async load(key: string): Promise<string | null> {\r\n return this.store.get(key) ?? null;\r\n }\r\n async save(key: string, value: string): Promise<void> {\r\n this.store.set(key, value);\r\n }\r\n async clear(key: string): Promise<void> {\r\n this.store.delete(key);\r\n }\r\n}\r\n","import type { StorageAdapter } from './storage-adapter';\r\n\r\nexport interface IndexedDBAdapterOptions {\r\n dbName?: string;\r\n storeName?: string;\r\n indexedDB?: IDBFactory;\r\n}\r\n\r\nconst DEFAULT_DB = 'fieldnotes';\r\nconst DEFAULT_STORE = 'state';\r\n\r\nexport class IndexedDBAdapter implements StorageAdapter {\r\n private readonly dbName: string;\r\n private readonly storeName: string;\r\n private readonly idb: IDBFactory | null;\r\n private dbPromise: Promise<IDBDatabase> | null = null;\r\n\r\n constructor(options: IndexedDBAdapterOptions = {}) {\r\n this.dbName = options.dbName ?? DEFAULT_DB;\r\n this.storeName = options.storeName ?? DEFAULT_STORE;\r\n this.idb = options.indexedDB ?? (typeof indexedDB !== 'undefined' ? indexedDB : null);\r\n }\r\n\r\n private open(): Promise<IDBDatabase> {\r\n const idb = this.idb;\r\n if (!idb) return Promise.reject(new Error('IndexedDB unavailable'));\r\n if (!this.dbPromise) {\r\n const storeName = this.storeName;\r\n this.dbPromise = new Promise((resolve, reject) => {\r\n const req = idb.open(this.dbName, 1);\r\n req.onupgradeneeded = () => {\r\n const db = req.result;\r\n if (!db.objectStoreNames.contains(storeName)) db.createObjectStore(storeName);\r\n };\r\n req.onsuccess = () => resolve(req.result);\r\n req.onerror = () => reject(req.error ?? new Error('IndexedDB open failed'));\r\n });\r\n }\r\n return this.dbPromise;\r\n }\r\n\r\n async load(key: string): Promise<string | null> {\r\n if (!this.idb) return null;\r\n const db = await this.open();\r\n return new Promise((resolve, reject) => {\r\n const req = db.transaction(this.storeName, 'readonly').objectStore(this.storeName).get(key);\r\n req.onsuccess = () => {\r\n const v = req.result;\r\n resolve(typeof v === 'string' ? v : null);\r\n };\r\n req.onerror = () => reject(req.error ?? new Error('IndexedDB read failed'));\r\n });\r\n }\r\n\r\n async save(key: string, value: string): Promise<void> {\r\n if (!this.idb) return;\r\n const db = await this.open();\r\n return new Promise((resolve, reject) => {\r\n const tx = db.transaction(this.storeName, 'readwrite');\r\n tx.objectStore(this.storeName).put(value, key);\r\n tx.oncomplete = () => resolve();\r\n tx.onerror = () => reject(tx.error ?? new Error('IndexedDB write failed'));\r\n tx.onabort = () => reject(tx.error ?? new Error('IndexedDB write aborted'));\r\n });\r\n }\r\n\r\n async clear(key: string): Promise<void> {\r\n if (!this.idb) return;\r\n const db = await this.open();\r\n return new Promise((resolve, reject) => {\r\n const tx = db.transaction(this.storeName, 'readwrite');\r\n tx.objectStore(this.storeName).delete(key);\r\n tx.oncomplete = () => resolve();\r\n tx.onerror = () => reject(tx.error ?? new Error('IndexedDB delete failed'));\r\n tx.onabort = () => reject(tx.error ?? new Error('IndexedDB delete aborted'));\r\n });\r\n }\r\n}\r\n","import type { Bounds, Point } from '../core/types';\r\n\r\nexport interface CameraOptions {\r\n minZoom?: number;\r\n maxZoom?: number;\r\n}\r\n\r\nexport interface CameraChangeInfo {\r\n panned: boolean;\r\n zoomed: boolean;\r\n}\r\n\r\nconst DEFAULT_MIN_ZOOM = 0.1;\r\nconst DEFAULT_MAX_ZOOM = 10;\r\n\r\nexport class Camera {\r\n private x = 0;\r\n private y = 0;\r\n private z = 1;\r\n private readonly minZoom: number;\r\n private readonly maxZoom: number;\r\n private changeListeners = new Set<(info: CameraChangeInfo) => void>();\r\n\r\n constructor(options: CameraOptions = {}) {\r\n this.minZoom = options.minZoom ?? DEFAULT_MIN_ZOOM;\r\n this.maxZoom = options.maxZoom ?? DEFAULT_MAX_ZOOM;\r\n }\r\n\r\n get position(): Point {\r\n return { x: this.x, y: this.y };\r\n }\r\n\r\n get zoom(): number {\r\n return this.z;\r\n }\r\n\r\n pan(dx: number, dy: number): void {\r\n this.x += dx;\r\n this.y += dy;\r\n this.notifyPan();\r\n }\r\n\r\n moveTo(x: number, y: number): void {\r\n this.x = x;\r\n this.y = y;\r\n this.notifyPan();\r\n }\r\n\r\n setZoom(level: number): void {\r\n this.z = Math.min(this.maxZoom, Math.max(this.minZoom, level));\r\n this.notifyZoom();\r\n }\r\n\r\n zoomAt(level: number, screenPoint: Point): void {\r\n const before = this.screenToWorld(screenPoint);\r\n this.z = Math.min(this.maxZoom, Math.max(this.minZoom, level));\r\n const after = this.screenToWorld(screenPoint);\r\n this.x += (after.x - before.x) * this.z;\r\n this.y += (after.y - before.y) * this.z;\r\n this.notifyPanAndZoom();\r\n }\r\n\r\n screenToWorld(screen: Point): Point {\r\n return {\r\n x: (screen.x - this.x) / this.z,\r\n y: (screen.y - this.y) / this.z,\r\n };\r\n }\r\n\r\n worldToScreen(world: Point): Point {\r\n return {\r\n x: world.x * this.z + this.x,\r\n y: world.y * this.z + this.y,\r\n };\r\n }\r\n\r\n getVisibleRect(canvasWidth: number, canvasHeight: number): Bounds {\r\n const topLeft = this.screenToWorld({ x: 0, y: 0 });\r\n const bottomRight = this.screenToWorld({ x: canvasWidth, y: canvasHeight });\r\n return {\r\n x: topLeft.x,\r\n y: topLeft.y,\r\n w: bottomRight.x - topLeft.x,\r\n h: bottomRight.y - topLeft.y,\r\n };\r\n }\r\n\r\n fitToContent(boundingBox: Bounds, canvasWidth: number, canvasHeight: number, padding = 40): void {\r\n if (boundingBox.w === 0 && boundingBox.h === 0) return;\r\n\r\n const scaleX = canvasWidth / (boundingBox.w + 2 * padding);\r\n const scaleY = canvasHeight / (boundingBox.h + 2 * padding);\r\n this.z = Math.min(this.maxZoom, Math.max(this.minZoom, Math.min(scaleX, scaleY)));\r\n this.x = (canvasWidth - boundingBox.w * this.z) / 2 - boundingBox.x * this.z;\r\n this.y = (canvasHeight - boundingBox.h * this.z) / 2 - boundingBox.y * this.z;\r\n this.notifyPanAndZoom();\r\n }\r\n\r\n toCSSTransform(): string {\r\n return `translate3d(${this.x}px, ${this.y}px, 0) scale(${this.z})`;\r\n }\r\n\r\n onChange(listener: (info: CameraChangeInfo) => void): () => void {\r\n this.changeListeners.add(listener);\r\n return () => this.changeListeners.delete(listener);\r\n }\r\n\r\n private notifyPan(): void {\r\n this.changeListeners.forEach((fn) => fn({ panned: true, zoomed: false }));\r\n }\r\n\r\n private notifyZoom(): void {\r\n this.changeListeners.forEach((fn) => fn({ panned: false, zoomed: true }));\r\n }\r\n\r\n private notifyPanAndZoom(): void {\r\n this.changeListeners.forEach((fn) => fn({ panned: true, zoomed: true }));\r\n }\r\n}\r\n","export type FilterAction = 'dispatch' | 'suppress' | 'defer';\r\n\r\nexport interface FilteredEvent {\r\n event: PointerEvent;\r\n action: FilterAction;\r\n}\r\n\r\nexport interface FilteredUpEvent extends FilteredEvent {\r\n pendingTap?: { x: number; y: number };\r\n}\r\n\r\nexport class InputFilter {\r\n private activePenId: number | null = null;\r\n private pendingTap: { pointerId: number; x: number; y: number } | null = null;\r\n\r\n static readonly MIN_MOVE_DISTANCE = 3;\r\n\r\n filterDown(e: PointerEvent): FilteredEvent {\r\n if (e.pointerType === 'pen') {\r\n this.activePenId = e.pointerId;\r\n return { event: e, action: 'dispatch' };\r\n }\r\n\r\n if (e.pointerType === 'touch' && this.activePenId !== null) {\r\n return { event: e, action: 'suppress' };\r\n }\r\n\r\n if (e.pointerType === 'touch') {\r\n this.pendingTap = { pointerId: e.pointerId, x: e.clientX, y: e.clientY };\r\n return { event: e, action: 'defer' };\r\n }\r\n\r\n return { event: e, action: 'dispatch' };\r\n }\r\n\r\n filterMove(e: PointerEvent): FilteredEvent {\r\n if (e.pointerType === 'touch' && this.activePenId !== null) {\r\n return { event: e, action: 'suppress' };\r\n }\r\n\r\n if (this.pendingTap && e.pointerId === this.pendingTap.pointerId) {\r\n const dx = e.clientX - this.pendingTap.x;\r\n const dy = e.clientY - this.pendingTap.y;\r\n if (dx * dx + dy * dy > InputFilter.MIN_MOVE_DISTANCE * InputFilter.MIN_MOVE_DISTANCE) {\r\n this.pendingTap = null;\r\n return { event: e, action: 'dispatch' };\r\n }\r\n return { event: e, action: 'suppress' };\r\n }\r\n\r\n return { event: e, action: 'dispatch' };\r\n }\r\n\r\n filterUp(e: PointerEvent): FilteredUpEvent {\r\n if (e.pointerId === this.activePenId) {\r\n this.activePenId = null;\r\n return { event: e, action: 'dispatch' };\r\n }\r\n\r\n if (e.pointerType === 'touch' && this.activePenId !== null) {\r\n return { event: e, action: 'suppress' };\r\n }\r\n\r\n if (this.pendingTap && e.pointerId === this.pendingTap.pointerId) {\r\n const tap = { x: this.pendingTap.x, y: this.pendingTap.y };\r\n this.pendingTap = null;\r\n return { event: e, action: 'dispatch', pendingTap: tap };\r\n }\r\n\r\n return { event: e, action: 'dispatch' };\r\n }\r\n\r\n reset(): void {\r\n this.activePenId = null;\r\n this.pendingTap = null;\r\n }\r\n}\r\n","let counter = 0;\r\n\r\nexport function randomClientComponent(): string {\r\n // getRandomValues works in NON-secure contexts (an iPad on http://LAN) — unlike crypto.randomUUID, which\r\n // is secure-context-gated in browsers. Uniqueness, not security.\r\n if (typeof crypto !== 'undefined' && typeof crypto.getRandomValues === 'function') {\r\n const bytes = new Uint8Array(8);\r\n crypto.getRandomValues(bytes);\r\n return Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join(''); // 16 hex = 64 bits\r\n }\r\n return Math.random().toString(36).slice(2, 14); // last resort — no crypto at all\r\n}\r\n\r\n// Per-process (per tab/worker) client component — generated ONCE at module load so two clients never collide\r\n// even at counter 0 in the same millisecond.\r\nconst CLIENT = randomClientComponent();\r\n\r\n// Internal (module-exported for tests; NOT in the package barrel — see index.ts / index.test.ts `removed`).\r\nexport function formatId(prefix: string, time: string, counter: string, client: string): string {\r\n return `${prefix}_${time}_${counter}_${client}`;\r\n}\r\n\r\nexport function createId(prefix: string): string {\r\n return formatId(prefix, Date.now().toString(36), (counter++).toString(36), CLIENT);\r\n}\r\n","import type { Point, Bounds } from './types';\r\n\r\nexport function distSqToSegment(p: Point, a: Point, b: Point): number {\r\n const abx = b.x - a.x;\r\n const aby = b.y - a.y;\r\n const apx = p.x - a.x;\r\n const apy = p.y - a.y;\r\n const lenSq = abx * abx + aby * aby;\r\n if (lenSq === 0) {\r\n return apx * apx + apy * apy;\r\n }\r\n const t = Math.max(0, Math.min(1, (apx * abx + apy * aby) / lenSq));\r\n const dx = p.x - (a.x + t * abx);\r\n const dy = p.y - (a.y + t * aby);\r\n return dx * dx + dy * dy;\r\n}\r\n\r\nexport function rotatePoint(p: Point, center: Point, angle: number): Point {\r\n if (angle === 0) return p;\r\n const cos = Math.cos(angle);\r\n const sin = Math.sin(angle);\r\n const dx = p.x - center.x;\r\n const dy = p.y - center.y;\r\n return { x: center.x + dx * cos - dy * sin, y: center.y + dx * sin + dy * cos };\r\n}\r\n\r\nexport function rotatedAABB(bounds: Bounds, angle: number): Bounds {\r\n if (angle === 0) return bounds;\r\n const c = { x: bounds.x + bounds.w / 2, y: bounds.y + bounds.h / 2 };\r\n const corners = [\r\n { x: bounds.x, y: bounds.y },\r\n { x: bounds.x + bounds.w, y: bounds.y },\r\n { x: bounds.x + bounds.w, y: bounds.y + bounds.h },\r\n { x: bounds.x, y: bounds.y + bounds.h },\r\n ].map((p) => rotatePoint(p, c, angle));\r\n const xs = corners.map((p) => p.x);\r\n const ys = corners.map((p) => p.y);\r\n const minX = Math.min(...xs);\r\n const minY = Math.min(...ys);\r\n return { x: minX, y: minY, w: Math.max(...xs) - minX, h: Math.max(...ys) - minY };\r\n}\r\n\r\nexport function normalizeAngle(angle: number): number {\r\n const twoPi = Math.PI * 2;\r\n let a = angle % twoPi;\r\n if (a <= -Math.PI) a += twoPi;\r\n else if (a > Math.PI) a -= twoPi;\r\n return a;\r\n}\r\n","import type { Bounds, Point } from '../core/types';\r\nimport { distSqToSegment } from '../core/geometry';\r\n\r\nexport function getArrowControlPoint(from: Point, to: Point, bend: number): Point {\r\n const midX = (from.x + to.x) / 2;\r\n const midY = (from.y + to.y) / 2;\r\n\r\n if (bend === 0) return { x: midX, y: midY };\r\n\r\n const dx = to.x - from.x;\r\n const dy = to.y - from.y;\r\n const len = Math.sqrt(dx * dx + dy * dy);\r\n\r\n if (len === 0) return { x: midX, y: midY };\r\n\r\n const perpX = -dy / len;\r\n const perpY = dx / len;\r\n\r\n return {\r\n x: midX + perpX * bend,\r\n y: midY + perpY * bend,\r\n };\r\n}\r\n\r\nexport function getArrowMidpoint(from: Point, to: Point, bend: number): Point {\r\n const cp = getArrowControlPoint(from, to, bend);\r\n return {\r\n x: 0.25 * from.x + 0.5 * cp.x + 0.25 * to.x,\r\n y: 0.25 * from.y + 0.5 * cp.y + 0.25 * to.y,\r\n };\r\n}\r\n\r\nexport function getBendFromPoint(from: Point, to: Point, dragPoint: Point): number {\r\n const midX = (from.x + to.x) / 2;\r\n const midY = (from.y + to.y) / 2;\r\n\r\n const dx = to.x - from.x;\r\n const dy = to.y - from.y;\r\n const len = Math.sqrt(dx * dx + dy * dy);\r\n\r\n if (len === 0) return 0;\r\n\r\n const perpX = -dy / len;\r\n const perpY = dx / len;\r\n\r\n // The bend handle sits at the curve midpoint (getArrowMidpoint), which is HALF the control-point\r\n // offset. Double the projection so the handle tracks the pointer 1:1 (bend is the control-point offset).\r\n return 2 * ((dragPoint.x - midX) * perpX + (dragPoint.y - midY) * perpY);\r\n}\r\n\r\nexport function getArrowTangentAngle(from: Point, to: Point, bend: number, t: number): number {\r\n const cp = getArrowControlPoint(from, to, bend);\r\n\r\n const tangentX = 2 * (1 - t) * (cp.x - from.x) + 2 * t * (to.x - cp.x);\r\n const tangentY = 2 * (1 - t) * (cp.y - from.y) + 2 * t * (to.y - cp.y);\r\n\r\n return Math.atan2(tangentY, tangentX);\r\n}\r\n\r\nexport function isNearBezier(\r\n point: Point,\r\n from: Point,\r\n to: Point,\r\n bend: number,\r\n threshold: number,\r\n): boolean {\r\n if (bend === 0) return isNearLine(point, from, to, threshold);\r\n\r\n const cp = getArrowControlPoint(from, to, bend);\r\n const segments = 20;\r\n\r\n for (let i = 0; i < segments; i++) {\r\n const t0 = i / segments;\r\n const t1 = (i + 1) / segments;\r\n const a = bezierPoint(from, cp, to, t0);\r\n const b = bezierPoint(from, cp, to, t1);\r\n if (isNearLine(point, a, b, threshold)) return true;\r\n }\r\n\r\n return false;\r\n}\r\n\r\nexport function getArrowBounds(from: Point, to: Point, bend: number): Bounds {\r\n if (bend === 0) {\r\n const minX = Math.min(from.x, to.x);\r\n const minY = Math.min(from.y, to.y);\r\n return {\r\n x: minX,\r\n y: minY,\r\n w: Math.abs(to.x - from.x),\r\n h: Math.abs(to.y - from.y),\r\n };\r\n }\r\n\r\n const cp = getArrowControlPoint(from, to, bend);\r\n const steps = 20;\r\n let minX = Math.min(from.x, to.x);\r\n let minY = Math.min(from.y, to.y);\r\n let maxX = Math.max(from.x, to.x);\r\n let maxY = Math.max(from.y, to.y);\r\n\r\n for (let i = 1; i < steps; i++) {\r\n const t = i / steps;\r\n const p = bezierPoint(from, cp, to, t);\r\n if (p.x < minX) minX = p.x;\r\n if (p.y < minY) minY = p.y;\r\n if (p.x > maxX) maxX = p.x;\r\n if (p.y > maxY) maxY = p.y;\r\n }\r\n\r\n return { x: minX, y: minY, w: maxX - minX, h: maxY - minY };\r\n}\r\n\r\nfunction bezierPoint(from: Point, cp: Point, to: Point, t: number): Point {\r\n const mt = 1 - t;\r\n return {\r\n x: mt * mt * from.x + 2 * mt * t * cp.x + t * t * to.x,\r\n y: mt * mt * from.y + 2 * mt * t * cp.y + t * t * to.y,\r\n };\r\n}\r\n\r\nfunction isNearLine(point: Point, a: Point, b: Point, threshold: number): boolean {\r\n return distSqToSegment(point, a, b) <= threshold * threshold;\r\n}\r\n","import type { Bounds } from '../core/types';\r\nimport { rotatedAABB } from '../core/geometry';\r\nimport type { CanvasElement, TemplateElement } from './types';\r\nimport { getArrowControlPoint } from './arrow-geometry';\r\n\r\n// Cache stroke bounds via WeakMap.\r\n// May miss after ElementStore.update() creates new object via spread,\r\n// acceptable since stroke points never change after commit.\r\nconst strokeBoundsCache = new WeakMap<CanvasElement, Bounds>();\r\n\r\nexport function getElementBounds(element: CanvasElement): Bounds | null {\r\n if (element.type === 'grid') return null;\r\n\r\n if ('size' in element) {\r\n return {\r\n x: element.position.x,\r\n y: element.position.y,\r\n w: element.size.w,\r\n h: element.size.h,\r\n };\r\n }\r\n\r\n if (element.type === 'stroke') {\r\n if (element.points.length === 0) return null;\r\n\r\n const cached = strokeBoundsCache.get(element);\r\n if (cached) return cached;\r\n\r\n let minX = Infinity;\r\n let minY = Infinity;\r\n let maxX = -Infinity;\r\n let maxY = -Infinity;\r\n\r\n for (const p of element.points) {\r\n const px = p.x + element.position.x;\r\n const py = p.y + element.position.y;\r\n if (px < minX) minX = px;\r\n if (py < minY) minY = py;\r\n if (px > maxX) maxX = px;\r\n if (py > maxY) maxY = py;\r\n }\r\n\r\n const bounds: Bounds = { x: minX, y: minY, w: maxX - minX, h: maxY - minY };\r\n strokeBoundsCache.set(element, bounds);\r\n return bounds;\r\n }\r\n\r\n if (element.type === 'arrow') {\r\n return getArrowBoundsAnalytical(element.from, element.to, element.bend);\r\n }\r\n\r\n if (element.type === 'template') {\r\n return getTemplateBounds(element);\r\n }\r\n\r\n return null;\r\n}\r\n\r\n/** Axis-aligned world bounds covering the element's complete rotated visual footprint. */\r\nexport function getElementVisualBounds(element: CanvasElement): Bounds | null {\r\n const bounds = getElementBounds(element);\r\n if (!bounds) return null;\r\n const rotation = element.rotation ?? 0;\r\n return rotation === 0 ? bounds : rotatedAABB(bounds, rotation);\r\n}\r\n\r\nfunction getArrowBoundsAnalytical(\r\n from: { x: number; y: number },\r\n to: { x: number; y: number },\r\n bend: number,\r\n): Bounds {\r\n if (bend === 0) {\r\n const minX = Math.min(from.x, to.x);\r\n const minY = Math.min(from.y, to.y);\r\n return {\r\n x: minX,\r\n y: minY,\r\n w: Math.abs(to.x - from.x),\r\n h: Math.abs(to.y - from.y),\r\n };\r\n }\r\n\r\n const cp = getArrowControlPoint(from, to, bend);\r\n\r\n let minX = Math.min(from.x, to.x);\r\n let maxX = Math.max(from.x, to.x);\r\n let minY = Math.min(from.y, to.y);\r\n let maxY = Math.max(from.y, to.y);\r\n\r\n // Analytical extrema for quadratic bezier: t = (P0 - P1) / (P0 - 2*P1 + P2)\r\n const tx = from.x - 2 * cp.x + to.x;\r\n if (tx !== 0) {\r\n const t = (from.x - cp.x) / tx;\r\n if (t > 0 && t < 1) {\r\n const mt = 1 - t;\r\n const x = mt * mt * from.x + 2 * mt * t * cp.x + t * t * to.x;\r\n if (x < minX) minX = x;\r\n if (x > maxX) maxX = x;\r\n }\r\n }\r\n\r\n const ty = from.y - 2 * cp.y + to.y;\r\n if (ty !== 0) {\r\n const t = (from.y - cp.y) / ty;\r\n if (t > 0 && t < 1) {\r\n const mt = 1 - t;\r\n const y = mt * mt * from.y + 2 * mt * t * cp.y + t * t * to.y;\r\n if (y < minY) minY = y;\r\n if (y > maxY) maxY = y;\r\n }\r\n }\r\n\r\n return { x: minX, y: minY, w: maxX - minX, h: maxY - minY };\r\n}\r\n\r\nfunction getTemplateBounds(el: TemplateElement): Bounds {\r\n const { x: cx, y: cy } = el.position;\r\n const r = el.radius;\r\n\r\n switch (el.templateShape) {\r\n case 'circle':\r\n return { x: cx - r, y: cy - r, w: 2 * r, h: 2 * r };\r\n\r\n case 'square':\r\n return { x: cx - r / 2, y: cy - r / 2, w: r, h: r };\r\n\r\n case 'cone': {\r\n const halfAngle = Math.atan(0.5);\r\n const tipX = cx;\r\n const tipY = cy;\r\n const leftX = cx + r * Math.cos(el.angle - halfAngle);\r\n const leftY = cy + r * Math.sin(el.angle - halfAngle);\r\n const rightX = cx + r * Math.cos(el.angle + halfAngle);\r\n const rightY = cy + r * Math.sin(el.angle + halfAngle);\r\n const farX = cx + r * Math.cos(el.angle);\r\n const farY = cy + r * Math.sin(el.angle);\r\n\r\n const xs = [tipX, leftX, rightX, farX];\r\n const ys = [tipY, leftY, rightY, farY];\r\n\r\n let minX = Infinity;\r\n let minY = Infinity;\r\n let maxX = -Infinity;\r\n let maxY = -Infinity;\r\n\r\n for (let i = 0; i < xs.length; i++) {\r\n const px = xs[i];\r\n const py = ys[i];\r\n if (px !== undefined && px < minX) minX = px;\r\n if (px !== undefined && px > maxX) maxX = px;\r\n if (py !== undefined && py < minY) minY = py;\r\n if (py !== undefined && py > maxY) maxY = py;\r\n }\r\n\r\n return { x: minX, y: minY, w: maxX - minX, h: maxY - minY };\r\n }\r\n\r\n case 'line': {\r\n const halfW = r / 12;\r\n const cos = Math.cos(el.angle);\r\n const sin = Math.sin(el.angle);\r\n const perpX = -sin * halfW;\r\n const perpY = cos * halfW;\r\n\r\n const x0 = cx + perpX;\r\n const y0 = cy + perpY;\r\n const x1 = cx + r * cos + perpX;\r\n const y1 = cy + r * sin + perpY;\r\n const x2 = cx + r * cos - perpX;\r\n const y2 = cy + r * sin - perpY;\r\n const x3 = cx - perpX;\r\n const y3 = cy - perpY;\r\n\r\n const minX = Math.min(x0, x1, x2, x3);\r\n const minY = Math.min(y0, y1, y2, y3);\r\n const maxX = Math.max(x0, x1, x2, x3);\r\n const maxY = Math.max(y0, y1, y2, y3);\r\n\r\n return { x: minX, y: minY, w: maxX - minX, h: maxY - minY };\r\n }\r\n\r\n case 'rectangle': {\r\n const halfW = (el.width ?? 0) / 2;\r\n const cos = Math.cos(el.angle);\r\n const sin = Math.sin(el.angle);\r\n const perpX = -sin * halfW;\r\n const perpY = cos * halfW;\r\n const x0 = cx + perpX;\r\n const y0 = cy + perpY;\r\n const x1 = cx + r * cos + perpX;\r\n const y1 = cy + r * sin + perpY;\r\n const x2 = cx + r * cos - perpX;\r\n const y2 = cy + r * sin - perpY;\r\n const x3 = cx - perpX;\r\n const y3 = cy - perpY;\r\n const minX = Math.min(x0, x1, x2, x3);\r\n const minY = Math.min(y0, y1, y2, y3);\r\n const maxX = Math.max(x0, x1, x2, x3);\r\n const maxY = Math.max(y0, y1, y2, y3);\r\n return { x: minX, y: minY, w: maxX - minX, h: maxY - minY };\r\n }\r\n }\r\n}\r\n\r\nexport function transferStrokeBounds(prev: CanvasElement, next: CanvasElement): void {\r\n if (prev.type !== 'stroke' || next.type !== 'stroke') return;\r\n if (prev.points !== next.points) return;\r\n if (prev.position.x !== next.position.x || prev.position.y !== next.position.y) return;\r\n const bounds = strokeBoundsCache.get(prev);\r\n if (bounds) strokeBoundsCache.set(next, bounds);\r\n}\r\n\r\nexport function boundsIntersect(a: Bounds, b: Bounds): boolean {\r\n return a.x <= b.x + b.w && a.x + a.w >= b.x && a.y <= b.y + b.h && a.y + a.h >= b.y;\r\n}\r\n","import type { Bounds } from '../core/types';\r\nimport type { CanvasElement } from './types';\r\nimport { getElementBounds } from './element-bounds';\r\n\r\nexport function getElementsBoundingBox(elements: CanvasElement[]): Bounds | null {\r\n let minX = Infinity;\r\n let minY = Infinity;\r\n let maxX = -Infinity;\r\n let maxY = -Infinity;\r\n let found = false;\r\n\r\n for (const el of elements) {\r\n const b = getElementBounds(el);\r\n if (!b) continue;\r\n found = true;\r\n if (b.x < minX) minX = b.x;\r\n if (b.y < minY) minY = b.y;\r\n if (b.x + b.w > maxX) maxX = b.x + b.w;\r\n if (b.y + b.h > maxY) maxY = b.y + b.h;\r\n }\r\n\r\n if (!found) return null;\r\n return { x: minX, y: minY, w: maxX - minX, h: maxY - minY };\r\n}\r\n","import type { ToolManager } from '../tools/tool-manager';\r\nimport type { ToolContext } from '../tools/types';\r\nimport type { SelectTool } from '../tools/select-tool';\r\nimport type { HistoryRecorder } from '../history/history-recorder';\r\nimport type { HistoryStack } from '../history/history-stack';\r\nimport type { CanvasElement } from '../elements/types';\r\nimport type { Point } from '../core/types';\r\nimport { createId } from '../elements/create-id';\r\nimport { getElementsBoundingBox } from '../elements/bounds';\r\nimport type { RotateDirection } from './selection-rotate';\r\n\r\nexport interface KeyboardActionsDeps {\r\n getToolManager: () => ToolManager | null;\r\n getToolContext: () => ToolContext | null;\r\n getHistoryRecorder: () => HistoryRecorder | null;\r\n getHistoryStack: () => HistoryStack | null;\r\n isToolActive: () => boolean;\r\n fitToContent?: () => void;\r\n group?: () => void;\r\n ungroup?: () => void;\r\n toggleLock?: () => void;\r\n rotate?: (direction: RotateDirection) => void;\r\n getLastPointerWorld?: () => Point | null;\r\n}\r\n\r\nexport class KeyboardActions {\r\n private clipboard: CanvasElement[] = [];\r\n private pasteCount = 0;\r\n private nudgeTimer: ReturnType<typeof setTimeout> | null = null;\r\n private nudgeTxId: number | null = null;\r\n\r\n constructor(private readonly deps: KeyboardActionsDeps) {}\r\n\r\n dispose(): void {\r\n this.flushPendingNudge();\r\n }\r\n\r\n private selectTool(): { tool: SelectTool; ctx: ToolContext } | null {\r\n const tm = this.deps.getToolManager();\r\n const ctx = this.deps.getToolContext();\r\n if (!tm || !ctx) return null;\r\n const tool = tm.activeTool;\r\n if (tool?.name !== 'select') return null;\r\n return { tool: tool as SelectTool, ctx };\r\n }\r\n\r\n private selectableElements(ctx: ToolContext): CanvasElement[] {\r\n return ctx.store\r\n .getAll()\r\n .filter(\r\n (el) =>\r\n !el.locked &&\r\n (ctx.isLayerVisible?.(el.layerId) ?? true) &&\r\n !(ctx.isLayerLocked?.(el.layerId) ?? false),\r\n );\r\n }\r\n\r\n nudge(dx: number, dy: number, byCell: boolean): boolean {\r\n if (this.deps.isToolActive()) return false;\r\n const sel = this.selectTool();\r\n if (!sel) return false;\r\n if (sel.tool.selectedIds.length === 0) return false;\r\n\r\n const step = byCell ? (sel.ctx.gridSize ?? 10) : 1;\r\n if (this.nudgeTimer === null) {\r\n const recorder = this.deps.getHistoryRecorder();\r\n recorder?.begin();\r\n this.nudgeTxId = recorder?.currentTransactionId ?? null;\r\n } else {\r\n clearTimeout(this.nudgeTimer);\r\n const recorder = this.deps.getHistoryRecorder();\r\n if (recorder?.currentTransactionId !== this.nudgeTxId) {\r\n recorder?.begin();\r\n this.nudgeTxId = recorder?.currentTransactionId ?? null;\r\n }\r\n }\r\n const moved = sel.tool.nudgeSelection(dx * step, dy * step, sel.ctx);\r\n this.nudgeTimer = setTimeout(() => this.flushPendingNudge(), 400);\r\n return moved;\r\n }\r\n\r\n flushPendingNudge(): void {\r\n if (this.nudgeTimer === null) return;\r\n clearTimeout(this.nudgeTimer);\r\n this.nudgeTimer = null;\r\n const recorder = this.deps.getHistoryRecorder();\r\n if (recorder?.currentTransactionId === this.nudgeTxId) {\r\n recorder?.commit();\r\n }\r\n this.nudgeTxId = null;\r\n }\r\n\r\n deleteSelected(): void {\r\n if (this.deps.isToolActive()) return;\r\n this.flushPendingNudge();\r\n const sel = this.selectTool();\r\n if (!sel) return;\r\n const ids = sel.tool.selectedIds;\r\n if (ids.length === 0) return;\r\n const recorder = this.deps.getHistoryRecorder();\r\n recorder?.begin();\r\n for (const id of ids) {\r\n sel.ctx.store.remove(id);\r\n }\r\n recorder?.commit();\r\n sel.ctx.requestRender();\r\n }\r\n\r\n undo(): void {\r\n if (this.deps.isToolActive()) return;\r\n this.flushPendingNudge();\r\n const ctx = this.deps.getToolContext();\r\n const stack = this.deps.getHistoryStack();\r\n if (!stack || !ctx) return;\r\n const recorder = this.deps.getHistoryRecorder();\r\n recorder?.pause();\r\n stack.undo(ctx.store);\r\n recorder?.resume();\r\n ctx.requestRender();\r\n }\r\n\r\n redo(): void {\r\n if (this.deps.isToolActive()) return;\r\n this.flushPendingNudge();\r\n const ctx = this.deps.getToolContext();\r\n const stack = this.deps.getHistoryStack();\r\n if (!stack || !ctx) return;\r\n const recorder = this.deps.getHistoryRecorder();\r\n recorder?.pause();\r\n stack.redo(ctx.store);\r\n recorder?.resume();\r\n ctx.requestRender();\r\n }\r\n\r\n copy(): void {\r\n if (this.deps.isToolActive()) return;\r\n const sel = this.selectTool();\r\n if (!sel) return;\r\n const ids = sel.tool.selectedIds;\r\n if (ids.length === 0) return;\r\n this.clipboard = [];\r\n for (const id of ids) {\r\n const el = sel.ctx.store.getById(id);\r\n if (el) this.clipboard.push(structuredClone(el));\r\n }\r\n this.pasteCount = 0;\r\n }\r\n\r\n cut(): void {\r\n if (this.deps.isToolActive()) return;\r\n this.copy();\r\n this.deleteSelected();\r\n }\r\n\r\n hasClipboard(): boolean {\r\n return this.clipboard.length > 0;\r\n }\r\n\r\n paste(): void {\r\n if (this.deps.isToolActive()) return;\r\n this.flushPendingNudge();\r\n if (this.clipboard.length === 0) return;\r\n const sel = this.selectTool();\r\n if (!sel) return;\r\n\r\n const cursor = this.deps.getLastPointerWorld?.() ?? null;\r\n if (cursor) {\r\n const bbox = getElementsBoundingBox(this.clipboard);\r\n if (bbox) {\r\n const centerX = bbox.x + bbox.w / 2;\r\n const centerY = bbox.y + bbox.h / 2;\r\n this.insertClones(this.clipboard, { x: cursor.x - centerX, y: cursor.y - centerY }, sel);\r\n return;\r\n }\r\n }\r\n\r\n this.pasteCount++;\r\n this.insertClones(this.clipboard, { x: this.pasteCount * 20, y: this.pasteCount * 20 }, sel);\r\n }\r\n\r\n duplicate(): void {\r\n if (this.deps.isToolActive()) return;\r\n this.flushPendingNudge();\r\n const sel = this.selectTool();\r\n if (!sel) return;\r\n const source: CanvasElement[] = [];\r\n for (const id of sel.tool.selectedIds) {\r\n const el = sel.ctx.store.getById(id);\r\n if (el) source.push(el);\r\n }\r\n if (source.length === 0) return;\r\n this.insertClones(source, { x: 20, y: 20 }, sel);\r\n }\r\n\r\n deselect(): void {\r\n if (this.deps.isToolActive()) return;\r\n const sel = this.selectTool();\r\n if (!sel) return;\r\n if (sel.tool.selectedIds.length === 0) return;\r\n sel.tool.setSelection([]);\r\n sel.ctx.requestRender();\r\n }\r\n\r\n selectAll(): void {\r\n if (this.deps.isToolActive()) return;\r\n const tm = this.deps.getToolManager();\r\n const ctx = this.deps.getToolContext();\r\n if (!tm || !ctx) return;\r\n if (tm.activeTool?.name !== 'select') {\r\n ctx.switchTool?.('select');\r\n }\r\n const sel = this.selectTool();\r\n if (!sel) return;\r\n const ids = this.selectableElements(sel.ctx).map((el) => el.id);\r\n sel.tool.setSelection(ids);\r\n sel.ctx.requestRender();\r\n }\r\n\r\n cycleSelection(direction: 1 | -1): void {\r\n if (this.deps.isToolActive()) return;\r\n const tm = this.deps.getToolManager();\r\n const ctx = this.deps.getToolContext();\r\n if (!tm || !ctx) return;\r\n if (tm.activeTool?.name !== 'select') ctx.switchTool?.('select');\r\n const sel = this.selectTool();\r\n if (!sel) return;\r\n const eligible = this.selectableElements(sel.ctx).filter((el) => el.type !== 'grid');\r\n if (eligible.length === 0) return;\r\n const idxs = sel.tool.selectedIds\r\n .map((id) => eligible.findIndex((e) => e.id === id))\r\n .filter((i) => i >= 0);\r\n const anchor =\r\n idxs.length === 0\r\n ? direction > 0\r\n ? -1\r\n : 0\r\n : direction > 0\r\n ? Math.max(...idxs)\r\n : Math.min(...idxs);\r\n const next = (anchor + direction + eligible.length) % eligible.length;\r\n const target = eligible[next];\r\n if (!target) return;\r\n sel.tool.setSelection([target.id]);\r\n sel.ctx.requestRender();\r\n }\r\n\r\n zoomToFit(): void {\r\n if (this.deps.isToolActive()) return;\r\n this.deps.fitToContent?.();\r\n }\r\n\r\n group(): void {\r\n if (this.deps.isToolActive()) return;\r\n this.deps.group?.();\r\n }\r\n\r\n ungroup(): void {\r\n if (this.deps.isToolActive()) return;\r\n this.deps.ungroup?.();\r\n }\r\n\r\n toggleLock(): void {\r\n if (this.deps.isToolActive()) return;\r\n this.deps.toggleLock?.();\r\n }\r\n\r\n rotate(direction: RotateDirection): void {\r\n if (this.deps.isToolActive()) return;\r\n this.flushPendingNudge();\r\n const sel = this.selectTool();\r\n if (!sel) return;\r\n if (sel.tool.selectedIds.length === 0) return;\r\n this.deps.rotate?.(direction);\r\n }\r\n\r\n zOrder(operation: 'forward' | 'backward' | 'front' | 'back'): void {\r\n if (this.deps.isToolActive()) return;\r\n this.flushPendingNudge();\r\n const sel = this.selectTool();\r\n if (!sel) return;\r\n const ids = sel.tool.selectedIds;\r\n if (ids.length === 0) return;\r\n const recorder = this.deps.getHistoryRecorder();\r\n recorder?.begin();\r\n for (const id of ids) {\r\n switch (operation) {\r\n case 'forward':\r\n sel.ctx.store.bringForward(id);\r\n break;\r\n case 'backward':\r\n sel.ctx.store.sendBackward(id);\r\n break;\r\n case 'front':\r\n sel.ctx.store.bringToFront(id);\r\n break;\r\n case 'back':\r\n sel.ctx.store.sendToBack(id);\r\n break;\r\n }\r\n }\r\n recorder?.commit();\r\n sel.ctx.requestRender();\r\n }\r\n\r\n private insertClones(\r\n source: CanvasElement[],\r\n offset: Point,\r\n sel: { tool: SelectTool; ctx: ToolContext },\r\n ): void {\r\n const idMap = new Map<string, string>();\r\n for (const el of source) {\r\n idMap.set(el.id, createId(el.type));\r\n }\r\n\r\n const groupIdMap = new Map<string, string>();\r\n for (const el of source) {\r\n if (el.groupId && !groupIdMap.has(el.groupId)) groupIdMap.set(el.groupId, createId('group'));\r\n }\r\n\r\n const newIds: string[] = [];\r\n const recorder = this.deps.getHistoryRecorder();\r\n recorder?.begin();\r\n\r\n for (const el of source) {\r\n const clone = structuredClone(el);\r\n const newId = idMap.get(el.id);\r\n if (!newId) continue;\r\n clone.id = newId;\r\n if (clone.groupId) clone.groupId = groupIdMap.get(clone.groupId) ?? clone.groupId;\r\n clone.position = { x: clone.position.x + offset.x, y: clone.position.y + offset.y };\r\n\r\n if (clone.type === 'arrow') {\r\n const arrow = clone;\r\n arrow.from = { x: arrow.from.x + offset.x, y: arrow.from.y + offset.y };\r\n arrow.to = { x: arrow.to.x + offset.x, y: arrow.to.y + offset.y };\r\n delete arrow.cachedControlPoint;\r\n\r\n if (arrow.fromBinding) {\r\n const newTarget = idMap.get(arrow.fromBinding.elementId);\r\n if (newTarget) {\r\n arrow.fromBinding = { elementId: newTarget };\r\n } else {\r\n delete arrow.fromBinding;\r\n }\r\n }\r\n if (arrow.toBinding) {\r\n const newTarget = idMap.get(arrow.toBinding.elementId);\r\n if (newTarget) {\r\n arrow.toBinding = { elementId: newTarget };\r\n } else {\r\n delete arrow.toBinding;\r\n }\r\n }\r\n }\r\n\r\n if (sel.ctx.activeLayerId) {\r\n clone.layerId = sel.ctx.activeLayerId;\r\n }\r\n\r\n sel.ctx.store.add(clone);\r\n newIds.push(clone.id);\r\n }\r\n\r\n recorder?.commit();\r\n sel.tool.setSelection(newIds);\r\n sel.ctx.requestRender();\r\n }\r\n}\r\n","export type ShortcutBindings = Record<string, string | string[] | null>;\r\n\r\nexport interface ShortcutOptions {\r\n scope?: 'focus' | 'window';\r\n bindings?: ShortcutBindings;\r\n}\r\n\r\nexport interface ShortcutsApi {\r\n rebind(action: string, bindings: string | string[] | null): void;\r\n disable(action: string): void;\r\n reset(action?: string): void;\r\n getBindings(): Record<string, string[]>;\r\n}\r\n\r\ninterface ParsedBinding {\r\n mod: boolean;\r\n ctrl: boolean;\r\n meta: boolean;\r\n shift: boolean;\r\n alt: boolean;\r\n key: string;\r\n digit: boolean;\r\n}\r\n\r\nconst DEFAULT_BINDINGS: readonly (readonly [string, readonly string[]])[] = [\r\n ['delete', ['delete', 'backspace']],\r\n ['deselect', ['escape']],\r\n ['undo', ['mod+z']],\r\n ['redo', ['mod+y', 'mod+shift+z']],\r\n ['select-all', ['mod+a']],\r\n ['cycle-selection', ['tab']],\r\n ['cycle-selection-reverse', ['shift+tab']],\r\n ['copy', ['mod+c']],\r\n ['duplicate', ['mod+d']],\r\n ['z-forward', [']']],\r\n ['z-backward', ['[']],\r\n ['z-front', ['mod+]']],\r\n ['z-back', ['mod+[']],\r\n ['zoom-fit', ['shift+1']],\r\n ['zoom-in', ['mod+=']],\r\n ['zoom-out', ['mod+-']],\r\n ['zoom-reset', ['mod+0']],\r\n ['group', ['mod+g']],\r\n ['ungroup', ['mod+shift+g']],\r\n ['cut', ['mod+x']],\r\n ['toggle-lock', ['mod+shift+l']],\r\n ['rotate-cw', ['r']],\r\n ['rotate-ccw', ['shift+r']],\r\n ['nudge-left', ['arrowleft']],\r\n ['nudge-right', ['arrowright']],\r\n ['nudge-up', ['arrowup']],\r\n ['nudge-down', ['arrowdown']],\r\n ['tool:select', ['v']],\r\n ['tool:hand', ['h']],\r\n ['tool:pencil', ['p']],\r\n ['tool:eraser', ['e']],\r\n ['tool:arrow', ['a']],\r\n ['tool:note', ['n']],\r\n ['tool:text', ['t']],\r\n ['tool:shape', ['s']],\r\n ['tool:measure', ['m']],\r\n ['tool:template', ['g']],\r\n];\r\n\r\nconst ALLOW_SHIFT = new Set(['nudge-left', 'nudge-right', 'nudge-up', 'nudge-down']);\r\nconst MODIFIERS = new Set(['mod', 'ctrl', 'meta', 'shift', 'alt']);\r\n\r\nfunction parseBinding(binding: string): ParsedBinding {\r\n const parts = binding.toLowerCase().split('+');\r\n const key = parts.pop();\r\n if (key === undefined || key.length === 0 || MODIFIERS.has(key)) {\r\n throw new Error(`Invalid shortcut binding \"${binding}\": missing key`);\r\n }\r\n const normalizedKey = key === 'space' ? ' ' : key;\r\n const parsed: ParsedBinding = {\r\n mod: false,\r\n ctrl: false,\r\n meta: false,\r\n shift: false,\r\n alt: false,\r\n key: normalizedKey,\r\n digit: /^[0-9]$/.test(normalizedKey),\r\n };\r\n for (const part of parts) {\r\n switch (part) {\r\n case 'mod':\r\n parsed.mod = true;\r\n break;\r\n case 'ctrl':\r\n parsed.ctrl = true;\r\n break;\r\n case 'meta':\r\n parsed.meta = true;\r\n break;\r\n case 'shift':\r\n parsed.shift = true;\r\n break;\r\n case 'alt':\r\n parsed.alt = true;\r\n break;\r\n default:\r\n throw new Error(`Invalid shortcut binding \"${binding}\": unknown modifier \"${part}\"`);\r\n }\r\n }\r\n if (parsed.mod && (parsed.ctrl || parsed.meta)) {\r\n throw new Error(\r\n `Invalid shortcut binding \"${binding}\": \"mod\" already means Ctrl or Cmd; don't combine it with ctrl/meta`,\r\n );\r\n }\r\n return parsed;\r\n}\r\n\r\nfunction bindingMatches(p: ParsedBinding, e: KeyboardEvent, allowShift: boolean): boolean {\r\n if (p.mod) {\r\n if (!e.ctrlKey && !e.metaKey) return false;\r\n } else if (e.ctrlKey !== p.ctrl || e.metaKey !== p.meta) {\r\n return false;\r\n }\r\n if (!allowShift && e.shiftKey !== p.shift) return false;\r\n if (e.altKey !== p.alt) return false;\r\n return p.digit ? e.code === `Digit${p.key}` : e.key.toLowerCase() === p.key;\r\n}\r\n\r\nfunction sameBinding(a: ParsedBinding, b: ParsedBinding): boolean {\r\n return (\r\n a.key === b.key &&\r\n a.mod === b.mod &&\r\n a.ctrl === b.ctrl &&\r\n a.meta === b.meta &&\r\n a.shift === b.shift &&\r\n a.alt === b.alt\r\n );\r\n}\r\n\r\nfunction toArray(bindings: string | string[] | null): string[] {\r\n if (bindings === null) return [];\r\n return Array.isArray(bindings) ? [...bindings] : [bindings];\r\n}\r\n\r\nexport class ShortcutMap implements ShortcutsApi {\r\n private raw = new Map<string, string[]>();\r\n private parsed = new Map<string, ParsedBinding[]>();\r\n\r\n constructor(overrides?: ShortcutBindings) {\r\n this.applyDefaults();\r\n if (overrides) {\r\n for (const [action, bindings] of Object.entries(overrides)) {\r\n this.rebind(action, bindings);\r\n }\r\n }\r\n }\r\n\r\n /** First matching action in registration order wins when bindings conflict. */\r\n match(e: KeyboardEvent): string | null {\r\n for (const [action, parsedList] of this.parsed) {\r\n const allowShift = ALLOW_SHIFT.has(action);\r\n for (const p of parsedList) {\r\n if (bindingMatches(p, e, allowShift)) return action;\r\n }\r\n }\r\n return null;\r\n }\r\n\r\n rebind(action: string, bindings: string | string[] | null): void {\r\n const list = toArray(bindings);\r\n const parsedList = list.map(parseBinding);\r\n for (const p of parsedList) {\r\n for (const [otherAction, otherList] of this.parsed) {\r\n if (otherAction === action) continue;\r\n if (otherList.some((q) => sameBinding(p, q))) {\r\n console.warn(\r\n `[fieldnotes] shortcut binding for \"${action}\" conflicts with \"${otherAction}\"; first registered wins`,\r\n );\r\n }\r\n }\r\n }\r\n this.raw.set(action, list);\r\n this.parsed.set(action, parsedList);\r\n }\r\n\r\n disable(action: string): void {\r\n this.rebind(action, null);\r\n }\r\n\r\n reset(action?: string): void {\r\n if (action === undefined) {\r\n this.raw.clear();\r\n this.parsed.clear();\r\n this.applyDefaults();\r\n return;\r\n }\r\n const def = DEFAULT_BINDINGS.find(([name]) => name === action);\r\n if (def) {\r\n this.rebind(action, [...def[1]]);\r\n } else if (this.raw.has(action)) {\r\n this.raw.delete(action);\r\n this.parsed.delete(action);\r\n }\r\n }\r\n\r\n getBindings(): Record<string, string[]> {\r\n const out: Record<string, string[]> = {};\r\n for (const [action, list] of this.raw) {\r\n out[action] = [...list];\r\n }\r\n return out;\r\n }\r\n\r\n private applyDefaults(): void {\r\n for (const [action, bindings] of DEFAULT_BINDINGS) {\r\n this.rebind(action, [...bindings]);\r\n }\r\n }\r\n}\r\n","import type { Camera } from './camera';\r\nimport type { ToolContext } from '../tools/types';\r\nimport type { ShortcutOptions, ShortcutsApi } from './shortcut-map';\r\nimport { ShortcutMap } from './shortcut-map';\r\nimport type { KeyboardActions } from './keyboard-actions';\r\n\r\nconst ZOOM_STEP = 1.2;\r\n\r\nconst NUDGE_DELTAS: Record<string, readonly [number, number]> = {\r\n 'nudge-left': [-1, 0],\r\n 'nudge-right': [1, 0],\r\n 'nudge-up': [0, -1],\r\n 'nudge-down': [0, 1],\r\n};\r\n\r\nexport interface KeyboardHandlerDeps {\r\n element: HTMLElement;\r\n camera: Camera;\r\n actions: KeyboardActions;\r\n scope: 'focus' | 'window';\r\n shortcuts?: ShortcutOptions;\r\n abortSignal: AbortSignal;\r\n getToolContext: () => ToolContext | null;\r\n getIsToolActive: () => boolean;\r\n getLastPointerEvent: () => PointerEvent | null;\r\n setSpaceHeld: (v: boolean) => void;\r\n getActivePointerCount: () => number;\r\n dispatchToolHover: (e: PointerEvent) => void;\r\n addImage: (src: string, world: { x: number; y: number }) => string;\r\n getLastPointerWorld: () => { x: number; y: number } | null;\r\n getCenteredWorld: () => { x: number; y: number };\r\n onPaste?: (e: ClipboardEvent, world: { x: number; y: number }) => void;\r\n}\r\n\r\nexport class KeyboardHandler {\r\n private readonly shortcutMap: ShortcutMap;\r\n\r\n constructor(private readonly deps: KeyboardHandlerDeps) {\r\n this.shortcutMap = new ShortcutMap(deps.shortcuts?.bindings);\r\n window.addEventListener('keydown', this.onKeyDown, { signal: deps.abortSignal });\r\n window.addEventListener('keyup', this.onKeyUp, { signal: deps.abortSignal });\r\n window.addEventListener('paste', this.onPaste, { signal: deps.abortSignal });\r\n }\r\n\r\n get shortcuts(): ShortcutsApi {\r\n return this.shortcutMap;\r\n }\r\n\r\n private viewportCenter(): { x: number; y: number } {\r\n const rect = this.deps.element.getBoundingClientRect();\r\n return { x: rect.width / 2, y: rect.height / 2 };\r\n }\r\n\r\n private zoomByFactor(factor: number): void {\r\n this.deps.camera.zoomAt(this.deps.camera.zoom * factor, this.viewportCenter());\r\n }\r\n\r\n private zoomToLevel(level: number): void {\r\n this.deps.camera.zoomAt(level, this.viewportCenter());\r\n }\r\n\r\n private shouldHandle(target: EventTarget | null): boolean {\r\n const el = target as HTMLElement | null;\r\n if (el?.isContentEditable) return false;\r\n const tag = el?.tagName;\r\n if (tag === 'INPUT' || tag === 'TEXTAREA' || tag === 'SELECT') return false;\r\n return this.isInScope();\r\n }\r\n\r\n onKeyDown = (e: KeyboardEvent): void => {\r\n if (!this.shouldHandle(e.target)) return;\r\n\r\n if (e.key === ' ') {\r\n this.deps.setSpaceHeld(true);\r\n }\r\n const action = this.shortcutMap.match(e);\r\n if (action !== null) {\r\n this.runAction(action, e);\r\n }\r\n };\r\n\r\n onKeyUp = (e: KeyboardEvent): void => {\r\n if (e.key === ' ') {\r\n this.deps.setSpaceHeld(false);\r\n if (this.deps.getActivePointerCount() === 0) {\r\n const lastPointerEvent = this.deps.getLastPointerEvent();\r\n if (lastPointerEvent) {\r\n this.deps.dispatchToolHover(lastPointerEvent);\r\n } else {\r\n this.deps.getToolContext()?.setCursor?.('default');\r\n }\r\n }\r\n }\r\n };\r\n\r\n onPaste = (e: ClipboardEvent): void => {\r\n if (!this.shouldHandle(e.target)) return;\r\n const items = e.clipboardData?.items;\r\n let file: File | null = null;\r\n if (items) {\r\n for (const it of items) {\r\n if (it.kind === 'file' && it.type.startsWith('image/')) {\r\n file = it.getAsFile();\r\n break;\r\n }\r\n }\r\n }\r\n if (file) {\r\n e.preventDefault();\r\n const world = this.deps.getLastPointerWorld() ?? this.deps.getCenteredWorld();\r\n if (this.deps.onPaste) {\r\n this.deps.onPaste(e, world);\r\n return;\r\n }\r\n const reader = new FileReader();\r\n reader.onload = () => {\r\n if (typeof reader.result === 'string') this.deps.addImage(reader.result, world);\r\n };\r\n reader.readAsDataURL(file);\r\n return;\r\n }\r\n this.deps.actions.paste();\r\n };\r\n\r\n runAction(action: string, e?: KeyboardEvent): void {\r\n switch (action) {\r\n case 'delete':\r\n e?.preventDefault();\r\n this.deps.actions.deleteSelected();\r\n return;\r\n case 'deselect':\r\n this.deps.actions.deselect();\r\n return;\r\n case 'undo':\r\n e?.preventDefault();\r\n this.deps.actions.undo();\r\n return;\r\n case 'redo':\r\n e?.preventDefault();\r\n this.deps.actions.redo();\r\n return;\r\n case 'select-all':\r\n e?.preventDefault();\r\n this.deps.actions.selectAll();\r\n return;\r\n case 'cycle-selection':\r\n e?.preventDefault();\r\n this.deps.actions.cycleSelection(1);\r\n return;\r\n case 'cycle-selection-reverse':\r\n e?.preventDefault();\r\n this.deps.actions.cycleSelection(-1);\r\n return;\r\n case 'copy':\r\n e?.preventDefault();\r\n this.deps.actions.copy();\r\n return;\r\n case 'paste':\r\n e?.preventDefault();\r\n this.deps.actions.paste();\r\n return;\r\n case 'duplicate':\r\n e?.preventDefault();\r\n this.deps.actions.duplicate();\r\n return;\r\n case 'z-forward':\r\n e?.preventDefault();\r\n this.deps.actions.zOrder('forward');\r\n return;\r\n case 'z-backward':\r\n e?.preventDefault();\r\n this.deps.actions.zOrder('backward');\r\n return;\r\n case 'z-front':\r\n e?.preventDefault();\r\n this.deps.actions.zOrder('front');\r\n return;\r\n case 'z-back':\r\n e?.preventDefault();\r\n this.deps.actions.zOrder('back');\r\n return;\r\n case 'zoom-fit':\r\n e?.preventDefault();\r\n this.deps.actions.zoomToFit();\r\n return;\r\n case 'group':\r\n e?.preventDefault();\r\n this.deps.actions.group();\r\n return;\r\n case 'ungroup':\r\n e?.preventDefault();\r\n this.deps.actions.ungroup();\r\n return;\r\n case 'cut':\r\n e?.preventDefault();\r\n this.deps.actions.cut();\r\n return;\r\n case 'toggle-lock':\r\n e?.preventDefault();\r\n this.deps.actions.toggleLock();\r\n return;\r\n case 'rotate-cw':\r\n e?.preventDefault();\r\n this.deps.actions.rotate('cw');\r\n return;\r\n case 'rotate-ccw':\r\n e?.preventDefault();\r\n this.deps.actions.rotate('ccw');\r\n return;\r\n case 'zoom-in':\r\n e?.preventDefault();\r\n this.zoomByFactor(ZOOM_STEP);\r\n return;\r\n case 'zoom-out':\r\n e?.preventDefault();\r\n this.zoomByFactor(1 / ZOOM_STEP);\r\n return;\r\n case 'zoom-reset':\r\n e?.preventDefault();\r\n this.zoomToLevel(1);\r\n return;\r\n case 'nudge-left':\r\n case 'nudge-right':\r\n case 'nudge-up':\r\n case 'nudge-down': {\r\n const delta = NUDGE_DELTAS[action];\r\n if (delta && this.deps.actions.nudge(delta[0], delta[1], e?.shiftKey ?? false)) {\r\n e?.preventDefault();\r\n }\r\n return;\r\n }\r\n default:\r\n if (action.startsWith('tool:')) {\r\n if (this.deps.getIsToolActive()) return;\r\n e?.preventDefault();\r\n this.deps.getToolContext()?.switchTool?.(action.slice('tool:'.length));\r\n return;\r\n }\r\n console.warn(`[fieldnotes] unknown shortcut action \"${action}\"`);\r\n }\r\n }\r\n\r\n private isInScope(): boolean {\r\n if (this.deps.scope === 'window') return true;\r\n const active = document.activeElement;\r\n return active === this.deps.element || this.deps.element.contains(active);\r\n }\r\n}\r\n","export interface PanInertiaDeps {\n pan: (dx: number, dy: number) => void;\n now: () => number;\n requestFrame: (cb: () => void) => number;\n cancelFrame: (id: number) => void;\n enabled: () => boolean;\n}\n\n// Only the last VELOCITY_WINDOW_MS of drag samples count toward release velocity,\n// so a paused or slow finger at release does not produce a coast.\nconst VELOCITY_WINDOW_MS = 60;\nconst FRICTION = 0.92;\nconst MIN_START_SPEED = 2;\nconst MIN_STOP_SPEED = 0.3;\n\ninterface Sample {\n dx: number;\n dy: number;\n t: number;\n}\n\nexport class PanInertia {\n private samples: Sample[] = [];\n private vx = 0;\n private vy = 0;\n private rafId: number | null = null;\n\n constructor(private readonly deps: PanInertiaDeps) {}\n\n sample(dx: number, dy: number): void {\n const t = this.deps.now();\n this.samples.push({ dx, dy, t });\n this.prune(t);\n }\n\n release(): void {\n if (!this.deps.enabled()) {\n this.reset();\n return;\n }\n const t = this.deps.now();\n this.prune(t);\n const recent = this.samples;\n if (recent.length === 0) {\n this.reset();\n return;\n }\n let sx = 0;\n let sy = 0;\n for (const s of recent) {\n sx += s.dx;\n sy += s.dy;\n }\n this.vx = sx / recent.length;\n this.vy = sy / recent.length;\n this.samples = [];\n if (Math.hypot(this.vx, this.vy) < MIN_START_SPEED) {\n this.vx = 0;\n this.vy = 0;\n return;\n }\n this.rafId = this.deps.requestFrame(this.step);\n }\n\n cancel(): void {\n this.reset();\n }\n\n /** Whether a coast frame is scheduled, i.e. the camera is still gliding. */\n isCoasting(): boolean {\n return this.rafId !== null;\n }\n\n private step = (): void => {\n if (this.rafId === null) return;\n this.deps.pan(this.vx, this.vy);\n this.vx *= FRICTION;\n this.vy *= FRICTION;\n if (Math.hypot(this.vx, this.vy) >= MIN_STOP_SPEED) {\n this.rafId = this.deps.requestFrame(this.step);\n } else {\n this.reset();\n }\n };\n\n private prune(now: number): void {\n const cutoff = now - VELOCITY_WINDOW_MS;\n this.samples = this.samples.filter((s) => s.t >= cutoff);\n }\n\n private reset(): void {\n if (this.rafId !== null) {\n this.deps.cancelFrame(this.rafId);\n this.rafId = null;\n }\n this.samples = [];\n this.vx = 0;\n this.vy = 0;\n }\n}\n","import type { Point } from '../core/types';\nimport type { Camera } from './camera';\nimport type { ToolManager } from '../tools/tool-manager';\nimport type { ToolContext, PointerState } from '../tools/types';\nimport type { HistoryRecorder } from '../history/history-recorder';\nimport type { HistoryStack } from '../history/history-stack';\nimport type { ShortcutOptions, ShortcutsApi } from './shortcut-map';\nimport type { RotateDirection } from './selection-rotate';\nimport { InputFilter } from './input-filter';\nimport { KeyboardActions } from './keyboard-actions';\nimport { KeyboardHandler } from './keyboard-handler';\nimport { PanInertia } from './pan-inertia';\n\nconst ZOOM_SENSITIVITY = 0.001;\nconst MIDDLE_BUTTON = 1;\nconst LONG_PRESS_MS = 500;\n\nexport interface InputHandlerOptions {\n toolManager?: ToolManager;\n toolContext?: ToolContext;\n historyRecorder?: HistoryRecorder;\n historyStack?: HistoryStack;\n fitToContent?: () => void;\n group?: () => void;\n ungroup?: () => void;\n toggleLock?: () => void;\n rotate?: (direction: RotateDirection) => void;\n openContextMenu?: (screenPos: Point, world: Point) => void;\n shortcuts?: ShortcutOptions;\n addImage?: (src: string, world: { x: number; y: number }) => string;\n getCenteredWorld?: () => { x: number; y: number };\n onPaste?: (event: ClipboardEvent, worldPosition: { x: number; y: number }) => void;\n panInertia?: boolean;\n}\n\nexport class InputHandler {\n private isPanning = false;\n private lastPointer = { x: 0, y: 0 };\n private spaceHeld = false;\n private activePointers = new Map<number, { x: number; y: number }>();\n private lastPinchDistance = 0;\n private lastPinchCenter = { x: 0, y: 0 };\n private toolManager: ToolManager | null;\n private toolContext: ToolContext | null;\n private historyRecorder: HistoryRecorder | null;\n private historyStack: HistoryStack | null;\n private isToolActive = false;\n private lastPointerEvent: PointerEvent | null = null;\n private readonly inputFilter = new InputFilter();\n private deferredDown: PointerEvent | null = null;\n private longPressTimer: ReturnType<typeof setTimeout> | null = null;\n private longPressStart: { x: number; y: number } | null = null;\n private readonly abortController = new AbortController();\n private readonly actions: KeyboardActions;\n private readonly keyboard: KeyboardHandler;\n private readonly scope: 'focus' | 'window';\n private readonly openContextMenu?: (screenPos: Point, world: Point) => void;\n private readonly panInertia: PanInertia;\n private readonly panInertiaEnabled: boolean;\n private coastStoppedByPointer = false;\n\n constructor(\n private readonly element: HTMLElement,\n private readonly camera: Camera,\n options: InputHandlerOptions = {},\n ) {\n this.toolManager = options.toolManager ?? null;\n this.toolContext = options.toolContext ?? null;\n this.historyRecorder = options.historyRecorder ?? null;\n this.historyStack = options.historyStack ?? null;\n this.actions = new KeyboardActions({\n getToolManager: () => this.toolManager,\n getToolContext: () => this.toolContext,\n getHistoryRecorder: () => this.historyRecorder,\n getHistoryStack: () => this.historyStack,\n isToolActive: () => this.isToolActive,\n fitToContent: options.fitToContent,\n group: options.group,\n ungroup: options.ungroup,\n toggleLock: options.toggleLock,\n rotate: options.rotate,\n getLastPointerWorld: () => this.lastPointerWorld(),\n });\n this.openContextMenu = options.openContextMenu;\n this.panInertiaEnabled = options.panInertia ?? true;\n this.panInertia = new PanInertia({\n pan: (dx, dy) => this.camera.pan(dx, dy),\n now: () => (typeof performance !== 'undefined' ? performance.now() : Date.now()),\n requestFrame: (cb) =>\n typeof requestAnimationFrame !== 'undefined' ? requestAnimationFrame(cb) : 0,\n cancelFrame: (id) => {\n if (typeof cancelAnimationFrame !== 'undefined') cancelAnimationFrame(id);\n },\n enabled: () => this.panInertiaEnabled,\n });\n this.scope = options.shortcuts?.scope ?? 'focus';\n this.keyboard = new KeyboardHandler({\n element: this.element,\n camera: this.camera,\n actions: this.actions,\n scope: this.scope,\n shortcuts: options.shortcuts,\n abortSignal: this.abortController.signal,\n getToolContext: () => this.toolContext,\n getIsToolActive: () => this.isToolActive,\n getLastPointerEvent: () => this.lastPointerEvent,\n setSpaceHeld: (v) => {\n this.spaceHeld = v;\n },\n getActivePointerCount: () => this.activePointers.size,\n dispatchToolHover: (e) => this.dispatchToolHover(e),\n addImage: options.addImage ?? (() => ''),\n getLastPointerWorld: () => this.lastPointerWorld(),\n getCenteredWorld: options.getCenteredWorld ?? (() => ({ x: 0, y: 0 })),\n onPaste: options.onPaste,\n });\n this.element.style.touchAction = 'none';\n if (this.scope === 'focus') {\n this.element.tabIndex = 0;\n // Suppressed like other canvas SDKs; consumers needing a focus ring style their container.\n this.element.style.outline = 'none';\n }\n this.bind();\n }\n\n setToolManager(toolManager: ToolManager, toolContext: ToolContext): void {\n this.toolManager = toolManager;\n this.toolContext = toolContext;\n }\n\n flushPendingHistory(): void {\n this.actions.flushPendingNudge();\n }\n\n get shortcuts(): ShortcutsApi {\n return this.keyboard.shortcuts;\n }\n\n /**\n * True while the camera glides under pan inertia, and while the pointer\n * gesture that just stopped such a glide is still down. Passive observers use\n * it to ignore a gesture that was only meant to halt the coast.\n */\n isCameraCoasting(): boolean {\n return this.panInertia.isCoasting() || this.coastStoppedByPointer;\n }\n\n destroy(): void {\n this.panInertia.cancel();\n this.coastStoppedByPointer = false;\n this.actions.dispose();\n this.abortController.abort();\n this.inputFilter.reset();\n this.cancelLongPress();\n this.deferredDown = null;\n this.lastPointerEvent = null;\n if (this.scope === 'focus') {\n this.element.removeAttribute('tabindex');\n this.element.style.outline = '';\n }\n }\n\n private bind(): void {\n const opts = { signal: this.abortController.signal };\n\n this.element.addEventListener('wheel', this.onWheel, { ...opts, passive: false });\n this.element.addEventListener('pointerdown', this.onPointerDown, opts);\n this.element.addEventListener('pointermove', this.onPointerMove, opts);\n this.element.addEventListener('pointerup', this.onPointerUp, opts);\n this.element.addEventListener('pointerleave', this.onPointerLeave, opts);\n this.element.addEventListener('pointercancel', this.onPointerUp, opts);\n this.element.addEventListener('contextmenu', this.onContextMenu, opts);\n\n // `coastStoppedByPointer` otherwise clears only when `activePointers` empties,\n // which never happens if the gesture's up/cancel/leave is truncated (lost\n // pointer capture, tab switch mid-press). Window-level, state-clearing only,\n // mirroring `ElementActivation`'s own blur/visibilitychange recovery.\n window.addEventListener('blur', this.onCoastInterrupt, opts);\n window.addEventListener('visibilitychange', this.onCoastInterrupt, opts);\n }\n\n private onWheel = (e: WheelEvent): void => {\n e.preventDefault();\n this.panInertia.cancel();\n const rect = this.element.getBoundingClientRect();\n const zoomFactor = 1 - e.deltaY * ZOOM_SENSITIVITY;\n const newZoom = this.camera.zoom * zoomFactor;\n this.camera.zoomAt(newZoom, {\n x: e.clientX - rect.left,\n y: e.clientY - rect.top,\n });\n };\n\n private onPointerDown = (e: PointerEvent): void => {\n // A pointer landing on the canvas STOPS a coast, and the stop is recorded\n // before it happens. Passive observers (element activation) are registered\n // after this handler, so by the time they see the same pointerdown\n // `panInertia.isCoasting()` already reads false and a gesture whose only\n // purpose was to halt the glide would look like a deliberate tap. The flag\n // outlives the cancel until the gesture's last pointer is released.\n if (this.panInertia.isCoasting()) this.coastStoppedByPointer = true;\n this.panInertia.cancel();\n this.focusSelf();\n this.activePointers.set(e.pointerId, { x: e.clientX, y: e.clientY });\n\n this.element.setPointerCapture?.(e.pointerId);\n\n if (this.activePointers.size === 2) {\n this.cancelLongPress();\n this.startPinch();\n this.cancelToolIfActive(e);\n return;\n }\n\n if (e.button === MIDDLE_BUTTON || (e.button === 0 && this.spaceHeld)) {\n this.cancelLongPress();\n this.isPanning = true;\n this.lastPointer = { x: e.clientX, y: e.clientY };\n return;\n }\n\n if (\n this.activePointers.size === 1 &&\n (e.button === 0 || e.pointerType === 'touch' || e.pointerType === 'pen')\n ) {\n const result = this.inputFilter.filterDown(e);\n if (result.action === 'suppress') return;\n if (result.action === 'defer') {\n this.deferredDown = e;\n this.startLongPress(e);\n return;\n }\n this.dispatchToolDown(e);\n }\n };\n\n private onPointerMove = (e: PointerEvent): void => {\n this.lastPointerEvent = e;\n\n if (this.activePointers.has(e.pointerId)) {\n this.activePointers.set(e.pointerId, { x: e.clientX, y: e.clientY });\n }\n\n if (this.activePointers.size >= 2) {\n this.handlePinchMove();\n return;\n }\n\n if (this.isPanning) {\n const dx = e.clientX - this.lastPointer.x;\n const dy = e.clientY - this.lastPointer.y;\n this.lastPointer = { x: e.clientX, y: e.clientY };\n this.camera.pan(dx, dy);\n this.panInertia.sample(dx, dy);\n return;\n }\n\n if (e.pointerType === 'pen' && !this.activePointers.has(e.pointerId)) {\n this.dispatchToolHover(e);\n } else if (this.isToolActive) {\n this.dispatchToolMove(e);\n } else if (this.deferredDown) {\n const result = this.inputFilter.filterMove(e);\n if (result.action === 'dispatch') {\n this.cancelLongPress();\n this.dispatchToolDown(this.deferredDown);\n this.deferredDown = null;\n this.dispatchToolMove(e);\n }\n } else if (this.activePointers.size === 0) {\n this.dispatchToolHover(e);\n }\n };\n\n private onPointerUp = (e: PointerEvent): void => {\n this.cancelLongPress();\n try {\n this.element.releasePointerCapture(e.pointerId);\n } catch {\n // Already released (e.g., pointercancel fired first)\n }\n const removedActivePointer = this.activePointers.delete(e.pointerId);\n\n if (removedActivePointer && this.activePointers.size >= 2) {\n // Pointer membership may have changed the first-two navigation pair. Rebaseline before the\n // next move so the replacement pointer cannot produce a discontinuous pan or zoom.\n this.startPinch();\n } else if (this.activePointers.size < 2) {\n this.lastPinchDistance = 0;\n const remainingPointer = this.activePointers.values().next().value;\n if (remainingPointer && this.isPanning) {\n this.lastPointer = { ...remainingPointer };\n }\n }\n\n if (this.isPanning && this.activePointers.size === 0) {\n this.isPanning = false;\n this.panInertia.release();\n }\n\n // The gesture that stopped a coast is over once nothing is left down. If it\n // released into a new coast, `panInertia.isCoasting()` reports that instead.\n if (this.activePointers.size === 0) this.coastStoppedByPointer = false;\n\n const upResult = this.inputFilter.filterUp(e);\n\n if (this.isToolActive) {\n this.dispatchToolUp(e);\n this.isToolActive = false;\n } else if (this.deferredDown && upResult.pendingTap) {\n this.dispatchToolDown(this.deferredDown);\n this.dispatchToolUp(e);\n this.deferredDown = null;\n } else {\n this.deferredDown = null;\n }\n };\n\n runAction(action: string, e?: KeyboardEvent): void {\n this.keyboard.runAction(action, e);\n }\n\n hasClipboard(): boolean {\n return this.actions.hasClipboard();\n }\n\n private startPinch(): void {\n this.panInertia.cancel();\n this.cancelLongPress();\n this.inputFilter.reset();\n this.deferredDown = null;\n this.isPanning = true;\n const [a, b] = this.getPinchPoints();\n this.lastPinchDistance = this.distance(a, b);\n this.lastPinchCenter = this.midpoint(a, b);\n this.lastPointer = { ...this.lastPinchCenter };\n }\n\n private handlePinchMove(): void {\n const [a, b] = this.getPinchPoints();\n const dist = this.distance(a, b);\n const center = this.midpoint(a, b);\n\n if (this.lastPinchDistance > 0) {\n const scale = dist / this.lastPinchDistance;\n const newZoom = this.camera.zoom * scale;\n const rect = this.element.getBoundingClientRect();\n this.camera.zoomAt(newZoom, {\n x: center.x - rect.left,\n y: center.y - rect.top,\n });\n }\n\n const dx = center.x - this.lastPointer.x;\n const dy = center.y - this.lastPointer.y;\n this.camera.pan(dx, dy);\n this.panInertia.sample(dx, dy);\n\n this.lastPinchDistance = dist;\n this.lastPinchCenter = center;\n this.lastPointer = { ...center };\n }\n\n private getPinchPoints(): [{ x: number; y: number }, { x: number; y: number }] {\n const pts = [...this.activePointers.values()];\n return [pts[0] ?? { x: 0, y: 0 }, pts[1] ?? { x: 0, y: 0 }];\n }\n\n private distance(a: { x: number; y: number }, b: { x: number; y: number }): number {\n const dx = a.x - b.x;\n const dy = a.y - b.y;\n return Math.sqrt(dx * dx + dy * dy);\n }\n\n private midpoint(\n a: { x: number; y: number },\n b: { x: number; y: number },\n ): { x: number; y: number } {\n return { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 };\n }\n\n private lastPointerWorld(): { x: number; y: number } | null {\n const e = this.lastPointerEvent;\n if (!e) return null;\n const rect = this.element.getBoundingClientRect();\n return this.camera.screenToWorld({ x: e.clientX - rect.left, y: e.clientY - rect.top });\n }\n\n private onContextMenu = (e: MouseEvent): void => {\n e.preventDefault();\n if (this.toolManager?.activeTool?.name !== 'select') return;\n const rect = this.element.getBoundingClientRect();\n const world = this.camera.screenToWorld({ x: e.clientX - rect.left, y: e.clientY - rect.top });\n this.openContextMenu?.({ x: e.clientX, y: e.clientY }, world);\n };\n\n private onPointerLeave = (e: PointerEvent): void => {\n this.lastPointerEvent = null;\n this.onPointerUp(e);\n };\n\n // Recovers `coastStoppedByPointer` when the gesture that set it never delivers\n // a matching pointerup/cancel/leave. Deliberately narrow: it clears only this\n // flag, not `activePointers`/`isPanning`, which is a separate pre-existing gap.\n private onCoastInterrupt = (): void => {\n this.coastStoppedByPointer = false;\n };\n\n private toPointerState(e: PointerEvent): PointerState {\n const rect = this.element.getBoundingClientRect();\n return {\n x: e.clientX - rect.left,\n y: e.clientY - rect.top,\n pressure: e.pressure,\n pointerType: e.pointerType === 'touch' || e.pointerType === 'pen' ? e.pointerType : 'mouse',\n shiftKey: e.shiftKey,\n };\n }\n\n private dispatchToolDown(e: PointerEvent): void {\n if (!this.toolManager || !this.toolContext) return;\n this.actions.flushPendingNudge();\n this.historyRecorder?.begin();\n this.isToolActive = true;\n this.toolManager.handlePointerDown(this.toPointerState(e), this.toolContext);\n }\n\n private dispatchToolMove(e: PointerEvent): void {\n if (!this.toolManager || !this.toolContext) return;\n this.toolManager.handlePointerMove(this.toPointerState(e), this.toolContext);\n }\n\n private dispatchToolHover(e: PointerEvent): void {\n if (!this.toolManager?.activeTool || !this.toolContext) return;\n const tool = this.toolManager.activeTool;\n if (tool.onHover) {\n tool.onHover(this.toPointerState(e), this.toolContext);\n }\n }\n\n private dispatchToolUp(e: PointerEvent): void {\n if (!this.toolManager || !this.toolContext) return;\n this.toolManager.handlePointerUp(this.toPointerState(e), this.toolContext);\n this.historyRecorder?.commit();\n }\n\n private isInScope(): boolean {\n if (this.scope === 'window') return true;\n const active = document.activeElement;\n return active === this.element || this.element.contains(active);\n }\n\n private focusSelf(): void {\n if (this.scope !== 'focus' || this.isInScope()) return;\n this.element.focus({ preventScroll: true });\n }\n\n private cancelToolIfActive(e: PointerEvent): void {\n this.cancelLongPress();\n if (this.isToolActive) {\n this.dispatchToolUp(e);\n this.isToolActive = false;\n }\n this.deferredDown = null;\n }\n\n private startLongPress(e: PointerEvent): void {\n if (e.pointerType !== 'touch') return;\n if (this.toolManager?.activeTool?.name !== 'select') return;\n this.longPressStart = { x: e.clientX, y: e.clientY };\n this.longPressTimer = setTimeout(() => this.fireLongPress(), LONG_PRESS_MS);\n }\n\n private cancelLongPress(): void {\n if (this.longPressTimer !== null) {\n clearTimeout(this.longPressTimer);\n this.longPressTimer = null;\n }\n this.longPressStart = null;\n }\n\n private fireLongPress(): void {\n this.longPressTimer = null;\n if (!this.deferredDown || this.activePointers.size !== 1 || this.isPanning) return;\n const start = this.longPressStart;\n if (!start) return;\n const rect = this.element.getBoundingClientRect();\n const world = this.camera.screenToWorld({ x: start.x - rect.left, y: start.y - rect.top });\n this.deferredDown = null;\n this.openContextMenu?.({ x: start.x, y: start.y }, world);\n }\n}\n","import type { Camera } from './camera';\r\n\r\nexport type BackgroundPattern = 'dots' | 'grid' | 'none';\r\n\r\nexport interface BackgroundOptions {\r\n pattern?: BackgroundPattern;\r\n spacing?: number;\r\n color?: string;\r\n dotRadius?: number;\r\n lineWidth?: number;\r\n}\r\n\r\nconst MIN_PATTERN_SPACING = 16;\r\n\r\nconst DEFAULTS = {\r\n pattern: 'dots' as BackgroundPattern,\r\n spacing: 24,\r\n color: '#d0d0d0',\r\n dotRadius: 1,\r\n lineWidth: 0.5,\r\n};\r\n\r\nexport class Background {\r\n private readonly pattern: BackgroundPattern;\r\n private readonly spacing: number;\r\n private readonly color: string;\r\n private readonly dotRadius: number;\r\n private readonly lineWidth: number;\r\n private cachedCanvas: OffscreenCanvas | HTMLCanvasElement | null = null;\r\n private cachedCtx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D | null = null;\r\n private lastZoom = -1;\r\n private lastOffsetX = -Infinity;\r\n private lastOffsetY = -Infinity;\r\n private lastWidth = 0;\r\n private lastHeight = 0;\r\n\r\n constructor(options: BackgroundOptions = {}) {\r\n this.pattern = options.pattern ?? DEFAULTS.pattern;\r\n this.spacing = options.spacing ?? DEFAULTS.spacing;\r\n this.color = options.color ?? DEFAULTS.color;\r\n this.dotRadius = options.dotRadius ?? DEFAULTS.dotRadius;\r\n this.lineWidth = options.lineWidth ?? DEFAULTS.lineWidth;\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, camera: Camera): void {\r\n const { width, height } = ctx.canvas;\r\n const dpr = typeof devicePixelRatio !== 'undefined' ? devicePixelRatio : 1;\r\n const cssWidth = width / dpr;\r\n const cssHeight = height / dpr;\r\n\r\n ctx.save();\r\n ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\r\n ctx.clearRect(0, 0, cssWidth, cssHeight);\r\n\r\n if (this.pattern === 'none') {\r\n ctx.restore();\r\n return;\r\n }\r\n\r\n const spacing = this.adaptSpacing(this.spacing, camera.zoom);\r\n const keyZoom = camera.zoom;\r\n const keyX = Math.floor(camera.position.x % spacing);\r\n const keyY = Math.floor(camera.position.y % spacing);\r\n\r\n if (\r\n this.cachedCanvas !== null &&\r\n keyZoom === this.lastZoom &&\r\n keyX === this.lastOffsetX &&\r\n keyY === this.lastOffsetY &&\r\n cssWidth === this.lastWidth &&\r\n cssHeight === this.lastHeight\r\n ) {\r\n ctx.drawImage(this.cachedCanvas as CanvasImageSource, 0, 0);\r\n ctx.restore();\r\n return;\r\n }\r\n\r\n this.ensureCachedCanvas(cssWidth, cssHeight, dpr);\r\n\r\n if (this.cachedCtx === null) {\r\n // Fallback: render directly when offscreen canvas is unavailable (e.g. jsdom)\r\n if (this.pattern === 'dots') {\r\n this.renderDots(ctx, camera, cssWidth, cssHeight);\r\n } else if (this.pattern === 'grid') {\r\n this.renderGrid(ctx, camera, cssWidth, cssHeight);\r\n }\r\n ctx.restore();\r\n return;\r\n }\r\n\r\n const offCtx = this.cachedCtx as CanvasRenderingContext2D;\r\n offCtx.clearRect(0, 0, cssWidth, cssHeight);\r\n if (this.pattern === 'dots') {\r\n this.renderDots(offCtx, camera, cssWidth, cssHeight);\r\n } else if (this.pattern === 'grid') {\r\n this.renderGrid(offCtx, camera, cssWidth, cssHeight);\r\n }\r\n\r\n this.lastZoom = keyZoom;\r\n this.lastOffsetX = keyX;\r\n this.lastOffsetY = keyY;\r\n this.lastWidth = cssWidth;\r\n this.lastHeight = cssHeight;\r\n\r\n ctx.drawImage(this.cachedCanvas as CanvasImageSource, 0, 0);\r\n ctx.restore();\r\n }\r\n\r\n private ensureCachedCanvas(cssWidth: number, cssHeight: number, dpr: number): void {\r\n if (\r\n this.cachedCanvas !== null &&\r\n this.lastWidth === cssWidth &&\r\n this.lastHeight === cssHeight\r\n ) {\r\n return;\r\n }\r\n\r\n const physWidth = Math.round(cssWidth * dpr);\r\n const physHeight = Math.round(cssHeight * dpr);\r\n\r\n if (typeof OffscreenCanvas !== 'undefined') {\r\n this.cachedCanvas = new OffscreenCanvas(physWidth, physHeight);\r\n } else if (typeof document !== 'undefined') {\r\n const el = document.createElement('canvas');\r\n el.width = physWidth;\r\n el.height = physHeight;\r\n this.cachedCanvas = el;\r\n } else {\r\n // No offscreen canvas support available; fall back to direct rendering\r\n this.cachedCanvas = null;\r\n this.cachedCtx = null;\r\n return;\r\n }\r\n\r\n const offCtx = this.cachedCanvas.getContext('2d');\r\n if (offCtx !== null) {\r\n (offCtx as CanvasRenderingContext2D).scale(dpr, dpr);\r\n }\r\n this.cachedCtx = offCtx as CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D | null;\r\n\r\n // Force re-render on next frame since canvas was recreated\r\n this.lastZoom = -1;\r\n }\r\n\r\n private adaptSpacing(baseSpacing: number, zoom: number): number {\r\n let spacing = baseSpacing * zoom;\r\n while (spacing < MIN_PATTERN_SPACING) {\r\n spacing *= 2;\r\n }\r\n return spacing;\r\n }\r\n\r\n private renderDots(\r\n ctx: CanvasRenderingContext2D,\r\n camera: Camera,\r\n width: number,\r\n height: number,\r\n ): void {\r\n const spacing = this.adaptSpacing(this.spacing, camera.zoom);\r\n const offsetX = camera.position.x % spacing;\r\n const offsetY = camera.position.y % spacing;\r\n const radius = this.dotRadius * Math.min(camera.zoom, 2);\r\n\r\n ctx.fillStyle = this.color;\r\n ctx.beginPath();\r\n\r\n for (let x = offsetX; x < width; x += spacing) {\r\n for (let y = offsetY; y < height; y += spacing) {\r\n ctx.moveTo(x + radius, y);\r\n ctx.arc(x, y, radius, 0, Math.PI * 2);\r\n }\r\n }\r\n\r\n ctx.fill();\r\n }\r\n\r\n private renderGrid(\r\n ctx: CanvasRenderingContext2D,\r\n camera: Camera,\r\n width: number,\r\n height: number,\r\n ): void {\r\n const spacing = this.adaptSpacing(this.spacing, camera.zoom);\r\n const offsetX = camera.position.x % spacing;\r\n const offsetY = camera.position.y % spacing;\r\n const lineW = this.lineWidth * Math.min(camera.zoom, 2);\r\n\r\n ctx.fillStyle = this.color;\r\n\r\n for (let x = offsetX; x < width; x += spacing) {\r\n ctx.fillRect(x, 0, lineW, height);\r\n }\r\n\r\n for (let y = offsetY; y < height; y += spacing) {\r\n ctx.fillRect(0, y, width, lineW);\r\n }\r\n }\r\n}\r\n","export interface EventMeta {\r\n origin?: string;\r\n}\r\n\r\nconst EMPTY_META: EventMeta = Object.freeze({});\r\n\r\ntype Listener<T> = (data: T, meta: EventMeta) => void;\r\n\r\nexport class EventBus<TEvents extends { [K in keyof TEvents]: TEvents[K] }> {\r\n private listeners = new Map<keyof TEvents, Set<Listener<never>>>();\r\n\r\n on<K extends keyof TEvents>(event: K, listener: Listener<TEvents[K]>): () => void {\r\n const existing = this.listeners.get(event);\r\n if (existing) {\r\n existing.add(listener as Listener<never>);\r\n } else {\r\n const set = new Set<Listener<never>>([listener as Listener<never>]);\r\n this.listeners.set(event, set);\r\n }\r\n return () => this.off(event, listener);\r\n }\r\n\r\n off<K extends keyof TEvents>(event: K, listener: Listener<TEvents[K]>): void {\r\n this.listeners.get(event)?.delete(listener as Listener<never>);\r\n }\r\n\r\n emit<K extends keyof TEvents>(event: K, data: TEvents[K], meta: EventMeta = EMPTY_META): void {\r\n this.listeners.get(event)?.forEach((listener) => {\r\n try {\r\n listener(data as never, meta);\r\n } catch (err) {\r\n console.error(`[fieldnotes] listener error for \"${String(event)}\"`, err);\r\n }\r\n });\r\n }\r\n\r\n clear(): void {\r\n this.listeners.clear();\r\n }\r\n}\r\n","import type { Bounds, Point } from './types';\r\n\r\ninterface Entry {\r\n id: string;\r\n bounds: Bounds;\r\n}\r\n\r\nconst MAX_ITEMS = 8;\r\nconst MAX_DEPTH = 8;\r\n\r\nfunction intersects(a: Bounds, b: Bounds): boolean {\r\n return a.x <= b.x + b.w && a.x + a.w >= b.x && a.y <= b.y + b.h && a.y + a.h >= b.y;\r\n}\r\n\r\nfunction contains(outer: Bounds, inner: Bounds): boolean {\r\n return (\r\n inner.x >= outer.x &&\r\n inner.x + inner.w <= outer.x + outer.w &&\r\n inner.y >= outer.y &&\r\n inner.y + inner.h <= outer.y + outer.h\r\n );\r\n}\r\n\r\nclass QuadNode {\r\n items: Entry[] = [];\r\n children: QuadNode[] | null = null;\r\n\r\n constructor(\r\n readonly bounds: Bounds,\r\n readonly depth: number,\r\n ) {}\r\n\r\n insert(entry: Entry): void {\r\n if (this.children) {\r\n const idx = this.getChildIndex(entry.bounds);\r\n if (idx !== -1) {\r\n const child = this.children[idx];\r\n if (child) child.insert(entry);\r\n return;\r\n }\r\n this.items.push(entry);\r\n return;\r\n }\r\n\r\n this.items.push(entry);\r\n\r\n if (this.items.length > MAX_ITEMS && this.depth < MAX_DEPTH) {\r\n this.split();\r\n }\r\n }\r\n\r\n remove(id: string): boolean {\r\n const idx = this.items.findIndex((e) => e.id === id);\r\n if (idx !== -1) {\r\n this.items.splice(idx, 1);\r\n return true;\r\n }\r\n\r\n if (this.children) {\r\n for (const child of this.children) {\r\n if (child.remove(id)) {\r\n this.collapseIfEmpty();\r\n return true;\r\n }\r\n }\r\n }\r\n\r\n return false;\r\n }\r\n\r\n query(rect: Bounds, result: string[]): void {\r\n if (!intersects(this.bounds, rect)) return;\r\n\r\n for (const item of this.items) {\r\n if (intersects(item.bounds, rect)) {\r\n result.push(item.id);\r\n }\r\n }\r\n\r\n if (this.children) {\r\n for (const child of this.children) {\r\n child.query(rect, result);\r\n }\r\n }\r\n }\r\n\r\n collect(result: Entry[]): void {\r\n result.push(...this.items);\r\n if (this.children) {\r\n for (const child of this.children) {\r\n child.collect(result);\r\n }\r\n }\r\n }\r\n\r\n private getChildIndex(itemBounds: Bounds): number {\r\n const midX = this.bounds.x + this.bounds.w / 2;\r\n const midY = this.bounds.y + this.bounds.h / 2;\r\n\r\n const left = itemBounds.x >= this.bounds.x && itemBounds.x + itemBounds.w <= midX;\r\n const right =\r\n itemBounds.x >= midX && itemBounds.x + itemBounds.w <= this.bounds.x + this.bounds.w;\r\n const top = itemBounds.y >= this.bounds.y && itemBounds.y + itemBounds.h <= midY;\r\n const bottom =\r\n itemBounds.y >= midY && itemBounds.y + itemBounds.h <= this.bounds.y + this.bounds.h;\r\n\r\n if (left && top) return 0;\r\n if (right && top) return 1;\r\n if (left && bottom) return 2;\r\n if (right && bottom) return 3;\r\n\r\n return -1;\r\n }\r\n\r\n private split(): void {\r\n const { x, y, w, h } = this.bounds;\r\n const halfW = w / 2;\r\n const halfH = h / 2;\r\n const d = this.depth + 1;\r\n\r\n this.children = [\r\n new QuadNode({ x, y, w: halfW, h: halfH }, d),\r\n new QuadNode({ x: x + halfW, y, w: halfW, h: halfH }, d),\r\n new QuadNode({ x, y: y + halfH, w: halfW, h: halfH }, d),\r\n new QuadNode({ x: x + halfW, y: y + halfH, w: halfW, h: halfH }, d),\r\n ];\r\n\r\n const remaining: Entry[] = [];\r\n for (const item of this.items) {\r\n const idx = this.getChildIndex(item.bounds);\r\n if (idx !== -1) {\r\n const target = this.children[idx];\r\n if (target) target.insert(item);\r\n } else {\r\n remaining.push(item);\r\n }\r\n }\r\n this.items = remaining;\r\n }\r\n\r\n private collapseIfEmpty(): void {\r\n if (!this.children) return;\r\n let totalItems = this.items.length;\r\n for (const child of this.children) {\r\n if (child.children) return;\r\n totalItems += child.items.length;\r\n }\r\n if (totalItems <= MAX_ITEMS) {\r\n for (const child of this.children) {\r\n this.items.push(...child.items);\r\n }\r\n this.children = null;\r\n }\r\n }\r\n}\r\n\r\nexport class Quadtree {\r\n private root: QuadNode;\r\n private _size = 0;\r\n private readonly worldBounds: Bounds;\r\n\r\n constructor(worldBounds: Bounds) {\r\n this.worldBounds = worldBounds;\r\n this.root = new QuadNode(worldBounds, 0);\r\n }\r\n\r\n get size(): number {\r\n return this._size;\r\n }\r\n\r\n insert(id: string, bounds: Bounds): void {\r\n this.expandToFit(bounds);\r\n this.root.insert({ id, bounds });\r\n this._size++;\r\n }\r\n\r\n remove(id: string): void {\r\n if (this.root.remove(id)) {\r\n this._size--;\r\n }\r\n }\r\n\r\n update(id: string, newBounds: Bounds): void {\r\n this.remove(id);\r\n this.insert(id, newBounds);\r\n }\r\n\r\n query(rect: Bounds): string[] {\r\n const result: string[] = [];\r\n this.root.query(rect, result);\r\n return result;\r\n }\r\n\r\n queryPoint(point: Point): string[] {\r\n return this.query({ x: point.x, y: point.y, w: 0, h: 0 });\r\n }\r\n\r\n clear(): void {\r\n this.root = new QuadNode(this.worldBounds, 0);\r\n this._size = 0;\r\n }\r\n\r\n private expandToFit(bounds: Bounds): void {\r\n const current = this.root.bounds;\r\n if (contains(current, bounds)) return;\r\n\r\n const currentRight = current.x + current.w;\r\n const currentBottom = current.y + current.h;\r\n const requiredWidth =\r\n Math.max(currentRight, bounds.x + bounds.w) - Math.min(current.x, bounds.x);\r\n const requiredHeight =\r\n Math.max(currentBottom, bounds.y + bounds.h) - Math.min(current.y, bounds.y);\r\n const width = Math.max(current.w * 2, requiredWidth);\r\n const height = Math.max(current.h * 2, requiredHeight);\r\n const x = bounds.x < current.x ? currentRight - width : current.x;\r\n const y = bounds.y < current.y ? currentBottom - height : current.y;\r\n\r\n const entries: Entry[] = [];\r\n this.root.collect(entries);\r\n this.root = new QuadNode({ x, y, w: width, h: height }, 0);\r\n for (const entry of entries) {\r\n this.root.insert(entry);\r\n }\r\n }\r\n}\r\n","import type { Point, StrokePoint } from '../core/types';\r\n\r\nexport interface CurveSegment {\r\n start: StrokePoint;\r\n cp1: Point;\r\n cp2: Point;\r\n end: StrokePoint;\r\n}\r\n\r\nconst MIN_PRESSURE_SCALE = 0.4;\r\nconst MAX_PRESSURE_SCALE = 1.8;\r\n\r\nexport function pressureToWidth(pressure: number, baseWidth: number): number {\r\n return baseWidth * (MIN_PRESSURE_SCALE + (MAX_PRESSURE_SCALE - MIN_PRESSURE_SCALE) * pressure);\r\n}\r\n\r\nexport function simplifyPoints(points: StrokePoint[], tolerance: number): StrokePoint[] {\r\n if (points.length <= 2) return points.slice();\r\n return rdp(points, 0, points.length - 1, tolerance);\r\n}\r\n\r\nfunction rdp(points: StrokePoint[], start: number, end: number, tolerance: number): StrokePoint[] {\r\n const first = points[start];\r\n const last = points[end];\r\n if (!first || !last) return [];\r\n\r\n if (end - start <= 1) return [first, last];\r\n\r\n let maxDist = 0;\r\n let maxIndex = start;\r\n\r\n for (let i = start + 1; i < end; i++) {\r\n const pt = points[i];\r\n if (!pt) continue;\r\n const dist = perpendicularDistance(pt, first, last);\r\n if (dist > maxDist) {\r\n maxDist = dist;\r\n maxIndex = i;\r\n }\r\n }\r\n\r\n if (maxDist <= tolerance) return [first, last];\r\n\r\n const left = rdp(points, start, maxIndex, tolerance);\r\n const right = rdp(points, maxIndex, end, tolerance);\r\n\r\n return left.concat(right.slice(1));\r\n}\r\n\r\nfunction perpendicularDistance(pt: Point, lineStart: Point, lineEnd: Point): number {\r\n const dx = lineEnd.x - lineStart.x;\r\n const dy = lineEnd.y - lineStart.y;\r\n const lenSq = dx * dx + dy * dy;\r\n\r\n if (lenSq === 0) {\r\n const ex = pt.x - lineStart.x;\r\n const ey = pt.y - lineStart.y;\r\n return Math.sqrt(ex * ex + ey * ey);\r\n }\r\n\r\n const num = Math.abs(dy * pt.x - dx * pt.y + lineEnd.x * lineStart.y - lineEnd.y * lineStart.x);\r\n return num / Math.sqrt(lenSq);\r\n}\r\n\r\nexport function smoothToSegments(points: StrokePoint[]): CurveSegment[] {\r\n if (points.length < 2) return [];\r\n\r\n if (points.length === 2) {\r\n const p0 = points[0];\r\n const p1 = points[1];\r\n if (!p0 || !p1) return [];\r\n const mx = (p0.x + p1.x) / 2;\r\n const my = (p0.y + p1.y) / 2;\r\n return [{ start: p0, cp1: { x: mx, y: my }, cp2: { x: mx, y: my }, end: p1 }];\r\n }\r\n\r\n const segments: CurveSegment[] = [];\r\n const n = points.length;\r\n\r\n for (let i = 0; i < n - 1; i++) {\r\n const p0 = points[Math.max(0, i - 1)];\r\n const p1 = points[i];\r\n const p2 = points[i + 1];\r\n const p3 = points[Math.min(n - 1, i + 2)];\r\n if (!p0 || !p1 || !p2 || !p3) continue;\r\n\r\n const cp1: Point = {\r\n x: p1.x + (p2.x - p0.x) / 6,\r\n y: p1.y + (p2.y - p0.y) / 6,\r\n };\r\n const cp2: Point = {\r\n x: p2.x - (p3.x - p1.x) / 6,\r\n y: p2.y - (p3.y - p1.y) / 6,\r\n };\r\n\r\n segments.push({ start: p1, cp1, cp2, end: p2 });\r\n }\r\n\r\n return segments;\r\n}\r\n","import type { CanvasElement, StrokeElement } from './types';\r\nimport type { CurveSegment } from './stroke-smoothing';\r\nimport { smoothToSegments, pressureToWidth } from './stroke-smoothing';\r\n\r\nexport interface StrokeWidthBucket {\r\n width: number;\r\n path: Path2D;\r\n}\r\n\r\nexport interface StrokeRenderData {\r\n segments: CurveSegment[]; // always populated; used by hit-testing and the no-Path2D fallback\r\n widths: number[];\r\n buckets: StrokeWidthBucket[] | null; // null when Path2D is unavailable (jsdom / old browsers)\r\n}\r\n\r\n// Strokes are immutable after commit. If points ever become mutable,\r\n// this cache must be invalidated on store.update().\r\nconst cache = new WeakMap<StrokeElement, StrokeRenderData>();\r\n\r\nconst WIDTH_QUANTUM = 0.25;\r\n\r\nfunction buildWidthBuckets(segments: CurveSegment[], widths: number[]): StrokeWidthBucket[] | null {\r\n if (typeof Path2D === 'undefined') return null;\r\n const byWidth = new Map<number, Path2D>();\r\n for (let i = 0; i < segments.length; i++) {\r\n const seg = segments[i];\r\n const w = widths[i];\r\n if (!seg || w === undefined) continue;\r\n const q = Math.max(WIDTH_QUANTUM, Math.round(w / WIDTH_QUANTUM) * WIDTH_QUANTUM);\r\n let path = byWidth.get(q);\r\n if (!path) {\r\n path = new Path2D();\r\n byWidth.set(q, path);\r\n }\r\n // Each segment is an independent open sub-path; moveTo resets the pen between them.\r\n path.moveTo(seg.start.x, seg.start.y);\r\n path.bezierCurveTo(seg.cp1.x, seg.cp1.y, seg.cp2.x, seg.cp2.y, seg.end.x, seg.end.y);\r\n }\r\n return [...byWidth.entries()].map(([width, path]) => ({ width, path }));\r\n}\r\n\r\nexport function computeStrokeSegments(stroke: StrokeElement): StrokeRenderData {\r\n const segments = smoothToSegments(stroke.points);\r\n const widths: number[] = [];\r\n\r\n for (const seg of segments) {\r\n const w =\r\n (pressureToWidth(seg.start.pressure, stroke.width) +\r\n pressureToWidth(seg.end.pressure, stroke.width)) /\r\n 2;\r\n widths.push(w);\r\n }\r\n\r\n const data: StrokeRenderData = { segments, widths, buckets: buildWidthBuckets(segments, widths) };\r\n cache.set(stroke, data);\r\n return data;\r\n}\r\n\r\nexport function getStrokeRenderData(stroke: StrokeElement): StrokeRenderData {\r\n const cached = cache.get(stroke);\r\n if (cached) return cached;\r\n return computeStrokeSegments(stroke);\r\n}\r\n\r\nexport function transferStrokeRenderData(prev: CanvasElement, next: CanvasElement): void {\r\n if (prev.type !== 'stroke' || next.type !== 'stroke') return;\r\n if (prev.points !== next.points) return;\r\n const data = cache.get(prev);\r\n if (data) cache.set(next, data);\r\n}\r\n","import { EventBus } from '../core/event-bus';\r\nimport type { Bounds, Point } from '../core/types';\r\nimport { Quadtree } from '../core/quadtree';\r\nimport { getElementVisualBounds, transferStrokeBounds } from './element-bounds';\r\nimport { getArrowControlPoint } from './arrow-geometry';\r\nimport { sanitizeNoteHtml } from './note-sanitizer';\r\nimport { computeStrokeSegments, transferStrokeRenderData } from './stroke-cache';\r\nimport type { CanvasElement, ElementType } from './types';\r\n\r\nfunction sanitizeRichText(element: CanvasElement): CanvasElement {\r\n if (element.type !== 'note' && element.type !== 'text') return element;\r\n const text = sanitizeNoteHtml(element.text);\r\n return text === element.text ? element : { ...element, text };\r\n}\r\n\r\nexport interface ElementUpdateEvent {\r\n previous: CanvasElement;\r\n current: CanvasElement;\r\n}\r\n\r\nexport interface ElementChangeMeta {\r\n /**\r\n * Identifies what caused the change. `undefined` or `'local'` = a local change (recorded to undo\r\n * history and observed as local). Any other value (e.g. `'remote'`) marks an externally-applied\r\n * change: it is NOT recorded to undo history, and is tagged so observers can avoid re-broadcasting it.\r\n */\r\n origin?: string;\r\n}\r\n\r\ninterface ElementStoreEvents {\r\n add: CanvasElement;\r\n remove: CanvasElement;\r\n update: ElementUpdateEvent;\r\n clear: null;\r\n}\r\n\r\nexport class ElementStore {\r\n private elements = new Map<string, CanvasElement>();\r\n private bus = new EventBus<ElementStoreEvents>();\r\n private layerOrderMap = new Map<string, number>();\r\n private spatialIndex = new Quadtree({ x: -100000, y: -100000, w: 200000, h: 200000 });\r\n private sortedCache: CanvasElement[] | null = null;\r\n private _versions = new Map<string, number>();\r\n\r\n get count(): number {\r\n return this.elements.size;\r\n }\r\n\r\n getVersion(id: string): number {\r\n return this._versions.get(id) ?? -1;\r\n }\r\n\r\n setLayerOrder(order: Map<string, number>): void {\r\n this.layerOrderMap = new Map(order);\r\n this.sortedCache = null;\r\n }\r\n\r\n getAll(): CanvasElement[] {\r\n if (this.sortedCache) return this.sortedCache;\r\n this.sortedCache = [...this.elements.values()].sort((a, b) => {\r\n const layerA = this.layerOrderMap.get(a.layerId) ?? 0;\r\n const layerB = this.layerOrderMap.get(b.layerId) ?? 0;\r\n if (layerA !== layerB) return layerA - layerB;\r\n return a.zIndex - b.zIndex;\r\n });\r\n return this.sortedCache;\r\n }\r\n\r\n getById(id: string): CanvasElement | undefined {\r\n return this.elements.get(id);\r\n }\r\n\r\n getElementsByType<T extends ElementType>(type: T): Extract<CanvasElement, { type: T }>[] {\r\n return this.getAll().filter(\r\n (el): el is Extract<CanvasElement, { type: T }> => el.type === type,\r\n );\r\n }\r\n\r\n // Spatial index stores the rotation-expanded AABB so rotated elements remain\r\n // broad-phase hit-test/marquee candidates; precise tests run against local bounds.\r\n private indexBounds(element: CanvasElement): Bounds | null {\r\n return getElementVisualBounds(element);\r\n }\r\n\r\n add(element: CanvasElement, meta?: ElementChangeMeta): void {\r\n element = sanitizeRichText(element);\r\n this.sortedCache = null;\r\n this._versions.set(element.id, 0);\r\n this.elements.set(element.id, element);\r\n const bounds = this.indexBounds(element);\r\n if (bounds) this.spatialIndex.insert(element.id, bounds);\r\n this.bus.emit('add', element, meta);\r\n }\r\n\r\n update(id: string, partial: Partial<CanvasElement>, meta?: ElementChangeMeta): void {\r\n const existing = this.elements.get(id);\r\n if (!existing) return;\r\n this.sortedCache = null;\r\n this._versions.set(id, (this._versions.get(id) ?? 0) + 1);\r\n\r\n // Shallow spread preserves the points array identity when `partial` omits points;\r\n // transferStrokeRenderData/transferStrokeBounds rely on that reference equality.\r\n const updated = {\r\n ...existing,\r\n ...partial,\r\n id: existing.id,\r\n type: existing.type,\r\n } as CanvasElement;\r\n\r\n if (updated.type === 'stroke' && existing.type === 'stroke') {\r\n transferStrokeRenderData(existing, updated);\r\n transferStrokeBounds(existing, updated);\r\n }\r\n\r\n if (updated.type === 'arrow') {\r\n const arrow = updated;\r\n arrow.cachedControlPoint = getArrowControlPoint(arrow.from, arrow.to, arrow.bend);\r\n }\r\n\r\n if ((updated.type === 'note' || updated.type === 'text') && 'text' in partial) {\r\n updated.text = sanitizeNoteHtml(updated.text);\r\n }\r\n\r\n this.elements.set(id, updated);\r\n\r\n const newBounds = this.indexBounds(updated);\r\n if (newBounds) {\r\n this.spatialIndex.update(id, newBounds);\r\n }\r\n\r\n this.bus.emit('update', { previous: existing, current: updated }, meta);\r\n }\r\n\r\n remove(id: string, meta?: ElementChangeMeta): void {\r\n const element = this.elements.get(id);\r\n if (!element) return;\r\n this.sortedCache = null;\r\n this._versions.delete(id);\r\n\r\n this.elements.delete(id);\r\n this.spatialIndex.remove(id);\r\n this.bus.emit('remove', element, meta);\r\n }\r\n\r\n clear(meta?: ElementChangeMeta): void {\r\n this.sortedCache = null;\r\n this._versions.clear();\r\n this.elements.clear();\r\n this.spatialIndex.clear();\r\n this.bus.emit('clear', null, meta);\r\n }\r\n\r\n snapshot(): CanvasElement[] {\r\n return this.getAll().map((el) => ({ ...el }));\r\n }\r\n\r\n loadSnapshot(elements: CanvasElement[], meta?: ElementChangeMeta): void {\r\n const sanitizedElements = elements.map(sanitizeRichText);\r\n this.sortedCache = null;\r\n this._versions.clear();\r\n this.elements.clear();\r\n this.spatialIndex.clear();\r\n for (const el of sanitizedElements) {\r\n this.elements.set(el.id, el);\r\n this._versions.set(el.id, 0);\r\n const bounds = this.indexBounds(el);\r\n if (bounds) this.spatialIndex.insert(el.id, bounds);\r\n if (el.type === 'stroke') {\r\n computeStrokeSegments(el);\r\n }\r\n if (el.type === 'arrow' && el.bend !== 0 && !el.cachedControlPoint) {\r\n el.cachedControlPoint = getArrowControlPoint(el.from, el.to, el.bend);\r\n }\r\n }\r\n this.bus.emit('clear', null, meta);\r\n for (const el of sanitizedElements) {\r\n this.bus.emit('add', el, meta);\r\n }\r\n }\r\n\r\n bringToFront(id: string): void {\r\n const el = this.elements.get(id);\r\n if (!el) return;\r\n const siblings = [...this.elements.values()].filter(\r\n (e) => e.layerId === el.layerId && e.id !== id,\r\n );\r\n if (siblings.length === 0) return;\r\n const maxZ = Math.max(...siblings.map((e) => e.zIndex));\r\n if (el.zIndex >= maxZ) return;\r\n this.update(id, { zIndex: maxZ + 1 });\r\n }\r\n\r\n sendToBack(id: string): void {\r\n const el = this.elements.get(id);\r\n if (!el) return;\r\n const siblings = [...this.elements.values()].filter(\r\n (e) => e.layerId === el.layerId && e.id !== id,\r\n );\r\n if (siblings.length === 0) return;\r\n const minZ = Math.min(...siblings.map((e) => e.zIndex));\r\n if (el.zIndex <= minZ) return;\r\n this.update(id, { zIndex: minZ - 1 });\r\n }\r\n\r\n bringForward(id: string): void {\r\n const el = this.elements.get(id);\r\n if (!el) return;\r\n const sorted = [...this.elements.values()]\r\n .filter((e) => e.layerId === el.layerId)\r\n .sort((a, b) => a.zIndex - b.zIndex);\r\n const idx = sorted.findIndex((e) => e.id === id);\r\n if (idx < 0 || idx >= sorted.length - 1) return;\r\n const next = sorted[idx + 1];\r\n if (!next) return;\r\n const myZ = el.zIndex;\r\n const nextZ = next.zIndex;\r\n this.update(id, { zIndex: nextZ });\r\n this.update(next.id, { zIndex: myZ });\r\n }\r\n\r\n sendBackward(id: string): void {\r\n const el = this.elements.get(id);\r\n if (!el) return;\r\n const sorted = [...this.elements.values()]\r\n .filter((e) => e.layerId === el.layerId)\r\n .sort((a, b) => a.zIndex - b.zIndex);\r\n const idx = sorted.findIndex((e) => e.id === id);\r\n if (idx <= 0) return;\r\n const prev = sorted[idx - 1];\r\n if (!prev) return;\r\n const myZ = el.zIndex;\r\n const prevZ = prev.zIndex;\r\n this.update(id, { zIndex: prevZ });\r\n this.update(prev.id, { zIndex: myZ });\r\n }\r\n\r\n queryRect(rect: Bounds): CanvasElement[] {\r\n const ids = this.spatialIndex.query(rect);\r\n const elements: CanvasElement[] = [];\r\n for (const id of ids) {\r\n const el = this.elements.get(id);\r\n if (el) elements.push(el);\r\n }\r\n return elements.sort((a, b) => {\r\n const layerA = this.layerOrderMap.get(a.layerId) ?? 0;\r\n const layerB = this.layerOrderMap.get(b.layerId) ?? 0;\r\n if (layerA !== layerB) return layerA - layerB;\r\n return a.zIndex - b.zIndex;\r\n });\r\n }\r\n\r\n queryPoint(point: Point): CanvasElement[] {\r\n return this.queryRect({ x: point.x, y: point.y, w: 0, h: 0 });\r\n }\r\n\r\n on<K extends keyof ElementStoreEvents>(\r\n event: K,\r\n listener: (data: ElementStoreEvents[K], meta: ElementChangeMeta) => void,\r\n ): () => void {\r\n return this.bus.on(event, listener);\r\n }\r\n\r\n onChange(listener: () => void): () => void {\r\n const unsubs = [\r\n this.bus.on('add', listener),\r\n this.bus.on('remove', listener),\r\n this.bus.on('update', listener),\r\n this.bus.on('clear', listener),\r\n ];\r\n return () => unsubs.forEach((fn) => fn());\r\n }\r\n}\r\n","import type { Point } from '../core/types';\r\n\r\nexport function withRotation(\r\n ctx: CanvasRenderingContext2D,\r\n el: { rotation?: number },\r\n center: Point,\r\n draw: () => void,\r\n): void {\r\n const angle = el.rotation ?? 0;\r\n if (angle === 0) {\r\n draw();\r\n return;\r\n }\r\n ctx.save();\r\n ctx.translate(center.x, center.y);\r\n ctx.rotate(angle);\r\n ctx.translate(-center.x, -center.y);\r\n draw();\r\n ctx.restore();\r\n}\r\n","import type { StrokeElement } from '../types';\r\nimport { getStrokeRenderData } from '../stroke-cache';\r\n\r\nexport function renderStroke(ctx: CanvasRenderingContext2D, stroke: StrokeElement): void {\r\n if (stroke.points.length < 2) return;\r\n\r\n ctx.save();\r\n if (stroke.blendMode) ctx.globalCompositeOperation = stroke.blendMode;\r\n ctx.translate(stroke.position.x, stroke.position.y);\r\n ctx.strokeStyle = stroke.color;\r\n ctx.lineCap = 'round';\r\n ctx.lineJoin = 'round';\r\n ctx.globalAlpha = stroke.opacity;\r\n\r\n const data = getStrokeRenderData(stroke);\r\n if (data.buckets) {\r\n for (const bucket of data.buckets) {\r\n ctx.lineWidth = bucket.width;\r\n ctx.stroke(bucket.path);\r\n }\r\n } else {\r\n for (let i = 0; i < data.segments.length; i++) {\r\n const seg = data.segments[i];\r\n const w = data.widths[i];\r\n if (!seg || w === undefined) continue;\r\n ctx.lineWidth = w;\r\n ctx.beginPath();\r\n ctx.moveTo(seg.start.x, seg.start.y);\r\n ctx.bezierCurveTo(seg.cp1.x, seg.cp1.y, seg.cp2.x, seg.cp2.y, seg.end.x, seg.end.y);\r\n ctx.stroke();\r\n }\r\n }\r\n\r\n ctx.restore();\r\n}\r\n","import type { Point, Size } from '../core/types';\r\nimport type { ShapeElement } from './types';\r\n\r\n/** Inverse of lineEndpoints: two endpoints → a line shape's bbox + flip. */\r\nexport function lineFromEndpoints(a: Point, b: Point): { position: Point; size: Size; flip: boolean } {\r\n return {\r\n position: { x: Math.min(a.x, b.x), y: Math.min(a.y, b.y) },\r\n size: { w: Math.abs(b.x - a.x), h: Math.abs(b.y - a.y) },\r\n flip: (b.x > a.x) !== (b.y > a.y),\r\n };\r\n}\r\n\r\n/** The two segment endpoints of a 'line' shape, from its bbox + flip. */\r\nexport function lineEndpoints(shape: ShapeElement): [Point, Point] {\r\n const { x, y } = shape.position;\r\n const { w, h } = shape.size;\r\n return shape.flip\r\n ? [\r\n { x, y: y + h },\r\n { x: x + w, y },\r\n ]\r\n : [\r\n { x, y },\r\n { x: x + w, y: y + h },\r\n ];\r\n}\r\n","import type { ShapeElement } from '../types';\r\nimport { lineEndpoints } from '../shape-geometry';\r\n\r\nexport function renderShape(ctx: CanvasRenderingContext2D, shape: ShapeElement): void {\r\n ctx.save();\r\n\r\n if (shape.fillColor !== 'none' && shape.shape !== 'line') {\r\n ctx.fillStyle = shape.fillColor;\r\n fillShapePath(ctx, shape);\r\n }\r\n\r\n if (shape.strokeWidth > 0) {\r\n ctx.strokeStyle = shape.strokeColor;\r\n ctx.lineWidth = shape.strokeWidth;\r\n strokeShapePath(ctx, shape);\r\n }\r\n\r\n ctx.restore();\r\n}\r\n\r\nfunction fillShapePath(ctx: CanvasRenderingContext2D, shape: ShapeElement): void {\r\n switch (shape.shape) {\r\n case 'rectangle':\r\n ctx.fillRect(shape.position.x, shape.position.y, shape.size.w, shape.size.h);\r\n break;\r\n case 'ellipse': {\r\n const cx = shape.position.x + shape.size.w / 2;\r\n const cy = shape.position.y + shape.size.h / 2;\r\n ctx.beginPath();\r\n ctx.ellipse(cx, cy, shape.size.w / 2, shape.size.h / 2, 0, 0, Math.PI * 2);\r\n ctx.fill();\r\n break;\r\n }\r\n }\r\n}\r\n\r\nfunction strokeShapePath(ctx: CanvasRenderingContext2D, shape: ShapeElement): void {\r\n switch (shape.shape) {\r\n case 'rectangle':\r\n ctx.strokeRect(shape.position.x, shape.position.y, shape.size.w, shape.size.h);\r\n break;\r\n case 'ellipse': {\r\n const cx = shape.position.x + shape.size.w / 2;\r\n const cy = shape.position.y + shape.size.h / 2;\r\n ctx.beginPath();\r\n ctx.ellipse(cx, cy, shape.size.w / 2, shape.size.h / 2, 0, 0, Math.PI * 2);\r\n ctx.stroke();\r\n break;\r\n }\r\n case 'line': {\r\n const [a, b] = lineEndpoints(shape);\r\n ctx.lineCap = 'round';\r\n ctx.beginPath();\r\n ctx.moveTo(a.x, a.y);\r\n ctx.lineTo(b.x, b.y);\r\n ctx.stroke();\r\n break;\r\n }\r\n }\r\n}\r\n","import type { Point } from '../core/types';\r\nimport type { ArrowElement } from './types';\r\nimport { getArrowControlPoint, getArrowTangentAngle } from './arrow-geometry';\r\n\r\nexport interface ArrowRenderGeometry {\r\n controlPoint: Point | null;\r\n tangentStart: number;\r\n tangentEnd: number;\r\n}\r\n\r\n// Intrinsic geometry only (from/to/bend). Binding-resolved endpoints are deliberately\r\n// NOT cached: bound targets can move without the arrow object being replaced.\r\nconst cache = new WeakMap<ArrowElement, ArrowRenderGeometry>();\r\n\r\nexport function getArrowRenderGeometry(arrow: ArrowElement): ArrowRenderGeometry {\r\n const hit = cache.get(arrow);\r\n if (hit) return hit;\r\n const geometry: ArrowRenderGeometry = {\r\n controlPoint:\r\n arrow.bend !== 0\r\n ? (arrow.cachedControlPoint ?? getArrowControlPoint(arrow.from, arrow.to, arrow.bend))\r\n : null,\r\n tangentStart: getArrowTangentAngle(arrow.from, arrow.to, arrow.bend, 0),\r\n tangentEnd: getArrowTangentAngle(arrow.from, arrow.to, arrow.bend, 1),\r\n };\r\n cache.set(arrow, geometry);\r\n return geometry;\r\n}\r\n","import type { Bounds, Point } from '../core/types';\r\nimport type { ArrowElement, CanvasElement } from './types';\r\nimport type { ElementStore } from './element-store';\r\nimport { getArrowTangentAngle } from './arrow-geometry';\r\nimport { getElementBounds } from './element-bounds';\r\n\r\nconst BINDABLE_TYPES = new Set(['note', 'text', 'image', 'html', 'shape']);\r\n\r\nexport function isBindable(element: CanvasElement): boolean {\r\n return BINDABLE_TYPES.has(element.type);\r\n}\r\n\r\nexport function getElementCenter(element: CanvasElement): Point {\r\n if (!('size' in element)) {\r\n throw new Error(`getElementCenter: element type \"${element.type}\" has no size`);\r\n }\r\n return {\r\n x: element.position.x + element.size.w / 2,\r\n y: element.position.y + element.size.h / 2,\r\n };\r\n}\r\n\r\nexport function getEdgeIntersection(bounds: Bounds, outsidePoint: Point): Point {\r\n const cx = bounds.x + bounds.w / 2;\r\n const cy = bounds.y + bounds.h / 2;\r\n const dx = outsidePoint.x - cx;\r\n const dy = outsidePoint.y - cy;\r\n\r\n if (dx === 0 && dy === 0) return { x: cx, y: cy };\r\n\r\n const halfW = bounds.w / 2;\r\n const halfH = bounds.h / 2;\r\n\r\n const scaleX = dx !== 0 ? halfW / Math.abs(dx) : Infinity;\r\n const scaleY = dy !== 0 ? halfH / Math.abs(dy) : Infinity;\r\n const scale = Math.min(scaleX, scaleY);\r\n\r\n return {\r\n x: cx + dx * scale,\r\n y: cy + dy * scale,\r\n };\r\n}\r\n\r\nexport function findBindTarget(\r\n point: Point,\r\n store: ElementStore,\r\n threshold: number,\r\n excludeId?: string,\r\n filter?: (el: CanvasElement) => boolean,\r\n): CanvasElement | null {\r\n let closest: CanvasElement | null = null;\r\n let closestDist = Infinity;\r\n\r\n for (const el of store.getAll()) {\r\n if (!isBindable(el)) continue;\r\n if (excludeId && el.id === excludeId) continue;\r\n if (filter && !filter(el)) continue;\r\n\r\n const bounds = getElementBounds(el);\r\n if (!bounds) continue;\r\n\r\n const dist = distToBounds(point, bounds);\r\n if (dist <= threshold && dist < closestDist) {\r\n closest = el;\r\n closestDist = dist;\r\n }\r\n }\r\n\r\n return closest;\r\n}\r\n\r\nfunction distToBounds(point: Point, bounds: Bounds): number {\r\n const clampedX = Math.max(bounds.x, Math.min(point.x, bounds.x + bounds.w));\r\n const clampedY = Math.max(bounds.y, Math.min(point.y, bounds.y + bounds.h));\r\n return Math.hypot(point.x - clampedX, point.y - clampedY);\r\n}\r\n\r\nexport function findBoundArrows(elementId: string, store: ElementStore): ArrowElement[] {\r\n return store\r\n .getElementsByType('arrow')\r\n .filter((a) => a.fromBinding?.elementId === elementId || a.toBinding?.elementId === elementId);\r\n}\r\n\r\n/** Re-anchor every arrow bound to any of the moved non-arrow elements (each updated once). */\r\nexport function updateArrowsBoundToElements(movedIds: Iterable<string>, store: ElementStore): void {\r\n const movedNonArrowIds = new Set<string>();\r\n for (const id of movedIds) {\r\n const el = store.getById(id);\r\n if (el && el.type !== 'arrow') movedNonArrowIds.add(id);\r\n }\r\n if (movedNonArrowIds.size === 0) return;\r\n const updated = new Set<string>();\r\n for (const id of movedNonArrowIds) {\r\n for (const ba of findBoundArrows(id, store)) {\r\n if (updated.has(ba.id)) continue;\r\n updated.add(ba.id);\r\n const updates = updateBoundArrow(ba, store);\r\n if (updates) store.update(ba.id, updates);\r\n }\r\n }\r\n}\r\n\r\nexport function updateBoundArrow(\r\n arrow: ArrowElement,\r\n store: ElementStore,\r\n): Partial<ArrowElement> | null {\r\n if (!arrow.fromBinding && !arrow.toBinding) return null;\r\n\r\n const updates: Partial<ArrowElement> = {};\r\n\r\n if (arrow.fromBinding) {\r\n const el = store.getById(arrow.fromBinding.elementId);\r\n if (el) {\r\n const center = getElementCenter(el);\r\n updates.from = center;\r\n updates.position = center;\r\n }\r\n }\r\n\r\n if (arrow.toBinding) {\r\n const el = store.getById(arrow.toBinding.elementId);\r\n if (el) {\r\n updates.to = getElementCenter(el);\r\n }\r\n }\r\n\r\n return Object.keys(updates).length > 0 ? updates : null;\r\n}\r\n\r\nexport function clearStaleBindings(\r\n arrow: ArrowElement,\r\n store: ElementStore,\r\n): Partial<ArrowElement> | null {\r\n const updates: Partial<ArrowElement> = {};\r\n let hasUpdates = false;\r\n\r\n if (arrow.fromBinding && !store.getById(arrow.fromBinding.elementId)) {\r\n updates.fromBinding = undefined;\r\n hasUpdates = true;\r\n }\r\n\r\n if (arrow.toBinding && !store.getById(arrow.toBinding.elementId)) {\r\n updates.toBinding = undefined;\r\n hasUpdates = true;\r\n }\r\n\r\n return hasUpdates ? updates : null;\r\n}\r\n\r\nexport function unbindArrow(arrow: ArrowElement, store: ElementStore): Partial<ArrowElement> {\r\n const updates: Partial<ArrowElement> = {};\r\n\r\n if (arrow.fromBinding) {\r\n const el = store.getById(arrow.fromBinding.elementId);\r\n const bounds = el ? getElementBounds(el) : null;\r\n if (bounds) {\r\n const angle = getArrowTangentAngle(arrow.from, arrow.to, arrow.bend, 0);\r\n const rayTarget = {\r\n x: arrow.from.x + Math.cos(angle) * 1000,\r\n y: arrow.from.y + Math.sin(angle) * 1000,\r\n };\r\n const edge = getEdgeIntersection(bounds, rayTarget);\r\n updates.from = edge;\r\n updates.position = edge;\r\n }\r\n updates.fromBinding = undefined;\r\n }\r\n\r\n if (arrow.toBinding) {\r\n const el = store.getById(arrow.toBinding.elementId);\r\n const bounds = el ? getElementBounds(el) : null;\r\n if (bounds) {\r\n const angle = getArrowTangentAngle(arrow.from, arrow.to, arrow.bend, 1);\r\n // Reverse tangent direction — tangent at t=1 points away from curve body\r\n const rayTarget = {\r\n x: arrow.to.x - Math.cos(angle) * 1000,\r\n y: arrow.to.y - Math.sin(angle) * 1000,\r\n };\r\n updates.to = getEdgeIntersection(bounds, rayTarget);\r\n }\r\n updates.toBinding = undefined;\r\n }\r\n\r\n return updates;\r\n}\r\n","import type { ArrowElement, ArrowStrokeStyle } from '../types';\r\nimport type { ElementStore } from '../element-store';\r\nimport { getArrowRenderGeometry } from '../arrow-render-cache';\r\nimport { getArrowMidpoint } from '../arrow-geometry';\r\nimport { getEdgeIntersection } from '../arrow-binding';\r\nimport { getElementBounds } from '../element-bounds';\r\n\r\nconst ARROWHEAD_LENGTH = 12;\r\nconst ARROWHEAD_ANGLE = Math.PI / 6;\r\nconst ARROW_LABEL_FONT_SIZE = 14;\r\n\r\nexport function getArrowDashPattern(strokeStyle: ArrowStrokeStyle | undefined): number[] {\r\n switch (strokeStyle) {\r\n case 'dashed':\r\n return [8, 4];\r\n case 'dotted':\r\n return [2, 4];\r\n default:\r\n return [];\r\n }\r\n}\r\n\r\nexport function renderArrow(\r\n ctx: CanvasRenderingContext2D,\r\n arrow: ArrowElement,\r\n store: ElementStore | null,\r\n labelEditingId: string | null,\r\n): void {\r\n const geometry = getArrowRenderGeometry(arrow);\r\n const { visualFrom, visualTo } = getVisualEndpoints(arrow, geometry, store);\r\n\r\n ctx.save();\r\n ctx.strokeStyle = arrow.color;\r\n ctx.lineWidth = arrow.width;\r\n ctx.lineCap = 'round';\r\n\r\n const dash = getArrowDashPattern(arrow.strokeStyle);\r\n if (dash.length > 0) ctx.setLineDash(dash);\r\n\r\n ctx.beginPath();\r\n ctx.moveTo(visualFrom.x, visualFrom.y);\r\n\r\n if (arrow.bend !== 0) {\r\n const cp = geometry.controlPoint;\r\n if (cp) {\r\n ctx.quadraticCurveTo(cp.x, cp.y, visualTo.x, visualTo.y);\r\n }\r\n } else {\r\n ctx.lineTo(visualTo.x, visualTo.y);\r\n }\r\n ctx.stroke();\r\n\r\n renderArrowhead(ctx, arrow, visualTo, geometry.tangentEnd);\r\n ctx.restore();\r\n renderArrowLabel(ctx, arrow, labelEditingId);\r\n}\r\n\r\nfunction renderArrowLabel(\r\n ctx: CanvasRenderingContext2D,\r\n arrow: ArrowElement,\r\n labelEditingId: string | null,\r\n): void {\r\n if (!arrow.label || arrow.label.length === 0) return;\r\n if (arrow.id === labelEditingId) return;\r\n const mid = getArrowMidpoint(arrow.from, arrow.to, arrow.bend);\r\n ctx.save();\r\n ctx.font = `${ARROW_LABEL_FONT_SIZE}px system-ui, sans-serif`;\r\n const metrics = ctx.measureText(arrow.label);\r\n const padX = 6;\r\n const padY = 4;\r\n const w = metrics.width + padX * 2;\r\n const h = ARROW_LABEL_FONT_SIZE + padY * 2;\r\n ctx.fillStyle = 'rgba(255, 255, 255, 0.9)';\r\n ctx.beginPath();\r\n ctx.roundRect(mid.x - w / 2, mid.y - h / 2, w, h, 4);\r\n ctx.fill();\r\n ctx.fillStyle = '#1a1a1a';\r\n ctx.textAlign = 'center';\r\n ctx.textBaseline = 'middle';\r\n ctx.fillText(arrow.label, mid.x, mid.y);\r\n ctx.restore();\r\n}\r\n\r\nfunction renderArrowhead(\r\n ctx: CanvasRenderingContext2D,\r\n arrow: ArrowElement,\r\n tip: { x: number; y: number },\r\n angle: number,\r\n): void {\r\n ctx.beginPath();\r\n ctx.moveTo(tip.x, tip.y);\r\n ctx.lineTo(\r\n tip.x - ARROWHEAD_LENGTH * Math.cos(angle - ARROWHEAD_ANGLE),\r\n tip.y - ARROWHEAD_LENGTH * Math.sin(angle - ARROWHEAD_ANGLE),\r\n );\r\n ctx.lineTo(\r\n tip.x - ARROWHEAD_LENGTH * Math.cos(angle + ARROWHEAD_ANGLE),\r\n tip.y - ARROWHEAD_LENGTH * Math.sin(angle + ARROWHEAD_ANGLE),\r\n );\r\n ctx.closePath();\r\n ctx.fillStyle = arrow.color;\r\n ctx.fill();\r\n}\r\n\r\nexport function getVisualEndpoints(\r\n arrow: ArrowElement,\r\n geometry: ReturnType<typeof getArrowRenderGeometry>,\r\n store: ElementStore | null,\r\n): {\r\n visualFrom: { x: number; y: number };\r\n visualTo: { x: number; y: number };\r\n} {\r\n let visualFrom = arrow.from;\r\n let visualTo = arrow.to;\r\n\r\n if (!store) return { visualFrom, visualTo };\r\n\r\n if (arrow.fromBinding) {\r\n const el = store.getById(arrow.fromBinding.elementId);\r\n if (el) {\r\n const bounds = getElementBounds(el);\r\n if (bounds) {\r\n const tangentAngle = geometry.tangentStart;\r\n const rayTarget = {\r\n x: arrow.from.x + Math.cos(tangentAngle) * 1000,\r\n y: arrow.from.y + Math.sin(tangentAngle) * 1000,\r\n };\r\n visualFrom = getEdgeIntersection(bounds, rayTarget);\r\n }\r\n }\r\n }\r\n\r\n if (arrow.toBinding) {\r\n const el = store.getById(arrow.toBinding.elementId);\r\n if (el) {\r\n const bounds = getElementBounds(el);\r\n if (bounds) {\r\n const tangentAngle = geometry.tangentEnd;\r\n // Reverse tangent — at t=1 tangent points away from curve body,\r\n // but we need the ray from center back toward the curve\r\n const rayTarget = {\r\n x: arrow.to.x - Math.cos(tangentAngle) * 1000,\r\n y: arrow.to.y - Math.sin(tangentAngle) * 1000,\r\n };\r\n visualTo = getEdgeIntersection(bounds, rayTarget);\r\n }\r\n }\r\n }\r\n\r\n return { visualFrom, visualTo };\r\n}\r\n","import type { ImageElement } from '../types';\r\n\r\nexport function renderImage(\r\n ctx: CanvasRenderingContext2D,\r\n image: ImageElement,\r\n imageCache: Map<string, ImageBitmap | HTMLImageElement | 'failed'>,\r\n onImageLoad: (() => void) | null,\r\n onImageError: ((src: string, cause?: unknown) => void) | null,\r\n): void {\r\n if (imageCache.get(image.src) === 'failed') {\r\n renderImagePlaceholder(ctx, image);\r\n return;\r\n }\r\n const img = getImage(image.src, imageCache, onImageLoad, onImageError);\r\n if (!img) return;\r\n ctx.drawImage(\r\n img as CanvasImageSource,\r\n image.position.x,\r\n image.position.y,\r\n image.size.w,\r\n image.size.h,\r\n );\r\n}\r\n\r\nfunction renderImagePlaceholder(ctx: CanvasRenderingContext2D, image: ImageElement): void {\r\n const { x, y } = image.position;\r\n const { w, h } = image.size;\r\n ctx.save();\r\n ctx.fillStyle = '#eeeeee';\r\n ctx.fillRect(x, y, w, h);\r\n ctx.strokeStyle = '#bdbdbd';\r\n ctx.lineWidth = 1;\r\n ctx.strokeRect(x, y, w, h);\r\n\r\n const glyph = Math.min(24, w / 2, h / 2);\r\n const cx = x + w / 2;\r\n const cy = y + h / 2;\r\n ctx.strokeStyle = '#9e9e9e';\r\n ctx.lineWidth = 2;\r\n ctx.beginPath();\r\n ctx.arc(cx, cy, glyph / 2, 0, Math.PI * 2);\r\n ctx.moveTo(cx - glyph / 2, cy + glyph / 2);\r\n ctx.lineTo(cx + glyph / 2, cy - glyph / 2);\r\n ctx.stroke();\r\n ctx.restore();\r\n}\r\n\r\nfunction getImage(\r\n src: string,\r\n imageCache: Map<string, ImageBitmap | HTMLImageElement | 'failed'>,\r\n onImageLoad: (() => void) | null,\r\n onImageError: ((src: string, cause?: unknown) => void) | null,\r\n): ImageBitmap | HTMLImageElement | null {\r\n const cached = imageCache.get(src);\r\n if (cached) {\r\n if (cached === 'failed') return null;\r\n if (cached instanceof HTMLImageElement) return cached.complete ? cached : null;\r\n return cached;\r\n }\r\n\r\n const img = new Image();\r\n img.src = src;\r\n imageCache.set(src, img);\r\n img.onload = () => {\r\n onImageLoad?.();\r\n // Decode from already-loaded image in memory, not a re-fetch\r\n if (typeof createImageBitmap !== 'undefined') {\r\n createImageBitmap(img)\r\n .then((bitmap) => {\r\n imageCache.set(src, bitmap);\r\n onImageLoad?.();\r\n })\r\n .catch(() => {\r\n /* keep HTMLImageElement fallback — handles CORS rejection */\r\n });\r\n }\r\n };\r\n img.onerror = (event) => {\r\n // failed srcs stay failed for the session; pointing the element at a new src loads fresh\r\n imageCache.set(src, 'failed');\r\n onImageError?.(src, event);\r\n onImageLoad?.();\r\n };\r\n return null;\r\n}\r\n","import type { Point } from '../core/types';\r\nimport type { HexOrientation } from './types';\r\n\r\ninterface HexCoord {\r\n col: number;\r\n row: number;\r\n}\r\n\r\nfunction offsetToCube(\r\n col: number,\r\n row: number,\r\n orientation: HexOrientation,\r\n): { q: number; r: number } {\r\n if (orientation === 'pointy') {\r\n return { q: col - (row - (row & 1)) / 2, r: row };\r\n }\r\n return { q: col, r: row - (col - (col & 1)) / 2 };\r\n}\r\n\r\nfunction cubeToOffset(q: number, r: number, orientation: HexOrientation): HexCoord {\r\n if (orientation === 'pointy') {\r\n return { col: q + (r - (r & 1)) / 2, row: r };\r\n }\r\n return { col: q, row: r + (q - (q & 1)) / 2 };\r\n}\r\n\r\nfunction offsetToPixel(\r\n col: number,\r\n row: number,\r\n cellSize: number,\r\n orientation: HexOrientation,\r\n): Point {\r\n if (orientation === 'pointy') {\r\n const hexW = Math.sqrt(3) * cellSize;\r\n const rowH = 1.5 * cellSize;\r\n const offsetX = row % 2 !== 0 ? hexW / 2 : 0;\r\n return { x: col * hexW + offsetX, y: row * rowH };\r\n }\r\n const hexH = Math.sqrt(3) * cellSize;\r\n const colW = 1.5 * cellSize;\r\n const offsetY = col % 2 !== 0 ? hexH / 2 : 0;\r\n return { x: col * colW, y: row * hexH + offsetY };\r\n}\r\n\r\nfunction pixelToOffset(\r\n x: number,\r\n y: number,\r\n cellSize: number,\r\n orientation: HexOrientation,\r\n): HexCoord {\r\n if (orientation === 'pointy') {\r\n const hexW = Math.sqrt(3) * cellSize;\r\n const rowH = 1.5 * cellSize;\r\n const row = Math.round(y / rowH);\r\n const offsetX = row % 2 !== 0 ? hexW / 2 : 0;\r\n return { col: Math.round((x - offsetX) / hexW), row };\r\n }\r\n const hexH = Math.sqrt(3) * cellSize;\r\n const colW = 1.5 * cellSize;\r\n const col = Math.round(x / colW);\r\n const offsetY = col % 2 !== 0 ? hexH / 2 : 0;\r\n return { col, row: Math.round((y - offsetY) / hexH) };\r\n}\r\n\r\nfunction enumerateHexRing(\r\n centerQ: number,\r\n centerR: number,\r\n n: number,\r\n orientation: HexOrientation,\r\n cellSize: number,\r\n): Point[] {\r\n const cells: Point[] = [];\r\n for (let dq = -n; dq <= n; dq++) {\r\n const rMin = Math.max(-n, -dq - n);\r\n const rMax = Math.min(n, -dq + n);\r\n for (let dr = rMin; dr <= rMax; dr++) {\r\n const absQ = centerQ + dq;\r\n const absR = centerR + dr;\r\n const off = cubeToOffset(absQ, absR, orientation);\r\n cells.push(offsetToPixel(off.col, off.row, cellSize, orientation));\r\n }\r\n }\r\n return cells;\r\n}\r\n\r\nexport function getHexDistance(\r\n a: Point,\r\n b: Point,\r\n cellSize: number,\r\n orientation: HexOrientation,\r\n): number {\r\n const offA = pixelToOffset(a.x, a.y, cellSize, orientation);\r\n const offB = pixelToOffset(b.x, b.y, cellSize, orientation);\r\n const cubeA = offsetToCube(offA.col, offA.row, orientation);\r\n const cubeB = offsetToCube(offB.col, offB.row, orientation);\r\n const dq = cubeA.q - cubeB.q;\r\n const dr = cubeA.r - cubeB.r;\r\n const ds = -dq - dr;\r\n return Math.max(Math.abs(dq), Math.abs(dr), Math.abs(ds));\r\n}\r\n\r\nexport function getHexCellsInRadius(\r\n center: Point,\r\n radiusCells: number,\r\n cellSize: number,\r\n orientation: HexOrientation,\r\n): Point[] {\r\n const n = Math.round(radiusCells);\r\n const off = pixelToOffset(center.x, center.y, cellSize, orientation);\r\n const cube = offsetToCube(off.col, off.row, orientation);\r\n if (n <= 0) {\r\n return [offsetToPixel(off.col, off.row, cellSize, orientation)];\r\n }\r\n return enumerateHexRing(cube.q, cube.r, n, orientation, cellSize);\r\n}\r\n\r\nexport function getHexCellsInCone(\r\n center: Point,\r\n angle: number,\r\n radiusCells: number,\r\n cellSize: number,\r\n orientation: HexOrientation,\r\n): Point[] {\r\n const n = Math.round(radiusCells);\r\n const off = pixelToOffset(center.x, center.y, cellSize, orientation);\r\n const cube = offsetToCube(off.col, off.row, orientation);\r\n const centerPixel = offsetToPixel(off.col, off.row, cellSize, orientation);\r\n\r\n if (n <= 0) return [centerPixel];\r\n\r\n const vertexOffset = orientation === 'pointy' ? Math.PI / 6 : 0;\r\n const step = Math.PI / 3;\r\n const snappedAngle = Math.round((angle - vertexOffset) / step) * step + vertexOffset;\r\n\r\n const halfAngle = Math.PI / 6 + 1e-6;\r\n const cells: Point[] = [centerPixel];\r\n\r\n for (let dq = -n; dq <= n; dq++) {\r\n const rMin = Math.max(-n, -dq - n);\r\n const rMax = Math.min(n, -dq + n);\r\n for (let dr = rMin; dr <= rMax; dr++) {\r\n if (dq === 0 && dr === 0) continue;\r\n const absQ = cube.q + dq;\r\n const absR = cube.r + dr;\r\n const pixel = offsetToPixel(\r\n cubeToOffset(absQ, absR, orientation).col,\r\n cubeToOffset(absQ, absR, orientation).row,\r\n cellSize,\r\n orientation,\r\n );\r\n\r\n const dx = pixel.x - centerPixel.x;\r\n const dy = pixel.y - centerPixel.y;\r\n let diff = Math.atan2(dy, dx) - snappedAngle;\r\n if (diff > Math.PI) diff -= 2 * Math.PI;\r\n if (diff < -Math.PI) diff += 2 * Math.PI;\r\n\r\n if (Math.abs(diff) <= halfAngle) {\r\n cells.push(pixel);\r\n }\r\n }\r\n }\r\n return cells;\r\n}\r\n\r\nexport function getHexCellsInLine(\r\n center: Point,\r\n angle: number,\r\n radiusCells: number,\r\n cellSize: number,\r\n orientation: HexOrientation,\r\n): Point[] {\r\n const n = Math.round(radiusCells);\r\n const off = pixelToOffset(center.x, center.y, cellSize, orientation);\r\n const cube = offsetToCube(off.col, off.row, orientation);\r\n const centerPixel = offsetToPixel(off.col, off.row, cellSize, orientation);\r\n\r\n if (n <= 0) return [centerPixel];\r\n\r\n const vertexOffset = orientation === 'pointy' ? Math.PI / 6 : 0;\r\n const step = Math.PI / 3;\r\n const snappedAngle = Math.round((angle - vertexOffset) / step) * step + vertexOffset;\r\n\r\n const cos = Math.cos(snappedAngle);\r\n const sin = Math.sin(snappedAngle);\r\n const snapUnit = Math.sqrt(3) * cellSize;\r\n const lineLength = n * snapUnit;\r\n const halfWidth = snapUnit * 0.5 + 1e-6;\r\n const cells: Point[] = [];\r\n\r\n for (let dq = -n; dq <= n; dq++) {\r\n const rMin = Math.max(-n, -dq - n);\r\n const rMax = Math.min(n, -dq + n);\r\n for (let dr = rMin; dr <= rMax; dr++) {\r\n const absQ = cube.q + dq;\r\n const absR = cube.r + dr;\r\n const pixel = offsetToPixel(\r\n cubeToOffset(absQ, absR, orientation).col,\r\n cubeToOffset(absQ, absR, orientation).row,\r\n cellSize,\r\n orientation,\r\n );\r\n\r\n const dx = pixel.x - centerPixel.x;\r\n const dy = pixel.y - centerPixel.y;\r\n const along = dx * cos + dy * sin;\r\n const perp = Math.abs(-dx * sin + dy * cos);\r\n\r\n if (along >= -snapUnit * 0.1 && along <= lineLength + snapUnit * 0.1 && perp <= halfWidth) {\r\n cells.push(pixel);\r\n }\r\n }\r\n }\r\n return cells;\r\n}\r\n\r\nexport function getHexCellsInRectangle(\r\n center: Point,\r\n angle: number,\r\n lengthCells: number,\r\n widthCells: number,\r\n cellSize: number,\r\n orientation: HexOrientation,\r\n): Point[] {\r\n const nLen = Math.round(lengthCells);\r\n const wCells = Math.max(1, Math.round(widthCells));\r\n const off = pixelToOffset(center.x, center.y, cellSize, orientation);\r\n const cube = offsetToCube(off.col, off.row, orientation);\r\n const centerPixel = offsetToPixel(off.col, off.row, cellSize, orientation);\r\n\r\n if (nLen <= 0) return [centerPixel];\r\n\r\n const vertexOffset = orientation === 'pointy' ? Math.PI / 6 : 0;\r\n const step = Math.PI / 3;\r\n const snappedAngle = Math.round((angle - vertexOffset) / step) * step + vertexOffset;\r\n\r\n const cos = Math.cos(snappedAngle);\r\n const sin = Math.sin(snappedAngle);\r\n const snapUnit = Math.sqrt(3) * cellSize;\r\n const lineLength = nLen * snapUnit;\r\n const halfWidth = (wCells * snapUnit) / 2 + 1e-6;\r\n const iterM = nLen + Math.ceil(wCells / 2) + 1;\r\n const cells: Point[] = [];\r\n\r\n for (let dq = -iterM; dq <= iterM; dq++) {\r\n const rMin = Math.max(-iterM, -dq - iterM);\r\n const rMax = Math.min(iterM, -dq + iterM);\r\n for (let dr = rMin; dr <= rMax; dr++) {\r\n const absQ = cube.q + dq;\r\n const absR = cube.r + dr;\r\n const pixel = offsetToPixel(\r\n cubeToOffset(absQ, absR, orientation).col,\r\n cubeToOffset(absQ, absR, orientation).row,\r\n cellSize,\r\n orientation,\r\n );\r\n const dx = pixel.x - centerPixel.x;\r\n const dy = pixel.y - centerPixel.y;\r\n const along = dx * cos + dy * sin;\r\n const perp = Math.abs(-dx * sin + dy * cos);\r\n if (along >= -snapUnit * 0.1 && along <= lineLength + snapUnit * 0.1 && perp <= halfWidth) {\r\n cells.push(pixel);\r\n }\r\n }\r\n }\r\n return cells;\r\n}\r\n\r\nexport function getHexCellsInSquare(\r\n center: Point,\r\n radiusCells: number,\r\n cellSize: number,\r\n orientation: HexOrientation,\r\n): Point[] {\r\n const n = Math.round(radiusCells);\r\n const off = pixelToOffset(center.x, center.y, cellSize, orientation);\r\n const cube = offsetToCube(off.col, off.row, orientation);\r\n const centerPixel = offsetToPixel(off.col, off.row, cellSize, orientation);\r\n\r\n if (n <= 0) return [centerPixel];\r\n\r\n const snapUnit = Math.sqrt(3) * cellSize;\r\n const halfSide = (n * snapUnit) / 2;\r\n const cells: Point[] = [];\r\n\r\n for (let dq = -n; dq <= n; dq++) {\r\n const rMin = Math.max(-n, -dq - n);\r\n const rMax = Math.min(n, -dq + n);\r\n for (let dr = rMin; dr <= rMax; dr++) {\r\n const absQ = cube.q + dq;\r\n const absR = cube.r + dr;\r\n const pixel = offsetToPixel(\r\n cubeToOffset(absQ, absR, orientation).col,\r\n cubeToOffset(absQ, absR, orientation).row,\r\n cellSize,\r\n orientation,\r\n );\r\n\r\n if (\r\n Math.abs(pixel.x - centerPixel.x) <= halfSide &&\r\n Math.abs(pixel.y - centerPixel.y) <= halfSide\r\n ) {\r\n cells.push(pixel);\r\n }\r\n }\r\n }\r\n return cells;\r\n}\r\n\r\nexport function drawHexPath(\r\n ctx: CanvasRenderingContext2D,\r\n cx: number,\r\n cy: number,\r\n cellSize: number,\r\n orientation: HexOrientation,\r\n): void {\r\n const angleOffset = orientation === 'pointy' ? Math.PI / 6 : 0;\r\n ctx.moveTo(cx + cellSize * Math.cos(angleOffset), cy + cellSize * Math.sin(angleOffset));\r\n for (let i = 1; i < 6; i++) {\r\n const a = angleOffset + (Math.PI / 3) * i;\r\n ctx.lineTo(cx + cellSize * Math.cos(a), cy + cellSize * Math.sin(a));\r\n }\r\n ctx.closePath();\r\n}\r\n","import type { Point } from '../../core/types';\r\nimport type { TemplateShape } from '../types';\r\n\r\nexport interface TemplateFeetLabelParams {\r\n position: Point;\r\n radius: number;\r\n angle: number;\r\n templateShape: TemplateShape;\r\n feet: number;\r\n color: string;\r\n}\r\n\r\nexport function renderTemplateFeetLabel(\r\n ctx: CanvasRenderingContext2D,\r\n p: TemplateFeetLabelParams,\r\n): void {\r\n if (p.feet <= 0) return;\r\n\r\n const directional =\r\n p.templateShape === 'cone' || p.templateShape === 'line' || p.templateShape === 'rectangle';\r\n const dir = directional ? p.angle : 0;\r\n const length = p.templateShape === 'square' ? p.radius / 2 : p.radius;\r\n const cos = Math.cos(dir);\r\n const sin = Math.sin(dir);\r\n const start = p.position;\r\n const end = { x: start.x + length * cos, y: start.y + length * sin };\r\n const midX = start.x + (length / 2) * cos;\r\n const midY = start.y + (length / 2) * sin;\r\n\r\n ctx.save();\r\n ctx.globalAlpha = 1;\r\n\r\n ctx.beginPath();\r\n ctx.setLineDash([4, 4]);\r\n ctx.strokeStyle = p.color;\r\n ctx.lineWidth = 1.5;\r\n ctx.moveTo(start.x, start.y);\r\n ctx.lineTo(end.x, end.y);\r\n ctx.stroke();\r\n ctx.setLineDash([]);\r\n\r\n const label = `${Math.round(p.feet)} ft`;\r\n const fontSize = Math.max(10, Math.min(14, p.radius * 0.15));\r\n ctx.font = `bold ${fontSize}px system-ui, sans-serif`;\r\n ctx.textAlign = 'center';\r\n ctx.textBaseline = 'bottom';\r\n const textY = midY - 4;\r\n\r\n const metrics = ctx.measureText(label);\r\n const padX = 4;\r\n const padY = 2;\r\n const textW = metrics.width + padX * 2;\r\n const textH = fontSize + padY * 2;\r\n\r\n ctx.fillStyle = 'rgba(255, 255, 255, 0.85)';\r\n ctx.beginPath();\r\n ctx.roundRect(midX - textW / 2, textY - textH, textW, textH, 3);\r\n ctx.fill();\r\n\r\n ctx.fillStyle = p.color;\r\n ctx.fillText(label, midX, textY - padY);\r\n\r\n ctx.restore();\r\n}\r\n","import type { TemplateElement, HexOrientation } from '../types';\r\nimport type { ElementStore } from '../element-store';\r\nimport {\r\n getHexCellsInRadius,\r\n getHexCellsInCone,\r\n getHexCellsInLine,\r\n getHexCellsInSquare,\r\n getHexCellsInRectangle,\r\n drawHexPath,\r\n} from '../hex-fill';\r\nimport { renderTemplateFeetLabel } from './template-measure';\r\n\r\nexport function renderTemplate(\r\n ctx: CanvasRenderingContext2D,\r\n template: TemplateElement,\r\n store: ElementStore | null,\r\n): void {\r\n const grid = store?.getElementsByType('grid')[0];\r\n if (grid && grid.gridType === 'hex' && template.renderStyle !== 'geometric') {\r\n renderHexTemplate(ctx, template, grid.cellSize, grid.hexOrientation);\r\n return;\r\n }\r\n\r\n renderGeometricTemplate(ctx, template);\r\n}\r\n\r\nfunction renderGeometricTemplate(ctx: CanvasRenderingContext2D, template: TemplateElement): void {\r\n const { x: cx, y: cy } = template.position;\r\n const r = template.radius;\r\n\r\n ctx.save();\r\n ctx.globalAlpha = template.opacity;\r\n ctx.fillStyle = template.fillColor;\r\n ctx.strokeStyle = template.strokeColor;\r\n ctx.lineWidth = template.strokeWidth;\r\n\r\n switch (template.templateShape) {\r\n case 'circle':\r\n ctx.beginPath();\r\n ctx.arc(cx, cy, r, 0, Math.PI * 2);\r\n ctx.fill();\r\n ctx.stroke();\r\n break;\r\n\r\n case 'square':\r\n ctx.fillRect(cx - r / 2, cy - r / 2, r, r);\r\n ctx.strokeRect(cx - r / 2, cy - r / 2, r, r);\r\n break;\r\n\r\n case 'cone': {\r\n const halfAngle = Math.atan(0.5);\r\n ctx.beginPath();\r\n ctx.moveTo(cx, cy);\r\n ctx.arc(cx, cy, r, template.angle - halfAngle, template.angle + halfAngle);\r\n ctx.closePath();\r\n ctx.fill();\r\n ctx.stroke();\r\n break;\r\n }\r\n\r\n case 'line': {\r\n const halfW = r / 12;\r\n const cos = Math.cos(template.angle);\r\n const sin = Math.sin(template.angle);\r\n const perpX = -sin * halfW;\r\n const perpY = cos * halfW;\r\n\r\n ctx.beginPath();\r\n ctx.moveTo(cx + perpX, cy + perpY);\r\n ctx.lineTo(cx + r * cos + perpX, cy + r * sin + perpY);\r\n ctx.lineTo(cx + r * cos - perpX, cy + r * sin - perpY);\r\n ctx.lineTo(cx - perpX, cy - perpY);\r\n ctx.closePath();\r\n ctx.fill();\r\n ctx.stroke();\r\n break;\r\n }\r\n\r\n case 'rectangle': {\r\n const halfW = (template.width ?? 0) / 2;\r\n const cos = Math.cos(template.angle);\r\n const sin = Math.sin(template.angle);\r\n const perpX = -sin * halfW;\r\n const perpY = cos * halfW;\r\n ctx.beginPath();\r\n ctx.moveTo(cx + perpX, cy + perpY);\r\n ctx.lineTo(cx + r * cos + perpX, cy + r * sin + perpY);\r\n ctx.lineTo(cx + r * cos - perpX, cy + r * sin - perpY);\r\n ctx.lineTo(cx - perpX, cy - perpY);\r\n ctx.closePath();\r\n ctx.fill();\r\n ctx.stroke();\r\n break;\r\n }\r\n }\r\n\r\n if (template.radiusFeet != null && template.radiusFeet > 0) {\r\n renderTemplateFeetLabel(ctx, {\r\n position: template.position,\r\n radius: template.radius,\r\n angle: template.angle,\r\n templateShape: template.templateShape,\r\n feet: template.radiusFeet,\r\n color: template.strokeColor,\r\n });\r\n }\r\n\r\n ctx.restore();\r\n}\r\n\r\nfunction renderHexTemplate(\r\n ctx: CanvasRenderingContext2D,\r\n template: TemplateElement,\r\n cellSize: number,\r\n orientation: HexOrientation,\r\n): void {\r\n const snapUnit = Math.sqrt(3) * cellSize;\r\n const radiusCells = template.radius / snapUnit;\r\n const center = template.position;\r\n\r\n let cells: { x: number; y: number }[];\r\n switch (template.templateShape) {\r\n case 'circle':\r\n cells = getHexCellsInRadius(center, radiusCells, cellSize, orientation);\r\n break;\r\n case 'cone':\r\n cells = getHexCellsInCone(center, template.angle, radiusCells, cellSize, orientation);\r\n break;\r\n case 'line':\r\n cells = getHexCellsInLine(center, template.angle, radiusCells, cellSize, orientation);\r\n break;\r\n case 'square':\r\n cells = getHexCellsInSquare(center, radiusCells, cellSize, orientation);\r\n break;\r\n case 'rectangle': {\r\n const widthCells = (template.width ?? 0) / snapUnit;\r\n cells = getHexCellsInRectangle(\r\n center,\r\n template.angle,\r\n radiusCells,\r\n widthCells,\r\n cellSize,\r\n orientation,\r\n );\r\n break;\r\n }\r\n }\r\n\r\n ctx.save();\r\n ctx.globalAlpha = template.opacity;\r\n\r\n ctx.beginPath();\r\n for (const cell of cells) {\r\n drawHexPath(ctx, cell.x, cell.y, cellSize, orientation);\r\n }\r\n ctx.fillStyle = template.fillColor;\r\n ctx.fill();\r\n\r\n ctx.beginPath();\r\n for (const cell of cells) {\r\n drawHexPath(ctx, cell.x, cell.y, cellSize, orientation);\r\n }\r\n ctx.strokeStyle = template.strokeColor;\r\n ctx.lineWidth = template.strokeWidth;\r\n ctx.stroke();\r\n\r\n {\r\n ctx.globalAlpha = Math.min(template.opacity + 0.1, 1);\r\n ctx.beginPath();\r\n drawHexPath(ctx, center.x, center.y, cellSize, orientation);\r\n ctx.fillStyle = template.strokeColor;\r\n ctx.fill();\r\n ctx.strokeStyle = template.strokeColor;\r\n ctx.lineWidth = template.strokeWidth;\r\n ctx.stroke();\r\n }\r\n\r\n if (template.radiusFeet != null && template.radiusFeet > 0) {\r\n renderTemplateFeetLabel(ctx, {\r\n position: template.position,\r\n radius: template.radius,\r\n angle: template.angle,\r\n templateShape: template.templateShape,\r\n feet: template.radiusFeet,\r\n color: template.strokeColor,\r\n });\r\n }\r\n\r\n ctx.restore();\r\n}\r\n","import type { HexOrientation } from './types';\r\n\r\nexport interface VisibleBounds {\r\n minX: number;\r\n minY: number;\r\n maxX: number;\r\n maxY: number;\r\n}\r\n\r\nexport interface SquareGridLines {\r\n verticals: number[];\r\n horizontals: number[];\r\n}\r\n\r\nexport function getSquareGridLines(bounds: VisibleBounds, cellSize: number): SquareGridLines {\r\n if (cellSize <= 0) return { verticals: [], horizontals: [] };\r\n\r\n const verticals: number[] = [];\r\n const startX = Math.floor(bounds.minX / cellSize) * cellSize;\r\n const endX = Math.ceil(bounds.maxX / cellSize) * cellSize;\r\n for (let x = startX; x <= endX; x += cellSize) {\r\n verticals.push(x);\r\n }\r\n\r\n const horizontals: number[] = [];\r\n const startY = Math.floor(bounds.minY / cellSize) * cellSize;\r\n const endY = Math.ceil(bounds.maxY / cellSize) * cellSize;\r\n for (let y = startY; y <= endY; y += cellSize) {\r\n horizontals.push(y);\r\n }\r\n\r\n return { verticals, horizontals };\r\n}\r\n\r\nexport interface HexVertex {\r\n x: number;\r\n y: number;\r\n}\r\n\r\nexport function getHexVertices(\r\n cx: number,\r\n cy: number,\r\n circumradius: number,\r\n orientation: HexOrientation,\r\n): HexVertex[] {\r\n const vertices: HexVertex[] = [];\r\n const angleOffset = orientation === 'pointy' ? -Math.PI / 2 : 0;\r\n for (let i = 0; i < 6; i++) {\r\n const angle = (Math.PI / 3) * i + angleOffset;\r\n vertices.push({\r\n x: cx + circumradius * Math.cos(angle),\r\n y: cy + circumradius * Math.sin(angle),\r\n });\r\n }\r\n return vertices;\r\n}\r\n\r\nexport function getHexCenters(\r\n bounds: VisibleBounds,\r\n circumradius: number,\r\n orientation: HexOrientation,\r\n): HexVertex[] {\r\n if (circumradius <= 0) return [];\r\n\r\n const centers: HexVertex[] = [];\r\n\r\n if (orientation === 'pointy') {\r\n const hexW = Math.sqrt(3) * circumradius;\r\n const hexH = 2 * circumradius;\r\n const rowH = hexH * 0.75;\r\n\r\n const startRow = Math.floor((bounds.minY - circumradius) / rowH);\r\n const endRow = Math.ceil((bounds.maxY + circumradius) / rowH);\r\n const startCol = Math.floor((bounds.minX - hexW) / hexW);\r\n const endCol = Math.ceil((bounds.maxX + hexW) / hexW);\r\n\r\n for (let row = startRow; row <= endRow; row++) {\r\n const offsetX = row % 2 !== 0 ? hexW / 2 : 0;\r\n for (let col = startCol; col <= endCol; col++) {\r\n centers.push({\r\n x: col * hexW + offsetX,\r\n y: row * rowH,\r\n });\r\n }\r\n }\r\n } else {\r\n const hexW = 2 * circumradius;\r\n const hexH = Math.sqrt(3) * circumradius;\r\n const colW = hexW * 0.75;\r\n\r\n const startCol = Math.floor((bounds.minX - circumradius) / colW);\r\n const endCol = Math.ceil((bounds.maxX + circumradius) / colW);\r\n const startRow = Math.floor((bounds.minY - hexH) / hexH);\r\n const endRow = Math.ceil((bounds.maxY + hexH) / hexH);\r\n\r\n for (let col = startCol; col <= endCol; col++) {\r\n const offsetY = col % 2 !== 0 ? hexH / 2 : 0;\r\n for (let row = startRow; row <= endRow; row++) {\r\n centers.push({\r\n x: col * colW,\r\n y: row * hexH + offsetY,\r\n });\r\n }\r\n }\r\n }\r\n\r\n return centers;\r\n}\r\n\r\nexport function renderSquareGrid(\r\n ctx: CanvasRenderingContext2D,\r\n bounds: VisibleBounds,\r\n cellSize: number,\r\n strokeColor: string,\r\n strokeWidth: number,\r\n opacity: number,\r\n): void {\r\n if (cellSize <= 0) return;\r\n\r\n const { verticals, horizontals } = getSquareGridLines(bounds, cellSize);\r\n\r\n ctx.save();\r\n ctx.strokeStyle = strokeColor;\r\n ctx.lineWidth = strokeWidth;\r\n ctx.globalAlpha *= opacity;\r\n ctx.beginPath();\r\n\r\n for (const x of verticals) {\r\n ctx.moveTo(x, bounds.minY);\r\n ctx.lineTo(x, bounds.maxY);\r\n }\r\n for (const y of horizontals) {\r\n ctx.moveTo(bounds.minX, y);\r\n ctx.lineTo(bounds.maxX, y);\r\n }\r\n\r\n ctx.stroke();\r\n ctx.restore();\r\n}\r\n\r\nexport function renderHexGrid(\r\n ctx: CanvasRenderingContext2D,\r\n bounds: VisibleBounds,\r\n cellSize: number,\r\n orientation: HexOrientation,\r\n strokeColor: string,\r\n strokeWidth: number,\r\n opacity: number,\r\n): void {\r\n if (cellSize <= 0) return;\r\n\r\n // Precompute 6 vertex offsets once (12 trig calls total, not 12 per hex)\r\n const angleOffset = orientation === 'pointy' ? -Math.PI / 2 : 0;\r\n const ox0 = cellSize * Math.cos(angleOffset);\r\n const oy0 = cellSize * Math.sin(angleOffset);\r\n const ox1 = cellSize * Math.cos(Math.PI / 3 + angleOffset);\r\n const oy1 = cellSize * Math.sin(Math.PI / 3 + angleOffset);\r\n const ox2 = cellSize * Math.cos((2 * Math.PI) / 3 + angleOffset);\r\n const oy2 = cellSize * Math.sin((2 * Math.PI) / 3 + angleOffset);\r\n const ox3 = cellSize * Math.cos(Math.PI + angleOffset);\r\n const oy3 = cellSize * Math.sin(Math.PI + angleOffset);\r\n const ox4 = cellSize * Math.cos((4 * Math.PI) / 3 + angleOffset);\r\n const oy4 = cellSize * Math.sin((4 * Math.PI) / 3 + angleOffset);\r\n const ox5 = cellSize * Math.cos((5 * Math.PI) / 3 + angleOffset);\r\n const oy5 = cellSize * Math.sin((5 * Math.PI) / 3 + angleOffset);\r\n\r\n ctx.save();\r\n ctx.strokeStyle = strokeColor;\r\n ctx.lineWidth = strokeWidth;\r\n ctx.globalAlpha *= opacity;\r\n ctx.beginPath();\r\n\r\n // Inline center iteration — zero allocations per hex\r\n if (orientation === 'pointy') {\r\n const hexW = Math.sqrt(3) * cellSize;\r\n const rowH = 1.5 * cellSize;\r\n\r\n const startRow = Math.floor((bounds.minY - cellSize) / rowH);\r\n const endRow = Math.ceil((bounds.maxY + cellSize) / rowH);\r\n const startCol = Math.floor((bounds.minX - hexW) / hexW);\r\n const endCol = Math.ceil((bounds.maxX + hexW) / hexW);\r\n\r\n for (let row = startRow; row <= endRow; row++) {\r\n const offX = row % 2 !== 0 ? hexW / 2 : 0;\r\n for (let col = startCol; col <= endCol; col++) {\r\n const cx = col * hexW + offX;\r\n const cy = row * rowH;\r\n ctx.moveTo(cx + ox0, cy + oy0);\r\n ctx.lineTo(cx + ox1, cy + oy1);\r\n ctx.lineTo(cx + ox2, cy + oy2);\r\n ctx.lineTo(cx + ox3, cy + oy3);\r\n ctx.lineTo(cx + ox4, cy + oy4);\r\n ctx.lineTo(cx + ox5, cy + oy5);\r\n ctx.closePath();\r\n }\r\n }\r\n } else {\r\n const hexH = Math.sqrt(3) * cellSize;\r\n const colW = 1.5 * cellSize;\r\n\r\n const startCol = Math.floor((bounds.minX - cellSize) / colW);\r\n const endCol = Math.ceil((bounds.maxX + cellSize) / colW);\r\n const startRow = Math.floor((bounds.minY - hexH) / hexH);\r\n const endRow = Math.ceil((bounds.maxY + hexH) / hexH);\r\n\r\n for (let col = startCol; col <= endCol; col++) {\r\n const offY = col % 2 !== 0 ? hexH / 2 : 0;\r\n for (let row = startRow; row <= endRow; row++) {\r\n const cx = col * colW;\r\n const cy = row * hexH + offY;\r\n ctx.moveTo(cx + ox0, cy + oy0);\r\n ctx.lineTo(cx + ox1, cy + oy1);\r\n ctx.lineTo(cx + ox2, cy + oy2);\r\n ctx.lineTo(cx + ox3, cy + oy3);\r\n ctx.lineTo(cx + ox4, cy + oy4);\r\n ctx.lineTo(cx + ox5, cy + oy5);\r\n ctx.closePath();\r\n }\r\n }\r\n }\r\n\r\n ctx.stroke();\r\n ctx.restore();\r\n}\r\n\r\nexport interface HexGridTile {\r\n canvas: HTMLCanvasElement | OffscreenCanvas;\r\n tileW: number;\r\n tileH: number;\r\n}\r\n\r\nexport function createHexGridTile(\r\n cellSize: number,\r\n orientation: HexOrientation,\r\n strokeColor: string,\r\n strokeWidth: number,\r\n opacity: number,\r\n scale: number,\r\n): HexGridTile | null {\r\n let tileW: number;\r\n let tileH: number;\r\n if (orientation === 'pointy') {\r\n tileW = Math.sqrt(3) * cellSize;\r\n tileH = 3 * cellSize;\r\n } else {\r\n tileW = 3 * cellSize;\r\n tileH = Math.sqrt(3) * cellSize;\r\n }\r\n\r\n const pxW = Math.ceil(tileW * scale);\r\n const pxH = Math.ceil(tileH * scale);\r\n if (pxW <= 0 || pxH <= 0) return null;\r\n\r\n let canvas: HTMLCanvasElement | OffscreenCanvas;\r\n if (typeof OffscreenCanvas !== 'undefined') {\r\n canvas = new OffscreenCanvas(pxW, pxH);\r\n } else if (typeof document !== 'undefined') {\r\n const el = document.createElement('canvas');\r\n el.width = pxW;\r\n el.height = pxH;\r\n canvas = el;\r\n } else {\r\n return null;\r\n }\r\n\r\n const tc = canvas.getContext('2d') as CanvasRenderingContext2D | null;\r\n if (!tc) return null;\r\n\r\n tc.scale(scale, scale);\r\n tc.beginPath();\r\n tc.rect(0, 0, tileW, tileH);\r\n tc.clip();\r\n\r\n const angleOffset = orientation === 'pointy' ? -Math.PI / 2 : 0;\r\n const ox0 = cellSize * Math.cos(angleOffset);\r\n const oy0 = cellSize * Math.sin(angleOffset);\r\n const ox1 = cellSize * Math.cos(Math.PI / 3 + angleOffset);\r\n const oy1 = cellSize * Math.sin(Math.PI / 3 + angleOffset);\r\n const ox2 = cellSize * Math.cos((2 * Math.PI) / 3 + angleOffset);\r\n const oy2 = cellSize * Math.sin((2 * Math.PI) / 3 + angleOffset);\r\n const ox3 = cellSize * Math.cos(Math.PI + angleOffset);\r\n const oy3 = cellSize * Math.sin(Math.PI + angleOffset);\r\n const ox4 = cellSize * Math.cos((4 * Math.PI) / 3 + angleOffset);\r\n const oy4 = cellSize * Math.sin((4 * Math.PI) / 3 + angleOffset);\r\n const ox5 = cellSize * Math.cos((5 * Math.PI) / 3 + angleOffset);\r\n const oy5 = cellSize * Math.sin((5 * Math.PI) / 3 + angleOffset);\r\n\r\n tc.strokeStyle = strokeColor;\r\n tc.lineWidth = strokeWidth;\r\n tc.globalAlpha = opacity;\r\n tc.beginPath();\r\n\r\n if (orientation === 'pointy') {\r\n const hexW = tileW;\r\n const rowH = 1.5 * cellSize;\r\n for (let row = -1; row <= 3; row++) {\r\n const offX = row % 2 !== 0 ? hexW / 2 : 0;\r\n for (let col = -1; col <= 1; col++) {\r\n const cx = col * hexW + offX;\r\n const cy = row * rowH;\r\n tc.moveTo(cx + ox0, cy + oy0);\r\n tc.lineTo(cx + ox1, cy + oy1);\r\n tc.lineTo(cx + ox2, cy + oy2);\r\n tc.lineTo(cx + ox3, cy + oy3);\r\n tc.lineTo(cx + ox4, cy + oy4);\r\n tc.lineTo(cx + ox5, cy + oy5);\r\n tc.closePath();\r\n }\r\n }\r\n } else {\r\n const hexH = tileH;\r\n const colW = 1.5 * cellSize;\r\n for (let col = -1; col <= 3; col++) {\r\n const offY = col % 2 !== 0 ? hexH / 2 : 0;\r\n for (let row = -1; row <= 1; row++) {\r\n const cx = col * colW;\r\n const cy = row * hexH + offY;\r\n tc.moveTo(cx + ox0, cy + oy0);\r\n tc.lineTo(cx + ox1, cy + oy1);\r\n tc.lineTo(cx + ox2, cy + oy2);\r\n tc.lineTo(cx + ox3, cy + oy3);\r\n tc.lineTo(cx + ox4, cy + oy4);\r\n tc.lineTo(cx + ox5, cy + oy5);\r\n tc.closePath();\r\n }\r\n }\r\n }\r\n\r\n tc.stroke();\r\n return { canvas, tileW, tileH };\r\n}\r\n\r\nexport function renderHexGridTiled(\r\n ctx: CanvasRenderingContext2D,\r\n bounds: VisibleBounds,\r\n cellSize: number,\r\n tile: HexGridTile,\r\n): void {\r\n const { tileW, tileH } = tile;\r\n\r\n const startCol = Math.floor(bounds.minX / tileW) - 1;\r\n const endCol = Math.ceil(bounds.maxX / tileW) + 1;\r\n const startRow = Math.floor(bounds.minY / tileH) - 1;\r\n const endRow = Math.ceil(bounds.maxY / tileH) + 1;\r\n\r\n for (let row = startRow; row <= endRow; row++) {\r\n for (let col = startCol; col <= endCol; col++) {\r\n ctx.drawImage(tile.canvas as CanvasImageSource, col * tileW, row * tileH, tileW, tileH);\r\n }\r\n }\r\n}\r\n","import type { HtmlElement } from '../elements/types';\nimport type { Size } from '../core/types';\n\nexport interface HtmlPaintContext {\n /** Translated to the element origin, rotated about its centre, clipped, save()d.\n * Layer opacity is NOT applied here — each surface owns that boundary. */\n ctx: CanvasRenderingContext2D;\n element: Readonly<HtmlElement>;\n size: Readonly<Size>;\n /** CSS pixels per world unit for THIS surface (screen | minimap | export). */\n zoom: number;\n}\n\nexport type HtmlPainter = (paint: HtmlPaintContext) => void;\nexport type HtmlRouting = 'dom' | 'canvas' | 'missing';\n\nexport class HtmlPainterMissingError extends Error {\n readonly elementId: string;\n readonly htmlType: string | undefined;\n constructor(elementId: string, htmlType: string | undefined) {\n super(`[fieldnotes] no painter registered for canvas-backed htmlType \"${htmlType ?? ''}\"`);\n this.name = 'HtmlPainterMissingError';\n this.elementId = elementId;\n this.htmlType = htmlType;\n }\n}\n\ninterface PainterEntry {\n token: symbol;\n painter: HtmlPainter;\n}\n\nexport class HtmlPainterRegistry {\n private readonly painters = new Map<string, PainterEntry[]>();\n private readonly declared = new Map<string, number>();\n private readonly listeners = new Set<() => void>();\n private _version = 0;\n private canvasTypesCache: ReadonlySet<string> | null = null;\n\n get version(): number {\n return this._version;\n }\n\n /**\n * Memoized: this is the hottest read in the feature — `isDomElement` consults it several\n * times per element per frame, and every html-element store update re-reconciles every\n * html element. The cache is dropped in `bump()`, which is called on exactly the\n * transitions that can change the membership of this set (first `expect` of a type, last\n * release of a type, any `register`, and any unregister that empties a type's stack).\n *\n * The returned `Set` is the LIVE memoized instance, not a copy: callers must not mutate\n * it, and a caller that holds it across a `bump()` holds a stale snapshot. Nothing in the\n * codebase does either — `withHtmlDefaults` passes it straight through to the exporters\n * unless the caller supplied `expectedCanvasTypes`, in which case it builds a fresh union\n * — and holding it across a change was already a stale snapshot before memoization.\n */\n get canvasTypes(): ReadonlySet<string> {\n const cached = this.canvasTypesCache;\n if (cached) return cached;\n const types = new Set<string>(this.declared.keys());\n for (const [type, stack] of this.painters) {\n if (stack.length > 0) types.add(type);\n }\n this.canvasTypesCache = types;\n return types;\n }\n\n expect(htmlTypes: Iterable<string>): () => void {\n const claimed = [...htmlTypes];\n let changed = false;\n for (const type of claimed) {\n const count = this.declared.get(type) ?? 0;\n if (count === 0) changed = true;\n this.declared.set(type, count + 1);\n }\n if (changed) this.bump();\n\n let released = false;\n return () => {\n if (released) return;\n released = true;\n let releaseChanged = false;\n for (const type of claimed) {\n const count = this.declared.get(type) ?? 0;\n if (count <= 1) {\n this.declared.delete(type);\n releaseChanged = true;\n } else {\n this.declared.set(type, count - 1);\n }\n }\n if (releaseChanged) this.bump();\n };\n }\n\n register(htmlType: string, painter: HtmlPainter): () => void {\n const entry: PainterEntry = { token: Symbol('html-painter'), painter };\n const stack = this.painters.get(htmlType) ?? [];\n stack.push(entry);\n this.painters.set(htmlType, stack);\n this.bump(); // pushing always changes the active entry\n\n let released = false;\n return () => {\n if (released) return;\n released = true;\n const current = this.painters.get(htmlType);\n if (!current) return;\n const index = current.findIndex((candidate) => candidate.token === entry.token);\n if (index === -1) return;\n const wasActive = index === current.length - 1;\n current.splice(index, 1);\n if (current.length === 0) this.painters.delete(htmlType);\n if (wasActive) this.bump();\n };\n }\n\n getActivePainter(htmlType: string): HtmlPainter | undefined {\n const stack = this.painters.get(htmlType);\n return stack && stack.length > 0 ? stack[stack.length - 1]?.painter : undefined;\n }\n\n onChange(listener: () => void): () => void {\n this.listeners.add(listener);\n return () => this.listeners.delete(listener);\n }\n\n private bump(): void {\n this.canvasTypesCache = null;\n this._version += 1;\n for (const listener of [...this.listeners]) {\n try {\n listener();\n } catch {\n // Listener faults must not break registration for siblings.\n }\n }\n }\n}\n\nexport function resolveHtmlRouting(\n el: Readonly<HtmlElement>,\n registry: HtmlPainterRegistry | null,\n expectedCanvasTypes?: ReadonlySet<string>,\n): HtmlRouting {\n const htmlType = el.htmlType;\n if (htmlType === undefined) return 'dom';\n const expected =\n (registry?.canvasTypes.has(htmlType) ?? false) || (expectedCanvasTypes?.has(htmlType) ?? false);\n if (!expected) return 'dom';\n return registry?.getActivePainter(htmlType) ? 'canvas' : 'missing';\n}\n","import type { HtmlElement } from '../elements/types';\nimport type { HtmlPainter } from './html-painter-registry';\nimport type { HtmlPaintDiagnostic, HtmlRenderTarget } from './html-paint-diagnostics';\n\nexport interface PaintHtmlOptions {\n ctx: CanvasRenderingContext2D;\n zoom: number;\n target: HtmlRenderTarget;\n onDiagnostic?: (diagnostic: HtmlPaintDiagnostic) => void;\n /** Default true. Set false when the CALLER applies rotation (svg export wraps the\n * raster in withRotationSvg, so rotating here would double-apply it). */\n applyRotation?: boolean;\n}\n\n/**\n * The single place canvas-routed html elements are drawn. Screen, minimap and\n * export all call this, so the transform math cannot drift between surfaces.\n * Deliberately applies NO layer opacity — each surface owns that boundary\n * (cached layers composite it; the hybrid path sets it per element).\n */\nexport function paintHtmlElement(\n el: Readonly<HtmlElement>,\n painter: HtmlPainter,\n opts: PaintHtmlOptions,\n): void {\n const { ctx, zoom, target, onDiagnostic } = opts;\n const { w, h } = el.size;\n if (!(w > 0) || !(h > 0)) {\n onDiagnostic?.({ kind: 'degenerate-size', elementId: el.id, htmlType: el.htmlType, target });\n return;\n }\n\n ctx.save();\n try {\n const rotation = opts.applyRotation === false ? 0 : (el.rotation ?? 0);\n if (rotation !== 0) {\n ctx.translate(el.position.x + w / 2, el.position.y + h / 2);\n ctx.rotate(rotation);\n ctx.translate(-w / 2, -h / 2);\n } else {\n ctx.translate(el.position.x, el.position.y);\n }\n ctx.beginPath();\n ctx.rect(0, 0, w, h);\n ctx.clip();\n painter({ ctx, element: el, size: { w, h }, zoom });\n } catch (error) {\n onDiagnostic?.({\n kind: 'painter-threw',\n elementId: el.id,\n htmlType: el.htmlType,\n target,\n error,\n });\n } finally {\n ctx.restore();\n }\n}\n","import type { CanvasElement, GridElement, HtmlElement } from './types';\nimport { getElementBounds } from './element-bounds';\nimport { withRotation } from './rotate-canvas';\nimport { renderStroke } from './renderers/stroke-renderer';\nimport { renderShape } from './renderers/shape-renderer';\nimport { renderArrow } from './renderers/arrow-renderer';\nimport { renderImage } from './renderers/image-renderer';\nimport { renderTemplate } from './renderers/template-renderer';\nimport type { ElementStore } from './element-store';\nimport {\n renderSquareGrid,\n renderHexGrid,\n createHexGridTile,\n renderHexGridTiled,\n} from './grid-renderer';\nimport type { HexGridTile } from './grid-renderer';\nimport type { HexOrientation } from './types';\nimport type { Camera } from '../canvas/camera';\nimport { resolveHtmlRouting } from '../canvas/html-painter-registry';\nimport type { HtmlPainterRegistry } from '../canvas/html-painter-registry';\nimport { paintHtmlElement } from '../canvas/html-paint';\nimport type { HtmlPaintDiagnostic, HtmlRenderTarget } from '../canvas/html-paint-diagnostics';\n\nconst DOM_ELEMENT_TYPES = new Set(['note', 'html', 'text']);\n\nexport class ElementRenderer {\n private store: ElementStore | null = null;\n private imageCache = new Map<string, ImageBitmap | HTMLImageElement | 'failed'>();\n private onImageLoad: (() => void) | null = null;\n private onImageError: ((src: string, cause?: unknown) => void) | null = null;\n private camera: Camera | null = null;\n private canvasSize: { w: number; h: number } | null = null;\n private hexTileCache: HexGridTile | null = null;\n private hexTileCacheKey = '';\n private gridBoundsOverride: { minX: number; minY: number; maxX: number; maxY: number } | null =\n null;\n private labelEditingId: string | null = null;\n private htmlPainters: HtmlPainterRegistry | null = null;\n private expectedCanvasTypes: ReadonlySet<string> | undefined;\n private renderTarget: HtmlRenderTarget = 'screen';\n private diagnosticSink: ((d: HtmlPaintDiagnostic) => void) | null = null;\n private surfaceZoom: number | null = null;\n\n setStore(store: ElementStore): void {\n this.store = store;\n }\n\n setOnImageLoad(callback: () => void): void {\n this.onImageLoad = callback;\n }\n\n setOnImageError(callback: (src: string, cause?: unknown) => void): void {\n this.onImageError = callback;\n }\n\n setCamera(camera: Camera): void {\n this.camera = camera;\n }\n\n setCanvasSize(w: number, h: number): void {\n this.canvasSize = { w, h };\n }\n\n setGridBoundsOverride(\n bounds: { minX: number; minY: number; maxX: number; maxY: number } | null,\n ): void {\n this.gridBoundsOverride = bounds;\n }\n\n setLabelEditingId(id: string | null): void {\n this.labelEditingId = id;\n }\n\n /** Registry of canvas-backed html painters, plus any types declared canvas-routed\n * before a painter is registered (`expectedCanvasTypes`). Null clears routing back\n * to legacy DOM-only behavior. */\n setHtmlPainters(registry: HtmlPainterRegistry | null, expected?: ReadonlySet<string>): void {\n this.htmlPainters = registry;\n this.expectedCanvasTypes = expected;\n }\n\n setRenderTarget(target: HtmlRenderTarget): void {\n this.renderTarget = target;\n }\n\n setDiagnosticSink(sink: ((d: HtmlPaintDiagnostic) => void) | null): void {\n this.diagnosticSink = sink;\n }\n\n /** Explicit zoom used for surfaces with no camera (minimap, export). Ignored for\n * the 'screen' target, which always reads the live camera zoom. */\n setSurfaceZoom(zoom: number): void {\n this.surfaceZoom = zoom;\n }\n\n isDomElement(element: CanvasElement): boolean {\n if (element.type !== 'html') return DOM_ELEMENT_TYPES.has(element.type);\n // canvas and missing are NOT DOM-participating; dom is.\n return resolveHtmlRouting(element, this.htmlPainters, this.expectedCanvasTypes) === 'dom';\n }\n\n renderCanvasElement(ctx: CanvasRenderingContext2D, element: CanvasElement): void {\n switch (element.type) {\n case 'stroke': {\n const b = getElementBounds(element);\n const c = b ? { x: b.x + b.w / 2, y: b.y + b.h / 2 } : element.position;\n withRotation(ctx, element, c, () => renderStroke(ctx, element));\n break;\n }\n case 'arrow':\n renderArrow(ctx, element, this.store, this.labelEditingId);\n break;\n case 'shape': {\n const b = getElementBounds(element);\n const c = b ? { x: b.x + b.w / 2, y: b.y + b.h / 2 } : element.position;\n withRotation(ctx, element, c, () => renderShape(ctx, element));\n break;\n }\n case 'image': {\n const b = getElementBounds(element);\n const c = b ? { x: b.x + b.w / 2, y: b.y + b.h / 2 } : element.position;\n withRotation(ctx, element, c, () =>\n renderImage(ctx, element, this.imageCache, this.onImageLoad, this.onImageError),\n );\n break;\n }\n case 'grid':\n this.renderGrid(ctx, element);\n break;\n case 'template':\n renderTemplate(ctx, element, this.store);\n break;\n case 'html':\n this.renderHtml(ctx, element);\n break;\n }\n }\n\n /** Only reached for canvas-routed html (isDomElement already sent 'dom'-routed\n * elements down the DOM sync branch instead). */\n private renderHtml(ctx: CanvasRenderingContext2D, el: HtmlElement): void {\n const routing = resolveHtmlRouting(el, this.htmlPainters, this.expectedCanvasTypes);\n if (routing === 'dom') return; // DOM layer owns it\n if (routing === 'missing') {\n this.diagnosticSink?.({\n kind: 'missing-painter',\n elementId: el.id,\n htmlType: el.htmlType,\n target: this.renderTarget,\n });\n return; // never fall back to DOM\n }\n const painter = this.htmlPainters?.getActivePainter(el.htmlType ?? '');\n if (!painter) return;\n paintHtmlElement(el, painter, {\n ctx,\n zoom: this.zoomForTarget(),\n target: this.renderTarget,\n onDiagnostic: this.diagnosticSink ?? undefined,\n });\n }\n\n private zoomForTarget(): number {\n if (this.renderTarget === 'screen') return this.camera?.zoom ?? 1;\n return this.surfaceZoom ?? 1;\n }\n\n private renderGrid(ctx: CanvasRenderingContext2D, grid: GridElement): void {\n const canvasSize = this.canvasSize;\n if (!canvasSize) return;\n\n const cam = this.camera;\n if (!cam) return;\n\n const bounds =\n this.gridBoundsOverride ??\n (() => {\n const topLeft = cam.screenToWorld({ x: 0, y: 0 });\n const bottomRight = cam.screenToWorld({ x: canvasSize.w, y: canvasSize.h });\n return {\n minX: topLeft.x,\n minY: topLeft.y,\n maxX: bottomRight.x,\n maxY: bottomRight.y,\n };\n })();\n\n if (grid.gridType === 'hex') {\n const dpr = typeof devicePixelRatio !== 'undefined' ? devicePixelRatio : 1;\n const scale = cam.zoom * dpr;\n const tile = this.getHexTile(\n grid.cellSize,\n grid.hexOrientation,\n grid.strokeColor,\n grid.strokeWidth,\n grid.opacity,\n scale,\n );\n if (tile) {\n renderHexGridTiled(ctx, bounds, grid.cellSize, tile);\n } else {\n renderHexGrid(\n ctx,\n bounds,\n grid.cellSize,\n grid.hexOrientation,\n grid.strokeColor,\n grid.strokeWidth,\n grid.opacity,\n );\n }\n } else {\n renderSquareGrid(\n ctx,\n bounds,\n grid.cellSize,\n grid.strokeColor,\n grid.strokeWidth,\n grid.opacity,\n );\n }\n }\n\n private getHexTile(\n cellSize: number,\n orientation: HexOrientation,\n strokeColor: string,\n strokeWidth: number,\n opacity: number,\n scale: number,\n ): HexGridTile | null {\n const key = `${cellSize}:${orientation}:${strokeColor}:${strokeWidth}:${opacity}:${scale}`;\n if (this.hexTileCacheKey === key && this.hexTileCache) {\n return this.hexTileCache;\n }\n const tile = createHexGridTile(cellSize, orientation, strokeColor, strokeWidth, opacity, scale);\n if (tile) {\n this.hexTileCache = tile;\n this.hexTileCacheKey = key;\n }\n return tile;\n }\n}\n","import type { Point, Size, StrokePoint } from '../core/types';\nimport type {\n Binding,\n StrokeElement,\n NoteElement,\n ArrowElement,\n ArrowStrokeStyle,\n ImageElement,\n HtmlElement,\n TextElement,\n ShapeElement,\n ShapeKind,\n GridElement,\n HexOrientation,\n TemplateElement,\n TemplateShape,\n TemplateRenderStyle,\n} from './types';\nimport { createId } from './create-id';\nimport { getArrowControlPoint } from './arrow-geometry';\nimport { sanitizeNoteHtml } from './note-sanitizer';\n\nexport const DEFAULT_NOTE_FONT_SIZE = 18;\n\ninterface BaseDefaults {\n position?: Point;\n zIndex?: number;\n locked?: boolean;\n layerId?: string;\n}\n\ninterface StrokeInput extends BaseDefaults {\n points: StrokePoint[];\n color?: string;\n width?: number;\n opacity?: number;\n blendMode?: 'multiply';\n}\n\ninterface NoteInput extends BaseDefaults {\n position: Point;\n size?: Size;\n text?: string;\n backgroundColor?: string;\n textColor?: string;\n fontSize?: number;\n}\n\ninterface ArrowInput extends BaseDefaults {\n from: Point;\n to: Point;\n bend?: number;\n color?: string;\n width?: number;\n fromBinding?: Binding;\n toBinding?: Binding;\n label?: string;\n strokeStyle?: ArrowStrokeStyle;\n}\n\ninterface ImageInput extends BaseDefaults {\n position: Point;\n size: Size;\n src: string;\n}\n\ninterface HtmlInput extends BaseDefaults {\n position: Point;\n size: Size;\n domId?: string;\n interactive?: boolean;\n htmlType?: string;\n data?: Record<string, unknown>;\n rotation?: number;\n}\n\ninterface TextInput extends BaseDefaults {\n position: Point;\n size?: Size;\n text?: string;\n fontSize?: number;\n color?: string;\n textAlign?: 'left' | 'center' | 'right';\n}\n\nexport function createStroke(input: StrokeInput): StrokeElement {\n const result: StrokeElement = {\n id: createId('stroke'),\n type: 'stroke',\n position: input.position ?? { x: 0, y: 0 },\n zIndex: input.zIndex ?? 0,\n locked: input.locked ?? false,\n layerId: input.layerId ?? '',\n points: input.points,\n color: input.color ?? '#000000',\n width: input.width ?? 2,\n opacity: input.opacity ?? 1,\n };\n if (input.blendMode) result.blendMode = input.blendMode;\n return result;\n}\n\nexport function createNote(input: NoteInput): NoteElement {\n return {\n id: createId('note'),\n type: 'note',\n position: input.position,\n zIndex: input.zIndex ?? 0,\n locked: input.locked ?? false,\n layerId: input.layerId ?? '',\n size: input.size ?? { w: 200, h: 100 },\n text: sanitizeNoteHtml(input.text ?? ''),\n backgroundColor: input.backgroundColor ?? '#ffeb3b',\n textColor: input.textColor ?? '#000000',\n fontSize: input.fontSize ?? DEFAULT_NOTE_FONT_SIZE,\n };\n}\n\nexport function createArrow(input: ArrowInput): ArrowElement {\n const bend = input.bend ?? 0;\n const result: ArrowElement = {\n id: createId('arrow'),\n type: 'arrow',\n position: input.position ?? { x: 0, y: 0 },\n zIndex: input.zIndex ?? 0,\n locked: input.locked ?? false,\n layerId: input.layerId ?? '',\n from: input.from,\n to: input.to,\n bend,\n color: input.color ?? '#000000',\n width: input.width ?? 2,\n cachedControlPoint: getArrowControlPoint(input.from, input.to, bend),\n };\n if (input.fromBinding) result.fromBinding = input.fromBinding;\n if (input.toBinding) result.toBinding = input.toBinding;\n if (input.label !== undefined) result.label = input.label;\n if (input.strokeStyle !== undefined) result.strokeStyle = input.strokeStyle;\n return result;\n}\n\nexport function createImage(input: ImageInput): ImageElement {\n return {\n id: createId('image'),\n type: 'image',\n position: input.position,\n zIndex: input.zIndex ?? 0,\n locked: input.locked ?? false,\n layerId: input.layerId ?? '',\n size: input.size,\n src: input.src,\n };\n}\n\nexport function createHtmlElement(input: HtmlInput): HtmlElement {\n const el: HtmlElement = {\n id: createId('html'),\n type: 'html',\n position: input.position,\n zIndex: input.zIndex ?? 0,\n locked: input.locked ?? false,\n layerId: input.layerId ?? '',\n size: input.size,\n };\n if (input.domId) el.domId = input.domId;\n if (input.interactive) el.interactive = input.interactive;\n if (input.htmlType) el.htmlType = input.htmlType;\n if (input.data) el.data = input.data;\n if (input.rotation !== undefined) el.rotation = input.rotation;\n return el;\n}\n\ninterface ShapeInput extends BaseDefaults {\n position: Point;\n size: Size;\n shape?: ShapeKind;\n strokeColor?: string;\n strokeWidth?: number;\n fillColor?: string;\n flip?: boolean;\n}\n\nexport function createShape(input: ShapeInput): ShapeElement {\n const result: ShapeElement = {\n id: createId('shape'),\n type: 'shape',\n position: input.position,\n zIndex: input.zIndex ?? 0,\n locked: input.locked ?? false,\n layerId: input.layerId ?? '',\n shape: input.shape ?? 'rectangle',\n size: input.size,\n strokeColor: input.strokeColor ?? '#000000',\n strokeWidth: input.strokeWidth ?? 2,\n fillColor: input.fillColor ?? 'none',\n };\n if (input.flip) result.flip = input.flip;\n return result;\n}\n\ninterface GridInput extends BaseDefaults {\n gridType?: 'square' | 'hex';\n hexOrientation?: HexOrientation;\n cellSize?: number;\n strokeColor?: string;\n strokeWidth?: number;\n opacity?: number;\n}\n\nexport function createGrid(input: GridInput): GridElement {\n return {\n id: createId('grid'),\n type: 'grid',\n position: input.position ?? { x: 0, y: 0 },\n zIndex: input.zIndex ?? 0,\n locked: input.locked ?? false,\n layerId: input.layerId ?? '',\n gridType: input.gridType ?? 'square',\n hexOrientation: input.hexOrientation ?? 'pointy',\n cellSize: input.cellSize ?? 40,\n strokeColor: input.strokeColor ?? '#000000',\n strokeWidth: input.strokeWidth ?? 1,\n opacity: input.opacity ?? 1,\n };\n}\n\nexport function createText(input: TextInput): TextElement {\n return {\n id: createId('text'),\n type: 'text',\n position: input.position,\n zIndex: input.zIndex ?? 0,\n locked: input.locked ?? false,\n layerId: input.layerId ?? '',\n size: input.size ?? { w: 200, h: 28 },\n text: sanitizeNoteHtml(input.text ?? ''),\n fontSize: input.fontSize ?? 16,\n color: input.color ?? '#1a1a1a',\n textAlign: input.textAlign ?? 'left',\n };\n}\n\ninterface TemplateInput extends BaseDefaults {\n position: Point;\n templateShape: TemplateShape;\n radius: number;\n angle?: number;\n width?: number;\n fillColor?: string;\n strokeColor?: string;\n strokeWidth?: number;\n opacity?: number;\n feetPerCell?: number;\n radiusFeet?: number;\n renderStyle?: TemplateRenderStyle;\n}\n\nexport function createTemplate(input: TemplateInput): TemplateElement {\n return {\n id: createId('template'),\n type: 'template',\n position: input.position,\n zIndex: input.zIndex ?? 0,\n locked: input.locked ?? false,\n layerId: input.layerId ?? '',\n templateShape: input.templateShape,\n radius: input.radius,\n angle: input.angle ?? 0,\n fillColor: input.fillColor ?? 'rgba(255, 87, 34, 0.2)',\n strokeColor: input.strokeColor ?? '#FF5722',\n strokeWidth: input.strokeWidth ?? 2,\n opacity: input.opacity ?? 0.6,\n feetPerCell: input.feetPerCell,\n radiusFeet: input.radiusFeet,\n ...(input.renderStyle !== undefined ? { renderStyle: input.renderStyle } : {}),\n ...(input.width !== undefined ? { width: input.width } : {}),\n };\n}\n","export interface ActiveFormats {\r\n bold: boolean;\r\n italic: boolean;\r\n underline: boolean;\r\n strikethrough: boolean;\r\n}\r\n\r\nexport function toggleBold(): void {\r\n document.execCommand('bold');\r\n}\r\n\r\nexport function toggleItalic(): void {\r\n document.execCommand('italic');\r\n}\r\n\r\nexport function toggleUnderline(): void {\r\n document.execCommand('underline');\r\n}\r\n\r\nexport function toggleStrikethrough(): void {\r\n document.execCommand('strikeThrough');\r\n}\r\n\r\nexport function setFontSize(size: number): void {\r\n const sel = window.getSelection();\r\n if (!sel || sel.rangeCount === 0) return;\r\n\r\n const range = sel.getRangeAt(0);\r\n if (range.collapsed) return;\r\n\r\n const span = document.createElement('span');\r\n span.style.fontSize = `${size}px`;\r\n try {\r\n range.surroundContents(span);\r\n } catch {\r\n span.appendChild(range.extractContents());\r\n range.insertNode(span);\r\n }\r\n}\r\n\r\nexport function getActiveFormats(): ActiveFormats {\r\n const query = (cmd: string): boolean => {\r\n try {\r\n return document.queryCommandState(cmd);\r\n } catch {\r\n return false;\r\n }\r\n };\r\n\r\n return {\r\n bold: query('bold'),\r\n italic: query('italic'),\r\n underline: query('underline'),\r\n strikethrough: query('strikeThrough'),\r\n };\r\n}\r\n","import { DEFAULT_NOTE_FONT_SIZE } from './element-factory';\r\nimport { setFontSize, getActiveFormats } from './note-formatting';\r\n\r\nconst TOOLBAR_HEIGHT = 52;\r\nconst TOOLBAR_GAP = 4;\r\n\r\ninterface FormatButton {\r\n label: string;\r\n format: string;\r\n command: string;\r\n}\r\n\r\nconst FORMAT_BUTTONS: FormatButton[] = [\r\n { label: 'B', format: 'bold', command: 'bold' },\r\n { label: 'I', format: 'italic', command: 'italic' },\r\n { label: 'U', format: 'underline', command: 'underline' },\r\n { label: 'S', format: 'strikethrough', command: 'strikeThrough' },\r\n];\r\n\r\nexport interface FontSizePreset {\r\n label: string;\r\n size: number;\r\n}\r\n\r\nexport const DEFAULT_FONT_SIZE_PRESETS: FontSizePreset[] = [\r\n { label: 'Small', size: 14 },\r\n { label: 'Normal', size: 18 },\r\n { label: 'Large', size: 24 },\r\n { label: 'Heading', size: 32 },\r\n];\r\n\r\nexport class NoteToolbar {\r\n private el: HTMLDivElement | null = null;\r\n private anchor: HTMLElement | null = null;\r\n private selectionListener: (() => void) | null = null;\r\n private readonly fontSizePresets: FontSizePreset[];\r\n\r\n constructor(fontSizePresets?: FontSizePreset[]) {\r\n this.fontSizePresets = fontSizePresets ?? DEFAULT_FONT_SIZE_PRESETS;\r\n }\r\n\r\n show(anchor: HTMLElement): void {\r\n this.hide();\r\n this.anchor = anchor;\r\n this.el = this.createToolbarElement();\r\n document.body.appendChild(this.el);\r\n this.positionToolbar(anchor);\r\n this.selectionListener = () => this.updateActiveStates();\r\n document.addEventListener('selectionchange', this.selectionListener);\r\n }\r\n\r\n hide(): void {\r\n if (this.selectionListener) {\r\n document.removeEventListener('selectionchange', this.selectionListener);\r\n this.selectionListener = null;\r\n }\r\n if (this.el) {\r\n this.el.remove();\r\n this.el = null;\r\n }\r\n this.anchor = null;\r\n }\r\n\r\n getElement(): HTMLDivElement | null {\r\n return this.el;\r\n }\r\n\r\n updatePosition(anchor: HTMLElement): void {\r\n if (this.el) {\r\n this.positionToolbar(anchor);\r\n }\r\n }\r\n\r\n private createToolbarElement(): HTMLDivElement {\r\n const toolbar = document.createElement('div');\r\n toolbar.dataset['noteToolbar'] = '';\r\n Object.assign(toolbar.style, {\r\n position: 'fixed',\r\n display: 'flex',\r\n alignItems: 'center',\r\n gap: '2px',\r\n padding: '2px 4px',\r\n background: '#fff',\r\n border: '1px solid #ccc',\r\n borderRadius: '4px',\r\n boxShadow: '0 2px 8px rgba(0,0,0,0.15)',\r\n zIndex: '10000',\r\n height: `${TOOLBAR_HEIGHT}px`,\r\n userSelect: 'none',\r\n });\r\n\r\n for (const btn of FORMAT_BUTTONS) {\r\n toolbar.appendChild(this.createFormatButton(btn));\r\n }\r\n\r\n toolbar.appendChild(this.createFontSizeSelect());\r\n\r\n return toolbar;\r\n }\r\n\r\n private createFormatButton(config: FormatButton): HTMLButtonElement {\r\n const btn = document.createElement('button');\r\n btn.dataset['format'] = config.format;\r\n btn.textContent = config.label;\r\n Object.assign(btn.style, {\r\n border: '1px solid transparent',\r\n borderRadius: '3px',\r\n background: 'none',\r\n cursor: 'pointer',\r\n padding: '2px 6px',\r\n fontSize: '13px',\r\n fontWeight: config.format === 'bold' ? 'bold' : 'normal',\r\n fontStyle: config.format === 'italic' ? 'italic' : 'normal',\r\n textDecoration:\r\n config.format === 'underline'\r\n ? 'underline'\r\n : config.format === 'strikethrough'\r\n ? 'line-through'\r\n : 'none',\r\n minWidth: '44px',\r\n height: '44px',\r\n lineHeight: '44px',\r\n });\r\n\r\n btn.addEventListener('pointerdown', (e) => {\r\n e.preventDefault();\r\n document.execCommand(config.command);\r\n this.updateActiveStates();\r\n });\r\n\r\n return btn;\r\n }\r\n\r\n private createFontSizeSelect(): HTMLSelectElement {\r\n const select = document.createElement('select');\r\n Object.assign(select.style, {\r\n border: '1px solid #ccc',\r\n borderRadius: '3px',\r\n background: '#fff',\r\n cursor: 'pointer',\r\n padding: '2px',\r\n fontSize: '12px',\r\n height: '44px',\r\n marginLeft: '4px',\r\n });\r\n\r\n for (const preset of this.fontSizePresets) {\r\n const option = document.createElement('option');\r\n option.value = String(preset.size);\r\n option.textContent = preset.label;\r\n select.appendChild(option);\r\n }\r\n\r\n select.value = String(DEFAULT_NOTE_FONT_SIZE);\r\n\r\n select.addEventListener('pointerdown', (e) => {\r\n e.stopPropagation();\r\n });\r\n\r\n select.addEventListener('change', () => {\r\n this.applyFontSize(Number(select.value));\r\n this.updateActiveStates();\r\n this.anchor?.focus();\r\n });\r\n\r\n return select;\r\n }\r\n\r\n private applyFontSize(size: number): void {\r\n const sel = window.getSelection();\r\n const collapsed = !sel || sel.rangeCount === 0 || sel.getRangeAt(0).collapsed;\r\n if (collapsed && this.anchor) {\r\n const range = document.createRange();\r\n range.selectNodeContents(this.anchor);\r\n sel?.removeAllRanges();\r\n sel?.addRange(range);\r\n setFontSize(size);\r\n const after = window.getSelection();\r\n if (after) {\r\n const caret = document.createRange();\r\n caret.selectNodeContents(this.anchor);\r\n caret.collapse(false);\r\n after.removeAllRanges();\r\n after.addRange(caret);\r\n }\r\n return;\r\n }\r\n setFontSize(size);\r\n }\r\n\r\n private positionToolbar(anchor: HTMLElement): void {\r\n if (!this.el) return;\r\n\r\n const rect = anchor.getBoundingClientRect();\r\n const toolbarWidth = this.el.offsetWidth || 200;\r\n\r\n let top = rect.top - TOOLBAR_HEIGHT - TOOLBAR_GAP;\r\n if (top < 0) {\r\n top = rect.bottom + TOOLBAR_GAP;\r\n }\r\n\r\n let left = rect.left + (rect.width - toolbarWidth) / 2;\r\n left = Math.max(4, left);\r\n\r\n Object.assign(this.el.style, {\r\n top: `${top}px`,\r\n left: `${left}px`,\r\n });\r\n }\r\n\r\n private updateActiveStates(): void {\r\n if (!this.el) return;\r\n\r\n const active = getActiveFormats();\r\n for (const config of FORMAT_BUTTONS) {\r\n const btn = this.el.querySelector(`[data-format=\"${config.format}\"]`) as HTMLElement | null;\r\n if (!btn) continue;\r\n\r\n const isActive = active[config.format as keyof typeof active] ?? false;\r\n btn.style.background = isActive ? '#e0e0e0' : 'none';\r\n btn.style.borderColor = isActive ? '#bbb' : 'transparent';\r\n }\r\n }\r\n}\r\n","import type { ElementStore } from './element-store';\r\nimport { NoteToolbar } from './note-toolbar';\r\nimport type { FontSizePreset } from './note-toolbar';\r\nimport { sanitizeNoteHtml } from './note-sanitizer';\r\nimport { toggleBold, toggleItalic, toggleUnderline } from './note-formatting';\r\n\r\nconst FORMAT_SHORTCUTS: Record<string, () => void> = {\r\n b: toggleBold,\r\n i: toggleItalic,\r\n u: toggleUnderline,\r\n};\r\n\r\nexport interface NoteEditorOptions {\r\n fontSizePresets?: FontSizePreset[];\r\n toolbar?: boolean;\r\n placeholder?: string;\r\n}\r\n\r\nfunction ensureEditorStyles(): void {\r\n if (document.querySelector('style[data-fieldnotes-editor]')) return;\r\n const style = document.createElement('style');\r\n style.setAttribute('data-fieldnotes-editor', '');\r\n style.textContent = `[data-fn-placeholder][data-fn-empty='true']::before {\r\n content: attr(data-fn-placeholder);\r\n color: #9e9e9e;\r\n position: absolute;\r\n pointer-events: none;\r\n}`;\r\n document.head.appendChild(style);\r\n}\r\n\r\nfunction isNodeEmpty(node: HTMLElement): boolean {\r\n const text = node.textContent ?? '';\r\n return text.replace(/\\u00a0/g, ' ').trim().length === 0;\r\n}\r\n\r\nexport class NoteEditor {\r\n private editingId: string | null = null;\r\n private editingNode: HTMLDivElement | null = null;\r\n private blurHandler: ((e: FocusEvent) => void) | null = null;\r\n private keyHandler: ((e: KeyboardEvent) => void) | null = null;\r\n private pointerHandler: ((e: PointerEvent) => void) | null = null;\r\n private inputHandler: (() => void) | null = null;\r\n private pendingEditId: string | null = null;\r\n private onStopCallback: ((elementId: string) => void) | null = null;\r\n private onInputCallback: ((elementId: string) => void) | null = null;\r\n private beginHistory: (() => void) | null = null;\r\n private commitHistory: (() => void) | null = null;\r\n private toolbar: NoteToolbar | null;\r\n private readonly placeholder: string;\r\n\r\n constructor(options?: NoteEditorOptions) {\r\n this.toolbar = options?.toolbar === false ? null : new NoteToolbar(options?.fontSizePresets);\r\n this.placeholder = options?.placeholder ?? 'Type…';\r\n }\r\n\r\n get isEditing(): boolean {\r\n return this.editingId !== null;\r\n }\r\n\r\n get editingElementId(): string | null {\r\n return this.editingId;\r\n }\r\n\r\n setOnStop(callback: (elementId: string) => void): void {\r\n this.onStopCallback = callback;\r\n }\r\n\r\n setOnInput(callback: (elementId: string) => void): void {\r\n this.onInputCallback = callback;\r\n }\r\n\r\n setHistoryHooks(begin: () => void, commit: () => void): void {\r\n this.beginHistory = begin;\r\n this.commitHistory = commit;\r\n }\r\n\r\n startEditing(node: HTMLDivElement, elementId: string, store: ElementStore): void {\r\n if (this.editingId === elementId) return;\r\n\r\n if (this.editingId) {\r\n this.stopEditing(store);\r\n }\r\n\r\n this.pendingEditId = elementId;\r\n\r\n requestAnimationFrame(() => {\r\n if (this.pendingEditId !== elementId) return;\r\n this.pendingEditId = null;\r\n this.activateEditing(node, elementId, store);\r\n });\r\n }\r\n\r\n stopEditing(store: ElementStore): void {\r\n this.pendingEditId = null;\r\n\r\n if (!this.editingId || !this.editingNode) return;\r\n\r\n if (this.blurHandler) {\r\n this.editingNode.removeEventListener('blur', this.blurHandler);\r\n }\r\n if (this.keyHandler) {\r\n this.editingNode.removeEventListener('keydown', this.keyHandler);\r\n }\r\n if (this.pointerHandler) {\r\n this.editingNode.removeEventListener('pointerdown', this.pointerHandler);\r\n }\r\n if (this.inputHandler) {\r\n this.editingNode.removeEventListener('input', this.inputHandler);\r\n }\r\n this.editingNode.removeAttribute('data-fn-placeholder');\r\n this.editingNode.removeAttribute('data-fn-empty');\r\n\r\n const text = sanitizeNoteHtml(this.editingNode.innerHTML);\r\n const current = store.getById(this.editingId);\r\n const textChanged =\r\n !!current && (current.type === 'note' || current.type === 'text') && current.text !== text;\r\n\r\n this.editingNode.contentEditable = 'false';\r\n Object.assign(this.editingNode.style, {\r\n userSelect: 'none',\r\n cursor: 'default',\r\n });\r\n\r\n this.toolbar?.hide();\r\n\r\n // The history transaction spans the whole edit session: opened at activate, committed\r\n // here at stop. Live height fits during editing plus the final text write all touch the\r\n // same element, so the recorder coalesces them into one undo step.\r\n if (textChanged) {\r\n store.update(this.editingId, { text });\r\n }\r\n if (this.editingId && this.onStopCallback) {\r\n this.onStopCallback(this.editingId);\r\n }\r\n this.commitHistory?.();\r\n\r\n this.editingId = null;\r\n this.editingNode = null;\r\n this.blurHandler = null;\r\n this.keyHandler = null;\r\n this.pointerHandler = null;\r\n this.inputHandler = null;\r\n }\r\n\r\n destroy(store: ElementStore): void {\r\n this.pendingEditId = null;\r\n if (this.isEditing) {\r\n this.stopEditing(store);\r\n }\r\n }\r\n\r\n updateToolbarPosition(): void {\r\n if (this.editingNode) {\r\n this.toolbar?.updatePosition(this.editingNode);\r\n }\r\n }\r\n\r\n private activateEditing(node: HTMLDivElement, elementId: string, store: ElementStore): void {\r\n this.editingId = elementId;\r\n this.editingNode = node;\r\n this.beginHistory?.();\r\n\r\n node.contentEditable = 'true';\r\n Object.assign(node.style, {\r\n userSelect: 'text',\r\n cursor: 'text',\r\n outline: 'none',\r\n });\r\n node.focus();\r\n\r\n const selection = window.getSelection?.();\r\n if (selection) {\r\n const range = document.createRange();\r\n range.selectNodeContents(node);\r\n range.collapse(false);\r\n selection.removeAllRanges();\r\n selection.addRange(range);\r\n }\r\n\r\n ensureEditorStyles();\r\n node.setAttribute('data-fn-placeholder', this.placeholder);\r\n node.setAttribute('data-fn-empty', String(isNodeEmpty(node)));\r\n this.inputHandler = () => {\r\n node.setAttribute('data-fn-empty', String(isNodeEmpty(node)));\r\n this.onInputCallback?.(elementId);\r\n };\r\n node.addEventListener('input', this.inputHandler);\r\n\r\n this.toolbar?.show(node);\r\n\r\n this.blurHandler = (e: FocusEvent) => {\r\n const related = e.relatedTarget as Node | null;\r\n if (related && this.toolbar?.getElement()?.contains(related)) return;\r\n this.stopEditing(store);\r\n };\r\n this.keyHandler = (e: KeyboardEvent) => {\r\n if ((e.ctrlKey || e.metaKey) && !e.shiftKey && !e.altKey) {\r\n const action = FORMAT_SHORTCUTS[e.key.toLowerCase()];\r\n if (action) {\r\n e.preventDefault();\r\n action();\r\n return;\r\n }\r\n }\r\n if (e.key === 'Escape') {\r\n node.blur();\r\n }\r\n e.stopPropagation();\r\n };\r\n this.pointerHandler = (e: PointerEvent) => {\r\n e.stopPropagation();\r\n };\r\n\r\n node.addEventListener('blur', this.blurHandler);\r\n node.addEventListener('keydown', this.keyHandler);\r\n node.addEventListener('pointerdown', this.pointerHandler);\r\n }\r\n}\r\n","import type { Point } from '../core/types';\r\n\r\nexport interface ContextMenuItem {\r\n label: string;\r\n action: string;\r\n disabled?: boolean;\r\n}\r\n\r\nexport interface ContextMenuOptions {\r\n onCommand: (action: string) => void;\r\n onClose: () => void;\r\n}\r\n\r\nexport class ContextMenu {\r\n private el: HTMLDivElement | null = null;\r\n private outsideListener: ((e: PointerEvent) => void) | null = null;\r\n private keyListener: ((e: KeyboardEvent) => void) | null = null;\r\n\r\n constructor(private readonly options: ContextMenuOptions) {}\r\n\r\n isOpen(): boolean {\r\n return this.el !== null;\r\n }\r\n\r\n open(items: ContextMenuItem[], screenPos: Point): void {\r\n this.close();\r\n const el = document.createElement('div');\r\n el.className = 'fieldnotes-context-menu';\r\n Object.assign(el.style, {\r\n position: 'fixed',\r\n left: `${screenPos.x}px`,\r\n top: `${screenPos.y}px`,\r\n zIndex: '10000',\r\n display: 'flex',\r\n flexDirection: 'column',\r\n });\r\n for (const item of items) {\r\n const btn = document.createElement('button');\r\n btn.type = 'button';\r\n btn.className =\r\n 'fieldnotes-context-menu-item' +\r\n (item.disabled ? ' fieldnotes-context-menu-item--disabled' : '');\r\n btn.textContent = item.label;\r\n if (item.disabled) {\r\n btn.disabled = true;\r\n } else {\r\n btn.addEventListener('click', () => {\r\n this.options.onCommand(item.action);\r\n this.close();\r\n });\r\n }\r\n el.appendChild(btn);\r\n }\r\n document.body.appendChild(el);\r\n this.el = el;\r\n this.clampToViewport(el, screenPos);\r\n\r\n this.keyListener = (e: KeyboardEvent) => {\r\n if (e.key === 'Escape') this.close();\r\n };\r\n document.addEventListener('keydown', this.keyListener);\r\n\r\n this.outsideListener = (e: PointerEvent) => {\r\n if (this.el && !this.el.contains(e.target as Node)) this.close();\r\n };\r\n // Defer attaching so the opening gesture's own pointerdown doesn't immediately close it.\r\n setTimeout(() => {\r\n if (this.outsideListener) document.addEventListener('pointerdown', this.outsideListener);\r\n }, 0);\r\n }\r\n\r\n close(): void {\r\n if (this.keyListener) {\r\n document.removeEventListener('keydown', this.keyListener);\r\n this.keyListener = null;\r\n }\r\n if (this.outsideListener) {\r\n document.removeEventListener('pointerdown', this.outsideListener);\r\n this.outsideListener = null;\r\n }\r\n if (this.el) {\r\n this.el.remove();\r\n this.el = null;\r\n this.options.onClose();\r\n }\r\n }\r\n\r\n dispose(): void {\r\n this.close();\r\n }\r\n\r\n private clampToViewport(el: HTMLElement, screenPos: Point): void {\r\n const rect = el.getBoundingClientRect();\r\n if (rect.width > 0 && screenPos.x + rect.width > window.innerWidth) {\r\n el.style.left = `${Math.max(0, screenPos.x - rect.width)}px`;\r\n }\r\n if (rect.height > 0 && screenPos.y + rect.height > window.innerHeight) {\r\n el.style.top = `${Math.max(0, screenPos.y - rect.height)}px`;\r\n }\r\n }\r\n}\r\n","import type { Bounds, Point } from '../core/types';\r\n\r\nexport interface MinimapTransform {\r\n scale: number;\r\n offsetX: number;\r\n offsetY: number;\r\n}\r\n\r\nexport function unionBounds(a: Bounds, b: Bounds): Bounds {\r\n const minX = Math.min(a.x, b.x);\r\n const minY = Math.min(a.y, b.y);\r\n const maxX = Math.max(a.x + a.w, b.x + b.w);\r\n const maxY = Math.max(a.y + a.h, b.y + b.h);\r\n return { x: minX, y: minY, w: maxX - minX, h: maxY - minY };\r\n}\r\n\r\n// `mapping` is the union of the content bounds and the visible viewport, so the\r\n// minimap always frames both what exists and where the camera is looking.\r\nexport function computeMinimapTransform(\r\n mapping: Bounds,\r\n miniW: number,\r\n miniH: number,\r\n padding: number,\r\n): MinimapTransform {\r\n const availW = Math.max(1, miniW - 2 * padding);\r\n const availH = Math.max(1, miniH - 2 * padding);\r\n const w = Math.max(mapping.w, 1);\r\n const h = Math.max(mapping.h, 1);\r\n const scale = Math.min(availW / w, availH / h);\r\n const offsetX = (miniW - mapping.w * scale) / 2 - mapping.x * scale;\r\n const offsetY = (miniH - mapping.h * scale) / 2 - mapping.y * scale;\r\n return { scale, offsetX, offsetY };\r\n}\r\n\r\nexport function worldToMini(t: MinimapTransform, p: Point): Point {\r\n return { x: p.x * t.scale + t.offsetX, y: p.y * t.scale + t.offsetY };\r\n}\r\n\r\nexport function miniToWorld(t: MinimapTransform, p: Point): Point {\r\n return { x: (p.x - t.offsetX) / t.scale, y: (p.y - t.offsetY) / t.scale };\r\n}\r\n","import type { Bounds, Point } from '../core/types';\nimport type { CanvasElement } from '../elements/types';\nimport type { Viewport } from './viewport';\nimport type { HtmlPainterRegistry } from './html-painter-registry';\nimport { ElementRenderer } from '../elements/element-renderer';\nimport { getElementBounds } from '../elements/element-bounds';\nimport { getElementsBoundingBox } from '../elements/bounds';\nimport {\n computeMinimapTransform,\n miniToWorld,\n unionBounds,\n worldToMini,\n type MinimapTransform,\n} from './minimap-transform';\n\nexport interface MinimapControllerOptions {\n /** Minimap width in CSS pixels. Default `200`. */\n width?: number;\n /** Minimap height in CSS pixels. Default `140`. */\n height?: number;\n /** Content inset inside the minimap, in minimap pixels. Default `8`. */\n padding?: number;\n /** Backdrop fill behind the thumbnail. Default: none (transparent). */\n background?: string;\n /** Stroke color of the viewport rectangle. Default `'#3b82f6'`. */\n viewportStroke?: string;\n /** Trailing debounce for scene bitmap re-renders. Default `200`. */\n debounceMs?: number;\n /** Tap/drag-to-center navigation on the canvas. Default `true`. */\n interactive?: boolean;\n /** Frame scheduler; default `requestAnimationFrame`. Injected by tests. */\n requestFrame?: (cb: () => void) => number;\n /** Frame canceller; default `cancelAnimationFrame`. Injected by tests. */\n cancelFrame?: (id: number) => void;\n}\n\nconst DEFAULT_WIDTH = 200;\nconst DEFAULT_HEIGHT = 140;\nconst DEFAULT_PADDING = 8;\nconst DEFAULT_DEBOUNCE_MS = 200;\nconst DEFAULT_VIEWPORT_STROKE = '#3b82f6';\nconst NEUTRAL = 'rgba(100,116,139,0.6)';\n\nfunction elementColor(el: CanvasElement): string {\n return 'color' in el && typeof el.color === 'string' ? el.color : NEUTRAL;\n}\n\ninterface SceneCache {\n canvas: HTMLCanvasElement;\n transform: MinimapTransform;\n mapping: Bounds;\n}\n\nfunction sameBounds(a: Bounds, b: Bounds): boolean {\n return a.x === b.x && a.y === b.y && a.w === b.w && a.h === b.h;\n}\n\n/**\n * Thumbnail overview navigator: renders the scene (real element shapes,\n * downscaled images, per-layer opacity compositing) into a cached offscreen\n * bitmap, composites it with the live viewport rectangle each frame, and\n * centers the camera on tap/drag. The cached bitmap and its transform swap\n * atomically: camera motion never renders the scene, only re-composites.\n */\nexport class MinimapController {\n private width: number;\n private height: number;\n private readonly padding: number;\n private readonly background: string | null;\n private readonly viewportStroke: string;\n private readonly debounceMs: number;\n private readonly interactive: boolean;\n private readonly requestFrame: (cb: () => void) => number;\n private readonly cancelFrame: (id: number) => void;\n private readonly renderer = new ElementRenderer();\n // Declared, not initialized here: a field initializer runs before parameter\n // properties are assigned (ES2022 useDefineForClassFields), so it cannot\n // read the `viewport` parameter. Assigned in the constructor body instead.\n private readonly htmlPainters: HtmlPainterRegistry;\n private scene: SceneCache | null = null;\n private frameId: number | null = null;\n private debounceTimer: ReturnType<typeof setTimeout> | null = null;\n private dragging = false;\n private disposed = false;\n private readonly unsubs: (() => void)[] = [];\n\n constructor(\n private readonly viewport: Viewport,\n private readonly canvas: HTMLCanvasElement,\n options: MinimapControllerOptions = {},\n ) {\n this.width = options.width ?? DEFAULT_WIDTH;\n this.height = options.height ?? DEFAULT_HEIGHT;\n this.padding = options.padding ?? DEFAULT_PADDING;\n this.background = options.background ?? null;\n this.viewportStroke = options.viewportStroke ?? DEFAULT_VIEWPORT_STROKE;\n this.debounceMs = options.debounceMs ?? DEFAULT_DEBOUNCE_MS;\n this.interactive = options.interactive !== false;\n this.requestFrame =\n options.requestFrame ??\n ((cb) => (typeof requestAnimationFrame !== 'undefined' ? requestAnimationFrame(cb) : 0));\n this.cancelFrame =\n options.cancelFrame ??\n ((id) => {\n if (typeof cancelAnimationFrame !== 'undefined') cancelAnimationFrame(id);\n });\n\n this.renderer.setStore(viewport.store);\n this.renderer.setOnImageLoad(() => this.markSceneDirty());\n this.htmlPainters = viewport.getHtmlPainters(); // parameter, not this.viewport\n this.renderer.setHtmlPainters(this.htmlPainters);\n this.renderer.setRenderTarget('minimap');\n this.applyCanvasSize();\n\n const onScene = () => this.markSceneDirty();\n this.unsubs.push(\n viewport.store.on('add', onScene),\n viewport.store.on('remove', onScene),\n viewport.store.on('update', onScene),\n viewport.store.on('clear', onScene),\n viewport.layerManager.on('change', onScene),\n viewport.camera.onChange(() => this.onViewChanged()),\n viewport.onResize(() => this.onViewChanged()),\n this.htmlPainters.onChange(() => this.invalidateScene()),\n );\n\n if (this.interactive) {\n canvas.style.touchAction = 'none';\n canvas.style.cursor = 'pointer';\n canvas.addEventListener('pointerdown', this.onPointerDown);\n canvas.addEventListener('pointermove', this.onPointerMove);\n canvas.addEventListener('pointerup', this.onPointerUp);\n canvas.addEventListener('pointercancel', this.onPointerEnd);\n canvas.addEventListener('lostpointercapture', this.onPointerEnd);\n }\n\n this.renderScene();\n this.requestDraw();\n }\n\n setSize(width: number, height: number): void {\n if (this.disposed) return;\n this.width = width;\n this.height = height;\n this.applyCanvasSize();\n this.clearDebounce();\n this.renderScene();\n this.requestDraw();\n }\n\n requestDraw(): void {\n if (this.disposed || this.frameId !== null) return;\n this.frameId = this.requestFrame(this.draw);\n }\n\n /**\n * Invalidates the cached scene bitmap in response to html-painter registry\n * changes (a painter registering/unregistering, or an `expect` declaration\n * changing) and schedules the same debounced rebuild `markSceneDirty` uses\n * for every other invalidation source. Unlike those other sources — which\n * deliberately keep compositing the OLD bitmap until the rebuild lands, so\n * camera motion and content edits never stall on a render — painter\n * availability has no \"old bitmap is still valid\" reading: an element that\n * was falling back to a neutral fillRect (no painter yet) or a stale\n * painter's output is not a safe thing to keep showing, so the cached\n * bitmap is dropped immediately instead of composited a further time.\n */\n invalidateScene(): void {\n if (this.disposed) return;\n this.scene = null;\n this.markSceneDirty();\n }\n\n dispose(): void {\n if (this.disposed) return;\n this.disposed = true;\n this.clearDebounce();\n if (this.frameId !== null) {\n this.cancelFrame(this.frameId);\n this.frameId = null;\n }\n for (const unsub of this.unsubs.splice(0)) unsub();\n if (this.interactive) {\n this.canvas.removeEventListener('pointerdown', this.onPointerDown);\n this.canvas.removeEventListener('pointermove', this.onPointerMove);\n this.canvas.removeEventListener('pointerup', this.onPointerUp);\n this.canvas.removeEventListener('pointercancel', this.onPointerEnd);\n this.canvas.removeEventListener('lostpointercapture', this.onPointerEnd);\n }\n }\n\n private clearDebounce(): void {\n if (this.debounceTimer !== null) {\n clearTimeout(this.debounceTimer);\n this.debounceTimer = null;\n }\n }\n\n private dpr(): number {\n return typeof devicePixelRatio !== 'undefined' ? devicePixelRatio : 1;\n }\n\n private applyCanvasSize(): void {\n const dpr = this.dpr();\n this.canvas.width = Math.max(1, Math.round(this.width * dpr));\n this.canvas.height = Math.max(1, Math.round(this.height * dpr));\n }\n\n // Single source for both mapping bounds and rendering: layer-visible,\n // grids excluded. (getElementBounds already returns null for grids, so they\n // cannot extend the bounding box today — this filter makes the invariant\n // structural instead of relying on that special case.)\n private sceneElements(): CanvasElement[] {\n return this.viewport.store\n .getAll()\n .filter((el) => el.type !== 'grid' && this.viewport.layerManager.isLayerVisible(el.layerId));\n }\n\n private currentMapping(): Bounds {\n const viewportRect = this.viewport.getVisibleRect();\n const content = getElementsBoundingBox(this.sceneElements());\n return content ? unionBounds(content, viewportRect) : viewportRect;\n }\n\n private onViewChanged(): void {\n if (this.disposed) return;\n const mapping = this.currentMapping();\n if (!this.scene || !sameBounds(mapping, this.scene.mapping)) {\n this.markSceneDirty();\n }\n this.requestDraw();\n }\n\n private markSceneDirty(): void {\n if (this.disposed) return;\n this.clearDebounce();\n this.debounceTimer = setTimeout(() => {\n this.debounceTimer = null;\n this.renderScene();\n this.requestDraw();\n }, this.debounceMs);\n }\n\n private renderScene(): void {\n if (this.disposed) return;\n const dpr = this.dpr();\n const mapping = this.currentMapping();\n const transform = computeMinimapTransform(mapping, this.width, this.height, this.padding);\n // The minimap fit scale, not the live camera zoom — canvas-routed html\n // painters read this via HtmlPaintContext.zoom (renderTarget 'minimap'\n // ignores the camera entirely; see ElementRenderer.zoomForTarget).\n this.renderer.setSurfaceZoom(transform.scale);\n const sceneCanvas = document.createElement('canvas');\n sceneCanvas.width = Math.max(1, Math.round(this.width * dpr));\n sceneCanvas.height = Math.max(1, Math.round(this.height * dpr));\n const ctx = sceneCanvas.getContext('2d');\n if (!ctx) return;\n\n const byLayer = new Map<string, CanvasElement[]>();\n for (const el of this.sceneElements()) {\n let list = byLayer.get(el.layerId);\n if (!list) {\n list = [];\n byLayer.set(el.layerId, list);\n }\n list.push(el);\n }\n\n for (const layer of this.viewport.layerManager.getLayers()) {\n const els = byLayer.get(layer.id);\n if (!els || els.length === 0) continue;\n const opacity = layer.opacity;\n if (opacity >= 1) {\n this.renderLayerElements(ctx, els, transform, dpr);\n continue;\n }\n // Translucent layers composite ONCE so overlapping elements within the\n // layer do not darken each other (main-renderer semantics).\n const layerCanvas = document.createElement('canvas');\n layerCanvas.width = sceneCanvas.width;\n layerCanvas.height = sceneCanvas.height;\n const layerCtx = layerCanvas.getContext('2d');\n if (!layerCtx) continue;\n this.renderLayerElements(layerCtx, els, transform, dpr);\n ctx.save();\n ctx.globalAlpha = opacity;\n ctx.drawImage(layerCanvas, 0, 0);\n ctx.restore();\n }\n\n // Atomic swap: bitmap, transform, and mapping replace together.\n this.scene = { canvas: sceneCanvas, transform, mapping };\n }\n\n private renderLayerElements(\n ctx: CanvasRenderingContext2D,\n elements: CanvasElement[],\n t: MinimapTransform,\n dpr: number,\n ): void {\n for (const el of elements) {\n // note/text always fall back; 'html' only falls back when the shared\n // renderer's routing resolves it to 'dom' (no canvas painter claims\n // it) — the SAME routing decision the main renderer and export make,\n // via the registry this controller forwarded in setHtmlPainters().\n if (this.renderer.isDomElement(el)) {\n const b = getElementBounds(el);\n if (!b) continue;\n const tl = worldToMini(t, { x: b.x, y: b.y });\n ctx.save();\n ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n ctx.fillStyle = elementColor(el);\n ctx.fillRect(tl.x, tl.y, Math.max(1, b.w * t.scale), Math.max(1, b.h * t.scale));\n ctx.restore();\n continue;\n }\n ctx.save();\n ctx.setTransform(dpr * t.scale, 0, 0, dpr * t.scale, dpr * t.offsetX, dpr * t.offsetY);\n this.renderer.renderCanvasElement(ctx, el);\n ctx.restore();\n }\n }\n\n private draw = (): void => {\n this.frameId = null;\n if (this.disposed) return;\n const ctx = this.canvas.getContext('2d');\n if (!ctx) return;\n const dpr = this.dpr();\n ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n ctx.clearRect(0, 0, this.width, this.height);\n if (this.background) {\n ctx.fillStyle = this.background;\n ctx.fillRect(0, 0, this.width, this.height);\n }\n const scene = this.scene;\n if (!scene) return;\n ctx.drawImage(scene.canvas, 0, 0, this.width, this.height);\n // The rect projects through the SAME transform the bitmap was rendered\n // with (atomic-swap invariant) — never a fresher transform.\n const viewportRect = this.viewport.getVisibleRect();\n const tl = worldToMini(scene.transform, { x: viewportRect.x, y: viewportRect.y });\n ctx.strokeStyle = this.viewportStroke;\n ctx.lineWidth = 1.5;\n ctx.strokeRect(\n tl.x,\n tl.y,\n viewportRect.w * scene.transform.scale,\n viewportRect.h * scene.transform.scale,\n );\n };\n\n private navTransform(): MinimapTransform {\n return (\n this.scene?.transform ??\n computeMinimapTransform(this.currentMapping(), this.width, this.height, this.padding)\n );\n }\n\n private navigateFromEvent(e: PointerEvent): void {\n const rect = this.canvas.getBoundingClientRect();\n // The canvas's DISPLAYED CSS size (rect.width/height) can differ from the\n // logical width/height the minimap transform is built for — applyCanvasSize\n // only sets the backing-store pixel attributes, never canvas.style\n // width/height, so a consumer that doesn't explicitly style the canvas (or\n // that CSS-scales it responsively) can display it at a different CSS size.\n // Normalize the pointer position from displayed to logical space first.\n // A zero-size rect (unmeasured/unlaid-out canvas) carries no scaling\n // information, so it falls back to an identity ratio rather than\n // dividing by zero.\n const scaleX = rect.width > 0 ? this.width / rect.width : 1;\n const scaleY = rect.height > 0 ? this.height / rect.height : 1;\n const point = {\n x: (e.clientX - rect.left) * scaleX,\n y: (e.clientY - rect.top) * scaleY,\n };\n const world: Point = miniToWorld(this.navTransform(), point);\n this.viewport.centerCameraAt(world);\n }\n\n private onPointerDown = (e: PointerEvent): void => {\n e.stopPropagation();\n e.preventDefault();\n this.dragging = true;\n this.canvas.setPointerCapture?.(e.pointerId);\n this.navigateFromEvent(e);\n };\n\n private onPointerMove = (e: PointerEvent): void => {\n if (!this.dragging) return;\n e.stopPropagation();\n this.navigateFromEvent(e);\n };\n\n private onPointerUp = (e: PointerEvent): void => {\n this.dragging = false;\n try {\n this.canvas.releasePointerCapture(e.pointerId);\n } catch {\n // already released\n }\n };\n\n // pointercancel / lostpointercapture: a browser gesture or interrupted touch\n // can end the interaction without a pointerup — the drag must not stick.\n private onPointerEnd = (): void => {\n this.dragging = false;\n };\n}\n","import type { Viewport } from './viewport';\r\nimport { MinimapController } from './minimap-controller';\r\n\r\nconst WIDTH = 200;\r\nconst HEIGHT = 140;\r\nconst MARGIN = 16;\r\n\r\n/**\r\n * Built-in bottom-right minimap for `ViewportOptions.minimap: true`. Thin DOM\r\n * wrapper over `MinimapController`, which owns rendering, invalidation, and\r\n * tap/drag navigation.\r\n */\r\nexport class Minimap {\r\n private readonly canvas: HTMLCanvasElement;\r\n private readonly controller: MinimapController;\r\n\r\n constructor(container: HTMLElement, viewport: Viewport) {\r\n const canvas = document.createElement('canvas');\r\n Object.assign(canvas.style, {\r\n position: 'absolute',\r\n right: `${MARGIN}px`,\r\n bottom: `${MARGIN}px`,\r\n width: `${WIDTH}px`,\r\n height: `${HEIGHT}px`,\r\n background: 'rgba(255,255,255,0.85)',\r\n border: '1px solid rgba(0,0,0,0.15)',\r\n borderRadius: '4px',\r\n zIndex: '10',\r\n });\r\n canvas.dataset.fieldnotesMinimap = 'true';\r\n container.appendChild(canvas);\r\n this.canvas = canvas;\r\n this.controller = new MinimapController(viewport, canvas, { width: WIDTH, height: HEIGHT });\r\n }\r\n\r\n scheduleDraw(): void {\r\n this.controller.requestDraw();\r\n }\r\n\r\n destroy(): void {\r\n this.controller.dispose();\r\n this.canvas.remove();\r\n }\r\n}\r\n","export function createWrapper(): HTMLDivElement {\r\n const el = document.createElement('div');\r\n Object.assign(el.style, {\r\n position: 'relative',\r\n width: '100%',\r\n height: '100%',\r\n overflow: 'hidden',\r\n overscrollBehavior: 'none',\r\n userSelect: 'none',\r\n webkitUserSelect: 'none',\r\n });\r\n return el;\r\n}\r\n\r\nexport function createCanvas(): HTMLCanvasElement {\r\n const el = document.createElement('canvas');\r\n Object.assign(el.style, {\r\n position: 'absolute',\r\n top: '0',\r\n left: '0',\r\n width: '100%',\r\n height: '100%',\r\n });\r\n return el;\r\n}\r\n\r\nexport function createDomLayer(): HTMLDivElement {\r\n const el = document.createElement('div');\r\n Object.assign(el.style, {\r\n position: 'absolute',\r\n top: '0',\r\n left: '0',\r\n width: '100%',\r\n height: '100%',\r\n pointerEvents: 'none',\r\n transformOrigin: '0 0',\r\n });\r\n return el;\r\n}\r\n\r\nexport function createPaintStack(): HTMLDivElement {\r\n const el = createDomLayer();\r\n el.dataset['fieldnotesPaintStack'] = '';\r\n el.style.transformOrigin = '';\r\n return el;\r\n}\r\n","export class HybridRenderSurface {\r\n private readonly canvases = new Map<number, HTMLCanvasElement>();\r\n\r\n constructor(private readonly root: HTMLDivElement) {}\r\n\r\n beginFrame(activeOrders: ReadonlySet<number>, width: number, height: number): void {\r\n for (const [order, canvas] of this.canvases) {\r\n if (!activeOrders.has(order)) {\r\n canvas.remove();\r\n this.canvases.delete(order);\r\n }\r\n }\r\n\r\n for (const order of activeOrders) {\r\n const canvas = this.getCanvas(order);\r\n if (canvas.width !== width) canvas.width = width;\r\n if (canvas.height !== height) canvas.height = height;\r\n canvas.style.zIndex = String(order);\r\n }\r\n }\r\n\r\n getContext(order: number): CanvasRenderingContext2D | null {\r\n return this.getCanvas(order).getContext('2d');\r\n }\r\n\r\n clear(): void {\r\n for (const canvas of this.canvases.values()) canvas.remove();\r\n this.canvases.clear();\r\n }\r\n\r\n private getCanvas(order: number): HTMLCanvasElement {\r\n let canvas = this.canvases.get(order);\r\n if (canvas) return canvas;\r\n\r\n canvas = document.createElement('canvas');\r\n canvas.dataset['paintOrder'] = String(order);\r\n Object.assign(canvas.style, {\r\n position: 'absolute',\r\n inset: '0',\r\n width: '100%',\r\n height: '100%',\r\n pointerEvents: 'none',\r\n });\r\n this.root.appendChild(canvas);\r\n this.canvases.set(order, canvas);\r\n return canvas;\r\n }\r\n}\r\n","import type { ArrowElement } from './types';\r\nimport type { ElementStore } from './element-store';\r\nimport type { HistoryRecorder } from '../history/history-recorder';\r\nimport { getArrowMidpoint } from './arrow-geometry';\r\n\r\nexport interface ArrowLabelEditStart {\r\n arrow: ArrowElement;\r\n layer: HTMLElement;\r\n store: ElementStore;\r\n recorder: HistoryRecorder;\r\n onDone: () => void;\r\n}\r\n\r\nexport class ArrowLabelEditor {\r\n private input: HTMLInputElement | null = null;\r\n private done = false;\r\n\r\n get isEditing(): boolean {\r\n return this.input !== null;\r\n }\r\n\r\n startEditing(start: ArrowLabelEditStart): void {\r\n if (this.input) this.cleanup();\r\n const { arrow, layer, store, recorder, onDone } = start;\r\n const mid = getArrowMidpoint(arrow.from, arrow.to, arrow.bend);\r\n\r\n const input = document.createElement('input');\r\n input.type = 'text';\r\n input.value = arrow.label ?? '';\r\n Object.assign(input.style, {\r\n position: 'absolute',\r\n left: `${mid.x}px`,\r\n top: `${mid.y}px`,\r\n transform: 'translate(-50%, -50%)',\r\n // domLayer is pointer-events:none; the input must opt back in to receive taps/clicks.\r\n pointerEvents: 'auto',\r\n font: '14px system-ui, sans-serif',\r\n padding: '2px 6px',\r\n border: '1px solid #2196F3',\r\n borderRadius: '4px',\r\n background: '#ffffff',\r\n color: '#1a1a1a',\r\n outline: 'none',\r\n minWidth: '40px',\r\n });\r\n\r\n this.done = false;\r\n\r\n const commit = (): void => {\r\n if (this.done) return;\r\n this.done = true;\r\n const next = input.value.trim() || undefined;\r\n if (next !== arrow.label) {\r\n recorder.begin();\r\n store.update(arrow.id, { label: next });\r\n recorder.commit();\r\n }\r\n this.cleanup();\r\n onDone();\r\n };\r\n\r\n const cancel = (): void => {\r\n if (this.done) return;\r\n this.done = true;\r\n this.cleanup();\r\n onDone();\r\n };\r\n\r\n input.addEventListener('keydown', (e) => {\r\n if (e.key === 'Enter') {\r\n e.preventDefault();\r\n commit();\r\n } else if (e.key === 'Escape') {\r\n e.preventDefault();\r\n cancel();\r\n }\r\n e.stopPropagation();\r\n });\r\n input.addEventListener('blur', commit);\r\n\r\n layer.appendChild(input);\r\n this.input = input;\r\n input.focus();\r\n input.select();\r\n }\r\n\r\n /** Abort any in-progress edit without committing (e.g. on viewport teardown). */\r\n cancel(): void {\r\n this.done = true;\r\n this.cleanup();\r\n }\r\n\r\n private cleanup(): void {\r\n if (this.input) {\r\n this.input.remove();\r\n this.input = null;\r\n }\r\n }\r\n}\r\n","import type { Tool, ToolContext, PointerState } from './types';\r\n\r\nexport class ToolManager {\r\n private tools = new Map<string, Tool>();\r\n private current: Tool | null = null;\r\n private changeListeners = new Set<(name: string) => void>();\r\n private registerListeners = new Set<(tool: Tool) => void>();\r\n\r\n get activeTool(): Tool | null {\r\n return this.current;\r\n }\r\n\r\n get toolNames(): string[] {\r\n return [...this.tools.keys()];\r\n }\r\n\r\n register(tool: Tool): void {\r\n this.tools.set(tool.name, tool);\r\n this.registerListeners.forEach((fn) => fn(tool));\r\n }\r\n\r\n getTool<T extends Tool = Tool>(name: string): T | undefined {\r\n return this.tools.get(name) as T | undefined;\r\n }\r\n\r\n setTool(name: string, ctx: ToolContext): void {\r\n const tool = this.tools.get(name);\r\n if (!tool) return;\r\n\r\n this.current?.onDeactivate?.(ctx);\r\n this.current = tool;\r\n this.current.onActivate?.(ctx);\r\n this.changeListeners.forEach((fn) => fn(name));\r\n }\r\n\r\n handlePointerDown(state: PointerState, ctx: ToolContext): void {\r\n this.current?.onPointerDown(state, ctx);\r\n }\r\n\r\n handlePointerMove(state: PointerState, ctx: ToolContext): void {\r\n this.current?.onPointerMove(state, ctx);\r\n }\r\n\r\n handlePointerUp(state: PointerState, ctx: ToolContext): void {\r\n this.current?.onPointerUp(state, ctx);\r\n }\r\n\r\n onChange(listener: (name: string) => void): () => void {\r\n this.changeListeners.add(listener);\r\n return () => this.changeListeners.delete(listener);\r\n }\r\n\r\n onRegister(listener: (tool: Tool) => void): () => void {\r\n this.registerListeners.add(listener);\r\n return () => this.registerListeners.delete(listener);\r\n }\r\n}\r\n","import type { ElementStore } from '../elements/element-store';\nimport type { Command } from './types';\n\nexport interface HistoryStackOptions {\n maxSize?: number;\n}\n\nconst DEFAULT_MAX_SIZE = 100;\n\nexport class HistoryStack {\n private undoStack: Command[] = [];\n private redoStack: Command[] = [];\n private readonly maxSize: number;\n private changeListeners = new Set<() => void>();\n\n constructor(options: HistoryStackOptions = {}) {\n this.maxSize = options.maxSize ?? DEFAULT_MAX_SIZE;\n }\n\n get canUndo(): boolean {\n return this.undoStack.length > 0;\n }\n\n get canRedo(): boolean {\n return this.redoStack.length > 0;\n }\n\n get undoCount(): number {\n return this.undoStack.length;\n }\n\n get redoCount(): number {\n return this.redoStack.length;\n }\n\n push(command: Command): void {\n this.undoStack.push(command);\n this.redoStack = [];\n\n if (this.undoStack.length > this.maxSize) {\n this.undoStack.shift();\n }\n\n this.notifyChange();\n }\n\n undo(store: ElementStore): boolean {\n const command = this.undoStack.pop();\n if (!command) return false;\n\n command.undo(store);\n this.redoStack.push(command);\n this.notifyChange();\n return true;\n }\n\n redo(store: ElementStore): boolean {\n const command = this.redoStack.pop();\n if (!command) return false;\n\n command.execute(store);\n this.undoStack.push(command);\n this.notifyChange();\n return true;\n }\n\n clear(): void {\n this.undoStack = [];\n this.redoStack = [];\n this.notifyChange();\n }\n\n onChange(listener: () => void): () => void {\n this.changeListeners.add(listener);\n return () => this.changeListeners.delete(listener);\n }\n\n private notifyChange(): void {\n this.changeListeners.forEach((fn) => fn());\n }\n}\n","import type { CanvasElement } from '../elements/types';\r\nimport type { ElementStore } from '../elements/element-store';\r\nimport type { Command } from './types';\r\n\r\nexport class AddElementCommand implements Command {\r\n private readonly element: CanvasElement;\r\n\r\n constructor(element: CanvasElement) {\r\n this.element = { ...element };\r\n }\r\n\r\n execute(store: ElementStore): void {\r\n store.add(this.element);\r\n }\r\n\r\n undo(store: ElementStore): void {\r\n store.remove(this.element.id);\r\n }\r\n}\r\n\r\nexport class RemoveElementCommand implements Command {\r\n private readonly element: CanvasElement;\r\n\r\n constructor(element: CanvasElement) {\r\n this.element = { ...element };\r\n }\r\n\r\n execute(store: ElementStore): void {\r\n store.remove(this.element.id);\r\n }\r\n\r\n undo(store: ElementStore): void {\r\n store.add(this.element);\r\n }\r\n}\r\n\r\nexport class UpdateElementCommand implements Command {\r\n constructor(\r\n private readonly id: string,\r\n private readonly previous: CanvasElement,\r\n private readonly current: CanvasElement,\r\n ) {}\r\n\r\n execute(store: ElementStore): void {\r\n store.update(this.id, diffPatch(this.previous, this.current));\r\n }\r\n\r\n undo(store: ElementStore): void {\r\n store.update(this.id, diffPatch(this.current, this.previous));\r\n }\r\n}\r\n\r\n// Patch turning `from` into `to`, explicitly setting keys that exist on `from`\r\n// but not `to` to `undefined` so a merge-based `update` clears them.\r\nfunction diffPatch(from: CanvasElement, to: CanvasElement): Partial<CanvasElement> {\r\n const patch: Record<string, unknown> = { ...to };\r\n for (const key of Object.keys(from)) {\r\n if (!(key in to)) patch[key] = undefined;\r\n }\r\n return patch as Partial<CanvasElement>;\r\n}\r\n\r\nexport class BatchCommand implements Command {\r\n readonly commands: readonly Command[];\r\n\r\n constructor(commands: Command[]) {\r\n this.commands = [...commands];\r\n }\r\n\r\n execute(store: ElementStore): void {\r\n for (const cmd of this.commands) {\r\n cmd.execute(store);\r\n }\r\n }\r\n\r\n undo(store: ElementStore): void {\r\n for (let i = this.commands.length - 1; i >= 0; i--) {\r\n this.commands[i]?.undo(store);\r\n }\r\n }\r\n}\r\n","import type { ElementStore } from '../elements/element-store';\r\nimport type { Command } from './types';\r\nimport type { LayerManager } from '../layers/layer-manager';\r\nimport type { Layer } from '../layers/types';\r\n\r\nexport class CreateLayerCommand implements Command {\r\n constructor(\r\n private readonly manager: LayerManager,\r\n private readonly layer: Layer,\r\n ) {}\r\n\r\n execute(_store: ElementStore): void {\r\n this.manager.addLayerDirect(this.layer);\r\n }\r\n\r\n undo(_store: ElementStore): void {\r\n this.manager.removeLayerDirect(this.layer.id);\r\n }\r\n}\r\n\r\nexport class RemoveLayerCommand implements Command {\r\n constructor(\r\n private readonly manager: LayerManager,\r\n private readonly layer: Layer,\r\n ) {}\r\n\r\n execute(_store: ElementStore): void {\r\n this.manager.removeLayerDirect(this.layer.id);\r\n }\r\n\r\n undo(_store: ElementStore): void {\r\n this.manager.addLayerDirect(this.layer);\r\n }\r\n}\r\n\r\nexport class UpdateLayerCommand implements Command {\r\n constructor(\r\n private readonly manager: LayerManager,\r\n private readonly layerId: string,\r\n private readonly previous: Layer,\r\n private readonly current: Layer,\r\n ) {}\r\n\r\n execute(_store: ElementStore): void {\r\n this.manager.updateLayerDirect(this.layerId, { ...this.current });\r\n }\r\n\r\n undo(_store: ElementStore): void {\r\n this.manager.updateLayerDirect(this.layerId, { ...this.previous });\r\n }\r\n}\r\n","import type { ElementStore } from '../elements/element-store';\r\nimport type { EventMeta } from '../core/event-bus';\r\nimport type { CanvasElement } from '../elements/types';\r\nimport type { Command } from './types';\r\nimport type { HistoryStack } from './history-stack';\r\nimport type { LayerManager } from '../layers/layer-manager';\r\nimport type { Layer } from '../layers/types';\r\nimport {\r\n AddElementCommand,\r\n RemoveElementCommand,\r\n UpdateElementCommand,\r\n BatchCommand,\r\n} from './commands';\r\nimport { CreateLayerCommand, RemoveLayerCommand, UpdateLayerCommand } from './layer-commands';\r\n\r\nfunction isExternalChange(meta: EventMeta): boolean {\r\n return meta.origin !== undefined && meta.origin !== 'local';\r\n}\r\n\r\nexport class HistoryRecorder {\r\n private recording = true;\r\n private transaction: Command[] | null = null;\r\n private generation = 0;\r\n private updateSnapshots = new Map<string, CanvasElement>();\r\n private unsubscribers: (() => void)[];\r\n private transactionEndListeners = new Set<() => void>();\r\n\r\n constructor(\r\n private readonly store: ElementStore,\r\n private readonly stack: HistoryStack,\r\n private readonly layerManager?: LayerManager,\r\n ) {\r\n this.unsubscribers = [\r\n store.on('add', (el, meta) => this.onAdd(el, meta)),\r\n store.on('remove', (el, meta) => this.onRemove(el, meta)),\r\n store.on('update', ({ previous, current }, meta) => this.onUpdate(previous, current, meta)),\r\n ];\r\n\r\n if (layerManager) {\r\n this.unsubscribers.push(\r\n layerManager.on('create', (layer) => this.onLayerCreate(layer)),\r\n layerManager.on('remove', (layer) => this.onLayerRemove(layer)),\r\n layerManager.on('update', ({ previous, current }) => this.onLayerUpdate(previous, current)),\r\n );\r\n }\r\n }\r\n\r\n pause(): void {\r\n this.recording = false;\r\n }\r\n\r\n resume(): void {\r\n this.recording = true;\r\n }\r\n\r\n begin(): void {\r\n if (this.transaction !== null) {\r\n this.commit();\r\n }\r\n this.transaction = [];\r\n this.updateSnapshots.clear();\r\n this.generation += 1;\r\n }\r\n\r\n get currentTransactionId(): number | null {\r\n return this.transaction !== null ? this.generation : null;\r\n }\r\n\r\n onTransactionEnd(listener: () => void): () => void {\r\n this.transactionEndListeners.add(listener);\r\n return () => this.transactionEndListeners.delete(listener);\r\n }\r\n\r\n private notifyTransactionEnd(): void {\r\n for (const listener of this.transactionEndListeners) {\r\n try {\r\n listener();\r\n } catch {\r\n // Listeners must not interrupt history commit.\r\n }\r\n }\r\n }\r\n\r\n commit(): void {\r\n if (!this.transaction) return;\r\n\r\n const finalCommands = this.flushUpdateSnapshots();\r\n const all = [...this.transaction, ...finalCommands];\r\n this.transaction = null;\r\n this.updateSnapshots.clear();\r\n\r\n if (all.length > 0) {\r\n const first = all[0];\r\n this.stack.push(all.length === 1 && first ? first : new BatchCommand(all));\r\n }\r\n this.notifyTransactionEnd();\r\n }\r\n\r\n rollback(): void {\r\n const wasOpen = this.transaction !== null;\r\n this.transaction = null;\r\n this.updateSnapshots.clear();\r\n if (wasOpen) this.notifyTransactionEnd();\r\n }\r\n\r\n destroy(): void {\r\n this.unsubscribers.forEach((fn) => fn());\r\n }\r\n\r\n private record(command: Command): void {\r\n if (this.transaction) {\r\n this.transaction.push(command);\r\n } else {\r\n this.stack.push(command);\r\n }\r\n }\r\n\r\n private onAdd(element: CanvasElement, meta: EventMeta): void {\r\n if (isExternalChange(meta)) return;\r\n if (!this.recording) return;\r\n this.record(new AddElementCommand(element));\r\n }\r\n\r\n private onRemove(element: CanvasElement, meta: EventMeta): void {\r\n if (isExternalChange(meta)) return;\r\n if (!this.recording) return;\r\n\r\n if (this.transaction && this.updateSnapshots.has(element.id)) {\r\n this.updateSnapshots.delete(element.id);\r\n }\r\n\r\n this.record(new RemoveElementCommand(element));\r\n }\r\n\r\n private onUpdate(previous: CanvasElement, current: CanvasElement, meta: EventMeta): void {\r\n if (isExternalChange(meta)) return;\r\n if (!this.recording) return;\r\n\r\n if (this.transaction) {\r\n if (!this.updateSnapshots.has(current.id)) {\r\n this.updateSnapshots.set(current.id, { ...previous });\r\n }\r\n } else {\r\n this.stack.push(new UpdateElementCommand(current.id, previous, current));\r\n }\r\n }\r\n\r\n private onLayerCreate(layer: Layer): void {\r\n if (!this.recording) return;\r\n if (!this.layerManager) return;\r\n this.record(new CreateLayerCommand(this.layerManager, layer));\r\n }\r\n\r\n private onLayerRemove(layer: Layer): void {\r\n if (!this.recording) return;\r\n if (!this.layerManager) return;\r\n this.record(new RemoveLayerCommand(this.layerManager, layer));\r\n }\r\n\r\n private onLayerUpdate(previous: Layer, current: Layer): void {\r\n if (!this.recording) return;\r\n if (!this.layerManager) return;\r\n this.record(new UpdateLayerCommand(this.layerManager, current.id, previous, current));\r\n }\r\n\r\n private flushUpdateSnapshots(): Command[] {\r\n const commands: Command[] = [];\r\n for (const [id, previous] of this.updateSnapshots) {\r\n const current = this.store.getById(id);\r\n if (current) {\r\n commands.push(new UpdateElementCommand(id, previous, current));\r\n }\r\n }\r\n return commands;\r\n }\r\n}\r\n","import type { NoteElement } from '../elements/types';\r\nimport { DEFAULT_NOTE_FONT_SIZE } from '../elements/element-factory';\r\nimport { parseStyledRuns } from '../elements/note-sanitizer';\r\nimport type { StyledRun } from '../elements/note-sanitizer';\r\n\r\nexport { parseStyledRuns };\r\nexport type { StyledRun };\r\n\r\nexport function renderNoteOnCanvas(ctx: CanvasRenderingContext2D, note: NoteElement): void {\r\n const { x, y } = note.position;\r\n const { w, h } = note.size;\r\n const r = 4;\r\n const pad = 8;\r\n const baseFontSize = note.fontSize ?? DEFAULT_NOTE_FONT_SIZE;\r\n\r\n ctx.save();\r\n ctx.fillStyle = note.backgroundColor;\r\n ctx.beginPath();\r\n ctx.moveTo(x + r, y);\r\n ctx.lineTo(x + w - r, y);\r\n ctx.arcTo(x + w, y, x + w, y + r, r);\r\n ctx.lineTo(x + w, y + h - r);\r\n ctx.arcTo(x + w, y + h, x + w - r, y + h, r);\r\n ctx.lineTo(x + r, y + h);\r\n ctx.arcTo(x, y + h, x, y + h - r, r);\r\n ctx.lineTo(x, y + r);\r\n ctx.arcTo(x, y, x + r, y, r);\r\n ctx.closePath();\r\n ctx.fill();\r\n\r\n if (note.text) {\r\n ctx.fillStyle = note.textColor;\r\n const runs = parseStyledRuns(note.text, baseFontSize);\r\n renderStyledRuns(ctx, runs, x + pad, y + pad, w - pad * 2);\r\n }\r\n\r\n ctx.restore();\r\n}\r\n\r\nfunction buildFontString(run: StyledRun): string {\r\n const style = run.italic ? 'italic' : 'normal';\r\n const weight = run.bold ? 'bold' : 'normal';\r\n return `${style} ${weight} ${run.fontSize}px system-ui, sans-serif`;\r\n}\r\n\r\ninterface LineFragment {\r\n text: string;\r\n font: string;\r\n x: number;\r\n width: number;\r\n fontSize: number;\r\n underline: boolean;\r\n strikethrough: boolean;\r\n}\r\n\r\ninterface LaidOutLine {\r\n y: number;\r\n width: number;\r\n fragments: LineFragment[];\r\n}\r\n\r\nexport function renderStyledRuns(\r\n ctx: CanvasRenderingContext2D,\r\n runs: StyledRun[],\r\n startX: number,\r\n startY: number,\r\n maxWidth: number,\r\n opts: { align?: 'left' | 'center' | 'right'; lineHeight?: number } = {},\r\n): void {\r\n const align = opts.align ?? 'left';\r\n const lhMul = opts.lineHeight ?? 1.3;\r\n ctx.textBaseline = 'top';\r\n\r\n // PASS 1 — lay runs out into lines (no drawing). Wrap behaviour mirrors the\r\n // original single-pass renderer exactly so wrap points are alignment-agnostic.\r\n const lines: LaidOutLine[] = [];\r\n let cursorX = startX;\r\n let lineY = startY;\r\n let lineHeight = 0;\r\n let fragments: LineFragment[] = [];\r\n\r\n const finalizeLine = (): void => {\r\n const last = fragments[fragments.length - 1];\r\n const width = last ? last.x + last.width : 0;\r\n lines.push({ y: lineY, width, fragments });\r\n };\r\n\r\n const breakLine = (runLineHeight: number): void => {\r\n finalizeLine();\r\n lineY += lineHeight;\r\n lineHeight = runLineHeight;\r\n fragments = [];\r\n cursorX = startX;\r\n };\r\n\r\n for (const run of runs) {\r\n const font = buildFontString(run);\r\n ctx.font = font;\r\n const runLineHeight = run.fontSize * lhMul;\r\n lineHeight = Math.max(lineHeight, runLineHeight);\r\n\r\n const words = run.text.split(/(\\n| )/);\r\n for (const word of words) {\r\n if (word === '\\n') {\r\n breakLine(runLineHeight);\r\n continue;\r\n }\r\n if (word === ' ') {\r\n const spaceWidth = ctx.measureText(' ').width;\r\n if (cursorX + spaceWidth > startX + maxWidth && cursorX > startX) {\r\n breakLine(runLineHeight);\r\n } else {\r\n cursorX += spaceWidth;\r\n }\r\n continue;\r\n }\r\n if (!word) continue;\r\n\r\n const metrics = ctx.measureText(word);\r\n if (cursorX + metrics.width > startX + maxWidth && cursorX > startX) {\r\n breakLine(runLineHeight);\r\n }\r\n\r\n fragments.push({\r\n text: word,\r\n font,\r\n x: cursorX - startX,\r\n width: metrics.width,\r\n fontSize: run.fontSize,\r\n underline: run.underline,\r\n strikethrough: run.strikethrough,\r\n });\r\n cursorX += metrics.width;\r\n }\r\n }\r\n finalizeLine();\r\n\r\n // PASS 2 — draw each line at its alignment offset. For align 'left' the\r\n // offset is 0, so the absolute x equals the original streaming cursorX.\r\n for (const line of lines) {\r\n const offset =\r\n align === 'center'\r\n ? (maxWidth - line.width) / 2\r\n : align === 'right'\r\n ? maxWidth - line.width\r\n : 0;\r\n for (const fragment of line.fragments) {\r\n ctx.font = fragment.font;\r\n const fx = startX + offset + fragment.x;\r\n ctx.fillText(fragment.text, fx, line.y);\r\n\r\n if (fragment.underline) {\r\n ctx.fillRect(fx, line.y + fragment.fontSize + 1, fragment.width, 1);\r\n }\r\n\r\n if (fragment.strikethrough) {\r\n ctx.fillRect(fx, line.y + fragment.fontSize * 0.55, fragment.width, 1);\r\n }\r\n }\r\n }\r\n}\r\n","import type { TextElement } from '../elements/types';\r\nimport { parseStyledRuns, renderStyledRuns } from './note-canvas-renderer';\r\n\r\nexport function renderTextOnCanvas(ctx: CanvasRenderingContext2D, text: TextElement): void {\r\n const pad = 2; // matches the DOM text padding\r\n ctx.save();\r\n ctx.fillStyle = text.color;\r\n const runs = parseStyledRuns(text.text ?? '', text.fontSize);\r\n renderStyledRuns(ctx, runs, text.position.x + pad, text.position.y + pad, text.size.w - pad * 2, {\r\n align: text.textAlign,\r\n lineHeight: 1.4,\r\n });\r\n ctx.restore();\r\n}\r\n","import type { HtmlElement } from '../elements/types';\n\nexport type HtmlExportRenderer = (\n element: HtmlElement,\n) => CanvasImageSource | null | Promise<CanvasImageSource | null>;\n\nexport type HtmlExportErrorReason =\n | 'unsupported'\n | 'timeout'\n | 'render'\n | 'encode'\n | 'missing-painter'\n | 'painter-threw'\n | 'degenerate-size';\n\nexport interface HtmlExportError {\n elementId: string;\n htmlType?: string;\n reason: HtmlExportErrorReason;\n cause?: unknown;\n}\n\nexport interface HtmlExportOptions {\n /** Converts an application-owned HTML embed into a ready canvas image source. */\n renderHtml?: HtmlExportRenderer;\n /** Maximum wait for each HTML renderer. Defaults to 10 seconds. */\n htmlTimeoutMs?: number;\n /** Called when an HTML embed cannot be rendered or encoded. The export continues. */\n onHtmlError?: (error: HtmlExportError) => void;\n}\n\nconst DEFAULT_HTML_TIMEOUT_MS = 10_000;\nconst TIMEOUT = Symbol('html-export-timeout');\n\nexport function validateHtmlExportOptions(options: HtmlExportOptions): number {\n const timeoutMs = options.htmlTimeoutMs ?? DEFAULT_HTML_TIMEOUT_MS;\n if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {\n throw new RangeError('htmlTimeoutMs must be a finite number greater than 0');\n }\n return timeoutMs;\n}\n\nexport async function renderHtmlElements(\n elements: HtmlElement[],\n options: HtmlExportOptions,\n): Promise<Map<string, CanvasImageSource>> {\n const timeoutMs = validateHtmlExportOptions(options);\n const sources = new Map<string, CanvasImageSource>();\n\n await Promise.all(\n elements.map(async (element) => {\n if (!options.renderHtml) {\n options.onHtmlError?.({\n elementId: element.id,\n htmlType: element.htmlType,\n reason: 'unsupported',\n });\n return;\n }\n\n let timer: ReturnType<typeof setTimeout> | undefined;\n try {\n const timeout = new Promise<typeof TIMEOUT>((resolve) => {\n timer = setTimeout(() => resolve(TIMEOUT), timeoutMs);\n });\n const result = await Promise.race([Promise.resolve(options.renderHtml(element)), timeout]);\n if (result === TIMEOUT) {\n options.onHtmlError?.({\n elementId: element.id,\n htmlType: element.htmlType,\n reason: 'timeout',\n });\n return;\n }\n if (!result) {\n options.onHtmlError?.({\n elementId: element.id,\n htmlType: element.htmlType,\n reason: 'render',\n });\n return;\n }\n sources.set(element.id, result);\n } catch (cause) {\n options.onHtmlError?.({\n elementId: element.id,\n htmlType: element.htmlType,\n reason: 'render',\n cause,\n });\n } finally {\n if (timer !== undefined) clearTimeout(timer);\n }\n }),\n );\n\n return sources;\n}\n","import type { CanvasElement, GridElement, HtmlElement } from '../elements/types';\nimport type { ElementStore } from '../elements/element-store';\nimport { ElementRenderer } from '../elements/element-renderer';\nimport { getArrowBounds } from '../elements/arrow-geometry';\nimport { getElementBounds } from '../elements/element-bounds';\nimport { renderSquareGrid, renderHexGrid } from '../elements/grid-renderer';\nimport { withRotation } from '../elements/rotate-canvas';\nimport { rotatedAABB } from '../core/geometry';\nimport type { LayerManager } from '../layers/layer-manager';\nimport { renderNoteOnCanvas } from './note-canvas-renderer';\nimport { renderTextOnCanvas } from './text-canvas-renderer';\nimport { renderHtmlElements, validateHtmlExportOptions } from './html-export';\nimport type { HtmlExportOptions } from './html-export';\nimport { resolveHtmlRouting, HtmlPainterMissingError } from './html-painter-registry';\nimport type { HtmlPainterRegistry } from './html-painter-registry';\nimport { paintHtmlElement } from './html-paint';\nimport type { HtmlPaintDiagnostic } from './html-paint-diagnostics';\n\nexport interface ExportImageOptions extends ExportResourceOptions, HtmlExportOptions {\n scale?: number;\n padding?: number;\n background?: string;\n filter?: (element: CanvasElement) => boolean;\n /**\n * Optional world-space crop. When set it replaces the computed content\n * bounds; `padding` still applies around it. Elements outside the region\n * clip naturally. A region export with no intersecting elements still\n * produces a background-filled image.\n */\n region?: { x: number; y: number; w: number; h: number };\n /**\n * Output encoding. Defaults to 'png'. JPEG output is opaque — a transparent\n * `background` renders as black; keep the default `#ffffff` (or any opaque color)\n * for JPEG exports.\n */\n format?: 'png' | 'jpeg';\n /** Encoder quality in (0, 1]. Only meaningful for 'jpeg'. */\n quality?: number;\n /**\n * 'exact' (default) throws when scale × bounds exceeds maxDimension/maxPixels.\n * 'fit' reduces the effective scale to the largest value that satisfies both\n * caps (never above the requested scale).\n */\n scaleMode?: 'exact' | 'fit';\n /** Registry of canvas-backed html painters, keyed by `htmlType`. When absent (or when\n * an element's `htmlType` isn't claimed), html elements fall back to the legacy\n * DOM-raster path (`renderHtml`). */\n htmlPainters?: HtmlPainterRegistry;\n /** `htmlType`s that must route to canvas even before a painter for them is\n * registered — lets a host declare intent up front (mirrors `HtmlPainterRegistry.expect`). */\n expectedCanvasTypes?: ReadonlySet<string>;\n /**\n * When true, a canvas-routed html element with no active painter throws\n * `HtmlPainterMissingError` instead of reporting `onHtmlError` and continuing.\n * DOM-routed html elements are never affected — a missing `renderHtml` stays\n * a non-fatal `'unsupported'` diagnostic regardless of this flag.\n */\n strictMissingCanvasHtml?: boolean;\n}\n\nexport type ExportAssetErrorReason = 'load' | 'timeout' | 'encode';\n\nexport interface ExportAssetError {\n elementId: string;\n src: string;\n reason: ExportAssetErrorReason;\n cause?: unknown;\n}\n\nexport interface ExportResourceOptions {\n /** Maximum wait for each image asset. Defaults to 10 seconds. */\n imageTimeoutMs?: number;\n /** Maximum width or height of any allocated export canvas. Defaults to 16,384. */\n maxDimension?: number;\n /** Maximum pixel count of any allocated export canvas. Defaults to 67,108,864. */\n maxPixels?: number;\n /** Called when an image cannot be loaded or embedded. The export continues. */\n onAssetError?: (error: ExportAssetError) => void;\n}\n\nconst DEFAULT_IMAGE_TIMEOUT_MS = 10_000;\nconst DEFAULT_MAX_DIMENSION = 16_384;\nconst DEFAULT_MAX_PIXELS = 67_108_864;\n\ninterface Rect {\n x: number;\n y: number;\n w: number;\n h: number;\n}\n\nconst center = (b: Rect): { x: number; y: number } => ({ x: b.x + b.w / 2, y: b.y + b.h / 2 });\n\nfunction getStrokeBounds(el: CanvasElement): Rect | null {\n if (el.type !== 'stroke') return null;\n if (el.points.length === 0) return null;\n\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n\n for (const p of el.points) {\n const px = el.position.x + p.x;\n const py = el.position.y + p.y;\n minX = Math.min(minX, px);\n minY = Math.min(minY, py);\n maxX = Math.max(maxX, px);\n maxY = Math.max(maxY, py);\n }\n\n const pad = el.width / 2;\n return {\n x: minX - pad,\n y: minY - pad,\n w: maxX - minX + el.width,\n h: maxY - minY + el.width,\n };\n}\n\nfunction getElementRect(el: CanvasElement): Rect | null {\n switch (el.type) {\n case 'stroke': {\n const r = getStrokeBounds(el);\n return r ? rotatedAABB(r, el.rotation ?? 0) : r;\n }\n case 'arrow': {\n const b = getArrowBounds(el.from, el.to, el.bend);\n const pad = el.width / 2 + 14;\n return { x: b.x - pad, y: b.y - pad, w: b.w + pad * 2, h: b.h + pad * 2 };\n }\n case 'grid':\n return null;\n case 'template': {\n const bounds = getElementBounds(el);\n if (!bounds) return null;\n return bounds;\n }\n case 'note':\n case 'image':\n case 'html':\n case 'text':\n case 'shape':\n if ('size' in el) {\n return rotatedAABB(\n { x: el.position.x, y: el.position.y, w: el.size.w, h: el.size.h },\n el.rotation ?? 0,\n );\n }\n return null;\n default:\n return null;\n }\n}\n\nfunction computeBounds(\n elements: CanvasElement[],\n padding: number,\n): { x: number; y: number; w: number; h: number } | null {\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n let found = false;\n\n for (const el of elements) {\n const rect = getElementRect(el);\n if (!rect) continue;\n found = true;\n minX = Math.min(minX, rect.x);\n minY = Math.min(minY, rect.y);\n maxX = Math.max(maxX, rect.x + rect.w);\n maxY = Math.max(maxY, rect.y + rect.h);\n }\n\n if (!found) return null;\n\n return {\n x: minX - padding,\n y: minY - padding,\n w: maxX - minX + padding * 2,\n h: maxY - minY + padding * 2,\n };\n}\n\nfunction resolveExportBounds(\n region: { x: number; y: number; w: number; h: number } | undefined,\n elements: CanvasElement[],\n padding: number,\n): Rect | null {\n if (!region) return computeBounds(elements, padding);\n const finite =\n Number.isFinite(region.x) &&\n Number.isFinite(region.y) &&\n Number.isFinite(region.w) &&\n Number.isFinite(region.h);\n if (!finite || region.w <= 0 || region.h <= 0) {\n throw new RangeError('region must have finite coordinates and positive w/h');\n }\n return {\n x: region.x - padding,\n y: region.y - padding,\n w: region.w + padding * 2,\n h: region.h + padding * 2,\n };\n}\n\nfunction renderGridForBounds(\n ctx: CanvasRenderingContext2D,\n grid: GridElement,\n bounds: { x: number; y: number; w: number; h: number },\n): void {\n const visibleBounds = {\n minX: bounds.x,\n minY: bounds.y,\n maxX: bounds.x + bounds.w,\n maxY: bounds.y + bounds.h,\n };\n\n if (grid.gridType === 'hex') {\n renderHexGrid(\n ctx,\n visibleBounds,\n grid.cellSize,\n grid.hexOrientation,\n grid.strokeColor,\n grid.strokeWidth,\n grid.opacity,\n );\n } else {\n renderSquareGrid(\n ctx,\n visibleBounds,\n grid.cellSize,\n grid.strokeColor,\n grid.strokeWidth,\n grid.opacity,\n );\n }\n}\n\nfunction positiveOption(value: number | undefined, fallback: number, name: string): number {\n const resolved = value ?? fallback;\n if (!Number.isFinite(resolved) || resolved <= 0) {\n throw new RangeError(`${name} must be a finite number greater than 0`);\n }\n return resolved;\n}\n\nfunction nonNegativeOption(value: number | undefined, fallback: number, name: string): number {\n const resolved = value ?? fallback;\n if (!Number.isFinite(resolved) || resolved < 0) {\n throw new RangeError(`${name} must be a finite number greater than or equal to 0`);\n }\n return resolved;\n}\n\nfunction fitExportScale(\n bounds: { w: number; h: number },\n requestedScale: number,\n options: Pick<ExportResourceOptions, 'maxDimension' | 'maxPixels'>,\n): number {\n const maxDimension = positiveOption(options.maxDimension, DEFAULT_MAX_DIMENSION, 'maxDimension');\n const maxPixels = positiveOption(options.maxPixels, DEFAULT_MAX_PIXELS, 'maxPixels');\n const fits = (scale: number): boolean => {\n const w = Math.ceil(bounds.w * scale);\n const h = Math.ceil(bounds.h * scale);\n return w <= maxDimension && h <= maxDimension && w * h <= maxPixels;\n };\n if (fits(requestedScale)) return requestedScale;\n // Every fitting scale satisfies w·s ≤ maxDimension and (w·s)(h·s) ≤ maxPixels\n // (ceil(x) ≤ n ⟹ x ≤ n), so the analytical candidate is a true upper bound —\n // this keeps the search interval tight even for astronomically large bounds.\n // ceil rounding makes the candidate itself unreliable, so binary-search the\n // narrow rounding-sensitive interval below it; the predicate is monotonic.\n // Divide by each sqrt separately: forming bounds.w * bounds.h first can\n // overflow to Infinity for large finite bounds, collapsing the candidate to 0.\n const analytical = Math.min(\n maxDimension / Math.max(bounds.w, bounds.h),\n Math.sqrt(maxPixels) / Math.sqrt(bounds.w) / Math.sqrt(bounds.h),\n );\n let hi = Math.min(requestedScale, analytical);\n if (fits(hi)) return hi;\n let lo = 0;\n for (let i = 0; i < 40; i++) {\n const mid = (lo + hi) / 2;\n if (fits(mid)) lo = mid;\n else hi = mid;\n }\n return lo;\n}\n\nfunction assertExportSize(\n width: number,\n height: number,\n options: Pick<ExportResourceOptions, 'maxDimension' | 'maxPixels'>,\n): void {\n const maxDimension = positiveOption(options.maxDimension, DEFAULT_MAX_DIMENSION, 'maxDimension');\n const maxPixels = positiveOption(options.maxPixels, DEFAULT_MAX_PIXELS, 'maxPixels');\n if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) {\n throw new RangeError('Export dimensions must be finite numbers greater than 0');\n }\n if (width > maxDimension || height > maxDimension) {\n throw new RangeError(\n `Export dimensions ${width}x${height} exceed the maximum dimension of ${maxDimension}`,\n );\n }\n if (width * height > maxPixels) {\n throw new RangeError(\n `Export size ${width}x${height} exceeds the maximum of ${maxPixels} pixels`,\n );\n }\n}\n\nfunction validateExportResourceOptions(options: ExportResourceOptions): void {\n positiveOption(options.imageTimeoutMs, DEFAULT_IMAGE_TIMEOUT_MS, 'imageTimeoutMs');\n positiveOption(options.maxDimension, DEFAULT_MAX_DIMENSION, 'maxDimension');\n positiveOption(options.maxPixels, DEFAULT_MAX_PIXELS, 'maxPixels');\n}\n\nfunction loadImages(\n elements: CanvasElement[],\n options: Pick<ExportResourceOptions, 'imageTimeoutMs' | 'onAssetError'> = {},\n): Promise<Map<string, HTMLImageElement>> {\n const imageElements = elements.filter(\n (el): el is CanvasElement & { src: string } => el.type === 'image' && 'src' in el,\n );\n\n const cache = new Map<string, HTMLImageElement>();\n if (imageElements.length === 0) return Promise.resolve(cache);\n\n const timeoutMs = positiveOption(\n options.imageTimeoutMs,\n DEFAULT_IMAGE_TIMEOUT_MS,\n 'imageTimeoutMs',\n );\n\n return new Promise((resolve) => {\n let remaining = imageElements.length;\n const done = () => {\n remaining--;\n if (remaining <= 0) resolve(cache);\n };\n\n for (const el of imageElements) {\n const img = new Image();\n img.crossOrigin = 'anonymous';\n let settled = false;\n const timer = setTimeout(() => {\n if (settled) return;\n settled = true;\n img.onload = null;\n img.onerror = null;\n options.onAssetError?.({ elementId: el.id, src: el.src, reason: 'timeout' });\n done();\n }, timeoutMs);\n const settle = (): boolean => {\n if (settled) return false;\n settled = true;\n clearTimeout(timer);\n img.onload = null;\n img.onerror = null;\n return true;\n };\n img.onload = () => {\n if (!settle()) return;\n cache.set(el.id, img);\n done();\n };\n img.onerror = (cause) => {\n if (!settle()) return;\n options.onAssetError?.({ elementId: el.id, src: el.src, reason: 'load', cause });\n done();\n };\n img.src = el.src;\n }\n });\n}\n\nexport async function exportImage(\n store: ElementStore,\n options: ExportImageOptions = {},\n layerManager?: LayerManager,\n): Promise<Blob | null> {\n const requestedScale = positiveOption(options.scale, 2, 'scale');\n const scaleMode = options.scaleMode ?? 'exact';\n if (scaleMode !== 'exact' && scaleMode !== 'fit') {\n throw new RangeError(`scaleMode must be 'exact' or 'fit'`);\n }\n const padding = nonNegativeOption(options.padding, 0, 'padding');\n validateExportResourceOptions(options);\n validateHtmlExportOptions(options);\n const format = options.format ?? 'png';\n if (format !== 'png' && format !== 'jpeg') {\n throw new RangeError(`format must be 'png' or 'jpeg'`);\n }\n if (options.quality !== undefined) {\n if (!Number.isFinite(options.quality) || options.quality <= 0 || options.quality > 1) {\n throw new RangeError('quality must be a finite number in (0, 1]');\n }\n }\n const background = options.background ?? '#ffffff';\n const filter = options.filter;\n\n const allElements = store.getAll();\n let visibleElements = layerManager\n ? allElements.filter((el) => layerManager.isLayerVisible(el.layerId))\n : allElements;\n\n if (filter) {\n visibleElements = visibleElements.filter(filter);\n }\n\n const bounds = resolveExportBounds(options.region, visibleElements, padding);\n if (!bounds) return null;\n\n const scale =\n scaleMode === 'fit' ? fitExportScale(bounds, requestedScale, options) : requestedScale;\n const width = Math.ceil(bounds.w * scale);\n const height = Math.ceil(bounds.h * scale);\n assertExportSize(width, height, options);\n const imageCache = await loadImages(visibleElements, options);\n const htmlElements = visibleElements.filter((el): el is HtmlElement => el.type === 'html');\n\n // Resolve routing per visible html element before doing any rendering work: canvas-routed\n // elements never reach the DOM-raster path (renderHtmlElements), and 'missing' is either\n // fatal (strictMissingCanvasHtml) or reported once here — it never falls back to DOM.\n const canvasRoutedIds = new Set<string>();\n const domHtmlElements: HtmlElement[] = [];\n for (const el of htmlElements) {\n const routing = resolveHtmlRouting(\n el,\n options.htmlPainters ?? null,\n options.expectedCanvasTypes,\n );\n if (routing === 'missing') {\n if (options.strictMissingCanvasHtml) {\n throw new HtmlPainterMissingError(el.id, el.htmlType);\n }\n options.onHtmlError?.({ elementId: el.id, htmlType: el.htmlType, reason: 'missing-painter' });\n continue;\n }\n if (routing === 'canvas') {\n canvasRoutedIds.add(el.id);\n } else {\n domHtmlElements.push(el);\n }\n }\n const htmlSources = await renderHtmlElements(domHtmlElements, options);\n\n const canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n\n const ctx = canvas.getContext('2d');\n if (!ctx) return null;\n\n ctx.scale(scale, scale);\n ctx.translate(-bounds.x, -bounds.y);\n\n ctx.fillStyle = background;\n ctx.fillRect(bounds.x, bounds.y, bounds.w, bounds.h);\n\n const renderer = new ElementRenderer();\n renderer.setStore(store);\n\n const onHtmlPaintDiagnostic = (d: HtmlPaintDiagnostic): void => {\n options.onHtmlError?.({\n elementId: d.elementId,\n htmlType: d.htmlType,\n reason: d.kind,\n cause: d.kind === 'painter-threw' ? d.error : undefined,\n });\n };\n\n const grids: GridElement[] = [];\n const renderElement = (target: CanvasRenderingContext2D, el: CanvasElement): void => {\n if (el.type === 'note') {\n const b = getElementBounds(el);\n withRotation(target, el, b ? center(b) : el.position, () => renderNoteOnCanvas(target, el));\n return;\n }\n\n if (el.type === 'text') {\n const b = getElementBounds(el);\n withRotation(target, el, b ? center(b) : el.position, () => renderTextOnCanvas(target, el));\n return;\n }\n\n if (el.type === 'html') {\n if (canvasRoutedIds.has(el.id)) {\n // paintHtmlElement rotates internally (applyRotation defaults to true), so this\n // must stay OUTSIDE withRotation — wrapping it too would double-rotate.\n const painter = options.htmlPainters?.getActivePainter(el.htmlType ?? '');\n if (!painter) {\n // Routing was resolved before `await renderHtmlElements(...)`; a painter\n // unregistered inside that window lands here. Reporting it keeps every dropped\n // element accounted for — a silent omission is the one outcome this exporter\n // never produces.\n options.onHtmlError?.({\n elementId: el.id,\n htmlType: el.htmlType,\n reason: 'missing-painter',\n });\n return;\n }\n paintHtmlElement(el, painter, {\n ctx: target,\n zoom: scale,\n target: 'export',\n onDiagnostic: onHtmlPaintDiagnostic,\n });\n return;\n }\n\n const source = htmlSources.get(el.id);\n if (!source) return;\n const b = getElementBounds(el);\n try {\n withRotation(target, el, b ? center(b) : el.position, () =>\n target.drawImage(source, el.position.x, el.position.y, el.size.w, el.size.h),\n );\n } catch (cause) {\n options.onHtmlError?.({\n elementId: el.id,\n htmlType: el.htmlType,\n reason: 'render',\n cause,\n });\n }\n return;\n }\n\n if (el.type === 'image') {\n const img = imageCache.get(el.id);\n if (img) {\n const b = getElementBounds(el);\n withRotation(target, el, b ? center(b) : el.position, () =>\n target.drawImage(img, el.position.x, el.position.y, el.size.w, el.size.h),\n );\n }\n return;\n }\n\n renderer.renderCanvasElement(target, el);\n };\n\n const layerGroups = new Map<string, CanvasElement[]>();\n for (const el of visibleElements) {\n if (el.type === 'grid') {\n grids.push(el);\n continue;\n }\n const group = layerGroups.get(el.layerId) ?? [];\n group.push(el);\n layerGroups.set(el.layerId, group);\n }\n\n for (const [layerId, elements] of layerGroups) {\n const opacity = layerManager?.getLayer?.(layerId)?.opacity ?? 1;\n if (opacity === 1) {\n for (const el of elements) renderElement(ctx, el);\n continue;\n }\n\n const layerCanvas = document.createElement('canvas');\n layerCanvas.width = canvas.width;\n layerCanvas.height = canvas.height;\n const layerCtx = layerCanvas.getContext('2d');\n if (!layerCtx) continue;\n layerCtx.scale(scale, scale);\n layerCtx.translate(-bounds.x, -bounds.y);\n for (const el of elements) renderElement(layerCtx, el);\n\n ctx.save();\n ctx.setTransform(1, 0, 0, 1, 0, 0);\n ctx.globalAlpha = opacity;\n ctx.drawImage(layerCanvas, 0, 0);\n ctx.restore();\n }\n\n for (const grid of grids) {\n ctx.save();\n ctx.globalAlpha = layerManager?.getLayer?.(grid.layerId)?.opacity ?? 1;\n renderGridForBounds(ctx, grid, bounds);\n ctx.restore();\n }\n\n const mimeType = format === 'jpeg' ? 'image/jpeg' : 'image/png';\n return new Promise((resolve) => {\n canvas.toBlob((blob) => resolve(blob), mimeType, options.quality);\n });\n}\n\nexport {\n assertExportSize,\n computeBounds,\n fitExportScale,\n getElementRect,\n loadImages,\n nonNegativeOption,\n positiveOption,\n validateExportResourceOptions,\n};\n","import type {\n CanvasElement,\n StrokeElement,\n ShapeElement,\n ArrowElement,\n ImageElement,\n TextElement,\n NoteElement,\n GridElement,\n TemplateElement,\n HtmlElement,\n} from '../elements/types';\nimport type { ElementStore } from '../elements/element-store';\nimport type { LayerManager } from '../layers/layer-manager';\nimport { getStrokeRenderData } from '../elements/stroke-cache';\nimport { lineEndpoints } from '../elements/shape-geometry';\nimport { getArrowControlPoint, getArrowMidpoint } from '../elements/arrow-geometry';\nimport { getArrowRenderGeometry } from '../elements/arrow-render-cache';\nimport { getVisualEndpoints, getArrowDashPattern } from '../elements/renderers/arrow-renderer';\nimport { getSquareGridLines, getHexVertices, getHexCenters } from '../elements/grid-renderer';\nimport {\n getHexCellsInRadius,\n getHexCellsInCone,\n getHexCellsInLine,\n getHexCellsInSquare,\n getHexCellsInRectangle,\n} from '../elements/hex-fill';\nimport { getElementBounds } from '../elements/element-bounds';\nimport { renderNoteOnCanvas } from './note-canvas-renderer';\nimport { renderTextOnCanvas } from './text-canvas-renderer';\nimport {\n assertExportSize,\n loadImages,\n computeBounds,\n nonNegativeOption,\n positiveOption,\n validateExportResourceOptions,\n} from './export-image';\nimport type { ExportResourceOptions } from './export-image';\nimport { renderHtmlElements, validateHtmlExportOptions } from './html-export';\nimport type { HtmlExportOptions } from './html-export';\nimport { resolveHtmlRouting, HtmlPainterMissingError } from './html-painter-registry';\nimport type { HtmlPainterRegistry } from './html-painter-registry';\nimport { paintHtmlElement } from './html-paint';\nimport type { HtmlPaintDiagnostic } from './html-paint-diagnostics';\n\nexport interface ExportSvgOptions extends ExportResourceOptions, HtmlExportOptions {\n padding?: number;\n background?: string;\n filter?: (el: CanvasElement) => boolean;\n rasterScale?: number;\n /** Registry of canvas-backed html painters, keyed by `htmlType`. When absent (or when\n * an element's `htmlType` isn't claimed), html elements fall back to the legacy\n * DOM-raster path (`renderHtml`). */\n htmlPainters?: HtmlPainterRegistry;\n /** `htmlType`s that must route to canvas even before a painter for them is\n * registered — lets a host declare intent up front (mirrors `HtmlPainterRegistry.expect`). */\n expectedCanvasTypes?: ReadonlySet<string>;\n /**\n * When true, a canvas-routed html element with no active painter throws\n * `HtmlPainterMissingError` instead of reporting `onHtmlError` and continuing.\n * DOM-routed html elements are never affected — a missing `renderHtml` stays\n * a non-fatal `'unsupported'` diagnostic regardless of this flag.\n */\n strictMissingCanvasHtml?: boolean;\n}\n\ninterface Bounds {\n x: number;\n y: number;\n w: number;\n h: number;\n}\n\nconst ARROWHEAD_LENGTH = 12;\nconst ARROWHEAD_ANGLE = Math.PI / 6;\nconst ARROW_LABEL_FONT_SIZE = 14;\n\nfunction esc(s: string): string {\n return s\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#39;');\n}\n\nconst n = (v: number): string => (Number.isFinite(v) ? `${Math.round(v * 1000) / 1000}` : '0');\n\nfunction elementCenter(el: CanvasElement): { x: number; y: number } | null {\n const b = getElementBounds(el);\n if (!b) return null;\n return { x: b.x + b.w / 2, y: b.y + b.h / 2 };\n}\n\n/** Wrap a fragment in a rotation group matching withRotation (radians → degrees). */\nfunction withRotationSvg(el: CanvasElement, fragment: string): string {\n const angle = el.rotation ?? 0;\n if (!angle || !fragment) return fragment;\n const c = elementCenter(el);\n if (!c) return fragment;\n const deg = (angle * 180) / Math.PI;\n return `<g transform=\"rotate(${n(deg)} ${n(c.x)} ${n(c.y)})\">${fragment}</g>`;\n}\n\n// Strokes use variable per-point width on the canvas; SVG <path> takes a single\n// stroke-width, so we mirror the canvas width-bucketing: segments are grouped by\n// quantized width and each bucket becomes one <path> of bezier sub-paths. This\n// reproduces the canvas geometry exactly. We rebuild buckets from segments+widths\n// (always populated) rather than the Path2D buckets, which are absent under jsdom.\nconst WIDTH_QUANTUM = 0.25;\n\nfunction emitStroke(stroke: StrokeElement): string {\n if (stroke.points.length < 2) return '';\n const data = getStrokeRenderData(stroke);\n const { x: ox, y: oy } = stroke.position;\n\n const byWidth = new Map<number, string[]>();\n for (let i = 0; i < data.segments.length; i++) {\n const seg = data.segments[i];\n const w = data.widths[i];\n if (!seg || w === undefined) continue;\n const q = Math.max(WIDTH_QUANTUM, Math.round(w / WIDTH_QUANTUM) * WIDTH_QUANTUM);\n let parts = byWidth.get(q);\n if (!parts) {\n parts = [];\n byWidth.set(q, parts);\n }\n parts.push(\n `M${n(ox + seg.start.x)} ${n(oy + seg.start.y)} C${n(ox + seg.cp1.x)} ${n(oy + seg.cp1.y)} ${n(ox + seg.cp2.x)} ${n(oy + seg.cp2.y)} ${n(ox + seg.end.x)} ${n(oy + seg.end.y)}`,\n );\n }\n\n const blend = stroke.blendMode === 'multiply' ? ' style=\"mix-blend-mode:multiply\"' : '';\n let out = '';\n for (const [width, parts] of byWidth) {\n out += `<path d=\"${parts.join(' ')}\" fill=\"none\" stroke=\"${esc(stroke.color)}\" stroke-width=\"${n(width)}\" stroke-linecap=\"round\" stroke-linejoin=\"round\" opacity=\"${n(stroke.opacity)}\"${blend} />`;\n }\n return out;\n}\n\nfunction emitShape(shape: ShapeElement): string {\n const { x, y } = shape.position;\n const { w, h } = shape.size;\n const fill = shape.fillColor !== 'none' && shape.shape !== 'line' ? esc(shape.fillColor) : 'none';\n const stroke = shape.strokeWidth > 0 ? esc(shape.strokeColor) : 'none';\n const sw = shape.strokeWidth > 0 ? ` stroke-width=\"${n(shape.strokeWidth)}\"` : '';\n\n switch (shape.shape) {\n case 'rectangle':\n return `<rect x=\"${n(x)}\" y=\"${n(y)}\" width=\"${n(w)}\" height=\"${n(h)}\" fill=\"${fill}\" stroke=\"${stroke}\"${sw} />`;\n case 'ellipse':\n return `<ellipse cx=\"${n(x + w / 2)}\" cy=\"${n(y + h / 2)}\" rx=\"${n(w / 2)}\" ry=\"${n(h / 2)}\" fill=\"${fill}\" stroke=\"${stroke}\"${sw} />`;\n case 'line': {\n const [a, b] = lineEndpoints(shape);\n return `<line x1=\"${n(a.x)}\" y1=\"${n(a.y)}\" x2=\"${n(b.x)}\" y2=\"${n(b.y)}\" stroke=\"${stroke}\"${sw} stroke-linecap=\"round\" />`;\n }\n }\n}\n\nfunction emitArrow(arrow: ArrowElement, store: ElementStore): string {\n const geometry = getArrowRenderGeometry(arrow);\n // Bound arrows store from/to at the bound element's CENTER; the canvas renderer\n // snaps them to the element EDGE at draw time. Mirror that for PNG/canvas parity.\n const { visualFrom: from, visualTo: to } = getVisualEndpoints(arrow, geometry, store);\n\n let d: string;\n if (arrow.bend !== 0) {\n const cp = geometry.controlPoint ?? getArrowControlPoint(from, to, arrow.bend);\n d = `M${n(from.x)} ${n(from.y)} Q${n(cp.x)} ${n(cp.y)} ${n(to.x)} ${n(to.y)}`;\n } else {\n d = `M${n(from.x)} ${n(from.y)} L${n(to.x)} ${n(to.y)}`;\n }\n\n const pattern = getArrowDashPattern(arrow.strokeStyle);\n const dash = pattern.length > 0 ? ` stroke-dasharray=\"${pattern.join(' ')}\"` : '';\n let out = `<path d=\"${d}\" fill=\"none\" stroke=\"${esc(arrow.color)}\" stroke-width=\"${n(arrow.width)}\" stroke-linecap=\"round\"${dash} />`;\n\n // Arrowhead — mirror arrow-renderer's polygon math (tip at the visual endpoint).\n const angle = geometry.tangentEnd;\n const p1x = to.x - ARROWHEAD_LENGTH * Math.cos(angle - ARROWHEAD_ANGLE);\n const p1y = to.y - ARROWHEAD_LENGTH * Math.sin(angle - ARROWHEAD_ANGLE);\n const p2x = to.x - ARROWHEAD_LENGTH * Math.cos(angle + ARROWHEAD_ANGLE);\n const p2y = to.y - ARROWHEAD_LENGTH * Math.sin(angle + ARROWHEAD_ANGLE);\n out += `<polygon points=\"${n(to.x)},${n(to.y)} ${n(p1x)},${n(p1y)} ${n(p2x)},${n(p2y)}\" fill=\"${esc(arrow.color)}\" />`;\n\n if (arrow.label && arrow.label.length > 0) {\n // Canvas renderer places the label at the raw-endpoint midpoint, not the visual one.\n const mid = getArrowMidpoint(arrow.from, arrow.to, arrow.bend);\n const approxW = arrow.label.length * ARROW_LABEL_FONT_SIZE * 0.6;\n const padX = 6;\n const padY = 4;\n const lw = approxW + padX * 2;\n const lh = ARROW_LABEL_FONT_SIZE + padY * 2;\n out += `<rect x=\"${n(mid.x - lw / 2)}\" y=\"${n(mid.y - lh / 2)}\" width=\"${n(lw)}\" height=\"${n(lh)}\" rx=\"4\" fill=\"rgba(255,255,255,0.9)\" />`;\n out += `<text x=\"${n(mid.x)}\" y=\"${n(mid.y)}\" font-family=\"system-ui, sans-serif\" font-size=\"${ARROW_LABEL_FONT_SIZE}\" fill=\"#1a1a1a\" text-anchor=\"middle\" dominant-baseline=\"central\">${esc(arrow.label)}</text>`;\n }\n\n return out;\n}\n\nfunction emitImage(image: ImageElement | HtmlElement, dataUri: string | undefined): string {\n const href = dataUri ?? ('src' in image ? image.src : '');\n if (!href) return '';\n const { x, y } = image.position;\n const { w, h } = image.size;\n return `<image href=\"${esc(href)}\" x=\"${n(x)}\" y=\"${n(y)}\" width=\"${n(w)}\" height=\"${n(h)}\" />`;\n}\n\nfunction emitText(\n text: TextElement,\n rasterScale: number,\n resourceOptions: ExportResourceOptions,\n): string {\n if (!text.text) return '';\n const { x, y } = text.position;\n const { w, h } = text.size;\n if (typeof document === 'undefined') return '';\n\n const width = Math.max(1, Math.ceil(w * rasterScale));\n const height = Math.max(1, Math.ceil(h * rasterScale));\n assertExportSize(width, height, resourceOptions);\n const canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n const ctx = canvas.getContext('2d');\n if (!ctx) return '';\n\n ctx.scale(rasterScale, rasterScale);\n ctx.translate(-x, -y);\n renderTextOnCanvas(ctx, text);\n\n let dataUri: string;\n try {\n dataUri = canvas.toDataURL();\n } catch {\n return '';\n }\n if (!dataUri || !dataUri.startsWith('data:')) return '';\n\n return `<image href=\"${esc(dataUri)}\" x=\"${n(x)}\" y=\"${n(y)}\" width=\"${n(w)}\" height=\"${n(h)}\" />`;\n}\n\nfunction emitNote(\n note: NoteElement,\n rasterScale: number,\n resourceOptions: ExportResourceOptions,\n): string {\n const { x, y } = note.position;\n const { w, h } = note.size;\n if (typeof document === 'undefined') return emitNotePlaceholder(note);\n\n const width = Math.max(1, Math.ceil(w * rasterScale));\n const height = Math.max(1, Math.ceil(h * rasterScale));\n assertExportSize(width, height, resourceOptions);\n const canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n const ctx = canvas.getContext('2d');\n if (!ctx) return emitNotePlaceholder(note);\n\n ctx.scale(rasterScale, rasterScale);\n ctx.translate(-x, -y);\n renderNoteOnCanvas(ctx, note);\n\n let dataUri: string;\n try {\n dataUri = canvas.toDataURL();\n } catch {\n return emitNotePlaceholder(note);\n }\n if (!dataUri || !dataUri.startsWith('data:')) return emitNotePlaceholder(note);\n\n return `<image href=\"${esc(dataUri)}\" x=\"${n(x)}\" y=\"${n(y)}\" width=\"${n(w)}\" height=\"${n(h)}\" />`;\n}\n\nfunction emitNotePlaceholder(note: NoteElement): string {\n const { x, y } = note.position;\n const { w, h } = note.size;\n return `<rect x=\"${n(x)}\" y=\"${n(y)}\" width=\"${n(w)}\" height=\"${n(h)}\" rx=\"4\" fill=\"${esc(note.backgroundColor)}\" />`;\n}\n\nfunction emitGrid(grid: GridElement, bounds: Bounds): string {\n if (grid.cellSize <= 0) return '';\n const vb = {\n minX: bounds.x,\n minY: bounds.y,\n maxX: bounds.x + bounds.w,\n maxY: bounds.y + bounds.h,\n };\n const stroke = esc(grid.strokeColor);\n const sw = n(grid.strokeWidth);\n const op = n(grid.opacity);\n\n if (grid.gridType === 'hex') {\n const centers = getHexCenters(vb, grid.cellSize, grid.hexOrientation);\n let d = '';\n for (const c of centers) {\n const verts = getHexVertices(c.x, c.y, grid.cellSize, grid.hexOrientation);\n const first = verts[0];\n if (!first) continue;\n d += `M${n(first.x)} ${n(first.y)}`;\n for (let i = 1; i < verts.length; i++) {\n const v = verts[i];\n if (v) d += `L${n(v.x)} ${n(v.y)}`;\n }\n d += 'Z';\n }\n return `<path d=\"${d}\" fill=\"none\" stroke=\"${stroke}\" stroke-width=\"${sw}\" opacity=\"${op}\" />`;\n }\n\n const { verticals, horizontals } = getSquareGridLines(vb, grid.cellSize);\n let d = '';\n for (const gx of verticals) d += `M${n(gx)} ${n(vb.minY)}L${n(gx)} ${n(vb.maxY)}`;\n for (const gy of horizontals) d += `M${n(vb.minX)} ${n(gy)}L${n(vb.maxX)} ${n(gy)}`;\n return `<path d=\"${d}\" fill=\"none\" stroke=\"${stroke}\" stroke-width=\"${sw}\" opacity=\"${op}\" />`;\n}\n\n// Geometric template only (square-grid context). Hex-grid templates fill snapped\n// hex cells; we approximate by emitting the cell hex outlines.\nfunction emitTemplate(template: TemplateElement, grid: GridElement | undefined): string {\n if (grid && grid.gridType === 'hex') {\n return emitHexTemplate(template, grid);\n }\n return emitGeometricTemplate(template);\n}\n\nfunction emitGeometricTemplate(t: TemplateElement): string {\n const { x: cx, y: cy } = t.position;\n const r = t.radius;\n const fill = esc(t.fillColor);\n const stroke = esc(t.strokeColor);\n const sw = n(t.strokeWidth);\n const op = n(t.opacity);\n const attrs = `fill=\"${fill}\" stroke=\"${stroke}\" stroke-width=\"${sw}\" opacity=\"${op}\"`;\n\n switch (t.templateShape) {\n case 'circle':\n return `<circle cx=\"${n(cx)}\" cy=\"${n(cy)}\" r=\"${n(r)}\" ${attrs} />`;\n case 'square':\n return `<rect x=\"${n(cx - r / 2)}\" y=\"${n(cy - r / 2)}\" width=\"${n(r)}\" height=\"${n(r)}\" ${attrs} />`;\n case 'cone': {\n const halfAngle = Math.atan(0.5);\n const a0 = t.angle - halfAngle;\n const a1 = t.angle + halfAngle;\n const p0x = cx + r * Math.cos(a0);\n const p0y = cy + r * Math.sin(a0);\n const p1x = cx + r * Math.cos(a1);\n const p1y = cy + r * Math.sin(a1);\n const large = a1 - a0 > Math.PI ? 1 : 0;\n return `<path d=\"M${n(cx)} ${n(cy)} L${n(p0x)} ${n(p0y)} A${n(r)} ${n(r)} 0 ${large} 1 ${n(p1x)} ${n(p1y)} Z\" ${attrs} />`;\n }\n case 'line': {\n const halfW = r / 12;\n const cos = Math.cos(t.angle);\n const sin = Math.sin(t.angle);\n const perpX = -sin * halfW;\n const perpY = cos * halfW;\n const pts = [\n [cx + perpX, cy + perpY],\n [cx + r * cos + perpX, cy + r * sin + perpY],\n [cx + r * cos - perpX, cy + r * sin - perpY],\n [cx - perpX, cy - perpY],\n ]\n .map(([px, py]) => `${n(px ?? 0)},${n(py ?? 0)}`)\n .join(' ');\n return `<polygon points=\"${pts}\" ${attrs} />`;\n }\n case 'rectangle': {\n const halfW = (t.width ?? 0) / 2;\n const cos = Math.cos(t.angle);\n const sin = Math.sin(t.angle);\n const perpX = -sin * halfW;\n const perpY = cos * halfW;\n const pts = [\n [cx + perpX, cy + perpY],\n [cx + r * cos + perpX, cy + r * sin + perpY],\n [cx + r * cos - perpX, cy + r * sin - perpY],\n [cx - perpX, cy - perpY],\n ]\n .map(([px, py]) => `${n(px ?? 0)},${n(py ?? 0)}`)\n .join(' ');\n return `<polygon points=\"${pts}\" ${attrs} />`;\n }\n }\n}\n\nfunction emitHexTemplate(t: TemplateElement, grid: GridElement): string {\n const cellSize = grid.cellSize;\n const orientation = grid.hexOrientation;\n const snapUnit = Math.sqrt(3) * cellSize;\n const radiusCells = t.radius / snapUnit;\n const center = t.position;\n\n let cells: { x: number; y: number }[];\n switch (t.templateShape) {\n case 'circle':\n cells = getHexCellsInRadius(center, radiusCells, cellSize, orientation);\n break;\n case 'cone':\n cells = getHexCellsInCone(center, t.angle, radiusCells, cellSize, orientation);\n break;\n case 'line':\n cells = getHexCellsInLine(center, t.angle, radiusCells, cellSize, orientation);\n break;\n case 'square':\n cells = getHexCellsInSquare(center, radiusCells, cellSize, orientation);\n break;\n case 'rectangle': {\n const widthCells = (t.width ?? 0) / snapUnit;\n cells = getHexCellsInRectangle(\n center,\n t.angle,\n radiusCells,\n widthCells,\n cellSize,\n orientation,\n );\n break;\n }\n }\n\n let d = '';\n for (const cell of cells) {\n const verts = getHexVertices(cell.x, cell.y, cellSize, orientation);\n const first = verts[0];\n if (!first) continue;\n d += `M${n(first.x)} ${n(first.y)}`;\n for (let i = 1; i < verts.length; i++) {\n const v = verts[i];\n if (v) d += `L${n(v.x)} ${n(v.y)}`;\n }\n d += 'Z';\n }\n return `<path d=\"${d}\" fill=\"${esc(t.fillColor)}\" stroke=\"${esc(t.strokeColor)}\" stroke-width=\"${n(t.strokeWidth)}\" opacity=\"${n(t.opacity)}\" />`;\n}\n\nexport async function exportSvg(\n store: ElementStore,\n options: ExportSvgOptions = {},\n layerManager?: LayerManager,\n): Promise<string> {\n const padding = nonNegativeOption(options.padding, 0, 'padding');\n const rasterScale = positiveOption(options.rasterScale, 2, 'rasterScale');\n validateExportResourceOptions(options);\n validateHtmlExportOptions(options);\n const filter = options.filter;\n\n const allElements = store.getAll();\n let visibleElements = layerManager\n ? allElements.filter((el) => layerManager.isLayerVisible(el.layerId))\n : allElements;\n if (filter) visibleElements = visibleElements.filter(filter);\n\n const bounds = computeBounds(visibleElements, padding);\n if (!bounds) {\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"0\" height=\"0\" viewBox=\"0 0 0 0\"></svg>`;\n }\n assertExportSize(Math.ceil(bounds.w), Math.ceil(bounds.h), options);\n\n // Only remote/blob image srcs need network loading; data: srcs pass through.\n const remoteImages = visibleElements.filter(\n (el) => el.type === 'image' && !el.src.startsWith('data:'),\n );\n const imageCache = await loadImages(remoteImages, options);\n const imageDataUris = encodeImages(visibleElements, imageCache, rasterScale, options);\n const htmlElements = visibleElements.filter((el): el is HtmlElement => el.type === 'html');\n\n // Resolve routing per visible html element before doing any rendering work: canvas-routed\n // elements never reach the DOM-raster path (renderHtmlElements), and 'missing' is either\n // fatal (strictMissingCanvasHtml) or reported once here — it never falls back to DOM.\n const canvasRoutedElements: HtmlElement[] = [];\n const domHtmlElements: HtmlElement[] = [];\n for (const el of htmlElements) {\n const routing = resolveHtmlRouting(\n el,\n options.htmlPainters ?? null,\n options.expectedCanvasTypes,\n );\n if (routing === 'missing') {\n if (options.strictMissingCanvasHtml) {\n throw new HtmlPainterMissingError(el.id, el.htmlType);\n }\n options.onHtmlError?.({ elementId: el.id, htmlType: el.htmlType, reason: 'missing-painter' });\n continue;\n }\n if (routing === 'canvas') {\n canvasRoutedElements.push(el);\n } else {\n domHtmlElements.push(el);\n }\n }\n const htmlSources = await renderHtmlElements(domHtmlElements, options);\n const htmlDataUris = encodeHtmlElements(domHtmlElements, htmlSources, rasterScale, options);\n const canvasHtmlDataUris = rasterizeCanvasRoutedHtml(\n canvasRoutedElements,\n options.htmlPainters,\n rasterScale,\n options,\n );\n for (const [id, uri] of canvasHtmlDataUris) htmlDataUris.set(id, uri);\n\n const grids = visibleElements.filter((el): el is GridElement => el.type === 'grid');\n const firstGrid = grids[0];\n\n let body = '';\n if (options.background) {\n body += `<rect x=\"${n(bounds.x)}\" y=\"${n(bounds.y)}\" width=\"${n(bounds.w)}\" height=\"${n(bounds.h)}\" fill=\"${esc(options.background)}\" />`;\n }\n\n const layerBodies = new Map<string, string>();\n for (const el of visibleElements) {\n const emitted = emitElement(\n el,\n imageDataUris,\n htmlDataUris,\n rasterScale,\n firstGrid,\n store,\n options,\n );\n layerBodies.set(el.layerId, (layerBodies.get(el.layerId) ?? '') + emitted);\n }\n for (const [layerId, emitted] of layerBodies) {\n const opacity = layerManager?.getLayer?.(layerId)?.opacity ?? 1;\n body += opacity === 1 || emitted === '' ? emitted : `<g opacity=\"${n(opacity)}\">${emitted}</g>`;\n }\n for (const grid of grids) {\n const emitted = emitGrid(grid, bounds);\n const opacity = layerManager?.getLayer?.(grid.layerId)?.opacity ?? 1;\n body += opacity === 1 ? emitted : `<g opacity=\"${n(opacity)}\">${emitted}</g>`;\n }\n\n return (\n `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${n(bounds.w)}\" height=\"${n(bounds.h)}\" ` +\n `viewBox=\"${n(bounds.x)} ${n(bounds.y)} ${n(bounds.w)} ${n(bounds.h)}\">${body}</svg>`\n );\n}\n\nfunction emitElement(\n el: CanvasElement,\n imageDataUris: Map<string, string>,\n htmlDataUris: Map<string, string>,\n rasterScale: number,\n firstGrid: GridElement | undefined,\n store: ElementStore,\n resourceOptions: ExportResourceOptions,\n): string {\n switch (el.type) {\n case 'stroke':\n return withRotationSvg(el, emitStroke(el));\n case 'shape':\n return withRotationSvg(el, emitShape(el));\n case 'arrow':\n return emitArrow(el, store);\n case 'image':\n return withRotationSvg(el, emitImage(el, imageDataUris.get(el.id)));\n case 'text':\n return withRotationSvg(el, emitText(el, rasterScale, resourceOptions));\n case 'note':\n return withRotationSvg(el, emitNote(el, rasterScale, resourceOptions));\n case 'template':\n return emitTemplate(el, firstGrid);\n case 'grid':\n return '';\n case 'html':\n return withRotationSvg(el, emitImage(el, htmlDataUris.get(el.id)));\n default:\n return '';\n }\n}\n\n/**\n * Rasterizes canvas-routed html elements through the shared `paintHtmlElement` path into\n * their own offscreen canvas, one per element, sized to the element's own w×h (not the\n * export bounds). `emitElement`'s 'html' case then places the resulting data-URI in an\n * `<image>` unchanged, identical to the DOM-raster path.\n */\nfunction rasterizeCanvasRoutedHtml(\n elements: HtmlElement[],\n registry: HtmlPainterRegistry | undefined,\n rasterScale: number,\n options: ExportSvgOptions,\n): Map<string, string> {\n const encoded = new Map<string, string>();\n const onDiagnostic = (d: HtmlPaintDiagnostic): void => {\n options.onHtmlError?.({\n elementId: d.elementId,\n htmlType: d.htmlType,\n reason: d.kind,\n cause: d.kind === 'painter-threw' ? d.error : undefined,\n });\n };\n\n for (const element of elements) {\n const painter = registry?.getActivePainter(element.htmlType ?? '');\n if (!painter) {\n // Routing was resolved before `await renderHtmlElements(...)`; a painter unregistered\n // inside that window lands here. Reporting it keeps every dropped element accounted\n // for — a silent omission is the one outcome this exporter never produces.\n options.onHtmlError?.({\n elementId: element.id,\n htmlType: element.htmlType,\n reason: 'missing-painter',\n });\n continue;\n }\n if (typeof document === 'undefined') {\n options.onHtmlError?.({\n elementId: element.id,\n htmlType: element.htmlType,\n reason: 'encode',\n });\n continue;\n }\n const width = Math.max(1, Math.ceil(element.size.w * rasterScale));\n const height = Math.max(1, Math.ceil(element.size.h * rasterScale));\n assertExportSize(width, height, options);\n const off = document.createElement('canvas');\n off.width = width;\n off.height = height;\n const octx = off.getContext('2d');\n if (!octx) {\n options.onHtmlError?.({\n elementId: element.id,\n htmlType: element.htmlType,\n reason: 'encode',\n });\n continue;\n }\n octx.scale(rasterScale, rasterScale);\n // LOCALIZING TRANSFORM — paintHtmlElement translates by the element's WORLD position,\n // but this offscreen canvas is sized to only the element's own w×h. Without cancelling\n // the world offset here first, the paint lands outside the canvas and the raster comes\n // out fully transparent.\n octx.translate(-element.position.x, -element.position.y);\n paintHtmlElement(element, painter, {\n ctx: octx,\n zoom: rasterScale,\n target: 'export',\n applyRotation: false, // withRotationSvg wraps the emitted <image>; rotating here too would double it\n onDiagnostic,\n });\n try {\n const dataUri = off.toDataURL('image/png');\n if (dataUri.startsWith('data:')) {\n encoded.set(element.id, dataUri);\n } else {\n options.onHtmlError?.({\n elementId: element.id,\n htmlType: element.htmlType,\n reason: 'encode',\n });\n }\n } catch (cause) {\n options.onHtmlError?.({\n elementId: element.id,\n htmlType: element.htmlType,\n reason: 'encode',\n cause,\n });\n }\n }\n return encoded;\n}\n\nfunction encodeHtmlElements(\n elements: HtmlElement[],\n sources: Map<string, CanvasImageSource>,\n rasterScale: number,\n options: ExportSvgOptions,\n): Map<string, string> {\n const encoded = new Map<string, string>();\n for (const element of elements) {\n const source = sources.get(element.id);\n if (!source) continue;\n const width = Math.max(1, Math.ceil(element.size.w * rasterScale));\n const height = Math.max(1, Math.ceil(element.size.h * rasterScale));\n assertExportSize(width, height, options);\n if (typeof document === 'undefined') {\n options.onHtmlError?.({\n elementId: element.id,\n htmlType: element.htmlType,\n reason: 'encode',\n });\n continue;\n }\n const canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n const ctx = canvas.getContext('2d');\n if (!ctx) {\n options.onHtmlError?.({\n elementId: element.id,\n htmlType: element.htmlType,\n reason: 'encode',\n });\n continue;\n }\n try {\n ctx.drawImage(source, 0, 0, width, height);\n const dataUri = canvas.toDataURL();\n if (dataUri.startsWith('data:')) {\n encoded.set(element.id, dataUri);\n } else {\n options.onHtmlError?.({\n elementId: element.id,\n htmlType: element.htmlType,\n reason: 'encode',\n });\n }\n } catch (cause) {\n options.onHtmlError?.({\n elementId: element.id,\n htmlType: element.htmlType,\n reason: 'encode',\n cause,\n });\n }\n }\n return encoded;\n}\n\n/** data: srcs pass through; remote/blob srcs are rasterized to data-URIs via the loaded image. */\nfunction encodeImages(\n elements: CanvasElement[],\n imageCache: Map<string, HTMLImageElement>,\n rasterScale: number,\n resourceOptions: ExportResourceOptions,\n): Map<string, string> {\n const out = new Map<string, string>();\n for (const el of elements) {\n if (el.type !== 'image') continue;\n if (el.src.startsWith('data:')) {\n out.set(el.id, el.src);\n continue;\n }\n const img = imageCache.get(el.id);\n if (!img || typeof document === 'undefined') continue;\n const width = Math.max(1, Math.ceil(el.size.w * rasterScale));\n const height = Math.max(1, Math.ceil(el.size.h * rasterScale));\n assertExportSize(width, height, resourceOptions);\n const canvas = document.createElement('canvas');\n canvas.width = width;\n canvas.height = height;\n const ctx = canvas.getContext('2d');\n if (!ctx) {\n resourceOptions.onAssetError?.({ elementId: el.id, src: el.src, reason: 'encode' });\n continue;\n }\n try {\n ctx.drawImage(img, 0, 0, canvas.width, canvas.height);\n const uri = canvas.toDataURL();\n if (uri.startsWith('data:')) out.set(el.id, uri);\n else resourceOptions.onAssetError?.({ elementId: el.id, src: el.src, reason: 'encode' });\n } catch (cause) {\n resourceOptions.onAssetError?.({ elementId: el.id, src: el.src, reason: 'encode', cause });\n }\n }\n return out;\n}\n","import { EventBus } from '../core/event-bus';\r\nimport type { ElementStore } from '../elements/element-store';\r\nimport type { Layer } from './types';\r\nimport { createId } from '../elements/create-id';\r\n\r\ninterface LayerManagerEvents {\r\n change: null;\r\n create: Layer;\r\n remove: Layer;\r\n update: { previous: Layer; current: Layer };\r\n}\r\n\r\nexport class LayerManager {\r\n private layers = new Map<string, Layer>();\r\n private _activeLayerId: string;\r\n private bus = new EventBus<LayerManagerEvents>();\r\n\r\n constructor(private readonly store: ElementStore) {\r\n const defaultLayer: Layer = {\r\n id: createId('layer'),\r\n name: 'Layer 1',\r\n visible: true,\r\n locked: false,\r\n order: 0,\r\n opacity: 1.0,\r\n };\r\n this.layers.set(defaultLayer.id, defaultLayer);\r\n this._activeLayerId = defaultLayer.id;\r\n this.syncLayerOrder();\r\n }\r\n\r\n get activeLayer(): Layer {\r\n const layer = this.layers.get(this._activeLayerId);\r\n if (!layer) throw new Error('Active layer not found');\r\n return { ...layer };\r\n }\r\n\r\n get activeLayerId(): string {\r\n return this._activeLayerId;\r\n }\r\n\r\n getLayers(): Layer[] {\r\n return [...this.layers.values()].sort((a, b) => a.order - b.order).map((l) => ({ ...l }));\r\n }\r\n\r\n getLayer(id: string): Layer | undefined {\r\n const layer = this.layers.get(id);\r\n return layer ? { ...layer } : undefined;\r\n }\r\n\r\n isLayerVisible(id: string): boolean {\r\n return this.layers.get(id)?.visible ?? true;\r\n }\r\n\r\n isLayerLocked(id: string): boolean {\r\n return this.layers.get(id)?.locked ?? false;\r\n }\r\n\r\n createLayer(name?: string): Layer {\r\n const maxOrder = Math.max(...[...this.layers.values()].map((l) => l.order), -1);\r\n const autoName = name ?? `Layer ${this.layers.size + 1}`;\r\n const layer: Layer = {\r\n id: createId('layer'),\r\n name: autoName,\r\n visible: true,\r\n locked: false,\r\n order: maxOrder + 1,\r\n opacity: 1.0,\r\n };\r\n this.addLayerDirect(layer);\r\n return { ...layer };\r\n }\r\n\r\n removeLayer(id: string): void {\r\n if (this.layers.size <= 1) {\r\n throw new Error('Cannot remove the last layer');\r\n }\r\n if (this._activeLayerId === id) {\r\n const remaining = [...this.layers.values()]\r\n .filter((l) => l.id !== id)\r\n .sort((a, b) => b.order - a.order);\r\n const fallback = remaining[0];\r\n if (fallback) this._activeLayerId = fallback.id;\r\n }\r\n const elements = this.store.getAll().filter((el) => el.layerId === id);\r\n for (const el of elements) {\r\n this.store.update(el.id, { layerId: this._activeLayerId });\r\n }\r\n this.removeLayerDirect(id);\r\n }\r\n\r\n renameLayer(id: string, name: string): void {\r\n this.updateLayerDirect(id, { name });\r\n }\r\n\r\n reorderLayer(id: string, newOrder: number): void {\r\n if (!this.layers.has(id)) return;\r\n this.updateLayerDirect(id, { order: newOrder });\r\n }\r\n\r\n setLayerVisible(id: string, visible: boolean): boolean {\r\n if (!visible && id === this._activeLayerId) {\r\n const fallback = this.findFallbackLayer(id);\r\n if (!fallback) return false;\r\n this._activeLayerId = fallback.id;\r\n }\r\n this.updateLayerDirect(id, { visible });\r\n return true;\r\n }\r\n\r\n setLayerLocked(id: string, locked: boolean): boolean {\r\n if (locked && id === this._activeLayerId) {\r\n const fallback = this.findFallbackLayer(id);\r\n if (!fallback) return false;\r\n this._activeLayerId = fallback.id;\r\n }\r\n this.updateLayerDirect(id, { locked });\r\n return true;\r\n }\r\n\r\n setLayerOpacity(id: string, opacity: number): void {\r\n if (!this.layers.has(id)) return;\r\n this.updateLayerDirect(id, { opacity: Math.max(0, Math.min(1, opacity)) });\r\n }\r\n\r\n setActiveLayer(id: string): void {\r\n if (!this.layers.has(id)) return;\r\n this._activeLayerId = id;\r\n this.bus.emit('change', null);\r\n }\r\n\r\n moveElementToLayer(elementId: string, layerId: string): void {\r\n if (!this.layers.has(layerId)) return;\r\n this.store.update(elementId, { layerId });\r\n this.bus.emit('change', null);\r\n }\r\n\r\n snapshot(): Layer[] {\r\n return this.getLayers();\r\n }\r\n\r\n loadSnapshot(layers: Layer[]): void {\r\n this.layers.clear();\r\n for (const layer of layers) {\r\n this.layers.set(layer.id, { ...layer });\r\n }\r\n const first = this.getLayers()[0];\r\n if (first) this._activeLayerId = first.id;\r\n this.syncLayerOrder();\r\n this.bus.emit('change', null);\r\n }\r\n\r\n on<K extends keyof LayerManagerEvents>(\r\n event: K,\r\n callback: (data: LayerManagerEvents[K]) => void,\r\n ): () => void {\r\n return this.bus.on(event, callback);\r\n }\r\n\r\n addLayerDirect(layer: Layer): void {\r\n this.layers.set(layer.id, { ...layer });\r\n this.syncLayerOrder();\r\n this.bus.emit('create', { ...layer });\r\n this.bus.emit('change', null);\r\n }\r\n\r\n removeLayerDirect(id: string): void {\r\n const layer = this.layers.get(id);\r\n this.layers.delete(id);\r\n this.syncLayerOrder();\r\n if (layer) this.bus.emit('remove', { ...layer });\r\n this.bus.emit('change', null);\r\n }\r\n\r\n updateLayerDirect(id: string, props: Omit<Partial<Layer>, 'id'>): void {\r\n const layer = this.layers.get(id);\r\n if (!layer) return;\r\n const previous = { ...layer };\r\n Object.assign(layer, props);\r\n if ('order' in props) this.syncLayerOrder();\r\n this.bus.emit('update', { previous, current: { ...layer } });\r\n this.bus.emit('change', null);\r\n }\r\n\r\n private syncLayerOrder(): void {\r\n const order = new Map<string, number>();\r\n for (const layer of this.layers.values()) {\r\n order.set(layer.id, layer.order);\r\n }\r\n this.store.setLayerOrder(order);\r\n }\r\n\r\n private findFallbackLayer(excludeId: string): Layer | undefined {\r\n return [...this.layers.values()]\r\n .filter((l) => l.id !== excludeId && l.visible && !l.locked)\r\n .sort((a, b) => b.order - a.order)[0];\r\n }\r\n}\r\n","export interface InteractModeDeps {\r\n getNode: (id: string) => HTMLDivElement | undefined;\r\n}\r\n\r\nexport class InteractMode {\r\n private interactingElementId: string | null = null;\r\n private readonly getNode: (id: string) => HTMLDivElement | undefined;\r\n\r\n constructor(deps: InteractModeDeps) {\r\n this.getNode = deps.getNode;\r\n }\r\n\r\n startInteracting(id: string): void {\r\n this.stopInteracting();\r\n const node = this.getNode(id);\r\n if (!node) return;\r\n\r\n this.interactingElementId = id;\r\n node.style.pointerEvents = 'auto';\r\n node.addEventListener('pointerdown', this.onNodePointerDown);\r\n\r\n window.addEventListener('keydown', this.onKeyDown);\r\n window.addEventListener('pointerdown', this.onPointerDown);\r\n }\r\n\r\n stopInteracting(): void {\r\n if (!this.interactingElementId) return;\r\n\r\n const node = this.getNode(this.interactingElementId);\r\n if (node) {\r\n node.style.pointerEvents = 'none';\r\n node.removeEventListener('pointerdown', this.onNodePointerDown);\r\n }\r\n\r\n this.interactingElementId = null;\r\n window.removeEventListener('keydown', this.onKeyDown);\r\n window.removeEventListener('pointerdown', this.onPointerDown);\r\n }\r\n\r\n isInteracting(): boolean {\r\n return this.interactingElementId !== null;\r\n }\r\n\r\n destroy(): void {\r\n this.stopInteracting();\r\n }\r\n\r\n private onNodePointerDown = (e: PointerEvent): void => {\r\n e.stopPropagation();\r\n };\r\n\r\n private onKeyDown = (e: KeyboardEvent): void => {\r\n if (e.key === 'Escape') {\r\n this.stopInteracting();\r\n }\r\n };\r\n\r\n private onPointerDown = (e: PointerEvent): void => {\r\n if (!this.interactingElementId) return;\r\n const target = e.target;\r\n if (!(target instanceof Element)) {\r\n this.stopInteracting();\r\n return;\r\n }\r\n\r\n const node = this.getNode(this.interactingElementId);\r\n if (node && !node.contains(target)) {\r\n this.stopInteracting();\r\n }\r\n };\r\n}\r\n","export interface DoubleTapDetectorOptions {\r\n timeout?: number;\r\n maxDistance?: number;\r\n}\r\n\r\nconst DEFAULT_TIMEOUT = 300;\r\nconst DEFAULT_MAX_DISTANCE = 20;\r\n\r\nexport class DoubleTapDetector {\r\n private readonly timeout: number;\r\n private readonly maxDistance: number;\r\n private lastTapTime = 0;\r\n private lastTapX = 0;\r\n private lastTapY = 0;\r\n private hasPendingTap = false;\r\n\r\n constructor(options?: DoubleTapDetectorOptions) {\r\n this.timeout = options?.timeout ?? DEFAULT_TIMEOUT;\r\n this.maxDistance = options?.maxDistance ?? DEFAULT_MAX_DISTANCE;\r\n }\r\n\r\n feed(e: PointerEvent): boolean {\r\n const now = Date.now();\r\n const x = e.clientX;\r\n const y = e.clientY;\r\n\r\n if (this.hasPendingTap) {\r\n const elapsed = now - this.lastTapTime;\r\n const dx = x - this.lastTapX;\r\n const dy = y - this.lastTapY;\r\n const dist = Math.sqrt(dx * dx + dy * dy);\r\n\r\n if (elapsed <= this.timeout && dist <= this.maxDistance) {\r\n this.reset();\r\n return true;\r\n }\r\n }\r\n\r\n this.lastTapTime = now;\r\n this.lastTapX = x;\r\n this.lastTapY = y;\r\n this.hasPendingTap = true;\r\n return false;\r\n }\r\n\r\n reset(): void {\r\n this.hasPendingTap = false;\r\n this.lastTapTime = 0;\r\n this.lastTapX = 0;\r\n this.lastTapY = 0;\r\n }\r\n}\r\n","import type { CanvasElement, HtmlElement } from '../elements/types';\nimport type { ElementStore } from '../elements/element-store';\nimport { DEFAULT_NOTE_FONT_SIZE } from '../elements/element-factory';\nimport { DoubleTapDetector } from './double-tap-detector';\nexport interface DomNodeManagerDeps {\n domLayer: HTMLDivElement;\n onEditRequest: (id: string) => void;\n isEditingElement: (id: string) => boolean;\n getVersion?: (id: string) => number;\n}\n\nexport class DomNodeManager {\n private domNodes = new Map<string, HTMLDivElement>();\n private strata = new Map<number, HTMLDivElement>();\n private htmlContent = new Map<string, HTMLElement>();\n /** Elements whose node carries host-supplied content (see `markHostOwnedContent`). */\n private hostOwnedContent = new Set<string>();\n /** Host-owned nodes removed from the DOM but kept alive for a later remount. */\n private preservedNodes = new Map<string, HTMLDivElement>();\n private readonly domLayer: HTMLDivElement;\n private readonly onEditRequest: (id: string) => void;\n private readonly isEditingElement: (id: string) => boolean;\n private readonly getVersion: ((id: string) => number) | null;\n private lastSyncedVersion = new Map<string, number>();\n private lastSyncedZIndex = new Map<string, number>();\n private lastSyncedOpacity = new Map<string, number>();\n private cameraTransform = '';\n\n constructor(deps: DomNodeManagerDeps) {\n this.domLayer = deps.domLayer;\n this.onEditRequest = deps.onEditRequest;\n this.isEditingElement = deps.isEditingElement;\n this.getVersion = deps.getVersion ?? null;\n }\n\n getNode(id: string): HTMLDivElement | undefined {\n return this.domNodes.get(id);\n }\n\n setCameraTransform(transform: string): void {\n if (transform === this.cameraTransform) return;\n this.cameraTransform = transform;\n for (const stratum of this.strata.values()) stratum.style.transform = transform;\n }\n\n storeHtmlContent(elementId: string, dom: HTMLElement): void {\n this.htmlContent.set(elementId, dom);\n // Content arriving (or changing) is not reflected in the element's own data version, so\n // the dirty-tracking fast path in syncDomNode must be invalidated explicitly — otherwise a\n // contentless node stuck at pointerEvents:'none' (G2) would never re-render once content\n // shows up.\n this.lastSyncedVersion.delete(elementId);\n }\n\n /**\n * Marks an element's node as carrying content the HOST mounted into it directly\n * (`ViewportOptions.onHtmlElementMount`). That content is never recorded in\n * `htmlContent` — the host appends straight into the node — so a detach would\n * destroy it and no remount could ever bring it back. Preserving the node itself\n * (rather than a guessed-at child) keeps arbitrary subtrees, host-attached\n * listeners, and the host's own reference to the node all valid.\n *\n * Callers mark UNCONDITIONALLY, without inspecting the node — a host that only attaches\n * listeners or styles owns its node just as much as one that appended children, and\n * there is no way to tell those apart from the outside. Two consequences follow, both\n * accepted: a node the host never populated can still round-trip back into the DOM (the\n * documented exception to \"never had content -> never remount\", reachable only via\n * `onHtmlElementMount`), and one detached `<div>` is retained per such element for its\n * lifetime.\n */\n markHostOwnedContent(elementId: string): void {\n this.hostOwnedContent.add(elementId);\n }\n\n hasContent(elementId: string): boolean {\n return this.htmlContent.has(elementId);\n }\n\n resetHtmlContent(elementId: string): void {\n this.htmlContent.delete(elementId);\n // Replacing an element's content ends host ownership: the caller owns it now, and a\n // stale preserved node would remount the OLD content ahead of the new.\n this.hostOwnedContent.delete(elementId);\n this.preservedNodes.delete(elementId);\n this.lastSyncedVersion.delete(elementId);\n this.lastSyncedZIndex.delete(elementId);\n this.lastSyncedOpacity.delete(elementId);\n const node = this.domNodes.get(elementId);\n if (!node) return;\n while (node.firstChild) {\n node.removeChild(node.firstChild);\n }\n delete node.dataset['initialized'];\n }\n\n syncDomNode(element: CanvasElement, zIndex = 0, opacity = 1): void {\n let node = this.domNodes.get(element.id);\n if (!node) {\n const preserved = this.preservedNodes.get(element.id);\n if (preserved) {\n // Host-owned node coming back from a canvas detour: reattach the ORIGINAL node so\n // the host's content survives. A fresh node here would be permanently empty.\n this.preservedNodes.delete(element.id);\n node = preserved;\n } else {\n node = document.createElement('div');\n node.dataset['elementId'] = element.id;\n Object.assign(node.style, {\n position: 'absolute',\n pointerEvents: 'auto',\n });\n }\n this.getStratum(zIndex).appendChild(node);\n this.domNodes.set(element.id, node);\n } else if (this.getVersion) {\n const currentVersion = this.getVersion(element.id);\n const lastVersion = this.lastSyncedVersion.get(element.id);\n const lastZ = this.lastSyncedZIndex.get(element.id);\n const lastOpacity = this.lastSyncedOpacity.get(element.id);\n if (lastVersion === currentVersion && lastZ === zIndex && lastOpacity === opacity) {\n return;\n }\n }\n\n if (node.parentElement !== this.getStratum(zIndex)) {\n const previousStratum = node.parentElement;\n this.getStratum(zIndex).appendChild(node);\n if (previousStratum?.childElementCount === 0) {\n const previousOrder = Number(previousStratum.dataset['paintOrder']);\n previousStratum.remove();\n this.strata.delete(previousOrder);\n }\n }\n\n if (this.getVersion) {\n this.lastSyncedVersion.set(element.id, this.getVersion(element.id));\n this.lastSyncedZIndex.set(element.id, zIndex);\n this.lastSyncedOpacity.set(element.id, opacity);\n }\n\n const size = 'size' in element ? element.size : null;\n Object.assign(node.style, {\n display: 'block',\n left: `${element.position.x}px`,\n top: `${element.position.y}px`,\n width: size ? `${size.w}px` : 'auto',\n height: size ? `${size.h}px` : 'auto',\n zIndex: String(zIndex),\n opacity: String(opacity),\n transform: element.rotation ? `rotate(${element.rotation}rad)` : '',\n transformOrigin: '50% 50%',\n });\n\n this.renderDomContent(node, element);\n }\n\n hideDomNode(id: string): void {\n const node = this.domNodes.get(id);\n if (node) {\n node.style.display = 'none';\n this.lastSyncedVersion.delete(id);\n }\n }\n\n removeDomNode(id: string): void {\n this.htmlContent.delete(id);\n this.hostOwnedContent.delete(id);\n this.preservedNodes.delete(id);\n this.detachNodeElement(id);\n }\n\n /** Removes the node but KEEPS htmlContent, so a later re-mount restores the original embed.\n * The registry factory that produces embed content only runs in loadState (G1), so dropping\n * content here would be unrecoverable. For a host-owned node there is no recorded content at\n * all, so the node ITSELF is kept alive off-DOM and reattached by `syncDomNode`.\n * Use `removeDomNode` when the element itself is gone. */\n detachDomNode(id: string): void {\n if (this.hostOwnedContent.has(id)) {\n const node = this.domNodes.get(id);\n if (node) this.preservedNodes.set(id, node);\n }\n this.detachNodeElement(id);\n }\n\n /** Shared by `removeDomNode` and `detachDomNode`: clears dirty-tracking caches, removes the\n * node from the DOM, and cleans up its stratum if now empty. Does NOT touch `htmlContent` —\n * that distinction is each caller's own responsibility. */\n private detachNodeElement(id: string): void {\n this.lastSyncedVersion.delete(id);\n this.lastSyncedZIndex.delete(id);\n this.lastSyncedOpacity.delete(id);\n const node = this.domNodes.get(id);\n if (!node) return;\n const stratum = node.parentElement;\n node.remove();\n this.domNodes.delete(id);\n if (stratum?.childElementCount === 0) {\n const order = Number(stratum.dataset['paintOrder']);\n stratum.remove();\n this.strata.delete(order);\n }\n }\n\n /** Reconciles BOTH directions synchronously. Canvas/missing routing detaches the node\n * (content preserved); dom routing remounts preserved content immediately, so a painter\n * unregistration does not wait for an unrelated render pass. */\n reconcileHtmlRouting(\n store: ElementStore,\n resolve: (el: HtmlElement) => 'dom' | 'canvas' | 'missing',\n ): void {\n for (const el of store.getElementsByType('html')) {\n if (resolve(el) !== 'dom') {\n this.detachDomNode(el.id);\n continue;\n }\n // Reverse transition: only meaningful when content — recorded content, or a preserved\n // host-owned node — survived a detach.\n if (\n (this.htmlContent.has(el.id) || this.preservedNodes.has(el.id)) &&\n !this.domNodes.has(el.id)\n ) {\n this.syncDomNode(el);\n }\n }\n }\n\n clearDomNodes(): void {\n this.domNodes.forEach((node) => node.remove());\n this.domNodes.clear();\n this.htmlContent.clear();\n this.hostOwnedContent.clear();\n this.preservedNodes.clear();\n this.lastSyncedVersion.clear();\n this.lastSyncedZIndex.clear();\n this.lastSyncedOpacity.clear();\n for (const stratum of this.strata.values()) stratum.remove();\n this.strata.clear();\n }\n\n private getStratum(order: number): HTMLDivElement {\n let stratum = this.strata.get(order);\n if (stratum) return stratum;\n stratum = document.createElement('div');\n stratum.dataset['paintOrder'] = String(order);\n Object.assign(stratum.style, {\n position: 'absolute',\n inset: '0',\n width: '100%',\n height: '100%',\n pointerEvents: 'none',\n transformOrigin: '0 0',\n transform: this.cameraTransform,\n zIndex: String(order),\n });\n this.domLayer.appendChild(stratum);\n this.strata.set(order, stratum);\n return stratum;\n }\n\n reattachHtmlContent(store: ElementStore): void {\n for (const el of store.getElementsByType('html')) {\n if (el.domId) {\n const dom = document.getElementById(el.domId);\n if (dom) {\n this.htmlContent.set(el.id, dom);\n }\n }\n }\n }\n\n private renderDomContent(node: HTMLDivElement, element: CanvasElement): void {\n if (element.type === 'note') {\n if (!node.dataset['initialized']) {\n node.dataset['initialized'] = 'true';\n Object.assign(node.style, {\n backgroundColor: element.backgroundColor,\n color: element.textColor,\n padding: '8px',\n borderRadius: '4px',\n boxShadow: '0 2px 8px rgba(0,0,0,0.15)',\n fontSize: `${element.fontSize ?? DEFAULT_NOTE_FONT_SIZE}px`,\n overflow: 'hidden',\n cursor: 'default',\n userSelect: 'none',\n wordWrap: 'break-word',\n });\n node.innerHTML = element.text || '';\n\n // One-time per node: this pointerup/double-tap listener is attached once (guarded by\n // `initialized`) for note/text nodes and is GC'd with the node — no teardown.\n // `resetHtmlContent()` (the only path clearing `initialized`) is html-only, and the html\n // init branch attaches no listener, so re-init is safe. INVARIANT: never call\n // resetHtmlContent on a note/text node, and if you add a listener to the html init branch,\n // add matching teardown in resetHtmlContent — else a second listener would stack.\n const detector = new DoubleTapDetector();\n node.addEventListener('pointerup', (e) => {\n if (detector.feed(e)) {\n e.stopPropagation();\n const id = node.dataset['elementId'];\n if (id) this.onEditRequest(id);\n }\n });\n }\n\n if (!this.isEditingElement(element.id)) {\n const text = element.text || '';\n if (node.innerHTML !== text) {\n node.innerHTML = text;\n }\n node.style.backgroundColor = element.backgroundColor;\n node.style.color = element.textColor;\n node.style.fontSize = `${element.fontSize ?? DEFAULT_NOTE_FONT_SIZE}px`;\n }\n }\n\n if (element.type === 'html') {\n const content = this.htmlContent.get(element.id);\n if (!node.dataset['initialized']) {\n if (content) {\n node.dataset['initialized'] = 'true';\n Object.assign(node.style, {\n overflow: 'hidden',\n pointerEvents: element.interactive ? 'auto' : 'none',\n });\n node.appendChild(content);\n } else {\n // G2: a contentless html node must not swallow pointer events. This is what an\n // unknown htmlType on an older client produces.\n node.style.pointerEvents = 'none';\n }\n } else {\n node.style.pointerEvents = element.interactive ? 'auto' : 'none';\n }\n }\n\n if (element.type === 'text') {\n if (!node.dataset['initialized']) {\n node.dataset['initialized'] = 'true';\n Object.assign(node.style, {\n padding: '2px',\n fontSize: `${element.fontSize}px`,\n color: element.color,\n textAlign: element.textAlign,\n background: 'none',\n border: 'none',\n boxShadow: 'none',\n overflow: 'visible',\n cursor: 'default',\n userSelect: 'none',\n wordWrap: 'break-word',\n lineHeight: '1.4',\n });\n node.innerHTML = element.text || '';\n\n // One-time per node; see the note branch above for the one-listener-per-node invariant.\n const detector = new DoubleTapDetector();\n node.addEventListener('pointerup', (e) => {\n if (detector.feed(e)) {\n e.stopPropagation();\n const id = node.dataset['elementId'];\n if (id) this.onEditRequest(id);\n }\n });\n }\n\n if (!this.isEditingElement(element.id)) {\n const text = element.text || '';\n if (node.innerHTML !== text) {\n node.innerHTML = text;\n }\n Object.assign(node.style, {\n fontSize: `${element.fontSize}px`,\n color: element.color,\n textAlign: element.textAlign,\n });\n }\n }\n }\n}\n","const SAMPLE_SIZE = 60;\r\n\r\nexport interface RenderStatsSnapshot {\r\n fps: number;\r\n avgFrameMs: number;\r\n p95FrameMs: number;\r\n lastFrameMs: number;\r\n lastGridMs: number;\r\n layersMs: number;\r\n backgroundMs: number;\r\n compositeMs: number;\r\n overlayMs: number;\r\n frameCount: number;\r\n}\r\n\r\ninterface FrameBreakdown {\r\n gridMs?: number;\r\n layersMs?: number;\r\n backgroundMs?: number;\r\n compositeMs?: number;\r\n overlayMs?: number;\r\n}\r\n\r\nexport class RenderStats {\r\n private frameTimes: number[] = [];\r\n private frameCount = 0;\r\n private _lastGridMs = 0;\r\n private _lastLayersMs = 0;\r\n private _lastBackgroundMs = 0;\r\n private _lastCompositeMs = 0;\r\n private _lastOverlayMs = 0;\r\n\r\n recordFrame(durationMs: number, breakdown?: FrameBreakdown): void {\r\n this.frameCount++;\r\n this.frameTimes.push(durationMs);\r\n if (this.frameTimes.length > SAMPLE_SIZE) {\r\n this.frameTimes.shift();\r\n }\r\n if (breakdown !== undefined) {\r\n if (breakdown.gridMs !== undefined) this._lastGridMs = breakdown.gridMs;\r\n if (breakdown.layersMs !== undefined) this._lastLayersMs = breakdown.layersMs;\r\n if (breakdown.backgroundMs !== undefined) this._lastBackgroundMs = breakdown.backgroundMs;\r\n if (breakdown.compositeMs !== undefined) this._lastCompositeMs = breakdown.compositeMs;\r\n if (breakdown.overlayMs !== undefined) this._lastOverlayMs = breakdown.overlayMs;\r\n }\r\n }\r\n\r\n getSnapshot(): RenderStatsSnapshot {\r\n const times = this.frameTimes;\r\n if (times.length === 0) {\r\n return {\r\n fps: 0,\r\n avgFrameMs: 0,\r\n p95FrameMs: 0,\r\n lastFrameMs: 0,\r\n lastGridMs: 0,\r\n layersMs: 0,\r\n backgroundMs: 0,\r\n compositeMs: 0,\r\n overlayMs: 0,\r\n frameCount: 0,\r\n };\r\n }\r\n\r\n const avg = times.reduce((a, b) => a + b, 0) / times.length;\r\n const sorted = [...times].sort((a, b) => a - b);\r\n const p95Index = Math.min(Math.floor(sorted.length * 0.95), sorted.length - 1);\r\n const lastFrame = times[times.length - 1] ?? 0;\r\n\r\n return {\r\n fps: avg > 0 ? Math.round(1000 / avg) : 0,\r\n avgFrameMs: Math.round(avg * 100) / 100,\r\n p95FrameMs: Math.round((sorted[p95Index] ?? 0) * 100) / 100,\r\n lastFrameMs: Math.round(lastFrame * 100) / 100,\r\n lastGridMs: Math.round(this._lastGridMs * 100) / 100,\r\n layersMs: Math.round(this._lastLayersMs * 100) / 100,\r\n backgroundMs: Math.round(this._lastBackgroundMs * 100) / 100,\r\n compositeMs: Math.round(this._lastCompositeMs * 100) / 100,\r\n overlayMs: Math.round(this._lastOverlayMs * 100) / 100,\r\n frameCount: this.frameCount,\r\n };\r\n }\r\n\r\n reset(): void {\r\n this.frameTimes = [];\r\n this.frameCount = 0;\r\n }\r\n}\r\n","import type { Camera } from './camera';\nimport type { Background } from './background';\nimport type { ElementStore } from '../elements/element-store';\nimport type { ElementRenderer } from '../elements/element-renderer';\nimport type { ToolManager } from '../tools/tool-manager';\nimport type { LayerManager } from '../layers/layer-manager';\nimport type { DomNodeManager } from './dom-node-manager';\nimport type { LayerCache } from './layer-cache';\nimport type { MarginViewport } from './margin-viewport';\nimport type { Bounds } from '../core/types';\nimport type { CanvasElement } from '../elements/types';\nimport { getElementVisualBounds, boundsIntersect } from '../elements/element-bounds';\nimport { RenderStats } from './render-stats';\nimport type { RenderStatsSnapshot } from './render-stats';\nimport type { HybridRenderSurface } from './hybrid-render-surface';\n\n/**\n * A world-space draw callback rendered above elements on every frame,\n * regardless of which tool is active. The context arrives with the camera\n * transform applied; implementations must not assume exclusive context state\n * (each renderer is wrapped in save/restore). A throwing renderer is isolated\n * per frame and must not break the render loop.\n */\nexport type OverlayRenderer = (ctx: CanvasRenderingContext2D) => void;\n\nexport interface RenderLoopDeps {\n canvasEl: HTMLCanvasElement;\n camera: Camera;\n background: Background;\n store: ElementStore;\n renderer: ElementRenderer;\n toolManager: ToolManager;\n layerManager: LayerManager;\n domNodeManager: DomNodeManager;\n layerCache: LayerCache;\n marginViewport: MarginViewport;\n hybridSurface: HybridRenderSurface;\n}\n\nexport class RenderLoop {\n private needsRender = false;\n private animFrameId = 0;\n private readonly canvasEl: HTMLCanvasElement;\n private readonly camera: Camera;\n private readonly background: Background;\n private readonly store: ElementStore;\n private readonly renderer: ElementRenderer;\n private readonly toolManager: ToolManager;\n private readonly layerManager: LayerManager;\n private readonly domNodeManager: DomNodeManager;\n private readonly layerCache: LayerCache;\n private readonly marginViewport: MarginViewport;\n private readonly hybridSurface: HybridRenderSurface;\n private activeDrawingLayerId: string | null = null;\n private gridCacheDirty = true; // set on recenter/viewport-change; consumed by the grid block\n private readonly stats = new RenderStats();\n private layerGroups = new Map<string, CanvasElement[]>();\n private readonly overlays = new Set<OverlayRenderer>();\n private gridCacheCanvas: HTMLCanvasElement | null = null;\n private gridCacheCtx: CanvasRenderingContext2D | null = null;\n private lastGridRefs: CanvasElement[] = [];\n private htmlScratchCanvas: HTMLCanvasElement | null = null;\n private htmlScratchCtx: CanvasRenderingContext2D | null = null;\n\n constructor(deps: RenderLoopDeps) {\n this.canvasEl = deps.canvasEl;\n this.camera = deps.camera;\n this.background = deps.background;\n this.store = deps.store;\n this.renderer = deps.renderer;\n this.toolManager = deps.toolManager;\n this.layerManager = deps.layerManager;\n this.domNodeManager = deps.domNodeManager;\n this.layerCache = deps.layerCache;\n this.marginViewport = deps.marginViewport;\n this.hybridSurface = deps.hybridSurface;\n }\n\n requestRender(): void {\n this.needsRender = true;\n }\n\n flush(): void {\n if (this.needsRender) {\n this.render();\n this.needsRender = false;\n }\n }\n\n start(): void {\n const loop = (): void => {\n if (this.needsRender) {\n this.render();\n this.needsRender = false;\n }\n this.animFrameId = requestAnimationFrame(loop);\n };\n this.animFrameId = requestAnimationFrame(loop);\n }\n\n stop(): void {\n cancelAnimationFrame(this.animFrameId);\n }\n\n setCanvasSize(width: number, height: number): void {\n this.canvasEl.width = width;\n this.canvasEl.height = height;\n const dpr = typeof devicePixelRatio !== 'undefined' ? devicePixelRatio : 1;\n this.marginViewport.setViewport(width / dpr, height / dpr, dpr);\n this.layerCache.resize();\n }\n\n setActiveDrawingLayer(layerId: string | null): void {\n this.activeDrawingLayerId = layerId;\n }\n\n markLayerDirty(layerId: string): void {\n this.layerCache.markDirty(layerId);\n }\n\n markAllLayersDirty(): void {\n this.layerCache.markAllDirty();\n this.gridCacheDirty = true;\n }\n\n getStats(): RenderStatsSnapshot {\n return this.stats.getSnapshot();\n }\n\n /**\n * Registers a viewport overlay drawn beneath the active tool's own overlay.\n * Returns an idempotent unsubscribe that also erases the overlay's last\n * frame.\n */\n registerOverlay(draw: OverlayRenderer): () => void {\n this.overlays.add(draw);\n this.requestRender();\n return () => {\n if (this.overlays.delete(draw)) this.requestRender();\n };\n }\n\n private drawRegisteredOverlays(ctx: CanvasRenderingContext2D): void {\n for (const draw of this.overlays) {\n ctx.save();\n try {\n draw(ctx);\n } catch {\n // One faulty overlay must not take down the frame or its siblings.\n } finally {\n ctx.restore();\n }\n }\n }\n\n private compositeLayerCache(\n ctx: CanvasRenderingContext2D,\n layerId: string,\n opacity: number,\n ): void {\n const cached = this.layerCache.getCanvas(layerId);\n const offset = this.marginViewport.compositeOffset(\n this.camera.position.x,\n this.camera.position.y,\n );\n ctx.save();\n ctx.setTransform(1, 0, 0, 1, 0, 0);\n ctx.globalAlpha = opacity;\n ctx.drawImage(cached as CanvasImageSource, offset.x, offset.y);\n ctx.restore();\n }\n\n private ensureGridCache(): void {\n const w = this.marginViewport.physicalWidth();\n const h = this.marginViewport.physicalHeight();\n if (\n this.gridCacheCanvas !== null &&\n this.gridCacheCanvas.width === w &&\n this.gridCacheCanvas.height === h\n ) {\n return;\n }\n\n if (typeof OffscreenCanvas !== 'undefined') {\n this.gridCacheCanvas = new OffscreenCanvas(w, h) as unknown as HTMLCanvasElement;\n } else if (typeof document !== 'undefined') {\n const el = document.createElement('canvas');\n el.width = w;\n el.height = h;\n this.gridCacheCanvas = el;\n } else {\n this.gridCacheCanvas = null;\n this.gridCacheCtx = null;\n return;\n }\n\n this.gridCacheCtx = this.gridCacheCanvas.getContext('2d') as CanvasRenderingContext2D | null;\n }\n\n /**\n * Lazily allocated, and only ever touched by the translucent-layer html branch below.\n * Grow-only: the branch runs once per element per frame, and reassigning `width` or\n * `height` reallocates the backing store, so shrinking to each element in turn would\n * thrash. The requested size is always clipped to the visible canvas by\n * `htmlScratchRect`, so this stays bounded by the canvas itself.\n */\n private ensureHtmlScratch(w: number, h: number): CanvasRenderingContext2D | null {\n if (this.htmlScratchCanvas === null || this.htmlScratchCtx === null) {\n if (typeof OffscreenCanvas !== 'undefined') {\n this.htmlScratchCanvas = new OffscreenCanvas(w, h) as unknown as HTMLCanvasElement;\n } else if (typeof document !== 'undefined') {\n this.htmlScratchCanvas = document.createElement('canvas');\n } else {\n return null;\n }\n this.htmlScratchCtx = this.htmlScratchCanvas.getContext(\n '2d',\n ) as CanvasRenderingContext2D | null;\n if (this.htmlScratchCtx === null) {\n this.htmlScratchCanvas = null;\n return null;\n }\n }\n if (this.htmlScratchCanvas.width < w) this.htmlScratchCanvas.width = w;\n if (this.htmlScratchCanvas.height < h) this.htmlScratchCanvas.height = h;\n return this.htmlScratchCtx;\n }\n\n /**\n * The device-pixel footprint an element occupies on the hybrid surface: its world\n * bounds mapped through the same `scale(dpr) -> translate(cam) -> scale(zoom)` chain\n * the hybrid context uses, snapped OUT to whole pixels (so the clip edge's antialiased\n * pixel is included) and intersected with the surface.\n *\n * Null when nothing of the element lands on the surface. That includes the case where\n * the surface has no pixels at all: a host hiding the viewport (`display: none`) drives\n * `canvasEl.width` to 0 via `syncCanvasSize`, culling does not go degenerate with it,\n * and a zero-dimension canvas throws `InvalidStateError` when used as a `drawImage`\n * SOURCE — which would escape `render()` and kill the frame loop permanently.\n * Non-finite bounds fail the same `>= 1` test and are rejected here too.\n */\n private htmlScratchRect(bounds: Bounds | null, dpr: number): Bounds | null {\n let left = 0;\n let top = 0;\n let right = this.canvasEl.width;\n let bottom = this.canvasEl.height;\n if (bounds) {\n const zoom = this.camera.zoom;\n const camX = this.camera.position.x;\n const camY = this.camera.position.y;\n left = Math.max(left, Math.floor((bounds.x * zoom + camX) * dpr));\n top = Math.max(top, Math.floor((bounds.y * zoom + camY) * dpr));\n right = Math.min(right, Math.ceil(((bounds.x + bounds.w) * zoom + camX) * dpr));\n bottom = Math.min(bottom, Math.ceil(((bounds.y + bounds.h) * zoom + camY) * dpr));\n }\n const w = right - left;\n const h = bottom - top;\n if (!(w >= 1) || !(h >= 1)) return null;\n return { x: left, y: top, w, h };\n }\n\n /**\n * Draws one canvas-routed html element on the hybrid stratum with the layer-opacity\n * boundary the painter contract requires: paint at `globalAlpha === 1` into a scratch\n * surface, then composite that raster at the layer's opacity. Mirrors `exportImage`'s\n * per-layer temp canvas and the minimap's layer composite.\n *\n * The scratch covers only the element's own device-pixel rect, the way\n * `rasterizeCanvasRoutedHtml` sizes its offscreen to the element rather than the export\n * bounds. That is exact rather than approximate because `paintHtmlElement` clips every\n * painter to the element's (rotated) rect, so nothing can land outside those bounds.\n * The offset is whole device pixels and the blit is 1:1, so the element occupies\n * exactly the pixels a full-canvas scratch would have given it.\n */\n private paintHybridHtmlAtLayerOpacity(\n hybridCtx: CanvasRenderingContext2D,\n element: CanvasElement,\n elementBounds: Bounds | null,\n layerOpacity: number,\n dpr: number,\n ): void {\n const rect = this.htmlScratchRect(elementBounds, dpr);\n if (!rect) return; // no pixels to paint into, and no degenerate drawImage source\n const scratchCtx = this.ensureHtmlScratch(rect.w, rect.h);\n const scratchCanvas = this.htmlScratchCanvas;\n if (!scratchCtx || !scratchCanvas) {\n // No scratch surface available: drawing the element pre-multiplied still beats\n // dropping it, and this is the same fallback shape the grid cache uses.\n hybridCtx.save();\n hybridCtx.globalAlpha = layerOpacity;\n this.renderer.renderCanvasElement(hybridCtx, element);\n hybridCtx.restore();\n return;\n }\n\n scratchCtx.setTransform(1, 0, 0, 1, 0, 0);\n scratchCtx.clearRect(0, 0, rect.w, rect.h);\n scratchCtx.save();\n scratchCtx.globalAlpha = 1;\n scratchCtx.translate(-rect.x, -rect.y);\n scratchCtx.scale(dpr, dpr);\n scratchCtx.translate(this.camera.position.x, this.camera.position.y);\n scratchCtx.scale(this.camera.zoom, this.camera.zoom);\n this.renderer.renderCanvasElement(scratchCtx, element);\n scratchCtx.restore();\n\n hybridCtx.save();\n hybridCtx.setTransform(1, 0, 0, 1, 0, 0);\n hybridCtx.globalAlpha = layerOpacity;\n hybridCtx.drawImage(\n scratchCanvas as CanvasImageSource,\n 0,\n 0,\n rect.w,\n rect.h,\n rect.x,\n rect.y,\n rect.w,\n rect.h,\n );\n hybridCtx.restore();\n }\n\n private render(): void {\n const t0 = performance.now();\n const ctx = this.canvasEl.getContext('2d');\n if (!ctx) return;\n\n let layersMs = 0;\n let compositeMs = 0;\n let gridMs = 0;\n\n const dpr = typeof devicePixelRatio !== 'undefined' ? devicePixelRatio : 1;\n const cssWidth = this.canvasEl.clientWidth;\n const cssHeight = this.canvasEl.clientHeight;\n\n // idempotent; catches resizes that bypass setCanvasSize\n this.marginViewport.setViewport(cssWidth, cssHeight, dpr);\n\n const currentZoom = this.camera.zoom;\n const currentCamX = this.camera.position.x;\n const currentCamY = this.camera.position.y;\n if (this.marginViewport.needsRecenter(currentCamX, currentCamY, currentZoom)) {\n this.marginViewport.recenter(currentCamX, currentCamY, currentZoom);\n this.layerCache.markAllDirty();\n this.gridCacheDirty = true;\n }\n\n ctx.save();\n ctx.scale(dpr, dpr);\n\n this.renderer.setCanvasSize(cssWidth, cssHeight);\n const hasGridElement = this.store.getElementsByType('grid').length > 0;\n const bgT0 = performance.now();\n if (hasGridElement) {\n ctx.save();\n ctx.setTransform(dpr, 0, 0, dpr, 0, 0);\n ctx.clearRect(0, 0, cssWidth, cssHeight);\n ctx.restore();\n } else {\n this.background.render(ctx, this.camera);\n }\n const backgroundMs = performance.now() - bgT0;\n\n ctx.save();\n ctx.translate(this.camera.position.x, this.camera.position.y);\n ctx.scale(this.camera.zoom, this.camera.zoom);\n\n const cullBounds = this.marginViewport.cachedWorldBounds();\n const cullPad = Math.max(cullBounds.w, cullBounds.h) * 0.05;\n const cullingRect: Bounds = {\n x: cullBounds.x - cullPad,\n y: cullBounds.y - cullPad,\n w: cullBounds.w + cullPad * 2,\n h: cullBounds.h + cullPad * 2,\n };\n\n const allElements = this.store.getAll();\n const visibleElements = allElements.filter((element) =>\n this.layerManager.isLayerVisible(element.layerId),\n );\n const firstDomIndex = visibleElements.findIndex((element) =>\n this.renderer.isDomElement(element),\n );\n const hybridActive =\n firstDomIndex >= 0 &&\n visibleElements\n .slice(firstDomIndex + 1)\n .some((element) => !this.renderer.isDomElement(element));\n const hybridCanvasRuns = new Map<number, CanvasElement[]>();\n const hybridOrders = new Set<number>();\n let activeHybridOrder: number | null = null;\n this.layerGroups.clear();\n const gridElements: CanvasElement[] = [];\n let paintOrder = 0;\n\n for (const element of allElements) {\n if (!this.layerManager.isLayerVisible(element.layerId)) {\n if (this.renderer.isDomElement(element)) {\n this.domNodeManager.hideDomNode(element.id);\n }\n continue;\n }\n\n const order = ++paintOrder;\n\n if (this.renderer.isDomElement(element)) {\n activeHybridOrder = null;\n const layerOpacity = this.layerManager.getLayer?.(element.layerId)?.opacity ?? 1;\n const elBounds = getElementVisualBounds(element);\n if (elBounds && !boundsIntersect(elBounds, cullingRect)) {\n this.domNodeManager.hideDomNode(element.id);\n } else {\n this.domNodeManager.syncDomNode(element, order, layerOpacity);\n }\n continue;\n }\n\n if (hybridActive && paintOrder > firstDomIndex + 1 && element.type !== 'grid') {\n activeHybridOrder ??= order;\n let run = hybridCanvasRuns.get(activeHybridOrder);\n if (!run) {\n run = [];\n hybridCanvasRuns.set(activeHybridOrder, run);\n hybridOrders.add(activeHybridOrder);\n }\n run.push(element);\n continue;\n }\n\n // Grids are viewport-filling; handled via anchored cache below\n if (element.type === 'grid') {\n gridElements.push(element);\n continue;\n }\n\n let group = this.layerGroups.get(element.layerId);\n if (!group) {\n group = [];\n this.layerGroups.set(element.layerId, group);\n }\n group.push(element);\n }\n\n const activeTool = this.toolManager.activeTool;\n const overlayOrder = visibleElements.length + 1;\n const hasOverlay = activeTool?.renderOverlay !== undefined || this.overlays.size > 0;\n if (hybridActive && hasOverlay) hybridOrders.add(overlayOrder);\n this.hybridSurface.beginFrame(hybridOrders, this.canvasEl.width, this.canvasEl.height);\n\n for (const [layerId, elements] of this.layerGroups) {\n const isActiveDrawingLayer = layerId === this.activeDrawingLayerId;\n const layerOpacity = this.layerManager.getLayer?.(layerId)?.opacity ?? 1;\n\n if (!this.layerCache.isDirty(layerId)) {\n const compT0 = performance.now();\n this.compositeLayerCache(ctx, layerId, layerOpacity);\n compositeMs += performance.now() - compT0;\n continue;\n }\n\n if (isActiveDrawingLayer) {\n const compT0 = performance.now();\n this.compositeLayerCache(ctx, layerId, layerOpacity);\n compositeMs += performance.now() - compT0;\n continue;\n }\n\n const offCtx = this.layerCache.getContext(layerId);\n if (offCtx) {\n const layerT0 = performance.now();\n const offCanvas = this.layerCache.getCanvas(layerId);\n offCtx.clearRect(0, 0, offCanvas.width, offCanvas.height);\n offCtx.save();\n this.marginViewport.applyRenderTransform(offCtx);\n for (const element of elements) {\n const elBounds = getElementVisualBounds(element);\n if (elBounds && !boundsIntersect(elBounds, cullingRect)) continue;\n this.renderer.renderCanvasElement(offCtx as CanvasRenderingContext2D, element);\n }\n offCtx.restore();\n this.layerCache.markClean(layerId);\n layersMs += performance.now() - layerT0;\n\n const compT0 = performance.now();\n this.compositeLayerCache(ctx, layerId, layerOpacity);\n compositeMs += performance.now() - compT0;\n }\n }\n\n // Render grids on top of layer elements\n if (gridElements.length > 0) {\n const gridT0 = performance.now();\n const gridsChanged =\n gridElements.length !== this.lastGridRefs.length ||\n gridElements.some((grid, index) => grid !== this.lastGridRefs[index]);\n const gridDirty = this.gridCacheDirty || gridsChanged;\n\n if (gridDirty) {\n this.ensureGridCache();\n if (this.gridCacheCtx && this.gridCacheCanvas) {\n const cb = this.marginViewport.cachedWorldBounds();\n this.renderer.setGridBoundsOverride({\n minX: cb.x,\n minY: cb.y,\n maxX: cb.x + cb.w,\n maxY: cb.y + cb.h,\n });\n const gc = this.gridCacheCtx;\n gc.clearRect(0, 0, this.gridCacheCanvas.width, this.gridCacheCanvas.height);\n gc.save();\n this.marginViewport.applyRenderTransform(gc);\n try {\n for (const grid of gridElements) {\n gc.save();\n gc.globalAlpha = this.layerManager.getLayer?.(grid.layerId)?.opacity ?? 1;\n this.renderer.renderCanvasElement(gc as CanvasRenderingContext2D, grid);\n gc.restore();\n }\n } finally {\n gc.restore();\n this.renderer.setGridBoundsOverride(null);\n }\n }\n this.gridCacheDirty = false;\n this.lastGridRefs = [...gridElements];\n }\n\n if (this.gridCacheCanvas) {\n const offset = this.marginViewport.compositeOffset(\n this.camera.position.x,\n this.camera.position.y,\n );\n ctx.save();\n ctx.setTransform(1, 0, 0, 1, 0, 0);\n ctx.drawImage(this.gridCacheCanvas as CanvasImageSource, offset.x, offset.y);\n ctx.restore();\n } else {\n for (const grid of gridElements) {\n ctx.save();\n ctx.globalAlpha = this.layerManager.getLayer?.(grid.layerId)?.opacity ?? 1;\n this.renderer.renderCanvasElement(ctx, grid);\n ctx.restore();\n }\n }\n gridMs = performance.now() - gridT0;\n } else {\n this.lastGridRefs = [];\n }\n\n for (const [order, elements] of hybridCanvasRuns) {\n const hybridCtx = this.hybridSurface.getContext(order);\n if (!hybridCtx) continue;\n hybridCtx.clearRect(0, 0, this.canvasEl.width, this.canvasEl.height);\n hybridCtx.save();\n hybridCtx.scale(dpr, dpr);\n hybridCtx.translate(this.camera.position.x, this.camera.position.y);\n hybridCtx.scale(this.camera.zoom, this.camera.zoom);\n for (const element of elements) {\n const elBounds = getElementVisualBounds(element);\n if (elBounds && !boundsIntersect(elBounds, cullingRect)) continue;\n const layerOpacity = this.layerManager.getLayer?.(element.layerId)?.opacity ?? 1;\n // Canvas-routed html gets the painter's ALPHA BOUNDARY that every other surface\n // honours (cached-layer composite, minimap, image export, svg export): the painter\n // is handed globalAlpha 1 and layer opacity is applied to the painted RESULT.\n // Pre-multiplying here — which is the right thing for every other element type,\n // and stays that way — would let a painter that assigns globalAlpha wipe the\n // layer's opacity out, so a marker's on-screen opacity would change the moment an\n // unrelated note pushed the frame onto this hybrid path.\n //\n // The COMPOSITING GRANULARITY still differs from those surfaces, and deliberately\n // so: they composite once per layer, this composites once per element. Two\n // overlapping elements on a layer at opacity 0.5 therefore reach ~0.75 effective\n // coverage here versus 0.5 there. That is pre-existing on this path — it held for\n // every element type before the alpha boundary was fixed — and closing it means\n // grouping the hybrid run by layer and compositing once, which is a restructuring\n // this fix deliberately does not attempt.\n if (element.type === 'html' && layerOpacity < 1) {\n this.paintHybridHtmlAtLayerOpacity(hybridCtx, element, elBounds, layerOpacity, dpr);\n continue;\n }\n // html only reaches here with layerOpacity >= 1, so this is the pre-multiplied\n // path for every other element type and a no-op assignment for html.\n hybridCtx.save();\n hybridCtx.globalAlpha = layerOpacity;\n this.renderer.renderCanvasElement(hybridCtx, element);\n hybridCtx.restore();\n }\n hybridCtx.restore();\n }\n\n const overlayT0 = performance.now();\n if (hybridActive && hasOverlay) {\n const overlayCtx = this.hybridSurface.getContext(overlayOrder);\n if (overlayCtx) {\n overlayCtx.clearRect(0, 0, this.canvasEl.width, this.canvasEl.height);\n overlayCtx.save();\n overlayCtx.scale(dpr, dpr);\n overlayCtx.translate(this.camera.position.x, this.camera.position.y);\n overlayCtx.scale(this.camera.zoom, this.camera.zoom);\n this.drawRegisteredOverlays(overlayCtx);\n if (activeTool?.renderOverlay) activeTool.renderOverlay(overlayCtx);\n overlayCtx.restore();\n }\n } else if (hasOverlay) {\n this.drawRegisteredOverlays(ctx);\n if (activeTool?.renderOverlay) activeTool.renderOverlay(ctx);\n }\n const overlayMs = performance.now() - overlayT0;\n\n ctx.restore();\n ctx.restore();\n\n this.stats.recordFrame(performance.now() - t0, {\n gridMs,\n layersMs,\n backgroundMs,\n compositeMs,\n overlayMs,\n });\n }\n}\n","export type HtmlRenderTarget = 'screen' | 'minimap' | 'export';\n\nexport interface HtmlPaintDiagnostic {\n kind: 'missing-painter' | 'painter-threw' | 'degenerate-size';\n elementId: string;\n htmlType?: string;\n target: HtmlRenderTarget;\n error?: unknown;\n}\n\n/**\n * Painters run every frame, so an unfiltered diagnostic would flood the host.\n * The element version is part of the key so a fail -> repair -> fail-again\n * sequence reports twice instead of being suppressed forever.\n */\nexport class HtmlPaintDiagnosticDeduper {\n private readonly seen = new Map<string, Set<string>>();\n constructor(private readonly sink: (d: HtmlPaintDiagnostic) => void) {}\n\n emit(\n diagnostic: HtmlPaintDiagnostic,\n keyParts: { registryVersion: number; elementVersion: number },\n ): void {\n const key = `${diagnostic.target}|${diagnostic.kind}|${keyParts.registryVersion}|${keyParts.elementVersion}`;\n const forElement = this.seen.get(diagnostic.elementId) ?? new Set<string>();\n if (forElement.has(key)) return;\n forElement.add(key);\n this.seen.set(diagnostic.elementId, forElement);\n this.sink(diagnostic);\n }\n\n forget(elementId: string): void {\n this.seen.delete(elementId);\n }\n\n reset(): void {\n this.seen.clear();\n }\n}\n","import type { MarginViewport } from './margin-viewport';\r\n\r\nfunction createOffscreenCanvas(width: number, height: number): HTMLCanvasElement | OffscreenCanvas {\r\n if (typeof OffscreenCanvas !== 'undefined') {\r\n return new OffscreenCanvas(width, height);\r\n }\r\n const canvas = document.createElement('canvas');\r\n canvas.width = width;\r\n canvas.height = height;\r\n return canvas;\r\n}\r\n\r\nexport class LayerCache {\r\n private canvases = new Map<string, HTMLCanvasElement | OffscreenCanvas>();\r\n private dirtyFlags = new Map<string, boolean>();\r\n\r\n constructor(private readonly viewport: MarginViewport) {}\r\n\r\n isDirty(layerId: string): boolean {\r\n return this.dirtyFlags.get(layerId) !== false;\r\n }\r\n\r\n markDirty(layerId: string): void {\r\n this.dirtyFlags.set(layerId, true);\r\n }\r\n\r\n markClean(layerId: string): void {\r\n this.dirtyFlags.set(layerId, false);\r\n }\r\n\r\n markAllDirty(): void {\r\n for (const [id] of this.dirtyFlags) {\r\n this.dirtyFlags.set(id, true);\r\n }\r\n }\r\n\r\n getCanvas(layerId: string): HTMLCanvasElement | OffscreenCanvas {\r\n let canvas = this.canvases.get(layerId);\r\n if (!canvas) {\r\n canvas = createOffscreenCanvas(this.viewport.physicalWidth(), this.viewport.physicalHeight());\r\n this.canvases.set(layerId, canvas);\r\n this.dirtyFlags.set(layerId, true);\r\n }\r\n return canvas;\r\n }\r\n\r\n getContext(layerId: string): CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D | null {\r\n const canvas = this.getCanvas(layerId);\r\n return canvas.getContext('2d') as\r\n | CanvasRenderingContext2D\r\n | OffscreenCanvasRenderingContext2D\r\n | null;\r\n }\r\n\r\n resize(): void {\r\n const w = this.viewport.physicalWidth();\r\n const h = this.viewport.physicalHeight();\r\n for (const [id, canvas] of this.canvases) {\r\n canvas.width = w;\r\n canvas.height = h;\r\n this.dirtyFlags.set(id, true);\r\n }\r\n }\r\n\r\n clear(): void {\r\n this.canvases.clear();\r\n this.dirtyFlags.clear();\r\n }\r\n}\r\n","import type { Bounds } from '../core/types';\r\n\r\n/**\r\n * Owns the cache anchor (the camera state the screen-space caches were last rendered at)\r\n * and the margin geometry. Pure — holds no canvas. Caches render a region inflated by\r\n * `marginPx` on every side, so a pan within the margin is an offset-blit, not a re-raster.\r\n *\r\n * Call setViewport(cssW, cssH, dpr) before physicalWidth/Height, applyRenderTransform, or compositeOffset — they read the stored dpr.\r\n */\r\nexport class MarginViewport {\r\n private cssW = 0;\r\n private cssH = 0;\r\n private dpr = 1;\r\n private anchorCamX = 0;\r\n private anchorCamY = 0;\r\n private anchorZoom = Number.NaN; // sentinel → first needsRecenter is true\r\n private viewportDirty = true;\r\n\r\n constructor(private marginPx: number) {}\r\n\r\n setMargin(marginPx: number): void {\r\n if (marginPx !== this.marginPx) {\r\n this.marginPx = marginPx;\r\n this.viewportDirty = true;\r\n }\r\n }\r\n\r\n setViewport(cssW: number, cssH: number, dpr: number): void {\r\n if (cssW !== this.cssW || cssH !== this.cssH || dpr !== this.dpr) {\r\n this.cssW = cssW;\r\n this.cssH = cssH;\r\n this.dpr = dpr;\r\n this.viewportDirty = true;\r\n }\r\n }\r\n\r\n physicalWidth(): number {\r\n return Math.round((this.cssW + 2 * this.marginPx) * this.dpr);\r\n }\r\n\r\n physicalHeight(): number {\r\n return Math.round((this.cssH + 2 * this.marginPx) * this.dpr);\r\n }\r\n\r\n needsRecenter(camX: number, camY: number, zoom: number): boolean {\r\n return (\r\n this.viewportDirty ||\r\n zoom !== this.anchorZoom ||\r\n Math.abs(camX - this.anchorCamX) > this.marginPx ||\r\n Math.abs(camY - this.anchorCamY) > this.marginPx\r\n );\r\n }\r\n\r\n recenter(camX: number, camY: number, zoom: number): void {\r\n this.anchorCamX = camX;\r\n this.anchorCamY = camY;\r\n this.anchorZoom = zoom;\r\n this.viewportDirty = false;\r\n }\r\n\r\n /** Applies dpr scale + anchor-relative world transform. setViewport must have been called first. */\r\n applyRenderTransform(ctx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D): void {\r\n ctx.scale(this.dpr, this.dpr);\r\n ctx.translate(this.marginPx + this.anchorCamX, this.marginPx + this.anchorCamY);\r\n ctx.scale(this.anchorZoom, this.anchorZoom);\r\n }\r\n\r\n // Device-px destination for drawImage(cache, x, y).\r\n // A world point P sits in the cache at CSS x `margin + anchorCamX + P*zoom`; it must land on\r\n // screen at `camX + P*zoom`; so the blit offset is `camX - anchorCamX - margin` (CSS) * dpr.\r\n compositeOffset(camX: number, camY: number): { x: number; y: number } {\r\n return {\r\n x: (camX - this.anchorCamX - this.marginPx) * this.dpr,\r\n y: (camY - this.anchorCamY - this.marginPx) * this.dpr,\r\n };\r\n }\r\n\r\n // World-space bounds of the whole cached region at the anchor (cull rect for re-renders).\r\n cachedWorldBounds(): Bounds {\r\n const z = this.anchorZoom;\r\n return {\r\n x: (-this.marginPx - this.anchorCamX) / z,\r\n y: (-this.marginPx - this.anchorCamY) / z,\r\n w: (this.cssW + 2 * this.marginPx) / z,\r\n h: (this.cssH + 2 * this.marginPx) / z,\r\n };\r\n }\r\n}\r\n","import type { CanvasElement } from './types';\r\n\r\n/** Patch that translates an element by (dx, dy). Arrows move position + from + to;\r\n * every other type moves position only (strokes carry points relative to position). */\r\nexport function translateElementPatch(\r\n el: CanvasElement,\r\n dx: number,\r\n dy: number,\r\n): Partial<CanvasElement> {\r\n const position = { x: el.position.x + dx, y: el.position.y + dy };\r\n if (el.type === 'arrow') {\r\n return {\r\n position,\r\n from: { x: el.from.x + dx, y: el.from.y + dy },\r\n to: { x: el.to.x + dx, y: el.to.y + dy },\r\n };\r\n }\r\n return { position };\r\n}\r\n","import type { ArrowStrokeStyle, CanvasElement } from './types';\r\n\r\nexport interface ElementStyle {\r\n color?: string;\r\n fillColor?: string;\r\n strokeWidth?: number;\r\n opacity?: number;\r\n fontSize?: number;\r\n strokeStyle?: ArrowStrokeStyle;\r\n}\r\n\r\nexport function styleToPatch(element: CanvasElement, style: ElementStyle): Partial<CanvasElement> {\r\n const { color, fillColor, strokeWidth, opacity, fontSize, strokeStyle } = style;\r\n switch (element.type) {\r\n case 'stroke':\r\n return {\r\n ...(color !== undefined ? { color } : {}),\r\n ...(strokeWidth !== undefined ? { width: strokeWidth } : {}),\r\n ...(opacity !== undefined ? { opacity } : {}),\r\n };\r\n case 'arrow':\r\n return {\r\n ...(color !== undefined ? { color } : {}),\r\n ...(strokeWidth !== undefined ? { width: strokeWidth } : {}),\r\n ...(strokeStyle !== undefined ? { strokeStyle } : {}),\r\n };\r\n case 'shape':\r\n return {\r\n ...(color !== undefined ? { strokeColor: color } : {}),\r\n ...(fillColor !== undefined ? { fillColor } : {}),\r\n ...(strokeWidth !== undefined ? { strokeWidth } : {}),\r\n };\r\n case 'text':\r\n return {\r\n ...(color !== undefined ? { color } : {}),\r\n ...(fontSize !== undefined ? { fontSize } : {}),\r\n };\r\n case 'note':\r\n return {\r\n ...(color !== undefined ? { textColor: color } : {}),\r\n ...(fillColor !== undefined ? { backgroundColor: fillColor } : {}),\r\n ...(fontSize !== undefined ? { fontSize } : {}),\r\n };\r\n case 'grid':\r\n return {\r\n ...(color !== undefined ? { strokeColor: color } : {}),\r\n ...(strokeWidth !== undefined ? { strokeWidth } : {}),\r\n ...(opacity !== undefined ? { opacity } : {}),\r\n };\r\n case 'template':\r\n return {\r\n ...(color !== undefined ? { strokeColor: color } : {}),\r\n ...(fillColor !== undefined ? { fillColor } : {}),\r\n ...(strokeWidth !== undefined ? { strokeWidth } : {}),\r\n ...(opacity !== undefined ? { opacity } : {}),\r\n };\r\n default:\r\n return {};\r\n }\r\n}\r\n\r\nexport function getElementStyle(element: CanvasElement): ElementStyle {\r\n switch (element.type) {\r\n case 'stroke':\r\n return { color: element.color, strokeWidth: element.width, opacity: element.opacity };\r\n case 'arrow':\r\n return {\r\n color: element.color,\r\n strokeWidth: element.width,\r\n ...(element.strokeStyle !== undefined ? { strokeStyle: element.strokeStyle } : {}),\r\n };\r\n case 'shape':\r\n return {\r\n color: element.strokeColor,\r\n fillColor: element.fillColor,\r\n strokeWidth: element.strokeWidth,\r\n };\r\n case 'text':\r\n return { color: element.color, fontSize: element.fontSize };\r\n case 'note':\r\n return {\r\n color: element.textColor,\r\n fillColor: element.backgroundColor,\r\n ...(element.fontSize !== undefined ? { fontSize: element.fontSize } : {}),\r\n };\r\n case 'grid':\r\n return {\r\n color: element.strokeColor,\r\n strokeWidth: element.strokeWidth,\r\n opacity: element.opacity,\r\n };\r\n case 'template':\r\n return {\r\n color: element.strokeColor,\r\n fillColor: element.fillColor,\r\n strokeWidth: element.strokeWidth,\r\n opacity: element.opacity,\r\n };\r\n default:\r\n return {};\r\n }\r\n}\r\n","import type { Bounds, Point } from '../core/types';\r\nimport type { CanvasElement } from '../elements/types';\r\nimport { normalizeAngle, rotatePoint, rotatedAABB } from '../core/geometry';\r\n\r\nexport type RotateDirection = 'cw' | 'ccw';\r\n\r\nexport interface BoundedElement {\r\n id: string;\r\n el: CanvasElement;\r\n bounds: Bounds;\r\n}\r\n\r\nexport function unionBounds(list: Bounds[]): Bounds {\r\n let minX = Infinity,\r\n minY = Infinity,\r\n maxX = -Infinity,\r\n maxY = -Infinity;\r\n for (const b of list) {\r\n minX = Math.min(minX, b.x);\r\n minY = Math.min(minY, b.y);\r\n maxX = Math.max(maxX, b.x + b.w);\r\n maxY = Math.max(maxY, b.y + b.h);\r\n }\r\n return { x: minX, y: minY, w: maxX - minX, h: maxY - minY };\r\n}\r\n\r\nexport function rotationPivot(items: readonly BoundedElement[]): Point {\r\n const first = items[0];\r\n if (items.length === 1 && first) {\r\n return { x: first.bounds.x + first.bounds.w / 2, y: first.bounds.y + first.bounds.h / 2 };\r\n }\r\n const u = unionBounds(items.map((it) => rotatedAABB(it.bounds, it.el.rotation ?? 0)));\r\n return { x: u.x + u.w / 2, y: u.y + u.h / 2 };\r\n}\r\n\r\nexport function rotateElementPatch(\r\n el: CanvasElement,\r\n bounds: Bounds,\r\n pivot: Point,\r\n delta: number,\r\n): Partial<CanvasElement> {\r\n if (el.type === 'arrow') {\r\n const center = { x: bounds.x + bounds.w / 2, y: bounds.y + bounds.h / 2 };\r\n const moved = rotatePoint(center, pivot, delta);\r\n return {\r\n position: { x: el.position.x + moved.x - center.x, y: el.position.y + moved.y - center.y },\r\n from: rotatePoint(el.from, pivot, delta),\r\n to: rotatePoint(el.to, pivot, delta),\r\n };\r\n }\r\n if (el.type === 'template') {\r\n return {\r\n position: rotatePoint(el.position, pivot, delta),\r\n angle: normalizeAngle(el.angle + delta),\r\n };\r\n }\r\n const center = { x: bounds.x + bounds.w / 2, y: bounds.y + bounds.h / 2 };\r\n const moved = rotatePoint(center, pivot, delta);\r\n return {\r\n position: { x: el.position.x + moved.x - center.x, y: el.position.y + moved.y - center.y },\r\n rotation: normalizeAngle((el.rotation ?? 0) + delta),\r\n };\r\n}\r\n","import type { ElementStore } from '../elements/element-store';\r\nimport type { HistoryRecorder } from '../history/history-recorder';\r\nimport { updateArrowsBoundToElements } from '../elements/arrow-binding';\r\nimport { translateElementPatch } from '../elements/translate';\r\nimport { getElementBounds } from '../elements/element-bounds';\r\nimport { createId } from '../elements/create-id';\r\nimport { styleToPatch, getElementStyle } from '../elements/element-style';\r\nimport type { ElementStyle } from '../elements/element-style';\r\nimport type { CanvasElement } from '../elements/types';\r\nimport type { Bounds } from '../core/types';\r\nimport { rotationPivot, rotateElementPatch, unionBounds } from './selection-rotate';\r\nimport type { RotateDirection } from './selection-rotate';\r\n\r\nconst STYLE_FIELDS = [\r\n 'color',\r\n 'fillColor',\r\n 'strokeWidth',\r\n 'opacity',\r\n 'fontSize',\r\n 'strokeStyle',\r\n] as const;\r\n\r\nexport interface SelectionStyleDetails {\r\n common: ElementStyle;\r\n applicable: readonly (keyof ElementStyle)[];\r\n mixed: readonly (keyof ElementStyle)[];\r\n}\r\n\r\nexport type AlignEdge = 'left' | 'center-x' | 'right' | 'top' | 'middle' | 'bottom';\r\nexport type DistributeAxis = 'horizontal' | 'vertical';\r\n\r\nfunction sharedValue<T>(values: (T | undefined)[]): T | undefined {\r\n const present = values.filter((v): v is T => v !== undefined);\r\n if (present.length === 0) return undefined;\r\n const first = present[0];\r\n return present.every((v) => v === first) ? first : undefined;\r\n}\r\n\r\nexport interface SelectionOpsDeps {\r\n store: ElementStore;\r\n recorder: HistoryRecorder;\r\n getSelectedIds: () => string[];\r\n requestRender: () => void;\r\n}\r\n\r\nexport class SelectionOps {\r\n constructor(private readonly deps: SelectionOpsDeps) {}\r\n\r\n getStyle(): ElementStyle | null {\r\n const ids = this.deps.getSelectedIds();\r\n if (ids.length === 0) return null;\r\n const styles: ElementStyle[] = [];\r\n for (const id of ids) {\r\n const el = this.deps.store.getById(id);\r\n if (el) styles.push(getElementStyle(el));\r\n }\r\n if (styles.length === 0) return null;\r\n const result: ElementStyle = {};\r\n const color = sharedValue(styles.map((s) => s.color));\r\n if (color !== undefined) result.color = color;\r\n const fillColor = sharedValue(styles.map((s) => s.fillColor));\r\n if (fillColor !== undefined) result.fillColor = fillColor;\r\n const strokeWidth = sharedValue(styles.map((s) => s.strokeWidth));\r\n if (strokeWidth !== undefined) result.strokeWidth = strokeWidth;\r\n const opacity = sharedValue(styles.map((s) => s.opacity));\r\n if (opacity !== undefined) result.opacity = opacity;\r\n const fontSize = sharedValue(styles.map((s) => s.fontSize));\r\n if (fontSize !== undefined) result.fontSize = fontSize;\r\n const strokeStyle = sharedValue(styles.map((s) => s.strokeStyle));\r\n if (strokeStyle !== undefined) result.strokeStyle = strokeStyle;\r\n return result;\r\n }\r\n\r\n /**\r\n * Unlike `getStyle()` — which returns `{}` for a selection whose elements\r\n * have no applicable style fields (e.g. images) — this returns `null` when\r\n * no field is applicable, so callers can distinguish \"nothing to show\" from\r\n * \"everything shared but empty\".\r\n */\r\n getStyleDetails(): SelectionStyleDetails | null {\r\n const ids = this.deps.getSelectedIds();\r\n if (ids.length === 0) return null;\r\n const styles: ElementStyle[] = [];\r\n for (const id of ids) {\r\n const el = this.deps.store.getById(id);\r\n if (el) styles.push(getElementStyle(el));\r\n }\r\n if (styles.length === 0) return null;\r\n const common: ElementStyle = {};\r\n const applicable: (keyof ElementStyle)[] = [];\r\n const mixed: (keyof ElementStyle)[] = [];\r\n for (const field of STYLE_FIELDS) {\r\n const allValues = styles.map((s) => s[field]);\r\n // Filter out undefined values without requiring a type predicate\r\n const values: NonNullable<(typeof allValues)[0]>[] = [];\r\n for (const v of allValues) {\r\n if (v !== undefined) values.push(v);\r\n }\r\n if (values.length === 0) continue;\r\n applicable.push(field);\r\n const distinct = new Set(values);\r\n if (distinct.size > 1) {\r\n mixed.push(field);\r\n } else {\r\n (common as Record<string, unknown>)[field] = values[0];\r\n }\r\n }\r\n if (applicable.length === 0) return null;\r\n return { common, applicable, mixed };\r\n }\r\n\r\n applyStyle(style: ElementStyle): void {\r\n const ids = this.deps.getSelectedIds();\r\n if (ids.length === 0) return;\r\n this.deps.recorder.begin();\r\n for (const id of ids) {\r\n const el = this.deps.store.getById(id);\r\n if (!el) continue;\r\n const patch = styleToPatch(el, style);\r\n if (Object.keys(patch).length > 0) {\r\n this.deps.store.update(id, patch);\r\n }\r\n }\r\n this.deps.recorder.commit();\r\n }\r\n\r\n group(): void {\r\n const ids = this.deps.getSelectedIds();\r\n if (ids.length < 2) return;\r\n const groupId = createId('group');\r\n this.deps.recorder.begin();\r\n for (const id of ids) {\r\n if (this.deps.store.getById(id)) this.deps.store.update(id, { groupId });\r\n }\r\n this.deps.recorder.commit();\r\n }\r\n\r\n ungroup(): void {\r\n const ids = this.deps.getSelectedIds();\r\n if (ids.length === 0) return;\r\n this.deps.recorder.begin();\r\n for (const id of ids) {\r\n const el = this.deps.store.getById(id);\r\n if (el && el.groupId !== undefined) this.deps.store.update(id, { groupId: undefined });\r\n }\r\n this.deps.recorder.commit();\r\n }\r\n\r\n toggleLock(): void {\r\n const ids = this.deps.getSelectedIds();\r\n if (ids.length === 0) return;\r\n const anyUnlocked = ids.some((id) => {\r\n const el = this.deps.store.getById(id);\r\n return el ? !el.locked : false;\r\n });\r\n this.deps.recorder.begin();\r\n for (const id of ids) {\r\n const el = this.deps.store.getById(id);\r\n if (el && el.locked !== anyUnlocked) this.deps.store.update(id, { locked: anyUnlocked });\r\n }\r\n this.deps.recorder.commit();\r\n }\r\n\r\n align(edge: AlignEdge): void {\r\n const bounded = this.boundedSelection();\r\n if (bounded.length < 2) return;\r\n const B = unionBounds(bounded.map((e) => e.bounds));\r\n this.deps.recorder.begin();\r\n const moved: string[] = [];\r\n for (const { id, el, bounds: b } of bounded) {\r\n if (!this.isMovable(el)) continue;\r\n let dx = 0;\r\n let dy = 0;\r\n switch (edge) {\r\n case 'left':\r\n dx = B.x - b.x;\r\n break;\r\n case 'right':\r\n dx = B.x + B.w - (b.x + b.w);\r\n break;\r\n case 'center-x':\r\n dx = B.x + B.w / 2 - (b.x + b.w / 2);\r\n break;\r\n case 'top':\r\n dy = B.y - b.y;\r\n break;\r\n case 'bottom':\r\n dy = B.y + B.h - (b.y + b.h);\r\n break;\r\n case 'middle':\r\n dy = B.y + B.h / 2 - (b.y + b.h / 2);\r\n break;\r\n }\r\n if (dx === 0 && dy === 0) continue;\r\n this.deps.store.update(id, translateElementPatch(el, dx, dy));\r\n moved.push(id);\r\n }\r\n updateArrowsBoundToElements(moved, this.deps.store);\r\n this.deps.recorder.commit();\r\n this.deps.requestRender();\r\n }\r\n\r\n distribute(axis: DistributeAxis): void {\r\n const bounded = this.boundedSelection();\r\n if (bounded.length < 3) return;\r\n const center = (b: Bounds) => (axis === 'horizontal' ? b.x + b.w / 2 : b.y + b.h / 2);\r\n const sorted = [...bounded].sort((p, q) => center(p.bounds) - center(q.bounds));\r\n const first = sorted[0];\r\n const last = sorted[sorted.length - 1];\r\n if (!first || !last) return;\r\n const c0 = center(first.bounds);\r\n const cN = center(last.bounds);\r\n const n = sorted.length;\r\n this.deps.recorder.begin();\r\n const moved: string[] = [];\r\n for (let i = 1; i < n - 1; i++) {\r\n const item = sorted[i];\r\n if (!item || !this.isMovable(item.el)) continue;\r\n const target = c0 + (i * (cN - c0)) / (n - 1);\r\n const delta = target - center(item.bounds);\r\n if (delta === 0) continue;\r\n const [dx, dy] = axis === 'horizontal' ? [delta, 0] : [0, delta];\r\n this.deps.store.update(item.id, translateElementPatch(item.el, dx, dy));\r\n moved.push(item.id);\r\n }\r\n updateArrowsBoundToElements(moved, this.deps.store);\r\n this.deps.recorder.commit();\r\n this.deps.requestRender();\r\n }\r\n\r\n rotateSelection(direction: RotateDirection): void {\r\n const eligible = this.boundedSelection().filter(({ el }) => this.isMovable(el));\r\n if (eligible.length === 0) return;\r\n const delta = direction === 'cw' ? Math.PI / 2 : -Math.PI / 2;\r\n const pivot = rotationPivot(eligible);\r\n this.deps.recorder.begin();\r\n const moved: string[] = [];\r\n for (const { id, el, bounds } of eligible) {\r\n this.deps.store.update(id, rotateElementPatch(el, bounds, pivot, delta));\r\n moved.push(id);\r\n }\r\n updateArrowsBoundToElements(moved, this.deps.store);\r\n this.deps.recorder.commit();\r\n this.deps.requestRender();\r\n }\r\n\r\n private boundedSelection(): { id: string; el: CanvasElement; bounds: Bounds }[] {\r\n const out: { id: string; el: CanvasElement; bounds: Bounds }[] = [];\r\n for (const id of this.deps.getSelectedIds()) {\r\n const el = this.deps.store.getById(id);\r\n if (!el) continue;\r\n const bounds = getElementBounds(el);\r\n if (bounds) out.push({ id, el, bounds });\r\n }\r\n return out;\r\n }\r\n\r\n private isMovable(el: CanvasElement): boolean {\r\n if (el.locked) return false;\r\n if (el.type === 'arrow' && (el.fromBinding ?? el.toBinding)) return false;\r\n return true;\r\n }\r\n}\r\n","import type { ElementStore } from '../elements/element-store';\r\nimport type { HistoryRecorder } from '../history/history-recorder';\r\nimport type { ToolContext } from '../tools/types';\r\nimport type { GridElement } from '../elements/types';\r\nimport { createGrid } from '../elements/element-factory';\r\n\r\nexport interface GridInfo {\r\n gridType: 'square' | 'hex';\r\n hexOrientation: 'pointy' | 'flat';\r\n cellSize: number;\r\n cellRadius: number;\r\n}\r\n\r\nexport interface GridControllerDeps {\r\n store: ElementStore;\r\n recorder: HistoryRecorder;\r\n requestRender: () => void;\r\n getActiveLayerId: () => string;\r\n toolContext: ToolContext;\r\n defaultGridSize: number;\r\n}\r\n\r\nexport class GridController {\r\n private readonly listeners = new Set<(info: GridInfo | null) => void>();\r\n\r\n constructor(private readonly deps: GridControllerDeps) {}\r\n\r\n add(input: {\r\n gridType?: 'square' | 'hex';\r\n hexOrientation?: 'pointy' | 'flat';\r\n cellSize?: number;\r\n strokeColor?: string;\r\n strokeWidth?: number;\r\n opacity?: number;\r\n }): string {\r\n const existing = this.deps.store.getElementsByType('grid')[0];\r\n this.deps.recorder.begin();\r\n if (existing) {\r\n this.deps.store.remove(existing.id);\r\n }\r\n const grid = createGrid({ ...input, layerId: this.deps.getActiveLayerId() });\r\n this.deps.store.add(grid);\r\n this.deps.recorder.commit();\r\n this.deps.requestRender();\r\n return grid.id;\r\n }\r\n\r\n update(\r\n updates: Partial<\r\n Pick<\r\n GridElement,\r\n 'gridType' | 'hexOrientation' | 'cellSize' | 'strokeColor' | 'strokeWidth' | 'opacity'\r\n >\r\n >,\r\n ): void {\r\n const grid = this.deps.store.getElementsByType('grid')[0];\r\n if (!grid) return;\r\n this.deps.recorder.begin();\r\n this.deps.store.update(grid.id, updates);\r\n this.deps.recorder.commit();\r\n this.deps.requestRender();\r\n }\r\n\r\n remove(): void {\r\n const grid = this.deps.store.getElementsByType('grid')[0];\r\n if (!grid) return;\r\n this.deps.recorder.begin();\r\n this.deps.store.remove(grid.id);\r\n this.deps.recorder.commit();\r\n this.deps.requestRender();\r\n }\r\n\r\n getInfo(): GridInfo | null {\r\n const grid = this.deps.store.getElementsByType('grid')[0];\r\n if (!grid) return null;\r\n return {\r\n gridType: grid.gridType,\r\n hexOrientation: grid.hexOrientation,\r\n cellSize: grid.cellSize,\r\n cellRadius: grid.gridType === 'hex' ? grid.cellSize : grid.cellSize / 2,\r\n };\r\n }\r\n\r\n onChange(listener: (info: GridInfo | null) => void): () => void {\r\n this.listeners.add(listener);\r\n return () => {\r\n this.listeners.delete(listener);\r\n };\r\n }\r\n\r\n syncContext(): void {\r\n const grid = this.deps.store.getElementsByType('grid')[0];\r\n if (grid) {\r\n this.deps.toolContext.gridSize = grid.cellSize;\r\n this.deps.toolContext.gridType = grid.gridType;\r\n this.deps.toolContext.hexOrientation = grid.hexOrientation;\r\n } else {\r\n this.deps.toolContext.gridSize = this.deps.defaultGridSize;\r\n this.deps.toolContext.gridType = undefined;\r\n this.deps.toolContext.hexOrientation = undefined;\r\n }\r\n this.notify();\r\n }\r\n\r\n private notify(): void {\r\n const info = this.getInfo();\r\n for (const listener of this.listeners) {\r\n listener(info);\r\n }\r\n }\r\n}\r\n","import type { Camera } from './camera';\nimport type { ElementStore } from '../elements/element-store';\nimport type { ElementRenderer } from '../elements/element-renderer';\nimport type { NoteEditor } from '../elements/note-editor';\nimport type { ArrowLabelEditor } from '../elements/arrow-label-editor';\nimport type { InteractMode } from './interact-mode';\nimport type { DomNodeManager } from './dom-node-manager';\nimport type { RenderLoop } from './render-loop';\nimport type { HistoryRecorder } from '../history/history-recorder';\nimport type { CanvasElement, ArrowElement } from '../elements/types';\nimport { DoubleTapDetector } from './double-tap-detector';\nimport { isNearBezier } from '../elements/arrow-geometry';\nimport { isNoteContentEmpty } from '../elements/note-sanitizer';\n\nconst ARROW_HIT_THRESHOLD = 10;\n\nexport interface ViewportInteractionsDeps {\n store: ElementStore;\n camera: Camera;\n wrapper: HTMLDivElement;\n domLayer: HTMLDivElement;\n renderLoop: RenderLoop;\n domNodeManager: DomNodeManager;\n noteEditor: NoteEditor;\n arrowLabelEditor: ArrowLabelEditor;\n interactMode: InteractMode;\n renderer: ElementRenderer;\n recorder: HistoryRecorder;\n requestRender: () => void;\n addImage: (src: string, position: { x: number; y: number }) => string;\n dropHandler?: (event: DragEvent, worldPosition: { x: number; y: number }) => void;\n}\n\nexport class ViewportInteractions {\n private readonly doubleTapDetector = new DoubleTapDetector();\n private tapDownX = 0;\n private tapDownY = 0;\n\n constructor(private readonly deps: ViewportInteractionsDeps) {}\n\n startEditingElement(id: string): void {\n const element = this.deps.store.getById(id);\n if (!element || (element.type !== 'note' && element.type !== 'text')) return;\n\n this.deps.renderLoop.flush();\n\n const node = this.deps.domNodeManager.getNode(id);\n if (node) {\n this.deps.noteEditor.startEditing(node, id, this.deps.store);\n }\n }\n\n liveFitHeight(elementId: string): void {\n const element = this.deps.store.getById(elementId);\n if (!element || (element.type !== 'note' && element.type !== 'text')) return;\n const node = this.deps.domNodeManager.getNode(elementId);\n if (!node) return;\n const measured = node.scrollHeight;\n if (measured > 0 && measured !== element.size.h) {\n this.deps.store.update(elementId, { size: { w: element.size.w, h: measured } });\n }\n }\n\n fitNoteHeight(elementId: string): void {\n const element = this.deps.store.getById(elementId);\n if (!element || element.type !== 'note') return;\n if (isNoteContentEmpty(element.text)) return;\n const node = this.deps.domNodeManager.getNode(elementId);\n if (!node) return;\n const measured = node.scrollHeight;\n if (measured > element.size.h) {\n this.deps.store.update(elementId, { size: { w: element.size.w, h: measured } });\n }\n }\n\n onTextEditStop(elementId: string): void {\n const element = this.deps.store.getById(elementId);\n if (!element) return;\n\n if (element.type === 'note') {\n if (isNoteContentEmpty(element.text)) {\n this.deps.store.remove(elementId);\n return;\n }\n this.liveFitHeight(elementId);\n return;\n }\n\n if (element.type !== 'text') return;\n\n if (!element.text || element.text.trim() === '') {\n this.deps.store.remove(elementId);\n return;\n }\n\n this.liveFitHeight(elementId);\n }\n\n onTapDown = (e: PointerEvent): void => {\n this.tapDownX = e.clientX;\n this.tapDownY = e.clientY;\n };\n\n onDoubleTap = (e: PointerEvent): void => {\n const dx = e.clientX - this.tapDownX;\n const dy = e.clientY - this.tapDownY;\n const moved = Math.sqrt(dx * dx + dy * dy);\n if (moved > 10) return;\n\n if (!this.doubleTapDetector.feed(e)) return;\n if (typeof document.elementFromPoint !== 'function') return;\n\n const el = document.elementFromPoint(e.clientX, e.clientY);\n\n const nodeEl = (el as HTMLElement | null)?.closest<HTMLDivElement>('[data-element-id]');\n if (nodeEl) {\n const elementId = nodeEl.dataset['elementId'];\n if (elementId) {\n const element = this.deps.store.getById(elementId);\n if (element?.type === 'note' || element?.type === 'text') {\n this.startEditingElement(elementId);\n return;\n }\n }\n }\n\n const rect = this.deps.wrapper.getBoundingClientRect();\n const screen = { x: e.clientX - rect.left, y: e.clientY - rect.top };\n const world = this.deps.camera.screenToWorld(screen);\n\n // HTML embeds keep double-tap priority: you double-tapped inside the embed even if an\n // arrow's curve passes nearby. Arrow-label editing only when no embed is hit.\n const hit = this.hitTestWorld(world);\n if (hit?.type === 'html') {\n this.deps.interactMode.startInteracting(hit.id);\n return;\n }\n\n const arrow = this.findArrowAt(world);\n if (arrow) {\n this.startArrowLabelEdit(arrow);\n }\n };\n\n findArrowAt(world: { x: number; y: number }): ArrowElement | undefined {\n const candidates = this.deps.store.queryPoint(world).reverse();\n for (const el of candidates) {\n if (\n el.type === 'arrow' &&\n isNearBezier(world, el.from, el.to, el.bend, ARROW_HIT_THRESHOLD)\n ) {\n return el;\n }\n }\n return undefined;\n }\n\n startArrowLabelEdit(arrow: ArrowElement): void {\n this.deps.arrowLabelEditor.startEditing({\n arrow,\n layer: this.deps.domLayer,\n store: this.deps.store,\n recorder: this.deps.recorder,\n onDone: () => {\n this.deps.renderer.setLabelEditingId(null);\n this.deps.requestRender();\n },\n });\n // Set AFTER startEditing: starting a new edit cleans up any prior session, whose onDone\n // synchronously clears the editing id — so claim suppression for this arrow last.\n this.deps.renderer.setLabelEditingId(arrow.id);\n }\n\n private hitTestWorld(world: { x: number; y: number }): CanvasElement | null {\n const candidates = this.deps.store.queryPoint(world).reverse();\n for (const el of candidates) {\n if (!('size' in el)) continue;\n const { x, y } = el.position;\n const { w, h } = el.size;\n if (world.x >= x && world.x <= x + w && world.y >= y && world.y <= y + h) {\n return el;\n }\n }\n return null;\n }\n\n onDragOver = (e: DragEvent): void => {\n e.preventDefault();\n };\n\n onDrop = (e: DragEvent): void => {\n e.preventDefault();\n const rect = this.deps.wrapper.getBoundingClientRect();\n const screenPos = { x: e.clientX - rect.left, y: e.clientY - rect.top };\n const worldPos = this.deps.camera.screenToWorld(screenPos);\n\n if (this.deps.dropHandler) {\n this.deps.dropHandler(e, worldPos);\n return;\n }\n\n const files = e.dataTransfer?.files;\n if (!files) return;\n\n for (const file of files) {\n if (!file.type.startsWith('image/')) continue;\n\n const reader = new FileReader();\n reader.onload = () => {\n const src = reader.result;\n if (typeof src !== 'string') return;\n this.deps.addImage(src, worldPos);\n };\n reader.readAsDataURL(file);\n }\n };\n}\n","import type { Point } from '../core/types';\r\nimport type { StrokeElement } from './types';\r\nimport { getElementBounds } from './element-bounds';\r\nimport { getStrokeRenderData } from './stroke-cache';\r\nimport { distSqToSegment } from '../core/geometry';\r\n\r\nexport function hitTestStroke(stroke: StrokeElement, point: Point, radius: number): boolean {\r\n const bounds = getElementBounds(stroke);\r\n if (!bounds) return false;\r\n if (\r\n point.x < bounds.x - radius ||\r\n point.x > bounds.x + bounds.w + radius ||\r\n point.y < bounds.y - radius ||\r\n point.y > bounds.y + bounds.h + radius\r\n ) {\r\n return false;\r\n }\r\n\r\n const radiusSq = radius * radius;\r\n const local: Point = { x: point.x - stroke.position.x, y: point.y - stroke.position.y };\r\n const { segments } = getStrokeRenderData(stroke);\r\n\r\n if (segments.length === 0) {\r\n const p = stroke.points[0];\r\n if (!p) return false;\r\n const dx = p.x - local.x;\r\n const dy = p.y - local.y;\r\n return dx * dx + dy * dy <= radiusSq;\r\n }\r\n\r\n for (const seg of segments) {\r\n if (distSqToSegment(local, seg.start, seg.end) <= radiusSq) return true;\r\n }\r\n return false;\r\n}\r\n","import type { Point } from '../core/types';\r\nimport type { ArrowElement, CanvasElement } from '../elements/types';\r\nimport type { ToolContext } from './types';\r\nimport { getArrowMidpoint, getBendFromPoint } from '../elements/arrow-geometry';\r\nimport { findBindTarget, getElementCenter } from '../elements/arrow-binding';\r\nimport { getElementBounds } from '../elements/element-bounds';\r\n\r\nconst BIND_THRESHOLD = 20;\r\n\r\nexport type ArrowHandle = 'start' | 'mid' | 'end';\r\n\r\nconst HANDLE_RADIUS = 5;\r\nconst HANDLE_HIT_PADDING = 4;\r\n\r\nconst ARROW_HANDLE_CURSORS: Record<ArrowHandle, string> = {\r\n start: 'crosshair',\r\n end: 'crosshair',\r\n mid: 'grab',\r\n};\r\n\r\nexport function getArrowHandleCursor(handle: ArrowHandle, active: boolean): string {\r\n if (handle === 'mid' && active) return 'grabbing';\r\n return ARROW_HANDLE_CURSORS[handle];\r\n}\r\n\r\nexport function getArrowHandlePositions(arrow: ArrowElement): [ArrowHandle, Point][] {\r\n const mid = getArrowMidpoint(arrow.from, arrow.to, arrow.bend);\r\n return [\r\n ['start', arrow.from],\r\n ['mid', mid],\r\n ['end', arrow.to],\r\n ];\r\n}\r\n\r\nexport function hitTestArrowHandles(\r\n world: Point,\r\n selectedIds: string[],\r\n ctx: ToolContext,\r\n): { elementId: string; handle: ArrowHandle } | null {\r\n if (selectedIds.length === 0) return null;\r\n\r\n const zoom = ctx.camera.zoom;\r\n const hitRadius = (HANDLE_RADIUS + HANDLE_HIT_PADDING) / zoom;\r\n\r\n for (const id of selectedIds) {\r\n const el = ctx.store.getById(id);\r\n if (!el || el.type !== 'arrow' || el.locked || (ctx.isLayerLocked?.(el.layerId) ?? false))\r\n continue;\r\n\r\n const handles = getArrowHandlePositions(el);\r\n for (const [handle, pos] of handles) {\r\n const dx = world.x - pos.x;\r\n const dy = world.y - pos.y;\r\n if (dx * dx + dy * dy <= hitRadius * hitRadius) {\r\n return { elementId: id, handle };\r\n }\r\n }\r\n }\r\n\r\n return null;\r\n}\r\n\r\nexport function applyArrowHandleDrag(\r\n handle: ArrowHandle,\r\n elementId: string,\r\n world: Point,\r\n ctx: ToolContext,\r\n): void {\r\n const el = ctx.store.getById(elementId);\r\n if (!el || el.type !== 'arrow' || el.locked || (ctx.isLayerLocked?.(el.layerId) ?? false)) return;\r\n\r\n const threshold = BIND_THRESHOLD / ctx.camera.zoom;\r\n\r\n const layerFilter = (candidate: CanvasElement) => candidate.layerId === el.layerId;\r\n\r\n switch (handle) {\r\n case 'start': {\r\n const excludeId = el.toBinding?.elementId;\r\n const target = findBindTarget(world, ctx.store, threshold, excludeId, layerFilter);\r\n if (target) {\r\n const center = getElementCenter(target);\r\n ctx.store.update(elementId, {\r\n from: center,\r\n position: center,\r\n fromBinding: { elementId: target.id },\r\n });\r\n } else {\r\n ctx.store.update(elementId, {\r\n from: { x: world.x, y: world.y },\r\n position: { x: world.x, y: world.y },\r\n fromBinding: undefined,\r\n });\r\n }\r\n break;\r\n }\r\n case 'end': {\r\n const excludeId = el.fromBinding?.elementId;\r\n const target = findBindTarget(world, ctx.store, threshold, excludeId, layerFilter);\r\n if (target) {\r\n const center = getElementCenter(target);\r\n ctx.store.update(elementId, {\r\n to: center,\r\n toBinding: { elementId: target.id },\r\n });\r\n } else {\r\n ctx.store.update(elementId, {\r\n to: { x: world.x, y: world.y },\r\n toBinding: undefined,\r\n });\r\n }\r\n break;\r\n }\r\n case 'mid': {\r\n const bend = getBendFromPoint(el.from, el.to, world);\r\n ctx.store.update(elementId, { bend });\r\n break;\r\n }\r\n }\r\n\r\n ctx.requestRender();\r\n}\r\n\r\nexport function getArrowHandleDragTarget(\r\n handle: ArrowHandle,\r\n elementId: string,\r\n world: Point,\r\n ctx: ToolContext,\r\n): { x: number; y: number; w: number; h: number } | null {\r\n if (handle === 'mid') return null;\r\n\r\n const el = ctx.store.getById(elementId);\r\n if (!el || el.type !== 'arrow' || el.locked || (ctx.isLayerLocked?.(el.layerId) ?? false)) {\r\n return null;\r\n }\r\n\r\n const threshold = BIND_THRESHOLD / ctx.camera.zoom;\r\n const excludeId = handle === 'start' ? el.toBinding?.elementId : el.fromBinding?.elementId;\r\n const layerFilter = (candidate: CanvasElement) => candidate.layerId === el.layerId;\r\n const target = findBindTarget(world, ctx.store, threshold, excludeId, layerFilter);\r\n if (!target) return null;\r\n\r\n return getElementBounds(target);\r\n}\r\n\r\nexport function renderArrowHandles(\r\n canvasCtx: CanvasRenderingContext2D,\r\n arrow: ArrowElement,\r\n zoom: number,\r\n): void {\r\n const radius = HANDLE_RADIUS / zoom;\r\n const handles = getArrowHandlePositions(arrow);\r\n\r\n canvasCtx.setLineDash([]);\r\n canvasCtx.lineWidth = 1.5 / zoom;\r\n\r\n for (const [handle, pos] of handles) {\r\n canvasCtx.fillStyle = handle === 'mid' ? '#2196F3' : '#ffffff';\r\n canvasCtx.strokeStyle = '#2196F3';\r\n\r\n canvasCtx.beginPath();\r\n canvasCtx.arc(pos.x, pos.y, radius, 0, Math.PI * 2);\r\n canvasCtx.fill();\r\n canvasCtx.stroke();\r\n }\r\n}\r\n\r\nexport function renderArrowHoverHandle(\r\n canvasCtx: CanvasRenderingContext2D,\r\n arrow: ArrowElement,\r\n zoom: number,\r\n): void {\r\n const mid = getArrowMidpoint(arrow.from, arrow.to, arrow.bend);\r\n const radius = HANDLE_RADIUS / zoom;\r\n canvasCtx.fillStyle = '#2196F3';\r\n canvasCtx.strokeStyle = '#2196F3';\r\n canvasCtx.lineWidth = 1.5 / zoom;\r\n canvasCtx.beginPath();\r\n canvasCtx.arc(mid.x, mid.y, radius, 0, Math.PI * 2);\r\n canvasCtx.fill();\r\n canvasCtx.stroke();\r\n}\r\n","import type { Bounds, Point } from '../core/types';\r\nimport type { CanvasElement, ArrowElement } from '../elements/types';\r\nimport type { ElementStore } from '../elements/element-store';\r\nimport type { SnapGuide } from '../elements/snap-guides';\r\nimport { getElementBounds } from '../elements/element-bounds';\r\nimport { rotatePoint } from '../core/geometry';\r\nimport { lineEndpoints } from '../elements/shape-geometry';\r\nimport { renderArrowHandles } from './arrow-handles';\r\n\r\nexport type HandlePosition = 'nw' | 'ne' | 'sw' | 'se';\r\n\r\nexport const HANDLE_SIZE = 8;\r\nexport const HANDLE_HIT_PADDING = 4;\r\nexport const SELECTION_PAD = 4;\r\nexport const ROTATE_HANDLE_OFFSET = 24;\r\nexport const ROTATABLE_TYPES = new Set(['note', 'text', 'image', 'html', 'shape', 'stroke']);\r\n\r\nexport const HANDLE_CURSORS: Record<HandlePosition, string> = {\r\n nw: 'nwse-resize',\r\n se: 'nwse-resize',\r\n ne: 'nesw-resize',\r\n sw: 'nesw-resize',\r\n};\r\n\r\nexport interface OverlayLayout {\r\n center: Point;\r\n corners: [HandlePosition, Point][];\r\n rotateHandle: Point;\r\n angle: number;\r\n}\r\n\r\nexport function getOverlayLayout(el: CanvasElement, zoom: number): OverlayLayout | null {\r\n const bounds = getElementBounds(el);\r\n if (!bounds) return null;\r\n const angle = el.rotation ?? 0;\r\n const pad = SELECTION_PAD / zoom;\r\n const center = { x: bounds.x + bounds.w / 2, y: bounds.y + bounds.h / 2 };\r\n const raw: [HandlePosition, Point][] = [\r\n ['nw', { x: bounds.x - pad, y: bounds.y - pad }],\r\n ['ne', { x: bounds.x + bounds.w + pad, y: bounds.y - pad }],\r\n ['sw', { x: bounds.x - pad, y: bounds.y + bounds.h + pad }],\r\n ['se', { x: bounds.x + bounds.w + pad, y: bounds.y + bounds.h + pad }],\r\n ];\r\n const corners = raw.map(\r\n ([h, p]) => [h, rotatePoint(p, center, angle)] as [HandlePosition, Point],\r\n );\r\n const topMid = { x: center.x, y: bounds.y - pad - ROTATE_HANDLE_OFFSET / zoom };\r\n const rotateHandle = rotatePoint(topMid, center, angle);\r\n return { center, corners, rotateHandle, angle };\r\n}\r\n\r\nexport function templateAimKnob(\r\n el: CanvasElement,\r\n zoom: number,\r\n): { origin: Point; knob: Point } | null {\r\n if (el.type !== 'template') return null;\r\n if (\r\n el.templateShape !== 'cone' &&\r\n el.templateShape !== 'line' &&\r\n el.templateShape !== 'rectangle'\r\n )\r\n return null;\r\n const gap = ROTATE_HANDLE_OFFSET / zoom;\r\n const dist = el.radius + gap;\r\n const origin = el.position;\r\n return {\r\n origin,\r\n knob: {\r\n x: origin.x + dist * Math.cos(el.angle),\r\n y: origin.y + dist * Math.sin(el.angle),\r\n },\r\n };\r\n}\r\n\r\nexport function getHandlePositions(bounds: Bounds): [HandlePosition, Point][] {\r\n return [\r\n ['nw', { x: bounds.x, y: bounds.y }],\r\n ['ne', { x: bounds.x + bounds.w, y: bounds.y }],\r\n ['sw', { x: bounds.x, y: bounds.y + bounds.h }],\r\n ['se', { x: bounds.x + bounds.w, y: bounds.y + bounds.h }],\r\n ];\r\n}\r\n\r\nexport function topMidpoint(layout: { corners: [HandlePosition, Point][] }): Point {\r\n const nw = layout.corners.find(([h]) => h === 'nw')?.[1] ?? { x: 0, y: 0 };\r\n const ne = layout.corners.find(([h]) => h === 'ne')?.[1] ?? { x: 0, y: 0 };\r\n return { x: (nw.x + ne.x) / 2, y: (nw.y + ne.y) / 2 };\r\n}\r\n\r\nexport function drawLockBadge(ctx: CanvasRenderingContext2D, at: Point, zoom: number): void {\r\n const r = 9 / zoom;\r\n ctx.save();\r\n ctx.setLineDash([]);\r\n ctx.beginPath();\r\n ctx.arc(at.x, at.y, r, 0, Math.PI * 2);\r\n ctx.fillStyle = '#ffffff';\r\n ctx.fill();\r\n ctx.strokeStyle = '#2196F3';\r\n ctx.lineWidth = 1.5 / zoom;\r\n ctx.stroke();\r\n const bw = 8 / zoom;\r\n const bh = 6 / zoom;\r\n ctx.fillStyle = '#2196F3';\r\n ctx.fillRect(at.x - bw / 2, at.y - bh / 2 + 1 / zoom, bw, bh);\r\n ctx.beginPath();\r\n ctx.arc(at.x, at.y - bh / 2 + 1 / zoom, 2.5 / zoom, Math.PI, 0);\r\n ctx.lineWidth = 1.4 / zoom;\r\n ctx.stroke();\r\n ctx.restore();\r\n}\r\n\r\nexport function renderMarquee(ctx: CanvasRenderingContext2D, rect: Bounds): void {\r\n ctx.save();\r\n ctx.strokeStyle = '#2196F3';\r\n ctx.fillStyle = 'rgba(33, 150, 243, 0.08)';\r\n ctx.lineWidth = 1;\r\n ctx.setLineDash([4, 4]);\r\n ctx.strokeRect(rect.x, rect.y, rect.w, rect.h);\r\n ctx.fillRect(rect.x, rect.y, rect.w, rect.h);\r\n ctx.restore();\r\n}\r\n\r\nexport function renderBindingHighlights(\r\n ctx: CanvasRenderingContext2D,\r\n arrow: ArrowElement,\r\n zoom: number,\r\n store: ElementStore,\r\n): void {\r\n if (!arrow.fromBinding && !arrow.toBinding) return;\r\n\r\n const pad = SELECTION_PAD / zoom;\r\n\r\n ctx.save();\r\n ctx.strokeStyle = '#2196F3';\r\n ctx.lineWidth = 2 / zoom;\r\n ctx.setLineDash([]);\r\n\r\n const drawn = new Set<string>();\r\n for (const binding of [arrow.fromBinding, arrow.toBinding]) {\r\n if (!binding || drawn.has(binding.elementId)) continue;\r\n drawn.add(binding.elementId);\r\n\r\n const target = store.getById(binding.elementId);\r\n if (!target) continue;\r\n\r\n const bounds = getElementBounds(target);\r\n if (!bounds) continue;\r\n\r\n ctx.strokeRect(bounds.x - pad, bounds.y - pad, bounds.w + pad * 2, bounds.h + pad * 2);\r\n }\r\n\r\n ctx.restore();\r\n}\r\n\r\nexport function renderSelectionBoxes(\r\n ctx: CanvasRenderingContext2D,\r\n p: {\r\n selectedIds: string[];\r\n store: ElementStore;\r\n zoom: number;\r\n isLayerLocked?: (layerId: string) => boolean;\r\n },\r\n): void {\r\n if (p.selectedIds.length === 0) return;\r\n\r\n const zoom = p.zoom;\r\n const handleWorldSize = HANDLE_SIZE / zoom;\r\n\r\n ctx.save();\r\n ctx.strokeStyle = '#2196F3';\r\n ctx.lineWidth = 1.5 / zoom;\r\n ctx.setLineDash([4 / zoom, 4 / zoom]);\r\n\r\n for (const id of p.selectedIds) {\r\n const el = p.store.getById(id);\r\n if (!el) continue;\r\n const locked = el.locked || (p.isLayerLocked?.(el.layerId) ?? false);\r\n\r\n if (el.type === 'arrow') {\r\n if (!locked) renderArrowHandles(ctx, el, zoom);\r\n renderBindingHighlights(ctx, el, zoom, p.store);\r\n continue;\r\n }\r\n\r\n if (el.type === 'shape' && el.shape === 'line') {\r\n if (!locked) {\r\n ctx.setLineDash([]);\r\n ctx.fillStyle = '#ffffff';\r\n const r = handleWorldSize / 2;\r\n for (const pt of lineEndpoints(el)) {\r\n ctx.beginPath();\r\n ctx.arc(pt.x, pt.y, r, 0, Math.PI * 2);\r\n ctx.fill();\r\n ctx.stroke();\r\n }\r\n ctx.setLineDash([4 / zoom, 4 / zoom]);\r\n }\r\n continue;\r\n }\r\n\r\n const bounds = getElementBounds(el);\r\n if (!bounds) continue;\r\n\r\n const layout = getOverlayLayout(el, zoom);\r\n if (!layout) continue;\r\n\r\n const pad = SELECTION_PAD / zoom;\r\n if (layout.angle === 0) {\r\n ctx.strokeRect(bounds.x - pad, bounds.y - pad, bounds.w + pad * 2, bounds.h + pad * 2);\r\n } else {\r\n const ordered = (['nw', 'ne', 'se', 'sw'] as HandlePosition[])\r\n .map((h) => layout.corners.find(([c]) => c === h)?.[1])\r\n .filter((pp): pp is Point => !!pp);\r\n const [p0, ...others] = ordered;\r\n if (p0) {\r\n ctx.beginPath();\r\n ctx.moveTo(p0.x, p0.y);\r\n for (const pp of others) ctx.lineTo(pp.x, pp.y);\r\n ctx.closePath();\r\n ctx.stroke();\r\n }\r\n }\r\n\r\n if (!el.locked) {\r\n if ('size' in el) {\r\n ctx.setLineDash([]);\r\n ctx.fillStyle = '#ffffff';\r\n const corners = layout.angle === 0 ? getHandlePositions(bounds) : layout.corners;\r\n for (const [, pos] of corners) {\r\n ctx.fillRect(\r\n pos.x - handleWorldSize / 2,\r\n pos.y - handleWorldSize / 2,\r\n handleWorldSize,\r\n handleWorldSize,\r\n );\r\n ctx.strokeRect(\r\n pos.x - handleWorldSize / 2,\r\n pos.y - handleWorldSize / 2,\r\n handleWorldSize,\r\n handleWorldSize,\r\n );\r\n }\r\n ctx.setLineDash([4 / zoom, 4 / zoom]);\r\n } else if (el.type === 'template') {\r\n ctx.setLineDash([]);\r\n ctx.fillStyle = '#ffffff';\r\n if (el.templateShape === 'rectangle') {\r\n if (p.selectedIds.length === 1) {\r\n const cos = Math.cos(el.angle);\r\n const sin = Math.sin(el.angle);\r\n const halfW = (el.width ?? 0) / 2;\r\n const pts: [number, number][] = [\r\n [el.position.x + el.radius * cos, el.position.y + el.radius * sin],\r\n [\r\n el.position.x + (el.radius / 2) * cos + halfW * -sin,\r\n el.position.y + (el.radius / 2) * sin + halfW * cos,\r\n ],\r\n ];\r\n for (const [hx, hy] of pts) {\r\n ctx.fillRect(\r\n hx - handleWorldSize / 2,\r\n hy - handleWorldSize / 2,\r\n handleWorldSize,\r\n handleWorldSize,\r\n );\r\n ctx.strokeRect(\r\n hx - handleWorldSize / 2,\r\n hy - handleWorldSize / 2,\r\n handleWorldSize,\r\n handleWorldSize,\r\n );\r\n }\r\n }\r\n } else {\r\n const hx = bounds.x + bounds.w;\r\n const hy = bounds.y + bounds.h;\r\n ctx.fillRect(\r\n hx - handleWorldSize / 2,\r\n hy - handleWorldSize / 2,\r\n handleWorldSize,\r\n handleWorldSize,\r\n );\r\n ctx.strokeRect(\r\n hx - handleWorldSize / 2,\r\n hy - handleWorldSize / 2,\r\n handleWorldSize,\r\n handleWorldSize,\r\n );\r\n }\r\n ctx.setLineDash([4 / zoom, 4 / zoom]);\r\n\r\n if (\r\n p.selectedIds.length === 1 &&\r\n (el.templateShape === 'cone' ||\r\n el.templateShape === 'line' ||\r\n el.templateShape === 'rectangle')\r\n ) {\r\n const aim = templateAimKnob(el, zoom);\r\n if (aim) {\r\n ctx.beginPath();\r\n ctx.moveTo(aim.origin.x, aim.origin.y);\r\n ctx.lineTo(aim.knob.x, aim.knob.y);\r\n ctx.stroke();\r\n\r\n ctx.setLineDash([]);\r\n ctx.fillStyle = '#ffffff';\r\n ctx.beginPath();\r\n ctx.arc(aim.knob.x, aim.knob.y, handleWorldSize / 2, 0, Math.PI * 2);\r\n ctx.fill();\r\n ctx.stroke();\r\n ctx.setLineDash([4 / zoom, 4 / zoom]);\r\n }\r\n }\r\n }\r\n\r\n if (p.selectedIds.length === 1 && ROTATABLE_TYPES.has(el.type)) {\r\n const stemStart = topMidpoint(layout);\r\n const stemEnd = layout.rotateHandle;\r\n ctx.beginPath();\r\n ctx.moveTo(stemStart.x, stemStart.y);\r\n ctx.lineTo(stemEnd.x, stemEnd.y);\r\n ctx.stroke();\r\n\r\n ctx.setLineDash([]);\r\n ctx.fillStyle = '#ffffff';\r\n ctx.beginPath();\r\n ctx.arc(stemEnd.x, stemEnd.y, handleWorldSize / 2, 0, Math.PI * 2);\r\n ctx.fill();\r\n ctx.stroke();\r\n ctx.setLineDash([4 / zoom, 4 / zoom]);\r\n }\r\n }\r\n\r\n if (el.locked) {\r\n const ne = layout.corners.find(([h]) => h === 'ne')?.[1];\r\n if (ne) drawLockBadge(ctx, ne, zoom);\r\n }\r\n }\r\n\r\n ctx.restore();\r\n}\r\n\r\nexport function renderGuideLines(\r\n ctx: CanvasRenderingContext2D,\r\n p: { guides: SnapGuide[]; rect: Bounds | null; currentWorld: Point; zoom: number },\r\n): void {\r\n const zoom = p.zoom;\r\n const rect = p.rect; // cached at drag start (same source as the candidate query)\r\n ctx.save();\r\n ctx.strokeStyle = '#FF4081';\r\n ctx.lineWidth = 1 / zoom;\r\n ctx.setLineDash([]);\r\n for (const g of p.guides) {\r\n ctx.beginPath();\r\n if (g.axis === 'x') {\r\n const y0 = rect ? rect.y : p.currentWorld.y - 1e5;\r\n const y1 = rect ? rect.y + rect.h : p.currentWorld.y + 1e5;\r\n ctx.moveTo(g.position, y0);\r\n ctx.lineTo(g.position, y1);\r\n } else {\r\n const x0 = rect ? rect.x : p.currentWorld.x - 1e5;\r\n const x1 = rect ? rect.x + rect.w : p.currentWorld.x + 1e5;\r\n ctx.moveTo(x0, g.position);\r\n ctx.lineTo(x1, g.position);\r\n }\r\n ctx.stroke();\r\n }\r\n ctx.restore();\r\n}\r\n","import type { Bounds, Point } from '../core/types';\r\nimport type { ToolContext } from './types';\r\nimport { distSqToSegment, rotatePoint, rotatedAABB } from '../core/geometry';\r\nimport type { CanvasElement } from '../elements/types';\r\nimport { isNearBezier } from '../elements/arrow-geometry';\r\nimport { getElementBounds } from '../elements/element-bounds';\r\nimport { hitTestStroke } from '../elements/stroke-hit';\r\nimport { lineEndpoints } from '../elements/shape-geometry';\r\nimport type { HandlePosition } from './select-overlay';\r\nimport {\r\n HANDLE_SIZE,\r\n HANDLE_HIT_PADDING,\r\n ROTATABLE_TYPES,\r\n getOverlayLayout,\r\n templateAimKnob,\r\n} from './select-overlay';\r\n\r\nexport function hitTest(world: Point, ctx: ToolContext): CanvasElement | null {\r\n // Inflate query by hit radius so strokes/arrows near the point are included\r\n const r = 10;\r\n const candidates = ctx.store\r\n .queryRect({ x: world.x - r, y: world.y - r, w: r * 2, h: r * 2 })\r\n .reverse();\r\n for (const el of candidates) {\r\n if (ctx.isLayerVisible && !ctx.isLayerVisible(el.layerId)) continue;\r\n if (ctx.isLayerLocked && ctx.isLayerLocked(el.layerId)) continue;\r\n if (el.type === 'grid') continue;\r\n if (isInsideBounds(world, el)) return el;\r\n }\r\n return null;\r\n}\r\n\r\nexport function isInsideBounds(point: Point, el: CanvasElement): boolean {\r\n if (el.type === 'grid') return false;\r\n const angle = el.rotation ?? 0;\r\n if (angle !== 0) {\r\n const b = getElementBounds(el);\r\n if (b) {\r\n point = rotatePoint(point, { x: b.x + b.w / 2, y: b.y + b.h / 2 }, -angle);\r\n }\r\n }\r\n if (el.type === 'shape' && el.shape === 'line') {\r\n const [a, b] = lineEndpoints(el);\r\n const threshold = Math.max(el.strokeWidth / 2, 6);\r\n return distSqToSegment(point, a, b) <= threshold * threshold;\r\n }\r\n if ('size' in el) {\r\n const s = el.size;\r\n return (\r\n point.x >= el.position.x &&\r\n point.x <= el.position.x + s.w &&\r\n point.y >= el.position.y &&\r\n point.y <= el.position.y + s.h\r\n );\r\n }\r\n\r\n if (el.type === 'stroke') {\r\n return hitTestStroke(el, point, 10);\r\n }\r\n\r\n if (el.type === 'arrow') {\r\n return isNearBezier(point, el.from, el.to, el.bend, 10);\r\n }\r\n\r\n if (el.type === 'template') {\r\n const bounds = getElementBounds(el);\r\n if (!bounds) return false;\r\n return (\r\n point.x >= bounds.x &&\r\n point.x <= bounds.x + bounds.w &&\r\n point.y >= bounds.y &&\r\n point.y <= bounds.y + bounds.h\r\n );\r\n }\r\n\r\n return false;\r\n}\r\n\r\nexport function hitTestResizeHandle(\r\n world: Point,\r\n ctx: ToolContext,\r\n selectedIds: string[],\r\n): { elementId: string; handle: HandlePosition } | null {\r\n if (selectedIds.length === 0) return null;\r\n\r\n const zoom = ctx.camera.zoom;\r\n const handleHalf = (HANDLE_SIZE / 2 + HANDLE_HIT_PADDING) / zoom;\r\n\r\n for (const id of selectedIds) {\r\n const el = ctx.store.getById(id);\r\n if (!el || !('size' in el)) continue;\r\n if (el.locked) continue;\r\n if (el.type === 'shape' && el.shape === 'line') continue;\r\n\r\n const layout = getOverlayLayout(el, zoom);\r\n if (!layout) continue;\r\n for (const [handle, pos] of layout.corners) {\r\n if (Math.abs(world.x - pos.x) <= handleHalf && Math.abs(world.y - pos.y) <= handleHalf) {\r\n return { elementId: id, handle };\r\n }\r\n }\r\n }\r\n\r\n return null;\r\n}\r\n\r\nexport function hitTestRotateHandle(\r\n world: Point,\r\n ctx: ToolContext,\r\n selectedIds: string[],\r\n): { elementId: string } | null {\r\n if (selectedIds.length !== 1) return null;\r\n const id = selectedIds[0];\r\n if (!id) return null;\r\n const el = ctx.store.getById(id);\r\n if (!el || el.locked || !ROTATABLE_TYPES.has(el.type)) return null;\r\n const layout = getOverlayLayout(el, ctx.camera.zoom);\r\n if (!layout) return null;\r\n const r = (HANDLE_SIZE / 2 + HANDLE_HIT_PADDING) / ctx.camera.zoom;\r\n const dx = world.x - layout.rotateHandle.x;\r\n const dy = world.y - layout.rotateHandle.y;\r\n return dx * dx + dy * dy <= r * r ? { elementId: id } : null;\r\n}\r\n\r\nexport function hitTestLineHandles(\r\n world: Point,\r\n ctx: ToolContext,\r\n selectedIds: string[],\r\n): { elementId: string; fixed: Point } | null {\r\n if (selectedIds.length === 0) return null;\r\n const zoom = ctx.camera.zoom;\r\n const r = (HANDLE_SIZE / 2 + HANDLE_HIT_PADDING) / zoom;\r\n const r2 = r * r;\r\n for (const id of selectedIds) {\r\n const el = ctx.store.getById(id);\r\n if (\r\n !el ||\r\n el.type !== 'shape' ||\r\n el.shape !== 'line' ||\r\n el.locked ||\r\n (ctx.isLayerLocked?.(el.layerId) ?? false)\r\n )\r\n continue;\r\n const [a, b] = lineEndpoints(el);\r\n if ((world.x - a.x) ** 2 + (world.y - a.y) ** 2 <= r2) return { elementId: id, fixed: b };\r\n if ((world.x - b.x) ** 2 + (world.y - b.y) ** 2 <= r2) return { elementId: id, fixed: a };\r\n }\r\n return null;\r\n}\r\n\r\nexport function hitTestTemplateResizeHandle(\r\n world: Point,\r\n ctx: ToolContext,\r\n selectedIds: string[],\r\n): string | null {\r\n if (selectedIds.length === 0) return null;\r\n\r\n const zoom = ctx.camera.zoom;\r\n const handleHalf = (HANDLE_SIZE / 2 + HANDLE_HIT_PADDING) / zoom;\r\n\r\n for (const id of selectedIds) {\r\n const el = ctx.store.getById(id);\r\n if (!el || el.type !== 'template') continue;\r\n if (el.templateShape === 'rectangle') continue;\r\n\r\n const bounds = getElementBounds(el);\r\n if (!bounds) continue;\r\n\r\n const hx = bounds.x + bounds.w;\r\n const hy = bounds.y + bounds.h;\r\n if (Math.abs(world.x - hx) <= handleHalf && Math.abs(world.y - hy) <= handleHalf) {\r\n return id;\r\n }\r\n }\r\n\r\n return null;\r\n}\r\n\r\nexport function hitTestTemplateAimHandle(\r\n world: Point,\r\n ctx: ToolContext,\r\n selectedIds: string[],\r\n): { elementId: string } | null {\r\n if (selectedIds.length !== 1) return null;\r\n const id = selectedIds[0];\r\n if (!id) return null;\r\n const el = ctx.store.getById(id);\r\n if (!el || el.locked) return null;\r\n const knob = templateAimKnob(el, ctx.camera.zoom);\r\n if (!knob) return null;\r\n const r = (HANDLE_SIZE / 2 + HANDLE_HIT_PADDING) / ctx.camera.zoom;\r\n const dx = world.x - knob.knob.x;\r\n const dy = world.y - knob.knob.y;\r\n return dx * dx + dy * dy <= r * r ? { elementId: id } : null;\r\n}\r\n\r\nexport function hitTestRectangleLengthHandle(\r\n world: Point,\r\n ctx: ToolContext,\r\n selectedIds: string[],\r\n): { elementId: string } | null {\r\n if (selectedIds.length !== 1) return null;\r\n const id = selectedIds[0];\r\n if (!id) return null;\r\n const el = ctx.store.getById(id);\r\n if (!el || el.locked || el.type !== 'template' || el.templateShape !== 'rectangle') return null;\r\n const zoom = ctx.camera.zoom;\r\n const r = (HANDLE_SIZE / 2 + HANDLE_HIT_PADDING) / zoom;\r\n const hx = el.position.x + el.radius * Math.cos(el.angle);\r\n const hy = el.position.y + el.radius * Math.sin(el.angle);\r\n const dx = world.x - hx;\r\n const dy = world.y - hy;\r\n return dx * dx + dy * dy <= r * r ? { elementId: id } : null;\r\n}\r\n\r\nexport function hitTestRectangleWidthHandle(\r\n world: Point,\r\n ctx: ToolContext,\r\n selectedIds: string[],\r\n): { elementId: string } | null {\r\n if (selectedIds.length !== 1) return null;\r\n const id = selectedIds[0];\r\n if (!id) return null;\r\n const el = ctx.store.getById(id);\r\n if (!el || el.locked || el.type !== 'template' || el.templateShape !== 'rectangle') return null;\r\n const zoom = ctx.camera.zoom;\r\n const r = (HANDLE_SIZE / 2 + HANDLE_HIT_PADDING) / zoom;\r\n const cos = Math.cos(el.angle);\r\n const sin = Math.sin(el.angle);\r\n const halfW = (el.width ?? 0) / 2;\r\n const hx = el.position.x + (el.radius / 2) * cos + halfW * -sin;\r\n const hy = el.position.y + (el.radius / 2) * sin + halfW * cos;\r\n const dx = world.x - hx;\r\n const dy = world.y - hy;\r\n return dx * dx + dy * dy <= r * r ? { elementId: id } : null;\r\n}\r\n\r\nexport function findElementsInRect(marquee: Bounds, ctx: ToolContext): string[] {\r\n const candidates = ctx.store.queryRect(marquee);\r\n const ids: string[] = [];\r\n for (const el of candidates) {\r\n if (ctx.isLayerVisible && !ctx.isLayerVisible(el.layerId)) continue;\r\n if (ctx.isLayerLocked && ctx.isLayerLocked(el.layerId)) continue;\r\n if (el.type === 'grid') continue;\r\n const bounds = getElementBounds(el);\r\n if (bounds && rectsOverlap(marquee, rotatedAABB(bounds, el.rotation ?? 0))) {\r\n ids.push(el.id);\r\n }\r\n }\r\n return ids;\r\n}\r\n\r\nexport function rectsOverlap(a: Bounds, b: Bounds): boolean {\r\n return a.x <= b.x + b.w && a.x + a.w >= b.x && a.y <= b.y + b.h && a.y + a.h >= b.y;\r\n}\r\n","import type { Camera } from './camera';\nimport type { ElementStore } from '../elements/element-store';\nimport type { CanvasElement, HtmlElement } from '../elements/types';\nimport type { Point } from '../core/types';\nimport type { HtmlRouting } from './html-painter-registry';\nimport type { ToolContext } from '../tools/types';\nimport { hitTest } from '../tools/select-hit';\n\nexport interface ElementActivationEvent {\n element: Readonly<CanvasElement>;\n /** Pointerup location converted through the pointerup camera snapshot. */\n world: Point;\n /**\n * Raw `PointerEvent.pointerType`. Usually `'mouse' | 'touch' | 'pen'`, but the\n * spec permits vendor-defined and empty strings, so this is NOT narrowed and\n * NOT normalised.\n */\n pointerType: string;\n gesture: 'single' | 'double';\n}\n\nexport interface ActivationOptions {\n gesture: 'single' | 'double';\n /** Additional host filter, applied on top of the core canvas-routing gate. */\n isActivatable?: (el: Readonly<CanvasElement>) => boolean;\n /** Host-owned camera animators the viewport cannot see. */\n isCameraBusy?: () => boolean;\n /** Maximum pointer travel between down and up. Default `8` (PingInput parity). */\n slopPx?: number;\n /** Maximum gap between the halves of a double tap. Default `300`. */\n doubleDelayMs?: number;\n}\n\nexport interface ElementActivationDeps {\n /** The viewport wrapper. Activation may only fire from a pointerup on it. */\n element: HTMLElement;\n camera: Camera;\n store: ElementStore;\n resolveHtmlRouting: (el: Readonly<HtmlElement>) => HtmlRouting;\n isLayerVisible: (layerId: string) => boolean;\n /** Owner-side busy signal, OR-ed with the host's `options.isCameraBusy`. */\n isCameraBusy?: () => boolean;\n}\n\nexport const DEFAULT_ACTIVATION_SLOP_PX = 8;\nexport const DEFAULT_ACTIVATION_DOUBLE_DELAY_MS = 300;\n\ninterface ActivePointer {\n pointerId: number;\n pointerType: string;\n /** Client-space pointerdown position; slop is measured against this. */\n clientPoint: Point;\n elementId: string;\n cameraRevision: number;\n}\n\ninterface PendingTap {\n elementId: string;\n pointerType: string;\n /**\n * Where the first half landed. Recorded because the contract specifies this\n * record shape, but deliberately NOT compared: pairing is decided by element\n * identity, which is strictly stronger than screen distance (that is exactly\n * what lets two adjacent markers fuse in the shared `DoubleTapDetector`).\n *\n * The consequence is deliberate but worth stating: `slopPx` bounds travel\n * WITHIN one tap and never BETWEEN taps. Two taps on opposite corners of the\n * SAME element, inside `doubleDelayMs`, therefore pair into a `'double'`\n * however far apart they landed — inert for a 40x40 marker, surprising on a\n * 400x400 canvas-routed element.\n */\n clientPoint: Point;\n time: number;\n}\n\nconst PASSIVE: AddEventListenerOptions = { passive: true };\n\nfunction noop(): void {\n // Hit-testing never renders.\n}\n\n/**\n * Turns a gesture on a canvas-painted element into a typed activation event.\n *\n * Canvas-painted elements are not DOM nodes, so they cannot receive DOM events.\n * This controller is the bridge: it hit-tests pointer gestures against the\n * element store and emits `ElementActivationEvent` for the ones a host declared\n * activatable.\n *\n * Like `PingInput`, it is a **passive observer by contract**: every listener is\n * registered `{ passive: true }` and it never calls `preventDefault`,\n * `stopPropagation`, or takes pointer capture, so native scroll/zoom, the active\n * tool, panning and pinch navigation behave exactly as if it were absent.\n *\n * Recognition is **element-aware**: the shared `DoubleTapDetector` compares only\n * time and screen distance, so two adjacent markers could fuse into one double\n * tap. This controller keeps its own pending record and pairs a second tap only\n * when it resolves to the same element id and the same `pointerType`.\n */\nexport class ElementActivation {\n private readonly deps: ElementActivationDeps;\n private readonly options: ActivationOptions;\n private readonly slopPx: number;\n private readonly doubleDelayMs: number;\n private readonly hitContext: ToolContext;\n\n private active: ActivePointer | null = null;\n private pending: PendingTap | null = null;\n private pendingTimer: ReturnType<typeof setTimeout> | null = null;\n private readonly downPointers = new Set<number>();\n private cameraRevision = 0;\n private disposed = false;\n\n private readonly listeners = new Set<(e: ElementActivationEvent) => void>();\n private readonly unsubCamera: () => void;\n private readonly unsubStore: (() => void)[];\n\n private readonly handlePointerDown = (e: PointerEvent): void => this.onPointerDown(e);\n private readonly handlePointerMove = (e: PointerEvent): void => this.onPointerMove(e);\n private readonly handlePointerUp = (e: PointerEvent): void => this.onPointerUp(e);\n private readonly handlePointerCancel = (e: PointerEvent): void => this.onPointerCancel(e);\n private readonly handleWindowPointerEnd = (e: PointerEvent): void => this.onWindowPointerEnd(e);\n private readonly handleInterrupt = (): void => this.reset();\n\n constructor(deps: ElementActivationDeps, options: ActivationOptions) {\n this.slopPx = options.slopPx ?? DEFAULT_ACTIVATION_SLOP_PX;\n this.doubleDelayMs = options.doubleDelayMs ?? DEFAULT_ACTIVATION_DOUBLE_DELAY_MS;\n if (!Number.isFinite(this.slopPx) || this.slopPx < 0) {\n throw new RangeError(`[fieldnotes] activation slopPx must be finite and >= 0`);\n }\n if (!Number.isFinite(this.doubleDelayMs) || this.doubleDelayMs <= 0) {\n throw new RangeError(`[fieldnotes] activation doubleDelayMs must be finite and > 0`);\n }\n this.deps = deps;\n this.options = options;\n\n // Reuses `select-hit`'s topmost-first bounds walk. `isLayerLocked` is\n // deliberately OMITTED rather than passed: locking prevents moving an\n // element, not reading it, so a marker on a locked layer still activates\n // while staying undraggable.\n this.hitContext = {\n camera: deps.camera,\n store: deps.store,\n requestRender: noop,\n isLayerVisible: deps.isLayerVisible,\n };\n\n // Own monotonic revision derived from the existing public `camera.onChange`;\n // integer comparison, never float, and no new public member on `Camera`.\n this.unsubCamera = deps.camera.onChange(() => {\n this.cameraRevision += 1;\n });\n\n this.unsubStore = [\n deps.store.on('remove', (el) => this.forgetElement(el.id)),\n deps.store.on('clear', () => this.reset()),\n ];\n\n deps.element.addEventListener('pointerdown', this.handlePointerDown, PASSIVE);\n deps.element.addEventListener('pointermove', this.handlePointerMove, PASSIVE);\n deps.element.addEventListener('pointerup', this.handlePointerUp, PASSIVE);\n deps.element.addEventListener('pointercancel', this.handlePointerCancel, PASSIVE);\n\n // State-clearing only — these can never activate. Without capture, a pointer\n // pressed on the canvas and released elsewhere would leave a stale record.\n window.addEventListener('pointerup', this.handleWindowPointerEnd, PASSIVE);\n window.addEventListener('pointercancel', this.handleWindowPointerEnd, PASSIVE);\n window.addEventListener('blur', this.handleInterrupt, PASSIVE);\n window.addEventListener('visibilitychange', this.handleInterrupt, PASSIVE);\n }\n\n /**\n * Subscribes to activations. Emission iterates a snapshot with a per-listener\n * try/catch, so one throwing listener cannot break its siblings and a\n * concurrent unsubscribe cannot skip one. Returns an idempotent unsubscribe.\n */\n onActivate(listener: (e: ElementActivationEvent) => void): () => void {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n /** Removes every listener, clears timers and gesture state. Idempotent. */\n dispose(): void {\n if (this.disposed) return;\n this.disposed = true;\n this.reset();\n this.unsubCamera();\n for (const unsub of this.unsubStore) unsub();\n this.deps.element.removeEventListener('pointerdown', this.handlePointerDown);\n this.deps.element.removeEventListener('pointermove', this.handlePointerMove);\n this.deps.element.removeEventListener('pointerup', this.handlePointerUp);\n this.deps.element.removeEventListener('pointercancel', this.handlePointerCancel);\n window.removeEventListener('pointerup', this.handleWindowPointerEnd);\n window.removeEventListener('pointercancel', this.handleWindowPointerEnd);\n window.removeEventListener('blur', this.handleInterrupt);\n window.removeEventListener('visibilitychange', this.handleInterrupt);\n this.listeners.clear();\n }\n\n private now(): number {\n return performance.now();\n }\n\n private isCameraBusy(): boolean {\n return (this.deps.isCameraBusy?.() ?? false) || (this.options.isCameraBusy?.() ?? false);\n }\n\n private toWorld(e: PointerEvent): Point {\n const rect = this.deps.element.getBoundingClientRect();\n return this.deps.camera.screenToWorld({ x: e.clientX - rect.left, y: e.clientY - rect.top });\n }\n\n /**\n * Topmost visible element under `world` that activation accepts, or `null`.\n * The topmost hit wins outright: a rejected hit does not fall through to\n * whatever sits beneath it.\n */\n private resolveTarget(world: Point): CanvasElement | null {\n const hit = hitTest(world, this.hitContext);\n if (!hit) return null;\n // Core-side routing gate: only elements actually drawn on the canvas.\n if (hit.type === 'note' || hit.type === 'text') return null;\n if (hit.type === 'html' && this.deps.resolveHtmlRouting(hit) !== 'canvas') return null;\n if (this.options.isActivatable && !this.options.isActivatable(hit)) return null;\n return hit;\n }\n\n private beyondSlop(from: Point, to: Point): boolean {\n return Math.hypot(to.x - from.x, to.y - from.y) > this.slopPx;\n }\n\n private onPointerDown(e: PointerEvent): void {\n // EVERY contact is tracked, whichever button it reports. Per the Pointer\n // Events spec a pen barrel-button contact arrives as `button === 2`, as does\n // a held mouse right button, yet both are pointers physically down; skipping\n // them here would let the next pointer arm a gesture two-pointers-deep.\n //\n // `downPointers` counts button-presses per pointer id, not physical\n // contacts: a mouse or pen reports ONE constant `pointerId` across buttons,\n // so primary-down, barrel/right-down (same id), then barrel/right-up\n // deletes that id while the primary button is still physically held. This\n // is harmless — the primary button cannot emit another `pointerdown`\n // without an intervening `pointerup`, and `active` is already `null` by\n // then — but it does mean an empty set is not proof no contact remains.\n const hadPointers = this.downPointers.size > 0;\n this.downPointers.add(e.pointerId);\n if (hadPointers) {\n // A second pointer means navigation, not activation. The down-pointer set\n // is deliberately NOT cleared here: the earlier pointers are still down,\n // and forgetting them would let a third pointer arm a gesture mid-pinch.\n this.clearGesture();\n return;\n }\n\n // A non-primary button never ARMS a gesture. On its own — no other pointer\n // down — it also leaves any pending tap alone; only its membership in\n // `downPointers` above affects the pointers that follow it.\n if (e.button !== 0) return;\n\n this.active = null;\n if (this.isCameraBusy()) {\n this.clearPending();\n return;\n }\n\n const target = this.resolveTarget(this.toWorld(e));\n if (!target) {\n // Empty space, or a hit activation rejected: the pending half dies with it.\n this.clearPending();\n return;\n }\n\n this.active = {\n pointerId: e.pointerId,\n pointerType: e.pointerType,\n clientPoint: { x: e.clientX, y: e.clientY },\n elementId: target.id,\n cameraRevision: this.cameraRevision,\n };\n }\n\n private onPointerMove(e: PointerEvent): void {\n const active = this.active;\n if (!active || active.pointerId !== e.pointerId) return;\n if (this.beyondSlop(active.clientPoint, { x: e.clientX, y: e.clientY })) this.clearGesture();\n }\n\n private onPointerUp(e: PointerEvent): void {\n this.downPointers.delete(e.pointerId);\n const active = this.active;\n if (!active || active.pointerId !== e.pointerId) return;\n this.active = null;\n\n if (this.beyondSlop(active.clientPoint, { x: e.clientX, y: e.clientY })) {\n this.clearPending();\n return;\n }\n // Two independent camera signals: moved during the gesture, or busy now.\n if (this.cameraRevision !== active.cameraRevision || this.isCameraBusy()) {\n this.clearPending();\n return;\n }\n\n // Down/up identity: the release must resolve to the SAME element, still\n // activatable and still canvas-routed.\n const world = this.toWorld(e);\n const target = this.resolveTarget(world);\n if (!target || target.id !== active.elementId) {\n this.clearPending();\n return;\n }\n\n if (this.options.gesture === 'single') {\n this.clearPending();\n this.emit({ element: target, world, pointerType: e.pointerType, gesture: 'single' });\n return;\n }\n\n const pending = this.pending;\n const time = this.now();\n // The elapsed-time comparison below is belt-and-braces: `setPending` also\n // arms a `doubleDelayMs` timeout that nulls `pending`, so under both real and\n // fake timers `pending` is already gone whenever the comparison would reject\n // — no test can make it fail, and no mutation of it can be caught. It is kept\n // as the defence against a backgrounded tab, where timer throttling can\n // delay that callback long past the deadline while events still arrive.\n if (\n pending &&\n pending.elementId === target.id &&\n pending.pointerType === e.pointerType &&\n time - pending.time <= this.doubleDelayMs\n ) {\n this.clearPending();\n this.emit({ element: target, world, pointerType: e.pointerType, gesture: 'double' });\n return;\n }\n\n this.setPending({\n elementId: target.id,\n pointerType: e.pointerType,\n clientPoint: { x: e.clientX, y: e.clientY },\n time,\n });\n }\n\n private onPointerCancel(e: PointerEvent): void {\n this.downPointers.delete(e.pointerId);\n // Scoped to the tracked pointer: another pointer's cancel leaves an\n // in-flight gesture alone, but with none in flight the pending half dies.\n if (this.active && this.active.pointerId !== e.pointerId) return;\n this.clearGesture();\n }\n\n /**\n * A pointer pressed on the wrapper and released outside it. State-clearing\n * only: this path can never activate. Events that bubbled up from inside the\n * wrapper were already handled by the wrapper listener.\n */\n private onWindowPointerEnd(e: PointerEvent): void {\n const target = e.target;\n if (target instanceof Node && this.deps.element.contains(target)) return;\n this.downPointers.delete(e.pointerId);\n if (this.active && this.active.pointerId !== e.pointerId) return;\n this.clearGesture();\n }\n\n private forgetElement(id: string): void {\n if (this.active?.elementId === id) this.active = null;\n if (this.pending?.elementId === id) this.clearPending();\n }\n\n private setPending(pending: PendingTap): void {\n this.clearPending();\n this.pending = pending;\n this.pendingTimer = setTimeout(() => this.clearPending(), this.doubleDelayMs);\n }\n\n private clearPending(): void {\n this.pending = null;\n if (this.pendingTimer !== null) {\n clearTimeout(this.pendingTimer);\n this.pendingTimer = null;\n }\n }\n\n /** Drops the in-flight gesture and its pending half; leaves pointer bookkeeping. */\n private clearGesture(): void {\n this.active = null;\n this.clearPending();\n }\n\n /** Drops everything, including which pointers are believed to be down. */\n private reset(): void {\n this.clearGesture();\n this.downPointers.clear();\n }\n\n private emit(event: ElementActivationEvent): void {\n for (const listener of [...this.listeners]) {\n try {\n listener(event);\n } catch {\n // A throwing host listener must not break its siblings or input handling.\n }\n }\n }\n}\n","import { Camera } from './camera';\nimport type { CameraOptions } from './camera';\nimport { InputHandler } from './input-handler';\nimport type { ShortcutOptions, ShortcutsApi } from './shortcut-map';\nimport { Background } from './background';\nimport type { BackgroundOptions } from './background';\nimport { ElementStore } from '../elements/element-store';\nimport { ElementRenderer } from '../elements/element-renderer';\nimport { NoteEditor } from '../elements/note-editor';\nimport type { FontSizePreset } from '../elements/note-toolbar';\nimport type {\n CanvasElement,\n ArrowElement,\n GridElement,\n HtmlElement,\n ShapeKind,\n} from '../elements/types';\nimport type { Point, Bounds } from '../core/types';\nimport { ContextMenu } from './context-menu';\nimport type { ContextMenuItem } from './context-menu';\nimport { Minimap } from './minimap';\nimport { createWrapper, createCanvas, createDomLayer, createPaintStack } from './viewport-dom';\nimport { HybridRenderSurface } from './hybrid-render-surface';\nimport { findBoundArrows, getEdgeIntersection } from '../elements/arrow-binding';\nimport { getElementBounds } from '../elements/element-bounds';\nimport { getElementsBoundingBox } from '../elements/bounds';\nimport { getArrowTangentAngle } from '../elements/arrow-geometry';\nimport { ArrowLabelEditor } from '../elements/arrow-label-editor';\nimport { ToolManager } from '../tools/tool-manager';\nimport type { ToolContext, Tool } from '../tools/types';\nimport type { SelectTool } from '../tools/select-tool';\nimport { HistoryStack } from '../history/history-stack';\nimport { HistoryRecorder } from '../history/history-recorder';\nimport { createImage, createHtmlElement, createShape } from '../elements/element-factory';\nimport { exportState as exportCanvasState, parseState } from '../core/state-serializer';\nimport { exportImage } from './export-image';\nimport type { ExportImageOptions } from './export-image';\nimport { exportSvg } from './export-svg';\nimport type { ExportSvgOptions } from './export-svg';\nimport type { CanvasState } from '../core/state-serializer';\nimport { LayerManager } from '../layers/layer-manager';\nimport { InteractMode } from './interact-mode';\nimport { DomNodeManager } from './dom-node-manager';\nimport { RenderLoop } from './render-loop';\nimport type { OverlayRenderer } from './render-loop';\nimport { HtmlPainterRegistry, resolveHtmlRouting } from './html-painter-registry';\nimport type { HtmlPainter, HtmlRouting } from './html-painter-registry';\nimport { HtmlPaintDiagnosticDeduper } from './html-paint-diagnostics';\nimport type { HtmlPaintDiagnostic } from './html-paint-diagnostics';\nimport type { RenderStatsSnapshot } from './render-stats';\nimport { LayerCache } from './layer-cache';\nimport { MarginViewport } from './margin-viewport';\nimport type { ElementStyle } from '../elements/element-style';\nimport { SelectionOps } from './selection-ops';\nimport type { SelectionStyleDetails } from './selection-ops';\nimport type { AlignEdge, DistributeAxis } from './selection-ops';\nimport { GridController } from './grid-controller';\nimport type { GridInfo } from './grid-controller';\nimport { ViewportInteractions } from './viewport-interactions';\nimport type { RotateDirection } from './selection-rotate';\nimport { ElementActivation } from './element-activation';\nimport type { ActivationOptions, ElementActivationEvent } from './element-activation';\n\nexport type { AlignEdge, DistributeAxis } from './selection-ops';\nexport type { GridInfo } from './grid-controller';\nexport type { RotateDirection } from './selection-rotate';\n\nconst EMPTY_IDS: string[] = [];\n\nfunction noop(): void {\n // Stable unsubscribe handle returned when no select tool is registered.\n}\n\nexport interface ViewportOptions {\n camera?: CameraOptions;\n background?: BackgroundOptions;\n fontSizePresets?: FontSizePreset[];\n toolbar?: boolean;\n placeholder?: string;\n shortcuts?: ShortcutOptions;\n onHtmlElementMount?: (\n elementId: string,\n domId: string | undefined,\n container: HTMLDivElement,\n ) => void;\n onDrop?: (event: DragEvent, worldPosition: { x: number; y: number }) => void;\n onPaste?: (event: ClipboardEvent, worldPosition: { x: number; y: number }) => void;\n onImageError?: (info: { src: string; elementIds: string[]; cause?: unknown }) => void;\n /** CSS-pixel margin cached beyond the viewport. Default `256`. Set `0` to disable. */\n panBufferMargin?: number;\n /** Enable the built-in context menu. Default `true`. */\n contextMenu?: boolean;\n /** Coast (inertial glide) after a pan flick. Default `true`. */\n panInertia?: boolean;\n /** Show an overview minimap (bottom-right) with tap/drag-to-navigate. Default `false`. */\n minimap?: boolean;\n}\n\nexport class Viewport {\n readonly camera: Camera;\n readonly store: ElementStore;\n readonly layerManager: LayerManager;\n readonly toolManager: ToolManager;\n readonly history: HistoryStack;\n readonly domLayer: HTMLDivElement;\n private readonly canvasEl: HTMLCanvasElement;\n private readonly paintStack: HTMLDivElement;\n private readonly wrapper: HTMLDivElement;\n private readonly unsubCamera: () => void;\n private readonly unsubToolChange: () => void;\n private readonly unsubStore: (() => void)[];\n private readonly inputHandler: InputHandler;\n private readonly background: Background;\n private readonly renderer: ElementRenderer;\n private readonly noteEditor: NoteEditor;\n private readonly arrowLabelEditor: ArrowLabelEditor;\n private readonly historyRecorder: HistoryRecorder;\n private transactionDepth = 0;\n private readonly selectionOps: SelectionOps;\n readonly toolContext: ToolContext;\n private readonly marginViewport: MarginViewport;\n private resizeObserver: ResizeObserver | null = null;\n private _snapToGrid = false;\n private _smartGuides = false;\n private readonly _gridSize: number;\n private readonly renderLoop: RenderLoop;\n private readonly domNodeManager: DomNodeManager;\n private readonly interactMode: InteractMode;\n private readonly onHtmlElementMount?: (\n elementId: string,\n domId: string | undefined,\n container: HTMLDivElement,\n ) => void;\n private readonly dropHandler?: (\n event: DragEvent,\n worldPosition: { x: number; y: number },\n ) => void;\n private readonly gridController: GridController;\n private readonly interactions: ViewportInteractions;\n private contextMenu: ContextMenu | null = null;\n private minimap: Minimap | null = null;\n private readonly htmlRenderers = new Map<string, (el: HtmlElement) => HTMLElement>();\n private readonly htmlPainters = new HtmlPainterRegistry();\n private readonly htmlDiagnosticListeners = new Set<(d: HtmlPaintDiagnostic) => void>();\n private readonly htmlDiagnostics = new HtmlPaintDiagnosticDeduper((d) => {\n for (const listener of [...this.htmlDiagnosticListeners]) {\n try {\n listener(d);\n } catch {\n /* isolated: one listener's fault must not break its siblings */\n }\n }\n });\n private readonly resolveRouting = (el: HtmlElement): HtmlRouting =>\n resolveHtmlRouting(el, this.htmlPainters);\n private readonly unsubHtmlPainters: () => void;\n private activation: ElementActivation | null = null;\n private activationGeneration = 0;\n private readonly activationListeners = new Set<(e: ElementActivationEvent) => void>();\n private readonly resizeListeners = new Set<() => void>();\n private readonly selectionListeners = new Set<() => void>();\n private detachSelectionSource: (() => void) | null = null;\n private unsubToolRegister: () => void = () => {\n // Replaced synchronously in the constructor below.\n };\n private pendingSelectionPrune = false;\n private unsubRecorderEnd: () => void = () => {\n // Replaced synchronously in the constructor below.\n };\n\n constructor(\n private readonly container: HTMLElement,\n options: ViewportOptions = {},\n ) {\n this.camera = new Camera(options.camera);\n this.background = new Background(options.background);\n this._gridSize = options.background?.spacing ?? 24;\n this.store = new ElementStore();\n this.layerManager = new LayerManager(this.store);\n this.toolManager = new ToolManager();\n this.unsubToolRegister = this.toolManager.onRegister((tool) => {\n if (Viewport.isSelectionSource(tool)) this.attachSelectionSource(tool);\n });\n const existingSelect = this.getSelectTool();\n if (existingSelect && Viewport.isSelectionSource(existingSelect)) {\n this.attachSelectionSource(existingSelect);\n }\n this.renderer = new ElementRenderer();\n this.renderer.setStore(this.store);\n this.renderer.setCamera(this.camera);\n this.renderer.setOnImageLoad(() => {\n this.renderLoop.markAllLayersDirty();\n this.requestRender();\n });\n this.renderer.setOnImageError((src, cause) => {\n const elementIds: string[] = [];\n for (const el of this.store.getAll()) {\n if (el.type === 'image' && el.src === src) elementIds.push(el.id);\n }\n if (options.onImageError) {\n options.onImageError({ src, elementIds, cause });\n } else {\n console.warn(`[fieldnotes] image failed to load: ${src}`);\n }\n });\n this.renderer.setHtmlPainters(this.htmlPainters);\n this.renderer.setDiagnosticSink((d) => {\n this.htmlDiagnostics.emit(d, {\n registryVersion: this.htmlPainters.version,\n elementVersion: this.store.getVersion(d.elementId),\n });\n });\n this.noteEditor = new NoteEditor({\n fontSizePresets: options.fontSizePresets,\n toolbar: options.toolbar,\n placeholder: options.placeholder,\n });\n this.noteEditor.setOnStop((id) => this.interactions.onTextEditStop(id));\n this.noteEditor.setOnInput((id) => this.interactions.liveFitHeight(id));\n this.arrowLabelEditor = new ArrowLabelEditor();\n this.noteEditor.setHistoryHooks(\n () => this.historyRecorder.begin(),\n () => this.historyRecorder.commit(),\n );\n this.onHtmlElementMount = options.onHtmlElementMount;\n this.dropHandler = options.onDrop;\n this.history = new HistoryStack();\n this.historyRecorder = new HistoryRecorder(this.store, this.history, this.layerManager);\n this.unsubRecorderEnd = this.historyRecorder.onTransactionEnd(() => {\n if (!this.pendingSelectionPrune) return;\n this.pendingSelectionPrune = false;\n this.pruneSelection();\n });\n this.selectionOps = new SelectionOps({\n store: this.store,\n recorder: this.historyRecorder,\n getSelectedIds: () => this.getSelectedIds(),\n requestRender: () => this.requestRender(),\n });\n\n this.wrapper = createWrapper();\n this.canvasEl = createCanvas();\n this.paintStack = createPaintStack();\n this.domLayer = createDomLayer();\n this.domLayer.style.zIndex = '2147483647';\n\n this.wrapper.appendChild(this.canvasEl);\n this.wrapper.appendChild(this.paintStack);\n this.wrapper.appendChild(this.domLayer);\n this.container.appendChild(this.wrapper);\n\n this.toolContext = {\n camera: this.camera,\n store: this.store,\n requestRender: () => this.requestRender(),\n switchTool: (name: string) => this.toolManager.setTool(name, this.toolContext),\n editElement: (id: string) => this.interactions.startEditingElement(id),\n fitNoteHeight: (id: string) => this.interactions.fitNoteHeight(id),\n setCursor: (cursor: string) => {\n this.wrapper.style.cursor = cursor;\n },\n snapToGrid: false,\n gridSize: this._gridSize,\n activeLayerId: this.layerManager.activeLayerId,\n isLayerVisible: (id: string) => this.layerManager.isLayerVisible(id),\n isLayerLocked: (id: string) => this.layerManager.isLayerLocked(id),\n smartGuides: false,\n getVisibleRect: () =>\n this.camera.getVisibleRect(this.canvasEl.clientWidth, this.canvasEl.clientHeight),\n };\n\n this.inputHandler = new InputHandler(this.wrapper, this.camera, {\n toolManager: this.toolManager,\n toolContext: this.toolContext,\n historyRecorder: this.historyRecorder,\n historyStack: this.history,\n fitToContent: () => this.fitToContent(),\n group: () => this.groupSelection(),\n ungroup: () => this.ungroupSelection(),\n toggleLock: () => this.toggleLockSelection(),\n rotate: (direction) => this.rotateSelection(direction),\n openContextMenu: (screenPos, world) => {\n this.getSelectTool()?.selectAtPoint(world, this.toolContext);\n this.openContextMenu(screenPos);\n },\n shortcuts: options.shortcuts,\n addImage: (src, world) => this.addImage(src, world),\n getCenteredWorld: () => this.centeredPosition({ w: 300, h: 200 }),\n onPaste: options.onPaste,\n panInertia: options.panInertia,\n });\n\n if (options.contextMenu !== false) {\n this.contextMenu = new ContextMenu({\n onCommand: (action) => this.runAction(action),\n onClose: noop,\n });\n }\n this.unsubToolChange = this.toolManager.onChange(() => this.contextMenu?.close());\n\n if (options.minimap) {\n this.minimap = new Minimap(this.wrapper, this);\n }\n\n this.domNodeManager = new DomNodeManager({\n domLayer: this.paintStack,\n onEditRequest: (id) => this.interactions.startEditingElement(id),\n isEditingElement: (id) =>\n this.noteEditor.isEditing && this.noteEditor.editingElementId === id,\n getVersion: (id) => this.store.getVersion(id),\n });\n this.domNodeManager.setCameraTransform(this.camera.toCSSTransform());\n\n this.interactMode = new InteractMode({\n getNode: (id) => this.domNodeManager.getNode(id),\n });\n\n this.marginViewport = new MarginViewport(options.panBufferMargin ?? 256);\n this.marginViewport.setViewport(\n this.canvasEl.clientWidth || 800,\n this.canvasEl.clientHeight || 600,\n typeof devicePixelRatio !== 'undefined' ? devicePixelRatio : 1,\n );\n const layerCache = new LayerCache(this.marginViewport);\n\n this.renderLoop = new RenderLoop({\n canvasEl: this.canvasEl,\n camera: this.camera,\n background: this.background,\n store: this.store,\n renderer: this.renderer,\n toolManager: this.toolManager,\n layerManager: this.layerManager,\n domNodeManager: this.domNodeManager,\n layerCache,\n marginViewport: this.marginViewport,\n hybridSurface: new HybridRenderSurface(this.paintStack),\n });\n\n this.unsubHtmlPainters = this.htmlPainters.onChange(() => this.onHtmlRegistryChanged());\n\n this.unsubCamera = this.camera.onChange(() => {\n this.applyCameraTransform();\n this.noteEditor.updateToolbarPosition();\n this.contextMenu?.close();\n this.requestRender();\n });\n\n this.gridController = new GridController({\n store: this.store,\n recorder: this.historyRecorder,\n requestRender: () => this.requestRender(),\n getActiveLayerId: () => this.layerManager.activeLayerId,\n toolContext: this.toolContext,\n defaultGridSize: this._gridSize,\n });\n\n this.unsubStore = [\n this.store.on('add', (el) => {\n if (el.type === 'grid') this.gridController.syncContext();\n if (el.type === 'html') {\n this.domNodeManager.reconcileHtmlRouting(this.store, this.resolveRouting);\n }\n this.renderLoop.markLayerDirty(el.layerId);\n this.requestRender();\n }),\n this.store.on('remove', (el) => {\n if (el.type === 'grid') this.gridController.syncContext();\n this.unbindArrowsFrom(el);\n this.domNodeManager.removeDomNode(el.id);\n this.htmlDiagnostics.forget(el.id);\n this.renderLoop.markLayerDirty(el.layerId);\n this.requestRender();\n this.handleRemovedElement(el.id);\n }),\n this.store.on('update', ({ previous, current }) => {\n if (current.type === 'grid') this.gridController.syncContext();\n if (current.type === 'html') {\n this.domNodeManager.reconcileHtmlRouting(this.store, this.resolveRouting);\n }\n this.renderLoop.markLayerDirty(current.layerId);\n if (previous.layerId !== current.layerId) {\n this.renderLoop.markLayerDirty(previous.layerId);\n }\n this.requestRender();\n }),\n this.store.on('clear', () => {\n this.domNodeManager.clearDomNodes();\n this.htmlDiagnostics.reset();\n this.renderLoop.markAllLayersDirty();\n this.gridController.syncContext();\n this.requestRender();\n this.pruneSelection();\n }),\n ];\n\n this.layerManager.on('change', () => {\n this.toolContext.activeLayerId = this.layerManager.activeLayerId;\n this.renderLoop.markAllLayersDirty();\n this.requestRender();\n });\n\n this.interactions = new ViewportInteractions({\n store: this.store,\n camera: this.camera,\n wrapper: this.wrapper,\n domLayer: this.domLayer,\n renderLoop: this.renderLoop,\n domNodeManager: this.domNodeManager,\n noteEditor: this.noteEditor,\n arrowLabelEditor: this.arrowLabelEditor,\n interactMode: this.interactMode,\n renderer: this.renderer,\n recorder: this.historyRecorder,\n requestRender: () => this.requestRender(),\n addImage: (src, position) => this.addImage(src, position),\n dropHandler: this.dropHandler,\n });\n\n this.wrapper.addEventListener('pointerdown', this.interactions.onTapDown);\n this.wrapper.addEventListener('pointerup', this.interactions.onDoubleTap);\n this.wrapper.addEventListener('dragover', this.interactions.onDragOver);\n this.wrapper.addEventListener('drop', this.interactions.onDrop);\n this.observeResize();\n this.syncCanvasSize();\n this.renderLoop.start();\n this.gridController.syncContext();\n }\n\n get ctx(): CanvasRenderingContext2D | null {\n return this.canvasEl.getContext('2d');\n }\n\n get snapToGrid(): boolean {\n return this._snapToGrid;\n }\n\n setSnapToGrid(enabled: boolean): void {\n this._snapToGrid = enabled;\n this.toolContext.snapToGrid = enabled;\n }\n\n get smartGuides(): boolean {\n return this._smartGuides;\n }\n\n setSmartGuides(enabled: boolean): void {\n this._smartGuides = enabled;\n this.toolContext.smartGuides = enabled;\n }\n\n fitToContent(padding = 40): void {\n if (this.wrapper.clientWidth === 0 || this.wrapper.clientHeight === 0) return;\n const visibleElements = this.store\n .getAll()\n .filter((el) => this.layerManager.isLayerVisible(el.layerId));\n const bbox = getElementsBoundingBox(visibleElements);\n if (!bbox) return;\n this.camera.fitToContent(bbox, this.wrapper.clientWidth, this.wrapper.clientHeight, padding);\n }\n\n /** World-space rectangle currently visible through the canvas. */\n getVisibleRect(): Bounds {\n return this.camera.getVisibleRect(this.canvasEl.clientWidth, this.canvasEl.clientHeight);\n }\n\n /**\n * Size in CSS pixels of the canvas that `getVisibleRect()` measures.\n * Exposed because `canvasEl` is private: consumers can only reach the\n * wrapper (via `domLayer.parentElement`), so without this accessor the\n * canonical size behind `getVisibleRect()` is unreachable and callers\n * resort to `getVisibleRect().w * camera.zoom`. Capture and restore must\n * measure the same element or saved views do not round-trip.\n */\n getCanvasSize(): { w: number; h: number } {\n return { w: this.canvasEl.clientWidth, h: this.canvasEl.clientHeight };\n }\n\n /** Centers the camera on a world point without changing zoom. */\n centerCameraAt(world: Point): void {\n const z = this.camera.zoom;\n this.camera.moveTo(\n this.canvasEl.clientWidth / 2 - world.x * z,\n this.canvasEl.clientHeight / 2 - world.y * z,\n );\n }\n\n /**\n * Notifies after the host container resizes (ResizeObserver-driven). A resize\n * changes the visible world rect without a camera event; overlays such as the\n * minimap subscribe to stay current. Returns an idempotent unsubscribe.\n */\n onResize(listener: () => void): () => void {\n this.resizeListeners.add(listener);\n return () => this.resizeListeners.delete(listener);\n }\n\n requestRender(): void {\n this.renderLoop.requestRender();\n }\n\n /**\n * Registers a world-space overlay drawn above elements on every frame,\n * regardless of the active tool — the surface for remote presence visuals\n * such as laser trails, cursors, pings, and shared rulers. Overlays draw\n * beneath the active tool's own `renderOverlay` and never touch elements,\n * history, or persisted state. Returns an idempotent unsubscribe that also\n * erases the overlay's last frame.\n */\n registerOverlay(draw: OverlayRenderer): () => void {\n return this.renderLoop.registerOverlay(draw);\n }\n\n exportState(): CanvasState {\n return exportCanvasState(\n this.store.snapshot(),\n this.camera,\n this.layerManager.snapshot(),\n this.layerManager.activeLayerId,\n );\n }\n\n exportJSON(): string {\n return JSON.stringify(this.exportState());\n }\n\n /**\n * Injects this viewport's own html painter registry into export options so a host\n * that registered painters via `registerHtmlPainter`/`expectCanvasHtmlTypes` gets\n * markers in exports without passing anything. An explicitly passed `htmlPainters`\n * REPLACES the viewport's registry rather than merging with it. `expectedCanvasTypes`\n * is always UNIONED with the resolved registry's own declarations — a caller's set\n * can only add expectations, never shrink the registry's own.\n */\n private withHtmlDefaults<\n T extends { htmlPainters?: HtmlPainterRegistry; expectedCanvasTypes?: ReadonlySet<string> },\n >(options?: T): T {\n const base = (options ?? {}) as T;\n const registry = base.htmlPainters ?? this.htmlPainters;\n const declared = registry.canvasTypes;\n const expected = base.expectedCanvasTypes\n ? new Set([...declared, ...base.expectedCanvasTypes]) // union only; never shrink\n : declared;\n return { ...base, htmlPainters: registry, expectedCanvasTypes: expected };\n }\n\n async exportImage(options?: ExportImageOptions): Promise<Blob | null> {\n return exportImage(this.store, this.withHtmlDefaults(options), this.layerManager);\n }\n\n async exportSVG(options?: ExportSvgOptions): Promise<string> {\n return exportSvg(this.store, this.withHtmlDefaults(options), this.layerManager);\n }\n\n loadState(state: CanvasState): void {\n this.inputHandler.flushPendingHistory();\n this.historyRecorder.pause();\n this.noteEditor.destroy(this.store);\n this.domNodeManager.clearDomNodes();\n this.store.loadSnapshot(state.elements);\n if (state.layers && state.layers.length > 0) {\n this.layerManager.loadSnapshot(state.layers);\n }\n if (state.activeLayerId) {\n this.layerManager.setActiveLayer(state.activeLayerId);\n }\n this.domNodeManager.reattachHtmlContent(this.store);\n for (const el of this.store.getElementsByType('html')) {\n if (this.domNodeManager.hasContent(el.id)) continue;\n\n // Registry first: rebuild the embed from serialized data and mount it via the html branch\n // of renderDomContent. This stores content BEFORE the onHtmlElementMount path's hasContent\n // check, so a factory-rebuilt element never also gets an empty node from the callback path.\n const factory = el.htmlType ? this.htmlRenderers.get(el.htmlType) : undefined;\n const rebuilt = factory ? factory(el) : null;\n if (rebuilt) {\n this.domNodeManager.storeHtmlContent(el.id, rebuilt);\n this.domNodeManager.syncDomNode(el);\n }\n\n // Callback still fires for wiring (both fire; registry produces the node, callback wires it).\n if (this.onHtmlElementMount) {\n if (!rebuilt) this.domNodeManager.syncDomNode(el);\n const node = this.domNodeManager.getNode(el.id);\n if (node) {\n this.onHtmlElementMount(el.id, el.domId, node);\n // The host mounted its content INTO the node; nothing else records it. Without\n // this marker a routing change to canvas would detach the node and destroy the\n // host's content, and the return leg would mount a fresh, permanently empty one.\n this.domNodeManager.markHostOwnedContent(el.id);\n node.dataset['initialized'] = 'true';\n Object.assign(node.style, {\n overflow: 'hidden',\n pointerEvents: el.interactive ? 'auto' : 'none',\n });\n }\n }\n }\n this.history.clear();\n this.historyRecorder.resume();\n this.camera.moveTo(state.camera.position.x, state.camera.position.y);\n this.camera.setZoom(state.camera.zoom);\n this.domNodeManager.reconcileHtmlRouting(this.store, this.resolveRouting);\n }\n\n loadJSON(json: string): void {\n this.loadState(parseState(json));\n }\n\n setTool(name: string): void {\n if (!this.toolManager.getTool(name)) {\n console.warn(`[fieldnotes] setTool: no tool registered as \"${name}\"`);\n return;\n }\n this.toolManager.setTool(name, this.toolContext);\n }\n\n get shortcuts(): ShortcutsApi {\n return this.inputHandler.shortcuts;\n }\n\n /**\n * Groups synchronous local store and layer mutations into one undo step.\n * Nested calls join the outer transaction. If the callback throws, mutations\n * already applied remain undoable and the original error is rethrown.\n */\n transaction<T>(operation: () => T): T {\n const isOuterTransaction = this.transactionDepth === 0;\n if (isOuterTransaction) {\n this.inputHandler.flushPendingHistory();\n this.historyRecorder.begin();\n }\n this.transactionDepth += 1;\n try {\n return operation();\n } finally {\n this.transactionDepth -= 1;\n if (isOuterTransaction) this.historyRecorder.commit();\n }\n }\n\n /** Removes existing elements as one undoable operation and returns the number removed. */\n removeElements(ids: Iterable<string>): number {\n const existingIds = [...new Set(ids)].filter((id) => this.store.getById(id) !== undefined);\n if (existingIds.length === 0) return 0;\n this.transaction(() => {\n for (const id of existingIds) this.store.remove(id);\n });\n this.requestRender();\n return existingIds.length;\n }\n\n undo(): boolean {\n this.inputHandler.flushPendingHistory();\n this.historyRecorder.pause();\n const result = this.history.undo(this.store);\n this.historyRecorder.resume();\n if (result) this.requestRender();\n return result;\n }\n\n redo(): boolean {\n this.inputHandler.flushPendingHistory();\n this.historyRecorder.pause();\n const result = this.history.redo(this.store);\n this.historyRecorder.resume();\n if (result) this.requestRender();\n return result;\n }\n\n addImage(src: string, position: { x: number; y: number }, size = { w: 300, h: 200 }): string {\n const image = createImage({ position, size, src, layerId: this.layerManager.activeLayerId });\n this.historyRecorder.begin();\n this.store.add(image);\n this.historyRecorder.commit();\n this.requestRender();\n return image.id;\n }\n\n addHtmlElement(\n dom: HTMLElement,\n position: { x: number; y: number },\n size = { w: 200, h: 150 },\n opts?: { htmlType?: string; data?: Record<string, unknown> },\n ): string {\n const domId = dom.id || undefined;\n const el = createHtmlElement({\n position,\n size,\n domId,\n htmlType: opts?.htmlType,\n data: opts?.data,\n layerId: this.layerManager.activeLayerId,\n });\n this.domNodeManager.storeHtmlContent(el.id, dom);\n this.historyRecorder.begin();\n this.store.add(el);\n this.historyRecorder.commit();\n this.requestRender();\n return el.id;\n }\n\n addShape(\n opts: {\n shape?: ShapeKind;\n size?: { w: number; h: number };\n position?: { x: number; y: number };\n strokeColor?: string;\n fillColor?: string;\n strokeWidth?: number;\n } = {},\n ): string {\n const size = opts.size ?? { w: 100, h: 100 };\n const position = opts.position ?? this.centeredPosition(size);\n const shape = createShape({\n position,\n size,\n shape: opts.shape,\n strokeColor: opts.strokeColor,\n strokeWidth: opts.strokeWidth,\n fillColor: opts.fillColor,\n layerId: this.layerManager.activeLayerId,\n });\n this.historyRecorder.begin();\n this.store.add(shape);\n this.historyRecorder.commit();\n this.getSelectTool()?.setSelection([shape.id]);\n this.requestRender();\n return shape.id;\n }\n\n private centeredPosition(size: { w: number; h: number }): { x: number; y: number } {\n const c = this.camera.screenToWorld({\n x: this.wrapper.clientWidth / 2,\n y: this.wrapper.clientHeight / 2,\n });\n return { x: c.x - size.w / 2, y: c.y - size.h / 2 };\n }\n\n removeLayer(id: string): void {\n this.historyRecorder.begin();\n this.layerManager.removeLayer(id);\n this.historyRecorder.commit();\n }\n\n registerHtmlRenderer(htmlType: string, factory: (el: HtmlElement) => HTMLElement): void {\n this.htmlRenderers.set(htmlType, factory);\n }\n\n updateHtmlElement(id: string, newContent: HTMLElement): void {\n const el = this.store.getById(id);\n if (!el) throw new Error(`Element not found: ${id}`);\n if (el.type !== 'html') throw new Error(`Element ${id} is not an HTML element`);\n this.domNodeManager.resetHtmlContent(id);\n this.domNodeManager.storeHtmlContent(id, newContent);\n // Content changes need the same synchronous reconciliation as registry changes: newly\n // available content for a dom-routed element must mount immediately rather than waiting\n // for the next render pass (and this method never calls store.update, so the store's own\n // 'update' listener never fires for it).\n this.domNodeManager.reconcileHtmlRouting(this.store, this.resolveRouting);\n this.requestRender();\n }\n\n /**\n * Declares htmlTypes that route to canvas painters even before a painter for\n * them registers, so the element renderer never treats them as DOM-backed\n * (avoiding a DOM-mount flash while a host is still loading its painter).\n * Returns an idempotent release; each `expect` call is independently reference\n * counted by the registry.\n */\n expectCanvasHtmlTypes(htmlTypes: Iterable<string>): () => void {\n return this.htmlPainters.expect(htmlTypes);\n }\n\n /**\n * Direct access to the viewport's live html-painter registry — the same\n * instance the viewport itself uses to route canvas-backed html elements.\n * Beyond `register`/`expectCanvasHtmlTypes` (already exposed above), this\n * hands out `getActivePainter`, `canvasTypes`, `onChange`, and `version`,\n * so a surface such as the minimap that needs to read routing state or\n * react to registry changes can do so without the viewport re-deriving or\n * proxying each capability individually.\n */\n getHtmlPainters(): HtmlPainterRegistry {\n return this.htmlPainters;\n }\n\n /**\n * Registers the canvas painter for `htmlType`. Later registrations for the\n * same type shadow earlier ones (LIFO); unregistering restores the previous\n * entry. Existing elements of this type reconcile synchronously — DOM nodes\n * detach and the render loop repaints on the next frame.\n */\n registerHtmlPainter(htmlType: string, painter: HtmlPainter): () => void {\n return this.htmlPainters.register(htmlType, painter);\n }\n\n /**\n * Subscribes to diagnostics emitted while painting canvas-routed html\n * elements (missing painter, painter threw, degenerate size). Deduped per\n * element/target/kind against the current registry and element versions, so\n * a fail -> repair -> fail-again sequence reports twice rather than being\n * suppressed forever. Returns an idempotent unsubscribe.\n */\n onHtmlPaintDiagnostic(listener: (d: HtmlPaintDiagnostic) => void): () => void {\n this.htmlDiagnosticListeners.add(listener);\n return () => this.htmlDiagnosticListeners.delete(listener);\n }\n\n /**\n * Enables (or replaces, or with `null` disables) pointer activation of\n * canvas-painted elements — the bridge for elements that are drawn rather than\n * mounted and so cannot receive DOM events. **Default off**, so every existing\n * consumer behaves identically.\n *\n * The controller is a passive observer: listeners are `{ passive: true }` and\n * it never calls `preventDefault`, `stopPropagation`, or takes pointer capture.\n * Changing or disabling activation resets all active and pending gestures.\n * Throws `RangeError` for a non-finite/negative `slopPx` or a non-positive\n * `doubleDelayMs`, leaving any existing activation untouched.\n *\n * The returned disposer clears **only its own generation**, so a stale\n * Strict-Mode cleanup cannot tear down a newer registration.\n */\n setActivation(options: ActivationOptions | null): () => void {\n // Construct before tearing down: a RangeError must leave the current\n // controller — and every outstanding disposer's generation — intact.\n const next = options\n ? new ElementActivation(\n {\n element: this.wrapper,\n camera: this.camera,\n store: this.store,\n resolveHtmlRouting: this.resolveRouting,\n isLayerVisible: (layerId: string) => this.layerManager.isLayerVisible(layerId),\n // Owner-side busy signal: the camera is gliding under pan inertia, or\n // this very gesture is the one that stopped the glide. Suppressing\n // both is what keeps \"tap to stop a flick\" from activating whatever\n // sits under the finger.\n isCameraBusy: () => this.inputHandler.isCameraCoasting(),\n },\n options,\n )\n : null;\n this.activation?.dispose();\n this.activation = next;\n next?.onActivate((e) => this.emitActivation(e));\n const generation = ++this.activationGeneration;\n return () => {\n if (this.activationGeneration !== generation) return;\n this.activation?.dispose();\n this.activation = null;\n };\n }\n\n /**\n * Subscribes to element activations. Persistent and independent of\n * `setActivation`: subscribing before activation is enabled, or across a\n * replacement, keeps working. Emission iterates a snapshot with per-listener\n * try/catch. Returns an idempotent unsubscribe.\n */\n onElementActivate(listener: (e: ElementActivationEvent) => void): () => void {\n this.activationListeners.add(listener);\n return () => {\n this.activationListeners.delete(listener);\n };\n }\n\n private emitActivation(event: ElementActivationEvent): void {\n for (const listener of [...this.activationListeners]) {\n try {\n listener(event);\n } catch {\n // One host listener's fault must not break its siblings.\n }\n }\n }\n\n /**\n * Fires whenever the html painter registry's active-painter set changes\n * (declare, register, or their release). Reconciliation is synchronous —\n * routing flips (and any DOM detach/remount) happen before this returns —\n * while the actual repaint of newly canvas-routed elements is deferred to\n * the next render frame via markAllLayersDirty + requestRender. Does NOT\n * touch a minimap: Viewport does not own a MinimapController, and the\n * built-in wrapper / React <Minimap /> each subscribe to the registry\n * directly.\n */\n private onHtmlRegistryChanged(): void {\n this.domNodeManager.reconcileHtmlRouting(this.store, this.resolveRouting);\n this.renderLoop.markAllLayersDirty();\n this.requestRender();\n }\n\n addGrid(input: {\n gridType?: 'square' | 'hex';\n hexOrientation?: 'pointy' | 'flat';\n cellSize?: number;\n strokeColor?: string;\n strokeWidth?: number;\n opacity?: number;\n }): string {\n return this.gridController.add(input);\n }\n\n updateGrid(\n updates: Partial<\n Pick<\n GridElement,\n 'gridType' | 'hexOrientation' | 'cellSize' | 'strokeColor' | 'strokeWidth' | 'opacity'\n >\n >,\n ): void {\n this.gridController.update(updates);\n }\n\n removeGrid(): void {\n this.gridController.remove();\n }\n\n getGridInfo(): GridInfo | null {\n return this.gridController.getInfo();\n }\n\n onGridChange(listener: (info: GridInfo | null) => void): () => void {\n return this.gridController.onChange(listener);\n }\n\n private getSelectTool(): SelectTool | undefined {\n return this.toolManager.getTool<SelectTool>('select');\n }\n\n private pruneSelection(): void {\n const tool = this.getSelectTool();\n if (!tool) return;\n const ids = tool.selectedIds;\n const filtered = ids.filter((id) => this.store.getById(id) !== undefined);\n if (filtered.length !== ids.length) tool.setSelection(filtered);\n }\n\n private handleRemovedElement(id: string): void {\n if (!this.getSelectedIds().includes(id)) return;\n if (this.historyRecorder.currentTransactionId !== null) {\n this.pendingSelectionPrune = true;\n return;\n }\n this.pruneSelection();\n }\n\n private static isSelectionSource(tool: Tool): tool is SelectTool {\n const candidate = tool as Partial<SelectTool>;\n return (\n tool.name === 'select' &&\n typeof candidate.onSelectionChange === 'function' &&\n typeof candidate.setSelection === 'function'\n );\n }\n\n private emitSelectionChange(): void {\n for (const listener of this.selectionListeners) {\n try {\n listener();\n } catch {\n // Selection listeners must not break each other or the caller.\n }\n }\n }\n\n private attachSelectionSource(tool: SelectTool): void {\n this.detachSelectionSource?.();\n this.detachSelectionSource = tool.onSelectionChange(() => this.emitSelectionChange());\n }\n\n /**\n * getSelectedIds() and the onSelectionChange emitter never surface stale ids:\n * once the enclosing history transaction completes, both reflect\n * the current selection.\n */\n getSelectedIds(): string[] {\n return this.getSelectTool()?.selectedIds ?? EMPTY_IDS;\n }\n\n runAction(action: string): void {\n this.inputHandler.runAction(action);\n }\n\n canPaste(): boolean {\n return this.inputHandler.hasClipboard();\n }\n\n openContextMenu(screenPos: Point): void {\n if (!this.contextMenu) return;\n const ids = this.getSelectedIds();\n const items: ContextMenuItem[] = [];\n if (ids.length > 0) {\n items.push({ label: 'Cut', action: 'cut' });\n items.push({ label: 'Copy', action: 'copy' });\n if (this.canPaste()) items.push({ label: 'Paste', action: 'paste' });\n items.push({ label: 'Duplicate', action: 'duplicate' });\n items.push({ label: 'Delete', action: 'delete' });\n items.push({ label: 'Bring to Front', action: 'z-front' });\n items.push({ label: 'Bring Forward', action: 'z-forward' });\n items.push({ label: 'Send Backward', action: 'z-backward' });\n items.push({ label: 'Send to Back', action: 'z-back' });\n items.push({ label: 'Rotate 90° CW', action: 'rotate-cw' });\n items.push({ label: 'Rotate 90° CCW', action: 'rotate-ccw' });\n const allLocked = ids.every((id) => this.store.getById(id)?.locked);\n items.push({ label: allLocked ? 'Unlock' : 'Lock', action: 'toggle-lock' });\n } else if (this.canPaste()) {\n items.push({ label: 'Paste', action: 'paste' });\n }\n if (items.length === 0) return;\n this.contextMenu.open(items, screenPos);\n }\n\n /**\n * Persistent, viewport-owned selection-change emitter. Subscribing works\n * regardless of whether a select tool is registered yet; it forwards\n * events from whichever select tool is currently attached via\n * `toolManager.onRegister`. Never delivers stale ids once the enclosing\n * history transaction completes.\n */\n onSelectionChange(listener: () => void): () => void {\n this.selectionListeners.add(listener);\n return () => {\n this.selectionListeners.delete(listener);\n };\n }\n\n getSelectionStyle(): ElementStyle | null {\n return this.selectionOps.getStyle();\n }\n\n /**\n * Unlike `getSelectionStyle()` — which returns `{}` for a style-less\n * selection — this returns `null` when no style field is applicable.\n */\n getSelectionStyleDetails(): SelectionStyleDetails | null {\n return this.selectionOps.getStyleDetails();\n }\n\n applyStyleToSelection(style: ElementStyle): void {\n this.selectionOps.applyStyle(style);\n }\n\n groupSelection(): void {\n this.selectionOps.group();\n }\n\n ungroupSelection(): void {\n this.selectionOps.ungroup();\n }\n\n toggleLockSelection(): void {\n this.selectionOps.toggleLock();\n }\n\n alignSelection(edge: AlignEdge): void {\n this.selectionOps.align(edge);\n }\n\n distributeSelection(axis: DistributeAxis): void {\n this.selectionOps.distribute(axis);\n }\n\n rotateSelection(direction: RotateDirection): void {\n this.selectionOps.rotateSelection(direction);\n }\n\n getRenderStats(): RenderStatsSnapshot {\n return this.renderLoop.getStats();\n }\n\n logPerformance(intervalMs = 2000): () => void {\n const id = setInterval(() => {\n const s = this.getRenderStats();\n console.log(\n `[FieldNotes] fps=${s.fps} frame=${s.avgFrameMs}ms p95=${s.p95FrameMs}ms grid=${s.lastGridMs}ms layers=${s.layersMs}ms comp=${s.compositeMs}ms bg=${s.backgroundMs}ms overlay=${s.overlayMs}ms`,\n );\n }, intervalMs);\n return () => clearInterval(id);\n }\n\n destroy(): void {\n this.renderLoop.stop();\n this.interactMode.destroy();\n this.noteEditor.destroy(this.store);\n this.arrowLabelEditor.cancel();\n this.historyRecorder.destroy();\n this.contextMenu?.dispose();\n this.minimap?.destroy();\n this.wrapper.removeEventListener('pointerdown', this.interactions.onTapDown);\n this.wrapper.removeEventListener('pointerup', this.interactions.onDoubleTap);\n this.wrapper.removeEventListener('dragover', this.interactions.onDragOver);\n this.wrapper.removeEventListener('drop', this.interactions.onDrop);\n this.inputHandler.destroy();\n this.unsubCamera();\n this.unsubToolChange();\n this.unsubToolRegister();\n this.unsubRecorderEnd();\n this.unsubHtmlPainters();\n this.activation?.dispose();\n this.activation = null;\n this.activationListeners.clear();\n this.htmlDiagnosticListeners.clear();\n this.detachSelectionSource?.();\n this.detachSelectionSource = null;\n this.selectionListeners.clear();\n this.unsubStore.forEach((fn) => fn());\n this.resizeObserver?.disconnect();\n this.resizeObserver = null;\n this.resizeListeners.clear();\n this.wrapper.remove();\n }\n\n stopInteracting(): void {\n this.interactMode.stopInteracting();\n }\n\n private unbindArrowsFrom(removedElement: CanvasElement): void {\n const boundArrows = findBoundArrows(removedElement.id, this.store);\n const bounds = getElementBounds(removedElement);\n\n for (const arrow of boundArrows) {\n const updates: Partial<ArrowElement> = {};\n\n if (arrow.fromBinding?.elementId === removedElement.id) {\n updates.fromBinding = undefined;\n if (bounds) {\n const angle = getArrowTangentAngle(arrow.from, arrow.to, arrow.bend, 0);\n const rayTarget = {\n x: arrow.from.x + Math.cos(angle) * 1000,\n y: arrow.from.y + Math.sin(angle) * 1000,\n };\n const edge = getEdgeIntersection(bounds, rayTarget);\n updates.from = edge;\n updates.position = edge;\n }\n }\n\n if (arrow.toBinding?.elementId === removedElement.id) {\n updates.toBinding = undefined;\n if (bounds) {\n const angle = getArrowTangentAngle(arrow.from, arrow.to, arrow.bend, 1);\n const rayTarget = {\n x: arrow.to.x - Math.cos(angle) * 1000,\n y: arrow.to.y - Math.sin(angle) * 1000,\n };\n updates.to = getEdgeIntersection(bounds, rayTarget);\n }\n }\n\n if (Object.keys(updates).length > 0) {\n this.store.update(arrow.id, updates);\n }\n }\n }\n\n private applyCameraTransform(): void {\n const transform = this.camera.toCSSTransform();\n this.domLayer.style.transform = transform;\n this.domNodeManager.setCameraTransform(transform);\n }\n\n private syncCanvasSize(): void {\n const rect = this.container.getBoundingClientRect();\n const dpr = typeof devicePixelRatio !== 'undefined' ? devicePixelRatio : 1;\n this.renderLoop.setCanvasSize(rect.width * dpr, rect.height * dpr);\n this.requestRender();\n this.resizeListeners.forEach((fn) => fn());\n }\n\n private observeResize(): void {\n if (typeof ResizeObserver === 'undefined') return;\n this.resizeObserver = new ResizeObserver(() => this.syncCanvasSize());\n this.resizeObserver.observe(this.container);\n }\n}\n","import type { Point } from '../core/types';\r\nimport type { OverlayRenderer } from './render-loop';\r\nimport type { LaserTrailEmission } from '../tools/laser-tool';\r\n\r\n/**\r\n * The wire shape of a laser-trail presence payload. Presence data is untyped\r\n * on the wire, so hosts discriminate on `kind`; `isLaserTrailPresence`\r\n * validates a received payload before it reaches the overlay. Trails are\r\n * ephemeral by contract: they must travel as presence only — never as\r\n * elements, undo history, persisted canvas state, or durable operations.\r\n */\r\nexport interface LaserTrailPresence {\r\n readonly kind: 'laser';\r\n /** World-space points, oldest first. */\r\n readonly points: readonly Point[];\r\n readonly color?: string;\r\n readonly width?: number;\r\n readonly fadeMs?: number;\r\n}\r\n\r\nexport const LASER_TRAIL_PRESENCE_KIND = 'laser';\r\n\r\nfunction isFinitePoint(value: unknown): value is Point {\r\n if (typeof value !== 'object' || value === null) return false;\r\n const point = value as { x?: unknown; y?: unknown };\r\n return (\r\n typeof point.x === 'number' &&\r\n Number.isFinite(point.x) &&\r\n typeof point.y === 'number' &&\r\n Number.isFinite(point.y)\r\n );\r\n}\r\n\r\nexport function isLaserTrailPresence(data: unknown): data is LaserTrailPresence {\r\n if (typeof data !== 'object' || data === null) return false;\r\n const payload = data as {\r\n kind?: unknown;\r\n points?: unknown;\r\n color?: unknown;\r\n width?: unknown;\r\n fadeMs?: unknown;\r\n };\r\n if (payload.kind !== LASER_TRAIL_PRESENCE_KIND) return false;\r\n if (!Array.isArray(payload.points) || !payload.points.every(isFinitePoint)) return false;\r\n if (payload.color !== undefined && typeof payload.color !== 'string') return false;\r\n if (payload.width !== undefined && !(typeof payload.width === 'number' && payload.width > 0)) {\r\n return false;\r\n }\r\n if (payload.fadeMs !== undefined && !(typeof payload.fadeMs === 'number' && payload.fadeMs > 0)) {\r\n return false;\r\n }\r\n return true;\r\n}\r\n\r\n/** Builds the presence payload for one local `LaserTool` emission. */\r\nexport function toLaserTrailPresence(emission: LaserTrailEmission): LaserTrailPresence {\r\n return {\r\n kind: LASER_TRAIL_PRESENCE_KIND,\r\n points: emission.points.map((point) => ({ x: point.x, y: point.y })),\r\n color: emission.color,\r\n width: emission.width,\r\n fadeMs: emission.fadeMs,\r\n };\r\n}\r\n\r\n/**\r\n * The two viewport capabilities the overlay needs; `Viewport` satisfies it.\r\n */\r\nexport interface RemoteLaserOverlayHost {\r\n registerOverlay(draw: OverlayRenderer): () => void;\r\n requestRender(): void;\r\n}\r\n\r\nexport interface RemoteLaserOverlayOptions {\r\n /** Style fallbacks when a payload omits them. */\r\n color?: string;\r\n width?: number;\r\n fadeMs?: number;\r\n /** Per-sender point cap; oldest points drop first. Default `512`. */\r\n maxPointsPerSender?: number;\r\n}\r\n\r\ninterface RemoteTrailPoint {\r\n x: number;\r\n y: number;\r\n t: number;\r\n}\r\n\r\ninterface RemoteTrail {\r\n points: RemoteTrailPoint[];\r\n color: string;\r\n width: number;\r\n fadeMs: number;\r\n}\r\n\r\nconst DEFAULT_COLOR = '#ff3b30';\r\nconst DEFAULT_WIDTH = 4;\r\nconst DEFAULT_FADE_MS = 1200;\r\nconst DEFAULT_MAX_POINTS = 512;\r\n\r\n/**\r\n * Renders fading laser trails for remote senders through the viewport overlay\r\n * registration, independent of the viewer's active tool. Points are stamped\r\n * with local receive time (remote clocks are never trusted), fade like the\r\n * local `LaserTool`, and a sender's trail disappears immediately on\r\n * `remove()` — wire that to `presence-leave`/disconnect. The controller never\r\n * touches elements, history, or persisted state.\r\n */\r\nexport class RemoteLaserOverlay {\r\n private readonly host: RemoteLaserOverlayHost;\r\n private readonly color: string;\r\n private readonly width: number;\r\n private readonly fadeMs: number;\r\n private readonly maxPointsPerSender: number;\r\n private readonly trails = new Map<string, RemoteTrail>();\r\n private unregister: (() => void) | null;\r\n private rafId: number | null = null;\r\n private disposed = false;\r\n\r\n constructor(host: RemoteLaserOverlayHost, options: RemoteLaserOverlayOptions = {}) {\r\n this.host = host;\r\n this.color = options.color ?? DEFAULT_COLOR;\r\n this.width = options.width ?? DEFAULT_WIDTH;\r\n this.fadeMs = options.fadeMs ?? DEFAULT_FADE_MS;\r\n this.maxPointsPerSender = options.maxPointsPerSender ?? DEFAULT_MAX_POINTS;\r\n this.unregister = host.registerOverlay((ctx) => this.renderTrails(ctx));\r\n }\r\n\r\n private now(): number {\r\n return performance.now();\r\n }\r\n\r\n /**\r\n * Applies a presence payload from `sender` (any opaque per-sender key, e.g.\r\n * the envelope `from`). Non-laser or malformed payloads are ignored and\r\n * reported as `false`, so hosts can feed every presence frame through.\r\n */\r\n apply(sender: string, data: unknown): boolean {\r\n if (this.disposed || !isLaserTrailPresence(data)) return false;\r\n let trail = this.trails.get(sender);\r\n if (!trail) {\r\n trail = { points: [], color: this.color, width: this.width, fadeMs: this.fadeMs };\r\n this.trails.set(sender, trail);\r\n }\r\n trail.color = data.color ?? this.color;\r\n trail.width = data.width ?? this.width;\r\n trail.fadeMs = data.fadeMs ?? this.fadeMs;\r\n const t = this.now();\r\n for (const point of data.points) {\r\n trail.points.push({ x: point.x, y: point.y, t });\r\n }\r\n const excess = trail.points.length - this.maxPointsPerSender;\r\n if (excess > 0) trail.points.splice(0, excess);\r\n this.ensureAnimating();\r\n this.host.requestRender();\r\n return true;\r\n }\r\n\r\n /** Removes a sender's trail immediately (presence-leave/disconnect). */\r\n remove(sender: string): void {\r\n if (this.trails.delete(sender)) this.host.requestRender();\r\n }\r\n\r\n /** Removes every trail immediately. */\r\n clear(): void {\r\n if (this.trails.size === 0) return;\r\n this.trails.clear();\r\n this.host.requestRender();\r\n }\r\n\r\n /** Number of senders with a live (unfaded) trail. */\r\n get activeSenderCount(): number {\r\n return this.trails.size;\r\n }\r\n\r\n /** Unregisters the overlay and stops the fade loop. Idempotent. */\r\n dispose(): void {\r\n if (this.disposed) return;\r\n this.disposed = true;\r\n if (this.rafId !== null) {\r\n cancelAnimationFrame(this.rafId);\r\n this.rafId = null;\r\n }\r\n this.trails.clear();\r\n this.unregister?.();\r\n this.unregister = null;\r\n }\r\n\r\n private ensureAnimating(): void {\r\n if (this.rafId === null) {\r\n this.rafId = requestAnimationFrame(() => this.tick());\r\n }\r\n }\r\n\r\n private tick(): void {\r\n if (this.disposed) return;\r\n const now = this.now();\r\n for (const [sender, trail] of this.trails) {\r\n const cutoff = now - trail.fadeMs;\r\n trail.points = trail.points.filter((point) => point.t >= cutoff);\r\n if (trail.points.length === 0) this.trails.delete(sender);\r\n }\r\n this.host.requestRender();\r\n this.rafId = this.trails.size > 0 ? requestAnimationFrame(() => this.tick()) : null;\r\n }\r\n\r\n private renderTrails(ctx: CanvasRenderingContext2D): void {\r\n if (this.trails.size === 0) return;\r\n const now = this.now();\r\n for (const trail of this.trails.values()) {\r\n if (trail.points.length < 2) continue;\r\n ctx.save();\r\n ctx.strokeStyle = trail.color;\r\n ctx.lineWidth = trail.width;\r\n ctx.lineCap = 'round';\r\n ctx.lineJoin = 'round';\r\n for (let i = 0; i < trail.points.length - 1; i++) {\r\n const a = trail.points[i];\r\n const b = trail.points[i + 1];\r\n if (!a || !b) continue;\r\n const age = now - b.t;\r\n ctx.globalAlpha = Math.max(0, 1 - age / trail.fadeMs);\r\n ctx.beginPath();\r\n ctx.moveTo(a.x, a.y);\r\n ctx.lineTo(b.x, b.y);\r\n ctx.stroke();\r\n }\r\n ctx.restore();\r\n }\r\n }\r\n}\r\n","/**\r\n * Shared expanding-pulse rendering for map pings. Internal helper used by the\r\n * local `PingTool` overlay and the `RemotePingOverlay` so a viewer sees the\r\n * same animation for local and remote pings. Not part of the public API.\r\n */\r\n\r\nexport interface PingPulseStyle {\r\n color: string;\r\n /** Total animation length in milliseconds. */\r\n durationMs: number;\r\n /** Maximum ripple radius in world units. */\r\n radius: number;\r\n}\r\n\r\n/** Ripple start offsets as fractions of the total duration. */\r\nconst RIPPLE_OFFSETS = [0, 0.25] as const;\r\n\r\nfunction easeOutCubic(t: number): number {\r\n const inv = 1 - t;\r\n return 1 - inv * inv * inv;\r\n}\r\n\r\n/**\r\n * Draws one ping at world position (`x`, `y`) given its age. The context is\r\n * already in world space. Draws nothing once `ageMs >= durationMs`.\r\n */\r\nexport function renderPingPulse(\r\n ctx: CanvasRenderingContext2D,\r\n x: number,\r\n y: number,\r\n ageMs: number,\r\n style: PingPulseStyle,\r\n): void {\r\n if (ageMs < 0 || ageMs >= style.durationMs) return;\r\n\r\n ctx.save();\r\n ctx.strokeStyle = style.color;\r\n ctx.fillStyle = style.color;\r\n\r\n for (const offset of RIPPLE_OFFSETS) {\r\n const rippleSpan = style.durationMs * (1 - offset);\r\n const rippleAge = ageMs - style.durationMs * offset;\r\n if (rippleAge < 0) continue;\r\n const progress = Math.min(1, rippleAge / rippleSpan);\r\n const rippleRadius = style.radius * easeOutCubic(progress);\r\n if (rippleRadius <= 0) continue;\r\n ctx.globalAlpha = Math.max(0, 1 - progress);\r\n ctx.lineWidth = Math.max(1.5, style.radius / 12);\r\n ctx.beginPath();\r\n ctx.arc(x, y, rippleRadius, 0, Math.PI * 2);\r\n ctx.stroke();\r\n }\r\n\r\n // Center dot: solid for the first half, then fades with the ripples.\r\n const dotProgress = ageMs / style.durationMs;\r\n ctx.globalAlpha = Math.max(0, 1 - Math.max(0, dotProgress - 0.5) * 2);\r\n ctx.beginPath();\r\n ctx.arc(x, y, Math.max(2, style.radius / 8), 0, Math.PI * 2);\r\n ctx.fill();\r\n\r\n ctx.restore();\r\n}\r\n","import type { OverlayRenderer } from './render-loop';\r\nimport { renderPingPulse } from './ping-pulse';\r\nimport type { PingEmission } from '../tools/ping-tool';\r\n\r\n/**\r\n * The wire shape of a map-ping presence payload. Presence data is untyped on\r\n * the wire, so hosts discriminate on `kind`; `isPingPresence` validates a\r\n * received payload before it reaches the overlay. Pings are ephemeral by\r\n * contract: they must travel as presence only — never as elements, undo\r\n * history, persisted canvas state, or durable operations.\r\n */\r\nexport interface PingPresence {\r\n readonly kind: 'ping';\r\n /** World-space ping position. */\r\n readonly x: number;\r\n readonly y: number;\r\n readonly color?: string;\r\n readonly durationMs?: number;\r\n readonly radius?: number;\r\n}\r\n\r\nexport const PING_PRESENCE_KIND = 'ping';\r\n\r\nexport function isPingPresence(data: unknown): data is PingPresence {\r\n if (typeof data !== 'object' || data === null) return false;\r\n const payload = data as {\r\n kind?: unknown;\r\n x?: unknown;\r\n y?: unknown;\r\n color?: unknown;\r\n durationMs?: unknown;\r\n radius?: unknown;\r\n };\r\n if (payload.kind !== PING_PRESENCE_KIND) return false;\r\n if (typeof payload.x !== 'number' || !Number.isFinite(payload.x)) return false;\r\n if (typeof payload.y !== 'number' || !Number.isFinite(payload.y)) return false;\r\n if (payload.color !== undefined && typeof payload.color !== 'string') return false;\r\n if (\r\n payload.durationMs !== undefined &&\r\n !(\r\n typeof payload.durationMs === 'number' &&\r\n Number.isFinite(payload.durationMs) &&\r\n payload.durationMs > 0\r\n )\r\n ) {\r\n return false;\r\n }\r\n if (\r\n payload.radius !== undefined &&\r\n !(typeof payload.radius === 'number' && Number.isFinite(payload.radius) && payload.radius > 0)\r\n ) {\r\n return false;\r\n }\r\n return true;\r\n}\r\n\r\n/** Builds the presence payload for one local `PingTool` emission. */\r\nexport function toPingPresence(emission: PingEmission): PingPresence {\r\n return {\r\n kind: PING_PRESENCE_KIND,\r\n x: emission.x,\r\n y: emission.y,\r\n color: emission.color,\r\n durationMs: emission.durationMs,\r\n radius: emission.radius,\r\n };\r\n}\r\n\r\n/**\r\n * The two viewport capabilities the overlay needs; `Viewport` satisfies it.\r\n */\r\nexport interface RemotePingOverlayHost {\r\n registerOverlay(draw: OverlayRenderer): () => void;\r\n requestRender(): void;\r\n}\r\n\r\nexport interface RemotePingOverlayOptions {\r\n /** Style fallbacks when a payload omits them. */\r\n color?: string;\r\n durationMs?: number;\r\n radius?: number;\r\n /** Per-sender live-ping cap; oldest pings drop first. Default `8`. */\r\n maxPingsPerSender?: number;\r\n}\r\n\r\ninterface RemotePing {\r\n x: number;\r\n y: number;\r\n t: number;\r\n color: string;\r\n durationMs: number;\r\n radius: number;\r\n}\r\n\r\nconst DEFAULT_COLOR = '#ff3b30';\r\nconst DEFAULT_DURATION_MS = 1800;\r\nconst DEFAULT_RADIUS = 48;\r\nconst DEFAULT_MAX_PINGS = 8;\r\n\r\n/**\r\n * Renders expanding-pulse pings for remote senders through the viewport\r\n * overlay registration, independent of the viewer's active tool. Pings are\r\n * stamped with local receive time (remote clocks are never trusted),\r\n * self-expire when their animation ends, and a sender's pings disappear\r\n * immediately on `remove()` — wire that to `presence-leave`/disconnect. The\r\n * controller never touches elements, history, or persisted state, and it\r\n * never moves the viewer's camera: pings are visual only.\r\n */\r\nexport class RemotePingOverlay {\r\n private readonly host: RemotePingOverlayHost;\r\n private readonly color: string;\r\n private readonly durationMs: number;\r\n private readonly radius: number;\r\n private readonly maxPingsPerSender: number;\r\n private readonly pings = new Map<string, RemotePing[]>();\r\n private unregister: (() => void) | null;\r\n private rafId: number | null = null;\r\n private disposed = false;\r\n\r\n constructor(host: RemotePingOverlayHost, options: RemotePingOverlayOptions = {}) {\r\n this.host = host;\r\n this.color = options.color ?? DEFAULT_COLOR;\r\n this.durationMs = options.durationMs ?? DEFAULT_DURATION_MS;\r\n this.radius = options.radius ?? DEFAULT_RADIUS;\r\n this.maxPingsPerSender = options.maxPingsPerSender ?? DEFAULT_MAX_PINGS;\r\n this.unregister = host.registerOverlay((ctx) => this.renderPings(ctx));\r\n }\r\n\r\n private now(): number {\r\n return performance.now();\r\n }\r\n\r\n /**\r\n * Applies a presence payload from `sender` (any opaque per-sender key, e.g.\r\n * the envelope `from`). Non-ping or malformed payloads are ignored and\r\n * reported as `false`, so hosts can feed every presence frame through.\r\n */\r\n apply(sender: string, data: unknown): boolean {\r\n if (this.disposed || !isPingPresence(data)) return false;\r\n let senderPings = this.pings.get(sender);\r\n if (!senderPings) {\r\n senderPings = [];\r\n this.pings.set(sender, senderPings);\r\n }\r\n senderPings.push({\r\n x: data.x,\r\n y: data.y,\r\n t: this.now(),\r\n color: data.color ?? this.color,\r\n durationMs: data.durationMs ?? this.durationMs,\r\n radius: data.radius ?? this.radius,\r\n });\r\n const excess = senderPings.length - this.maxPingsPerSender;\r\n if (excess > 0) senderPings.splice(0, excess);\r\n this.ensureAnimating();\r\n this.host.requestRender();\r\n return true;\r\n }\r\n\r\n /** Removes a sender's pings immediately (presence-leave/disconnect). */\r\n remove(sender: string): void {\r\n if (this.pings.delete(sender)) this.host.requestRender();\r\n }\r\n\r\n /** Removes every ping immediately. */\r\n clear(): void {\r\n if (this.pings.size === 0) return;\r\n this.pings.clear();\r\n this.host.requestRender();\r\n }\r\n\r\n /** Number of senders with a live (unexpired) ping. */\r\n get activeSenderCount(): number {\r\n return this.pings.size;\r\n }\r\n\r\n /** Unregisters the overlay and stops the animation loop. Idempotent. */\r\n dispose(): void {\r\n if (this.disposed) return;\r\n this.disposed = true;\r\n if (this.rafId !== null) {\r\n cancelAnimationFrame(this.rafId);\r\n this.rafId = null;\r\n }\r\n this.pings.clear();\r\n this.unregister?.();\r\n this.unregister = null;\r\n }\r\n\r\n private ensureAnimating(): void {\r\n if (this.rafId === null) {\r\n this.rafId = requestAnimationFrame(() => this.tick());\r\n }\r\n }\r\n\r\n private tick(): void {\r\n if (this.disposed) return;\r\n const now = this.now();\r\n for (const [sender, senderPings] of this.pings) {\r\n const live = senderPings.filter((ping) => now - ping.t < ping.durationMs);\r\n if (live.length === 0) {\r\n this.pings.delete(sender);\r\n } else {\r\n this.pings.set(sender, live);\r\n }\r\n }\r\n this.host.requestRender();\r\n this.rafId = this.pings.size > 0 ? requestAnimationFrame(() => this.tick()) : null;\r\n }\r\n\r\n private renderPings(ctx: CanvasRenderingContext2D): void {\r\n if (this.pings.size === 0) return;\r\n const now = this.now();\r\n for (const senderPings of this.pings.values()) {\r\n for (const ping of senderPings) {\r\n renderPingPulse(ctx, ping.x, ping.y, now - ping.t, {\r\n color: ping.color,\r\n durationMs: ping.durationMs,\r\n radius: ping.radius,\r\n });\r\n }\r\n }\r\n }\r\n}\r\n","import type { Point } from '../core/types';\r\n\r\n/** Label parity contract: local tool and remote overlay must format identically. */\r\nexport function formatMeasureLabel(feet: number): string {\r\n return `${Math.round(feet)} ft`;\r\n}\r\n\r\nexport interface MeasureRenderModel {\r\n readonly start: Point;\r\n readonly end: Point;\r\n readonly feet: number;\r\n readonly color: string;\r\n}\r\n\r\n/**\r\n * Draws one measurement — dashed segment, endpoint dots, rounded-pill distance\r\n * label — in world space. Shared by `MeasureTool.renderOverlay` and\r\n * `RemoteMeasureOverlay` so local and remote rulers stay pixel-identical.\r\n */\r\nexport function drawMeasurement(\r\n ctx: CanvasRenderingContext2D,\r\n m: MeasureRenderModel,\r\n opts: { alpha?: number } = {},\r\n): void {\r\n ctx.save();\r\n if (opts.alpha !== undefined) ctx.globalAlpha = opts.alpha;\r\n\r\n ctx.strokeStyle = m.color;\r\n ctx.setLineDash([8, 4]);\r\n ctx.lineWidth = 2;\r\n ctx.beginPath();\r\n ctx.moveTo(m.start.x, m.start.y);\r\n ctx.lineTo(m.end.x, m.end.y);\r\n ctx.stroke();\r\n\r\n ctx.setLineDash([]);\r\n ctx.fillStyle = m.color;\r\n const dotRadius = 4;\r\n ctx.beginPath();\r\n ctx.arc(m.start.x, m.start.y, dotRadius, 0, Math.PI * 2);\r\n ctx.fill();\r\n ctx.beginPath();\r\n ctx.arc(m.end.x, m.end.y, dotRadius, 0, Math.PI * 2);\r\n ctx.fill();\r\n\r\n const label = formatMeasureLabel(m.feet);\r\n const midX = (m.start.x + m.end.x) / 2;\r\n const midY = (m.start.y + m.end.y) / 2;\r\n ctx.font = '14px sans-serif';\r\n const metrics = ctx.measureText(label);\r\n const padX = 6;\r\n const padY = 4;\r\n const textH = 14;\r\n\r\n ctx.fillStyle = 'rgba(0, 0, 0, 0.75)';\r\n ctx.beginPath();\r\n ctx.roundRect(\r\n midX - metrics.width / 2 - padX,\r\n midY - textH / 2 - padY,\r\n metrics.width + padX * 2,\r\n textH + padY * 2,\r\n 4,\r\n );\r\n ctx.fill();\r\n\r\n ctx.fillStyle = '#FFFFFF';\r\n ctx.textAlign = 'center';\r\n ctx.textBaseline = 'middle';\r\n ctx.fillText(label, midX, midY);\r\n\r\n ctx.restore();\r\n}\r\n","import type { Point } from '../core/types';\r\nimport type { MeasureEmission } from '../tools/measure-tool';\r\nimport type { OverlayRenderer } from './render-loop';\r\nimport { drawMeasurement } from './measure-render';\r\n\r\n/**\r\n * The wire shape of a shared-ruler presence payload. Presence data is untyped\r\n * on the wire, so hosts discriminate on `kind`; `isMeasurePresence` validates\r\n * a received payload before it reaches the overlay. Distance is\r\n * sender-authoritative: receivers render the payload's `feet`/`cells` and\r\n * never recompute from their own grid. Measurements are ephemeral by\r\n * contract: presence only — never elements, undo history, persisted canvas\r\n * state, or durable operations.\r\n */\r\nexport type MeasurePresence =\r\n | {\r\n readonly kind: 'measure';\r\n readonly start: Point;\r\n readonly end: Point;\r\n readonly cells: number;\r\n readonly feet: number;\r\n readonly color?: string;\r\n }\r\n | { readonly kind: 'measure'; readonly cleared: true };\r\n\r\nexport const MEASURE_PRESENCE_KIND = 'measure';\r\n\r\nfunction isFinitePoint(value: unknown): value is Point {\r\n if (typeof value !== 'object' || value === null) return false;\r\n const point = value as { x?: unknown; y?: unknown };\r\n return (\r\n typeof point.x === 'number' &&\r\n Number.isFinite(point.x) &&\r\n typeof point.y === 'number' &&\r\n Number.isFinite(point.y)\r\n );\r\n}\r\n\r\nexport function isMeasurePresence(data: unknown): data is MeasurePresence {\r\n if (typeof data !== 'object' || data === null) return false;\r\n const payload = data as {\r\n kind?: unknown;\r\n cleared?: unknown;\r\n start?: unknown;\r\n end?: unknown;\r\n cells?: unknown;\r\n feet?: unknown;\r\n color?: unknown;\r\n };\r\n if (payload.kind !== MEASURE_PRESENCE_KIND) return false;\r\n if ('cleared' in payload) return payload.cleared === true;\r\n if (!isFinitePoint(payload.start) || !isFinitePoint(payload.end)) return false;\r\n if (typeof payload.cells !== 'number' || !Number.isFinite(payload.cells)) return false;\r\n if (typeof payload.feet !== 'number' || !Number.isFinite(payload.feet)) return false;\r\n if (payload.color !== undefined && typeof payload.color !== 'string') return false;\r\n return true;\r\n}\r\n\r\n/** Builds the presence payload for one local `MeasureTool` emission. */\r\nexport function toMeasurePresence(emission: MeasureEmission | null): MeasurePresence {\r\n if (emission === null) return { kind: MEASURE_PRESENCE_KIND, cleared: true };\r\n return {\r\n kind: MEASURE_PRESENCE_KIND,\r\n start: emission.start,\r\n end: emission.end,\r\n cells: emission.cells,\r\n feet: emission.feet,\r\n color: emission.color,\r\n };\r\n}\r\n\r\n/** The two viewport capabilities the overlay needs; `Viewport` satisfies it. */\r\nexport interface RemoteMeasureOverlayHost {\r\n registerOverlay(draw: OverlayRenderer): () => void;\r\n requestRender(): void;\r\n}\r\n\r\nexport interface RemoteMeasureOverlayOptions {\r\n /** Style fallback when a payload omits `color`. Default `'#FF5722'`. */\r\n color?: string;\r\n /** Full-opacity hold after a cleared payload. Default `1500`. */\r\n holdMs?: number;\r\n /** Linear fade to 0 after the hold. Default `400`. */\r\n fadeMs?: number;\r\n /** Stale active entries are treated as cleared after this. Default `30000`. */\r\n maxAgeMs?: number;\r\n}\r\n\r\ninterface RemoteMeasurement {\r\n start: Point;\r\n end: Point;\r\n feet: number;\r\n color: string;\r\n /** Local receive time of the linger start; `null` while active. */\r\n clearedAt: number | null;\r\n expiryTimer: ReturnType<typeof setTimeout> | null;\r\n}\r\n\r\nconst DEFAULT_COLOR = '#FF5722';\r\nconst DEFAULT_HOLD_MS = 1500;\r\nconst DEFAULT_FADE_MS = 400;\r\nconst DEFAULT_MAX_AGE_MS = 30_000;\r\n\r\n/**\r\n * Renders remote shared-ruler measurements through the viewport overlay\r\n * registration, independent of the viewer's active tool. Entries are stamped\r\n * with local receive time (remote clocks are never trusted). A cleared\r\n * payload holds the final measurement for `holdMs`, fades over `fadeMs`, and\r\n * deletes; presence-leave (`remove`) deletes immediately. An active entry not\r\n * updated for `maxAgeMs` is expired by a timer — an idle map never renders,\r\n * so expiry cannot ride on the draw path. The overlay never touches elements,\r\n * history, or persisted state, and never moves the viewer's camera.\r\n */\r\nexport class RemoteMeasureOverlay {\r\n private readonly host: RemoteMeasureOverlayHost;\r\n private readonly color: string;\r\n private readonly holdMs: number;\r\n private readonly fadeMs: number;\r\n private readonly maxAgeMs: number;\r\n private readonly measurements = new Map<string, RemoteMeasurement>();\r\n private unregister: (() => void) | null;\r\n private rafId: number | null = null;\r\n private disposed = false;\r\n\r\n constructor(host: RemoteMeasureOverlayHost, options: RemoteMeasureOverlayOptions = {}) {\r\n this.host = host;\r\n this.color = options.color ?? DEFAULT_COLOR;\r\n this.holdMs = options.holdMs ?? DEFAULT_HOLD_MS;\r\n this.fadeMs = options.fadeMs ?? DEFAULT_FADE_MS;\r\n this.maxAgeMs = options.maxAgeMs ?? DEFAULT_MAX_AGE_MS;\r\n this.unregister = host.registerOverlay((ctx) => this.renderMeasurements(ctx));\r\n }\r\n\r\n private now(): number {\r\n return performance.now();\r\n }\r\n\r\n /**\r\n * Applies a presence payload from `sender` (any opaque per-sender key, e.g.\r\n * the envelope `from`). Non-measure or malformed payloads are ignored and\r\n * reported as `false`, so hosts can feed every presence frame through.\r\n */\r\n apply(sender: string, data: unknown): boolean {\r\n if (this.disposed || !isMeasurePresence(data)) return false;\r\n if ('cleared' in data) {\r\n this.beginLinger(sender);\r\n return true;\r\n }\r\n const existing = this.measurements.get(sender);\r\n if (existing?.expiryTimer != null) clearTimeout(existing.expiryTimer);\r\n this.measurements.set(sender, {\r\n start: data.start,\r\n end: data.end,\r\n feet: data.feet,\r\n color: data.color ?? this.color,\r\n clearedAt: null,\r\n expiryTimer: setTimeout(() => this.beginLinger(sender), this.maxAgeMs),\r\n });\r\n this.host.requestRender();\r\n return true;\r\n }\r\n\r\n /** Removes a sender's ruler immediately (presence-leave/disconnect). */\r\n remove(sender: string): void {\r\n const entry = this.measurements.get(sender);\r\n if (!entry) return;\r\n if (entry.expiryTimer != null) clearTimeout(entry.expiryTimer);\r\n this.measurements.delete(sender);\r\n this.host.requestRender();\r\n }\r\n\r\n /** Removes every ruler immediately. */\r\n clear(): void {\r\n if (this.measurements.size === 0) return;\r\n for (const entry of this.measurements.values()) {\r\n if (entry.expiryTimer != null) clearTimeout(entry.expiryTimer);\r\n }\r\n this.measurements.clear();\r\n this.host.requestRender();\r\n }\r\n\r\n /** Number of senders with a visible (active or lingering) ruler. */\r\n get activeSenderCount(): number {\r\n return this.measurements.size;\r\n }\r\n\r\n /** Unregisters the overlay, cancels timers, stops animating. Idempotent. */\r\n dispose(): void {\r\n if (this.disposed) return;\r\n this.disposed = true;\r\n if (this.rafId !== null) {\r\n cancelAnimationFrame(this.rafId);\r\n this.rafId = null;\r\n }\r\n for (const entry of this.measurements.values()) {\r\n if (entry.expiryTimer != null) clearTimeout(entry.expiryTimer);\r\n }\r\n this.measurements.clear();\r\n this.unregister?.();\r\n this.unregister = null;\r\n this.host.requestRender();\r\n }\r\n\r\n private beginLinger(sender: string): void {\r\n const entry = this.measurements.get(sender);\r\n if (!entry || entry.clearedAt !== null) return;\r\n if (entry.expiryTimer != null) {\r\n clearTimeout(entry.expiryTimer);\r\n entry.expiryTimer = null;\r\n }\r\n entry.clearedAt = this.now();\r\n this.ensureAnimating();\r\n this.host.requestRender();\r\n }\r\n\r\n private ensureAnimating(): void {\r\n if (this.rafId === null) {\r\n this.rafId = requestAnimationFrame(() => this.tick());\r\n }\r\n }\r\n\r\n private tick(): void {\r\n if (this.disposed) return;\r\n const now = this.now();\r\n let lingering = 0;\r\n for (const [sender, entry] of this.measurements) {\r\n if (entry.clearedAt === null) continue;\r\n if (now - entry.clearedAt >= this.holdMs + this.fadeMs) {\r\n this.measurements.delete(sender);\r\n } else {\r\n lingering += 1;\r\n }\r\n }\r\n this.host.requestRender();\r\n this.rafId = lingering > 0 ? requestAnimationFrame(() => this.tick()) : null;\r\n }\r\n\r\n private renderMeasurements(ctx: CanvasRenderingContext2D): void {\r\n if (this.measurements.size === 0) return;\r\n const now = this.now();\r\n for (const entry of this.measurements.values()) {\r\n let alpha = 1;\r\n if (entry.clearedAt !== null) {\r\n const fadeAge = now - entry.clearedAt - this.holdMs;\r\n if (fadeAge > 0) alpha = Math.max(0, 1 - fadeAge / this.fadeMs);\r\n }\r\n drawMeasurement(ctx, entry, { alpha });\r\n }\r\n }\r\n}\r\n","import type { Point } from '../core/types';\r\nimport type { PingEmission } from '../tools/ping-tool';\r\n\r\n/**\r\n * The one camera capability `PingInput` needs; `Camera` satisfies it. Screen\r\n * coordinates are element-local (the same space `Camera.screenToWorld`\r\n * expects).\r\n */\r\nexport interface PingInputHost {\r\n screenToWorld(screen: Point): Point;\r\n}\r\n\r\nexport interface PingInputOptions {\r\n /**\r\n * Opt-in for the long-press gesture. Off by default: a hidden hold-to-ping\r\n * gesture surprises users outside shared-canvas products, so hosts enable\r\n * it deliberately. The keyboard/programmatic paths (`pingAtPointer`,\r\n * `pingAt`) are always available. Default `false`.\r\n */\r\n longPressEnabled?: boolean;\r\n /** Hold duration before a still press pings. Default `600`. */\r\n longPressMs?: number;\r\n /** Maximum pointer travel while holding; moving further cancels. Default `8`. */\r\n slopPx?: number;\r\n /** Emission style forwarded to hosts; matches `PingTool` defaults. */\r\n color?: string;\r\n durationMs?: number;\r\n radius?: number;\r\n /**\r\n * Minimum interval between emitted pings, shared across the long-press and\r\n * keyboard/programmatic paths. Faster pings are dropped entirely. Default\r\n * `300`.\r\n */\r\n minIntervalMs?: number;\r\n /**\r\n * Host veto consulted at fire time on every path (e.g. return `false` while\r\n * a ping tool is active to avoid double pings). A veto does not consume the\r\n * rate-limit interval.\r\n */\r\n shouldPing?: () => boolean;\r\n}\r\n\r\ninterface PressState {\r\n pointerId: number;\r\n /** Element-local press position; the ping fires here, not where the pointer drifted. */\r\n x: number;\r\n y: number;\r\n timer: ReturnType<typeof setTimeout>;\r\n}\r\n\r\nconst DEFAULT_LONG_PRESS_MS = 600;\r\nconst DEFAULT_SLOP_PX = 8;\r\nconst DEFAULT_COLOR = '#ff3b30';\r\nconst DEFAULT_DURATION_MS = 1800;\r\nconst DEFAULT_RADIUS = 48;\r\nconst DEFAULT_MIN_INTERVAL_MS = 300;\r\n\r\n/**\r\n * Always-available ping input alongside the active tool: long-press-to-ping\r\n * plus keyboard/programmatic pings, independent of `PingTool`.\r\n *\r\n * `PingInput` is a passive observer by contract. Its DOM pointer listeners are\r\n * registered `passive: true` and it never calls `preventDefault`,\r\n * `stopPropagation`, or captures pointers, so the active tool, panning, and\r\n * pinch navigation behave exactly as if it were absent (with a pencil active,\r\n * a still hold pings AND the pencil still draws its dot). It also never\r\n * renders: hosts feed emissions into their own `RemotePingOverlay` under a\r\n * `'self'` sender key. Pings are ephemeral — no elements, no undo history, no\r\n * persisted state, no camera movement.\r\n *\r\n * The long-press gesture is opt-in via `longPressEnabled` (hosts whose users\r\n * would not expect hold-to-ping simply leave it off and keep the keyboard\r\n * paths). When enabled, a long-press arms on the first pointer down (mouse\r\n * primary button, touch, or pen), fires after `longPressMs` at the original\r\n * press position, and\r\n * cancels on movement past `slopPx`, a second pointer (two-finger\r\n * navigation), or pointer up/cancel/leave. Keyboard support is a capability,\r\n * not a binding: hosts call `pingAtPointer()` (last tracked hover position,\r\n * world-converted at call time) or `pingAt(world)` from their own shortcut\r\n * handling.\r\n */\r\nexport class PingInput {\r\n private readonly element: HTMLElement;\r\n private readonly host: PingInputHost;\r\n private longPressEnabled: boolean;\r\n private longPressMs: number;\r\n private slopPx: number;\r\n private color: string;\r\n private durationMs: number;\r\n private radius: number;\r\n private minIntervalMs: number;\r\n private shouldPing: (() => boolean) | undefined;\r\n\r\n private press: PressState | null = null;\r\n private readonly downPointers = new Set<number>();\r\n private lastPointerScreen: Point | null = null;\r\n private lastEmitAt = -Infinity;\r\n private disposed = false;\r\n private optionListeners = new Set<() => void>();\r\n private pingListeners = new Set<(emission: PingEmission) => void>();\r\n\r\n private readonly handlePointerDown = (e: PointerEvent): void => this.onPointerDown(e);\r\n private readonly handlePointerMove = (e: PointerEvent): void => this.onPointerMove(e);\r\n private readonly handlePointerUp = (e: PointerEvent): void => this.onPointerEnd(e);\r\n private readonly handlePointerCancel = (e: PointerEvent): void => this.onPointerEnd(e);\r\n private readonly handlePointerLeave = (e: PointerEvent): void => this.onPointerEnd(e);\r\n\r\n constructor(element: HTMLElement, host: PingInputHost, options: PingInputOptions = {}) {\r\n this.element = element;\r\n this.host = host;\r\n this.longPressEnabled = options.longPressEnabled ?? false;\r\n this.longPressMs = options.longPressMs ?? DEFAULT_LONG_PRESS_MS;\r\n this.slopPx = options.slopPx ?? DEFAULT_SLOP_PX;\r\n this.color = options.color ?? DEFAULT_COLOR;\r\n this.durationMs = options.durationMs ?? DEFAULT_DURATION_MS;\r\n this.radius = options.radius ?? DEFAULT_RADIUS;\r\n this.minIntervalMs = options.minIntervalMs ?? DEFAULT_MIN_INTERVAL_MS;\r\n this.shouldPing = options.shouldPing;\r\n\r\n const opts: AddEventListenerOptions = { passive: true };\r\n element.addEventListener('pointerdown', this.handlePointerDown, opts);\r\n element.addEventListener('pointermove', this.handlePointerMove, opts);\r\n element.addEventListener('pointerup', this.handlePointerUp, opts);\r\n element.addEventListener('pointercancel', this.handlePointerCancel, opts);\r\n element.addEventListener('pointerleave', this.handlePointerLeave, opts);\r\n }\r\n\r\n private now(): number {\r\n return performance.now();\r\n }\r\n\r\n getOptions(): PingInputOptions {\r\n return {\r\n longPressEnabled: this.longPressEnabled,\r\n longPressMs: this.longPressMs,\r\n slopPx: this.slopPx,\r\n color: this.color,\r\n durationMs: this.durationMs,\r\n radius: this.radius,\r\n minIntervalMs: this.minIntervalMs,\r\n ...(this.shouldPing ? { shouldPing: this.shouldPing } : {}),\r\n };\r\n }\r\n\r\n setOptions(options: PingInputOptions): void {\r\n if (options.longPressEnabled !== undefined) {\r\n this.longPressEnabled = options.longPressEnabled;\r\n if (!this.longPressEnabled) this.cancelPress();\r\n }\r\n if (options.longPressMs !== undefined) this.longPressMs = options.longPressMs;\r\n if (options.slopPx !== undefined) this.slopPx = options.slopPx;\r\n if (options.color !== undefined) this.color = options.color;\r\n if (options.durationMs !== undefined) this.durationMs = options.durationMs;\r\n if (options.radius !== undefined) this.radius = options.radius;\r\n if (options.minIntervalMs !== undefined) this.minIntervalMs = options.minIntervalMs;\r\n if (options.shouldPing !== undefined) this.shouldPing = options.shouldPing;\r\n for (const listener of this.optionListeners) listener();\r\n }\r\n\r\n onOptionsChange(listener: () => void): () => void {\r\n this.optionListeners.add(listener);\r\n return () => this.optionListeners.delete(listener);\r\n }\r\n\r\n /**\r\n * Subscribes to emitted pings. Listeners must not throw; a throwing\r\n * listener is isolated so it cannot break input handling or other\r\n * listeners.\r\n */\r\n onPing(listener: (emission: PingEmission) => void): () => void {\r\n this.pingListeners.add(listener);\r\n return () => this.pingListeners.delete(listener);\r\n }\r\n\r\n /**\r\n * Pings at the last tracked pointer position (hover moves and presses),\r\n * world-converted at call time. Returns `false` when no pointer has been\r\n * seen yet, the host vetoes, or the rate limit drops the ping.\r\n */\r\n pingAtPointer(): boolean {\r\n if (this.disposed || this.lastPointerScreen === null) return false;\r\n return this.emit(this.host.screenToWorld(this.lastPointerScreen));\r\n }\r\n\r\n /** Pings a world position directly. Same veto and rate limit as every path. */\r\n pingAt(world: Point): boolean {\r\n if (this.disposed) return false;\r\n return this.emit(world);\r\n }\r\n\r\n /** Removes all DOM listeners and cancels any pending press. Idempotent. */\r\n dispose(): void {\r\n if (this.disposed) return;\r\n this.disposed = true;\r\n this.cancelPress();\r\n this.downPointers.clear();\r\n this.element.removeEventListener('pointerdown', this.handlePointerDown);\r\n this.element.removeEventListener('pointermove', this.handlePointerMove);\r\n this.element.removeEventListener('pointerup', this.handlePointerUp);\r\n this.element.removeEventListener('pointercancel', this.handlePointerCancel);\r\n this.element.removeEventListener('pointerleave', this.handlePointerLeave);\r\n this.optionListeners.clear();\r\n this.pingListeners.clear();\r\n }\r\n\r\n private toLocal(e: PointerEvent): Point {\r\n const rect = this.element.getBoundingClientRect();\r\n return { x: e.clientX - rect.left, y: e.clientY - rect.top };\r\n }\r\n\r\n private onPointerDown(e: PointerEvent): void {\r\n const local = this.toLocal(e);\r\n this.lastPointerScreen = local;\r\n\r\n const hadPointers = this.downPointers.size > 0;\r\n this.downPointers.add(e.pointerId);\r\n if (hadPointers) {\r\n // A second pointer means navigation, not a press — and the new pointer\r\n // must not arm its own press while others are down.\r\n this.cancelPress();\r\n return;\r\n }\r\n if (!this.longPressEnabled) return;\r\n if (e.pointerType === 'mouse' && e.button !== 0) return;\r\n\r\n this.press = {\r\n pointerId: e.pointerId,\r\n x: local.x,\r\n y: local.y,\r\n timer: setTimeout(() => this.firePress(), this.longPressMs),\r\n };\r\n }\r\n\r\n private onPointerMove(e: PointerEvent): void {\r\n const local = this.toLocal(e);\r\n this.lastPointerScreen = local;\r\n if (this.press === null || e.pointerId !== this.press.pointerId) return;\r\n const dx = local.x - this.press.x;\r\n const dy = local.y - this.press.y;\r\n if (Math.hypot(dx, dy) > this.slopPx) this.cancelPress();\r\n }\r\n\r\n private onPointerEnd(e: PointerEvent): void {\r\n this.downPointers.delete(e.pointerId);\r\n if (this.press !== null && e.pointerId === this.press.pointerId) this.cancelPress();\r\n }\r\n\r\n private cancelPress(): void {\r\n if (this.press === null) return;\r\n clearTimeout(this.press.timer);\r\n this.press = null;\r\n }\r\n\r\n private firePress(): void {\r\n if (this.press === null) return;\r\n const screen = { x: this.press.x, y: this.press.y };\r\n this.press = null;\r\n // Convert at fire time so the ping lands where the held pointer points now.\r\n this.emit(this.host.screenToWorld(screen));\r\n }\r\n\r\n private emit(world: Point): boolean {\r\n if (this.shouldPing && !this.shouldPing()) return false;\r\n const t = this.now();\r\n if (t - this.lastEmitAt < this.minIntervalMs) return false;\r\n this.lastEmitAt = t;\r\n const emission: PingEmission = {\r\n x: world.x,\r\n y: world.y,\r\n color: this.color,\r\n durationMs: this.durationMs,\r\n radius: this.radius,\r\n };\r\n for (const listener of this.pingListeners) {\r\n try {\r\n listener(emission);\r\n } catch {\r\n // A throwing host listener must not break input handling.\r\n }\r\n }\r\n return true;\r\n }\r\n}\r\n","import type { Point } from '../core/types';\r\nimport type { Camera } from './camera';\r\n\r\n/**\r\n * A viewport-size-independent camera view: the world rectangle to frame.\r\n * Restored by contain-fit, so the same view frames the same world content on\r\n * any screen size or aspect — a DM's saved zone looks right on a phone and a\r\n * TV. Center+zoom would NOT have this property.\r\n */\r\nexport interface CameraView {\r\n x: number;\r\n y: number;\r\n w: number;\r\n h: number;\r\n}\r\n\r\nexport function assertValidView(view: CameraView): void {\r\n const { x, y, w, h } = view;\r\n if (!Number.isFinite(x) || !Number.isFinite(y) || !Number.isFinite(w) || !Number.isFinite(h)) {\r\n throw new Error('[fieldnotes] CameraView requires finite x, y, w, and h');\r\n }\r\n if (w <= 0 || h <= 0) {\r\n throw new Error('[fieldnotes] CameraView requires positive w and h');\r\n }\r\n}\r\n\r\n/**\r\n * Rejects dimensions that would poison the camera. Zero is NOT rejected here:\r\n * callers decide, because a zero-size canvas is a legitimate transient (an\r\n * unmounted or `display: none` host reports 0) while a negative or non-finite\r\n * dimension is always a bug or a poisoned measurement.\r\n */\r\nexport function assertCanvasDims(canvasW: number, canvasH: number): void {\r\n if (!Number.isFinite(canvasW) || !Number.isFinite(canvasH)) {\r\n throw new Error('[fieldnotes] canvas dimensions must be finite');\r\n }\r\n if (canvasW < 0 || canvasH < 0) {\r\n throw new Error('[fieldnotes] canvas dimensions must not be negative');\r\n }\r\n}\r\n\r\n/**\r\n * Non-throwing companion to `assertCanvasDims`, for call sites that cannot\r\n * throw (the per-frame animation path) and must instead resolve a zero-size\r\n * canvas into a clean lifecycle outcome. Zero IS accepted here — see\r\n * `assertCanvasDims` for why zero is a legitimate transient rather than a bug.\r\n */\r\nexport function canvasDimsUsable(canvasW: number, canvasH: number): boolean {\r\n return Number.isFinite(canvasW) && Number.isFinite(canvasH) && canvasW >= 0 && canvasH >= 0;\r\n}\r\n\r\n/** Captures the currently visible world rect. */\r\nexport function captureCameraView(viewport: {\r\n getVisibleRect(): { x: number; y: number; w: number; h: number };\r\n}): CameraView {\r\n const rect = viewport.getVisibleRect();\r\n return { x: rect.x, y: rect.y, w: rect.w, h: rect.h };\r\n}\r\n\r\n/**\r\n * Unclamped contain-fit zoom: the largest zoom at which the whole rect fits.\r\n * Contain, never crop — a view whose aspect differs from the canvas shows\r\n * extra world content on the short axis.\r\n */\r\nexport function fitZoomForView(view: CameraView, canvasW: number, canvasH: number): number {\r\n assertValidView(view);\r\n assertCanvasDims(canvasW, canvasH);\r\n if (canvasW === 0 || canvasH === 0) {\r\n throw new Error('[fieldnotes] fitZoomForView requires a non-zero canvas size');\r\n }\r\n return Math.min(canvasW / view.w, canvasH / view.h);\r\n}\r\n\r\n/** Camera origin that centers `view` on the canvas at an already-decided zoom. */\r\nexport function cameraOriginForView(\r\n view: CameraView,\r\n zoom: number,\r\n canvasW: number,\r\n canvasH: number,\r\n): Point {\r\n return {\r\n x: canvasW / 2 - (view.x + view.w / 2) * zoom,\r\n y: canvasH / 2 - (view.y + view.h / 2) * zoom,\r\n };\r\n}\r\n\r\n/**\r\n * Writes `view` to `camera`. No-ops on a zero canvas dimension (mount and\r\n * visibility races are legitimate); throws on an invalid view or on negative\r\n * or non-finite dimensions.\r\n */\r\nexport function applyCameraView(\r\n camera: Camera,\r\n view: CameraView,\r\n canvasW: number,\r\n canvasH: number,\r\n): void {\r\n assertValidView(view);\r\n assertCanvasDims(canvasW, canvasH);\r\n if (canvasW === 0 || canvasH === 0) return;\r\n\r\n camera.setZoom(fitZoomForView(view, canvasW, canvasH));\r\n // Read the zoom BACK: when the fit zoom exceeds the camera's private clamp,\r\n // centering must use the value the camera accepted or the view lands\r\n // off-center. `Camera.moveTo` takes two numbers, not a Point.\r\n const origin = cameraOriginForView(view, camera.zoom, canvasW, canvasH);\r\n camera.moveTo(origin.x, origin.y);\r\n}\r\n","import type { Camera } from './camera';\r\nimport {\r\n applyCameraView,\r\n assertCanvasDims,\r\n assertValidView,\r\n canvasDimsUsable,\r\n type CameraView,\r\n} from './camera-view';\r\n\r\n/** A scheduler and its matching canceller. Inseparable by construction. */\r\nexport interface FrameScheduler {\r\n requestFrame: (cb: () => void) => number;\r\n cancelFrame: (id: number) => void;\r\n}\r\n\r\nexport interface CameraAnimatorOptions {\r\n /** REQUIRED. `element` is used for input listeners only, never measurement. */\r\n getCanvasSize: () => { w: number; h: number };\r\n durationMs?: number;\r\n easing?: (t: number) => number;\r\n interactive?: boolean;\r\n frames?: FrameScheduler;\r\n now?: () => number;\r\n}\r\n\r\nexport type CameraAnimationEndReason = 'complete' | 'cancelled' | 'superseded';\r\n\r\nconst DEFAULT_DURATION_MS = 400;\r\nconst FRAMED_EPSILON = 1e-6;\r\n\r\nconst easeOutCubic = (t: number): number => 1 - Math.pow(1 - t, 3);\r\n\r\nfunction lerp(a: number, b: number, k: number): number {\r\n return a + (b - a) * k;\r\n}\r\n\r\nfunction lerpView(from: CameraView, to: CameraView, k: number): CameraView {\r\n return {\r\n x: lerp(from.x, to.x, k),\r\n y: lerp(from.y, to.y, k),\r\n w: lerp(from.w, to.w, k),\r\n h: lerp(from.h, to.h, k),\r\n };\r\n}\r\n\r\nfunction viewsClose(a: CameraView, b: CameraView): boolean {\r\n return (\r\n Math.abs(a.x - b.x) < FRAMED_EPSILON &&\r\n Math.abs(a.y - b.y) < FRAMED_EPSILON &&\r\n Math.abs(a.w - b.w) < FRAMED_EPSILON &&\r\n Math.abs(a.h - b.h) < FRAMED_EPSILON\r\n );\r\n}\r\n\r\n/**\r\n * Animates a camera to a `CameraView`. Standalone controller in the\r\n * `PingInput`/`MinimapController` shape: the host owns construction and\r\n * disposal, and every timing dependency is injectable for deterministic tests.\r\n */\r\nexport class CameraAnimator {\r\n private readonly camera: Camera;\r\n private readonly getCanvasSize: () => { w: number; h: number };\r\n private readonly frames: FrameScheduler;\r\n private readonly now: () => number;\r\n private readonly durationMs: number;\r\n private readonly easing: (t: number) => number;\r\n\r\n private rafId: number | null = null;\r\n private from: CameraView | null = null;\r\n private to: CameraView | null = null;\r\n private startedAt = 0;\r\n private endListeners = new Set<(reason: CameraAnimationEndReason) => void>();\r\n /**\r\n * Monotonic operation counter. `animateTo`/`jumpTo` claim a generation\r\n * before emitting 'superseded'; if an onEnd listener starts a newer\r\n * operation during that emit, the outer call sees a bumped counter and\r\n * bails instead of overwriting the nested animation's state. Without this,\r\n * the nested animation would run to completion having never reported an end\r\n * reason, breaking the exactly-one guarantee the spec makes.\r\n */\r\n private generation = 0;\r\n\r\n private lastWrite: { x: number; y: number; zoom: number } | null = null;\r\n private disposed = false;\r\n private detachListeners: (() => void) | null = null;\r\n\r\n constructor(element: HTMLElement, camera: Camera, options: CameraAnimatorOptions) {\r\n if (options.frames !== undefined) {\r\n const { requestFrame, cancelFrame } = options.frames;\r\n if (typeof requestFrame !== 'function' || typeof cancelFrame !== 'function') {\r\n throw new Error(\r\n '[fieldnotes] CameraAnimator: `frames` must supply both requestFrame and cancelFrame',\r\n );\r\n }\r\n }\r\n this.camera = camera;\r\n this.getCanvasSize = options.getCanvasSize;\r\n this.frames = options.frames ?? {\r\n requestFrame: (cb) => requestAnimationFrame(cb),\r\n cancelFrame: (id) => cancelAnimationFrame(id),\r\n };\r\n this.now = options.now ?? (() => performance.now());\r\n this.durationMs = options.durationMs ?? DEFAULT_DURATION_MS;\r\n this.easing = options.easing ?? easeOutCubic;\r\n\r\n if (options.interactive ?? true) {\r\n const onUserInput = (): void => {\r\n this.end('cancelled');\r\n };\r\n const types = ['pointerdown', 'wheel', 'keydown'] as const;\r\n for (const type of types) {\r\n element.addEventListener(type, onUserInput, { passive: true });\r\n }\r\n this.detachListeners = () => {\r\n for (const type of types) {\r\n element.removeEventListener(type, onUserInput);\r\n }\r\n };\r\n }\r\n }\r\n\r\n get animating(): boolean {\r\n return this.to !== null;\r\n }\r\n\r\n onEnd(listener: (reason: CameraAnimationEndReason) => void): () => void {\r\n this.endListeners.add(listener);\r\n return () => this.endListeners.delete(listener);\r\n }\r\n\r\n animateTo(view: CameraView): void {\r\n const size = this.validateAndMeasure(view);\r\n if (size === null) return;\r\n\r\n const current = this.camera.getVisibleRect(size.w, size.h);\r\n const generation = ++this.generation;\r\n this.end('superseded');\r\n // An onEnd listener may have started a newer operation during that\r\n // 'superseded' emit. It now owns the animator; overwriting its state here\r\n // would leave it running with no end reason ever reported.\r\n if (this.generation !== generation) return;\r\n\r\n if (viewsClose(current, view)) {\r\n applyCameraView(this.camera, view, size.w, size.h);\r\n this.emit('complete');\r\n return;\r\n }\r\n\r\n this.from = current;\r\n this.to = view;\r\n this.startedAt = this.now();\r\n this.lastWrite = null;\r\n this.rafId = this.frames.requestFrame(this.step);\r\n }\r\n\r\n jumpTo(view: CameraView): void {\r\n const size = this.validateAndMeasure(view);\r\n if (size === null) return;\r\n const generation = ++this.generation;\r\n this.end('superseded');\r\n if (this.generation !== generation) return; // nested operation owns us now\r\n applyCameraView(this.camera, view, size.w, size.h);\r\n this.lastWrite = null;\r\n }\r\n\r\n cancel(): void {\r\n if (this.disposed) return;\r\n this.end('cancelled');\r\n }\r\n\r\n /**\r\n * Terminal. Order is load-bearing: the flag is set BEFORE any listener runs,\r\n * because an onEnd listener can call animateTo during the disposal callback.\r\n * With the flag set last, that call would start a real animation which the\r\n * listener clear then silently discards — a second animation with no end\r\n * reason, breaking the exactly-one guarantee.\r\n */\r\n dispose(): void {\r\n if (this.disposed) return;\r\n this.disposed = true;\r\n // Bump the generation so an animateTo/jumpTo call whose 'superseded' emit\r\n // reached this dispose() (nested inside its own emit) sees its claimed\r\n // generation go stale, just like nested animateTo/jumpTo re-entrancy. Without\r\n // this, the outer call's generation guard passes and it writes state (or\r\n // schedules a frame) onto a disposed animator.\r\n this.generation++;\r\n\r\n const wasAnimating = this.to !== null;\r\n this.clearFrame();\r\n this.from = null;\r\n this.to = null;\r\n this.lastWrite = null;\r\n\r\n if (wasAnimating) this.emit('cancelled');\r\n\r\n this.endListeners.clear();\r\n this.detachListeners?.();\r\n this.detachListeners = null;\r\n }\r\n\r\n /**\r\n * Steps 1-3 of the public-call contract. Returns null when the caller must\r\n * stop, having already handled termination.\r\n *\r\n * The disposed check precedes validation deliberately: ordering it after\r\n * would make `disposed.animateTo(invalidView)` both required to throw and\r\n * required to stay silent. Disposal wins — a terminal animator is inert for\r\n * every input, and post-disposal calls are exactly the racy teardown paths\r\n * where a throw is least useful.\r\n */\r\n private validateAndMeasure(view: CameraView): { w: number; h: number } | null {\r\n if (this.disposed) return null;\r\n assertValidView(view);\r\n const size = this.getCanvasSize();\r\n // Validate the MEASUREMENT too, not just the target. A negative or\r\n // non-finite dimension would otherwise reach camera.getVisibleRect()\r\n // before applyCameraView could reject it, and NaN propagates through\r\n // Camera.setZoom's Math.min/Math.max clamp to poison the camera\r\n // permanently. Throws synchronously here, where the caller can catch it.\r\n assertCanvasDims(size.w, size.h);\r\n if (size.w === 0 || size.h === 0) {\r\n // A valid target meeting a zero size cancels any running animation\r\n // synchronously within this call, so `animating` is false the instant it\r\n // returns. 'cancelled', never 'superseded': the animation was ended by\r\n // the host becoming unmeasurable, not replaced by a running successor.\r\n this.end('cancelled');\r\n return null;\r\n }\r\n return size;\r\n }\r\n\r\n private step = (): void => {\r\n if (this.disposed || this.to === null || this.from === null) return;\r\n\r\n // Foreign-write guard: if the camera no longer matches what this animator\r\n // last wrote, another writer moved it — drag, pinch, wheel, keyboard zoom,\r\n // a PanInertia coast frame, a minimap tap, fitToContent, or loadState.\r\n if (this.foreignWrite()) {\r\n this.end('cancelled');\r\n return;\r\n }\r\n\r\n const size = this.getCanvasSize();\r\n if (!canvasDimsUsable(size.w, size.h)) {\r\n // A poisoned measurement mid-flight TERMINATES rather than throws.\r\n // Throwing from inside a frame callback has no catcher and would strand\r\n // the animation state with its lifecycle unresolved — the exact orphan\r\n // this contract exists to prevent. Public calls still throw, because\r\n // there a caller can handle it.\r\n this.end('cancelled');\r\n return;\r\n }\r\n if (size.w === 0 || size.h === 0) {\r\n // The clock keeps advancing while a host is hidden, so without this the\r\n // animation would reach t=1, write nothing, and report a false 'complete'.\r\n this.end('cancelled');\r\n return;\r\n }\r\n\r\n const elapsed = this.now() - this.startedAt;\r\n const t = this.durationMs <= 0 ? 1 : Math.min(1, elapsed / this.durationMs);\r\n const view = lerpView(this.from, this.to, this.easing(t));\r\n applyCameraView(this.camera, view, size.w, size.h);\r\n this.recordWrite();\r\n\r\n if (t >= 1) {\r\n this.end('complete');\r\n return;\r\n }\r\n this.rafId = this.frames.requestFrame(this.step);\r\n };\r\n\r\n private recordWrite(): void {\r\n this.lastWrite = {\r\n x: this.camera.position.x,\r\n y: this.camera.position.y,\r\n zoom: this.camera.zoom,\r\n };\r\n }\r\n\r\n private foreignWrite(): boolean {\r\n if (this.lastWrite === null) return false;\r\n const eps = 1e-6;\r\n return (\r\n Math.abs(this.camera.position.x - this.lastWrite.x) > eps ||\r\n Math.abs(this.camera.position.y - this.lastWrite.y) > eps ||\r\n Math.abs(this.camera.zoom - this.lastWrite.zoom) > eps\r\n );\r\n }\r\n\r\n /** Terminates an in-flight animation with `reason`. No-op when idle. */\r\n private end(reason: CameraAnimationEndReason): void {\r\n if (this.disposed || this.to === null) return;\r\n this.clearFrame();\r\n this.from = null;\r\n this.to = null;\r\n this.lastWrite = null;\r\n this.emit(reason);\r\n }\r\n\r\n private clearFrame(): void {\r\n if (this.rafId !== null) {\r\n this.frames.cancelFrame(this.rafId);\r\n this.rafId = null;\r\n }\r\n }\r\n\r\n private emit(reason: CameraAnimationEndReason): void {\r\n for (const listener of [...this.endListeners]) {\r\n try {\r\n listener(reason);\r\n } catch {\r\n // Listener faults must never wedge the animator.\r\n }\r\n }\r\n }\r\n}\r\n","import type { CameraView } from './camera-view';\r\n\r\n/**\r\n * The wire shape of a focus-request presence payload. Focus is ephemeral by\r\n * contract: presence frames only — never elements, undo history, persisted\r\n * canvas state, or durable operations. A frame that arrives while a client is\r\n * offline is dropped, never queued, and late joiners are never retro-focused.\r\n *\r\n * `audience` is a delivery hint, NOT a security boundary: the relay broadcasts\r\n * presence room-wide and receivers filter by their own role. The payload is a\r\n * map rectangle, not secret data; hidden elements stay behind relay `canRead`.\r\n */\r\nexport interface FocusPresence {\r\n readonly kind: 'focus';\r\n readonly x: number;\r\n readonly y: number;\r\n readonly w: number;\r\n readonly h: number;\r\n readonly audience: FocusAudience;\r\n readonly color?: string;\r\n}\r\n\r\nexport type FocusAudience = 'all' | 'players' | 'display';\r\n\r\nexport const FOCUS_PRESENCE_KIND = 'focus';\r\n\r\nconst AUDIENCES: readonly FocusAudience[] = ['all', 'players', 'display'];\r\n\r\nfunction isPositiveFinite(value: unknown): value is number {\r\n return typeof value === 'number' && Number.isFinite(value) && value > 0;\r\n}\r\n\r\nfunction isFiniteNumber(value: unknown): value is number {\r\n return typeof value === 'number' && Number.isFinite(value);\r\n}\r\n\r\n/**\r\n * The only trust boundary between untyped wire data and the canvas. Mirrors\r\n * `isPingPresence`: every field is validated, and `color` is rejected when\r\n * defined but not a string, because it flows into canvas styling.\r\n *\r\n * These rules deliberately match `CameraView` validation, so a payload that\r\n * passes here can never make the animator's synchronous target validation\r\n * throw on the receive path.\r\n */\r\nexport function isFocusPresence(data: unknown): data is FocusPresence {\r\n if (typeof data !== 'object' || data === null) return false;\r\n const payload = data as {\r\n kind?: unknown;\r\n x?: unknown;\r\n y?: unknown;\r\n w?: unknown;\r\n h?: unknown;\r\n audience?: unknown;\r\n color?: unknown;\r\n };\r\n if (payload.kind !== FOCUS_PRESENCE_KIND) return false;\r\n if (!isFiniteNumber(payload.x) || !isFiniteNumber(payload.y)) return false;\r\n if (!isPositiveFinite(payload.w) || !isPositiveFinite(payload.h)) return false;\r\n if (typeof payload.audience !== 'string' || !AUDIENCES.some((a) => a === payload.audience)) {\r\n return false;\r\n }\r\n if (payload.color !== undefined && typeof payload.color !== 'string') return false;\r\n return true;\r\n}\r\n\r\n/** Builds the presence payload for one local focus request. */\r\nexport function toFocusPresence(\r\n view: CameraView,\r\n audience: FocusAudience,\r\n color?: string,\r\n): FocusPresence {\r\n return {\r\n kind: FOCUS_PRESENCE_KIND,\r\n x: view.x,\r\n y: view.y,\r\n w: view.w,\r\n h: view.h,\r\n audience,\r\n ...(color === undefined ? {} : { color }),\r\n };\r\n}\r\n","import type { CameraAnimator } from './camera-animator';\r\nimport { isFocusPresence, type FocusAudience } from './focus-presence';\r\nimport { RemotePingOverlay, type RemotePingOverlayHost } from './remote-ping-overlay';\r\n\r\nexport type FocusRole = 'dm' | 'player' | 'display';\r\n\r\n/** The two viewport capabilities the receiver needs; `Viewport` satisfies it. */\r\nexport type RemoteFocusReceiverHost = RemotePingOverlayHost;\r\n\r\nexport interface RemoteFocusReceiverOptions {\r\n role: FocusRole;\r\n animator: CameraAnimator;\r\n /** Draw an arrival pulse at the focus target. Default `true`. */\r\n pulse?: boolean;\r\n pulseColor?: string;\r\n pulseDurationMs?: number;\r\n pulseRadius?: number;\r\n /** Animate the camera (default) or jump instantly. */\r\n animate?: boolean;\r\n}\r\n\r\nfunction audienceIncludes(audience: FocusAudience, role: FocusRole): boolean {\r\n if (role === 'dm') return false; // a DM device is never moved by a focus frame\r\n if (audience === 'all') return true;\r\n if (audience === 'players') return role === 'player';\r\n return role === 'display';\r\n}\r\n\r\n/**\r\n * Applies remote focus requests addressed to this client's role: moves the\r\n * camera and marks the target with one pulse.\r\n *\r\n * The pulse is DELEGATED to a private `RemotePingOverlay` rather than\r\n * reimplemented. `renderPingPulse` draws a single frame from an elapsed time,\r\n * so an animated pulse needs a rAF loop that re-requests renders, expires the\r\n * pulse, and cancels on disposal — machinery that already exists and is tested\r\n * there. `maxPingsPerSender: 1` makes a rapid second focus REPLACE the older\r\n * pulse instead of leaving two competing markers; different senders keep\r\n * separate keys and coexist, which is correct when two DMs share a table.\r\n */\r\nexport class RemoteFocusReceiver {\r\n private readonly role: FocusRole;\r\n private readonly animator: CameraAnimator;\r\n private readonly animate: boolean;\r\n private readonly pulseColor: string | undefined;\r\n private readonly overlay: RemotePingOverlay | null;\r\n private disposed = false;\r\n\r\n constructor(host: RemoteFocusReceiverHost, options: RemoteFocusReceiverOptions) {\r\n this.role = options.role;\r\n this.animator = options.animator;\r\n this.animate = options.animate ?? true;\r\n this.pulseColor = options.pulseColor;\r\n this.overlay =\r\n (options.pulse ?? true)\r\n ? new RemotePingOverlay(host, {\r\n ...(options.pulseColor === undefined ? {} : { color: options.pulseColor }),\r\n ...(options.pulseDurationMs === undefined\r\n ? {}\r\n : { durationMs: options.pulseDurationMs }),\r\n ...(options.pulseRadius === undefined ? {} : { radius: options.pulseRadius }),\r\n maxPingsPerSender: 1,\r\n })\r\n : null;\r\n }\r\n\r\n /**\r\n * Applies a presence payload from `sender`. Returns `false` for payloads\r\n * that are not focus frames, or are addressed to a different role, so hosts\r\n * can feed every presence frame through without disturbing other handlers.\r\n */\r\n apply(from: string, data: unknown): boolean {\r\n if (this.disposed || !isFocusPresence(data)) return false;\r\n if (!audienceIncludes(data.audience, this.role)) return false;\r\n\r\n const view = { x: data.x, y: data.y, w: data.w, h: data.h };\r\n // `isFocusPresence` enforces the same rules as CameraView validation, so\r\n // wire data cannot make the animator's synchronous validation throw here.\r\n if (this.animate) {\r\n this.animator.animateTo(view);\r\n } else {\r\n this.animator.jumpTo(view);\r\n }\r\n\r\n this.overlay?.apply(from, {\r\n kind: 'ping',\r\n x: view.x + view.w / 2,\r\n y: view.y + view.h / 2,\r\n color: data.color ?? this.pulseColor,\r\n });\r\n return true;\r\n }\r\n\r\n /** Idempotent. Does NOT dispose the animator — the host owns that. */\r\n dispose(): void {\r\n if (this.disposed) return;\r\n this.disposed = true;\r\n this.overlay?.dispose();\r\n }\r\n}\r\n","import type { Tool, ToolContext, PointerState } from './types';\n\nexport class HandTool implements Tool {\n readonly name = 'hand';\n private panning = false;\n private lastScreen = { x: 0, y: 0 };\n\n onActivate(ctx: ToolContext): void {\n ctx.setCursor?.('grab');\n }\n\n onDeactivate(ctx: ToolContext): void {\n ctx.setCursor?.('default');\n }\n\n onPointerDown(state: PointerState, ctx: ToolContext): void {\n this.panning = true;\n this.lastScreen = { x: state.x, y: state.y };\n ctx.setCursor?.('grabbing');\n }\n\n onPointerMove(state: PointerState, ctx: ToolContext): void {\n if (!this.panning) return;\n const dx = state.x - this.lastScreen.x;\n const dy = state.y - this.lastScreen.y;\n this.lastScreen = { x: state.x, y: state.y };\n ctx.camera.pan(dx, dy);\n }\n\n onPointerUp(_state: PointerState, ctx: ToolContext): void {\n this.panning = false;\n ctx.setCursor?.('grab');\n }\n}\n","import type { StrokePoint } from '../core/types';\r\nimport type { Tool, ToolContext, PointerState } from './types';\r\nimport { createStroke } from '../elements/element-factory';\r\nimport { simplifyPoints, smoothToSegments, pressureToWidth } from '../elements/stroke-smoothing';\r\nimport { computeStrokeSegments } from '../elements/stroke-cache';\r\n\r\nexport interface PencilToolOptions {\r\n name?: string;\r\n color?: string;\r\n width?: number;\r\n smoothing?: number;\r\n minPointDistance?: number;\r\n progressiveSimplifyThreshold?: number;\r\n opacity?: number;\r\n blendMode?: 'multiply';\r\n}\r\n\r\nconst MIN_POINTS_FOR_STROKE = 2;\r\nconst DEFAULT_SMOOTHING = 1.5;\r\nconst DEFAULT_PRESSURE = 0.5;\r\nconst DEFAULT_MIN_POINT_DISTANCE = 3;\r\nconst DEFAULT_PROGRESSIVE_THRESHOLD = 200;\r\nconst PROGRESSIVE_HOT_ZONE = 30;\r\n\r\nexport class PencilTool implements Tool {\r\n readonly name: string;\r\n private drawing = false;\r\n private points: StrokePoint[] = [];\r\n private color: string;\r\n private width: number;\r\n private smoothing: number;\r\n private minPointDistance: number;\r\n private progressiveThreshold: number;\r\n private nextSimplifyAt: number;\r\n private opacity: number;\r\n private blendMode: 'multiply' | undefined;\r\n private optionListeners = new Set<() => void>();\r\n\r\n constructor(options: PencilToolOptions = {}) {\r\n this.name = options.name ?? 'pencil';\r\n this.color = options.color ?? '#000000';\r\n this.width = options.width ?? 2;\r\n this.smoothing = options.smoothing ?? DEFAULT_SMOOTHING;\r\n this.minPointDistance = options.minPointDistance ?? DEFAULT_MIN_POINT_DISTANCE;\r\n this.progressiveThreshold =\r\n options.progressiveSimplifyThreshold ?? DEFAULT_PROGRESSIVE_THRESHOLD;\r\n this.nextSimplifyAt = this.progressiveThreshold;\r\n this.opacity = options.opacity ?? 1;\r\n this.blendMode = options.blendMode;\r\n }\r\n\r\n onActivate(ctx: ToolContext): void {\r\n ctx.setCursor?.('crosshair');\r\n }\r\n\r\n onDeactivate(ctx: ToolContext): void {\r\n ctx.setCursor?.('default');\r\n }\r\n\r\n getOptions(): PencilToolOptions {\r\n return {\r\n color: this.color,\r\n width: this.width,\r\n smoothing: this.smoothing,\r\n minPointDistance: this.minPointDistance,\r\n progressiveSimplifyThreshold: this.progressiveThreshold,\r\n opacity: this.opacity,\r\n blendMode: this.blendMode,\r\n };\r\n }\r\n\r\n onOptionsChange(listener: () => void): () => void {\r\n this.optionListeners.add(listener);\r\n return () => this.optionListeners.delete(listener);\r\n }\r\n\r\n setOptions(options: PencilToolOptions): void {\r\n if (options.color !== undefined) this.color = options.color;\r\n if (options.width !== undefined) this.width = options.width;\r\n if (options.smoothing !== undefined) this.smoothing = options.smoothing;\r\n if (options.minPointDistance !== undefined) this.minPointDistance = options.minPointDistance;\r\n if (options.progressiveSimplifyThreshold !== undefined)\r\n this.progressiveThreshold = options.progressiveSimplifyThreshold;\r\n if (options.opacity !== undefined) this.opacity = options.opacity;\r\n if (options.blendMode !== undefined) this.blendMode = options.blendMode;\r\n this.notifyOptionsChange();\r\n }\r\n\r\n onPointerDown(state: PointerState, ctx: ToolContext): void {\r\n this.drawing = true;\r\n const world = ctx.camera.screenToWorld({ x: state.x, y: state.y });\r\n const pressure = state.pressure === 0 ? DEFAULT_PRESSURE : state.pressure;\r\n this.points = [{ x: world.x, y: world.y, pressure }];\r\n this.nextSimplifyAt = this.progressiveThreshold;\r\n }\r\n\r\n onPointerMove(state: PointerState, ctx: ToolContext): void {\r\n if (!this.drawing) return;\r\n const world = ctx.camera.screenToWorld({ x: state.x, y: state.y });\r\n const pressure = state.pressure === 0 ? DEFAULT_PRESSURE : state.pressure;\r\n\r\n const last = this.points[this.points.length - 1];\r\n if (last) {\r\n const dx = world.x - last.x;\r\n const dy = world.y - last.y;\r\n if (dx * dx + dy * dy < this.minPointDistance * this.minPointDistance) return;\r\n }\r\n\r\n this.points.push({ x: world.x, y: world.y, pressure });\r\n\r\n // Progressively simplify the cold zone to bound memory on very long strokes.\r\n // nextSimplifyAt doubles after each pass to avoid compounding data loss.\r\n if (this.points.length > this.nextSimplifyAt) {\r\n const hotZone = this.points.slice(-PROGRESSIVE_HOT_ZONE);\r\n const coldZone = this.points.slice(0, -PROGRESSIVE_HOT_ZONE);\r\n const simplified = simplifyPoints(coldZone, this.smoothing * 2);\r\n this.points = [...simplified, ...hotZone];\r\n this.nextSimplifyAt = this.points.length + this.progressiveThreshold;\r\n }\r\n\r\n ctx.requestRender();\r\n }\r\n\r\n onPointerUp(_state: PointerState, ctx: ToolContext): void {\r\n if (!this.drawing) return;\r\n this.drawing = false;\r\n\r\n if (this.points.length < MIN_POINTS_FOR_STROKE) {\r\n this.points = [];\r\n return;\r\n }\r\n\r\n const simplified = simplifyPoints(this.points, this.smoothing);\r\n const stroke = createStroke({\r\n points: simplified,\r\n color: this.color,\r\n width: this.width,\r\n layerId: ctx.activeLayerId ?? '',\r\n opacity: this.opacity,\r\n blendMode: this.blendMode,\r\n });\r\n ctx.store.add(stroke);\r\n computeStrokeSegments(stroke);\r\n this.points = [];\r\n ctx.requestRender();\r\n }\r\n\r\n private notifyOptionsChange(): void {\r\n for (const listener of this.optionListeners) listener();\r\n }\r\n\r\n renderOverlay(ctx: CanvasRenderingContext2D): void {\r\n if (!this.drawing || this.points.length < 2) return;\r\n\r\n ctx.save();\r\n ctx.strokeStyle = this.color;\r\n ctx.lineCap = 'round';\r\n ctx.lineJoin = 'round';\r\n // Preview a highlighter at its real opacity + blend so it doesn't snap on commit;\r\n // a normal pencil keeps the lighter 0.8 in-progress affordance.\r\n ctx.globalAlpha = this.blendMode ? this.opacity : 0.8;\r\n if (this.blendMode) ctx.globalCompositeOperation = this.blendMode;\r\n\r\n const segments = smoothToSegments(this.points);\r\n for (const seg of segments) {\r\n const w =\r\n (pressureToWidth(seg.start.pressure, this.width) +\r\n pressureToWidth(seg.end.pressure, this.width)) /\r\n 2;\r\n ctx.lineWidth = w;\r\n ctx.beginPath();\r\n ctx.moveTo(seg.start.x, seg.start.y);\r\n ctx.bezierCurveTo(seg.cp1.x, seg.cp1.y, seg.cp2.x, seg.cp2.y, seg.end.x, seg.end.y);\r\n ctx.stroke();\r\n }\r\n\r\n ctx.restore();\r\n }\r\n}\r\n","import type { Point, StrokePoint } from '../core/types';\r\n\r\nfunction lerp(a: StrokePoint, b: StrokePoint, t: number): StrokePoint {\r\n return {\r\n x: a.x + (b.x - a.x) * t,\r\n y: a.y + (b.y - a.y) * t,\r\n pressure: a.pressure + (b.pressure - a.pressure) * t,\r\n };\r\n}\r\n\r\n/**\r\n * Split a stroke's points by an eraser circle (all in the stroke's local space).\r\n * Returns surviving runs (each ≥2 points), `[]` if fully erased, or `null` if nothing\r\n * was within the radius (no change).\r\n */\r\nexport function erasePoints(\r\n points: StrokePoint[],\r\n eraser: Point,\r\n radius: number,\r\n): StrokePoint[][] | null {\r\n const r2 = radius * radius;\r\n\r\n if (points.length < 2) {\r\n const p = points[0];\r\n if (p && (p.x - eraser.x) ** 2 + (p.y - eraser.y) ** 2 <= r2) return [];\r\n return null;\r\n }\r\n\r\n const runs: StrokePoint[][] = [];\r\n let current: StrokePoint[] = [];\r\n let erased = false;\r\n\r\n const flush = (): void => {\r\n if (current.length >= 2) runs.push(current);\r\n current = [];\r\n };\r\n\r\n for (let i = 0; i < points.length - 1; i++) {\r\n const a = points[i];\r\n const b = points[i + 1];\r\n if (!a || !b) continue;\r\n\r\n const dx = b.x - a.x;\r\n const dy = b.y - a.y;\r\n const fx = a.x - eraser.x;\r\n const fy = a.y - eraser.y;\r\n const A = dx * dx + dy * dy;\r\n const B = 2 * (fx * dx + fy * dy);\r\n const C = fx * fx + fy * fy - r2;\r\n\r\n let tLo = 1;\r\n let tHi = 0;\r\n if (A === 0) {\r\n if (C <= 0) {\r\n tLo = 0;\r\n tHi = 1;\r\n }\r\n } else {\r\n const disc = B * B - 4 * A * C;\r\n if (disc >= 0) {\r\n const sq = Math.sqrt(disc);\r\n const lo = Math.max(0, (-B - sq) / (2 * A));\r\n const hi = Math.min(1, (-B + sq) / (2 * A));\r\n // Strict `<`: a tangent graze (lo === hi, zero-width overlap) is not an erase —\r\n // it would otherwise split a stroke in two at a single duplicated point.\r\n if (lo < hi) {\r\n tLo = lo;\r\n tHi = hi;\r\n }\r\n }\r\n }\r\n\r\n if (tLo > tHi) {\r\n if (current.length === 0) current.push(a);\r\n current.push(b);\r\n continue;\r\n }\r\n\r\n erased = true;\r\n if (tLo > 0) {\r\n if (current.length === 0) current.push(a);\r\n current.push(lerp(a, b, tLo));\r\n flush();\r\n } else {\r\n flush();\r\n }\r\n if (tHi < 1) {\r\n current = [lerp(a, b, tHi), b];\r\n }\r\n }\r\n\r\n flush();\r\n return erased ? runs : null;\r\n}\r\n","import type { Bounds, Point } from '../core/types';\r\nimport type { Tool, ToolContext, PointerState } from './types';\r\nimport type { StrokeElement } from '../elements/types';\r\nimport { hitTestStroke } from '../elements/stroke-hit';\r\nimport { createStroke } from '../elements/element-factory';\r\nimport { erasePoints } from '../elements/stroke-erase';\r\n\r\nexport interface EraserToolOptions {\r\n /** Eraser radius in SCREEN pixels (matches the cursor circle; converted to world units per zoom). */\r\n radius?: number;\r\n mode?: 'partial' | 'stroke';\r\n}\r\n\r\nconst DEFAULT_RADIUS = 20;\r\n\r\nfunction makeEraserCursor(radius: number): string {\r\n const size = radius * 2;\r\n const svg = `<svg xmlns='http://www.w3.org/2000/svg' width='${size}' height='${size}'><circle cx='${radius}' cy='${radius}' r='${radius - 1}' fill='none' stroke='%23666' stroke-width='1.5'/></svg>`;\r\n return `url(\"data:image/svg+xml,${svg}\") ${radius} ${radius}, crosshair`;\r\n}\r\n\r\nexport class EraserTool implements Tool {\r\n readonly name = 'eraser';\r\n private erasing = false;\r\n private radius: number;\r\n private cursor: string;\r\n private mode: 'partial' | 'stroke';\r\n\r\n constructor(options: EraserToolOptions = {}) {\r\n this.radius = options.radius ?? DEFAULT_RADIUS;\r\n this.cursor = makeEraserCursor(this.radius);\r\n this.mode = options.mode ?? 'partial';\r\n }\r\n\r\n getOptions(): EraserToolOptions {\r\n return { radius: this.radius, mode: this.mode };\r\n }\r\n\r\n setOptions(options: EraserToolOptions): void {\r\n if (options.mode !== undefined) this.mode = options.mode;\r\n if (options.radius !== undefined) {\r\n this.radius = options.radius;\r\n this.cursor = makeEraserCursor(this.radius); // applied on next activate\r\n }\r\n }\r\n\r\n onActivate(ctx: ToolContext): void {\r\n ctx.setCursor?.(this.cursor);\r\n }\r\n\r\n onDeactivate(ctx: ToolContext): void {\r\n ctx.setCursor?.('default');\r\n }\r\n\r\n onPointerDown(state: PointerState, ctx: ToolContext): void {\r\n this.erasing = true;\r\n this.eraseAt(state, ctx);\r\n }\r\n\r\n onPointerMove(state: PointerState, ctx: ToolContext): void {\r\n if (!this.erasing) return;\r\n this.eraseAt(state, ctx);\r\n }\r\n\r\n onPointerUp(_state: PointerState, _ctx: ToolContext): void {\r\n this.erasing = false;\r\n }\r\n\r\n private eraseAt(state: PointerState, ctx: ToolContext): void {\r\n const world = ctx.camera.screenToWorld({ x: state.x, y: state.y });\r\n const worldRadius = this.radius / ctx.camera.zoom;\r\n const queryBounds: Bounds = {\r\n x: world.x - worldRadius,\r\n y: world.y - worldRadius,\r\n w: worldRadius * 2,\r\n h: worldRadius * 2,\r\n };\r\n const candidates = ctx.store.queryRect(queryBounds);\r\n let erased = false;\r\n\r\n for (const el of candidates) {\r\n if (el.type !== 'stroke') continue;\r\n if (ctx.isLayerVisible && !ctx.isLayerVisible(el.layerId)) continue;\r\n if (ctx.isLayerLocked && ctx.isLayerLocked(el.layerId)) continue;\r\n if (!this.strokeIntersects(el, world, worldRadius)) continue;\r\n if (this.mode === 'stroke') {\r\n ctx.store.remove(el.id);\r\n erased = true;\r\n continue;\r\n }\r\n const localEraser = { x: world.x - el.position.x, y: world.y - el.position.y };\r\n const runs = erasePoints(el.points, localEraser, worldRadius);\r\n if (runs === null) continue;\r\n ctx.store.remove(el.id);\r\n for (const run of runs) {\r\n ctx.store.add(\r\n createStroke({\r\n points: run,\r\n color: el.color,\r\n width: el.width,\r\n opacity: el.opacity,\r\n layerId: el.layerId,\r\n zIndex: el.zIndex,\r\n position: el.position,\r\n }),\r\n );\r\n }\r\n erased = true;\r\n }\r\n\r\n if (erased) ctx.requestRender();\r\n }\r\n\r\n private strokeIntersects(stroke: StrokeElement, point: Point, worldRadius: number): boolean {\r\n return hitTestStroke(stroke, point, worldRadius);\r\n }\r\n}\r\n","import type { CanvasElement } from './types';\r\n\r\n/** Expand a selection to include every co-member of any group it touches. Returns `ids`\r\n * unchanged (same reference) when no selected element is grouped. */\r\nexport function expandToGroups(ids: string[], elements: CanvasElement[]): string[] {\r\n const byId = new Map(elements.map((e) => [e.id, e]));\r\n const groupIds = new Set<string>();\r\n for (const id of ids) {\r\n const g = byId.get(id)?.groupId;\r\n if (g) groupIds.add(g);\r\n }\r\n if (groupIds.size === 0) return ids;\r\n const idSet = new Set(ids);\r\n const result = [...ids];\r\n for (const el of elements) {\r\n if (el.groupId && groupIds.has(el.groupId) && !idSet.has(el.id)) {\r\n result.push(el.id);\r\n idSet.add(el.id);\r\n }\r\n }\r\n return result;\r\n}\r\n","import type { Bounds } from '../core/types';\r\n\r\nexport interface SnapGuide {\r\n axis: 'x' | 'y';\r\n position: number;\r\n}\r\nexport interface SnapResult {\r\n dx: number;\r\n dy: number;\r\n guides: SnapGuide[];\r\n}\r\n\r\ninterface AxisAnchors {\r\n lo: number;\r\n mid: number;\r\n hi: number;\r\n}\r\n\r\nfunction xAnchors(b: Bounds): AxisAnchors {\r\n return { lo: b.x, mid: b.x + b.w / 2, hi: b.x + b.w };\r\n}\r\n\r\nfunction yAnchors(b: Bounds): AxisAnchors {\r\n return { lo: b.y, mid: b.y + b.h / 2, hi: b.y + b.h };\r\n}\r\n\r\nfunction bestAxisSnap(\r\n moving: AxisAnchors,\r\n targets: Bounds[],\r\n anchorsFn: (b: Bounds) => AxisAnchors,\r\n threshold: number,\r\n): { delta: number; position: number } | null {\r\n let best: { delta: number; position: number } | null = null;\r\n\r\n for (const t of targets) {\r\n const ta = anchorsFn(t);\r\n const pairs: [number, number][] = [\r\n // colinear alignment: same-type edges/centers line up\r\n [ta.lo - moving.lo, ta.lo],\r\n [ta.mid - moving.mid, ta.mid],\r\n [ta.hi - moving.hi, ta.hi],\r\n // abutment: the moving box sits flush against the target's opposite edge\r\n [ta.lo - moving.hi, ta.lo],\r\n [ta.hi - moving.lo, ta.hi],\r\n ];\r\n\r\n for (const [delta, position] of pairs) {\r\n const abs = Math.abs(delta);\r\n if (abs <= threshold && (best === null || abs < Math.abs(best.delta))) {\r\n best = { delta, position };\r\n }\r\n }\r\n }\r\n\r\n return best;\r\n}\r\n\r\nexport function computeSnapGuides(\r\n moving: Bounds,\r\n targets: Bounds[],\r\n threshold: number,\r\n): SnapResult {\r\n const xSnap = bestAxisSnap(xAnchors(moving), targets, xAnchors, threshold);\r\n const ySnap = bestAxisSnap(yAnchors(moving), targets, yAnchors, threshold);\r\n\r\n const guides: SnapGuide[] = [];\r\n if (xSnap) guides.push({ axis: 'x', position: xSnap.position });\r\n if (ySnap) guides.push({ axis: 'y', position: ySnap.position });\r\n\r\n return { dx: xSnap?.delta ?? 0, dy: ySnap?.delta ?? 0, guides };\r\n}\r\n","import type { Point } from '../core/types';\r\nimport type { CanvasElement, TemplateElement } from '../elements/types';\r\nimport { rotatePoint } from '../core/geometry';\r\nimport type { HandlePosition } from './select-overlay';\r\n\r\nexport const MIN_ELEMENT_SIZE = 20;\r\n\r\nexport function anchorOffset(handle: HandlePosition, w: number, h: number): Point {\r\n switch (handle) {\r\n case 'se':\r\n return { x: -w / 2, y: -h / 2 };\r\n case 'sw':\r\n return { x: w / 2, y: -h / 2 };\r\n case 'ne':\r\n return { x: -w / 2, y: h / 2 };\r\n case 'nw':\r\n return { x: w / 2, y: h / 2 };\r\n default:\r\n return { x: 0, y: 0 };\r\n }\r\n}\r\n\r\nexport function computeResize(\r\n el: CanvasElement & { size: { w: number; h: number } },\r\n handle: HandlePosition,\r\n world: Point,\r\n lastWorld: Point,\r\n aspectRatio: number,\r\n lockAspect: boolean,\r\n): { position: { x: number; y: number }; size: { w: number; h: number } } {\r\n const dx = world.x - lastWorld.x;\r\n const dy = world.y - lastWorld.y;\r\n\r\n let { x, y, w, h } = { x: el.position.x, y: el.position.y, w: el.size.w, h: el.size.h };\r\n\r\n switch (handle) {\r\n case 'se':\r\n w += dx;\r\n h += dy;\r\n break;\r\n case 'sw':\r\n x += dx;\r\n w -= dx;\r\n h += dy;\r\n break;\r\n case 'ne':\r\n y += dy;\r\n w += dx;\r\n h -= dy;\r\n break;\r\n case 'nw':\r\n x += dx;\r\n y += dy;\r\n w -= dx;\r\n h -= dy;\r\n break;\r\n }\r\n\r\n if (lockAspect && aspectRatio > 0) {\r\n const absDw = Math.abs(w - el.size.w);\r\n const absDh = Math.abs(h - el.size.h);\r\n if (absDw >= absDh) {\r\n h = w / aspectRatio;\r\n } else {\r\n w = h * aspectRatio;\r\n }\r\n if (handle === 'nw' || handle === 'sw') {\r\n x = el.position.x + el.size.w - w;\r\n }\r\n if (handle === 'nw' || handle === 'ne') {\r\n y = el.position.y + el.size.h - h;\r\n }\r\n }\r\n\r\n if (w < MIN_ELEMENT_SIZE) {\r\n if (handle === 'nw' || handle === 'sw') x = el.position.x + el.size.w - MIN_ELEMENT_SIZE;\r\n w = MIN_ELEMENT_SIZE;\r\n }\r\n if (h < MIN_ELEMENT_SIZE) {\r\n if (handle === 'nw' || handle === 'ne') y = el.position.y + el.size.h - MIN_ELEMENT_SIZE;\r\n h = MIN_ELEMENT_SIZE;\r\n }\r\n\r\n return { position: { x, y }, size: { w, h } };\r\n}\r\n\r\nexport function computeRotatedResize(\r\n el: CanvasElement & { size: { w: number; h: number } },\r\n handle: HandlePosition,\r\n angle: number,\r\n world: Point,\r\n lastWorld: Point,\r\n aspectRatio: number,\r\n lockAspect: boolean,\r\n): { position: { x: number; y: number }; size: { w: number; h: number } } {\r\n const wdx = world.x - lastWorld.x;\r\n const wdy = world.y - lastWorld.y;\r\n\r\n // world delta → element local frame (inverse rotation of the vector)\r\n const cosN = Math.cos(-angle);\r\n const sinN = Math.sin(-angle);\r\n const ldx = wdx * cosN - wdy * sinN;\r\n const ldy = wdx * sinN + wdy * cosN;\r\n\r\n let w = el.size.w;\r\n let h = el.size.h;\r\n switch (handle) {\r\n case 'se':\r\n w += ldx;\r\n h += ldy;\r\n break;\r\n case 'sw':\r\n w -= ldx;\r\n h += ldy;\r\n break;\r\n case 'ne':\r\n w += ldx;\r\n h -= ldy;\r\n break;\r\n case 'nw':\r\n w -= ldx;\r\n h -= ldy;\r\n break;\r\n }\r\n\r\n if (lockAspect && aspectRatio > 0) {\r\n const absDw = Math.abs(w - el.size.w);\r\n const absDh = Math.abs(h - el.size.h);\r\n if (absDw >= absDh) h = w / aspectRatio;\r\n else w = h * aspectRatio;\r\n }\r\n w = Math.max(w, MIN_ELEMENT_SIZE);\r\n h = Math.max(h, MIN_ELEMENT_SIZE);\r\n\r\n // anchor (opposite corner) fixed in world space, computed from OLD geometry\r\n const oldCenter = { x: el.position.x + el.size.w / 2, y: el.position.y + el.size.h / 2 };\r\n const oldAnchorLocal = anchorOffset(handle, el.size.w, el.size.h);\r\n const anchorWorld = rotatePoint(\r\n { x: oldCenter.x + oldAnchorLocal.x, y: oldCenter.y + oldAnchorLocal.y },\r\n oldCenter,\r\n angle,\r\n );\r\n\r\n // new center so the anchor stays put: anchorWorld = newCenter + R(angle)·newAnchorLocal\r\n const newAnchorLocal = anchorOffset(handle, w, h);\r\n const cos = Math.cos(angle);\r\n const sin = Math.sin(angle);\r\n const rotatedAnchor = {\r\n x: newAnchorLocal.x * cos - newAnchorLocal.y * sin,\r\n y: newAnchorLocal.x * sin + newAnchorLocal.y * cos,\r\n };\r\n const newCenter = { x: anchorWorld.x - rotatedAnchor.x, y: anchorWorld.y - rotatedAnchor.y };\r\n const position = { x: newCenter.x - w / 2, y: newCenter.y - h / 2 };\r\n\r\n return { position, size: { w, h } };\r\n}\r\n\r\nexport interface TemplateResizeOptions {\r\n snapToGrid?: boolean;\r\n gridSize?: number;\r\n gridType?: 'square' | 'hex';\r\n}\r\n\r\nexport function computeTemplateResize(\r\n el: TemplateElement,\r\n world: Point,\r\n opts: TemplateResizeOptions,\r\n): Record<string, unknown> | null {\r\n const dx = world.x - el.position.x;\r\n const dy = world.y - el.position.y;\r\n let newRadius = Math.sqrt(dx * dx + dy * dy);\r\n\r\n if (opts.snapToGrid && opts.gridSize && opts.gridSize > 0) {\r\n const snapUnit = opts.gridType === 'hex' ? Math.sqrt(3) * opts.gridSize : opts.gridSize;\r\n newRadius = Math.max(snapUnit, Math.round(newRadius / snapUnit) * snapUnit);\r\n }\r\n newRadius = Math.max(MIN_ELEMENT_SIZE, newRadius);\r\n\r\n const updates: Record<string, unknown> = { radius: newRadius };\r\n if (el.feetPerCell != null && opts.gridSize && opts.gridSize > 0) {\r\n const snapUnit = opts.gridType === 'hex' ? Math.sqrt(3) * opts.gridSize : opts.gridSize;\r\n updates.radiusFeet = (newRadius / snapUnit) * el.feetPerCell;\r\n }\r\n\r\n return updates;\r\n}\r\n\r\nexport function computeRectangleLengthResize(\r\n el: TemplateElement,\r\n world: Point,\r\n opts: TemplateResizeOptions,\r\n): Record<string, unknown> | null {\r\n const cos = Math.cos(el.angle);\r\n const sin = Math.sin(el.angle);\r\n let len = (world.x - el.position.x) * cos + (world.y - el.position.y) * sin;\r\n if (opts.snapToGrid && opts.gridSize && opts.gridSize > 0) {\r\n const snapUnit = opts.gridType === 'hex' ? Math.sqrt(3) * opts.gridSize : opts.gridSize;\r\n len = Math.max(snapUnit, Math.round(len / snapUnit) * snapUnit);\r\n }\r\n len = Math.max(MIN_ELEMENT_SIZE, len);\r\n const updates: Record<string, unknown> = { radius: len };\r\n if (el.feetPerCell != null && opts.gridSize && opts.gridSize > 0) {\r\n const snapUnit = opts.gridType === 'hex' ? Math.sqrt(3) * opts.gridSize : opts.gridSize;\r\n updates.radiusFeet = (len / snapUnit) * el.feetPerCell;\r\n }\r\n return updates;\r\n}\r\n\r\nexport function computeRectangleWidthResize(\r\n el: TemplateElement,\r\n world: Point,\r\n opts: TemplateResizeOptions,\r\n): Record<string, unknown> | null {\r\n const cos = Math.cos(el.angle);\r\n const sin = Math.sin(el.angle);\r\n const perp = Math.abs(-(world.x - el.position.x) * sin + (world.y - el.position.y) * cos);\r\n let width = perp * 2;\r\n if (opts.snapToGrid && opts.gridSize && opts.gridSize > 0) {\r\n const snapUnit = opts.gridType === 'hex' ? Math.sqrt(3) * opts.gridSize : opts.gridSize;\r\n width = Math.max(snapUnit, Math.round(width / snapUnit) * snapUnit);\r\n }\r\n width = Math.max(MIN_ELEMENT_SIZE, width);\r\n return { width };\r\n}\r\n","import type { Bounds, Point } from '../core/types';\r\nimport type { Tool, ToolContext, PointerState } from './types';\r\nimport { smartSnap } from '../core/snap';\r\nimport { normalizeAngle } from '../core/geometry';\r\nimport type { CanvasElement } from '../elements/types';\r\nimport { updateArrowsBoundToElements } from '../elements/arrow-binding';\r\nimport { getElementBounds } from '../elements/element-bounds';\r\nimport { expandToGroups } from '../elements/group';\r\nimport { getElementsBoundingBox } from '../elements/bounds';\r\nimport { lineFromEndpoints } from '../elements/shape-geometry';\r\nimport { translateElementPatch } from '../elements/translate';\r\nimport {\r\n type ArrowHandle,\r\n hitTestArrowHandles,\r\n applyArrowHandleDrag,\r\n getArrowHandleCursor,\r\n getArrowHandleDragTarget,\r\n renderArrowHoverHandle,\r\n} from './arrow-handles';\r\nimport { computeSnapGuides } from '../elements/snap-guides';\r\nimport type { SnapGuide } from '../elements/snap-guides';\r\nimport {\r\n hitTest,\r\n hitTestResizeHandle,\r\n hitTestRotateHandle,\r\n hitTestLineHandles,\r\n hitTestTemplateResizeHandle,\r\n hitTestTemplateAimHandle,\r\n hitTestRectangleLengthHandle,\r\n hitTestRectangleWidthHandle,\r\n findElementsInRect,\r\n} from './select-hit';\r\nimport type { HandlePosition, OverlayLayout } from './select-overlay';\r\nimport {\r\n HANDLE_CURSORS,\r\n getOverlayLayout,\r\n renderMarquee,\r\n renderSelectionBoxes,\r\n renderGuideLines,\r\n} from './select-overlay';\r\nimport {\r\n computeResize,\r\n computeRotatedResize,\r\n computeTemplateResize,\r\n computeRectangleLengthResize,\r\n computeRectangleWidthResize,\r\n} from './select-resize';\r\n\r\nconst SNAP_PX = 6;\r\nconst ROTATE_SNAP = Math.PI / 12; // 15°\r\n\r\ntype Mode =\r\n | { type: 'idle' }\r\n | { type: 'dragging' }\r\n | { type: 'marquee'; start: Point }\r\n | { type: 'resizing'; elementId: string; handle: HandlePosition }\r\n | { type: 'resizing-template'; elementId: string }\r\n | { type: 'aiming-template'; elementId: string }\r\n | { type: 'resizing-rect-length'; elementId: string }\r\n | { type: 'resizing-rect-width'; elementId: string }\r\n | { type: 'arrow-handle'; elementId: string; handle: ArrowHandle }\r\n | { type: 'line-handle'; elementId: string; fixed: Point }\r\n | {\r\n type: 'rotating';\r\n elementId: string;\r\n center: Point;\r\n startPointerAngle: number;\r\n startRotation: number;\r\n };\r\n\r\nexport class SelectTool implements Tool {\r\n readonly name = 'select';\r\n private _selectedIds: string[] = [];\r\n private selectionListeners = new Set<() => void>();\r\n private mode: Mode = { type: 'idle' };\r\n private lastWorld: Point = { x: 0, y: 0 };\r\n private currentWorld: Point = { x: 0, y: 0 };\r\n private ctx: ToolContext | null = null;\r\n private pendingSingleSelectId: string | null = null;\r\n private hasDragged = false;\r\n private activeGuides: SnapGuide[] = [];\r\n private dragSnapTargets: Bounds[] | null = null;\r\n private dragVisibleRect: Bounds | null = null;\r\n private resizeAspectRatio = 0;\r\n private hoveredId: string | null = null;\r\n\r\n get selectedIds(): string[] {\r\n return this._selectedIds;\r\n }\r\n\r\n onSelectionChange(listener: () => void): () => void {\r\n this.selectionListeners.add(listener);\r\n return () => {\r\n this.selectionListeners.delete(listener);\r\n };\r\n }\r\n\r\n private setSelectedIds(ids: string[]): void {\r\n const prev = this._selectedIds;\r\n if (prev.length === ids.length && prev.every((id, i) => id === ids[i])) return;\r\n this._selectedIds = ids;\r\n for (const listener of this.selectionListeners) listener();\r\n }\r\n\r\n setSelection(ids: string[]): void {\r\n this.setSelectedIds(ids);\r\n this.ctx?.requestRender();\r\n }\r\n\r\n selectAtPoint(world: Point, ctx: ToolContext): void {\r\n const hit = hitTest(world, ctx);\r\n if (!hit) {\r\n this.setSelectedIds([]);\r\n return;\r\n }\r\n if (this._selectedIds.includes(hit.id)) return;\r\n this.setSelectedIds(expandToGroups([hit.id], ctx.store.getAll()));\r\n }\r\n\r\n get isMarqueeActive(): boolean {\r\n return this.mode.type === 'marquee';\r\n }\r\n\r\n onActivate(ctx: ToolContext): void {\r\n this.ctx = ctx;\r\n }\r\n\r\n onDeactivate(ctx: ToolContext): void {\r\n this.setSelectedIds([]);\r\n this.mode = { type: 'idle' };\r\n this.hoveredId = null;\r\n this.activeGuides = [];\r\n this.dragSnapTargets = null;\r\n this.dragVisibleRect = null;\r\n ctx.setCursor?.('default');\r\n }\r\n\r\n private snap(point: Point, ctx: ToolContext): Point {\r\n return smartSnap(point, ctx);\r\n }\r\n\r\n onPointerDown(state: PointerState, ctx: ToolContext): void {\r\n this.ctx = ctx;\r\n this.setHovered(null, ctx);\r\n this.dragSnapTargets = null;\r\n this.dragVisibleRect = null;\r\n const world = ctx.camera.screenToWorld({ x: state.x, y: state.y });\r\n this.lastWorld = this.snap(world, ctx);\r\n this.currentWorld = world;\r\n\r\n const arrowHit = hitTestArrowHandles(world, this._selectedIds, ctx);\r\n if (arrowHit) {\r\n this.mode = {\r\n type: 'arrow-handle',\r\n elementId: arrowHit.elementId,\r\n handle: arrowHit.handle,\r\n };\r\n ctx.requestRender();\r\n return;\r\n }\r\n\r\n const lineHit = hitTestLineHandles(world, ctx, this._selectedIds);\r\n if (lineHit) {\r\n this.mode = { type: 'line-handle', elementId: lineHit.elementId, fixed: lineHit.fixed };\r\n ctx.requestRender();\r\n return;\r\n }\r\n\r\n const templateResizeHit = hitTestTemplateResizeHandle(world, ctx, this._selectedIds);\r\n if (templateResizeHit) {\r\n this.mode = { type: 'resizing-template', elementId: templateResizeHit };\r\n ctx.requestRender();\r\n return;\r\n }\r\n\r\n const rectLengthHit = hitTestRectangleLengthHandle(world, ctx, this._selectedIds);\r\n if (rectLengthHit) {\r\n this.mode = { type: 'resizing-rect-length', elementId: rectLengthHit.elementId };\r\n ctx.requestRender();\r\n return;\r\n }\r\n\r\n const rectWidthHit = hitTestRectangleWidthHandle(world, ctx, this._selectedIds);\r\n if (rectWidthHit) {\r\n this.mode = { type: 'resizing-rect-width', elementId: rectWidthHit.elementId };\r\n ctx.requestRender();\r\n return;\r\n }\r\n\r\n const aimHit = hitTestTemplateAimHandle(world, ctx, this._selectedIds);\r\n if (aimHit) {\r\n this.mode = { type: 'aiming-template', elementId: aimHit.elementId };\r\n ctx.requestRender();\r\n return;\r\n }\r\n\r\n const rotateHit = hitTestRotateHandle(world, ctx, this._selectedIds);\r\n if (rotateHit) {\r\n const el = ctx.store.getById(rotateHit.elementId);\r\n const layout = el ? this.getOverlayLayout(el, ctx.camera.zoom) : null;\r\n if (el && layout) {\r\n this.mode = {\r\n type: 'rotating',\r\n elementId: rotateHit.elementId,\r\n center: layout.center,\r\n startPointerAngle: Math.atan2(world.y - layout.center.y, world.x - layout.center.x),\r\n startRotation: el.rotation ?? 0,\r\n };\r\n ctx.requestRender();\r\n return;\r\n }\r\n }\r\n\r\n const resizeHit = hitTestResizeHandle(world, ctx, this._selectedIds);\r\n if (resizeHit) {\r\n const el = ctx.store.getById(resizeHit.elementId);\r\n if (el && 'size' in el) {\r\n this.resizeAspectRatio = el.size.h > 0 ? el.size.w / el.size.h : 0;\r\n this.mode = {\r\n type: 'resizing',\r\n elementId: resizeHit.elementId,\r\n handle: resizeHit.handle,\r\n };\r\n ctx.requestRender();\r\n return;\r\n }\r\n }\r\n\r\n this.pendingSingleSelectId = null;\r\n this.hasDragged = false;\r\n const hit = hitTest(world, ctx);\r\n if (hit) {\r\n const all = ctx.store.getAll();\r\n const alreadySelected = this._selectedIds.includes(hit.id);\r\n if (state.shiftKey) {\r\n if (alreadySelected) {\r\n const grp = new Set(expandToGroups([hit.id], all));\r\n this.setSelectedIds(this._selectedIds.filter((id) => !grp.has(id)));\r\n this.mode = { type: 'idle' };\r\n } else {\r\n this.setSelectedIds(expandToGroups([...this._selectedIds, hit.id], all));\r\n this.mode = hit.locked ? { type: 'idle' } : { type: 'dragging' };\r\n }\r\n } else {\r\n if (!alreadySelected) {\r\n this.setSelectedIds(expandToGroups([hit.id], all));\r\n } else if (this._selectedIds.length > 1) {\r\n this.pendingSingleSelectId = hit.id;\r\n }\r\n this.mode = hit.locked ? { type: 'idle' } : { type: 'dragging' };\r\n }\r\n } else {\r\n this.setSelectedIds([]);\r\n this.mode = { type: 'marquee', start: world };\r\n }\r\n\r\n ctx.requestRender();\r\n }\r\n\r\n onPointerMove(state: PointerState, ctx: ToolContext): void {\r\n const world = ctx.camera.screenToWorld({ x: state.x, y: state.y });\r\n this.currentWorld = world;\r\n\r\n if (this.mode.type === 'arrow-handle') {\r\n ctx.setCursor?.(getArrowHandleCursor(this.mode.handle, true));\r\n applyArrowHandleDrag(this.mode.handle, this.mode.elementId, world, ctx);\r\n return;\r\n }\r\n\r\n if (this.mode.type === 'line-handle') {\r\n ctx.setCursor?.('grabbing');\r\n const el = ctx.store.getById(this.mode.elementId);\r\n if (\r\n el &&\r\n el.type === 'shape' &&\r\n el.shape === 'line' &&\r\n !el.locked &&\r\n !(ctx.isLayerLocked?.(el.layerId) ?? false)\r\n ) {\r\n ctx.store.update(el.id, lineFromEndpoints(this.mode.fixed, world));\r\n ctx.requestRender();\r\n }\r\n return;\r\n }\r\n\r\n if (this.mode.type === 'resizing-template') {\r\n ctx.setCursor?.('nwse-resize');\r\n this.handleTemplateResize(world, ctx);\r\n return;\r\n }\r\n\r\n if (this.mode.type === 'aiming-template') {\r\n const el = ctx.store.getById(this.mode.elementId);\r\n if (el && el.type === 'template' && !el.locked) {\r\n let a = Math.atan2(world.y - el.position.y, world.x - el.position.x);\r\n if (state.shiftKey) {\r\n const snap = ctx.gridType === 'hex' ? Math.PI / 3 : ROTATE_SNAP;\r\n a = Math.round(a / snap) * snap;\r\n }\r\n ctx.store.update(this.mode.elementId, { angle: normalizeAngle(a) });\r\n ctx.requestRender();\r\n }\r\n return;\r\n }\r\n\r\n if (this.mode.type === 'resizing-rect-length' || this.mode.type === 'resizing-rect-width') {\r\n ctx.setCursor?.(this.mode.type === 'resizing-rect-length' ? 'ew-resize' : 'ns-resize');\r\n const el = ctx.store.getById(this.mode.elementId);\r\n if (el && el.type === 'template' && !el.locked) {\r\n const opts = { snapToGrid: ctx.snapToGrid, gridSize: ctx.gridSize, gridType: ctx.gridType };\r\n const patch =\r\n this.mode.type === 'resizing-rect-length'\r\n ? computeRectangleLengthResize(el, world, opts)\r\n : computeRectangleWidthResize(el, world, opts);\r\n if (patch) {\r\n ctx.store.update(this.mode.elementId, patch);\r\n ctx.requestRender();\r\n }\r\n }\r\n return;\r\n }\r\n\r\n if (this.mode.type === 'rotating') {\r\n const { elementId, center, startPointerAngle, startRotation } = this.mode;\r\n const a = Math.atan2(world.y - center.y, world.x - center.x);\r\n let next = startRotation + (a - startPointerAngle);\r\n if (state.shiftKey) next = Math.round(next / ROTATE_SNAP) * ROTATE_SNAP;\r\n ctx.store.update(elementId, { rotation: normalizeAngle(next) });\r\n ctx.requestRender();\r\n return;\r\n }\r\n\r\n if (this.mode.type === 'resizing') {\r\n ctx.setCursor?.(HANDLE_CURSORS[this.mode.handle]);\r\n this.handleResize(world, ctx, state.shiftKey);\r\n return;\r\n }\r\n\r\n if (this.mode.type === 'dragging' && this._selectedIds.length > 0) {\r\n this.hasDragged = true;\r\n ctx.setCursor?.('move');\r\n const snapped = this.snap(world, ctx);\r\n const dx = snapped.x - this.lastWorld.x;\r\n const dy = snapped.y - this.lastWorld.y;\r\n this.lastWorld = snapped;\r\n\r\n let adjDx = dx;\r\n let adjDy = dy;\r\n this.activeGuides = [];\r\n if (ctx.smartGuides) {\r\n // Candidates (non-selected visible elements) and the viewport rect don't change\r\n // during a single-pointer drag, so compute them once per drag and reuse each frame.\r\n if (this.dragSnapTargets === null) {\r\n const selSet = new Set(this._selectedIds);\r\n this.dragVisibleRect = ctx.getVisibleRect?.() ?? null;\r\n const candidates = (\r\n this.dragVisibleRect ? ctx.store.queryRect(this.dragVisibleRect) : ctx.store.getAll()\r\n ).filter((el) => !selSet.has(el.id) && el.type !== 'grid');\r\n const targets: Bounds[] = [];\r\n for (const el of candidates) {\r\n const b = getElementBounds(el);\r\n if (b) targets.push(b);\r\n }\r\n this.dragSnapTargets = targets;\r\n }\r\n const selectedEls = this._selectedIds\r\n .map((id) => ctx.store.getById(id))\r\n .filter((el): el is CanvasElement => !!el && !el.locked);\r\n const base = getElementsBoundingBox(selectedEls);\r\n if (base) {\r\n const moving: Bounds = { x: base.x + dx, y: base.y + dy, w: base.w, h: base.h };\r\n const res = computeSnapGuides(moving, this.dragSnapTargets, SNAP_PX / ctx.camera.zoom);\r\n adjDx = dx + res.dx;\r\n adjDy = dy + res.dy;\r\n this.activeGuides = res.guides;\r\n }\r\n }\r\n\r\n for (const id of this._selectedIds) {\r\n const el = ctx.store.getById(id);\r\n if (!el || el.locked) continue;\r\n\r\n if (el.type === 'arrow') {\r\n if (el.fromBinding || el.toBinding) {\r\n continue;\r\n }\r\n\r\n ctx.store.update(id, {\r\n position: { x: el.position.x + adjDx, y: el.position.y + adjDy },\r\n from: { x: el.from.x + adjDx, y: el.from.y + adjDy },\r\n to: { x: el.to.x + adjDx, y: el.to.y + adjDy },\r\n });\r\n } else if (!ctx.smartGuides && ctx.gridType && 'size' in el) {\r\n const centerX = el.position.x + el.size.w / 2 + adjDx;\r\n const centerY = el.position.y + el.size.h / 2 + adjDy;\r\n const snappedCenter = this.snap({ x: centerX, y: centerY }, ctx);\r\n ctx.store.update(id, {\r\n position: {\r\n x: snappedCenter.x - el.size.w / 2,\r\n y: snappedCenter.y - el.size.h / 2,\r\n },\r\n });\r\n } else {\r\n ctx.store.update(id, {\r\n position: { x: el.position.x + adjDx, y: el.position.y + adjDy },\r\n });\r\n }\r\n }\r\n\r\n this.updateArrowsBoundTo(this._selectedIds, ctx);\r\n\r\n ctx.requestRender();\r\n return;\r\n }\r\n\r\n if (this.mode.type === 'marquee') {\r\n ctx.setCursor?.('crosshair');\r\n ctx.requestRender();\r\n return;\r\n }\r\n\r\n this.updateHoverCursor(world, ctx);\r\n }\r\n\r\n onPointerUp(_state: PointerState, ctx: ToolContext): void {\r\n if (this.mode.type === 'marquee') {\r\n const rect = this.getMarqueeRect();\r\n if (rect) {\r\n this.setSelectedIds(expandToGroups(findElementsInRect(rect, ctx), ctx.store.getAll()));\r\n }\r\n ctx.requestRender();\r\n }\r\n\r\n if (!this.hasDragged && this.pendingSingleSelectId !== null) {\r\n this.setSelectedIds(expandToGroups([this.pendingSingleSelectId], ctx.store.getAll()));\r\n }\r\n this.pendingSingleSelectId = null;\r\n this.hasDragged = false;\r\n\r\n const resizedNoteId = this.mode.type === 'resizing' ? this.mode.elementId : null;\r\n\r\n this.mode = { type: 'idle' };\r\n this.activeGuides = [];\r\n this.dragSnapTargets = null;\r\n this.dragVisibleRect = null;\r\n ctx.requestRender();\r\n ctx.setCursor?.('default');\r\n\r\n if (resizedNoteId !== null) {\r\n const el = ctx.store.getById(resizedNoteId);\r\n // Runs during tool pointer-up, inside the InputHandler resize transaction, so the\r\n // height fit coalesces into the same undo step as the resize.\r\n if (el?.type === 'note') ctx.fitNoteHeight?.(resizedNoteId);\r\n }\r\n }\r\n\r\n onHover(state: PointerState, ctx: ToolContext): void {\r\n const world = ctx.camera.screenToWorld({ x: state.x, y: state.y });\r\n const hoverId = this.updateHoverCursor(world, ctx);\r\n this.setHovered(hoverId, ctx);\r\n }\r\n\r\n renderOverlay(canvasCtx: CanvasRenderingContext2D): void {\r\n if (this.mode.type === 'marquee') {\r\n const rect = this.getMarqueeRect();\r\n if (rect) renderMarquee(canvasCtx, rect);\r\n }\r\n if (this.ctx)\r\n renderSelectionBoxes(canvasCtx, {\r\n selectedIds: this._selectedIds,\r\n store: this.ctx.store,\r\n zoom: this.ctx.camera.zoom,\r\n isLayerLocked: this.ctx.isLayerLocked,\r\n });\r\n\r\n if (this.mode.type === 'arrow-handle' && this.ctx) {\r\n const target = getArrowHandleDragTarget(\r\n this.mode.handle,\r\n this.mode.elementId,\r\n this.currentWorld,\r\n this.ctx,\r\n );\r\n if (target) {\r\n canvasCtx.save();\r\n canvasCtx.strokeStyle = '#2196F3';\r\n canvasCtx.lineWidth = 2 / this.ctx.camera.zoom;\r\n canvasCtx.setLineDash([]);\r\n canvasCtx.strokeRect(target.x, target.y, target.w, target.h);\r\n canvasCtx.restore();\r\n }\r\n }\r\n\r\n if (this.hoveredId && this.ctx && this.mode.type === 'idle') {\r\n if (!this._selectedIds.includes(this.hoveredId)) {\r\n const el = this.ctx.store.getById(this.hoveredId);\r\n if (el?.type === 'arrow') {\r\n canvasCtx.save();\r\n canvasCtx.globalAlpha = 0.35;\r\n canvasCtx.setLineDash([]);\r\n renderArrowHoverHandle(canvasCtx, el, this.ctx.camera.zoom);\r\n canvasCtx.restore();\r\n } else if (el) {\r\n const b = getElementBounds(el);\r\n if (b) {\r\n canvasCtx.save();\r\n canvasCtx.strokeStyle = '#2196F3';\r\n canvasCtx.globalAlpha = 0.35;\r\n canvasCtx.lineWidth = 1.5 / this.ctx.camera.zoom;\r\n canvasCtx.setLineDash([]);\r\n canvasCtx.strokeRect(b.x, b.y, b.w, b.h);\r\n canvasCtx.restore();\r\n }\r\n }\r\n }\r\n }\r\n\r\n if (this.mode.type === 'dragging' && this.ctx && this.activeGuides.length)\r\n renderGuideLines(canvasCtx, {\r\n guides: this.activeGuides,\r\n rect: this.dragVisibleRect,\r\n currentWorld: this.currentWorld,\r\n zoom: this.ctx.camera.zoom,\r\n });\r\n }\r\n\r\n private updateArrowsBoundTo(ids: Iterable<string>, ctx: ToolContext): void {\r\n updateArrowsBoundToElements(ids, ctx.store);\r\n }\r\n\r\n nudgeSelection(dx: number, dy: number, ctx: ToolContext): boolean {\r\n let moved = false;\r\n for (const id of this._selectedIds) {\r\n const el = ctx.store.getById(id);\r\n if (!el || el.locked) continue;\r\n if (el.type === 'arrow' && (el.fromBinding || el.toBinding)) continue;\r\n ctx.store.update(id, translateElementPatch(el, dx, dy));\r\n moved = true;\r\n }\r\n\r\n if (moved) {\r\n this.updateArrowsBoundTo(this._selectedIds, ctx);\r\n ctx.requestRender();\r\n }\r\n return moved;\r\n }\r\n\r\n private updateHoverCursor(world: Point, ctx: ToolContext): string | null {\r\n const arrowHit = hitTestArrowHandles(world, this._selectedIds, ctx);\r\n if (arrowHit) {\r\n ctx.setCursor?.(getArrowHandleCursor(arrowHit.handle, false));\r\n return null;\r\n }\r\n\r\n if (hitTestLineHandles(world, ctx, this._selectedIds)) {\r\n ctx.setCursor?.('grab');\r\n return null;\r\n }\r\n\r\n const templateResizeHit = hitTestTemplateResizeHandle(world, ctx, this._selectedIds);\r\n if (templateResizeHit) {\r\n ctx.setCursor?.('nwse-resize');\r\n return null;\r\n }\r\n\r\n if (hitTestRectangleLengthHandle(world, ctx, this._selectedIds)) {\r\n ctx.setCursor?.('ew-resize');\r\n return null;\r\n }\r\n if (hitTestRectangleWidthHandle(world, ctx, this._selectedIds)) {\r\n ctx.setCursor?.('ns-resize');\r\n return null;\r\n }\r\n\r\n if (hitTestTemplateAimHandle(world, ctx, this._selectedIds)) {\r\n ctx.setCursor?.('grab');\r\n return null;\r\n }\r\n\r\n if (hitTestRotateHandle(world, ctx, this._selectedIds)) {\r\n ctx.setCursor?.('grab');\r\n return null;\r\n }\r\n\r\n const resizeHit = hitTestResizeHandle(world, ctx, this._selectedIds);\r\n if (resizeHit) {\r\n ctx.setCursor?.(HANDLE_CURSORS[resizeHit.handle]);\r\n return null;\r\n }\r\n\r\n const hit = hitTest(world, ctx);\r\n ctx.setCursor?.(hit ? 'move' : 'default');\r\n return hit ? hit.id : null;\r\n }\r\n\r\n private setHovered(id: string | null, ctx: ToolContext): void {\r\n if (this.hoveredId === id) return;\r\n this.hoveredId = id;\r\n ctx.requestRender();\r\n }\r\n\r\n private handleResize(world: Point, ctx: ToolContext, shiftKey = false): void {\r\n if (this.mode.type !== 'resizing') return;\r\n\r\n const el = ctx.store.getById(this.mode.elementId);\r\n if (!el || !('size' in el) || el.locked) return;\r\n\r\n const lockAspect = shiftKey !== (el.type === 'image');\r\n\r\n const angle = el.rotation ?? 0;\r\n const patch =\r\n angle !== 0\r\n ? computeRotatedResize(\r\n el,\r\n this.mode.handle,\r\n angle,\r\n world,\r\n this.lastWorld,\r\n this.resizeAspectRatio,\r\n lockAspect,\r\n )\r\n : computeResize(\r\n el,\r\n this.mode.handle,\r\n world,\r\n this.lastWorld,\r\n this.resizeAspectRatio,\r\n lockAspect,\r\n );\r\n\r\n this.lastWorld = world;\r\n ctx.store.update(this.mode.elementId, patch);\r\n this.updateArrowsBoundTo([this.mode.elementId], ctx);\r\n ctx.requestRender();\r\n }\r\n\r\n private getOverlayLayout(el: CanvasElement, zoom: number): OverlayLayout | null {\r\n return getOverlayLayout(el, zoom);\r\n }\r\n\r\n private handleTemplateResize(world: Point, ctx: ToolContext): void {\r\n if (this.mode.type !== 'resizing-template') return;\r\n\r\n const el = ctx.store.getById(this.mode.elementId);\r\n if (!el || el.type !== 'template' || el.locked) return;\r\n\r\n const patch = computeTemplateResize(el, world, {\r\n snapToGrid: ctx.snapToGrid,\r\n gridSize: ctx.gridSize,\r\n gridType: ctx.gridType,\r\n });\r\n if (patch) {\r\n ctx.store.update(this.mode.elementId, patch);\r\n ctx.requestRender();\r\n }\r\n }\r\n\r\n private getMarqueeRect(): Bounds | null {\r\n if (this.mode.type !== 'marquee') return null;\r\n\r\n const { start } = this.mode;\r\n const end = this.currentWorld;\r\n const x = Math.min(start.x, end.x);\r\n const y = Math.min(start.y, end.y);\r\n const w = Math.abs(end.x - start.x);\r\n const h = Math.abs(end.y - start.y);\r\n\r\n if (w === 0 && h === 0) return null;\r\n return { x, y, w, h };\r\n }\r\n}\r\n","import type { Point } from '../core/types';\r\nimport type { ArrowStrokeStyle, Binding, CanvasElement } from '../elements/types';\r\nimport type { Tool, ToolContext, PointerState } from './types';\r\nimport { createArrow } from '../elements/element-factory';\r\nimport { findBindTarget, getElementCenter } from '../elements/arrow-binding';\r\nimport { getElementBounds } from '../elements/element-bounds';\r\nimport { smartSnap } from '../core/snap';\r\n\r\nconst BIND_THRESHOLD = 20;\r\n\r\nexport interface ArrowToolOptions {\r\n color?: string;\r\n width?: number;\r\n strokeStyle?: ArrowStrokeStyle;\r\n}\r\n\r\nexport class ArrowTool implements Tool {\r\n readonly name = 'arrow';\r\n private drawing = false;\r\n private start: Point = { x: 0, y: 0 };\r\n private end: Point = { x: 0, y: 0 };\r\n private color: string;\r\n private width: number;\r\n private strokeStyle: ArrowStrokeStyle;\r\n private fromBinding: Binding | undefined;\r\n private fromTarget: CanvasElement | null = null;\r\n private toTarget: CanvasElement | null = null;\r\n private optionListeners = new Set<() => void>();\r\n\r\n constructor(options: ArrowToolOptions = {}) {\r\n this.color = options.color ?? '#000000';\r\n this.width = options.width ?? 2;\r\n this.strokeStyle = options.strokeStyle ?? 'solid';\r\n }\r\n\r\n getOptions(): ArrowToolOptions {\r\n return { color: this.color, width: this.width, strokeStyle: this.strokeStyle };\r\n }\r\n\r\n onOptionsChange(listener: () => void): () => void {\r\n this.optionListeners.add(listener);\r\n return () => this.optionListeners.delete(listener);\r\n }\r\n\r\n setOptions(options: ArrowToolOptions): void {\r\n if (options.color !== undefined) this.color = options.color;\r\n if (options.width !== undefined) this.width = options.width;\r\n if (options.strokeStyle !== undefined) this.strokeStyle = options.strokeStyle;\r\n this.notifyOptionsChange();\r\n }\r\n\r\n private notifyOptionsChange(): void {\r\n for (const listener of this.optionListeners) listener();\r\n }\r\n\r\n private layerFilter(ctx: ToolContext): ((el: CanvasElement) => boolean) | undefined {\r\n const activeLayerId = ctx.activeLayerId;\r\n if (!activeLayerId && !ctx.isLayerVisible && !ctx.isLayerLocked) return undefined;\r\n return (el: CanvasElement) => {\r\n if (activeLayerId && el.layerId !== activeLayerId) return false;\r\n if (ctx.isLayerVisible && !ctx.isLayerVisible(el.layerId)) return false;\r\n if (ctx.isLayerLocked && ctx.isLayerLocked(el.layerId)) return false;\r\n return true;\r\n };\r\n }\r\n\r\n onPointerDown(state: PointerState, ctx: ToolContext): void {\r\n this.drawing = true;\r\n const world = ctx.camera.screenToWorld({ x: state.x, y: state.y });\r\n const threshold = BIND_THRESHOLD / ctx.camera.zoom;\r\n const filter = this.layerFilter(ctx);\r\n\r\n const target = findBindTarget(world, ctx.store, threshold, undefined, filter);\r\n if (target) {\r\n this.start = getElementCenter(target);\r\n this.fromBinding = { elementId: target.id };\r\n this.fromTarget = target;\r\n } else {\r\n this.start = smartSnap(world, ctx);\r\n this.fromBinding = undefined;\r\n this.fromTarget = null;\r\n }\r\n this.end = { ...this.start };\r\n this.toTarget = null;\r\n }\r\n\r\n onPointerMove(state: PointerState, ctx: ToolContext): void {\r\n if (!this.drawing) return;\r\n const world = ctx.camera.screenToWorld({ x: state.x, y: state.y });\r\n const threshold = BIND_THRESHOLD / ctx.camera.zoom;\r\n const excludeId = this.fromBinding?.elementId;\r\n const filter = this.layerFilter(ctx);\r\n\r\n const target = findBindTarget(world, ctx.store, threshold, excludeId, filter);\r\n if (target) {\r\n this.end = getElementCenter(target);\r\n this.toTarget = target;\r\n } else {\r\n this.end = smartSnap(world, ctx);\r\n this.toTarget = null;\r\n }\r\n ctx.requestRender();\r\n }\r\n\r\n onPointerUp(_state: PointerState, ctx: ToolContext): void {\r\n if (!this.drawing) return;\r\n this.drawing = false;\r\n\r\n if (this.start.x === this.end.x && this.start.y === this.end.y) return;\r\n\r\n const arrow = createArrow({\r\n from: this.start,\r\n to: this.end,\r\n position: this.start,\r\n color: this.color,\r\n width: this.width,\r\n strokeStyle: this.strokeStyle,\r\n fromBinding: this.fromBinding,\r\n toBinding: this.toTarget ? { elementId: this.toTarget.id } : undefined,\r\n layerId: ctx.activeLayerId ?? '',\r\n });\r\n ctx.store.add(arrow);\r\n this.fromTarget = null;\r\n this.toTarget = null;\r\n ctx.requestRender();\r\n ctx.switchTool?.('select');\r\n }\r\n\r\n renderOverlay(ctx: CanvasRenderingContext2D): void {\r\n if (!this.drawing) return;\r\n if (this.start.x === this.end.x && this.start.y === this.end.y) return;\r\n\r\n ctx.save();\r\n\r\n if (this.fromTarget) {\r\n const bounds = getElementBounds(this.fromTarget);\r\n if (bounds) {\r\n ctx.strokeStyle = '#2196F3';\r\n ctx.lineWidth = 2;\r\n ctx.setLineDash([]);\r\n ctx.strokeRect(bounds.x, bounds.y, bounds.w, bounds.h);\r\n }\r\n }\r\n\r\n if (this.toTarget) {\r\n const bounds = getElementBounds(this.toTarget);\r\n if (bounds) {\r\n ctx.strokeStyle = '#2196F3';\r\n ctx.lineWidth = 2;\r\n ctx.setLineDash([]);\r\n ctx.strokeRect(bounds.x, bounds.y, bounds.w, bounds.h);\r\n }\r\n }\r\n\r\n ctx.strokeStyle = this.color;\r\n ctx.lineWidth = this.width;\r\n ctx.lineCap = 'round';\r\n ctx.globalAlpha = 0.6;\r\n\r\n ctx.beginPath();\r\n ctx.moveTo(this.start.x, this.start.y);\r\n ctx.lineTo(this.end.x, this.end.y);\r\n ctx.stroke();\r\n\r\n const angle = Math.atan2(this.end.y - this.start.y, this.end.x - this.start.x);\r\n const headLen = 12;\r\n const headAngle = Math.PI / 6;\r\n\r\n ctx.fillStyle = this.color;\r\n ctx.beginPath();\r\n ctx.moveTo(this.end.x, this.end.y);\r\n ctx.lineTo(\r\n this.end.x - headLen * Math.cos(angle - headAngle),\r\n this.end.y - headLen * Math.sin(angle - headAngle),\r\n );\r\n ctx.lineTo(\r\n this.end.x - headLen * Math.cos(angle + headAngle),\r\n this.end.y - headLen * Math.sin(angle + headAngle),\r\n );\r\n ctx.closePath();\r\n ctx.fill();\r\n ctx.restore();\r\n }\r\n}\r\n","import type { Size } from '../core/types';\r\nimport type { Tool, ToolContext, PointerState } from './types';\r\nimport { createNote, DEFAULT_NOTE_FONT_SIZE } from '../elements/element-factory';\r\nimport { smartSnap } from '../core/snap';\r\n\r\nexport interface NoteToolOptions {\r\n backgroundColor?: string;\r\n textColor?: string;\r\n size?: Size;\r\n fontSize?: number;\r\n}\r\n\r\nexport class NoteTool implements Tool {\r\n readonly name = 'note';\r\n private backgroundColor: string;\r\n private textColor: string;\r\n private size: Size;\r\n private fontSize: number;\r\n private optionListeners = new Set<() => void>();\r\n\r\n constructor(options: NoteToolOptions = {}) {\r\n this.backgroundColor = options.backgroundColor ?? '#ffeb3b';\r\n this.textColor = options.textColor ?? '#000000';\r\n this.size = options.size ?? { w: 200, h: 100 };\r\n this.fontSize = options.fontSize ?? DEFAULT_NOTE_FONT_SIZE;\r\n }\r\n\r\n getOptions(): NoteToolOptions {\r\n return {\r\n backgroundColor: this.backgroundColor,\r\n textColor: this.textColor,\r\n size: { ...this.size },\r\n fontSize: this.fontSize,\r\n };\r\n }\r\n\r\n onOptionsChange(listener: () => void): () => void {\r\n this.optionListeners.add(listener);\r\n return () => this.optionListeners.delete(listener);\r\n }\r\n\r\n setOptions(options: NoteToolOptions): void {\r\n if (options.backgroundColor !== undefined) this.backgroundColor = options.backgroundColor;\r\n if (options.textColor !== undefined) this.textColor = options.textColor;\r\n if (options.size !== undefined) this.size = options.size;\r\n if (options.fontSize !== undefined) this.fontSize = options.fontSize;\r\n this.notifyOptionsChange();\r\n }\r\n\r\n private notifyOptionsChange(): void {\r\n for (const listener of this.optionListeners) listener();\r\n }\r\n\r\n onPointerDown(_state: PointerState, _ctx: ToolContext): void {\r\n // Note is placed on pointer up\r\n }\r\n\r\n onPointerMove(_state: PointerState, _ctx: ToolContext): void {\r\n // No drag behavior for note placement\r\n }\r\n\r\n onPointerUp(state: PointerState, ctx: ToolContext): void {\r\n let world = ctx.camera.screenToWorld({ x: state.x, y: state.y });\r\n world = smartSnap(world, ctx);\r\n const note = createNote({\r\n position: world,\r\n size: { ...this.size },\r\n backgroundColor: this.backgroundColor,\r\n textColor: this.textColor,\r\n fontSize: this.fontSize,\r\n layerId: ctx.activeLayerId ?? '',\r\n });\r\n ctx.store.add(note);\r\n ctx.requestRender();\r\n\r\n ctx.switchTool?.('select');\r\n ctx.editElement?.(note.id);\r\n }\r\n}\r\n","import type { Tool, ToolContext, PointerState } from './types';\r\nimport { createText } from '../elements/element-factory';\r\nimport { smartSnap } from '../core/snap';\r\n\r\nexport interface TextToolOptions {\r\n fontSize?: number;\r\n color?: string;\r\n textAlign?: 'left' | 'center' | 'right';\r\n}\r\n\r\nexport class TextTool implements Tool {\r\n readonly name = 'text';\r\n private fontSize: number;\r\n private color: string;\r\n private textAlign: 'left' | 'center' | 'right';\r\n private optionListeners = new Set<() => void>();\r\n\r\n constructor(options: TextToolOptions = {}) {\r\n this.fontSize = options.fontSize ?? 16;\r\n this.color = options.color ?? '#1a1a1a';\r\n this.textAlign = options.textAlign ?? 'left';\r\n }\r\n\r\n getOptions(): TextToolOptions {\r\n return { fontSize: this.fontSize, color: this.color, textAlign: this.textAlign };\r\n }\r\n\r\n onOptionsChange(listener: () => void): () => void {\r\n this.optionListeners.add(listener);\r\n return () => this.optionListeners.delete(listener);\r\n }\r\n\r\n setOptions(options: TextToolOptions): void {\r\n if (options.fontSize !== undefined) this.fontSize = options.fontSize;\r\n if (options.color !== undefined) this.color = options.color;\r\n if (options.textAlign !== undefined) this.textAlign = options.textAlign;\r\n this.notifyOptionsChange();\r\n }\r\n\r\n private notifyOptionsChange(): void {\r\n for (const listener of this.optionListeners) listener();\r\n }\r\n\r\n onActivate(ctx: ToolContext): void {\r\n ctx.setCursor?.('text');\r\n }\r\n\r\n onDeactivate(ctx: ToolContext): void {\r\n ctx.setCursor?.('default');\r\n }\r\n\r\n onPointerDown(_state: PointerState, _ctx: ToolContext): void {\r\n // Text is placed on pointer up\r\n }\r\n\r\n onPointerMove(_state: PointerState, _ctx: ToolContext): void {\r\n // No drag behavior for text placement\r\n }\r\n\r\n onPointerUp(state: PointerState, ctx: ToolContext): void {\r\n let world = ctx.camera.screenToWorld({ x: state.x, y: state.y });\r\n world = smartSnap(world, ctx);\r\n const textEl = createText({\r\n position: world,\r\n fontSize: this.fontSize,\r\n color: this.color,\r\n textAlign: this.textAlign,\r\n layerId: ctx.activeLayerId ?? '',\r\n });\r\n ctx.store.add(textEl);\r\n ctx.requestRender();\r\n\r\n ctx.switchTool?.('select');\r\n ctx.editElement?.(textEl.id);\r\n }\r\n}\r\n","import type { Size } from '../core/types';\r\nimport type { Tool, ToolContext, PointerState } from './types';\r\nimport { createImage } from '../elements/element-factory';\r\nimport { smartSnap } from '../core/snap';\r\n\r\nexport interface ImageToolOptions {\r\n size?: Size;\r\n}\r\n\r\nexport class ImageTool implements Tool {\r\n readonly name = 'image';\r\n private size: Size;\r\n private src: string | null = null;\r\n\r\n constructor(options: ImageToolOptions = {}) {\r\n this.size = options.size ?? { w: 300, h: 200 };\r\n }\r\n\r\n setSrc(src: string): void {\r\n this.src = src;\r\n }\r\n\r\n onPointerDown(_state: PointerState, _ctx: ToolContext): void {\r\n // No action on pointer down — image is placed on pointer up\r\n }\r\n\r\n onPointerMove(_state: PointerState, _ctx: ToolContext): void {\r\n // No action on pointer move\r\n }\r\n\r\n onPointerUp(state: PointerState, ctx: ToolContext): void {\r\n if (!this.src) return;\r\n\r\n const world = ctx.camera.screenToWorld({ x: state.x, y: state.y });\r\n const snapped = smartSnap(world, ctx);\r\n const image = createImage({\r\n position: {\r\n x: snapped.x - this.size.w / 2,\r\n y: snapped.y - this.size.h / 2,\r\n },\r\n size: { ...this.size },\r\n src: this.src,\r\n });\r\n ctx.store.add(image);\r\n ctx.requestRender();\r\n\r\n this.src = null;\r\n ctx.switchTool?.('select');\r\n }\r\n}\r\n","import type { Point } from '../core/types';\r\nimport type { ShapeKind } from '../elements/types';\r\nimport type { Tool, ToolContext, PointerState } from './types';\r\nimport { createShape } from '../elements/element-factory';\r\nimport { smartSnap } from '../core/snap';\r\n\r\nfunction snapTo45(start: Point, end: Point): Point {\r\n const dx = end.x - start.x;\r\n const dy = end.y - start.y;\r\n const len = Math.hypot(dx, dy);\r\n if (len === 0) return { ...end };\r\n const step = Math.PI / 4;\r\n const angle = Math.round(Math.atan2(dy, dx) / step) * step;\r\n return { x: start.x + Math.cos(angle) * len, y: start.y + Math.sin(angle) * len };\r\n}\r\n\r\nexport interface ShapeToolOptions {\r\n shape?: ShapeKind;\r\n strokeColor?: string;\r\n strokeWidth?: number;\r\n fillColor?: string;\r\n}\r\n\r\nexport class ShapeTool implements Tool {\r\n readonly name = 'shape';\r\n private drawing = false;\r\n private start: Point = { x: 0, y: 0 };\r\n private end: Point = { x: 0, y: 0 };\r\n private shiftHeld = false;\r\n private shape: ShapeKind;\r\n private strokeColor: string;\r\n private strokeWidth: number;\r\n private fillColor: string;\r\n private optionListeners = new Set<() => void>();\r\n\r\n constructor(options: ShapeToolOptions = {}) {\r\n this.shape = options.shape ?? 'rectangle';\r\n this.strokeColor = options.strokeColor ?? '#000000';\r\n this.strokeWidth = options.strokeWidth ?? 2;\r\n this.fillColor = options.fillColor ?? 'none';\r\n }\r\n\r\n getOptions(): ShapeToolOptions {\r\n return {\r\n shape: this.shape,\r\n strokeColor: this.strokeColor,\r\n strokeWidth: this.strokeWidth,\r\n fillColor: this.fillColor,\r\n };\r\n }\r\n\r\n onOptionsChange(listener: () => void): () => void {\r\n this.optionListeners.add(listener);\r\n return () => this.optionListeners.delete(listener);\r\n }\r\n\r\n setOptions(options: ShapeToolOptions): void {\r\n if (options.shape !== undefined) this.shape = options.shape;\r\n if (options.strokeColor !== undefined) this.strokeColor = options.strokeColor;\r\n if (options.strokeWidth !== undefined) this.strokeWidth = options.strokeWidth;\r\n if (options.fillColor !== undefined) this.fillColor = options.fillColor;\r\n this.notifyOptionsChange();\r\n }\r\n\r\n onActivate(_ctx: ToolContext): void {\r\n if (typeof window !== 'undefined') {\r\n window.addEventListener('keydown', this.onKeyDown);\r\n window.addEventListener('keyup', this.onKeyUp);\r\n }\r\n }\r\n\r\n onDeactivate(_ctx: ToolContext): void {\r\n this.shiftHeld = false;\r\n if (typeof window !== 'undefined') {\r\n window.removeEventListener('keydown', this.onKeyDown);\r\n window.removeEventListener('keyup', this.onKeyUp);\r\n }\r\n }\r\n\r\n onPointerDown(state: PointerState, ctx: ToolContext): void {\r\n this.drawing = true;\r\n this.start = this.snap(ctx.camera.screenToWorld({ x: state.x, y: state.y }), ctx);\r\n this.end = { ...this.start };\r\n }\r\n\r\n onPointerMove(state: PointerState, ctx: ToolContext): void {\r\n if (!this.drawing) return;\r\n this.end = this.snap(ctx.camera.screenToWorld({ x: state.x, y: state.y }), ctx);\r\n if (this.shape === 'line' && this.shiftHeld) {\r\n this.end = snapTo45(this.start, this.end);\r\n }\r\n ctx.requestRender();\r\n }\r\n\r\n onPointerUp(_state: PointerState, ctx: ToolContext): void {\r\n if (!this.drawing) return;\r\n this.drawing = false;\r\n\r\n const { position, size } = this.computeRect();\r\n const isLine = this.shape === 'line';\r\n if (isLine ? size.w === 0 && size.h === 0 : size.w === 0 || size.h === 0) return;\r\n\r\n const shape = createShape({\r\n position,\r\n size,\r\n shape: this.shape,\r\n strokeColor: this.strokeColor,\r\n strokeWidth: this.strokeWidth,\r\n fillColor: this.fillColor,\r\n ...(isLine ? { flip: this.end.x > this.start.x !== this.end.y > this.start.y } : {}),\r\n layerId: ctx.activeLayerId ?? '',\r\n });\r\n ctx.store.add(shape);\r\n ctx.requestRender();\r\n ctx.switchTool?.('select');\r\n }\r\n\r\n renderOverlay(ctx: CanvasRenderingContext2D): void {\r\n if (!this.drawing) return;\r\n\r\n const { position, size } = this.computeRect();\r\n if (size.w === 0 && size.h === 0) return;\r\n\r\n ctx.save();\r\n ctx.globalAlpha = 0.5;\r\n ctx.strokeStyle = this.strokeColor;\r\n ctx.lineWidth = this.strokeWidth;\r\n\r\n if (this.fillColor !== 'none') {\r\n ctx.fillStyle = this.fillColor;\r\n }\r\n\r\n switch (this.shape) {\r\n case 'rectangle':\r\n if (this.fillColor !== 'none') {\r\n ctx.fillRect(position.x, position.y, size.w, size.h);\r\n }\r\n ctx.strokeRect(position.x, position.y, size.w, size.h);\r\n break;\r\n case 'ellipse': {\r\n const cx = position.x + size.w / 2;\r\n const cy = position.y + size.h / 2;\r\n ctx.beginPath();\r\n ctx.ellipse(cx, cy, size.w / 2, size.h / 2, 0, 0, Math.PI * 2);\r\n if (this.fillColor !== 'none') ctx.fill();\r\n ctx.stroke();\r\n break;\r\n }\r\n case 'line':\r\n ctx.lineCap = 'round';\r\n ctx.beginPath();\r\n ctx.moveTo(this.start.x, this.start.y);\r\n ctx.lineTo(this.end.x, this.end.y);\r\n ctx.stroke();\r\n break;\r\n }\r\n\r\n ctx.restore();\r\n }\r\n\r\n private computeRect(): { position: Point; size: { w: number; h: number } } {\r\n let x = Math.min(this.start.x, this.end.x);\r\n let y = Math.min(this.start.y, this.end.y);\r\n let w = Math.abs(this.end.x - this.start.x);\r\n let h = Math.abs(this.end.y - this.start.y);\r\n\r\n if (this.shiftHeld && this.shape !== 'line') {\r\n const side = Math.max(w, h);\r\n w = side;\r\n h = side;\r\n x = this.end.x >= this.start.x ? this.start.x : this.start.x - side;\r\n y = this.end.y >= this.start.y ? this.start.y : this.start.y - side;\r\n }\r\n\r\n return { position: { x, y }, size: { w, h } };\r\n }\r\n\r\n private notifyOptionsChange(): void {\r\n for (const listener of this.optionListeners) listener();\r\n }\r\n\r\n private snap(point: Point, ctx: ToolContext): Point {\r\n return smartSnap(point, ctx);\r\n }\r\n\r\n private onKeyDown = (e: KeyboardEvent): void => {\r\n if (e.key === 'Shift') this.shiftHeld = true;\r\n };\r\n\r\n private onKeyUp = (e: KeyboardEvent): void => {\r\n if (e.key === 'Shift') this.shiftHeld = false;\r\n };\r\n}\r\n","import type { Point } from '../core/types';\r\nimport type { HexOrientation } from '../elements/types';\r\nimport type { Tool, ToolContext, PointerState } from './types';\r\nimport { snapPoint, snapToHexCenter } from '../core/snap';\r\nimport { getHexDistance } from '../elements/hex-fill';\r\nimport { drawMeasurement } from '../canvas/measure-render';\r\n\r\nexport interface MeasureToolOptions {\r\n feetPerCell?: number;\r\n color?: string;\r\n}\r\n\r\nexport interface Measurement {\r\n start: Point;\r\n end: Point;\r\n worldDistance: number;\r\n cells: number;\r\n feet: number;\r\n}\r\n\r\n/**\r\n * A raf-coalesced snapshot of the in-progress measurement — the outgoing\r\n * side of a shared live ruler. Emissions carry world coordinates, derived\r\n * distance, and the tool's current color so a host can forward them as\r\n * ephemeral presence without duplicating the tool's input handling.\r\n * Ephemeral by contract: presence only — never elements, history, or\r\n * persisted state.\r\n */\r\nexport interface MeasureEmission {\r\n readonly start: Point;\r\n readonly end: Point;\r\n readonly worldDistance: number;\r\n readonly cells: number;\r\n readonly feet: number;\r\n readonly color: string;\r\n}\r\n\r\nexport class MeasureTool implements Tool {\r\n readonly name = 'measure';\r\n private start: Point | null = null;\r\n private end: Point | null = null;\r\n private gridSize = 1;\r\n private gridType: 'square' | 'hex' | undefined;\r\n private hexOrientation: HexOrientation | undefined;\r\n private feetPerCell: number;\r\n private color: string;\r\n private optionListeners = new Set<() => void>();\r\n private measurementListeners = new Set<(emission: MeasureEmission | null) => void>();\r\n private emissionRafId: number | null = null;\r\n\r\n constructor(options: MeasureToolOptions = {}) {\r\n this.feetPerCell = options.feetPerCell ?? 5;\r\n this.color = options.color ?? '#FF5722';\r\n }\r\n\r\n getOptions(): MeasureToolOptions {\r\n return { feetPerCell: this.feetPerCell, color: this.color };\r\n }\r\n\r\n setOptions(options: MeasureToolOptions): void {\r\n if (options.feetPerCell !== undefined) this.feetPerCell = options.feetPerCell;\r\n if (options.color !== undefined) this.color = options.color;\r\n this.notifyOptionsChange();\r\n }\r\n\r\n onOptionsChange(listener: () => void): () => void {\r\n this.optionListeners.add(listener);\r\n return () => this.optionListeners.delete(listener);\r\n }\r\n\r\n /**\r\n * Subscribes to raf-coalesced measurement snapshots. While a measurement is\r\n * in progress, listeners receive at most one snapshot per animation frame\r\n * carrying the latest state; `null` is delivered synchronously when the\r\n * measurement clears (pointer-up or deactivate). Emissions are ephemeral by\r\n * contract: presence only — never elements, history, or persisted state.\r\n */\r\n onMeasurement(listener: (emission: MeasureEmission | null) => void): () => void {\r\n this.measurementListeners.add(listener);\r\n return () => this.measurementListeners.delete(listener);\r\n }\r\n\r\n onPointerDown(state: PointerState, ctx: ToolContext): void {\r\n this.gridSize = ctx.gridSize ?? 1;\r\n this.gridType = ctx.gridType;\r\n this.hexOrientation = ctx.hexOrientation;\r\n const world = ctx.camera.screenToWorld({ x: state.x, y: state.y });\r\n this.start = this.snapToGrid(world, ctx);\r\n this.end = { ...this.start };\r\n this.scheduleEmission();\r\n }\r\n\r\n onPointerMove(state: PointerState, ctx: ToolContext): void {\r\n if (!this.start) return;\r\n const world = ctx.camera.screenToWorld({ x: state.x, y: state.y });\r\n this.end = this.snapToGrid(world, ctx);\r\n ctx.requestRender();\r\n this.scheduleEmission();\r\n }\r\n\r\n onPointerUp(_state: PointerState, ctx: ToolContext): void {\r\n if (!this.start) return;\r\n this.start = null;\r\n this.end = null;\r\n ctx.requestRender();\r\n this.emitClear();\r\n }\r\n\r\n onDeactivate(_ctx: ToolContext): void {\r\n const wasActive = this.start !== null;\r\n this.start = null;\r\n this.end = null;\r\n if (wasActive) this.emitClear();\r\n }\r\n\r\n getMeasurement(): Measurement | null {\r\n if (!this.start || !this.end) return null;\r\n const dx = this.end.x - this.start.x;\r\n const dy = this.end.y - this.start.y;\r\n const worldDistance = Math.sqrt(dx * dx + dy * dy);\r\n\r\n let cells: number;\r\n if (this.gridType === 'hex' && this.hexOrientation) {\r\n cells = getHexDistance(this.start, this.end, this.gridSize, this.hexOrientation);\r\n } else {\r\n const snapUnit = this.gridSize;\r\n cells = worldDistance / snapUnit;\r\n }\r\n\r\n const feet = cells * this.feetPerCell;\r\n return {\r\n start: { ...this.start },\r\n end: { ...this.end },\r\n worldDistance,\r\n cells,\r\n feet,\r\n };\r\n }\r\n\r\n renderOverlay(ctx: CanvasRenderingContext2D): void {\r\n const m = this.getMeasurement();\r\n if (!m) return;\r\n drawMeasurement(ctx, { start: m.start, end: m.end, feet: m.feet, color: this.color });\r\n }\r\n\r\n private snapToGrid(point: Point, ctx: ToolContext): Point {\r\n if (!ctx.gridSize) return point;\r\n if (ctx.gridType === 'hex' && ctx.hexOrientation) {\r\n return snapToHexCenter(point, ctx.gridSize, ctx.hexOrientation);\r\n }\r\n if (ctx.gridType === 'square') {\r\n return snapPoint(point, ctx.gridSize);\r\n }\r\n if (ctx.snapToGrid) {\r\n return snapPoint(point, ctx.gridSize);\r\n }\r\n return point;\r\n }\r\n\r\n private notifyOptionsChange(): void {\r\n for (const listener of this.optionListeners) listener();\r\n }\r\n\r\n private scheduleEmission(): void {\r\n if (this.measurementListeners.size === 0) return;\r\n if (this.emissionRafId !== null) return;\r\n this.emissionRafId = requestAnimationFrame(() => {\r\n this.emissionRafId = null;\r\n const m = this.getMeasurement();\r\n if (!m) return; // cleared before the frame; the sync null already went out\r\n this.emit({ ...m, color: this.color });\r\n });\r\n }\r\n\r\n private emitClear(): void {\r\n if (this.emissionRafId !== null) {\r\n cancelAnimationFrame(this.emissionRafId);\r\n this.emissionRafId = null;\r\n }\r\n if (this.measurementListeners.size === 0) return;\r\n this.emit(null);\r\n }\r\n\r\n private emit(emission: MeasureEmission | null): void {\r\n for (const listener of this.measurementListeners) {\r\n try {\r\n listener(emission);\r\n } catch {\r\n // A throwing host listener must not break measurement input.\r\n }\r\n }\r\n }\r\n}\r\n","import type { Point } from '../core/types';\r\nimport type { TemplateShape, HexOrientation, TemplateRenderStyle } from '../elements/types';\r\nimport type { Tool, ToolContext, PointerState } from './types';\r\nimport { createTemplate } from '../elements/element-factory';\r\nimport { snapPoint, snapToHexCenter } from '../core/snap';\r\nimport {\r\n getHexCellsInRadius,\r\n getHexCellsInCone,\r\n getHexCellsInLine,\r\n getHexCellsInSquare,\r\n getHexCellsInRectangle,\r\n drawHexPath,\r\n} from '../elements/hex-fill';\r\nimport { renderTemplateFeetLabel } from '../elements/renderers/template-measure';\r\n\r\nconst MIN_RECT_WIDTH = 20;\r\n\r\nexport function defaultRectWidth(radius: number, scaleUnit: number): number {\r\n if (scaleUnit > 0) return scaleUnit; // one grid cell\r\n return Math.max(MIN_RECT_WIDTH, radius * 0.25);\r\n}\r\n\r\nexport interface TemplateToolOptions {\r\n templateShape?: TemplateShape;\r\n fillColor?: string;\r\n strokeColor?: string;\r\n strokeWidth?: number;\r\n opacity?: number;\r\n feetPerCell?: number;\r\n renderStyle?: TemplateRenderStyle;\r\n}\r\n\r\nexport class TemplateTool implements Tool {\r\n readonly name = 'template';\r\n private drawing = false;\r\n private origin: Point = { x: 0, y: 0 };\r\n private current: Point = { x: 0, y: 0 };\r\n private gridSize = 1;\r\n private gridType: 'square' | 'hex' | undefined;\r\n private hexOrientation: HexOrientation | undefined;\r\n private snapEnabled = false;\r\n private feetScaleUnit = 0;\r\n private templateShape: TemplateShape;\r\n private fillColor: string;\r\n private strokeColor: string;\r\n private strokeWidth: number;\r\n private opacity: number;\r\n private feetPerCell: number;\r\n private renderStyle: TemplateRenderStyle;\r\n private optionListeners = new Set<() => void>();\r\n\r\n constructor(options: TemplateToolOptions = {}) {\r\n this.templateShape = options.templateShape ?? 'circle';\r\n this.fillColor = options.fillColor ?? 'rgba(255, 87, 34, 0.2)';\r\n this.strokeColor = options.strokeColor ?? '#FF5722';\r\n this.strokeWidth = options.strokeWidth ?? 2;\r\n this.opacity = options.opacity ?? 0.6;\r\n this.feetPerCell = options.feetPerCell ?? 5;\r\n this.renderStyle = options.renderStyle ?? 'cells';\r\n }\r\n\r\n getOptions(): TemplateToolOptions {\r\n return {\r\n templateShape: this.templateShape,\r\n fillColor: this.fillColor,\r\n strokeColor: this.strokeColor,\r\n strokeWidth: this.strokeWidth,\r\n opacity: this.opacity,\r\n feetPerCell: this.feetPerCell,\r\n renderStyle: this.renderStyle,\r\n };\r\n }\r\n\r\n setOptions(options: TemplateToolOptions): void {\r\n if (options.templateShape !== undefined) this.templateShape = options.templateShape;\r\n if (options.fillColor !== undefined) this.fillColor = options.fillColor;\r\n if (options.strokeColor !== undefined) this.strokeColor = options.strokeColor;\r\n if (options.strokeWidth !== undefined) this.strokeWidth = options.strokeWidth;\r\n if (options.opacity !== undefined) this.opacity = options.opacity;\r\n if (options.feetPerCell !== undefined) this.feetPerCell = options.feetPerCell;\r\n if (options.renderStyle !== undefined) this.renderStyle = options.renderStyle;\r\n this.notifyOptionsChange();\r\n }\r\n\r\n onOptionsChange(listener: () => void): () => void {\r\n this.optionListeners.add(listener);\r\n return () => this.optionListeners.delete(listener);\r\n }\r\n\r\n onPointerDown(state: PointerState, ctx: ToolContext): void {\r\n this.drawing = true;\r\n this.gridSize = ctx.gridSize ?? 1;\r\n this.gridType = ctx.gridType;\r\n this.hexOrientation = ctx.hexOrientation;\r\n this.snapEnabled = !!ctx.gridType || (ctx.snapToGrid ?? false);\r\n this.feetScaleUnit =\r\n ctx.gridSize && ctx.gridSize > 0\r\n ? ctx.gridType === 'hex'\r\n ? Math.sqrt(3) * ctx.gridSize\r\n : ctx.gridSize\r\n : 0;\r\n const world = ctx.camera.screenToWorld({ x: state.x, y: state.y });\r\n this.origin = this.snapToGrid(world, ctx);\r\n this.current = { ...this.origin };\r\n }\r\n\r\n onPointerMove(state: PointerState, ctx: ToolContext): void {\r\n if (!this.drawing) return;\r\n this.current = ctx.camera.screenToWorld({ x: state.x, y: state.y });\r\n ctx.requestRender();\r\n }\r\n\r\n onPointerUp(_state: PointerState, ctx: ToolContext): void {\r\n if (!this.drawing) return;\r\n this.drawing = false;\r\n\r\n const radius = this.computeRadius();\r\n if (radius <= 0) return;\r\n\r\n const angle = this.computeAngle();\r\n const gridSize = ctx.gridSize;\r\n const snapUnit =\r\n gridSize && gridSize > 0 ? (ctx.gridType === 'hex' ? Math.sqrt(3) * gridSize : gridSize) : 0;\r\n const cells = snapUnit > 0 ? radius / snapUnit : 0;\r\n const radiusFeet = cells * this.feetPerCell;\r\n const width =\r\n this.templateShape === 'rectangle' ? defaultRectWidth(radius, this.feetScaleUnit) : undefined;\r\n\r\n const element = createTemplate({\r\n position: { ...this.origin },\r\n templateShape: this.templateShape,\r\n radius,\r\n angle,\r\n width,\r\n fillColor: this.fillColor,\r\n strokeColor: this.strokeColor,\r\n strokeWidth: this.strokeWidth,\r\n opacity: this.opacity,\r\n feetPerCell: this.feetPerCell,\r\n radiusFeet: radiusFeet > 0 ? radiusFeet : undefined,\r\n renderStyle: this.renderStyle,\r\n layerId: ctx.activeLayerId ?? '',\r\n });\r\n ctx.store.add(element);\r\n ctx.requestRender();\r\n ctx.switchTool?.('select');\r\n }\r\n\r\n onDeactivate(_ctx: ToolContext): void {\r\n this.drawing = false;\r\n this.origin = { x: 0, y: 0 };\r\n this.current = { x: 0, y: 0 };\r\n }\r\n\r\n renderOverlay(ctx: CanvasRenderingContext2D): void {\r\n if (!this.drawing) return;\r\n\r\n const radius = this.computeRadius();\r\n if (radius <= 0) return;\r\n\r\n if (this.gridType === 'hex' && this.hexOrientation && this.renderStyle !== 'geometric') {\r\n this.renderHexOverlay(ctx, radius);\r\n return;\r\n }\r\n\r\n this.renderGeometricOverlay(ctx, radius);\r\n }\r\n\r\n private renderGeometricOverlay(ctx: CanvasRenderingContext2D, radius: number): void {\r\n const cx = this.origin.x;\r\n const cy = this.origin.y;\r\n const angle = this.computeAngle();\r\n\r\n ctx.save();\r\n ctx.globalAlpha = 0.4;\r\n ctx.fillStyle = this.fillColor;\r\n ctx.strokeStyle = this.strokeColor;\r\n ctx.lineWidth = this.strokeWidth;\r\n\r\n switch (this.templateShape) {\r\n case 'circle':\r\n ctx.beginPath();\r\n ctx.arc(cx, cy, radius, 0, Math.PI * 2);\r\n ctx.fill();\r\n ctx.stroke();\r\n break;\r\n\r\n case 'square':\r\n ctx.fillRect(cx - radius / 2, cy - radius / 2, radius, radius);\r\n ctx.strokeRect(cx - radius / 2, cy - radius / 2, radius, radius);\r\n break;\r\n\r\n case 'cone': {\r\n const halfAngle = Math.atan(0.5);\r\n ctx.beginPath();\r\n ctx.moveTo(cx, cy);\r\n ctx.arc(cx, cy, radius, angle - halfAngle, angle + halfAngle);\r\n ctx.closePath();\r\n ctx.fill();\r\n ctx.stroke();\r\n break;\r\n }\r\n\r\n case 'line': {\r\n const halfW = radius / 12;\r\n const cos = Math.cos(angle);\r\n const sin = Math.sin(angle);\r\n const perpX = -sin * halfW;\r\n const perpY = cos * halfW;\r\n\r\n ctx.beginPath();\r\n ctx.moveTo(cx + perpX, cy + perpY);\r\n ctx.lineTo(cx + radius * cos + perpX, cy + radius * sin + perpY);\r\n ctx.lineTo(cx + radius * cos - perpX, cy + radius * sin - perpY);\r\n ctx.lineTo(cx - perpX, cy - perpY);\r\n ctx.closePath();\r\n ctx.fill();\r\n ctx.stroke();\r\n break;\r\n }\r\n\r\n case 'rectangle': {\r\n const halfW = defaultRectWidth(radius, this.feetScaleUnit) / 2;\r\n const cos = Math.cos(angle);\r\n const sin = Math.sin(angle);\r\n const perpX = -sin * halfW;\r\n const perpY = cos * halfW;\r\n ctx.beginPath();\r\n ctx.moveTo(cx + perpX, cy + perpY);\r\n ctx.lineTo(cx + radius * cos + perpX, cy + radius * sin + perpY);\r\n ctx.lineTo(cx + radius * cos - perpX, cy + radius * sin - perpY);\r\n ctx.lineTo(cx - perpX, cy - perpY);\r\n ctx.closePath();\r\n ctx.fill();\r\n ctx.stroke();\r\n break;\r\n }\r\n }\r\n\r\n this.drawFeetLabel(ctx, radius);\r\n ctx.restore();\r\n }\r\n\r\n private renderHexOverlay(ctx: CanvasRenderingContext2D, radius: number): void {\r\n const orientation = this.hexOrientation;\r\n if (!orientation) return;\r\n const cellSize = this.gridSize;\r\n const snapUnit = Math.sqrt(3) * cellSize;\r\n const radiusCells = radius / snapUnit;\r\n const angle = this.computeAngle();\r\n const center = this.origin;\r\n\r\n let hexCells: Point[];\r\n switch (this.templateShape) {\r\n case 'circle':\r\n hexCells = getHexCellsInRadius(center, radiusCells, cellSize, orientation);\r\n break;\r\n case 'cone':\r\n hexCells = getHexCellsInCone(center, angle, radiusCells, cellSize, orientation);\r\n break;\r\n case 'line':\r\n hexCells = getHexCellsInLine(center, angle, radiusCells, cellSize, orientation);\r\n break;\r\n case 'square':\r\n hexCells = getHexCellsInSquare(center, radiusCells, cellSize, orientation);\r\n break;\r\n case 'rectangle': {\r\n const widthCells = defaultRectWidth(radius, this.feetScaleUnit) / snapUnit;\r\n hexCells = getHexCellsInRectangle(\r\n center,\r\n angle,\r\n radiusCells,\r\n widthCells,\r\n cellSize,\r\n orientation,\r\n );\r\n break;\r\n }\r\n }\r\n\r\n ctx.save();\r\n ctx.globalAlpha = 0.4;\r\n\r\n ctx.beginPath();\r\n for (const cell of hexCells) {\r\n drawHexPath(ctx, cell.x, cell.y, cellSize, orientation);\r\n }\r\n ctx.fillStyle = this.fillColor;\r\n ctx.fill();\r\n\r\n ctx.beginPath();\r\n for (const cell of hexCells) {\r\n drawHexPath(ctx, cell.x, cell.y, cellSize, orientation);\r\n }\r\n ctx.strokeStyle = this.strokeColor;\r\n ctx.lineWidth = this.strokeWidth;\r\n ctx.stroke();\r\n\r\n if (\r\n this.templateShape === 'cone' ||\r\n this.templateShape === 'line' ||\r\n this.templateShape === 'circle' ||\r\n this.templateShape === 'square' ||\r\n this.templateShape === 'rectangle'\r\n ) {\r\n ctx.globalAlpha = 0.5;\r\n ctx.beginPath();\r\n drawHexPath(ctx, center.x, center.y, cellSize, orientation);\r\n ctx.fillStyle = this.strokeColor;\r\n ctx.fill();\r\n ctx.strokeStyle = this.strokeColor;\r\n ctx.lineWidth = this.strokeWidth;\r\n ctx.stroke();\r\n }\r\n\r\n this.drawFeetLabel(ctx, radius);\r\n ctx.restore();\r\n }\r\n\r\n private computeRadius(): number {\r\n const dx = this.current.x - this.origin.x;\r\n const dy = this.current.y - this.origin.y;\r\n const raw = Math.sqrt(dx * dx + dy * dy);\r\n if (this.snapEnabled && this.gridSize > 0) {\r\n const snapUnit = this.gridType === 'hex' ? Math.sqrt(3) * this.gridSize : this.gridSize;\r\n return Math.max(snapUnit, Math.round(raw / snapUnit) * snapUnit);\r\n }\r\n return raw;\r\n }\r\n\r\n private computeAngle(): number {\r\n const dx = this.current.x - this.origin.x;\r\n const dy = this.current.y - this.origin.y;\r\n return Math.atan2(dy, dx);\r\n }\r\n\r\n private drawFeetLabel(ctx: CanvasRenderingContext2D, radius: number): void {\r\n const feet = this.feetScaleUnit > 0 ? (radius / this.feetScaleUnit) * this.feetPerCell : 0;\r\n renderTemplateFeetLabel(ctx, {\r\n position: this.origin,\r\n radius,\r\n angle: this.computeAngle(),\r\n templateShape: this.templateShape,\r\n feet,\r\n color: this.strokeColor,\r\n });\r\n }\r\n\r\n private snapToGrid(point: Point, ctx: ToolContext): Point {\r\n if (!ctx.gridSize) return point;\r\n if (ctx.gridType === 'hex' && ctx.hexOrientation) {\r\n return snapToHexCenter(point, ctx.gridSize, ctx.hexOrientation);\r\n }\r\n if (ctx.gridType === 'square') {\r\n return snapPoint(point, ctx.gridSize);\r\n }\r\n if (ctx.snapToGrid) {\r\n return snapPoint(point, ctx.gridSize);\r\n }\r\n return point;\r\n }\r\n\r\n private notifyOptionsChange(): void {\r\n for (const listener of this.optionListeners) listener();\r\n }\r\n}\r\n","import type { Tool, ToolContext, PointerState } from './types';\r\nimport type { Point } from '../core/types';\r\n\r\nexport interface LaserToolOptions {\r\n name?: string;\r\n color?: string;\r\n width?: number;\r\n fadeMs?: number;\r\n}\r\n\r\n/**\r\n * A coalesced batch of locally drawn trail points, flushed at most once per\r\n * animation frame — the outgoing side of a shared laser pointer. Emissions\r\n * carry world coordinates and the tool's current style so a host can forward\r\n * them as ephemeral presence without duplicating the tool's input handling.\r\n */\r\nexport interface LaserTrailEmission {\r\n /** World-space points recorded since the previous emission, oldest first. */\r\n readonly points: readonly Point[];\r\n readonly color: string;\r\n readonly width: number;\r\n readonly fadeMs: number;\r\n}\r\n\r\ninterface TrailPoint {\r\n x: number;\r\n y: number;\r\n t: number;\r\n}\r\n\r\nconst DEFAULT_COLOR = '#ff3b30';\r\nconst DEFAULT_WIDTH = 4;\r\nconst DEFAULT_FADE_MS = 1200;\r\n\r\nexport class LaserTool implements Tool {\r\n readonly name: string;\r\n private color: string;\r\n private width: number;\r\n private fadeMs: number;\r\n private trail: TrailPoint[] = [];\r\n private rafId: number | null = null;\r\n private drawing = false;\r\n private optionListeners = new Set<() => void>();\r\n private trailListeners = new Set<(emission: LaserTrailEmission) => void>();\r\n private pendingEmission: Point[] = [];\r\n\r\n constructor(options: LaserToolOptions = {}) {\r\n this.name = options.name ?? 'laser';\r\n this.color = options.color ?? DEFAULT_COLOR;\r\n this.width = options.width ?? DEFAULT_WIDTH;\r\n this.fadeMs = options.fadeMs ?? DEFAULT_FADE_MS;\r\n }\r\n\r\n private now(): number {\r\n return performance.now();\r\n }\r\n\r\n onActivate(ctx: ToolContext): void {\r\n ctx.setCursor?.('crosshair');\r\n }\r\n\r\n onDeactivate(ctx: ToolContext): void {\r\n if (this.rafId !== null) {\r\n cancelAnimationFrame(this.rafId);\r\n this.rafId = null;\r\n }\r\n this.trail = [];\r\n this.drawing = false;\r\n this.pendingEmission = [];\r\n ctx.setCursor?.('default');\r\n ctx.requestRender();\r\n }\r\n\r\n getOptions(): LaserToolOptions {\r\n return {\r\n name: this.name,\r\n color: this.color,\r\n width: this.width,\r\n fadeMs: this.fadeMs,\r\n };\r\n }\r\n\r\n onOptionsChange(listener: () => void): () => void {\r\n this.optionListeners.add(listener);\r\n return () => this.optionListeners.delete(listener);\r\n }\r\n\r\n /**\r\n * Subscribes to coalesced trail emissions. Points recorded by pointer input\r\n * are batched and delivered at most once per animation frame, keeping\r\n * outgoing presence packets small. Listeners must not throw; a throwing\r\n * listener is isolated so it cannot stall the fade loop.\r\n */\r\n onTrail(listener: (emission: LaserTrailEmission) => void): () => void {\r\n this.trailListeners.add(listener);\r\n return () => this.trailListeners.delete(listener);\r\n }\r\n\r\n setOptions(options: LaserToolOptions): void {\r\n if (options.color !== undefined) this.color = options.color;\r\n if (options.width !== undefined) this.width = options.width;\r\n if (options.fadeMs !== undefined) this.fadeMs = options.fadeMs;\r\n this.notifyOptionsChange();\r\n }\r\n\r\n onPointerDown(state: PointerState, ctx: ToolContext): void {\r\n this.drawing = true;\r\n this.recordPoint(state, ctx);\r\n }\r\n\r\n onPointerMove(state: PointerState, ctx: ToolContext): void {\r\n if (!this.drawing) return;\r\n this.recordPoint(state, ctx);\r\n }\r\n\r\n private recordPoint(state: PointerState, ctx: ToolContext): void {\r\n const world = ctx.camera.screenToWorld({ x: state.x, y: state.y });\r\n this.trail.push({ x: world.x, y: world.y, t: this.now() });\r\n if (this.trailListeners.size > 0) {\r\n this.pendingEmission.push({ x: world.x, y: world.y });\r\n }\r\n this.ensureAnimating(ctx);\r\n }\r\n\r\n onPointerUp(_state: PointerState, _ctx: ToolContext): void {\r\n this.drawing = false;\r\n }\r\n\r\n renderOverlay(ctx: CanvasRenderingContext2D): void {\r\n if (this.trail.length < 2) return;\r\n\r\n ctx.save();\r\n ctx.strokeStyle = this.color;\r\n ctx.lineWidth = this.width;\r\n ctx.lineCap = 'round';\r\n ctx.lineJoin = 'round';\r\n\r\n const now = this.now();\r\n for (let i = 0; i < this.trail.length - 1; i++) {\r\n const a = this.trail[i];\r\n const b = this.trail[i + 1];\r\n if (!a || !b) continue;\r\n const age = now - b.t;\r\n ctx.globalAlpha = Math.max(0, 1 - age / this.fadeMs);\r\n ctx.beginPath();\r\n ctx.moveTo(a.x, a.y);\r\n ctx.lineTo(b.x, b.y);\r\n ctx.stroke();\r\n }\r\n\r\n ctx.restore();\r\n }\r\n\r\n private ensureAnimating(ctx: ToolContext): void {\r\n if (this.rafId === null) {\r\n this.rafId = requestAnimationFrame(() => this.tick(ctx));\r\n }\r\n }\r\n\r\n private flushEmission(): void {\r\n if (this.pendingEmission.length === 0) return;\r\n const emission: LaserTrailEmission = {\r\n points: this.pendingEmission,\r\n color: this.color,\r\n width: this.width,\r\n fadeMs: this.fadeMs,\r\n };\r\n this.pendingEmission = [];\r\n for (const listener of this.trailListeners) {\r\n try {\r\n listener(emission);\r\n } catch {\r\n // A throwing host listener must not stall the fade/emission loop.\r\n }\r\n }\r\n }\r\n\r\n private tick(ctx: ToolContext): void {\r\n this.flushEmission();\r\n const cutoff = this.now() - this.fadeMs;\r\n this.trail = this.trail.filter((p) => p.t >= cutoff);\r\n if (this.trail.length > 0) {\r\n ctx.requestRender();\r\n this.rafId = requestAnimationFrame(() => this.tick(ctx));\r\n } else {\r\n ctx.requestRender();\r\n this.rafId = null;\r\n }\r\n }\r\n\r\n private notifyOptionsChange(): void {\r\n for (const listener of this.optionListeners) listener();\r\n }\r\n}\r\n","import type { Tool, ToolContext, PointerState } from './types';\r\nimport { renderPingPulse } from '../canvas/ping-pulse';\r\n\r\nexport interface PingToolOptions {\r\n name?: string;\r\n color?: string;\r\n /** Total pulse animation length in milliseconds. */\r\n durationMs?: number;\r\n /** Maximum ripple radius in world units. */\r\n radius?: number;\r\n /**\r\n * Minimum interval between emitted pings. Taps arriving faster are ignored\r\n * entirely (no local pulse, no emission), so rapid-fire pings cannot starve\r\n * durable sync traffic.\r\n */\r\n minIntervalMs?: number;\r\n}\r\n\r\n/**\r\n * One emitted ping — the outgoing side of a shared \"look here\" marker.\r\n * Emissions carry the world position and the tool's current style so a host\r\n * can forward them as ephemeral presence without duplicating input handling.\r\n */\r\nexport interface PingEmission {\r\n /** World-space ping position. */\r\n readonly x: number;\r\n readonly y: number;\r\n readonly color: string;\r\n readonly durationMs: number;\r\n readonly radius: number;\r\n}\r\n\r\ninterface LocalPing {\r\n x: number;\r\n y: number;\r\n t: number;\r\n}\r\n\r\nconst DEFAULT_COLOR = '#ff3b30';\r\nconst DEFAULT_DURATION_MS = 1800;\r\nconst DEFAULT_RADIUS = 48;\r\nconst DEFAULT_MIN_INTERVAL_MS = 300;\r\n\r\n/**\r\n * Tap or click to ping a world position: a short expanding-pulse animation is\r\n * rendered locally and one `PingEmission` is delivered to `onPing` listeners\r\n * per accepted tap. Pings are ephemeral by contract: they never create\r\n * elements, enter undo history, or touch persisted canvas state — hosts\r\n * forward emissions as presence only.\r\n */\r\nexport class PingTool implements Tool {\r\n readonly name: string;\r\n private color: string;\r\n private durationMs: number;\r\n private radius: number;\r\n private minIntervalMs: number;\r\n private pings: LocalPing[] = [];\r\n private lastEmitAt = -Infinity;\r\n private rafId: number | null = null;\r\n private optionListeners = new Set<() => void>();\r\n private pingListeners = new Set<(emission: PingEmission) => void>();\r\n\r\n constructor(options: PingToolOptions = {}) {\r\n this.name = options.name ?? 'ping';\r\n this.color = options.color ?? DEFAULT_COLOR;\r\n this.durationMs = options.durationMs ?? DEFAULT_DURATION_MS;\r\n this.radius = options.radius ?? DEFAULT_RADIUS;\r\n this.minIntervalMs = options.minIntervalMs ?? DEFAULT_MIN_INTERVAL_MS;\r\n }\r\n\r\n private now(): number {\r\n return performance.now();\r\n }\r\n\r\n onActivate(ctx: ToolContext): void {\r\n ctx.setCursor?.('crosshair');\r\n }\r\n\r\n onDeactivate(ctx: ToolContext): void {\r\n if (this.rafId !== null) {\r\n cancelAnimationFrame(this.rafId);\r\n this.rafId = null;\r\n }\r\n this.pings = [];\r\n ctx.setCursor?.('default');\r\n ctx.requestRender();\r\n }\r\n\r\n getOptions(): PingToolOptions {\r\n return {\r\n name: this.name,\r\n color: this.color,\r\n durationMs: this.durationMs,\r\n radius: this.radius,\r\n minIntervalMs: this.minIntervalMs,\r\n };\r\n }\r\n\r\n setOptions(options: PingToolOptions): void {\r\n if (options.color !== undefined) this.color = options.color;\r\n if (options.durationMs !== undefined) this.durationMs = options.durationMs;\r\n if (options.radius !== undefined) this.radius = options.radius;\r\n if (options.minIntervalMs !== undefined) this.minIntervalMs = options.minIntervalMs;\r\n this.notifyOptionsChange();\r\n }\r\n\r\n onOptionsChange(listener: () => void): () => void {\r\n this.optionListeners.add(listener);\r\n return () => this.optionListeners.delete(listener);\r\n }\r\n\r\n /**\r\n * Subscribes to accepted pings. Listeners must not throw; a throwing\r\n * listener is isolated so it cannot break the tap handling or other\r\n * listeners.\r\n */\r\n onPing(listener: (emission: PingEmission) => void): () => void {\r\n this.pingListeners.add(listener);\r\n return () => this.pingListeners.delete(listener);\r\n }\r\n\r\n onPointerDown(state: PointerState, ctx: ToolContext): void {\r\n const t = this.now();\r\n if (t - this.lastEmitAt < this.minIntervalMs) return;\r\n this.lastEmitAt = t;\r\n\r\n const world = ctx.camera.screenToWorld({ x: state.x, y: state.y });\r\n this.pings.push({ x: world.x, y: world.y, t });\r\n const emission: PingEmission = {\r\n x: world.x,\r\n y: world.y,\r\n color: this.color,\r\n durationMs: this.durationMs,\r\n radius: this.radius,\r\n };\r\n for (const listener of this.pingListeners) {\r\n try {\r\n listener(emission);\r\n } catch {\r\n // A throwing host listener must not break tap handling.\r\n }\r\n }\r\n this.ensureAnimating(ctx);\r\n ctx.requestRender();\r\n }\r\n\r\n onPointerMove(_state: PointerState, _ctx: ToolContext): void {\r\n // Pings are discrete taps; dragging does nothing.\r\n }\r\n\r\n onPointerUp(_state: PointerState, _ctx: ToolContext): void {\r\n // Nothing to finish; the ping fired on pointer down.\r\n }\r\n\r\n renderOverlay(ctx: CanvasRenderingContext2D): void {\r\n if (this.pings.length === 0) return;\r\n const now = this.now();\r\n for (const ping of this.pings) {\r\n renderPingPulse(ctx, ping.x, ping.y, now - ping.t, {\r\n color: this.color,\r\n durationMs: this.durationMs,\r\n radius: this.radius,\r\n });\r\n }\r\n }\r\n\r\n private ensureAnimating(ctx: ToolContext): void {\r\n if (this.rafId === null) {\r\n this.rafId = requestAnimationFrame(() => this.tick(ctx));\r\n }\r\n }\r\n\r\n private tick(ctx: ToolContext): void {\r\n const cutoff = this.now() - this.durationMs;\r\n this.pings = this.pings.filter((ping) => ping.t > cutoff);\r\n ctx.requestRender();\r\n this.rafId = this.pings.length > 0 ? requestAnimationFrame(() => this.tick(ctx)) : null;\r\n }\r\n\r\n private notifyOptionsChange(): void {\r\n for (const listener of this.optionListeners) listener();\r\n }\r\n}\r\n"],"mappings":"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","names":["counter","center","minX","minY","minX","minY","center","n","center","cache","center","n","center","center","DEFAULT_DEBOUNCE_MS","cache","ARROWHEAD_LENGTH","ARROWHEAD_ANGLE","ARROW_LABEL_FONT_SIZE","WIDTH_QUANTUM","d","center","unionBounds","center","moved","unionBounds","center","n","center","HANDLE_HIT_PADDING","center","HANDLE_HIT_PADDING","noop","DEFAULT_WIDTH","DEFAULT_COLOR","isFinitePoint","DEFAULT_COLOR","DEFAULT_FADE_MS","DEFAULT_COLOR","DEFAULT_DURATION_MS","DEFAULT_RADIUS","DEFAULT_DURATION_MS","easeOutCubic","isFiniteNumber","lerp","DEFAULT_RADIUS","center","BIND_THRESHOLD","center","DEFAULT_COLOR","DEFAULT_WIDTH","DEFAULT_FADE_MS","DEFAULT_COLOR","DEFAULT_DURATION_MS","DEFAULT_RADIUS","DEFAULT_MIN_INTERVAL_MS"]}