@utisha/graph-editor 1.0.1 → 1.0.3
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.
|
@@ -1246,8 +1246,8 @@ class GraphEditorComponent {
|
|
|
1246
1246
|
return nodeConfig?.icon || '●';
|
|
1247
1247
|
}
|
|
1248
1248
|
/**
|
|
1249
|
-
* Get
|
|
1250
|
-
*
|
|
1249
|
+
* Get image URL for a node icon.
|
|
1250
|
+
* Priority: node.data['imageUrl'] > nodeType.iconSvg (converted to data URL) > nodeType.defaultData['imageUrl']
|
|
1251
1251
|
* Returns null if no image is configured (will render text icon instead).
|
|
1252
1252
|
*/
|
|
1253
1253
|
getNodeImage(node) {
|
|
@@ -1255,13 +1255,61 @@ class GraphEditorComponent {
|
|
|
1255
1255
|
if (node.data['imageUrl']) {
|
|
1256
1256
|
return node.data['imageUrl'];
|
|
1257
1257
|
}
|
|
1258
|
-
// Fall back to node type default
|
|
1259
1258
|
const nodeConfig = this.config.nodes.types.find(t => t.type === node.type);
|
|
1259
|
+
// Check for iconSvg definition (convert to data URL)
|
|
1260
|
+
if (nodeConfig?.iconSvg) {
|
|
1261
|
+
return this.svgIconToDataUrl(nodeConfig.iconSvg);
|
|
1262
|
+
}
|
|
1263
|
+
// Fall back to node type default imageUrl
|
|
1260
1264
|
if (nodeConfig?.defaultData['imageUrl']) {
|
|
1261
1265
|
return nodeConfig.defaultData['imageUrl'];
|
|
1262
1266
|
}
|
|
1263
1267
|
return null;
|
|
1264
1268
|
}
|
|
1269
|
+
/**
|
|
1270
|
+
* Convert an SvgIconDefinition to a data URL for use in <image> elements.
|
|
1271
|
+
* Caches results to avoid repeated conversion.
|
|
1272
|
+
*/
|
|
1273
|
+
svgIconCache = new Map();
|
|
1274
|
+
svgIconToDataUrl(icon) {
|
|
1275
|
+
// Check cache first
|
|
1276
|
+
const cached = this.svgIconCache.get(icon);
|
|
1277
|
+
if (cached)
|
|
1278
|
+
return cached;
|
|
1279
|
+
const viewBox = icon.viewBox || '0 0 24 24';
|
|
1280
|
+
const fill = icon.fill || 'none';
|
|
1281
|
+
const stroke = icon.stroke || '#1D6A96';
|
|
1282
|
+
const strokeWidth = icon.strokeWidth || 2;
|
|
1283
|
+
// Build SVG markup with proper path handling
|
|
1284
|
+
const paths = icon.path
|
|
1285
|
+
.split(/\n/)
|
|
1286
|
+
.map(p => p.trim())
|
|
1287
|
+
.filter(p => p.length > 0)
|
|
1288
|
+
.map(p => `<path d="${p}"/>`)
|
|
1289
|
+
.join('');
|
|
1290
|
+
const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="${viewBox}" fill="${fill}" stroke="${stroke}" stroke-width="${strokeWidth}" stroke-linecap="round" stroke-linejoin="round">${paths}</svg>`;
|
|
1291
|
+
// Encode as data URL
|
|
1292
|
+
const dataUrl = `data:image/svg+xml;base64,${btoa(svg)}`;
|
|
1293
|
+
this.svgIconCache.set(icon, dataUrl);
|
|
1294
|
+
return dataUrl;
|
|
1295
|
+
}
|
|
1296
|
+
/**
|
|
1297
|
+
* Get the SVG icon definition for a node type (for palette rendering).
|
|
1298
|
+
* Returns null if no iconSvg is configured.
|
|
1299
|
+
*/
|
|
1300
|
+
getNodeTypeSvgIcon(nodeType) {
|
|
1301
|
+
return nodeType.iconSvg || null;
|
|
1302
|
+
}
|
|
1303
|
+
/**
|
|
1304
|
+
* Split SVG path data by newlines for template iteration.
|
|
1305
|
+
* Used to render multiple path elements from a single path string.
|
|
1306
|
+
*/
|
|
1307
|
+
splitIconPaths(pathData) {
|
|
1308
|
+
return pathData
|
|
1309
|
+
.split(/\n/)
|
|
1310
|
+
.map(p => p.trim())
|
|
1311
|
+
.filter(p => p.length > 0);
|
|
1312
|
+
}
|
|
1265
1313
|
/**
|
|
1266
1314
|
* Get the position for the node image (top-left corner of image).
|
|
1267
1315
|
* Uses same positioning logic as icon but accounts for image dimensions.
|
|
@@ -1435,7 +1483,7 @@ class GraphEditorComponent {
|
|
|
1435
1483
|
}
|
|
1436
1484
|
}
|
|
1437
1485
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.19", ngImport: i0, type: GraphEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1438
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.19", type: GraphEditorComponent, isStandalone: true, selector: "graph-editor", inputs: { config: "config", graph: "graph", readonly: "readonly", visualizationMode: "visualizationMode", overlayData: "overlayData" }, outputs: { graphChange: "graphChange", nodeAdded: "nodeAdded", nodeUpdated: "nodeUpdated", nodeRemoved: "nodeRemoved", edgeAdded: "edgeAdded", edgeUpdated: "edgeUpdated", edgeRemoved: "edgeRemoved", selectionChange: "selectionChange", validationChange: "validationChange", nodeClick: "nodeClick", nodeDoubleClick: "nodeDoubleClick", edgeClick: "edgeClick", edgeDoubleClick: "edgeDoubleClick", canvasClick: "canvasClick", contextMenu: "contextMenu" }, host: { attributes: { "tabindex": "0" }, listeners: { "keydown": "onKeyDown($event)" }, styleAttribute: "outline: none;" }, providers: [GraphHistoryService], viewQueries: [{ propertyName: "canvasSvgRef", first: true, predicate: ["canvasSvg"], descendants: true, isSignal: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"graph-editor-container\">\n <!-- Canvas with overlaid palette -->\n <div class=\"graph-canvas-wrapper\">\n <!-- Top-left horizontal palette overlay -->\n @if (config.palette?.enabled !== false) {\n <div class=\"graph-palette-overlay\">\n <!-- Tools -->\n <button\n class=\"palette-item tool-item\"\n [class.active]=\"activeTool() === 'hand'\"\n title=\"Hand tool (move nodes)\"\n (click)=\"switchTool('hand')\"\n >\n <span class=\"icon\">\u270B</span>\n </button>\n <button\n class=\"palette-item tool-item\"\n [class.active]=\"activeTool() === 'line'\"\n title=\"Line tool (draw connections)\"\n (click)=\"switchTool('line')\"\n >\n <span class=\"icon\">\u2215</span>\n </button>\n\n <!-- Divider -->\n <div class=\"palette-divider\"></div>\n\n <!-- Node types -->\n @for (nodeType of config.nodes.types; track nodeType.type) {\n <button\n class=\"palette-item\"\n [attr.data-node-type]=\"nodeType.type\"\n [attr.title]=\"nodeType.label || nodeType.type\"\n (click)=\"addNode(nodeType.type)\"\n >\n @if (nodeType.defaultData['imageUrl']) {\n <img\n class=\"palette-icon-img\"\n [src]=\"nodeType.defaultData['imageUrl']\"\n [alt]=\"nodeType.label || nodeType.type\"\n />\n } @else {\n <span class=\"icon\">{{ nodeType.icon || '\u25CF' }}</span>\n }\n </button>\n }\n </div>\n }\n\n <svg\n #canvasSvg\n [class.tool-line]=\"activeTool() === 'line'\"\n [attr.width]=\"'100%'\"\n [attr.height]=\"'100%'\"\n (mousedown)=\"onCanvasMouseDown($event)\"\n (mousemove)=\"onCanvasMouseMove($event)\"\n (mouseup)=\"onCanvasMouseUp($event)\"\n (wheel)=\"onWheel($event)\"\n (contextmenu)=\"onContextMenu($event)\"\n >\n <!-- Arrow marker definitions -->\n <defs>\n <marker id=\"arrow-end\" viewBox=\"0 0 10 10\" refX=\"9\" refY=\"5\"\n markerWidth=\"8\" markerHeight=\"8\" orient=\"auto\">\n <path d=\"M 0 1 L 8 5 L 0 9 z\" fill=\"#94a3b8\"/>\n </marker>\n <marker id=\"arrow-end-selected\" viewBox=\"0 0 10 10\" refX=\"9\" refY=\"5\"\n markerWidth=\"8\" markerHeight=\"8\" orient=\"auto\">\n <path d=\"M 0 1 L 8 5 L 0 9 z\" fill=\"#3b82f6\"/>\n </marker>\n <marker id=\"arrow-start\" viewBox=\"0 0 10 10\" refX=\"1\" refY=\"5\"\n markerWidth=\"8\" markerHeight=\"8\" orient=\"auto\">\n <path d=\"M 10 1 L 2 5 L 10 9 z\" fill=\"#94a3b8\"/>\n </marker>\n <marker id=\"arrow-start-selected\" viewBox=\"0 0 10 10\" refX=\"1\" refY=\"5\"\n markerWidth=\"8\" markerHeight=\"8\" orient=\"auto\">\n <path d=\"M 10 1 L 2 5 L 10 9 z\" fill=\"#3b82f6\"/>\n </marker>\n </defs>\n\n <!-- Main transform group (pan + zoom) -->\n <g [attr.transform]=\"transform()\">\n <!-- Grid (if enabled) -->\n <!-- Grid (if enabled) - extended to cover viewport during pan -->\n @if (config.canvas?.grid?.enabled) {\n <defs>\n <pattern\n id=\"grid\"\n [attr.width]=\"config.canvas!.grid!.size\"\n [attr.height]=\"config.canvas!.grid!.size\"\n patternUnits=\"userSpaceOnUse\"\n >\n <path\n [attr.d]=\"'M ' + config.canvas!.grid!.size + ' 0 L 0 0 0 ' + config.canvas!.grid!.size\"\n fill=\"none\"\n [attr.stroke]=\"config.canvas!.grid!.color || '#e0e0e0'\"\n stroke-width=\"1\"\n />\n </pattern>\n </defs>\n <!-- Extended grid background covering viewport + pan offset -->\n <rect\n [attr.x]=\"gridBounds().x\"\n [attr.y]=\"gridBounds().y\"\n [attr.width]=\"gridBounds().width\"\n [attr.height]=\"gridBounds().height\"\n fill=\"url(#grid)\"\n />\n }\n\n <!-- Layer 0.5: Preview line for line tool (rubber-band) -->\n @if (previewLine()) {\n <line\n class=\"preview-line\"\n [attr.x1]=\"previewLine()!.source.x\"\n [attr.y1]=\"previewLine()!.source.y\"\n [attr.x2]=\"previewLine()!.target.x\"\n [attr.y2]=\"previewLine()!.target.y\"\n stroke=\"#3b82f6\"\n stroke-width=\"2.5\"\n stroke-dasharray=\"8,6\"\n stroke-linecap=\"round\"\n opacity=\"0.7\"\n />\n }\n\n <!-- Layer 1: Edge paths (behind everything) -->\n @for (edge of internalGraph().edges; track edge.id) {\n <!-- Edge shadow for depth (optional) -->\n @if (shadowsEnabled()) {\n <path\n class=\"edge-shadow\"\n [attr.d]=\"getEdgePath(edge)\"\n stroke=\"rgba(0,0,0,0.06)\"\n stroke-width=\"6\"\n fill=\"none\"\n stroke-linecap=\"round\"\n [attr.transform]=\"'translate(1, 2)'\"\n />\n }\n <!-- Invisible wide hit-area for easier clicking (hand tool only) -->\n <path\n [attr.d]=\"getEdgePath(edge)\"\n stroke=\"transparent\"\n [attr.stroke-width]=\"20\"\n fill=\"none\"\n class=\"edge-hit-area\"\n [attr.pointer-events]=\"activeTool() === 'hand' ? 'stroke' : 'none'\"\n (click)=\"onEdgeClick($event, edge)\"\n (dblclick)=\"onEdgeDoubleClick($event, edge)\"\n />\n <!-- Visible edge line -->\n <path\n class=\"edge-line\"\n [attr.d]=\"getEdgePath(edge)\"\n [attr.stroke]=\"selection().edges.includes(edge.id) ? '#3b82f6' : '#94a3b8'\"\n [attr.stroke-width]=\"selection().edges.includes(edge.id) ? 2.5 : 2\"\n fill=\"none\"\n stroke-linecap=\"round\"\n [class.selected]=\"selection().edges.includes(edge.id)\"\n [attr.marker-end]=\"getEdgeMarkerEnd(edge)\"\n [attr.marker-start]=\"getEdgeMarkerStart(edge)\"\n pointer-events=\"none\"\n />\n }\n\n <!-- Layer 2: Nodes -->\n @for (node of internalGraph().nodes; track node.id) {\n <g\n [attr.transform]=\"'translate(' + node.position.x + ',' + node.position.y + ')'\"\n class=\"graph-node\"\n [class.selected]=\"selection().nodes.includes(node.id)\"\n [attr.data-node-id]=\"node.id\"\n (mousedown)=\"onNodeMouseDown($event, node)\"\n (click)=\"onNodeClick($event, node)\"\n (dblclick)=\"nodeDoubleClick.emit(node)\"\n >\n <!-- Node shadow (optional) -->\n @if (shadowsEnabled()) {\n <rect\n class=\"node-shadow\"\n [attr.width]=\"getNodeSize(node).width\"\n [attr.height]=\"getNodeSize(node).height\"\n fill=\"rgba(0,0,0,0.08)\"\n rx=\"12\"\n transform=\"translate(2, 3)\"\n style=\"filter: blur(4px);\"\n />\n }\n <!-- Node background -->\n <rect\n class=\"node-bg\"\n [attr.width]=\"getNodeSize(node).width\"\n [attr.height]=\"getNodeSize(node).height\"\n fill=\"white\"\n [attr.stroke]=\"selection().nodes.includes(node.id) ? '#3b82f6' : '#e2e8f0'\"\n [attr.stroke-width]=\"selection().nodes.includes(node.id) ? 2.5 : 1.5\"\n rx=\"12\"\n />\n\n <!-- Node type icon (text/emoji) or custom image -->\n @if (getNodeImage(node)) {\n <image\n class=\"node-image\"\n [attr.href]=\"getNodeImage(node)\"\n [attr.xlink:href]=\"getNodeImage(node)\"\n [attr.x]=\"getImagePosition(node).x\"\n [attr.y]=\"getImagePosition(node).y\"\n [attr.width]=\"getImageSize(node)\"\n [attr.height]=\"getImageSize(node)\"\n preserveAspectRatio=\"xMidYMid meet\"\n />\n } @else {\n <text\n class=\"node-icon\"\n [attr.x]=\"getIconPosition(node).x\"\n [attr.y]=\"getIconPosition(node).y\"\n text-anchor=\"middle\"\n dominant-baseline=\"middle\"\n [attr.font-size]=\"getNodeSize(node).height * 0.28\"\n >\n {{ getNodeTypeIcon(node) }}\n </text>\n }\n\n <!-- Node label -->\n <text\n class=\"node-label\"\n [attr.x]=\"getLabelPosition(node).x\"\n [attr.y]=\"getLabelPosition(node).y\"\n text-anchor=\"middle\"\n dominant-baseline=\"middle\"\n font-size=\"14\"\n font-weight=\"500\"\n fill=\"#1e293b\"\n >\n {{ node.data['name'] || node.type }}\n </text>\n </g>\n }\n\n <!-- Layer 3: Attachment points (on top of nodes) -->\n @for (node of internalGraph().nodes; track node.id) {\n @if (showAttachmentPoints() === node.id) {\n <g [attr.transform]=\"'translate(' + node.position.x + ',' + node.position.y + ')'\">\n @for (port of getNodePorts(node); track port.position) {\n <circle\n [attr.cx]=\"port.x\"\n [attr.cy]=\"port.y\"\n [attr.r]=\"hoveredPort?.nodeId === node.id && hoveredPort?.port === port.position ? 8 : 6\"\n [attr.fill]=\"hoveredPort?.nodeId === node.id && hoveredPort?.port === port.position ? '#2563eb' : '#94a3b8'\"\n stroke=\"white\"\n stroke-width=\"2\"\n class=\"attachment-point\"\n [class.hovered]=\"hoveredPort?.nodeId === node.id && hoveredPort?.port === port.position\"\n (mousedown)=\"$event.stopPropagation()\"\n (click)=\"onAttachmentPointClick($event, node, port.position)\"\n />\n }\n </g>\n }\n }\n\n <!-- Layer 4: Edge endpoints (only visible when edge is selected) -->\n @for (edge of internalGraph().edges; track edge.id) {\n @if (selection().edges.includes(edge.id)) {\n <g>\n <!-- Source endpoint -->\n <circle\n [attr.cx]=\"getEdgeSourcePoint(edge).x\"\n [attr.cy]=\"getEdgeSourcePoint(edge).y\"\n r=\"6\"\n fill=\"#3b82f6\"\n stroke=\"white\"\n stroke-width=\"2\"\n class=\"edge-endpoint selected\"\n (mousedown)=\"onEdgeEndpointMouseDown($event, edge, 'source')\"\n />\n\n <!-- Target endpoint -->\n <circle\n [attr.cx]=\"getEdgeTargetPoint(edge).x\"\n [attr.cy]=\"getEdgeTargetPoint(edge).y\"\n r=\"6\"\n fill=\"#3b82f6\"\n stroke=\"white\"\n stroke-width=\"2\"\n class=\"edge-endpoint selected\"\n (mousedown)=\"onEdgeEndpointMouseDown($event, edge, 'target')\"\n />\n </g>\n }\n }\n\n <!-- Layer 5: Selection box (Shift+drag) -->\n @if (selectionBox()) {\n <rect\n class=\"selection-box\"\n [attr.x]=\"selectionBox()!.x\"\n [attr.y]=\"selectionBox()!.y\"\n [attr.width]=\"selectionBox()!.width\"\n [attr.height]=\"selectionBox()!.height\"\n fill=\"rgba(59, 130, 246, 0.1)\"\n stroke=\"#3b82f6\"\n stroke-width=\"1\"\n stroke-dasharray=\"4,2\"\n />\n }\n </g>\n </svg>\n </div>\n\n <!-- Edge direction selector overlay -->\n @if (selectedEdgeMidpoint()) {\n <div\n class=\"edge-direction-selector\"\n [style.left.px]=\"selectedEdgeMidpoint()!.x\"\n [style.top.px]=\"selectedEdgeMidpoint()!.y\"\n >\n <button\n class=\"direction-btn\"\n [class.active]=\"selectedEdgeMidpoint()!.edge.direction === 'backward'\"\n title=\"Backward\"\n (click)=\"setEdgeDirection('backward')\"\n >\u2190</button>\n <button\n class=\"direction-btn\"\n [class.active]=\"selectedEdgeMidpoint()!.edge.direction === 'bidirectional'\"\n title=\"Bidirectional\"\n (click)=\"setEdgeDirection('bidirectional')\"\n >\u2194</button>\n <button\n class=\"direction-btn\"\n [class.active]=\"!selectedEdgeMidpoint()!.edge.direction || selectedEdgeMidpoint()!.edge.direction === 'forward'\"\n title=\"Forward\"\n (click)=\"setEdgeDirection('forward')\"\n >\u2192</button>\n </div>\n }\n <!-- Validation errors -->\n @if (validationResult() && !validationResult()!.valid) {\n <div class=\"validation-panel\">\n <h4>Validation Errors</h4>\n @for (error of validationResult()!.errors; track error.rule) {\n <div class=\"error-item\" [class.warning]=\"error.severity === 'warning'\">\n {{ error.message }}\n </div>\n }\n </div>\n }\n</div>\n", styles: [".graph-editor-container{display:flex;width:100%;height:100%;position:relative;background:var(--graph-editor-canvas-bg, #f8f9fa)}.graph-palette-overlay{position:absolute;top:16px;left:16px;display:flex;gap:4px;z-index:10;background:#fffffff2;padding:6px;border-radius:var(--radius-md, 8px);box-shadow:0 2px 8px #0000001a;backdrop-filter:blur(4px)}.palette-item{display:inline-flex;align-items:center;justify-content:center;width:40px;height:40px;padding:0;border:1.5px solid var(--neutral-200, #e5e7eb);border-radius:var(--radius-md, 8px);background:var(--white, #fff);color:var(--neutral-600, #4b5563);cursor:pointer;-webkit-user-select:none;user-select:none;transition:all .15s ease;font-size:20px}.palette-icon-img{width:24px;height:24px;object-fit:contain}.palette-item:focus-visible{outline:2px solid var(--indigo-400, #818cf8);outline-offset:2px}.palette-item:hover{background:var(--neutral-50, #f9fafb);border-color:var(--interactive, #3b82f6);color:var(--interactive, #3b82f6);transform:translateY(-1px);box-shadow:0 2px 6px #00000014}.palette-item:active{transform:translateY(0);box-shadow:none}.palette-item.tool-item.active{background:var(--interactive, #3b82f6);border-color:var(--interactive, #3b82f6);color:#fff}.palette-item.tool-item.active:hover{background:var(--interactive-hover, #2563eb);border-color:var(--interactive-hover, #2563eb);color:#fff}.palette-divider{width:1px;background:var(--neutral-200, #e5e7eb);align-self:stretch;margin:4px 2px}.graph-canvas-wrapper{flex:1;position:relative;overflow:hidden}.graph-canvas{width:100%;height:100%;cursor:grab}.graph-canvas:active{cursor:grabbing}.graph-canvas.tool-line,.graph-canvas.tool-line .graph-node{cursor:crosshair}.graph-node{cursor:move;user-select:none;-webkit-user-select:none;transition:transform .1s ease-out}.graph-node:hover .node-bg{stroke:#cbd5e1}.graph-node text{pointer-events:none}.graph-node .node-label{font-family:system-ui,-apple-system,sans-serif}.graph-node.selected .node-bg{stroke:#3b82f6;filter:drop-shadow(0 4px 12px rgba(59,130,246,.25))}.edge-line{transition:stroke .15s,stroke-width .15s}.edge-line.selected{filter:drop-shadow(0 2px 4px rgba(59,130,246,.3))}.edge-hit-area{cursor:pointer}.edge-endpoint{cursor:pointer;transition:r .2s,fill .2s}.edge-endpoint:hover{r:8;fill:#2563eb}.edge-endpoint.selected{fill:#2563eb}.attachment-point{cursor:crosshair;transition:all .2s}.attachment-point.hovered{filter:drop-shadow(0 0 4px rgba(37,99,235,.6))}.validation-panel{position:absolute;bottom:0;left:0;right:0;max-height:200px;overflow-y:auto;background:#fff;border-top:1px solid #e5e7eb;padding:16px}.error-item{padding:8px 12px;margin-bottom:8px;background:#fee2e2;border-left:3px solid #ef4444;border-radius:4px;font-size:14px}.error-item.warning{background:#fef3c7;border-left-color:#f59e0b}.edge-direction-selector{position:absolute;transform:translate(-50%,-100%);margin-top:-12px;display:flex;gap:2px;background:#fffffff2;padding:4px;border-radius:6px;box-shadow:0 2px 8px #00000026;backdrop-filter:blur(4px);z-index:20;pointer-events:auto}.direction-btn{display:flex;align-items:center;justify-content:center;width:28px;height:28px;padding:0;border:1px solid #e5e7eb;border-radius:4px;background:#fff;cursor:pointer;font-size:16px;transition:all .15s;color:#6b7280}.direction-btn:hover{background:#f3f4f6;border-color:#3b82f6;color:#3b82f6}.direction-btn.active{background:#3b82f6;border-color:#3b82f6;color:#fff}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1486
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.19", type: GraphEditorComponent, isStandalone: true, selector: "graph-editor", inputs: { config: "config", graph: "graph", readonly: "readonly", visualizationMode: "visualizationMode", overlayData: "overlayData" }, outputs: { graphChange: "graphChange", nodeAdded: "nodeAdded", nodeUpdated: "nodeUpdated", nodeRemoved: "nodeRemoved", edgeAdded: "edgeAdded", edgeUpdated: "edgeUpdated", edgeRemoved: "edgeRemoved", selectionChange: "selectionChange", validationChange: "validationChange", nodeClick: "nodeClick", nodeDoubleClick: "nodeDoubleClick", edgeClick: "edgeClick", edgeDoubleClick: "edgeDoubleClick", canvasClick: "canvasClick", contextMenu: "contextMenu" }, host: { attributes: { "tabindex": "0" }, listeners: { "keydown": "onKeyDown($event)" }, styleAttribute: "outline: none;" }, providers: [GraphHistoryService], viewQueries: [{ propertyName: "canvasSvgRef", first: true, predicate: ["canvasSvg"], descendants: true, isSignal: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"graph-editor-container\">\n <!-- Canvas with overlaid palette -->\n <div class=\"graph-canvas-wrapper\">\n <!-- Top-left horizontal palette overlay -->\n @if (config.palette?.enabled !== false) {\n <div class=\"graph-palette-overlay\">\n <!-- Tools -->\n <button\n class=\"palette-item tool-item\"\n [class.active]=\"activeTool() === 'hand'\"\n title=\"Hand tool (move nodes)\"\n (click)=\"switchTool('hand')\"\n >\n <span class=\"icon\">\u270B</span>\n </button>\n <button\n class=\"palette-item tool-item\"\n [class.active]=\"activeTool() === 'line'\"\n title=\"Line tool (draw connections)\"\n (click)=\"switchTool('line')\"\n >\n <span class=\"icon\">\u2215</span>\n </button>\n\n <!-- Divider -->\n <div class=\"palette-divider\"></div>\n\n <!-- Node types -->\n @for (nodeType of config.nodes.types; track nodeType.type) {\n <button\n class=\"palette-item\"\n [attr.data-node-type]=\"nodeType.type\"\n [attr.title]=\"nodeType.label || nodeType.type\"\n (click)=\"addNode(nodeType.type)\"\n >\n @if (nodeType.iconSvg) {\n <svg\n class=\"palette-icon-svg\"\n [attr.viewBox]=\"nodeType.iconSvg.viewBox || '0 0 24 24'\"\n [attr.fill]=\"nodeType.iconSvg.fill || 'none'\"\n [attr.stroke]=\"nodeType.iconSvg.stroke || '#1D6A96'\"\n [attr.stroke-width]=\"nodeType.iconSvg.strokeWidth || 2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n @for (pathData of splitIconPaths(nodeType.iconSvg.path); track $index) {\n <path [attr.d]=\"pathData\"/>\n }\n </svg>\n } @else if (nodeType.defaultData['imageUrl']) {\n <img\n class=\"palette-icon-img\"\n [src]=\"nodeType.defaultData['imageUrl']\"\n [alt]=\"nodeType.label || nodeType.type\"\n />\n } @else {\n <span class=\"icon\">{{ nodeType.icon || '\u25CF' }}</span>\n }\n </button>\n }\n </div>\n }\n\n <svg\n #canvasSvg\n [class.tool-line]=\"activeTool() === 'line'\"\n [attr.width]=\"'100%'\"\n [attr.height]=\"'100%'\"\n (mousedown)=\"onCanvasMouseDown($event)\"\n (mousemove)=\"onCanvasMouseMove($event)\"\n (mouseup)=\"onCanvasMouseUp($event)\"\n (wheel)=\"onWheel($event)\"\n (contextmenu)=\"onContextMenu($event)\"\n >\n <!-- Arrow marker definitions -->\n <defs>\n <marker id=\"arrow-end\" viewBox=\"0 0 10 10\" refX=\"9\" refY=\"5\"\n markerWidth=\"8\" markerHeight=\"8\" orient=\"auto\">\n <path d=\"M 0 1 L 8 5 L 0 9 z\" fill=\"#94a3b8\"/>\n </marker>\n <marker id=\"arrow-end-selected\" viewBox=\"0 0 10 10\" refX=\"9\" refY=\"5\"\n markerWidth=\"8\" markerHeight=\"8\" orient=\"auto\">\n <path d=\"M 0 1 L 8 5 L 0 9 z\" fill=\"#3b82f6\"/>\n </marker>\n <marker id=\"arrow-start\" viewBox=\"0 0 10 10\" refX=\"1\" refY=\"5\"\n markerWidth=\"8\" markerHeight=\"8\" orient=\"auto\">\n <path d=\"M 10 1 L 2 5 L 10 9 z\" fill=\"#94a3b8\"/>\n </marker>\n <marker id=\"arrow-start-selected\" viewBox=\"0 0 10 10\" refX=\"1\" refY=\"5\"\n markerWidth=\"8\" markerHeight=\"8\" orient=\"auto\">\n <path d=\"M 10 1 L 2 5 L 10 9 z\" fill=\"#3b82f6\"/>\n </marker>\n </defs>\n\n <!-- Main transform group (pan + zoom) -->\n <g [attr.transform]=\"transform()\">\n <!-- Grid (if enabled) -->\n <!-- Grid (if enabled) - extended to cover viewport during pan -->\n @if (config.canvas?.grid?.enabled) {\n <defs>\n <pattern\n id=\"grid\"\n [attr.width]=\"config.canvas!.grid!.size\"\n [attr.height]=\"config.canvas!.grid!.size\"\n patternUnits=\"userSpaceOnUse\"\n >\n <path\n [attr.d]=\"'M ' + config.canvas!.grid!.size + ' 0 L 0 0 0 ' + config.canvas!.grid!.size\"\n fill=\"none\"\n [attr.stroke]=\"config.canvas!.grid!.color || '#e0e0e0'\"\n stroke-width=\"1\"\n />\n </pattern>\n </defs>\n <!-- Extended grid background covering viewport + pan offset -->\n <rect\n [attr.x]=\"gridBounds().x\"\n [attr.y]=\"gridBounds().y\"\n [attr.width]=\"gridBounds().width\"\n [attr.height]=\"gridBounds().height\"\n fill=\"url(#grid)\"\n />\n }\n\n <!-- Layer 0.5: Preview line for line tool (rubber-band) -->\n @if (previewLine()) {\n <line\n class=\"preview-line\"\n [attr.x1]=\"previewLine()!.source.x\"\n [attr.y1]=\"previewLine()!.source.y\"\n [attr.x2]=\"previewLine()!.target.x\"\n [attr.y2]=\"previewLine()!.target.y\"\n stroke=\"#3b82f6\"\n stroke-width=\"2.5\"\n stroke-dasharray=\"8,6\"\n stroke-linecap=\"round\"\n opacity=\"0.7\"\n />\n }\n\n <!-- Layer 1: Edge paths (behind everything) -->\n @for (edge of internalGraph().edges; track edge.id) {\n <!-- Edge shadow for depth (optional) -->\n @if (shadowsEnabled()) {\n <path\n class=\"edge-shadow\"\n [attr.d]=\"getEdgePath(edge)\"\n stroke=\"rgba(0,0,0,0.06)\"\n stroke-width=\"6\"\n fill=\"none\"\n stroke-linecap=\"round\"\n [attr.transform]=\"'translate(1, 2)'\"\n />\n }\n <!-- Invisible wide hit-area for easier clicking (hand tool only) -->\n <path\n [attr.d]=\"getEdgePath(edge)\"\n stroke=\"transparent\"\n [attr.stroke-width]=\"20\"\n fill=\"none\"\n class=\"edge-hit-area\"\n [attr.pointer-events]=\"activeTool() === 'hand' ? 'stroke' : 'none'\"\n (click)=\"onEdgeClick($event, edge)\"\n (dblclick)=\"onEdgeDoubleClick($event, edge)\"\n />\n <!-- Visible edge line -->\n <path\n class=\"edge-line\"\n [attr.d]=\"getEdgePath(edge)\"\n [attr.stroke]=\"selection().edges.includes(edge.id) ? '#3b82f6' : '#94a3b8'\"\n [attr.stroke-width]=\"selection().edges.includes(edge.id) ? 2.5 : 2\"\n fill=\"none\"\n stroke-linecap=\"round\"\n [class.selected]=\"selection().edges.includes(edge.id)\"\n [attr.marker-end]=\"getEdgeMarkerEnd(edge)\"\n [attr.marker-start]=\"getEdgeMarkerStart(edge)\"\n pointer-events=\"none\"\n />\n }\n\n <!-- Layer 2: Nodes -->\n @for (node of internalGraph().nodes; track node.id) {\n <g\n [attr.transform]=\"'translate(' + node.position.x + ',' + node.position.y + ')'\"\n class=\"graph-node\"\n [class.selected]=\"selection().nodes.includes(node.id)\"\n [attr.data-node-id]=\"node.id\"\n (mousedown)=\"onNodeMouseDown($event, node)\"\n (click)=\"onNodeClick($event, node)\"\n (dblclick)=\"nodeDoubleClick.emit(node)\"\n >\n <!-- Node shadow (optional) -->\n @if (shadowsEnabled()) {\n <rect\n class=\"node-shadow\"\n [attr.width]=\"getNodeSize(node).width\"\n [attr.height]=\"getNodeSize(node).height\"\n fill=\"rgba(0,0,0,0.08)\"\n rx=\"12\"\n transform=\"translate(2, 3)\"\n style=\"filter: blur(4px);\"\n />\n }\n <!-- Node background -->\n <rect\n class=\"node-bg\"\n [attr.width]=\"getNodeSize(node).width\"\n [attr.height]=\"getNodeSize(node).height\"\n fill=\"white\"\n [attr.stroke]=\"selection().nodes.includes(node.id) ? '#3b82f6' : '#e2e8f0'\"\n [attr.stroke-width]=\"selection().nodes.includes(node.id) ? 2.5 : 1.5\"\n rx=\"12\"\n />\n\n <!-- Node type icon (text/emoji) or custom image -->\n @if (getNodeImage(node)) {\n <image\n class=\"node-image\"\n [attr.href]=\"getNodeImage(node)\"\n [attr.xlink:href]=\"getNodeImage(node)\"\n [attr.x]=\"getImagePosition(node).x\"\n [attr.y]=\"getImagePosition(node).y\"\n [attr.width]=\"getImageSize(node)\"\n [attr.height]=\"getImageSize(node)\"\n preserveAspectRatio=\"xMidYMid meet\"\n />\n } @else {\n <text\n class=\"node-icon\"\n [attr.x]=\"getIconPosition(node).x\"\n [attr.y]=\"getIconPosition(node).y\"\n text-anchor=\"middle\"\n dominant-baseline=\"middle\"\n [attr.font-size]=\"getNodeSize(node).height * 0.28\"\n >\n {{ getNodeTypeIcon(node) }}\n </text>\n }\n\n <!-- Node label -->\n <text\n class=\"node-label\"\n [attr.x]=\"getLabelPosition(node).x\"\n [attr.y]=\"getLabelPosition(node).y\"\n text-anchor=\"middle\"\n dominant-baseline=\"middle\"\n font-size=\"14\"\n font-weight=\"500\"\n fill=\"#1e293b\"\n >\n {{ node.data['name'] || node.type }}\n </text>\n </g>\n }\n\n <!-- Layer 3: Attachment points (on top of nodes) -->\n @for (node of internalGraph().nodes; track node.id) {\n @if (showAttachmentPoints() === node.id) {\n <g [attr.transform]=\"'translate(' + node.position.x + ',' + node.position.y + ')'\">\n @for (port of getNodePorts(node); track port.position) {\n <circle\n [attr.cx]=\"port.x\"\n [attr.cy]=\"port.y\"\n [attr.r]=\"hoveredPort?.nodeId === node.id && hoveredPort?.port === port.position ? 8 : 6\"\n [attr.fill]=\"hoveredPort?.nodeId === node.id && hoveredPort?.port === port.position ? '#2563eb' : '#94a3b8'\"\n stroke=\"white\"\n stroke-width=\"2\"\n class=\"attachment-point\"\n [class.hovered]=\"hoveredPort?.nodeId === node.id && hoveredPort?.port === port.position\"\n (mousedown)=\"$event.stopPropagation()\"\n (click)=\"onAttachmentPointClick($event, node, port.position)\"\n />\n }\n </g>\n }\n }\n\n <!-- Layer 4: Edge endpoints (only visible when edge is selected) -->\n @for (edge of internalGraph().edges; track edge.id) {\n @if (selection().edges.includes(edge.id)) {\n <g>\n <!-- Source endpoint -->\n <circle\n [attr.cx]=\"getEdgeSourcePoint(edge).x\"\n [attr.cy]=\"getEdgeSourcePoint(edge).y\"\n r=\"6\"\n fill=\"#3b82f6\"\n stroke=\"white\"\n stroke-width=\"2\"\n class=\"edge-endpoint selected\"\n (mousedown)=\"onEdgeEndpointMouseDown($event, edge, 'source')\"\n />\n\n <!-- Target endpoint -->\n <circle\n [attr.cx]=\"getEdgeTargetPoint(edge).x\"\n [attr.cy]=\"getEdgeTargetPoint(edge).y\"\n r=\"6\"\n fill=\"#3b82f6\"\n stroke=\"white\"\n stroke-width=\"2\"\n class=\"edge-endpoint selected\"\n (mousedown)=\"onEdgeEndpointMouseDown($event, edge, 'target')\"\n />\n </g>\n }\n }\n\n <!-- Layer 5: Selection box (Shift+drag) -->\n @if (selectionBox()) {\n <rect\n class=\"selection-box\"\n [attr.x]=\"selectionBox()!.x\"\n [attr.y]=\"selectionBox()!.y\"\n [attr.width]=\"selectionBox()!.width\"\n [attr.height]=\"selectionBox()!.height\"\n fill=\"rgba(59, 130, 246, 0.1)\"\n stroke=\"#3b82f6\"\n stroke-width=\"1\"\n stroke-dasharray=\"4,2\"\n />\n }\n </g>\n </svg>\n </div>\n\n <!-- Edge direction selector overlay -->\n @if (selectedEdgeMidpoint()) {\n <div\n class=\"edge-direction-selector\"\n [style.left.px]=\"selectedEdgeMidpoint()!.x\"\n [style.top.px]=\"selectedEdgeMidpoint()!.y\"\n >\n <button\n class=\"direction-btn\"\n [class.active]=\"selectedEdgeMidpoint()!.edge.direction === 'backward'\"\n title=\"Backward\"\n (click)=\"setEdgeDirection('backward')\"\n >\u2190</button>\n <button\n class=\"direction-btn\"\n [class.active]=\"selectedEdgeMidpoint()!.edge.direction === 'bidirectional'\"\n title=\"Bidirectional\"\n (click)=\"setEdgeDirection('bidirectional')\"\n >\u2194</button>\n <button\n class=\"direction-btn\"\n [class.active]=\"!selectedEdgeMidpoint()!.edge.direction || selectedEdgeMidpoint()!.edge.direction === 'forward'\"\n title=\"Forward\"\n (click)=\"setEdgeDirection('forward')\"\n >\u2192</button>\n </div>\n }\n</div>\n", styles: [".graph-editor-container{display:flex;width:100%;height:100%;position:relative;background:var(--graph-editor-canvas-bg, #f8f9fa)}.graph-palette-overlay{position:absolute;top:16px;left:16px;display:flex;gap:4px;z-index:10;background:#fffffff2;padding:6px;border-radius:var(--radius-md, 8px);box-shadow:0 2px 8px #0000001a;backdrop-filter:blur(4px)}.palette-item{display:inline-flex;align-items:center;justify-content:center;width:40px;height:40px;padding:0;border:1.5px solid var(--neutral-200, #e5e7eb);border-radius:var(--radius-md, 8px);background:var(--white, #fff);color:var(--neutral-600, #4b5563);cursor:pointer;-webkit-user-select:none;user-select:none;transition:all .15s ease;font-size:20px}.palette-icon-img{width:24px;height:24px;object-fit:contain}.palette-icon-svg{width:22px;height:22px;flex-shrink:0}.palette-item:focus-visible{outline:2px solid var(--indigo-400, #818cf8);outline-offset:2px}.palette-item:hover{background:var(--neutral-50, #f9fafb);border-color:var(--interactive, #3b82f6);color:var(--interactive, #3b82f6);transform:translateY(-1px);box-shadow:0 2px 6px #00000014}.palette-item:active{transform:translateY(0);box-shadow:none}.palette-item.tool-item.active{background:var(--interactive, #3b82f6);border-color:var(--interactive, #3b82f6);color:#fff}.palette-item.tool-item.active:hover{background:var(--interactive-hover, #2563eb);border-color:var(--interactive-hover, #2563eb);color:#fff}.palette-divider{width:1px;background:var(--neutral-200, #e5e7eb);align-self:stretch;margin:4px 2px}.graph-canvas-wrapper{flex:1;position:relative;overflow:hidden}.graph-canvas{width:100%;height:100%;cursor:grab}.graph-canvas:active{cursor:grabbing}.graph-canvas.tool-line,.graph-canvas.tool-line .graph-node{cursor:crosshair}.graph-node{cursor:move;user-select:none;-webkit-user-select:none;transition:transform .1s ease-out}.graph-node:hover .node-bg{stroke:#cbd5e1}.graph-node text{pointer-events:none}.graph-node .node-label{font-family:system-ui,-apple-system,sans-serif}.graph-node.selected .node-bg{stroke:#3b82f6;filter:drop-shadow(0 4px 12px rgba(59,130,246,.25))}.edge-line{transition:stroke .15s,stroke-width .15s}.edge-line.selected{filter:drop-shadow(0 2px 4px rgba(59,130,246,.3))}.edge-hit-area{cursor:pointer}.edge-endpoint{cursor:pointer;transition:r .2s,fill .2s}.edge-endpoint:hover{r:8;fill:#2563eb}.edge-endpoint.selected{fill:#2563eb}.attachment-point{cursor:crosshair;transition:all .2s}.attachment-point.hovered{filter:drop-shadow(0 0 4px rgba(37,99,235,.6))}.validation-panel{position:absolute;bottom:0;left:0;right:0;max-height:200px;overflow-y:auto;background:#fff;border-top:1px solid #e5e7eb;padding:16px}.error-item{padding:8px 12px;margin-bottom:8px;background:#fee2e2;border-left:3px solid #ef4444;border-radius:4px;font-size:14px}.error-item.warning{background:#fef3c7;border-left-color:#f59e0b}.edge-direction-selector{position:absolute;transform:translate(-50%,-100%);margin-top:-12px;display:flex;gap:2px;background:#fffffff2;padding:4px;border-radius:6px;box-shadow:0 2px 8px #00000026;backdrop-filter:blur(4px);z-index:20;pointer-events:auto}.direction-btn{display:flex;align-items:center;justify-content:center;width:28px;height:28px;padding:0;border:1px solid #e5e7eb;border-radius:4px;background:#fff;cursor:pointer;font-size:16px;transition:all .15s;color:#6b7280}.direction-btn:hover{background:#f3f4f6;border-color:#3b82f6;color:#3b82f6}.direction-btn.active{background:#3b82f6;border-color:#3b82f6;color:#fff}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1439
1487
|
}
|
|
1440
1488
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.19", ngImport: i0, type: GraphEditorComponent, decorators: [{
|
|
1441
1489
|
type: Component,
|
|
@@ -1443,7 +1491,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.19", ngImpo
|
|
|
1443
1491
|
'tabindex': '0',
|
|
1444
1492
|
'style': 'outline: none;',
|
|
1445
1493
|
'(keydown)': 'onKeyDown($event)'
|
|
1446
|
-
}, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"graph-editor-container\">\n <!-- Canvas with overlaid palette -->\n <div class=\"graph-canvas-wrapper\">\n <!-- Top-left horizontal palette overlay -->\n @if (config.palette?.enabled !== false) {\n <div class=\"graph-palette-overlay\">\n <!-- Tools -->\n <button\n class=\"palette-item tool-item\"\n [class.active]=\"activeTool() === 'hand'\"\n title=\"Hand tool (move nodes)\"\n (click)=\"switchTool('hand')\"\n >\n <span class=\"icon\">\u270B</span>\n </button>\n <button\n class=\"palette-item tool-item\"\n [class.active]=\"activeTool() === 'line'\"\n title=\"Line tool (draw connections)\"\n (click)=\"switchTool('line')\"\n >\n <span class=\"icon\">\u2215</span>\n </button>\n\n <!-- Divider -->\n <div class=\"palette-divider\"></div>\n\n <!-- Node types -->\n @for (nodeType of config.nodes.types; track nodeType.type) {\n <button\n class=\"palette-item\"\n [attr.data-node-type]=\"nodeType.type\"\n [attr.title]=\"nodeType.label || nodeType.type\"\n (click)=\"addNode(nodeType.type)\"\n >\n @if (nodeType.defaultData['imageUrl']) {\n <img\n class=\"palette-icon-img\"\n [src]=\"nodeType.defaultData['imageUrl']\"\n [alt]=\"nodeType.label || nodeType.type\"\n />\n } @else {\n <span class=\"icon\">{{ nodeType.icon || '\u25CF' }}</span>\n }\n </button>\n }\n </div>\n }\n\n <svg\n #canvasSvg\n [class.tool-line]=\"activeTool() === 'line'\"\n [attr.width]=\"'100%'\"\n [attr.height]=\"'100%'\"\n (mousedown)=\"onCanvasMouseDown($event)\"\n (mousemove)=\"onCanvasMouseMove($event)\"\n (mouseup)=\"onCanvasMouseUp($event)\"\n (wheel)=\"onWheel($event)\"\n (contextmenu)=\"onContextMenu($event)\"\n >\n <!-- Arrow marker definitions -->\n <defs>\n <marker id=\"arrow-end\" viewBox=\"0 0 10 10\" refX=\"9\" refY=\"5\"\n markerWidth=\"8\" markerHeight=\"8\" orient=\"auto\">\n <path d=\"M 0 1 L 8 5 L 0 9 z\" fill=\"#94a3b8\"/>\n </marker>\n <marker id=\"arrow-end-selected\" viewBox=\"0 0 10 10\" refX=\"9\" refY=\"5\"\n markerWidth=\"8\" markerHeight=\"8\" orient=\"auto\">\n <path d=\"M 0 1 L 8 5 L 0 9 z\" fill=\"#3b82f6\"/>\n </marker>\n <marker id=\"arrow-start\" viewBox=\"0 0 10 10\" refX=\"1\" refY=\"5\"\n markerWidth=\"8\" markerHeight=\"8\" orient=\"auto\">\n <path d=\"M 10 1 L 2 5 L 10 9 z\" fill=\"#94a3b8\"/>\n </marker>\n <marker id=\"arrow-start-selected\" viewBox=\"0 0 10 10\" refX=\"1\" refY=\"5\"\n markerWidth=\"8\" markerHeight=\"8\" orient=\"auto\">\n <path d=\"M 10 1 L 2 5 L 10 9 z\" fill=\"#3b82f6\"/>\n </marker>\n </defs>\n\n <!-- Main transform group (pan + zoom) -->\n <g [attr.transform]=\"transform()\">\n <!-- Grid (if enabled) -->\n <!-- Grid (if enabled) - extended to cover viewport during pan -->\n @if (config.canvas?.grid?.enabled) {\n <defs>\n <pattern\n id=\"grid\"\n [attr.width]=\"config.canvas!.grid!.size\"\n [attr.height]=\"config.canvas!.grid!.size\"\n patternUnits=\"userSpaceOnUse\"\n >\n <path\n [attr.d]=\"'M ' + config.canvas!.grid!.size + ' 0 L 0 0 0 ' + config.canvas!.grid!.size\"\n fill=\"none\"\n [attr.stroke]=\"config.canvas!.grid!.color || '#e0e0e0'\"\n stroke-width=\"1\"\n />\n </pattern>\n </defs>\n <!-- Extended grid background covering viewport + pan offset -->\n <rect\n [attr.x]=\"gridBounds().x\"\n [attr.y]=\"gridBounds().y\"\n [attr.width]=\"gridBounds().width\"\n [attr.height]=\"gridBounds().height\"\n fill=\"url(#grid)\"\n />\n }\n\n <!-- Layer 0.5: Preview line for line tool (rubber-band) -->\n @if (previewLine()) {\n <line\n class=\"preview-line\"\n [attr.x1]=\"previewLine()!.source.x\"\n [attr.y1]=\"previewLine()!.source.y\"\n [attr.x2]=\"previewLine()!.target.x\"\n [attr.y2]=\"previewLine()!.target.y\"\n stroke=\"#3b82f6\"\n stroke-width=\"2.5\"\n stroke-dasharray=\"8,6\"\n stroke-linecap=\"round\"\n opacity=\"0.7\"\n />\n }\n\n <!-- Layer 1: Edge paths (behind everything) -->\n @for (edge of internalGraph().edges; track edge.id) {\n <!-- Edge shadow for depth (optional) -->\n @if (shadowsEnabled()) {\n <path\n class=\"edge-shadow\"\n [attr.d]=\"getEdgePath(edge)\"\n stroke=\"rgba(0,0,0,0.06)\"\n stroke-width=\"6\"\n fill=\"none\"\n stroke-linecap=\"round\"\n [attr.transform]=\"'translate(1, 2)'\"\n />\n }\n <!-- Invisible wide hit-area for easier clicking (hand tool only) -->\n <path\n [attr.d]=\"getEdgePath(edge)\"\n stroke=\"transparent\"\n [attr.stroke-width]=\"20\"\n fill=\"none\"\n class=\"edge-hit-area\"\n [attr.pointer-events]=\"activeTool() === 'hand' ? 'stroke' : 'none'\"\n (click)=\"onEdgeClick($event, edge)\"\n (dblclick)=\"onEdgeDoubleClick($event, edge)\"\n />\n <!-- Visible edge line -->\n <path\n class=\"edge-line\"\n [attr.d]=\"getEdgePath(edge)\"\n [attr.stroke]=\"selection().edges.includes(edge.id) ? '#3b82f6' : '#94a3b8'\"\n [attr.stroke-width]=\"selection().edges.includes(edge.id) ? 2.5 : 2\"\n fill=\"none\"\n stroke-linecap=\"round\"\n [class.selected]=\"selection().edges.includes(edge.id)\"\n [attr.marker-end]=\"getEdgeMarkerEnd(edge)\"\n [attr.marker-start]=\"getEdgeMarkerStart(edge)\"\n pointer-events=\"none\"\n />\n }\n\n <!-- Layer 2: Nodes -->\n @for (node of internalGraph().nodes; track node.id) {\n <g\n [attr.transform]=\"'translate(' + node.position.x + ',' + node.position.y + ')'\"\n class=\"graph-node\"\n [class.selected]=\"selection().nodes.includes(node.id)\"\n [attr.data-node-id]=\"node.id\"\n (mousedown)=\"onNodeMouseDown($event, node)\"\n (click)=\"onNodeClick($event, node)\"\n (dblclick)=\"nodeDoubleClick.emit(node)\"\n >\n <!-- Node shadow (optional) -->\n @if (shadowsEnabled()) {\n <rect\n class=\"node-shadow\"\n [attr.width]=\"getNodeSize(node).width\"\n [attr.height]=\"getNodeSize(node).height\"\n fill=\"rgba(0,0,0,0.08)\"\n rx=\"12\"\n transform=\"translate(2, 3)\"\n style=\"filter: blur(4px);\"\n />\n }\n <!-- Node background -->\n <rect\n class=\"node-bg\"\n [attr.width]=\"getNodeSize(node).width\"\n [attr.height]=\"getNodeSize(node).height\"\n fill=\"white\"\n [attr.stroke]=\"selection().nodes.includes(node.id) ? '#3b82f6' : '#e2e8f0'\"\n [attr.stroke-width]=\"selection().nodes.includes(node.id) ? 2.5 : 1.5\"\n rx=\"12\"\n />\n\n <!-- Node type icon (text/emoji) or custom image -->\n @if (getNodeImage(node)) {\n <image\n class=\"node-image\"\n [attr.href]=\"getNodeImage(node)\"\n [attr.xlink:href]=\"getNodeImage(node)\"\n [attr.x]=\"getImagePosition(node).x\"\n [attr.y]=\"getImagePosition(node).y\"\n [attr.width]=\"getImageSize(node)\"\n [attr.height]=\"getImageSize(node)\"\n preserveAspectRatio=\"xMidYMid meet\"\n />\n } @else {\n <text\n class=\"node-icon\"\n [attr.x]=\"getIconPosition(node).x\"\n [attr.y]=\"getIconPosition(node).y\"\n text-anchor=\"middle\"\n dominant-baseline=\"middle\"\n [attr.font-size]=\"getNodeSize(node).height * 0.28\"\n >\n {{ getNodeTypeIcon(node) }}\n </text>\n }\n\n <!-- Node label -->\n <text\n class=\"node-label\"\n [attr.x]=\"getLabelPosition(node).x\"\n [attr.y]=\"getLabelPosition(node).y\"\n text-anchor=\"middle\"\n dominant-baseline=\"middle\"\n font-size=\"14\"\n font-weight=\"500\"\n fill=\"#1e293b\"\n >\n {{ node.data['name'] || node.type }}\n </text>\n </g>\n }\n\n <!-- Layer 3: Attachment points (on top of nodes) -->\n @for (node of internalGraph().nodes; track node.id) {\n @if (showAttachmentPoints() === node.id) {\n <g [attr.transform]=\"'translate(' + node.position.x + ',' + node.position.y + ')'\">\n @for (port of getNodePorts(node); track port.position) {\n <circle\n [attr.cx]=\"port.x\"\n [attr.cy]=\"port.y\"\n [attr.r]=\"hoveredPort?.nodeId === node.id && hoveredPort?.port === port.position ? 8 : 6\"\n [attr.fill]=\"hoveredPort?.nodeId === node.id && hoveredPort?.port === port.position ? '#2563eb' : '#94a3b8'\"\n stroke=\"white\"\n stroke-width=\"2\"\n class=\"attachment-point\"\n [class.hovered]=\"hoveredPort?.nodeId === node.id && hoveredPort?.port === port.position\"\n (mousedown)=\"$event.stopPropagation()\"\n (click)=\"onAttachmentPointClick($event, node, port.position)\"\n />\n }\n </g>\n }\n }\n\n <!-- Layer 4: Edge endpoints (only visible when edge is selected) -->\n @for (edge of internalGraph().edges; track edge.id) {\n @if (selection().edges.includes(edge.id)) {\n <g>\n <!-- Source endpoint -->\n <circle\n [attr.cx]=\"getEdgeSourcePoint(edge).x\"\n [attr.cy]=\"getEdgeSourcePoint(edge).y\"\n r=\"6\"\n fill=\"#3b82f6\"\n stroke=\"white\"\n stroke-width=\"2\"\n class=\"edge-endpoint selected\"\n (mousedown)=\"onEdgeEndpointMouseDown($event, edge, 'source')\"\n />\n\n <!-- Target endpoint -->\n <circle\n [attr.cx]=\"getEdgeTargetPoint(edge).x\"\n [attr.cy]=\"getEdgeTargetPoint(edge).y\"\n r=\"6\"\n fill=\"#3b82f6\"\n stroke=\"white\"\n stroke-width=\"2\"\n class=\"edge-endpoint selected\"\n (mousedown)=\"onEdgeEndpointMouseDown($event, edge, 'target')\"\n />\n </g>\n }\n }\n\n <!-- Layer 5: Selection box (Shift+drag) -->\n @if (selectionBox()) {\n <rect\n class=\"selection-box\"\n [attr.x]=\"selectionBox()!.x\"\n [attr.y]=\"selectionBox()!.y\"\n [attr.width]=\"selectionBox()!.width\"\n [attr.height]=\"selectionBox()!.height\"\n fill=\"rgba(59, 130, 246, 0.1)\"\n stroke=\"#3b82f6\"\n stroke-width=\"1\"\n stroke-dasharray=\"4,2\"\n />\n }\n </g>\n </svg>\n </div>\n\n <!-- Edge direction selector overlay -->\n @if (selectedEdgeMidpoint()) {\n <div\n class=\"edge-direction-selector\"\n [style.left.px]=\"selectedEdgeMidpoint()!.x\"\n [style.top.px]=\"selectedEdgeMidpoint()!.y\"\n >\n <button\n class=\"direction-btn\"\n [class.active]=\"selectedEdgeMidpoint()!.edge.direction === 'backward'\"\n title=\"Backward\"\n (click)=\"setEdgeDirection('backward')\"\n >\u2190</button>\n <button\n class=\"direction-btn\"\n [class.active]=\"selectedEdgeMidpoint()!.edge.direction === 'bidirectional'\"\n title=\"Bidirectional\"\n (click)=\"setEdgeDirection('bidirectional')\"\n >\u2194</button>\n <button\n class=\"direction-btn\"\n [class.active]=\"!selectedEdgeMidpoint()!.edge.direction || selectedEdgeMidpoint()!.edge.direction === 'forward'\"\n title=\"Forward\"\n (click)=\"setEdgeDirection('forward')\"\n >\u2192</button>\n </div>\n }\n <!-- Validation errors -->\n @if (validationResult() && !validationResult()!.valid) {\n <div class=\"validation-panel\">\n <h4>Validation Errors</h4>\n @for (error of validationResult()!.errors; track error.rule) {\n <div class=\"error-item\" [class.warning]=\"error.severity === 'warning'\">\n {{ error.message }}\n </div>\n }\n </div>\n }\n</div>\n", styles: [".graph-editor-container{display:flex;width:100%;height:100%;position:relative;background:var(--graph-editor-canvas-bg, #f8f9fa)}.graph-palette-overlay{position:absolute;top:16px;left:16px;display:flex;gap:4px;z-index:10;background:#fffffff2;padding:6px;border-radius:var(--radius-md, 8px);box-shadow:0 2px 8px #0000001a;backdrop-filter:blur(4px)}.palette-item{display:inline-flex;align-items:center;justify-content:center;width:40px;height:40px;padding:0;border:1.5px solid var(--neutral-200, #e5e7eb);border-radius:var(--radius-md, 8px);background:var(--white, #fff);color:var(--neutral-600, #4b5563);cursor:pointer;-webkit-user-select:none;user-select:none;transition:all .15s ease;font-size:20px}.palette-icon-img{width:24px;height:24px;object-fit:contain}.palette-item:focus-visible{outline:2px solid var(--indigo-400, #818cf8);outline-offset:2px}.palette-item:hover{background:var(--neutral-50, #f9fafb);border-color:var(--interactive, #3b82f6);color:var(--interactive, #3b82f6);transform:translateY(-1px);box-shadow:0 2px 6px #00000014}.palette-item:active{transform:translateY(0);box-shadow:none}.palette-item.tool-item.active{background:var(--interactive, #3b82f6);border-color:var(--interactive, #3b82f6);color:#fff}.palette-item.tool-item.active:hover{background:var(--interactive-hover, #2563eb);border-color:var(--interactive-hover, #2563eb);color:#fff}.palette-divider{width:1px;background:var(--neutral-200, #e5e7eb);align-self:stretch;margin:4px 2px}.graph-canvas-wrapper{flex:1;position:relative;overflow:hidden}.graph-canvas{width:100%;height:100%;cursor:grab}.graph-canvas:active{cursor:grabbing}.graph-canvas.tool-line,.graph-canvas.tool-line .graph-node{cursor:crosshair}.graph-node{cursor:move;user-select:none;-webkit-user-select:none;transition:transform .1s ease-out}.graph-node:hover .node-bg{stroke:#cbd5e1}.graph-node text{pointer-events:none}.graph-node .node-label{font-family:system-ui,-apple-system,sans-serif}.graph-node.selected .node-bg{stroke:#3b82f6;filter:drop-shadow(0 4px 12px rgba(59,130,246,.25))}.edge-line{transition:stroke .15s,stroke-width .15s}.edge-line.selected{filter:drop-shadow(0 2px 4px rgba(59,130,246,.3))}.edge-hit-area{cursor:pointer}.edge-endpoint{cursor:pointer;transition:r .2s,fill .2s}.edge-endpoint:hover{r:8;fill:#2563eb}.edge-endpoint.selected{fill:#2563eb}.attachment-point{cursor:crosshair;transition:all .2s}.attachment-point.hovered{filter:drop-shadow(0 0 4px rgba(37,99,235,.6))}.validation-panel{position:absolute;bottom:0;left:0;right:0;max-height:200px;overflow-y:auto;background:#fff;border-top:1px solid #e5e7eb;padding:16px}.error-item{padding:8px 12px;margin-bottom:8px;background:#fee2e2;border-left:3px solid #ef4444;border-radius:4px;font-size:14px}.error-item.warning{background:#fef3c7;border-left-color:#f59e0b}.edge-direction-selector{position:absolute;transform:translate(-50%,-100%);margin-top:-12px;display:flex;gap:2px;background:#fffffff2;padding:4px;border-radius:6px;box-shadow:0 2px 8px #00000026;backdrop-filter:blur(4px);z-index:20;pointer-events:auto}.direction-btn{display:flex;align-items:center;justify-content:center;width:28px;height:28px;padding:0;border:1px solid #e5e7eb;border-radius:4px;background:#fff;cursor:pointer;font-size:16px;transition:all .15s;color:#6b7280}.direction-btn:hover{background:#f3f4f6;border-color:#3b82f6;color:#3b82f6}.direction-btn.active{background:#3b82f6;border-color:#3b82f6;color:#fff}\n"] }]
|
|
1494
|
+
}, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"graph-editor-container\">\n <!-- Canvas with overlaid palette -->\n <div class=\"graph-canvas-wrapper\">\n <!-- Top-left horizontal palette overlay -->\n @if (config.palette?.enabled !== false) {\n <div class=\"graph-palette-overlay\">\n <!-- Tools -->\n <button\n class=\"palette-item tool-item\"\n [class.active]=\"activeTool() === 'hand'\"\n title=\"Hand tool (move nodes)\"\n (click)=\"switchTool('hand')\"\n >\n <span class=\"icon\">\u270B</span>\n </button>\n <button\n class=\"palette-item tool-item\"\n [class.active]=\"activeTool() === 'line'\"\n title=\"Line tool (draw connections)\"\n (click)=\"switchTool('line')\"\n >\n <span class=\"icon\">\u2215</span>\n </button>\n\n <!-- Divider -->\n <div class=\"palette-divider\"></div>\n\n <!-- Node types -->\n @for (nodeType of config.nodes.types; track nodeType.type) {\n <button\n class=\"palette-item\"\n [attr.data-node-type]=\"nodeType.type\"\n [attr.title]=\"nodeType.label || nodeType.type\"\n (click)=\"addNode(nodeType.type)\"\n >\n @if (nodeType.iconSvg) {\n <svg\n class=\"palette-icon-svg\"\n [attr.viewBox]=\"nodeType.iconSvg.viewBox || '0 0 24 24'\"\n [attr.fill]=\"nodeType.iconSvg.fill || 'none'\"\n [attr.stroke]=\"nodeType.iconSvg.stroke || '#1D6A96'\"\n [attr.stroke-width]=\"nodeType.iconSvg.strokeWidth || 2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n @for (pathData of splitIconPaths(nodeType.iconSvg.path); track $index) {\n <path [attr.d]=\"pathData\"/>\n }\n </svg>\n } @else if (nodeType.defaultData['imageUrl']) {\n <img\n class=\"palette-icon-img\"\n [src]=\"nodeType.defaultData['imageUrl']\"\n [alt]=\"nodeType.label || nodeType.type\"\n />\n } @else {\n <span class=\"icon\">{{ nodeType.icon || '\u25CF' }}</span>\n }\n </button>\n }\n </div>\n }\n\n <svg\n #canvasSvg\n [class.tool-line]=\"activeTool() === 'line'\"\n [attr.width]=\"'100%'\"\n [attr.height]=\"'100%'\"\n (mousedown)=\"onCanvasMouseDown($event)\"\n (mousemove)=\"onCanvasMouseMove($event)\"\n (mouseup)=\"onCanvasMouseUp($event)\"\n (wheel)=\"onWheel($event)\"\n (contextmenu)=\"onContextMenu($event)\"\n >\n <!-- Arrow marker definitions -->\n <defs>\n <marker id=\"arrow-end\" viewBox=\"0 0 10 10\" refX=\"9\" refY=\"5\"\n markerWidth=\"8\" markerHeight=\"8\" orient=\"auto\">\n <path d=\"M 0 1 L 8 5 L 0 9 z\" fill=\"#94a3b8\"/>\n </marker>\n <marker id=\"arrow-end-selected\" viewBox=\"0 0 10 10\" refX=\"9\" refY=\"5\"\n markerWidth=\"8\" markerHeight=\"8\" orient=\"auto\">\n <path d=\"M 0 1 L 8 5 L 0 9 z\" fill=\"#3b82f6\"/>\n </marker>\n <marker id=\"arrow-start\" viewBox=\"0 0 10 10\" refX=\"1\" refY=\"5\"\n markerWidth=\"8\" markerHeight=\"8\" orient=\"auto\">\n <path d=\"M 10 1 L 2 5 L 10 9 z\" fill=\"#94a3b8\"/>\n </marker>\n <marker id=\"arrow-start-selected\" viewBox=\"0 0 10 10\" refX=\"1\" refY=\"5\"\n markerWidth=\"8\" markerHeight=\"8\" orient=\"auto\">\n <path d=\"M 10 1 L 2 5 L 10 9 z\" fill=\"#3b82f6\"/>\n </marker>\n </defs>\n\n <!-- Main transform group (pan + zoom) -->\n <g [attr.transform]=\"transform()\">\n <!-- Grid (if enabled) -->\n <!-- Grid (if enabled) - extended to cover viewport during pan -->\n @if (config.canvas?.grid?.enabled) {\n <defs>\n <pattern\n id=\"grid\"\n [attr.width]=\"config.canvas!.grid!.size\"\n [attr.height]=\"config.canvas!.grid!.size\"\n patternUnits=\"userSpaceOnUse\"\n >\n <path\n [attr.d]=\"'M ' + config.canvas!.grid!.size + ' 0 L 0 0 0 ' + config.canvas!.grid!.size\"\n fill=\"none\"\n [attr.stroke]=\"config.canvas!.grid!.color || '#e0e0e0'\"\n stroke-width=\"1\"\n />\n </pattern>\n </defs>\n <!-- Extended grid background covering viewport + pan offset -->\n <rect\n [attr.x]=\"gridBounds().x\"\n [attr.y]=\"gridBounds().y\"\n [attr.width]=\"gridBounds().width\"\n [attr.height]=\"gridBounds().height\"\n fill=\"url(#grid)\"\n />\n }\n\n <!-- Layer 0.5: Preview line for line tool (rubber-band) -->\n @if (previewLine()) {\n <line\n class=\"preview-line\"\n [attr.x1]=\"previewLine()!.source.x\"\n [attr.y1]=\"previewLine()!.source.y\"\n [attr.x2]=\"previewLine()!.target.x\"\n [attr.y2]=\"previewLine()!.target.y\"\n stroke=\"#3b82f6\"\n stroke-width=\"2.5\"\n stroke-dasharray=\"8,6\"\n stroke-linecap=\"round\"\n opacity=\"0.7\"\n />\n }\n\n <!-- Layer 1: Edge paths (behind everything) -->\n @for (edge of internalGraph().edges; track edge.id) {\n <!-- Edge shadow for depth (optional) -->\n @if (shadowsEnabled()) {\n <path\n class=\"edge-shadow\"\n [attr.d]=\"getEdgePath(edge)\"\n stroke=\"rgba(0,0,0,0.06)\"\n stroke-width=\"6\"\n fill=\"none\"\n stroke-linecap=\"round\"\n [attr.transform]=\"'translate(1, 2)'\"\n />\n }\n <!-- Invisible wide hit-area for easier clicking (hand tool only) -->\n <path\n [attr.d]=\"getEdgePath(edge)\"\n stroke=\"transparent\"\n [attr.stroke-width]=\"20\"\n fill=\"none\"\n class=\"edge-hit-area\"\n [attr.pointer-events]=\"activeTool() === 'hand' ? 'stroke' : 'none'\"\n (click)=\"onEdgeClick($event, edge)\"\n (dblclick)=\"onEdgeDoubleClick($event, edge)\"\n />\n <!-- Visible edge line -->\n <path\n class=\"edge-line\"\n [attr.d]=\"getEdgePath(edge)\"\n [attr.stroke]=\"selection().edges.includes(edge.id) ? '#3b82f6' : '#94a3b8'\"\n [attr.stroke-width]=\"selection().edges.includes(edge.id) ? 2.5 : 2\"\n fill=\"none\"\n stroke-linecap=\"round\"\n [class.selected]=\"selection().edges.includes(edge.id)\"\n [attr.marker-end]=\"getEdgeMarkerEnd(edge)\"\n [attr.marker-start]=\"getEdgeMarkerStart(edge)\"\n pointer-events=\"none\"\n />\n }\n\n <!-- Layer 2: Nodes -->\n @for (node of internalGraph().nodes; track node.id) {\n <g\n [attr.transform]=\"'translate(' + node.position.x + ',' + node.position.y + ')'\"\n class=\"graph-node\"\n [class.selected]=\"selection().nodes.includes(node.id)\"\n [attr.data-node-id]=\"node.id\"\n (mousedown)=\"onNodeMouseDown($event, node)\"\n (click)=\"onNodeClick($event, node)\"\n (dblclick)=\"nodeDoubleClick.emit(node)\"\n >\n <!-- Node shadow (optional) -->\n @if (shadowsEnabled()) {\n <rect\n class=\"node-shadow\"\n [attr.width]=\"getNodeSize(node).width\"\n [attr.height]=\"getNodeSize(node).height\"\n fill=\"rgba(0,0,0,0.08)\"\n rx=\"12\"\n transform=\"translate(2, 3)\"\n style=\"filter: blur(4px);\"\n />\n }\n <!-- Node background -->\n <rect\n class=\"node-bg\"\n [attr.width]=\"getNodeSize(node).width\"\n [attr.height]=\"getNodeSize(node).height\"\n fill=\"white\"\n [attr.stroke]=\"selection().nodes.includes(node.id) ? '#3b82f6' : '#e2e8f0'\"\n [attr.stroke-width]=\"selection().nodes.includes(node.id) ? 2.5 : 1.5\"\n rx=\"12\"\n />\n\n <!-- Node type icon (text/emoji) or custom image -->\n @if (getNodeImage(node)) {\n <image\n class=\"node-image\"\n [attr.href]=\"getNodeImage(node)\"\n [attr.xlink:href]=\"getNodeImage(node)\"\n [attr.x]=\"getImagePosition(node).x\"\n [attr.y]=\"getImagePosition(node).y\"\n [attr.width]=\"getImageSize(node)\"\n [attr.height]=\"getImageSize(node)\"\n preserveAspectRatio=\"xMidYMid meet\"\n />\n } @else {\n <text\n class=\"node-icon\"\n [attr.x]=\"getIconPosition(node).x\"\n [attr.y]=\"getIconPosition(node).y\"\n text-anchor=\"middle\"\n dominant-baseline=\"middle\"\n [attr.font-size]=\"getNodeSize(node).height * 0.28\"\n >\n {{ getNodeTypeIcon(node) }}\n </text>\n }\n\n <!-- Node label -->\n <text\n class=\"node-label\"\n [attr.x]=\"getLabelPosition(node).x\"\n [attr.y]=\"getLabelPosition(node).y\"\n text-anchor=\"middle\"\n dominant-baseline=\"middle\"\n font-size=\"14\"\n font-weight=\"500\"\n fill=\"#1e293b\"\n >\n {{ node.data['name'] || node.type }}\n </text>\n </g>\n }\n\n <!-- Layer 3: Attachment points (on top of nodes) -->\n @for (node of internalGraph().nodes; track node.id) {\n @if (showAttachmentPoints() === node.id) {\n <g [attr.transform]=\"'translate(' + node.position.x + ',' + node.position.y + ')'\">\n @for (port of getNodePorts(node); track port.position) {\n <circle\n [attr.cx]=\"port.x\"\n [attr.cy]=\"port.y\"\n [attr.r]=\"hoveredPort?.nodeId === node.id && hoveredPort?.port === port.position ? 8 : 6\"\n [attr.fill]=\"hoveredPort?.nodeId === node.id && hoveredPort?.port === port.position ? '#2563eb' : '#94a3b8'\"\n stroke=\"white\"\n stroke-width=\"2\"\n class=\"attachment-point\"\n [class.hovered]=\"hoveredPort?.nodeId === node.id && hoveredPort?.port === port.position\"\n (mousedown)=\"$event.stopPropagation()\"\n (click)=\"onAttachmentPointClick($event, node, port.position)\"\n />\n }\n </g>\n }\n }\n\n <!-- Layer 4: Edge endpoints (only visible when edge is selected) -->\n @for (edge of internalGraph().edges; track edge.id) {\n @if (selection().edges.includes(edge.id)) {\n <g>\n <!-- Source endpoint -->\n <circle\n [attr.cx]=\"getEdgeSourcePoint(edge).x\"\n [attr.cy]=\"getEdgeSourcePoint(edge).y\"\n r=\"6\"\n fill=\"#3b82f6\"\n stroke=\"white\"\n stroke-width=\"2\"\n class=\"edge-endpoint selected\"\n (mousedown)=\"onEdgeEndpointMouseDown($event, edge, 'source')\"\n />\n\n <!-- Target endpoint -->\n <circle\n [attr.cx]=\"getEdgeTargetPoint(edge).x\"\n [attr.cy]=\"getEdgeTargetPoint(edge).y\"\n r=\"6\"\n fill=\"#3b82f6\"\n stroke=\"white\"\n stroke-width=\"2\"\n class=\"edge-endpoint selected\"\n (mousedown)=\"onEdgeEndpointMouseDown($event, edge, 'target')\"\n />\n </g>\n }\n }\n\n <!-- Layer 5: Selection box (Shift+drag) -->\n @if (selectionBox()) {\n <rect\n class=\"selection-box\"\n [attr.x]=\"selectionBox()!.x\"\n [attr.y]=\"selectionBox()!.y\"\n [attr.width]=\"selectionBox()!.width\"\n [attr.height]=\"selectionBox()!.height\"\n fill=\"rgba(59, 130, 246, 0.1)\"\n stroke=\"#3b82f6\"\n stroke-width=\"1\"\n stroke-dasharray=\"4,2\"\n />\n }\n </g>\n </svg>\n </div>\n\n <!-- Edge direction selector overlay -->\n @if (selectedEdgeMidpoint()) {\n <div\n class=\"edge-direction-selector\"\n [style.left.px]=\"selectedEdgeMidpoint()!.x\"\n [style.top.px]=\"selectedEdgeMidpoint()!.y\"\n >\n <button\n class=\"direction-btn\"\n [class.active]=\"selectedEdgeMidpoint()!.edge.direction === 'backward'\"\n title=\"Backward\"\n (click)=\"setEdgeDirection('backward')\"\n >\u2190</button>\n <button\n class=\"direction-btn\"\n [class.active]=\"selectedEdgeMidpoint()!.edge.direction === 'bidirectional'\"\n title=\"Bidirectional\"\n (click)=\"setEdgeDirection('bidirectional')\"\n >\u2194</button>\n <button\n class=\"direction-btn\"\n [class.active]=\"!selectedEdgeMidpoint()!.edge.direction || selectedEdgeMidpoint()!.edge.direction === 'forward'\"\n title=\"Forward\"\n (click)=\"setEdgeDirection('forward')\"\n >\u2192</button>\n </div>\n }\n</div>\n", styles: [".graph-editor-container{display:flex;width:100%;height:100%;position:relative;background:var(--graph-editor-canvas-bg, #f8f9fa)}.graph-palette-overlay{position:absolute;top:16px;left:16px;display:flex;gap:4px;z-index:10;background:#fffffff2;padding:6px;border-radius:var(--radius-md, 8px);box-shadow:0 2px 8px #0000001a;backdrop-filter:blur(4px)}.palette-item{display:inline-flex;align-items:center;justify-content:center;width:40px;height:40px;padding:0;border:1.5px solid var(--neutral-200, #e5e7eb);border-radius:var(--radius-md, 8px);background:var(--white, #fff);color:var(--neutral-600, #4b5563);cursor:pointer;-webkit-user-select:none;user-select:none;transition:all .15s ease;font-size:20px}.palette-icon-img{width:24px;height:24px;object-fit:contain}.palette-icon-svg{width:22px;height:22px;flex-shrink:0}.palette-item:focus-visible{outline:2px solid var(--indigo-400, #818cf8);outline-offset:2px}.palette-item:hover{background:var(--neutral-50, #f9fafb);border-color:var(--interactive, #3b82f6);color:var(--interactive, #3b82f6);transform:translateY(-1px);box-shadow:0 2px 6px #00000014}.palette-item:active{transform:translateY(0);box-shadow:none}.palette-item.tool-item.active{background:var(--interactive, #3b82f6);border-color:var(--interactive, #3b82f6);color:#fff}.palette-item.tool-item.active:hover{background:var(--interactive-hover, #2563eb);border-color:var(--interactive-hover, #2563eb);color:#fff}.palette-divider{width:1px;background:var(--neutral-200, #e5e7eb);align-self:stretch;margin:4px 2px}.graph-canvas-wrapper{flex:1;position:relative;overflow:hidden}.graph-canvas{width:100%;height:100%;cursor:grab}.graph-canvas:active{cursor:grabbing}.graph-canvas.tool-line,.graph-canvas.tool-line .graph-node{cursor:crosshair}.graph-node{cursor:move;user-select:none;-webkit-user-select:none;transition:transform .1s ease-out}.graph-node:hover .node-bg{stroke:#cbd5e1}.graph-node text{pointer-events:none}.graph-node .node-label{font-family:system-ui,-apple-system,sans-serif}.graph-node.selected .node-bg{stroke:#3b82f6;filter:drop-shadow(0 4px 12px rgba(59,130,246,.25))}.edge-line{transition:stroke .15s,stroke-width .15s}.edge-line.selected{filter:drop-shadow(0 2px 4px rgba(59,130,246,.3))}.edge-hit-area{cursor:pointer}.edge-endpoint{cursor:pointer;transition:r .2s,fill .2s}.edge-endpoint:hover{r:8;fill:#2563eb}.edge-endpoint.selected{fill:#2563eb}.attachment-point{cursor:crosshair;transition:all .2s}.attachment-point.hovered{filter:drop-shadow(0 0 4px rgba(37,99,235,.6))}.validation-panel{position:absolute;bottom:0;left:0;right:0;max-height:200px;overflow-y:auto;background:#fff;border-top:1px solid #e5e7eb;padding:16px}.error-item{padding:8px 12px;margin-bottom:8px;background:#fee2e2;border-left:3px solid #ef4444;border-radius:4px;font-size:14px}.error-item.warning{background:#fef3c7;border-left-color:#f59e0b}.edge-direction-selector{position:absolute;transform:translate(-50%,-100%);margin-top:-12px;display:flex;gap:2px;background:#fffffff2;padding:4px;border-radius:6px;box-shadow:0 2px 8px #00000026;backdrop-filter:blur(4px);z-index:20;pointer-events:auto}.direction-btn{display:flex;align-items:center;justify-content:center;width:28px;height:28px;padding:0;border:1px solid #e5e7eb;border-radius:4px;background:#fff;cursor:pointer;font-size:16px;transition:all .15s;color:#6b7280}.direction-btn:hover{background:#f3f4f6;border-color:#3b82f6;color:#3b82f6}.direction-btn.active{background:#3b82f6;border-color:#3b82f6;color:#fff}\n"] }]
|
|
1447
1495
|
}], ctorParameters: () => [], propDecorators: { config: [{
|
|
1448
1496
|
type: Input,
|
|
1449
1497
|
args: [{ required: true }]
|
|
@@ -1487,11 +1535,29 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.19", ngImpo
|
|
|
1487
1535
|
type: Output
|
|
1488
1536
|
}] } });
|
|
1489
1537
|
|
|
1538
|
+
/**
|
|
1539
|
+
* Generate inline SVG markup for an icon (for use in palette/toolbar)
|
|
1540
|
+
*/
|
|
1541
|
+
function renderIconSvg(icon, size = 24) {
|
|
1542
|
+
const viewBox = icon.viewBox || '0 0 24 24';
|
|
1543
|
+
const fill = icon.fill || 'none';
|
|
1544
|
+
const stroke = icon.stroke || 'currentColor';
|
|
1545
|
+
const strokeWidth = icon.strokeWidth || 2;
|
|
1546
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" viewBox="${viewBox}" fill="${fill}" stroke="${stroke}" stroke-width="${strokeWidth}" stroke-linecap="round" stroke-linejoin="round">${icon.path.split('\n').map(p => `<path d="${p.trim()}"/>`).join('')}</svg>`;
|
|
1547
|
+
}
|
|
1548
|
+
/**
|
|
1549
|
+
* Generate data URL for an icon (for use as image source)
|
|
1550
|
+
*/
|
|
1551
|
+
function iconToDataUrl(icon, size = 48) {
|
|
1552
|
+
const svg = renderIconSvg(icon, size);
|
|
1553
|
+
return `data:image/svg+xml;base64,${btoa(svg)}`;
|
|
1554
|
+
}
|
|
1555
|
+
|
|
1490
1556
|
// Main component
|
|
1491
1557
|
|
|
1492
1558
|
/**
|
|
1493
1559
|
* Generated bundle index. Do not edit.
|
|
1494
1560
|
*/
|
|
1495
1561
|
|
|
1496
|
-
export { GraphEditorComponent };
|
|
1562
|
+
export { GraphEditorComponent, iconToDataUrl, renderIconSvg };
|
|
1497
1563
|
//# sourceMappingURL=utisha-graph-editor.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utisha-graph-editor.mjs","sources":["../../../projects/graph-editor/src/lib/services/graph-history.service.ts","../../../projects/graph-editor/src/lib/graph-editor.component.ts","../../../projects/graph-editor/src/lib/graph-editor.component.html","../../../projects/graph-editor/src/public-api.ts","../../../projects/graph-editor/src/utisha-graph-editor.ts"],"sourcesContent":["import { Injectable, signal } from '@angular/core';\nimport { Graph } from '../graph.model';\n\n/**\n * Service for managing undo/redo history of graph state.\n * \n * Uses a simple snapshot-based approach where each history entry\n * is a deep copy of the entire graph state.\n */\n@Injectable()\nexport class GraphHistoryService {\n private history: Graph[] = [];\n private historyIndex = -1;\n private maxHistorySize = 100;\n \n /** Signal to track if an undo/redo operation is in progress */\n readonly isUndoRedo = signal(false);\n\n /**\n * Initialize history with the given graph state.\n * Clears any existing history.\n */\n init(graph: Graph): void {\n this.history = [structuredClone(graph)];\n this.historyIndex = 0;\n }\n\n /**\n * Push a new state to the history stack.\n * If we're not at the end of history, truncates future states.\n * Prevents duplicate consecutive states.\n * \n * @returns true if state was pushed, false if it was a duplicate\n */\n push(graph: Graph): boolean {\n const currentState = structuredClone(graph);\n \n // Don't push if state hasn't changed\n if (this.historyIndex >= 0 && this.historyIndex < this.history.length) {\n const lastState = this.history[this.historyIndex];\n if (JSON.stringify(lastState) === JSON.stringify(currentState)) {\n return false;\n }\n }\n \n // If we're not at the end of history, truncate future states\n if (this.historyIndex < this.history.length - 1) {\n this.history = this.history.slice(0, this.historyIndex + 1);\n }\n \n // Add new state\n this.history.push(currentState);\n this.historyIndex = this.history.length - 1;\n \n // Enforce max history size\n if (this.history.length > this.maxHistorySize) {\n this.history.shift();\n this.historyIndex--;\n }\n \n return true;\n }\n\n /**\n * Undo the last action.\n * @returns The previous graph state, or null if nothing to undo\n */\n undo(): Graph | null {\n if (this.historyIndex <= 0) {\n return null;\n }\n \n this.historyIndex--;\n this.isUndoRedo.set(true);\n const state = structuredClone(this.history[this.historyIndex]);\n // Note: caller should set isUndoRedo back to false after applying state\n return state;\n }\n\n /**\n * Redo the last undone action.\n * @returns The next graph state, or null if nothing to redo\n */\n redo(): Graph | null {\n if (this.historyIndex >= this.history.length - 1) {\n return null;\n }\n \n this.historyIndex++;\n this.isUndoRedo.set(true);\n const state = structuredClone(this.history[this.historyIndex]);\n // Note: caller should set isUndoRedo back to false after applying state\n return state;\n }\n\n /**\n * Complete an undo/redo operation.\n * Call this after applying the state returned by undo() or redo().\n */\n completeUndoRedo(): void {\n this.isUndoRedo.set(false);\n }\n\n /** Check if undo is available */\n canUndo(): boolean {\n return this.historyIndex > 0;\n }\n\n /** Check if redo is available */\n canRedo(): boolean {\n return this.historyIndex < this.history.length - 1;\n }\n\n /** Clear history and reset to given state */\n clear(graph: Graph): void {\n this.init(graph);\n }\n\n /** Get current history size */\n get size(): number {\n return this.history.length;\n }\n\n /** Get current position in history (0-indexed) */\n get position(): number {\n return this.historyIndex;\n }\n\n /** Set maximum history size */\n setMaxSize(size: number): void {\n this.maxHistorySize = size;\n // Trim history if necessary\n while (this.history.length > this.maxHistorySize) {\n this.history.shift();\n this.historyIndex--;\n }\n }\n}\n","import {\n ChangeDetectionStrategy,\n Component,\n computed,\n ElementRef,\n EventEmitter,\n inject,\n Input,\n OnChanges,\n OnInit,\n Output,\n signal,\n SimpleChanges,\n viewChild\n} from '@angular/core';\n// dagre is loaded dynamically in applyLayout() to avoid compile-time resolution issues\nimport {Graph, GraphEdge, GraphNode, Position} from './graph.model';\nimport {ContextMenuEvent, GraphEditorConfig, SelectionState, ValidationResult} from './graph-editor.config';\nimport {GraphHistoryService} from './services/graph-history.service';\n\n/**\n * Main graph editor component.\n *\n * @example\n * <graph-editor\n * [config]=\"editorConfig\"\n * [graph]=\"currentGraph()\"\n * (graphChange)=\"onGraphChange($event)\"\n * />\n */\n@Component({\n selector: 'graph-editor',\n standalone: true,\n imports: [],\n providers: [GraphHistoryService],\n host: {\n 'tabindex': '0',\n 'style': 'outline: none;',\n '(keydown)': 'onKeyDown($event)'\n },\n templateUrl: './graph-editor.component.html',\n styleUrl: './graph-editor.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class GraphEditorComponent implements OnInit, OnChanges {\n // Inputs\n @Input({ required: true }) config!: GraphEditorConfig;\n @Input() graph: Graph = { nodes: [], edges: [] };\n @Input() readonly = false;\n @Input() visualizationMode = false;\n @Input() overlayData?: Map<string, any>;\n\n // Outputs\n @Output() graphChange = new EventEmitter<Graph>();\n @Output() nodeAdded = new EventEmitter<GraphNode>();\n @Output() nodeUpdated = new EventEmitter<GraphNode>();\n @Output() nodeRemoved = new EventEmitter<GraphNode>();\n @Output() edgeAdded = new EventEmitter<GraphEdge>();\n @Output() edgeUpdated = new EventEmitter<GraphEdge>();\n @Output() edgeRemoved = new EventEmitter<GraphEdge>();\n @Output() selectionChange = new EventEmitter<SelectionState>();\n @Output() validationChange = new EventEmitter<ValidationResult>();\n @Output() nodeClick = new EventEmitter<GraphNode>();\n @Output() nodeDoubleClick = new EventEmitter<GraphNode>();\n @Output() edgeClick = new EventEmitter<GraphEdge>();\n @Output() edgeDoubleClick = new EventEmitter<GraphEdge>();\n @Output() canvasClick = new EventEmitter<Position>();\n @Output() contextMenu = new EventEmitter<ContextMenuEvent>();\n\n private readonly canvasSvgRef = viewChild<ElementRef>('canvasSvg');\n private readonly historyService = inject(GraphHistoryService);\n\n // Internal state\n internalGraph = signal<Graph>({ nodes: [], edges: [] });\n selection = signal<SelectionState>({ nodes: [], edges: [] });\n validationResult = signal<ValidationResult | null>(null);\n\n // Pan & Zoom state\n panX = signal(0);\n panY = signal(0);\n scale = signal(1);\n\n // Dragging state\n private draggedNode: GraphNode | null = null;\n private dragOffset: Position = { x: 0, y: 0 };\n private draggedNodeOffsets: Map<string, Position> = new Map(); // For multi-node drag\n private didDrag = false; // Track if actual dragging occurred (to suppress click after drag)\n private isPanning = false;\n private lastMousePos: Position = { x: 0, y: 0 };\n private draggedEdge: { edge: GraphEdge; endpoint: 'source' | 'target' } | null = null;\n private hoveredNodeId: string | null = null;\n hoveredPort: { nodeId: string; port: 'top' | 'bottom' | 'left' | 'right' } | null = null;\n\n // Attachment points visibility\n showAttachmentPoints = signal<string | null>(null); // nodeId to show ports for\n\n // Active tool\n activeTool = signal<'hand' | 'line'>('hand');\n\n // Line tool state\n private pendingEdge: { sourceId: string; sourcePort: 'top' | 'bottom' | 'left' | 'right' } | null = null;\n\n // Preview line for line tool (rubber-band from source to cursor)\n previewLine = signal<{ source: Position; target: Position } | null>(null);\n\n // Box selection state (Shift+drag)\n private isBoxSelecting = false;\n private boxSelectStart: Position = { x: 0, y: 0 };\n selectionBox = signal<{ x: number; y: number; width: number; height: number } | null>(null);\n\n // Computed\n transform = computed(() =>\n `translate(${this.panX()}, ${this.panY()}) scale(${this.scale()})`\n );\n\n gridBounds = computed(() => {\n const gridSize = this.config.canvas?.grid?.size || 20;\n const viewportWidth = 10000; // Large enough to cover any reasonable viewport\n const viewportHeight = 10000;\n\n // Calculate grid offset to align with pan\n const x = Math.floor(-this.panX() / this.scale() / gridSize) * gridSize - viewportWidth / 2;\n const y = Math.floor(-this.panY() / this.scale() / gridSize) * gridSize - viewportHeight / 2;\n\n return {\n x,\n y,\n width: viewportWidth * 2,\n height: viewportHeight * 2\n };\n });\n\n // Shadow configuration (defaults to true)\n shadowsEnabled = computed(() => this.config.theme?.shadows !== false);\n\n // Selected edge info for direction selector positioning\n selectedEdgeMidpoint = computed(() => {\n const sel = this.selection();\n if (sel.edges.length !== 1) return null;\n const edge = this.internalGraph().edges.find(e => e.id === sel.edges[0]);\n if (!edge) return null;\n\n const sourcePoint = this.getEdgeSourcePoint(edge);\n const targetPoint = this.getEdgeTargetPoint(edge);\n const midX = (sourcePoint.x + targetPoint.x) / 2;\n const midY = (sourcePoint.y + targetPoint.y) / 2;\n\n return {\n edge,\n x: midX * this.scale() + this.panX(),\n y: midY * this.scale() + this.panY()\n };\n });\n\n constructor() {}\n\n ngOnChanges(changes: SimpleChanges) {\n // Sync graph input to internal signal\n if (changes['graph'] && changes['graph'].currentValue) {\n this.internalGraph.set(structuredClone(changes['graph'].currentValue));\n }\n }\n\n ngOnInit() {\n // Initialize with current graph value\n if (this.graph) {\n this.internalGraph.set(structuredClone(this.graph));\n }\n this.validate();\n // Initialize history with starting state\n this.historyService.init(this.internalGraph());\n }\n\n // Node operations\n addNode(type: string, position?: Position): GraphNode {\n const nodeConfig = this.config.nodes.types.find(t => t.type === type);\n if (!nodeConfig) {\n throw new Error(`Unknown node type: ${type}`);\n }\n\n const newNode: GraphNode = {\n id: this.generateId(),\n type,\n data: structuredClone(nodeConfig.defaultData),\n position: position || { x: 100, y: 100 }\n };\n\n const graph = this.internalGraph();\n this.internalGraph.set({\n ...graph,\n nodes: [...graph.nodes, newNode]\n });\n\n this.emitGraphChange();\n this.nodeAdded.emit(newNode);\n this.switchTool('hand');\n return newNode;\n }\n\n removeNode(nodeId: string, removeAttachedEdges = false): void {\n const graph = this.internalGraph();\n const removedNode = graph.nodes.find(n => n.id === nodeId);\n this.internalGraph.set({\n ...graph,\n nodes: graph.nodes.filter(n => n.id !== nodeId),\n edges: removeAttachedEdges\n ? graph.edges.filter(e => e.source !== nodeId && e.target !== nodeId)\n : graph.edges\n });\n this.selection.set({ nodes: [], edges: [] });\n this.emitGraphChange();\n if (removedNode) this.nodeRemoved.emit(removedNode);\n }\n\n removeEdge(edgeId: string): void {\n const graph = this.internalGraph();\n const removedEdge = graph.edges.find(e => e.id === edgeId);\n this.internalGraph.set({\n ...graph,\n edges: graph.edges.filter(e => e.id !== edgeId)\n });\n this.selection.set({ nodes: [], edges: [] });\n this.emitGraphChange();\n if (removedEdge) this.edgeRemoved.emit(removedEdge);\n }\n\n updateNode(nodeId: string, updates: Partial<GraphNode>): void {\n const graph = this.internalGraph();\n const nodeIndex = graph.nodes.findIndex(n => n.id === nodeId);\n if (nodeIndex === -1) return;\n\n const updatedNodes = [...graph.nodes];\n updatedNodes[nodeIndex] = { ...updatedNodes[nodeIndex], ...updates };\n\n this.internalGraph.set({\n ...graph,\n nodes: updatedNodes\n });\n this.emitGraphChange();\n }\n\n // Selection\n selectNode(nodeId: string | null): void {\n if (nodeId === null) {\n this.selection.set({ nodes: [], edges: [] });\n } else {\n this.selection.set({ nodes: [nodeId], edges: [] });\n }\n this.selectionChange.emit(this.selection());\n }\n\n selectEdge(edgeId: string | null): void {\n if (edgeId === null) {\n this.selection.set({ nodes: [], edges: [] });\n } else {\n this.selection.set({ nodes: [], edges: [edgeId] });\n }\n this.selectionChange.emit(this.selection());\n }\n\n /** Toggle a node in/out of the current selection (for Ctrl+Click) */\n toggleNodeSelection(nodeId: string): void {\n const sel = this.selection();\n const isSelected = sel.nodes.includes(nodeId);\n if (isSelected) {\n // Remove from selection\n this.selection.set({\n nodes: sel.nodes.filter(id => id !== nodeId),\n edges: sel.edges\n });\n } else {\n // Add to selection\n this.selection.set({\n nodes: [...sel.nodes, nodeId],\n edges: sel.edges\n });\n }\n this.selectionChange.emit(this.selection());\n }\n\n /** Toggle an edge in/out of the current selection (for Ctrl+Click) */\n toggleEdgeSelection(edgeId: string): void {\n const sel = this.selection();\n const isSelected = sel.edges.includes(edgeId);\n if (isSelected) {\n // Remove from selection\n this.selection.set({\n nodes: sel.nodes,\n edges: sel.edges.filter(id => id !== edgeId)\n });\n } else {\n // Add to selection\n this.selection.set({\n nodes: sel.nodes,\n edges: [...sel.edges, edgeId]\n });\n }\n this.selectionChange.emit(this.selection());\n }\n\n onKeyDown(event: KeyboardEvent): void {\n if (this.readonly || this.config.interaction?.readonly) return;\n\n // Escape: cancel line drawing, clear selection\n if (event.key === 'Escape') {\n this.pendingEdge = null;\n this.previewLine.set(null);\n this.selection.set({ nodes: [], edges: [] });\n this.selectionChange.emit(this.selection());\n this.showAttachmentPoints.set(null);\n event.preventDefault();\n return;\n }\n\n // Undo: Ctrl+Z (or Cmd+Z on Mac)\n if ((event.ctrlKey || event.metaKey) && event.key === 'z' && !event.shiftKey) {\n if (this.undo()) {\n event.preventDefault();\n }\n return;\n }\n\n // Redo: Ctrl+Y or Ctrl+Shift+Z (or Cmd+Y / Cmd+Shift+Z on Mac)\n if ((event.ctrlKey || event.metaKey) && (event.key === 'y' || (event.key === 'z' && event.shiftKey))) {\n if (this.redo()) {\n event.preventDefault();\n }\n return;\n }\n\n if (event.key === 'Delete' || event.key === 'Backspace') {\n const sel = this.selection();\n if (sel.nodes.length === 0 && sel.edges.length === 0) return;\n\n // Batch delete: remove all selected items atomically (single history entry)\n const graph = this.internalGraph();\n const nodeIdsToRemove = new Set(sel.nodes);\n const edgeIdsToRemove = new Set(sel.edges);\n\n // Collect removed items for events\n const removedNodes = graph.nodes.filter(n => nodeIdsToRemove.has(n.id));\n const removedEdges = graph.edges.filter(e => edgeIdsToRemove.has(e.id));\n\n // Filter out selected nodes\n const remainingNodes = graph.nodes.filter(n => !nodeIdsToRemove.has(n.id));\n\n // Filter out selected edges AND edges connected to deleted nodes\n const remainingEdges = graph.edges.filter(e =>\n !edgeIdsToRemove.has(e.id) &&\n !nodeIdsToRemove.has(e.source) &&\n !nodeIdsToRemove.has(e.target)\n );\n\n // Find edges that were removed because they connected to deleted nodes\n const additionalRemovedEdges = graph.edges.filter(e =>\n !edgeIdsToRemove.has(e.id) &&\n (nodeIdsToRemove.has(e.source) || nodeIdsToRemove.has(e.target))\n );\n\n // Update graph atomically (single history push)\n this.internalGraph.set({ ...graph, nodes: remainingNodes, edges: remainingEdges });\n this.emitGraphChange();\n\n // Emit removal events\n for (const edge of removedEdges) {\n this.edgeRemoved.emit(edge);\n }\n for (const edge of additionalRemovedEdges) {\n this.edgeRemoved.emit(edge);\n }\n for (const node of removedNodes) {\n this.nodeRemoved.emit(node);\n }\n\n // Clear selection\n this.selection.set({ nodes: [], edges: [] });\n this.selectionChange.emit(this.selection());\n\n event.preventDefault();\n return;\n }\n\n // Arrow keys: nudge selected node(s) — 1px default, 10px with Shift\n if (event.key.startsWith('Arrow')) {\n const sel = this.selection();\n if (sel.nodes.length === 0) return;\n\n const step = event.shiftKey ? 10 : 1;\n let dx = 0;\n let dy = 0;\n switch (event.key) {\n case 'ArrowUp': dy = -step; break;\n case 'ArrowDown': dy = step; break;\n case 'ArrowLeft': dx = -step; break;\n case 'ArrowRight': dx = step; break;\n }\n\n event.preventDefault();\n\n const graph = this.internalGraph();\n const updatedNodes = [...graph.nodes];\n for (const nodeId of sel.nodes) {\n const idx = updatedNodes.findIndex(n => n.id === nodeId);\n if (idx === -1) continue;\n const pos = updatedNodes[idx].position;\n updatedNodes[idx] = { ...updatedNodes[idx], position: { x: pos.x + dx, y: pos.y + dy } };\n }\n\n // Recalculate edge ports for moved nodes (atomic update)\n const movedIds = new Set(sel.nodes);\n const updatedEdges = graph.edges.map(edge => {\n if (!movedIds.has(edge.source) && !movedIds.has(edge.target)) return edge;\n const sourceNode = updatedNodes.find(n => n.id === edge.source);\n const targetNode = updatedNodes.find(n => n.id === edge.target);\n if (!sourceNode || !targetNode) return edge;\n const newSourcePort = this.findClosestPortForEdge(sourceNode, targetNode, 'source');\n const newTargetPort = this.findClosestPortForEdge(targetNode, sourceNode, 'target');\n if (edge.sourcePort === newSourcePort && edge.targetPort === newTargetPort) return edge;\n return { ...edge, sourcePort: newSourcePort, targetPort: newTargetPort };\n });\n\n this.internalGraph.set({ ...graph, nodes: updatedNodes, edges: updatedEdges });\n this.emitGraphChange();\n }\n }\n\n switchTool(tool: 'hand' | 'line'): void {\n const previousTool = this.activeTool();\n\n // Cancel any in-progress line drawing\n this.pendingEdge = null;\n this.previewLine.set(null);\n this.showAttachmentPoints.set(null);\n\n // Preserve node selection when switching hand → line\n if (!(previousTool === 'hand' && tool === 'line')) {\n this.selection.set({ nodes: [], edges: [] });\n this.selectionChange.emit(this.selection());\n }\n\n this.activeTool.set(tool);\n\n // Hand → line with a node selected: start edge from that node\n if (previousTool === 'hand' && tool === 'line') {\n const sel = this.selection();\n if (sel.nodes.length === 1) {\n this.pendingEdge = { sourceId: sel.nodes[0], sourcePort: 'bottom' };\n }\n }\n }\n\n /** @deprecated Use switchTool('line') instead */\n switchToLineTool(): void {\n this.switchTool('line');\n }\n\n onEdgeClick(event: MouseEvent, edge: GraphEdge): void {\n if (this.activeTool() !== 'hand') return;\n event.stopPropagation();\n if (event.ctrlKey || event.metaKey) {\n // Ctrl/Cmd+Click: toggle edge in selection\n this.toggleEdgeSelection(edge.id);\n } else {\n // Normal click: replace selection with this edge\n this.selectEdge(edge.id);\n }\n this.edgeClick.emit(edge);\n }\n\n onEdgeDoubleClick(event: MouseEvent, edge: GraphEdge): void {\n if (this.activeTool() !== 'hand') return;\n event.stopPropagation();\n this.selectEdge(edge.id);\n this.edgeDoubleClick.emit(edge);\n }\n\n clearSelection(): void {\n this.selection.set({ nodes: [], edges: [] });\n this.selectionChange.emit(this.selection());\n }\n\n // Validation\n validate(): ValidationResult {\n if (!this.config.validation) {\n const result = { valid: true, errors: [] };\n this.validationResult.set(result);\n return result;\n }\n\n const errors = this.config.validation!.validators.flatMap(rule =>\n rule.validator(this.internalGraph(), this.config)\n );\n\n const result = {\n valid: errors.filter(e => e.severity !== 'warning').length === 0,\n errors\n };\n\n this.validationResult.set(result);\n this.validationChange.emit(result);\n return result;\n }\n\n // Layout\n async applyLayout(direction: 'TB' | 'LR' = 'TB'): Promise<void> {\n const graph = this.internalGraph();\n if (graph.nodes.length === 0) return;\n\n // Dynamic import to avoid compile-time module resolution issues\n const dagreModule = await import('dagre');\n const dagre = dagreModule.default ?? dagreModule;\n\n const g = new dagre.graphlib.Graph();\n g.setGraph({\n rankdir: direction,\n nodesep: 60,\n ranksep: 80,\n marginx: 40,\n marginy: 40,\n });\n g.setDefaultEdgeLabel(() => ({}));\n\n for (const node of graph.nodes) {\n const size = this.getNodeSize(node);\n g.setNode(node.id, { width: size.width, height: size.height });\n }\n\n for (const edge of graph.edges) {\n g.setEdge(edge.source, edge.target);\n }\n\n dagre.layout(g);\n\n const updatedNodes = graph.nodes.map(node => {\n const dagreNode = g.node(node.id);\n if (!dagreNode) return node;\n const size = this.getNodeSize(node);\n return {\n ...node,\n position: {\n x: dagreNode.x - size.width / 2,\n y: dagreNode.y - size.height / 2,\n },\n };\n });\n\n // Recalculate edge ports based on new node positions\n const updatedEdges = graph.edges.map(edge => {\n const sourceNode = updatedNodes.find(n => n.id === edge.source);\n const targetNode = updatedNodes.find(n => n.id === edge.target);\n if (!sourceNode || !targetNode) return edge;\n const newSourcePort = this.findClosestPortForEdge(sourceNode, targetNode, 'source');\n const newTargetPort = this.findClosestPortForEdge(targetNode, sourceNode, 'target');\n return { ...edge, sourcePort: newSourcePort, targetPort: newTargetPort };\n });\n\n this.internalGraph.set({ ...graph, nodes: updatedNodes, edges: updatedEdges });\n this.emitGraphChange();\n\n setTimeout(() => this.fitToScreen());\n }\n\n fitToScreen(padding = 40): void {\n const nodes = this.internalGraph().nodes;\n if (nodes.length === 0) return;\n\n // Get SVG element dimensions\n const ref = this.canvasSvgRef();\n const svgEl: SVGSVGElement | null = ref?.nativeElement ?? ref ?? null;\n if (!svgEl || typeof svgEl.getBoundingClientRect !== 'function') return;\n\n const rect = svgEl.getBoundingClientRect();\n const viewW = rect.width;\n const viewH = rect.height;\n if (viewW === 0 || viewH === 0) return;\n\n // Calculate bounding box of all nodes\n let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;\n for (const node of nodes) {\n const size = this.getNodeSize(node);\n minX = Math.min(minX, node.position.x);\n minY = Math.min(minY, node.position.y);\n maxX = Math.max(maxX, node.position.x + size.width);\n maxY = Math.max(maxY, node.position.y + size.height);\n }\n\n const contentW = maxX - minX;\n const contentH = maxY - minY;\n\n // Handle single node or all nodes stacked\n if (contentW <= 0 && contentH <= 0) {\n this.scale.set(1);\n this.panX.set(viewW / 2 - (minX + 110) * 1);\n this.panY.set(viewH / 2 - (minY + 50) * 1);\n return;\n }\n\n // Calculate scale to fit content with padding (cap at 1 to avoid zooming in too much)\n const zoomConfig = this.config.canvas?.zoom;\n const minScale = zoomConfig?.min ?? 0.25;\n const scaleX = contentW > 0 ? (viewW - padding * 2) / contentW : 1;\n const scaleY = contentH > 0 ? (viewH - padding * 2) / contentH : 1;\n const newScale = Math.max(minScale, Math.min(1, Math.min(scaleX, scaleY)));\n\n // Center the content in the viewport\n const centerX = (minX + maxX) / 2;\n const centerY = (minY + maxY) / 2;\n const newPanX = viewW / 2 - centerX * newScale;\n const newPanY = viewH / 2 - centerY * newScale;\n\n this.scale.set(newScale);\n this.panX.set(newPanX);\n this.panY.set(newPanY);\n }\n\n zoomTo(level: number): void {\n const zoomConfig = this.config.canvas?.zoom;\n const min = zoomConfig?.min ?? 0.25;\n const max = zoomConfig?.max ?? 2.0;\n this.scale.set(Math.max(min, Math.min(max, level)));\n }\n\n getSelection(): SelectionState {\n return this.selection();\n }\n\n // Event handlers\n onCanvasMouseDown(event: MouseEvent): void {\n if (this.readonly) return;\n\n // Cancel pending edge on empty space click\n if (this.pendingEdge) {\n this.pendingEdge = null;\n this.previewLine.set(null);\n this.showAttachmentPoints.set(null);\n this.hoveredPort = null;\n this.clearSelection();\n }\n\n const target = event.target as SVGElement;\n const isNode = !!target.closest('.graph-node');\n const isEdgeEndpoint = target.classList.contains('edge-endpoint');\n const isAttachmentPoint = target.classList.contains('attachment-point');\n const isHitArea = target.classList.contains('edge-hit-area');\n const isInteractive = isNode || isEdgeEndpoint || isAttachmentPoint || isHitArea;\n\n if (!isInteractive) {\n const rect = (event.currentTarget as SVGSVGElement).getBoundingClientRect();\n const mouseX = (event.clientX - rect.left - this.panX()) / this.scale();\n const mouseY = (event.clientY - rect.top - this.panY()) / this.scale();\n\n if (event.shiftKey && this.activeTool() === 'hand') {\n // Shift+drag = box selection (only with hand tool)\n this.isBoxSelecting = true;\n this.boxSelectStart = { x: mouseX, y: mouseY };\n this.selectionBox.set({ x: mouseX, y: mouseY, width: 0, height: 0 });\n } else {\n // Normal drag = pan\n this.isPanning = true;\n }\n this.lastMousePos = { x: event.clientX, y: event.clientY };\n this.clearSelection();\n event.preventDefault();\n }\n }\n\n onCanvasMouseMove(event: MouseEvent): void {\n if (this.isBoxSelecting) {\n // Update selection box\n const rect = (event.currentTarget as SVGSVGElement).getBoundingClientRect();\n const mouseX = (event.clientX - rect.left - this.panX()) / this.scale();\n const mouseY = (event.clientY - rect.top - this.panY()) / this.scale();\n\n const x = Math.min(this.boxSelectStart.x, mouseX);\n const y = Math.min(this.boxSelectStart.y, mouseY);\n const width = Math.abs(mouseX - this.boxSelectStart.x);\n const height = Math.abs(mouseY - this.boxSelectStart.y);\n\n this.selectionBox.set({ x, y, width, height });\n } else if (this.isPanning) {\n const dx = event.clientX - this.lastMousePos.x;\n const dy = event.clientY - this.lastMousePos.y;\n this.panX.set(this.panX() + dx);\n this.panY.set(this.panY() + dy);\n this.lastMousePos = { x: event.clientX, y: event.clientY };\n } else if (this.draggedNode) {\n this.didDrag = true; // Mark that dragging occurred\n const rect = (event.currentTarget as SVGSVGElement).getBoundingClientRect();\n const mouseX = (event.clientX - rect.left - this.panX()) / this.scale();\n const mouseY = (event.clientY - rect.top - this.panY()) / this.scale();\n const graph = this.internalGraph();\n const updatedNodes = [...graph.nodes];\n const movedNodeIds = new Set<string>();\n\n // Check if we're dragging multiple selected nodes\n if (this.draggedNodeOffsets.size > 1) {\n // Multi-node drag: move all selected nodes\n for (const [nodeId, offset] of this.draggedNodeOffsets) {\n const nodeIndex = updatedNodes.findIndex(n => n.id === nodeId);\n if (nodeIndex === -1) continue;\n\n let x = mouseX - offset.x;\n let y = mouseY - offset.y;\n\n // Smart snap to grid\n if (this.config.canvas?.grid?.snap) {\n const gridSize = this.config.canvas.grid.size || 20;\n const snapThreshold = gridSize / 4;\n const snapX = Math.round(x / gridSize) * gridSize;\n const snapY = Math.round(y / gridSize) * gridSize;\n if (Math.abs(x - snapX) < snapThreshold) x = snapX;\n if (Math.abs(y - snapY) < snapThreshold) y = snapY;\n }\n\n updatedNodes[nodeIndex] = { ...updatedNodes[nodeIndex], position: { x, y } };\n movedNodeIds.add(nodeId);\n }\n } else {\n // Single node drag\n let x = mouseX - this.dragOffset.x;\n let y = mouseY - this.dragOffset.y;\n\n // Smart snap to grid\n if (this.config.canvas?.grid?.snap) {\n const gridSize = this.config.canvas.grid.size || 20;\n const snapThreshold = gridSize / 4;\n const snapX = Math.round(x / gridSize) * gridSize;\n const snapY = Math.round(y / gridSize) * gridSize;\n if (Math.abs(x - snapX) < snapThreshold) x = snapX;\n if (Math.abs(y - snapY) < snapThreshold) y = snapY;\n }\n\n const nodeIndex = updatedNodes.findIndex(n => n.id === this.draggedNode!.id);\n if (nodeIndex !== -1) {\n updatedNodes[nodeIndex] = { ...updatedNodes[nodeIndex], position: { x, y } };\n movedNodeIds.add(this.draggedNode!.id);\n }\n }\n\n // Recalculate ports for all edges connected to moved nodes\n const updatedEdges = graph.edges.map(edge => {\n if (!movedNodeIds.has(edge.source) && !movedNodeIds.has(edge.target)) return edge;\n const sourceNode = updatedNodes.find(n => n.id === edge.source);\n const targetNode = updatedNodes.find(n => n.id === edge.target);\n if (!sourceNode || !targetNode) return edge;\n const newSourcePort = this.findClosestPortForEdge(sourceNode, targetNode, 'source');\n const newTargetPort = this.findClosestPortForEdge(targetNode, sourceNode, 'target');\n if (edge.sourcePort === newSourcePort && edge.targetPort === newTargetPort) return edge;\n return { ...edge, sourcePort: newSourcePort, targetPort: newTargetPort };\n });\n\n this.internalGraph.set({ ...graph, nodes: updatedNodes, edges: updatedEdges });\n this.emitGraphChange();\n } else if (this.draggedEdge) {\n // Edge reconnection - find hovered node and closest port\n const rect = (event.currentTarget as SVGSVGElement).getBoundingClientRect();\n const mouseX = (event.clientX - rect.left - this.panX()) / this.scale();\n const mouseY = (event.clientY - rect.top - this.panY()) / this.scale();\n\n // Find node under cursor\n const nodeId = this.findNodeAtPosition({ x: mouseX, y: mouseY });\n\n if (nodeId) {\n // Show attachment points for this node\n this.showAttachmentPoints.set(nodeId);\n\n // Find closest port\n const closestPort = this.findClosestPort(nodeId, { x: mouseX, y: mouseY });\n\n // Highlight port if within snap distance (40px)\n if (closestPort && closestPort.distance < 40) {\n this.hoveredPort = { nodeId, port: closestPort.port };\n this.hoveredNodeId = nodeId;\n } else {\n this.hoveredPort = null;\n this.hoveredNodeId = null;\n }\n } else {\n // No node nearby - hide attachment points\n this.showAttachmentPoints.set(null);\n this.hoveredPort = null;\n this.hoveredNodeId = null;\n }\n } else if (this.pendingEdge && this.activeTool() === 'line') {\n // Line tool pending state - show rubber-band preview + attachment points on hovered node\n const rect = (event.currentTarget as SVGSVGElement).getBoundingClientRect();\n const mouseX = (event.clientX - rect.left - this.panX()) / this.scale();\n const mouseY = (event.clientY - rect.top - this.panY()) / this.scale();\n\n // Get source port position\n const sourceNode = this.internalGraph().nodes.find(n => n.id === this.pendingEdge!.sourceId);\n if (sourceNode) {\n const sourcePoint = this.getPortWorldPosition(sourceNode, this.pendingEdge.sourcePort);\n\n // Check if cursor is near a node - snap to its closest port\n const hoveredNodeId = this.findNodeAtPosition({ x: mouseX, y: mouseY });\n let targetPoint: Position = { x: mouseX, y: mouseY };\n\n if (hoveredNodeId && hoveredNodeId !== this.pendingEdge.sourceId) {\n // Show attachment points on hovered node\n this.showAttachmentPoints.set(hoveredNodeId);\n\n // Find and highlight closest port\n const closestPort = this.findClosestPort(hoveredNodeId, { x: mouseX, y: mouseY });\n if (closestPort && closestPort.distance < 40) {\n this.hoveredPort = { nodeId: hoveredNodeId, port: closestPort.port };\n // Snap preview line to port\n const hoveredNode = this.internalGraph().nodes.find(n => n.id === hoveredNodeId);\n if (hoveredNode) {\n targetPoint = this.getPortWorldPosition(hoveredNode, closestPort.port);\n }\n } else {\n this.hoveredPort = null;\n }\n } else {\n // Not over a valid target node - hide attachment points\n this.showAttachmentPoints.set(null);\n this.hoveredPort = null;\n }\n\n this.previewLine.set({ source: sourcePoint, target: targetPoint });\n }\n }\n }\n\n onCanvasMouseUp(_event: MouseEvent): void {\n // Handle box selection completion\n if (this.isBoxSelecting) {\n const box = this.selectionBox();\n if (box && (box.width > 5 || box.height > 5)) {\n // Find all nodes within the selection box\n const selectedNodes: string[] = [];\n for (const node of this.internalGraph().nodes) {\n const size = this.getNodeSize(node);\n const nodeRight = node.position.x + size.width;\n const nodeBottom = node.position.y + size.height;\n const boxRight = box.x + box.width;\n const boxBottom = box.y + box.height;\n\n // Check if node intersects with selection box\n if (node.position.x < boxRight &&\n nodeRight > box.x &&\n node.position.y < boxBottom &&\n nodeBottom > box.y) {\n selectedNodes.push(node.id);\n }\n }\n\n if (selectedNodes.length > 0) {\n // Also select edges where both source and target are selected\n const selectedEdges: string[] = [];\n for (const edge of this.internalGraph().edges) {\n if (selectedNodes.includes(edge.source) && selectedNodes.includes(edge.target)) {\n selectedEdges.push(edge.id);\n }\n }\n this.selection.set({ nodes: selectedNodes, edges: selectedEdges });\n this.selectionChange.emit(this.selection());\n }\n }\n this.isBoxSelecting = false;\n this.selectionBox.set(null);\n }\n\n // Handle edge reconnection with port snapping\n if (this.draggedEdge && this.hoveredNodeId && this.hoveredPort) {\n const graph = this.internalGraph();\n const edgeIndex = graph.edges.findIndex(e => e.id === this.draggedEdge!.edge.id);\n\n if (edgeIndex !== -1) {\n const updatedEdges = [...graph.edges];\n const updatedEdge = { ...updatedEdges[edgeIndex] };\n\n // Update node connection and store port information (non-null: guarded by if condition)\n if (this.draggedEdge.endpoint === 'source') {\n updatedEdge.source = this.hoveredNodeId!;\n updatedEdge.sourcePort = this.hoveredPort!.port;\n } else {\n updatedEdge.target = this.hoveredNodeId!;\n updatedEdge.targetPort = this.hoveredPort!.port;\n }\n\n updatedEdges[edgeIndex] = updatedEdge;\n this.internalGraph.set({ ...graph, edges: updatedEdges });\n this.emitGraphChange();\n this.edgeUpdated.emit(updatedEdge);\n }\n }\n\n this.isPanning = false;\n this.draggedNode = null;\n this.draggedNodeOffsets.clear();\n this.draggedEdge = null;\n this.hoveredNodeId = null;\n this.hoveredPort = null;\n this.showAttachmentPoints.set(null);\n }\n\n onNodeMouseDown(event: MouseEvent, node: GraphNode): void {\n if (this.readonly) return;\n event.stopPropagation(); // Always prevent canvas from seeing node mousedowns\n if (this.activeTool() !== 'hand') return;\n\n this.draggedNode = node;\n this.didDrag = false; // Reset - will be set true if actual movement occurs\n // Calculate offset between mouse position and node origin to prevent jump\n const svg = (event.target as SVGElement).closest('svg')!;\n const rect = svg.getBoundingClientRect();\n const mouseX = (event.clientX - rect.left - this.panX()) / this.scale();\n const mouseY = (event.clientY - rect.top - this.panY()) / this.scale();\n this.dragOffset = {\n x: mouseX - node.position.x,\n y: mouseY - node.position.y\n };\n\n // If this node is part of a multi-selection, calculate offsets for all selected nodes\n const sel = this.selection();\n this.draggedNodeOffsets.clear();\n if (sel.nodes.includes(node.id) && sel.nodes.length > 1) {\n const graph = this.internalGraph();\n for (const nodeId of sel.nodes) {\n const n = graph.nodes.find(nd => nd.id === nodeId);\n if (n) {\n this.draggedNodeOffsets.set(nodeId, {\n x: mouseX - n.position.x,\n y: mouseY - n.position.y\n });\n }\n }\n }\n }\n\n onNodeClick(event: MouseEvent, node: GraphNode): void {\n if (this.activeTool() === 'line') {\n event.stopPropagation();\n\n if (!this.pendingEdge) {\n // First click - start edge from this node\n // Pick initial port based on geometry (will be recalculated on second click)\n this.pendingEdge = { sourceId: node.id, sourcePort: 'bottom' };\n this.selectNode(node.id);\n } else if (this.pendingEdge.sourceId !== node.id) {\n // Second click on different node - complete the edge\n const sourceNode = this.internalGraph().nodes.find(n => n.id === this.pendingEdge!.sourceId);\n if (sourceNode) {\n const sourcePort = this.findClosestPortForEdge(sourceNode, node, 'source');\n const targetPort = this.findClosestPortForEdge(node, sourceNode, 'target');\n\n const newEdge: GraphEdge = {\n id: `edge_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,\n source: this.pendingEdge.sourceId,\n target: node.id,\n sourcePort,\n targetPort\n };\n\n const graph = this.internalGraph();\n this.internalGraph.set({\n ...graph,\n edges: [...graph.edges, newEdge]\n });\n this.emitGraphChange();\n this.edgeAdded.emit(newEdge);\n }\n this.pendingEdge = null;\n this.previewLine.set(null);\n this.showAttachmentPoints.set(null);\n this.hoveredPort = null;\n this.clearSelection();\n } else {\n // Clicked same node - cancel\n this.pendingEdge = null;\n this.previewLine.set(null);\n this.showAttachmentPoints.set(null);\n this.hoveredPort = null;\n this.clearSelection();\n }\n } else {\n // Hand tool - select or toggle selection\n // Skip selection change if we just finished dragging\n if (this.didDrag) {\n this.didDrag = false;\n return;\n }\n if (event.ctrlKey || event.metaKey) {\n // Ctrl/Cmd+Click: toggle node in selection\n this.toggleNodeSelection(node.id);\n } else {\n // Normal click: replace selection with this node\n this.selectNode(node.id);\n }\n }\n }\n\n onAttachmentPointClick(event: MouseEvent, node: GraphNode, port: 'top' | 'bottom' | 'left' | 'right'): void {\n event.stopPropagation();\n if (this.readonly) return;\n\n if (this.activeTool() === 'line') {\n if (!this.pendingEdge) {\n // First click on attachment point - start edge from this specific port\n this.pendingEdge = { sourceId: node.id, sourcePort: port };\n this.selectNode(node.id);\n } else if (this.pendingEdge.sourceId !== node.id) {\n // Second click - complete edge to this specific port\n const sourceNode = this.internalGraph().nodes.find(n => n.id === this.pendingEdge!.sourceId);\n if (sourceNode) {\n const sourcePort = this.findClosestPortForEdge(sourceNode, node, 'source');\n\n const newEdge: GraphEdge = {\n id: `edge_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,\n source: this.pendingEdge.sourceId,\n target: node.id,\n sourcePort,\n targetPort: port\n };\n\n const graph = this.internalGraph();\n this.internalGraph.set({\n ...graph,\n edges: [...graph.edges, newEdge]\n });\n this.emitGraphChange();\n this.edgeAdded.emit(newEdge);\n }\n this.pendingEdge = null;\n this.previewLine.set(null);\n this.showAttachmentPoints.set(null);\n this.hoveredPort = null;\n this.clearSelection();\n } else {\n // Clicked same node - cancel\n this.pendingEdge = null;\n this.previewLine.set(null);\n this.showAttachmentPoints.set(null);\n this.hoveredPort = null;\n this.clearSelection();\n }\n }\n }\n\n onEdgeEndpointMouseDown(event: MouseEvent, edge: GraphEdge, endpoint: 'source' | 'target'): void {\n if (this.readonly) return;\n event.stopPropagation();\n this.draggedEdge = { edge, endpoint };\n }\n\n onWheel(event: WheelEvent): void {\n const zoomConfig = this.config.canvas?.zoom;\n if (!zoomConfig?.wheelEnabled) return;\n\n event.preventDefault();\n const delta = -event.deltaY;\n const step = zoomConfig.step ?? 0.1;\n const newScale = Math.max(\n zoomConfig.min ?? 0.25,\n Math.min(\n zoomConfig.max ?? 2.0,\n this.scale() + (delta > 0 ? step : -step)\n )\n );\n\n this.scale.set(newScale);\n }\n\n onContextMenu(event: MouseEvent): void {\n event.preventDefault();\n\n const svgRect = this.canvasSvgRef()?.nativeElement.getBoundingClientRect();\n if (!svgRect) return;\n\n // Calculate position in graph coordinates\n const x = (event.clientX - svgRect.left - this.panX()) / this.scale();\n const y = (event.clientY - svgRect.top - this.panY()) / this.scale();\n\n // Check if clicking on a node\n const nodeId = this.findNodeAtPosition({ x, y });\n if (nodeId) {\n this.contextMenu.emit({\n type: 'node',\n position: { x: event.clientX, y: event.clientY },\n nodeId\n });\n return;\n }\n\n // Check if clicking on an edge (use hit area logic)\n const edgeId = this.findEdgeAtPosition({ x, y });\n if (edgeId) {\n this.contextMenu.emit({\n type: 'edge',\n position: { x: event.clientX, y: event.clientY },\n edgeId\n });\n return;\n }\n\n // Canvas click\n this.contextMenu.emit({\n type: 'canvas',\n position: { x: event.clientX, y: event.clientY }\n });\n }\n\n // Helper methods\n private emitGraphChange(): void {\n // Push to history (unless this is an undo/redo operation)\n if (!this.historyService.isUndoRedo()) {\n this.historyService.push(this.internalGraph());\n }\n this.graphChange.emit(this.internalGraph());\n if (this.config.validation?.validateOnChange) {\n this.validate();\n }\n }\n\n /** Undo the last action (Ctrl+Z) */\n undo(): boolean {\n const state = this.historyService.undo();\n if (!state) {\n return false;\n }\n \n this.internalGraph.set(state);\n this.graphChange.emit(this.internalGraph());\n this.historyService.completeUndoRedo();\n \n // Clear selection after undo\n this.selection.set({ nodes: [], edges: [] });\n this.selectionChange.emit(this.selection());\n \n return true;\n }\n\n /** Redo the last undone action (Ctrl+Y / Ctrl+Shift+Z) */\n redo(): boolean {\n const state = this.historyService.redo();\n if (!state) {\n return false;\n }\n \n this.internalGraph.set(state);\n this.graphChange.emit(this.internalGraph());\n this.historyService.completeUndoRedo();\n \n // Clear selection after redo\n this.selection.set({ nodes: [], edges: [] });\n this.selectionChange.emit(this.selection());\n \n return true;\n }\n\n /** Check if undo is available */\n canUndo(): boolean {\n return this.historyService.canUndo();\n }\n\n /** Check if redo is available */\n canRedo(): boolean {\n return this.historyService.canRedo();\n }\n\n /** Clear history and reset to current state */\n clearHistory(): void {\n this.historyService.clear(this.internalGraph());\n }\n\n private generateId(): string {\n return `node_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n }\n\n private recalculateEdgePorts(nodeId: string): void {\n const graph = this.internalGraph();\n let changed = false;\n const updatedEdges = graph.edges.map(edge => {\n if (edge.source !== nodeId && edge.target !== nodeId) return edge;\n\n const sourceNode = graph.nodes.find(n => n.id === edge.source);\n const targetNode = graph.nodes.find(n => n.id === edge.target);\n if (!sourceNode || !targetNode) return edge;\n\n const newSourcePort = this.findClosestPortForEdge(sourceNode, targetNode, 'source');\n const newTargetPort = this.findClosestPortForEdge(targetNode, sourceNode, 'target');\n\n if (edge.sourcePort === newSourcePort && edge.targetPort === newTargetPort) return edge;\n\n changed = true;\n return { ...edge, sourcePort: newSourcePort, targetPort: newTargetPort };\n });\n\n if (changed) {\n this.internalGraph.set({ ...graph, edges: updatedEdges });\n }\n }\n\n getNodeSize(node: GraphNode): { width: number; height: number } {\n const nodeConfig = this.config.nodes.types.find(t => t.type === node.type);\n return nodeConfig?.size || this.config.nodes.defaultSize || { width: 220, height: 100 };\n }\n\n getEdgePath(edge: GraphEdge): string {\n const sourceNode = this.internalGraph().nodes.find(n => n.id === edge.source);\n const targetNode = this.internalGraph().nodes.find(n => n.id === edge.target);\n\n if (!sourceNode || !targetNode) return '';\n\n // Get port positions from edge or calculate closest\n const sourcePort = (edge.sourcePort as 'top' | 'bottom' | 'left' | 'right') || this.findClosestPortForEdge(sourceNode, targetNode, 'source');\n const targetPort = (edge.targetPort as 'top' | 'bottom' | 'left' | 'right') || this.findClosestPortForEdge(targetNode, sourceNode, 'target');\n\n const sourcePoint = this.getPortWorldPosition(sourceNode, sourcePort);\n const targetPoint = this.getPortWorldPosition(targetNode, targetPort);\n\n // Simple straight line\n return `M ${sourcePoint.x},${sourcePoint.y} L ${targetPoint.x},${targetPoint.y}`;\n }\n\n getEdgeColor(edge: GraphEdge): string {\n return edge.metadata?.style?.stroke || this.config.edges.style?.stroke || '#94a3b8';\n }\n\n getEdgeMarkerEnd(edge: GraphEdge): string | null {\n const dir = edge.direction || 'forward';\n const selected = this.selection().edges.includes(edge.id);\n if (dir === 'forward' || dir === 'bidirectional') {\n return selected ? 'url(#arrow-end-selected)' : 'url(#arrow-end)';\n }\n return null;\n }\n\n getEdgeMarkerStart(edge: GraphEdge): string | null {\n const dir = edge.direction || 'forward';\n const selected = this.selection().edges.includes(edge.id);\n if (dir === 'backward' || dir === 'bidirectional') {\n return selected ? 'url(#arrow-start-selected)' : 'url(#arrow-start)';\n }\n return null;\n }\n\n setEdgeDirection(direction: 'forward' | 'backward' | 'bidirectional'): void {\n const sel = this.selection();\n if (sel.edges.length !== 1) return;\n\n const graph = this.internalGraph();\n const edgeIndex = graph.edges.findIndex(e => e.id === sel.edges[0]);\n if (edgeIndex === -1) return;\n\n const updatedEdges = [...graph.edges];\n updatedEdges[edgeIndex] = { ...updatedEdges[edgeIndex], direction };\n this.internalGraph.set({ ...graph, edges: updatedEdges });\n this.emitGraphChange();\n this.edgeUpdated.emit(updatedEdges[edgeIndex]);\n }\n\n getEdgeSourcePoint(edge: GraphEdge): Position {\n const sourceNode = this.internalGraph().nodes.find(n => n.id === edge.source);\n const targetNode = this.internalGraph().nodes.find(n => n.id === edge.target);\n if (!sourceNode || !targetNode) return { x: 0, y: 0 };\n\n const sourcePort = (edge.sourcePort as 'top' | 'bottom' | 'left' | 'right') || this.findClosestPortForEdge(sourceNode, targetNode, 'source');\n return this.getPortWorldPosition(sourceNode, sourcePort);\n }\n\n getEdgeTargetPoint(edge: GraphEdge): Position {\n const sourceNode = this.internalGraph().nodes.find(n => n.id === edge.source);\n const targetNode = this.internalGraph().nodes.find(n => n.id === edge.target);\n if (!sourceNode || !targetNode) return { x: 0, y: 0 };\n\n const targetPort = (edge.targetPort as 'top' | 'bottom' | 'left' | 'right') || this.findClosestPortForEdge(targetNode, sourceNode, 'target');\n return this.getPortWorldPosition(targetNode, targetPort);\n }\n\n getNodeTypeIcon(node: GraphNode): string {\n const nodeConfig = this.config.nodes.types.find(t => t.type === node.type);\n return nodeConfig?.icon || '●';\n }\n\n /**\n * Get custom image URL for a node.\n * Checks node.data['imageUrl'] first, then falls back to nodeType.defaultData['imageUrl'].\n * Returns null if no image is configured (will render text icon instead).\n */\n getNodeImage(node: GraphNode): string | null {\n // Check instance-level image first\n if (node.data['imageUrl']) {\n return node.data['imageUrl'] as string;\n }\n // Fall back to node type default\n const nodeConfig = this.config.nodes.types.find(t => t.type === node.type);\n if (nodeConfig?.defaultData['imageUrl']) {\n return nodeConfig.defaultData['imageUrl'] as string;\n }\n return null;\n }\n\n /**\n * Get the position for the node image (top-left corner of image).\n * Uses same positioning logic as icon but accounts for image dimensions.\n */\n getImagePosition(node: GraphNode): Position {\n const size = this.getNodeSize(node);\n const imageSize = this.getImageSize(node);\n const pos = this.config.nodes.iconPosition || 'top-left';\n const padding = 8;\n\n const positions: Record<string, Position> = {\n 'top-left': { x: padding, y: padding },\n 'top': { x: (size.width - imageSize) / 2, y: padding },\n 'top-right': { x: size.width - imageSize - padding, y: padding },\n 'right': { x: size.width - imageSize - padding, y: (size.height - imageSize) / 2 },\n 'bottom-right': { x: size.width - imageSize - padding, y: size.height - imageSize - padding },\n 'bottom': { x: (size.width - imageSize) / 2, y: size.height - imageSize - padding },\n 'bottom-left': { x: padding, y: size.height - imageSize - padding },\n 'left': { x: padding, y: (size.height - imageSize) / 2 }\n };\n\n return positions[pos] || positions['top-left'];\n }\n\n /**\n * Get the size (width/height) for node images.\n * Images are rendered as squares, sized proportionally to node height.\n */\n getImageSize(node: GraphNode): number {\n const size = this.getNodeSize(node);\n // Image takes up ~40% of node height, with min 24px and max 64px\n return Math.min(64, Math.max(24, size.height * 0.4));\n }\n\n getIconPosition(node: GraphNode): Position {\n const size = this.getNodeSize(node);\n const pos = this.config.nodes.iconPosition || 'top-left';\n const padding = size.height * 0.25;\n const iconSize = size.height * 0.28;\n\n const positions: Record<string, Position> = {\n 'top-left': { x: padding, y: padding },\n 'top': { x: size.width / 2, y: padding },\n 'top-right': { x: size.width - padding, y: padding },\n 'right': { x: size.width - padding, y: size.height / 2 },\n 'bottom-right': { x: size.width - padding, y: size.height - padding },\n 'bottom': { x: size.width / 2, y: size.height - padding },\n 'bottom-left': { x: padding, y: size.height - padding },\n 'left': { x: padding, y: size.height / 2 }\n };\n\n return positions[pos] || positions['left'];\n }\n\n getLabelPosition(node: GraphNode): Position {\n const size = this.getNodeSize(node);\n const pos = this.config.nodes.iconPosition || 'top-left';\n const padding = size.height * 0.25;\n\n // Label position adjusts based on icon position\n const labelPositions: Record<string, Position> = {\n 'top-left': { x: size.width / 2 + padding / 2, y: size.height / 2 + 4 },\n 'top': { x: size.width / 2, y: size.height / 2 + padding / 2 },\n 'top-right': { x: size.width / 2 - padding / 2, y: size.height / 2 + 4 },\n 'right': { x: size.width / 2 - padding / 2, y: size.height / 2 },\n 'bottom-right': { x: size.width / 2 - padding / 2, y: size.height / 2 - 4 },\n 'bottom': { x: size.width / 2, y: size.height / 2 - padding / 2 },\n 'bottom-left': { x: size.width / 2 + padding / 2, y: size.height / 2 - 4 },\n 'left': { x: size.width / 2 + padding / 2, y: size.height / 2 }\n };\n\n return labelPositions[pos] || labelPositions['top-left'];\n }\n\n private findNodeAtPosition(pos: Position): string | null {\n for (const node of this.internalGraph().nodes) {\n const size = this.getNodeSize(node);\n if (\n pos.x >= node.position.x &&\n pos.x <= node.position.x + size.width &&\n pos.y >= node.position.y &&\n pos.y <= node.position.y + size.height\n ) {\n return node.id;\n }\n }\n return null;\n }\n\n private findEdgeAtPosition(pos: Position): string | null {\n const hitDistance = 10; // pixels tolerance\n for (const edge of this.internalGraph().edges) {\n const sourcePoint = this.getEdgeSourcePoint(edge);\n const targetPoint = this.getEdgeTargetPoint(edge);\n\n // Calculate distance from point to line segment\n const dist = this.pointToSegmentDistance(pos, sourcePoint, targetPoint);\n if (dist < hitDistance) {\n return edge.id;\n }\n }\n return null;\n }\n\n private pointToSegmentDistance(point: Position, lineStart: Position, lineEnd: Position): number {\n const dx = lineEnd.x - lineStart.x;\n const dy = lineEnd.y - lineStart.y;\n const lengthSquared = dx * dx + dy * dy;\n\n if (lengthSquared === 0) {\n // Line segment is a point\n return Math.sqrt((point.x - lineStart.x) ** 2 + (point.y - lineStart.y) ** 2);\n }\n\n // Project point onto line segment\n let t = ((point.x - lineStart.x) * dx + (point.y - lineStart.y) * dy) / lengthSquared;\n t = Math.max(0, Math.min(1, t));\n\n const projX = lineStart.x + t * dx;\n const projY = lineStart.y + t * dy;\n\n return Math.sqrt((point.x - projX) ** 2 + (point.y - projY) ** 2);\n }\n\n getNodePorts(node: GraphNode): Array<{ position: 'top' | 'bottom' | 'left' | 'right'; x: number; y: number }> {\n const size = this.getNodeSize(node);\n return [\n { position: 'top', x: size.width / 2, y: 0 },\n { position: 'bottom', x: size.width / 2, y: size.height },\n { position: 'left', x: 0, y: size.height / 2 },\n { position: 'right', x: size.width, y: size.height / 2 }\n ];\n }\n\n private findClosestPort(nodeId: string, worldPos: Position): { port: 'top' | 'bottom' | 'left' | 'right'; distance: number } | null {\n const node = this.internalGraph().nodes.find(n => n.id === nodeId);\n if (!node) return null;\n\n const ports = this.getNodePorts(node);\n let closestPort: typeof ports[0] | null = null;\n let minDistance = Infinity;\n\n for (const port of ports) {\n const portWorldX = node.position.x + port.x;\n const portWorldY = node.position.y + port.y;\n const dx = worldPos.x - portWorldX;\n const dy = worldPos.y - portWorldY;\n const distance = Math.sqrt(dx * dx + dy * dy);\n\n if (distance < minDistance) {\n minDistance = distance;\n closestPort = port;\n }\n }\n\n return closestPort ? { port: closestPort.position, distance: minDistance } : null;\n }\n\n private getPortWorldPosition(node: GraphNode, port: 'top' | 'bottom' | 'left' | 'right'): Position {\n const size = this.getNodeSize(node);\n const portOffsets = {\n top: { x: size.width / 2, y: 0 },\n bottom: { x: size.width / 2, y: size.height },\n left: { x: 0, y: size.height / 2 },\n right: { x: size.width, y: size.height / 2 }\n };\n\n const offset = portOffsets[port];\n return {\n x: node.position.x + offset.x,\n y: node.position.y + offset.y\n };\n }\n\n private findClosestPortForEdge(\n node: GraphNode,\n otherNode: GraphNode,\n endpoint: 'source' | 'target'\n ): 'top' | 'bottom' | 'left' | 'right' {\n const size = this.getNodeSize(node);\n const nodeCenter = {\n x: node.position.x + size.width / 2,\n y: node.position.y + size.height / 2\n };\n const otherSize = this.getNodeSize(otherNode);\n const otherCenter = {\n x: otherNode.position.x + otherSize.width / 2,\n y: otherNode.position.y + otherSize.height / 2\n };\n\n const dx = otherCenter.x - nodeCenter.x;\n const dy = otherCenter.y - nodeCenter.y;\n\n // Determine which port is closest based on relative position\n const absDx = Math.abs(dx);\n const absDy = Math.abs(dy);\n\n if (absDx > absDy) {\n // Horizontal connection\n return dx > 0 ? 'right' : 'left';\n } else {\n // Vertical connection\n return dy > 0 ? 'bottom' : 'top';\n }\n }\n}\n","<div class=\"graph-editor-container\">\n <!-- Canvas with overlaid palette -->\n <div class=\"graph-canvas-wrapper\">\n <!-- Top-left horizontal palette overlay -->\n @if (config.palette?.enabled !== false) {\n <div class=\"graph-palette-overlay\">\n <!-- Tools -->\n <button\n class=\"palette-item tool-item\"\n [class.active]=\"activeTool() === 'hand'\"\n title=\"Hand tool (move nodes)\"\n (click)=\"switchTool('hand')\"\n >\n <span class=\"icon\">✋</span>\n </button>\n <button\n class=\"palette-item tool-item\"\n [class.active]=\"activeTool() === 'line'\"\n title=\"Line tool (draw connections)\"\n (click)=\"switchTool('line')\"\n >\n <span class=\"icon\">∕</span>\n </button>\n\n <!-- Divider -->\n <div class=\"palette-divider\"></div>\n\n <!-- Node types -->\n @for (nodeType of config.nodes.types; track nodeType.type) {\n <button\n class=\"palette-item\"\n [attr.data-node-type]=\"nodeType.type\"\n [attr.title]=\"nodeType.label || nodeType.type\"\n (click)=\"addNode(nodeType.type)\"\n >\n @if (nodeType.defaultData['imageUrl']) {\n <img\n class=\"palette-icon-img\"\n [src]=\"nodeType.defaultData['imageUrl']\"\n [alt]=\"nodeType.label || nodeType.type\"\n />\n } @else {\n <span class=\"icon\">{{ nodeType.icon || '●' }}</span>\n }\n </button>\n }\n </div>\n }\n\n <svg\n #canvasSvg\n [class.tool-line]=\"activeTool() === 'line'\"\n [attr.width]=\"'100%'\"\n [attr.height]=\"'100%'\"\n (mousedown)=\"onCanvasMouseDown($event)\"\n (mousemove)=\"onCanvasMouseMove($event)\"\n (mouseup)=\"onCanvasMouseUp($event)\"\n (wheel)=\"onWheel($event)\"\n (contextmenu)=\"onContextMenu($event)\"\n >\n <!-- Arrow marker definitions -->\n <defs>\n <marker id=\"arrow-end\" viewBox=\"0 0 10 10\" refX=\"9\" refY=\"5\"\n markerWidth=\"8\" markerHeight=\"8\" orient=\"auto\">\n <path d=\"M 0 1 L 8 5 L 0 9 z\" fill=\"#94a3b8\"/>\n </marker>\n <marker id=\"arrow-end-selected\" viewBox=\"0 0 10 10\" refX=\"9\" refY=\"5\"\n markerWidth=\"8\" markerHeight=\"8\" orient=\"auto\">\n <path d=\"M 0 1 L 8 5 L 0 9 z\" fill=\"#3b82f6\"/>\n </marker>\n <marker id=\"arrow-start\" viewBox=\"0 0 10 10\" refX=\"1\" refY=\"5\"\n markerWidth=\"8\" markerHeight=\"8\" orient=\"auto\">\n <path d=\"M 10 1 L 2 5 L 10 9 z\" fill=\"#94a3b8\"/>\n </marker>\n <marker id=\"arrow-start-selected\" viewBox=\"0 0 10 10\" refX=\"1\" refY=\"5\"\n markerWidth=\"8\" markerHeight=\"8\" orient=\"auto\">\n <path d=\"M 10 1 L 2 5 L 10 9 z\" fill=\"#3b82f6\"/>\n </marker>\n </defs>\n\n <!-- Main transform group (pan + zoom) -->\n <g [attr.transform]=\"transform()\">\n <!-- Grid (if enabled) -->\n <!-- Grid (if enabled) - extended to cover viewport during pan -->\n @if (config.canvas?.grid?.enabled) {\n <defs>\n <pattern\n id=\"grid\"\n [attr.width]=\"config.canvas!.grid!.size\"\n [attr.height]=\"config.canvas!.grid!.size\"\n patternUnits=\"userSpaceOnUse\"\n >\n <path\n [attr.d]=\"'M ' + config.canvas!.grid!.size + ' 0 L 0 0 0 ' + config.canvas!.grid!.size\"\n fill=\"none\"\n [attr.stroke]=\"config.canvas!.grid!.color || '#e0e0e0'\"\n stroke-width=\"1\"\n />\n </pattern>\n </defs>\n <!-- Extended grid background covering viewport + pan offset -->\n <rect\n [attr.x]=\"gridBounds().x\"\n [attr.y]=\"gridBounds().y\"\n [attr.width]=\"gridBounds().width\"\n [attr.height]=\"gridBounds().height\"\n fill=\"url(#grid)\"\n />\n }\n\n <!-- Layer 0.5: Preview line for line tool (rubber-band) -->\n @if (previewLine()) {\n <line\n class=\"preview-line\"\n [attr.x1]=\"previewLine()!.source.x\"\n [attr.y1]=\"previewLine()!.source.y\"\n [attr.x2]=\"previewLine()!.target.x\"\n [attr.y2]=\"previewLine()!.target.y\"\n stroke=\"#3b82f6\"\n stroke-width=\"2.5\"\n stroke-dasharray=\"8,6\"\n stroke-linecap=\"round\"\n opacity=\"0.7\"\n />\n }\n\n <!-- Layer 1: Edge paths (behind everything) -->\n @for (edge of internalGraph().edges; track edge.id) {\n <!-- Edge shadow for depth (optional) -->\n @if (shadowsEnabled()) {\n <path\n class=\"edge-shadow\"\n [attr.d]=\"getEdgePath(edge)\"\n stroke=\"rgba(0,0,0,0.06)\"\n stroke-width=\"6\"\n fill=\"none\"\n stroke-linecap=\"round\"\n [attr.transform]=\"'translate(1, 2)'\"\n />\n }\n <!-- Invisible wide hit-area for easier clicking (hand tool only) -->\n <path\n [attr.d]=\"getEdgePath(edge)\"\n stroke=\"transparent\"\n [attr.stroke-width]=\"20\"\n fill=\"none\"\n class=\"edge-hit-area\"\n [attr.pointer-events]=\"activeTool() === 'hand' ? 'stroke' : 'none'\"\n (click)=\"onEdgeClick($event, edge)\"\n (dblclick)=\"onEdgeDoubleClick($event, edge)\"\n />\n <!-- Visible edge line -->\n <path\n class=\"edge-line\"\n [attr.d]=\"getEdgePath(edge)\"\n [attr.stroke]=\"selection().edges.includes(edge.id) ? '#3b82f6' : '#94a3b8'\"\n [attr.stroke-width]=\"selection().edges.includes(edge.id) ? 2.5 : 2\"\n fill=\"none\"\n stroke-linecap=\"round\"\n [class.selected]=\"selection().edges.includes(edge.id)\"\n [attr.marker-end]=\"getEdgeMarkerEnd(edge)\"\n [attr.marker-start]=\"getEdgeMarkerStart(edge)\"\n pointer-events=\"none\"\n />\n }\n\n <!-- Layer 2: Nodes -->\n @for (node of internalGraph().nodes; track node.id) {\n <g\n [attr.transform]=\"'translate(' + node.position.x + ',' + node.position.y + ')'\"\n class=\"graph-node\"\n [class.selected]=\"selection().nodes.includes(node.id)\"\n [attr.data-node-id]=\"node.id\"\n (mousedown)=\"onNodeMouseDown($event, node)\"\n (click)=\"onNodeClick($event, node)\"\n (dblclick)=\"nodeDoubleClick.emit(node)\"\n >\n <!-- Node shadow (optional) -->\n @if (shadowsEnabled()) {\n <rect\n class=\"node-shadow\"\n [attr.width]=\"getNodeSize(node).width\"\n [attr.height]=\"getNodeSize(node).height\"\n fill=\"rgba(0,0,0,0.08)\"\n rx=\"12\"\n transform=\"translate(2, 3)\"\n style=\"filter: blur(4px);\"\n />\n }\n <!-- Node background -->\n <rect\n class=\"node-bg\"\n [attr.width]=\"getNodeSize(node).width\"\n [attr.height]=\"getNodeSize(node).height\"\n fill=\"white\"\n [attr.stroke]=\"selection().nodes.includes(node.id) ? '#3b82f6' : '#e2e8f0'\"\n [attr.stroke-width]=\"selection().nodes.includes(node.id) ? 2.5 : 1.5\"\n rx=\"12\"\n />\n\n <!-- Node type icon (text/emoji) or custom image -->\n @if (getNodeImage(node)) {\n <image\n class=\"node-image\"\n [attr.href]=\"getNodeImage(node)\"\n [attr.xlink:href]=\"getNodeImage(node)\"\n [attr.x]=\"getImagePosition(node).x\"\n [attr.y]=\"getImagePosition(node).y\"\n [attr.width]=\"getImageSize(node)\"\n [attr.height]=\"getImageSize(node)\"\n preserveAspectRatio=\"xMidYMid meet\"\n />\n } @else {\n <text\n class=\"node-icon\"\n [attr.x]=\"getIconPosition(node).x\"\n [attr.y]=\"getIconPosition(node).y\"\n text-anchor=\"middle\"\n dominant-baseline=\"middle\"\n [attr.font-size]=\"getNodeSize(node).height * 0.28\"\n >\n {{ getNodeTypeIcon(node) }}\n </text>\n }\n\n <!-- Node label -->\n <text\n class=\"node-label\"\n [attr.x]=\"getLabelPosition(node).x\"\n [attr.y]=\"getLabelPosition(node).y\"\n text-anchor=\"middle\"\n dominant-baseline=\"middle\"\n font-size=\"14\"\n font-weight=\"500\"\n fill=\"#1e293b\"\n >\n {{ node.data['name'] || node.type }}\n </text>\n </g>\n }\n\n <!-- Layer 3: Attachment points (on top of nodes) -->\n @for (node of internalGraph().nodes; track node.id) {\n @if (showAttachmentPoints() === node.id) {\n <g [attr.transform]=\"'translate(' + node.position.x + ',' + node.position.y + ')'\">\n @for (port of getNodePorts(node); track port.position) {\n <circle\n [attr.cx]=\"port.x\"\n [attr.cy]=\"port.y\"\n [attr.r]=\"hoveredPort?.nodeId === node.id && hoveredPort?.port === port.position ? 8 : 6\"\n [attr.fill]=\"hoveredPort?.nodeId === node.id && hoveredPort?.port === port.position ? '#2563eb' : '#94a3b8'\"\n stroke=\"white\"\n stroke-width=\"2\"\n class=\"attachment-point\"\n [class.hovered]=\"hoveredPort?.nodeId === node.id && hoveredPort?.port === port.position\"\n (mousedown)=\"$event.stopPropagation()\"\n (click)=\"onAttachmentPointClick($event, node, port.position)\"\n />\n }\n </g>\n }\n }\n\n <!-- Layer 4: Edge endpoints (only visible when edge is selected) -->\n @for (edge of internalGraph().edges; track edge.id) {\n @if (selection().edges.includes(edge.id)) {\n <g>\n <!-- Source endpoint -->\n <circle\n [attr.cx]=\"getEdgeSourcePoint(edge).x\"\n [attr.cy]=\"getEdgeSourcePoint(edge).y\"\n r=\"6\"\n fill=\"#3b82f6\"\n stroke=\"white\"\n stroke-width=\"2\"\n class=\"edge-endpoint selected\"\n (mousedown)=\"onEdgeEndpointMouseDown($event, edge, 'source')\"\n />\n\n <!-- Target endpoint -->\n <circle\n [attr.cx]=\"getEdgeTargetPoint(edge).x\"\n [attr.cy]=\"getEdgeTargetPoint(edge).y\"\n r=\"6\"\n fill=\"#3b82f6\"\n stroke=\"white\"\n stroke-width=\"2\"\n class=\"edge-endpoint selected\"\n (mousedown)=\"onEdgeEndpointMouseDown($event, edge, 'target')\"\n />\n </g>\n }\n }\n\n <!-- Layer 5: Selection box (Shift+drag) -->\n @if (selectionBox()) {\n <rect\n class=\"selection-box\"\n [attr.x]=\"selectionBox()!.x\"\n [attr.y]=\"selectionBox()!.y\"\n [attr.width]=\"selectionBox()!.width\"\n [attr.height]=\"selectionBox()!.height\"\n fill=\"rgba(59, 130, 246, 0.1)\"\n stroke=\"#3b82f6\"\n stroke-width=\"1\"\n stroke-dasharray=\"4,2\"\n />\n }\n </g>\n </svg>\n </div>\n\n <!-- Edge direction selector overlay -->\n @if (selectedEdgeMidpoint()) {\n <div\n class=\"edge-direction-selector\"\n [style.left.px]=\"selectedEdgeMidpoint()!.x\"\n [style.top.px]=\"selectedEdgeMidpoint()!.y\"\n >\n <button\n class=\"direction-btn\"\n [class.active]=\"selectedEdgeMidpoint()!.edge.direction === 'backward'\"\n title=\"Backward\"\n (click)=\"setEdgeDirection('backward')\"\n >←</button>\n <button\n class=\"direction-btn\"\n [class.active]=\"selectedEdgeMidpoint()!.edge.direction === 'bidirectional'\"\n title=\"Bidirectional\"\n (click)=\"setEdgeDirection('bidirectional')\"\n >↔</button>\n <button\n class=\"direction-btn\"\n [class.active]=\"!selectedEdgeMidpoint()!.edge.direction || selectedEdgeMidpoint()!.edge.direction === 'forward'\"\n title=\"Forward\"\n (click)=\"setEdgeDirection('forward')\"\n >→</button>\n </div>\n }\n <!-- Validation errors -->\n @if (validationResult() && !validationResult()!.valid) {\n <div class=\"validation-panel\">\n <h4>Validation Errors</h4>\n @for (error of validationResult()!.errors; track error.rule) {\n <div class=\"error-item\" [class.warning]=\"error.severity === 'warning'\">\n {{ error.message }}\n </div>\n }\n </div>\n }\n</div>\n","// Main component\nexport { GraphEditorComponent } from './lib/graph-editor.component';\n\n// Data model - use 'export type' for re-exports when isolatedModules is enabled\nexport type {\n Graph,\n GraphNode,\n GraphEdge,\n Position,\n NodeMetadata,\n EdgeMetadata,\n EdgeStyle,\n GraphMetadata\n} from './lib/graph.model';\n\n// Configuration - use 'export type' for re-exports\nexport type {\n GraphEditorConfig,\n NodesConfig,\n EdgesConfig,\n CanvasConfig,\n ValidationConfig,\n LayoutConfig,\n InteractionConfig,\n ThemeConfig,\n PaletteConfig,\n NodeTypeDefinition,\n PortConfig,\n PortDefinition,\n NodeConstraints,\n GridConfig,\n ZoomConfig,\n PanConfig,\n ValidationRule,\n ValidationError,\n LayoutOptions,\n ContextMenuConfig,\n ContextMenuItem,\n ContextMenuContext,\n SelectionState,\n ValidationResult,\n ContextMenuEvent\n} from './lib/graph-editor.config';","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"utisha-graph-editor.mjs","sources":["../../../projects/graph-editor/src/lib/services/graph-history.service.ts","../../../projects/graph-editor/src/lib/graph-editor.component.ts","../../../projects/graph-editor/src/lib/graph-editor.component.html","../../../projects/graph-editor/src/lib/icons/workflow-icons.ts","../../../projects/graph-editor/src/public-api.ts","../../../projects/graph-editor/src/utisha-graph-editor.ts"],"sourcesContent":["import { Injectable, signal } from '@angular/core';\nimport { Graph } from '../graph.model';\n\n/**\n * Service for managing undo/redo history of graph state.\n * \n * Uses a simple snapshot-based approach where each history entry\n * is a deep copy of the entire graph state.\n */\n@Injectable()\nexport class GraphHistoryService {\n private history: Graph[] = [];\n private historyIndex = -1;\n private maxHistorySize = 100;\n \n /** Signal to track if an undo/redo operation is in progress */\n readonly isUndoRedo = signal(false);\n\n /**\n * Initialize history with the given graph state.\n * Clears any existing history.\n */\n init(graph: Graph): void {\n this.history = [structuredClone(graph)];\n this.historyIndex = 0;\n }\n\n /**\n * Push a new state to the history stack.\n * If we're not at the end of history, truncates future states.\n * Prevents duplicate consecutive states.\n * \n * @returns true if state was pushed, false if it was a duplicate\n */\n push(graph: Graph): boolean {\n const currentState = structuredClone(graph);\n \n // Don't push if state hasn't changed\n if (this.historyIndex >= 0 && this.historyIndex < this.history.length) {\n const lastState = this.history[this.historyIndex];\n if (JSON.stringify(lastState) === JSON.stringify(currentState)) {\n return false;\n }\n }\n \n // If we're not at the end of history, truncate future states\n if (this.historyIndex < this.history.length - 1) {\n this.history = this.history.slice(0, this.historyIndex + 1);\n }\n \n // Add new state\n this.history.push(currentState);\n this.historyIndex = this.history.length - 1;\n \n // Enforce max history size\n if (this.history.length > this.maxHistorySize) {\n this.history.shift();\n this.historyIndex--;\n }\n \n return true;\n }\n\n /**\n * Undo the last action.\n * @returns The previous graph state, or null if nothing to undo\n */\n undo(): Graph | null {\n if (this.historyIndex <= 0) {\n return null;\n }\n \n this.historyIndex--;\n this.isUndoRedo.set(true);\n const state = structuredClone(this.history[this.historyIndex]);\n // Note: caller should set isUndoRedo back to false after applying state\n return state;\n }\n\n /**\n * Redo the last undone action.\n * @returns The next graph state, or null if nothing to redo\n */\n redo(): Graph | null {\n if (this.historyIndex >= this.history.length - 1) {\n return null;\n }\n \n this.historyIndex++;\n this.isUndoRedo.set(true);\n const state = structuredClone(this.history[this.historyIndex]);\n // Note: caller should set isUndoRedo back to false after applying state\n return state;\n }\n\n /**\n * Complete an undo/redo operation.\n * Call this after applying the state returned by undo() or redo().\n */\n completeUndoRedo(): void {\n this.isUndoRedo.set(false);\n }\n\n /** Check if undo is available */\n canUndo(): boolean {\n return this.historyIndex > 0;\n }\n\n /** Check if redo is available */\n canRedo(): boolean {\n return this.historyIndex < this.history.length - 1;\n }\n\n /** Clear history and reset to given state */\n clear(graph: Graph): void {\n this.init(graph);\n }\n\n /** Get current history size */\n get size(): number {\n return this.history.length;\n }\n\n /** Get current position in history (0-indexed) */\n get position(): number {\n return this.historyIndex;\n }\n\n /** Set maximum history size */\n setMaxSize(size: number): void {\n this.maxHistorySize = size;\n // Trim history if necessary\n while (this.history.length > this.maxHistorySize) {\n this.history.shift();\n this.historyIndex--;\n }\n }\n}\n","import {\n ChangeDetectionStrategy,\n Component,\n computed,\n ElementRef,\n EventEmitter,\n inject,\n Input,\n OnChanges,\n OnInit,\n Output,\n signal,\n SimpleChanges,\n viewChild\n} from '@angular/core';\n// dagre is loaded dynamically in applyLayout() to avoid compile-time resolution issues\nimport {Graph, GraphEdge, GraphNode, Position} from './graph.model';\nimport {ContextMenuEvent, GraphEditorConfig, NodeTypeDefinition, SelectionState, ValidationResult} from './graph-editor.config';\nimport {GraphHistoryService} from './services/graph-history.service';\nimport {SvgIconDefinition} from './icons/workflow-icons';\n\n/**\n * Main graph editor component.\n *\n * @example\n * <graph-editor\n * [config]=\"editorConfig\"\n * [graph]=\"currentGraph()\"\n * (graphChange)=\"onGraphChange($event)\"\n * />\n */\n@Component({\n selector: 'graph-editor',\n standalone: true,\n imports: [],\n providers: [GraphHistoryService],\n host: {\n 'tabindex': '0',\n 'style': 'outline: none;',\n '(keydown)': 'onKeyDown($event)'\n },\n templateUrl: './graph-editor.component.html',\n styleUrl: './graph-editor.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class GraphEditorComponent implements OnInit, OnChanges {\n // Inputs\n @Input({ required: true }) config!: GraphEditorConfig;\n @Input() graph: Graph = { nodes: [], edges: [] };\n @Input() readonly = false;\n @Input() visualizationMode = false;\n @Input() overlayData?: Map<string, any>;\n\n // Outputs\n @Output() graphChange = new EventEmitter<Graph>();\n @Output() nodeAdded = new EventEmitter<GraphNode>();\n @Output() nodeUpdated = new EventEmitter<GraphNode>();\n @Output() nodeRemoved = new EventEmitter<GraphNode>();\n @Output() edgeAdded = new EventEmitter<GraphEdge>();\n @Output() edgeUpdated = new EventEmitter<GraphEdge>();\n @Output() edgeRemoved = new EventEmitter<GraphEdge>();\n @Output() selectionChange = new EventEmitter<SelectionState>();\n @Output() validationChange = new EventEmitter<ValidationResult>();\n @Output() nodeClick = new EventEmitter<GraphNode>();\n @Output() nodeDoubleClick = new EventEmitter<GraphNode>();\n @Output() edgeClick = new EventEmitter<GraphEdge>();\n @Output() edgeDoubleClick = new EventEmitter<GraphEdge>();\n @Output() canvasClick = new EventEmitter<Position>();\n @Output() contextMenu = new EventEmitter<ContextMenuEvent>();\n\n private readonly canvasSvgRef = viewChild<ElementRef>('canvasSvg');\n private readonly historyService = inject(GraphHistoryService);\n\n // Internal state\n internalGraph = signal<Graph>({ nodes: [], edges: [] });\n selection = signal<SelectionState>({ nodes: [], edges: [] });\n validationResult = signal<ValidationResult | null>(null);\n\n // Pan & Zoom state\n panX = signal(0);\n panY = signal(0);\n scale = signal(1);\n\n // Dragging state\n private draggedNode: GraphNode | null = null;\n private dragOffset: Position = { x: 0, y: 0 };\n private draggedNodeOffsets: Map<string, Position> = new Map(); // For multi-node drag\n private didDrag = false; // Track if actual dragging occurred (to suppress click after drag)\n private isPanning = false;\n private lastMousePos: Position = { x: 0, y: 0 };\n private draggedEdge: { edge: GraphEdge; endpoint: 'source' | 'target' } | null = null;\n private hoveredNodeId: string | null = null;\n hoveredPort: { nodeId: string; port: 'top' | 'bottom' | 'left' | 'right' } | null = null;\n\n // Attachment points visibility\n showAttachmentPoints = signal<string | null>(null); // nodeId to show ports for\n\n // Active tool\n activeTool = signal<'hand' | 'line'>('hand');\n\n // Line tool state\n private pendingEdge: { sourceId: string; sourcePort: 'top' | 'bottom' | 'left' | 'right' } | null = null;\n\n // Preview line for line tool (rubber-band from source to cursor)\n previewLine = signal<{ source: Position; target: Position } | null>(null);\n\n // Box selection state (Shift+drag)\n private isBoxSelecting = false;\n private boxSelectStart: Position = { x: 0, y: 0 };\n selectionBox = signal<{ x: number; y: number; width: number; height: number } | null>(null);\n\n // Computed\n transform = computed(() =>\n `translate(${this.panX()}, ${this.panY()}) scale(${this.scale()})`\n );\n\n gridBounds = computed(() => {\n const gridSize = this.config.canvas?.grid?.size || 20;\n const viewportWidth = 10000; // Large enough to cover any reasonable viewport\n const viewportHeight = 10000;\n\n // Calculate grid offset to align with pan\n const x = Math.floor(-this.panX() / this.scale() / gridSize) * gridSize - viewportWidth / 2;\n const y = Math.floor(-this.panY() / this.scale() / gridSize) * gridSize - viewportHeight / 2;\n\n return {\n x,\n y,\n width: viewportWidth * 2,\n height: viewportHeight * 2\n };\n });\n\n // Shadow configuration (defaults to true)\n shadowsEnabled = computed(() => this.config.theme?.shadows !== false);\n\n // Selected edge info for direction selector positioning\n selectedEdgeMidpoint = computed(() => {\n const sel = this.selection();\n if (sel.edges.length !== 1) return null;\n const edge = this.internalGraph().edges.find(e => e.id === sel.edges[0]);\n if (!edge) return null;\n\n const sourcePoint = this.getEdgeSourcePoint(edge);\n const targetPoint = this.getEdgeTargetPoint(edge);\n const midX = (sourcePoint.x + targetPoint.x) / 2;\n const midY = (sourcePoint.y + targetPoint.y) / 2;\n\n return {\n edge,\n x: midX * this.scale() + this.panX(),\n y: midY * this.scale() + this.panY()\n };\n });\n\n constructor() {}\n\n ngOnChanges(changes: SimpleChanges) {\n // Sync graph input to internal signal\n if (changes['graph'] && changes['graph'].currentValue) {\n this.internalGraph.set(structuredClone(changes['graph'].currentValue));\n }\n }\n\n ngOnInit() {\n // Initialize with current graph value\n if (this.graph) {\n this.internalGraph.set(structuredClone(this.graph));\n }\n this.validate();\n // Initialize history with starting state\n this.historyService.init(this.internalGraph());\n }\n\n // Node operations\n addNode(type: string, position?: Position): GraphNode {\n const nodeConfig = this.config.nodes.types.find(t => t.type === type);\n if (!nodeConfig) {\n throw new Error(`Unknown node type: ${type}`);\n }\n\n const newNode: GraphNode = {\n id: this.generateId(),\n type,\n data: structuredClone(nodeConfig.defaultData),\n position: position || { x: 100, y: 100 }\n };\n\n const graph = this.internalGraph();\n this.internalGraph.set({\n ...graph,\n nodes: [...graph.nodes, newNode]\n });\n\n this.emitGraphChange();\n this.nodeAdded.emit(newNode);\n this.switchTool('hand');\n return newNode;\n }\n\n removeNode(nodeId: string, removeAttachedEdges = false): void {\n const graph = this.internalGraph();\n const removedNode = graph.nodes.find(n => n.id === nodeId);\n this.internalGraph.set({\n ...graph,\n nodes: graph.nodes.filter(n => n.id !== nodeId),\n edges: removeAttachedEdges\n ? graph.edges.filter(e => e.source !== nodeId && e.target !== nodeId)\n : graph.edges\n });\n this.selection.set({ nodes: [], edges: [] });\n this.emitGraphChange();\n if (removedNode) this.nodeRemoved.emit(removedNode);\n }\n\n removeEdge(edgeId: string): void {\n const graph = this.internalGraph();\n const removedEdge = graph.edges.find(e => e.id === edgeId);\n this.internalGraph.set({\n ...graph,\n edges: graph.edges.filter(e => e.id !== edgeId)\n });\n this.selection.set({ nodes: [], edges: [] });\n this.emitGraphChange();\n if (removedEdge) this.edgeRemoved.emit(removedEdge);\n }\n\n updateNode(nodeId: string, updates: Partial<GraphNode>): void {\n const graph = this.internalGraph();\n const nodeIndex = graph.nodes.findIndex(n => n.id === nodeId);\n if (nodeIndex === -1) return;\n\n const updatedNodes = [...graph.nodes];\n updatedNodes[nodeIndex] = { ...updatedNodes[nodeIndex], ...updates };\n\n this.internalGraph.set({\n ...graph,\n nodes: updatedNodes\n });\n this.emitGraphChange();\n }\n\n // Selection\n selectNode(nodeId: string | null): void {\n if (nodeId === null) {\n this.selection.set({ nodes: [], edges: [] });\n } else {\n this.selection.set({ nodes: [nodeId], edges: [] });\n }\n this.selectionChange.emit(this.selection());\n }\n\n selectEdge(edgeId: string | null): void {\n if (edgeId === null) {\n this.selection.set({ nodes: [], edges: [] });\n } else {\n this.selection.set({ nodes: [], edges: [edgeId] });\n }\n this.selectionChange.emit(this.selection());\n }\n\n /** Toggle a node in/out of the current selection (for Ctrl+Click) */\n toggleNodeSelection(nodeId: string): void {\n const sel = this.selection();\n const isSelected = sel.nodes.includes(nodeId);\n if (isSelected) {\n // Remove from selection\n this.selection.set({\n nodes: sel.nodes.filter(id => id !== nodeId),\n edges: sel.edges\n });\n } else {\n // Add to selection\n this.selection.set({\n nodes: [...sel.nodes, nodeId],\n edges: sel.edges\n });\n }\n this.selectionChange.emit(this.selection());\n }\n\n /** Toggle an edge in/out of the current selection (for Ctrl+Click) */\n toggleEdgeSelection(edgeId: string): void {\n const sel = this.selection();\n const isSelected = sel.edges.includes(edgeId);\n if (isSelected) {\n // Remove from selection\n this.selection.set({\n nodes: sel.nodes,\n edges: sel.edges.filter(id => id !== edgeId)\n });\n } else {\n // Add to selection\n this.selection.set({\n nodes: sel.nodes,\n edges: [...sel.edges, edgeId]\n });\n }\n this.selectionChange.emit(this.selection());\n }\n\n onKeyDown(event: KeyboardEvent): void {\n if (this.readonly || this.config.interaction?.readonly) return;\n\n // Escape: cancel line drawing, clear selection\n if (event.key === 'Escape') {\n this.pendingEdge = null;\n this.previewLine.set(null);\n this.selection.set({ nodes: [], edges: [] });\n this.selectionChange.emit(this.selection());\n this.showAttachmentPoints.set(null);\n event.preventDefault();\n return;\n }\n\n // Undo: Ctrl+Z (or Cmd+Z on Mac)\n if ((event.ctrlKey || event.metaKey) && event.key === 'z' && !event.shiftKey) {\n if (this.undo()) {\n event.preventDefault();\n }\n return;\n }\n\n // Redo: Ctrl+Y or Ctrl+Shift+Z (or Cmd+Y / Cmd+Shift+Z on Mac)\n if ((event.ctrlKey || event.metaKey) && (event.key === 'y' || (event.key === 'z' && event.shiftKey))) {\n if (this.redo()) {\n event.preventDefault();\n }\n return;\n }\n\n if (event.key === 'Delete' || event.key === 'Backspace') {\n const sel = this.selection();\n if (sel.nodes.length === 0 && sel.edges.length === 0) return;\n\n // Batch delete: remove all selected items atomically (single history entry)\n const graph = this.internalGraph();\n const nodeIdsToRemove = new Set(sel.nodes);\n const edgeIdsToRemove = new Set(sel.edges);\n\n // Collect removed items for events\n const removedNodes = graph.nodes.filter(n => nodeIdsToRemove.has(n.id));\n const removedEdges = graph.edges.filter(e => edgeIdsToRemove.has(e.id));\n\n // Filter out selected nodes\n const remainingNodes = graph.nodes.filter(n => !nodeIdsToRemove.has(n.id));\n\n // Filter out selected edges AND edges connected to deleted nodes\n const remainingEdges = graph.edges.filter(e =>\n !edgeIdsToRemove.has(e.id) &&\n !nodeIdsToRemove.has(e.source) &&\n !nodeIdsToRemove.has(e.target)\n );\n\n // Find edges that were removed because they connected to deleted nodes\n const additionalRemovedEdges = graph.edges.filter(e =>\n !edgeIdsToRemove.has(e.id) &&\n (nodeIdsToRemove.has(e.source) || nodeIdsToRemove.has(e.target))\n );\n\n // Update graph atomically (single history push)\n this.internalGraph.set({ ...graph, nodes: remainingNodes, edges: remainingEdges });\n this.emitGraphChange();\n\n // Emit removal events\n for (const edge of removedEdges) {\n this.edgeRemoved.emit(edge);\n }\n for (const edge of additionalRemovedEdges) {\n this.edgeRemoved.emit(edge);\n }\n for (const node of removedNodes) {\n this.nodeRemoved.emit(node);\n }\n\n // Clear selection\n this.selection.set({ nodes: [], edges: [] });\n this.selectionChange.emit(this.selection());\n\n event.preventDefault();\n return;\n }\n\n // Arrow keys: nudge selected node(s) — 1px default, 10px with Shift\n if (event.key.startsWith('Arrow')) {\n const sel = this.selection();\n if (sel.nodes.length === 0) return;\n\n const step = event.shiftKey ? 10 : 1;\n let dx = 0;\n let dy = 0;\n switch (event.key) {\n case 'ArrowUp': dy = -step; break;\n case 'ArrowDown': dy = step; break;\n case 'ArrowLeft': dx = -step; break;\n case 'ArrowRight': dx = step; break;\n }\n\n event.preventDefault();\n\n const graph = this.internalGraph();\n const updatedNodes = [...graph.nodes];\n for (const nodeId of sel.nodes) {\n const idx = updatedNodes.findIndex(n => n.id === nodeId);\n if (idx === -1) continue;\n const pos = updatedNodes[idx].position;\n updatedNodes[idx] = { ...updatedNodes[idx], position: { x: pos.x + dx, y: pos.y + dy } };\n }\n\n // Recalculate edge ports for moved nodes (atomic update)\n const movedIds = new Set(sel.nodes);\n const updatedEdges = graph.edges.map(edge => {\n if (!movedIds.has(edge.source) && !movedIds.has(edge.target)) return edge;\n const sourceNode = updatedNodes.find(n => n.id === edge.source);\n const targetNode = updatedNodes.find(n => n.id === edge.target);\n if (!sourceNode || !targetNode) return edge;\n const newSourcePort = this.findClosestPortForEdge(sourceNode, targetNode, 'source');\n const newTargetPort = this.findClosestPortForEdge(targetNode, sourceNode, 'target');\n if (edge.sourcePort === newSourcePort && edge.targetPort === newTargetPort) return edge;\n return { ...edge, sourcePort: newSourcePort, targetPort: newTargetPort };\n });\n\n this.internalGraph.set({ ...graph, nodes: updatedNodes, edges: updatedEdges });\n this.emitGraphChange();\n }\n }\n\n switchTool(tool: 'hand' | 'line'): void {\n const previousTool = this.activeTool();\n\n // Cancel any in-progress line drawing\n this.pendingEdge = null;\n this.previewLine.set(null);\n this.showAttachmentPoints.set(null);\n\n // Preserve node selection when switching hand → line\n if (!(previousTool === 'hand' && tool === 'line')) {\n this.selection.set({ nodes: [], edges: [] });\n this.selectionChange.emit(this.selection());\n }\n\n this.activeTool.set(tool);\n\n // Hand → line with a node selected: start edge from that node\n if (previousTool === 'hand' && tool === 'line') {\n const sel = this.selection();\n if (sel.nodes.length === 1) {\n this.pendingEdge = { sourceId: sel.nodes[0], sourcePort: 'bottom' };\n }\n }\n }\n\n /** @deprecated Use switchTool('line') instead */\n switchToLineTool(): void {\n this.switchTool('line');\n }\n\n onEdgeClick(event: MouseEvent, edge: GraphEdge): void {\n if (this.activeTool() !== 'hand') return;\n event.stopPropagation();\n if (event.ctrlKey || event.metaKey) {\n // Ctrl/Cmd+Click: toggle edge in selection\n this.toggleEdgeSelection(edge.id);\n } else {\n // Normal click: replace selection with this edge\n this.selectEdge(edge.id);\n }\n this.edgeClick.emit(edge);\n }\n\n onEdgeDoubleClick(event: MouseEvent, edge: GraphEdge): void {\n if (this.activeTool() !== 'hand') return;\n event.stopPropagation();\n this.selectEdge(edge.id);\n this.edgeDoubleClick.emit(edge);\n }\n\n clearSelection(): void {\n this.selection.set({ nodes: [], edges: [] });\n this.selectionChange.emit(this.selection());\n }\n\n // Validation\n validate(): ValidationResult {\n if (!this.config.validation) {\n const result = { valid: true, errors: [] };\n this.validationResult.set(result);\n return result;\n }\n\n const errors = this.config.validation!.validators.flatMap(rule =>\n rule.validator(this.internalGraph(), this.config)\n );\n\n const result = {\n valid: errors.filter(e => e.severity !== 'warning').length === 0,\n errors\n };\n\n this.validationResult.set(result);\n this.validationChange.emit(result);\n return result;\n }\n\n // Layout\n async applyLayout(direction: 'TB' | 'LR' = 'TB'): Promise<void> {\n const graph = this.internalGraph();\n if (graph.nodes.length === 0) return;\n\n // Dynamic import to avoid compile-time module resolution issues\n const dagreModule = await import('dagre');\n const dagre = dagreModule.default ?? dagreModule;\n\n const g = new dagre.graphlib.Graph();\n g.setGraph({\n rankdir: direction,\n nodesep: 60,\n ranksep: 80,\n marginx: 40,\n marginy: 40,\n });\n g.setDefaultEdgeLabel(() => ({}));\n\n for (const node of graph.nodes) {\n const size = this.getNodeSize(node);\n g.setNode(node.id, { width: size.width, height: size.height });\n }\n\n for (const edge of graph.edges) {\n g.setEdge(edge.source, edge.target);\n }\n\n dagre.layout(g);\n\n const updatedNodes = graph.nodes.map(node => {\n const dagreNode = g.node(node.id);\n if (!dagreNode) return node;\n const size = this.getNodeSize(node);\n return {\n ...node,\n position: {\n x: dagreNode.x - size.width / 2,\n y: dagreNode.y - size.height / 2,\n },\n };\n });\n\n // Recalculate edge ports based on new node positions\n const updatedEdges = graph.edges.map(edge => {\n const sourceNode = updatedNodes.find(n => n.id === edge.source);\n const targetNode = updatedNodes.find(n => n.id === edge.target);\n if (!sourceNode || !targetNode) return edge;\n const newSourcePort = this.findClosestPortForEdge(sourceNode, targetNode, 'source');\n const newTargetPort = this.findClosestPortForEdge(targetNode, sourceNode, 'target');\n return { ...edge, sourcePort: newSourcePort, targetPort: newTargetPort };\n });\n\n this.internalGraph.set({ ...graph, nodes: updatedNodes, edges: updatedEdges });\n this.emitGraphChange();\n\n setTimeout(() => this.fitToScreen());\n }\n\n fitToScreen(padding = 40): void {\n const nodes = this.internalGraph().nodes;\n if (nodes.length === 0) return;\n\n // Get SVG element dimensions\n const ref = this.canvasSvgRef();\n const svgEl: SVGSVGElement | null = ref?.nativeElement ?? ref ?? null;\n if (!svgEl || typeof svgEl.getBoundingClientRect !== 'function') return;\n\n const rect = svgEl.getBoundingClientRect();\n const viewW = rect.width;\n const viewH = rect.height;\n if (viewW === 0 || viewH === 0) return;\n\n // Calculate bounding box of all nodes\n let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;\n for (const node of nodes) {\n const size = this.getNodeSize(node);\n minX = Math.min(minX, node.position.x);\n minY = Math.min(minY, node.position.y);\n maxX = Math.max(maxX, node.position.x + size.width);\n maxY = Math.max(maxY, node.position.y + size.height);\n }\n\n const contentW = maxX - minX;\n const contentH = maxY - minY;\n\n // Handle single node or all nodes stacked\n if (contentW <= 0 && contentH <= 0) {\n this.scale.set(1);\n this.panX.set(viewW / 2 - (minX + 110) * 1);\n this.panY.set(viewH / 2 - (minY + 50) * 1);\n return;\n }\n\n // Calculate scale to fit content with padding (cap at 1 to avoid zooming in too much)\n const zoomConfig = this.config.canvas?.zoom;\n const minScale = zoomConfig?.min ?? 0.25;\n const scaleX = contentW > 0 ? (viewW - padding * 2) / contentW : 1;\n const scaleY = contentH > 0 ? (viewH - padding * 2) / contentH : 1;\n const newScale = Math.max(minScale, Math.min(1, Math.min(scaleX, scaleY)));\n\n // Center the content in the viewport\n const centerX = (minX + maxX) / 2;\n const centerY = (minY + maxY) / 2;\n const newPanX = viewW / 2 - centerX * newScale;\n const newPanY = viewH / 2 - centerY * newScale;\n\n this.scale.set(newScale);\n this.panX.set(newPanX);\n this.panY.set(newPanY);\n }\n\n zoomTo(level: number): void {\n const zoomConfig = this.config.canvas?.zoom;\n const min = zoomConfig?.min ?? 0.25;\n const max = zoomConfig?.max ?? 2.0;\n this.scale.set(Math.max(min, Math.min(max, level)));\n }\n\n getSelection(): SelectionState {\n return this.selection();\n }\n\n // Event handlers\n onCanvasMouseDown(event: MouseEvent): void {\n if (this.readonly) return;\n\n // Cancel pending edge on empty space click\n if (this.pendingEdge) {\n this.pendingEdge = null;\n this.previewLine.set(null);\n this.showAttachmentPoints.set(null);\n this.hoveredPort = null;\n this.clearSelection();\n }\n\n const target = event.target as SVGElement;\n const isNode = !!target.closest('.graph-node');\n const isEdgeEndpoint = target.classList.contains('edge-endpoint');\n const isAttachmentPoint = target.classList.contains('attachment-point');\n const isHitArea = target.classList.contains('edge-hit-area');\n const isInteractive = isNode || isEdgeEndpoint || isAttachmentPoint || isHitArea;\n\n if (!isInteractive) {\n const rect = (event.currentTarget as SVGSVGElement).getBoundingClientRect();\n const mouseX = (event.clientX - rect.left - this.panX()) / this.scale();\n const mouseY = (event.clientY - rect.top - this.panY()) / this.scale();\n\n if (event.shiftKey && this.activeTool() === 'hand') {\n // Shift+drag = box selection (only with hand tool)\n this.isBoxSelecting = true;\n this.boxSelectStart = { x: mouseX, y: mouseY };\n this.selectionBox.set({ x: mouseX, y: mouseY, width: 0, height: 0 });\n } else {\n // Normal drag = pan\n this.isPanning = true;\n }\n this.lastMousePos = { x: event.clientX, y: event.clientY };\n this.clearSelection();\n event.preventDefault();\n }\n }\n\n onCanvasMouseMove(event: MouseEvent): void {\n if (this.isBoxSelecting) {\n // Update selection box\n const rect = (event.currentTarget as SVGSVGElement).getBoundingClientRect();\n const mouseX = (event.clientX - rect.left - this.panX()) / this.scale();\n const mouseY = (event.clientY - rect.top - this.panY()) / this.scale();\n\n const x = Math.min(this.boxSelectStart.x, mouseX);\n const y = Math.min(this.boxSelectStart.y, mouseY);\n const width = Math.abs(mouseX - this.boxSelectStart.x);\n const height = Math.abs(mouseY - this.boxSelectStart.y);\n\n this.selectionBox.set({ x, y, width, height });\n } else if (this.isPanning) {\n const dx = event.clientX - this.lastMousePos.x;\n const dy = event.clientY - this.lastMousePos.y;\n this.panX.set(this.panX() + dx);\n this.panY.set(this.panY() + dy);\n this.lastMousePos = { x: event.clientX, y: event.clientY };\n } else if (this.draggedNode) {\n this.didDrag = true; // Mark that dragging occurred\n const rect = (event.currentTarget as SVGSVGElement).getBoundingClientRect();\n const mouseX = (event.clientX - rect.left - this.panX()) / this.scale();\n const mouseY = (event.clientY - rect.top - this.panY()) / this.scale();\n const graph = this.internalGraph();\n const updatedNodes = [...graph.nodes];\n const movedNodeIds = new Set<string>();\n\n // Check if we're dragging multiple selected nodes\n if (this.draggedNodeOffsets.size > 1) {\n // Multi-node drag: move all selected nodes\n for (const [nodeId, offset] of this.draggedNodeOffsets) {\n const nodeIndex = updatedNodes.findIndex(n => n.id === nodeId);\n if (nodeIndex === -1) continue;\n\n let x = mouseX - offset.x;\n let y = mouseY - offset.y;\n\n // Smart snap to grid\n if (this.config.canvas?.grid?.snap) {\n const gridSize = this.config.canvas.grid.size || 20;\n const snapThreshold = gridSize / 4;\n const snapX = Math.round(x / gridSize) * gridSize;\n const snapY = Math.round(y / gridSize) * gridSize;\n if (Math.abs(x - snapX) < snapThreshold) x = snapX;\n if (Math.abs(y - snapY) < snapThreshold) y = snapY;\n }\n\n updatedNodes[nodeIndex] = { ...updatedNodes[nodeIndex], position: { x, y } };\n movedNodeIds.add(nodeId);\n }\n } else {\n // Single node drag\n let x = mouseX - this.dragOffset.x;\n let y = mouseY - this.dragOffset.y;\n\n // Smart snap to grid\n if (this.config.canvas?.grid?.snap) {\n const gridSize = this.config.canvas.grid.size || 20;\n const snapThreshold = gridSize / 4;\n const snapX = Math.round(x / gridSize) * gridSize;\n const snapY = Math.round(y / gridSize) * gridSize;\n if (Math.abs(x - snapX) < snapThreshold) x = snapX;\n if (Math.abs(y - snapY) < snapThreshold) y = snapY;\n }\n\n const nodeIndex = updatedNodes.findIndex(n => n.id === this.draggedNode!.id);\n if (nodeIndex !== -1) {\n updatedNodes[nodeIndex] = { ...updatedNodes[nodeIndex], position: { x, y } };\n movedNodeIds.add(this.draggedNode!.id);\n }\n }\n\n // Recalculate ports for all edges connected to moved nodes\n const updatedEdges = graph.edges.map(edge => {\n if (!movedNodeIds.has(edge.source) && !movedNodeIds.has(edge.target)) return edge;\n const sourceNode = updatedNodes.find(n => n.id === edge.source);\n const targetNode = updatedNodes.find(n => n.id === edge.target);\n if (!sourceNode || !targetNode) return edge;\n const newSourcePort = this.findClosestPortForEdge(sourceNode, targetNode, 'source');\n const newTargetPort = this.findClosestPortForEdge(targetNode, sourceNode, 'target');\n if (edge.sourcePort === newSourcePort && edge.targetPort === newTargetPort) return edge;\n return { ...edge, sourcePort: newSourcePort, targetPort: newTargetPort };\n });\n\n this.internalGraph.set({ ...graph, nodes: updatedNodes, edges: updatedEdges });\n this.emitGraphChange();\n } else if (this.draggedEdge) {\n // Edge reconnection - find hovered node and closest port\n const rect = (event.currentTarget as SVGSVGElement).getBoundingClientRect();\n const mouseX = (event.clientX - rect.left - this.panX()) / this.scale();\n const mouseY = (event.clientY - rect.top - this.panY()) / this.scale();\n\n // Find node under cursor\n const nodeId = this.findNodeAtPosition({ x: mouseX, y: mouseY });\n\n if (nodeId) {\n // Show attachment points for this node\n this.showAttachmentPoints.set(nodeId);\n\n // Find closest port\n const closestPort = this.findClosestPort(nodeId, { x: mouseX, y: mouseY });\n\n // Highlight port if within snap distance (40px)\n if (closestPort && closestPort.distance < 40) {\n this.hoveredPort = { nodeId, port: closestPort.port };\n this.hoveredNodeId = nodeId;\n } else {\n this.hoveredPort = null;\n this.hoveredNodeId = null;\n }\n } else {\n // No node nearby - hide attachment points\n this.showAttachmentPoints.set(null);\n this.hoveredPort = null;\n this.hoveredNodeId = null;\n }\n } else if (this.pendingEdge && this.activeTool() === 'line') {\n // Line tool pending state - show rubber-band preview + attachment points on hovered node\n const rect = (event.currentTarget as SVGSVGElement).getBoundingClientRect();\n const mouseX = (event.clientX - rect.left - this.panX()) / this.scale();\n const mouseY = (event.clientY - rect.top - this.panY()) / this.scale();\n\n // Get source port position\n const sourceNode = this.internalGraph().nodes.find(n => n.id === this.pendingEdge!.sourceId);\n if (sourceNode) {\n const sourcePoint = this.getPortWorldPosition(sourceNode, this.pendingEdge.sourcePort);\n\n // Check if cursor is near a node - snap to its closest port\n const hoveredNodeId = this.findNodeAtPosition({ x: mouseX, y: mouseY });\n let targetPoint: Position = { x: mouseX, y: mouseY };\n\n if (hoveredNodeId && hoveredNodeId !== this.pendingEdge.sourceId) {\n // Show attachment points on hovered node\n this.showAttachmentPoints.set(hoveredNodeId);\n\n // Find and highlight closest port\n const closestPort = this.findClosestPort(hoveredNodeId, { x: mouseX, y: mouseY });\n if (closestPort && closestPort.distance < 40) {\n this.hoveredPort = { nodeId: hoveredNodeId, port: closestPort.port };\n // Snap preview line to port\n const hoveredNode = this.internalGraph().nodes.find(n => n.id === hoveredNodeId);\n if (hoveredNode) {\n targetPoint = this.getPortWorldPosition(hoveredNode, closestPort.port);\n }\n } else {\n this.hoveredPort = null;\n }\n } else {\n // Not over a valid target node - hide attachment points\n this.showAttachmentPoints.set(null);\n this.hoveredPort = null;\n }\n\n this.previewLine.set({ source: sourcePoint, target: targetPoint });\n }\n }\n }\n\n onCanvasMouseUp(_event: MouseEvent): void {\n // Handle box selection completion\n if (this.isBoxSelecting) {\n const box = this.selectionBox();\n if (box && (box.width > 5 || box.height > 5)) {\n // Find all nodes within the selection box\n const selectedNodes: string[] = [];\n for (const node of this.internalGraph().nodes) {\n const size = this.getNodeSize(node);\n const nodeRight = node.position.x + size.width;\n const nodeBottom = node.position.y + size.height;\n const boxRight = box.x + box.width;\n const boxBottom = box.y + box.height;\n\n // Check if node intersects with selection box\n if (node.position.x < boxRight &&\n nodeRight > box.x &&\n node.position.y < boxBottom &&\n nodeBottom > box.y) {\n selectedNodes.push(node.id);\n }\n }\n\n if (selectedNodes.length > 0) {\n // Also select edges where both source and target are selected\n const selectedEdges: string[] = [];\n for (const edge of this.internalGraph().edges) {\n if (selectedNodes.includes(edge.source) && selectedNodes.includes(edge.target)) {\n selectedEdges.push(edge.id);\n }\n }\n this.selection.set({ nodes: selectedNodes, edges: selectedEdges });\n this.selectionChange.emit(this.selection());\n }\n }\n this.isBoxSelecting = false;\n this.selectionBox.set(null);\n }\n\n // Handle edge reconnection with port snapping\n if (this.draggedEdge && this.hoveredNodeId && this.hoveredPort) {\n const graph = this.internalGraph();\n const edgeIndex = graph.edges.findIndex(e => e.id === this.draggedEdge!.edge.id);\n\n if (edgeIndex !== -1) {\n const updatedEdges = [...graph.edges];\n const updatedEdge = { ...updatedEdges[edgeIndex] };\n\n // Update node connection and store port information (non-null: guarded by if condition)\n if (this.draggedEdge.endpoint === 'source') {\n updatedEdge.source = this.hoveredNodeId!;\n updatedEdge.sourcePort = this.hoveredPort!.port;\n } else {\n updatedEdge.target = this.hoveredNodeId!;\n updatedEdge.targetPort = this.hoveredPort!.port;\n }\n\n updatedEdges[edgeIndex] = updatedEdge;\n this.internalGraph.set({ ...graph, edges: updatedEdges });\n this.emitGraphChange();\n this.edgeUpdated.emit(updatedEdge);\n }\n }\n\n this.isPanning = false;\n this.draggedNode = null;\n this.draggedNodeOffsets.clear();\n this.draggedEdge = null;\n this.hoveredNodeId = null;\n this.hoveredPort = null;\n this.showAttachmentPoints.set(null);\n }\n\n onNodeMouseDown(event: MouseEvent, node: GraphNode): void {\n if (this.readonly) return;\n event.stopPropagation(); // Always prevent canvas from seeing node mousedowns\n if (this.activeTool() !== 'hand') return;\n\n this.draggedNode = node;\n this.didDrag = false; // Reset - will be set true if actual movement occurs\n // Calculate offset between mouse position and node origin to prevent jump\n const svg = (event.target as SVGElement).closest('svg')!;\n const rect = svg.getBoundingClientRect();\n const mouseX = (event.clientX - rect.left - this.panX()) / this.scale();\n const mouseY = (event.clientY - rect.top - this.panY()) / this.scale();\n this.dragOffset = {\n x: mouseX - node.position.x,\n y: mouseY - node.position.y\n };\n\n // If this node is part of a multi-selection, calculate offsets for all selected nodes\n const sel = this.selection();\n this.draggedNodeOffsets.clear();\n if (sel.nodes.includes(node.id) && sel.nodes.length > 1) {\n const graph = this.internalGraph();\n for (const nodeId of sel.nodes) {\n const n = graph.nodes.find(nd => nd.id === nodeId);\n if (n) {\n this.draggedNodeOffsets.set(nodeId, {\n x: mouseX - n.position.x,\n y: mouseY - n.position.y\n });\n }\n }\n }\n }\n\n onNodeClick(event: MouseEvent, node: GraphNode): void {\n if (this.activeTool() === 'line') {\n event.stopPropagation();\n\n if (!this.pendingEdge) {\n // First click - start edge from this node\n // Pick initial port based on geometry (will be recalculated on second click)\n this.pendingEdge = { sourceId: node.id, sourcePort: 'bottom' };\n this.selectNode(node.id);\n } else if (this.pendingEdge.sourceId !== node.id) {\n // Second click on different node - complete the edge\n const sourceNode = this.internalGraph().nodes.find(n => n.id === this.pendingEdge!.sourceId);\n if (sourceNode) {\n const sourcePort = this.findClosestPortForEdge(sourceNode, node, 'source');\n const targetPort = this.findClosestPortForEdge(node, sourceNode, 'target');\n\n const newEdge: GraphEdge = {\n id: `edge_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,\n source: this.pendingEdge.sourceId,\n target: node.id,\n sourcePort,\n targetPort\n };\n\n const graph = this.internalGraph();\n this.internalGraph.set({\n ...graph,\n edges: [...graph.edges, newEdge]\n });\n this.emitGraphChange();\n this.edgeAdded.emit(newEdge);\n }\n this.pendingEdge = null;\n this.previewLine.set(null);\n this.showAttachmentPoints.set(null);\n this.hoveredPort = null;\n this.clearSelection();\n } else {\n // Clicked same node - cancel\n this.pendingEdge = null;\n this.previewLine.set(null);\n this.showAttachmentPoints.set(null);\n this.hoveredPort = null;\n this.clearSelection();\n }\n } else {\n // Hand tool - select or toggle selection\n // Skip selection change if we just finished dragging\n if (this.didDrag) {\n this.didDrag = false;\n return;\n }\n if (event.ctrlKey || event.metaKey) {\n // Ctrl/Cmd+Click: toggle node in selection\n this.toggleNodeSelection(node.id);\n } else {\n // Normal click: replace selection with this node\n this.selectNode(node.id);\n }\n }\n }\n\n onAttachmentPointClick(event: MouseEvent, node: GraphNode, port: 'top' | 'bottom' | 'left' | 'right'): void {\n event.stopPropagation();\n if (this.readonly) return;\n\n if (this.activeTool() === 'line') {\n if (!this.pendingEdge) {\n // First click on attachment point - start edge from this specific port\n this.pendingEdge = { sourceId: node.id, sourcePort: port };\n this.selectNode(node.id);\n } else if (this.pendingEdge.sourceId !== node.id) {\n // Second click - complete edge to this specific port\n const sourceNode = this.internalGraph().nodes.find(n => n.id === this.pendingEdge!.sourceId);\n if (sourceNode) {\n const sourcePort = this.findClosestPortForEdge(sourceNode, node, 'source');\n\n const newEdge: GraphEdge = {\n id: `edge_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,\n source: this.pendingEdge.sourceId,\n target: node.id,\n sourcePort,\n targetPort: port\n };\n\n const graph = this.internalGraph();\n this.internalGraph.set({\n ...graph,\n edges: [...graph.edges, newEdge]\n });\n this.emitGraphChange();\n this.edgeAdded.emit(newEdge);\n }\n this.pendingEdge = null;\n this.previewLine.set(null);\n this.showAttachmentPoints.set(null);\n this.hoveredPort = null;\n this.clearSelection();\n } else {\n // Clicked same node - cancel\n this.pendingEdge = null;\n this.previewLine.set(null);\n this.showAttachmentPoints.set(null);\n this.hoveredPort = null;\n this.clearSelection();\n }\n }\n }\n\n onEdgeEndpointMouseDown(event: MouseEvent, edge: GraphEdge, endpoint: 'source' | 'target'): void {\n if (this.readonly) return;\n event.stopPropagation();\n this.draggedEdge = { edge, endpoint };\n }\n\n onWheel(event: WheelEvent): void {\n const zoomConfig = this.config.canvas?.zoom;\n if (!zoomConfig?.wheelEnabled) return;\n\n event.preventDefault();\n const delta = -event.deltaY;\n const step = zoomConfig.step ?? 0.1;\n const newScale = Math.max(\n zoomConfig.min ?? 0.25,\n Math.min(\n zoomConfig.max ?? 2.0,\n this.scale() + (delta > 0 ? step : -step)\n )\n );\n\n this.scale.set(newScale);\n }\n\n onContextMenu(event: MouseEvent): void {\n event.preventDefault();\n\n const svgRect = this.canvasSvgRef()?.nativeElement.getBoundingClientRect();\n if (!svgRect) return;\n\n // Calculate position in graph coordinates\n const x = (event.clientX - svgRect.left - this.panX()) / this.scale();\n const y = (event.clientY - svgRect.top - this.panY()) / this.scale();\n\n // Check if clicking on a node\n const nodeId = this.findNodeAtPosition({ x, y });\n if (nodeId) {\n this.contextMenu.emit({\n type: 'node',\n position: { x: event.clientX, y: event.clientY },\n nodeId\n });\n return;\n }\n\n // Check if clicking on an edge (use hit area logic)\n const edgeId = this.findEdgeAtPosition({ x, y });\n if (edgeId) {\n this.contextMenu.emit({\n type: 'edge',\n position: { x: event.clientX, y: event.clientY },\n edgeId\n });\n return;\n }\n\n // Canvas click\n this.contextMenu.emit({\n type: 'canvas',\n position: { x: event.clientX, y: event.clientY }\n });\n }\n\n // Helper methods\n private emitGraphChange(): void {\n // Push to history (unless this is an undo/redo operation)\n if (!this.historyService.isUndoRedo()) {\n this.historyService.push(this.internalGraph());\n }\n this.graphChange.emit(this.internalGraph());\n if (this.config.validation?.validateOnChange) {\n this.validate();\n }\n }\n\n /** Undo the last action (Ctrl+Z) */\n undo(): boolean {\n const state = this.historyService.undo();\n if (!state) {\n return false;\n }\n \n this.internalGraph.set(state);\n this.graphChange.emit(this.internalGraph());\n this.historyService.completeUndoRedo();\n \n // Clear selection after undo\n this.selection.set({ nodes: [], edges: [] });\n this.selectionChange.emit(this.selection());\n \n return true;\n }\n\n /** Redo the last undone action (Ctrl+Y / Ctrl+Shift+Z) */\n redo(): boolean {\n const state = this.historyService.redo();\n if (!state) {\n return false;\n }\n \n this.internalGraph.set(state);\n this.graphChange.emit(this.internalGraph());\n this.historyService.completeUndoRedo();\n \n // Clear selection after redo\n this.selection.set({ nodes: [], edges: [] });\n this.selectionChange.emit(this.selection());\n \n return true;\n }\n\n /** Check if undo is available */\n canUndo(): boolean {\n return this.historyService.canUndo();\n }\n\n /** Check if redo is available */\n canRedo(): boolean {\n return this.historyService.canRedo();\n }\n\n /** Clear history and reset to current state */\n clearHistory(): void {\n this.historyService.clear(this.internalGraph());\n }\n\n private generateId(): string {\n return `node_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n }\n\n private recalculateEdgePorts(nodeId: string): void {\n const graph = this.internalGraph();\n let changed = false;\n const updatedEdges = graph.edges.map(edge => {\n if (edge.source !== nodeId && edge.target !== nodeId) return edge;\n\n const sourceNode = graph.nodes.find(n => n.id === edge.source);\n const targetNode = graph.nodes.find(n => n.id === edge.target);\n if (!sourceNode || !targetNode) return edge;\n\n const newSourcePort = this.findClosestPortForEdge(sourceNode, targetNode, 'source');\n const newTargetPort = this.findClosestPortForEdge(targetNode, sourceNode, 'target');\n\n if (edge.sourcePort === newSourcePort && edge.targetPort === newTargetPort) return edge;\n\n changed = true;\n return { ...edge, sourcePort: newSourcePort, targetPort: newTargetPort };\n });\n\n if (changed) {\n this.internalGraph.set({ ...graph, edges: updatedEdges });\n }\n }\n\n getNodeSize(node: GraphNode): { width: number; height: number } {\n const nodeConfig = this.config.nodes.types.find(t => t.type === node.type);\n return nodeConfig?.size || this.config.nodes.defaultSize || { width: 220, height: 100 };\n }\n\n getEdgePath(edge: GraphEdge): string {\n const sourceNode = this.internalGraph().nodes.find(n => n.id === edge.source);\n const targetNode = this.internalGraph().nodes.find(n => n.id === edge.target);\n\n if (!sourceNode || !targetNode) return '';\n\n // Get port positions from edge or calculate closest\n const sourcePort = (edge.sourcePort as 'top' | 'bottom' | 'left' | 'right') || this.findClosestPortForEdge(sourceNode, targetNode, 'source');\n const targetPort = (edge.targetPort as 'top' | 'bottom' | 'left' | 'right') || this.findClosestPortForEdge(targetNode, sourceNode, 'target');\n\n const sourcePoint = this.getPortWorldPosition(sourceNode, sourcePort);\n const targetPoint = this.getPortWorldPosition(targetNode, targetPort);\n\n // Simple straight line\n return `M ${sourcePoint.x},${sourcePoint.y} L ${targetPoint.x},${targetPoint.y}`;\n }\n\n getEdgeColor(edge: GraphEdge): string {\n return edge.metadata?.style?.stroke || this.config.edges.style?.stroke || '#94a3b8';\n }\n\n getEdgeMarkerEnd(edge: GraphEdge): string | null {\n const dir = edge.direction || 'forward';\n const selected = this.selection().edges.includes(edge.id);\n if (dir === 'forward' || dir === 'bidirectional') {\n return selected ? 'url(#arrow-end-selected)' : 'url(#arrow-end)';\n }\n return null;\n }\n\n getEdgeMarkerStart(edge: GraphEdge): string | null {\n const dir = edge.direction || 'forward';\n const selected = this.selection().edges.includes(edge.id);\n if (dir === 'backward' || dir === 'bidirectional') {\n return selected ? 'url(#arrow-start-selected)' : 'url(#arrow-start)';\n }\n return null;\n }\n\n setEdgeDirection(direction: 'forward' | 'backward' | 'bidirectional'): void {\n const sel = this.selection();\n if (sel.edges.length !== 1) return;\n\n const graph = this.internalGraph();\n const edgeIndex = graph.edges.findIndex(e => e.id === sel.edges[0]);\n if (edgeIndex === -1) return;\n\n const updatedEdges = [...graph.edges];\n updatedEdges[edgeIndex] = { ...updatedEdges[edgeIndex], direction };\n this.internalGraph.set({ ...graph, edges: updatedEdges });\n this.emitGraphChange();\n this.edgeUpdated.emit(updatedEdges[edgeIndex]);\n }\n\n getEdgeSourcePoint(edge: GraphEdge): Position {\n const sourceNode = this.internalGraph().nodes.find(n => n.id === edge.source);\n const targetNode = this.internalGraph().nodes.find(n => n.id === edge.target);\n if (!sourceNode || !targetNode) return { x: 0, y: 0 };\n\n const sourcePort = (edge.sourcePort as 'top' | 'bottom' | 'left' | 'right') || this.findClosestPortForEdge(sourceNode, targetNode, 'source');\n return this.getPortWorldPosition(sourceNode, sourcePort);\n }\n\n getEdgeTargetPoint(edge: GraphEdge): Position {\n const sourceNode = this.internalGraph().nodes.find(n => n.id === edge.source);\n const targetNode = this.internalGraph().nodes.find(n => n.id === edge.target);\n if (!sourceNode || !targetNode) return { x: 0, y: 0 };\n\n const targetPort = (edge.targetPort as 'top' | 'bottom' | 'left' | 'right') || this.findClosestPortForEdge(targetNode, sourceNode, 'target');\n return this.getPortWorldPosition(targetNode, targetPort);\n }\n\n getNodeTypeIcon(node: GraphNode): string {\n const nodeConfig = this.config.nodes.types.find(t => t.type === node.type);\n return nodeConfig?.icon || '●';\n }\n\n /**\n * Get image URL for a node icon.\n * Priority: node.data['imageUrl'] > nodeType.iconSvg (converted to data URL) > nodeType.defaultData['imageUrl']\n * Returns null if no image is configured (will render text icon instead).\n */\n getNodeImage(node: GraphNode): string | null {\n // Check instance-level image first\n if (node.data['imageUrl']) {\n return node.data['imageUrl'] as string;\n }\n\n const nodeConfig = this.config.nodes.types.find(t => t.type === node.type);\n\n // Check for iconSvg definition (convert to data URL)\n if (nodeConfig?.iconSvg) {\n return this.svgIconToDataUrl(nodeConfig.iconSvg);\n }\n\n // Fall back to node type default imageUrl\n if (nodeConfig?.defaultData['imageUrl']) {\n return nodeConfig.defaultData['imageUrl'] as string;\n }\n\n return null;\n }\n\n /**\n * Convert an SvgIconDefinition to a data URL for use in <image> elements.\n * Caches results to avoid repeated conversion.\n */\n private svgIconCache = new Map<SvgIconDefinition, string>();\n\n private svgIconToDataUrl(icon: SvgIconDefinition): string {\n // Check cache first\n const cached = this.svgIconCache.get(icon);\n if (cached) return cached;\n\n const viewBox = icon.viewBox || '0 0 24 24';\n const fill = icon.fill || 'none';\n const stroke = icon.stroke || '#1D6A96';\n const strokeWidth = icon.strokeWidth || 2;\n\n // Build SVG markup with proper path handling\n const paths = icon.path\n .split(/\\n/)\n .map(p => p.trim())\n .filter(p => p.length > 0)\n .map(p => `<path d=\"${p}\"/>`)\n .join('');\n\n const svg = `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"48\" height=\"48\" viewBox=\"${viewBox}\" fill=\"${fill}\" stroke=\"${stroke}\" stroke-width=\"${strokeWidth}\" stroke-linecap=\"round\" stroke-linejoin=\"round\">${paths}</svg>`;\n\n // Encode as data URL\n const dataUrl = `data:image/svg+xml;base64,${btoa(svg)}`;\n this.svgIconCache.set(icon, dataUrl);\n return dataUrl;\n }\n\n /**\n * Get the SVG icon definition for a node type (for palette rendering).\n * Returns null if no iconSvg is configured.\n */\n getNodeTypeSvgIcon(nodeType: NodeTypeDefinition): SvgIconDefinition | null {\n return nodeType.iconSvg || null;\n }\n\n /**\n * Split SVG path data by newlines for template iteration.\n * Used to render multiple path elements from a single path string.\n */\n splitIconPaths(pathData: string): string[] {\n return pathData\n .split(/\\n/)\n .map(p => p.trim())\n .filter(p => p.length > 0);\n }\n\n /**\n * Get the position for the node image (top-left corner of image).\n * Uses same positioning logic as icon but accounts for image dimensions.\n */\n getImagePosition(node: GraphNode): Position {\n const size = this.getNodeSize(node);\n const imageSize = this.getImageSize(node);\n const pos = this.config.nodes.iconPosition || 'top-left';\n const padding = 8;\n\n const positions: Record<string, Position> = {\n 'top-left': { x: padding, y: padding },\n 'top': { x: (size.width - imageSize) / 2, y: padding },\n 'top-right': { x: size.width - imageSize - padding, y: padding },\n 'right': { x: size.width - imageSize - padding, y: (size.height - imageSize) / 2 },\n 'bottom-right': { x: size.width - imageSize - padding, y: size.height - imageSize - padding },\n 'bottom': { x: (size.width - imageSize) / 2, y: size.height - imageSize - padding },\n 'bottom-left': { x: padding, y: size.height - imageSize - padding },\n 'left': { x: padding, y: (size.height - imageSize) / 2 }\n };\n\n return positions[pos] || positions['top-left'];\n }\n\n /**\n * Get the size (width/height) for node images.\n * Images are rendered as squares, sized proportionally to node height.\n */\n getImageSize(node: GraphNode): number {\n const size = this.getNodeSize(node);\n // Image takes up ~40% of node height, with min 24px and max 64px\n return Math.min(64, Math.max(24, size.height * 0.4));\n }\n\n getIconPosition(node: GraphNode): Position {\n const size = this.getNodeSize(node);\n const pos = this.config.nodes.iconPosition || 'top-left';\n const padding = size.height * 0.25;\n const iconSize = size.height * 0.28;\n\n const positions: Record<string, Position> = {\n 'top-left': { x: padding, y: padding },\n 'top': { x: size.width / 2, y: padding },\n 'top-right': { x: size.width - padding, y: padding },\n 'right': { x: size.width - padding, y: size.height / 2 },\n 'bottom-right': { x: size.width - padding, y: size.height - padding },\n 'bottom': { x: size.width / 2, y: size.height - padding },\n 'bottom-left': { x: padding, y: size.height - padding },\n 'left': { x: padding, y: size.height / 2 }\n };\n\n return positions[pos] || positions['left'];\n }\n\n getLabelPosition(node: GraphNode): Position {\n const size = this.getNodeSize(node);\n const pos = this.config.nodes.iconPosition || 'top-left';\n const padding = size.height * 0.25;\n\n // Label position adjusts based on icon position\n const labelPositions: Record<string, Position> = {\n 'top-left': { x: size.width / 2 + padding / 2, y: size.height / 2 + 4 },\n 'top': { x: size.width / 2, y: size.height / 2 + padding / 2 },\n 'top-right': { x: size.width / 2 - padding / 2, y: size.height / 2 + 4 },\n 'right': { x: size.width / 2 - padding / 2, y: size.height / 2 },\n 'bottom-right': { x: size.width / 2 - padding / 2, y: size.height / 2 - 4 },\n 'bottom': { x: size.width / 2, y: size.height / 2 - padding / 2 },\n 'bottom-left': { x: size.width / 2 + padding / 2, y: size.height / 2 - 4 },\n 'left': { x: size.width / 2 + padding / 2, y: size.height / 2 }\n };\n\n return labelPositions[pos] || labelPositions['top-left'];\n }\n\n private findNodeAtPosition(pos: Position): string | null {\n for (const node of this.internalGraph().nodes) {\n const size = this.getNodeSize(node);\n if (\n pos.x >= node.position.x &&\n pos.x <= node.position.x + size.width &&\n pos.y >= node.position.y &&\n pos.y <= node.position.y + size.height\n ) {\n return node.id;\n }\n }\n return null;\n }\n\n private findEdgeAtPosition(pos: Position): string | null {\n const hitDistance = 10; // pixels tolerance\n for (const edge of this.internalGraph().edges) {\n const sourcePoint = this.getEdgeSourcePoint(edge);\n const targetPoint = this.getEdgeTargetPoint(edge);\n\n // Calculate distance from point to line segment\n const dist = this.pointToSegmentDistance(pos, sourcePoint, targetPoint);\n if (dist < hitDistance) {\n return edge.id;\n }\n }\n return null;\n }\n\n private pointToSegmentDistance(point: Position, lineStart: Position, lineEnd: Position): number {\n const dx = lineEnd.x - lineStart.x;\n const dy = lineEnd.y - lineStart.y;\n const lengthSquared = dx * dx + dy * dy;\n\n if (lengthSquared === 0) {\n // Line segment is a point\n return Math.sqrt((point.x - lineStart.x) ** 2 + (point.y - lineStart.y) ** 2);\n }\n\n // Project point onto line segment\n let t = ((point.x - lineStart.x) * dx + (point.y - lineStart.y) * dy) / lengthSquared;\n t = Math.max(0, Math.min(1, t));\n\n const projX = lineStart.x + t * dx;\n const projY = lineStart.y + t * dy;\n\n return Math.sqrt((point.x - projX) ** 2 + (point.y - projY) ** 2);\n }\n\n getNodePorts(node: GraphNode): Array<{ position: 'top' | 'bottom' | 'left' | 'right'; x: number; y: number }> {\n const size = this.getNodeSize(node);\n return [\n { position: 'top', x: size.width / 2, y: 0 },\n { position: 'bottom', x: size.width / 2, y: size.height },\n { position: 'left', x: 0, y: size.height / 2 },\n { position: 'right', x: size.width, y: size.height / 2 }\n ];\n }\n\n private findClosestPort(nodeId: string, worldPos: Position): { port: 'top' | 'bottom' | 'left' | 'right'; distance: number } | null {\n const node = this.internalGraph().nodes.find(n => n.id === nodeId);\n if (!node) return null;\n\n const ports = this.getNodePorts(node);\n let closestPort: typeof ports[0] | null = null;\n let minDistance = Infinity;\n\n for (const port of ports) {\n const portWorldX = node.position.x + port.x;\n const portWorldY = node.position.y + port.y;\n const dx = worldPos.x - portWorldX;\n const dy = worldPos.y - portWorldY;\n const distance = Math.sqrt(dx * dx + dy * dy);\n\n if (distance < minDistance) {\n minDistance = distance;\n closestPort = port;\n }\n }\n\n return closestPort ? { port: closestPort.position, distance: minDistance } : null;\n }\n\n private getPortWorldPosition(node: GraphNode, port: 'top' | 'bottom' | 'left' | 'right'): Position {\n const size = this.getNodeSize(node);\n const portOffsets = {\n top: { x: size.width / 2, y: 0 },\n bottom: { x: size.width / 2, y: size.height },\n left: { x: 0, y: size.height / 2 },\n right: { x: size.width, y: size.height / 2 }\n };\n\n const offset = portOffsets[port];\n return {\n x: node.position.x + offset.x,\n y: node.position.y + offset.y\n };\n }\n\n private findClosestPortForEdge(\n node: GraphNode,\n otherNode: GraphNode,\n endpoint: 'source' | 'target'\n ): 'top' | 'bottom' | 'left' | 'right' {\n const size = this.getNodeSize(node);\n const nodeCenter = {\n x: node.position.x + size.width / 2,\n y: node.position.y + size.height / 2\n };\n const otherSize = this.getNodeSize(otherNode);\n const otherCenter = {\n x: otherNode.position.x + otherSize.width / 2,\n y: otherNode.position.y + otherSize.height / 2\n };\n\n const dx = otherCenter.x - nodeCenter.x;\n const dy = otherCenter.y - nodeCenter.y;\n\n // Determine which port is closest based on relative position\n const absDx = Math.abs(dx);\n const absDy = Math.abs(dy);\n\n if (absDx > absDy) {\n // Horizontal connection\n return dx > 0 ? 'right' : 'left';\n } else {\n // Vertical connection\n return dy > 0 ? 'bottom' : 'top';\n }\n }\n}\n","<div class=\"graph-editor-container\">\n <!-- Canvas with overlaid palette -->\n <div class=\"graph-canvas-wrapper\">\n <!-- Top-left horizontal palette overlay -->\n @if (config.palette?.enabled !== false) {\n <div class=\"graph-palette-overlay\">\n <!-- Tools -->\n <button\n class=\"palette-item tool-item\"\n [class.active]=\"activeTool() === 'hand'\"\n title=\"Hand tool (move nodes)\"\n (click)=\"switchTool('hand')\"\n >\n <span class=\"icon\">✋</span>\n </button>\n <button\n class=\"palette-item tool-item\"\n [class.active]=\"activeTool() === 'line'\"\n title=\"Line tool (draw connections)\"\n (click)=\"switchTool('line')\"\n >\n <span class=\"icon\">∕</span>\n </button>\n\n <!-- Divider -->\n <div class=\"palette-divider\"></div>\n\n <!-- Node types -->\n @for (nodeType of config.nodes.types; track nodeType.type) {\n <button\n class=\"palette-item\"\n [attr.data-node-type]=\"nodeType.type\"\n [attr.title]=\"nodeType.label || nodeType.type\"\n (click)=\"addNode(nodeType.type)\"\n >\n @if (nodeType.iconSvg) {\n <svg\n class=\"palette-icon-svg\"\n [attr.viewBox]=\"nodeType.iconSvg.viewBox || '0 0 24 24'\"\n [attr.fill]=\"nodeType.iconSvg.fill || 'none'\"\n [attr.stroke]=\"nodeType.iconSvg.stroke || '#1D6A96'\"\n [attr.stroke-width]=\"nodeType.iconSvg.strokeWidth || 2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n >\n @for (pathData of splitIconPaths(nodeType.iconSvg.path); track $index) {\n <path [attr.d]=\"pathData\"/>\n }\n </svg>\n } @else if (nodeType.defaultData['imageUrl']) {\n <img\n class=\"palette-icon-img\"\n [src]=\"nodeType.defaultData['imageUrl']\"\n [alt]=\"nodeType.label || nodeType.type\"\n />\n } @else {\n <span class=\"icon\">{{ nodeType.icon || '●' }}</span>\n }\n </button>\n }\n </div>\n }\n\n <svg\n #canvasSvg\n [class.tool-line]=\"activeTool() === 'line'\"\n [attr.width]=\"'100%'\"\n [attr.height]=\"'100%'\"\n (mousedown)=\"onCanvasMouseDown($event)\"\n (mousemove)=\"onCanvasMouseMove($event)\"\n (mouseup)=\"onCanvasMouseUp($event)\"\n (wheel)=\"onWheel($event)\"\n (contextmenu)=\"onContextMenu($event)\"\n >\n <!-- Arrow marker definitions -->\n <defs>\n <marker id=\"arrow-end\" viewBox=\"0 0 10 10\" refX=\"9\" refY=\"5\"\n markerWidth=\"8\" markerHeight=\"8\" orient=\"auto\">\n <path d=\"M 0 1 L 8 5 L 0 9 z\" fill=\"#94a3b8\"/>\n </marker>\n <marker id=\"arrow-end-selected\" viewBox=\"0 0 10 10\" refX=\"9\" refY=\"5\"\n markerWidth=\"8\" markerHeight=\"8\" orient=\"auto\">\n <path d=\"M 0 1 L 8 5 L 0 9 z\" fill=\"#3b82f6\"/>\n </marker>\n <marker id=\"arrow-start\" viewBox=\"0 0 10 10\" refX=\"1\" refY=\"5\"\n markerWidth=\"8\" markerHeight=\"8\" orient=\"auto\">\n <path d=\"M 10 1 L 2 5 L 10 9 z\" fill=\"#94a3b8\"/>\n </marker>\n <marker id=\"arrow-start-selected\" viewBox=\"0 0 10 10\" refX=\"1\" refY=\"5\"\n markerWidth=\"8\" markerHeight=\"8\" orient=\"auto\">\n <path d=\"M 10 1 L 2 5 L 10 9 z\" fill=\"#3b82f6\"/>\n </marker>\n </defs>\n\n <!-- Main transform group (pan + zoom) -->\n <g [attr.transform]=\"transform()\">\n <!-- Grid (if enabled) -->\n <!-- Grid (if enabled) - extended to cover viewport during pan -->\n @if (config.canvas?.grid?.enabled) {\n <defs>\n <pattern\n id=\"grid\"\n [attr.width]=\"config.canvas!.grid!.size\"\n [attr.height]=\"config.canvas!.grid!.size\"\n patternUnits=\"userSpaceOnUse\"\n >\n <path\n [attr.d]=\"'M ' + config.canvas!.grid!.size + ' 0 L 0 0 0 ' + config.canvas!.grid!.size\"\n fill=\"none\"\n [attr.stroke]=\"config.canvas!.grid!.color || '#e0e0e0'\"\n stroke-width=\"1\"\n />\n </pattern>\n </defs>\n <!-- Extended grid background covering viewport + pan offset -->\n <rect\n [attr.x]=\"gridBounds().x\"\n [attr.y]=\"gridBounds().y\"\n [attr.width]=\"gridBounds().width\"\n [attr.height]=\"gridBounds().height\"\n fill=\"url(#grid)\"\n />\n }\n\n <!-- Layer 0.5: Preview line for line tool (rubber-band) -->\n @if (previewLine()) {\n <line\n class=\"preview-line\"\n [attr.x1]=\"previewLine()!.source.x\"\n [attr.y1]=\"previewLine()!.source.y\"\n [attr.x2]=\"previewLine()!.target.x\"\n [attr.y2]=\"previewLine()!.target.y\"\n stroke=\"#3b82f6\"\n stroke-width=\"2.5\"\n stroke-dasharray=\"8,6\"\n stroke-linecap=\"round\"\n opacity=\"0.7\"\n />\n }\n\n <!-- Layer 1: Edge paths (behind everything) -->\n @for (edge of internalGraph().edges; track edge.id) {\n <!-- Edge shadow for depth (optional) -->\n @if (shadowsEnabled()) {\n <path\n class=\"edge-shadow\"\n [attr.d]=\"getEdgePath(edge)\"\n stroke=\"rgba(0,0,0,0.06)\"\n stroke-width=\"6\"\n fill=\"none\"\n stroke-linecap=\"round\"\n [attr.transform]=\"'translate(1, 2)'\"\n />\n }\n <!-- Invisible wide hit-area for easier clicking (hand tool only) -->\n <path\n [attr.d]=\"getEdgePath(edge)\"\n stroke=\"transparent\"\n [attr.stroke-width]=\"20\"\n fill=\"none\"\n class=\"edge-hit-area\"\n [attr.pointer-events]=\"activeTool() === 'hand' ? 'stroke' : 'none'\"\n (click)=\"onEdgeClick($event, edge)\"\n (dblclick)=\"onEdgeDoubleClick($event, edge)\"\n />\n <!-- Visible edge line -->\n <path\n class=\"edge-line\"\n [attr.d]=\"getEdgePath(edge)\"\n [attr.stroke]=\"selection().edges.includes(edge.id) ? '#3b82f6' : '#94a3b8'\"\n [attr.stroke-width]=\"selection().edges.includes(edge.id) ? 2.5 : 2\"\n fill=\"none\"\n stroke-linecap=\"round\"\n [class.selected]=\"selection().edges.includes(edge.id)\"\n [attr.marker-end]=\"getEdgeMarkerEnd(edge)\"\n [attr.marker-start]=\"getEdgeMarkerStart(edge)\"\n pointer-events=\"none\"\n />\n }\n\n <!-- Layer 2: Nodes -->\n @for (node of internalGraph().nodes; track node.id) {\n <g\n [attr.transform]=\"'translate(' + node.position.x + ',' + node.position.y + ')'\"\n class=\"graph-node\"\n [class.selected]=\"selection().nodes.includes(node.id)\"\n [attr.data-node-id]=\"node.id\"\n (mousedown)=\"onNodeMouseDown($event, node)\"\n (click)=\"onNodeClick($event, node)\"\n (dblclick)=\"nodeDoubleClick.emit(node)\"\n >\n <!-- Node shadow (optional) -->\n @if (shadowsEnabled()) {\n <rect\n class=\"node-shadow\"\n [attr.width]=\"getNodeSize(node).width\"\n [attr.height]=\"getNodeSize(node).height\"\n fill=\"rgba(0,0,0,0.08)\"\n rx=\"12\"\n transform=\"translate(2, 3)\"\n style=\"filter: blur(4px);\"\n />\n }\n <!-- Node background -->\n <rect\n class=\"node-bg\"\n [attr.width]=\"getNodeSize(node).width\"\n [attr.height]=\"getNodeSize(node).height\"\n fill=\"white\"\n [attr.stroke]=\"selection().nodes.includes(node.id) ? '#3b82f6' : '#e2e8f0'\"\n [attr.stroke-width]=\"selection().nodes.includes(node.id) ? 2.5 : 1.5\"\n rx=\"12\"\n />\n\n <!-- Node type icon (text/emoji) or custom image -->\n @if (getNodeImage(node)) {\n <image\n class=\"node-image\"\n [attr.href]=\"getNodeImage(node)\"\n [attr.xlink:href]=\"getNodeImage(node)\"\n [attr.x]=\"getImagePosition(node).x\"\n [attr.y]=\"getImagePosition(node).y\"\n [attr.width]=\"getImageSize(node)\"\n [attr.height]=\"getImageSize(node)\"\n preserveAspectRatio=\"xMidYMid meet\"\n />\n } @else {\n <text\n class=\"node-icon\"\n [attr.x]=\"getIconPosition(node).x\"\n [attr.y]=\"getIconPosition(node).y\"\n text-anchor=\"middle\"\n dominant-baseline=\"middle\"\n [attr.font-size]=\"getNodeSize(node).height * 0.28\"\n >\n {{ getNodeTypeIcon(node) }}\n </text>\n }\n\n <!-- Node label -->\n <text\n class=\"node-label\"\n [attr.x]=\"getLabelPosition(node).x\"\n [attr.y]=\"getLabelPosition(node).y\"\n text-anchor=\"middle\"\n dominant-baseline=\"middle\"\n font-size=\"14\"\n font-weight=\"500\"\n fill=\"#1e293b\"\n >\n {{ node.data['name'] || node.type }}\n </text>\n </g>\n }\n\n <!-- Layer 3: Attachment points (on top of nodes) -->\n @for (node of internalGraph().nodes; track node.id) {\n @if (showAttachmentPoints() === node.id) {\n <g [attr.transform]=\"'translate(' + node.position.x + ',' + node.position.y + ')'\">\n @for (port of getNodePorts(node); track port.position) {\n <circle\n [attr.cx]=\"port.x\"\n [attr.cy]=\"port.y\"\n [attr.r]=\"hoveredPort?.nodeId === node.id && hoveredPort?.port === port.position ? 8 : 6\"\n [attr.fill]=\"hoveredPort?.nodeId === node.id && hoveredPort?.port === port.position ? '#2563eb' : '#94a3b8'\"\n stroke=\"white\"\n stroke-width=\"2\"\n class=\"attachment-point\"\n [class.hovered]=\"hoveredPort?.nodeId === node.id && hoveredPort?.port === port.position\"\n (mousedown)=\"$event.stopPropagation()\"\n (click)=\"onAttachmentPointClick($event, node, port.position)\"\n />\n }\n </g>\n }\n }\n\n <!-- Layer 4: Edge endpoints (only visible when edge is selected) -->\n @for (edge of internalGraph().edges; track edge.id) {\n @if (selection().edges.includes(edge.id)) {\n <g>\n <!-- Source endpoint -->\n <circle\n [attr.cx]=\"getEdgeSourcePoint(edge).x\"\n [attr.cy]=\"getEdgeSourcePoint(edge).y\"\n r=\"6\"\n fill=\"#3b82f6\"\n stroke=\"white\"\n stroke-width=\"2\"\n class=\"edge-endpoint selected\"\n (mousedown)=\"onEdgeEndpointMouseDown($event, edge, 'source')\"\n />\n\n <!-- Target endpoint -->\n <circle\n [attr.cx]=\"getEdgeTargetPoint(edge).x\"\n [attr.cy]=\"getEdgeTargetPoint(edge).y\"\n r=\"6\"\n fill=\"#3b82f6\"\n stroke=\"white\"\n stroke-width=\"2\"\n class=\"edge-endpoint selected\"\n (mousedown)=\"onEdgeEndpointMouseDown($event, edge, 'target')\"\n />\n </g>\n }\n }\n\n <!-- Layer 5: Selection box (Shift+drag) -->\n @if (selectionBox()) {\n <rect\n class=\"selection-box\"\n [attr.x]=\"selectionBox()!.x\"\n [attr.y]=\"selectionBox()!.y\"\n [attr.width]=\"selectionBox()!.width\"\n [attr.height]=\"selectionBox()!.height\"\n fill=\"rgba(59, 130, 246, 0.1)\"\n stroke=\"#3b82f6\"\n stroke-width=\"1\"\n stroke-dasharray=\"4,2\"\n />\n }\n </g>\n </svg>\n </div>\n\n <!-- Edge direction selector overlay -->\n @if (selectedEdgeMidpoint()) {\n <div\n class=\"edge-direction-selector\"\n [style.left.px]=\"selectedEdgeMidpoint()!.x\"\n [style.top.px]=\"selectedEdgeMidpoint()!.y\"\n >\n <button\n class=\"direction-btn\"\n [class.active]=\"selectedEdgeMidpoint()!.edge.direction === 'backward'\"\n title=\"Backward\"\n (click)=\"setEdgeDirection('backward')\"\n >←</button>\n <button\n class=\"direction-btn\"\n [class.active]=\"selectedEdgeMidpoint()!.edge.direction === 'bidirectional'\"\n title=\"Bidirectional\"\n (click)=\"setEdgeDirection('bidirectional')\"\n >↔</button>\n <button\n class=\"direction-btn\"\n [class.active]=\"!selectedEdgeMidpoint()!.edge.direction || selectedEdgeMidpoint()!.edge.direction === 'forward'\"\n title=\"Forward\"\n (click)=\"setEdgeDirection('forward')\"\n >→</button>\n </div>\n }\n</div>\n","/**\n * SVG icon definition interface for custom node icons.\n * Use this to define your own icons that match your design system.\n *\n * Example usage:\n * const myIcons = {\n * process: {\n * viewBox: '0 0 24 24',\n * fill: 'none',\n * stroke: '#1D6A96',\n * strokeWidth: 1.75,\n * path: 'M12 15a3 3 0 1 0 0-6 3 3 0 0 0 0 6Z...'\n * }\n * };\n */\nexport interface SvgIconDefinition {\n /** SVG path data (d attribute) or full SVG markup */\n path: string;\n /** ViewBox dimensions (default: '0 0 24 24') */\n viewBox?: string;\n /** Fill color (default: 'none' for stroke-based icons) */\n fill?: string;\n /** Stroke color (default: currentColor) */\n stroke?: string;\n /** Stroke width (default: 2) */\n strokeWidth?: number;\n}\n\n/**\n * Generate inline SVG markup for an icon (for use in palette/toolbar)\n */\nexport function renderIconSvg(icon: SvgIconDefinition, size: number = 24): string {\n const viewBox = icon.viewBox || '0 0 24 24';\n const fill = icon.fill || 'none';\n const stroke = icon.stroke || 'currentColor';\n const strokeWidth = icon.strokeWidth || 2;\n\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${size}\" height=\"${size}\" viewBox=\"${viewBox}\" fill=\"${fill}\" stroke=\"${stroke}\" stroke-width=\"${strokeWidth}\" stroke-linecap=\"round\" stroke-linejoin=\"round\">${icon.path.split('\\n').map(p => `<path d=\"${p.trim()}\"/>`).join('')}</svg>`;\n}\n\n/**\n * Generate data URL for an icon (for use as image source)\n */\nexport function iconToDataUrl(icon: SvgIconDefinition, size: number = 48): string {\n const svg = renderIconSvg(icon, size);\n return `data:image/svg+xml;base64,${btoa(svg)}`;\n}\n","// Main component\nexport { GraphEditorComponent } from './lib/graph-editor.component';\n\n// Data model - use 'export type' for re-exports when isolatedModules is enabled\nexport type {\n Graph,\n GraphNode,\n GraphEdge,\n Position,\n NodeMetadata,\n EdgeMetadata,\n EdgeStyle,\n GraphMetadata\n} from './lib/graph.model';\n\n// Configuration - use 'export type' for re-exports\nexport type {\n GraphEditorConfig,\n NodesConfig,\n EdgesConfig,\n CanvasConfig,\n ValidationConfig,\n LayoutConfig,\n InteractionConfig,\n ThemeConfig,\n PaletteConfig,\n NodeTypeDefinition,\n PortConfig,\n PortDefinition,\n NodeConstraints,\n GridConfig,\n ZoomConfig,\n PanConfig,\n ValidationRule,\n ValidationError,\n LayoutOptions,\n ContextMenuConfig,\n ContextMenuItem,\n ContextMenuContext,\n SelectionState,\n ValidationResult,\n ContextMenuEvent\n} from './lib/graph-editor.config';\n\n// SVG icon utilities\nexport type { SvgIconDefinition } from './lib/icons/workflow-icons';\nexport { renderIconSvg, iconToDataUrl } from './lib/icons/workflow-icons';","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { EventEmitter, OnChanges, OnInit, SimpleChanges } from '@angular/core';
|
|
2
2
|
import { Graph, GraphEdge, GraphNode, Position } from './graph.model';
|
|
3
|
-
import { ContextMenuEvent, GraphEditorConfig, SelectionState, ValidationResult } from './graph-editor.config';
|
|
3
|
+
import { ContextMenuEvent, GraphEditorConfig, NodeTypeDefinition, SelectionState, ValidationResult } from './graph-editor.config';
|
|
4
|
+
import { SvgIconDefinition } from './icons/workflow-icons';
|
|
4
5
|
import * as i0 from "@angular/core";
|
|
5
6
|
/**
|
|
6
7
|
* Main graph editor component.
|
|
@@ -141,11 +142,27 @@ export declare class GraphEditorComponent implements OnInit, OnChanges {
|
|
|
141
142
|
getEdgeTargetPoint(edge: GraphEdge): Position;
|
|
142
143
|
getNodeTypeIcon(node: GraphNode): string;
|
|
143
144
|
/**
|
|
144
|
-
* Get
|
|
145
|
-
*
|
|
145
|
+
* Get image URL for a node icon.
|
|
146
|
+
* Priority: node.data['imageUrl'] > nodeType.iconSvg (converted to data URL) > nodeType.defaultData['imageUrl']
|
|
146
147
|
* Returns null if no image is configured (will render text icon instead).
|
|
147
148
|
*/
|
|
148
149
|
getNodeImage(node: GraphNode): string | null;
|
|
150
|
+
/**
|
|
151
|
+
* Convert an SvgIconDefinition to a data URL for use in <image> elements.
|
|
152
|
+
* Caches results to avoid repeated conversion.
|
|
153
|
+
*/
|
|
154
|
+
private svgIconCache;
|
|
155
|
+
private svgIconToDataUrl;
|
|
156
|
+
/**
|
|
157
|
+
* Get the SVG icon definition for a node type (for palette rendering).
|
|
158
|
+
* Returns null if no iconSvg is configured.
|
|
159
|
+
*/
|
|
160
|
+
getNodeTypeSvgIcon(nodeType: NodeTypeDefinition): SvgIconDefinition | null;
|
|
161
|
+
/**
|
|
162
|
+
* Split SVG path data by newlines for template iteration.
|
|
163
|
+
* Used to render multiple path elements from a single path string.
|
|
164
|
+
*/
|
|
165
|
+
splitIconPaths(pathData: string): string[];
|
|
149
166
|
/**
|
|
150
167
|
* Get the position for the node image (top-left corner of image).
|
|
151
168
|
* Uses same positioning logic as icon but accounts for image dimensions.
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Type } from '@angular/core';
|
|
2
2
|
import { EdgeStyle, Graph, Position } from './graph.model';
|
|
3
|
+
import { SvgIconDefinition } from './icons/workflow-icons';
|
|
3
4
|
export interface GraphEditorConfig {
|
|
4
5
|
/** Node type definitions */
|
|
5
6
|
nodes: NodesConfig;
|
|
@@ -39,8 +40,15 @@ export interface NodeTypeDefinition {
|
|
|
39
40
|
type: string;
|
|
40
41
|
/** Display name in palette */
|
|
41
42
|
label?: string;
|
|
42
|
-
/** Icon identifier (
|
|
43
|
+
/** Icon identifier (emoji, text, or symbol for fallback display) */
|
|
43
44
|
icon?: string;
|
|
45
|
+
/**
|
|
46
|
+
* SVG icon definition for professional node icons.
|
|
47
|
+
* When set, renders an SVG icon in the node and palette instead of text/emoji.
|
|
48
|
+
* Use WORKFLOW_ICONS from '@utisha/graph-editor' or provide custom SvgIconDefinition.
|
|
49
|
+
* @example iconSvg: WORKFLOW_ICONS.process
|
|
50
|
+
*/
|
|
51
|
+
iconSvg?: SvgIconDefinition;
|
|
44
52
|
/** Palette category/group */
|
|
45
53
|
category?: string;
|
|
46
54
|
/** Angular component to render this node type */
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SVG icon definition interface for custom node icons.
|
|
3
|
+
* Use this to define your own icons that match your design system.
|
|
4
|
+
*
|
|
5
|
+
* Example usage:
|
|
6
|
+
* const myIcons = {
|
|
7
|
+
* process: {
|
|
8
|
+
* viewBox: '0 0 24 24',
|
|
9
|
+
* fill: 'none',
|
|
10
|
+
* stroke: '#1D6A96',
|
|
11
|
+
* strokeWidth: 1.75,
|
|
12
|
+
* path: 'M12 15a3 3 0 1 0 0-6 3 3 0 0 0 0 6Z...'
|
|
13
|
+
* }
|
|
14
|
+
* };
|
|
15
|
+
*/
|
|
16
|
+
export interface SvgIconDefinition {
|
|
17
|
+
/** SVG path data (d attribute) or full SVG markup */
|
|
18
|
+
path: string;
|
|
19
|
+
/** ViewBox dimensions (default: '0 0 24 24') */
|
|
20
|
+
viewBox?: string;
|
|
21
|
+
/** Fill color (default: 'none' for stroke-based icons) */
|
|
22
|
+
fill?: string;
|
|
23
|
+
/** Stroke color (default: currentColor) */
|
|
24
|
+
stroke?: string;
|
|
25
|
+
/** Stroke width (default: 2) */
|
|
26
|
+
strokeWidth?: number;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Generate inline SVG markup for an icon (for use in palette/toolbar)
|
|
30
|
+
*/
|
|
31
|
+
export declare function renderIconSvg(icon: SvgIconDefinition, size?: number): string;
|
|
32
|
+
/**
|
|
33
|
+
* Generate data URL for an icon (for use as image source)
|
|
34
|
+
*/
|
|
35
|
+
export declare function iconToDataUrl(icon: SvgIconDefinition, size?: number): string;
|
package/package.json
CHANGED
package/public-api.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
export { GraphEditorComponent } from './lib/graph-editor.component';
|
|
2
2
|
export type { Graph, GraphNode, GraphEdge, Position, NodeMetadata, EdgeMetadata, EdgeStyle, GraphMetadata } from './lib/graph.model';
|
|
3
3
|
export type { GraphEditorConfig, NodesConfig, EdgesConfig, CanvasConfig, ValidationConfig, LayoutConfig, InteractionConfig, ThemeConfig, PaletteConfig, NodeTypeDefinition, PortConfig, PortDefinition, NodeConstraints, GridConfig, ZoomConfig, PanConfig, ValidationRule, ValidationError, LayoutOptions, ContextMenuConfig, ContextMenuItem, ContextMenuContext, SelectionState, ValidationResult, ContextMenuEvent } from './lib/graph-editor.config';
|
|
4
|
+
export type { SvgIconDefinition } from './lib/icons/workflow-icons';
|
|
5
|
+
export { renderIconSvg, iconToDataUrl } from './lib/icons/workflow-icons';
|