ngx-vflow 2.0.0 → 2.2.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/fesm2022/ngx-vflow.mjs +271 -56
- package/fesm2022/ngx-vflow.mjs.map +1 -1
- package/lib/vflow/components/background/background.component.d.ts +2 -1
- package/lib/vflow/directives/node-handles-controller.directive.d.ts +2 -1
- package/lib/vflow/directives/node-resize-controller.directive.d.ts +4 -4
- package/lib/vflow/interfaces/node.interface.d.ts +2 -0
- package/lib/vflow/models/handle.model.d.ts +4 -1
- package/lib/vflow/models/node.model.d.ts +1 -0
- package/lib/vflow/public-components/handle/handle.component.d.ts +2 -0
- package/lib/vflow/services/offset-batching-cache.service.d.ts +20 -0
- package/lib/vflow/services/request-animation-frame-batching.service.d.ts +8 -0
- package/lib/vflow/services/resize-observer.service.d.ts +13 -0
- package/lib/vflow/types/background.type.d.ts +20 -1
- package/package.json +1 -1
package/fesm2022/ngx-vflow.mjs
CHANGED
|
@@ -759,7 +759,7 @@ class DraggableService {
|
|
|
759
759
|
moveNode(model, point) {
|
|
760
760
|
const parent = model.parent();
|
|
761
761
|
// keep node in bounds of parent
|
|
762
|
-
if (parent) {
|
|
762
|
+
if (model.extent() === 'parent' && parent) {
|
|
763
763
|
point.x = Math.min(parent.width() - model.width(), point.x);
|
|
764
764
|
point.x = Math.max(0, point.x);
|
|
765
765
|
point.y = Math.min(parent.height() - model.height(), point.y);
|
|
@@ -1059,6 +1059,7 @@ const NODE_DEFAULTS = {
|
|
|
1059
1059
|
height: 50,
|
|
1060
1060
|
draggable: true,
|
|
1061
1061
|
parentId: null,
|
|
1062
|
+
extent: 'parent',
|
|
1062
1063
|
preview: { style: {} },
|
|
1063
1064
|
selected: false,
|
|
1064
1065
|
color: '#1b262c',
|
|
@@ -1093,10 +1094,11 @@ function createBaseNode(node, useDefaults) {
|
|
|
1093
1094
|
return {
|
|
1094
1095
|
id: node.id,
|
|
1095
1096
|
point: signal(node.point),
|
|
1096
|
-
draggable: signal(node.draggable
|
|
1097
|
-
parentId: signal(node.parentId
|
|
1098
|
-
|
|
1099
|
-
|
|
1097
|
+
draggable: signal(isDefined(node.draggable) ? node.draggable : NODE_DEFAULTS.draggable),
|
|
1098
|
+
parentId: signal(isDefined(node.parentId) ? node.parentId : NODE_DEFAULTS.parentId),
|
|
1099
|
+
extent: signal(isDefined(node.extent) ? node.extent : NODE_DEFAULTS.extent),
|
|
1100
|
+
preview: signal(isDefined(node.preview) ? node.preview : NODE_DEFAULTS.preview),
|
|
1101
|
+
selected: signal(isDefined(node.selected) ? node.selected : NODE_DEFAULTS.selected),
|
|
1100
1102
|
};
|
|
1101
1103
|
}
|
|
1102
1104
|
else {
|
|
@@ -1105,6 +1107,7 @@ function createBaseNode(node, useDefaults) {
|
|
|
1105
1107
|
point: signal(node.point),
|
|
1106
1108
|
draggable: isDefined(node.draggable) ? signal(node.draggable) : undefined,
|
|
1107
1109
|
parentId: isDefined(node.parentId) ? signal(node.parentId) : undefined,
|
|
1110
|
+
extent: isDefined(node.extent) ? signal(node.extent) : undefined,
|
|
1108
1111
|
preview: isDefined(node.preview) ? signal(node.preview) : undefined,
|
|
1109
1112
|
selected: isDefined(node.selected) ? signal(node.selected) : undefined,
|
|
1110
1113
|
};
|
|
@@ -1413,6 +1416,7 @@ class NodeModel {
|
|
|
1413
1416
|
this.renderOrder = signal(0);
|
|
1414
1417
|
this.selected = signal(false);
|
|
1415
1418
|
this.preview = signal({ style: {} });
|
|
1419
|
+
this.extent = signal(NODE_DEFAULTS.extent);
|
|
1416
1420
|
this.globalPoint = computed(() => {
|
|
1417
1421
|
let parent = this.parent();
|
|
1418
1422
|
let x = this.point().x;
|
|
@@ -1499,6 +1503,9 @@ class NodeModel {
|
|
|
1499
1503
|
if (rawNode.selected) {
|
|
1500
1504
|
this.selected = rawNode.selected;
|
|
1501
1505
|
}
|
|
1506
|
+
if (rawNode.extent) {
|
|
1507
|
+
this.extent = rawNode.extent;
|
|
1508
|
+
}
|
|
1502
1509
|
if (rawNode.type === 'default-group' && rawNode.color) {
|
|
1503
1510
|
this.color = rawNode.color;
|
|
1504
1511
|
}
|
|
@@ -1569,18 +1576,18 @@ function createEdge(edge, options = { useDefaults: true }) {
|
|
|
1569
1576
|
if (options.useDefaults) {
|
|
1570
1577
|
return {
|
|
1571
1578
|
id: edge.id,
|
|
1572
|
-
type: edge.type ?? EDGE_DEFAULTS.type,
|
|
1573
1579
|
source: edge.source,
|
|
1574
1580
|
target: edge.target,
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1581
|
+
type: isDefined(edge.type) ? edge.type : EDGE_DEFAULTS.type,
|
|
1582
|
+
sourceHandle: isDefined(edge.sourceHandle) ? edge.sourceHandle : '',
|
|
1583
|
+
targetHandle: isDefined(edge.targetHandle) ? edge.targetHandle : '',
|
|
1584
|
+
curve: signal(isDefined(edge.curve) ? edge.curve : EDGE_DEFAULTS.curve),
|
|
1585
|
+
data: signal(isDefined(edge.data) ? edge.data : EDGE_DEFAULTS.data),
|
|
1586
|
+
edgeLabels: signal(isDefined(edge.edgeLabels) ? edge.edgeLabels : EDGE_DEFAULTS.edgeLabels),
|
|
1587
|
+
markers: signal(isDefined(edge.markers) ? edge.markers : EDGE_DEFAULTS.markers),
|
|
1588
|
+
reconnectable: signal(isDefined(edge.reconnectable) ? edge.reconnectable : EDGE_DEFAULTS.reconnectable),
|
|
1589
|
+
floating: signal(isDefined(edge.floating) ? edge.floating : EDGE_DEFAULTS.floating),
|
|
1590
|
+
selected: signal(isDefined(edge.selected) ? edge.selected : EDGE_DEFAULTS.selected),
|
|
1584
1591
|
};
|
|
1585
1592
|
}
|
|
1586
1593
|
else {
|
|
@@ -3307,9 +3314,10 @@ function constrainRect(rect, model, side, minWidth, minHeight, maxWidth, maxHeig
|
|
|
3307
3314
|
}
|
|
3308
3315
|
|
|
3309
3316
|
class HandleModel {
|
|
3310
|
-
constructor(rawHandle, parentNode) {
|
|
3317
|
+
constructor(rawHandle, parentNode, batchingService) {
|
|
3311
3318
|
this.rawHandle = rawHandle;
|
|
3312
3319
|
this.parentNode = parentNode;
|
|
3320
|
+
this.batchingService = batchingService;
|
|
3313
3321
|
this.strokeWidth = 2;
|
|
3314
3322
|
/**
|
|
3315
3323
|
* Pre-computed size for default handle, changed dynamically
|
|
@@ -3332,10 +3340,15 @@ class HandleModel {
|
|
|
3332
3340
|
initialValue: { width: 0, height: 0 },
|
|
3333
3341
|
});
|
|
3334
3342
|
// TODO: for some reason toLazySignal breaks unit tests, so we use toSignal here
|
|
3335
|
-
this.hostPosition = toSignal(this.updateHostSizeAndPosition$.pipe(map(() =>
|
|
3336
|
-
|
|
3337
|
-
|
|
3338
|
-
|
|
3343
|
+
this.hostPosition = toSignal(this.updateHostSizeAndPosition$.pipe(map(() => {
|
|
3344
|
+
const offsets = this.hostReference instanceof HTMLElement
|
|
3345
|
+
? this.batchingService.getElementOffsets(this.hostReference)
|
|
3346
|
+
: undefined;
|
|
3347
|
+
return {
|
|
3348
|
+
x: offsets ? offsets.offsetLeft : 0, // for now just 0 for group nodes
|
|
3349
|
+
y: offsets ? offsets.offsetTop : 0, // for now just 0 for group nodes
|
|
3350
|
+
};
|
|
3351
|
+
})), {
|
|
3339
3352
|
initialValue: { x: 0, y: 0 },
|
|
3340
3353
|
});
|
|
3341
3354
|
this.hostOffset = computed(() => {
|
|
@@ -3383,16 +3396,29 @@ class HandleModel {
|
|
|
3383
3396
|
node: this.parentNode.rawNode,
|
|
3384
3397
|
},
|
|
3385
3398
|
};
|
|
3399
|
+
if (this.hostReference instanceof HTMLElement) {
|
|
3400
|
+
this.batchingService.addElementCache(this.hostReference);
|
|
3401
|
+
}
|
|
3402
|
+
}
|
|
3403
|
+
onDestroy() {
|
|
3404
|
+
if (this.hostReference instanceof HTMLElement) {
|
|
3405
|
+
this.batchingService.removeElementCache(this.hostReference);
|
|
3406
|
+
}
|
|
3386
3407
|
}
|
|
3387
3408
|
updateHost() {
|
|
3409
|
+
this.batchingService.markCacheAsDirty();
|
|
3388
3410
|
this.updateHostSizeAndPosition$.next();
|
|
3389
3411
|
}
|
|
3390
3412
|
getHostSize() {
|
|
3413
|
+
//TODO only get the hist ref width once ?
|
|
3391
3414
|
if (this.hostReference instanceof HTMLElement) {
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3415
|
+
const offsets = this.batchingService.getElementOffsets(this.hostReference);
|
|
3416
|
+
if (offsets) {
|
|
3417
|
+
return {
|
|
3418
|
+
width: offsets.offsetWidth,
|
|
3419
|
+
height: offsets.offsetHeight,
|
|
3420
|
+
};
|
|
3421
|
+
}
|
|
3396
3422
|
}
|
|
3397
3423
|
else if (this.hostReference instanceof SVGGraphicsElement) {
|
|
3398
3424
|
return this.hostReference.getBBox();
|
|
@@ -3401,12 +3427,102 @@ class HandleModel {
|
|
|
3401
3427
|
}
|
|
3402
3428
|
}
|
|
3403
3429
|
|
|
3430
|
+
class OffsetBatchingCacheService {
|
|
3431
|
+
constructor() {
|
|
3432
|
+
this.elementOffsetCache = new Map();
|
|
3433
|
+
this.cacheIsDirty = true;
|
|
3434
|
+
this.minMsBetweenDirty = 16; //1000 ms/second to get 60fps = ~16ms
|
|
3435
|
+
this.lastDirty = undefined;
|
|
3436
|
+
}
|
|
3437
|
+
addElementCache(element) {
|
|
3438
|
+
this.elementOffsetCache.set(element, undefined);
|
|
3439
|
+
this.markCacheAsDirty();
|
|
3440
|
+
}
|
|
3441
|
+
removeElementCache(element) {
|
|
3442
|
+
this.elementOffsetCache.delete(element);
|
|
3443
|
+
}
|
|
3444
|
+
getElementOffsets(requestedElement) {
|
|
3445
|
+
let requestedCache = undefined;
|
|
3446
|
+
const cachedOffset = this.elementOffsetCache.get(requestedElement);
|
|
3447
|
+
if (cachedOffset === undefined) {
|
|
3448
|
+
this.addElementCache(requestedElement);
|
|
3449
|
+
}
|
|
3450
|
+
else {
|
|
3451
|
+
requestedCache = cachedOffset;
|
|
3452
|
+
}
|
|
3453
|
+
//When something request to get the offset of a given element, compute the cache of all the elements of interest until we get the next dirty request.
|
|
3454
|
+
if (this.cacheIsDirty) {
|
|
3455
|
+
for (const { [0]: element } of this.elementOffsetCache) {
|
|
3456
|
+
const offsetWidth = element.offsetWidth;
|
|
3457
|
+
const offsetHeight = element.offsetHeight;
|
|
3458
|
+
const offsetLeft = element.offsetLeft;
|
|
3459
|
+
const offsetTop = element.offsetTop;
|
|
3460
|
+
const cacheEntry = { offsetWidth, offsetHeight, offsetLeft, offsetTop };
|
|
3461
|
+
this.elementOffsetCache.set(element, cacheEntry);
|
|
3462
|
+
if (element === requestedElement) {
|
|
3463
|
+
requestedCache = cacheEntry;
|
|
3464
|
+
}
|
|
3465
|
+
}
|
|
3466
|
+
this.cacheIsDirty = false;
|
|
3467
|
+
}
|
|
3468
|
+
return requestedCache;
|
|
3469
|
+
}
|
|
3470
|
+
markCacheAsDirty() {
|
|
3471
|
+
const now = new Date();
|
|
3472
|
+
if (this.lastDirty === undefined) {
|
|
3473
|
+
this.cacheIsDirty = true;
|
|
3474
|
+
this.lastDirty = now;
|
|
3475
|
+
return;
|
|
3476
|
+
}
|
|
3477
|
+
//force the cache ttl to at minimum 16ms before considering it dirty
|
|
3478
|
+
const msSinceLastDirty = now.getTime() - this.lastDirty?.getTime();
|
|
3479
|
+
if (msSinceLastDirty > this.minMsBetweenDirty) {
|
|
3480
|
+
this.cacheIsDirty = true;
|
|
3481
|
+
this.lastDirty = now;
|
|
3482
|
+
}
|
|
3483
|
+
}
|
|
3484
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: OffsetBatchingCacheService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
3485
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: OffsetBatchingCacheService }); }
|
|
3486
|
+
}
|
|
3487
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: OffsetBatchingCacheService, decorators: [{
|
|
3488
|
+
type: Injectable
|
|
3489
|
+
}] });
|
|
3490
|
+
|
|
3491
|
+
class RequestAnimationFrameBatchingService {
|
|
3492
|
+
constructor() {
|
|
3493
|
+
this.callbacks = [];
|
|
3494
|
+
this.requestAnimationFrameStarted = false;
|
|
3495
|
+
}
|
|
3496
|
+
batchAnimationFrame(callback) {
|
|
3497
|
+
this.callbacks.push(callback);
|
|
3498
|
+
if (!this.requestAnimationFrameStarted) {
|
|
3499
|
+
this.requestAnimationFrameStarted = true;
|
|
3500
|
+
requestAnimationFrame(() => {
|
|
3501
|
+
this.callbacks.map((x) => {
|
|
3502
|
+
if (x) {
|
|
3503
|
+
x();
|
|
3504
|
+
}
|
|
3505
|
+
});
|
|
3506
|
+
this.callbacks = [];
|
|
3507
|
+
this.requestAnimationFrameStarted = false;
|
|
3508
|
+
});
|
|
3509
|
+
}
|
|
3510
|
+
}
|
|
3511
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: RequestAnimationFrameBatchingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
3512
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: RequestAnimationFrameBatchingService }); }
|
|
3513
|
+
}
|
|
3514
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: RequestAnimationFrameBatchingService, decorators: [{
|
|
3515
|
+
type: Injectable
|
|
3516
|
+
}] });
|
|
3517
|
+
|
|
3404
3518
|
class HandleComponent {
|
|
3405
3519
|
constructor() {
|
|
3406
3520
|
this.injector = inject(Injector);
|
|
3407
3521
|
this.handleService = inject(HandleService);
|
|
3408
3522
|
this.element = inject(ElementRef).nativeElement;
|
|
3409
3523
|
this.destroyRef = inject(DestroyRef);
|
|
3524
|
+
this.requestAnimationFrameBatchingService = inject(RequestAnimationFrameBatchingService);
|
|
3525
|
+
this.offsetBatchingCacheService = inject(OffsetBatchingCacheService);
|
|
3410
3526
|
/**
|
|
3411
3527
|
* At what side of node this component should be placed
|
|
3412
3528
|
*/
|
|
@@ -3435,10 +3551,15 @@ class HandleComponent {
|
|
|
3435
3551
|
template: this.template(),
|
|
3436
3552
|
userOffsetX: this.offsetX(),
|
|
3437
3553
|
userOffsetY: this.offsetY(),
|
|
3438
|
-
}, node);
|
|
3554
|
+
}, node, this.offsetBatchingCacheService);
|
|
3439
3555
|
this.handleService.createHandle(model);
|
|
3440
|
-
|
|
3441
|
-
|
|
3556
|
+
this.requestAnimationFrameBatchingService.batchAnimationFrame(() => {
|
|
3557
|
+
model.updateHost();
|
|
3558
|
+
});
|
|
3559
|
+
this.destroyRef.onDestroy(() => {
|
|
3560
|
+
this.handleService.destroyHandle(model);
|
|
3561
|
+
model.onDestroy();
|
|
3562
|
+
});
|
|
3442
3563
|
}
|
|
3443
3564
|
});
|
|
3444
3565
|
}
|
|
@@ -3450,19 +3571,77 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
3450
3571
|
args: [{ standalone: true, selector: 'handle', changeDetection: ChangeDetectionStrategy.OnPush, template: "" }]
|
|
3451
3572
|
}] });
|
|
3452
3573
|
|
|
3574
|
+
class ResizeObserverService {
|
|
3575
|
+
constructor() {
|
|
3576
|
+
this.zone = inject(NgZone);
|
|
3577
|
+
this.thingsToObserve = new Map();
|
|
3578
|
+
this.resizeObserver = new ResizeObserver((entries) => {
|
|
3579
|
+
this.zone.run(() => {
|
|
3580
|
+
for (const entry of entries) {
|
|
3581
|
+
const callbacks = this.thingsToObserve.get(entry.target);
|
|
3582
|
+
if (callbacks !== undefined) {
|
|
3583
|
+
callbacks.forEach((c) => c(entry));
|
|
3584
|
+
}
|
|
3585
|
+
}
|
|
3586
|
+
});
|
|
3587
|
+
});
|
|
3588
|
+
}
|
|
3589
|
+
addObserver(element, callback) {
|
|
3590
|
+
const callbacks = this.thingsToObserve.get(element);
|
|
3591
|
+
if (callbacks === undefined) {
|
|
3592
|
+
this.thingsToObserve.set(element, [callback]);
|
|
3593
|
+
}
|
|
3594
|
+
else {
|
|
3595
|
+
callbacks.push(callback);
|
|
3596
|
+
}
|
|
3597
|
+
this.resizeObserver.observe(element);
|
|
3598
|
+
}
|
|
3599
|
+
removeObserver(element) {
|
|
3600
|
+
this.thingsToObserve.delete(element);
|
|
3601
|
+
if (this.resizeObserver) {
|
|
3602
|
+
this.resizeObserver.unobserve(element);
|
|
3603
|
+
}
|
|
3604
|
+
}
|
|
3605
|
+
ngOnDestroy() {
|
|
3606
|
+
this.resizeObserver.disconnect();
|
|
3607
|
+
}
|
|
3608
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: ResizeObserverService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
3609
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: ResizeObserverService }); }
|
|
3610
|
+
}
|
|
3611
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: ResizeObserverService, decorators: [{
|
|
3612
|
+
type: Injectable
|
|
3613
|
+
}], ctorParameters: () => [] });
|
|
3614
|
+
|
|
3453
3615
|
class NodeHandlesControllerDirective {
|
|
3454
3616
|
constructor() {
|
|
3455
3617
|
this.nodeAccessor = inject(NodeAccessorService);
|
|
3456
|
-
this.zone = inject(NgZone);
|
|
3457
3618
|
this.destroyRef = inject(DestroyRef);
|
|
3458
3619
|
this.hostElementRef = inject(ElementRef);
|
|
3620
|
+
this.resizeObserverService = inject(ResizeObserverService);
|
|
3621
|
+
this.requestAnimationFrameBatchingService = inject(RequestAnimationFrameBatchingService);
|
|
3459
3622
|
}
|
|
3460
3623
|
ngOnInit() {
|
|
3461
3624
|
const model = this.nodeAccessor.model();
|
|
3625
|
+
let isTrackingHostElement = false;
|
|
3462
3626
|
model.handles$
|
|
3463
|
-
.pipe(
|
|
3627
|
+
.pipe(pairwise(), tap(([previousHandles, currentHandles]) => {
|
|
3628
|
+
const handlesToRemove = previousHandles.filter((prev) => currentHandles.find((curr) => curr.hostReference === prev.hostReference) === undefined);
|
|
3629
|
+
handlesToRemove.forEach((h) => this.resizeObserverService.removeObserver(h.hostReference));
|
|
3630
|
+
const handlesToAdd = currentHandles.filter((curr) => previousHandles.find((prev) => curr.hostReference === prev.hostReference) === undefined);
|
|
3631
|
+
if (!isTrackingHostElement) {
|
|
3632
|
+
this.resizeObserverService.addObserver(this.hostElementRef.nativeElement, () => {
|
|
3633
|
+
currentHandles.forEach((h) => h.updateHost());
|
|
3634
|
+
});
|
|
3635
|
+
isTrackingHostElement = true;
|
|
3636
|
+
}
|
|
3637
|
+
handlesToAdd.forEach((h) => this.resizeObserverService.addObserver(h.hostReference, () => {
|
|
3638
|
+
currentHandles.forEach((h) => h.updateHost());
|
|
3639
|
+
}));
|
|
3640
|
+
//Here we need this to be in a requestAnimationFrame otherwise the handle can still be present in the dom which throws off the offset cache
|
|
3641
|
+
this.requestAnimationFrameBatchingService.batchAnimationFrame(() => {
|
|
3642
|
+
currentHandles.forEach((h) => h.updateHost());
|
|
3643
|
+
});
|
|
3464
3644
|
// TODO (performance) inspect how to avoid calls of this when flow initially rendered
|
|
3465
|
-
handles.forEach((h) => h.updateHost());
|
|
3466
3645
|
}), takeUntilDestroyed(this.destroyRef))
|
|
3467
3646
|
.subscribe();
|
|
3468
3647
|
}
|
|
@@ -3483,19 +3662,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
3483
3662
|
class NodeResizeControllerDirective {
|
|
3484
3663
|
constructor() {
|
|
3485
3664
|
this.nodeAccessor = inject(NodeAccessorService);
|
|
3486
|
-
this.
|
|
3487
|
-
this.destroyRef = inject(DestroyRef);
|
|
3665
|
+
this.resizeObserverService = inject(ResizeObserverService);
|
|
3488
3666
|
this.hostElementRef = inject(ElementRef);
|
|
3489
3667
|
}
|
|
3490
3668
|
ngOnInit() {
|
|
3491
3669
|
const model = this.nodeAccessor.model();
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
.
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3670
|
+
this.resizeObserverService.addObserver(this.hostElementRef.nativeElement, (resizeEntry) => {
|
|
3671
|
+
model.width.set(resizeEntry.target.clientWidth);
|
|
3672
|
+
model.height.set(resizeEntry.target.clientHeight);
|
|
3673
|
+
});
|
|
3674
|
+
}
|
|
3675
|
+
ngOnDestroy() {
|
|
3676
|
+
this.resizeObserverService.removeObserver(this.hostElementRef.nativeElement);
|
|
3499
3677
|
}
|
|
3500
3678
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: NodeResizeControllerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
3501
3679
|
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.17", type: NodeResizeControllerDirective, isStandalone: true, selector: "[nodeResizeController]", ngImport: i0 }); }
|
|
@@ -3749,6 +3927,8 @@ const defaultBg = '#fff';
|
|
|
3749
3927
|
const defaultGap = 20;
|
|
3750
3928
|
const defaultDotSize = 2;
|
|
3751
3929
|
const defaultDotColor = 'rgb(177, 177, 183)';
|
|
3930
|
+
const defaultGridSize = 20;
|
|
3931
|
+
const defaultStrokeWidth = 2;
|
|
3752
3932
|
const defaultImageScale = 0.1;
|
|
3753
3933
|
const defaultRepeated = true;
|
|
3754
3934
|
class BackgroundComponent {
|
|
@@ -3757,21 +3937,16 @@ class BackgroundComponent {
|
|
|
3757
3937
|
this.rootSvg = inject(RootSvgReferenceDirective).element;
|
|
3758
3938
|
this.settingsService = inject(FlowSettingsService);
|
|
3759
3939
|
this.backgroundSignal = this.settingsService.background;
|
|
3760
|
-
|
|
3761
|
-
|
|
3762
|
-
|
|
3763
|
-
|
|
3764
|
-
|
|
3765
|
-
return zoom * (background.gap ?? defaultGap);
|
|
3766
|
-
}
|
|
3767
|
-
return 0;
|
|
3940
|
+
this.x = computed(() => {
|
|
3941
|
+
return this.viewportService.readableViewport().x % this.scaledGap();
|
|
3942
|
+
});
|
|
3943
|
+
this.y = computed(() => {
|
|
3944
|
+
return this.viewportService.readableViewport().y % this.scaledGap();
|
|
3768
3945
|
});
|
|
3769
|
-
this.x = computed(() => this.viewportService.readableViewport().x % this.scaledGap());
|
|
3770
|
-
this.y = computed(() => this.viewportService.readableViewport().y % this.scaledGap());
|
|
3771
3946
|
this.patternColor = computed(() => {
|
|
3772
|
-
const
|
|
3773
|
-
if (
|
|
3774
|
-
return
|
|
3947
|
+
const background = this.backgroundSignal();
|
|
3948
|
+
if (background.type === 'dots' || background.type === 'grid') {
|
|
3949
|
+
return background.color ?? defaultDotColor;
|
|
3775
3950
|
}
|
|
3776
3951
|
return defaultDotColor;
|
|
3777
3952
|
});
|
|
@@ -3780,6 +3955,29 @@ class BackgroundComponent {
|
|
|
3780
3955
|
if (background.type === 'dots') {
|
|
3781
3956
|
return (this.viewportService.readableViewport().zoom * (background.size ?? defaultDotSize)) / 2;
|
|
3782
3957
|
}
|
|
3958
|
+
if (background.type === 'grid') {
|
|
3959
|
+
return this.viewportService.readableViewport().zoom * (background.size ?? defaultGridSize);
|
|
3960
|
+
}
|
|
3961
|
+
return 0;
|
|
3962
|
+
});
|
|
3963
|
+
this.scaledGap = computed(() => {
|
|
3964
|
+
const background = this.backgroundSignal();
|
|
3965
|
+
const zoom = this.viewportService.readableViewport().zoom;
|
|
3966
|
+
if (background.type === 'dots') {
|
|
3967
|
+
return zoom * (background.gap ?? defaultGap);
|
|
3968
|
+
}
|
|
3969
|
+
if (background.type === 'grid') {
|
|
3970
|
+
return zoom * (background.size ?? defaultGridSize);
|
|
3971
|
+
}
|
|
3972
|
+
return 0;
|
|
3973
|
+
});
|
|
3974
|
+
// GRID PATTERN
|
|
3975
|
+
this.strokeWidth = computed(() => {
|
|
3976
|
+
const background = this.backgroundSignal();
|
|
3977
|
+
if (background.type === 'grid') {
|
|
3978
|
+
const zoom = this.viewportService.readableViewport().zoom;
|
|
3979
|
+
return zoom * ((background.strokeWidth ?? defaultStrokeWidth) / 2);
|
|
3980
|
+
}
|
|
3783
3981
|
return 0;
|
|
3784
3982
|
});
|
|
3785
3983
|
// IMAGE PATTERN
|
|
@@ -3837,17 +4035,20 @@ class BackgroundComponent {
|
|
|
3837
4035
|
if (background.type === 'dots') {
|
|
3838
4036
|
this.rootSvg.style.backgroundColor = background.backgroundColor ?? defaultBg;
|
|
3839
4037
|
}
|
|
4038
|
+
if (background.type === 'grid') {
|
|
4039
|
+
this.rootSvg.style.backgroundColor = background.backgroundColor ?? defaultBg;
|
|
4040
|
+
}
|
|
3840
4041
|
if (background.type === 'solid') {
|
|
3841
4042
|
this.rootSvg.style.backgroundColor = background.color;
|
|
3842
4043
|
}
|
|
3843
4044
|
});
|
|
3844
4045
|
}
|
|
3845
4046
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: BackgroundComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3846
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: BackgroundComponent, isStandalone: true, selector: "g[background]", ngImport: i0, template: "@if (backgroundSignal().type === 'dots') {\n <svg:pattern\n patternUnits=\"userSpaceOnUse\"\n [attr.id]=\"patternId\"\n [attr.x]=\"x()\"\n [attr.y]=\"y()\"\n [attr.width]=\"scaledGap()\"\n [attr.height]=\"scaledGap()\">\n <svg:circle\n [attr.cx]=\"patternSize()\"\n [attr.cy]=\"patternSize()\"\n [attr.r]=\"patternSize()\"\n [attr.fill]=\"patternColor()\" />\n </svg:pattern>\n\n <svg:rect x=\"0\" y=\"0\" width=\"100%\" height=\"100%\" [attr.fill]=\"patternUrl\" />\n}\n\n@if (backgroundSignal().type === 'image') {\n @if (repeated()) {\n <svg:pattern\n patternUnits=\"userSpaceOnUse\"\n [attr.id]=\"patternId\"\n [attr.x]=\"imageX()\"\n [attr.y]=\"imageY()\"\n [attr.width]=\"scaledImageWidth()\"\n [attr.height]=\"scaledImageHeight()\">\n <svg:image [attr.href]=\"bgImageSrc()\" [attr.width]=\"scaledImageWidth()\" [attr.height]=\"scaledImageHeight()\" />\n </svg:pattern>\n\n <svg:rect x=\"0\" y=\"0\" width=\"100%\" height=\"100%\" [attr.fill]=\"patternUrl\" />\n }\n\n @if (!repeated()) {\n <svg:image\n [attr.x]=\"imageX()\"\n [attr.y]=\"imageY()\"\n [attr.width]=\"scaledImageWidth()\"\n [attr.height]=\"scaledImageHeight()\"\n [attr.href]=\"bgImageSrc()\" />\n }\n}\n", changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
4047
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.17", type: BackgroundComponent, isStandalone: true, selector: "g[background]", ngImport: i0, template: "@if (backgroundSignal().type === 'dots') {\n <svg:pattern\n patternUnits=\"userSpaceOnUse\"\n [attr.id]=\"patternId\"\n [attr.x]=\"x()\"\n [attr.y]=\"y()\"\n [attr.width]=\"scaledGap()\"\n [attr.height]=\"scaledGap()\">\n <svg:circle\n [attr.cx]=\"patternSize()\"\n [attr.cy]=\"patternSize()\"\n [attr.r]=\"patternSize()\"\n [attr.fill]=\"patternColor()\" />\n </svg:pattern>\n\n <svg:rect x=\"0\" y=\"0\" width=\"100%\" height=\"100%\" [attr.fill]=\"patternUrl\" />\n}\n\n@if (backgroundSignal().type === 'image') {\n @if (repeated()) {\n <svg:pattern\n patternUnits=\"userSpaceOnUse\"\n [attr.id]=\"patternId\"\n [attr.x]=\"imageX()\"\n [attr.y]=\"imageY()\"\n [attr.width]=\"scaledImageWidth()\"\n [attr.height]=\"scaledImageHeight()\">\n <svg:image [attr.href]=\"bgImageSrc()\" [attr.width]=\"scaledImageWidth()\" [attr.height]=\"scaledImageHeight()\" />\n </svg:pattern>\n\n <svg:rect x=\"0\" y=\"0\" width=\"100%\" height=\"100%\" [attr.fill]=\"patternUrl\" />\n }\n\n @if (!repeated()) {\n <svg:image\n [attr.x]=\"imageX()\"\n [attr.y]=\"imageY()\"\n [attr.width]=\"scaledImageWidth()\"\n [attr.height]=\"scaledImageHeight()\"\n [attr.href]=\"bgImageSrc()\" />\n }\n}\n\n@if (backgroundSignal().type === 'grid') {\n <svg:pattern\n patternUnits=\"userSpaceOnUse\"\n [attr.id]=\"patternId\"\n [attr.x]=\"x()\"\n [attr.y]=\"y()\"\n [attr.width]=\"patternSize()\"\n [attr.height]=\"patternSize()\">\n <svg:path\n fill=\"none\"\n [attr.d]=\"'M ' + patternSize() + ' 0 L 0 0 0 ' + patternSize()\"\n [attr.stroke]=\"patternColor()\"\n [attr.stroke-width]=\"strokeWidth()\" />\n </svg:pattern>\n\n <svg:rect x=\"0\" y=\"0\" width=\"100%\" height=\"100%\" [attr.fill]=\"patternUrl\" />\n}\n", changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
3847
4048
|
}
|
|
3848
4049
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: BackgroundComponent, decorators: [{
|
|
3849
4050
|
type: Component,
|
|
3850
|
-
args: [{ standalone: true, selector: 'g[background]', changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (backgroundSignal().type === 'dots') {\n <svg:pattern\n patternUnits=\"userSpaceOnUse\"\n [attr.id]=\"patternId\"\n [attr.x]=\"x()\"\n [attr.y]=\"y()\"\n [attr.width]=\"scaledGap()\"\n [attr.height]=\"scaledGap()\">\n <svg:circle\n [attr.cx]=\"patternSize()\"\n [attr.cy]=\"patternSize()\"\n [attr.r]=\"patternSize()\"\n [attr.fill]=\"patternColor()\" />\n </svg:pattern>\n\n <svg:rect x=\"0\" y=\"0\" width=\"100%\" height=\"100%\" [attr.fill]=\"patternUrl\" />\n}\n\n@if (backgroundSignal().type === 'image') {\n @if (repeated()) {\n <svg:pattern\n patternUnits=\"userSpaceOnUse\"\n [attr.id]=\"patternId\"\n [attr.x]=\"imageX()\"\n [attr.y]=\"imageY()\"\n [attr.width]=\"scaledImageWidth()\"\n [attr.height]=\"scaledImageHeight()\">\n <svg:image [attr.href]=\"bgImageSrc()\" [attr.width]=\"scaledImageWidth()\" [attr.height]=\"scaledImageHeight()\" />\n </svg:pattern>\n\n <svg:rect x=\"0\" y=\"0\" width=\"100%\" height=\"100%\" [attr.fill]=\"patternUrl\" />\n }\n\n @if (!repeated()) {\n <svg:image\n [attr.x]=\"imageX()\"\n [attr.y]=\"imageY()\"\n [attr.width]=\"scaledImageWidth()\"\n [attr.height]=\"scaledImageHeight()\"\n [attr.href]=\"bgImageSrc()\" />\n }\n}\n" }]
|
|
4051
|
+
args: [{ standalone: true, selector: 'g[background]', changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (backgroundSignal().type === 'dots') {\n <svg:pattern\n patternUnits=\"userSpaceOnUse\"\n [attr.id]=\"patternId\"\n [attr.x]=\"x()\"\n [attr.y]=\"y()\"\n [attr.width]=\"scaledGap()\"\n [attr.height]=\"scaledGap()\">\n <svg:circle\n [attr.cx]=\"patternSize()\"\n [attr.cy]=\"patternSize()\"\n [attr.r]=\"patternSize()\"\n [attr.fill]=\"patternColor()\" />\n </svg:pattern>\n\n <svg:rect x=\"0\" y=\"0\" width=\"100%\" height=\"100%\" [attr.fill]=\"patternUrl\" />\n}\n\n@if (backgroundSignal().type === 'image') {\n @if (repeated()) {\n <svg:pattern\n patternUnits=\"userSpaceOnUse\"\n [attr.id]=\"patternId\"\n [attr.x]=\"imageX()\"\n [attr.y]=\"imageY()\"\n [attr.width]=\"scaledImageWidth()\"\n [attr.height]=\"scaledImageHeight()\">\n <svg:image [attr.href]=\"bgImageSrc()\" [attr.width]=\"scaledImageWidth()\" [attr.height]=\"scaledImageHeight()\" />\n </svg:pattern>\n\n <svg:rect x=\"0\" y=\"0\" width=\"100%\" height=\"100%\" [attr.fill]=\"patternUrl\" />\n }\n\n @if (!repeated()) {\n <svg:image\n [attr.x]=\"imageX()\"\n [attr.y]=\"imageY()\"\n [attr.width]=\"scaledImageWidth()\"\n [attr.height]=\"scaledImageHeight()\"\n [attr.href]=\"bgImageSrc()\" />\n }\n}\n\n@if (backgroundSignal().type === 'grid') {\n <svg:pattern\n patternUnits=\"userSpaceOnUse\"\n [attr.id]=\"patternId\"\n [attr.x]=\"x()\"\n [attr.y]=\"y()\"\n [attr.width]=\"patternSize()\"\n [attr.height]=\"patternSize()\">\n <svg:path\n fill=\"none\"\n [attr.d]=\"'M ' + patternSize() + ' 0 L 0 0 0 ' + patternSize()\"\n [attr.stroke]=\"patternColor()\"\n [attr.stroke-width]=\"strokeWidth()\" />\n </svg:pattern>\n\n <svg:rect x=\"0\" y=\"0\" width=\"100%\" height=\"100%\" [attr.fill]=\"patternUrl\" />\n}\n" }]
|
|
3851
4052
|
}], ctorParameters: () => [] });
|
|
3852
4053
|
function createImage(url) {
|
|
3853
4054
|
const image = new Image();
|
|
@@ -4263,8 +4464,16 @@ class AlignmentHelperComponent {
|
|
|
4263
4464
|
.pipe(filter(isNodeDragEndStatus), map((status) => status.payload.node), map((node) => [node, this.intersections()]), tap(([node, intersections]) => {
|
|
4264
4465
|
if (intersections) {
|
|
4265
4466
|
const snapped = { x: intersections.snappedX, y: intersections.snappedY };
|
|
4266
|
-
const
|
|
4267
|
-
|
|
4467
|
+
const parent = node.parent();
|
|
4468
|
+
if (parent) {
|
|
4469
|
+
node.setPoint({
|
|
4470
|
+
x: snapped.x - parent.globalPoint().x,
|
|
4471
|
+
y: snapped.y - parent.globalPoint().y,
|
|
4472
|
+
});
|
|
4473
|
+
}
|
|
4474
|
+
else {
|
|
4475
|
+
node.setPoint(snapped);
|
|
4476
|
+
}
|
|
4268
4477
|
}
|
|
4269
4478
|
}), takeUntilDestroyed())
|
|
4270
4479
|
.subscribe();
|
|
@@ -4680,6 +4889,9 @@ class VflowComponent {
|
|
|
4680
4889
|
OverlaysService,
|
|
4681
4890
|
{ provide: PreviewFlowRenderStrategyService, useClass: ViewportPreviewFlowRenderStrategyService },
|
|
4682
4891
|
FlowRenderingService,
|
|
4892
|
+
ResizeObserverService,
|
|
4893
|
+
OffsetBatchingCacheService,
|
|
4894
|
+
RequestAnimationFrameBatchingService,
|
|
4683
4895
|
], queries: [{ propertyName: "nodeTemplateDirective", first: true, predicate: NodeHtmlTemplateDirective, descendants: true, isSignal: true }, { propertyName: "nodeSvgTemplateDirective", first: true, predicate: NodeSvgTemplateDirective, descendants: true, isSignal: true }, { propertyName: "groupNodeTemplateDirective", first: true, predicate: GroupNodeTemplateDirective, descendants: true, isSignal: true }, { propertyName: "edgeTemplateDirective", first: true, predicate: EdgeTemplateDirective, descendants: true, isSignal: true }, { propertyName: "edgeLabelHtmlDirective", first: true, predicate: EdgeLabelHtmlTemplateDirective, descendants: true, isSignal: true }, { propertyName: "connectionTemplateDirective", first: true, predicate: ConnectionTemplateDirective, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "mapContext", first: true, predicate: MapContextDirective, descendants: true, isSignal: true }, { propertyName: "spacePointContext", first: true, predicate: SpacePointContextDirective, descendants: true, isSignal: true }], hostDirectives: [{ directive: ChangesControllerDirective, outputs: ["nodesChanges", "nodesChanges", "nodesChanges.position", "nodesChanges.position", "nodesChanges.size", "nodesChanges.size", "nodesChanges.add", "nodesChanges.add", "nodesChanges.remove", "nodesChanges.remove", "nodesChanges.select", "nodesChanges.select", "edgesChanges", "edgesChanges", "edgesChanges.detached", "edgesChanges.detached", "edgesChanges.add", "edgesChanges.add", "edgesChanges.remove", "edgesChanges.remove", "edgesChanges.select", "edgesChanges.select"] }], ngImport: i0, template: "<svg:svg #flow rootSvgRef rootSvgContext rootPointer flowSizeController class=\"root-svg\">\n <defs flowDefs [markers]=\"markers()\" />\n\n <g background />\n\n <svg:g mapContext spacePointContext autoPan>\n @if (alignmentHelper(); as alignmentHelper) {\n @if (alignmentHelper === true) {\n <svg:g alignmentHelper />\n } @else {\n <svg:g alignmentHelper [tolerance]=\"alignmentHelper.tolerance\" [lineColor]=\"alignmentHelper.lineColor\" />\n }\n }\n\n <!-- Connection -->\n <svg:g connection [model]=\"connection\" [template]=\"connectionTemplateDirective()?.templateRef\" />\n\n @if (flowOptimization().detachedGroupsLayer) {\n <!-- Groups -->\n @for (model of groups(); track trackNodes($index, model)) {\n <svg:g\n node\n [model]=\"model\"\n [groupNodeTemplate]=\"groupNodeTemplateDirective()?.templateRef\"\n [attr.transform]=\"model.pointTransform()\" />\n }\n <!-- Edges -->\n @for (model of edgeModels(); track trackEdges($index, model)) {\n <svg:g\n edge\n [model]=\"model\"\n [edgeTemplate]=\"edgeTemplateDirective()?.templateRef\"\n [edgeLabelHtmlTemplate]=\"edgeLabelHtmlDirective()?.templateRef\" />\n }\n <!-- Nodes -->\n @for (model of nonGroups(); track trackNodes($index, model)) {\n <svg:g\n node\n [model]=\"model\"\n [nodeTemplate]=\"nodeTemplateDirective()?.templateRef\"\n [nodeSvgTemplate]=\"nodeSvgTemplateDirective()?.templateRef\"\n [attr.transform]=\"model.pointTransform()\" />\n }\n }\n\n @if (!flowOptimization().detachedGroupsLayer) {\n <!-- Edges -->\n @for (model of edgeModels(); track trackEdges($index, model)) {\n <svg:g\n edge\n [model]=\"model\"\n [edgeTemplate]=\"edgeTemplateDirective()?.templateRef\"\n [edgeLabelHtmlTemplate]=\"edgeLabelHtmlDirective()?.templateRef\" />\n }\n\n @for (model of nodeModels(); track trackNodes($index, model)) {\n <svg:g\n node\n [model]=\"model\"\n [nodeTemplate]=\"nodeTemplateDirective()?.templateRef\"\n [nodeSvgTemplate]=\"nodeSvgTemplateDirective()?.templateRef\"\n [groupNodeTemplate]=\"groupNodeTemplateDirective()?.templateRef\"\n [attr.transform]=\"model.pointTransform()\" />\n }\n }\n </svg:g>\n\n <!-- Minimap -->\n @if (minimap(); as minimap) {\n <ng-container [ngTemplateOutlet]=\"minimap.template()\" />\n }\n</svg:svg>\n\n@if (flowOptimization().virtualization) {\n <canvas previewFlow class=\"preview-flow\" [width]=\"flowWidth()\" [height]=\"flowHeight()\"></canvas>\n}\n", styles: [":host{display:grid;grid-template-columns:1fr;width:100%;height:100%;-webkit-user-select:none;user-select:none}:host ::ng-deep *{box-sizing:border-box}.root-svg{grid-row-start:1;grid-column-start:1}.preview-flow{pointer-events:none;grid-row-start:1;grid-column-start:1}\n"], dependencies: [{ 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]" }, { kind: "component", type: DefsComponent, selector: "defs[flowDefs]", inputs: ["markers"] }, { kind: "component", type: BackgroundComponent, selector: "g[background]" }, { kind: "directive", type: MapContextDirective, selector: "g[mapContext]" }, { kind: "directive", type: SpacePointContextDirective, selector: "g[spacePointContext]" }, { kind: "component", type: ConnectionComponent, selector: "g[connection]", inputs: ["model", "template"] }, { kind: "component", type: NodeComponent, selector: "g[node]", inputs: ["model", "nodeTemplate", "nodeSvgTemplate", "groupNodeTemplate"] }, { kind: "component", type: EdgeComponent, selector: "g[edge]", inputs: ["model", "edgeTemplate", "edgeLabelHtmlTemplate"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: PreviewFlowComponent, selector: "canvas[previewFlow]", inputs: ["width", "height"] }, { kind: "component", type: AlignmentHelperComponent, selector: "g[alignmentHelper]", inputs: ["tolerance", "lineColor"] }, { kind: "directive", type: AutoPanDirective, selector: "[autoPan]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
4684
4896
|
}
|
|
4685
4897
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: VflowComponent, decorators: [{
|
|
@@ -4700,6 +4912,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
4700
4912
|
OverlaysService,
|
|
4701
4913
|
{ provide: PreviewFlowRenderStrategyService, useClass: ViewportPreviewFlowRenderStrategyService },
|
|
4702
4914
|
FlowRenderingService,
|
|
4915
|
+
ResizeObserverService,
|
|
4916
|
+
OffsetBatchingCacheService,
|
|
4917
|
+
RequestAnimationFrameBatchingService,
|
|
4703
4918
|
], hostDirectives: [changesControllerHostDirective], imports: [
|
|
4704
4919
|
RootSvgReferenceDirective,
|
|
4705
4920
|
RootSvgContextDirective,
|