ngx-vflow 2.1.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 +239 -39
- 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/models/handle.model.d.ts +4 -1
- 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
|
@@ -3314,9 +3314,10 @@ function constrainRect(rect, model, side, minWidth, minHeight, maxWidth, maxHeig
|
|
|
3314
3314
|
}
|
|
3315
3315
|
|
|
3316
3316
|
class HandleModel {
|
|
3317
|
-
constructor(rawHandle, parentNode) {
|
|
3317
|
+
constructor(rawHandle, parentNode, batchingService) {
|
|
3318
3318
|
this.rawHandle = rawHandle;
|
|
3319
3319
|
this.parentNode = parentNode;
|
|
3320
|
+
this.batchingService = batchingService;
|
|
3320
3321
|
this.strokeWidth = 2;
|
|
3321
3322
|
/**
|
|
3322
3323
|
* Pre-computed size for default handle, changed dynamically
|
|
@@ -3339,10 +3340,15 @@ class HandleModel {
|
|
|
3339
3340
|
initialValue: { width: 0, height: 0 },
|
|
3340
3341
|
});
|
|
3341
3342
|
// TODO: for some reason toLazySignal breaks unit tests, so we use toSignal here
|
|
3342
|
-
this.hostPosition = toSignal(this.updateHostSizeAndPosition$.pipe(map(() =>
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
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
|
+
})), {
|
|
3346
3352
|
initialValue: { x: 0, y: 0 },
|
|
3347
3353
|
});
|
|
3348
3354
|
this.hostOffset = computed(() => {
|
|
@@ -3390,16 +3396,29 @@ class HandleModel {
|
|
|
3390
3396
|
node: this.parentNode.rawNode,
|
|
3391
3397
|
},
|
|
3392
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
|
+
}
|
|
3393
3407
|
}
|
|
3394
3408
|
updateHost() {
|
|
3409
|
+
this.batchingService.markCacheAsDirty();
|
|
3395
3410
|
this.updateHostSizeAndPosition$.next();
|
|
3396
3411
|
}
|
|
3397
3412
|
getHostSize() {
|
|
3413
|
+
//TODO only get the hist ref width once ?
|
|
3398
3414
|
if (this.hostReference instanceof HTMLElement) {
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3415
|
+
const offsets = this.batchingService.getElementOffsets(this.hostReference);
|
|
3416
|
+
if (offsets) {
|
|
3417
|
+
return {
|
|
3418
|
+
width: offsets.offsetWidth,
|
|
3419
|
+
height: offsets.offsetHeight,
|
|
3420
|
+
};
|
|
3421
|
+
}
|
|
3403
3422
|
}
|
|
3404
3423
|
else if (this.hostReference instanceof SVGGraphicsElement) {
|
|
3405
3424
|
return this.hostReference.getBBox();
|
|
@@ -3408,12 +3427,102 @@ class HandleModel {
|
|
|
3408
3427
|
}
|
|
3409
3428
|
}
|
|
3410
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
|
+
|
|
3411
3518
|
class HandleComponent {
|
|
3412
3519
|
constructor() {
|
|
3413
3520
|
this.injector = inject(Injector);
|
|
3414
3521
|
this.handleService = inject(HandleService);
|
|
3415
3522
|
this.element = inject(ElementRef).nativeElement;
|
|
3416
3523
|
this.destroyRef = inject(DestroyRef);
|
|
3524
|
+
this.requestAnimationFrameBatchingService = inject(RequestAnimationFrameBatchingService);
|
|
3525
|
+
this.offsetBatchingCacheService = inject(OffsetBatchingCacheService);
|
|
3417
3526
|
/**
|
|
3418
3527
|
* At what side of node this component should be placed
|
|
3419
3528
|
*/
|
|
@@ -3442,10 +3551,15 @@ class HandleComponent {
|
|
|
3442
3551
|
template: this.template(),
|
|
3443
3552
|
userOffsetX: this.offsetX(),
|
|
3444
3553
|
userOffsetY: this.offsetY(),
|
|
3445
|
-
}, node);
|
|
3554
|
+
}, node, this.offsetBatchingCacheService);
|
|
3446
3555
|
this.handleService.createHandle(model);
|
|
3447
|
-
|
|
3448
|
-
|
|
3556
|
+
this.requestAnimationFrameBatchingService.batchAnimationFrame(() => {
|
|
3557
|
+
model.updateHost();
|
|
3558
|
+
});
|
|
3559
|
+
this.destroyRef.onDestroy(() => {
|
|
3560
|
+
this.handleService.destroyHandle(model);
|
|
3561
|
+
model.onDestroy();
|
|
3562
|
+
});
|
|
3449
3563
|
}
|
|
3450
3564
|
});
|
|
3451
3565
|
}
|
|
@@ -3457,19 +3571,77 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
3457
3571
|
args: [{ standalone: true, selector: 'handle', changeDetection: ChangeDetectionStrategy.OnPush, template: "" }]
|
|
3458
3572
|
}] });
|
|
3459
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
|
+
|
|
3460
3615
|
class NodeHandlesControllerDirective {
|
|
3461
3616
|
constructor() {
|
|
3462
3617
|
this.nodeAccessor = inject(NodeAccessorService);
|
|
3463
|
-
this.zone = inject(NgZone);
|
|
3464
3618
|
this.destroyRef = inject(DestroyRef);
|
|
3465
3619
|
this.hostElementRef = inject(ElementRef);
|
|
3620
|
+
this.resizeObserverService = inject(ResizeObserverService);
|
|
3621
|
+
this.requestAnimationFrameBatchingService = inject(RequestAnimationFrameBatchingService);
|
|
3466
3622
|
}
|
|
3467
3623
|
ngOnInit() {
|
|
3468
3624
|
const model = this.nodeAccessor.model();
|
|
3625
|
+
let isTrackingHostElement = false;
|
|
3469
3626
|
model.handles$
|
|
3470
|
-
.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
|
+
});
|
|
3471
3644
|
// TODO (performance) inspect how to avoid calls of this when flow initially rendered
|
|
3472
|
-
handles.forEach((h) => h.updateHost());
|
|
3473
3645
|
}), takeUntilDestroyed(this.destroyRef))
|
|
3474
3646
|
.subscribe();
|
|
3475
3647
|
}
|
|
@@ -3490,19 +3662,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
3490
3662
|
class NodeResizeControllerDirective {
|
|
3491
3663
|
constructor() {
|
|
3492
3664
|
this.nodeAccessor = inject(NodeAccessorService);
|
|
3493
|
-
this.
|
|
3494
|
-
this.destroyRef = inject(DestroyRef);
|
|
3665
|
+
this.resizeObserverService = inject(ResizeObserverService);
|
|
3495
3666
|
this.hostElementRef = inject(ElementRef);
|
|
3496
3667
|
}
|
|
3497
3668
|
ngOnInit() {
|
|
3498
3669
|
const model = this.nodeAccessor.model();
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
.
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
|
|
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);
|
|
3506
3677
|
}
|
|
3507
3678
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: NodeResizeControllerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
3508
3679
|
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.17", type: NodeResizeControllerDirective, isStandalone: true, selector: "[nodeResizeController]", ngImport: i0 }); }
|
|
@@ -3756,6 +3927,8 @@ const defaultBg = '#fff';
|
|
|
3756
3927
|
const defaultGap = 20;
|
|
3757
3928
|
const defaultDotSize = 2;
|
|
3758
3929
|
const defaultDotColor = 'rgb(177, 177, 183)';
|
|
3930
|
+
const defaultGridSize = 20;
|
|
3931
|
+
const defaultStrokeWidth = 2;
|
|
3759
3932
|
const defaultImageScale = 0.1;
|
|
3760
3933
|
const defaultRepeated = true;
|
|
3761
3934
|
class BackgroundComponent {
|
|
@@ -3764,21 +3937,16 @@ class BackgroundComponent {
|
|
|
3764
3937
|
this.rootSvg = inject(RootSvgReferenceDirective).element;
|
|
3765
3938
|
this.settingsService = inject(FlowSettingsService);
|
|
3766
3939
|
this.backgroundSignal = this.settingsService.background;
|
|
3767
|
-
|
|
3768
|
-
|
|
3769
|
-
|
|
3770
|
-
|
|
3771
|
-
|
|
3772
|
-
return zoom * (background.gap ?? defaultGap);
|
|
3773
|
-
}
|
|
3774
|
-
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();
|
|
3775
3945
|
});
|
|
3776
|
-
this.x = computed(() => this.viewportService.readableViewport().x % this.scaledGap());
|
|
3777
|
-
this.y = computed(() => this.viewportService.readableViewport().y % this.scaledGap());
|
|
3778
3946
|
this.patternColor = computed(() => {
|
|
3779
|
-
const
|
|
3780
|
-
if (
|
|
3781
|
-
return
|
|
3947
|
+
const background = this.backgroundSignal();
|
|
3948
|
+
if (background.type === 'dots' || background.type === 'grid') {
|
|
3949
|
+
return background.color ?? defaultDotColor;
|
|
3782
3950
|
}
|
|
3783
3951
|
return defaultDotColor;
|
|
3784
3952
|
});
|
|
@@ -3787,6 +3955,29 @@ class BackgroundComponent {
|
|
|
3787
3955
|
if (background.type === 'dots') {
|
|
3788
3956
|
return (this.viewportService.readableViewport().zoom * (background.size ?? defaultDotSize)) / 2;
|
|
3789
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
|
+
}
|
|
3790
3981
|
return 0;
|
|
3791
3982
|
});
|
|
3792
3983
|
// IMAGE PATTERN
|
|
@@ -3844,17 +4035,20 @@ class BackgroundComponent {
|
|
|
3844
4035
|
if (background.type === 'dots') {
|
|
3845
4036
|
this.rootSvg.style.backgroundColor = background.backgroundColor ?? defaultBg;
|
|
3846
4037
|
}
|
|
4038
|
+
if (background.type === 'grid') {
|
|
4039
|
+
this.rootSvg.style.backgroundColor = background.backgroundColor ?? defaultBg;
|
|
4040
|
+
}
|
|
3847
4041
|
if (background.type === 'solid') {
|
|
3848
4042
|
this.rootSvg.style.backgroundColor = background.color;
|
|
3849
4043
|
}
|
|
3850
4044
|
});
|
|
3851
4045
|
}
|
|
3852
4046
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: BackgroundComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3853
|
-
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 }); }
|
|
3854
4048
|
}
|
|
3855
4049
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: BackgroundComponent, decorators: [{
|
|
3856
4050
|
type: Component,
|
|
3857
|
-
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" }]
|
|
3858
4052
|
}], ctorParameters: () => [] });
|
|
3859
4053
|
function createImage(url) {
|
|
3860
4054
|
const image = new Image();
|
|
@@ -4695,6 +4889,9 @@ class VflowComponent {
|
|
|
4695
4889
|
OverlaysService,
|
|
4696
4890
|
{ provide: PreviewFlowRenderStrategyService, useClass: ViewportPreviewFlowRenderStrategyService },
|
|
4697
4891
|
FlowRenderingService,
|
|
4892
|
+
ResizeObserverService,
|
|
4893
|
+
OffsetBatchingCacheService,
|
|
4894
|
+
RequestAnimationFrameBatchingService,
|
|
4698
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 }); }
|
|
4699
4896
|
}
|
|
4700
4897
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: VflowComponent, decorators: [{
|
|
@@ -4715,6 +4912,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImpo
|
|
|
4715
4912
|
OverlaysService,
|
|
4716
4913
|
{ provide: PreviewFlowRenderStrategyService, useClass: ViewportPreviewFlowRenderStrategyService },
|
|
4717
4914
|
FlowRenderingService,
|
|
4915
|
+
ResizeObserverService,
|
|
4916
|
+
OffsetBatchingCacheService,
|
|
4917
|
+
RequestAnimationFrameBatchingService,
|
|
4718
4918
|
], hostDirectives: [changesControllerHostDirective], imports: [
|
|
4719
4919
|
RootSvgReferenceDirective,
|
|
4720
4920
|
RootSvgContextDirective,
|