html-overlay-node 0.1.9 → 0.1.11

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,"file":"html-overlay-node.umd.js","sources":["../src/core/Registry.js","../src/utils/utils.js","../src/core/Node.js","../src/core/Edge.js","../src/groups/GroupManager.js","../src/core/Graph.js","../src/render/hitTest.js","../src/render/CanvasRenderer.js","../src/core/commands.js","../src/core/CommandStack.js","../src/interact/Controller.js","../src/interact/ContextMenu.js","../src/core/Runner.js","../src/render/HtmlOverlay.js","../src/minimap/Minimap.js","../src/ui/PropertyPanel.js","../src/index.js","../src/core/Hooks.js","../src/defaults/contextMenu.js"],"sourcesContent":["// src/core/Registry.js\r\n\r\n/**\r\n * Registry for managing node type definitions\r\n */\r\nexport class Registry {\r\n constructor() {\r\n this.types = new Map();\r\n }\r\n\r\n /**\r\n * Register a new node type\r\n * @param {string} type - Unique type identifier (e.g., \"core/Note\")\r\n * @param {Object} def - Node definition\r\n * @param {string} [def.title] - Display title\r\n * @param {Object} [def.size] - Default size {w, h}\r\n * @param {Array} [def.inputs] - Input port definitions\r\n * @param {Array} [def.outputs] - Output port definitions\r\n * @param {Function} [def.onCreate] - Called when node is created\r\n * @param {Function} [def.onExecute] - Called each execution cycle\r\n * @param {Function} [def.onDraw] - Custom drawing function\r\n * @param {Object} [def.html] - HTML overlay configuration\r\n * @throws {Error} If type is already registered or invalid\r\n */\r\n register(type, def) {\r\n if (!type || typeof type !== 'string') {\r\n throw new Error(`Invalid node type: type must be a non-empty string, got ${typeof type}`);\r\n }\r\n if (!def || typeof def !== 'object') {\r\n throw new Error(`Invalid definition for type \"${type}\": definition must be an object`);\r\n }\r\n if (this.types.has(type)) {\r\n throw new Error(`Node type \"${type}\" is already registered. Use unregister() first to replace it.`);\r\n }\r\n this.types.set(type, def);\r\n }\r\n\r\n /**\r\n * Unregister a node type\r\n * @param {string} type - Type identifier to unregister\r\n * @throws {Error} If type doesn't exist\r\n */\r\n unregister(type) {\r\n if (!this.types.has(type)) {\r\n throw new Error(`Cannot unregister type \"${type}\": type is not registered`);\r\n }\r\n this.types.delete(type);\r\n }\r\n\r\n /**\r\n * Remove all registered node types\r\n */\r\n removeAll() {\r\n this.types.clear();\r\n }\r\n\r\n /**\r\n * Get the definition for a registered node type\r\n * @param {string} type - Type identifier\r\n * @returns {Object} Node definition\r\n * @throws {Error} If type is not registered\r\n */\r\n createInstance(type) {\r\n const def = this.types.get(type);\r\n if (!def) {\r\n const available = Array.from(this.types.keys()).join(', ') || 'none';\r\n throw new Error(`Unknown node type: \"${type}\". Available types: ${available}`);\r\n }\r\n return def;\r\n }\r\n}\r\n","export function randomUUID() {\r\n // 1) 전역 객체 안전 획득\r\n const g =\r\n typeof globalThis !== \"undefined\" ? globalThis :\r\n typeof self !== \"undefined\" ? self :\r\n typeof window !== \"undefined\" ? window :\r\n typeof global !== \"undefined\" ? global : {};\r\n\r\n const c = g.crypto || g.msCrypto; // IE11 호환\r\n\r\n // 2) 네이티브 지원 (브라우저/Deno 등)\r\n if (c && typeof c.randomUUID === \"function\") {\r\n return c.randomUUID();\r\n }\r\n\r\n // 3) Web Crypto만 있는 경우 (getRandomValues로 직접 생성)\r\n if (c && typeof c.getRandomValues === \"function\") {\r\n const bytes = new Uint8Array(16);\r\n c.getRandomValues(bytes);\r\n // RFC4122 버전/변형 비트 설정\r\n bytes[6] = (bytes[6] & 0x0f) | 0x40;\r\n bytes[8] = (bytes[8] & 0x3f) | 0x80;\r\n\r\n const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, \"0\"));\r\n return (\r\n hex.slice(0, 4).join(\"\") + \"-\" +\r\n hex.slice(4, 6).join(\"\") + \"-\" +\r\n hex.slice(6, 8).join(\"\") + \"-\" +\r\n hex.slice(8, 10).join(\"\") + \"-\" +\r\n hex.slice(10, 16).join(\"\")\r\n );\r\n }\r\n\r\n // 4) Node.js 전용 대체 (require가 있을 때)\r\n try {\r\n // 번들러/ESM 충돌 피하려고 런타임에만 require 접근\r\n\r\n const req = Function('return typeof require === \"function\" ? require : null')();\r\n if (req) {\r\n const nodeCrypto = req(\"crypto\");\r\n if (typeof nodeCrypto.randomUUID === \"function\") {\r\n return nodeCrypto.randomUUID();\r\n }\r\n const bytes = nodeCrypto.randomBytes(16);\r\n bytes[6] = (bytes[6] & 0x0f) | 0x40;\r\n bytes[8] = (bytes[8] & 0x3f) | 0x80;\r\n\r\n const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, \"0\"));\r\n return (\r\n hex.slice(0, 4).join(\"\") + \"-\" +\r\n hex.slice(4, 6).join(\"\") + \"-\" +\r\n hex.slice(6, 8).join(\"\") + \"-\" +\r\n hex.slice(8, 10).join(\"\") + \"-\" +\r\n hex.slice(10, 16).join(\"\")\r\n );\r\n }\r\n } catch {\r\n // ignore\r\n }\r\n\r\n // 5) 최후의 비보안 대체 (CSPRNG 아님!)\r\n const bytes = new Uint8Array(16);\r\n for (let i = 0; i < 16; i++) bytes[i] = Math.floor(Math.random() * 256);\r\n bytes[6] = (bytes[6] & 0x0f) | 0x40;\r\n bytes[8] = (bytes[8] & 0x3f) | 0x80;\r\n\r\n const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, \"0\"));\r\n return (\r\n hex.slice(0, 4).join(\"\") + \"-\" +\r\n hex.slice(4, 6).join(\"\") + \"-\" +\r\n hex.slice(6, 8).join(\"\") + \"-\" +\r\n hex.slice(8, 10).join(\"\") + \"-\" +\r\n hex.slice(10, 16).join(\"\")\r\n );\r\n}","import { randomUUID } from \"../utils/utils.js\";\r\n\r\n// src/core/Node.js\r\n\r\n/**\r\n * Node represents a single node in the graph\r\n */\r\nexport class Node {\r\n /**\r\n * Create a new Node\r\n * @param {Object} options - Node configuration\r\n * @param {string} [options.id] - Unique identifier (auto-generated if not provided)\r\n * @param {string} options.type - Node type identifier\r\n * @param {string} [options.title] - Display title (defaults to type)\r\n * @param {number} [options.x=0] - X position\r\n * @param {number} [options.y=0] - Y position\r\n * @param {number} [options.width=160] - Node width\r\n * @param {number} [options.height=60] - Node height\r\n */\r\n constructor({ id, type, title, x = 0, y = 0, width = 160, height = 60 }) {\r\n if (!type) {\r\n throw new Error(\"Node type is required\");\r\n }\r\n this.id = id ?? randomUUID();\r\n this.type = type;\r\n this.title = title ?? type;\r\n this.pos = { x, y };\r\n this.size = { width, height };\r\n this.inputs = []; // {id,name,datatype,portType,dir}\r\n this.outputs = []; // {id,name,datatype,portType,dir}\r\n this.state = {}; // User state data\r\n\r\n // Tree Structure\r\n this.parent = null; // Parent Node (or null if root)\r\n this.children = new Set(); // Set<Node>\r\n this.computed = { x: 0, y: 0, w: 0, h: 0 }; // World Transform\r\n }\r\n\r\n /**\r\n * Add an input port to this node\r\n * @param {string} name - Port name\r\n * @param {string} [datatype=\"any\"] - Data type for the port\r\n * @param {string} [portType=\"data\"] - Port type: \"exec\" or \"data\"\r\n * @returns {Object} The created port\r\n */\r\n /**\r\n * Recalculate minimum size based on ports\r\n */\r\n _updateMinSize() {\r\n const HEADER_HEIGHT = 28;\r\n const PORT_SPACING = 24;\r\n const BOTTOM_PADDING = 10;\r\n\r\n // Calculate required height for inputs and outputs\r\n const inHeight = HEADER_HEIGHT + 10 + this.inputs.length * PORT_SPACING + BOTTOM_PADDING;\r\n const outHeight = HEADER_HEIGHT + 10 + this.outputs.length * PORT_SPACING + BOTTOM_PADDING;\r\n\r\n const minHeight = Math.max(inHeight, outHeight, 60); // Minimum 60px base\r\n\r\n if (this.size.height < minHeight) {\r\n this.size.height = minHeight;\r\n }\r\n }\r\n\r\n addInput(name, datatype = \"any\", portType = \"data\") {\r\n // ... existing validation ...\r\n if (typeof name !== \"string\" || (portType === \"data\" && !name)) {\r\n throw new Error(\"Input port name must be a string (non-empty for data ports)\");\r\n }\r\n const port = { id: randomUUID(), name, datatype, portType, dir: \"in\" };\r\n this.inputs.push(port);\r\n this._updateMinSize();\r\n return port;\r\n }\r\n\r\n addOutput(name, datatype = \"any\", portType = \"data\") {\r\n // ... existing validation ...\r\n if (typeof name !== \"string\" || (portType === \"data\" && !name)) {\r\n throw new Error(\"Output port name must be a string (non-empty for data ports)\");\r\n }\r\n const port = { id: randomUUID(), name, datatype, portType, dir: \"out\" };\r\n this.outputs.push(port);\r\n this._updateMinSize();\r\n return port;\r\n }\r\n}\r\n","import { randomUUID } from \"../utils/utils.js\";\r\n\r\n// src/core/Edge.js\r\n\r\n/**\r\n * Edge represents a connection between two node ports\r\n */\r\nexport class Edge {\r\n /**\r\n * Create a new Edge\r\n * @param {Object} options - Edge configuration\r\n * @param {string} [options.id] - Unique identifier (auto-generated if not provided)\r\n * @param {string} options.fromNode - Source node ID\r\n * @param {string} options.fromPort - Source port ID\r\n * @param {string} options.toNode - Target node ID\r\n * @param {string} options.toPort - Target port ID\r\n */\r\n constructor({ id, fromNode, fromPort, toNode, toPort }) {\r\n // Allow empty strings for port names (exec ports use empty names)\r\n // Only check for null/undefined\r\n if (fromNode == null || fromPort == null || toNode == null || toPort == null) {\r\n throw new Error(\"Edge requires fromNode, fromPort, toNode, and toPort (null/undefined not allowed)\");\r\n }\r\n this.id = id ?? randomUUID();\r\n this.fromNode = fromNode;\r\n this.fromPort = fromPort;\r\n this.toNode = toNode;\r\n this.toPort = toPort;\r\n }\r\n}\r\n","// src/groups/GroupManager.js\r\n\r\n\r\nexport class GroupManager {\r\n constructor({ graph, hooks }) {\r\n this.graph = graph;\r\n this.hooks = hooks;\r\n this._groups = [];\r\n }\r\n\r\n // ---------- CRUD ----------\r\n addGroup({\r\n title = \"Group\",\r\n x = 0,\r\n y = 0,\r\n width = 240,\r\n height = 160,\r\n color = \"#39424e\",\r\n members = [],\r\n } = {}) {\r\n // Validate parameters\r\n if (width < 100 || height < 60) {\r\n console.warn(\"Group size too small, using minimum size\");\r\n width = Math.max(100, width);\r\n height = Math.max(60, height);\r\n }\r\n\r\n const groupNode = this.graph.addNode(\"core/Group\", {\r\n title,\r\n x,\r\n y,\r\n width,\r\n height,\r\n });\r\n groupNode.state.color = color;\r\n\r\n // Reparent members with validation\r\n for (const memberId of members) {\r\n const node = this.graph.getNodeById(memberId);\r\n if (node) {\r\n if (node.type === \"core/Group\") {\r\n console.warn(`Cannot add group ${memberId} as member of another group`);\r\n continue;\r\n }\r\n this.graph.reparent(node, groupNode);\r\n } else {\r\n console.warn(`Member node ${memberId} not found, skipping`);\r\n }\r\n }\r\n\r\n this._groups.push(groupNode);\r\n this.hooks?.emit(\"group:change\");\r\n return groupNode;\r\n }\r\n\r\n addGroupFromSelection({ _title = \"Group\", _margin = { x: 12, y: 12 } } = {}) {\r\n // Controller에서 selection을 받아와야 함\r\n // 여기서는 간단히 graph.nodes를 순회하며 selected 상태를 확인한다고 가정하거나\r\n // 외부에서 members를 넘겨받는 것이 좋음\r\n // 일단은 외부에서 members를 넘겨받는 addGroup을 활용.\r\n return null;\r\n }\r\n\r\n removeGroup(id) {\r\n const groupNode = this.graph.getNodeById(id);\r\n if (!groupNode || groupNode.type !== \"core/Group\") return;\r\n\r\n // Ungroup: reparent children to group's parent\r\n const children = [...groupNode.children];\r\n for (const child of children) {\r\n this.graph.reparent(child, groupNode.parent);\r\n }\r\n\r\n this.graph.removeNode(id);\r\n this.hooks?.emit(\"group:change\");\r\n }\r\n\r\n // ---------- 이동/리사이즈 ----------\r\n // 이제 Node의 이동/리사이즈 로직을 따름.\r\n // Controller에서 Node 이동 시 updateWorldTransforms가 호출되므로 자동 처리됨.\r\n\r\n resizeGroup(id, dw, dh) {\r\n const g = this.graph.getNodeById(id);\r\n if (!g || g.type !== \"core/Group\") return;\r\n\r\n const minW = 100;\r\n const minH = 60;\r\n g.size.width = Math.max(minW, g.size.width + dw);\r\n g.size.height = Math.max(minH, g.size.height + dh);\r\n\r\n this.graph.updateWorldTransforms();\r\n this.hooks?.emit(\"group:change\");\r\n }\r\n\r\n // ---------- 히트테스트 & 드래그 ----------\r\n // 이제 Group도 Node이므로 Controller의 Node 히트테스트 로직을 따름.\r\n // 단, Resize Handle은 별도 처리가 필요할 수 있음.\r\n\r\n hitTestResizeHandle(x, y) {\r\n const handleSize = 10;\r\n // 역순 순회 (위에 있는 것부터)\r\n const nodes = [...this.graph.nodes.values()].reverse();\r\n\r\n for (const node of nodes) {\r\n if (node.type !== \"core/Group\") continue;\r\n\r\n // World Transform 사용\r\n const { x: gx, y: gy, w: gw, h: gh } = node.computed;\r\n\r\n if (x >= gx + gw - handleSize && x <= gx + gw && y >= gy + gh - handleSize && y <= gy + gh) {\r\n return { group: node, handle: \"se\" };\r\n }\r\n }\r\n return null;\r\n }\r\n}\r\n","import { Node } from \"./Node.js\";\r\nimport { Edge } from \"./Edge.js\";\r\nimport { GroupManager } from \"../groups/GroupManager.js\";\r\n\r\n/**\r\n * Graph manages the collection of nodes and edges\r\n */\r\nexport class Graph {\r\n /**\r\n * Create a new Graph\r\n * @param {Object} options - Graph configuration\r\n * @param {Object} options.hooks - Event hooks system\r\n * @param {Object} options.registry - Node type registry\r\n */\r\n constructor({ hooks, registry }) {\r\n if (!registry) {\r\n throw new Error(\"Graph requires a registry\");\r\n }\r\n this.nodes = new Map();\r\n this.edges = new Map();\r\n this.hooks = hooks;\r\n this.registry = registry;\r\n // double buffer for deterministic cycles\r\n this._valuesA = new Map(); // current\r\n this._valuesB = new Map(); // next\r\n this._useAasCurrent = true;\r\n\r\n this.groupManager = new GroupManager({\r\n graph: this,\r\n hooks: this.hooks,\r\n });\r\n }\r\n /**\r\n * Get a node by its ID\r\n * @param {string} id - Node ID\r\n * @returns {Node|null} The node or null if not found\r\n */\r\n getNodeById(id) {\r\n return this.nodes.get(id) || null;\r\n }\r\n /**\r\n * Add a node to the graph\r\n * @param {string} type - Node type identifier\r\n * @param {Object} [opts={}] - Additional node options (x, y, width, height, etc.)\r\n * @returns {Node} The created node\r\n * @throws {Error} If node type is not registered\r\n */\r\n addNode(type, opts = {}) {\r\n const def = this.registry.types.get(type);\r\n if (!def) {\r\n const available = Array.from(this.registry.types.keys()).join(\", \") || \"none\";\r\n throw new Error(`Unknown node type: \"${type}\". Available types: ${available}`);\r\n }\r\n const node = new Node({\r\n type,\r\n title: def.title,\r\n width: def.size?.w,\r\n height: def.size?.h,\r\n ...opts,\r\n });\r\n for (const i of def.inputs || []) node.addInput(i.name, i.datatype, i.portType || \"data\");\r\n for (const o of def.outputs || []) node.addOutput(o.name, o.datatype, o.portType || \"data\");\r\n def.onCreate?.(node);\r\n this.nodes.set(node.id, node);\r\n this.hooks?.emit(\"node:create\", node);\r\n return node;\r\n }\r\n /**\r\n * Remove a node and its connected edges from the graph\r\n * @param {string} nodeId - ID of the node to remove\r\n */\r\n removeNode(nodeId) {\r\n // Remove all edges connected to this node\r\n for (const [eid, e] of this.edges) {\r\n if (e.fromNode === nodeId || e.toNode === nodeId) {\r\n this.edges.delete(eid);\r\n }\r\n }\r\n this.nodes.delete(nodeId);\r\n }\r\n /**\r\n * Add an edge connecting two node ports\r\n * @param {string} fromNode - Source node ID\r\n * @param {string} fromPort - Source port ID\r\n * @param {string} toNode - Target node ID\r\n * @param {string} toPort - Target port ID\r\n * @returns {Edge} The created edge\r\n * @throws {Error} If nodes don't exist\r\n */\r\n addEdge(fromNode, fromPort, toNode, toPort) {\r\n // Validate nodes exist\r\n if (!this.nodes.has(fromNode)) {\r\n throw new Error(`Cannot create edge: source node \"${fromNode}\" not found`);\r\n }\r\n if (!this.nodes.has(toNode)) {\r\n throw new Error(`Cannot create edge: target node \"${toNode}\" not found`);\r\n }\r\n\r\n const e = new Edge({ fromNode, fromPort, toNode, toPort });\r\n this.edges.set(e.id, e);\r\n this.hooks?.emit(\"edge:create\", e);\r\n return e;\r\n }\r\n\r\n /**\r\n * Clear all nodes and edges from the graph\r\n */\r\n clear() {\r\n this.nodes.clear();\r\n this.edges.clear();\r\n }\r\n\r\n updateWorldTransforms() {\r\n // 1. Find roots\r\n const roots = [];\r\n for (const n of this.nodes.values()) {\r\n if (!n.parent) roots.push(n);\r\n }\r\n\r\n // 2. Traverse\r\n const stack = roots.map((n) => ({ node: n, px: 0, py: 0 }));\r\n while (stack.length > 0) {\r\n const { node, px, py } = stack.pop();\r\n node.computed.x = px + node.pos.x;\r\n node.computed.y = py + node.pos.y;\r\n node.computed.w = node.size.width;\r\n node.computed.h = node.size.height;\r\n\r\n for (const child of node.children) {\r\n stack.push({ node: child, px: node.computed.x, py: node.computed.y });\r\n }\r\n }\r\n }\r\n\r\n reparent(node, newParent) {\r\n if (node.parent === newParent) return;\r\n\r\n // 1. Calculate current world pos\r\n const wx = node.computed.x;\r\n const wy = node.computed.y;\r\n\r\n // 2. Remove from old parent\r\n if (node.parent) {\r\n node.parent.children.delete(node);\r\n }\r\n\r\n // 3. Add to new parent\r\n node.parent = newParent;\r\n if (newParent) {\r\n newParent.children.add(node);\r\n // 4. Calculate new local pos\r\n // world = parentWorld + local => local = world - parentWorld\r\n node.pos.x = wx - newParent.computed.x;\r\n node.pos.y = wy - newParent.computed.y;\r\n } else {\r\n // Root\r\n node.pos.x = wx;\r\n node.pos.y = wy;\r\n }\r\n\r\n this.updateWorldTransforms();\r\n }\r\n\r\n // buffer helpers\r\n _curBuf() {\r\n return this._useAasCurrent ? this._valuesA : this._valuesB;\r\n }\r\n _nextBuf() {\r\n return this._useAasCurrent ? this._valuesB : this._valuesA;\r\n }\r\n swapBuffers() {\r\n // when moving to next cycle, promote next->current and clear next\r\n this._useAasCurrent = !this._useAasCurrent;\r\n this._nextBuf().clear();\r\n }\r\n // data helpers\r\n setOutput(nodeId, portId, value) {\r\n console.log(`[Graph.setOutput] nodeId: ${nodeId}, portId: ${portId}, value:`, value);\r\n const key = `${nodeId}:${portId}`;\r\n this._nextBuf().set(key, value);\r\n }\r\n getInput(nodeId, portId) {\r\n // Find incoming edge to this port\r\n for (const edge of this.edges.values()) {\r\n if (edge.toNode === nodeId && edge.toPort === portId) {\r\n const key = `${edge.fromNode}:${edge.fromPort}`;\r\n const value = this._curBuf().get(key);\r\n console.log(`[Graph.getInput] nodeId: ${nodeId}, portId: ${portId}, reading from ${edge.fromNode}:${edge.fromPort}, value:`, value);\r\n return value;\r\n }\r\n }\r\n console.log(`[Graph.getInput] nodeId: ${nodeId}, portId: ${portId}, no edge found, returning undefined`);\r\n return undefined;\r\n }\r\n toJSON() {\r\n const json = {\r\n nodes: [...this.nodes.values()].map((n) => ({\r\n id: n.id,\r\n type: n.type,\r\n title: n.title,\r\n x: n.pos.x,\r\n y: n.pos.y,\r\n w: n.size.width,\r\n h: n.size.height,\r\n inputs: n.inputs,\r\n outputs: n.outputs,\r\n state: n.state,\r\n parentId: n.parent?.id || null, // Save parent relationship\r\n })),\r\n edges: [...this.edges.values()],\r\n };\r\n this.hooks?.emit(\"graph:serialize\", json);\r\n return json;\r\n }\r\n fromJSON(json) {\r\n this.clear();\r\n\r\n // Restore nodes first\r\n for (const nd of json.nodes) {\r\n const node = new Node({\r\n id: nd.id,\r\n type: nd.type,\r\n title: nd.title,\r\n x: nd.x,\r\n y: nd.y,\r\n width: nd.w,\r\n height: nd.h,\r\n });\r\n // Call onCreate to initialize node with defaults first\r\n const def = this.registry?.types?.get(nd.type);\r\n if (def?.onCreate) {\r\n def.onCreate(node);\r\n }\r\n\r\n node.inputs = nd.inputs;\r\n node.outputs = nd.outputs;\r\n // Merge loaded state over defaults\r\n node.state = { ...node.state, ...(nd.state || {}) };\r\n\r\n this.nodes.set(node.id, node);\r\n }\r\n\r\n // Restore parent-child relationships\r\n for (const nd of json.nodes) {\r\n if (nd.parentId) {\r\n const node = this.nodes.get(nd.id);\r\n const parent = this.nodes.get(nd.parentId);\r\n if (node && parent) {\r\n node.parent = parent;\r\n parent.children.add(node);\r\n }\r\n }\r\n }\r\n\r\n // Restore edges\r\n for (const ed of json.edges) {\r\n this.edges.set(ed.id, new Edge(ed));\r\n }\r\n\r\n // Update world transforms to calculate proper positions\r\n this.updateWorldTransforms();\r\n\r\n this.hooks?.emit(\"graph:deserialize\", json);\r\n\r\n return this;\r\n }\r\n}\r\n","// src/render/hitTest.js\r\nexport function hitTestNode(node, x, y) {\r\n const {\r\n x: nx,\r\n y: ny,\r\n w: width,\r\n h: height,\r\n } = node.computed || {\r\n x: node.pos.x,\r\n y: node.pos.y,\r\n w: node.size.width,\r\n h: node.size.height,\r\n };\r\n return x >= nx && x <= nx + width && y >= ny && y <= ny + height;\r\n}\r\n\r\nexport function portRect(node, port, idx, dir) {\r\n const {\r\n x: nx,\r\n y: ny,\r\n w: width,\r\n h: height,\r\n } = node.computed || {\r\n x: node.pos.x,\r\n y: node.pos.y,\r\n w: node.size.width,\r\n h: node.size.height,\r\n };\r\n\r\n // Fixed spacing\r\n const headerHeight = 28;\r\n const y = ny + headerHeight + 10 + idx * 24;\r\n\r\n // Ports centered on node edges (half inside, half outside)\r\n const portWidth = 12;\r\n const portHeight = 12;\r\n\r\n if (dir === \"in\") {\r\n return { x: nx - portWidth / 2, y: y - portHeight / 2, w: portWidth, h: portHeight };\r\n }\r\n if (dir === \"out\") {\r\n return { x: nx + width - portWidth / 2, y: y - portHeight / 2, w: portWidth, h: portHeight };\r\n }\r\n}\r\n","import { portRect } from \"./hitTest.js\";\r\n\r\nexport class CanvasRenderer {\r\n static FONT_SIZE = 12;\r\n static SELECTED_NODE_COLOR = \"#6cf\";\r\n constructor(canvas, { theme = {}, registry, edgeStyle = \"orthogonal\" } = {}) {\r\n this.canvas = canvas;\r\n this.ctx = canvas.getContext(\"2d\");\r\n this.registry = registry; // to call per-node onDraw\r\n\r\n // viewport transform\r\n this.scale = 1;\r\n this.minScale = 0.25;\r\n this.maxScale = 3;\r\n this.offsetX = 0;\r\n this.offsetY = 0;\r\n\r\n // 'bezier' | 'line' | 'orthogonal'\r\n this.edgeStyle = edgeStyle;\r\n\r\n this.theme = Object.assign(\r\n {\r\n bg: \"#0d0d0f\", // Darker background\r\n grid: \"#1a1a1d\", // Subtle grid\r\n node: \"#16161a\", // Darker nodes\r\n nodeBorder: \"#2a2a2f\", // Subtle border\r\n title: \"#1f1f24\", // Darker header\r\n text: \"#e4e4e7\", // Softer white\r\n textMuted: \"#a1a1aa\", // Muted text\r\n port: \"#6366f1\", // Indigo for data ports\r\n portExec: \"#10b981\", // Emerald for exec ports\r\n edge: \"#52525b\", // Neutral edge color\r\n edgeActive: \"#8b5cf6\", // Purple for active\r\n accent: \"#6366f1\", // Indigo accent\r\n accentBright: \"#818cf8\", // Brighter accent\r\n },\r\n theme\r\n );\r\n }\r\n setEdgeStyle(style) {\r\n this.edgeStyle = style === \"line\" || style === \"orthogonal\" ? style : \"bezier\";\r\n }\r\n setRegistry(reg) {\r\n this.registry = reg;\r\n }\r\n resize(w, h) {\r\n this.canvas.width = w;\r\n this.canvas.height = h;\r\n }\r\n setTransform({ scale = this.scale, offsetX = this.offsetX, offsetY = this.offsetY } = {}) {\r\n this.scale = Math.min(this.maxScale, Math.max(this.minScale, scale));\r\n this.offsetX = offsetX;\r\n this.offsetY = offsetY;\r\n // Trigger callback to sync HTML overlay transform\r\n this._onTransformChange?.();\r\n }\r\n\r\n /**\r\n * Set callback to be called when transform changes (zoom/pan)\r\n * @param {Function} callback - Function to call on transform change\r\n */\r\n setTransformChangeCallback(callback) {\r\n this._onTransformChange = callback;\r\n }\r\n panBy(dx, dy) {\r\n this.offsetX += dx;\r\n this.offsetY += dy;\r\n // Trigger callback to sync HTML overlay transform\r\n this._onTransformChange?.();\r\n }\r\n zoomAt(factor, cx, cy) {\r\n // factor > 1 zoom in, < 1 zoom out, centered at screen point (cx, cy)\r\n const prev = this.scale;\r\n const next = Math.min(this.maxScale, Math.max(this.minScale, prev * factor));\r\n if (next === prev) return;\r\n // keep the world point under cursor fixed: adjust offset\r\n const wx = (cx - this.offsetX) / prev;\r\n const wy = (cy - this.offsetY) / prev;\r\n this.offsetX = cx - wx * next;\r\n this.offsetY = cy - wy * next;\r\n this.scale = next;\r\n // Trigger callback to sync HTML overlay transform\r\n this._onTransformChange?.();\r\n }\r\n\r\n screenToWorld(x, y) {\r\n return {\r\n x: (x - this.offsetX) / this.scale,\r\n y: (y - this.offsetY) / this.scale,\r\n };\r\n }\r\n worldToScreen(x, y) {\r\n return {\r\n x: x * this.scale + this.offsetX,\r\n y: y * this.scale + this.offsetY,\r\n };\r\n }\r\n _applyTransform() {\r\n const { ctx } = this;\r\n // CRITICAL: Must match HTMLOverlay transformation order (translate then scale)\r\n ctx.setTransform(1, 0, 0, 1, 0, 0); // Reset first\r\n ctx.translate(this.offsetX, this.offsetY);\r\n ctx.scale(this.scale, this.scale);\r\n }\r\n _resetTransform() {\r\n this.ctx.setTransform(1, 0, 0, 1, 0, 0);\r\n }\r\n\r\n // ── Drawing ────────────────────────────────────────────────────────────────\r\n _drawArrowhead(x1, y1, x2, y2, size = 10) {\r\n const { ctx } = this;\r\n const s = size / this.scale; // 줌에 따라 크기 보정\r\n const ang = Math.atan2(y2 - y1, x2 - x1);\r\n\r\n ctx.beginPath();\r\n ctx.moveTo(x2, y2);\r\n ctx.lineTo(x2 - s * Math.cos(ang - Math.PI / 6), y2 - s * Math.sin(ang - Math.PI / 6));\r\n ctx.lineTo(x2 - s * Math.cos(ang + Math.PI / 6), y2 - s * Math.sin(ang + Math.PI / 6));\r\n ctx.closePath();\r\n ctx.fill(); // 선 색상과 동일한 fill이 자연스러움\r\n }\r\n\r\n _drawScreenText(\r\n text,\r\n lx,\r\n ly,\r\n {\r\n fontPx = 12,\r\n color = this.theme.text,\r\n align = \"left\",\r\n baseline = \"alphabetic\",\r\n dpr = 1, // 추후 devicePixelRatio 도입\r\n } = {}\r\n ) {\r\n const { ctx } = this;\r\n const { x: sx, y: sy } = this.worldToScreen(lx, ly);\r\n\r\n ctx.save();\r\n // 화면 좌표계(스케일=1)로 리셋\r\n this._resetTransform();\r\n\r\n // 픽셀 스냅(번짐 방지)\r\n const px = Math.round(sx) + 0.5;\r\n const py = Math.round(sy) + 0.5;\r\n\r\n ctx.font = `${fontPx * this.scale}px system-ui`;\r\n ctx.fillStyle = color;\r\n ctx.textAlign = align;\r\n ctx.textBaseline = baseline;\r\n ctx.fillText(text, px, py);\r\n ctx.restore();\r\n }\r\n\r\n drawGrid() {\r\n const { ctx, canvas, theme, scale, offsetX, offsetY } = this;\r\n // clear screen in screen space\r\n\r\n this._resetTransform();\r\n ctx.fillStyle = theme.bg;\r\n ctx.fillRect(0, 0, canvas.width, canvas.height);\r\n\r\n // draw grid in world space so it pans/zooms\r\n this._applyTransform();\r\n // Make grid subtle but visible\r\n ctx.strokeStyle = this._rgba(theme.grid, 0.35); // Subtle but visible\r\n ctx.lineWidth = 1 / scale; // keep 1px apparent\r\n\r\n const base = 20; // world units\r\n const step = base;\r\n\r\n // visible world bounds\r\n const x0 = -offsetX / scale;\r\n const y0 = -offsetY / scale;\r\n const x1 = (canvas.width - offsetX) / scale;\r\n const y1 = (canvas.height - offsetY) / scale;\r\n\r\n const startX = Math.floor(x0 / step) * step;\r\n const startY = Math.floor(y0 / step) * step;\r\n\r\n ctx.beginPath();\r\n for (let x = startX; x <= x1; x += step) {\r\n ctx.moveTo(x, y0);\r\n ctx.lineTo(x, y1);\r\n }\r\n for (let y = startY; y <= y1; y += step) {\r\n ctx.moveTo(x0, y);\r\n ctx.lineTo(x1, y);\r\n }\r\n ctx.stroke();\r\n\r\n this._resetTransform();\r\n }\r\n\r\n draw(\r\n graph,\r\n {\r\n selection = new Set(),\r\n tempEdge = null,\r\n running = false,\r\n time = performance.now(),\r\n dt = 0,\r\n groups = null,\r\n activeEdges = new Set(),\r\n drawEdges = true,\r\n } = {}\r\n ) {\r\n // Update transforms first\r\n graph.updateWorldTransforms();\r\n\r\n this.drawGrid();\r\n const { ctx, theme } = this;\r\n this._applyTransform();\r\n\r\n ctx.save();\r\n\r\n // 1. Draw Groups (Backgrounds)\r\n for (const n of graph.nodes.values()) {\r\n if (n.type === \"core/Group\") {\r\n const sel = selection.has(n.id);\r\n const def = this.registry?.types?.get(n.type);\r\n if (def?.onDraw) def.onDraw(n, { ctx, theme, renderer: this });\r\n else this._drawNode(n, sel);\r\n }\r\n }\r\n\r\n // 2. Draw Edges (conditionally - can be skipped for port canvas rendering)\r\n if (drawEdges) {\r\n ctx.lineWidth = 1.5 / this.scale;\r\n\r\n // Calculate animation values if running\r\n let dashArray = null;\r\n let dashOffset = 0;\r\n if (running) {\r\n const speed = 120;\r\n const phase = (((time / 1000) * speed) / this.scale) % CanvasRenderer.FONT_SIZE;\r\n dashArray = [6 / this.scale, 6 / this.scale];\r\n dashOffset = -phase;\r\n }\r\n\r\n for (const e of graph.edges.values()) {\r\n const shouldAnimate = activeEdges && activeEdges.size > 0 && activeEdges.has(e.id);\r\n\r\n if (running && shouldAnimate && dashArray) {\r\n ctx.setLineDash(dashArray);\r\n ctx.lineDashOffset = dashOffset;\r\n } else {\r\n ctx.setLineDash([]);\r\n ctx.lineDashOffset = 0;\r\n }\r\n\r\n const isActive = activeEdges && activeEdges.has(e.id);\r\n if (isActive) {\r\n ctx.strokeStyle = \"#00ffff\";\r\n ctx.lineWidth = 3 / this.scale;\r\n } else {\r\n ctx.strokeStyle = theme.edge;\r\n ctx.lineWidth = 1.5 / this.scale;\r\n }\r\n this._drawEdge(graph, e);\r\n }\r\n }\r\n\r\n // temp edge preview\r\n if (tempEdge) {\r\n const a = this.screenToWorld(tempEdge.x1, tempEdge.y1);\r\n const b = this.screenToWorld(tempEdge.x2, tempEdge.y2);\r\n\r\n const prevDash = this.ctx.getLineDash();\r\n this.ctx.setLineDash([6 / this.scale, 6 / this.scale]);\r\n\r\n let ptsForArrow = null;\r\n if (this.edgeStyle === \"line\") {\r\n this._drawLine(a.x, a.y, b.x, b.y);\r\n ptsForArrow = [\r\n { x: a.x, y: a.y },\r\n { x: b.x, y: b.y },\r\n ];\r\n } else if (this.edgeStyle === \"orthogonal\") {\r\n ptsForArrow = this._drawOrthogonal(a.x, a.y, b.x, b.y);\r\n } else {\r\n this._drawCurve(a.x, a.y, b.x, b.y);\r\n ptsForArrow = [\r\n { x: a.x, y: a.y },\r\n { x: b.x, y: b.y },\r\n ];\r\n }\r\n\r\n this.ctx.setLineDash(prevDash);\r\n\r\n if (ptsForArrow && ptsForArrow.length >= 2) {\r\n const p1 = ptsForArrow[ptsForArrow.length - 2];\r\n const p2 = ptsForArrow[ptsForArrow.length - 1];\r\n this.ctx.fillStyle = this.theme.edge;\r\n this.ctx.strokeStyle = this.theme.edge; // Ensure color is set\r\n this._drawArrowhead(p1.x, p1.y, p2.x, p2.y, 12);\r\n }\r\n }\r\n\r\n // 3. Draw Other Nodes (AFTER edges)\r\n // For nodes with HTML overlays, SKIP canvas rendering entirely\r\n for (const n of graph.nodes.values()) {\r\n if (n.type !== \"core/Group\") {\r\n const sel = selection.has(n.id);\r\n const def = this.registry?.types?.get(n.type);\r\n const hasHtmlOverlay = !!def?.html;\r\n\r\n // Only draw node body on canvas if it DOESN'T have HTML overlay\r\n if (!hasHtmlOverlay) {\r\n this._drawNode(n, sel, true); // Draw WITHOUT ports (drawn on port canvas)\r\n if (def?.onDraw) def.onDraw(n, { ctx, theme, renderer: this });\r\n }\r\n }\r\n }\r\n\r\n // 4. Draw ports for HTML overlay nodes LAST (so they appear above HTML)\r\n for (const n of graph.nodes.values()) {\r\n if (n.type !== \"core/Group\") {\r\n const def = this.registry?.types?.get(n.type);\r\n const hasHtmlOverlay = !!def?.html;\r\n\r\n if (hasHtmlOverlay) {\r\n this._drawPorts(n);\r\n }\r\n }\r\n }\r\n\r\n this._resetTransform();\r\n }\r\n\r\n _rgba(hex, a) {\r\n const c = hex.replace(\"#\", \"\");\r\n const n = parseInt(\r\n c.length === 3\r\n ? c\r\n .split(\"\")\r\n .map((x) => x + x)\r\n .join(\"\")\r\n : c,\r\n 16\r\n );\r\n const r = (n >> 16) & 255,\r\n g = (n >> 8) & 255,\r\n b = n & 255;\r\n return `rgba(${r},${g},${b},${a})`;\r\n }\r\n\r\n _drawNode(node, selected, skipPorts = false) {\r\n const { ctx, theme } = this;\r\n const r = 8;\r\n const { x, y, w, h } = node.computed;\r\n\r\n // Draw subtle shadow\r\n if (!selected) {\r\n ctx.save();\r\n ctx.shadowColor = \"rgba(0, 0, 0, 0.3)\";\r\n ctx.shadowBlur = 8 / this.scale;\r\n ctx.shadowOffsetY = 2 / this.scale;\r\n ctx.fillStyle = \"rgba(0, 0, 0, 0.2)\";\r\n roundRect(ctx, x, y, w, h, r);\r\n ctx.fill();\r\n ctx.restore();\r\n }\r\n\r\n // Draw main body\r\n ctx.fillStyle = theme.node;\r\n ctx.strokeStyle = selected ? theme.accentBright : theme.nodeBorder;\r\n ctx.lineWidth = (selected ? 1.5 : 1) / this.scale;\r\n roundRect(ctx, x, y, w, h, r);\r\n ctx.fill();\r\n ctx.stroke();\r\n\r\n // Draw header\r\n ctx.fillStyle = theme.title;\r\n roundRect(ctx, x, y, w, 24, { tl: r, tr: r, br: 0, bl: 0 });\r\n ctx.fill();\r\n\r\n // Header border (only top and sides)\r\n ctx.strokeStyle = selected ? theme.accentBright : theme.nodeBorder;\r\n ctx.lineWidth = (selected ? 1.5 : 1) / this.scale;\r\n ctx.beginPath();\r\n // Top-left corner to top-right corner\r\n ctx.moveTo(x + r, y);\r\n ctx.lineTo(x + w - r, y);\r\n ctx.quadraticCurveTo(x + w, y, x + w, y + r);\r\n // Right side down to header bottom\r\n ctx.lineTo(x + w, y + 24);\r\n // Move to left side header bottom\r\n ctx.moveTo(x, y + 24);\r\n // Left side up to top-left corner\r\n ctx.lineTo(x, y + r);\r\n ctx.quadraticCurveTo(x, y, x + r, y);\r\n ctx.stroke();\r\n\r\n this._drawScreenText(node.title, x + 8, y + CanvasRenderer.FONT_SIZE, {\r\n fontPx: CanvasRenderer.FONT_SIZE,\r\n color: theme.text,\r\n baseline: \"middle\",\r\n align: \"left\",\r\n });\r\n\r\n // Skip port drawing if requested (for HTML overlay nodes)\r\n if (skipPorts) return;\r\n\r\n // Draw input ports\r\n node.inputs.forEach((p, i) => {\r\n const rct = portRect(node, p, i, \"in\");\r\n const cx = rct.x + rct.w / 2;\r\n const cy = rct.y + rct.h / 2;\r\n\r\n if (p.portType === \"exec\") {\r\n // Draw exec port - rounded square\r\n const portSize = 8;\r\n ctx.fillStyle = theme.portExec;\r\n ctx.strokeStyle = \"rgba(16, 185, 129, 0.3)\";\r\n ctx.lineWidth = 2 / this.scale;\r\n ctx.beginPath();\r\n ctx.roundRect(cx - portSize / 2, cy - portSize / 2, portSize, portSize, 2);\r\n ctx.fill();\r\n ctx.stroke();\r\n } else {\r\n // Draw data port - circle with outline\r\n ctx.fillStyle = theme.port;\r\n ctx.strokeStyle = \"rgba(99, 102, 241, 0.3)\";\r\n ctx.lineWidth = 2 / this.scale;\r\n ctx.beginPath();\r\n ctx.arc(cx, cy, 5, 0, Math.PI * 2);\r\n ctx.fill();\r\n ctx.stroke();\r\n }\r\n });\r\n\r\n // Draw output ports\r\n node.outputs.forEach((p, i) => {\r\n const rct = portRect(node, p, i, \"out\");\r\n const cx = rct.x + rct.w / 2;\r\n const cy = rct.y + rct.h / 2;\r\n\r\n if (p.portType === \"exec\") {\r\n // Draw exec port - rounded square\r\n const portSize = 8;\r\n ctx.fillStyle = theme.portExec;\r\n ctx.strokeStyle = \"rgba(16, 185, 129, 0.3)\";\r\n ctx.lineWidth = 2 / this.scale;\r\n ctx.beginPath();\r\n ctx.roundRect(cx - portSize / 2, cy - portSize / 2, portSize, portSize, 2);\r\n ctx.fill();\r\n ctx.stroke();\r\n } else {\r\n // Draw data port - circle with outline\r\n ctx.fillStyle = theme.port;\r\n ctx.strokeStyle = \"rgba(99, 102, 241, 0.3)\";\r\n ctx.lineWidth = 2 / this.scale;\r\n ctx.beginPath();\r\n ctx.arc(cx, cy, 5, 0, Math.PI * 2);\r\n ctx.fill();\r\n ctx.stroke();\r\n }\r\n });\r\n }\r\n\r\n _drawPorts(node) {\r\n const { ctx, theme } = this;\r\n\r\n // Draw input ports\r\n node.inputs.forEach((p, i) => {\r\n const rct = portRect(node, p, i, \"in\");\r\n const cx = rct.x + rct.w / 2;\r\n const cy = rct.y + rct.h / 2;\r\n\r\n if (p.portType === \"exec\") {\r\n // Draw exec port - rounded square with subtle glow\r\n const portSize = 8;\r\n ctx.fillStyle = theme.portExec;\r\n ctx.strokeStyle = \"rgba(16, 185, 129, 0.3)\";\r\n ctx.lineWidth = 2 / this.scale;\r\n ctx.beginPath();\r\n ctx.roundRect(cx - portSize / 2, cy - portSize / 2, portSize, portSize, 2);\r\n ctx.fill();\r\n ctx.stroke();\r\n } else {\r\n // Draw data port - circle with subtle outline\r\n ctx.fillStyle = theme.port;\r\n ctx.strokeStyle = \"rgba(99, 102, 241, 0.3)\";\r\n ctx.lineWidth = 2 / this.scale;\r\n ctx.beginPath();\r\n ctx.arc(cx, cy, 5, 0, Math.PI * 2);\r\n ctx.fill();\r\n }\r\n });\r\n\r\n // Draw output ports\r\n node.outputs.forEach((p, i) => {\r\n const rct = portRect(node, p, i, \"out\");\r\n const cx = rct.x + rct.w / 2;\r\n const cy = rct.y + rct.h / 2;\r\n\r\n if (p.portType === \"exec\") {\r\n // Draw exec port - rounded square\r\n const portSize = 8;\r\n ctx.fillStyle = theme.portExec;\r\n ctx.strokeStyle = \"rgba(16, 185, 129, 0.3)\";\r\n ctx.lineWidth = 2 / this.scale;\r\n ctx.beginPath();\r\n ctx.roundRect(cx - portSize / 2, cy - portSize / 2, portSize, portSize, 2);\r\n ctx.fill();\r\n ctx.stroke();\r\n } else {\r\n // Draw data port - circle with outline\r\n ctx.fillStyle = theme.port;\r\n ctx.strokeStyle = \"rgba(99, 102, 241, 0.3)\";\r\n ctx.lineWidth = 2 / this.scale;\r\n ctx.beginPath();\r\n ctx.arc(cx, cy, 5, 0, Math.PI * 2);\r\n ctx.fill();\r\n ctx.stroke();\r\n }\r\n });\r\n }\r\n\r\n _drawEdge(graph, e) {\r\n const from = graph.nodes.get(e.fromNode);\r\n const to = graph.nodes.get(e.toNode);\r\n if (!from || !to) return;\r\n const iOut = from.outputs.findIndex((p) => p.id === e.fromPort);\r\n const iIn = to.inputs.findIndex((p) => p.id === e.toPort);\r\n const pr1 = portRect(from, null, iOut, \"out\");\r\n const pr2 = portRect(to, null, iIn, \"in\");\r\n const x1 = pr1.x + pr1.w / 2,\r\n y1 = pr1.y + pr1.h / 2, // Center of port\r\n x2 = pr2.x + pr2.w / 2,\r\n y2 = pr2.y + pr2.h / 2; // Center of port\r\n if (this.edgeStyle === \"line\") {\r\n this._drawLine(x1, y1, x2, y2);\r\n } else if (this.edgeStyle === \"orthogonal\") {\r\n this._drawOrthogonal(x1, y1, x2, y2);\r\n } else {\r\n this._drawCurve(x1, y1, x2, y2); // bezier (기존)\r\n }\r\n }\r\n\r\n _drawLine(x1, y1, x2, y2) {\r\n const { ctx } = this;\r\n ctx.beginPath();\r\n ctx.moveTo(x1, y1);\r\n ctx.lineTo(x2, y2);\r\n ctx.stroke();\r\n }\r\n\r\n _drawPolyline(points) {\r\n const { ctx } = this;\r\n ctx.beginPath();\r\n ctx.moveTo(points[0].x, points[0].y);\r\n for (let i = 1; i < points.length; i++) ctx.lineTo(points[i].x, points[i].y);\r\n ctx.stroke();\r\n }\r\n\r\n _drawOrthogonal(x1, y1, x2, y2) {\r\n // 중간 축을 결정 (더 짧은 축을 가운데에 두면 보기 좋음)\r\n const useHVH = true; // 가로-세로-가로(HVH) vs 세로-가로-세로(VHV)\r\n const midX = (x1 + x2) / 2;\r\n const midY = (y1 + y2) / 2;\r\n\r\n let pts;\r\n if (useHVH) {\r\n // x1,y1 → midX,y1 → midX,y2 → x2,y2\r\n pts = [\r\n { x: x1, y: y1 },\r\n { x: midX, y: y1 },\r\n { x: midX, y: y2 },\r\n { x: x2, y: y2 },\r\n ];\r\n }\r\n // else {\r\n // // x1,y1 → x1,midY → x2,midY → x2,y2\r\n // pts = [\r\n // { x: x1, y: y1 },\r\n // { x: x1, y: midY },\r\n // { x: x2, y: midY },\r\n // { x: x2, y: y2 },\r\n // ];\r\n // }\r\n\r\n // 라운드 코너\r\n const { ctx } = this;\r\n const prevJoin = ctx.lineJoin,\r\n prevCap = ctx.lineCap;\r\n ctx.lineJoin = \"round\";\r\n ctx.lineCap = \"round\";\r\n this._drawPolyline(pts);\r\n ctx.lineJoin = prevJoin;\r\n ctx.lineCap = prevCap;\r\n\r\n return pts; // 화살표 각도 계산에 사용\r\n }\r\n _drawCurve(x1, y1, x2, y2) {\r\n const { ctx } = this;\r\n const dx = Math.max(40, Math.abs(x2 - x1) * 0.4);\r\n ctx.beginPath();\r\n ctx.moveTo(x1, y1);\r\n ctx.bezierCurveTo(x1 + dx, y1, x2 - dx, y2, x2, y2);\r\n ctx.stroke();\r\n }\r\n\r\n /**\r\n * Draw only edges on a separate canvas (for layering above HTML overlay)\r\n * @param {Graph} graph - The graph\r\n * @param {Object} options - Rendering options\r\n */\r\n drawEdgesOnly(\r\n graph,\r\n { activeEdges = new Set(), running = false, time = performance.now(), tempEdge = null } = {}\r\n ) {\r\n // Clear canvas\r\n this._resetTransform();\r\n this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);\r\n\r\n this._applyTransform();\r\n\r\n const { ctx, theme } = this;\r\n\r\n // Calculate animation values\r\n let dashArray = null;\r\n let dashOffset = 0;\r\n if (running || activeEdges.size > 0) {\r\n const speed = 120;\r\n const phase = (((time / 1000) * speed) / this.scale) % 12;\r\n dashArray = [6 / this.scale, 6 / this.scale];\r\n dashOffset = -phase;\r\n }\r\n\r\n // Draw all edges\r\n ctx.lineWidth = 1.5 / this.scale;\r\n // Set default edge style\r\n ctx.strokeStyle = theme.edge;\r\n for (const e of graph.edges.values()) {\r\n const isActive = activeEdges && activeEdges.has(e.id);\r\n\r\n if (isActive && dashArray) {\r\n ctx.setLineDash(dashArray);\r\n ctx.lineDashOffset = dashOffset;\r\n ctx.strokeStyle = \"#00ffff\";\r\n ctx.lineWidth = 3 / this.scale;\r\n } else {\r\n ctx.setLineDash([]);\r\n ctx.strokeStyle = theme.edge;\r\n ctx.lineWidth = 1.5 / this.scale;\r\n }\r\n\r\n this._drawEdge(graph, e);\r\n }\r\n\r\n // temp edge preview\r\n if (tempEdge) {\r\n const a = this.screenToWorld(tempEdge.x1, tempEdge.y1);\r\n const b = this.screenToWorld(tempEdge.x2, tempEdge.y2);\r\n\r\n const prevDash = this.ctx.getLineDash();\r\n this.ctx.setLineDash([6 / this.scale, 6 / this.scale]);\r\n\r\n let ptsForArrow = null;\r\n if (this.edgeStyle === \"line\") {\r\n this._drawLine(a.x, a.y, b.x, b.y);\r\n ptsForArrow = [\r\n { x: a.x, y: a.y },\r\n { x: b.x, y: b.y },\r\n ];\r\n } else if (this.edgeStyle === \"orthogonal\") {\r\n ptsForArrow = this._drawOrthogonal(a.x, a.y, b.x, b.y);\r\n } else {\r\n this._drawCurve(a.x, a.y, b.x, b.y);\r\n ptsForArrow = [\r\n { x: a.x, y: a.y },\r\n { x: b.x, y: b.y },\r\n ];\r\n }\r\n\r\n this.ctx.setLineDash(prevDash);\r\n\r\n if (ptsForArrow && ptsForArrow.length >= 2) {\r\n const p1 = ptsForArrow[ptsForArrow.length - 2];\r\n const p2 = ptsForArrow[ptsForArrow.length - 1];\r\n this.ctx.fillStyle = this.theme.edge;\r\n this.ctx.strokeStyle = this.theme.edge; // Ensure color is set\r\n this._drawArrowhead(p1.x, p1.y, p2.x, p2.y, 12);\r\n }\r\n }\r\n\r\n this._resetTransform();\r\n }\r\n}\r\nfunction roundRect(ctx, x, y, w, h, r = 6) {\r\n if (typeof r === \"number\") r = { tl: r, tr: r, br: r, bl: r };\r\n ctx.beginPath();\r\n ctx.moveTo(x + r.tl, y);\r\n ctx.lineTo(x + w - r.tr, y);\r\n ctx.quadraticCurveTo(x + w, y, x + w, y + r.tr);\r\n ctx.lineTo(x + w, y + h - r.br);\r\n ctx.quadraticCurveTo(x + w, y + h, x + w - r.br, y + h);\r\n ctx.lineTo(x + r.bl, y + h);\r\n ctx.quadraticCurveTo(x, y + h, x, y + h - r.bl);\r\n ctx.lineTo(x, y + r.tl);\r\n ctx.quadraticCurveTo(x, y, x + r.tl, y);\r\n ctx.closePath();\r\n}\r\n","// Find an edge id by its endpoints (fallback for undo)\r\nfunction findEdgeId(graph, a, b, c, d) {\r\n for (const [id, e] of graph.edges) {\r\n if (\r\n e.fromNode === a &&\r\n e.fromPort === b &&\r\n e.toNode === c &&\r\n e.toPort === d\r\n )\r\n return id;\r\n }\r\n return null;\r\n}\r\n\r\nexport function MoveNodeCmd(node, fromPos, toPos) {\r\n return {\r\n do() {\r\n node.pos = { ...toPos };\r\n },\r\n undo() {\r\n node.pos = { ...fromPos };\r\n },\r\n };\r\n}\r\n\r\nexport function AddEdgeCmd(graph, fromNode, fromPort, toNode, toPort) {\r\n let addedId = null;\r\n return {\r\n do() {\r\n graph.addEdge(fromNode, fromPort, toNode, toPort);\r\n addedId = findEdgeId(graph, fromNode, fromPort, toNode, toPort);\r\n },\r\n undo() {\r\n const id =\r\n addedId ?? findEdgeId(graph, fromNode, fromPort, toNode, toPort);\r\n if (id != null) graph.edges.delete(id);\r\n },\r\n };\r\n}\r\n\r\nexport function RemoveEdgeCmd(graph, edgeId) {\r\n const e = graph.edges.get(edgeId);\r\n if (!e) return null;\r\n // capture for undo\r\n const { fromNode, fromPort, toNode, toPort } = e;\r\n return {\r\n do() {\r\n graph.edges.delete(edgeId);\r\n },\r\n undo() {\r\n graph.addEdge(fromNode, fromPort, toNode, toPort);\r\n },\r\n };\r\n}\r\n\r\n// Optional: group multiple commands as one (used for \"rewire\")\r\nexport function CompoundCmd(cmds) {\r\n return {\r\n do() {\r\n cmds.forEach((c) => c?.do());\r\n },\r\n undo() {\r\n [...cmds].reverse().forEach((c) => c?.undo());\r\n },\r\n };\r\n}\r\n\r\nexport function RemoveNodeCmd(graph, node) {\r\n let removedNode = null;\r\n let removedEdges = [];\r\n\r\n return {\r\n do() {\r\n // Store the node and its connected edges for undo\r\n removedNode = node;\r\n removedEdges = graph.edges\r\n ? [...graph.edges.values()].filter((e) => {\r\n return e.fromNode === node.id || e.toNode === node.id;\r\n })\r\n : [];\r\n\r\n // Remove edges first\r\n for (const edge of removedEdges) {\r\n graph.edges.delete(edge.id);\r\n }\r\n // Remove the node\r\n graph.nodes.delete(node.id);\r\n },\r\n\r\n undo() {\r\n // Restore node\r\n if (removedNode) {\r\n graph.nodes.set(removedNode.id, removedNode);\r\n }\r\n // Restore edges\r\n for (const edge of removedEdges) {\r\n graph.edges.set(edge.id, edge);\r\n }\r\n },\r\n };\r\n}\r\n\r\nexport function ResizeNodeCmd(node, fromSize, toSize) {\r\n return {\r\n do() {\r\n node.size.width = toSize.w;\r\n node.size.height = toSize.h;\r\n },\r\n undo() {\r\n node.size.width = fromSize.w;\r\n node.size.height = fromSize.h;\r\n },\r\n };\r\n}\r\n\r\nexport function ChangeGroupColorCmd(node, fromColor, toColor) {\r\n return {\r\n do() {\r\n node.state.color = toColor;\r\n },\r\n undo() {\r\n node.state.color = fromColor;\r\n },\r\n };\r\n}\r\n","// src/core/CommandStack.js\r\nexport class CommandStack {\r\n constructor() {\r\n this.undoStack = [];\r\n this.redoStack = [];\r\n }\r\n exec(cmd) {\r\n cmd.do();\r\n this.undoStack.push(cmd);\r\n this.redoStack.length = 0;\r\n }\r\n undo() {\r\n const c = this.undoStack.pop();\r\n if (c) {\r\n c.undo();\r\n this.redoStack.push(c);\r\n }\r\n }\r\n redo() {\r\n const c = this.redoStack.pop();\r\n if (c) {\r\n c.do();\r\n this.undoStack.push(c);\r\n }\r\n }\r\n}\r\n","import { portRect } from \"../render/hitTest.js\";\r\nimport { AddEdgeCmd, RemoveEdgeCmd, RemoveNodeCmd, ResizeNodeCmd } from \"../core/commands.js\";\r\nimport { CommandStack } from \"../core/CommandStack.js\";\r\n\r\nexport class Controller {\r\n static MIN_NODE_WIDTH = 80;\r\n static MIN_NODE_HEIGHT = 60;\r\n\r\n constructor({ graph, renderer, hooks, htmlOverlay, contextMenu, edgeRenderer, portRenderer }) {\r\n this.graph = graph;\r\n this.renderer = renderer;\r\n this.hooks = hooks;\r\n this.htmlOverlay = htmlOverlay;\r\n this.contextMenu = contextMenu;\r\n this.edgeRenderer = edgeRenderer; // Separate renderer for edges/animations above HTML\r\n this.portRenderer = portRenderer; // Separate renderer for ports above HTML\r\n\r\n this.stack = new CommandStack();\r\n this.selection = new Set();\r\n this.dragging = null; // { nodeId, dx, dy }\r\n this.connecting = null; // { fromNode, fromPort, x(screen), y(screen) }\r\n this.panning = null; // { x(screen), y(screen) }\r\n this.resizing = null;\r\n this.gDragging = null;\r\n this.gResizing = null;\r\n this.boxSelecting = null; // { startX, startY, currentX, currentY } - world coords\r\n\r\n // Feature flags\r\n this.snapToGrid = true; // Snap nodes to grid (toggle with G key)\r\n this.gridSize = 20; // Grid size for snapping\r\n\r\n this._cursor = \"default\";\r\n\r\n this._onKeyPressEvt = this._onKeyPress.bind(this);\r\n this._onDownEvt = this._onDown.bind(this);\r\n this._onWheelEvt = this._onWheel.bind(this);\r\n this._onMoveEvt = this._onMove.bind(this);\r\n this._onUpEvt = this._onUp.bind(this);\r\n this._onContextMenuEvt = this._onContextMenu.bind(this);\r\n this._onDblClickEvt = this._onDblClick.bind(this);\r\n\r\n this._bindEvents();\r\n }\r\n\r\n destroy() {\r\n const c = this.renderer.canvas;\r\n c.removeEventListener(\"mousedown\", this._onDownEvt);\r\n c.removeEventListener(\"dblclick\", this._onDblClickEvt);\r\n c.removeEventListener(\"wheel\", this._onWheelEvt, { passive: false });\r\n c.removeEventListener(\"contextmenu\", this._onContextMenuEvt);\r\n window.removeEventListener(\"mousemove\", this._onMoveEvt);\r\n window.removeEventListener(\"mouseup\", this._onUpEvt);\r\n window.removeEventListener(\"keydown\", this._onKeyPressEvt);\r\n }\r\n\r\n _bindEvents() {\r\n const c = this.renderer.canvas;\r\n c.addEventListener(\"mousedown\", this._onDownEvt);\r\n c.addEventListener(\"dblclick\", this._onDblClickEvt);\r\n c.addEventListener(\"wheel\", this._onWheelEvt, { passive: false });\r\n c.addEventListener(\"contextmenu\", this._onContextMenuEvt);\r\n window.addEventListener(\"mousemove\", this._onMoveEvt);\r\n window.addEventListener(\"mouseup\", this._onUpEvt);\r\n window.addEventListener(\"keydown\", this._onKeyPressEvt);\r\n }\r\n\r\n _onKeyPress(e) {\r\n this.isAlt = e.altKey;\r\n this.isShift = e.shiftKey;\r\n this.isCtrl = e.ctrlKey;\r\n\r\n // Toggle snap-to-grid with G key\r\n if (e.key.toLowerCase() === \"g\" && !e.ctrlKey && !e.metaKey) {\r\n this.snapToGrid = !this.snapToGrid;\r\n this.render(); // Update UI\r\n return;\r\n }\r\n\r\n // Group selected nodes: Ctrl/Cmd + G\r\n if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === \"g\") {\r\n e.preventDefault();\r\n this._createGroupFromSelection();\r\n return;\r\n }\r\n\r\n // Undo: Ctrl/Cmd + Z (Shift+Z → Redo)\r\n if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === \"z\") {\r\n e.preventDefault();\r\n if (e.shiftKey) this.stack.redo();\r\n else this.stack.undo();\r\n this.render();\r\n return;\r\n }\r\n\r\n // Redo: Ctrl/Cmd + Y\r\n if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === \"y\") {\r\n e.preventDefault();\r\n this.stack.redo();\r\n this.render();\r\n return;\r\n }\r\n\r\n // Align nodes: A (horizontal), Shift+A (vertical)\r\n if (e.key.toLowerCase() === \"a\" && this.selection.size > 1) {\r\n e.preventDefault();\r\n if (e.shiftKey) {\r\n this._alignNodesVertical();\r\n } else {\r\n this._alignNodesHorizontal();\r\n }\r\n return;\r\n }\r\n\r\n // remove the selected nodes\r\n if (e.key === \"Delete\") {\r\n [...this.selection].forEach((node) => {\r\n const nodeObj = this.graph.getNodeById(node);\r\n this.stack.exec(RemoveNodeCmd(this.graph, nodeObj));\r\n this.graph.removeNode(node);\r\n });\r\n\r\n this.render();\r\n }\r\n }\r\n\r\n _setCursor(c) {\r\n if (this._cursor !== c) {\r\n this._cursor = c;\r\n this.renderer.canvas.style.cursor = c;\r\n }\r\n }\r\n\r\n _posScreen(e) {\r\n const r = this.renderer.canvas.getBoundingClientRect();\r\n return { x: e.clientX - r.left, y: e.clientY - r.top };\r\n }\r\n\r\n _posWorld(e) {\r\n const s = this._posScreen(e);\r\n return this.renderer.screenToWorld(s.x, s.y);\r\n }\r\n\r\n _findNodeAtWorld(x, y) {\r\n // Reverse order (top to bottom)\r\n const list = [...this.graph.nodes.values()].reverse();\r\n\r\n for (const n of list) {\r\n // Use computed world transform for hit testing\r\n const { x: nx, y: ny, w, h } = n.computed;\r\n if (x >= nx && x <= nx + w && y >= ny && y <= ny + h) {\r\n // If this is a group, check if any of its children are under the cursor\r\n if (n.type === \"core/Group\") {\r\n // Check all children of this group (recursively)\r\n const child = this._findChildNodeAtWorld(n, x, y);\r\n if (child) {\r\n return child; // Return the child instead of the group\r\n }\r\n }\r\n return n;\r\n }\r\n }\r\n return null;\r\n }\r\n\r\n /**\r\n * Find child node at world coordinates (recursive helper for _findNodeAtWorld)\r\n * @param {Node} parentNode - Parent node (group)\r\n * @param {number} x - World x coordinate\r\n * @param {number} y - World y coordinate\r\n * @returns {Node|null} - Child node at position, or null\r\n */\r\n _findChildNodeAtWorld(parentNode, x, y) {\r\n // Get all children of this parent\r\n const children = [];\r\n for (const node of this.graph.nodes.values()) {\r\n if (node.parent === parentNode) {\r\n children.push(node);\r\n }\r\n }\r\n\r\n // Check children in reverse order (top to bottom)\r\n for (let i = children.length - 1; i >= 0; i--) {\r\n const child = children[i];\r\n const { x: nx, y: ny, w, h } = child.computed;\r\n\r\n if (x >= nx && x <= nx + w && y >= ny && y <= ny + h) {\r\n // If this child is also a group, recursively check its children\r\n if (child.type === \"core/Group\") {\r\n const grandchild = this._findChildNodeAtWorld(child, x, y);\r\n if (grandchild) {\r\n return grandchild;\r\n }\r\n }\r\n return child;\r\n }\r\n }\r\n\r\n return null;\r\n }\r\n\r\n _findPortAtWorld(x, y) {\r\n for (const n of this.graph.nodes.values()) {\r\n for (let i = 0; i < n.inputs.length; i++) {\r\n const r = portRect(n, n.inputs[i], i, \"in\");\r\n if (rectHas(r, x, y)) return { node: n, port: n.inputs[i], dir: \"in\", idx: i };\r\n }\r\n for (let i = 0; i < n.outputs.length; i++) {\r\n const r = portRect(n, n.outputs[i], i, \"out\");\r\n if (rectHas(r, x, y)) return { node: n, port: n.outputs[i], dir: \"out\", idx: i };\r\n }\r\n }\r\n return null;\r\n }\r\n\r\n _findIncomingEdge(nodeId, portId) {\r\n for (const [eid, e] of this.graph.edges) {\r\n if (e.toNode === nodeId && e.toPort === portId) {\r\n return { id: eid, edge: e };\r\n }\r\n }\r\n return null;\r\n }\r\n\r\n _onWheel(e) {\r\n e.preventDefault();\r\n const { x, y } = this._posScreen(e);\r\n const factor = Math.pow(1.0015, -e.deltaY); // smooth zoom\r\n this.renderer.zoomAt(factor, x, y);\r\n this.render();\r\n }\r\n\r\n _onContextMenu(e) {\r\n e.preventDefault();\r\n\r\n // Only show context menu if we have a contextMenu instance\r\n if (!this.contextMenu) return;\r\n\r\n const w = this._posWorld(e);\r\n const node = this._findNodeAtWorld(w.x, w.y);\r\n\r\n // Show menu with node or null (for canvas background) and world position\r\n this.contextMenu.show(node, e.clientX, e.clientY, w);\r\n }\r\n\r\n _onDblClick(e) {\r\n const w = this._posWorld(e);\r\n const node = this._findNodeAtWorld(w.x, w.y);\r\n\r\n if (node) {\r\n this.hooks?.emit(\"node:dblclick\", node);\r\n }\r\n }\r\n\r\n _resizeHandleRect(node) {\r\n const s = 10;\r\n const { x, y, w, h } = node.computed;\r\n return {\r\n x: x + w - s,\r\n y: y + h - s,\r\n w: s,\r\n h: s,\r\n };\r\n }\r\n\r\n _hitResizeHandle(node, wx, wy) {\r\n const r = this._resizeHandleRect(node);\r\n return wx >= r.x && wx <= r.x + r.w && wy >= r.y && wy <= r.y + r.h;\r\n }\r\n\r\n _onDown(e) {\r\n const s = this._posScreen(e);\r\n const w = this._posWorld(e);\r\n\r\n if (e.button === 1) {\r\n this.panning = { x: s.x, y: s.y };\r\n return;\r\n }\r\n\r\n // 1. Resize Handle Hit Test (for all nodes including groups)\r\n const node = this._findNodeAtWorld(w.x, w.y);\r\n if (e.button === 0 && node && this._hitResizeHandle(node, w.x, w.y)) {\r\n this.resizing = {\r\n nodeId: node.id,\r\n startW: node.size.width,\r\n startH: node.size.height,\r\n startX: w.x,\r\n startY: w.y,\r\n };\r\n if (!e.shiftKey) this.selection.clear();\r\n this.selection.add(node.id);\r\n this._setCursor(\"se-resize\");\r\n this.render();\r\n return;\r\n }\r\n\r\n // 2. Port Hit Test\r\n const port = this._findPortAtWorld(w.x, w.y);\r\n\r\n // Handle input port click - disconnect existing connection\r\n if (e.button === 0 && port && port.dir === \"in\") {\r\n const incoming = this._findIncomingEdge(port.node.id, port.port.id);\r\n if (incoming) {\r\n // Disconnect the existing edge\r\n this.stack.exec(RemoveEdgeCmd(this.graph, incoming.id));\r\n this.render();\r\n return;\r\n }\r\n }\r\n\r\n // Handle output port click - start new connection\r\n if (e.button === 0 && port && port.dir === \"out\") {\r\n const outR = portRect(port.node, port.port, port.idx, \"out\");\r\n const screenFrom = this.renderer.worldToScreen(outR.x, outR.y + 7);\r\n this.connecting = {\r\n fromNode: port.node.id,\r\n fromPort: port.port.id,\r\n x: screenFrom.x,\r\n y: screenFrom.y,\r\n };\r\n return;\r\n }\r\n\r\n // 3. Node Hit Test (Selection & Drag)\r\n if (e.button === 0 && node) {\r\n if (!e.shiftKey) this.selection.clear();\r\n this.selection.add(node.id);\r\n\r\n // Dragging: store initial world pos difference for all selected nodes\r\n this.dragging = {\r\n nodeId: node.id,\r\n offsetX: w.x - node.computed.x,\r\n offsetY: w.y - node.computed.y,\r\n startPos: { ...node.pos }, // for undo\r\n selectedNodes: [], // Store all selected nodes and their initial positions\r\n };\r\n\r\n // Store positions of all selected nodes\r\n for (const selectedId of this.selection) {\r\n const selectedNode = this.graph.nodes.get(selectedId);\r\n if (selectedNode) {\r\n this.dragging.selectedNodes.push({\r\n node: selectedNode,\r\n startWorldX: selectedNode.computed.x,\r\n startWorldY: selectedNode.computed.y,\r\n startLocalX: selectedNode.pos.x,\r\n startLocalY: selectedNode.pos.y,\r\n });\r\n }\r\n }\r\n\r\n // If dragging a group, store children's world positions\r\n if (node.type === \"core/Group\") {\r\n this.dragging.childrenWorldPos = [];\r\n for (const child of this.graph.nodes.values()) {\r\n if (child.parent === node) {\r\n this.dragging.childrenWorldPos.push({\r\n node: child,\r\n worldX: child.computed.x,\r\n worldY: child.computed.y,\r\n });\r\n }\r\n }\r\n }\r\n\r\n this.render();\r\n return;\r\n }\r\n\r\n // 4. Background Click (Pan or Box Selection)\r\n if (e.button === 0) {\r\n if (this.selection.size) this.selection.clear();\r\n\r\n // Start box selection if Ctrl is held\r\n if (e.ctrlKey || e.metaKey) {\r\n this.boxSelecting = {\r\n startX: w.x,\r\n startY: w.y,\r\n currentX: w.x,\r\n currentY: w.y,\r\n };\r\n } else {\r\n this.panning = { x: s.x, y: s.y };\r\n }\r\n this.render();\r\n return;\r\n }\r\n }\r\n\r\n _onMove(e) {\r\n // Track key states\r\n this.isAlt = e.altKey;\r\n this.isShift = e.shiftKey;\r\n this.isCtrl = e.ctrlKey;\r\n\r\n const s = this._posScreen(e);\r\n const w = this.renderer.screenToWorld(s.x, s.y);\r\n\r\n if (this.resizing) {\r\n const n = this.graph.nodes.get(this.resizing.nodeId);\r\n const dx = w.x - this.resizing.startX;\r\n const dy = w.y - this.resizing.startY;\r\n\r\n const minW = Controller.MIN_NODE_WIDTH;\r\n const minH = Controller.MIN_NODE_HEIGHT;\r\n n.size.width = Math.max(minW, this.resizing.startW + dx);\r\n n.size.height = Math.max(minH, this.resizing.startH + dy);\r\n\r\n this.hooks?.emit(\"node:resize\", n);\r\n this._setCursor(\"se-resize\");\r\n this.render();\r\n return;\r\n }\r\n\r\n if (this.panning) {\r\n const dx = s.x - this.panning.x;\r\n const dy = s.y - this.panning.y;\r\n this.panning = { x: s.x, y: s.y };\r\n this.renderer.panBy(dx, dy);\r\n this.render();\r\n return;\r\n }\r\n\r\n if (this.dragging) {\r\n const n = this.graph.nodes.get(this.dragging.nodeId);\r\n\r\n // Calculate delta for main node\r\n let targetWx = w.x - this.dragging.offsetX;\r\n let targetWy = this.isShift ? w.y - 0 : w.y - this.dragging.offsetY;\r\n\r\n // Apply snap-to-grid if enabled\r\n if (this.snapToGrid) {\r\n targetWx = this._snapToGrid(targetWx);\r\n targetWy = this._snapToGrid(targetWy);\r\n }\r\n\r\n // Calculate delta from original position\r\n const deltaX =\r\n targetWx - this.dragging.selectedNodes.find((sn) => sn.node.id === n.id).startWorldX;\r\n const deltaY =\r\n targetWy - this.dragging.selectedNodes.find((sn) => sn.node.id === n.id).startWorldY;\r\n\r\n // Update world transforms\r\n this.graph.updateWorldTransforms();\r\n\r\n // Move all selected nodes by the same delta\r\n for (const { node: selectedNode, startWorldX, startWorldY } of this.dragging.selectedNodes) {\r\n // Skip group nodes when shift-dragging (vertical only)\r\n if (this.isShift && selectedNode.type === \"core/Group\") {\r\n continue;\r\n }\r\n\r\n const newWorldX = startWorldX + deltaX;\r\n const newWorldY = startWorldY + deltaY;\r\n\r\n // Convert to local position\r\n let parentWx = 0;\r\n let parentWy = 0;\r\n if (selectedNode.parent) {\r\n parentWx = selectedNode.parent.computed.x;\r\n parentWy = selectedNode.parent.computed.y;\r\n }\r\n\r\n selectedNode.pos.x = newWorldX - parentWx;\r\n selectedNode.pos.y = newWorldY - parentWy;\r\n }\r\n\r\n // If Alt is held and dragging a group, restore children to original world positions\r\n if (this.isAlt && n.type === \"core/Group\" && this.dragging.childrenWorldPos) {\r\n this.graph.updateWorldTransforms();\r\n for (const childInfo of this.dragging.childrenWorldPos) {\r\n const child = childInfo.node;\r\n const newGroupX = n.computed.x;\r\n const newGroupY = n.computed.y;\r\n\r\n child.pos.x = childInfo.worldX - newGroupX;\r\n child.pos.y = childInfo.worldY - newGroupY;\r\n }\r\n }\r\n\r\n this.hooks?.emit(\"node:move\", n);\r\n this.render();\r\n return;\r\n }\r\n\r\n if (this.boxSelecting) {\r\n this.boxSelecting.currentX = w.x;\r\n this.boxSelecting.currentY = w.y;\r\n this.render();\r\n return;\r\n }\r\n\r\n if (this.connecting) {\r\n this.connecting.x = s.x;\r\n this.connecting.y = s.y;\r\n this.render();\r\n }\r\n\r\n // Cursor update\r\n const port = this._findPortAtWorld(w.x, w.y);\r\n const node = this._findNodeAtWorld(w.x, w.y);\r\n\r\n if (node && this._hitResizeHandle(node, w.x, w.y)) {\r\n this._setCursor(\"se-resize\");\r\n } else if (port) {\r\n // Show pointer cursor over ports (for connecting/disconnecting)\r\n this._setCursor(\"pointer\");\r\n } else {\r\n this._setCursor(\"default\");\r\n }\r\n }\r\n\r\n _onUp(e) {\r\n this.isAlt = e.altKey;\r\n this.isShift = e.shiftKey;\r\n this.isCtrl = e.ctrlKey;\r\n\r\n const w = this._posWorld(e);\r\n\r\n if (this.panning) {\r\n this.panning = null;\r\n return;\r\n }\r\n\r\n if (this.connecting) {\r\n // ... (existing connection logic)\r\n const from = this.connecting;\r\n const portIn = this._findPortAtWorld(w.x, w.y);\r\n if (portIn && portIn.dir === \"in\") {\r\n this.stack.exec(\r\n AddEdgeCmd(this.graph, from.fromNode, from.fromPort, portIn.node.id, portIn.port.id)\r\n );\r\n }\r\n this.connecting = null;\r\n this.render();\r\n }\r\n\r\n if (this.resizing) {\r\n const n = this.graph.nodes.get(this.resizing.nodeId);\r\n const from = { w: this.resizing.startW, h: this.resizing.startH };\r\n const to = { w: n.size.width, h: n.size.height };\r\n if (from.w !== to.w || from.h !== to.h) {\r\n this.stack.exec(ResizeNodeCmd(n, from, to));\r\n }\r\n this.resizing = null;\r\n this._setCursor(\"default\");\r\n }\r\n\r\n if (this.dragging) {\r\n const n = this.graph.nodes.get(this.dragging.nodeId);\r\n\r\n // If we're dragging a GROUP with Alt, only move the group (keep children in place)\r\n if (n.type === \"core/Group\" && this.isAlt && this.dragging.childrenWorldPos) {\r\n // Restore children to their original world positions\r\n for (const childInfo of this.dragging.childrenWorldPos) {\r\n const child = childInfo.node;\r\n // Convert world position back to local position relative to new group position\r\n this.graph.updateWorldTransforms();\r\n const newGroupX = n.computed.x;\r\n const newGroupY = n.computed.y;\r\n\r\n child.pos.x = childInfo.worldX - newGroupX;\r\n child.pos.y = childInfo.worldY - newGroupY;\r\n }\r\n } else if (n.type === \"core/Group\" && !this.isAlt) {\r\n // Normal group drag - auto-parent nodes\r\n this._autoParentNodesInGroup(n);\r\n } else if (n.type !== \"core/Group\") {\r\n // Normal node: Reparenting Logic\r\n // Check if dropped onto a group\r\n const potentialParent = this._findPotentialParent(w.x, w.y, n);\r\n\r\n if (potentialParent && potentialParent !== n.parent) {\r\n this.graph.reparent(n, potentialParent);\r\n } else if (!potentialParent && n.parent) {\r\n // Dropped on empty space -> move to root\r\n this.graph.reparent(n, null);\r\n }\r\n }\r\n\r\n this.dragging = null;\r\n this.render();\r\n }\r\n\r\n if (this.boxSelecting) {\r\n // Select all nodes within the box\r\n const { startX, startY, currentX, currentY } = this.boxSelecting;\r\n const minX = Math.min(startX, currentX);\r\n const maxX = Math.max(startX, currentX);\r\n const minY = Math.min(startY, currentY);\r\n const maxY = Math.max(startY, currentY);\r\n\r\n for (const node of this.graph.nodes.values()) {\r\n const { x, y, w, h } = node.computed;\r\n // Check if node intersects with selection box\r\n if (x + w >= minX && x <= maxX && y + h >= minY && y <= maxY) {\r\n this.selection.add(node.id);\r\n }\r\n }\r\n\r\n this.boxSelecting = null;\r\n this.render();\r\n }\r\n }\r\n\r\n /**\r\n * Automatically parent nodes that are within the group's bounds\r\n * @param {Node} groupNode - The group node\r\n */\r\n _autoParentNodesInGroup(groupNode) {\r\n const { x: gx, y: gy, w: gw, h: gh } = groupNode.computed;\r\n\r\n // Find all nodes that are within the group bounds\r\n for (const node of this.graph.nodes.values()) {\r\n // Skip the group itself\r\n if (node === groupNode) continue;\r\n\r\n // Skip if it's already a child of this group\r\n if (node.parent === groupNode) continue;\r\n\r\n // Skip if it's another group (prevent nested groups for now)\r\n if (node.type === \"core/Group\") continue;\r\n\r\n // Check if node is within group bounds\r\n const { x: nx, y: ny, w: nw, h: nh } = node.computed;\r\n const nodeCenterX = nx + nw / 2;\r\n const nodeCenterY = ny + nh / 2;\r\n\r\n // Use center point to determine if node is inside group\r\n if (\r\n nodeCenterX >= gx &&\r\n nodeCenterX <= gx + gw &&\r\n nodeCenterY >= gy &&\r\n nodeCenterY <= gy + gh\r\n ) {\r\n // Parent this node to the group\r\n this.graph.reparent(node, groupNode);\r\n }\r\n }\r\n }\r\n\r\n _findPotentialParent(x, y, excludeNode) {\r\n // Find top-most group under x,y that is not excludeNode or its descendants\r\n const list = [...this.graph.nodes.values()].reverse();\r\n for (const n of list) {\r\n if (n.type !== \"core/Group\") continue;\r\n if (n === excludeNode) continue;\r\n // Check if n is descendant of excludeNode\r\n let p = n.parent;\r\n let isDescendant = false;\r\n while (p) {\r\n if (p === excludeNode) {\r\n isDescendant = true;\r\n break;\r\n }\r\n p = p.parent;\r\n }\r\n if (isDescendant) continue;\r\n\r\n const { x: nx, y: ny, w, h } = n.computed;\r\n if (x >= nx && x <= nx + w && y >= ny && y <= ny + h) {\r\n return n;\r\n }\r\n }\r\n return null;\r\n }\r\n\r\n /**\r\n * Snap a coordinate to the grid\r\n * @param {number} value - The value to snap\r\n * @returns {number} - Snapped value\r\n */\r\n _snapToGrid(value) {\r\n return Math.round(value / this.gridSize) * this.gridSize;\r\n }\r\n\r\n /**\r\n * Create a group from currently selected nodes\r\n */\r\n _createGroupFromSelection() {\r\n if (this.selection.size === 0) {\r\n console.warn(\"No nodes selected to group\");\r\n return;\r\n }\r\n\r\n // Get selected nodes\r\n const selectedNodes = Array.from(this.selection).map((id) => this.graph.getNodeById(id));\r\n\r\n // Calculate bounding box\r\n let minX = Infinity,\r\n minY = Infinity,\r\n maxX = -Infinity,\r\n maxY = -Infinity;\r\n for (const node of selectedNodes) {\r\n const { x, y, w, h } = node.computed;\r\n minX = Math.min(minX, x);\r\n minY = Math.min(minY, y);\r\n maxX = Math.max(maxX, x + w);\r\n maxY = Math.max(maxY, y + h);\r\n }\r\n\r\n const margin = 20;\r\n const groupX = minX - margin;\r\n const groupY = minY - margin;\r\n const groupWidth = maxX - minX + margin * 2;\r\n const groupHeight = maxY - minY + margin * 2;\r\n\r\n // Create group via GroupManager\r\n if (this.graph.groupManager) {\r\n this.graph.groupManager.addGroup({\r\n title: \"Group\",\r\n x: groupX,\r\n y: groupY,\r\n width: groupWidth,\r\n height: groupHeight,\r\n members: Array.from(this.selection),\r\n });\r\n this.selection.clear();\r\n this.render();\r\n }\r\n }\r\n\r\n /**\r\n * Align selected nodes horizontally (same Y position)\r\n */\r\n _alignNodesHorizontal() {\r\n if (this.selection.size < 2) return;\r\n\r\n const nodes = Array.from(this.selection).map((id) => this.graph.getNodeById(id));\r\n const avgY = nodes.reduce((sum, n) => sum + n.computed.y, 0) / nodes.length;\r\n\r\n for (const node of nodes) {\r\n const parentY = node.parent ? node.parent.computed.y : 0;\r\n node.pos.y = avgY - parentY;\r\n }\r\n\r\n this.graph.updateWorldTransforms();\r\n this.render();\r\n }\r\n\r\n /**\r\n * Align selected nodes vertically (same X position)\r\n */\r\n _alignNodesVertical() {\r\n if (this.selection.size < 2) return;\r\n\r\n const nodes = Array.from(this.selection).map((id) => this.graph.getNodeById(id));\r\n const avgX = nodes.reduce((sum, n) => sum + n.computed.x, 0) / nodes.length;\r\n\r\n for (const node of nodes) {\r\n const parentX = node.parent ? node.parent.computed.x : 0;\r\n node.pos.x = avgX - parentX;\r\n }\r\n\r\n this.graph.updateWorldTransforms();\r\n this.render();\r\n }\r\n\r\n render() {\r\n const tEdge = this.renderTempEdge();\r\n\r\n // 1. Draw background (grid, canvas-only nodes) on main canvas\r\n this.renderer.draw(this.graph, {\r\n selection: this.selection,\r\n tempEdge: null, // Don't draw temp edge on background\r\n boxSelecting: this.boxSelecting,\r\n activeEdges: this.activeEdges || new Set(),\r\n drawEdges: !this.edgeRenderer, // Only draw edges here if no separate edge renderer\r\n });\r\n\r\n // 2. HTML Overlay layer (HTML nodes at z-index 10)\r\n this.htmlOverlay?.draw(this.graph, this.selection);\r\n\r\n // 3. Draw edges and animations on edge canvas (above HTML overlay at z-index 15)\r\n if (this.edgeRenderer) {\r\n const edgeCtx = this.edgeRenderer.ctx;\r\n edgeCtx.clearRect(0, 0, this.edgeRenderer.canvas.width, this.edgeRenderer.canvas.height);\r\n\r\n // Edges use shared transform (via property getters)\r\n this.edgeRenderer._applyTransform();\r\n\r\n this.edgeRenderer.drawEdgesOnly(this.graph, {\r\n activeEdges: this.activeEdges || new Set(),\r\n running: false,\r\n time: performance.now(),\r\n tempEdge: tEdge, // Draw temp edge on edge layer\r\n });\r\n\r\n this.edgeRenderer._resetTransform();\r\n }\r\n\r\n // 4. Draw box selection rectangle on top of edges\r\n if (this.boxSelecting) {\r\n const { startX, startY, currentX, currentY } = this.boxSelecting;\r\n const minX = Math.min(startX, currentX);\r\n const minY = Math.min(startY, currentY);\r\n const width = Math.abs(currentX - startX);\r\n const height = Math.abs(currentY - startY);\r\n\r\n const screenStart = this.renderer.worldToScreen(minX, minY);\r\n const screenEnd = this.renderer.worldToScreen(minX + width, minY + height);\r\n\r\n const ctx = this.edgeRenderer ? this.edgeRenderer.ctx : this.renderer.ctx;\r\n ctx.save();\r\n if (this.edgeRenderer) {\r\n this.edgeRenderer._resetTransform();\r\n } else {\r\n this.renderer._resetTransform();\r\n }\r\n\r\n // Draw selection box\r\n ctx.strokeStyle = \"#6cf\";\r\n ctx.fillStyle = \"rgba(102, 204, 255, 0.1)\";\r\n ctx.lineWidth = 2;\r\n ctx.strokeRect(\r\n screenStart.x,\r\n screenStart.y,\r\n screenEnd.x - screenStart.x,\r\n screenEnd.y - screenStart.y\r\n );\r\n ctx.fillRect(\r\n screenStart.x,\r\n screenStart.y,\r\n screenEnd.x - screenStart.x,\r\n screenEnd.y - screenStart.y\r\n );\r\n\r\n ctx.restore();\r\n }\r\n\r\n // 5. Draw ports on port canvas (above edges at z-index 20)\r\n if (this.portRenderer) {\r\n const portCtx = this.portRenderer.ctx;\r\n portCtx.clearRect(0, 0, this.portRenderer.canvas.width, this.portRenderer.canvas.height);\r\n\r\n // Sync transform\r\n this.portRenderer.scale = this.renderer.scale;\r\n this.portRenderer.offsetX = this.renderer.offsetX;\r\n this.portRenderer.offsetY = this.renderer.offsetY;\r\n\r\n this.portRenderer._applyTransform();\r\n\r\n // Draw ports for HTML overlay nodes only\r\n // Draw ports for ALL nodes to ensure they are above edges\r\n for (const n of this.graph.nodes.values()) {\r\n if (n.type !== \"core/Group\") {\r\n this.portRenderer._drawPorts(n);\r\n }\r\n }\r\n this.portRenderer._resetTransform();\r\n }\r\n }\r\n\r\n renderTempEdge() {\r\n if (!this.connecting) return null;\r\n const a = this._portAnchorScreen(this.connecting.fromNode, this.connecting.fromPort); // {x,y}\r\n return {\r\n x1: a.x,\r\n y1: a.y,\r\n x2: this.connecting.x,\r\n y2: this.connecting.y,\r\n };\r\n }\r\n\r\n _portAnchorScreen(nodeId, portId) {\r\n const n = this.graph.nodes.get(nodeId);\r\n const iOut = n.outputs.findIndex((p) => p.id === portId);\r\n const r = portRect(n, null, iOut, \"out\"); // world rect\r\n return this.renderer.worldToScreen(r.x + r.w / 2, r.y + r.h / 2); // -> screen point (CENTER)\r\n }\r\n}\r\n\r\nfunction rectHas(r, x, y) {\r\n return x >= r.x && x <= r.x + r.w && y >= r.y && y <= r.y + r.h;\r\n}\r\n","/**\r\n * ContextMenu - Extensible context menu for nodes and groups\r\n * Provides right-click functionality with customizable menu items\r\n */\r\nexport class ContextMenu {\r\n constructor({ graph, hooks, renderer, commandStack }) {\r\n this.graph = graph;\r\n this.hooks = hooks;\r\n this.renderer = renderer;\r\n this.commandStack = commandStack;\r\n\r\n this.items = [];\r\n this.visible = false;\r\n this.target = null;\r\n this.position = { x: 0, y: 0 };\r\n\r\n this.menuElement = this._createMenuElement();\r\n\r\n // Close menu on any click outside\r\n this._onDocumentClick = (e) => {\r\n if (!this.menuElement.contains(e.target)) {\r\n this.hide();\r\n }\r\n };\r\n }\r\n\r\n /**\r\n * Add a menu item\r\n * @param {string} id - Unique identifier for the menu item\r\n * @param {string} label - Display label\r\n * @param {Object} options - Options\r\n * @param {Function} options.action - Action to execute (receives target)\r\n * @param {Array} options.submenu - Submenu items\r\n * @param {Function} options.condition - Optional condition to show item (receives target)\r\n * @param {number} options.order - Optional sort order (default: 100)\r\n */\r\n addItem(id, label, options = {}) {\r\n const { action, submenu, condition, order = 100 } = options;\r\n\r\n // Either action or submenu must be provided\r\n if (!action && !submenu) {\r\n console.error(\"ContextMenu.addItem: either action or submenu is required\");\r\n return;\r\n }\r\n\r\n // Remove existing item with same id\r\n this.removeItem(id);\r\n\r\n this.items.push({\r\n id,\r\n label,\r\n action,\r\n submenu,\r\n condition,\r\n order,\r\n });\r\n\r\n // Sort by order\r\n this.items.sort((a, b) => a.order - b.order);\r\n }\r\n\r\n /**\r\n * Remove a menu item by id\r\n * @param {string} id - Item id to remove\r\n */\r\n removeItem(id) {\r\n this.items = this.items.filter((item) => item.id !== id);\r\n }\r\n\r\n /**\r\n * Show the context menu\r\n * @param {Object} target - Target node/group\r\n * @param {number} x - Screen x position\r\n * @param {number} y - Screen y position\r\n * @param {Object} worldPos - Optional world position {x, y}\r\n */\r\n show(target, x, y, worldPos = null) {\r\n this.target = target;\r\n this.position = { x, y };\r\n this.worldPosition = worldPos; // Store world position for node creation\r\n this.visible = true;\r\n\r\n this._renderItems();\r\n\r\n // Position menu\r\n this.menuElement.style.left = `${x}px`;\r\n this.menuElement.style.top = `${y}px`;\r\n this.menuElement.style.display = \"block\";\r\n\r\n // Adjust position if menu goes off-screen\r\n requestAnimationFrame(() => {\r\n const rect = this.menuElement.getBoundingClientRect();\r\n const vw = window.innerWidth;\r\n const vh = window.innerHeight;\r\n\r\n let adjustedX = x;\r\n let adjustedY = y;\r\n\r\n if (rect.right > vw) {\r\n adjustedX = vw - rect.width - 5;\r\n }\r\n if (rect.bottom > vh) {\r\n adjustedY = vh - rect.height - 5;\r\n }\r\n\r\n this.menuElement.style.left = `${adjustedX}px`;\r\n this.menuElement.style.top = `${adjustedY}px`;\r\n });\r\n\r\n // Listen for clicks to close menu\r\n document.addEventListener(\"click\", this._onDocumentClick);\r\n }\r\n\r\n /**\r\n * Hide the context menu\r\n */\r\n hide() {\r\n this.visible = false;\r\n this.target = null;\r\n\r\n // Clean up any open submenus\r\n const allSubmenus = document.querySelectorAll(\".context-submenu\");\r\n allSubmenus.forEach(submenu => submenu.remove());\r\n\r\n this.menuElement.style.display = \"none\";\r\n document.removeEventListener(\"click\", this._onDocumentClick);\r\n }\r\n\r\n /**\r\n * Cleanup\r\n */\r\n destroy() {\r\n this.hide();\r\n if (this.menuElement && this.menuElement.parentNode) {\r\n this.menuElement.parentNode.removeChild(this.menuElement);\r\n }\r\n }\r\n\r\n /**\r\n * Create the menu DOM element\r\n * @private\r\n */\r\n _createMenuElement() {\r\n const menu = document.createElement(\"div\");\r\n menu.className = \"html-overlay-node-context-menu\";\r\n\r\n // Styling\r\n Object.assign(menu.style, {\r\n position: \"fixed\",\r\n display: \"none\",\r\n minWidth: \"180px\",\r\n backgroundColor: \"#2a2a2e\",\r\n border: \"1px solid #444\",\r\n borderRadius: \"6px\",\r\n boxShadow: \"0 4px 16px rgba(0, 0, 0, 0.4)\",\r\n zIndex: \"10000\",\r\n padding: \"4px 0\",\r\n fontFamily: \"system-ui, -apple-system, sans-serif\",\r\n fontSize: \"13px\",\r\n color: \"#e9e9ef\",\r\n });\r\n\r\n document.body.appendChild(menu);\r\n return menu;\r\n }\r\n\r\n /**\r\n * Render menu items based on current target\r\n * @private\r\n */\r\n _renderItems() {\r\n this.menuElement.innerHTML = \"\";\r\n\r\n const visibleItems = this.items.filter((item) => {\r\n if (item.condition) {\r\n return item.condition(this.target);\r\n }\r\n return true;\r\n });\r\n\r\n if (visibleItems.length === 0) {\r\n this.hide();\r\n return;\r\n }\r\n\r\n visibleItems.forEach((item) => {\r\n const itemEl = document.createElement(\"div\");\r\n itemEl.className = \"context-menu-item\";\r\n\r\n // Create item content wrapper\r\n const contentWrapper = document.createElement(\"div\");\r\n Object.assign(contentWrapper.style, {\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"space-between\",\r\n width: \"100%\",\r\n });\r\n\r\n const labelEl = document.createElement(\"span\");\r\n labelEl.textContent = item.label;\r\n contentWrapper.appendChild(labelEl);\r\n\r\n // Add arrow indicator if item has submenu\r\n if (item.submenu) {\r\n const arrow = document.createElement(\"span\");\r\n arrow.textContent = \"▶\";\r\n arrow.style.marginLeft = \"12px\";\r\n arrow.style.fontSize = \"10px\";\r\n arrow.style.opacity = \"0.7\";\r\n contentWrapper.appendChild(arrow);\r\n }\r\n\r\n itemEl.appendChild(contentWrapper);\r\n\r\n Object.assign(itemEl.style, {\r\n padding: \"4px 8px\",\r\n cursor: \"pointer\",\r\n transition: \"background-color 0.15s ease\",\r\n userSelect: \"none\",\r\n position: \"relative\",\r\n });\r\n\r\n // Hover effect\r\n itemEl.addEventListener(\"mouseenter\", () => {\r\n itemEl.style.backgroundColor = \"#3a3a3e\";\r\n\r\n // Clear any pending hide timeout\r\n if (itemEl._hideTimeout) {\r\n clearTimeout(itemEl._hideTimeout);\r\n itemEl._hideTimeout = null;\r\n }\r\n\r\n // Show submenu if exists\r\n if (item.submenu) {\r\n // Support function-based submenus for dynamic content\r\n const submenuItems = typeof item.submenu === 'function'\r\n ? item.submenu()\r\n : item.submenu;\r\n this._showSubmenu(submenuItems, itemEl);\r\n }\r\n });\r\n\r\n itemEl.addEventListener(\"mouseleave\", (e) => {\r\n itemEl.style.backgroundColor = \"transparent\";\r\n\r\n // Hide submenu with delay if moving to submenu\r\n if (item.submenu) {\r\n const submenuEl = itemEl._submenuElement;\r\n if (submenuEl) {\r\n // Add delay before hiding to allow mouse to reach submenu\r\n itemEl._hideTimeout = setTimeout(() => {\r\n if (!submenuEl.contains(document.elementFromPoint(e.clientX, e.clientY))) {\r\n this._hideSubmenu(itemEl);\r\n }\r\n }, 150); // 150ms delay\r\n }\r\n }\r\n });\r\n\r\n // Click handler\r\n if (!item.submenu) {\r\n itemEl.addEventListener(\"click\", (e) => {\r\n e.stopPropagation();\r\n item.action(this.target);\r\n this.hide();\r\n });\r\n }\r\n\r\n this.menuElement.appendChild(itemEl);\r\n });\r\n }\r\n\r\n /**\r\n * Show submenu for an item\r\n * @private\r\n */\r\n _showSubmenu(submenuItems, parentItemEl) {\r\n // Remove any existing submenu\r\n this._hideSubmenu(parentItemEl);\r\n\r\n const submenuEl = document.createElement(\"div\");\r\n submenuEl.className = \"context-submenu\";\r\n\r\n Object.assign(submenuEl.style, {\r\n position: \"fixed\",\r\n minWidth: \"140px\",\r\n backgroundColor: \"#2a2a2e\",\r\n border: \"1px solid #444\",\r\n borderRadius: \"6px\",\r\n boxShadow: \"0 4px 16px rgba(0, 0, 0, 0.4)\",\r\n zIndex: \"10001\",\r\n padding: \"4px 0\",\r\n fontFamily: \"system-ui, -apple-system, sans-serif\",\r\n fontSize: \"13px\",\r\n color: \"#e9e9ef\",\r\n });\r\n\r\n submenuItems.forEach((subItem) => {\r\n const subItemEl = document.createElement(\"div\");\r\n subItemEl.className = \"context-submenu-item\";\r\n\r\n // Create content with color swatch if available\r\n const contentWrapper = document.createElement(\"div\");\r\n Object.assign(contentWrapper.style, {\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n gap: \"8px\",\r\n });\r\n\r\n // Color swatch\r\n if (subItem.color) {\r\n const swatch = document.createElement(\"div\");\r\n Object.assign(swatch.style, {\r\n width: \"16px\",\r\n height: \"16px\",\r\n borderRadius: \"3px\",\r\n backgroundColor: subItem.color,\r\n border: \"1px solid #555\",\r\n flexShrink: \"0\",\r\n });\r\n contentWrapper.appendChild(swatch);\r\n }\r\n\r\n const labelEl = document.createElement(\"span\");\r\n labelEl.textContent = subItem.label;\r\n contentWrapper.appendChild(labelEl);\r\n\r\n subItemEl.appendChild(contentWrapper);\r\n\r\n Object.assign(subItemEl.style, {\r\n padding: \"4px 8px\",\r\n cursor: \"pointer\",\r\n transition: \"background-color 0.15s ease\",\r\n userSelect: \"none\",\r\n });\r\n\r\n subItemEl.addEventListener(\"mouseenter\", () => {\r\n subItemEl.style.backgroundColor = \"#3a3a3e\";\r\n });\r\n\r\n subItemEl.addEventListener(\"mouseleave\", () => {\r\n subItemEl.style.backgroundColor = \"transparent\";\r\n });\r\n\r\n subItemEl.addEventListener(\"click\", (e) => {\r\n e.stopPropagation();\r\n subItem.action(this.target);\r\n this.hide();\r\n });\r\n\r\n submenuEl.appendChild(subItemEl);\r\n });\r\n\r\n // Keep submenu open when hovering over it\r\n submenuEl.addEventListener(\"mouseenter\", () => {\r\n // Clear parent's hide timeout\r\n if (parentItemEl._hideTimeout) {\r\n clearTimeout(parentItemEl._hideTimeout);\r\n parentItemEl._hideTimeout = null;\r\n }\r\n });\r\n\r\n submenuEl.addEventListener(\"mouseleave\", (e) => {\r\n if (!parentItemEl.contains(e.relatedTarget)) {\r\n this._hideSubmenu(parentItemEl);\r\n }\r\n });\r\n\r\n document.body.appendChild(submenuEl);\r\n parentItemEl._submenuElement = submenuEl;\r\n\r\n // Position submenu next to parent item\r\n requestAnimationFrame(() => {\r\n const parentRect = parentItemEl.getBoundingClientRect();\r\n const submenuRect = submenuEl.getBoundingClientRect();\r\n\r\n let left = parentRect.right + 2;\r\n let top = parentRect.top;\r\n\r\n // Adjust if submenu goes off-screen\r\n if (left + submenuRect.width > window.innerWidth) {\r\n left = parentRect.left - submenuRect.width - 2;\r\n }\r\n\r\n if (top + submenuRect.height > window.innerHeight) {\r\n top = window.innerHeight - submenuRect.height - 5;\r\n }\r\n\r\n submenuEl.style.left = `${left}px`;\r\n submenuEl.style.top = `${top}px`;\r\n });\r\n }\r\n\r\n /**\r\n * Hide submenu for an item\r\n * @private\r\n */\r\n _hideSubmenu(parentItemEl) {\r\n if (parentItemEl._submenuElement) {\r\n parentItemEl._submenuElement.remove();\r\n parentItemEl._submenuElement = null;\r\n }\r\n }\r\n}\r\n","export class Runner {\r\n constructor({ graph, registry, hooks, cyclesPerFrame = 1 }) {\r\n this.graph = graph;\r\n this.registry = registry;\r\n this.hooks = hooks;\r\n this.running = false;\r\n this._raf = null;\r\n this._last = 0;\r\n this.cyclesPerFrame = Math.max(1, cyclesPerFrame | 0);\r\n }\r\n\r\n // 외부에서 실행 중인지 확인\r\n isRunning() {\r\n return this.running;\r\n }\r\n\r\n // 실행 도중에도 CPS 변경 가능\r\n setCyclesPerFrame(n) {\r\n this.cyclesPerFrame = Math.max(1, n | 0);\r\n }\r\n\r\n step(cycles = 1, dt = 0) {\r\n const nCycles = Math.max(1, cycles | 0);\r\n for (let c = 0; c < nCycles; c++) {\r\n for (const node of this.graph.nodes.values()) {\r\n const def = this.registry.types.get(node.type);\r\n if (def?.onExecute) {\r\n try {\r\n def.onExecute(node, {\r\n dt,\r\n graph: this.graph,\r\n getInput: (portName) => {\r\n const p =\r\n node.inputs.find((i) => i.name === portName) ||\r\n node.inputs[0];\r\n return p ? this.graph.getInput(node.id, p.id) : undefined;\r\n },\r\n setOutput: (portName, value) => {\r\n const p =\r\n node.outputs.find((o) => o.name === portName) ||\r\n node.outputs[0];\r\n if (p) this.graph.setOutput(node.id, p.id, value);\r\n },\r\n });\r\n } catch (err) {\r\n this.hooks?.emit?.(\"error\", err);\r\n }\r\n }\r\n }\r\n // commit writes for this cycle\r\n this.graph.swapBuffers();\r\n }\r\n }\r\n\r\n /**\r\n * Execute connected nodes once from a starting node\r\n * Uses queue-based traversal to support branching exec flows\r\n * @param {string} startNodeId - ID of the node to start from\r\n * @param {number} dt - Delta time\r\n */\r\n runOnce(startNodeId, dt = 0) {\r\n console.log(\"[Runner.runOnce] Starting exec flow from node:\", startNodeId);\r\n\r\n const executedNodes = [];\r\n const allConnectedNodes = new Set();\r\n const queue = [startNodeId];\r\n const visited = new Set(); // Prevent infinite loops\r\n\r\n // Queue-based traversal for branching execution\r\n while (queue.length > 0) {\r\n const currentNodeId = queue.shift();\r\n\r\n // Skip if already executed (prevents cycles)\r\n if (visited.has(currentNodeId)) continue;\r\n visited.add(currentNodeId);\r\n\r\n const node = this.graph.nodes.get(currentNodeId);\r\n if (!node) {\r\n console.warn(`[Runner.runOnce] Node not found: ${currentNodeId}`);\r\n continue;\r\n }\r\n\r\n executedNodes.push(currentNodeId);\r\n allConnectedNodes.add(currentNodeId);\r\n console.log(`[Runner.runOnce] Executing: ${node.title} (${node.type})`);\r\n\r\n // Find and add data dependency nodes (nodes providing input data)\r\n for (const input of node.inputs) {\r\n if (input.portType === \"data\") {\r\n // Find edge feeding this data input\r\n for (const edge of this.graph.edges.values()) {\r\n if (edge.toNode === currentNodeId && edge.toPort === input.id) {\r\n const sourceNode = this.graph.nodes.get(edge.fromNode);\r\n if (sourceNode && !allConnectedNodes.has(edge.fromNode)) {\r\n allConnectedNodes.add(edge.fromNode);\r\n // Execute data source node before current node\r\n this.executeNode(edge.fromNode, dt);\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Execute current node\r\n this.executeNode(currentNodeId, dt);\r\n\r\n // Find all next nodes via exec outputs and add to queue\r\n const nextNodes = this.findAllNextExecNodes(currentNodeId);\r\n queue.push(...nextNodes);\r\n }\r\n\r\n console.log(\"[Runner.runOnce] Executed nodes:\", executedNodes.length);\r\n\r\n // Find all edges involved (both exec and data)\r\n const connectedEdges = new Set();\r\n for (const edge of this.graph.edges.values()) {\r\n if (allConnectedNodes.has(edge.fromNode) && allConnectedNodes.has(edge.toNode)) {\r\n connectedEdges.add(edge.id);\r\n }\r\n }\r\n\r\n console.log(\"[Runner.runOnce] Connected edges count:\", connectedEdges.size);\r\n return { connectedNodes: allConnectedNodes, connectedEdges };\r\n }\r\n\r\n /**\r\n * Find all nodes connected via exec outputs\r\n * Supports multiple connections from a single exec output\r\n * @param {string} nodeId - Current node ID\r\n * @returns {string[]} Array of next node IDs\r\n */\r\n findAllNextExecNodes(nodeId) {\r\n const node = this.graph.nodes.get(nodeId);\r\n if (!node) return [];\r\n\r\n // Find all exec output ports\r\n const execOutputs = node.outputs.filter(p => p.portType === \"exec\");\r\n if (execOutputs.length === 0) return [];\r\n\r\n const nextNodes = [];\r\n\r\n // Find all edges from exec outputs\r\n for (const execOutput of execOutputs) {\r\n for (const edge of this.graph.edges.values()) {\r\n if (edge.fromNode === nodeId && edge.fromPort === execOutput.id) {\r\n nextNodes.push(edge.toNode);\r\n }\r\n }\r\n }\r\n\r\n return nextNodes;\r\n }\r\n\r\n /**\r\n * Execute a single node\r\n * @param {string} nodeId - Node ID to execute\r\n * @param {number} dt - Delta time\r\n */\r\n executeNode(nodeId, dt) {\r\n const node = this.graph.nodes.get(nodeId);\r\n if (!node) return;\r\n\r\n const def = this.registry.types.get(node.type);\r\n if (!def?.onExecute) return;\r\n\r\n try {\r\n def.onExecute(node, {\r\n dt,\r\n graph: this.graph,\r\n getInput: (portName) => {\r\n const p = node.inputs.find((i) => i.name === portName) || node.inputs[0];\r\n return p ? this.graph.getInput(node.id, p.id) : undefined;\r\n },\r\n setOutput: (portName, value) => {\r\n const p = node.outputs.find((o) => o.name === portName) || node.outputs[0];\r\n if (p) {\r\n // Write directly to current buffer so other nodes can read it immediately\r\n const key = `${node.id}:${p.id}`;\r\n this.graph._curBuf().set(key, value);\r\n }\r\n },\r\n });\r\n } catch (err) {\r\n this.hooks?.emit?.(\"error\", err);\r\n }\r\n }\r\n\r\n start() {\r\n if (this.running) return;\r\n this.running = true;\r\n this._last = 0;\r\n this.hooks?.emit?.(\"runner:start\");\r\n\r\n const loop = (t) => {\r\n if (!this.running) return;\r\n const dtMs = this._last ? t - this._last : 0;\r\n this._last = t;\r\n const dt = dtMs / 1000; // seconds\r\n\r\n // 1) 스텝 실행\r\n this.step(this.cyclesPerFrame, dt);\r\n\r\n // 2) 프레임 훅 (렌더러/컨트롤러는 여기서 running, time, dt를 받아 표현 업데이트)\r\n this.hooks?.emit?.(\"runner:tick\", {\r\n time: t,\r\n dt,\r\n running: true,\r\n cps: this.cyclesPerFrame,\r\n });\r\n\r\n this._raf = requestAnimationFrame(loop);\r\n };\r\n\r\n this._raf = requestAnimationFrame(loop);\r\n }\r\n\r\n stop() {\r\n if (!this.running) return;\r\n this.running = false;\r\n if (this._raf) cancelAnimationFrame(this._raf);\r\n this._raf = null;\r\n this._last = 0;\r\n this.hooks?.emit?.(\"runner:stop\");\r\n }\r\n}\r\n","// 캔버스 위에 붙는 DOM 오버레이. 캔버스의 scale/offset에 맞춰 CSS transform을 적용.\r\n// 동기화 하기 까다로워서 아직 적용하지 않음\r\nexport class HtmlOverlay {\r\n /**\r\n * @param {HTMLElement} host 캔버스를 감싸는 래퍼( position: relative )\r\n * @param {CanvasRenderer} renderer\r\n * @param {Registry} registry\r\n */\r\n constructor(host, renderer, registry) {\r\n this.host = host;\r\n this.renderer = renderer;\r\n this.registry = registry;\r\n this.container = document.createElement(\"div\");\r\n Object.assign(this.container.style, {\r\n position: \"absolute\",\r\n inset: \"0\",\r\n pointerEvents: \"none\", // 기본은 통과\r\n zIndex: \"10\",\r\n });\r\n host.appendChild(this.container);\r\n\r\n /** @type {Map<string, HTMLElement>} */\r\n this.nodes = new Map();\r\n }\r\n\r\n /** 기본 노드 레이아웃 생성 (헤더 + 바디) */\r\n _createDefaultNodeLayout(_node) {\r\n const container = document.createElement(\"div\");\r\n container.className = \"node-overlay\";\r\n Object.assign(container.style, {\r\n position: \"absolute\",\r\n display: \"flex\",\r\n flexDirection: \"column\",\r\n boxSizing: \"border-box\",\r\n pointerEvents: \"none\", // 기본은 통과 (캔버스 인터랙션 위해)\r\n overflow: \"hidden\", // 둥근 모서리 등\r\n });\r\n\r\n const header = document.createElement(\"div\");\r\n header.className = \"node-header\";\r\n Object.assign(header.style, {\r\n height: \"24px\",\r\n flexShrink: \"0\",\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n padding: \"0 8px\",\r\n cursor: \"grab\",\r\n userSelect: \"none\",\r\n pointerEvents: \"none\", // 헤더 클릭시 드래그는 캔버스가 처리\r\n });\r\n\r\n const body = document.createElement(\"div\");\r\n body.className = \"node-body\";\r\n Object.assign(body.style, {\r\n flex: \"1\",\r\n position: \"relative\",\r\n overflow: \"hidden\",\r\n // 바디 내부는 인터랙션 가능하게? 아니면 이것도 none하고 자식만 auto?\r\n // 일단 바디는 auto로 두면 바디 영역 클릭시 드래그가 안됨.\r\n // 그래서 바디도 none으로 하고, 내부 컨텐츠(input 등)만 auto로 하는게 맞음.\r\n pointerEvents: \"none\",\r\n });\r\n\r\n container.appendChild(header);\r\n container.appendChild(body);\r\n\r\n // 나중에 접근하기 쉽게 프로퍼티로 저장\r\n container._domParts = { header, body };\r\n return container;\r\n }\r\n\r\n /** 노드용 엘리먼트 생성(한 번만) */\r\n _ensureNodeElement(node, def, graph) {\r\n let el = this.nodes.get(node.id);\r\n if (!el) {\r\n // 1) 사용자 정의 render 함수가 있으면 우선 사용\r\n if (def.html?.render) {\r\n el = def.html.render(node);\r\n }\r\n // 2) 아니면 기본 레이아웃 사용 (html 설정이 있는 경우)\r\n else if (def.html) {\r\n el = this._createDefaultNodeLayout(node);\r\n // 초기화 훅 - graph reference 전달\r\n if (def.html.init) {\r\n def.html.init(node, el, { ...el._domParts, graph });\r\n }\r\n } else {\r\n return null; // HTML 없음\r\n }\r\n\r\n if (!el) return null;\r\n\r\n el.style.position = \"absolute\";\r\n el.style.pointerEvents = \"none\"; // 기본적으로 캔버스 통과\r\n this.container.appendChild(el);\r\n this.nodes.set(node.id, el);\r\n }\r\n return el;\r\n }\r\n\r\n /** 그래프와 변환 동기화하여 렌더링 */\r\n draw(graph, selection = new Set()) {\r\n // 컨테이너 전체에 월드 변환 적용 (CSS 픽셀 기준)\r\n const { scale, offsetX, offsetY } = this.renderer;\r\n this.container.style.transform = `translate(${offsetX}px, ${offsetY}px) scale(${scale})`;\r\n this.container.style.transformOrigin = \"0 0\";\r\n\r\n const seen = new Set();\r\n\r\n for (const node of graph.nodes.values()) {\r\n const def = this.registry.types.get(node.type);\r\n\r\n // render 함수가 있거나, html 설정 객체가 있으면 처리\r\n const hasHtml = !!(def?.html);\r\n if (!hasHtml) continue;\r\n\r\n const el = this._ensureNodeElement(node, def, graph);\r\n if (!el) continue;\r\n\r\n // 노드 위치/크기 동기화 (월드 좌표 → 컨테이너 내부는 이미 scale/translate 적용)\r\n el.style.left = `${node.computed.x}px`;\r\n el.style.top = `${node.computed.y}px`;\r\n el.style.width = `${node.computed.w}px`;\r\n el.style.height = `${node.computed.h}px`;\r\n\r\n // 선택 상태 등 업데이트 훅\r\n if (def.html.update) {\r\n // 기본 레이아웃이면 header/body도 함께 전달\r\n const parts = el._domParts || {};\r\n def.html.update(node, el, {\r\n selected: selection.has(node.id),\r\n header: parts.header,\r\n body: parts.body\r\n });\r\n }\r\n\r\n seen.add(node.id);\r\n }\r\n\r\n // 없어진 노드 제거\r\n for (const [id, el] of this.nodes) {\r\n if (!seen.has(id)) {\r\n el.remove();\r\n this.nodes.delete(id);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Sync container transform with renderer state (lightweight update)\r\n * Called when zoom/pan occurs without needing full redraw\r\n */\r\n syncTransform() {\r\n const { scale, offsetX, offsetY } = this.renderer;\r\n this.container.style.transform = `translate(${offsetX}px, ${offsetY}px) scale(${scale})`;\r\n this.container.style.transformOrigin = \"0 0\";\r\n }\r\n\r\n clear() {\r\n // Remove all node elements\r\n for (const [, el] of this.nodes) {\r\n el.remove();\r\n }\r\n this.nodes.clear();\r\n }\r\n\r\n destroy() {\r\n this.clear();\r\n this.container.remove();\r\n }\r\n}\r\n","/**\r\n * Minimap - Shows overview of entire graph with viewport indicator\r\n */\r\nexport class Minimap {\r\n constructor(container, { graph, renderer, width = 200, height = 150 } = {}) {\r\n this.graph = graph;\r\n this.renderer = renderer;\r\n this.width = width;\r\n this.height = height;\r\n\r\n // Create canvas element\r\n this.canvas = document.createElement(\"canvas\");\r\n this.canvas.id = \"minimap\";\r\n this.canvas.width = width;\r\n this.canvas.height = height;\r\n this.canvas.style.position = \"fixed\";\r\n this.canvas.style.bottom = \"20px\";\r\n this.canvas.style.right = \"20px\";\r\n this.canvas.style.border = \"2px solid #444\";\r\n this.canvas.style.borderRadius = \"8px\";\r\n this.canvas.style.background = \"rgba(20, 20, 23, 0.9)\";\r\n this.canvas.style.boxShadow = \"0 4px 12px rgba(0, 0, 0, 0.5)\";\r\n this.canvas.style.pointerEvents = \"none\"; // Don't block clicks\r\n\r\n this.ctx = this.canvas.getContext(\"2d\");\r\n\r\n // Add to container\r\n container.appendChild(this.canvas);\r\n }\r\n\r\n /**\r\n * Render the minimap\r\n */\r\n render() {\r\n const { graph, renderer, ctx, width: w, height: h } = this;\r\n\r\n // Clear\r\n ctx.fillStyle = \"#141417\";\r\n ctx.fillRect(0, 0, w, h);\r\n\r\n if (graph.nodes.size === 0) return;\r\n\r\n // Calculate bounds of all nodes\r\n let minX = Infinity,\r\n minY = Infinity,\r\n maxX = -Infinity,\r\n maxY = -Infinity;\r\n for (const node of graph.nodes.values()) {\r\n const { x, y, w: nw, h: nh } = node.computed;\r\n minX = Math.min(minX, x);\r\n minY = Math.min(minY, y);\r\n maxX = Math.max(maxX, x + nw);\r\n maxY = Math.max(maxY, y + nh);\r\n }\r\n\r\n // Add margin to the bounds\r\n const margin = 100; // World units margin\r\n const graphWidth = Math.max(300, maxX - minX + margin * 2);\r\n const graphHeight = Math.max(200, maxY - minY + margin * 2);\r\n\r\n // Adjust minX and minY to center the content\r\n minX -= margin;\r\n minY -= margin;\r\n\r\n const padding = 10;\r\n\r\n const scale = Math.min(\r\n (w - padding * 2) / graphWidth,\r\n (h - padding * 2) / graphHeight\r\n );\r\n\r\n const offsetX = (w - graphWidth * scale) / 2;\r\n const offsetY = (h - graphHeight * scale) / 2;\r\n\r\n // Draw edges first (so they appear behind nodes)\r\n ctx.strokeStyle = \"rgba(127, 140, 255, 0.5)\"; // Semi-transparent edge color\r\n ctx.lineWidth = 1;\r\n for (const edge of graph.edges.values()) {\r\n const fromNode = graph.nodes.get(edge.fromNode);\r\n const toNode = graph.nodes.get(edge.toNode);\r\n if (!fromNode || !toNode) continue;\r\n\r\n // Get center points of nodes\r\n const x1 = fromNode.computed.x + fromNode.computed.w / 2;\r\n const y1 = fromNode.computed.y + fromNode.computed.h / 2;\r\n const x2 = toNode.computed.x + toNode.computed.w / 2;\r\n const y2 = toNode.computed.y + toNode.computed.h / 2;\r\n\r\n // Transform to minimap coordinates\r\n const mx1 = (x1 - minX) * scale + offsetX;\r\n const my1 = (y1 - minY) * scale + offsetY;\r\n const mx2 = (x2 - minX) * scale + offsetX;\r\n const my2 = (y2 - minY) * scale + offsetY;\r\n\r\n ctx.beginPath();\r\n ctx.moveTo(mx1, my1);\r\n ctx.lineTo(mx2, my2);\r\n ctx.stroke();\r\n }\r\n\r\n // Draw nodes\r\n ctx.fillStyle = \"#6cf\";\r\n for (const node of graph.nodes.values()) {\r\n const { x, y, w: nw, h: nh } = node.computed;\r\n const mx = (x - minX) * scale + offsetX;\r\n const my = (y - minY) * scale + offsetY;\r\n const mw = nw * scale;\r\n const mh = nh * scale;\r\n\r\n if (node.type === \"core/Group\") {\r\n ctx.fillStyle = \"rgba(102, 204, 255, 0.2)\";\r\n ctx.strokeStyle = \"#6cf\";\r\n ctx.lineWidth = 1;\r\n ctx.fillRect(mx, my, mw, mh);\r\n ctx.strokeRect(mx, my, mw, mh);\r\n } else {\r\n ctx.fillStyle = \"#6cf\";\r\n ctx.fillRect(mx, my, Math.max(2, mw), Math.max(2, mh));\r\n }\r\n }\r\n\r\n // Draw viewport rectangle\r\n const vx0 = -renderer.offsetX / renderer.scale;\r\n const vy0 = -renderer.offsetY / renderer.scale;\r\n const vw = renderer.canvas.width / renderer.scale;\r\n const vh = renderer.canvas.height / renderer.scale;\r\n\r\n const vmx = (vx0 - minX) * scale + offsetX;\r\n const vmy = (vy0 - minY) * scale + offsetY;\r\n const vmw = vw * scale;\r\n const vmh = vh * scale;\r\n\r\n ctx.strokeStyle = \"#ff6b6b\";\r\n ctx.lineWidth = 2;\r\n ctx.strokeRect(vmx, vmy, vmw, vmh);\r\n }\r\n\r\n /**\r\n * Cleanup\r\n */\r\n destroy() {\r\n if (this.canvas.parentElement) {\r\n this.canvas.parentElement.removeChild(this.canvas);\r\n }\r\n }\r\n}\r\n","/**\r\n * PropertyPanel - Node property editor panel\r\n */\r\nexport class PropertyPanel {\r\n constructor(container, { graph, hooks, registry, render }) {\r\n this.container = container;\r\n this.graph = graph;\r\n this.hooks = hooks;\r\n this.registry = registry;\r\n this.render = render; // Store render callback\r\n\r\n this.panel = null;\r\n this.currentNode = null;\r\n this.isVisible = false;\r\n\r\n this._createPanel();\r\n }\r\n\r\n _createPanel() {\r\n // Create panel element\r\n this.panel = document.createElement('div');\r\n this.panel.className = 'property-panel';\r\n this.panel.style.display = 'none';\r\n\r\n // Panel HTML structure\r\n this.panel.innerHTML = `\r\n <div class=\"panel-inner\">\r\n <div class=\"panel-header\">\r\n <div class=\"panel-title\">\r\n <span class=\"title-text\">Node Properties</span>\r\n </div>\r\n <button class=\"panel-close\" type=\"button\">×</button>\r\n </div>\r\n <div class=\"panel-content\">\r\n <!-- Content will be dynamically generated -->\r\n </div>\r\n </div>\r\n `;\r\n\r\n this.container.appendChild(this.panel);\r\n\r\n // Event listeners\r\n this.panel.querySelector('.panel-close').addEventListener('click', () => {\r\n this.close();\r\n });\r\n\r\n // Close on ESC key\r\n document.addEventListener('keydown', (e) => {\r\n if (e.key === 'Escape' && this.isVisible) {\r\n this.close();\r\n }\r\n });\r\n }\r\n\r\n open(node) {\r\n if (!node) return;\r\n\r\n this.currentNode = node;\r\n this.isVisible = true;\r\n\r\n // Update content\r\n this._renderContent();\r\n\r\n // Show panel\r\n this.panel.style.display = 'block';\r\n this.panel.classList.add('panel-visible');\r\n }\r\n\r\n close() {\r\n this.isVisible = false;\r\n this.panel.classList.remove('panel-visible');\r\n\r\n setTimeout(() => {\r\n this.panel.style.display = 'none';\r\n this.currentNode = null;\r\n }, 200);\r\n }\r\n\r\n _renderContent() {\r\n const node = this.currentNode;\r\n if (!node) return;\r\n\r\n const content = this.panel.querySelector('.panel-content');\r\n\r\n content.innerHTML = `\r\n <div class=\"section\">\r\n <div class=\"section-title\">Basic Info</div>\r\n <div class=\"section-body\">\r\n <div class=\"field\">\r\n <label>Type</label>\r\n <input type=\"text\" value=\"${node.type}\" readonly />\r\n </div>\r\n <div class=\"field\">\r\n <label>Title</label>\r\n <input type=\"text\" data-field=\"title\" value=\"${node.title || ''}\" />\r\n </div>\r\n <div class=\"field\">\r\n <label>ID</label>\r\n <input type=\"text\" value=\"${node.id}\" readonly />\r\n </div>\r\n </div>\r\n </div>\r\n \r\n <div class=\"section\">\r\n <div class=\"section-title\">Position & Size</div>\r\n <div class=\"section-body\">\r\n <div class=\"field-row\">\r\n <div class=\"field\">\r\n <label>X</label>\r\n <input type=\"number\" data-field=\"x\" value=\"${Math.round(node.computed.x)}\" />\r\n </div>\r\n <div class=\"field\">\r\n <label>Y</label>\r\n <input type=\"number\" data-field=\"y\" value=\"${Math.round(node.computed.y)}\" />\r\n </div>\r\n </div>\r\n <div class=\"field-row\">\r\n <div class=\"field\">\r\n <label>Width</label>\r\n <input type=\"number\" data-field=\"width\" value=\"${node.computed.w}\" />\r\n </div>\r\n <div class=\"field\">\r\n <label>Height</label>\r\n <input type=\"number\" data-field=\"height\" value=\"${node.computed.h}\" />\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n \r\n ${this._renderPorts(node)}\r\n ${this._renderState(node)}\r\n \r\n <div class=\"panel-actions\">\r\n <button class=\"btn-secondary panel-close-btn\">Close</button>\r\n </div>\r\n `;\r\n\r\n // Add event listeners for inputs\r\n this._attachInputListeners();\r\n }\r\n\r\n _renderPorts(node) {\r\n if (!node.inputs.length && !node.outputs.length) return '';\r\n\r\n return `\r\n <div class=\"section\">\r\n <div class=\"section-title\">Ports</div>\r\n <div class=\"section-body\">\r\n ${node.inputs.length ? `\r\n <div class=\"port-group\">\r\n <div class=\"port-group-title\">Inputs (${node.inputs.length})</div>\r\n ${node.inputs.map(p => `\r\n <div class=\"port-item\">\r\n <span class=\"port-icon ${p.portType || 'data'}\"></span>\r\n <span class=\"port-name\">${p.name}</span>\r\n ${p.datatype ? `<span class=\"port-type\">${p.datatype}</span>` : ''}\r\n </div>\r\n `).join('')}\r\n </div>\r\n ` : ''}\r\n \r\n ${node.outputs.length ? `\r\n <div class=\"port-group\">\r\n <div class=\"port-group-title\">Outputs (${node.outputs.length})</div>\r\n ${node.outputs.map(p => `\r\n <div class=\"port-item\">\r\n <span class=\"port-icon ${p.portType || 'data'}\"></span>\r\n <span class=\"port-name\">${p.name}</span>\r\n ${p.datatype ? `<span class=\"port-type\">${p.datatype}</span>` : ''}\r\n </div>\r\n `).join('')}\r\n </div>\r\n ` : ''}\r\n </div>\r\n </div>\r\n `;\r\n }\r\n\r\n _renderState(node) {\r\n if (!node.state || Object.keys(node.state).length === 0) return '';\r\n\r\n return `\r\n <div class=\"section\">\r\n <div class=\"section-title\">State</div>\r\n <div class=\"section-body\">\r\n ${Object.entries(node.state).map(([key, value]) => `\r\n <div class=\"field\">\r\n <label>${key}</label>\r\n <input \r\n type=\"${typeof value === 'number' ? 'number' : 'text'}\" \r\n data-field=\"state.${key}\" \r\n value=\"${value}\" \r\n />\r\n </div>\r\n `).join('')}\r\n </div>\r\n </div>\r\n `;\r\n }\r\n\r\n _attachInputListeners() {\r\n const inputs = this.panel.querySelectorAll('[data-field]');\r\n\r\n inputs.forEach(input => {\r\n input.addEventListener('change', () => {\r\n this._handleFieldChange(input.dataset.field, input.value);\r\n });\r\n });\r\n\r\n // Close button\r\n this.panel.querySelector('.panel-close-btn').addEventListener('click', () => {\r\n this.close();\r\n });\r\n }\r\n\r\n _handleFieldChange(field, value) {\r\n const node = this.currentNode;\r\n if (!node) return;\r\n\r\n switch (field) {\r\n case 'title':\r\n node.title = value;\r\n break;\r\n\r\n case 'x':\r\n node.pos.x = parseFloat(value);\r\n this.graph.updateWorldTransforms();\r\n break;\r\n\r\n case 'y':\r\n node.pos.y = parseFloat(value);\r\n this.graph.updateWorldTransforms();\r\n break;\r\n\r\n case 'width':\r\n node.size.width = parseFloat(value);\r\n break;\r\n\r\n case 'height':\r\n node.size.height = parseFloat(value);\r\n break;\r\n\r\n default:\r\n // Handle state fields\r\n if (field.startsWith('state.')) {\r\n const key = field.substring(6);\r\n if (node.state) {\r\n const originalValue = node.state[key];\r\n node.state[key] = typeof originalValue === 'number' ? parseFloat(value) : value;\r\n }\r\n }\r\n }\r\n\r\n // Emit update event\r\n this.hooks?.emit('node:updated', node);\r\n\r\n // Trigger render to update canvas immediately\r\n if (this.render) {\r\n this.render();\r\n }\r\n }\r\n\r\n destroy() {\r\n if (this.panel) {\r\n this.panel.remove();\r\n }\r\n }\r\n}\r\n","import { Registry } from \"./core/Registry.js\";\r\nimport { createHooks } from \"./core/Hooks.js\";\r\nimport { Graph } from \"./core/Graph.js\";\r\nimport { CanvasRenderer } from \"./render/CanvasRenderer.js\";\r\nimport { Controller } from \"./interact/Controller.js\";\r\nimport { ContextMenu } from \"./interact/ContextMenu.js\";\r\nimport { Runner } from \"./core/Runner.js\";\r\n\r\nimport { HtmlOverlay } from \"./render/HtmlOverlay.js\";\r\nimport { RemoveNodeCmd, ChangeGroupColorCmd } from \"./core/commands.js\";\r\nimport { Minimap } from \"./minimap/Minimap.js\";\r\nimport { PropertyPanel } from \"./ui/PropertyPanel.js\";\r\nimport { setupDefaultContextMenu as defaultContextMenuSetup } from \"./defaults/contextMenu.js\";\r\n\r\n\r\n\r\nexport function createGraphEditor(\r\n target,\r\n {\r\n theme,\r\n hooks: customHooks,\r\n autorun = true,\r\n showMinimap = true,\r\n enablePropertyPanel = true,\r\n propertyPanelContainer = null,\r\n setupDefaultContextMenu = true,\r\n setupContextMenu = null,\r\n plugins = [],\r\n } = {}\r\n) {\r\n let canvas;\r\n let container;\r\n\r\n if (typeof target === \"string\") {\r\n target = document.querySelector(target);\r\n }\r\n\r\n if (!target) {\r\n throw new Error(\"createGraphEditor: target element not found\");\r\n }\r\n\r\n if (target instanceof HTMLCanvasElement) {\r\n canvas = target;\r\n container = canvas.parentElement;\r\n } else {\r\n container = target;\r\n canvas = container.querySelector(\"canvas\");\r\n if (!canvas) {\r\n canvas = document.createElement(\"canvas\");\r\n canvas.style.display = \"block\";\r\n canvas.style.width = \"100%\";\r\n canvas.style.height = \"100%\";\r\n container.appendChild(canvas);\r\n }\r\n }\r\n\r\n // Ensure container has relative positioning for overlays\r\n if (getComputedStyle(container).position === \"static\") {\r\n container.style.position = \"relative\";\r\n }\r\n const hooks =\r\n customHooks ??\r\n createHooks([\r\n // essential hooks\r\n \"node:create\",\r\n \"node:move\",\r\n \"node:click\",\r\n \"node:dblclick\",\r\n \"edge:create\",\r\n \"edge:delete\",\r\n \"graph:serialize\",\r\n \"graph:deserialize\",\r\n \"error\",\r\n \"runner:tick\",\r\n \"runner:start\",\r\n \"runner:stop\",\r\n \"node:resize\",\r\n \"group:change\",\r\n \"node:updated\",\r\n ]);\r\n const registry = new Registry();\r\n const graph = new Graph({ hooks, registry });\r\n const renderer = new CanvasRenderer(canvas, { theme, registry });\r\n // HTML Overlay\r\n const htmlOverlay = new HtmlOverlay(canvas.parentElement, renderer, registry);\r\n\r\n // Register callback to sync HTML overlay transform when renderer zoom/pan changes\r\n renderer.setTransformChangeCallback(() => {\r\n htmlOverlay.syncTransform();\r\n });\r\n\r\n // Edge Canvas (above HTML overlay, for edge animations)\r\n const edgeCanvas = document.createElement(\"canvas\");\r\n edgeCanvas.id = \"edge-canvas\";\r\n Object.assign(edgeCanvas.style, {\r\n position: \"absolute\",\r\n top: \"0\",\r\n left: \"0\",\r\n pointerEvents: \"none\", // Pass through clicks\r\n zIndex: \"15\", // Above HTML overlay (10), below port canvas (20)\r\n });\r\n canvas.parentElement.appendChild(edgeCanvas);\r\n\r\n // Create edge renderer (shares transform with main renderer)\r\n const edgeRenderer = new CanvasRenderer(edgeCanvas, { theme, registry });\r\n // Sync transform properties with main renderer\r\n Object.defineProperty(edgeRenderer, 'scale', {\r\n get() { return renderer.scale; },\r\n set(v) { renderer.scale = v; }\r\n });\r\n Object.defineProperty(edgeRenderer, 'offsetX', {\r\n get() { return renderer.offsetX; },\r\n set(v) { renderer.offsetX = v; }\r\n });\r\n Object.defineProperty(edgeRenderer, 'offsetY', {\r\n get() { return renderer.offsetY; },\r\n set(v) { renderer.offsetY = v; }\r\n });\r\n\r\n // Port Canvas (above HTML overlay)\r\n const portCanvas = document.createElement(\"canvas\");\r\n portCanvas.id = \"port-canvas\";\r\n Object.assign(portCanvas.style, {\r\n position: \"absolute\",\r\n top: \"0\",\r\n left: \"0\",\r\n pointerEvents: \"none\", // Pass through clicks\r\n zIndex: \"20\", // Above edge canvas (15)\r\n });\r\n canvas.parentElement.appendChild(portCanvas);\r\n\r\n // Create port renderer (shares transform with main renderer)\r\n const portRenderer = new CanvasRenderer(portCanvas, { theme, registry });\r\n portRenderer.setTransform = renderer.setTransform.bind(renderer);\r\n portRenderer.scale = renderer.scale;\r\n portRenderer.offsetX = renderer.offsetX;\r\n portRenderer.offsetY = renderer.offsetY;\r\n\r\n const controller = new Controller({ graph, renderer, hooks, htmlOverlay, edgeRenderer, portRenderer });\r\n\r\n // Create context menu after controller (needs commandStack)\r\n const contextMenu = new ContextMenu({\r\n graph,\r\n hooks,\r\n renderer,\r\n commandStack: controller.stack,\r\n });\r\n\r\n // Connect context menu to controller\r\n controller.contextMenu = contextMenu;\r\n\r\n // Create minimap if enabled\r\n let minimap = null;\r\n if (showMinimap) {\r\n minimap = new Minimap(container, { graph, renderer });\r\n }\r\n\r\n // Initialize Property Panel if enabled\r\n let propertyPanel = null;\r\n if (enablePropertyPanel) {\r\n propertyPanel = new PropertyPanel(propertyPanelContainer || container, {\r\n graph,\r\n hooks,\r\n registry,\r\n render: () => controller.render(),\r\n });\r\n\r\n // Handle node double-click to open property panel\r\n hooks.on(\"node:dblclick\", (node) => {\r\n propertyPanel.open(node);\r\n });\r\n }\r\n\r\n const runner = new Runner({ graph, registry, hooks });\r\n\r\n // Attach runner and controller to graph for node access\r\n // This allows any node (like Trigger) to execute flows without tight coupling\r\n graph.runner = runner;\r\n graph.controller = controller;\r\n\r\n hooks.on(\"runner:tick\", ({ time, dt }) => {\r\n renderer.draw(graph, {\r\n selection: controller.selection,\r\n tempEdge: controller.connecting ? controller.renderTempEdge() : null, // 필요시 helper\r\n running: true,\r\n time,\r\n dt,\r\n });\r\n htmlOverlay.draw(graph, controller.selection);\r\n });\r\n hooks.on(\"runner:start\", () => {\r\n // 첫 프레임 즉시 렌더\r\n renderer.draw(graph, {\r\n selection: controller.selection,\r\n tempEdge: controller.connecting ? controller.renderTempEdge() : null,\r\n running: true,\r\n time: performance.now(),\r\n dt: 0,\r\n });\r\n htmlOverlay.draw(graph, controller.selection);\r\n });\r\n hooks.on(\"runner:stop\", () => {\r\n // 정지 프레임\r\n renderer.draw(graph, {\r\n selection: controller.selection,\r\n tempEdge: controller.connecting ? controller.renderTempEdge() : null,\r\n running: false,\r\n time: performance.now(),\r\n dt: 0,\r\n });\r\n htmlOverlay.draw(graph, controller.selection);\r\n });\r\n\r\n hooks.on(\"node:updated\", () => {\r\n controller.render();\r\n });\r\n\r\n // Note: Example nodes have been moved to src/nodes/\r\n // Users can import and register them selectively:\r\n // import { registerAllNodes } from \"html-overlay-node/nodes\";\r\n // registerAllNodes(registry, hooks);\r\n\r\n // Setup context menu\r\n if (setupDefaultContextMenu) {\r\n // Use default context menu setup\r\n defaultContextMenuSetup(contextMenu, { controller, graph, hooks });\r\n }\r\n\r\n // Allow custom context menu setup\r\n if (setupContextMenu) {\r\n setupContextMenu(contextMenu, { controller, graph, hooks });\r\n }\r\n\r\n // Install plugins\r\n if (plugins && plugins.length > 0) {\r\n for (const plugin of plugins) {\r\n if (typeof plugin.install === \"function\") {\r\n try {\r\n plugin.install({ graph, registry, hooks, runner, controller, contextMenu }, plugin.options || {});\r\n } catch (err) {\r\n console.error(`[createGraphEditor] Failed to install plugin \"${plugin.name || 'unknown'}\":`, err);\r\n hooks?.emit?.(\"error\", err);\r\n }\r\n } else {\r\n console.warn(`[createGraphEditor] Plugin \"${plugin.name || 'unknown'}\" does not have an install() method`);\r\n }\r\n }\r\n }\r\n\r\n\r\n // initial render & resize\r\n renderer.resize(canvas.clientWidth, canvas.clientHeight);\r\n edgeRenderer.resize(canvas.clientWidth, canvas.clientHeight);\r\n portRenderer.resize(canvas.clientWidth, canvas.clientHeight);\r\n controller.render();\r\n\r\n const ro = new ResizeObserver(() => {\r\n renderer.resize(canvas.clientWidth, canvas.clientHeight);\r\n edgeRenderer.resize(canvas.clientWidth, canvas.clientHeight);\r\n portRenderer.resize(canvas.clientWidth, canvas.clientHeight);\r\n controller.render();\r\n });\r\n ro.observe(canvas);\r\n\r\n // Wrap controller.render to update minimap\r\n const originalRender = controller.render.bind(controller);\r\n controller.render = function () {\r\n originalRender();\r\n if (minimap) {\r\n minimap.render();\r\n }\r\n };\r\n\r\n const api = {\r\n addGroup: (args = {}) => {\r\n controller.graph.groupManager.addGroup(args);\r\n controller.render();\r\n },\r\n graph,\r\n renderer,\r\n controller, // Expose controller for snap-to-grid access\r\n runner, // Expose runner for trigger\r\n minimap, // Expose minimap\r\n contextMenu,\r\n hooks, // Expose hooks for event handling\r\n registry, // Expose registry for node types\r\n htmlOverlay, // Expose htmlOverlay for clearing/resetting\r\n propertyPanel, // Expose propertyPanel\r\n render: () => controller.render(),\r\n start: () => runner.start(),\r\n stop: () => runner.stop(),\r\n destroy: () => {\r\n runner.stop();\r\n ro.disconnect();\r\n controller.destroy();\r\n htmlOverlay.destroy();\r\n contextMenu.destroy();\r\n if (propertyPanel) propertyPanel.destroy();\r\n if (minimap) minimap.destroy();\r\n },\r\n };\r\n\r\n if (autorun) runner.start();\r\n return api;\r\n}\r\n","export function createHooks(names) {\r\n const map = Object.fromEntries(names.map((n) => [n, new Set()]));\r\n return {\r\n on(name, fn) {\r\n if (!map[name]) map[name] = new Set();\r\n map[name].add(fn);\r\n return () => map[name].delete(fn);\r\n },\r\n off(name, fn) {\r\n if (map[name]) {\r\n map[name].delete(fn);\r\n }\r\n },\r\n emit(name, ...args) {\r\n if (!map[name]) return;\r\n for (const fn of map[name]) fn(...args);\r\n },\r\n };\r\n}\r\n","/**\r\n * Default Context Menu Setup\r\n * \r\n * This module provides the default context menu configuration.\r\n * Users can import and use this directly, modify it, or create their own.\r\n * \r\n * @example\r\n * import { setupDefaultContextMenu } from \"html-overlay-node/defaults\";\r\n * setupDefaultContextMenu(editor.contextMenu, { controller, graph, hooks });\r\n */\r\n\r\nimport { RemoveNodeCmd, ChangeGroupColorCmd } from \"../core/commands.js\";\r\n\r\n/**\r\n * Setup default context menu items\r\n * @param {ContextMenu} contextMenu - Context menu instance\r\n * @param {Object} options - Configuration options\r\n * @param {Controller} options.controller - Controller instance\r\n * @param {Graph} options.graph - Graph instance\r\n * @param {Hooks} options.hooks - Hooks instance\r\n */\r\nexport function setupDefaultContextMenu(contextMenu, { controller, graph, hooks }) {\r\n // Add Node submenu (canvas background only)\r\n // Use a function to dynamically generate node types when menu is shown\r\n const getNodeTypes = () => {\r\n const nodeTypes = [];\r\n for (const [key, typeDef] of graph.registry.types.entries()) {\r\n nodeTypes.push({\r\n id: `add-${key}`,\r\n label: typeDef.title || key,\r\n action: () => {\r\n // Get world position from context menu\r\n const worldPos = contextMenu.worldPosition || { x: 100, y: 100 };\r\n\r\n // Add node at click position\r\n const node = graph.addNode(key, {\r\n x: worldPos.x,\r\n y: worldPos.y,\r\n });\r\n\r\n hooks?.emit(\"node:updated\", node);\r\n controller.render(); // Update minimap and canvas\r\n },\r\n });\r\n }\r\n return nodeTypes;\r\n };\r\n\r\n contextMenu.addItem(\"add-node\", \"Add Node\", {\r\n condition: (target) => !target,\r\n submenu: getNodeTypes, // Pass function instead of array\r\n order: 5,\r\n });\r\n\r\n // Delete Node (for all nodes except groups)\r\n contextMenu.addItem(\"delete-node\", \"Delete Node\", {\r\n condition: (target) => target && target.type !== \"core/Group\",\r\n action: (target) => {\r\n const cmd = RemoveNodeCmd(graph, target);\r\n controller.stack.exec(cmd);\r\n hooks?.emit(\"node:updated\", target);\r\n },\r\n order: 10,\r\n });\r\n\r\n // Change Group Color (for groups only) - with submenu\r\n const colors = [\r\n { name: \"Default\", color: \"#39424e\" },\r\n { name: \"Slate\", color: \"#4a5568\" },\r\n { name: \"Gray\", color: \"#2d3748\" },\r\n { name: \"Blue\", color: \"#1a365d\" },\r\n { name: \"Green\", color: \"#22543d\" },\r\n { name: \"Red\", color: \"#742a2a\" },\r\n { name: \"Purple\", color: \"#44337a\" },\r\n ];\r\n\r\n contextMenu.addItem(\"change-group-color\", \"Change Color\", {\r\n condition: (target) => target && target.type === \"core/Group\",\r\n submenu: colors.map((colorInfo) => ({\r\n id: `color-${colorInfo.color}`,\r\n label: colorInfo.name,\r\n color: colorInfo.color,\r\n action: (target) => {\r\n const currentColor = target.state.color || \"#39424e\";\r\n const cmd = ChangeGroupColorCmd(target, currentColor, colorInfo.color);\r\n controller.stack.exec(cmd);\r\n hooks?.emit(\"node:updated\", target);\r\n },\r\n })),\r\n order: 20,\r\n });\r\n\r\n contextMenu.addItem(\"delete-group\", \"Delete Group\", {\r\n condition: (target) => target && target.type === \"core/Group\",\r\n action: (target) => {\r\n const cmd = RemoveNodeCmd(graph, target);\r\n controller.stack.exec(cmd);\r\n hooks?.emit(\"node:updated\", target);\r\n },\r\n order: 20,\r\n });\r\n}\r\n"],"names":["Registry","constructor","this","types","Map","register","type","def","Error","has","set","unregister","delete","removeAll","clear","createInstance","get","available","Array","from","keys","join","randomUUID","g","globalThis","self","window","global","c","crypto","msCrypto","getRandomValues","bytes","Uint8Array","hex","b","toString","padStart","slice","req","Function","nodeCrypto","randomBytes","i","Math","floor","random","Node","id","title","x","y","width","height","pos","size","inputs","outputs","state","parent","children","Set","computed","w","h","_updateMinSize","inHeight","HEADER_HEIGHT","length","outHeight","minHeight","max","addInput","name","datatype","portType","port","dir","push","addOutput","Edge","fromNode","fromPort","toNode","toPort","GroupManager","graph","hooks","_groups","addGroup","color","members","console","warn","groupNode","addNode","memberId","node","getNodeById","reparent","_a","emit","addGroupFromSelection","_title","_margin","removeGroup","child","removeNode","resizeGroup","dw","dh","updateWorldTransforms","hitTestResizeHandle","nodes","values","reverse","gx","gy","gw","gh","group","handle","Graph","registry","edges","_valuesA","_valuesB","_useAasCurrent","groupManager","opts","_b","o","_c","onCreate","call","_d","nodeId","eid","e","addEdge","roots","n","stack","map","px","py","pop","newParent","wx","wy","add","_curBuf","_nextBuf","swapBuffers","setOutput","portId","value","log","key","getInput","edge","toJSON","json","parentId","fromJSON","nd","ed","portRect","idx","nx","ny","portWidth","portHeight","_CanvasRenderer","canvas","theme","edgeStyle","ctx","getContext","scale","minScale","maxScale","offsetX","offsetY","Object","assign","bg","grid","nodeBorder","text","textMuted","portExec","edgeActive","accent","accentBright","setEdgeStyle","style","setRegistry","reg","resize","setTransform","min","_onTransformChange","setTransformChangeCallback","callback","panBy","dx","dy","zoomAt","factor","cx","cy","prev","next","screenToWorld","worldToScreen","_applyTransform","translate","_resetTransform","_drawArrowhead","x1","y1","x2","y2","s","ang","atan2","beginPath","moveTo","lineTo","cos","PI","sin","closePath","fill","_drawScreenText","lx","ly","fontPx","align","baseline","dpr","sx","sy","save","round","font","fillStyle","textAlign","textBaseline","fillText","restore","drawGrid","fillRect","strokeStyle","_rgba","lineWidth","step","x0","y0","startX","startY","stroke","draw","selection","tempEdge","running","time","performance","now","dt","groups","activeEdges","drawEdges","sel","onDraw","renderer","_drawNode","dashArray","dashOffset","phase","FONT_SIZE","shouldAnimate","setLineDash","lineDashOffset","_drawEdge","a","prevDash","getLineDash","ptsForArrow","_drawLine","_drawOrthogonal","_drawCurve","p1","p2","html","_f","_e","_drawPorts","replace","parseInt","split","selected","skipPorts","shadowColor","shadowBlur","shadowOffsetY","roundRect","tl","tr","br","bl","quadraticCurveTo","forEach","p","rct","portSize","arc","to","iOut","findIndex","iIn","pr1","pr2","_drawPolyline","points","midX","pts","prevJoin","lineJoin","prevCap","lineCap","abs","bezierCurveTo","drawEdgesOnly","clearRect","__publicField","CanvasRenderer","r","findEdgeId","d","RemoveNodeCmd","removedNode","removedEdges","filter","undo","CommandStack","undoStack","redoStack","exec","cmd","do","redo","_Controller","htmlOverlay","contextMenu","edgeRenderer","portRenderer","dragging","connecting","panning","resizing","gDragging","gResizing","boxSelecting","snapToGrid","gridSize","_cursor","_onKeyPressEvt","_onKeyPress","bind","_onDownEvt","_onDown","_onWheelEvt","_onWheel","_onMoveEvt","_onMove","_onUpEvt","_onUp","_onContextMenuEvt","_onContextMenu","_onDblClickEvt","_onDblClick","_bindEvents","destroy","removeEventListener","passive","addEventListener","isAlt","altKey","isShift","shiftKey","isCtrl","ctrlKey","toLowerCase","metaKey","preventDefault","_createGroupFromSelection","render","_alignNodesVertical","_alignNodesHorizontal","nodeObj","_setCursor","cursor","_posScreen","getBoundingClientRect","clientX","left","clientY","top","_posWorld","_findNodeAtWorld","list","_findChildNodeAtWorld","parentNode","grandchild","_findPortAtWorld","rectHas","_findIncomingEdge","pow","deltaY","show","_resizeHandleRect","_hitResizeHandle","button","startW","startH","incoming","edgeId","RemoveEdgeCmd","outR","screenFrom","currentX","currentY","startPos","selectedNodes","selectedId","selectedNode","startWorldX","startWorldY","startLocalX","startLocalY","childrenWorldPos","worldX","worldY","minW","MIN_NODE_WIDTH","minH","MIN_NODE_HEIGHT","targetWx","targetWy","_snapToGrid","deltaX","find","sn","newWorldX","newWorldY","parentWx","parentWy","childInfo","newGroupX","newGroupY","portIn","addedId","AddEdgeCmd","fromSize","toSize","potentialParent","_findPotentialParent","_autoParentNodesInGroup","minX","maxX","minY","maxY","nw","nh","nodeCenterX","nodeCenterY","excludeNode","isDescendant","Infinity","groupX","groupY","groupWidth","margin","groupHeight","avgY","reduce","sum","parentY","avgX","parentX","tEdge","renderTempEdge","screenStart","screenEnd","strokeRect","_portAnchorScreen","Controller","ContextMenu","commandStack","items","visible","target","position","menuElement","_createMenuElement","_onDocumentClick","contains","hide","addItem","label","options","action","submenu","condition","order","removeItem","sort","error","item","worldPos","worldPosition","_renderItems","display","requestAnimationFrame","rect","vw","innerWidth","vh","innerHeight","adjustedX","adjustedY","right","bottom","document","querySelectorAll","remove","removeChild","menu","createElement","className","minWidth","backgroundColor","border","borderRadius","boxShadow","zIndex","padding","fontFamily","fontSize","body","appendChild","innerHTML","visibleItems","itemEl","contentWrapper","alignItems","justifyContent","labelEl","textContent","arrow","marginLeft","opacity","transition","userSelect","_hideTimeout","clearTimeout","submenuItems","_showSubmenu","submenuEl","_submenuElement","setTimeout","elementFromPoint","_hideSubmenu","stopPropagation","parentItemEl","subItem","subItemEl","gap","swatch","flexShrink","relatedTarget","parentRect","submenuRect","Runner","cyclesPerFrame","_raf","_last","isRunning","setCyclesPerFrame","cycles","nCycles","onExecute","portName","err","runOnce","startNodeId","executedNodes","allConnectedNodes","queue","visited","currentNodeId","shift","input","executeNode","nextNodes","findAllNextExecNodes","connectedEdges","connectedNodes","execOutputs","execOutput","start","loop","t","dtMs","cps","stop","cancelAnimationFrame","HtmlOverlay","host","container","inset","pointerEvents","_createDefaultNodeLayout","_node","flexDirection","boxSizing","overflow","header","flex","_domParts","_ensureNodeElement","el","init","transform","transformOrigin","seen","update","parts","syncTransform","Minimap","background","graphWidth","graphHeight","mx1","my1","mx2","my2","mx","my","mw","mh","vmx","vmy","vmw","vmh","parentElement","PropertyPanel","panel","currentNode","isVisible","_createPanel","querySelector","close","open","_renderContent","classList","_renderPorts","_renderState","_attachInputListeners","entries","_handleFieldChange","dataset","field","parseFloat","startsWith","substring","originalValue","customHooks","autorun","showMinimap","enablePropertyPanel","propertyPanelContainer","setupDefaultContextMenu","setupContextMenu","plugins","HTMLCanvasElement","getComputedStyle","names","fromEntries","on","fn","off","args","createHooks","edgeCanvas","defineProperty","v","portCanvas","controller","minimap","propertyPanel","runner","nodeTypes","typeDef","colorInfo","currentColor","fromColor","toColor","defaultContextMenuSetup","plugin","install","clientWidth","clientHeight","ro","ResizeObserver","observe","originalRender","api","disconnect"],"mappings":"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"}
1
+ {"version":3,"file":"html-overlay-node.umd.js","sources":["../src/core/Registry.js","../src/utils/utils.js","../src/core/Node.js","../src/core/Edge.js","../src/groups/GroupManager.js","../src/core/Graph.js","../src/render/hitTest.js","../src/render/CanvasRenderer.js","../src/core/commands.js","../src/core/CommandStack.js","../src/interact/Controller.js","../src/interact/ContextMenu.js","../src/core/Runner.js","../src/render/HtmlOverlay.js","../src/minimap/Minimap.js","../src/ui/PropertyPanel.js","../src/ui/HelpOverlay.js","../src/index.js","../src/core/Hooks.js","../src/defaults/contextMenu.js"],"sourcesContent":["// src/core/Registry.js\r\n\r\n/**\r\n * Registry for managing node type definitions\r\n */\r\nexport class Registry {\r\n constructor() {\r\n this.types = new Map();\r\n }\r\n\r\n /**\r\n * Register a new node type\r\n * @param {string} type - Unique type identifier (e.g., \"core/Note\")\r\n * @param {Object} def - Node definition\r\n * @param {string} [def.title] - Display title\r\n * @param {Object} [def.size] - Default size {w, h}\r\n * @param {Array} [def.inputs] - Input port definitions\r\n * @param {Array} [def.outputs] - Output port definitions\r\n * @param {Function} [def.onCreate] - Called when node is created\r\n * @param {Function} [def.onExecute] - Called each execution cycle\r\n * @param {Function} [def.onDraw] - Custom drawing function\r\n * @param {Object} [def.html] - HTML overlay configuration\r\n * @throws {Error} If type is already registered or invalid\r\n */\r\n register(type, def) {\r\n if (!type || typeof type !== 'string') {\r\n throw new Error(`Invalid node type: type must be a non-empty string, got ${typeof type}`);\r\n }\r\n if (!def || typeof def !== 'object') {\r\n throw new Error(`Invalid definition for type \"${type}\": definition must be an object`);\r\n }\r\n if (this.types.has(type)) {\r\n throw new Error(`Node type \"${type}\" is already registered. Use unregister() first to replace it.`);\r\n }\r\n this.types.set(type, def);\r\n }\r\n\r\n /**\r\n * Unregister a node type\r\n * @param {string} type - Type identifier to unregister\r\n * @throws {Error} If type doesn't exist\r\n */\r\n unregister(type) {\r\n if (!this.types.has(type)) {\r\n throw new Error(`Cannot unregister type \"${type}\": type is not registered`);\r\n }\r\n this.types.delete(type);\r\n }\r\n\r\n /**\r\n * Remove all registered node types\r\n */\r\n removeAll() {\r\n this.types.clear();\r\n }\r\n\r\n /**\r\n * Get the definition for a registered node type\r\n * @param {string} type - Type identifier\r\n * @returns {Object} Node definition\r\n * @throws {Error} If type is not registered\r\n */\r\n createInstance(type) {\r\n const def = this.types.get(type);\r\n if (!def) {\r\n const available = Array.from(this.types.keys()).join(', ') || 'none';\r\n throw new Error(`Unknown node type: \"${type}\". Available types: ${available}`);\r\n }\r\n return def;\r\n }\r\n}\r\n","export function randomUUID() {\r\n // 1) 전역 객체 안전 획득\r\n const g =\r\n typeof globalThis !== \"undefined\" ? globalThis :\r\n typeof self !== \"undefined\" ? self :\r\n typeof window !== \"undefined\" ? window :\r\n typeof global !== \"undefined\" ? global : {};\r\n\r\n const c = g.crypto || g.msCrypto; // IE11 호환\r\n\r\n // 2) 네이티브 지원 (브라우저/Deno 등)\r\n if (c && typeof c.randomUUID === \"function\") {\r\n return c.randomUUID();\r\n }\r\n\r\n // 3) Web Crypto만 있는 경우 (getRandomValues로 직접 생성)\r\n if (c && typeof c.getRandomValues === \"function\") {\r\n const bytes = new Uint8Array(16);\r\n c.getRandomValues(bytes);\r\n // RFC4122 버전/변형 비트 설정\r\n bytes[6] = (bytes[6] & 0x0f) | 0x40;\r\n bytes[8] = (bytes[8] & 0x3f) | 0x80;\r\n\r\n const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, \"0\"));\r\n return (\r\n hex.slice(0, 4).join(\"\") + \"-\" +\r\n hex.slice(4, 6).join(\"\") + \"-\" +\r\n hex.slice(6, 8).join(\"\") + \"-\" +\r\n hex.slice(8, 10).join(\"\") + \"-\" +\r\n hex.slice(10, 16).join(\"\")\r\n );\r\n }\r\n\r\n // 4) Node.js 전용 대체 (require가 있을 때)\r\n try {\r\n // 번들러/ESM 충돌 피하려고 런타임에만 require 접근\r\n\r\n const req = Function('return typeof require === \"function\" ? require : null')();\r\n if (req) {\r\n const nodeCrypto = req(\"crypto\");\r\n if (typeof nodeCrypto.randomUUID === \"function\") {\r\n return nodeCrypto.randomUUID();\r\n }\r\n const bytes = nodeCrypto.randomBytes(16);\r\n bytes[6] = (bytes[6] & 0x0f) | 0x40;\r\n bytes[8] = (bytes[8] & 0x3f) | 0x80;\r\n\r\n const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, \"0\"));\r\n return (\r\n hex.slice(0, 4).join(\"\") + \"-\" +\r\n hex.slice(4, 6).join(\"\") + \"-\" +\r\n hex.slice(6, 8).join(\"\") + \"-\" +\r\n hex.slice(8, 10).join(\"\") + \"-\" +\r\n hex.slice(10, 16).join(\"\")\r\n );\r\n }\r\n } catch {\r\n // ignore\r\n }\r\n\r\n // 5) 최후의 비보안 대체 (CSPRNG 아님!)\r\n const bytes = new Uint8Array(16);\r\n for (let i = 0; i < 16; i++) bytes[i] = Math.floor(Math.random() * 256);\r\n bytes[6] = (bytes[6] & 0x0f) | 0x40;\r\n bytes[8] = (bytes[8] & 0x3f) | 0x80;\r\n\r\n const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, \"0\"));\r\n return (\r\n hex.slice(0, 4).join(\"\") + \"-\" +\r\n hex.slice(4, 6).join(\"\") + \"-\" +\r\n hex.slice(6, 8).join(\"\") + \"-\" +\r\n hex.slice(8, 10).join(\"\") + \"-\" +\r\n hex.slice(10, 16).join(\"\")\r\n );\r\n}","import { randomUUID } from \"../utils/utils.js\";\r\n\r\n// src/core/Node.js\r\n\r\n/**\r\n * Node represents a single node in the graph\r\n */\r\nexport class Node {\r\n /**\r\n * Create a new Node\r\n * @param {Object} options - Node configuration\r\n * @param {string} [options.id] - Unique identifier (auto-generated if not provided)\r\n * @param {string} options.type - Node type identifier\r\n * @param {string} [options.title] - Display title (defaults to type)\r\n * @param {number} [options.x=0] - X position\r\n * @param {number} [options.y=0] - Y position\r\n * @param {number} [options.width=160] - Node width\r\n * @param {number} [options.height=60] - Node height\r\n */\r\n constructor({ id, type, title, x = 0, y = 0, width = 160, height = 60 }) {\r\n if (!type) {\r\n throw new Error(\"Node type is required\");\r\n }\r\n this.id = id ?? randomUUID();\r\n this.type = type;\r\n this.title = title ?? type;\r\n this.pos = { x, y };\r\n this.size = { width, height };\r\n this.inputs = []; // {id,name,datatype,portType,dir}\r\n this.outputs = []; // {id,name,datatype,portType,dir}\r\n this.state = {}; // User state data\r\n\r\n // Tree Structure\r\n this.parent = null; // Parent Node (or null if root)\r\n this.children = new Set(); // Set<Node>\r\n this.computed = { x: 0, y: 0, w: 0, h: 0 }; // World Transform\r\n }\r\n\r\n /**\r\n * Add an input port to this node\r\n * @param {string} name - Port name\r\n * @param {string} [datatype=\"any\"] - Data type for the port\r\n * @param {string} [portType=\"data\"] - Port type: \"exec\" or \"data\"\r\n * @returns {Object} The created port\r\n */\r\n /**\r\n * Recalculate minimum size based on ports\r\n */\r\n _updateMinSize() {\r\n const HEADER_HEIGHT = 28;\r\n const PORT_SPACING = 24;\r\n const BOTTOM_PADDING = 10;\r\n\r\n // Calculate required height for inputs and outputs\r\n const inHeight = HEADER_HEIGHT + 10 + this.inputs.length * PORT_SPACING + BOTTOM_PADDING;\r\n const outHeight = HEADER_HEIGHT + 10 + this.outputs.length * PORT_SPACING + BOTTOM_PADDING;\r\n\r\n const minHeight = Math.max(inHeight, outHeight, 60); // Minimum 60px base\r\n\r\n if (this.size.height < minHeight) {\r\n this.size.height = minHeight;\r\n }\r\n }\r\n\r\n addInput(name, datatype = \"any\", portType = \"data\") {\r\n // ... existing validation ...\r\n if (typeof name !== \"string\" || (portType === \"data\" && !name)) {\r\n throw new Error(\"Input port name must be a string (non-empty for data ports)\");\r\n }\r\n const port = { id: randomUUID(), name, datatype, portType, dir: \"in\" };\r\n this.inputs.push(port);\r\n this._updateMinSize();\r\n return port;\r\n }\r\n\r\n addOutput(name, datatype = \"any\", portType = \"data\") {\r\n // ... existing validation ...\r\n if (typeof name !== \"string\" || (portType === \"data\" && !name)) {\r\n throw new Error(\"Output port name must be a string (non-empty for data ports)\");\r\n }\r\n const port = { id: randomUUID(), name, datatype, portType, dir: \"out\" };\r\n this.outputs.push(port);\r\n this._updateMinSize();\r\n return port;\r\n }\r\n}\r\n","import { randomUUID } from \"../utils/utils.js\";\r\n\r\n// src/core/Edge.js\r\n\r\n/**\r\n * Edge represents a connection between two node ports\r\n */\r\nexport class Edge {\r\n /**\r\n * Create a new Edge\r\n * @param {Object} options - Edge configuration\r\n * @param {string} [options.id] - Unique identifier (auto-generated if not provided)\r\n * @param {string} options.fromNode - Source node ID\r\n * @param {string} options.fromPort - Source port ID\r\n * @param {string} options.toNode - Target node ID\r\n * @param {string} options.toPort - Target port ID\r\n */\r\n constructor({ id, fromNode, fromPort, toNode, toPort }) {\r\n // Allow empty strings for port names (exec ports use empty names)\r\n // Only check for null/undefined\r\n if (fromNode == null || fromPort == null || toNode == null || toPort == null) {\r\n throw new Error(\"Edge requires fromNode, fromPort, toNode, and toPort (null/undefined not allowed)\");\r\n }\r\n this.id = id ?? randomUUID();\r\n this.fromNode = fromNode;\r\n this.fromPort = fromPort;\r\n this.toNode = toNode;\r\n this.toPort = toPort;\r\n }\r\n}\r\n","// src/groups/GroupManager.js\r\n\r\n\r\nexport class GroupManager {\r\n constructor({ graph, hooks }) {\r\n this.graph = graph;\r\n this.hooks = hooks;\r\n this._groups = [];\r\n }\r\n\r\n // ---------- CRUD ----------\r\n addGroup({\r\n title = \"Group\",\r\n x = 0,\r\n y = 0,\r\n width = 240,\r\n height = 160,\r\n color = \"#39424e\",\r\n members = [],\r\n } = {}) {\r\n // Validate parameters\r\n if (width < 100 || height < 60) {\r\n console.warn(\"Group size too small, using minimum size\");\r\n width = Math.max(100, width);\r\n height = Math.max(60, height);\r\n }\r\n\r\n const groupNode = this.graph.addNode(\"core/Group\", {\r\n title,\r\n x,\r\n y,\r\n width,\r\n height,\r\n });\r\n groupNode.state.color = color;\r\n\r\n // Reparent members with validation\r\n for (const memberId of members) {\r\n const node = this.graph.getNodeById(memberId);\r\n if (node) {\r\n if (node.type === \"core/Group\") {\r\n console.warn(`Cannot add group ${memberId} as member of another group`);\r\n continue;\r\n }\r\n this.graph.reparent(node, groupNode);\r\n } else {\r\n console.warn(`Member node ${memberId} not found, skipping`);\r\n }\r\n }\r\n\r\n this._groups.push(groupNode);\r\n this.hooks?.emit(\"group:change\");\r\n return groupNode;\r\n }\r\n\r\n addGroupFromSelection({ _title = \"Group\", _margin = { x: 12, y: 12 } } = {}) {\r\n // Controller에서 selection을 받아와야 함\r\n // 여기서는 간단히 graph.nodes를 순회하며 selected 상태를 확인한다고 가정하거나\r\n // 외부에서 members를 넘겨받는 것이 좋음\r\n // 일단은 외부에서 members를 넘겨받는 addGroup을 활용.\r\n return null;\r\n }\r\n\r\n removeGroup(id) {\r\n const groupNode = this.graph.getNodeById(id);\r\n if (!groupNode || groupNode.type !== \"core/Group\") return;\r\n\r\n // Ungroup: reparent children to group's parent\r\n const children = [...groupNode.children];\r\n for (const child of children) {\r\n this.graph.reparent(child, groupNode.parent);\r\n }\r\n\r\n this.graph.removeNode(id);\r\n this.hooks?.emit(\"group:change\");\r\n }\r\n\r\n // ---------- 이동/리사이즈 ----------\r\n // 이제 Node의 이동/리사이즈 로직을 따름.\r\n // Controller에서 Node 이동 시 updateWorldTransforms가 호출되므로 자동 처리됨.\r\n\r\n resizeGroup(id, dw, dh) {\r\n const g = this.graph.getNodeById(id);\r\n if (!g || g.type !== \"core/Group\") return;\r\n\r\n const minW = 100;\r\n const minH = 60;\r\n g.size.width = Math.max(minW, g.size.width + dw);\r\n g.size.height = Math.max(minH, g.size.height + dh);\r\n\r\n this.graph.updateWorldTransforms();\r\n this.hooks?.emit(\"group:change\");\r\n }\r\n\r\n // ---------- 히트테스트 & 드래그 ----------\r\n // 이제 Group도 Node이므로 Controller의 Node 히트테스트 로직을 따름.\r\n // 단, Resize Handle은 별도 처리가 필요할 수 있음.\r\n\r\n hitTestResizeHandle(x, y) {\r\n const handleSize = 10;\r\n // 역순 순회 (위에 있는 것부터)\r\n const nodes = [...this.graph.nodes.values()].reverse();\r\n\r\n for (const node of nodes) {\r\n if (node.type !== \"core/Group\") continue;\r\n\r\n // World Transform 사용\r\n const { x: gx, y: gy, w: gw, h: gh } = node.computed;\r\n\r\n if (x >= gx + gw - handleSize && x <= gx + gw && y >= gy + gh - handleSize && y <= gy + gh) {\r\n return { group: node, handle: \"se\" };\r\n }\r\n }\r\n return null;\r\n }\r\n}\r\n","import { Node } from \"./Node.js\";\r\nimport { Edge } from \"./Edge.js\";\r\nimport { GroupManager } from \"../groups/GroupManager.js\";\r\n\r\n/**\r\n * Graph manages the collection of nodes and edges\r\n */\r\nexport class Graph {\r\n /**\r\n * Create a new Graph\r\n * @param {Object} options - Graph configuration\r\n * @param {Object} options.hooks - Event hooks system\r\n * @param {Object} options.registry - Node type registry\r\n */\r\n constructor({ hooks, registry }) {\r\n if (!registry) {\r\n throw new Error(\"Graph requires a registry\");\r\n }\r\n this.nodes = new Map();\r\n this.edges = new Map();\r\n this.hooks = hooks;\r\n this.registry = registry;\r\n // double buffer for deterministic cycles\r\n this._valuesA = new Map(); // current\r\n this._valuesB = new Map(); // next\r\n this._useAasCurrent = true;\r\n\r\n this.groupManager = new GroupManager({\r\n graph: this,\r\n hooks: this.hooks,\r\n });\r\n }\r\n /**\r\n * Get a node by its ID\r\n * @param {string} id - Node ID\r\n * @returns {Node|null} The node or null if not found\r\n */\r\n getNodeById(id) {\r\n return this.nodes.get(id) || null;\r\n }\r\n /**\r\n * Add a node to the graph\r\n * @param {string} type - Node type identifier\r\n * @param {Object} [opts={}] - Additional node options (x, y, width, height, etc.)\r\n * @returns {Node} The created node\r\n * @throws {Error} If node type is not registered\r\n */\r\n addNode(type, opts = {}) {\r\n const def = this.registry.types.get(type);\r\n if (!def) {\r\n const available = Array.from(this.registry.types.keys()).join(\", \") || \"none\";\r\n throw new Error(`Unknown node type: \"${type}\". Available types: ${available}`);\r\n }\r\n const height = opts.height || def.size?.h || this._calculateDefaultNodeHeight(def);\r\n \r\n const node = new Node({\r\n type,\r\n title: def.title,\r\n width: opts.width || def.size?.w || 140,\r\n height,\r\n ...opts,\r\n });\r\n for (const i of def.inputs || []) node.addInput(i.name, i.datatype, i.portType || \"data\");\r\n for (const o of def.outputs || []) node.addOutput(o.name, o.datatype, o.portType || \"data\");\r\n def.onCreate?.(node);\r\n this.nodes.set(node.id, node);\r\n this.hooks?.emit(\"node:create\", node);\r\n return node;\r\n }\r\n /**\r\n * Remove a node and its connected edges from the graph\r\n * @param {string} nodeId - ID of the node to remove\r\n */\r\n removeNode(nodeId) {\r\n // Remove all edges connected to this node\r\n for (const [eid, e] of this.edges) {\r\n if (e.fromNode === nodeId || e.toNode === nodeId) {\r\n this.edges.delete(eid);\r\n }\r\n }\r\n this.nodes.delete(nodeId);\r\n }\r\n /**\r\n * Add an edge connecting two node ports\r\n * @param {string} fromNode - Source node ID\r\n * @param {string} fromPort - Source port ID\r\n * @param {string} toNode - Target node ID\r\n * @param {string} toPort - Target port ID\r\n * @returns {Edge} The created edge\r\n * @throws {Error} If nodes don't exist\r\n */\r\n addEdge(fromNode, fromPort, toNode, toPort) {\r\n // Validate nodes exist\r\n if (!this.nodes.has(fromNode)) {\r\n throw new Error(`Cannot create edge: source node \"${fromNode}\" not found`);\r\n }\r\n if (!this.nodes.has(toNode)) {\r\n throw new Error(`Cannot create edge: target node \"${toNode}\" not found`);\r\n }\r\n\r\n const e = new Edge({ fromNode, fromPort, toNode, toPort });\r\n this.edges.set(e.id, e);\r\n this.hooks?.emit(\"edge:create\", e);\r\n return e;\r\n }\r\n\r\n /**\r\n * Clear all nodes and edges from the graph\r\n */\r\n clear() {\r\n this.nodes.clear();\r\n this.edges.clear();\r\n }\r\n\r\n updateWorldTransforms() {\r\n // 1. Find roots\r\n const roots = [];\r\n for (const n of this.nodes.values()) {\r\n if (!n.parent) roots.push(n);\r\n }\r\n\r\n // 2. Traverse\r\n const stack = roots.map((n) => ({ node: n, px: 0, py: 0 }));\r\n while (stack.length > 0) {\r\n const { node, px, py } = stack.pop();\r\n node.computed.x = px + node.pos.x;\r\n node.computed.y = py + node.pos.y;\r\n node.computed.w = node.size.width;\r\n node.computed.h = node.size.height;\r\n\r\n for (const child of node.children) {\r\n stack.push({ node: child, px: node.computed.x, py: node.computed.y });\r\n }\r\n }\r\n }\r\n\r\n reparent(node, newParent) {\r\n if (node.parent === newParent) return;\r\n\r\n // 1. Calculate current world pos\r\n const wx = node.computed.x;\r\n const wy = node.computed.y;\r\n\r\n // 2. Remove from old parent\r\n if (node.parent) {\r\n node.parent.children.delete(node);\r\n }\r\n\r\n // 3. Add to new parent\r\n node.parent = newParent;\r\n if (newParent) {\r\n newParent.children.add(node);\r\n // 4. Calculate new local pos\r\n // world = parentWorld + local => local = world - parentWorld\r\n node.pos.x = wx - newParent.computed.x;\r\n node.pos.y = wy - newParent.computed.y;\r\n } else {\r\n // Root\r\n node.pos.x = wx;\r\n node.pos.y = wy;\r\n }\r\n\r\n this.updateWorldTransforms();\r\n }\r\n\r\n // buffer helpers\r\n _curBuf() {\r\n return this._useAasCurrent ? this._valuesA : this._valuesB;\r\n }\r\n _nextBuf() {\r\n return this._useAasCurrent ? this._valuesB : this._valuesA;\r\n }\r\n swapBuffers() {\r\n // when moving to next cycle, promote next->current and clear next\r\n this._useAasCurrent = !this._useAasCurrent;\r\n this._nextBuf().clear();\r\n }\r\n // data helpers\r\n setOutput(nodeId, portId, value) {\r\n console.log(`[Graph.setOutput] nodeId: ${nodeId}, portId: ${portId}, value:`, value);\r\n const key = `${nodeId}:${portId}`;\r\n this._nextBuf().set(key, value);\r\n }\r\n getInput(nodeId, portId) {\r\n // Find incoming edge to this port\r\n for (const edge of this.edges.values()) {\r\n if (edge.toNode === nodeId && edge.toPort === portId) {\r\n const key = `${edge.fromNode}:${edge.fromPort}`;\r\n const value = this._curBuf().get(key);\r\n console.log(`[Graph.getInput] nodeId: ${nodeId}, portId: ${portId}, reading from ${edge.fromNode}:${edge.fromPort}, value:`, value);\r\n return value;\r\n }\r\n }\r\n console.log(`[Graph.getInput] nodeId: ${nodeId}, portId: ${portId}, no edge found, returning undefined`);\r\n return undefined;\r\n }\r\n toJSON() {\r\n const json = {\r\n nodes: [...this.nodes.values()].map((n) => ({\r\n id: n.id,\r\n type: n.type,\r\n title: n.title,\r\n x: n.pos.x,\r\n y: n.pos.y,\r\n w: n.size.width,\r\n h: n.size.height,\r\n inputs: n.inputs,\r\n outputs: n.outputs,\r\n state: n.state,\r\n parentId: n.parent?.id || null, // Save parent relationship\r\n })),\r\n edges: [...this.edges.values()],\r\n };\r\n this.hooks?.emit(\"graph:serialize\", json);\r\n return json;\r\n }\r\n\r\n fromJSON(json) {\r\n this.nodes.clear();\r\n this.edges.clear();\r\n\r\n // Restore nodes first\r\n for (const nd of json.nodes) {\r\n const def = this.registry?.types?.get(nd.type);\r\n const minH = def ? this._calculateDefaultNodeHeight(def) : 60;\r\n const height = nd.h !== undefined ? nd.h : minH;\r\n\r\n const node = new Node({\r\n id: nd.id,\r\n type: nd.type,\r\n title: nd.title,\r\n x: nd.x,\r\n y: nd.y,\r\n width: nd.w,\r\n height: height,\r\n });\r\n\r\n // Call onCreate to initialize node with defaults first\r\n if (def?.onCreate) {\r\n def.onCreate(node);\r\n }\r\n\r\n node.inputs = nd.inputs;\r\n node.outputs = nd.outputs;\r\n // Merge loaded state over defaults\r\n node.state = { ...node.state, ...(nd.state || {}) };\r\n\r\n this.nodes.set(node.id, node);\r\n }\r\n\r\n // Restore parent-child relationships\r\n for (const nd of json.nodes) {\r\n if (nd.parentId) {\r\n const node = this.nodes.get(nd.id);\r\n const parent = this.nodes.get(nd.parentId);\r\n if (node && parent) {\r\n node.parent = parent;\r\n parent.children.add(node);\r\n }\r\n }\r\n }\r\n\r\n // Restore edges\r\n for (const ed of json.edges) {\r\n this.edges.set(ed.id, new Edge(ed));\r\n }\r\n\r\n // Update world transforms to calculate proper positions\r\n this.updateWorldTransforms();\r\n\r\n this.hooks?.emit(\"graph:deserialize\", json);\r\n\r\n return this;\r\n }\r\n\r\n _calculateDefaultNodeHeight(def) {\r\n const inCount = def.inputs?.length || 0;\r\n const outCount = def.outputs?.length || 0;\r\n const maxPorts = Math.max(inCount, outCount);\r\n const headerHeight = 26;\r\n const portSpacing = 20;\r\n\r\n if (def.html) {\r\n // For HTML overlay nodes: reserve space for content BELOW all port rows.\r\n // Port idx N bottom: headerHeight + 8 + N*portSpacing + portSpacing/2 + 6\r\n // = 50 + N*portSpacing (for N=0: 50, N=1: 70, ...)\r\n // Add ~50px for HTML content + bottom padding.\r\n const lastPortBottom = maxPorts > 0 ? 50 + (maxPorts - 1) * portSpacing : 26;\r\n return Math.max(lastPortBottom + 50, 90);\r\n }\r\n\r\n const padding = 8;\r\n let h = headerHeight + padding + (maxPorts * portSpacing) + padding;\r\n return Math.max(h, 40);\r\n }\r\n}\r\n","// src/render/hitTest.js\r\nexport function hitTestNode(node, x, y) {\r\n const {\r\n x: nx,\r\n y: ny,\r\n w: width,\r\n h: height,\r\n } = node.computed || {\r\n x: node.pos.x,\r\n y: node.pos.y,\r\n w: node.size.width,\r\n h: node.size.height,\r\n };\r\n return x >= nx && x <= nx + width && y >= ny && y <= ny + height;\r\n}\r\n\r\nexport function portRect(node, port, idx, dir) {\r\n const {\r\n x: nx,\r\n y: ny,\r\n w: width,\r\n h: height,\r\n } = node.computed || {\r\n x: node.pos.x,\r\n y: node.pos.y,\r\n w: node.size.width,\r\n h: node.size.height,\r\n };\r\n\r\n // Fixed spacing\r\n // Sync with CanvasRenderer (headerH = 26)\r\n const headerHeight = 26;\r\n const padding = 8;\r\n const portSpacing = 20;\r\n const y = ny + headerHeight + padding + (idx * portSpacing) + portSpacing / 2;\r\n\r\n // Ports centered on node edges (half inside, half outside)\r\n const portWidth = 12;\r\n const portHeight = 12;\r\n\r\n if (dir === \"in\") {\r\n return { x: nx - portWidth / 2, y: y - portHeight / 2, w: portWidth, h: portHeight };\r\n }\r\n if (dir === \"out\") {\r\n return { x: nx + width - portWidth / 2, y: y - portHeight / 2, w: portWidth, h: portHeight };\r\n }\r\n}\r\n","import { portRect } from \"./hitTest.js\";\r\n\r\nexport class CanvasRenderer {\r\n static FONT_SIZE = 11;\r\n static SELECTED_NODE_COLOR = \"#6cf\";\r\n constructor(canvas, { theme = {}, registry, edgeStyle = \"orthogonal\" } = {}) {\r\n this.canvas = canvas;\r\n this.ctx = canvas.getContext(\"2d\");\r\n this.registry = registry;\r\n\r\n this.scale = 1;\r\n this.minScale = 0.25;\r\n this.maxScale = 3;\r\n this.offsetX = 0;\r\n this.offsetY = 0;\r\n\r\n // 'bezier' | 'line' | 'orthogonal'\r\n this.edgeStyle = edgeStyle;\r\n\r\n this.theme = Object.assign(\r\n {\r\n bg: \"#0e0e16\",\r\n grid: \"#1c1c2c\",\r\n node: \"rgba(22, 22, 34, 0.9)\",\r\n nodeBorder: \"rgba(255, 255, 255, 0.08)\",\r\n title: \"rgba(28, 28, 42, 0.95)\",\r\n text: \"#f5f5f7\",\r\n textMuted: \"#8e8eaf\",\r\n port: \"#4f46e5\",\r\n portExec: \"#10b981\",\r\n edge: \"rgba(255, 255, 255, 0.12)\",\r\n edgeActive: \"#34c38f\", // green for active edge animation\r\n accent: \"#6366f1\",\r\n accentBright: \"#818cf8\",\r\n accentGlow: \"rgba(99, 102, 241, 0.25)\",\r\n },\r\n theme\r\n );\r\n }\r\n\r\n setEdgeStyle(style) {\r\n this.edgeStyle = style === \"line\" || style === \"orthogonal\" ? style : \"bezier\";\r\n }\r\n setRegistry(reg) {\r\n this.registry = reg;\r\n }\r\n resize(w, h) {\r\n this.canvas.width = w;\r\n this.canvas.height = h;\r\n }\r\n setTransform({ scale = this.scale, offsetX = this.offsetX, offsetY = this.offsetY } = {}) {\r\n this.scale = Math.min(this.maxScale, Math.max(this.minScale, scale));\r\n this.offsetX = offsetX;\r\n this.offsetY = offsetY;\r\n this._onTransformChange?.();\r\n }\r\n setTransformChangeCallback(callback) {\r\n this._onTransformChange = callback;\r\n }\r\n panBy(dx, dy) {\r\n this.offsetX += dx;\r\n this.offsetY += dy;\r\n this._onTransformChange?.();\r\n }\r\n zoomAt(factor, cx, cy) {\r\n const prev = this.scale;\r\n const next = Math.min(this.maxScale, Math.max(this.minScale, prev * factor));\r\n if (next === prev) return;\r\n const wx = (cx - this.offsetX) / prev;\r\n const wy = (cy - this.offsetY) / prev;\r\n this.offsetX = cx - wx * next;\r\n this.offsetY = cy - wy * next;\r\n this.scale = next;\r\n this._onTransformChange?.();\r\n }\r\n\r\n screenToWorld(x, y) {\r\n return {\r\n x: (x - this.offsetX) / this.scale,\r\n y: (y - this.offsetY) / this.scale,\r\n };\r\n }\r\n worldToScreen(x, y) {\r\n return {\r\n x: x * this.scale + this.offsetX,\r\n y: y * this.scale + this.offsetY,\r\n };\r\n }\r\n _applyTransform() {\r\n const { ctx } = this;\r\n ctx.setTransform(1, 0, 0, 1, 0, 0);\r\n ctx.translate(this.offsetX, this.offsetY);\r\n ctx.scale(this.scale, this.scale);\r\n }\r\n _resetTransform() {\r\n this.ctx.setTransform(1, 0, 0, 1, 0, 0);\r\n }\r\n\r\n // ── Drawing ────────────────────────────────────────────────────────────────\r\n _drawArrowhead(x1, y1, x2, y2, size = 8) {\r\n const { ctx } = this;\r\n const s = size / this.scale;\r\n const ang = Math.atan2(y2 - y1, x2 - x1);\r\n\r\n ctx.beginPath();\r\n ctx.moveTo(x2, y2);\r\n ctx.lineTo(x2 - s * Math.cos(ang - Math.PI / 6), y2 - s * Math.sin(ang - Math.PI / 6));\r\n ctx.lineTo(x2 - s * Math.cos(ang + Math.PI / 6), y2 - s * Math.sin(ang + Math.PI / 6));\r\n ctx.closePath();\r\n ctx.fill();\r\n }\r\n\r\n _drawScreenText(\r\n text,\r\n lx,\r\n ly,\r\n { fontPx = 11, color = this.theme.text, align = \"left\", baseline = \"alphabetic\" } = {}\r\n ) {\r\n const { ctx } = this;\r\n const { x: sx, y: sy } = this.worldToScreen(lx, ly);\r\n\r\n ctx.save();\r\n this._resetTransform();\r\n\r\n const px = Math.round(sx) + 0.5;\r\n const py = Math.round(sy) + 0.5;\r\n\r\n ctx.font = `${fontPx * this.scale}px \"Inter\", system-ui, sans-serif`;\r\n ctx.fillStyle = color;\r\n ctx.textAlign = align;\r\n ctx.textBaseline = baseline;\r\n ctx.fillText(text, px, py);\r\n ctx.restore();\r\n }\r\n\r\n drawGrid() {\r\n const { ctx, canvas, theme, scale, offsetX, offsetY } = this;\r\n\r\n this._resetTransform();\r\n ctx.fillStyle = theme.bg;\r\n ctx.fillRect(0, 0, canvas.width, canvas.height);\r\n\r\n this._applyTransform();\r\n\r\n const x0 = -offsetX / scale;\r\n const y0 = -offsetY / scale;\r\n const x1 = (canvas.width - offsetX) / scale;\r\n const y1 = (canvas.height - offsetY) / scale;\r\n\r\n // Minor dots (24px grid)\r\n const minorStep = 24;\r\n const majorStep = 120;\r\n const minorR = 1 / scale;\r\n const majorR = 1.5 / scale;\r\n\r\n const startX = Math.floor(x0 / minorStep) * minorStep;\r\n const startY = Math.floor(y0 / minorStep) * minorStep;\r\n\r\n ctx.fillStyle = this._rgba(theme.grid, 0.7);\r\n for (let gx = startX; gx <= x1; gx += minorStep) {\r\n for (let gy = startY; gy <= y1; gy += minorStep) {\r\n const isMajorX = Math.round(gx / majorStep) * majorStep === Math.round(gx);\r\n const isMajorY = Math.round(gy / majorStep) * majorStep === Math.round(gy);\r\n if (isMajorX && isMajorY) continue;\r\n ctx.beginPath();\r\n ctx.arc(gx, gy, minorR, 0, Math.PI * 2);\r\n ctx.fill();\r\n }\r\n }\r\n\r\n // Major intersection dots\r\n const majorStartX = Math.floor(x0 / majorStep) * majorStep;\r\n const majorStartY = Math.floor(y0 / majorStep) * majorStep;\r\n ctx.fillStyle = this._rgba(theme.grid, 1.0);\r\n for (let gx = majorStartX; gx <= x1; gx += majorStep) {\r\n for (let gy = majorStartY; gy <= y1; gy += majorStep) {\r\n ctx.beginPath();\r\n ctx.arc(gx, gy, majorR, 0, Math.PI * 2);\r\n ctx.fill();\r\n }\r\n }\r\n\r\n this._resetTransform();\r\n }\r\n\r\n draw(\r\n graph,\r\n {\r\n selection = new Set(),\r\n tempEdge = null,\r\n time = performance.now(),\r\n activeNodes = new Set(), // Now explicitly passing active nodes\r\n activeEdges = new Set(),\r\n activeEdgeTimes = new Map(),\r\n drawEdges = true,\r\n loopActiveEdges = false,\r\n } = {}\r\n ) {\r\n graph.updateWorldTransforms();\r\n\r\n this.drawGrid();\r\n const { ctx, theme } = this;\r\n this._applyTransform();\r\n\r\n ctx.save();\r\n\r\n // 1. Draw Groups\r\n for (const n of graph.nodes.values()) {\r\n if (n.type === \"core/Group\") {\r\n const sel = selection.has(n.id);\r\n const def = this.registry?.types?.get(n.type);\r\n if (def?.onDraw) def.onDraw(n, { ctx, theme, renderer: this });\r\n else this._drawNode(n, sel);\r\n }\r\n }\r\n\r\n // 2. Draw Edges\r\n if (drawEdges) {\r\n ctx.lineWidth = 2.5 / this.scale;\r\n\r\n for (const e of graph.edges.values()) {\r\n const isActive = activeEdges && activeEdges.has(e.id);\r\n\r\n if (isActive) {\r\n // Glow pass\r\n ctx.save();\r\n ctx.shadowColor = this.theme.edgeActive;\r\n ctx.shadowBlur = 8 / this.scale;\r\n ctx.strokeStyle = this.theme.edgeActive;\r\n ctx.lineWidth = 3 / this.scale;\r\n ctx.setLineDash([]);\r\n this._drawEdge(graph, e);\r\n ctx.restore();\r\n\r\n // Animated flowing dot\r\n const activationTime = activeEdgeTimes?.get(e.id) ?? time;\r\n const flowSpeed = this.theme.flowSpeed || 150;\r\n const duration = (edgeLen / flowSpeed) * 1000;\r\n const rawT = (time - activationTime) / duration;\r\n const dotT = loopActiveEdges ? ((time / 1000) * (flowSpeed / edgeLen)) % 1 : ((time / 1000) * 1.2) % 1;\r\n\r\n const dotPos = this._getEdgeDotPosition(graph, e, dotT);\r\n if (dotPos) {\r\n ctx.save();\r\n ctx.fillStyle = \"#ffffff\";\r\n ctx.shadowColor = this.theme.edgeActive;\r\n ctx.shadowBlur = 10 / this.scale;\r\n ctx.beginPath();\r\n ctx.arc(dotPos.x, dotPos.y, 3 / this.scale, 0, Math.PI * 2);\r\n ctx.fill();\r\n ctx.restore();\r\n }\r\n } else {\r\n ctx.setLineDash([]);\r\n ctx.strokeStyle = theme.edge;\r\n ctx.lineWidth = 2.5 / this.scale;\r\n this._drawEdge(graph, e);\r\n }\r\n }\r\n }\r\n\r\n // temp edge preview\r\n if (tempEdge) {\r\n const a = this.screenToWorld(tempEdge.x1, tempEdge.y1);\r\n const b = this.screenToWorld(tempEdge.x2, tempEdge.y2);\r\n\r\n const prevDash = this.ctx.getLineDash();\r\n this.ctx.setLineDash([5 / this.scale, 5 / this.scale]);\r\n this.ctx.strokeStyle = this._rgba(this.theme.accentBright, 0.7);\r\n this.ctx.lineWidth = 2.5 / this.scale;\r\n\r\n let ptsForArrow = null;\r\n if (this.edgeStyle === \"line\") {\r\n this._drawLine(a.x, a.y, b.x, b.y);\r\n ptsForArrow = [\r\n { x: a.x, y: a.y },\r\n { x: b.x, y: b.y },\r\n ];\r\n } else if (this.edgeStyle === \"orthogonal\") {\r\n ptsForArrow = this._drawOrthogonal(a.x, a.y, b.x, b.y);\r\n } else {\r\n this._drawCurve(a.x, a.y, b.x, b.y);\r\n ptsForArrow = [\r\n { x: a.x, y: a.y },\r\n { x: b.x, y: b.y },\r\n ];\r\n }\r\n\r\n this.ctx.setLineDash(prevDash);\r\n\r\n if (ptsForArrow && ptsForArrow.length >= 2) {\r\n const p1 = ptsForArrow[ptsForArrow.length - 2];\r\n const p2 = ptsForArrow[ptsForArrow.length - 1];\r\n this.ctx.fillStyle = this.theme.accentBright;\r\n this._drawArrowhead(p1.x, p1.y, p2.x, p2.y, 10);\r\n }\r\n }\r\n\r\n // 3. Draw Non-Group Nodes\r\n for (const n of graph.nodes.values()) {\r\n if (n.type !== \"core/Group\") {\r\n const sel = selection.has(n.id);\r\n const def = this.registry?.types?.get(n.type);\r\n const hasHtmlOverlay = !!def?.html;\r\n\r\n this._drawNode(n, sel, !hasHtmlOverlay ? true : false);\r\n\r\n if (def?.onDraw) {\r\n def.onDraw(n, { ctx, theme, renderer: this });\r\n }\r\n\r\n if (hasHtmlOverlay) {\r\n this._drawPorts(n);\r\n }\r\n }\r\n }\r\n\r\n // 4. Highlight Active Nodes (Marching Ants)\r\n if (activeNodes.size > 0) {\r\n for (const nodeId of activeNodes) {\r\n const node = graph.nodes.get(nodeId);\r\n if (node) this._drawActiveNodeBorder(node, time);\r\n }\r\n }\r\n\r\n this._resetTransform();\r\n }\r\n\r\n _rgba(hex, a) {\r\n const c = hex.replace(\"#\", \"\");\r\n const n = parseInt(\r\n c.length === 3\r\n ? c\r\n .split(\"\")\r\n .map((x) => x + x)\r\n .join(\"\")\r\n : c,\r\n 16\r\n );\r\n const r = (n >> 16) & 255,\r\n g = (n >> 8) & 255,\r\n b = n & 255;\r\n return `rgba(${r},${g},${b},${a})`;\r\n }\r\n\r\n _drawNode(node, selected, skipPorts = false) {\r\n const { ctx, theme } = this;\r\n const r = 2; // Sharp 2px rounding\r\n const { x, y, w, h } = node.computed;\r\n const headerH = 26; // Slightly taller header for premium feel\r\n\r\n // Get color from node or registry\r\n const typeDef = this.registry?.types?.get(node.type);\r\n const categoryColor = node.color || typeDef?.color || theme.accent;\r\n\r\n // Selection glow — white, slightly offset outside node\r\n if (selected) {\r\n ctx.save();\r\n ctx.shadowColor = \"rgba(255,255,255,0.3)\";\r\n ctx.shadowBlur = 8 / this.scale;\r\n ctx.strokeStyle = \"#ffffff\";\r\n ctx.lineWidth = 1.5 / this.scale;\r\n const pad = 8 / this.scale;\r\n roundRect(ctx, x - pad, y - pad, w + pad * 2, h + pad * 2, r + pad);\r\n ctx.stroke();\r\n ctx.restore();\r\n }\r\n\r\n // Drop shadow\r\n ctx.save();\r\n ctx.shadowColor = \"rgba(0,0,0,0.7)\";\r\n ctx.shadowBlur = 20 / this.scale;\r\n ctx.shadowOffsetY = 6 / this.scale;\r\n ctx.fillStyle = theme.node;\r\n roundRect(ctx, x, y, w, h, r);\r\n ctx.fill();\r\n ctx.restore();\r\n\r\n // Node body\r\n ctx.fillStyle = theme.node;\r\n ctx.strokeStyle = selected ? \"rgba(255,255,255,0.4)\" : theme.nodeBorder;\r\n ctx.lineWidth = 1 / this.scale;\r\n roundRect(ctx, x, y, w, h, r);\r\n ctx.fill();\r\n ctx.stroke();\r\n\r\n // Header\r\n ctx.fillStyle = theme.title;\r\n roundRect(ctx, x, y, w, headerH, { tl: r, tr: r, br: 0, bl: 0 });\r\n ctx.fill();\r\n\r\n // Subtle category-based header background\r\n ctx.save();\r\n ctx.globalCompositeOperation = \"source-atop\";\r\n ctx.fillStyle = categoryColor;\r\n ctx.globalAlpha = 0.25; // Increased from 0.12 for better visibility\r\n ctx.fillRect(x, y, w, headerH);\r\n ctx.restore();\r\n\r\n // Header bottom separator\r\n ctx.strokeStyle = selected ? \"rgba(255,255,255,0.2)\" : this._rgba(theme.nodeBorder, 0.6);\r\n ctx.lineWidth = 1 / this.scale;\r\n ctx.beginPath();\r\n ctx.moveTo(x, y + headerH);\r\n ctx.lineTo(x + w, y + headerH);\r\n ctx.stroke();\r\n\r\n // Accent strip at top\r\n ctx.fillStyle = categoryColor;\r\n ctx.beginPath();\r\n ctx.roundRect(x, y, w, 2.5 / this.scale, { tl: r, tr: r, br: 0, bl: 0 });\r\n ctx.fill();\r\n\r\n // Title\r\n this._drawScreenText(node.title, x + 10, y + headerH / 2, {\r\n fontPx: CanvasRenderer.FONT_SIZE,\r\n color: theme.text,\r\n baseline: \"middle\",\r\n align: \"left\",\r\n });\r\n\r\n if (skipPorts) return;\r\n\r\n // Input ports + labels\r\n node.inputs.forEach((p, i) => {\r\n const rct = portRect(node, p, i, \"in\");\r\n const cx = rct.x + rct.w / 2;\r\n const cy = rct.y + rct.h / 2;\r\n this._drawPortShape(cx, cy, p.portType);\r\n if (p.name) {\r\n this._drawScreenText(p.name, cx + 10, cy, {\r\n fontPx: 10,\r\n color: theme.textMuted,\r\n baseline: \"middle\",\r\n align: \"left\",\r\n });\r\n }\r\n });\r\n\r\n // Output ports + labels\r\n node.outputs.forEach((p, i) => {\r\n const rct = portRect(node, p, i, \"out\");\r\n const cx = rct.x + rct.w / 2;\r\n const cy = rct.y + rct.h / 2;\r\n this._drawPortShape(cx, cy, p.portType);\r\n if (p.name) {\r\n this._drawScreenText(p.name, cx - 10, cy, {\r\n fontPx: 10,\r\n color: theme.textMuted,\r\n baseline: \"middle\",\r\n align: \"right\",\r\n });\r\n }\r\n });\r\n }\r\n\r\n _drawActiveNodeBorder(node, time) {\r\n const { ctx, theme } = this;\r\n const { x, y, w, h } = node.computed;\r\n const r = node.radius || 12;\r\n const speed = 30; // pixels per second\r\n const dashLen = 6;\r\n const gapLen = 6;\r\n\r\n ctx.save();\r\n // 1. Exterior Glow\r\n ctx.shadowColor = theme.accentBright || \"#7080d8\";\r\n ctx.shadowBlur = (12 + Math.sin(time / 200) * 4) / this.scale; // Subtle pulse\r\n\r\n // 2. Marching Ants Border\r\n ctx.strokeStyle = theme.accentBright || \"#7080d8\";\r\n ctx.lineWidth = 3 / this.scale;\r\n // Set a dashed line that moves\r\n ctx.setLineDash([dashLen / this.scale, gapLen / this.scale]);\r\n // Offset increases over time to move clockwise\r\n ctx.lineDashOffset = -(time / 1000) * speed / this.scale;\r\n\r\n // Use a custom roundRect for the border\r\n ctx.beginPath();\r\n const pad = 2 / this.scale;\r\n this._roundRect(ctx, x - pad, y - pad, w + pad * 2, h + pad * 2, r + pad);\r\n ctx.stroke();\r\n ctx.restore();\r\n }\r\n\r\n // Internal helper for rounded rectangles if not using the browser's native one\r\n _roundRect(ctx, x, y, w, h, r) {\r\n if (typeof r === \"number\") {\r\n r = { tl: r, tr: r, br: r, bl: r };\r\n }\r\n ctx.beginPath();\r\n ctx.moveTo(x + r.tl, y);\r\n ctx.lineTo(x + w - r.tr, y);\r\n ctx.quadraticCurveTo(x + w, y, x + w, y + r.tr);\r\n ctx.lineTo(x + w, y + h - r.br);\r\n ctx.quadraticCurveTo(x + w, y + h, x + w - r.br, y + h);\r\n ctx.lineTo(x + r.bl, y + h);\r\n ctx.quadraticCurveTo(x, y + h, x, y + h - r.bl);\r\n ctx.lineTo(x, y + r.tl);\r\n ctx.quadraticCurveTo(x, y, x + r.tl, y);\r\n ctx.closePath();\r\n }\r\n\r\n _drawPortShape(cx, cy, portType) {\r\n const { ctx, theme } = this;\r\n\r\n if (portType === \"exec\") {\r\n // Diamond shape for exec ports\r\n const s = 5 / this.scale;\r\n ctx.save();\r\n ctx.fillStyle = theme.portExec;\r\n ctx.strokeStyle = this._rgba(theme.portExec, 0.4);\r\n ctx.lineWidth = 2 / this.scale;\r\n ctx.beginPath();\r\n ctx.moveTo(cx, cy - s);\r\n ctx.lineTo(cx + s, cy);\r\n ctx.lineTo(cx, cy + s);\r\n ctx.lineTo(cx - s, cy);\r\n ctx.closePath();\r\n ctx.fill();\r\n ctx.stroke();\r\n ctx.restore();\r\n } else {\r\n // Circle for data ports\r\n ctx.save();\r\n // Outer ring\r\n ctx.strokeStyle = this._rgba(theme.port, 0.35);\r\n ctx.lineWidth = 3 / this.scale;\r\n ctx.beginPath();\r\n ctx.arc(cx, cy, 5 / this.scale, 0, Math.PI * 2);\r\n ctx.stroke();\r\n // Inner fill\r\n ctx.fillStyle = theme.port;\r\n ctx.beginPath();\r\n ctx.arc(cx, cy, 3.5 / this.scale, 0, Math.PI * 2);\r\n ctx.fill();\r\n ctx.restore();\r\n }\r\n }\r\n\r\n _drawPorts(node) {\r\n node.inputs.forEach((p, i) => {\r\n const rct = portRect(node, p, i, \"in\");\r\n const cx = rct.x + rct.w / 2;\r\n const cy = rct.y + rct.h / 2;\r\n this._drawPortShape(cx, cy, p.portType);\r\n });\r\n\r\n node.outputs.forEach((p, i) => {\r\n const rct = portRect(node, p, i, \"out\");\r\n const cx = rct.x + rct.w / 2;\r\n const cy = rct.y + rct.h / 2;\r\n this._drawPortShape(cx, cy, p.portType);\r\n });\r\n }\r\n\r\n /** Selection border for HTML overlay nodes, drawn on the edge canvas */\r\n _drawHtmlSelectionBorder(node) {\r\n const { ctx } = this;\r\n const { x, y, w, h } = node.computed;\r\n const r = 2;\r\n const pad = 2.5 / this.scale;\r\n\r\n ctx.save();\r\n ctx.shadowColor = \"rgba(255,255,255,0.3)\";\r\n ctx.shadowBlur = 8 / this.scale;\r\n ctx.strokeStyle = \"#ffffff\";\r\n ctx.lineWidth = 1.5 / this.scale;\r\n roundRect(ctx, x - pad, y - pad, w + pad * 2, h + pad * 2, r);\r\n ctx.stroke();\r\n ctx.restore();\r\n }\r\n\r\n /** Rotating dashed border drawn on the edge canvas for executing nodes */\r\n _drawActiveNodeBorder(node, time) {\r\n const { ctx } = this;\r\n const { x, y, w, h } = node.computed;\r\n const r = 2;\r\n const pad = 8 / this.scale; // Same gap as selection border\r\n\r\n const dashLen = 8 / this.scale;\r\n const gapLen = 6 / this.scale;\r\n const offset = -(time / 1000) * (50 / this.scale);\r\n\r\n ctx.save();\r\n ctx.setLineDash([dashLen, gapLen]);\r\n ctx.lineDashOffset = offset;\r\n ctx.strokeStyle = \"rgba(74,176,217,0.9)\"; // Dark sky blue\r\n ctx.lineWidth = 2.0 / this.scale;\r\n ctx.shadowColor = \"#4ab0d9\";\r\n ctx.shadowBlur = 6 / this.scale;\r\n roundRect(ctx, x - pad, y - pad, w + pad * 2, h + pad * 2, r + pad);\r\n ctx.stroke();\r\n ctx.restore();\r\n }\r\n\r\n /** Approximate arc length of an edge in world coordinates */\r\n _getEdgeLength(graph, e) {\r\n const from = graph.nodes.get(e.fromNode);\r\n const to = graph.nodes.get(e.toNode);\r\n if (!from || !to) return 200;\r\n const iOut = from.outputs.findIndex((p) => p.id === e.fromPort);\r\n const iIn = to.inputs.findIndex((p) => p.id === e.toPort);\r\n const pr1 = portRect(from, null, iOut, \"out\");\r\n const pr2 = portRect(to, null, iIn, \"in\");\r\n const x1 = pr1.x + pr1.w / 2,\r\n y1 = pr1.y + pr1.h / 2;\r\n const x2 = pr2.x + pr2.w / 2,\r\n y2 = pr2.y + pr2.h / 2;\r\n if (this.edgeStyle === \"orthogonal\") {\r\n return Math.abs(x2 - x1) + Math.abs(y2 - y1);\r\n }\r\n const chord = Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2);\r\n return this.edgeStyle === \"bezier\" ? chord * 1.4 : chord;\r\n }\r\n\r\n _drawEdge(graph, e) {\r\n const from = graph.nodes.get(e.fromNode);\r\n const to = graph.nodes.get(e.toNode);\r\n if (!from || !to) return;\r\n const iOut = from.outputs.findIndex((p) => p.id === e.fromPort);\r\n const iIn = to.inputs.findIndex((p) => p.id === e.toPort);\r\n const pr1 = portRect(from, null, iOut, \"out\");\r\n const pr2 = portRect(to, null, iIn, \"in\");\r\n const x1 = pr1.x + pr1.w / 2,\r\n y1 = pr1.y + pr1.h / 2;\r\n const x2 = pr2.x + pr2.w / 2,\r\n y2 = pr2.y + pr2.h / 2;\r\n\r\n if (this.edgeStyle === \"line\") {\r\n this._drawLine(x1, y1, x2, y2);\r\n } else if (this.edgeStyle === \"orthogonal\") {\r\n this._drawOrthogonal(x1, y1, x2, y2);\r\n } else {\r\n this._drawCurve(x1, y1, x2, y2);\r\n }\r\n }\r\n\r\n _getEdgeDotPosition(graph, e, t) {\r\n const from = graph.nodes.get(e.fromNode);\r\n const to = graph.nodes.get(e.toNode);\r\n if (!from || !to) return null;\r\n\r\n const iOut = from.outputs.findIndex((p) => p.id === e.fromPort);\r\n const iIn = to.inputs.findIndex((p) => p.id === e.toPort);\r\n const pr1 = portRect(from, null, iOut, \"out\");\r\n const pr2 = portRect(to, null, iIn, \"in\");\r\n const x1 = pr1.x + pr1.w / 2,\r\n y1 = pr1.y + pr1.h / 2;\r\n const x2 = pr2.x + pr2.w / 2,\r\n y2 = pr2.y + pr2.h / 2;\r\n\r\n if (this.edgeStyle === \"bezier\") {\r\n const dx = Math.max(40, Math.abs(x2 - x1) * 0.4);\r\n return cubicBezierPoint(x1, y1, x1 + dx, y1, x2 - dx, y2, x2, y2, t);\r\n } else if (this.edgeStyle === \"orthogonal\") {\r\n const midX = (x1 + x2) / 2;\r\n const pts = [\r\n { x: x1, y: y1 },\r\n { x: midX, y: y1 },\r\n { x: midX, y: y2 },\r\n { x: x2, y: y2 },\r\n ];\r\n return polylinePoint(pts, t);\r\n } else {\r\n return { x: x1 + (x2 - x1) * t, y: y1 + (y2 - y1) * t };\r\n }\r\n }\r\n\r\n _drawLine(x1, y1, x2, y2) {\r\n const { ctx } = this;\r\n ctx.beginPath();\r\n ctx.moveTo(x1, y1);\r\n ctx.lineTo(x2, y2);\r\n ctx.stroke();\r\n }\r\n\r\n _drawPolyline(points) {\r\n const { ctx } = this;\r\n ctx.beginPath();\r\n ctx.moveTo(points[0].x, points[0].y);\r\n for (let i = 1; i < points.length; i++) ctx.lineTo(points[i].x, points[i].y);\r\n ctx.stroke();\r\n }\r\n\r\n _drawOrthogonal(x1, y1, x2, y2) {\r\n const midX = (x1 + x2) / 2;\r\n const pts = [\r\n { x: x1, y: y1 },\r\n { x: midX, y: y1 },\r\n { x: midX, y: y2 },\r\n { x: x2, y: y2 },\r\n ];\r\n\r\n const { ctx } = this;\r\n const prevJoin = ctx.lineJoin,\r\n prevCap = ctx.lineCap;\r\n ctx.lineJoin = \"round\";\r\n ctx.lineCap = \"round\";\r\n this._drawPolyline(pts);\r\n ctx.lineJoin = prevJoin;\r\n ctx.lineCap = prevCap;\r\n\r\n return pts;\r\n }\r\n\r\n _drawCurve(x1, y1, x2, y2) {\r\n const { ctx } = this;\r\n const dx = Math.max(40, Math.abs(x2 - x1) * 0.4);\r\n ctx.beginPath();\r\n ctx.moveTo(x1, y1);\r\n ctx.bezierCurveTo(x1 + dx, y1, x2 - dx, y2, x2, y2);\r\n ctx.stroke();\r\n }\r\n\r\n drawEdgesOnly(\r\n graph,\r\n {\r\n activeEdges = new Set(),\r\n activeEdgeTimes = new Map(),\r\n activeNodes = new Set(),\r\n selection = new Set(),\r\n time = performance.now(),\r\n tempEdge = null,\r\n loopActiveEdges = false,\r\n } = {}\r\n ) {\r\n this._resetTransform();\r\n this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);\r\n\r\n this._applyTransform();\r\n\r\n const { ctx, theme } = this;\r\n\r\n // Draw all edges\r\n for (const e of graph.edges.values()) {\r\n const isActive = activeEdges.has(e.id);\r\n\r\n if (isActive) {\r\n // Glow pass\r\n ctx.save();\r\n ctx.shadowColor = theme.edgeActive;\r\n ctx.shadowBlur = 6 / this.scale;\r\n ctx.strokeStyle = theme.edgeActive;\r\n ctx.lineWidth = 3 / this.scale;\r\n ctx.setLineDash([]);\r\n this._drawEdge(graph, e);\r\n ctx.restore();\r\n\r\n // Dot position: use configurable flow speed (default 150 px/sec)\r\n const flowSpeed = this.theme.flowSpeed || 150;\r\n const activationTime = activeEdgeTimes.get(e.id) ?? time;\r\n const edgeLen = Math.max(50, this._getEdgeLength(graph, e));\r\n const duration = (edgeLen / flowSpeed) * 1000; // ms for this edge\r\n\r\n // Loop animation if requested (e.g. in Step Mode)\r\n const rawT = (time - activationTime) / duration;\r\n const dotT = loopActiveEdges ? ((time / 1000) * (flowSpeed / edgeLen)) % 1 : Math.min(1, rawT);\r\n\r\n const dotPos = this._getEdgeDotPosition(graph, e, dotT);\r\n if (dotPos) {\r\n ctx.save();\r\n ctx.fillStyle = this._rgba(theme.edgeActive, 0.9);\r\n ctx.shadowColor = theme.edgeActive;\r\n ctx.shadowBlur = 8 / this.scale;\r\n ctx.beginPath();\r\n ctx.arc(dotPos.x, dotPos.y, 2.5 / this.scale, 0, Math.PI * 2);\r\n ctx.fill();\r\n ctx.restore();\r\n }\r\n } else {\r\n ctx.setLineDash([]);\r\n ctx.strokeStyle = theme.edge;\r\n ctx.lineWidth = 2.5 / this.scale;\r\n this._drawEdge(graph, e);\r\n }\r\n }\r\n\r\n // Selection borders for HTML overlay nodes (drawn above the HTML layer)\r\n for (const nodeId of selection) {\r\n const node = graph.nodes.get(nodeId);\r\n if (!node) continue;\r\n const def = this.registry?.types?.get(node.type);\r\n if (def?.html) this._drawHtmlSelectionBorder(node);\r\n }\r\n\r\n // Rotating dashed border for executing nodes\r\n if (activeNodes.size > 0) {\r\n for (const nodeId of activeNodes) {\r\n const node = graph.nodes.get(nodeId);\r\n if (node) this._drawActiveNodeBorder(node, time);\r\n }\r\n }\r\n\r\n // temp edge preview\r\n if (tempEdge) {\r\n const a = this.screenToWorld(tempEdge.x1, tempEdge.y1);\r\n const b = this.screenToWorld(tempEdge.x2, tempEdge.y2);\r\n\r\n const prevDash = this.ctx.getLineDash();\r\n this.ctx.setLineDash([5 / this.scale, 5 / this.scale]);\r\n this.ctx.strokeStyle = this._rgba(this.theme.accentBright, 0.7);\r\n this.ctx.lineWidth = 2.5 / this.scale;\r\n\r\n let ptsForArrow = null;\r\n if (this.edgeStyle === \"line\") {\r\n this._drawLine(a.x, a.y, b.x, b.y);\r\n ptsForArrow = [\r\n { x: a.x, y: a.y },\r\n { x: b.x, y: b.y },\r\n ];\r\n } else if (this.edgeStyle === \"orthogonal\") {\r\n ptsForArrow = this._drawOrthogonal(a.x, a.y, b.x, b.y);\r\n } else {\r\n this._drawCurve(a.x, a.y, b.x, b.y);\r\n ptsForArrow = [\r\n { x: a.x, y: a.y },\r\n { x: b.x, y: b.y },\r\n ];\r\n }\r\n\r\n this.ctx.setLineDash(prevDash);\r\n\r\n if (ptsForArrow && ptsForArrow.length >= 2) {\r\n const p1 = ptsForArrow[ptsForArrow.length - 2];\r\n const p2 = ptsForArrow[ptsForArrow.length - 1];\r\n this.ctx.fillStyle = this.theme.accentBright;\r\n this._drawArrowhead(p1.x, p1.y, p2.x, p2.y, 10);\r\n }\r\n }\r\n\r\n this._resetTransform();\r\n }\r\n}\r\n\r\nfunction roundRect(ctx, x, y, w, h, r = 6) {\r\n if (typeof r === \"number\") r = { tl: r, tr: r, br: r, bl: r };\r\n ctx.beginPath();\r\n ctx.moveTo(x + r.tl, y);\r\n ctx.lineTo(x + w - r.tr, y);\r\n ctx.quadraticCurveTo(x + w, y, x + w, y + r.tr);\r\n ctx.lineTo(x + w, y + h - r.br);\r\n ctx.quadraticCurveTo(x + w, y + h, x + w - r.br, y + h);\r\n ctx.lineTo(x + r.bl, y + h);\r\n ctx.quadraticCurveTo(x, y + h, x, y + h - r.bl);\r\n ctx.lineTo(x, y + r.tl);\r\n ctx.quadraticCurveTo(x, y, x + r.tl, y);\r\n ctx.closePath();\r\n}\r\n\r\nfunction cubicBezierPoint(x0, y0, x1, y1, x2, y2, x3, y3, t) {\r\n const mt = 1 - t;\r\n return {\r\n x: mt * mt * mt * x0 + 3 * mt * mt * t * x1 + 3 * mt * t * t * x2 + t * t * t * x3,\r\n y: mt * mt * mt * y0 + 3 * mt * mt * t * y1 + 3 * mt * t * t * y2 + t * t * t * y3,\r\n };\r\n}\r\n\r\nfunction polylinePoint(pts, t) {\r\n let totalLen = 0;\r\n const lens = [];\r\n for (let i = 0; i < pts.length - 1; i++) {\r\n const dx = pts[i + 1].x - pts[i].x;\r\n const dy = pts[i + 1].y - pts[i].y;\r\n const len = Math.sqrt(dx * dx + dy * dy);\r\n lens.push(len);\r\n totalLen += len;\r\n }\r\n if (totalLen === 0) return pts[0];\r\n\r\n let target = t * totalLen;\r\n let accum = 0;\r\n for (let i = 0; i < lens.length; i++) {\r\n if (accum + lens[i] >= target) {\r\n const segT = lens[i] > 0 ? (target - accum) / lens[i] : 0;\r\n return {\r\n x: pts[i].x + (pts[i + 1].x - pts[i].x) * segT,\r\n y: pts[i].y + (pts[i + 1].y - pts[i].y) * segT,\r\n };\r\n }\r\n accum += lens[i];\r\n }\r\n return pts[pts.length - 1];\r\n}\r\n","// Find an edge id by its endpoints (fallback for undo)\r\nfunction findEdgeId(graph, a, b, c, d) {\r\n for (const [id, e] of graph.edges) {\r\n if (\r\n e.fromNode === a &&\r\n e.fromPort === b &&\r\n e.toNode === c &&\r\n e.toPort === d\r\n )\r\n return id;\r\n }\r\n return null;\r\n}\r\n\r\nexport function MoveNodeCmd(node, fromPos, toPos) {\r\n return {\r\n do() {\r\n node.pos = { ...toPos };\r\n },\r\n undo() {\r\n node.pos = { ...fromPos };\r\n },\r\n };\r\n}\r\n\r\nexport function AddEdgeCmd(graph, fromNode, fromPort, toNode, toPort) {\r\n let addedId = null;\r\n return {\r\n do() {\r\n graph.addEdge(fromNode, fromPort, toNode, toPort);\r\n addedId = findEdgeId(graph, fromNode, fromPort, toNode, toPort);\r\n },\r\n undo() {\r\n const id =\r\n addedId ?? findEdgeId(graph, fromNode, fromPort, toNode, toPort);\r\n if (id != null) graph.edges.delete(id);\r\n },\r\n };\r\n}\r\n\r\nexport function RemoveEdgeCmd(graph, edgeId) {\r\n const e = graph.edges.get(edgeId);\r\n if (!e) return null;\r\n // capture for undo\r\n const { fromNode, fromPort, toNode, toPort } = e;\r\n return {\r\n do() {\r\n graph.edges.delete(edgeId);\r\n },\r\n undo() {\r\n graph.addEdge(fromNode, fromPort, toNode, toPort);\r\n },\r\n };\r\n}\r\n\r\n// Optional: group multiple commands as one (used for \"rewire\")\r\nexport function CompoundCmd(cmds) {\r\n return {\r\n do() {\r\n cmds.forEach((c) => c?.do());\r\n },\r\n undo() {\r\n [...cmds].reverse().forEach((c) => c?.undo());\r\n },\r\n };\r\n}\r\n\r\nexport function RemoveNodeCmd(graph, node) {\r\n let removedNode = null;\r\n let removedEdges = [];\r\n\r\n return {\r\n do() {\r\n // Store the node and its connected edges for undo\r\n removedNode = node;\r\n removedEdges = graph.edges\r\n ? [...graph.edges.values()].filter((e) => {\r\n return e.fromNode === node.id || e.toNode === node.id;\r\n })\r\n : [];\r\n\r\n // Remove edges first\r\n for (const edge of removedEdges) {\r\n graph.edges.delete(edge.id);\r\n }\r\n // Remove the node\r\n graph.nodes.delete(node.id);\r\n },\r\n\r\n undo() {\r\n // Restore node\r\n if (removedNode) {\r\n graph.nodes.set(removedNode.id, removedNode);\r\n }\r\n // Restore edges\r\n for (const edge of removedEdges) {\r\n graph.edges.set(edge.id, edge);\r\n }\r\n },\r\n };\r\n}\r\n\r\nexport function ResizeNodeCmd(node, fromSize, toSize) {\r\n return {\r\n do() {\r\n node.size.width = toSize.w;\r\n node.size.height = toSize.h;\r\n },\r\n undo() {\r\n node.size.width = fromSize.w;\r\n node.size.height = fromSize.h;\r\n },\r\n };\r\n}\r\n\r\nexport function ChangeGroupColorCmd(node, fromColor, toColor) {\r\n return {\r\n do() {\r\n node.state.color = toColor;\r\n },\r\n undo() {\r\n node.state.color = fromColor;\r\n },\r\n };\r\n}\r\n","// src/core/CommandStack.js\r\nexport class CommandStack {\r\n constructor() {\r\n this.undoStack = [];\r\n this.redoStack = [];\r\n }\r\n exec(cmd) {\r\n cmd.do();\r\n this.undoStack.push(cmd);\r\n this.redoStack.length = 0;\r\n }\r\n undo() {\r\n const c = this.undoStack.pop();\r\n if (c) {\r\n c.undo();\r\n this.redoStack.push(c);\r\n }\r\n }\r\n redo() {\r\n const c = this.redoStack.pop();\r\n if (c) {\r\n c.do();\r\n this.undoStack.push(c);\r\n }\r\n }\r\n}\r\n","import { portRect } from \"../render/hitTest.js\";\r\nimport { AddEdgeCmd, RemoveEdgeCmd, RemoveNodeCmd, ResizeNodeCmd } from \"../core/commands.js\";\r\nimport { CommandStack } from \"../core/CommandStack.js\";\r\n\r\nexport class Controller {\r\n static MIN_NODE_WIDTH = 80;\r\n static MIN_NODE_HEIGHT = 60;\r\n\r\n constructor({ graph, renderer, hooks, htmlOverlay, contextMenu, edgeRenderer, portRenderer }) {\r\n this.graph = graph;\r\n this.renderer = renderer;\r\n this.hooks = hooks;\r\n this.htmlOverlay = htmlOverlay;\r\n this.contextMenu = contextMenu;\r\n this.edgeRenderer = edgeRenderer; // Separate renderer for edges/animations above HTML\r\n this.portRenderer = portRenderer; // Separate renderer for ports above HTML\r\n\r\n this.stack = new CommandStack();\r\n this.selection = new Set();\r\n this.dragging = null; // { nodeId, dx, dy }\r\n this.connecting = null; // { fromNode, fromPort, x(screen), y(screen) }\r\n this.panning = null; // { x(screen), y(screen) }\r\n this.resizing = null;\r\n this.gDragging = null;\r\n this.gResizing = null;\r\n this.boxSelecting = null; // { startX, startY, currentX, currentY } - world coords\r\n\r\n // Edge / node animation state\r\n this.activeEdges = new Set();\r\n this.activeEdgeTimes = new Map(); // edge.id → activation timestamp\r\n this.activeNodes = new Set(); // node IDs currently executing\r\n\r\n // Feature flags\r\n this.snapToGrid = true; // Snap nodes to grid (toggle with G key)\r\n this.gridSize = 20; // Grid size for snapping\r\n\r\n this._cursor = \"default\";\r\n\r\n this._onKeyPressEvt = this._onKeyPress.bind(this);\r\n this._onDownEvt = this._onDown.bind(this);\r\n this._onWheelEvt = this._onWheel.bind(this);\r\n this._onMoveEvt = this._onMove.bind(this);\r\n this._onUpEvt = this._onUp.bind(this);\r\n this._onContextMenuEvt = this._onContextMenu.bind(this);\r\n this._onDblClickEvt = this._onDblClick.bind(this);\r\n\r\n this._bindEvents();\r\n\r\n // Listen for stepping updates from runner\r\n this.hooks.on(\"runner:step-updated\", ({ activeNodeId, activeEdgeIds = [] }) => {\r\n this.activeNodes = activeNodeId ? new Set([activeNodeId]) : new Set();\r\n this.activeEdges = new Set(activeEdgeIds);\r\n this.activeEdgeTimes.clear(); // Clear previous times to ensure fresh animation\r\n const now = performance.now();\r\n for (const edgeId of activeEdgeIds) {\r\n this.activeEdgeTimes.set(edgeId, now);\r\n }\r\n this.render();\r\n });\r\n }\r\n\r\n destroy() {\r\n const c = this.renderer.canvas;\r\n c.removeEventListener(\"mousedown\", this._onDownEvt);\r\n c.removeEventListener(\"dblclick\", this._onDblClickEvt);\r\n c.removeEventListener(\"wheel\", this._onWheelEvt, { passive: false });\r\n c.removeEventListener(\"contextmenu\", this._onContextMenuEvt);\r\n window.removeEventListener(\"mousemove\", this._onMoveEvt);\r\n window.removeEventListener(\"mouseup\", this._onUpEvt);\r\n window.removeEventListener(\"keydown\", this._onKeyPressEvt);\r\n }\r\n\r\n _bindEvents() {\r\n const c = this.renderer.canvas;\r\n c.addEventListener(\"mousedown\", this._onDownEvt);\r\n c.addEventListener(\"dblclick\", this._onDblClickEvt);\r\n c.addEventListener(\"wheel\", this._onWheelEvt, { passive: false });\r\n c.addEventListener(\"contextmenu\", this._onContextMenuEvt);\r\n window.addEventListener(\"mousemove\", this._onMoveEvt);\r\n window.addEventListener(\"mouseup\", this._onUpEvt);\r\n window.addEventListener(\"keydown\", this._onKeyPressEvt);\r\n }\r\n\r\n _onKeyPress(e) {\r\n this.isAlt = e.altKey;\r\n this.isShift = e.shiftKey;\r\n this.isCtrl = e.ctrlKey;\r\n\r\n // Toggle snap-to-grid with G key\r\n if (e.key.toLowerCase() === \"g\" && !e.ctrlKey && !e.metaKey) {\r\n this.snapToGrid = !this.snapToGrid;\r\n this.render(); // Update UI\r\n return;\r\n }\r\n\r\n // Group selected nodes: Ctrl/Cmd + G\r\n if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === \"g\") {\r\n e.preventDefault();\r\n this._createGroupFromSelection();\r\n return;\r\n }\r\n\r\n // Undo: Ctrl/Cmd + Z (Shift+Z → Redo)\r\n if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === \"z\") {\r\n e.preventDefault();\r\n if (e.shiftKey) this.stack.redo();\r\n else this.stack.undo();\r\n this.render();\r\n return;\r\n }\r\n\r\n // Redo: Ctrl/Cmd + Y\r\n if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === \"y\") {\r\n e.preventDefault();\r\n this.stack.redo();\r\n this.render();\r\n return;\r\n }\r\n\r\n // Align nodes: A (horizontal), Shift+A (vertical)\r\n if (e.key.toLowerCase() === \"a\" && this.selection.size > 1) {\r\n e.preventDefault();\r\n if (e.shiftKey) {\r\n this._alignNodesVertical();\r\n } else {\r\n this._alignNodesHorizontal();\r\n }\r\n return;\r\n }\r\n\r\n // remove the selected nodes\r\n if (e.key === \"Delete\") {\r\n [...this.selection].forEach((node) => {\r\n const nodeObj = this.graph.getNodeById(node);\r\n this.stack.exec(RemoveNodeCmd(this.graph, nodeObj));\r\n this.graph.removeNode(node);\r\n });\r\n\r\n this.render();\r\n }\r\n }\r\n\r\n _setCursor(c) {\r\n if (this._cursor !== c) {\r\n this._cursor = c;\r\n this.renderer.canvas.style.cursor = c;\r\n }\r\n }\r\n\r\n _posScreen(e) {\r\n const r = this.renderer.canvas.getBoundingClientRect();\r\n return { x: e.clientX - r.left, y: e.clientY - r.top };\r\n }\r\n\r\n _posWorld(e) {\r\n const s = this._posScreen(e);\r\n return this.renderer.screenToWorld(s.x, s.y);\r\n }\r\n\r\n _findNodeAtWorld(x, y) {\r\n // Reverse order (top to bottom)\r\n const list = [...this.graph.nodes.values()].reverse();\r\n\r\n for (const n of list) {\r\n // Use computed world transform for hit testing\r\n const { x: nx, y: ny, w, h } = n.computed;\r\n if (x >= nx && x <= nx + w && y >= ny && y <= ny + h) {\r\n // If this is a group, check if any of its children are under the cursor\r\n if (n.type === \"core/Group\") {\r\n // Check all children of this group (recursively)\r\n const child = this._findChildNodeAtWorld(n, x, y);\r\n if (child) {\r\n return child; // Return the child instead of the group\r\n }\r\n }\r\n return n;\r\n }\r\n }\r\n return null;\r\n }\r\n\r\n /**\r\n * Find child node at world coordinates (recursive helper for _findNodeAtWorld)\r\n * @param {Node} parentNode - Parent node (group)\r\n * @param {number} x - World x coordinate\r\n * @param {number} y - World y coordinate\r\n * @returns {Node|null} - Child node at position, or null\r\n */\r\n _findChildNodeAtWorld(parentNode, x, y) {\r\n // Get all children of this parent\r\n const children = [];\r\n for (const node of this.graph.nodes.values()) {\r\n if (node.parent === parentNode) {\r\n children.push(node);\r\n }\r\n }\r\n\r\n // Check children in reverse order (top to bottom)\r\n for (let i = children.length - 1; i >= 0; i--) {\r\n const child = children[i];\r\n const { x: nx, y: ny, w, h } = child.computed;\r\n\r\n if (x >= nx && x <= nx + w && y >= ny && y <= ny + h) {\r\n // If this child is also a group, recursively check its children\r\n if (child.type === \"core/Group\") {\r\n const grandchild = this._findChildNodeAtWorld(child, x, y);\r\n if (grandchild) {\r\n return grandchild;\r\n }\r\n }\r\n return child;\r\n }\r\n }\r\n\r\n return null;\r\n }\r\n\r\n _findPortAtWorld(x, y) {\r\n for (const n of this.graph.nodes.values()) {\r\n for (let i = 0; i < n.inputs.length; i++) {\r\n const r = portRect(n, n.inputs[i], i, \"in\");\r\n if (rectHas(r, x, y)) return { node: n, port: n.inputs[i], dir: \"in\", idx: i };\r\n }\r\n for (let i = 0; i < n.outputs.length; i++) {\r\n const r = portRect(n, n.outputs[i], i, \"out\");\r\n if (rectHas(r, x, y)) return { node: n, port: n.outputs[i], dir: \"out\", idx: i };\r\n }\r\n }\r\n return null;\r\n }\r\n\r\n _findIncomingEdge(nodeId, portId) {\r\n for (const [eid, e] of this.graph.edges) {\r\n if (e.toNode === nodeId && e.toPort === portId) {\r\n return { id: eid, edge: e };\r\n }\r\n }\r\n return null;\r\n }\r\n\r\n _onWheel(e) {\r\n e.preventDefault();\r\n const { x, y } = this._posScreen(e);\r\n const factor = Math.pow(1.0015, -e.deltaY); // smooth zoom\r\n this.renderer.zoomAt(factor, x, y);\r\n this.render();\r\n }\r\n\r\n _onContextMenu(e) {\r\n e.preventDefault();\r\n\r\n // Only show context menu if we have a contextMenu instance\r\n if (!this.contextMenu) return;\r\n\r\n const w = this._posWorld(e);\r\n const node = this._findNodeAtWorld(w.x, w.y);\r\n\r\n // Show menu with node or null (for canvas background) and world position\r\n this.contextMenu.show(node, e.clientX, e.clientY, w);\r\n }\r\n\r\n _onDblClick(e) {\r\n const w = this._posWorld(e);\r\n const node = this._findNodeAtWorld(w.x, w.y);\r\n\r\n if (node) {\r\n this.hooks?.emit(\"node:dblclick\", node);\r\n }\r\n }\r\n\r\n _resizeHandleRect(node) {\r\n const s = 10;\r\n const { x, y, w, h } = node.computed;\r\n return {\r\n x: x + w - s,\r\n y: y + h - s,\r\n w: s,\r\n h: s,\r\n };\r\n }\r\n\r\n _hitResizeHandle(node, wx, wy) {\r\n const r = this._resizeHandleRect(node);\r\n return wx >= r.x && wx <= r.x + r.w && wy >= r.y && wy <= r.y + r.h;\r\n }\r\n\r\n _onDown(e) {\r\n const s = this._posScreen(e);\r\n const w = this._posWorld(e);\r\n\r\n if (e.button === 1) {\r\n this.panning = { x: s.x, y: s.y };\r\n return;\r\n }\r\n\r\n // 1. Resize Handle Hit Test (for all nodes including groups)\r\n const node = this._findNodeAtWorld(w.x, w.y);\r\n if (e.button === 0 && node && this._hitResizeHandle(node, w.x, w.y)) {\r\n this.resizing = {\r\n nodeId: node.id,\r\n startW: node.size.width,\r\n startH: node.size.height,\r\n startX: w.x,\r\n startY: w.y,\r\n };\r\n if (!e.shiftKey) this.selection.clear();\r\n this.selection.add(node.id);\r\n this._setCursor(\"se-resize\");\r\n this.render();\r\n return;\r\n }\r\n\r\n // 2. Port Hit Test\r\n const port = this._findPortAtWorld(w.x, w.y);\r\n\r\n // Handle input port click - disconnect existing connection\r\n if (e.button === 0 && port && port.dir === \"in\") {\r\n const incoming = this._findIncomingEdge(port.node.id, port.port.id);\r\n if (incoming) {\r\n // Disconnect the existing edge\r\n this.stack.exec(RemoveEdgeCmd(this.graph, incoming.id));\r\n this.render();\r\n return;\r\n }\r\n }\r\n\r\n // Handle output port click - start new connection\r\n if (e.button === 0 && port && port.dir === \"out\") {\r\n const outR = portRect(port.node, port.port, port.idx, \"out\");\r\n const screenFrom = this.renderer.worldToScreen(outR.x, outR.y + 7);\r\n this.connecting = {\r\n fromNode: port.node.id,\r\n fromPort: port.port.id,\r\n x: screenFrom.x,\r\n y: screenFrom.y,\r\n };\r\n return;\r\n }\r\n\r\n // 3. Node Hit Test (Selection & Drag)\r\n if (e.button === 0 && node) {\r\n if (!e.shiftKey) this.selection.clear();\r\n this.selection.add(node.id);\r\n\r\n // Dragging: store initial world pos difference for all selected nodes\r\n this.dragging = {\r\n nodeId: node.id,\r\n offsetX: w.x - node.computed.x,\r\n offsetY: w.y - node.computed.y,\r\n startPos: { ...node.pos }, // for undo\r\n selectedNodes: [], // Store all selected nodes and their initial positions\r\n };\r\n\r\n // Store positions of all selected nodes\r\n for (const selectedId of this.selection) {\r\n const selectedNode = this.graph.nodes.get(selectedId);\r\n if (selectedNode) {\r\n this.dragging.selectedNodes.push({\r\n node: selectedNode,\r\n startWorldX: selectedNode.computed.x,\r\n startWorldY: selectedNode.computed.y,\r\n startLocalX: selectedNode.pos.x,\r\n startLocalY: selectedNode.pos.y,\r\n });\r\n }\r\n }\r\n\r\n // If dragging a group, store children's world positions\r\n if (node.type === \"core/Group\") {\r\n this.dragging.childrenWorldPos = [];\r\n for (const child of this.graph.nodes.values()) {\r\n if (child.parent === node) {\r\n this.dragging.childrenWorldPos.push({\r\n node: child,\r\n worldX: child.computed.x,\r\n worldY: child.computed.y,\r\n });\r\n }\r\n }\r\n }\r\n\r\n this.render();\r\n return;\r\n }\r\n\r\n // 4. Background Click (Pan or Box Selection)\r\n if (e.button === 0) {\r\n if (this.selection.size) this.selection.clear();\r\n\r\n // Start box selection if Ctrl is held\r\n if (e.ctrlKey || e.metaKey) {\r\n this.boxSelecting = {\r\n startX: w.x,\r\n startY: w.y,\r\n currentX: w.x,\r\n currentY: w.y,\r\n };\r\n } else {\r\n this.panning = { x: s.x, y: s.y };\r\n }\r\n this.render();\r\n return;\r\n }\r\n }\r\n\r\n _onMove(e) {\r\n // Track key states\r\n this.isAlt = e.altKey;\r\n this.isShift = e.shiftKey;\r\n this.isCtrl = e.ctrlKey;\r\n\r\n const s = this._posScreen(e);\r\n const w = this.renderer.screenToWorld(s.x, s.y);\r\n\r\n if (this.resizing) {\r\n const n = this.graph.nodes.get(this.resizing.nodeId);\r\n const dx = w.x - this.resizing.startX;\r\n const dy = w.y - this.resizing.startY;\r\n\r\n const minW = Controller.MIN_NODE_WIDTH;\r\n // Minimum height must fit all port rows\r\n const maxPorts = Math.max(n.inputs.length, n.outputs.length);\r\n const minH = maxPorts > 0\r\n ? Math.max(Controller.MIN_NODE_HEIGHT, 42 + maxPorts * 20)\r\n : Controller.MIN_NODE_HEIGHT;\r\n n.size.width = Math.max(minW, this.resizing.startW + dx);\r\n n.size.height = Math.max(minH, this.resizing.startH + dy);\r\n\r\n this.hooks?.emit(\"node:resize\", n);\r\n this._setCursor(\"se-resize\");\r\n this.render();\r\n return;\r\n }\r\n\r\n if (this.panning) {\r\n const dx = s.x - this.panning.x;\r\n const dy = s.y - this.panning.y;\r\n this.panning = { x: s.x, y: s.y };\r\n this.renderer.panBy(dx, dy);\r\n this.render();\r\n return;\r\n }\r\n\r\n if (this.dragging) {\r\n const n = this.graph.nodes.get(this.dragging.nodeId);\r\n\r\n // Calculate delta for main node\r\n let targetWx = w.x - this.dragging.offsetX;\r\n let targetWy = this.isShift ? w.y - 0 : w.y - this.dragging.offsetY;\r\n\r\n // Apply snap-to-grid if enabled\r\n if (this.snapToGrid) {\r\n targetWx = this._snapToGrid(targetWx);\r\n targetWy = this._snapToGrid(targetWy);\r\n }\r\n\r\n // Calculate delta from original position\r\n const deltaX =\r\n targetWx - this.dragging.selectedNodes.find((sn) => sn.node.id === n.id).startWorldX;\r\n const deltaY =\r\n targetWy - this.dragging.selectedNodes.find((sn) => sn.node.id === n.id).startWorldY;\r\n\r\n // Update world transforms\r\n this.graph.updateWorldTransforms();\r\n\r\n // Move all selected nodes by the same delta\r\n for (const { node: selectedNode, startWorldX, startWorldY } of this.dragging.selectedNodes) {\r\n // Skip group nodes when shift-dragging (vertical only)\r\n if (this.isShift && selectedNode.type === \"core/Group\") {\r\n continue;\r\n }\r\n\r\n const newWorldX = startWorldX + deltaX;\r\n const newWorldY = startWorldY + deltaY;\r\n\r\n // Convert to local position\r\n let parentWx = 0;\r\n let parentWy = 0;\r\n if (selectedNode.parent) {\r\n parentWx = selectedNode.parent.computed.x;\r\n parentWy = selectedNode.parent.computed.y;\r\n }\r\n\r\n selectedNode.pos.x = newWorldX - parentWx;\r\n selectedNode.pos.y = newWorldY - parentWy;\r\n }\r\n\r\n // If Alt is held and dragging a group, restore children to original world positions\r\n if (this.isAlt && n.type === \"core/Group\" && this.dragging.childrenWorldPos) {\r\n this.graph.updateWorldTransforms();\r\n for (const childInfo of this.dragging.childrenWorldPos) {\r\n const child = childInfo.node;\r\n const newGroupX = n.computed.x;\r\n const newGroupY = n.computed.y;\r\n\r\n child.pos.x = childInfo.worldX - newGroupX;\r\n child.pos.y = childInfo.worldY - newGroupY;\r\n }\r\n }\r\n\r\n this.hooks?.emit(\"node:move\", n);\r\n this.render();\r\n return;\r\n }\r\n\r\n if (this.boxSelecting) {\r\n this.boxSelecting.currentX = w.x;\r\n this.boxSelecting.currentY = w.y;\r\n this.render();\r\n return;\r\n }\r\n\r\n if (this.connecting) {\r\n this.connecting.x = s.x;\r\n this.connecting.y = s.y;\r\n this.render();\r\n }\r\n\r\n // Cursor update\r\n const port = this._findPortAtWorld(w.x, w.y);\r\n const node = this._findNodeAtWorld(w.x, w.y);\r\n\r\n if (node && this._hitResizeHandle(node, w.x, w.y)) {\r\n this._setCursor(\"se-resize\");\r\n } else if (port) {\r\n // Show pointer cursor over ports (for connecting/disconnecting)\r\n this._setCursor(\"pointer\");\r\n } else {\r\n this._setCursor(\"default\");\r\n }\r\n }\r\n\r\n _onUp(e) {\r\n this.isAlt = e.altKey;\r\n this.isShift = e.shiftKey;\r\n this.isCtrl = e.ctrlKey;\r\n\r\n const w = this._posWorld(e);\r\n\r\n if (this.panning) {\r\n this.panning = null;\r\n return;\r\n }\r\n\r\n if (this.connecting) {\r\n // ... (existing connection logic)\r\n const from = this.connecting;\r\n const portIn = this._findPortAtWorld(w.x, w.y);\r\n if (portIn && portIn.dir === \"in\") {\r\n this.stack.exec(\r\n AddEdgeCmd(this.graph, from.fromNode, from.fromPort, portIn.node.id, portIn.port.id)\r\n );\r\n }\r\n this.connecting = null;\r\n this.render();\r\n }\r\n\r\n if (this.resizing) {\r\n const n = this.graph.nodes.get(this.resizing.nodeId);\r\n const from = { w: this.resizing.startW, h: this.resizing.startH };\r\n const to = { w: n.size.width, h: n.size.height };\r\n if (from.w !== to.w || from.h !== to.h) {\r\n this.stack.exec(ResizeNodeCmd(n, from, to));\r\n }\r\n this.resizing = null;\r\n this._setCursor(\"default\");\r\n }\r\n\r\n if (this.dragging) {\r\n const n = this.graph.nodes.get(this.dragging.nodeId);\r\n\r\n // If we're dragging a GROUP with Alt, only move the group (keep children in place)\r\n if (n.type === \"core/Group\" && this.isAlt && this.dragging.childrenWorldPos) {\r\n // Restore children to their original world positions\r\n for (const childInfo of this.dragging.childrenWorldPos) {\r\n const child = childInfo.node;\r\n // Convert world position back to local position relative to new group position\r\n this.graph.updateWorldTransforms();\r\n const newGroupX = n.computed.x;\r\n const newGroupY = n.computed.y;\r\n\r\n child.pos.x = childInfo.worldX - newGroupX;\r\n child.pos.y = childInfo.worldY - newGroupY;\r\n }\r\n } else if (n.type === \"core/Group\" && !this.isAlt) {\r\n // Normal group drag - auto-parent nodes\r\n this._autoParentNodesInGroup(n);\r\n } else if (n.type !== \"core/Group\") {\r\n // Normal node: Reparenting Logic\r\n // Check if dropped onto a group\r\n const potentialParent = this._findPotentialParent(w.x, w.y, n);\r\n\r\n if (potentialParent && potentialParent !== n.parent) {\r\n this.graph.reparent(n, potentialParent);\r\n } else if (!potentialParent && n.parent) {\r\n // Dropped on empty space -> move to root\r\n this.graph.reparent(n, null);\r\n }\r\n }\r\n\r\n this.dragging = null;\r\n this.render();\r\n }\r\n\r\n if (this.boxSelecting) {\r\n // Select all nodes within the box\r\n const { startX, startY, currentX, currentY } = this.boxSelecting;\r\n const minX = Math.min(startX, currentX);\r\n const maxX = Math.max(startX, currentX);\r\n const minY = Math.min(startY, currentY);\r\n const maxY = Math.max(startY, currentY);\r\n\r\n for (const node of this.graph.nodes.values()) {\r\n const { x, y, w, h } = node.computed;\r\n // Check if node intersects with selection box\r\n if (x + w >= minX && x <= maxX && y + h >= minY && y <= maxY) {\r\n this.selection.add(node.id);\r\n }\r\n }\r\n\r\n this.boxSelecting = null;\r\n this.render();\r\n }\r\n }\r\n\r\n /**\r\n * Automatically parent nodes that are within the group's bounds\r\n * @param {Node} groupNode - The group node\r\n */\r\n _autoParentNodesInGroup(groupNode) {\r\n const { x: gx, y: gy, w: gw, h: gh } = groupNode.computed;\r\n\r\n // Find all nodes that are within the group bounds\r\n for (const node of this.graph.nodes.values()) {\r\n // Skip the group itself\r\n if (node === groupNode) continue;\r\n\r\n // Skip if it's already a child of this group\r\n if (node.parent === groupNode) continue;\r\n\r\n // Skip if it's another group (prevent nested groups for now)\r\n if (node.type === \"core/Group\") continue;\r\n\r\n // Check if node is within group bounds\r\n const { x: nx, y: ny, w: nw, h: nh } = node.computed;\r\n const nodeCenterX = nx + nw / 2;\r\n const nodeCenterY = ny + nh / 2;\r\n\r\n // Use center point to determine if node is inside group\r\n if (\r\n nodeCenterX >= gx &&\r\n nodeCenterX <= gx + gw &&\r\n nodeCenterY >= gy &&\r\n nodeCenterY <= gy + gh\r\n ) {\r\n // Parent this node to the group\r\n this.graph.reparent(node, groupNode);\r\n }\r\n }\r\n }\r\n\r\n _findPotentialParent(x, y, excludeNode) {\r\n // Find top-most group under x,y that is not excludeNode or its descendants\r\n const list = [...this.graph.nodes.values()].reverse();\r\n for (const n of list) {\r\n if (n.type !== \"core/Group\") continue;\r\n if (n === excludeNode) continue;\r\n // Check if n is descendant of excludeNode\r\n let p = n.parent;\r\n let isDescendant = false;\r\n while (p) {\r\n if (p === excludeNode) {\r\n isDescendant = true;\r\n break;\r\n }\r\n p = p.parent;\r\n }\r\n if (isDescendant) continue;\r\n\r\n const { x: nx, y: ny, w, h } = n.computed;\r\n if (x >= nx && x <= nx + w && y >= ny && y <= ny + h) {\r\n return n;\r\n }\r\n }\r\n return null;\r\n }\r\n\r\n /**\r\n * Snap a coordinate to the grid\r\n * @param {number} value - The value to snap\r\n * @returns {number} - Snapped value\r\n */\r\n _snapToGrid(value) {\r\n return Math.round(value / this.gridSize) * this.gridSize;\r\n }\r\n\r\n /**\r\n * Create a group from currently selected nodes\r\n */\r\n _createGroupFromSelection() {\r\n if (this.selection.size === 0) {\r\n console.warn(\"No nodes selected to group\");\r\n return;\r\n }\r\n\r\n // Get selected nodes\r\n const selectedNodes = Array.from(this.selection).map((id) => this.graph.getNodeById(id));\r\n\r\n // Calculate bounding box\r\n let minX = Infinity,\r\n minY = Infinity,\r\n maxX = -Infinity,\r\n maxY = -Infinity;\r\n for (const node of selectedNodes) {\r\n const { x, y, w, h } = node.computed;\r\n minX = Math.min(minX, x);\r\n minY = Math.min(minY, y);\r\n maxX = Math.max(maxX, x + w);\r\n maxY = Math.max(maxY, y + h);\r\n }\r\n\r\n const margin = 20;\r\n const groupX = minX - margin;\r\n const groupY = minY - margin;\r\n const groupWidth = maxX - minX + margin * 2;\r\n const groupHeight = maxY - minY + margin * 2;\r\n\r\n // Create group via GroupManager\r\n if (this.graph.groupManager) {\r\n this.graph.groupManager.addGroup({\r\n title: \"Group\",\r\n x: groupX,\r\n y: groupY,\r\n width: groupWidth,\r\n height: groupHeight,\r\n members: Array.from(this.selection),\r\n });\r\n this.selection.clear();\r\n this.render();\r\n }\r\n }\r\n\r\n /**\r\n * Align selected nodes horizontally (same Y position)\r\n */\r\n _alignNodesHorizontal() {\r\n if (this.selection.size < 2) return;\r\n\r\n const nodes = Array.from(this.selection).map((id) => this.graph.getNodeById(id));\r\n const avgY = nodes.reduce((sum, n) => sum + n.computed.y, 0) / nodes.length;\r\n\r\n for (const node of nodes) {\r\n const parentY = node.parent ? node.parent.computed.y : 0;\r\n node.pos.y = avgY - parentY;\r\n }\r\n\r\n this.graph.updateWorldTransforms();\r\n this.render();\r\n }\r\n\r\n /**\r\n * Align selected nodes vertically (same X position)\r\n */\r\n _alignNodesVertical() {\r\n if (this.selection.size < 2) return;\r\n\r\n const nodes = Array.from(this.selection).map((id) => this.graph.getNodeById(id));\r\n const avgX = nodes.reduce((sum, n) => sum + n.computed.x, 0) / nodes.length;\r\n\r\n for (const node of nodes) {\r\n const parentX = node.parent ? node.parent.computed.x : 0;\r\n node.pos.x = avgX - parentX;\r\n }\r\n\r\n this.graph.updateWorldTransforms();\r\n this.render();\r\n }\r\n\r\n render(time = performance.now()) {\r\n const tEdge = this.renderTempEdge();\r\n const runner = this.graph.runner;\r\n const isStepMode = !!runner && runner.executionMode === \"step\";\r\n\r\n // 1. Draw background (grid, canvas-only nodes) on main canvas\r\n this.renderer.draw(this.graph, {\r\n selection: this.selection,\r\n tempEdge: null, // Don't draw temp edge on background\r\n boxSelecting: this.boxSelecting,\r\n activeEdges: this.activeEdges || new Set(),\r\n activeEdgeTimes: this.activeEdgeTimes,\r\n drawEdges: !this.edgeRenderer, // Only draw edges here if no separate edge renderer\r\n time,\r\n loopActiveEdges: isStepMode,\r\n });\r\n\r\n // 2. HTML Overlay layer (HTML nodes at z-index 10)\r\n this.htmlOverlay?.draw(this.graph, this.selection);\r\n\r\n // 3. Draw edges and animations on edge canvas (above HTML overlay at z-index 15)\r\n if (this.edgeRenderer) {\r\n const edgeCtx = this.edgeRenderer.ctx;\r\n edgeCtx.clearRect(0, 0, this.edgeRenderer.canvas.width, this.edgeRenderer.canvas.height);\r\n\r\n // Edges use shared transform (via property getters)\r\n this.edgeRenderer._applyTransform();\r\n\r\n this.edgeRenderer.drawEdgesOnly(this.graph, {\r\n activeEdges: this.activeEdges,\r\n activeEdgeTimes: this.activeEdgeTimes,\r\n activeNodes: this.activeNodes,\r\n selection: this.selection,\r\n time,\r\n tempEdge: tEdge,\r\n loopActiveEdges: isStepMode,\r\n });\r\n\r\n this.edgeRenderer._resetTransform();\r\n }\r\n\r\n // 4. Draw box selection rectangle on top of edges\r\n if (this.boxSelecting) {\r\n const { startX, startY, currentX, currentY } = this.boxSelecting;\r\n const minX = Math.min(startX, currentX);\r\n const minY = Math.min(startY, currentY);\r\n const width = Math.abs(currentX - startX);\r\n const height = Math.abs(currentY - startY);\r\n\r\n const screenStart = this.renderer.worldToScreen(minX, minY);\r\n const screenEnd = this.renderer.worldToScreen(minX + width, minY + height);\r\n\r\n const ctx = this.edgeRenderer ? this.edgeRenderer.ctx : this.renderer.ctx;\r\n ctx.save();\r\n if (this.edgeRenderer) {\r\n this.edgeRenderer._resetTransform();\r\n } else {\r\n this.renderer._resetTransform();\r\n }\r\n\r\n // Draw selection box\r\n ctx.strokeStyle = \"#6cf\";\r\n ctx.fillStyle = \"rgba(102, 204, 255, 0.1)\";\r\n ctx.lineWidth = 2;\r\n ctx.strokeRect(\r\n screenStart.x,\r\n screenStart.y,\r\n screenEnd.x - screenStart.x,\r\n screenEnd.y - screenStart.y\r\n );\r\n ctx.fillRect(\r\n screenStart.x,\r\n screenStart.y,\r\n screenEnd.x - screenStart.x,\r\n screenEnd.y - screenStart.y\r\n );\r\n\r\n ctx.restore();\r\n }\r\n\r\n // 5. Draw ports on port canvas (above edges at z-index 20)\r\n if (this.portRenderer) {\r\n const portCtx = this.portRenderer.ctx;\r\n portCtx.clearRect(0, 0, this.portRenderer.canvas.width, this.portRenderer.canvas.height);\r\n\r\n // Sync transform\r\n this.portRenderer.scale = this.renderer.scale;\r\n this.portRenderer.offsetX = this.renderer.offsetX;\r\n this.portRenderer.offsetY = this.renderer.offsetY;\r\n\r\n this.portRenderer._applyTransform();\r\n\r\n // Draw ports for HTML overlay nodes only\r\n // Draw ports for ALL nodes to ensure they are above edges\r\n for (const n of this.graph.nodes.values()) {\r\n if (n.type !== \"core/Group\") {\r\n this.portRenderer._drawPorts(n);\r\n }\r\n }\r\n this.portRenderer._resetTransform();\r\n }\r\n }\r\n\r\n renderTempEdge() {\r\n if (!this.connecting) return null;\r\n const a = this._portAnchorScreen(this.connecting.fromNode, this.connecting.fromPort); // {x,y}\r\n return {\r\n x1: a.x,\r\n y1: a.y,\r\n x2: this.connecting.x,\r\n y2: this.connecting.y,\r\n };\r\n }\r\n\r\n _portAnchorScreen(nodeId, portId) {\r\n const n = this.graph.nodes.get(nodeId);\r\n const iOut = n.outputs.findIndex((p) => p.id === portId);\r\n const r = portRect(n, null, iOut, \"out\"); // world rect\r\n return this.renderer.worldToScreen(r.x + r.w / 2, r.y + r.h / 2); // -> screen point (CENTER)\r\n }\r\n}\r\n\r\nfunction rectHas(r, x, y) {\r\n return x >= r.x && x <= r.x + r.w && y >= r.y && y <= r.y + r.h;\r\n}\r\n","/**\r\n * ContextMenu - Extensible context menu for nodes and groups\r\n * Provides right-click functionality with customizable menu items\r\n */\r\nexport class ContextMenu {\r\n constructor({ graph, hooks, renderer, commandStack }) {\r\n this.graph = graph;\r\n this.hooks = hooks;\r\n this.renderer = renderer;\r\n this.commandStack = commandStack;\r\n\r\n this.items = [];\r\n this.visible = false;\r\n this.target = null;\r\n this.position = { x: 0, y: 0 };\r\n\r\n this.menuElement = this._createMenuElement();\r\n\r\n // Close menu on any click outside\r\n this._onDocumentClick = (e) => {\r\n if (!this.menuElement.contains(e.target)) {\r\n this.hide();\r\n }\r\n };\r\n }\r\n\r\n /**\r\n * Add a menu item\r\n * @param {string} id - Unique identifier for the menu item\r\n * @param {string} label - Display label\r\n * @param {Object} options - Options\r\n * @param {Function} options.action - Action to execute (receives target)\r\n * @param {Array} options.submenu - Submenu items\r\n * @param {Function} options.condition - Optional condition to show item (receives target)\r\n * @param {number} options.order - Optional sort order (default: 100)\r\n */\r\n addItem(id, label, options = {}) {\r\n const { action, submenu, condition, order = 100 } = options;\r\n\r\n // Either action or submenu must be provided\r\n if (!action && !submenu) {\r\n console.error(\"ContextMenu.addItem: either action or submenu is required\");\r\n return;\r\n }\r\n\r\n // Remove existing item with same id\r\n this.removeItem(id);\r\n\r\n this.items.push({\r\n id,\r\n label,\r\n action,\r\n submenu,\r\n condition,\r\n order,\r\n });\r\n\r\n // Sort by order\r\n this.items.sort((a, b) => a.order - b.order);\r\n }\r\n\r\n /**\r\n * Remove a menu item by id\r\n * @param {string} id - Item id to remove\r\n */\r\n removeItem(id) {\r\n this.items = this.items.filter((item) => item.id !== id);\r\n }\r\n\r\n /**\r\n * Show the context menu\r\n * @param {Object} target - Target node/group\r\n * @param {number} x - Screen x position\r\n * @param {number} y - Screen y position\r\n * @param {Object} worldPos - Optional world position {x, y}\r\n */\r\n show(target, x, y, worldPos = null) {\r\n this.target = target;\r\n this.position = { x, y };\r\n this.worldPosition = worldPos; // Store world position for node creation\r\n this.visible = true;\r\n\r\n this._renderItems();\r\n\r\n // Position menu\r\n this.menuElement.style.left = `${x}px`;\r\n this.menuElement.style.top = `${y}px`;\r\n this.menuElement.style.display = \"block\";\r\n\r\n // Adjust position if menu goes off-screen\r\n requestAnimationFrame(() => {\r\n const rect = this.menuElement.getBoundingClientRect();\r\n const vw = window.innerWidth;\r\n const vh = window.innerHeight;\r\n\r\n let adjustedX = x;\r\n let adjustedY = y;\r\n\r\n if (rect.right > vw) {\r\n adjustedX = vw - rect.width - 5;\r\n }\r\n if (rect.bottom > vh) {\r\n adjustedY = vh - rect.height - 5;\r\n }\r\n\r\n this.menuElement.style.left = `${adjustedX}px`;\r\n this.menuElement.style.top = `${adjustedY}px`;\r\n });\r\n\r\n // Listen for clicks to close menu\r\n document.addEventListener(\"click\", this._onDocumentClick);\r\n }\r\n\r\n /**\r\n * Hide the context menu\r\n */\r\n hide() {\r\n this.visible = false;\r\n this.target = null;\r\n\r\n // Clean up any open submenus\r\n const allSubmenus = document.querySelectorAll(\".context-submenu\");\r\n allSubmenus.forEach(submenu => submenu.remove());\r\n\r\n this.menuElement.style.display = \"none\";\r\n document.removeEventListener(\"click\", this._onDocumentClick);\r\n }\r\n\r\n /**\r\n * Cleanup\r\n */\r\n destroy() {\r\n this.hide();\r\n if (this.menuElement && this.menuElement.parentNode) {\r\n this.menuElement.parentNode.removeChild(this.menuElement);\r\n }\r\n }\r\n\r\n /**\r\n * Create the menu DOM element\r\n * @private\r\n */\r\n _createMenuElement() {\r\n const menu = document.createElement(\"div\");\r\n menu.className = \"html-overlay-node-context-menu\";\r\n\r\n // Styling\r\n Object.assign(menu.style, {\r\n position: \"fixed\",\r\n display: \"none\",\r\n minWidth: \"180px\",\r\n backgroundColor: \"#2a2a2e\",\r\n border: \"1px solid #444\",\r\n borderRadius: \"6px\",\r\n boxShadow: \"0 4px 16px rgba(0, 0, 0, 0.4)\",\r\n zIndex: \"10000\",\r\n padding: \"4px 0\",\r\n fontFamily: \"system-ui, -apple-system, sans-serif\",\r\n fontSize: \"13px\",\r\n color: \"#e9e9ef\",\r\n });\r\n\r\n document.body.appendChild(menu);\r\n return menu;\r\n }\r\n\r\n /**\r\n * Render menu items based on current target\r\n * @private\r\n */\r\n _renderItems() {\r\n this.menuElement.innerHTML = \"\";\r\n\r\n const visibleItems = this.items.filter((item) => {\r\n if (item.condition) {\r\n return item.condition(this.target);\r\n }\r\n return true;\r\n });\r\n\r\n if (visibleItems.length === 0) {\r\n this.hide();\r\n return;\r\n }\r\n\r\n visibleItems.forEach((item) => {\r\n const itemEl = document.createElement(\"div\");\r\n itemEl.className = \"context-menu-item\";\r\n\r\n // Create item content wrapper\r\n const contentWrapper = document.createElement(\"div\");\r\n Object.assign(contentWrapper.style, {\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"space-between\",\r\n width: \"100%\",\r\n });\r\n\r\n const labelEl = document.createElement(\"span\");\r\n labelEl.textContent = item.label;\r\n contentWrapper.appendChild(labelEl);\r\n\r\n // Add arrow indicator if item has submenu\r\n if (item.submenu) {\r\n const arrow = document.createElement(\"span\");\r\n arrow.textContent = \"▶\";\r\n arrow.style.marginLeft = \"12px\";\r\n arrow.style.fontSize = \"10px\";\r\n arrow.style.opacity = \"0.7\";\r\n contentWrapper.appendChild(arrow);\r\n }\r\n\r\n itemEl.appendChild(contentWrapper);\r\n\r\n Object.assign(itemEl.style, {\r\n padding: \"4px 8px\",\r\n cursor: \"pointer\",\r\n transition: \"background-color 0.15s ease\",\r\n userSelect: \"none\",\r\n position: \"relative\",\r\n });\r\n\r\n // Hover effect\r\n itemEl.addEventListener(\"mouseenter\", () => {\r\n itemEl.style.backgroundColor = \"#3a3a3e\";\r\n\r\n // Clear any pending hide timeout\r\n if (itemEl._hideTimeout) {\r\n clearTimeout(itemEl._hideTimeout);\r\n itemEl._hideTimeout = null;\r\n }\r\n\r\n // Show submenu if exists\r\n if (item.submenu) {\r\n // Support function-based submenus for dynamic content\r\n const submenuItems = typeof item.submenu === 'function'\r\n ? item.submenu()\r\n : item.submenu;\r\n this._showSubmenu(submenuItems, itemEl);\r\n }\r\n });\r\n\r\n itemEl.addEventListener(\"mouseleave\", (e) => {\r\n itemEl.style.backgroundColor = \"transparent\";\r\n\r\n // Hide submenu with delay if moving to submenu\r\n if (item.submenu) {\r\n const submenuEl = itemEl._submenuElement;\r\n if (submenuEl) {\r\n // Add delay before hiding to allow mouse to reach submenu\r\n itemEl._hideTimeout = setTimeout(() => {\r\n if (!submenuEl.contains(document.elementFromPoint(e.clientX, e.clientY))) {\r\n this._hideSubmenu(itemEl);\r\n }\r\n }, 150); // 150ms delay\r\n }\r\n }\r\n });\r\n\r\n // Click handler\r\n if (!item.submenu) {\r\n itemEl.addEventListener(\"click\", (e) => {\r\n e.stopPropagation();\r\n item.action(this.target);\r\n this.hide();\r\n });\r\n }\r\n\r\n this.menuElement.appendChild(itemEl);\r\n });\r\n }\r\n\r\n /**\r\n * Show submenu for an item\r\n * @private\r\n */\r\n _showSubmenu(submenuItems, parentItemEl) {\r\n // Remove any existing submenu\r\n this._hideSubmenu(parentItemEl);\r\n\r\n const submenuEl = document.createElement(\"div\");\r\n submenuEl.className = \"context-submenu\";\r\n\r\n Object.assign(submenuEl.style, {\r\n position: \"fixed\",\r\n minWidth: \"140px\",\r\n backgroundColor: \"#2a2a2e\",\r\n border: \"1px solid #444\",\r\n borderRadius: \"6px\",\r\n boxShadow: \"0 4px 16px rgba(0, 0, 0, 0.4)\",\r\n zIndex: \"10001\",\r\n padding: \"4px 0\",\r\n fontFamily: \"system-ui, -apple-system, sans-serif\",\r\n fontSize: \"13px\",\r\n color: \"#e9e9ef\",\r\n });\r\n\r\n submenuItems.forEach((subItem) => {\r\n const subItemEl = document.createElement(\"div\");\r\n subItemEl.className = \"context-submenu-item\";\r\n\r\n // Create content with color swatch if available\r\n const contentWrapper = document.createElement(\"div\");\r\n Object.assign(contentWrapper.style, {\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n gap: \"8px\",\r\n });\r\n\r\n // Color swatch\r\n if (subItem.color) {\r\n const swatch = document.createElement(\"div\");\r\n Object.assign(swatch.style, {\r\n width: \"16px\",\r\n height: \"16px\",\r\n borderRadius: \"3px\",\r\n backgroundColor: subItem.color,\r\n border: \"1px solid #555\",\r\n flexShrink: \"0\",\r\n });\r\n contentWrapper.appendChild(swatch);\r\n }\r\n\r\n const labelEl = document.createElement(\"span\");\r\n labelEl.textContent = subItem.label;\r\n contentWrapper.appendChild(labelEl);\r\n\r\n subItemEl.appendChild(contentWrapper);\r\n\r\n Object.assign(subItemEl.style, {\r\n padding: \"4px 8px\",\r\n cursor: \"pointer\",\r\n transition: \"background-color 0.15s ease\",\r\n userSelect: \"none\",\r\n });\r\n\r\n subItemEl.addEventListener(\"mouseenter\", () => {\r\n subItemEl.style.backgroundColor = \"#3a3a3e\";\r\n });\r\n\r\n subItemEl.addEventListener(\"mouseleave\", () => {\r\n subItemEl.style.backgroundColor = \"transparent\";\r\n });\r\n\r\n subItemEl.addEventListener(\"click\", (e) => {\r\n e.stopPropagation();\r\n subItem.action(this.target);\r\n this.hide();\r\n });\r\n\r\n submenuEl.appendChild(subItemEl);\r\n });\r\n\r\n // Keep submenu open when hovering over it\r\n submenuEl.addEventListener(\"mouseenter\", () => {\r\n // Clear parent's hide timeout\r\n if (parentItemEl._hideTimeout) {\r\n clearTimeout(parentItemEl._hideTimeout);\r\n parentItemEl._hideTimeout = null;\r\n }\r\n });\r\n\r\n submenuEl.addEventListener(\"mouseleave\", (e) => {\r\n if (!parentItemEl.contains(e.relatedTarget)) {\r\n this._hideSubmenu(parentItemEl);\r\n }\r\n });\r\n\r\n document.body.appendChild(submenuEl);\r\n parentItemEl._submenuElement = submenuEl;\r\n\r\n // Position submenu next to parent item\r\n requestAnimationFrame(() => {\r\n const parentRect = parentItemEl.getBoundingClientRect();\r\n const submenuRect = submenuEl.getBoundingClientRect();\r\n\r\n let left = parentRect.right + 2;\r\n let top = parentRect.top;\r\n\r\n // Adjust if submenu goes off-screen\r\n if (left + submenuRect.width > window.innerWidth) {\r\n left = parentRect.left - submenuRect.width - 2;\r\n }\r\n\r\n if (top + submenuRect.height > window.innerHeight) {\r\n top = window.innerHeight - submenuRect.height - 5;\r\n }\r\n\r\n submenuEl.style.left = `${left}px`;\r\n submenuEl.style.top = `${top}px`;\r\n });\r\n }\r\n\r\n /**\r\n * Hide submenu for an item\r\n * @private\r\n */\r\n _hideSubmenu(parentItemEl) {\r\n if (parentItemEl._submenuElement) {\r\n parentItemEl._submenuElement.remove();\r\n parentItemEl._submenuElement = null;\r\n }\r\n }\r\n}\r\n","export class Runner {\r\n constructor({ graph, registry, hooks, cyclesPerFrame = 1 }) {\r\n this.graph = graph;\r\n this.registry = registry;\r\n this.hooks = hooks;\r\n this.running = false;\r\n this._raf = null;\r\n this._last = 0;\r\n this.cyclesPerFrame = Math.max(1, cyclesPerFrame | 0);\r\n this.executionMode = \"run\"; // \"run\" or \"step\"\r\n this.activePlan = null;\r\n this.activeStepIndex = -1;\r\n this.stepCache = new Map();\r\n }\r\n\r\n isRunning() {\r\n return this.running;\r\n }\r\n\r\n setCyclesPerFrame(n) {\r\n this.cyclesPerFrame = Math.max(1, n | 0);\r\n }\r\n\r\n step(cycles = 1, dt = 0) {\r\n const nCycles = Math.max(1, cycles | 0);\r\n for (let c = 0; c < nCycles; c++) {\r\n for (const node of this.graph.nodes.values()) {\r\n const def = this.registry.types.get(node.type);\r\n if (def?.onExecute) {\r\n try {\r\n def.onExecute(node, {\r\n dt,\r\n graph: this.graph,\r\n getInput: (portName) => {\r\n const p =\r\n node.inputs.find((i) => i.name === portName) ||\r\n node.inputs[0];\r\n return p ? this.graph.getInput(node.id, p.id) : undefined;\r\n },\r\n setOutput: (portName, value) => {\r\n const p =\r\n node.outputs.find((o) => o.name === portName) ||\r\n node.outputs[0];\r\n if (p) this.graph.setOutput(node.id, p.id, value);\r\n },\r\n });\r\n } catch (err) {\r\n this.hooks?.emit?.(\"error\", err);\r\n }\r\n }\r\n }\r\n this.graph.swapBuffers();\r\n }\r\n }\r\n\r\n /**\r\n * Execute connected nodes once from a starting node.\r\n * Returns execEdgeOrder: exec edges in the order they were traversed.\r\n */\r\n runOnce(startNodeId, dt = 0) {\r\n const executedNodes = [];\r\n const allConnectedNodes = new Set();\r\n const execEdgeOrder = []; // exec edge IDs in traversal order\r\n\r\n // Local output cache: nodeId:portId → value\r\n // Ensures outputs written by executeNode are immediately readable by subsequent nodes\r\n const runCache = new Map();\r\n\r\n // Queue items: { nodeId, fromEdgeId }\r\n const queue = [{ nodeId: startNodeId, fromEdgeId: null }];\r\n const visited = new Set();\r\n\r\n while (queue.length > 0) {\r\n const { nodeId: currentNodeId, fromEdgeId } = queue.shift();\r\n\r\n if (visited.has(currentNodeId)) continue;\r\n visited.add(currentNodeId);\r\n\r\n // Record the exec edge that led to this node\r\n if (fromEdgeId) execEdgeOrder.push(fromEdgeId);\r\n\r\n const node = this.graph.nodes.get(currentNodeId);\r\n if (!node) continue;\r\n\r\n executedNodes.push(currentNodeId);\r\n allConnectedNodes.add(currentNodeId);\r\n\r\n // Execute data dependency nodes first\r\n for (const input of node.inputs) {\r\n if (input.portType === \"data\") {\r\n for (const edge of this.graph.edges.values()) {\r\n if (edge.toNode === currentNodeId && edge.toPort === input.id) {\r\n const sourceNode = this.graph.nodes.get(edge.fromNode);\r\n if (sourceNode && !allConnectedNodes.has(edge.fromNode)) {\r\n allConnectedNodes.add(edge.fromNode);\r\n this._executeNodeWithCache(edge.fromNode, dt, runCache);\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Execute this node\r\n this._executeNodeWithCache(currentNodeId, dt, runCache);\r\n\r\n // Find exec output edges and enqueue next nodes\r\n const execOutputPorts = node.outputs.filter((p) => p.portType === \"exec\");\r\n for (const execOutput of execOutputPorts) {\r\n for (const edge of this.graph.edges.values()) {\r\n if (edge.fromNode === currentNodeId && edge.fromPort === execOutput.id) {\r\n queue.push({ nodeId: edge.toNode, fromEdgeId: edge.id });\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Collect all edges involved (both exec and data)\r\n const connectedEdges = new Set();\r\n for (const edge of this.graph.edges.values()) {\r\n if (allConnectedNodes.has(edge.fromNode) && allConnectedNodes.has(edge.toNode)) {\r\n connectedEdges.add(edge.id);\r\n }\r\n }\r\n\r\n return { connectedNodes: allConnectedNodes, connectedEdges, execEdgeOrder };\r\n }\r\n\r\n setExecutionMode(mode) {\r\n this.executionMode = mode;\r\n if (mode === \"run\") this.resetStepping();\r\n }\r\n\r\n resetStepping() {\r\n this.activePlan = null;\r\n this.activeStepIndex = -1;\r\n this.stepCache.clear();\r\n this.hooks?.emit?.(\"runner:step-updated\", { activeNodeId: null });\r\n }\r\n\r\n buildPlan(startNodeId) {\r\n const plan = [];\r\n const allConnectedNodes = new Set();\r\n const queue = [{ nodeId: startNodeId, fromEdgeId: null }];\r\n const visited = new Set();\r\n\r\n while (queue.length > 0) {\r\n const { nodeId: currentNodeId, fromEdgeId } = queue.shift();\r\n if (visited.has(currentNodeId)) continue;\r\n visited.add(currentNodeId);\r\n allConnectedNodes.add(currentNodeId);\r\n\r\n const node = this.graph.nodes.get(currentNodeId);\r\n if (!node) continue;\r\n\r\n // Collect data dependency nodes (in order) for this exec node\r\n const dataDeps = [];\r\n for (const input of node.inputs) {\r\n if (input.portType === \"data\") {\r\n for (const edge of this.graph.edges.values()) {\r\n if (edge.toNode === currentNodeId && edge.toPort === input.id) {\r\n const srcId = edge.fromNode;\r\n if (!allConnectedNodes.has(srcId)) {\r\n allConnectedNodes.add(srcId);\r\n dataDeps.push(srcId);\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n // Find ALL incoming edges (both exec and data) to highlight them in Step Mode\r\n const incomingEdges = [];\r\n for (const edge of this.graph.edges.values()) {\r\n if (edge.toNode === currentNodeId) {\r\n incomingEdges.push(edge.id);\r\n }\r\n }\r\n\r\n plan.push({ nodeId: currentNodeId, fromEdgeId, incomingEdges, dataDeps });\r\n\r\n // Enqueue next exec nodes\r\n const execOutputs = node.outputs.filter((p) => p.portType === \"exec\");\r\n for (const execOutput of execOutputs) {\r\n for (const edge of this.graph.edges.values()) {\r\n if (edge.fromNode === currentNodeId && edge.fromPort === execOutput.id) {\r\n queue.push({ nodeId: edge.toNode, fromEdgeId: edge.id });\r\n }\r\n }\r\n }\r\n }\r\n\r\n return plan;\r\n }\r\n\r\n startStepping(startNodeId) {\r\n this.stepCache.clear();\r\n this.activePlan = this.buildPlan(startNodeId);\r\n this.activeStepIndex = 0;\r\n const step = this.activePlan[0];\r\n this.hooks?.emit?.(\"runner:step-updated\", {\r\n activeNodeId: step?.nodeId,\r\n activeEdgeIds: step?.incomingEdges || [],\r\n });\r\n this.start(); // Start the loop to driving animations\r\n }\r\n\r\n executeNextStep() {\r\n if (!this.activePlan || this.activeStepIndex < 0 || this.activeStepIndex >= this.activePlan.length) {\r\n this.resetStepping();\r\n return null;\r\n }\r\n\r\n const step = this.activePlan[this.activeStepIndex];\r\n\r\n // Execute data deps\r\n for (const depId of step.dataDeps) {\r\n this._executeNodeWithCache(depId, 0, this.stepCache);\r\n }\r\n\r\n // Execute main node\r\n this._executeNodeWithCache(step.nodeId, 0, this.stepCache);\r\n\r\n this.activeStepIndex++;\r\n\r\n if (this.activeStepIndex < this.activePlan.length) {\r\n const nextStep = this.activePlan[this.activeStepIndex];\r\n this.hooks?.emit?.(\"runner:step-updated\", {\r\n activeNodeId: nextStep.nodeId,\r\n activeEdgeIds: nextStep.incomingEdges || [],\r\n });\r\n } else {\r\n this.hooks?.emit?.(\"runner:step-updated\", { activeNodeId: null });\r\n this.resetStepping();\r\n }\r\n\r\n return step.nodeId;\r\n }\r\n\r\n /** Execute a node using a shared run-local output cache for reliable data passing. */\r\n _executeNodeWithCache(nodeId, dt, runCache) {\r\n const node = this.graph.nodes.get(nodeId);\r\n if (!node) return;\r\n const def = this.registry.types.get(node.type);\r\n if (!def?.onExecute) return;\r\n\r\n try {\r\n def.onExecute(node, {\r\n dt,\r\n graph: this.graph,\r\n getInput: (portName) => {\r\n const p = node.inputs.find((i) => i.name === portName) || node.inputs[0];\r\n if (!p) return undefined;\r\n for (const edge of this.graph.edges.values()) {\r\n if (edge.toNode === nodeId && edge.toPort === p.id) {\r\n const key = `${edge.fromNode}:${edge.fromPort}`;\r\n // Check run-local cache first, then fall back to graph buffer\r\n return runCache.has(key) ? runCache.get(key) : this.graph._curBuf().get(key);\r\n }\r\n }\r\n return undefined;\r\n },\r\n setOutput: (portName, value) => {\r\n const p = node.outputs.find((o) => o.name === portName) || node.outputs[0];\r\n if (p) {\r\n runCache.set(`${node.id}:${p.id}`, value);\r\n }\r\n },\r\n });\r\n } catch (err) {\r\n this.hooks?.emit?.(\"error\", err);\r\n }\r\n }\r\n\r\n findAllNextExecNodes(nodeId) {\r\n const node = this.graph.nodes.get(nodeId);\r\n if (!node) return [];\r\n\r\n const execOutputs = node.outputs.filter((p) => p.portType === \"exec\");\r\n if (execOutputs.length === 0) return [];\r\n\r\n const nextNodes = [];\r\n for (const execOutput of execOutputs) {\r\n for (const edge of this.graph.edges.values()) {\r\n if (edge.fromNode === nodeId && edge.fromPort === execOutput.id) {\r\n nextNodes.push(edge.toNode);\r\n }\r\n }\r\n }\r\n return nextNodes;\r\n }\r\n\r\n executeNode(nodeId, dt) {\r\n const node = this.graph.nodes.get(nodeId);\r\n if (!node) return;\r\n\r\n const def = this.registry.types.get(node.type);\r\n if (!def?.onExecute) return;\r\n\r\n try {\r\n def.onExecute(node, {\r\n dt,\r\n graph: this.graph,\r\n getInput: (portName) => {\r\n const p = node.inputs.find((i) => i.name === portName) || node.inputs[0];\r\n return p ? this.graph.getInput(node.id, p.id) : undefined;\r\n },\r\n setOutput: (portName, value) => {\r\n const p = node.outputs.find((o) => o.name === portName) || node.outputs[0];\r\n if (p) {\r\n const key = `${node.id}:${p.id}`;\r\n this.graph._curBuf().set(key, value);\r\n }\r\n },\r\n });\r\n } catch (err) {\r\n this.hooks?.emit?.(\"error\", err);\r\n }\r\n }\r\n\r\n start() {\r\n if (this.running) return;\r\n this.running = true;\r\n this._last = 0;\r\n this.hooks?.emit?.(\"runner:start\");\r\n\r\n const loop = (t) => {\r\n if (!this.running) return;\r\n const dtMs = this._last ? t - this._last : 0;\r\n this._last = t;\r\n const dt = dtMs / 1000;\r\n\r\n // Only execute nodes automatically in \"run\" mode.\r\n // In \"step\" mode, we only want the loop to fire for animations (via tick event).\r\n if (this.executionMode === \"run\") {\r\n this.step(this.cyclesPerFrame, dt);\r\n }\r\n\r\n this.hooks?.emit?.(\"runner:tick\", {\r\n time: t,\r\n dt,\r\n running: true,\r\n cps: this.cyclesPerFrame,\r\n });\r\n\r\n this._raf = requestAnimationFrame(loop);\r\n };\r\n\r\n this._raf = requestAnimationFrame(loop);\r\n }\r\n\r\n stop() {\r\n if (!this.running) return;\r\n this.running = false;\r\n if (this._raf) cancelAnimationFrame(this._raf);\r\n this._raf = null;\r\n this._last = 0;\r\n this.hooks?.emit?.(\"runner:stop\");\r\n }\r\n}\r\n","// 캔버스 위에 붙는 DOM 오버레이. 캔버스의 scale/offset에 맞춰 CSS transform을 적용.\r\n// 동기화 하기 까다로워서 아직 적용하지 않음\r\nexport class HtmlOverlay {\r\n /**\r\n * @param {HTMLElement} host 캔버스를 감싸는 래퍼( position: relative )\r\n * @param {CanvasRenderer} renderer\r\n * @param {Registry} registry\r\n */\r\n constructor(host, renderer, registry) {\r\n this.host = host;\r\n this.renderer = renderer;\r\n this.registry = registry;\r\n this.container = document.createElement(\"div\");\r\n Object.assign(this.container.style, {\r\n position: \"absolute\",\r\n inset: \"0\",\r\n pointerEvents: \"none\", // 기본은 통과\r\n zIndex: \"10\",\r\n });\r\n host.appendChild(this.container);\r\n\r\n /** @type {Map<string, HTMLElement>} */\r\n this.nodes = new Map();\r\n }\r\n\r\n /** 기본 노드 레이아웃 생성 (헤더 + 바디) */\r\n _createDefaultNodeLayout(_node) {\r\n const container = document.createElement(\"div\");\r\n container.className = \"node-overlay\";\r\n Object.assign(container.style, {\r\n position: \"absolute\",\r\n display: \"flex\",\r\n flexDirection: \"column\",\r\n boxSizing: \"border-box\",\r\n pointerEvents: \"none\", // 기본은 통과 (캔버스 인터랙션 위해)\r\n overflow: \"hidden\", // 둥근 모서리 등\r\n });\r\n\r\n const header = document.createElement(\"div\");\r\n header.className = \"node-header\";\r\n Object.assign(header.style, {\r\n height: \"26px\",\r\n flexShrink: \"0\",\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n padding: \"0 8px\",\r\n cursor: \"grab\",\r\n userSelect: \"none\",\r\n pointerEvents: \"none\", // 헤더 클릭시 드래그는 캔버스가 처리\r\n });\r\n\r\n const body = document.createElement(\"div\");\r\n body.className = \"node-body\";\r\n Object.assign(body.style, {\r\n flex: \"1\",\r\n position: \"relative\",\r\n overflow: \"hidden\",\r\n // 바디 내부는 인터랙션 가능하게? 아니면 이것도 none하고 자식만 auto?\r\n // 일단 바디는 auto로 두면 바디 영역 클릭시 드래그가 안됨.\r\n // 그래서 바디도 none으로 하고, 내부 컨텐츠(input 등)만 auto로 하는게 맞음.\r\n pointerEvents: \"none\",\r\n });\r\n\r\n container.appendChild(header);\r\n container.appendChild(body);\r\n\r\n // 나중에 접근하기 쉽게 프로퍼티로 저장\r\n container._domParts = { header, body };\r\n return container;\r\n }\r\n\r\n /** 노드용 엘리먼트 생성(한 번만) */\r\n _ensureNodeElement(node, def, graph) {\r\n let el = this.nodes.get(node.id);\r\n if (!el) {\r\n // 1) 사용자 정의 render 함수가 있으면 우선 사용\r\n if (def.html?.render) {\r\n el = def.html.render(node);\r\n }\r\n // 2) 아니면 기본 레이아웃 사용 (html 설정이 있는 경우)\r\n else if (def.html) {\r\n el = this._createDefaultNodeLayout(node);\r\n // 초기화 훅 - graph reference 전달\r\n if (def.html.init) {\r\n def.html.init(node, el, { ...el._domParts, graph });\r\n }\r\n } else {\r\n return null; // HTML 없음\r\n }\r\n\r\n if (!el) return null;\r\n\r\n el.style.position = \"absolute\";\r\n el.style.pointerEvents = \"none\"; // 기본적으로 캔버스 통과\r\n this.container.appendChild(el);\r\n this.nodes.set(node.id, el);\r\n }\r\n return el;\r\n }\r\n\r\n /** 그래프와 변환 동기화하여 렌더링 */\r\n draw(graph, selection = new Set()) {\r\n // 컨테이너 전체에 월드 변환 적용 (CSS 픽셀 기준)\r\n const { scale, offsetX, offsetY } = this.renderer;\r\n this.container.style.transform = `translate(${offsetX}px, ${offsetY}px) scale(${scale})`;\r\n this.container.style.transformOrigin = \"0 0\";\r\n\r\n const seen = new Set();\r\n\r\n for (const node of graph.nodes.values()) {\r\n const def = this.registry.types.get(node.type);\r\n\r\n // render 함수가 있거나, html 설정 객체가 있으면 처리\r\n const hasHtml = !!def?.html;\r\n if (!hasHtml) continue;\r\n\r\n const el = this._ensureNodeElement(node, def, graph);\r\n if (!el) continue;\r\n\r\n // 노드 위치/크기 동기화 (월드 좌표 → 컨테이너 내부는 이미 scale/translate 적용)\r\n el.style.left = `${node.computed.x}px`;\r\n el.style.top = `${node.computed.y}px`;\r\n el.style.width = `${node.computed.w}px`;\r\n el.style.height = `${node.computed.h}px`;\r\n\r\n // 선택 상태 등 업데이트 훅\r\n if (def.html.update) {\r\n // 기본 레이아웃이면 header/body도 함께 전달\r\n const parts = el._domParts || {};\r\n def.html.update(node, el, {\r\n selected: selection.has(node.id),\r\n header: parts.header,\r\n body: parts.body,\r\n });\r\n }\r\n\r\n seen.add(node.id);\r\n }\r\n\r\n // ── Interactive Stepping Play Button ─────────────────────\r\n this._drawStepOverlay(graph);\r\n\r\n // 없어진 노드 제거\r\n for (const [id, el] of this.nodes) {\r\n if (!seen.has(id)) {\r\n el.remove();\r\n this.nodes.delete(id);\r\n }\r\n }\r\n }\r\n\r\n _drawStepOverlay(graph) {\r\n const runner = graph.runner;\r\n if (!runner || runner.executionMode !== \"step\" || !runner.activePlan) {\r\n if (this._stepBtn) {\r\n this._stepBtn.style.display = \"none\";\r\n }\r\n return;\r\n }\r\n\r\n const nextStep = runner.activePlan[runner.activeStepIndex];\r\n if (!nextStep) {\r\n if (this._stepBtn) this._stepBtn.style.display = \"none\";\r\n return;\r\n }\r\n\r\n const node = graph.nodes.get(nextStep.nodeId);\r\n if (!node) return;\r\n\r\n if (!this._stepBtn) {\r\n this._stepBtn = document.createElement(\"button\");\r\n this._stepBtn.className = \"step-play-button\";\r\n this._stepBtn.innerHTML = \"▶\";\r\n Object.assign(this._stepBtn.style, {\r\n position: \"absolute\",\r\n zIndex: \"100\",\r\n width: \"20px\",\r\n height: \"20px\",\r\n borderRadius: \"4px\",\r\n border: \"none\",\r\n background: \"transparent\",\r\n color: \"white\",\r\n fontSize: \"12px\",\r\n cursor: \"pointer\",\r\n display: \"flex\",\r\n alignItems: \"center\",\r\n justifyContent: \"center\",\r\n // boxShadow: \"0 2px 6px rgba(0,0,0,0.3)\",\r\n pointerEvents: \"auto\",\r\n transition: \"transform 0.1s, background 0.2s\",\r\n });\r\n this._stepBtn.addEventListener(\"mouseover\", () => {\r\n this._stepBtn.style.transform = \"scale(1)\";\r\n });\r\n this._stepBtn.addEventListener(\"mouseout\", () => {\r\n this._stepBtn.style.transform = \"scale(1)\";\r\n });\r\n this._stepBtn.addEventListener(\"click\", (e) => {\r\n e.stopPropagation();\r\n runner.executeNextStep();\r\n });\r\n this.container.appendChild(this._stepBtn);\r\n }\r\n\r\n // Position the button in the top-right corner of the node (header area)\r\n this._stepBtn.style.display = \"flex\";\r\n this._stepBtn.style.left = `${node.computed.x + node.computed.w - 26}px`;\r\n this._stepBtn.style.top = `${node.computed.y + 2}px`;\r\n }\r\n\r\n /**\r\n * Sync container transform with renderer state (lightweight update)\r\n * Called when zoom/pan occurs without needing full redraw\r\n */\r\n syncTransform() {\r\n const { scale, offsetX, offsetY } = this.renderer;\r\n this.container.style.transform = `translate(${offsetX}px, ${offsetY}px) scale(${scale})`;\r\n this.container.style.transformOrigin = \"0 0\";\r\n }\r\n\r\n clear() {\r\n // Remove all node elements\r\n for (const [, el] of this.nodes) {\r\n el.remove();\r\n }\r\n this.nodes.clear();\r\n }\r\n\r\n destroy() {\r\n this.clear();\r\n this.container.remove();\r\n }\r\n}\r\n","/**\r\n * Minimap - Shows overview of entire graph with viewport indicator\r\n */\r\nexport class Minimap {\r\n constructor(container, { graph, renderer, width = 200, height = 150 } = {}) {\r\n this.graph = graph;\r\n this.renderer = renderer;\r\n this.width = width;\r\n this.height = height;\r\n\r\n // Create canvas element\r\n this.canvas = document.createElement(\"canvas\");\r\n this.canvas.id = \"minimap\";\r\n this.canvas.width = width;\r\n this.canvas.height = height;\r\n this.canvas.style.position = \"fixed\";\r\n this.canvas.style.bottom = \"20px\";\r\n this.canvas.style.right = \"20px\";\r\n this.canvas.style.border = \"2px solid #444\";\r\n this.canvas.style.borderRadius = \"8px\";\r\n this.canvas.style.background = \"rgba(20, 20, 23, 0.9)\";\r\n this.canvas.style.boxShadow = \"0 4px 12px rgba(0, 0, 0, 0.5)\";\r\n this.canvas.style.pointerEvents = \"none\"; // Don't block clicks\r\n\r\n this.ctx = this.canvas.getContext(\"2d\");\r\n\r\n // Add to container\r\n container.appendChild(this.canvas);\r\n }\r\n\r\n /**\r\n * Render the minimap\r\n */\r\n render() {\r\n const { graph, renderer, ctx, width: w, height: h } = this;\r\n\r\n // Clear\r\n ctx.fillStyle = \"#141417\";\r\n ctx.fillRect(0, 0, w, h);\r\n\r\n if (graph.nodes.size === 0) return;\r\n\r\n // Calculate bounds of all nodes\r\n let minX = Infinity,\r\n minY = Infinity,\r\n maxX = -Infinity,\r\n maxY = -Infinity;\r\n for (const node of graph.nodes.values()) {\r\n const { x, y, w: nw, h: nh } = node.computed;\r\n minX = Math.min(minX, x);\r\n minY = Math.min(minY, y);\r\n maxX = Math.max(maxX, x + nw);\r\n maxY = Math.max(maxY, y + nh);\r\n }\r\n\r\n // Add margin to the bounds\r\n const margin = 100; // World units margin\r\n const graphWidth = Math.max(300, maxX - minX + margin * 2);\r\n const graphHeight = Math.max(200, maxY - minY + margin * 2);\r\n\r\n // Adjust minX and minY to center the content\r\n minX -= margin;\r\n minY -= margin;\r\n\r\n const padding = 10;\r\n\r\n const scale = Math.min(\r\n (w - padding * 2) / graphWidth,\r\n (h - padding * 2) / graphHeight\r\n );\r\n\r\n const offsetX = (w - graphWidth * scale) / 2;\r\n const offsetY = (h - graphHeight * scale) / 2;\r\n\r\n // Draw edges first (so they appear behind nodes)\r\n ctx.strokeStyle = \"rgba(127, 140, 255, 0.5)\"; // Semi-transparent edge color\r\n ctx.lineWidth = 1;\r\n for (const edge of graph.edges.values()) {\r\n const fromNode = graph.nodes.get(edge.fromNode);\r\n const toNode = graph.nodes.get(edge.toNode);\r\n if (!fromNode || !toNode) continue;\r\n\r\n // Get center points of nodes\r\n const x1 = fromNode.computed.x + fromNode.computed.w / 2;\r\n const y1 = fromNode.computed.y + fromNode.computed.h / 2;\r\n const x2 = toNode.computed.x + toNode.computed.w / 2;\r\n const y2 = toNode.computed.y + toNode.computed.h / 2;\r\n\r\n // Transform to minimap coordinates\r\n const mx1 = (x1 - minX) * scale + offsetX;\r\n const my1 = (y1 - minY) * scale + offsetY;\r\n const mx2 = (x2 - minX) * scale + offsetX;\r\n const my2 = (y2 - minY) * scale + offsetY;\r\n\r\n ctx.beginPath();\r\n ctx.moveTo(mx1, my1);\r\n ctx.lineTo(mx2, my2);\r\n ctx.stroke();\r\n }\r\n\r\n // Draw nodes\r\n ctx.fillStyle = \"#6cf\";\r\n for (const node of graph.nodes.values()) {\r\n const { x, y, w: nw, h: nh } = node.computed;\r\n const mx = (x - minX) * scale + offsetX;\r\n const my = (y - minY) * scale + offsetY;\r\n const mw = nw * scale;\r\n const mh = nh * scale;\r\n\r\n if (node.type === \"core/Group\") {\r\n ctx.fillStyle = \"rgba(102, 204, 255, 0.2)\";\r\n ctx.strokeStyle = \"#6cf\";\r\n ctx.lineWidth = 1;\r\n ctx.fillRect(mx, my, mw, mh);\r\n ctx.strokeRect(mx, my, mw, mh);\r\n } else {\r\n ctx.fillStyle = \"#6cf\";\r\n ctx.fillRect(mx, my, Math.max(2, mw), Math.max(2, mh));\r\n }\r\n }\r\n\r\n // Draw viewport rectangle\r\n const vx0 = -renderer.offsetX / renderer.scale;\r\n const vy0 = -renderer.offsetY / renderer.scale;\r\n const vw = renderer.canvas.width / renderer.scale;\r\n const vh = renderer.canvas.height / renderer.scale;\r\n\r\n const vmx = (vx0 - minX) * scale + offsetX;\r\n const vmy = (vy0 - minY) * scale + offsetY;\r\n const vmw = vw * scale;\r\n const vmh = vh * scale;\r\n\r\n ctx.strokeStyle = \"#ff6b6b\";\r\n ctx.lineWidth = 2;\r\n ctx.strokeRect(vmx, vmy, vmw, vmh);\r\n }\r\n\r\n /**\r\n * Cleanup\r\n */\r\n destroy() {\r\n if (this.canvas.parentElement) {\r\n this.canvas.parentElement.removeChild(this.canvas);\r\n }\r\n }\r\n}\r\n","/**\n * PropertyPanel - Node property editor panel\n */\nexport class PropertyPanel {\n constructor(container, { graph, hooks, registry, render }) {\n this.container = container;\n this.graph = graph;\n this.hooks = hooks;\n this.registry = registry;\n this.render = render;\n this._def = null; // current node type definition\n\n this.panel = null;\n this.currentNode = null;\n this.isVisible = false;\n this._selfUpdating = false; // prevent re-render loop while user is editing\n\n this._createPanel();\n this._bindHooks();\n }\n\n _bindHooks() {\n // Refresh when edges change\n this.hooks?.on('edge:create', () => {\n if (this._canRefresh()) this._renderContent();\n });\n this.hooks?.on('edge:delete', () => {\n if (this._canRefresh()) this._renderContent();\n });\n // Refresh when node state changes externally\n this.hooks?.on('node:updated', (node) => {\n if (this._canRefresh() && this.currentNode?.id === node?.id && !this._selfUpdating) {\n this._renderContent();\n }\n });\n // Refresh position fields when node moves\n this.hooks?.on('node:move', (node) => {\n if (this._canRefresh() && this.currentNode?.id === node?.id) {\n this._updatePositionFields();\n }\n });\n // Refresh live values on every runner tick (lightweight DOM update)\n this.hooks?.on('runner:tick', () => {\n if (this._canRefresh()) this._updateLiveValues();\n });\n this.hooks?.on('runner:stop', () => {\n if (this._canRefresh()) this._updateLiveValues();\n });\n }\n\n _canRefresh() {\n if (!this.isVisible || !this.currentNode) return false;\n // Don't clobber in-progress edits\n return !this.panel.querySelector('[data-field]:focus');\n }\n\n _createPanel() {\n this.panel = document.createElement('div');\n this.panel.className = 'property-panel';\n this.panel.style.display = 'none';\n\n this.panel.innerHTML = `\n <div class=\"panel-inner\">\n <div class=\"panel-header\">\n <div class=\"panel-title\">\n <span class=\"title-text\">Node Properties</span>\n </div>\n <button class=\"panel-close\" type=\"button\">×</button>\n </div>\n <div class=\"panel-content\">\n <!-- Content will be dynamically generated -->\n </div>\n </div>\n `;\n\n this.container.appendChild(this.panel);\n\n this.panel.querySelector('.panel-close').addEventListener('click', () => {\n this.close();\n });\n\n document.addEventListener('keydown', (e) => {\n if (e.key === 'Escape' && this.isVisible) {\n this.close();\n }\n });\n }\n\n open(node) {\n if (!node) return;\n this.currentNode = node;\n this._def = this.registry?.types?.get(node.type) || null;\n this.isVisible = true;\n this._renderContent();\n this.panel.style.display = 'block';\n this.panel.classList.add('panel-visible');\n }\n\n close() {\n this.isVisible = false;\n this.panel.classList.remove('panel-visible');\n setTimeout(() => {\n this.panel.style.display = 'none';\n this.currentNode = null;\n }, 200);\n }\n\n _renderContent() {\n const node = this.currentNode;\n if (!node) return;\n\n const content = this.panel.querySelector('.panel-content');\n content.innerHTML = `\n <div class=\"section\">\n <div class=\"section-title\">Basic Info</div>\n <div class=\"section-body\">\n <div class=\"field\">\n <label>Type</label>\n <input type=\"text\" value=\"${node.type}\" readonly />\n </div>\n <div class=\"field\">\n <label>Title</label>\n <input type=\"text\" data-field=\"title\" value=\"${node.title || ''}\" />\n </div>\n <div class=\"field\">\n <label>ID</label>\n <input type=\"text\" value=\"${node.id}\" readonly />\n </div>\n </div>\n </div>\n\n <div class=\"section\">\n <div class=\"section-title\">Position &amp; Size</div>\n <div class=\"section-body\">\n <div class=\"field-row\">\n <div class=\"field\">\n <label>X</label>\n <input type=\"number\" data-field=\"x\" value=\"${Math.round(node.computed.x)}\" />\n </div>\n <div class=\"field\">\n <label>Y</label>\n <input type=\"number\" data-field=\"y\" value=\"${Math.round(node.computed.y)}\" />\n </div>\n </div>\n <div class=\"field-row\">\n <div class=\"field\">\n <label>Width</label>\n <input type=\"number\" data-field=\"width\" value=\"${node.computed.w}\" />\n </div>\n <div class=\"field\">\n <label>Height</label>\n <input type=\"number\" data-field=\"height\" value=\"${node.computed.h}\" />\n </div>\n </div>\n </div>\n </div>\n\n ${this._renderConnections(node)}\n ${this._renderPorts(node)}\n ${this._renderLiveValues(node)}\n ${this._renderState(node)}\n\n <div class=\"panel-actions\">\n <button class=\"btn-secondary panel-close-btn\">Close</button>\n </div>\n `;\n\n this._attachInputListeners();\n }\n\n _renderConnections(node) {\n const edges = [...this.graph.edges.values()];\n const incoming = edges.filter(e => e.toNode === node.id);\n const outgoing = edges.filter(e => e.fromNode === node.id);\n\n if (!incoming.length && !outgoing.length) return '';\n\n const edgeLabel = (e, dir) => {\n const otherId = dir === 'in' ? e.fromNode : e.toNode;\n const other = this.graph.nodes.get(otherId);\n return `<div class=\"port-item\">\n <span class=\"port-icon data\"></span>\n <span class=\"port-name\" style=\"font-size:10px;color:#5a5a78;\">${other?.title ?? otherId}</span>\n </div>`;\n };\n\n return `\n <div class=\"section\">\n <div class=\"section-title\">Connections</div>\n <div class=\"section-body\">\n ${incoming.length ? `\n <div class=\"port-group\">\n <div class=\"port-group-title\">Incoming (${incoming.length})</div>\n ${incoming.map(e => edgeLabel(e, 'in')).join('')}\n </div>` : ''}\n ${outgoing.length ? `\n <div class=\"port-group\">\n <div class=\"port-group-title\">Outgoing (${outgoing.length})</div>\n ${outgoing.map(e => edgeLabel(e, 'out')).join('')}\n </div>` : ''}\n </div>\n </div>\n `;\n }\n\n _renderLiveValues(node) {\n // Show live runtime values from the graph buffer (inputs & outputs)\n const cur = this.graph?._curBuf?.();\n if (!cur) return '';\n\n const lines = [];\n\n for (const input of node.inputs) {\n const key = `${node.id}:${input.id}`;\n // For inputs: look at the connected upstream node's output\n for (const edge of this.graph.edges.values()) {\n if (edge.toNode === node.id && edge.toPort === input.id) {\n const upKey = `${edge.fromNode}:${edge.fromPort}`;\n const val = cur.get(upKey);\n if (val !== undefined) {\n lines.push(`<div class=\"port-item\">\n <span class=\"port-icon data\"></span>\n <span class=\"port-name\">↳ ${input.name}</span>\n <span class=\"port-type\" style=\"color:var(--color-primary);background:rgba(99,102,241,0.1);\">${JSON.stringify(val)}</span>\n </div>`);\n }\n break;\n }\n }\n }\n\n for (const output of node.outputs) {\n const key = `${node.id}:${output.id}`;\n const val = cur.get(key);\n if (val !== undefined) {\n lines.push(`<div class=\"port-item\">\n <span class=\"port-icon exec\" style=\"background:#10b981;\"></span>\n <span class=\"port-name\">↳ ${output.name}</span>\n <span class=\"port-type\" style=\"color:#10b981;background:rgba(16,185,129,0.1);\">${JSON.stringify(val)}</span>\n </div>`);\n }\n }\n\n if (!lines.length) return '';\n\n return `\n <div class=\"section\">\n <div class=\"section-title\">Live Values</div>\n <div class=\"section-body\">\n ${lines.join('')}\n </div>\n </div>\n `;\n }\n\n _renderPorts(node) {\n if (!node.inputs.length && !node.outputs.length) return '';\n\n return `\n <div class=\"section\">\n <div class=\"section-title\">Ports</div>\n <div class=\"section-body\">\n ${node.inputs.length ? `\n <div class=\"port-group\">\n <div class=\"port-group-title\">Inputs (${node.inputs.length})</div>\n ${node.inputs.map(p => `\n <div class=\"port-item\">\n <span class=\"port-icon ${p.portType || 'data'}\"></span>\n <span class=\"port-name\">${p.name}</span>\n ${p.datatype ? `<span class=\"port-type\">${p.datatype}</span>` : ''}\n </div>\n `).join('')}\n </div>\n ` : ''}\n ${node.outputs.length ? `\n <div class=\"port-group\">\n <div class=\"port-group-title\">Outputs (${node.outputs.length})</div>\n ${node.outputs.map(p => `\n <div class=\"port-item\">\n <span class=\"port-icon ${p.portType || 'data'}\"></span>\n <span class=\"port-name\">${p.name}</span>\n ${p.datatype ? `<span class=\"port-type\">${p.datatype}</span>` : ''}\n </div>\n `).join('')}\n </div>\n ` : ''}\n </div>\n </div>\n `;\n }\n\n _renderState(node) {\n if (!node.state) return '';\n\n // Only show primitive, non-private keys\n const entries = Object.entries(node.state).filter(([key, value]) => {\n if (key.startsWith('_')) return false;\n const t = typeof value;\n return t === 'string' || t === 'number' || t === 'boolean';\n });\n\n if (!entries.length) return '';\n\n const fieldHtml = ([key, value]) => {\n if (typeof value === 'boolean') {\n return `\n <div class=\"field\">\n <label>${key}</label>\n <select data-field=\"state.${key}\">\n <option value=\"true\"${value ? ' selected' : ''}>true</option>\n <option value=\"false\"${!value ? ' selected' : ''}>false</option>\n </select>\n </div>`;\n }\n return `\n <div class=\"field\">\n <label>${key}</label>\n <input type=\"${typeof value === 'number' ? 'number' : 'text'}\"\n data-field=\"state.${key}\"\n value=\"${value}\" />\n </div>`;\n };\n\n return `\n <div class=\"section\">\n <div class=\"section-title\">State</div>\n <div class=\"section-body\">\n ${entries.map(fieldHtml).join('')}\n </div>\n </div>\n `;\n }\n\n _attachInputListeners() {\n this.panel.querySelectorAll('[data-field]').forEach(input => {\n input.addEventListener('change', () => {\n this._selfUpdating = true;\n this._handleFieldChange(input.dataset.field, input.value);\n this._selfUpdating = false;\n });\n });\n\n this.panel.querySelector('.panel-close-btn')?.addEventListener('click', () => {\n this.close();\n });\n }\n\n _handleFieldChange(field, value) {\n const node = this.currentNode;\n if (!node) return;\n\n switch (field) {\n case 'title':\n node.title = value;\n break;\n case 'x':\n node.pos.x = parseFloat(value);\n this.graph.updateWorldTransforms();\n break;\n case 'y':\n node.pos.y = parseFloat(value);\n this.graph.updateWorldTransforms();\n break;\n case 'width':\n node.size.width = parseFloat(value);\n break;\n case 'height':\n node.size.height = parseFloat(value);\n break;\n default:\n if (field.startsWith('state.')) {\n const key = field.substring(6);\n if (node.state && key in node.state) {\n const orig = node.state[key];\n if (typeof orig === 'boolean') {\n node.state[key] = value === 'true';\n } else if (typeof orig === 'number') {\n node.state[key] = parseFloat(value);\n } else {\n node.state[key] = value;\n }\n }\n }\n }\n\n this.hooks?.emit('node:updated', node);\n this.render?.();\n }\n\n /** Lightweight update of position fields only (no full re-render) */\n _updatePositionFields() {\n const node = this.currentNode;\n if (!node) return;\n const xEl = this.panel.querySelector('[data-field=\"x\"]');\n const yEl = this.panel.querySelector('[data-field=\"y\"]');\n if (xEl) xEl.value = Math.round(node.computed.x);\n if (yEl) yEl.value = Math.round(node.computed.y);\n }\n\n /** Lightweight in-place update of the Live Values section */\n _updateLiveValues() {\n const node = this.currentNode;\n if (!node) return;\n\n const cur = this.graph?._curBuf?.();\n if (!cur) return;\n\n // Find or create the live values section container\n let section = this.panel.querySelector('.live-values-section');\n const newHtml = this._renderLiveValues(node);\n\n if (!newHtml) {\n // No live values — remove section if present\n if (section) section.remove();\n return;\n }\n\n const wrapper = document.createElement('div');\n wrapper.innerHTML = newHtml;\n const newSection = wrapper.firstElementChild;\n newSection.classList.add('live-values-section');\n\n if (section) {\n section.replaceWith(newSection);\n } else {\n // Insert before the State section, or before panel-actions\n const stateSection = this.panel.querySelectorAll('.section');\n const actions = this.panel.querySelector('.panel-actions');\n // insert as second-to-last section (before actions)\n if (actions) {\n actions.before(newSection);\n } else {\n this.panel.querySelector('.panel-content').appendChild(newSection);\n }\n }\n }\n\n destroy() {\n this.panel?.remove();\n }\n}\n","/**\n * HelpOverlay - Modular help keyboard shortcuts overlay\n */\nexport class HelpOverlay {\n constructor(container, options = {}) {\n this.container = container;\n this.options = {\n shortcuts: options.shortcuts || this._getDefaultShortcuts(),\n onToggle: options.onToggle || null,\n };\n\n this.isVisible = false;\n this.overlay = null;\n this.toggleBtn = null;\n\n this._createElements();\n this._bindEvents();\n }\n\n _getDefaultShortcuts() {\n return [\n {\n group: \"Selection\",\n items: [\n { label: \"Select node\", key: \"Click\" },\n { label: \"Multi-select\", key: \"Shift+Click\" },\n { label: \"Box select\", key: \"Ctrl+Drag\" },\n ],\n },\n {\n group: \"Edit\",\n items: [\n { label: \"Delete\", key: \"Del\" },\n { label: \"Undo\", key: \"Ctrl+Z\" },\n { label: \"Redo\", key: \"Ctrl+Y\" },\n ],\n },\n {\n group: \"Group & Align\",\n items: [\n { label: \"Create group\", key: \"Ctrl+G\" },\n { label: \"Align horizontal\", key: \"A\" },\n { label: \"Align vertical\", key: \"Shift+A\" },\n ],\n },\n {\n group: \"View\",\n items: [\n { label: \"Toggle snap\", key: \"G\" },\n { label: \"Pan\", key: \"Mid+Drag\" },\n { label: \"Zoom\", key: \"Scroll\" },\n { label: \"Context menu\", key: \"RClick\" },\n ],\n },\n ];\n }\n\n _createElements() {\n // Create Toggle Button\n this.toggleBtn = document.createElement(\"div\");\n this.toggleBtn.id = \"helpToggle\";\n this.toggleBtn.title = \"단축키 (?)\";\n this.toggleBtn.textContent = \"?\";\n this.container.appendChild(this.toggleBtn);\n\n // Create Overlay\n this.overlay = document.createElement(\"div\");\n this.overlay.id = \"helpOverlay\";\n\n const sectionsHtml = this.options.shortcuts\n .map(\n (group) => `\n <h4>${group.group}</h4>\n ${group.items\n .map(\n (item) => `\n <div class=\"shortcut-item\">\n <span>${item.label}</span>\n <span class=\"shortcut-key\">${item.key}</span>\n </div>\n `\n )\n .join(\"\")}\n `\n )\n .join(\"\");\n\n this.overlay.innerHTML = `\n <h3>\n <span>Keyboard Shortcuts</span>\n <button class=\"close-btn\" id=\"helpClose\" title=\"Close\">×</button>\n </h3>\n ${sectionsHtml}\n `;\n\n this.container.appendChild(this.overlay);\n }\n\n _bindEvents() {\n this.toggleBtn.addEventListener(\"click\", () => this.toggle());\n\n const closeBtn = this.overlay.querySelector(\"#helpClose\");\n if (closeBtn) {\n closeBtn.addEventListener(\"click\", (e) => {\n e.stopPropagation();\n this.close();\n });\n }\n\n // Close when clicking outside\n document.addEventListener(\"mousedown\", (e) => {\n if (this.isVisible) {\n if (!this.overlay.contains(e.target) && !this.toggleBtn.contains(e.target)) {\n this.close();\n }\n }\n });\n\n // Keyboard shortcuts\n window.addEventListener(\"keydown\", (e) => {\n if (e.key === \"?\" || (e.shiftKey && e.key === \"/\")) {\n // Only toggle if not typing in an input\n if (![\"INPUT\", \"TEXTAREA\", \"SELECT\"].includes(document.activeElement.tagName)) {\n e.preventDefault();\n this.toggle();\n }\n }\n\n if (e.key === \"Escape\" && this.isVisible) {\n this.close();\n }\n });\n }\n\n toggle() {\n if (this.isVisible) this.close();\n else this.open();\n }\n\n open() {\n this.isVisible = true;\n this.overlay.classList.add(\"visible\");\n this.toggleBtn.classList.add(\"active\");\n if (this.options.onToggle) this.options.onToggle(true);\n }\n\n close() {\n this.isVisible = false;\n this.overlay.classList.remove(\"visible\");\n this.toggleBtn.classList.remove(\"active\");\n if (this.options.onToggle) this.options.onToggle(false);\n }\n\n destroy() {\n this.toggleBtn?.remove();\n this.overlay?.remove();\n }\n}\n","import { Registry } from \"./core/Registry.js\";\r\nimport { createHooks } from \"./core/Hooks.js\";\r\nimport { Graph } from \"./core/Graph.js\";\r\nimport { CanvasRenderer } from \"./render/CanvasRenderer.js\";\r\nimport { Controller } from \"./interact/Controller.js\";\r\nimport { ContextMenu } from \"./interact/ContextMenu.js\";\r\nimport { Runner } from \"./core/Runner.js\";\r\n\r\nimport { HtmlOverlay } from \"./render/HtmlOverlay.js\";\r\nimport { RemoveNodeCmd, ChangeGroupColorCmd } from \"./core/commands.js\";\r\nimport { Minimap } from \"./minimap/Minimap.js\";\r\nimport { PropertyPanel } from \"./ui/PropertyPanel.js\";\r\nimport { HelpOverlay } from \"./ui/HelpOverlay.js\";\r\nimport { setupDefaultContextMenu as defaultContextMenuSetup } from \"./defaults/contextMenu.js\";\r\n\r\n\r\n\r\nexport function createGraphEditor(\r\n target,\r\n {\r\n theme,\r\n hooks: customHooks,\r\n autorun = true,\r\n showMinimap = true,\r\n enablePropertyPanel = true,\r\n propertyPanelContainer = null,\r\n enableHelp = true,\r\n helpShortcuts = null,\r\n setupDefaultContextMenu = true,\r\n setupContextMenu = null,\r\n plugins = [],\r\n } = {}\r\n) {\r\n let canvas;\r\n let container;\r\n\r\n if (typeof target === \"string\") {\r\n target = document.querySelector(target);\r\n }\r\n\r\n if (!target) {\r\n throw new Error(\"createGraphEditor: target element not found\");\r\n }\r\n\r\n if (target instanceof HTMLCanvasElement) {\r\n canvas = target;\r\n container = canvas.parentElement;\r\n } else {\r\n container = target;\r\n canvas = container.querySelector(\"canvas\");\r\n if (!canvas) {\r\n canvas = document.createElement(\"canvas\");\r\n canvas.style.display = \"block\";\r\n canvas.style.width = \"100%\";\r\n canvas.style.height = \"100%\";\r\n container.appendChild(canvas);\r\n }\r\n }\r\n\r\n // Ensure container has relative positioning for overlays\r\n if (getComputedStyle(container).position === \"static\") {\r\n container.style.position = \"relative\";\r\n }\r\n const hooks =\r\n customHooks ??\r\n createHooks([\r\n // essential hooks\r\n \"node:create\",\r\n \"node:move\",\r\n \"node:click\",\r\n \"node:dblclick\",\r\n \"edge:create\",\r\n \"edge:delete\",\r\n \"graph:serialize\",\r\n \"graph:deserialize\",\r\n \"error\",\r\n \"runner:tick\",\r\n \"runner:start\",\r\n \"runner:stop\",\r\n \"node:resize\",\r\n \"group:change\",\r\n \"node:updated\",\r\n ]);\r\n const registry = new Registry();\r\n const graph = new Graph({ hooks, registry });\r\n const renderer = new CanvasRenderer(canvas, { theme, registry });\r\n // HTML Overlay\r\n const htmlOverlay = new HtmlOverlay(canvas.parentElement, renderer, registry);\r\n\r\n // Register callback to sync HTML overlay transform when renderer zoom/pan changes\r\n renderer.setTransformChangeCallback(() => {\r\n htmlOverlay.syncTransform();\r\n });\r\n\r\n // Edge Canvas (above HTML overlay, for edge animations)\r\n const edgeCanvas = document.createElement(\"canvas\");\r\n edgeCanvas.id = \"edge-canvas\";\r\n Object.assign(edgeCanvas.style, {\r\n position: \"absolute\",\r\n top: \"0\",\r\n left: \"0\",\r\n pointerEvents: \"none\", // Pass through clicks\r\n zIndex: \"15\", // Above HTML overlay (10), below port canvas (20)\r\n });\r\n canvas.parentElement.appendChild(edgeCanvas);\r\n\r\n // Create edge renderer (shares transform with main renderer)\r\n const edgeRenderer = new CanvasRenderer(edgeCanvas, { theme, registry });\r\n // Sync transform properties with main renderer\r\n Object.defineProperty(edgeRenderer, 'scale', {\r\n get() { return renderer.scale; },\r\n set(v) { renderer.scale = v; }\r\n });\r\n Object.defineProperty(edgeRenderer, 'offsetX', {\r\n get() { return renderer.offsetX; },\r\n set(v) { renderer.offsetX = v; }\r\n });\r\n Object.defineProperty(edgeRenderer, 'offsetY', {\r\n get() { return renderer.offsetY; },\r\n set(v) { renderer.offsetY = v; }\r\n });\r\n\r\n // Port Canvas (above HTML overlay)\r\n const portCanvas = document.createElement(\"canvas\");\r\n portCanvas.id = \"port-canvas\";\r\n Object.assign(portCanvas.style, {\r\n position: \"absolute\",\r\n top: \"0\",\r\n left: \"0\",\r\n pointerEvents: \"none\", // Pass through clicks\r\n zIndex: \"20\", // Above edge canvas (15)\r\n });\r\n canvas.parentElement.appendChild(portCanvas);\r\n\r\n // Create port renderer (shares transform with main renderer)\r\n const portRenderer = new CanvasRenderer(portCanvas, { theme, registry });\r\n portRenderer.setTransform = renderer.setTransform.bind(renderer);\r\n portRenderer.scale = renderer.scale;\r\n portRenderer.offsetX = renderer.offsetX;\r\n portRenderer.offsetY = renderer.offsetY;\r\n\r\n const controller = new Controller({ graph, renderer, hooks, htmlOverlay, edgeRenderer, portRenderer });\r\n\r\n // Create context menu after controller (needs commandStack)\r\n const contextMenu = new ContextMenu({\r\n graph,\r\n hooks,\r\n renderer,\r\n commandStack: controller.stack,\r\n });\r\n\r\n // Connect context menu to controller\r\n controller.contextMenu = contextMenu;\r\n\r\n // Create minimap if enabled\r\n let minimap = null;\r\n if (showMinimap) {\r\n minimap = new Minimap(container, { graph, renderer });\r\n }\r\n\r\n // Initialize Property Panel if enabled\r\n let propertyPanel = null;\r\n if (enablePropertyPanel) {\r\n propertyPanel = new PropertyPanel(propertyPanelContainer || container, {\r\n graph,\r\n hooks,\r\n registry,\r\n render: () => controller.render(),\r\n });\r\n\r\n // Handle node double-click to open property panel\r\n hooks.on(\"node:dblclick\", (node) => {\r\n propertyPanel.open(node);\r\n });\r\n }\r\n\r\n // Initialize Help Overlay if enabled\r\n let helpOverlay = null;\r\n if (enableHelp) {\r\n helpOverlay = new HelpOverlay(container, {\r\n shortcuts: helpShortcuts,\r\n });\r\n }\r\n\r\n const runner = new Runner({ graph, registry, hooks });\r\n\r\n // Attach runner and controller to graph for node access\r\n // This allows any node (like Trigger) to execute flows without tight coupling\r\n graph.runner = runner;\r\n graph.controller = controller;\r\n\r\n hooks.on(\"runner:tick\", ({ time, dt }) => {\r\n controller.render(time);\r\n });\r\n hooks.on(\"runner:start\", () => {\r\n controller.render(performance.now());\r\n });\r\n hooks.on(\"runner:stop\", () => {\r\n controller.render(performance.now());\r\n });\r\n\r\n hooks.on(\"node:updated\", () => {\r\n controller.render();\r\n });\r\n\r\n hooks.on(\"graph:deserialize\", () => {\r\n renderer.setTransform({ scale: 1, offsetX: 0, offsetY: 0 });\r\n controller.render();\r\n });\r\n\r\n // Note: Example nodes have been moved to src/nodes/\r\n // Users can import and register them selectively:\r\n // import { registerAllNodes } from \"html-overlay-node/nodes\";\r\n // registerAllNodes(registry, hooks);\r\n\r\n // Setup context menu\r\n if (setupDefaultContextMenu) {\r\n // Use default context menu setup\r\n defaultContextMenuSetup(contextMenu, { controller, graph, hooks });\r\n }\r\n\r\n // Allow custom context menu setup\r\n if (setupContextMenu) {\r\n setupContextMenu(contextMenu, { controller, graph, hooks });\r\n }\r\n\r\n // Install plugins\r\n if (plugins && plugins.length > 0) {\r\n for (const plugin of plugins) {\r\n if (typeof plugin.install === \"function\") {\r\n try {\r\n plugin.install({ graph, registry, hooks, runner, controller, contextMenu }, plugin.options || {});\r\n } catch (err) {\r\n console.error(`[createGraphEditor] Failed to install plugin \"${plugin.name || 'unknown'}\":`, err);\r\n hooks?.emit?.(\"error\", err);\r\n }\r\n } else {\r\n console.warn(`[createGraphEditor] Plugin \"${plugin.name || 'unknown'}\" does not have an install() method`);\r\n }\r\n }\r\n }\r\n\r\n\r\n // initial render & resize\r\n renderer.resize(canvas.clientWidth, canvas.clientHeight);\r\n edgeRenderer.resize(canvas.clientWidth, canvas.clientHeight);\r\n portRenderer.resize(canvas.clientWidth, canvas.clientHeight);\r\n controller.render();\r\n\r\n const ro = new ResizeObserver(() => {\r\n renderer.resize(canvas.clientWidth, canvas.clientHeight);\r\n edgeRenderer.resize(canvas.clientWidth, canvas.clientHeight);\r\n portRenderer.resize(canvas.clientWidth, canvas.clientHeight);\r\n controller.render();\r\n });\r\n ro.observe(canvas);\r\n\r\n // Wrap controller.render to update minimap\r\n const originalRender = controller.render.bind(controller);\r\n controller.render = function () {\r\n originalRender();\r\n if (minimap) {\r\n minimap.render();\r\n }\r\n };\r\n\r\n const api = {\r\n addGroup: (args = {}) => {\r\n controller.graph.groupManager.addGroup(args);\r\n controller.render();\r\n },\r\n graph,\r\n renderer,\r\n edgeRenderer, // Expose edge renderer for style changes\r\n controller, // Expose controller for snap-to-grid access\r\n runner, // Expose runner for trigger\r\n minimap, // Expose minimap\r\n contextMenu,\r\n hooks, // Expose hooks for event handling\r\n registry, // Expose registry for node types\r\n htmlOverlay, // Expose htmlOverlay for clearing/resetting\r\n propertyPanel, // Expose propertyPanel\r\n render: () => controller.render(),\r\n start: () => runner.start(),\r\n stop: () => runner.stop(),\r\n setEdgeStyle: (style) => {\r\n renderer.setEdgeStyle(style);\r\n edgeRenderer.setEdgeStyle(style);\r\n },\r\n setExecutionMode: (mode) => {\r\n runner.setExecutionMode(mode);\r\n controller.render(); // Redraw to update overlays\r\n },\r\n destroy: () => {\r\n runner.stop();\r\n ro.disconnect();\r\n controller.destroy();\r\n htmlOverlay.destroy();\r\n contextMenu.destroy();\r\n if (propertyPanel) propertyPanel.destroy();\r\n if (minimap) minimap.destroy();\r\n if (helpOverlay) helpOverlay.destroy();\r\n },\r\n };\r\n\r\n if (autorun) runner.start();\r\n return api;\r\n}\r\n","export function createHooks(names) {\r\n const map = Object.fromEntries(names.map((n) => [n, new Set()]));\r\n return {\r\n on(name, fn) {\r\n if (!map[name]) map[name] = new Set();\r\n map[name].add(fn);\r\n return () => map[name].delete(fn);\r\n },\r\n off(name, fn) {\r\n if (map[name]) {\r\n map[name].delete(fn);\r\n }\r\n },\r\n emit(name, ...args) {\r\n if (!map[name]) return;\r\n for (const fn of map[name]) fn(...args);\r\n },\r\n };\r\n}\r\n","/**\r\n * Default Context Menu Setup\r\n * \r\n * This module provides the default context menu configuration.\r\n * Users can import and use this directly, modify it, or create their own.\r\n * \r\n * @example\r\n * import { setupDefaultContextMenu } from \"html-overlay-node/defaults\";\r\n * setupDefaultContextMenu(editor.contextMenu, { controller, graph, hooks });\r\n */\r\n\r\nimport { RemoveNodeCmd, ChangeGroupColorCmd } from \"../core/commands.js\";\r\n\r\n/**\r\n * Setup default context menu items\r\n * @param {ContextMenu} contextMenu - Context menu instance\r\n * @param {Object} options - Configuration options\r\n * @param {Controller} options.controller - Controller instance\r\n * @param {Graph} options.graph - Graph instance\r\n * @param {Hooks} options.hooks - Hooks instance\r\n */\r\nexport function setupDefaultContextMenu(contextMenu, { controller, graph, hooks }) {\r\n // Add Node submenu (canvas background only)\r\n // Use a function to dynamically generate node types when menu is shown\r\n const getNodeTypes = () => {\r\n const nodeTypes = [];\r\n for (const [key, typeDef] of graph.registry.types.entries()) {\r\n nodeTypes.push({\r\n id: `add-${key}`,\r\n label: typeDef.title || key,\r\n action: () => {\r\n // Get world position from context menu\r\n const worldPos = contextMenu.worldPosition || { x: 100, y: 100 };\r\n\r\n // Add node at click position\r\n const node = graph.addNode(key, {\r\n x: worldPos.x,\r\n y: worldPos.y,\r\n });\r\n\r\n hooks?.emit(\"node:updated\", node);\r\n controller.render(); // Update minimap and canvas\r\n },\r\n });\r\n }\r\n return nodeTypes;\r\n };\r\n\r\n contextMenu.addItem(\"add-node\", \"Add Node\", {\r\n condition: (target) => !target,\r\n submenu: getNodeTypes, // Pass function instead of array\r\n order: 5,\r\n });\r\n\r\n // Delete Node (for all nodes except groups)\r\n contextMenu.addItem(\"delete-node\", \"Delete Node\", {\r\n condition: (target) => target && target.type !== \"core/Group\",\r\n action: (target) => {\r\n const cmd = RemoveNodeCmd(graph, target);\r\n controller.stack.exec(cmd);\r\n hooks?.emit(\"node:updated\", target);\r\n },\r\n order: 10,\r\n });\r\n\r\n // Change Group Color (for groups only) - with submenu\r\n const colors = [\r\n { name: \"Default\", color: \"#39424e\" },\r\n { name: \"Slate\", color: \"#4a5568\" },\r\n { name: \"Gray\", color: \"#2d3748\" },\r\n { name: \"Blue\", color: \"#1a365d\" },\r\n { name: \"Green\", color: \"#22543d\" },\r\n { name: \"Red\", color: \"#742a2a\" },\r\n { name: \"Purple\", color: \"#44337a\" },\r\n ];\r\n\r\n contextMenu.addItem(\"change-group-color\", \"Change Color\", {\r\n condition: (target) => target && target.type === \"core/Group\",\r\n submenu: colors.map((colorInfo) => ({\r\n id: `color-${colorInfo.color}`,\r\n label: colorInfo.name,\r\n color: colorInfo.color,\r\n action: (target) => {\r\n const currentColor = target.state.color || \"#39424e\";\r\n const cmd = ChangeGroupColorCmd(target, currentColor, colorInfo.color);\r\n controller.stack.exec(cmd);\r\n hooks?.emit(\"node:updated\", target);\r\n },\r\n })),\r\n order: 20,\r\n });\r\n\r\n contextMenu.addItem(\"delete-group\", \"Delete Group\", {\r\n condition: (target) => target && target.type === \"core/Group\",\r\n action: (target) => {\r\n const cmd = RemoveNodeCmd(graph, target);\r\n controller.stack.exec(cmd);\r\n hooks?.emit(\"node:updated\", target);\r\n },\r\n order: 20,\r\n });\r\n}\r\n"],"names":["Registry","constructor","this","types","Map","register","type","def","Error","has","set","unregister","delete","removeAll","clear","createInstance","get","available","Array","from","keys","join","randomUUID","g","globalThis","self","window","global","c","crypto","msCrypto","getRandomValues","bytes","Uint8Array","hex","b","toString","padStart","slice","req","Function","nodeCrypto","randomBytes","i","Math","floor","random","Node","id","title","x","y","width","height","pos","size","inputs","outputs","state","parent","children","Set","computed","w","h","_updateMinSize","inHeight","HEADER_HEIGHT","length","outHeight","minHeight","max","addInput","name","datatype","portType","port","dir","push","addOutput","Edge","fromNode","fromPort","toNode","toPort","GroupManager","graph","hooks","_groups","addGroup","color","members","console","warn","groupNode","addNode","memberId","node","getNodeById","reparent","_a","emit","addGroupFromSelection","_title","_margin","removeGroup","child","removeNode","resizeGroup","dw","dh","updateWorldTransforms","hitTestResizeHandle","nodes","values","reverse","gx","gy","gw","gh","group","handle","Graph","registry","edges","_valuesA","_valuesB","_useAasCurrent","groupManager","opts","_calculateDefaultNodeHeight","_b","o","_c","onCreate","call","_d","nodeId","eid","e","addEdge","roots","n","stack","map","px","py","pop","newParent","wx","wy","add","_curBuf","_nextBuf","swapBuffers","setOutput","portId","value","log","key","getInput","edge","toJSON","json","parentId","fromJSON","nd","minH","ed","inCount","outCount","maxPorts","html","lastPortBottom","headerHeight","portRect","idx","nx","ny","portSpacing","portWidth","portHeight","_CanvasRenderer","canvas","theme","edgeStyle","ctx","getContext","scale","minScale","maxScale","offsetX","offsetY","Object","assign","bg","grid","nodeBorder","text","textMuted","portExec","edgeActive","accent","accentBright","accentGlow","setEdgeStyle","style","setRegistry","reg","resize","setTransform","min","_onTransformChange","setTransformChangeCallback","callback","panBy","dx","dy","zoomAt","factor","cx","cy","prev","next","screenToWorld","worldToScreen","_applyTransform","translate","_resetTransform","_drawArrowhead","x1","y1","x2","y2","s","ang","atan2","beginPath","moveTo","lineTo","cos","PI","sin","closePath","fill","_drawScreenText","lx","ly","fontPx","align","baseline","sx","sy","save","round","font","fillStyle","textAlign","textBaseline","fillText","restore","drawGrid","fillRect","x0","y0","minorStep","majorStep","minorR","majorR","startX","startY","_rgba","isMajorX","isMajorY","arc","majorStartX","majorStartY","draw","selection","tempEdge","time","performance","now","activeNodes","activeEdges","activeEdgeTimes","drawEdges","loopActiveEdges","sel","onDraw","renderer","_drawNode","lineWidth","shadowColor","shadowBlur","strokeStyle","setLineDash","_drawEdge","flowSpeed","edgeLen","dotT","dotPos","_getEdgeDotPosition","a","prevDash","getLineDash","ptsForArrow","_drawLine","_drawOrthogonal","_drawCurve","p1","p2","hasHtmlOverlay","_drawPorts","_drawActiveNodeBorder","replace","parseInt","split","selected","skipPorts","typeDef","categoryColor","pad","roundRect","stroke","shadowOffsetY","tl","tr","br","bl","globalCompositeOperation","globalAlpha","headerH","FONT_SIZE","forEach","p","rct","_drawPortShape","r","radius","lineDashOffset","_roundRect","quadraticCurveTo","_drawHtmlSelectionBorder","dashLen","gapLen","offset","_getEdgeLength","to","iOut","findIndex","iIn","pr1","pr2","abs","chord","sqrt","t","x3","y3","mt","cubicBezierPoint","midX","pts","totalLen","lens","len","target","accum","segT","polylinePoint","_drawPolyline","points","prevJoin","lineJoin","prevCap","lineCap","bezierCurveTo","drawEdgesOnly","clearRect","activationTime","rawT","__publicField","CanvasRenderer","findEdgeId","d","RemoveNodeCmd","removedNode","removedEdges","filter","undo","CommandStack","undoStack","redoStack","exec","cmd","do","redo","_Controller","htmlOverlay","contextMenu","edgeRenderer","portRenderer","dragging","connecting","panning","resizing","gDragging","gResizing","boxSelecting","snapToGrid","gridSize","_cursor","_onKeyPressEvt","_onKeyPress","bind","_onDownEvt","_onDown","_onWheelEvt","_onWheel","_onMoveEvt","_onMove","_onUpEvt","_onUp","_onContextMenuEvt","_onContextMenu","_onDblClickEvt","_onDblClick","_bindEvents","on","activeNodeId","activeEdgeIds","edgeId","render","destroy","removeEventListener","passive","addEventListener","isAlt","altKey","isShift","shiftKey","isCtrl","ctrlKey","toLowerCase","metaKey","preventDefault","_createGroupFromSelection","_alignNodesVertical","_alignNodesHorizontal","nodeObj","_setCursor","cursor","_posScreen","getBoundingClientRect","clientX","left","clientY","top","_posWorld","_findNodeAtWorld","list","_findChildNodeAtWorld","parentNode","grandchild","_findPortAtWorld","rectHas","_findIncomingEdge","pow","deltaY","show","_resizeHandleRect","_hitResizeHandle","button","startW","startH","incoming","RemoveEdgeCmd","outR","screenFrom","currentX","currentY","startPos","selectedNodes","selectedId","selectedNode","startWorldX","startWorldY","startLocalX","startLocalY","childrenWorldPos","worldX","worldY","minW","MIN_NODE_WIDTH","MIN_NODE_HEIGHT","targetWx","targetWy","_snapToGrid","deltaX","find","sn","newWorldX","newWorldY","parentWx","parentWy","childInfo","newGroupX","newGroupY","portIn","addedId","AddEdgeCmd","fromSize","toSize","potentialParent","_findPotentialParent","_autoParentNodesInGroup","minX","maxX","minY","maxY","nw","nh","nodeCenterX","nodeCenterY","excludeNode","isDescendant","Infinity","groupX","groupY","groupWidth","margin","groupHeight","avgY","reduce","sum","parentY","avgX","parentX","tEdge","renderTempEdge","runner","isStepMode","executionMode","screenStart","screenEnd","strokeRect","_portAnchorScreen","Controller","ContextMenu","commandStack","items","visible","position","menuElement","_createMenuElement","_onDocumentClick","contains","hide","addItem","label","options","action","submenu","condition","order","removeItem","sort","error","item","worldPos","worldPosition","_renderItems","display","requestAnimationFrame","rect","vw","innerWidth","vh","innerHeight","adjustedX","adjustedY","right","bottom","document","querySelectorAll","remove","removeChild","menu","createElement","className","minWidth","backgroundColor","border","borderRadius","boxShadow","zIndex","padding","fontFamily","fontSize","body","appendChild","innerHTML","visibleItems","itemEl","contentWrapper","alignItems","justifyContent","labelEl","textContent","arrow","marginLeft","opacity","transition","userSelect","_hideTimeout","clearTimeout","submenuItems","_showSubmenu","submenuEl","_submenuElement","setTimeout","elementFromPoint","_hideSubmenu","stopPropagation","parentItemEl","subItem","subItemEl","gap","swatch","flexShrink","relatedTarget","parentRect","submenuRect","Runner","cyclesPerFrame","running","_raf","_last","activePlan","activeStepIndex","stepCache","isRunning","setCyclesPerFrame","step","cycles","dt","nCycles","onExecute","portName","err","runOnce","startNodeId","allConnectedNodes","execEdgeOrder","runCache","queue","fromEdgeId","visited","currentNodeId","shift","input","_executeNodeWithCache","execOutputPorts","execOutput","connectedEdges","connectedNodes","setExecutionMode","mode","resetStepping","buildPlan","plan","dataDeps","srcId","incomingEdges","execOutputs","startStepping","start","executeNextStep","depId","nextStep","findAllNextExecNodes","nextNodes","executeNode","loop","dtMs","cps","stop","cancelAnimationFrame","HtmlOverlay","host","container","inset","pointerEvents","_createDefaultNodeLayout","_node","flexDirection","boxSizing","overflow","header","flex","_domParts","_ensureNodeElement","el","init","transform","transformOrigin","seen","update","parts","_drawStepOverlay","_stepBtn","background","syncTransform","Minimap","graphWidth","graphHeight","mx1","my1","mx2","my2","mx","my","mw","mh","vmx","vmy","vmw","vmh","parentElement","PropertyPanel","_def","panel","currentNode","isVisible","_selfUpdating","_createPanel","_bindHooks","_canRefresh","_renderContent","_updatePositionFields","_e","_updateLiveValues","_f","querySelector","close","open","classList","_renderConnections","_renderPorts","_renderLiveValues","_renderState","_attachInputListeners","outgoing","edgeLabel","otherId","other","cur","lines","upKey","val","JSON","stringify","output","entries","startsWith","_handleFieldChange","dataset","field","parseFloat","substring","orig","xEl","yEl","section","newHtml","wrapper","newSection","firstElementChild","replaceWith","actions","before","HelpOverlay","shortcuts","_getDefaultShortcuts","onToggle","overlay","toggleBtn","_createElements","sectionsHtml","toggle","closeBtn","includes","activeElement","tagName","customHooks","autorun","showMinimap","enablePropertyPanel","propertyPanelContainer","enableHelp","helpShortcuts","setupDefaultContextMenu","setupContextMenu","plugins","HTMLCanvasElement","getComputedStyle","names","fromEntries","fn","off","args","createHooks","edgeCanvas","defineProperty","v","portCanvas","controller","minimap","propertyPanel","helpOverlay","nodeTypes","colorInfo","currentColor","fromColor","toColor","defaultContextMenuSetup","plugin","install","clientWidth","clientHeight","ro","ResizeObserver","observe","originalRender","api","disconnect"],"mappings":"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"}