html-overlay-node 0.1.4 → 0.1.5
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.
- package/dist/html-overlay-node.es.js +14 -10
- package/dist/html-overlay-node.es.js.map +1 -1
- package/dist/html-overlay-node.umd.js +1 -1
- package/dist/html-overlay-node.umd.js.map +1 -1
- package/package.json +1 -1
- package/src/core/Graph.test.js +2 -2
- package/src/core/Hooks.js +9 -2
- package/src/groups/GroupManager.js +1 -1
- package/src/index.js +1 -1
- package/src/interact/Controller.js +3 -5
- package/src/render/CanvasRenderer.js +1 -3
- package/src/render/HtmlOverlay.js +2 -2
- package/src/ui/PropertyPanel.js +0 -1
|
@@ -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"],"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 addInput(name, datatype = \"any\", portType = \"data\") {\r\n if (!name || typeof name !== \"string\") {\r\n throw new Error(\"Input port name must be a non-empty string\");\r\n }\r\n const port = { id: randomUUID(), name, datatype, portType, dir: \"in\" };\r\n this.inputs.push(port);\r\n return port;\r\n }\r\n\r\n /**\r\n * Add an output 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 addOutput(name, datatype = \"any\", portType = \"data\") {\r\n if (!name || typeof name !== \"string\") {\r\n throw new Error(\"Output port name must be a non-empty string\");\r\n }\r\n const port = { id: randomUUID(), name, datatype, portType, dir: \"out\" };\r\n this.outputs.push(port);\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 if (!fromNode || !fromPort || !toNode || !toPort) {\r\n throw new Error(\"Edge requires fromNode, fromPort, toNode, and toPort\");\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 { x: nx, y: ny, w: width, h: height } = 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 { x: nx, y: ny, w: width, h: height } = 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 // Calculate port count for better spacing\r\n const portCount = dir === \"in\" ? node.inputs.length : node.outputs.length;\r\n const headerHeight = 28;\r\n const availableHeight = (height || node.size.height) - headerHeight - 16;\r\n const spacing = availableHeight / (portCount + 1);\r\n\r\n const y = ny + headerHeight + spacing * (idx + 1);\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 { hitTestNode, 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 =\r\n 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({\r\n scale = this.scale,\r\n offsetX = this.offsetX,\r\n offsetY = this.offsetY,\r\n } = {}) {\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 }\r\n panBy(dx, dy) {\r\n this.offsetX += dx;\r\n this.offsetY += dy;\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(\r\n this.maxScale,\r\n Math.max(this.minScale, prev * factor)\r\n );\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 }\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(this.scale, 0, 0, this.scale, this.offsetX, this.offsetY);\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(\r\n x2 - s * Math.cos(ang - Math.PI / 6),\r\n y2 - s * Math.sin(ang - Math.PI / 6)\r\n );\r\n ctx.lineTo(\r\n x2 - s * Math.cos(ang + Math.PI / 6),\r\n y2 - s * Math.sin(ang + Math.PI / 6)\r\n );\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 } = {}\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 });\r\n else this._drawNode(n, sel);\r\n }\r\n }\r\n\r\n // 2. Draw Edges (BEFORE nodes so ports appear on top)\r\n ctx.lineWidth = 1.5 / this.scale; // Thinner, more refined edges\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 // 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 = [{ x: a.x, y: a.y }, { x: b.x, y: b.y }];\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 = [{ x: a.x, y: a.y }, { x: b.x, y: b.y }];\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;\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 ports initially\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 // Draw node, but skip ports if it has HTML overlay\r\n this._drawNode(n, sel, hasHtmlOverlay);\r\n if (def?.onDraw) def.onDraw(n, { ctx, theme });\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,\r\n y1 = pr1.y + 7,\r\n x2 = pr2.x,\r\n y2 = pr2.y + 7;\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++)\r\n 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 dx = Math.abs(x2 - x1);\r\n const dy = Math.abs(y2 - y1);\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\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 { hitTestNode, portRect } from \"../render/hitTest.js\";\r\nimport {\r\n MoveNodeCmd,\r\n AddEdgeCmd,\r\n RemoveEdgeCmd,\r\n CompoundCmd,\r\n RemoveNodeCmd,\r\n ResizeNodeCmd,\r\n} from \"../core/commands.js\";\r\nimport { CommandStack } from \"../core/CommandStack.js\";\r\n\r\nexport class Controller {\r\n\r\n static MIN_NODE_WIDTH = 80;\r\n static MIN_NODE_HEIGHT = 60;\r\n\r\n constructor({ graph, renderer, hooks, htmlOverlay, contextMenu, 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.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))\r\n 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))\r\n 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 = targetWx - this.dragging.selectedNodes.find(sn => sn.node.id === n.id).startWorldX;\r\n const deltaY = 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 let newWorldX = startWorldX + deltaX;\r\n let 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(\r\n this.graph,\r\n from.fromNode,\r\n from.fromPort,\r\n portIn.node.id,\r\n portIn.port.id\r\n )\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, minY = Infinity, maxX = -Infinity, 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 this.renderer.draw(this.graph, {\r\n selection: this.selection,\r\n tempEdge: tEdge,\r\n boxSelecting: this.boxSelecting,\r\n activeEdges: this.activeEdges || new Set(), // For animation\r\n });\r\n\r\n this.htmlOverlay?.draw(this.graph, this.selection);\r\n\r\n // Draw box selection rectangle on top of everything\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.renderer.ctx;\r\n ctx.save();\r\n this.renderer._resetTransform();\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(screenStart.x, screenStart.y, screenEnd.x - screenStart.x, screenEnd.y - screenStart.y);\r\n ctx.fillRect(screenStart.x, screenStart.y, screenEnd.x - screenStart.x, screenEnd.y - screenStart.y);\r\n\r\n ctx.restore();\r\n }\r\n\r\n // Draw ports for HTML overlay nodes on separate canvas (above HTML)\r\n if (this.portRenderer) {\r\n // Clear port canvas\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 // Draw ports for HTML overlay nodes\r\n this.portRenderer._applyTransform();\r\n for (const n of this.graph.nodes.values()) {\r\n if (n.type !== \"core/Group\") {\r\n const def = this.portRenderer.registry?.types?.get(n.type);\r\n const hasHtmlOverlay = !!(def?.html);\r\n\r\n if (hasHtmlOverlay) {\r\n this.portRenderer._drawPorts(n);\r\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(\r\n this.connecting.fromNode,\r\n this.connecting.fromPort\r\n ); // {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.y + 7); // -> screen point\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 this._showSubmenu(item.submenu, 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 * @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 let currentNodeId = startNodeId;\r\n\r\n // Follow exec flow\r\n while (currentNodeId) {\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 break;\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 next node via exec output\r\n currentNodeId = this.findNextExecNode(currentNodeId);\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 the next node to execute by following exec output\r\n * @param {string} nodeId - Current node ID\r\n * @returns {string|null} Next node ID or null\r\n */\r\n findNextExecNode(nodeId) {\r\n const node = this.graph.nodes.get(nodeId);\r\n if (!node) return null;\r\n\r\n // Find exec output port\r\n const execOutput = node.outputs.find(p => p.portType === \"exec\");\r\n if (!execOutput) return null;\r\n\r\n // Find edge from exec output\r\n for (const edge of this.graph.edges.values()) {\r\n if (edge.fromNode === nodeId && edge.fromPort === execOutput.id) {\r\n return edge.toNode;\r\n }\r\n }\r\n\r\n return null;\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 pointerEvents: \"auto\", // 바디 내부는 인터랙션 가능하게? 아니면 이것도 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) {\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 // 초기화 훅\r\n if (def.html.init) {\r\n def.html.init(node, el, el._domParts);\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);\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 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 const def = this.registry?.types?.get(node.type);\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\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 } = {}\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 // 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 HTML overlay (z-index 10)\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, 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 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 // default node\r\n registry.register(\"core/Note\", {\r\n title: \"Note\",\r\n size: { w: 180, h: 80 },\r\n inputs: [{ name: \"in\", datatype: \"any\" }],\r\n outputs: [{ name: \"out\", datatype: \"any\" }],\r\n onCreate(node) {\r\n node.state.text = \"hello\";\r\n },\r\n onExecute(node, { dt, getInput, setOutput }) {\r\n // Simple passthrough with uppercase and a heartbeat value\r\n const incoming = getInput(\"in\");\r\n const out = (incoming ?? node.state.text ?? \"\").toString().toUpperCase();\r\n setOutput(\r\n \"out\",\r\n out + ` · ${Math.floor((performance.now() / 1000) % 100)}`\r\n );\r\n },\r\n onDraw(node, { ctx, theme }) {\r\n const pr = 8;\r\n const { x, y } = node.pos;\r\n const { width: w } = node.size;\r\n const lx = x + pr; // 월드 x\r\n const ly = y + 24 + 6; // 타이틀 바(24) 아래 여백 6\r\n // renderer._drawScreenText(node.state.text ?? \"hello\", lx, ly, {\r\n // fontPx: 11,\r\n // color: theme.text,\r\n // baseline: \"top\",\r\n // align: \"left\",\r\n // });\r\n },\r\n });\r\n\r\n // HTML Custom Node Example\r\n registry.register(\"core/HtmlNote\", {\r\n title: \"HTML Note\",\r\n size: { w: 200, h: 150 },\r\n inputs: [{ name: \"in\", datatype: \"any\" }],\r\n outputs: [{ name: \"out\", datatype: \"any\" }],\r\n\r\n // HTML Overlay Configuration\r\n html: {\r\n // 초기화: 헤더/바디 구성\r\n init(node, el, { header, body }) {\r\n el.style.backgroundColor = \"#222\";\r\n el.style.borderRadius = \"8px\";\r\n el.style.border = \"1px solid #444\";\r\n el.style.boxShadow = \"0 4px 12px rgba(0,0,0,0.3)\";\r\n\r\n // Header\r\n header.style.backgroundColor = \"#333\";\r\n header.style.borderBottom = \"1px solid #444\";\r\n header.style.color = \"#eee\";\r\n header.style.fontSize = \"12px\";\r\n header.style.fontWeight = \"bold\";\r\n header.textContent = \"My HTML Node\";\r\n\r\n // Body\r\n body.style.padding = \"8px\";\r\n body.style.color = \"#ccc\";\r\n body.style.fontSize = \"12px\";\r\n\r\n const contentDiv = document.createElement(\"div\");\r\n contentDiv.textContent = \"Event Name\";\r\n body.appendChild(contentDiv);\r\n\r\n // Add some interactive content\r\n const input = document.createElement(\"input\");\r\n Object.assign(input.style, {\r\n marginTop: \"4px\",\r\n padding: \"4px\",\r\n background: \"#111\",\r\n border: \"1px solid #555\",\r\n color: \"#fff\",\r\n borderRadius: \"4px\",\r\n pointerEvents: \"auto\",\r\n });\r\n input.placeholder = \"Type here...\";\r\n input.addEventListener(\"input\", (e) => {\r\n node.state.text = e.target.value;\r\n });\r\n input.addEventListener(\"mousedown\", (e) => e.stopPropagation()); // 캔버스 드래그 방지\r\n\r\n body.appendChild(input);\r\n\r\n // Store input ref for updates\r\n el._input = input;\r\n },\r\n\r\n // 매 프레임(또는 필요시) 업데이트\r\n update(node, el, { header, body, selected }) {\r\n el.style.borderColor = selected ? \"#6cf\" : \"#444\";\r\n header.style.backgroundColor = selected ? \"#3a4a5a\" : \"#333\";\r\n\r\n // 상태 동기화 (외부에서 변경되었을 경우)\r\n if (el._input.value !== (node.state.text || \"\")) {\r\n el._input.value = node.state.text || \"\";\r\n }\r\n }\r\n },\r\n\r\n onCreate(node) {\r\n node.state.text = \"\";\r\n },\r\n onExecute(node, { getInput, setOutput }) {\r\n const incoming = getInput(\"in\");\r\n setOutput(\"out\", incoming);\r\n },\r\n // onDraw는 생략 가능 (HTML이 덮으니까)\r\n // 하지만 포트 등은 그려야 할 수도 있음. \r\n // 현재 구조상 CanvasRenderer가 기본 노드를 그리므로, \r\n // 투명하게 하거나 겹쳐서 그릴 수 있음.\r\n });\r\n\r\n // Todo List Node Example (HTML Overlay)\r\n registry.register(\"core/TodoNode\", {\r\n title: \"Todo List\",\r\n size: { w: 240, h: 300 },\r\n inputs: [{ name: \"in\", datatype: \"any\" }],\r\n outputs: [{ name: \"out\", datatype: \"any\" }],\r\n html: {\r\n init(node, el, { header, body }) {\r\n el.style.backgroundColor = \"#1e1e24\";\r\n el.style.borderRadius = \"8px\";\r\n el.style.boxShadow = \"0 4px 12px rgba(0,0,0,0.5)\";\r\n el.style.border = \"1px solid #333\";\r\n\r\n header.style.backgroundColor = \"#2a2a31\";\r\n header.style.padding = \"8px\";\r\n header.style.fontWeight = \"bold\";\r\n header.style.color = \"#e9e9ef\";\r\n header.textContent = node.title;\r\n\r\n body.style.display = \"flex\";\r\n body.style.flexDirection = \"column\";\r\n body.style.padding = \"8px\";\r\n body.style.color = \"#e9e9ef\";\r\n\r\n // Input Area\r\n const inputRow = document.createElement(\"div\");\r\n Object.assign(inputRow.style, { display: \"flex\", gap: \"4px\", marginBottom: \"8px\" });\r\n\r\n const input = document.createElement(\"input\");\r\n Object.assign(input.style, {\r\n flex: \"1\", padding: \"6px\", borderRadius: \"4px\",\r\n border: \"1px solid #444\", background: \"#141417\", color: \"#fff\",\r\n pointerEvents: \"auto\",\r\n });\r\n input.placeholder = \"Add task...\";\r\n\r\n const addBtn = document.createElement(\"button\");\r\n addBtn.textContent = \"+\";\r\n Object.assign(addBtn.style, {\r\n padding: \"0 12px\", cursor: \"pointer\", background: \"#4f5b66\",\r\n color: \"#fff\", border: \"none\", borderRadius: \"4px\",\r\n pointerEvents: \"auto\",\r\n });\r\n\r\n inputRow.append(input, addBtn);\r\n\r\n // List Area\r\n const list = document.createElement(\"ul\");\r\n Object.assign(list.style, {\r\n listStyle: \"none\", padding: \"0\", margin: \"0\",\r\n overflow: \"hidden\", flex: \"1\"\r\n });\r\n\r\n body.append(inputRow, list);\r\n\r\n // Logic\r\n const addTodo = () => {\r\n const text = input.value.trim();\r\n if (!text) return;\r\n const todos = node.state.todos || [];\r\n node.state.todos = [...todos, { id: Date.now(), text, done: false }];\r\n input.value = \"\";\r\n hooks.emit(\"node:updated\", node);\r\n };\r\n\r\n addBtn.onclick = addTodo;\r\n input.onkeydown = (e) => {\r\n if (e.key === \"Enter\") addTodo();\r\n e.stopPropagation();\r\n };\r\n input.onmousedown = (e) => e.stopPropagation(); // prevent drag\r\n\r\n el._refs = { list };\r\n },\r\n update(node, el, { selected }) {\r\n el.style.borderColor = selected ? \"#6cf\" : \"#333\";\r\n\r\n const { list } = el._refs;\r\n const todos = node.state.todos || [];\r\n\r\n // Re-render list (simple approach)\r\n list.innerHTML = \"\";\r\n todos.forEach((todo) => {\r\n const li = document.createElement(\"li\");\r\n Object.assign(li.style, {\r\n display: \"flex\", alignItems: \"center\", padding: \"6px 0\",\r\n borderBottom: \"1px solid #2a2a31\"\r\n });\r\n\r\n const chk = document.createElement(\"input\");\r\n chk.type = \"checkbox\";\r\n chk.checked = todo.done;\r\n chk.style.marginRight = \"8px\";\r\n chk.style.pointerEvents = \"auto\";\r\n chk.onchange = () => {\r\n todo.done = chk.checked;\r\n hooks.emit(\"node:updated\", node);\r\n };\r\n chk.onmousedown = (e) => e.stopPropagation();\r\n\r\n const span = document.createElement(\"span\");\r\n span.textContent = todo.text;\r\n span.style.flex = \"1\";\r\n span.style.textDecoration = todo.done ? \"line-through\" : \"none\";\r\n span.style.color = todo.done ? \"#777\" : \"#eee\";\r\n\r\n const del = document.createElement(\"button\");\r\n del.textContent = \"×\";\r\n Object.assign(del.style, {\r\n background: \"none\", border: \"none\", color: \"#f44\",\r\n cursor: \"pointer\", fontSize: \"16px\",\r\n pointerEvents: \"auto\",\r\n });\r\n del.onclick = () => {\r\n node.state.todos = node.state.todos.filter((t) => t.id !== todo.id);\r\n hooks.emit(\"node:updated\", node);\r\n };\r\n del.onmousedown = (e) => e.stopPropagation();\r\n\r\n li.append(chk, span, del);\r\n list.appendChild(li);\r\n });\r\n }\r\n },\r\n onCreate(node) {\r\n node.state.todos = [\r\n { id: 1, text: \"Welcome to Free Node\", done: false },\r\n { id: 2, text: \"Try adding a task\", done: true },\r\n ];\r\n },\r\n });\r\n\r\n // ===== MATH NODES =====\r\n registry.register(\"math/Add\", {\r\n title: \"Add\",\r\n size: { w: 140, h: 100 },\r\n inputs: [\r\n { name: \"exec\", portType: \"exec\" },\r\n { name: \"a\", portType: \"data\", datatype: \"number\" },\r\n { name: \"b\", portType: \"data\", datatype: \"number\" },\r\n ],\r\n outputs: [\r\n { name: \"exec\", portType: \"exec\" },\r\n { name: \"result\", portType: \"data\", datatype: \"number\" },\r\n ],\r\n onCreate(node) {\r\n node.state.a = 0;\r\n node.state.b = 0;\r\n },\r\n onExecute(node, { getInput, setOutput }) {\r\n const a = getInput(\"a\") ?? 0;\r\n const b = getInput(\"b\") ?? 0;\r\n const result = a + b;\r\n console.log(\"[Add] a:\", a, \"b:\", b, \"result:\", result);\r\n setOutput(\"result\", result);\r\n },\r\n });\r\n\r\n registry.register(\"math/Subtract\", {\r\n title: \"Subtract\",\r\n size: { w: 140, h: 80 },\r\n inputs: [\r\n { name: \"a\", datatype: \"number\" },\r\n { name: \"b\", datatype: \"number\" },\r\n ],\r\n outputs: [{ name: \"result\", datatype: \"number\" }],\r\n onExecute(node, { getInput, setOutput }) {\r\n const a = getInput(\"a\") ?? 0;\r\n const b = getInput(\"b\") ?? 0;\r\n setOutput(\"result\", a - b);\r\n },\r\n });\r\n\r\n registry.register(\"math/Multiply\", {\r\n title: \"Multiply\",\r\n size: { w: 140, h: 100 },\r\n inputs: [\r\n { name: \"exec\", portType: \"exec\" },\r\n { name: \"a\", portType: \"data\", datatype: \"number\" },\r\n { name: \"b\", portType: \"data\", datatype: \"number\" },\r\n ],\r\n outputs: [\r\n { name: \"exec\", portType: \"exec\" },\r\n { name: \"result\", portType: \"data\", datatype: \"number\" },\r\n ],\r\n onExecute(node, { getInput, setOutput }) {\r\n const a = getInput(\"a\") ?? 0;\r\n const b = getInput(\"b\") ?? 0;\r\n const result = a * b;\r\n console.log(\"[Multiply] a:\", a, \"b:\", b, \"result:\", result);\r\n setOutput(\"result\", result);\r\n },\r\n });\r\n\r\n registry.register(\"math/Divide\", {\r\n title: \"Divide\",\r\n size: { w: 140, h: 80 },\r\n inputs: [\r\n { name: \"a\", datatype: \"number\" },\r\n { name: \"b\", datatype: \"number\" },\r\n ],\r\n outputs: [{ name: \"result\", datatype: \"number\" }],\r\n onExecute(node, { getInput, setOutput }) {\r\n const a = getInput(\"a\") ?? 0;\r\n const b = getInput(\"b\") ?? 1;\r\n setOutput(\"result\", b !== 0 ? a / b : 0);\r\n },\r\n });\r\n\r\n // ===== LOGIC NODES =====\r\n registry.register(\"logic/AND\", {\r\n title: \"AND\",\r\n size: { w: 120, h: 100 },\r\n inputs: [\r\n { name: \"exec\", portType: \"exec\" },\r\n { name: \"a\", portType: \"data\", datatype: \"boolean\" },\r\n { name: \"b\", portType: \"data\", datatype: \"boolean\" },\r\n ],\r\n outputs: [\r\n { name: \"exec\", portType: \"exec\" },\r\n { name: \"result\", portType: \"data\", datatype: \"boolean\" },\r\n ],\r\n onExecute(node, { getInput, setOutput }) {\r\n const a = getInput(\"a\") ?? false;\r\n const b = getInput(\"b\") ?? false;\r\n console.log(\"[AND] Inputs - a:\", a, \"b:\", b);\r\n const result = a && b;\r\n console.log(\"[AND] Result:\", result);\r\n setOutput(\"result\", result);\r\n },\r\n });\r\n\r\n registry.register(\"logic/OR\", {\r\n title: \"OR\",\r\n size: { w: 120, h: 80 },\r\n inputs: [\r\n { name: \"a\", datatype: \"boolean\" },\r\n { name: \"b\", datatype: \"boolean\" },\r\n ],\r\n outputs: [{ name: \"result\", datatype: \"boolean\" }],\r\n onExecute(node, { getInput, setOutput }) {\r\n const a = getInput(\"a\") ?? false;\r\n const b = getInput(\"b\") ?? false;\r\n setOutput(\"result\", a || b);\r\n },\r\n });\r\n\r\n registry.register(\"logic/NOT\", {\r\n title: \"NOT\",\r\n size: { w: 120, h: 70 },\r\n inputs: [{ name: \"in\", datatype: \"boolean\" }],\r\n outputs: [{ name: \"out\", datatype: \"boolean\" }],\r\n onExecute(node, { getInput, setOutput }) {\r\n const val = getInput(\"in\") ?? false;\r\n setOutput(\"out\", !val);\r\n },\r\n });\r\n\r\n // ===== VALUE NODES =====\r\n registry.register(\"value/Number\", {\r\n title: \"Number\",\r\n size: { w: 140, h: 60 },\r\n outputs: [{ name: \"value\", portType: \"data\", datatype: \"number\" }],\r\n onCreate(node) {\r\n node.state.value = 0;\r\n },\r\n onExecute(node, { setOutput }) {\r\n console.log(\"[Number] Outputting value:\", node.state.value ?? 0);\r\n setOutput(\"value\", node.state.value ?? 0);\r\n },\r\n html: {\r\n init(node, el, { header, body }) {\r\n el.style.backgroundColor = \"#1e1e24\";\r\n el.style.border = \"1px solid #444\";\r\n el.style.borderRadius = \"8px\";\r\n\r\n header.style.backgroundColor = \"#2a2a31\";\r\n header.style.borderBottom = \"1px solid #444\";\r\n header.style.color = \"#eee\";\r\n header.style.fontSize = \"12px\";\r\n header.textContent = \"Number\";\r\n\r\n body.style.padding = \"12px\";\r\n body.style.display = \"flex\";\r\n body.style.alignItems = \"center\";\r\n body.style.justifyContent = \"center\";\r\n\r\n const input = document.createElement(\"input\");\r\n input.type = \"number\";\r\n input.value = node.state.value ?? 0;\r\n Object.assign(input.style, {\r\n width: \"100%\",\r\n padding: \"6px\",\r\n background: \"#141417\",\r\n border: \"1px solid #444\",\r\n borderRadius: \"4px\",\r\n color: \"#fff\",\r\n fontSize: \"14px\",\r\n textAlign: \"center\",\r\n pointerEvents: \"auto\",\r\n });\r\n\r\n input.addEventListener(\"change\", (e) => {\r\n node.state.value = parseFloat(e.target.value) || 0;\r\n });\r\n\r\n input.addEventListener(\"mousedown\", (e) => e.stopPropagation());\r\n input.addEventListener(\"keydown\", (e) => e.stopPropagation());\r\n\r\n body.appendChild(input);\r\n },\r\n update(node, el, { header, body, selected }) {\r\n el.style.borderColor = selected ? \"#6cf\" : \"#444\";\r\n header.style.backgroundColor = selected ? \"#3a4a5a\" : \"#2a2a31\";\r\n },\r\n },\r\n onDraw(node, { ctx, theme }) {\r\n const { x, y } = node.computed;\r\n ctx.fillStyle = \"#8f8\";\r\n ctx.font = \"14px sans-serif\";\r\n ctx.textAlign = \"center\";\r\n ctx.fillText(String(node.state.value ?? 0), x + 70, y + 42);\r\n },\r\n });\r\n\r\n registry.register(\"value/String\", {\r\n title: \"String\",\r\n size: { w: 160, h: 60 },\r\n outputs: [{ name: \"value\", datatype: \"string\" }],\r\n onCreate(node) {\r\n node.state.value = \"Hello\";\r\n },\r\n onExecute(node, { setOutput }) {\r\n setOutput(\"value\", node.state.value ?? \"\");\r\n },\r\n onDraw(node, { ctx, theme }) {\r\n const { x, y } = node.computed;\r\n ctx.fillStyle = \"#8f8\";\r\n ctx.font = \"12px sans-serif\";\r\n ctx.textAlign = \"center\";\r\n const text = String(node.state.value ?? \"\");\r\n const displayText = text.length > 15 ? text.substring(0, 15) + \"...\" : text;\r\n ctx.fillText(displayText, x + 80, y + 42);\r\n },\r\n });\r\n\r\n registry.register(\"value/Boolean\", {\r\n title: \"Boolean\",\r\n size: { w: 140, h: 60 },\r\n outputs: [{ name: \"value\", portType: \"data\", datatype: \"boolean\" }],\r\n onCreate(node) {\r\n node.state.value = true;\r\n },\r\n onExecute(node, { setOutput }) {\r\n console.log(\"[Boolean] Outputting value:\", node.state.value ?? false);\r\n setOutput(\"value\", node.state.value ?? false);\r\n },\r\n onDraw(node, { ctx, theme }) {\r\n const { x, y } = node.computed;\r\n ctx.fillStyle = node.state.value ? \"#8f8\" : \"#f88\";\r\n ctx.font = \"14px sans-serif\";\r\n ctx.textAlign = \"center\";\r\n ctx.fillText(String(node.state.value), x + 70, y + 42);\r\n },\r\n });\r\n\r\n // ===== UTILITY NODES =====\r\n registry.register(\"util/Print\", {\r\n title: \"Print\",\r\n size: { w: 140, h: 80 },\r\n inputs: [\r\n { name: \"exec\", portType: \"exec\" },\r\n { name: \"value\", portType: \"data\", datatype: \"any\" },\r\n ],\r\n onCreate(node) {\r\n node.state.lastValue = null;\r\n },\r\n onExecute(node, { getInput }) {\r\n const val = getInput(\"value\");\r\n if (val !== node.state.lastValue) {\r\n console.log(\"[Print]\", val);\r\n node.state.lastValue = val;\r\n }\r\n },\r\n });\r\n\r\n registry.register(\"util/Watch\", {\r\n title: \"Watch\",\r\n size: { w: 180, h: 110 },\r\n inputs: [\r\n { name: \"exec\", portType: \"exec\" },\r\n { name: \"value\", portType: \"data\", datatype: \"any\" },\r\n ],\r\n outputs: [\r\n { name: \"exec\", portType: \"exec\" },\r\n { name: \"value\", portType: \"data\", datatype: \"any\" },\r\n ],\r\n onCreate(node) {\r\n node.state.displayValue = \"---\";\r\n },\r\n onExecute(node, { getInput, setOutput }) {\r\n const val = getInput(\"value\");\r\n console.log(\"[Watch] onExecute called, value:\", val);\r\n node.state.displayValue = String(val ?? \"---\");\r\n setOutput(\"value\", val);\r\n },\r\n onDraw(node, { ctx, theme }) {\r\n const { x, y } = node.computed;\r\n ctx.fillStyle = \"#fa3\";\r\n ctx.font = \"11px monospace\";\r\n ctx.textAlign = \"left\";\r\n const text = String(node.state.displayValue ?? \"---\");\r\n const displayText = text.length > 20 ? text.substring(0, 20) + \"...\" : text;\r\n ctx.fillText(displayText, x + 8, y + 50);\r\n },\r\n });\r\n\r\n registry.register(\"util/Timer\", {\r\n title: \"Timer\",\r\n size: { w: 140, h: 60 },\r\n outputs: [{ name: \"time\", datatype: \"number\" }],\r\n onCreate(node) {\r\n node.state.startTime = performance.now();\r\n },\r\n onExecute(node, { setOutput }) {\r\n const elapsed = (performance.now() - (node.state.startTime ?? 0)) / 1000;\r\n setOutput(\"time\", elapsed.toFixed(2));\r\n },\r\n });\r\n\r\n // Trigger Node with Button (HTML Overlay)\r\n registry.register(\"util/Trigger\", {\r\n title: \"Trigger\",\r\n size: { w: 140, h: 80 },\r\n outputs: [{ name: \"exec\", portType: \"exec\" }], // Changed to exec port\r\n\r\n html: {\r\n init(node, el, { header, body }) {\r\n el.style.backgroundColor = \"#1e1e24\";\r\n el.style.border = \"1px solid #444\";\r\n el.style.borderRadius = \"8px\";\r\n\r\n header.style.backgroundColor = \"#2a2a31\";\r\n header.style.borderBottom = \"1px solid #444\";\r\n header.style.color = \"#eee\";\r\n header.style.fontSize = \"12px\";\r\n header.textContent = \"Trigger\";\r\n\r\n body.style.padding = \"12px\";\r\n body.style.display = \"flex\";\r\n body.style.alignItems = \"center\";\r\n body.style.justifyContent = \"center\";\r\n\r\n const button = document.createElement(\"button\");\r\n button.textContent = \"Fire!\";\r\n Object.assign(button.style, {\r\n padding: \"8px 16px\",\r\n background: \"#4a9eff\",\r\n border: \"none\",\r\n borderRadius: \"4px\",\r\n color: \"#fff\",\r\n fontWeight: \"bold\",\r\n cursor: \"pointer\",\r\n pointerEvents: \"auto\",\r\n transition: \"background 0.2s\",\r\n });\r\n\r\n button.addEventListener(\"mousedown\", (e) => {\r\n e.stopPropagation();\r\n button.style.background = \"#2a7ede\";\r\n });\r\n\r\n button.addEventListener(\"mouseup\", () => {\r\n button.style.background = \"#4a9eff\";\r\n });\r\n\r\n button.addEventListener(\"click\", (e) => {\r\n e.stopPropagation();\r\n node.state.triggered = true;\r\n console.log(\"[Trigger] Button clicked!\");\r\n\r\n // Use runner.runOnce for connected node execution\r\n if (node.__runnerRef && node.__controllerRef) {\r\n console.log(\"[Trigger] Runner and controller found\");\r\n const runner = node.__runnerRef;\r\n const controller = node.__controllerRef;\r\n const graph = controller.graph;\r\n console.log(\"[Trigger] Calling runner.runOnce with node.id:\", node.id);\r\n\r\n // Execute connected nodes using runner\r\n const result = runner.runOnce(node.id, 0);\r\n const connectedEdges = result.connectedEdges;\r\n\r\n\r\n\r\n // Show animation with manual rendering\r\n const startTime = performance.now();\r\n const animationDuration = 500;\r\n\r\n const animate = () => {\r\n const elapsed = performance.now() - startTime;\r\n if (elapsed < animationDuration) {\r\n controller.renderer.draw(graph, {\r\n selection: controller.selection,\r\n tempEdge: null,\r\n running: true,\r\n time: performance.now(),\r\n dt: 0,\r\n activeEdges: connectedEdges, // Only animate connected edges\r\n });\r\n controller.htmlOverlay?.draw(graph, controller.selection);\r\n requestAnimationFrame(animate);\r\n } else {\r\n controller.render();\r\n node.state.triggered = false;\r\n }\r\n };\r\n\r\n animate();\r\n }\r\n });\r\n\r\n body.appendChild(button);\r\n },\r\n\r\n update(node, el, { header, body, selected }) {\r\n el.style.borderColor = selected ? \"#6cf\" : \"#444\";\r\n header.style.backgroundColor = selected ? \"#3a4a5a\" : \"#2a2a31\";\r\n },\r\n },\r\n\r\n onCreate(node) {\r\n node.state.triggered = false;\r\n },\r\n\r\n onExecute(node, { setOutput }) {\r\n console.log(\"[Trigger] Outputting triggered:\", node.state.triggered);\r\n setOutput(\"triggered\", node.state.triggered);\r\n },\r\n });\r\n\r\n // Group Node\r\n registry.register(\"core/Group\", {\r\n title: \"Group\",\r\n size: { w: 240, h: 160 },\r\n onDraw(node, { ctx, theme }) {\r\n const { x, y, w, h } = node.computed;\r\n const headerH = 24;\r\n const color = node.state.color || \"#39424e\";\r\n const bgAlpha = 0.5;\r\n const textColor = theme.text || \"#e9e9ef\";\r\n\r\n // Helper for rgba\r\n const 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 // Helper for roundRect\r\n const roundRect = (ctx, x, y, w, h, r) => {\r\n if (w < 2 * r) r = w / 2;\r\n if (h < 2 * r) r = h / 2;\r\n ctx.beginPath();\r\n ctx.moveTo(x + r, y);\r\n ctx.arcTo(x + w, y, x + w, y + h, r);\r\n ctx.arcTo(x + w, y + h, x, y + h, r);\r\n ctx.arcTo(x, y + h, x, y, r);\r\n ctx.arcTo(x, y, x + w, y, r);\r\n ctx.closePath();\r\n };\r\n\r\n // Body\r\n ctx.fillStyle = rgba(color, bgAlpha);\r\n roundRect(ctx, x, y, w, h, 10);\r\n ctx.fill();\r\n\r\n // Header bar (subtle)\r\n ctx.fillStyle = rgba(color, 0.3);\r\n ctx.beginPath();\r\n ctx.roundRect(x, y, w, headerH, [10, 10, 0, 0]);\r\n ctx.fill();\r\n\r\n // Title - top left with better styling\r\n ctx.fillStyle = textColor;\r\n ctx.font = \"600 13px system-ui\";\r\n ctx.textBaseline = \"top\";\r\n ctx.fillText(node.title, x + 12, y + 6);\r\n },\r\n });\r\n\r\n /**\r\n * Setup default context menu items\r\n * This function can be customized or replaced by users\r\n */\r\n function setupDefaultContextMenu(contextMenu, { controller, graph, hooks }) {\r\n // Add Node submenu (canvas background only)\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\r\n contextMenu.addItem(\"add-node\", \"Add Node\", {\r\n condition: (target) => !target,\r\n submenu: nodeTypes,\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 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\r\n\r\n // Setup default context menu items\r\n // Users can easily override, remove, or add items here\r\n setupDefaultContextMenu(contextMenu, { controller, graph, hooks });\r\n\r\n // initial render & resize\r\n renderer.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 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 map[name].add(fn);\r\n return () => map[name].delete(fn);\r\n },\r\n async emit(name, ...args) {\r\n for (const fn of map[name]) await fn(...args);\r\n },\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","addInput","name","datatype","portType","port","dir","push","addOutput","Edge","fromNode","fromPort","toNode","toPort","GroupManager","graph","hooks","_groups","addGroup","color","members","console","warn","max","groupNode","addNode","memberId","node","getNodeById","reparent","_a","emit","addGroupFromSelection","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","length","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","portCount","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","panBy","dx","dy","zoomAt","factor","cx","cy","prev","next","screenToWorld","worldToScreen","_applyTransform","_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","sel","onDraw","_drawNode","dashArray","dashOffset","phase","FONT_SIZE","shouldAnimate","setLineDash","lineDashOffset","_drawEdge","a","prevDash","getLineDash","ptsForArrow","_drawLine","_drawOrthogonal","_drawCurve","p1","p2","hasHtmlOverlay","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","__publicField","CanvasRenderer","r","findEdgeId","d","RemoveNodeCmd","removedNode","removedEdges","filter","undo","CommandStack","undoStack","redoStack","exec","cmd","do","redo","_Controller","renderer","htmlOverlay","contextMenu","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","groupHeight","avgY","reduce","sum","parentY","avgX","parentX","tEdge","renderTempEdge","screenStart","screenEnd","strokeRect","clearRect","_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","_showSubmenu","submenuEl","_submenuElement","setTimeout","elementFromPoint","_hideSubmenu","stopPropagation","submenuItems","parentItemEl","subItem","subItemEl","gap","swatch","flexShrink","relatedTarget","parentRect","submenuRect","Runner","cyclesPerFrame","_raf","_last","isRunning","setCyclesPerFrame","cycles","nCycles","onExecute","portName","err","runOnce","startNodeId","executedNodes","allConnectedNodes","currentNodeId","input","executeNode","findNextExecNode","connectedEdges","connectedNodes","execOutput","start","loop","t","dtMs","cps","stop","cancelAnimationFrame","HtmlOverlay","host","container","inset","pointerEvents","_createDefaultNodeLayout","flexDirection","boxSizing","overflow","header","flex","_domParts","_ensureNodeElement","el","init","transform","transformOrigin","seen","update","parts","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","content","_renderPorts","_renderState","_attachInputListeners","entries","_handleFieldChange","dataset","field","parseFloat","startsWith","substring","originalValue","customHooks","autorun","showMinimap","enablePropertyPanel","propertyPanelContainer","HTMLCanvasElement","getComputedStyle","names","fromEntries","on","fn","args","createHooks","portCanvas","controller","minimap","propertyPanel","runner","toUpperCase","borderBottom","fontWeight","contentDiv","marginTop","placeholder","_input","borderColor","inputRow","marginBottom","addBtn","append","listStyle","addTodo","trim","todos","Date","done","onclick","onkeydown","onmousedown","_refs","todo","li","chk","checked","marginRight","onchange","span","textDecoration","del","result","String","displayText","lastValue","val","displayValue","startTime","toFixed","triggered","__runnerRef","__controllerRef","animationDuration","animate","textColor","rgba","arcTo","nodeTypes","typeDef","colorInfo","currentColor","fromColor","toColor","setupDefaultContextMenu","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/index.js","../src/core/Hooks.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 addInput(name, datatype = \"any\", portType = \"data\") {\r\n if (!name || typeof name !== \"string\") {\r\n throw new Error(\"Input port name must be a non-empty string\");\r\n }\r\n const port = { id: randomUUID(), name, datatype, portType, dir: \"in\" };\r\n this.inputs.push(port);\r\n return port;\r\n }\r\n\r\n /**\r\n * Add an output 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 addOutput(name, datatype = \"any\", portType = \"data\") {\r\n if (!name || typeof name !== \"string\") {\r\n throw new Error(\"Output port name must be a non-empty string\");\r\n }\r\n const port = { id: randomUUID(), name, datatype, portType, dir: \"out\" };\r\n this.outputs.push(port);\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 if (!fromNode || !fromPort || !toNode || !toPort) {\r\n throw new Error(\"Edge requires fromNode, fromPort, toNode, and toPort\");\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 { x: nx, y: ny, w: width, h: height } = 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 { x: nx, y: ny, w: width, h: height } = 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 // Calculate port count for better spacing\r\n const portCount = dir === \"in\" ? node.inputs.length : node.outputs.length;\r\n const headerHeight = 28;\r\n const availableHeight = (height || node.size.height) - headerHeight - 16;\r\n const spacing = availableHeight / (portCount + 1);\r\n\r\n const y = ny + headerHeight + spacing * (idx + 1);\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 =\r\n 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({\r\n scale = this.scale,\r\n offsetX = this.offsetX,\r\n offsetY = this.offsetY,\r\n } = {}) {\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 }\r\n panBy(dx, dy) {\r\n this.offsetX += dx;\r\n this.offsetY += dy;\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(\r\n this.maxScale,\r\n Math.max(this.minScale, prev * factor)\r\n );\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 }\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(this.scale, 0, 0, this.scale, this.offsetX, this.offsetY);\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(\r\n x2 - s * Math.cos(ang - Math.PI / 6),\r\n y2 - s * Math.sin(ang - Math.PI / 6)\r\n );\r\n ctx.lineTo(\r\n x2 - s * Math.cos(ang + Math.PI / 6),\r\n y2 - s * Math.sin(ang + Math.PI / 6)\r\n );\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 } = {}\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 });\r\n else this._drawNode(n, sel);\r\n }\r\n }\r\n\r\n // 2. Draw Edges (BEFORE nodes so ports appear on top)\r\n ctx.lineWidth = 1.5 / this.scale; // Thinner, more refined edges\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 // 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 = [{ x: a.x, y: a.y }, { x: b.x, y: b.y }];\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 = [{ x: a.x, y: a.y }, { x: b.x, y: b.y }];\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;\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 ports initially\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 // Draw node, but skip ports if it has HTML overlay\r\n this._drawNode(n, sel, hasHtmlOverlay);\r\n if (def?.onDraw) def.onDraw(n, { ctx, theme });\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,\r\n y1 = pr1.y + 7,\r\n x2 = pr2.x,\r\n y2 = pr2.y + 7;\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++)\r\n 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\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 {\r\n AddEdgeCmd,\r\n RemoveEdgeCmd,\r\n RemoveNodeCmd,\r\n ResizeNodeCmd,\r\n} from \"../core/commands.js\";\r\nimport { CommandStack } from \"../core/CommandStack.js\";\r\n\r\nexport class Controller {\r\n\r\n static MIN_NODE_WIDTH = 80;\r\n static MIN_NODE_HEIGHT = 60;\r\n\r\n constructor({ graph, renderer, hooks, htmlOverlay, contextMenu, 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.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))\r\n 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))\r\n 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 = targetWx - this.dragging.selectedNodes.find(sn => sn.node.id === n.id).startWorldX;\r\n const deltaY = 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(\r\n this.graph,\r\n from.fromNode,\r\n from.fromPort,\r\n portIn.node.id,\r\n portIn.port.id\r\n )\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, minY = Infinity, maxX = -Infinity, 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 this.renderer.draw(this.graph, {\r\n selection: this.selection,\r\n tempEdge: tEdge,\r\n boxSelecting: this.boxSelecting,\r\n activeEdges: this.activeEdges || new Set(), // For animation\r\n });\r\n\r\n this.htmlOverlay?.draw(this.graph, this.selection);\r\n\r\n // Draw box selection rectangle on top of everything\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.renderer.ctx;\r\n ctx.save();\r\n this.renderer._resetTransform();\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(screenStart.x, screenStart.y, screenEnd.x - screenStart.x, screenEnd.y - screenStart.y);\r\n ctx.fillRect(screenStart.x, screenStart.y, screenEnd.x - screenStart.x, screenEnd.y - screenStart.y);\r\n\r\n ctx.restore();\r\n }\r\n\r\n // Draw ports for HTML overlay nodes on separate canvas (above HTML)\r\n if (this.portRenderer) {\r\n // Clear port canvas\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 // Draw ports for HTML overlay nodes\r\n this.portRenderer._applyTransform();\r\n for (const n of this.graph.nodes.values()) {\r\n if (n.type !== \"core/Group\") {\r\n const def = this.portRenderer.registry?.types?.get(n.type);\r\n const hasHtmlOverlay = !!(def?.html);\r\n\r\n if (hasHtmlOverlay) {\r\n this.portRenderer._drawPorts(n);\r\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(\r\n this.connecting.fromNode,\r\n this.connecting.fromPort\r\n ); // {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.y + 7); // -> screen point\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 this._showSubmenu(item.submenu, 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 * @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 let currentNodeId = startNodeId;\r\n\r\n // Follow exec flow\r\n while (currentNodeId) {\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 break;\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 next node via exec output\r\n currentNodeId = this.findNextExecNode(currentNodeId);\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 the next node to execute by following exec output\r\n * @param {string} nodeId - Current node ID\r\n * @returns {string|null} Next node ID or null\r\n */\r\n findNextExecNode(nodeId) {\r\n const node = this.graph.nodes.get(nodeId);\r\n if (!node) return null;\r\n\r\n // Find exec output port\r\n const execOutput = node.outputs.find(p => p.portType === \"exec\");\r\n if (!execOutput) return null;\r\n\r\n // Find edge from exec output\r\n for (const edge of this.graph.edges.values()) {\r\n if (edge.fromNode === nodeId && edge.fromPort === execOutput.id) {\r\n return edge.toNode;\r\n }\r\n }\r\n\r\n return null;\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) {\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 // 초기화 훅\r\n if (def.html.init) {\r\n def.html.init(node, el, el._domParts);\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);\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 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\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 } = {}\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 // 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 HTML overlay (z-index 10)\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, 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 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 // default node\r\n registry.register(\"core/Note\", {\r\n title: \"Note\",\r\n size: { w: 180, h: 80 },\r\n inputs: [{ name: \"in\", datatype: \"any\" }],\r\n outputs: [{ name: \"out\", datatype: \"any\" }],\r\n onCreate(node) {\r\n node.state.text = \"hello\";\r\n },\r\n onExecute(node, { dt, getInput, setOutput }) {\r\n // Simple passthrough with uppercase and a heartbeat value\r\n const incoming = getInput(\"in\");\r\n const out = (incoming ?? node.state.text ?? \"\").toString().toUpperCase();\r\n setOutput(\r\n \"out\",\r\n out + ` · ${Math.floor((performance.now() / 1000) % 100)}`\r\n );\r\n },\r\n onDraw(node, { ctx, theme }) {\r\n const pr = 8;\r\n const { x, y } = node.pos;\r\n const { width: w } = node.size;\r\n const lx = x + pr; // 월드 x\r\n const ly = y + 24 + 6; // 타이틀 바(24) 아래 여백 6\r\n // renderer._drawScreenText(node.state.text ?? \"hello\", lx, ly, {\r\n // fontPx: 11,\r\n // color: theme.text,\r\n // baseline: \"top\",\r\n // align: \"left\",\r\n // });\r\n },\r\n });\r\n\r\n // HTML Custom Node Example\r\n registry.register(\"core/HtmlNote\", {\r\n title: \"HTML Note\",\r\n size: { w: 200, h: 150 },\r\n inputs: [{ name: \"in\", datatype: \"any\" }],\r\n outputs: [{ name: \"out\", datatype: \"any\" }],\r\n\r\n // HTML Overlay Configuration\r\n html: {\r\n // 초기화: 헤더/바디 구성\r\n init(node, el, { header, body }) {\r\n el.style.backgroundColor = \"#222\";\r\n el.style.borderRadius = \"8px\";\r\n el.style.border = \"1px solid #444\";\r\n el.style.boxShadow = \"0 4px 12px rgba(0,0,0,0.3)\";\r\n\r\n // Header\r\n header.style.backgroundColor = \"#333\";\r\n header.style.borderBottom = \"1px solid #444\";\r\n header.style.color = \"#eee\";\r\n header.style.fontSize = \"12px\";\r\n header.style.fontWeight = \"bold\";\r\n header.textContent = \"My HTML Node\";\r\n\r\n // Body\r\n body.style.padding = \"8px\";\r\n body.style.color = \"#ccc\";\r\n body.style.fontSize = \"12px\";\r\n\r\n const contentDiv = document.createElement(\"div\");\r\n contentDiv.textContent = \"Event Name\";\r\n body.appendChild(contentDiv);\r\n\r\n // Add some interactive content\r\n const input = document.createElement(\"input\");\r\n Object.assign(input.style, {\r\n marginTop: \"4px\",\r\n padding: \"4px\",\r\n background: \"#111\",\r\n border: \"1px solid #555\",\r\n color: \"#fff\",\r\n borderRadius: \"4px\",\r\n pointerEvents: \"auto\",\r\n });\r\n input.placeholder = \"Type here...\";\r\n input.addEventListener(\"input\", (e) => {\r\n node.state.text = e.target.value;\r\n });\r\n input.addEventListener(\"mousedown\", (e) => e.stopPropagation()); // 캔버스 드래그 방지\r\n\r\n body.appendChild(input);\r\n\r\n // Store input ref for updates\r\n el._input = input;\r\n },\r\n\r\n // 매 프레임(또는 필요시) 업데이트\r\n update(node, el, { header, _body, selected }) {\r\n el.style.borderColor = selected ? \"#6cf\" : \"#444\";\r\n header.style.backgroundColor = selected ? \"#3a4a5a\" : \"#333\";\r\n\r\n // 상태 동기화 (외부에서 변경되었을 경우)\r\n if (el._input.value !== (node.state.text || \"\")) {\r\n el._input.value = node.state.text || \"\";\r\n }\r\n }\r\n },\r\n\r\n onCreate(node) {\r\n node.state.text = \"\";\r\n },\r\n onExecute(node, { getInput, setOutput }) {\r\n const incoming = getInput(\"in\");\r\n setOutput(\"out\", incoming);\r\n },\r\n // onDraw는 생략 가능 (HTML이 덮으니까)\r\n // 하지만 포트 등은 그려야 할 수도 있음. \r\n // 현재 구조상 CanvasRenderer가 기본 노드를 그리므로, \r\n // 투명하게 하거나 겹쳐서 그릴 수 있음.\r\n });\r\n\r\n // Todo List Node Example (HTML Overlay)\r\n registry.register(\"core/TodoNode\", {\r\n title: \"Todo List\",\r\n size: { w: 240, h: 300 },\r\n inputs: [{ name: \"in\", datatype: \"any\" }],\r\n outputs: [{ name: \"out\", datatype: \"any\" }],\r\n html: {\r\n init(node, el, { header, body }) {\r\n el.style.backgroundColor = \"#1e1e24\";\r\n el.style.borderRadius = \"8px\";\r\n el.style.boxShadow = \"0 4px 12px rgba(0,0,0,0.5)\";\r\n el.style.border = \"1px solid #333\";\r\n\r\n header.style.backgroundColor = \"#2a2a31\";\r\n header.style.padding = \"8px\";\r\n header.style.fontWeight = \"bold\";\r\n header.style.color = \"#e9e9ef\";\r\n header.textContent = node.title;\r\n\r\n body.style.display = \"flex\";\r\n body.style.flexDirection = \"column\";\r\n body.style.padding = \"8px\";\r\n body.style.color = \"#e9e9ef\";\r\n\r\n // Input Area\r\n const inputRow = document.createElement(\"div\");\r\n Object.assign(inputRow.style, { display: \"flex\", gap: \"4px\", marginBottom: \"8px\" });\r\n\r\n const input = document.createElement(\"input\");\r\n Object.assign(input.style, {\r\n flex: \"1\", padding: \"6px\", borderRadius: \"4px\",\r\n border: \"1px solid #444\", background: \"#141417\", color: \"#fff\",\r\n pointerEvents: \"auto\",\r\n });\r\n input.placeholder = \"Add task...\";\r\n\r\n const addBtn = document.createElement(\"button\");\r\n addBtn.textContent = \"+\";\r\n Object.assign(addBtn.style, {\r\n padding: \"0 12px\", cursor: \"pointer\", background: \"#4f5b66\",\r\n color: \"#fff\", border: \"none\", borderRadius: \"4px\",\r\n pointerEvents: \"auto\",\r\n });\r\n\r\n inputRow.append(input, addBtn);\r\n\r\n // List Area\r\n const list = document.createElement(\"ul\");\r\n Object.assign(list.style, {\r\n listStyle: \"none\", padding: \"0\", margin: \"0\",\r\n overflow: \"hidden\", flex: \"1\"\r\n });\r\n\r\n body.append(inputRow, list);\r\n\r\n // Logic\r\n const addTodo = () => {\r\n const text = input.value.trim();\r\n if (!text) return;\r\n const todos = node.state.todos || [];\r\n node.state.todos = [...todos, { id: Date.now(), text, done: false }];\r\n input.value = \"\";\r\n hooks.emit(\"node:updated\", node);\r\n };\r\n\r\n addBtn.onclick = addTodo;\r\n input.onkeydown = (e) => {\r\n if (e.key === \"Enter\") addTodo();\r\n e.stopPropagation();\r\n };\r\n input.onmousedown = (e) => e.stopPropagation(); // prevent drag\r\n\r\n el._refs = { list };\r\n },\r\n update(node, el, { selected }) {\r\n el.style.borderColor = selected ? \"#6cf\" : \"#333\";\r\n\r\n const { list } = el._refs;\r\n const todos = node.state.todos || [];\r\n\r\n // Re-render list (simple approach)\r\n list.innerHTML = \"\";\r\n todos.forEach((todo) => {\r\n const li = document.createElement(\"li\");\r\n Object.assign(li.style, {\r\n display: \"flex\", alignItems: \"center\", padding: \"6px 0\",\r\n borderBottom: \"1px solid #2a2a31\"\r\n });\r\n\r\n const chk = document.createElement(\"input\");\r\n chk.type = \"checkbox\";\r\n chk.checked = todo.done;\r\n chk.style.marginRight = \"8px\";\r\n chk.style.pointerEvents = \"auto\";\r\n chk.onchange = () => {\r\n todo.done = chk.checked;\r\n hooks.emit(\"node:updated\", node);\r\n };\r\n chk.onmousedown = (e) => e.stopPropagation();\r\n\r\n const span = document.createElement(\"span\");\r\n span.textContent = todo.text;\r\n span.style.flex = \"1\";\r\n span.style.textDecoration = todo.done ? \"line-through\" : \"none\";\r\n span.style.color = todo.done ? \"#777\" : \"#eee\";\r\n\r\n const del = document.createElement(\"button\");\r\n del.textContent = \"×\";\r\n Object.assign(del.style, {\r\n background: \"none\", border: \"none\", color: \"#f44\",\r\n cursor: \"pointer\", fontSize: \"16px\",\r\n pointerEvents: \"auto\",\r\n });\r\n del.onclick = () => {\r\n node.state.todos = node.state.todos.filter((t) => t.id !== todo.id);\r\n hooks.emit(\"node:updated\", node);\r\n };\r\n del.onmousedown = (e) => e.stopPropagation();\r\n\r\n li.append(chk, span, del);\r\n list.appendChild(li);\r\n });\r\n }\r\n },\r\n onCreate(node) {\r\n node.state.todos = [\r\n { id: 1, text: \"Welcome to Free Node\", done: false },\r\n { id: 2, text: \"Try adding a task\", done: true },\r\n ];\r\n },\r\n });\r\n\r\n // ===== MATH NODES =====\r\n registry.register(\"math/Add\", {\r\n title: \"Add\",\r\n size: { w: 140, h: 100 },\r\n inputs: [\r\n { name: \"exec\", portType: \"exec\" },\r\n { name: \"a\", portType: \"data\", datatype: \"number\" },\r\n { name: \"b\", portType: \"data\", datatype: \"number\" },\r\n ],\r\n outputs: [\r\n { name: \"exec\", portType: \"exec\" },\r\n { name: \"result\", portType: \"data\", datatype: \"number\" },\r\n ],\r\n onCreate(node) {\r\n node.state.a = 0;\r\n node.state.b = 0;\r\n },\r\n onExecute(node, { getInput, setOutput }) {\r\n const a = getInput(\"a\") ?? 0;\r\n const b = getInput(\"b\") ?? 0;\r\n const result = a + b;\r\n console.log(\"[Add] a:\", a, \"b:\", b, \"result:\", result);\r\n setOutput(\"result\", result);\r\n },\r\n });\r\n\r\n registry.register(\"math/Subtract\", {\r\n title: \"Subtract\",\r\n size: { w: 140, h: 80 },\r\n inputs: [\r\n { name: \"a\", datatype: \"number\" },\r\n { name: \"b\", datatype: \"number\" },\r\n ],\r\n outputs: [{ name: \"result\", datatype: \"number\" }],\r\n onExecute(node, { getInput, setOutput }) {\r\n const a = getInput(\"a\") ?? 0;\r\n const b = getInput(\"b\") ?? 0;\r\n setOutput(\"result\", a - b);\r\n },\r\n });\r\n\r\n registry.register(\"math/Multiply\", {\r\n title: \"Multiply\",\r\n size: { w: 140, h: 100 },\r\n inputs: [\r\n { name: \"exec\", portType: \"exec\" },\r\n { name: \"a\", portType: \"data\", datatype: \"number\" },\r\n { name: \"b\", portType: \"data\", datatype: \"number\" },\r\n ],\r\n outputs: [\r\n { name: \"exec\", portType: \"exec\" },\r\n { name: \"result\", portType: \"data\", datatype: \"number\" },\r\n ],\r\n onExecute(node, { getInput, setOutput }) {\r\n const a = getInput(\"a\") ?? 0;\r\n const b = getInput(\"b\") ?? 0;\r\n const result = a * b;\r\n console.log(\"[Multiply] a:\", a, \"b:\", b, \"result:\", result);\r\n setOutput(\"result\", result);\r\n },\r\n });\r\n\r\n registry.register(\"math/Divide\", {\r\n title: \"Divide\",\r\n size: { w: 140, h: 80 },\r\n inputs: [\r\n { name: \"a\", datatype: \"number\" },\r\n { name: \"b\", datatype: \"number\" },\r\n ],\r\n outputs: [{ name: \"result\", datatype: \"number\" }],\r\n onExecute(node, { getInput, setOutput }) {\r\n const a = getInput(\"a\") ?? 0;\r\n const b = getInput(\"b\") ?? 1;\r\n setOutput(\"result\", b !== 0 ? a / b : 0);\r\n },\r\n });\r\n\r\n // ===== LOGIC NODES =====\r\n registry.register(\"logic/AND\", {\r\n title: \"AND\",\r\n size: { w: 120, h: 100 },\r\n inputs: [\r\n { name: \"exec\", portType: \"exec\" },\r\n { name: \"a\", portType: \"data\", datatype: \"boolean\" },\r\n { name: \"b\", portType: \"data\", datatype: \"boolean\" },\r\n ],\r\n outputs: [\r\n { name: \"exec\", portType: \"exec\" },\r\n { name: \"result\", portType: \"data\", datatype: \"boolean\" },\r\n ],\r\n onExecute(node, { getInput, setOutput }) {\r\n const a = getInput(\"a\") ?? false;\r\n const b = getInput(\"b\") ?? false;\r\n console.log(\"[AND] Inputs - a:\", a, \"b:\", b);\r\n const result = a && b;\r\n console.log(\"[AND] Result:\", result);\r\n setOutput(\"result\", result);\r\n },\r\n });\r\n\r\n registry.register(\"logic/OR\", {\r\n title: \"OR\",\r\n size: { w: 120, h: 80 },\r\n inputs: [\r\n { name: \"a\", datatype: \"boolean\" },\r\n { name: \"b\", datatype: \"boolean\" },\r\n ],\r\n outputs: [{ name: \"result\", datatype: \"boolean\" }],\r\n onExecute(node, { getInput, setOutput }) {\r\n const a = getInput(\"a\") ?? false;\r\n const b = getInput(\"b\") ?? false;\r\n setOutput(\"result\", a || b);\r\n },\r\n });\r\n\r\n registry.register(\"logic/NOT\", {\r\n title: \"NOT\",\r\n size: { w: 120, h: 70 },\r\n inputs: [{ name: \"in\", datatype: \"boolean\" }],\r\n outputs: [{ name: \"out\", datatype: \"boolean\" }],\r\n onExecute(node, { getInput, setOutput }) {\r\n const val = getInput(\"in\") ?? false;\r\n setOutput(\"out\", !val);\r\n },\r\n });\r\n\r\n // ===== VALUE NODES =====\r\n registry.register(\"value/Number\", {\r\n title: \"Number\",\r\n size: { w: 140, h: 60 },\r\n outputs: [{ name: \"value\", portType: \"data\", datatype: \"number\" }],\r\n onCreate(node) {\r\n node.state.value = 0;\r\n },\r\n onExecute(node, { setOutput }) {\r\n console.log(\"[Number] Outputting value:\", node.state.value ?? 0);\r\n setOutput(\"value\", node.state.value ?? 0);\r\n },\r\n html: {\r\n init(node, el, { header, body }) {\r\n el.style.backgroundColor = \"#1e1e24\";\r\n el.style.border = \"1px solid #444\";\r\n el.style.borderRadius = \"8px\";\r\n\r\n header.style.backgroundColor = \"#2a2a31\";\r\n header.style.borderBottom = \"1px solid #444\";\r\n header.style.color = \"#eee\";\r\n header.style.fontSize = \"12px\";\r\n header.textContent = \"Number\";\r\n\r\n body.style.padding = \"12px\";\r\n body.style.display = \"flex\";\r\n body.style.alignItems = \"center\";\r\n body.style.justifyContent = \"center\";\r\n\r\n const input = document.createElement(\"input\");\r\n input.type = \"number\";\r\n input.value = node.state.value ?? 0;\r\n Object.assign(input.style, {\r\n width: \"100%\",\r\n padding: \"6px\",\r\n background: \"#141417\",\r\n border: \"1px solid #444\",\r\n borderRadius: \"4px\",\r\n color: \"#fff\",\r\n fontSize: \"14px\",\r\n textAlign: \"center\",\r\n pointerEvents: \"auto\",\r\n });\r\n\r\n input.addEventListener(\"change\", (e) => {\r\n node.state.value = parseFloat(e.target.value) || 0;\r\n });\r\n\r\n input.addEventListener(\"mousedown\", (e) => e.stopPropagation());\r\n input.addEventListener(\"keydown\", (e) => e.stopPropagation());\r\n\r\n body.appendChild(input);\r\n },\r\n update(node, el, { header, body, selected }) {\r\n el.style.borderColor = selected ? \"#6cf\" : \"#444\";\r\n header.style.backgroundColor = selected ? \"#3a4a5a\" : \"#2a2a31\";\r\n },\r\n },\r\n onDraw(node, { ctx, theme }) {\r\n const { x, y } = node.computed;\r\n ctx.fillStyle = \"#8f8\";\r\n ctx.font = \"14px sans-serif\";\r\n ctx.textAlign = \"center\";\r\n ctx.fillText(String(node.state.value ?? 0), x + 70, y + 42);\r\n },\r\n });\r\n\r\n registry.register(\"value/String\", {\r\n title: \"String\",\r\n size: { w: 160, h: 60 },\r\n outputs: [{ name: \"value\", datatype: \"string\" }],\r\n onCreate(node) {\r\n node.state.value = \"Hello\";\r\n },\r\n onExecute(node, { setOutput }) {\r\n setOutput(\"value\", node.state.value ?? \"\");\r\n },\r\n onDraw(node, { ctx, theme }) {\r\n const { x, y } = node.computed;\r\n ctx.fillStyle = \"#8f8\";\r\n ctx.font = \"12px sans-serif\";\r\n ctx.textAlign = \"center\";\r\n const text = String(node.state.value ?? \"\");\r\n const displayText = text.length > 15 ? text.substring(0, 15) + \"...\" : text;\r\n ctx.fillText(displayText, x + 80, y + 42);\r\n },\r\n });\r\n\r\n registry.register(\"value/Boolean\", {\r\n title: \"Boolean\",\r\n size: { w: 140, h: 60 },\r\n outputs: [{ name: \"value\", portType: \"data\", datatype: \"boolean\" }],\r\n onCreate(node) {\r\n node.state.value = true;\r\n },\r\n onExecute(node, { setOutput }) {\r\n console.log(\"[Boolean] Outputting value:\", node.state.value ?? false);\r\n setOutput(\"value\", node.state.value ?? false);\r\n },\r\n onDraw(node, { ctx, theme }) {\r\n const { x, y } = node.computed;\r\n ctx.fillStyle = node.state.value ? \"#8f8\" : \"#f88\";\r\n ctx.font = \"14px sans-serif\";\r\n ctx.textAlign = \"center\";\r\n ctx.fillText(String(node.state.value), x + 70, y + 42);\r\n },\r\n });\r\n\r\n // ===== UTILITY NODES =====\r\n registry.register(\"util/Print\", {\r\n title: \"Print\",\r\n size: { w: 140, h: 80 },\r\n inputs: [\r\n { name: \"exec\", portType: \"exec\" },\r\n { name: \"value\", portType: \"data\", datatype: \"any\" },\r\n ],\r\n onCreate(node) {\r\n node.state.lastValue = null;\r\n },\r\n onExecute(node, { getInput }) {\r\n const val = getInput(\"value\");\r\n if (val !== node.state.lastValue) {\r\n console.log(\"[Print]\", val);\r\n node.state.lastValue = val;\r\n }\r\n },\r\n });\r\n\r\n registry.register(\"util/Watch\", {\r\n title: \"Watch\",\r\n size: { w: 180, h: 110 },\r\n inputs: [\r\n { name: \"exec\", portType: \"exec\" },\r\n { name: \"value\", portType: \"data\", datatype: \"any\" },\r\n ],\r\n outputs: [\r\n { name: \"exec\", portType: \"exec\" },\r\n { name: \"value\", portType: \"data\", datatype: \"any\" },\r\n ],\r\n onCreate(node) {\r\n node.state.displayValue = \"---\";\r\n },\r\n onExecute(node, { getInput, setOutput }) {\r\n const val = getInput(\"value\");\r\n console.log(\"[Watch] onExecute called, value:\", val);\r\n node.state.displayValue = String(val ?? \"---\");\r\n setOutput(\"value\", val);\r\n },\r\n onDraw(node, { ctx, theme }) {\r\n const { x, y } = node.computed;\r\n ctx.fillStyle = \"#fa3\";\r\n ctx.font = \"11px monospace\";\r\n ctx.textAlign = \"left\";\r\n const text = String(node.state.displayValue ?? \"---\");\r\n const displayText = text.length > 20 ? text.substring(0, 20) + \"...\" : text;\r\n ctx.fillText(displayText, x + 8, y + 50);\r\n },\r\n });\r\n\r\n registry.register(\"util/Timer\", {\r\n title: \"Timer\",\r\n size: { w: 140, h: 60 },\r\n outputs: [{ name: \"time\", datatype: \"number\" }],\r\n onCreate(node) {\r\n node.state.startTime = performance.now();\r\n },\r\n onExecute(node, { setOutput }) {\r\n const elapsed = (performance.now() - (node.state.startTime ?? 0)) / 1000;\r\n setOutput(\"time\", elapsed.toFixed(2));\r\n },\r\n });\r\n\r\n // Trigger Node with Button (HTML Overlay)\r\n registry.register(\"util/Trigger\", {\r\n title: \"Trigger\",\r\n size: { w: 140, h: 80 },\r\n outputs: [{ name: \"exec\", portType: \"exec\" }], // Changed to exec port\r\n\r\n html: {\r\n init(node, el, { header, body }) {\r\n el.style.backgroundColor = \"#1e1e24\";\r\n el.style.border = \"1px solid #444\";\r\n el.style.borderRadius = \"8px\";\r\n\r\n header.style.backgroundColor = \"#2a2a31\";\r\n header.style.borderBottom = \"1px solid #444\";\r\n header.style.color = \"#eee\";\r\n header.style.fontSize = \"12px\";\r\n header.textContent = \"Trigger\";\r\n\r\n body.style.padding = \"12px\";\r\n body.style.display = \"flex\";\r\n body.style.alignItems = \"center\";\r\n body.style.justifyContent = \"center\";\r\n\r\n const button = document.createElement(\"button\");\r\n button.textContent = \"Fire!\";\r\n Object.assign(button.style, {\r\n padding: \"8px 16px\",\r\n background: \"#4a9eff\",\r\n border: \"none\",\r\n borderRadius: \"4px\",\r\n color: \"#fff\",\r\n fontWeight: \"bold\",\r\n cursor: \"pointer\",\r\n pointerEvents: \"auto\",\r\n transition: \"background 0.2s\",\r\n });\r\n\r\n button.addEventListener(\"mousedown\", (e) => {\r\n e.stopPropagation();\r\n button.style.background = \"#2a7ede\";\r\n });\r\n\r\n button.addEventListener(\"mouseup\", () => {\r\n button.style.background = \"#4a9eff\";\r\n });\r\n\r\n button.addEventListener(\"click\", (e) => {\r\n e.stopPropagation();\r\n node.state.triggered = true;\r\n console.log(\"[Trigger] Button clicked!\");\r\n\r\n // Use runner.runOnce for connected node execution\r\n if (node.__runnerRef && node.__controllerRef) {\r\n console.log(\"[Trigger] Runner and controller found\");\r\n const runner = node.__runnerRef;\r\n const controller = node.__controllerRef;\r\n const graph = controller.graph;\r\n console.log(\"[Trigger] Calling runner.runOnce with node.id:\", node.id);\r\n\r\n // Execute connected nodes using runner\r\n const result = runner.runOnce(node.id, 0);\r\n const connectedEdges = result.connectedEdges;\r\n\r\n\r\n\r\n // Show animation with manual rendering\r\n const startTime = performance.now();\r\n const animationDuration = 500;\r\n\r\n const animate = () => {\r\n const elapsed = performance.now() - startTime;\r\n if (elapsed < animationDuration) {\r\n controller.renderer.draw(graph, {\r\n selection: controller.selection,\r\n tempEdge: null,\r\n running: true,\r\n time: performance.now(),\r\n dt: 0,\r\n activeEdges: connectedEdges, // Only animate connected edges\r\n });\r\n controller.htmlOverlay?.draw(graph, controller.selection);\r\n requestAnimationFrame(animate);\r\n } else {\r\n controller.render();\r\n node.state.triggered = false;\r\n }\r\n };\r\n\r\n animate();\r\n }\r\n });\r\n\r\n body.appendChild(button);\r\n },\r\n\r\n update(node, el, { header, body, selected }) {\r\n el.style.borderColor = selected ? \"#6cf\" : \"#444\";\r\n header.style.backgroundColor = selected ? \"#3a4a5a\" : \"#2a2a31\";\r\n },\r\n },\r\n\r\n onCreate(node) {\r\n node.state.triggered = false;\r\n },\r\n\r\n onExecute(node, { setOutput }) {\r\n console.log(\"[Trigger] Outputting triggered:\", node.state.triggered);\r\n setOutput(\"triggered\", node.state.triggered);\r\n },\r\n });\r\n\r\n // Group Node\r\n registry.register(\"core/Group\", {\r\n title: \"Group\",\r\n size: { w: 240, h: 160 },\r\n onDraw(node, { ctx, theme }) {\r\n const { x, y, w, h } = node.computed;\r\n const headerH = 24;\r\n const color = node.state.color || \"#39424e\";\r\n const bgAlpha = 0.5;\r\n const textColor = theme.text || \"#e9e9ef\";\r\n\r\n // Helper for rgba\r\n const 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 // Helper for roundRect\r\n const roundRect = (ctx, x, y, w, h, r) => {\r\n if (w < 2 * r) r = w / 2;\r\n if (h < 2 * r) r = h / 2;\r\n ctx.beginPath();\r\n ctx.moveTo(x + r, y);\r\n ctx.arcTo(x + w, y, x + w, y + h, r);\r\n ctx.arcTo(x + w, y + h, x, y + h, r);\r\n ctx.arcTo(x, y + h, x, y, r);\r\n ctx.arcTo(x, y, x + w, y, r);\r\n ctx.closePath();\r\n };\r\n\r\n // Body\r\n ctx.fillStyle = rgba(color, bgAlpha);\r\n roundRect(ctx, x, y, w, h, 10);\r\n ctx.fill();\r\n\r\n // Header bar (subtle)\r\n ctx.fillStyle = rgba(color, 0.3);\r\n ctx.beginPath();\r\n ctx.roundRect(x, y, w, headerH, [10, 10, 0, 0]);\r\n ctx.fill();\r\n\r\n // Title - top left with better styling\r\n ctx.fillStyle = textColor;\r\n ctx.font = \"600 13px system-ui\";\r\n ctx.textBaseline = \"top\";\r\n ctx.fillText(node.title, x + 12, y + 6);\r\n },\r\n });\r\n\r\n /**\r\n * Setup default context menu items\r\n * This function can be customized or replaced by users\r\n */\r\n function setupDefaultContextMenu(contextMenu, { controller, graph, hooks }) {\r\n // Add Node submenu (canvas background only)\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\r\n contextMenu.addItem(\"add-node\", \"Add Node\", {\r\n condition: (target) => !target,\r\n submenu: nodeTypes,\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 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\r\n\r\n // Setup default context menu items\r\n // Users can easily override, remove, or add items here\r\n setupDefaultContextMenu(contextMenu, { controller, graph, hooks });\r\n\r\n // initial render & resize\r\n renderer.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 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"],"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","addInput","name","datatype","portType","port","dir","push","addOutput","Edge","fromNode","fromPort","toNode","toPort","GroupManager","graph","hooks","_groups","addGroup","color","members","console","warn","max","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","length","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","portCount","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","panBy","dx","dy","zoomAt","factor","cx","cy","prev","next","screenToWorld","worldToScreen","_applyTransform","_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","sel","onDraw","_drawNode","dashArray","dashOffset","phase","FONT_SIZE","shouldAnimate","setLineDash","lineDashOffset","_drawEdge","a","prevDash","getLineDash","ptsForArrow","_drawLine","_drawOrthogonal","_drawCurve","p1","p2","hasHtmlOverlay","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","__publicField","CanvasRenderer","r","findEdgeId","d","RemoveNodeCmd","removedNode","removedEdges","filter","undo","CommandStack","undoStack","redoStack","exec","cmd","do","redo","_Controller","renderer","htmlOverlay","contextMenu","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","clearRect","_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","_showSubmenu","submenuEl","_submenuElement","setTimeout","elementFromPoint","_hideSubmenu","stopPropagation","submenuItems","parentItemEl","subItem","subItemEl","gap","swatch","flexShrink","relatedTarget","parentRect","submenuRect","Runner","cyclesPerFrame","_raf","_last","isRunning","setCyclesPerFrame","cycles","nCycles","onExecute","portName","err","runOnce","startNodeId","executedNodes","allConnectedNodes","currentNodeId","input","executeNode","findNextExecNode","connectedEdges","connectedNodes","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","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","HTMLCanvasElement","getComputedStyle","names","fromEntries","on","fn","off","args","createHooks","portCanvas","controller","minimap","propertyPanel","runner","toUpperCase","borderBottom","fontWeight","contentDiv","marginTop","placeholder","_input","_body","borderColor","inputRow","marginBottom","addBtn","append","listStyle","addTodo","trim","todos","Date","done","onclick","onkeydown","onmousedown","_refs","todo","li","chk","checked","marginRight","onchange","span","textDecoration","del","result","String","displayText","lastValue","val","displayValue","startTime","toFixed","triggered","__runnerRef","__controllerRef","animationDuration","animate","textColor","rgba","arcTo","nodeTypes","typeDef","colorInfo","currentColor","fromColor","toColor","setupDefaultContextMenu","clientWidth","clientHeight","ro","ResizeObserver","observe","originalRender","api","disconnect"],"mappings":"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"}
|