ngx-vflow 1.12.0 → 1.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/lib/vflow/components/node/node.component.mjs +3 -3
- package/esm2022/lib/vflow/directives/space-point-context.directive.mjs +3 -3
- package/esm2022/lib/vflow/interfaces/edge.interface.mjs +1 -1
- package/esm2022/lib/vflow/math/edge-path/smooth-step-path.mjs +60 -4
- package/esm2022/lib/vflow/models/edge.model.mjs +68 -19
- package/esm2022/lib/vflow/models/handle.model.mjs +9 -9
- package/esm2022/lib/vflow/public-components/handle/handle.component.mjs +6 -2
- package/esm2022/lib/vflow/services/handle.service.mjs +1 -1
- package/esm2022/testing/component-mocks/handle-mock.component.mjs +4 -2
- package/fesm2022/ngx-vflow-testing.mjs +3 -1
- package/fesm2022/ngx-vflow-testing.mjs.map +1 -1
- package/fesm2022/ngx-vflow.mjs +142 -33
- package/fesm2022/ngx-vflow.mjs.map +1 -1
- package/lib/vflow/interfaces/edge.interface.d.ts +1 -0
- package/lib/vflow/models/edge.model.d.ts +5 -0
- package/lib/vflow/models/handle.model.d.ts +1 -1
- package/lib/vflow/public-components/handle/handle.component.d.ts +4 -2
- package/lib/vflow/services/handle.service.d.ts +3 -1
- package/package.json +1 -1
- package/testing/component-mocks/handle-mock.component.d.ts +4 -2
package/fesm2022/ngx-vflow.mjs
CHANGED
|
@@ -1398,13 +1398,69 @@ function smoothStepPath({ sourcePoint, targetPoint, sourcePosition, targetPositi
|
|
|
1398
1398
|
res += segment;
|
|
1399
1399
|
return res;
|
|
1400
1400
|
}, '');
|
|
1401
|
+
// Performance optimization: Pre-calculate cumulative distances and use binary search
|
|
1402
|
+
const n = points.length;
|
|
1403
|
+
if (n < 2) {
|
|
1404
|
+
return {
|
|
1405
|
+
path,
|
|
1406
|
+
labelPoints: {
|
|
1407
|
+
start: { x: labelX, y: labelY },
|
|
1408
|
+
center: { x: labelX, y: labelY },
|
|
1409
|
+
end: { x: labelX, y: labelY },
|
|
1410
|
+
},
|
|
1411
|
+
};
|
|
1412
|
+
}
|
|
1413
|
+
// Pre-calculate segment lengths and cumulative distances in a single loop
|
|
1414
|
+
const segmentLengths = new Array(n - 1);
|
|
1415
|
+
const cumulativeDistances = new Array(n);
|
|
1416
|
+
cumulativeDistances[0] = 0;
|
|
1417
|
+
let totalLength = 0;
|
|
1418
|
+
for (let i = 0; i < n - 1; i++) {
|
|
1419
|
+
const dx = points[i + 1].x - points[i].x;
|
|
1420
|
+
const dy = points[i + 1].y - points[i].y;
|
|
1421
|
+
const len = Math.sqrt(dx * dx + dy * dy);
|
|
1422
|
+
segmentLengths[i] = len;
|
|
1423
|
+
totalLength += len;
|
|
1424
|
+
cumulativeDistances[i + 1] = totalLength;
|
|
1425
|
+
}
|
|
1426
|
+
// Optimized helper function using binary search
|
|
1427
|
+
const getPointAtRatio = (ratio) => {
|
|
1428
|
+
const targetDistance = totalLength * ratio;
|
|
1429
|
+
// Edge cases
|
|
1430
|
+
if (targetDistance <= 0)
|
|
1431
|
+
return points[0];
|
|
1432
|
+
if (targetDistance >= totalLength)
|
|
1433
|
+
return points[n - 1];
|
|
1434
|
+
// Binary search for the correct segment
|
|
1435
|
+
let low = 0;
|
|
1436
|
+
let high = n - 1;
|
|
1437
|
+
while (low < high - 1) {
|
|
1438
|
+
const mid = (low + high) >>> 1; // Bitwise right shift is faster than Math.floor
|
|
1439
|
+
if (cumulativeDistances[mid] < targetDistance) {
|
|
1440
|
+
low = mid;
|
|
1441
|
+
}
|
|
1442
|
+
else {
|
|
1443
|
+
high = mid;
|
|
1444
|
+
}
|
|
1445
|
+
}
|
|
1446
|
+
// Calculate position within the segment
|
|
1447
|
+
const segmentStartDistance = cumulativeDistances[low];
|
|
1448
|
+
const localDistance = targetDistance - segmentStartDistance;
|
|
1449
|
+
const t = localDistance / segmentLengths[low];
|
|
1450
|
+
// Linear interpolation
|
|
1451
|
+
const start = points[low];
|
|
1452
|
+
const end = points[low + 1];
|
|
1453
|
+
return {
|
|
1454
|
+
x: start.x + (end.x - start.x) * t,
|
|
1455
|
+
y: start.y + (end.y - start.y) * t,
|
|
1456
|
+
};
|
|
1457
|
+
};
|
|
1401
1458
|
return {
|
|
1402
1459
|
path,
|
|
1403
1460
|
labelPoints: {
|
|
1404
|
-
|
|
1405
|
-
start: { x: labelX, y: labelY },
|
|
1461
|
+
start: getPointAtRatio(0.15),
|
|
1406
1462
|
center: { x: labelX, y: labelY },
|
|
1407
|
-
end:
|
|
1463
|
+
end: getPointAtRatio(0.85),
|
|
1408
1464
|
},
|
|
1409
1465
|
};
|
|
1410
1466
|
}
|
|
@@ -1485,17 +1541,22 @@ class EdgeModel {
|
|
|
1485
1541
|
});
|
|
1486
1542
|
this.sourceHandle = extendedComputed((previousHandle) => {
|
|
1487
1543
|
let handle = null;
|
|
1488
|
-
if (this.
|
|
1489
|
-
handle =
|
|
1490
|
-
this.source()
|
|
1491
|
-
?.handles()
|
|
1492
|
-
.find((handle) => handle.rawHandle.id === this.edge.sourceHandle) ?? null;
|
|
1544
|
+
if (this.floating) {
|
|
1545
|
+
handle = this.closestHandles().sourceHandle;
|
|
1493
1546
|
}
|
|
1494
1547
|
else {
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1548
|
+
if (this.edge.sourceHandle) {
|
|
1549
|
+
handle =
|
|
1550
|
+
this.source()
|
|
1551
|
+
?.handles()
|
|
1552
|
+
.find((handle) => handle.rawHandle.id === this.edge.sourceHandle) ?? null;
|
|
1553
|
+
}
|
|
1554
|
+
else {
|
|
1555
|
+
handle =
|
|
1556
|
+
this.source()
|
|
1557
|
+
?.handles()
|
|
1558
|
+
.find((handle) => handle.rawHandle.type === 'source') ?? null;
|
|
1559
|
+
}
|
|
1499
1560
|
}
|
|
1500
1561
|
// In case of virtual scrolling, if the node is scrolled out of view the handle may disappear
|
|
1501
1562
|
// which could lead to the edge not being rendered
|
|
@@ -1508,17 +1569,22 @@ class EdgeModel {
|
|
|
1508
1569
|
});
|
|
1509
1570
|
this.targetHandle = extendedComputed((previousHandle) => {
|
|
1510
1571
|
let handle = null;
|
|
1511
|
-
if (this.
|
|
1512
|
-
handle =
|
|
1513
|
-
this.target()
|
|
1514
|
-
?.handles()
|
|
1515
|
-
.find((handle) => handle.rawHandle.id === this.edge.targetHandle) ?? null;
|
|
1572
|
+
if (this.floating) {
|
|
1573
|
+
handle = this.closestHandles().targetHandle;
|
|
1516
1574
|
}
|
|
1517
1575
|
else {
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1576
|
+
if (this.edge.targetHandle) {
|
|
1577
|
+
handle =
|
|
1578
|
+
this.target()
|
|
1579
|
+
?.handles()
|
|
1580
|
+
.find((handle) => handle.rawHandle.id === this.edge.targetHandle) ?? null;
|
|
1581
|
+
}
|
|
1582
|
+
else {
|
|
1583
|
+
handle =
|
|
1584
|
+
this.target()
|
|
1585
|
+
?.handles()
|
|
1586
|
+
.find((handle) => handle.rawHandle.type === 'target') ?? null;
|
|
1587
|
+
}
|
|
1522
1588
|
}
|
|
1523
1589
|
// In case of virtual scrolling, if the node is scrolled out of view the handle may disappear
|
|
1524
1590
|
// which could lead to the edge not being rendered
|
|
@@ -1529,6 +1595,44 @@ class EdgeModel {
|
|
|
1529
1595
|
}
|
|
1530
1596
|
return handle;
|
|
1531
1597
|
});
|
|
1598
|
+
this.closestHandles = computed(() => {
|
|
1599
|
+
const source = this.source();
|
|
1600
|
+
const target = this.target();
|
|
1601
|
+
if (!source || !target) {
|
|
1602
|
+
return { sourceHandle: null, targetHandle: null };
|
|
1603
|
+
}
|
|
1604
|
+
// Get all source handles from source node
|
|
1605
|
+
const sourceHandles = this.flowEntitiesService.connection().mode === 'strict'
|
|
1606
|
+
? source.handles().filter((h) => h.rawHandle.type === 'source')
|
|
1607
|
+
: source.handles();
|
|
1608
|
+
// Get all target handles from target node
|
|
1609
|
+
const targetHandles = this.flowEntitiesService.connection().mode === 'strict'
|
|
1610
|
+
? target.handles().filter((h) => h.rawHandle.type === 'target')
|
|
1611
|
+
: target.handles();
|
|
1612
|
+
if (sourceHandles.length === 0 || targetHandles.length === 0) {
|
|
1613
|
+
return { sourceHandle: null, targetHandle: null };
|
|
1614
|
+
}
|
|
1615
|
+
let minDistance = Infinity;
|
|
1616
|
+
let closestSourceHandle = null;
|
|
1617
|
+
let closestTargetHandle = null;
|
|
1618
|
+
// Check all combinations of source and target handles
|
|
1619
|
+
for (const sourceHandle of sourceHandles) {
|
|
1620
|
+
for (const targetHandle of targetHandles) {
|
|
1621
|
+
const sourcePoint = sourceHandle.pointAbsolute();
|
|
1622
|
+
const targetPoint = targetHandle.pointAbsolute();
|
|
1623
|
+
const distance = Math.sqrt(Math.pow(sourcePoint.x - targetPoint.x, 2) + Math.pow(sourcePoint.y - targetPoint.y, 2));
|
|
1624
|
+
if (distance < minDistance) {
|
|
1625
|
+
minDistance = distance;
|
|
1626
|
+
closestSourceHandle = sourceHandle;
|
|
1627
|
+
closestTargetHandle = targetHandle;
|
|
1628
|
+
}
|
|
1629
|
+
}
|
|
1630
|
+
}
|
|
1631
|
+
return {
|
|
1632
|
+
sourceHandle: closestSourceHandle,
|
|
1633
|
+
targetHandle: closestTargetHandle,
|
|
1634
|
+
};
|
|
1635
|
+
});
|
|
1532
1636
|
/**
|
|
1533
1637
|
* TODO: not reactive
|
|
1534
1638
|
*/
|
|
@@ -1557,6 +1661,7 @@ class EdgeModel {
|
|
|
1557
1661
|
this.type = edge.type ?? 'default';
|
|
1558
1662
|
this.curve = edge.curve ?? 'bezier';
|
|
1559
1663
|
this.reconnectable = edge.reconnectable ?? false;
|
|
1664
|
+
this.floating = edge.floating ?? false;
|
|
1560
1665
|
if (edge.edgeLabels?.start)
|
|
1561
1666
|
this.edgeLabels.start = new EdgeLabelModel(edge.edgeLabels.start);
|
|
1562
1667
|
if (edge.edgeLabels?.center)
|
|
@@ -2028,7 +2133,7 @@ class SpacePointContextDirective {
|
|
|
2028
2133
|
y: movement.y,
|
|
2029
2134
|
});
|
|
2030
2135
|
});
|
|
2031
|
-
this.pointerMovement =
|
|
2136
|
+
this.pointerMovement = toSignal(this.pointerMovementDirective.pointerMovement$);
|
|
2032
2137
|
}
|
|
2033
2138
|
documentPointToFlowPoint(documentPoint) {
|
|
2034
2139
|
const point = this.rootSvg.createSVGPoint();
|
|
@@ -2860,23 +2965,23 @@ class HandleModel {
|
|
|
2860
2965
|
switch (this.rawHandle.position) {
|
|
2861
2966
|
case 'left':
|
|
2862
2967
|
return {
|
|
2863
|
-
x:
|
|
2864
|
-
y: this.hostPosition().y + this.hostSize().height / 2,
|
|
2968
|
+
x: -this.rawHandle.userOffsetX,
|
|
2969
|
+
y: -this.rawHandle.userOffsetY + this.hostPosition().y + this.hostSize().height / 2,
|
|
2865
2970
|
};
|
|
2866
2971
|
case 'right':
|
|
2867
2972
|
return {
|
|
2868
|
-
x: this.parentNode.size().width,
|
|
2869
|
-
y: this.hostPosition().y + this.hostSize().height / 2,
|
|
2973
|
+
x: -this.rawHandle.userOffsetX + this.parentNode.size().width,
|
|
2974
|
+
y: -this.rawHandle.userOffsetY + this.hostPosition().y + this.hostSize().height / 2,
|
|
2870
2975
|
};
|
|
2871
2976
|
case 'top':
|
|
2872
2977
|
return {
|
|
2873
|
-
x: this.hostPosition().x + this.hostSize().width / 2,
|
|
2874
|
-
y:
|
|
2978
|
+
x: -this.rawHandle.userOffsetX + this.hostPosition().x + this.hostSize().width / 2,
|
|
2979
|
+
y: -this.rawHandle.userOffsetY,
|
|
2875
2980
|
};
|
|
2876
2981
|
case 'bottom':
|
|
2877
2982
|
return {
|
|
2878
|
-
x: this.hostPosition().x + this.hostSize().width / 2,
|
|
2879
|
-
y: this.parentNode.size().height,
|
|
2983
|
+
x: -this.rawHandle.userOffsetX + this.hostPosition().x + this.hostSize().width / 2,
|
|
2984
|
+
y: -this.rawHandle.userOffsetY + this.parentNode.size().height,
|
|
2880
2985
|
};
|
|
2881
2986
|
}
|
|
2882
2987
|
});
|
|
@@ -2938,6 +3043,8 @@ class HandleComponent {
|
|
|
2938
3043
|
*/
|
|
2939
3044
|
this.id = input();
|
|
2940
3045
|
this.template = input();
|
|
3046
|
+
this.offsetX = input(0);
|
|
3047
|
+
this.offsetY = input(0);
|
|
2941
3048
|
}
|
|
2942
3049
|
ngOnInit() {
|
|
2943
3050
|
runInInjectionContext(this.injector, () => {
|
|
@@ -2949,6 +3056,8 @@ class HandleComponent {
|
|
|
2949
3056
|
id: this.id(),
|
|
2950
3057
|
hostReference: this.element.parentElement,
|
|
2951
3058
|
template: this.template(),
|
|
3059
|
+
userOffsetX: this.offsetX(),
|
|
3060
|
+
userOffsetY: this.offsetY(),
|
|
2952
3061
|
}, node);
|
|
2953
3062
|
this.handleService.createHandle(model);
|
|
2954
3063
|
requestAnimationFrame(() => model.updateHost());
|
|
@@ -2957,7 +3066,7 @@ class HandleComponent {
|
|
|
2957
3066
|
});
|
|
2958
3067
|
}
|
|
2959
3068
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: HandleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2960
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "17.3.12", type: HandleComponent, isStandalone: true, selector: "handle", inputs: { position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: true, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: true, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, template: { classPropertyName: "template", publicName: "template", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "", changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
3069
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "17.3.12", type: HandleComponent, isStandalone: true, selector: "handle", inputs: { position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: true, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: true, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, template: { classPropertyName: "template", publicName: "template", isSignal: true, isRequired: false, transformFunction: null }, offsetX: { classPropertyName: "offsetX", publicName: "offsetX", isSignal: true, isRequired: false, transformFunction: null }, offsetY: { classPropertyName: "offsetY", publicName: "offsetY", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "", changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
2961
3070
|
}
|
|
2962
3071
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: HandleComponent, decorators: [{
|
|
2963
3072
|
type: Component,
|
|
@@ -3089,7 +3198,7 @@ class NodeComponent {
|
|
|
3089
3198
|
}
|
|
3090
3199
|
}
|
|
3091
3200
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NodeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3092
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: NodeComponent, isStandalone: true, selector: "g[node]", inputs: { model: { classPropertyName: "model", publicName: "model", isSignal: true, isRequired: true, transformFunction: null }, nodeTemplate: { classPropertyName: "nodeTemplate", publicName: "nodeTemplate", isSignal: true, isRequired: false, transformFunction: null }, nodeSvgTemplate: { classPropertyName: "nodeSvgTemplate", publicName: "nodeSvgTemplate", isSignal: true, isRequired: false, transformFunction: null }, groupNodeTemplate: { classPropertyName: "groupNodeTemplate", publicName: "groupNodeTemplate", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "vflow-node" }, providers: [HandleService, NodeAccessorService], ngImport: i0, template: "<!-- Default node -->\n@if (model().rawNode.type === 'default') {\n <svg:foreignObject\n class=\"selectable\"\n [attr.width]=\"model().foWidth()\"\n [attr.height]=\"model().foHeight()\"\n (click)=\"pullNode(); selectNode()\">\n <default-node\n nodeHandlesController\n [selected]=\"model().selected()\"\n [style.width]=\"model().styleWidth()\"\n [style.height]=\"model().styleHeight()\"\n [style.max-width]=\"model().styleWidth()\"\n [style.max-height]=\"model().styleHeight()\">\n <div [outerHTML]=\"model().text()\"></div>\n\n <handle type=\"source\" position=\"right\" />\n <handle type=\"target\" position=\"left\" />\n </default-node>\n </svg:foreignObject>\n}\n\n<!-- HTML Template node -->\n@if (model().rawNode.type === 'html-template' && nodeTemplate()) {\n <svg:foreignObject\n class=\"selectable\"\n [attr.width]=\"model().foWidth()\"\n [attr.height]=\"model().foHeight()\"\n (click)=\"pullNode()\">\n <div\n nodeHandlesController\n nodeResizeController\n class=\"wrapper\"\n [style.width]=\"model().styleWidth()\"\n [style.height]=\"model().styleHeight()\">\n <ng-container\n [ngTemplateOutlet]=\"nodeTemplate() ?? null\"\n [ngTemplateOutletContext]=\"model().context\"\n [ngTemplateOutletInjector]=\"injector\" />\n </div>\n </svg:foreignObject>\n}\n\n<!-- SVG Template node -->\n@if (model().rawNode.type === 'svg-template' && nodeSvgTemplate()) {\n <svg:g class=\"selectable\" nodeHandlesController (click)=\"pullNode()\">\n <ng-container\n [ngTemplateOutlet]=\"nodeSvgTemplate() ?? null\"\n [ngTemplateOutletContext]=\"model().context\"\n [ngTemplateOutletInjector]=\"injector\" />\n </svg:g>\n}\n\n<!-- Component node -->\n@if (model().isComponentType) {\n <svg:foreignObject\n class=\"selectable\"\n [attr.width]=\"model().foWidth()\"\n [attr.height]=\"model().foHeight()\"\n (click)=\"pullNode()\">\n <div\n nodeHandlesController\n nodeResizeController\n class=\"wrapper\"\n [style.width]=\"model().styleWidth()\"\n [style.height]=\"model().styleHeight()\">\n <ng-container\n [ngComponentOutlet]=\"$any(model().rawNode.type)\"\n [ngComponentOutletInputs]=\"model().componentTypeInputs\"\n [ngComponentOutletInjector]=\"injector\" />\n </div>\n </svg:foreignObject>\n}\n\n<!-- Default group node -->\n@if (model().rawNode.type === 'default-group') {\n <svg:rect\n class=\"default-group-node\"\n rx=\"5\"\n ry=\"5\"\n [resizable]=\"model().resizable()\"\n [gap]=\"3\"\n [resizerColor]=\"model().color()\"\n [class.default-group-node_selected]=\"model().selected()\"\n [attr.width]=\"model().size().width\"\n [attr.height]=\"model().size().height\"\n [style.stroke]=\"model().color()\"\n [style.fill]=\"model().color()\"\n (click)=\"pullNode(); selectNode()\" />\n}\n\n<!-- Template group node -->\n@if (model().rawNode.type === 'template-group' && groupNodeTemplate()) {\n <svg:g class=\"selectable\" nodeHandlesController (click)=\"pullNode()\">\n <ng-container\n [ngTemplateOutlet]=\"groupNodeTemplate() ?? null\"\n [ngTemplateOutletContext]=\"model().context\"\n [ngTemplateOutletInjector]=\"injector\" />\n </svg:g>\n}\n\n<!-- Resizer -->\n@if (model().resizerTemplate(); as template) {\n @if (model().resizable()) {\n <ng-template [ngTemplateOutlet]=\"template\" />\n }\n}\n\n<!-- Handles -->\n@for (handle of model().handles(); track handle) {\n @if (
|
|
3201
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: NodeComponent, isStandalone: true, selector: "g[node]", inputs: { model: { classPropertyName: "model", publicName: "model", isSignal: true, isRequired: true, transformFunction: null }, nodeTemplate: { classPropertyName: "nodeTemplate", publicName: "nodeTemplate", isSignal: true, isRequired: false, transformFunction: null }, nodeSvgTemplate: { classPropertyName: "nodeSvgTemplate", publicName: "nodeSvgTemplate", isSignal: true, isRequired: false, transformFunction: null }, groupNodeTemplate: { classPropertyName: "groupNodeTemplate", publicName: "groupNodeTemplate", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "vflow-node" }, providers: [HandleService, NodeAccessorService], ngImport: i0, template: "<!-- Default node -->\n@if (model().rawNode.type === 'default') {\n <svg:foreignObject\n class=\"selectable\"\n [attr.width]=\"model().foWidth()\"\n [attr.height]=\"model().foHeight()\"\n (click)=\"pullNode(); selectNode()\">\n <default-node\n nodeHandlesController\n [selected]=\"model().selected()\"\n [style.width]=\"model().styleWidth()\"\n [style.height]=\"model().styleHeight()\"\n [style.max-width]=\"model().styleWidth()\"\n [style.max-height]=\"model().styleHeight()\">\n <div [outerHTML]=\"model().text()\"></div>\n\n <handle type=\"source\" position=\"right\" />\n <handle type=\"target\" position=\"left\" />\n </default-node>\n </svg:foreignObject>\n}\n\n<!-- HTML Template node -->\n@if (model().rawNode.type === 'html-template' && nodeTemplate()) {\n <svg:foreignObject\n class=\"selectable\"\n [attr.width]=\"model().foWidth()\"\n [attr.height]=\"model().foHeight()\"\n (click)=\"pullNode()\">\n <div\n nodeHandlesController\n nodeResizeController\n class=\"wrapper\"\n [style.width]=\"model().styleWidth()\"\n [style.height]=\"model().styleHeight()\">\n <ng-container\n [ngTemplateOutlet]=\"nodeTemplate() ?? null\"\n [ngTemplateOutletContext]=\"model().context\"\n [ngTemplateOutletInjector]=\"injector\" />\n </div>\n </svg:foreignObject>\n}\n\n<!-- SVG Template node -->\n@if (model().rawNode.type === 'svg-template' && nodeSvgTemplate()) {\n <svg:g class=\"selectable\" nodeHandlesController (click)=\"pullNode()\">\n <ng-container\n [ngTemplateOutlet]=\"nodeSvgTemplate() ?? null\"\n [ngTemplateOutletContext]=\"model().context\"\n [ngTemplateOutletInjector]=\"injector\" />\n </svg:g>\n}\n\n<!-- Component node -->\n@if (model().isComponentType) {\n <svg:foreignObject\n class=\"selectable\"\n [attr.width]=\"model().foWidth()\"\n [attr.height]=\"model().foHeight()\"\n (click)=\"pullNode()\">\n <div\n nodeHandlesController\n nodeResizeController\n class=\"wrapper\"\n [style.width]=\"model().styleWidth()\"\n [style.height]=\"model().styleHeight()\">\n <ng-container\n [ngComponentOutlet]=\"$any(model().rawNode.type)\"\n [ngComponentOutletInputs]=\"model().componentTypeInputs\"\n [ngComponentOutletInjector]=\"injector\" />\n </div>\n </svg:foreignObject>\n}\n\n<!-- Default group node -->\n@if (model().rawNode.type === 'default-group') {\n <svg:rect\n class=\"default-group-node\"\n rx=\"5\"\n ry=\"5\"\n [resizable]=\"model().resizable()\"\n [gap]=\"3\"\n [resizerColor]=\"model().color()\"\n [class.default-group-node_selected]=\"model().selected()\"\n [attr.width]=\"model().size().width\"\n [attr.height]=\"model().size().height\"\n [style.stroke]=\"model().color()\"\n [style.fill]=\"model().color()\"\n (click)=\"pullNode(); selectNode()\" />\n}\n\n<!-- Template group node -->\n@if (model().rawNode.type === 'template-group' && groupNodeTemplate()) {\n <svg:g class=\"selectable\" nodeHandlesController (click)=\"pullNode()\">\n <ng-container\n [ngTemplateOutlet]=\"groupNodeTemplate() ?? null\"\n [ngTemplateOutletContext]=\"model().context\"\n [ngTemplateOutletInjector]=\"injector\" />\n </svg:g>\n}\n\n<!-- Resizer -->\n@if (model().resizerTemplate(); as template) {\n @if (model().resizable()) {\n <ng-template [ngTemplateOutlet]=\"template\" />\n }\n}\n\n<!-- Handles -->\n@for (handle of model().handles(); track handle) {\n @if (handle.template === undefined) {\n <svg:circle\n class=\"default-handle\"\n r=\"5\"\n [attr.cx]=\"handle.hostOffset().x\"\n [attr.cy]=\"handle.hostOffset().y\"\n [attr.stroke-width]=\"handle.strokeWidth\"\n (pointerStart)=\"startConnection($event, handle)\"\n (pointerEnd)=\"endConnection()\" />\n }\n\n @if (handle.template === null) {\n <svg:g\n [handleSizeController]=\"handle\"\n (pointerStart)=\"startConnection($event, handle)\"\n (pointerEnd)=\"endConnection()\" />\n }\n\n @if (handle.template) {\n <svg:g\n [handleSizeController]=\"handle\"\n (pointerStart)=\"startConnection($event, handle)\"\n (pointerEnd)=\"endConnection()\">\n <ng-container *ngTemplateOutlet=\"handle.template; context: handle.templateContext\" />\n </svg:g>\n }\n\n @if (showMagnet()) {\n <svg:circle\n class=\"magnet\"\n [attr.r]=\"model().magnetRadius\"\n [attr.cx]=\"handle.hostOffset().x\"\n [attr.cy]=\"handle.hostOffset().y\"\n (pointerEnd)=\"endConnection(); resetValidateConnection(handle)\"\n (pointerOver)=\"validateConnection(handle)\"\n (pointerOut)=\"resetValidateConnection(handle)\" />\n }\n}\n\n<!-- Toolbar -->\n@for (toolbar of toolbars(); track toolbar) {\n <svg:foreignObject\n [attr.width]=\"toolbar.size().width\"\n [attr.height]=\"toolbar.size().height\"\n [attr.transform]=\"toolbar.transform()\">\n <ng-container [ngTemplateOutlet]=\"toolbar.template()\" />\n </svg:foreignObject>\n}\n", styles: [".magnet{opacity:0}.wrapper{display:table-cell}.default-group-node{stroke-width:1.5px;fill-opacity:.05}.default-group-node_selected{stroke-width:2px}.default-handle{stroke:#fff;fill:#1b262c}\n"], dependencies: [{ kind: "directive", type: PointerDirective, selector: "[pointerStart], [pointerEnd], [pointerOver], [pointerOut]", outputs: ["pointerOver", "pointerOut", "pointerStart", "pointerEnd"] }, { kind: "component", type: DefaultNodeComponent, selector: "default-node", inputs: ["selected"] }, { kind: "component", type: HandleComponent, selector: "handle", inputs: ["position", "type", "id", "template", "offsetX", "offsetY"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"] }, { kind: "component", type: ResizableComponent, selector: "[resizable]", inputs: ["resizable", "resizerColor", "gap"] }, { kind: "directive", type: HandleSizeControllerDirective, selector: "[handleSizeController]", inputs: ["handleSizeController"] }, { kind: "directive", type: NodeHandlesControllerDirective, selector: "[nodeHandlesController]" }, { kind: "directive", type: NodeResizeControllerDirective, selector: "[nodeResizeController]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
3093
3202
|
}
|
|
3094
3203
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NodeComponent, decorators: [{
|
|
3095
3204
|
type: Component,
|
|
@@ -3105,7 +3214,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
3105
3214
|
HandleSizeControllerDirective,
|
|
3106
3215
|
NodeHandlesControllerDirective,
|
|
3107
3216
|
NodeResizeControllerDirective,
|
|
3108
|
-
], template: "<!-- Default node -->\n@if (model().rawNode.type === 'default') {\n <svg:foreignObject\n class=\"selectable\"\n [attr.width]=\"model().foWidth()\"\n [attr.height]=\"model().foHeight()\"\n (click)=\"pullNode(); selectNode()\">\n <default-node\n nodeHandlesController\n [selected]=\"model().selected()\"\n [style.width]=\"model().styleWidth()\"\n [style.height]=\"model().styleHeight()\"\n [style.max-width]=\"model().styleWidth()\"\n [style.max-height]=\"model().styleHeight()\">\n <div [outerHTML]=\"model().text()\"></div>\n\n <handle type=\"source\" position=\"right\" />\n <handle type=\"target\" position=\"left\" />\n </default-node>\n </svg:foreignObject>\n}\n\n<!-- HTML Template node -->\n@if (model().rawNode.type === 'html-template' && nodeTemplate()) {\n <svg:foreignObject\n class=\"selectable\"\n [attr.width]=\"model().foWidth()\"\n [attr.height]=\"model().foHeight()\"\n (click)=\"pullNode()\">\n <div\n nodeHandlesController\n nodeResizeController\n class=\"wrapper\"\n [style.width]=\"model().styleWidth()\"\n [style.height]=\"model().styleHeight()\">\n <ng-container\n [ngTemplateOutlet]=\"nodeTemplate() ?? null\"\n [ngTemplateOutletContext]=\"model().context\"\n [ngTemplateOutletInjector]=\"injector\" />\n </div>\n </svg:foreignObject>\n}\n\n<!-- SVG Template node -->\n@if (model().rawNode.type === 'svg-template' && nodeSvgTemplate()) {\n <svg:g class=\"selectable\" nodeHandlesController (click)=\"pullNode()\">\n <ng-container\n [ngTemplateOutlet]=\"nodeSvgTemplate() ?? null\"\n [ngTemplateOutletContext]=\"model().context\"\n [ngTemplateOutletInjector]=\"injector\" />\n </svg:g>\n}\n\n<!-- Component node -->\n@if (model().isComponentType) {\n <svg:foreignObject\n class=\"selectable\"\n [attr.width]=\"model().foWidth()\"\n [attr.height]=\"model().foHeight()\"\n (click)=\"pullNode()\">\n <div\n nodeHandlesController\n nodeResizeController\n class=\"wrapper\"\n [style.width]=\"model().styleWidth()\"\n [style.height]=\"model().styleHeight()\">\n <ng-container\n [ngComponentOutlet]=\"$any(model().rawNode.type)\"\n [ngComponentOutletInputs]=\"model().componentTypeInputs\"\n [ngComponentOutletInjector]=\"injector\" />\n </div>\n </svg:foreignObject>\n}\n\n<!-- Default group node -->\n@if (model().rawNode.type === 'default-group') {\n <svg:rect\n class=\"default-group-node\"\n rx=\"5\"\n ry=\"5\"\n [resizable]=\"model().resizable()\"\n [gap]=\"3\"\n [resizerColor]=\"model().color()\"\n [class.default-group-node_selected]=\"model().selected()\"\n [attr.width]=\"model().size().width\"\n [attr.height]=\"model().size().height\"\n [style.stroke]=\"model().color()\"\n [style.fill]=\"model().color()\"\n (click)=\"pullNode(); selectNode()\" />\n}\n\n<!-- Template group node -->\n@if (model().rawNode.type === 'template-group' && groupNodeTemplate()) {\n <svg:g class=\"selectable\" nodeHandlesController (click)=\"pullNode()\">\n <ng-container\n [ngTemplateOutlet]=\"groupNodeTemplate() ?? null\"\n [ngTemplateOutletContext]=\"model().context\"\n [ngTemplateOutletInjector]=\"injector\" />\n </svg:g>\n}\n\n<!-- Resizer -->\n@if (model().resizerTemplate(); as template) {\n @if (model().resizable()) {\n <ng-template [ngTemplateOutlet]=\"template\" />\n }\n}\n\n<!-- Handles -->\n@for (handle of model().handles(); track handle) {\n @if (
|
|
3217
|
+
], template: "<!-- Default node -->\n@if (model().rawNode.type === 'default') {\n <svg:foreignObject\n class=\"selectable\"\n [attr.width]=\"model().foWidth()\"\n [attr.height]=\"model().foHeight()\"\n (click)=\"pullNode(); selectNode()\">\n <default-node\n nodeHandlesController\n [selected]=\"model().selected()\"\n [style.width]=\"model().styleWidth()\"\n [style.height]=\"model().styleHeight()\"\n [style.max-width]=\"model().styleWidth()\"\n [style.max-height]=\"model().styleHeight()\">\n <div [outerHTML]=\"model().text()\"></div>\n\n <handle type=\"source\" position=\"right\" />\n <handle type=\"target\" position=\"left\" />\n </default-node>\n </svg:foreignObject>\n}\n\n<!-- HTML Template node -->\n@if (model().rawNode.type === 'html-template' && nodeTemplate()) {\n <svg:foreignObject\n class=\"selectable\"\n [attr.width]=\"model().foWidth()\"\n [attr.height]=\"model().foHeight()\"\n (click)=\"pullNode()\">\n <div\n nodeHandlesController\n nodeResizeController\n class=\"wrapper\"\n [style.width]=\"model().styleWidth()\"\n [style.height]=\"model().styleHeight()\">\n <ng-container\n [ngTemplateOutlet]=\"nodeTemplate() ?? null\"\n [ngTemplateOutletContext]=\"model().context\"\n [ngTemplateOutletInjector]=\"injector\" />\n </div>\n </svg:foreignObject>\n}\n\n<!-- SVG Template node -->\n@if (model().rawNode.type === 'svg-template' && nodeSvgTemplate()) {\n <svg:g class=\"selectable\" nodeHandlesController (click)=\"pullNode()\">\n <ng-container\n [ngTemplateOutlet]=\"nodeSvgTemplate() ?? null\"\n [ngTemplateOutletContext]=\"model().context\"\n [ngTemplateOutletInjector]=\"injector\" />\n </svg:g>\n}\n\n<!-- Component node -->\n@if (model().isComponentType) {\n <svg:foreignObject\n class=\"selectable\"\n [attr.width]=\"model().foWidth()\"\n [attr.height]=\"model().foHeight()\"\n (click)=\"pullNode()\">\n <div\n nodeHandlesController\n nodeResizeController\n class=\"wrapper\"\n [style.width]=\"model().styleWidth()\"\n [style.height]=\"model().styleHeight()\">\n <ng-container\n [ngComponentOutlet]=\"$any(model().rawNode.type)\"\n [ngComponentOutletInputs]=\"model().componentTypeInputs\"\n [ngComponentOutletInjector]=\"injector\" />\n </div>\n </svg:foreignObject>\n}\n\n<!-- Default group node -->\n@if (model().rawNode.type === 'default-group') {\n <svg:rect\n class=\"default-group-node\"\n rx=\"5\"\n ry=\"5\"\n [resizable]=\"model().resizable()\"\n [gap]=\"3\"\n [resizerColor]=\"model().color()\"\n [class.default-group-node_selected]=\"model().selected()\"\n [attr.width]=\"model().size().width\"\n [attr.height]=\"model().size().height\"\n [style.stroke]=\"model().color()\"\n [style.fill]=\"model().color()\"\n (click)=\"pullNode(); selectNode()\" />\n}\n\n<!-- Template group node -->\n@if (model().rawNode.type === 'template-group' && groupNodeTemplate()) {\n <svg:g class=\"selectable\" nodeHandlesController (click)=\"pullNode()\">\n <ng-container\n [ngTemplateOutlet]=\"groupNodeTemplate() ?? null\"\n [ngTemplateOutletContext]=\"model().context\"\n [ngTemplateOutletInjector]=\"injector\" />\n </svg:g>\n}\n\n<!-- Resizer -->\n@if (model().resizerTemplate(); as template) {\n @if (model().resizable()) {\n <ng-template [ngTemplateOutlet]=\"template\" />\n }\n}\n\n<!-- Handles -->\n@for (handle of model().handles(); track handle) {\n @if (handle.template === undefined) {\n <svg:circle\n class=\"default-handle\"\n r=\"5\"\n [attr.cx]=\"handle.hostOffset().x\"\n [attr.cy]=\"handle.hostOffset().y\"\n [attr.stroke-width]=\"handle.strokeWidth\"\n (pointerStart)=\"startConnection($event, handle)\"\n (pointerEnd)=\"endConnection()\" />\n }\n\n @if (handle.template === null) {\n <svg:g\n [handleSizeController]=\"handle\"\n (pointerStart)=\"startConnection($event, handle)\"\n (pointerEnd)=\"endConnection()\" />\n }\n\n @if (handle.template) {\n <svg:g\n [handleSizeController]=\"handle\"\n (pointerStart)=\"startConnection($event, handle)\"\n (pointerEnd)=\"endConnection()\">\n <ng-container *ngTemplateOutlet=\"handle.template; context: handle.templateContext\" />\n </svg:g>\n }\n\n @if (showMagnet()) {\n <svg:circle\n class=\"magnet\"\n [attr.r]=\"model().magnetRadius\"\n [attr.cx]=\"handle.hostOffset().x\"\n [attr.cy]=\"handle.hostOffset().y\"\n (pointerEnd)=\"endConnection(); resetValidateConnection(handle)\"\n (pointerOver)=\"validateConnection(handle)\"\n (pointerOut)=\"resetValidateConnection(handle)\" />\n }\n}\n\n<!-- Toolbar -->\n@for (toolbar of toolbars(); track toolbar) {\n <svg:foreignObject\n [attr.width]=\"toolbar.size().width\"\n [attr.height]=\"toolbar.size().height\"\n [attr.transform]=\"toolbar.transform()\">\n <ng-container [ngTemplateOutlet]=\"toolbar.template()\" />\n </svg:foreignObject>\n}\n", styles: [".magnet{opacity:0}.wrapper{display:table-cell}.default-group-node{stroke-width:1.5px;fill-opacity:.05}.default-group-node_selected{stroke-width:2px}.default-handle{stroke:#fff;fill:#1b262c}\n"] }]
|
|
3109
3218
|
}] });
|
|
3110
3219
|
|
|
3111
3220
|
class ConnectionComponent {
|