ngx-vflow 0.11.0 → 0.13.0-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/custom-node-base/custom-node-base.component.mjs +7 -3
- package/esm2022/lib/vflow/components/node/node.component.mjs +16 -13
- package/esm2022/lib/vflow/components/vflow/vflow.component.mjs +5 -2
- package/esm2022/lib/vflow/directives/changes-controller.directive.mjs +14 -2
- package/esm2022/lib/vflow/directives/flow-size-controller.directive.mjs +18 -17
- package/esm2022/lib/vflow/directives/root-pointer.directive.mjs +21 -4
- package/esm2022/lib/vflow/interfaces/component-node-event.interface.mjs +1 -1
- package/esm2022/lib/vflow/interfaces/node.interface.mjs +3 -3
- package/esm2022/lib/vflow/models/node.model.mjs +46 -7
- package/esm2022/lib/vflow/public-components/custom-dynamic-node/custom-dynamic-node.component.mjs +19 -0
- package/esm2022/lib/vflow/public-components/custom-node/custom-node.component.mjs +19 -0
- package/esm2022/lib/vflow/public-components/resizable/resizable.component.mjs +265 -0
- package/esm2022/lib/vflow/services/component-event-bus.service.mjs +1 -1
- package/esm2022/lib/vflow/services/draggable.service.mjs +2 -2
- package/esm2022/lib/vflow/services/node-accessor.service.mjs +16 -0
- package/esm2022/lib/vflow/services/node-changes.service.mjs +6 -2
- package/esm2022/lib/vflow/types/node-change.type.mjs +1 -1
- package/esm2022/lib/vflow/utils/resizable.mjs +3 -3
- package/esm2022/lib/vflow/vflow.module.mjs +9 -4
- package/esm2022/public-api.mjs +4 -3
- package/fesm2022/ngx-vflow.mjs +430 -77
- package/fesm2022/ngx-vflow.mjs.map +1 -1
- package/lib/vflow/components/node/node.component.d.ts +2 -0
- package/lib/vflow/components/vflow/vflow.component.d.ts +1 -1
- package/lib/vflow/directives/changes-controller.directive.d.ts +5 -2
- package/lib/vflow/directives/flow-size-controller.directive.d.ts +3 -2
- package/lib/vflow/directives/root-pointer.directive.d.ts +24 -6
- package/lib/vflow/directives/space-point-context.directive.d.ts +5 -0
- package/lib/vflow/interfaces/component-node-event.interface.d.ts +2 -2
- package/lib/vflow/interfaces/node.interface.d.ts +12 -2
- package/lib/vflow/models/edge.model.d.ts +1 -17
- package/lib/vflow/models/node.model.d.ts +13 -2
- package/lib/vflow/public-components/{custom-dynamic-node.component.d.ts → custom-dynamic-node/custom-dynamic-node.component.d.ts} +2 -2
- package/lib/vflow/public-components/{custom-node.component.d.ts → custom-node/custom-node.component.d.ts} +2 -2
- package/lib/vflow/public-components/resizable/resizable.component.d.ts +39 -0
- package/lib/vflow/services/node-accessor.service.d.ts +10 -0
- package/lib/vflow/services/node-changes.service.d.ts +8 -0
- package/lib/vflow/types/node-change.type.d.ts +8 -1
- package/lib/vflow/utils/resizable.d.ts +2 -1
- package/lib/vflow/vflow.module.d.ts +13 -12
- package/package.json +1 -1
- package/public-api.d.ts +3 -2
- package/esm2022/lib/vflow/public-components/custom-dynamic-node.component.mjs +0 -19
- package/esm2022/lib/vflow/public-components/custom-node.component.mjs +0 -19
package/fesm2022/ngx-vflow.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as i1 from '@angular/common';
|
|
2
2
|
import { CommonModule } from '@angular/common';
|
|
3
3
|
import * as i0 from '@angular/core';
|
|
4
|
-
import { signal, computed, Injectable, inject, ElementRef, Directive, effect, untracked, TemplateRef, EventEmitter, Output, DestroyRef, Input, runInInjectionContext, Injector, Component, ChangeDetectionStrategy, HostListener, ViewChild,
|
|
4
|
+
import { signal, computed, Injectable, inject, ElementRef, Directive, effect, untracked, TemplateRef, EventEmitter, Output, DestroyRef, Input, runInInjectionContext, Injector, Component, ChangeDetectionStrategy, HostListener, ViewChild, NgZone, ContentChild, NgModule } from '@angular/core';
|
|
5
5
|
import { select } from 'd3-selection';
|
|
6
6
|
import { zoomIdentity, zoom } from 'd3-zoom';
|
|
7
7
|
import { Subject, tap, merge, observeOn, animationFrameScheduler, switchMap, skip, map, pairwise, filter, distinctUntilChanged, asyncScheduler, zip, fromEvent, share, Observable, startWith } from 'rxjs';
|
|
@@ -432,7 +432,7 @@ class DraggableService {
|
|
|
432
432
|
point.y = Math.min(parent.size().height - model.size().height, point.y);
|
|
433
433
|
point.y = Math.max(0, point.y);
|
|
434
434
|
}
|
|
435
|
-
model.setPoint(point);
|
|
435
|
+
model.setPoint(point, true);
|
|
436
436
|
});
|
|
437
437
|
}
|
|
438
438
|
/**
|
|
@@ -734,7 +734,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
|
|
|
734
734
|
|
|
735
735
|
class CustomNodeBaseComponent {
|
|
736
736
|
constructor() {
|
|
737
|
-
this.eventBus = inject(ComponentEventBusService);
|
|
737
|
+
this.eventBus = inject(ComponentEventBusService, { optional: true });
|
|
738
738
|
this.destroyRef = inject(DestroyRef);
|
|
739
739
|
/**
|
|
740
740
|
* Signal with selected state of node
|
|
@@ -746,7 +746,11 @@ class CustomNodeBaseComponent {
|
|
|
746
746
|
this.selected.set(value);
|
|
747
747
|
}
|
|
748
748
|
ngOnInit() {
|
|
749
|
-
|
|
749
|
+
if (this.eventBus) {
|
|
750
|
+
this.trackEvents()
|
|
751
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
752
|
+
.subscribe();
|
|
753
|
+
}
|
|
750
754
|
}
|
|
751
755
|
trackEvents() {
|
|
752
756
|
const props = Object.getOwnPropertyNames(this);
|
|
@@ -844,6 +848,7 @@ function isTemplateDynamicGroupNode(node) {
|
|
|
844
848
|
return node.type === 'template-group';
|
|
845
849
|
}
|
|
846
850
|
|
|
851
|
+
// TODO bad naming around points
|
|
847
852
|
class NodeModel {
|
|
848
853
|
static { this.defaultWidth = 100; }
|
|
849
854
|
static { this.defaultHeight = 50; }
|
|
@@ -854,11 +859,15 @@ class NodeModel {
|
|
|
854
859
|
this.entitiesService = inject(FlowEntitiesService);
|
|
855
860
|
this.internalPoint = this.createInternalPointSignal();
|
|
856
861
|
this.throttledPoint$ = toObservable(this.internalPoint).pipe(observeOn(animationFrameScheduler));
|
|
857
|
-
this.
|
|
862
|
+
this.notThrottledPoint$ = new Subject();
|
|
863
|
+
this.point = toSignal(merge(this.throttledPoint$, this.notThrottledPoint$), {
|
|
858
864
|
initialValue: this.internalPoint()
|
|
859
865
|
});
|
|
860
866
|
this.point$ = this.throttledPoint$;
|
|
861
867
|
this.size = signal({ width: 0, height: 0 });
|
|
868
|
+
this.size$ = toObservable(this.size);
|
|
869
|
+
this.width = computed(() => this.size().width);
|
|
870
|
+
this.height = computed(() => this.size().height);
|
|
862
871
|
this.renderOrder = signal(0);
|
|
863
872
|
this.selected = signal(false);
|
|
864
873
|
this.selected$ = toObservable(this.selected);
|
|
@@ -895,7 +904,11 @@ class NodeModel {
|
|
|
895
904
|
};
|
|
896
905
|
});
|
|
897
906
|
this.parent = computed(() => this.entitiesService.nodes().find(n => n.node.id === this.parentId()) ?? null);
|
|
907
|
+
this.children = computed(() => this.entitiesService.nodes().filter(n => n.parentId() === this.node.id));
|
|
898
908
|
this.color = signal(NodeModel.defaultColor);
|
|
909
|
+
this.resizable = signal(false);
|
|
910
|
+
this.resizing = signal(false);
|
|
911
|
+
this.resizerTemplate = signal(null);
|
|
899
912
|
this.parentId = signal(null);
|
|
900
913
|
if (isDefined(node.draggable)) {
|
|
901
914
|
if (isDynamicNode(node)) {
|
|
@@ -921,9 +934,22 @@ class NodeModel {
|
|
|
921
934
|
this.color.set(node.color);
|
|
922
935
|
}
|
|
923
936
|
}
|
|
937
|
+
if (node.type === 'default-group' && node.resizable) {
|
|
938
|
+
if (isDynamicNode(node)) {
|
|
939
|
+
this.resizable = node.resizable;
|
|
940
|
+
}
|
|
941
|
+
else {
|
|
942
|
+
this.resizable.set(node.resizable);
|
|
943
|
+
}
|
|
944
|
+
}
|
|
924
945
|
}
|
|
925
|
-
setPoint(point) {
|
|
926
|
-
|
|
946
|
+
setPoint(point, throttle) {
|
|
947
|
+
if (throttle) {
|
|
948
|
+
this.internalPoint.set(point);
|
|
949
|
+
}
|
|
950
|
+
else {
|
|
951
|
+
this.notThrottledPoint$.next(point);
|
|
952
|
+
}
|
|
927
953
|
}
|
|
928
954
|
/**
|
|
929
955
|
* TODO find the way to implement this better
|
|
@@ -950,6 +976,23 @@ class NodeModel {
|
|
|
950
976
|
}
|
|
951
977
|
}
|
|
952
978
|
}
|
|
979
|
+
if (node.type === 'html-template' || this.isComponentType) {
|
|
980
|
+
if (isDynamicNode(node)) {
|
|
981
|
+
effect(() => {
|
|
982
|
+
if (node.width && node.height) {
|
|
983
|
+
this.size.set({
|
|
984
|
+
width: node.width(),
|
|
985
|
+
height: node.height(),
|
|
986
|
+
});
|
|
987
|
+
}
|
|
988
|
+
}, { allowSignalWrites: true });
|
|
989
|
+
}
|
|
990
|
+
else {
|
|
991
|
+
if (node.width && node.height) {
|
|
992
|
+
this.size.set({ width: node.width, height: node.height });
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
}
|
|
953
996
|
}
|
|
954
997
|
createTextSignal() {
|
|
955
998
|
const node = this.node;
|
|
@@ -1210,6 +1253,10 @@ class NodesChangeService {
|
|
|
1210
1253
|
map(changedNode => [
|
|
1211
1254
|
{ type: 'position', id: changedNode.node.id, point: changedNode.point() }
|
|
1212
1255
|
]));
|
|
1256
|
+
this.nodeSizeChange$ = toObservable(this.entitiesService.nodes)
|
|
1257
|
+
.pipe(switchMap((nodes) => merge(...nodes.map(node => node.size$.pipe(skip(1), map(() => node))))), map(changedNode => [
|
|
1258
|
+
{ type: 'size', id: changedNode.node.id, size: changedNode.size() }
|
|
1259
|
+
]));
|
|
1213
1260
|
this.nodeAddChange$ = toObservable(this.entitiesService.nodes)
|
|
1214
1261
|
.pipe(pairwise(), map(([oldList, newList]) => newList.filter(node => !oldList.includes(node))), filter((nodes) => !!nodes.length), map((nodes) => nodes.map(node => ({ type: 'add', id: node.node.id }))));
|
|
1215
1262
|
this.nodeRemoveChange$ = toObservable(this.entitiesService.nodes)
|
|
@@ -1218,7 +1265,7 @@ class NodesChangeService {
|
|
|
1218
1265
|
.pipe(switchMap((nodes) => merge(...nodes.map(node => node.selected$.pipe(distinctUntilChanged(), skip(1), map(() => node))))), map((changedNode) => [
|
|
1219
1266
|
{ type: 'select', id: changedNode.node.id, selected: changedNode.selected() }
|
|
1220
1267
|
]));
|
|
1221
|
-
this.changes$ = merge(this.nodesPositionChange$, this.nodeAddChange$, this.nodeRemoveChange$, this.nodeSelectedChange$).pipe(
|
|
1268
|
+
this.changes$ = merge(this.nodesPositionChange$, this.nodeSizeChange$, this.nodeAddChange$, this.nodeRemoveChange$, this.nodeSelectedChange$).pipe(
|
|
1222
1269
|
// this fixes a bug when on fire node event change,
|
|
1223
1270
|
// you can't get valid list of detached edges
|
|
1224
1271
|
observeOn(asyncScheduler, DELAY_FOR_SCHEDULER));
|
|
@@ -1285,6 +1332,9 @@ class ChangesControllerDirective {
|
|
|
1285
1332
|
this.onNodesChangePosition = this.nodeChangesOfType('position');
|
|
1286
1333
|
this.onNodesChangePositionSignle = this.singleChange(this.nodeChangesOfType('position'));
|
|
1287
1334
|
this.onNodesChangePositionMany = this.manyChanges(this.nodeChangesOfType('position'));
|
|
1335
|
+
this.onNodesChangeSize = this.nodeChangesOfType('size');
|
|
1336
|
+
this.onNodesChangeSizeSingle = this.singleChange(this.nodeChangesOfType('size'));
|
|
1337
|
+
this.onNodesChangeSizeMany = this.manyChanges(this.nodeChangesOfType('size'));
|
|
1288
1338
|
this.onNodesChangeAdd = this.nodeChangesOfType('add');
|
|
1289
1339
|
this.onNodesChangeAddSingle = this.singleChange(this.nodeChangesOfType('add'));
|
|
1290
1340
|
this.onNodesChangeAddMany = this.manyChanges(this.nodeChangesOfType('add'));
|
|
@@ -1324,7 +1374,7 @@ class ChangesControllerDirective {
|
|
|
1324
1374
|
return changes$.pipe(filter(changes => changes.length > 1));
|
|
1325
1375
|
}
|
|
1326
1376
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ChangesControllerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1327
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: ChangesControllerDirective, isStandalone: true, selector: "[changesController]", outputs: { onNodesChange: "onNodesChange", onNodesChangePosition: "onNodesChange.position", onNodesChangePositionSignle: "onNodesChange.position.single", onNodesChangePositionMany: "onNodesChange.position.many", onNodesChangeAdd: "onNodesChange.add", onNodesChangeAddSingle: "onNodesChange.add.single", onNodesChangeAddMany: "onNodesChange.add.many", onNodesChangeRemove: "onNodesChange.remove", onNodesChangeRemoveSingle: "onNodesChange.remove.single", onNodesChangeRemoveMany: "onNodesChange.remove.many", onNodesChangeSelect: "onNodesChange.select", onNodesChangeSelectSingle: "onNodesChange.select.single", onNodesChangeSelectMany: "onNodesChange.select.many", onEdgesChange: "onEdgesChange", onNodesChangeDetached: "onEdgesChange.detached", onNodesChangeDetachedSingle: "onEdgesChange.detached.single", onNodesChangeDetachedMany: "onEdgesChange.detached.many", onEdgesChangeAdd: "onEdgesChange.add", onEdgeChangeAddSingle: "onEdgesChange.add.single", onEdgeChangeAddMany: "onEdgesChange.add.many", onEdgeChangeRemove: "onEdgesChange.remove", onEdgeChangeRemoveSingle: "onEdgesChange.remove.single", onEdgeChangeRemoveMany: "onEdgesChange.remove.many", onEdgeChangeSelect: "onEdgesChange.select", onEdgeChangeSelectSingle: "onEdgesChange.select.single", onEdgeChangeSelectMany: "onEdgesChange.select.many" }, ngImport: i0 }); }
|
|
1377
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: ChangesControllerDirective, isStandalone: true, selector: "[changesController]", outputs: { onNodesChange: "onNodesChange", onNodesChangePosition: "onNodesChange.position", onNodesChangePositionSignle: "onNodesChange.position.single", onNodesChangePositionMany: "onNodesChange.position.many", onNodesChangeSize: "onNodesChange.size", onNodesChangeSizeSingle: "onNodesChange.size.single", onNodesChangeSizeMany: "onNodesChange.size.many", onNodesChangeAdd: "onNodesChange.add", onNodesChangeAddSingle: "onNodesChange.add.single", onNodesChangeAddMany: "onNodesChange.add.many", onNodesChangeRemove: "onNodesChange.remove", onNodesChangeRemoveSingle: "onNodesChange.remove.single", onNodesChangeRemoveMany: "onNodesChange.remove.many", onNodesChangeSelect: "onNodesChange.select", onNodesChangeSelectSingle: "onNodesChange.select.single", onNodesChangeSelectMany: "onNodesChange.select.many", onEdgesChange: "onEdgesChange", onNodesChangeDetached: "onEdgesChange.detached", onNodesChangeDetachedSingle: "onEdgesChange.detached.single", onNodesChangeDetachedMany: "onEdgesChange.detached.many", onEdgesChangeAdd: "onEdgesChange.add", onEdgeChangeAddSingle: "onEdgesChange.add.single", onEdgeChangeAddMany: "onEdgesChange.add.many", onEdgeChangeRemove: "onEdgesChange.remove", onEdgeChangeRemoveSingle: "onEdgesChange.remove.single", onEdgeChangeRemoveMany: "onEdgesChange.remove.many", onEdgeChangeSelect: "onEdgesChange.select", onEdgeChangeSelectSingle: "onEdgesChange.select.single", onEdgeChangeSelectMany: "onEdgesChange.select.many" }, ngImport: i0 }); }
|
|
1328
1378
|
}
|
|
1329
1379
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ChangesControllerDirective, decorators: [{
|
|
1330
1380
|
type: Directive,
|
|
@@ -1343,6 +1393,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
|
|
|
1343
1393
|
}], onNodesChangePositionMany: [{
|
|
1344
1394
|
type: Output,
|
|
1345
1395
|
args: ['onNodesChange.position.many']
|
|
1396
|
+
}], onNodesChangeSize: [{
|
|
1397
|
+
type: Output,
|
|
1398
|
+
args: ['onNodesChange.size']
|
|
1399
|
+
}], onNodesChangeSizeSingle: [{
|
|
1400
|
+
type: Output,
|
|
1401
|
+
args: ['onNodesChange.size.single']
|
|
1402
|
+
}], onNodesChangeSizeMany: [{
|
|
1403
|
+
type: Output,
|
|
1404
|
+
args: ['onNodesChange.size.many']
|
|
1346
1405
|
}], onNodesChangeAdd: [{
|
|
1347
1406
|
type: Output,
|
|
1348
1407
|
args: ['onNodesChange.add']
|
|
@@ -1442,25 +1501,42 @@ class RootPointerDirective {
|
|
|
1442
1501
|
constructor() {
|
|
1443
1502
|
this.host = inject(ElementRef).nativeElement;
|
|
1444
1503
|
this.initialTouch$ = new Subject();
|
|
1504
|
+
this.prevTouchEvent = null;
|
|
1445
1505
|
// TODO: do not emit if mouse not down
|
|
1446
1506
|
this.mouseMovement$ = fromEvent(this.host, 'mousemove').pipe(map(event => ({
|
|
1447
1507
|
x: event.clientX,
|
|
1448
1508
|
y: event.clientY,
|
|
1509
|
+
movementX: event.movementX,
|
|
1510
|
+
movementY: event.movementY,
|
|
1511
|
+
target: event.target,
|
|
1449
1512
|
originalEvent: event
|
|
1450
1513
|
})), observeOn(animationFrameScheduler), share());
|
|
1451
1514
|
this.touchMovement$ = merge(this.initialTouch$, fromEvent(this.host, 'touchmove')).pipe(tap((event) => event.preventDefault()), map((originalEvent) => {
|
|
1452
1515
|
const x = originalEvent.touches[0]?.clientX ?? 0;
|
|
1453
1516
|
const y = originalEvent.touches[0]?.clientY ?? 0;
|
|
1517
|
+
const movementX = this.prevTouchEvent
|
|
1518
|
+
? originalEvent.touches[0].pageX - this.prevTouchEvent.touches[0].pageX
|
|
1519
|
+
: 0;
|
|
1520
|
+
const movementY = this.prevTouchEvent
|
|
1521
|
+
? originalEvent.touches[0].pageY - this.prevTouchEvent.touches[0].pageY
|
|
1522
|
+
: 0;
|
|
1454
1523
|
const target = document.elementFromPoint(x, y);
|
|
1455
|
-
return { x, y, target, originalEvent };
|
|
1456
|
-
}), observeOn(animationFrameScheduler), share());
|
|
1524
|
+
return { x, y, movementX, movementY, target, originalEvent };
|
|
1525
|
+
}), tap((event) => this.prevTouchEvent = event.originalEvent), observeOn(animationFrameScheduler), share());
|
|
1526
|
+
this.pointerMovement$ = merge(this.mouseMovement$, this.touchMovement$);
|
|
1457
1527
|
this.touchEnd$ = fromEvent(this.host, 'touchend').pipe(map((originalEvent) => {
|
|
1458
1528
|
const x = originalEvent.changedTouches[0]?.clientX ?? 0;
|
|
1459
1529
|
const y = originalEvent.changedTouches[0]?.clientY ?? 0;
|
|
1460
1530
|
const target = document.elementFromPoint(x, y);
|
|
1461
1531
|
return { x, y, target, originalEvent };
|
|
1532
|
+
}), tap(() => this.prevTouchEvent = null), share());
|
|
1533
|
+
this.mouseUp$ = fromEvent(this.host, 'mouseup').pipe(map((originalEvent) => {
|
|
1534
|
+
const x = originalEvent.clientX;
|
|
1535
|
+
const y = originalEvent.clientY;
|
|
1536
|
+
const target = originalEvent.target;
|
|
1537
|
+
return { x, y, target, originalEvent };
|
|
1462
1538
|
}), share());
|
|
1463
|
-
this.
|
|
1539
|
+
this.documentPointerEnd$ = merge(fromEvent(document, 'mouseup'), fromEvent(document, 'touchend')).pipe(share());
|
|
1464
1540
|
}
|
|
1465
1541
|
/**
|
|
1466
1542
|
* We should know when user started a touch in order to not
|
|
@@ -1548,10 +1624,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
|
|
|
1548
1624
|
type: Injectable
|
|
1549
1625
|
}], propDecorators: { createHandle: [] } });
|
|
1550
1626
|
|
|
1551
|
-
function resizable(elems) {
|
|
1627
|
+
function resizable(elems, zone) {
|
|
1552
1628
|
return new Observable((subscriber) => {
|
|
1553
1629
|
let ro = new ResizeObserver((entries) => {
|
|
1554
|
-
subscriber.next(entries);
|
|
1630
|
+
zone.run(() => subscriber.next(entries));
|
|
1555
1631
|
});
|
|
1556
1632
|
elems.forEach(e => ro.observe(e));
|
|
1557
1633
|
return () => ro.disconnect();
|
|
@@ -1575,6 +1651,20 @@ const implementsWithInjector = (instance) => {
|
|
|
1575
1651
|
return 'injector' in instance && 'get' in instance.injector;
|
|
1576
1652
|
};
|
|
1577
1653
|
|
|
1654
|
+
/**
|
|
1655
|
+
* Service to fix cyclic dependency between node and resizable component
|
|
1656
|
+
*/
|
|
1657
|
+
class NodeAccessorService {
|
|
1658
|
+
constructor() {
|
|
1659
|
+
this.model = signal(null);
|
|
1660
|
+
}
|
|
1661
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NodeAccessorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1662
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NodeAccessorService }); }
|
|
1663
|
+
}
|
|
1664
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NodeAccessorService, decorators: [{
|
|
1665
|
+
type: Injectable
|
|
1666
|
+
}] });
|
|
1667
|
+
|
|
1578
1668
|
class HandleModel {
|
|
1579
1669
|
constructor(rawHandle, parentNode) {
|
|
1580
1670
|
this.rawHandle = rawHandle;
|
|
@@ -1704,42 +1794,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
|
|
|
1704
1794
|
type: Input
|
|
1705
1795
|
}], ngOnInit: [] } });
|
|
1706
1796
|
|
|
1707
|
-
class HandleSizeControllerDirective {
|
|
1708
|
-
constructor() {
|
|
1709
|
-
this.handleWrapper = inject(ElementRef);
|
|
1710
|
-
}
|
|
1711
|
-
ngAfterViewInit() {
|
|
1712
|
-
const element = this.handleWrapper.nativeElement;
|
|
1713
|
-
const rect = element.getBBox();
|
|
1714
|
-
const stroke = getChildStrokeWidth(element);
|
|
1715
|
-
this.handleModel.size.set({
|
|
1716
|
-
width: rect.width + stroke,
|
|
1717
|
-
height: rect.height + stroke
|
|
1718
|
-
});
|
|
1719
|
-
}
|
|
1720
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HandleSizeControllerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1721
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: HandleSizeControllerDirective, selector: "[handleSizeController]", inputs: { handleModel: ["handleSizeController", "handleModel"] }, ngImport: i0 }); }
|
|
1722
|
-
}
|
|
1723
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HandleSizeControllerDirective, decorators: [{
|
|
1724
|
-
type: Directive,
|
|
1725
|
-
args: [{ selector: '[handleSizeController]' }]
|
|
1726
|
-
}], propDecorators: { handleModel: [{
|
|
1727
|
-
type: Input,
|
|
1728
|
-
args: [{ required: true, alias: 'handleSizeController' }]
|
|
1729
|
-
}] } });
|
|
1730
|
-
function getChildStrokeWidth(element) {
|
|
1731
|
-
const child = element.firstElementChild;
|
|
1732
|
-
if (child) {
|
|
1733
|
-
const stroke = getComputedStyle(child).strokeWidth;
|
|
1734
|
-
const strokeAsNumber = Number(stroke.replace('px', ''));
|
|
1735
|
-
if (isNaN(strokeAsNumber)) {
|
|
1736
|
-
return 0;
|
|
1737
|
-
}
|
|
1738
|
-
return strokeAsNumber;
|
|
1739
|
-
}
|
|
1740
|
-
return 0;
|
|
1741
|
-
}
|
|
1742
|
-
|
|
1743
1797
|
class PointerDirective {
|
|
1744
1798
|
constructor() {
|
|
1745
1799
|
this.hostElement = inject(ElementRef).nativeElement;
|
|
@@ -1819,6 +1873,295 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
|
|
|
1819
1873
|
args: ['mouseout', ['$event']]
|
|
1820
1874
|
}] } });
|
|
1821
1875
|
|
|
1876
|
+
class ResizableComponent {
|
|
1877
|
+
constructor() {
|
|
1878
|
+
this.nodeAccessor = inject(NodeAccessorService);
|
|
1879
|
+
this.rootPointer = inject(RootPointerDirective);
|
|
1880
|
+
this.viewportService = inject(ViewportService);
|
|
1881
|
+
this.hostRef = inject(ElementRef);
|
|
1882
|
+
this.resizerColor = '#2e414c';
|
|
1883
|
+
this.gap = 1.5;
|
|
1884
|
+
this.lineGap = 3;
|
|
1885
|
+
this.handleSize = 6;
|
|
1886
|
+
this.resizeSide = null;
|
|
1887
|
+
this.zoom = computed(() => this.viewportService.readableViewport().zoom ?? 0);
|
|
1888
|
+
this.minWidth = 0;
|
|
1889
|
+
this.minHeight = 0;
|
|
1890
|
+
// TODO: allow reszie beside the flow
|
|
1891
|
+
this.resizeOnGlobalMouseMove = this.rootPointer.pointerMovement$
|
|
1892
|
+
.pipe(filter(() => this.resizeSide !== null), tap((event) => this.resize(event)), takeUntilDestroyed())
|
|
1893
|
+
.subscribe();
|
|
1894
|
+
this.endResizeOnGlobalMouseUp = this.rootPointer.documentPointerEnd$
|
|
1895
|
+
.pipe(tap(() => this.endResize()), takeUntilDestroyed())
|
|
1896
|
+
.subscribe();
|
|
1897
|
+
}
|
|
1898
|
+
set resizable(value) {
|
|
1899
|
+
if (typeof value === 'boolean') {
|
|
1900
|
+
this.model.resizable.set(value);
|
|
1901
|
+
}
|
|
1902
|
+
else {
|
|
1903
|
+
this.model.resizable.set(true);
|
|
1904
|
+
}
|
|
1905
|
+
}
|
|
1906
|
+
get model() {
|
|
1907
|
+
return this.nodeAccessor.model();
|
|
1908
|
+
}
|
|
1909
|
+
ngOnInit() {
|
|
1910
|
+
this.model.resizerTemplate.set(this.resizer);
|
|
1911
|
+
}
|
|
1912
|
+
ngAfterViewInit() {
|
|
1913
|
+
this.minWidth = +getComputedStyle(this.hostRef.nativeElement).minWidth.replace('px', '') || 0;
|
|
1914
|
+
this.minHeight = +getComputedStyle(this.hostRef.nativeElement).minHeight.replace('px', '') || 0;
|
|
1915
|
+
}
|
|
1916
|
+
startResize(side, event) {
|
|
1917
|
+
event.stopPropagation();
|
|
1918
|
+
this.resizeSide = side;
|
|
1919
|
+
this.model.resizing.set(true);
|
|
1920
|
+
}
|
|
1921
|
+
resize({ movementX, movementY }) {
|
|
1922
|
+
const offsetX = round(movementX / this.zoom());
|
|
1923
|
+
const offsetY = round(movementY / this.zoom());
|
|
1924
|
+
switch (this.resizeSide) {
|
|
1925
|
+
case 'left':
|
|
1926
|
+
let x = this.model.point().x + offsetX;
|
|
1927
|
+
x = Math.max(x, this.getMinX());
|
|
1928
|
+
x = Math.min(x, this.getMaxX());
|
|
1929
|
+
// TODO this fixes increasing width when current node hits the parent
|
|
1930
|
+
if (x === this.getMinX() || x === this.getMaxX()) {
|
|
1931
|
+
return;
|
|
1932
|
+
}
|
|
1933
|
+
this.model.setPoint({ x, y: this.model.point().y }, false);
|
|
1934
|
+
this.model.size.update(({ height, width }) => {
|
|
1935
|
+
width -= offsetX;
|
|
1936
|
+
width = Math.max(width, this.minWidth);
|
|
1937
|
+
width = Math.min(width, this.getMaxWidth());
|
|
1938
|
+
return { height, width: width };
|
|
1939
|
+
});
|
|
1940
|
+
return;
|
|
1941
|
+
case 'right':
|
|
1942
|
+
this.model.size.update(({ height, width }) => {
|
|
1943
|
+
width += offsetX;
|
|
1944
|
+
width = Math.max(width, this.minWidth);
|
|
1945
|
+
width = Math.min(width, this.getMaxWidth());
|
|
1946
|
+
const bounds = getNodesBounds(this.model.children());
|
|
1947
|
+
width = Math.max(width, bounds.x + bounds.width);
|
|
1948
|
+
return { height, width };
|
|
1949
|
+
});
|
|
1950
|
+
return;
|
|
1951
|
+
case 'top':
|
|
1952
|
+
let y = this.model.point().y + offsetY;
|
|
1953
|
+
y = Math.max(y, this.getMinY());
|
|
1954
|
+
y = Math.min(y, this.getMaxY());
|
|
1955
|
+
if (y === this.getMinY() || y === this.getMaxY()) {
|
|
1956
|
+
return;
|
|
1957
|
+
}
|
|
1958
|
+
this.model.setPoint({ x: this.model.point().x, y }, false);
|
|
1959
|
+
this.model.size.update(({ height, width }) => {
|
|
1960
|
+
height -= offsetY;
|
|
1961
|
+
height = Math.max(height, this.minHeight);
|
|
1962
|
+
height = Math.min(height, this.getMaxHeight());
|
|
1963
|
+
return { width, height };
|
|
1964
|
+
});
|
|
1965
|
+
return;
|
|
1966
|
+
case 'bottom':
|
|
1967
|
+
this.model.size.update(({ height, width }) => {
|
|
1968
|
+
height += offsetY;
|
|
1969
|
+
height = Math.max(height, this.minHeight);
|
|
1970
|
+
height = Math.min(height, this.getMaxHeight());
|
|
1971
|
+
const bounds = getNodesBounds(this.model.children());
|
|
1972
|
+
height = Math.max(height, bounds.y + bounds.height);
|
|
1973
|
+
return { width, height };
|
|
1974
|
+
});
|
|
1975
|
+
return;
|
|
1976
|
+
case 'top-left': {
|
|
1977
|
+
let x = this.model.point().x + offsetX;
|
|
1978
|
+
x = Math.max(x, this.getMinX());
|
|
1979
|
+
x = Math.min(x, this.getMaxX());
|
|
1980
|
+
let y = this.model.point().y + offsetY;
|
|
1981
|
+
y = Math.max(y, this.getMinY());
|
|
1982
|
+
y = Math.min(y, this.getMaxY());
|
|
1983
|
+
if (x === this.getMinX() || y === this.getMinY() ||
|
|
1984
|
+
x === this.getMaxX() || y === this.getMaxY()) {
|
|
1985
|
+
return;
|
|
1986
|
+
}
|
|
1987
|
+
this.model.setPoint({ x, y }, false);
|
|
1988
|
+
this.model.size.update(({ height, width }) => {
|
|
1989
|
+
width -= offsetX;
|
|
1990
|
+
width = Math.max(width, this.minWidth);
|
|
1991
|
+
width = Math.min(width, this.getMaxWidth());
|
|
1992
|
+
height -= offsetY;
|
|
1993
|
+
height = Math.max(height, this.minHeight);
|
|
1994
|
+
height = Math.min(height, this.getMaxHeight());
|
|
1995
|
+
return { height, width };
|
|
1996
|
+
});
|
|
1997
|
+
return;
|
|
1998
|
+
}
|
|
1999
|
+
case 'top-right': {
|
|
2000
|
+
let y = this.model.point().y + offsetY;
|
|
2001
|
+
y = Math.max(y, this.getMinY());
|
|
2002
|
+
y = Math.min(y, this.getMaxY());
|
|
2003
|
+
if (y === this.getMinX() || y === this.getMaxY()) {
|
|
2004
|
+
return;
|
|
2005
|
+
}
|
|
2006
|
+
this.model.setPoint({ x: this.model.point().x, y }, false);
|
|
2007
|
+
this.model.size.update(({ height, width }) => {
|
|
2008
|
+
const bounds = getNodesBounds(this.model.children());
|
|
2009
|
+
width += offsetX;
|
|
2010
|
+
width = Math.max(width, this.minWidth);
|
|
2011
|
+
width = Math.min(width, this.getMaxWidth());
|
|
2012
|
+
width = Math.max(width, bounds.x + bounds.width);
|
|
2013
|
+
height -= offsetY;
|
|
2014
|
+
height = Math.max(height, this.minHeight);
|
|
2015
|
+
height = Math.min(height, this.getMaxHeight());
|
|
2016
|
+
return { height, width };
|
|
2017
|
+
});
|
|
2018
|
+
return;
|
|
2019
|
+
}
|
|
2020
|
+
case 'bottom-left': {
|
|
2021
|
+
let x = this.model.point().x + offsetX;
|
|
2022
|
+
x = Math.max(x, this.getMinX());
|
|
2023
|
+
x = Math.min(x, this.getMaxX());
|
|
2024
|
+
if (x === this.getMinX() || x === this.getMaxX()) {
|
|
2025
|
+
return;
|
|
2026
|
+
}
|
|
2027
|
+
this.model.setPoint({ x, y: this.model.point().y }, false);
|
|
2028
|
+
this.model.size.update(({ height, width }) => {
|
|
2029
|
+
width -= offsetX;
|
|
2030
|
+
width = Math.max(width, this.minWidth);
|
|
2031
|
+
width = Math.min(width, this.getMaxWidth());
|
|
2032
|
+
height += offsetY;
|
|
2033
|
+
height = Math.max(height, this.minHeight);
|
|
2034
|
+
height = Math.min(height, this.getMaxHeight());
|
|
2035
|
+
const bounds = getNodesBounds(this.model.children());
|
|
2036
|
+
height = Math.max(height, bounds.y + bounds.height);
|
|
2037
|
+
return { height, width };
|
|
2038
|
+
});
|
|
2039
|
+
return;
|
|
2040
|
+
}
|
|
2041
|
+
case 'bottom-right': {
|
|
2042
|
+
this.model.size.update(({ height, width }) => {
|
|
2043
|
+
const bounds = getNodesBounds(this.model.children());
|
|
2044
|
+
width += offsetX;
|
|
2045
|
+
width = Math.max(width, this.minWidth);
|
|
2046
|
+
width = Math.min(width, this.getMaxWidth());
|
|
2047
|
+
width = Math.max(width, bounds.x + bounds.width);
|
|
2048
|
+
height += offsetY;
|
|
2049
|
+
height = Math.max(height, this.minHeight);
|
|
2050
|
+
height = Math.min(height, this.getMaxHeight());
|
|
2051
|
+
height = Math.max(height, bounds.y + bounds.height);
|
|
2052
|
+
return { height, width };
|
|
2053
|
+
});
|
|
2054
|
+
}
|
|
2055
|
+
}
|
|
2056
|
+
}
|
|
2057
|
+
endResize() {
|
|
2058
|
+
this.resizeSide = null;
|
|
2059
|
+
this.model.resizing.set(false);
|
|
2060
|
+
}
|
|
2061
|
+
getMaxWidth() {
|
|
2062
|
+
const parent = this.model.parent();
|
|
2063
|
+
if (parent) {
|
|
2064
|
+
return parent.size().width - this.model.point().x;
|
|
2065
|
+
}
|
|
2066
|
+
return Infinity;
|
|
2067
|
+
}
|
|
2068
|
+
getMaxHeight() {
|
|
2069
|
+
const parent = this.model.parent();
|
|
2070
|
+
if (parent) {
|
|
2071
|
+
return parent.size().height - this.model.point().y;
|
|
2072
|
+
}
|
|
2073
|
+
return Infinity;
|
|
2074
|
+
}
|
|
2075
|
+
getMinX() {
|
|
2076
|
+
const parent = this.model.parent();
|
|
2077
|
+
if (parent) {
|
|
2078
|
+
return 0;
|
|
2079
|
+
}
|
|
2080
|
+
return -Infinity;
|
|
2081
|
+
}
|
|
2082
|
+
getMinY() {
|
|
2083
|
+
const parent = this.model.parent();
|
|
2084
|
+
if (parent) {
|
|
2085
|
+
return 0;
|
|
2086
|
+
}
|
|
2087
|
+
return -Infinity;
|
|
2088
|
+
}
|
|
2089
|
+
getMaxX() {
|
|
2090
|
+
const x = this.model.point().x;
|
|
2091
|
+
const width = this.model.size().width;
|
|
2092
|
+
const children = this.model.children();
|
|
2093
|
+
if (children) {
|
|
2094
|
+
const bounds = getNodesBounds(children);
|
|
2095
|
+
return x + (bounds.x + bounds.width) >= x + width ? x : (width - this.minWidth) + x;
|
|
2096
|
+
}
|
|
2097
|
+
return (width - this.minWidth) + x;
|
|
2098
|
+
}
|
|
2099
|
+
getMaxY() {
|
|
2100
|
+
const y = this.model.point().y;
|
|
2101
|
+
const height = this.model.size().height;
|
|
2102
|
+
const children = this.model.children();
|
|
2103
|
+
if (children) {
|
|
2104
|
+
const bounds = getNodesBounds(children);
|
|
2105
|
+
return y + (bounds.y + bounds.height) >= y + height ? y : (height - this.minHeight) + y;
|
|
2106
|
+
}
|
|
2107
|
+
return (height - this.minHeight) + y;
|
|
2108
|
+
}
|
|
2109
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ResizableComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2110
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: ResizableComponent, selector: "[resizable]", inputs: { resizable: "resizable", resizerColor: "resizerColor", gap: "gap" }, viewQueries: [{ propertyName: "resizer", first: true, predicate: ["resizer"], descendants: true, static: true }], ngImport: i0, template: "<ng-template #resizer>\n <svg:g>\n <!-- top line -->\n <svg:line\n class=\"top\"\n [attr.x1]=\"lineGap\"\n [attr.y1]=\"-gap\"\n [attr.x2]=\"model.size().width - lineGap\"\n [attr.y2]=\"-gap\"\n [attr.stroke]=\"resizerColor\"\n stroke-width=\"2\"\n (pointerStart)=\"startResize('top', $event)\"\n />\n <!-- Left line -->\n <svg:line\n class=\"left\"\n [attr.x1]=\"-gap\"\n [attr.y1]=\"lineGap\"\n [attr.x2]=\"-gap\"\n [attr.y2]=\"model.size().height - lineGap\"\n [attr.stroke]=\"resizerColor\"\n stroke-width=\"2\"\n (pointerStart)=\"startResize('left', $event)\"\n />\n <!-- Bottom line -->\n <svg:line\n class=\"bottom\"\n [attr.x1]=\"lineGap\"\n [attr.y1]=\"model.size().height + gap\"\n [attr.x2]=\"model.size().width - lineGap\"\n [attr.y2]=\"model.size().height + gap\"\n [attr.stroke]=\"resizerColor\"\n stroke-width=\"2\"\n (pointerStart)=\"startResize('bottom', $event)\"\n />\n <!-- Right line -->\n <svg:line\n class=\"right\"\n [attr.x1]=\"model.size().width + gap\"\n [attr.y1]=\"lineGap\"\n [attr.x2]=\"model.size().width + gap\"\n [attr.y2]=\"model.size().height - lineGap\"\n [attr.stroke]=\"resizerColor\"\n stroke-width=\"2\"\n (pointerStart)=\"startResize('right', $event)\"\n />\n\n <!-- Top Left -->\n <svg:rect\n class=\"top-left\"\n [attr.x]=\"-(handleSize / 2) - gap\"\n [attr.y]=\"-(handleSize / 2) - gap\"\n [attr.width]=\"handleSize\"\n [attr.height]=\"handleSize\"\n [attr.fill]=\"resizerColor\"\n (pointerStart)=\"startResize('top-left', $event)\"\n />\n\n <!-- Top right -->\n <svg:rect\n class=\"top-right\"\n [attr.x]=\"model.size().width - (handleSize / 2) + gap\"\n [attr.y]=\"-(handleSize / 2) - gap\"\n [attr.width]=\"handleSize\"\n [attr.height]=\"handleSize\"\n [attr.fill]=\"resizerColor\"\n (pointerStart)=\"startResize('top-right', $event)\"\n />\n\n <!-- Bottom left -->\n <svg:rect\n class=\"bottom-left\"\n [attr.x]=\"-(handleSize / 2) - gap\"\n [attr.y]=\"model.size().height - (handleSize / 2) + gap\"\n [attr.width]=\"handleSize\"\n [attr.height]=\"handleSize\"\n [attr.fill]=\"resizerColor\"\n (pointerStart)=\"startResize('bottom-left', $event)\"\n />\n\n <!-- Bottom right -->\n <svg:rect\n class=\"bottom-right\"\n [attr.x]=\"model.size().width - (handleSize / 2) + gap\"\n [attr.y]=\"model.size().height - (handleSize / 2) + gap\"\n [attr.width]=\"handleSize\"\n [attr.height]=\"handleSize\"\n [attr.fill]=\"resizerColor\"\n (pointerStart)=\"startResize('bottom-right', $event)\"\n />\n </svg:g>\n</ng-template>\n\n<ng-content />\n", styles: [".top{cursor:n-resize}.left{cursor:w-resize}.right{cursor:e-resize}.bottom{cursor:s-resize}.top-left{cursor:nw-resize}.top-right{cursor:ne-resize}.bottom-left{cursor:sw-resize}.bottom-right{cursor:se-resize}\n"], dependencies: [{ kind: "directive", type: PointerDirective, selector: "[pointerStart], [pointerEnd], [pointerOver], [pointerOut]", outputs: ["pointerOver", "pointerOut", "pointerStart", "pointerEnd"] }] }); }
|
|
2111
|
+
}
|
|
2112
|
+
__decorate([
|
|
2113
|
+
Microtask
|
|
2114
|
+
], ResizableComponent.prototype, "ngAfterViewInit", null);
|
|
2115
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ResizableComponent, decorators: [{
|
|
2116
|
+
type: Component,
|
|
2117
|
+
args: [{ selector: '[resizable]', template: "<ng-template #resizer>\n <svg:g>\n <!-- top line -->\n <svg:line\n class=\"top\"\n [attr.x1]=\"lineGap\"\n [attr.y1]=\"-gap\"\n [attr.x2]=\"model.size().width - lineGap\"\n [attr.y2]=\"-gap\"\n [attr.stroke]=\"resizerColor\"\n stroke-width=\"2\"\n (pointerStart)=\"startResize('top', $event)\"\n />\n <!-- Left line -->\n <svg:line\n class=\"left\"\n [attr.x1]=\"-gap\"\n [attr.y1]=\"lineGap\"\n [attr.x2]=\"-gap\"\n [attr.y2]=\"model.size().height - lineGap\"\n [attr.stroke]=\"resizerColor\"\n stroke-width=\"2\"\n (pointerStart)=\"startResize('left', $event)\"\n />\n <!-- Bottom line -->\n <svg:line\n class=\"bottom\"\n [attr.x1]=\"lineGap\"\n [attr.y1]=\"model.size().height + gap\"\n [attr.x2]=\"model.size().width - lineGap\"\n [attr.y2]=\"model.size().height + gap\"\n [attr.stroke]=\"resizerColor\"\n stroke-width=\"2\"\n (pointerStart)=\"startResize('bottom', $event)\"\n />\n <!-- Right line -->\n <svg:line\n class=\"right\"\n [attr.x1]=\"model.size().width + gap\"\n [attr.y1]=\"lineGap\"\n [attr.x2]=\"model.size().width + gap\"\n [attr.y2]=\"model.size().height - lineGap\"\n [attr.stroke]=\"resizerColor\"\n stroke-width=\"2\"\n (pointerStart)=\"startResize('right', $event)\"\n />\n\n <!-- Top Left -->\n <svg:rect\n class=\"top-left\"\n [attr.x]=\"-(handleSize / 2) - gap\"\n [attr.y]=\"-(handleSize / 2) - gap\"\n [attr.width]=\"handleSize\"\n [attr.height]=\"handleSize\"\n [attr.fill]=\"resizerColor\"\n (pointerStart)=\"startResize('top-left', $event)\"\n />\n\n <!-- Top right -->\n <svg:rect\n class=\"top-right\"\n [attr.x]=\"model.size().width - (handleSize / 2) + gap\"\n [attr.y]=\"-(handleSize / 2) - gap\"\n [attr.width]=\"handleSize\"\n [attr.height]=\"handleSize\"\n [attr.fill]=\"resizerColor\"\n (pointerStart)=\"startResize('top-right', $event)\"\n />\n\n <!-- Bottom left -->\n <svg:rect\n class=\"bottom-left\"\n [attr.x]=\"-(handleSize / 2) - gap\"\n [attr.y]=\"model.size().height - (handleSize / 2) + gap\"\n [attr.width]=\"handleSize\"\n [attr.height]=\"handleSize\"\n [attr.fill]=\"resizerColor\"\n (pointerStart)=\"startResize('bottom-left', $event)\"\n />\n\n <!-- Bottom right -->\n <svg:rect\n class=\"bottom-right\"\n [attr.x]=\"model.size().width - (handleSize / 2) + gap\"\n [attr.y]=\"model.size().height - (handleSize / 2) + gap\"\n [attr.width]=\"handleSize\"\n [attr.height]=\"handleSize\"\n [attr.fill]=\"resizerColor\"\n (pointerStart)=\"startResize('bottom-right', $event)\"\n />\n </svg:g>\n</ng-template>\n\n<ng-content />\n", styles: [".top{cursor:n-resize}.left{cursor:w-resize}.right{cursor:e-resize}.bottom{cursor:s-resize}.top-left{cursor:nw-resize}.top-right{cursor:ne-resize}.bottom-left{cursor:sw-resize}.bottom-right{cursor:se-resize}\n"] }]
|
|
2118
|
+
}], propDecorators: { resizable: [{
|
|
2119
|
+
type: Input
|
|
2120
|
+
}], resizerColor: [{
|
|
2121
|
+
type: Input
|
|
2122
|
+
}], gap: [{
|
|
2123
|
+
type: Input
|
|
2124
|
+
}], resizer: [{
|
|
2125
|
+
type: ViewChild,
|
|
2126
|
+
args: ['resizer', { static: true }]
|
|
2127
|
+
}], ngAfterViewInit: [] } });
|
|
2128
|
+
|
|
2129
|
+
class HandleSizeControllerDirective {
|
|
2130
|
+
constructor() {
|
|
2131
|
+
this.handleWrapper = inject(ElementRef);
|
|
2132
|
+
}
|
|
2133
|
+
ngAfterViewInit() {
|
|
2134
|
+
const element = this.handleWrapper.nativeElement;
|
|
2135
|
+
const rect = element.getBBox();
|
|
2136
|
+
const stroke = getChildStrokeWidth(element);
|
|
2137
|
+
this.handleModel.size.set({
|
|
2138
|
+
width: rect.width + stroke,
|
|
2139
|
+
height: rect.height + stroke
|
|
2140
|
+
});
|
|
2141
|
+
}
|
|
2142
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HandleSizeControllerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
2143
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: HandleSizeControllerDirective, selector: "[handleSizeController]", inputs: { handleModel: ["handleSizeController", "handleModel"] }, ngImport: i0 }); }
|
|
2144
|
+
}
|
|
2145
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HandleSizeControllerDirective, decorators: [{
|
|
2146
|
+
type: Directive,
|
|
2147
|
+
args: [{ selector: '[handleSizeController]' }]
|
|
2148
|
+
}], propDecorators: { handleModel: [{
|
|
2149
|
+
type: Input,
|
|
2150
|
+
args: [{ required: true, alias: 'handleSizeController' }]
|
|
2151
|
+
}] } });
|
|
2152
|
+
function getChildStrokeWidth(element) {
|
|
2153
|
+
const child = element.firstElementChild;
|
|
2154
|
+
if (child) {
|
|
2155
|
+
const stroke = getComputedStyle(child).strokeWidth;
|
|
2156
|
+
const strokeAsNumber = Number(stroke.replace('px', ''));
|
|
2157
|
+
if (isNaN(strokeAsNumber)) {
|
|
2158
|
+
return 0;
|
|
2159
|
+
}
|
|
2160
|
+
return strokeAsNumber;
|
|
2161
|
+
}
|
|
2162
|
+
return 0;
|
|
2163
|
+
}
|
|
2164
|
+
|
|
1822
2165
|
class NodeComponent {
|
|
1823
2166
|
constructor() {
|
|
1824
2167
|
this.injector = inject(Injector);
|
|
@@ -1830,12 +2173,15 @@ class NodeComponent {
|
|
|
1830
2173
|
this.selectionService = inject(SelectionService);
|
|
1831
2174
|
this.hostRef = inject(ElementRef);
|
|
1832
2175
|
this.connectionController = inject(ConnectionControllerDirective);
|
|
2176
|
+
this.nodeAccessor = inject(NodeAccessorService);
|
|
2177
|
+
this.zone = inject(NgZone);
|
|
1833
2178
|
this.showMagnet = computed(() => this.flowStatusService.status().state === 'connection-start' ||
|
|
1834
2179
|
this.flowStatusService.status().state === 'connection-validation');
|
|
1835
2180
|
this.styleWidth = computed(() => `${this.nodeModel.size().width}px`);
|
|
1836
2181
|
this.styleHeight = computed(() => `${this.nodeModel.size().height}px`);
|
|
1837
2182
|
}
|
|
1838
2183
|
ngOnInit() {
|
|
2184
|
+
this.nodeAccessor.model.set(this.nodeModel);
|
|
1839
2185
|
this.handleService.node.set(this.nodeModel);
|
|
1840
2186
|
effect(() => {
|
|
1841
2187
|
if (this.nodeModel.draggable()) {
|
|
@@ -1846,7 +2192,8 @@ class NodeComponent {
|
|
|
1846
2192
|
}
|
|
1847
2193
|
});
|
|
1848
2194
|
this.nodeModel.handles$
|
|
1849
|
-
.pipe(switchMap((handles) => resizable(handles.map(h => h.parentReference)
|
|
2195
|
+
.pipe(switchMap((handles) => resizable(handles.map(h => h.parentReference), this.zone)
|
|
2196
|
+
.pipe(map(() => handles))), tap((handles) => {
|
|
1850
2197
|
// TODO (performance) inspect how to avoid calls of this when flow initially rendered
|
|
1851
2198
|
handles.forEach(h => h.updateParent());
|
|
1852
2199
|
}), takeUntilDestroyed())
|
|
@@ -1855,8 +2202,8 @@ class NodeComponent {
|
|
|
1855
2202
|
ngAfterViewInit() {
|
|
1856
2203
|
this.nodeModel.linkDefaultNodeSizeWithModelSize();
|
|
1857
2204
|
if (this.nodeModel.node.type === 'html-template' || this.nodeModel.isComponentType) {
|
|
1858
|
-
resizable([this.htmlWrapperRef.nativeElement])
|
|
1859
|
-
.pipe(startWith(null), tap(() => {
|
|
2205
|
+
resizable([this.htmlWrapperRef.nativeElement], this.zone)
|
|
2206
|
+
.pipe(startWith(null), tap(() => this.nodeModel.handles().forEach(h => h.updateParent())), filter(() => !this.nodeModel.resizing()), tap(() => {
|
|
1860
2207
|
const width = this.htmlWrapperRef.nativeElement.clientWidth;
|
|
1861
2208
|
const height = this.htmlWrapperRef.nativeElement.clientHeight;
|
|
1862
2209
|
this.nodeModel.size.set({ width, height });
|
|
@@ -1889,19 +2236,17 @@ class NodeComponent {
|
|
|
1889
2236
|
}
|
|
1890
2237
|
}
|
|
1891
2238
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NodeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1892
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: NodeComponent, selector: "g[node]", inputs: { nodeModel: "nodeModel", nodeTemplate: "nodeTemplate", groupNodeTemplate: "groupNodeTemplate" }, providers: [HandleService], viewQueries: [{ propertyName: "nodeContentRef", first: true, predicate: ["nodeContent"], descendants: true }, { propertyName: "htmlWrapperRef", first: true, predicate: ["htmlWrapper"], descendants: true }], ngImport: i0, template: "<!-- Default node -->\n<svg:foreignObject\n *ngIf=\"nodeModel.node.type === 'default'\"\n class=\"selectable\"\n #nodeContent\n [attr.width]=\"nodeModel.size().width\"\n [attr.height]=\"nodeModel.size().height\"\n (mousedown)=\"pullNode(); selectNode()\"\n>\n <div\n #htmlWrapper\n class=\"default-node\"\n [class.default-node_selected]=\"nodeModel.selected()\"\n [style.width]=\"styleWidth()\"\n [style.height]=\"styleHeight()\"\n [style.max-width]=\"styleWidth()\"\n [style.max-height]=\"styleHeight()\"\n >\n <div [outerHTML]=\"nodeModel.text()\"></div>\n\n <handle type=\"source\" [position]=\"nodeModel.sourcePosition()\" />\n <handle type=\"target\" [position]=\"nodeModel.targetPosition()\" />\n </div>\n</svg:foreignObject>\n\n<!-- Template node -->\n<svg:foreignObject\n *ngIf=\"nodeModel.node.type === 'html-template' && nodeTemplate\"\n class=\"selectable\"\n [attr.width]=\"nodeModel.size().width\"\n [attr.height]=\"nodeModel.size().height\"\n (mousedown)=\"pullNode()\"\n>\n <div
|
|
2239
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: NodeComponent, selector: "g[node]", inputs: { nodeModel: "nodeModel", nodeTemplate: "nodeTemplate", groupNodeTemplate: "groupNodeTemplate" }, providers: [HandleService, NodeAccessorService], viewQueries: [{ propertyName: "nodeContentRef", first: true, predicate: ["nodeContent"], descendants: true }, { propertyName: "htmlWrapperRef", first: true, predicate: ["htmlWrapper"], descendants: true }], ngImport: i0, template: "<!-- Default node -->\n<svg:foreignObject\n *ngIf=\"nodeModel.node.type === 'default'\"\n class=\"selectable\"\n #nodeContent\n [attr.width]=\"nodeModel.size().width\"\n [attr.height]=\"nodeModel.size().height\"\n (mousedown)=\"pullNode(); selectNode()\"\n>\n <div\n #htmlWrapper\n class=\"default-node\"\n [class.default-node_selected]=\"nodeModel.selected()\"\n [style.width]=\"styleWidth()\"\n [style.height]=\"styleHeight()\"\n [style.max-width]=\"styleWidth()\"\n [style.max-height]=\"styleHeight()\"\n >\n <div [outerHTML]=\"nodeModel.text()\"></div>\n\n <handle type=\"source\" [position]=\"nodeModel.sourcePosition()\" />\n <handle type=\"target\" [position]=\"nodeModel.targetPosition()\" />\n </div>\n</svg:foreignObject>\n\n<!-- Template node -->\n<svg:foreignObject\n *ngIf=\"nodeModel.node.type === 'html-template' && nodeTemplate\"\n class=\"selectable\"\n [attr.width]=\"nodeModel.size().width\"\n [attr.height]=\"nodeModel.size().height\"\n (mousedown)=\"pullNode()\"\n>\n <div\n #htmlWrapper\n class=\"wrapper\"\n [style.width]=\"styleWidth()\"\n [style.height]=\"styleHeight()\"\n >\n <ng-container\n [ngTemplateOutlet]=\"nodeTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: { node: nodeModel.node, selected: nodeModel.selected } }\"\n [ngTemplateOutletInjector]=\"injector\"\n />\n </div>\n</svg:foreignObject>\n\n<!-- Component node -->\n<svg:foreignObject\n *ngIf=\"nodeModel.isComponentType\"\n class=\"selectable\"\n [attr.width]=\"nodeModel.size().width\"\n [attr.height]=\"nodeModel.size().height\"\n (mousedown)=\"pullNode()\"\n>\n <div\n #htmlWrapper\n class=\"wrapper\"\n [style.width]=\"styleWidth()\"\n [style.height]=\"styleHeight()\"\n >\n <ng-container\n [ngComponentOutlet]=\"$any(nodeModel.node.type)\"\n [ngComponentOutletInputs]=\"nodeModel.componentTypeInputs()\"\n [ngComponentOutletInjector]=\"injector\"\n />\n </div>\n</svg:foreignObject>\n\n<!-- Default group node -->\n<svg:rect\n *ngIf=\"nodeModel.node.type === 'default-group'\"\n [resizable]=\"nodeModel.resizable()\"\n [gap]=\"3\"\n [resizerColor]=\"nodeModel.color()\"\n class=\"default-group-node\"\n rx=\"5\"\n ry=\"5\"\n [class.default-group-node_selected]=\"nodeModel.selected()\"\n [attr.width]=\"nodeModel.size().width\"\n [attr.height]=\"nodeModel.size().height\"\n [style.stroke]=\"nodeModel.color()\"\n [style.fill]=\"nodeModel.color()\"\n (mousedown)=\"pullNode(); selectNode()\"\n/>\n\n<!-- Template group node -->\n<svg:g\n *ngIf=\"nodeModel.node.type === 'template-group' && groupNodeTemplate\"\n class=\"selectable\"\n (mousedown)=\"pullNode()\"\n>\n <ng-container\n [ngTemplateOutlet]=\"groupNodeTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: { node: nodeModel.node, selected: nodeModel.selected, width: nodeModel.width, height: nodeModel.height } }\"\n [ngTemplateOutletInjector]=\"injector\"\n />\n</svg:g>\n\n<!-- Resizer -->\n<ng-container *ngIf=\"nodeModel.resizerTemplate() as template\">\n <ng-container *ngIf=\"nodeModel.resizable()\">\n <ng-template [ngTemplateOutlet]=\"template\" />\n </ng-container>\n</ng-container>\n\n<!-- Handles -->\n<ng-container *ngFor=\"let handle of nodeModel.handles()\">\n <svg:circle\n *ngIf=\"!handle.template\"\n class=\"default-handle\"\n [attr.cx]=\"handle.offset().x\"\n [attr.cy]=\"handle.offset().y\"\n [attr.stroke-width]=\"handle.strokeWidth\"\n r=\"5\"\n (pointerStart)=\"startConnection($event, handle)\"\n (pointerEnd)=\"endConnection(handle)\"\n />\n\n <svg:g\n *ngIf=\"handle.template\"\n [handleSizeController]=\"handle\"\n (pointerStart)=\"startConnection($event, handle)\"\n (pointerEnd)=\"endConnection(handle)\"\n >\n <ng-container *ngTemplateOutlet=\"handle.template; context: handle.templateContext\" />\n </svg:g>\n\n <svg:circle\n *ngIf=\"showMagnet()\"\n class=\"magnet\"\n [attr.r]=\"nodeModel.magnetRadius\"\n [attr.cx]=\"handle.offset().x\"\n [attr.cy]=\"handle.offset().y\"\n (pointerEnd)=\"endConnection(handle); resetValidateConnection(handle)\"\n (pointerOver)=\"validateConnection(handle)\"\n (pointerOut)=\"resetValidateConnection(handle)\"\n />\n</ng-container>\n", styles: [".magnet{opacity:0}.wrapper{display:table-cell}.default-node{border:1.5px solid #1b262c;border-radius:5px;display:flex;align-items:center;justify-content:center;color:#000;background-color:#fff}.default-node_selected{border-width:2px}.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: i1.NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: HandleComponent, selector: "handle", inputs: ["position", "type", "id", "template"] }, { kind: "component", type: ResizableComponent, selector: "[resizable]", inputs: ["resizable", "resizerColor", "gap"] }, { kind: "directive", type: HandleSizeControllerDirective, selector: "[handleSizeController]", inputs: ["handleSizeController"] }, { kind: "directive", type: PointerDirective, selector: "[pointerStart], [pointerEnd], [pointerOver], [pointerOut]", outputs: ["pointerOver", "pointerOut", "pointerStart", "pointerEnd"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
1893
2240
|
}
|
|
1894
2241
|
__decorate([
|
|
1895
2242
|
InjectionContext
|
|
1896
2243
|
], NodeComponent.prototype, "ngOnInit", null);
|
|
1897
2244
|
__decorate([
|
|
1898
|
-
Microtask // TODO (performance) check if we need microtask here
|
|
1899
|
-
,
|
|
1900
2245
|
InjectionContext
|
|
1901
2246
|
], NodeComponent.prototype, "ngAfterViewInit", null);
|
|
1902
2247
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NodeComponent, decorators: [{
|
|
1903
2248
|
type: Component,
|
|
1904
|
-
args: [{ selector: 'g[node]', changeDetection: ChangeDetectionStrategy.OnPush, providers: [HandleService], template: "<!-- Default node -->\n<svg:foreignObject\n *ngIf=\"nodeModel.node.type === 'default'\"\n class=\"selectable\"\n #nodeContent\n [attr.width]=\"nodeModel.size().width\"\n [attr.height]=\"nodeModel.size().height\"\n (mousedown)=\"pullNode(); selectNode()\"\n>\n <div\n #htmlWrapper\n class=\"default-node\"\n [class.default-node_selected]=\"nodeModel.selected()\"\n [style.width]=\"styleWidth()\"\n [style.height]=\"styleHeight()\"\n [style.max-width]=\"styleWidth()\"\n [style.max-height]=\"styleHeight()\"\n >\n <div [outerHTML]=\"nodeModel.text()\"></div>\n\n <handle type=\"source\" [position]=\"nodeModel.sourcePosition()\" />\n <handle type=\"target\" [position]=\"nodeModel.targetPosition()\" />\n </div>\n</svg:foreignObject>\n\n<!-- Template node -->\n<svg:foreignObject\n *ngIf=\"nodeModel.node.type === 'html-template' && nodeTemplate\"\n class=\"selectable\"\n [attr.width]=\"nodeModel.size().width\"\n [attr.height]=\"nodeModel.size().height\"\n (mousedown)=\"pullNode()\"\n>\n <div
|
|
2249
|
+
args: [{ selector: 'g[node]', changeDetection: ChangeDetectionStrategy.OnPush, providers: [HandleService, NodeAccessorService], template: "<!-- Default node -->\n<svg:foreignObject\n *ngIf=\"nodeModel.node.type === 'default'\"\n class=\"selectable\"\n #nodeContent\n [attr.width]=\"nodeModel.size().width\"\n [attr.height]=\"nodeModel.size().height\"\n (mousedown)=\"pullNode(); selectNode()\"\n>\n <div\n #htmlWrapper\n class=\"default-node\"\n [class.default-node_selected]=\"nodeModel.selected()\"\n [style.width]=\"styleWidth()\"\n [style.height]=\"styleHeight()\"\n [style.max-width]=\"styleWidth()\"\n [style.max-height]=\"styleHeight()\"\n >\n <div [outerHTML]=\"nodeModel.text()\"></div>\n\n <handle type=\"source\" [position]=\"nodeModel.sourcePosition()\" />\n <handle type=\"target\" [position]=\"nodeModel.targetPosition()\" />\n </div>\n</svg:foreignObject>\n\n<!-- Template node -->\n<svg:foreignObject\n *ngIf=\"nodeModel.node.type === 'html-template' && nodeTemplate\"\n class=\"selectable\"\n [attr.width]=\"nodeModel.size().width\"\n [attr.height]=\"nodeModel.size().height\"\n (mousedown)=\"pullNode()\"\n>\n <div\n #htmlWrapper\n class=\"wrapper\"\n [style.width]=\"styleWidth()\"\n [style.height]=\"styleHeight()\"\n >\n <ng-container\n [ngTemplateOutlet]=\"nodeTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: { node: nodeModel.node, selected: nodeModel.selected } }\"\n [ngTemplateOutletInjector]=\"injector\"\n />\n </div>\n</svg:foreignObject>\n\n<!-- Component node -->\n<svg:foreignObject\n *ngIf=\"nodeModel.isComponentType\"\n class=\"selectable\"\n [attr.width]=\"nodeModel.size().width\"\n [attr.height]=\"nodeModel.size().height\"\n (mousedown)=\"pullNode()\"\n>\n <div\n #htmlWrapper\n class=\"wrapper\"\n [style.width]=\"styleWidth()\"\n [style.height]=\"styleHeight()\"\n >\n <ng-container\n [ngComponentOutlet]=\"$any(nodeModel.node.type)\"\n [ngComponentOutletInputs]=\"nodeModel.componentTypeInputs()\"\n [ngComponentOutletInjector]=\"injector\"\n />\n </div>\n</svg:foreignObject>\n\n<!-- Default group node -->\n<svg:rect\n *ngIf=\"nodeModel.node.type === 'default-group'\"\n [resizable]=\"nodeModel.resizable()\"\n [gap]=\"3\"\n [resizerColor]=\"nodeModel.color()\"\n class=\"default-group-node\"\n rx=\"5\"\n ry=\"5\"\n [class.default-group-node_selected]=\"nodeModel.selected()\"\n [attr.width]=\"nodeModel.size().width\"\n [attr.height]=\"nodeModel.size().height\"\n [style.stroke]=\"nodeModel.color()\"\n [style.fill]=\"nodeModel.color()\"\n (mousedown)=\"pullNode(); selectNode()\"\n/>\n\n<!-- Template group node -->\n<svg:g\n *ngIf=\"nodeModel.node.type === 'template-group' && groupNodeTemplate\"\n class=\"selectable\"\n (mousedown)=\"pullNode()\"\n>\n <ng-container\n [ngTemplateOutlet]=\"groupNodeTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: { node: nodeModel.node, selected: nodeModel.selected, width: nodeModel.width, height: nodeModel.height } }\"\n [ngTemplateOutletInjector]=\"injector\"\n />\n</svg:g>\n\n<!-- Resizer -->\n<ng-container *ngIf=\"nodeModel.resizerTemplate() as template\">\n <ng-container *ngIf=\"nodeModel.resizable()\">\n <ng-template [ngTemplateOutlet]=\"template\" />\n </ng-container>\n</ng-container>\n\n<!-- Handles -->\n<ng-container *ngFor=\"let handle of nodeModel.handles()\">\n <svg:circle\n *ngIf=\"!handle.template\"\n class=\"default-handle\"\n [attr.cx]=\"handle.offset().x\"\n [attr.cy]=\"handle.offset().y\"\n [attr.stroke-width]=\"handle.strokeWidth\"\n r=\"5\"\n (pointerStart)=\"startConnection($event, handle)\"\n (pointerEnd)=\"endConnection(handle)\"\n />\n\n <svg:g\n *ngIf=\"handle.template\"\n [handleSizeController]=\"handle\"\n (pointerStart)=\"startConnection($event, handle)\"\n (pointerEnd)=\"endConnection(handle)\"\n >\n <ng-container *ngTemplateOutlet=\"handle.template; context: handle.templateContext\" />\n </svg:g>\n\n <svg:circle\n *ngIf=\"showMagnet()\"\n class=\"magnet\"\n [attr.r]=\"nodeModel.magnetRadius\"\n [attr.cx]=\"handle.offset().x\"\n [attr.cy]=\"handle.offset().y\"\n (pointerEnd)=\"endConnection(handle); resetValidateConnection(handle)\"\n (pointerOver)=\"validateConnection(handle)\"\n (pointerOut)=\"resetValidateConnection(handle)\"\n />\n</ng-container>\n", styles: [".magnet{opacity:0}.wrapper{display:table-cell}.default-node{border:1.5px solid #1b262c;border-radius:5px;display:flex;align-items:center;justify-content:center;color:#000;background-color:#fff}.default-node_selected{border-width:2px}.default-group-node{stroke-width:1.5px;fill-opacity:.05}.default-group-node_selected{stroke-width:2px}.default-handle{stroke:#fff;fill:#1b262c}\n"] }]
|
|
1905
2250
|
}], propDecorators: { nodeModel: [{
|
|
1906
2251
|
type: Input
|
|
1907
2252
|
}], nodeTemplate: [{
|
|
@@ -2242,31 +2587,32 @@ class FlowSizeControllerDirective {
|
|
|
2242
2587
|
constructor() {
|
|
2243
2588
|
this.host = inject(ElementRef);
|
|
2244
2589
|
this.flowSettingsService = inject(FlowSettingsService);
|
|
2245
|
-
this.flowWidth =
|
|
2246
|
-
this.flowHeight = 0;
|
|
2247
|
-
effect(() => {
|
|
2590
|
+
this.flowWidth = computed(() => {
|
|
2248
2591
|
const view = this.flowSettingsService.view();
|
|
2249
|
-
|
|
2250
|
-
this.flowHeight = view === 'auto' ? '100%' : view[1];
|
|
2592
|
+
return view === 'auto' ? '100%' : view[0];
|
|
2251
2593
|
});
|
|
2252
|
-
|
|
2594
|
+
this.flowHeight = computed(() => {
|
|
2595
|
+
const view = this.flowSettingsService.view();
|
|
2596
|
+
return view === 'auto' ? '100%' : view[1];
|
|
2597
|
+
});
|
|
2598
|
+
resizable([this.host.nativeElement], inject(NgZone)).pipe(tap(([entry]) => {
|
|
2253
2599
|
this.flowSettingsService.computedFlowWidth.set(entry.contentRect.width);
|
|
2254
2600
|
this.flowSettingsService.computedFlowHeight.set(entry.contentRect.height);
|
|
2255
2601
|
}), takeUntilDestroyed()).subscribe();
|
|
2256
2602
|
}
|
|
2257
2603
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FlowSizeControllerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
2258
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: FlowSizeControllerDirective, selector: "svg[flowSizeController]", host: { properties: { "attr.width": "
|
|
2604
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: FlowSizeControllerDirective, selector: "svg[flowSizeController]", host: { properties: { "attr.width": "flowWidth()", "attr.height": "flowHeight()" } }, ngImport: i0 }); }
|
|
2259
2605
|
}
|
|
2260
2606
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FlowSizeControllerDirective, decorators: [{
|
|
2261
2607
|
type: Directive,
|
|
2262
|
-
args: [{
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2608
|
+
args: [{
|
|
2609
|
+
selector: 'svg[flowSizeController]',
|
|
2610
|
+
host: {
|
|
2611
|
+
'[attr.width]': 'flowWidth()',
|
|
2612
|
+
'[attr.height]': 'flowHeight()'
|
|
2613
|
+
}
|
|
2614
|
+
}]
|
|
2615
|
+
}], ctorParameters: function () { return []; } });
|
|
2270
2616
|
|
|
2271
2617
|
const connectionControllerHostDirective = {
|
|
2272
2618
|
directive: ConnectionControllerDirective,
|
|
@@ -2279,6 +2625,9 @@ const changesControllerHostDirective = {
|
|
|
2279
2625
|
'onNodesChange.position',
|
|
2280
2626
|
'onNodesChange.position.single',
|
|
2281
2627
|
'onNodesChange.position.many',
|
|
2628
|
+
'onNodesChange.size',
|
|
2629
|
+
'onNodesChange.size.single',
|
|
2630
|
+
'onNodesChange.size.many',
|
|
2282
2631
|
'onNodesChange.add',
|
|
2283
2632
|
'onNodesChange.add.single',
|
|
2284
2633
|
'onNodesChange.add.many',
|
|
@@ -2513,7 +2862,7 @@ class VflowComponent {
|
|
|
2513
2862
|
SelectionService,
|
|
2514
2863
|
FlowSettingsService,
|
|
2515
2864
|
ComponentEventBusService
|
|
2516
|
-
], queries: [{ propertyName: "nodeTemplateDirective", first: true, predicate: NodeHtmlTemplateDirective, descendants: true }, { propertyName: "groupNodeTemplateDirective", first: true, predicate: GroupNodeTemplateDirective, descendants: true }, { propertyName: "edgeTemplateDirective", first: true, predicate: EdgeTemplateDirective, descendants: true }, { propertyName: "edgeLabelHtmlDirective", first: true, predicate: EdgeLabelHtmlTemplateDirective, descendants: true }, { propertyName: "connectionTemplateDirective", first: true, predicate: ConnectionTemplateDirective, descendants: true }], viewQueries: [{ propertyName: "mapContext", first: true, predicate: MapContextDirective, descendants: true }, { propertyName: "spacePointContext", first: true, predicate: SpacePointContextDirective, descendants: true }], hostDirectives: [{ directive: ConnectionControllerDirective, outputs: ["onConnect", "onConnect"] }, { directive: ChangesControllerDirective, outputs: ["onNodesChange", "onNodesChange", "onNodesChange.position", "onNodesChange.position", "onNodesChange.position.single", "onNodesChange.position.single", "onNodesChange.position.many", "onNodesChange.position.many", "onNodesChange.add", "onNodesChange.add", "onNodesChange.add.single", "onNodesChange.add.single", "onNodesChange.add.many", "onNodesChange.add.many", "onNodesChange.remove", "onNodesChange.remove", "onNodesChange.remove.single", "onNodesChange.remove.single", "onNodesChange.remove.many", "onNodesChange.remove.many", "onNodesChange.select", "onNodesChange.select", "onNodesChange.select.single", "onNodesChange.select.single", "onNodesChange.select.many", "onNodesChange.select.many", "onEdgesChange", "onEdgesChange", "onEdgesChange.detached", "onEdgesChange.detached", "onEdgesChange.detached.single", "onEdgesChange.detached.single", "onEdgesChange.detached.many", "onEdgesChange.detached.many", "onEdgesChange.add", "onEdgesChange.add", "onEdgesChange.add.single", "onEdgesChange.add.single", "onEdgesChange.add.many", "onEdgesChange.add.many", "onEdgesChange.remove", "onEdgesChange.remove", "onEdgesChange.remove.single", "onEdgesChange.remove.single", "onEdgesChange.remove.many", "onEdgesChange.remove.many", "onEdgesChange.select", "onEdgesChange.select", "onEdgesChange.select.single", "onEdgesChange.select.single", "onEdgesChange.select.many", "onEdgesChange.select.many"] }], ngImport: i0, template: "<svg:svg\n rootSvgRef\n rootSvgContext\n rootPointer\n flowSizeController\n class=\"root-svg\"\n #flow\n>\n <defs [markers]=\"markers()\" flowDefs />\n\n <g [background]=\"background\"/>\n\n <svg:g\n mapContext\n spacePointContext\n >\n <!-- Connection -->\n <svg:g\n connection\n [model]=\"connection\"\n [template]=\"connectionTemplateDirective?.templateRef\"\n />\n\n <!-- Edges -->\n <svg:g\n *ngFor=\"let model of edgeModels(); trackBy: trackEdges\"\n edge\n [model]=\"model\"\n [edgeTemplate]=\"edgeTemplateDirective?.templateRef\"\n [edgeLabelHtmlTemplate]=\"edgeLabelHtmlDirective?.templateRef\"\n />\n\n <!-- Nodes -->\n <svg:g\n *ngFor=\"let model of nodeModels(); trackBy: trackNodes\"\n node\n [nodeModel]=\"model\"\n [nodeTemplate]=\"nodeTemplateDirective?.templateRef\"\n [groupNodeTemplate]=\"groupNodeTemplateDirective?.templateRef\"\n [attr.transform]=\"model.pointTransform()\"\n />\n </svg:g>\n\n</svg:svg>\n", styles: [":host{display:block;width:100%;height:100%;-webkit-user-select:none;user-select:none}:host ::ng-deep *{box-sizing:border-box}\n"], dependencies: [{ kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: NodeComponent, selector: "g[node]", inputs: ["nodeModel", "nodeTemplate", "groupNodeTemplate"] }, { kind: "component", type: EdgeComponent, selector: "g[edge]", inputs: ["model", "edgeTemplate", "edgeLabelHtmlTemplate"] }, { kind: "component", type: ConnectionComponent, selector: "g[connection]", inputs: ["model", "template"] }, { kind: "component", type: DefsComponent, selector: "defs[flowDefs]", inputs: ["markers"] }, { kind: "component", type: BackgroundComponent, selector: "g[background]", inputs: ["background"] }, { kind: "directive", type: SpacePointContextDirective, selector: "g[spacePointContext]" }, { kind: "directive", type: MapContextDirective, selector: "g[mapContext]" }, { kind: "directive", type: RootSvgReferenceDirective, selector: "svg[rootSvgRef]" }, { kind: "directive", type: RootSvgContextDirective, selector: "svg[rootSvgContext]" }, { kind: "directive", type: RootPointerDirective, selector: "svg[rootPointer]" }, { kind: "directive", type: FlowSizeControllerDirective, selector: "svg[flowSizeController]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
2865
|
+
], queries: [{ propertyName: "nodeTemplateDirective", first: true, predicate: NodeHtmlTemplateDirective, descendants: true }, { propertyName: "groupNodeTemplateDirective", first: true, predicate: GroupNodeTemplateDirective, descendants: true }, { propertyName: "edgeTemplateDirective", first: true, predicate: EdgeTemplateDirective, descendants: true }, { propertyName: "edgeLabelHtmlDirective", first: true, predicate: EdgeLabelHtmlTemplateDirective, descendants: true }, { propertyName: "connectionTemplateDirective", first: true, predicate: ConnectionTemplateDirective, descendants: true }], viewQueries: [{ propertyName: "mapContext", first: true, predicate: MapContextDirective, descendants: true }, { propertyName: "spacePointContext", first: true, predicate: SpacePointContextDirective, descendants: true }], hostDirectives: [{ directive: ConnectionControllerDirective, outputs: ["onConnect", "onConnect"] }, { directive: ChangesControllerDirective, outputs: ["onNodesChange", "onNodesChange", "onNodesChange.position", "onNodesChange.position", "onNodesChange.position.single", "onNodesChange.position.single", "onNodesChange.position.many", "onNodesChange.position.many", "onNodesChange.size", "onNodesChange.size", "onNodesChange.size.single", "onNodesChange.size.single", "onNodesChange.size.many", "onNodesChange.size.many", "onNodesChange.add", "onNodesChange.add", "onNodesChange.add.single", "onNodesChange.add.single", "onNodesChange.add.many", "onNodesChange.add.many", "onNodesChange.remove", "onNodesChange.remove", "onNodesChange.remove.single", "onNodesChange.remove.single", "onNodesChange.remove.many", "onNodesChange.remove.many", "onNodesChange.select", "onNodesChange.select", "onNodesChange.select.single", "onNodesChange.select.single", "onNodesChange.select.many", "onNodesChange.select.many", "onEdgesChange", "onEdgesChange", "onEdgesChange.detached", "onEdgesChange.detached", "onEdgesChange.detached.single", "onEdgesChange.detached.single", "onEdgesChange.detached.many", "onEdgesChange.detached.many", "onEdgesChange.add", "onEdgesChange.add", "onEdgesChange.add.single", "onEdgesChange.add.single", "onEdgesChange.add.many", "onEdgesChange.add.many", "onEdgesChange.remove", "onEdgesChange.remove", "onEdgesChange.remove.single", "onEdgesChange.remove.single", "onEdgesChange.remove.many", "onEdgesChange.remove.many", "onEdgesChange.select", "onEdgesChange.select", "onEdgesChange.select.single", "onEdgesChange.select.single", "onEdgesChange.select.many", "onEdgesChange.select.many"] }], ngImport: i0, template: "<svg:svg\n rootSvgRef\n rootSvgContext\n rootPointer\n flowSizeController\n class=\"root-svg\"\n #flow\n>\n <defs [markers]=\"markers()\" flowDefs />\n\n <g [background]=\"background\"/>\n\n <svg:g\n mapContext\n spacePointContext\n >\n <!-- Connection -->\n <svg:g\n connection\n [model]=\"connection\"\n [template]=\"connectionTemplateDirective?.templateRef\"\n />\n\n <!-- Edges -->\n <svg:g\n *ngFor=\"let model of edgeModels(); trackBy: trackEdges\"\n edge\n [model]=\"model\"\n [edgeTemplate]=\"edgeTemplateDirective?.templateRef\"\n [edgeLabelHtmlTemplate]=\"edgeLabelHtmlDirective?.templateRef\"\n />\n\n <!-- Nodes -->\n <svg:g\n *ngFor=\"let model of nodeModels(); trackBy: trackNodes\"\n node\n [nodeModel]=\"model\"\n [nodeTemplate]=\"nodeTemplateDirective?.templateRef\"\n [groupNodeTemplate]=\"groupNodeTemplateDirective?.templateRef\"\n [attr.transform]=\"model.pointTransform()\"\n />\n </svg:g>\n\n</svg:svg>\n", styles: [":host{display:block;width:100%;height:100%;-webkit-user-select:none;user-select:none}:host ::ng-deep *{box-sizing:border-box}\n"], dependencies: [{ kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: NodeComponent, selector: "g[node]", inputs: ["nodeModel", "nodeTemplate", "groupNodeTemplate"] }, { kind: "component", type: EdgeComponent, selector: "g[edge]", inputs: ["model", "edgeTemplate", "edgeLabelHtmlTemplate"] }, { kind: "component", type: ConnectionComponent, selector: "g[connection]", inputs: ["model", "template"] }, { kind: "component", type: DefsComponent, selector: "defs[flowDefs]", inputs: ["markers"] }, { kind: "component", type: BackgroundComponent, selector: "g[background]", inputs: ["background"] }, { kind: "directive", type: SpacePointContextDirective, selector: "g[spacePointContext]" }, { kind: "directive", type: MapContextDirective, selector: "g[mapContext]" }, { kind: "directive", type: RootSvgReferenceDirective, selector: "svg[rootSvgRef]" }, { kind: "directive", type: RootSvgContextDirective, selector: "svg[rootSvgContext]" }, { kind: "directive", type: RootPointerDirective, selector: "svg[rootPointer]" }, { kind: "directive", type: FlowSizeControllerDirective, selector: "svg[flowSizeController]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
2517
2866
|
}
|
|
2518
2867
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: VflowComponent, decorators: [{
|
|
2519
2868
|
type: Component,
|
|
@@ -2620,7 +2969,8 @@ const components = [
|
|
|
2620
2969
|
ConnectionComponent,
|
|
2621
2970
|
HandleComponent,
|
|
2622
2971
|
DefsComponent,
|
|
2623
|
-
BackgroundComponent
|
|
2972
|
+
BackgroundComponent,
|
|
2973
|
+
ResizableComponent,
|
|
2624
2974
|
];
|
|
2625
2975
|
const directives = [
|
|
2626
2976
|
SpacePointContextDirective,
|
|
@@ -2631,7 +2981,7 @@ const directives = [
|
|
|
2631
2981
|
SelectableDirective,
|
|
2632
2982
|
PointerDirective,
|
|
2633
2983
|
RootPointerDirective,
|
|
2634
|
-
FlowSizeControllerDirective
|
|
2984
|
+
FlowSizeControllerDirective,
|
|
2635
2985
|
];
|
|
2636
2986
|
const templateDirectives = [
|
|
2637
2987
|
NodeHtmlTemplateDirective,
|
|
@@ -2650,7 +3000,8 @@ class VflowModule {
|
|
|
2650
3000
|
ConnectionComponent,
|
|
2651
3001
|
HandleComponent,
|
|
2652
3002
|
DefsComponent,
|
|
2653
|
-
BackgroundComponent,
|
|
3003
|
+
BackgroundComponent,
|
|
3004
|
+
ResizableComponent, SpacePointContextDirective,
|
|
2654
3005
|
MapContextDirective,
|
|
2655
3006
|
RootSvgReferenceDirective,
|
|
2656
3007
|
RootSvgContextDirective,
|
|
@@ -2665,6 +3016,7 @@ class VflowModule {
|
|
|
2665
3016
|
ConnectionTemplateDirective,
|
|
2666
3017
|
HandleTemplateDirective], imports: [CommonModule], exports: [VflowComponent,
|
|
2667
3018
|
HandleComponent,
|
|
3019
|
+
ResizableComponent,
|
|
2668
3020
|
SelectableDirective, NodeHtmlTemplateDirective,
|
|
2669
3021
|
GroupNodeTemplateDirective,
|
|
2670
3022
|
EdgeLabelHtmlTemplateDirective,
|
|
@@ -2680,6 +3032,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
|
|
|
2680
3032
|
exports: [
|
|
2681
3033
|
VflowComponent,
|
|
2682
3034
|
HandleComponent,
|
|
3035
|
+
ResizableComponent,
|
|
2683
3036
|
SelectableDirective,
|
|
2684
3037
|
...templateDirectives
|
|
2685
3038
|
],
|
|
@@ -2693,5 +3046,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
|
|
|
2693
3046
|
* Generated bundle index. Do not edit.
|
|
2694
3047
|
*/
|
|
2695
3048
|
|
|
2696
|
-
export { ChangesControllerDirective, ConnectionControllerDirective, ConnectionTemplateDirective, CustomDynamicNodeComponent, CustomNodeComponent, EdgeLabelHtmlTemplateDirective, EdgeTemplateDirective, GroupNodeTemplateDirective, HandleComponent, HandleTemplateDirective, NodeHtmlTemplateDirective, SelectableDirective, VflowComponent, VflowModule, isComponentDynamicNode, isComponentStaticNode, isDefaultDynamicGroupNode, isDefaultDynamicNode, isDefaultStaticGroupNode, isDefaultStaticNode, isDynamicNode, isStaticNode, isTemplateDynamicGroupNode, isTemplateDynamicNode, isTemplateStaticGroupNode, isTemplateStaticNode };
|
|
3049
|
+
export { ChangesControllerDirective, ConnectionControllerDirective, ConnectionTemplateDirective, CustomDynamicNodeComponent, CustomNodeComponent, EdgeLabelHtmlTemplateDirective, EdgeTemplateDirective, GroupNodeTemplateDirective, HandleComponent, HandleTemplateDirective, NodeHtmlTemplateDirective, ResizableComponent, SelectableDirective, VflowComponent, VflowModule, isComponentDynamicNode, isComponentStaticNode, isDefaultDynamicGroupNode, isDefaultDynamicNode, isDefaultStaticGroupNode, isDefaultStaticNode, isDynamicNode, isStaticNode, isTemplateDynamicGroupNode, isTemplateDynamicNode, isTemplateStaticGroupNode, isTemplateStaticNode };
|
|
2697
3050
|
//# sourceMappingURL=ngx-vflow.mjs.map
|