ngx-vflow 0.6.0 → 0.8.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/background/background.component.mjs +66 -0
- package/esm2022/lib/vflow/components/connection/connection.component.mjs +2 -2
- package/esm2022/lib/vflow/components/handle/handle.component.mjs +5 -5
- package/esm2022/lib/vflow/components/node/node.component.mjs +32 -84
- package/esm2022/lib/vflow/components/vflow/vflow.component.mjs +21 -10
- package/esm2022/lib/vflow/directives/connection-controller.directive.mjs +91 -12
- package/esm2022/lib/vflow/directives/space-point-context.directive.mjs +11 -5
- package/esm2022/lib/vflow/interfaces/connection-settings.interface.mjs +1 -1
- package/esm2022/lib/vflow/interfaces/connection.internal.interface.mjs +2 -0
- package/esm2022/lib/vflow/models/connection.model.mjs +28 -6
- package/esm2022/lib/vflow/models/handle.model.mjs +1 -1
- package/esm2022/lib/vflow/services/flow-entities.service.mjs +2 -2
- package/esm2022/lib/vflow/services/flow-status.service.mjs +7 -7
- package/esm2022/lib/vflow/services/handle.service.mjs +1 -1
- package/esm2022/lib/vflow/types/background.type.mjs +2 -0
- package/esm2022/lib/vflow/types/connection-mode.type.mjs +2 -0
- package/esm2022/lib/vflow/utils/adjust-direction.mjs +30 -0
- package/esm2022/lib/vflow/utils/id.mjs +5 -0
- package/esm2022/lib/vflow/utils/resizable.mjs +3 -3
- package/esm2022/lib/vflow/vflow.module.mjs +6 -3
- package/esm2022/public-api.mjs +3 -1
- package/fesm2022/ngx-vflow.mjs +409 -250
- package/fesm2022/ngx-vflow.mjs.map +1 -1
- package/lib/vflow/components/background/background.component.d.ts +20 -0
- package/lib/vflow/components/node/node.component.d.ts +4 -13
- package/lib/vflow/components/vflow/vflow.component.d.ts +9 -2
- package/lib/vflow/directives/connection-controller.directive.d.ts +6 -0
- package/lib/vflow/directives/space-point-context.directive.d.ts +1 -0
- package/lib/vflow/interfaces/connection-settings.interface.d.ts +2 -0
- package/lib/vflow/interfaces/connection.internal.interface.d.ts +8 -0
- package/lib/vflow/models/connection.model.d.ts +5 -2
- package/lib/vflow/models/edge.model.d.ts +1 -17
- package/lib/vflow/models/handle.model.d.ts +1 -1
- package/lib/vflow/services/flow-status.service.d.ts +7 -18
- package/lib/vflow/types/background.type.d.ts +24 -0
- package/lib/vflow/types/connection-mode.type.d.ts +1 -0
- package/lib/vflow/utils/adjust-direction.d.ts +11 -0
- package/lib/vflow/utils/id.d.ts +1 -0
- package/lib/vflow/utils/resizable.d.ts +1 -2
- package/lib/vflow/vflow.module.d.ts +12 -11
- package/package.json +1 -1
- package/public-api.d.ts +2 -0
package/fesm2022/ngx-vflow.mjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
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, Injectable, inject, ElementRef, Directive, computed, effect, untracked, Input, TemplateRef, EventEmitter, Output, DestroyRef, runInInjectionContext,
|
|
4
|
+
import { signal, Injectable, inject, ElementRef, Directive, computed, effect, untracked, Input, TemplateRef, EventEmitter, Output, DestroyRef, runInInjectionContext, Injector, Component, ChangeDetectionStrategy, HostListener, ViewChild, ContentChild, NgModule } from '@angular/core';
|
|
5
5
|
import { select } from 'd3-selection';
|
|
6
6
|
import { zoomIdentity, zoom } from 'd3-zoom';
|
|
7
|
-
import { Subject, tap, merge, BehaviorSubject, observeOn, animationFrameScheduler, switchMap, skip, map, pairwise, filter, distinctUntilChanged, asyncScheduler, zip,
|
|
7
|
+
import { Subject, tap, merge, BehaviorSubject, observeOn, animationFrameScheduler, switchMap, skip, map, pairwise, filter, distinctUntilChanged, asyncScheduler, zip, fromEvent, share, Observable, startWith } from 'rxjs';
|
|
8
8
|
import { takeUntilDestroyed, toSignal, toObservable } from '@angular/core/rxjs-interop';
|
|
9
9
|
import { drag } from 'd3-drag';
|
|
10
10
|
import { path } from 'd3-path';
|
|
@@ -59,13 +59,35 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
|
|
|
59
59
|
}] });
|
|
60
60
|
|
|
61
61
|
class ConnectionModel {
|
|
62
|
-
constructor(
|
|
63
|
-
this.
|
|
64
|
-
this.curve =
|
|
65
|
-
this.type =
|
|
66
|
-
this.
|
|
62
|
+
constructor(settings) {
|
|
63
|
+
this.settings = settings;
|
|
64
|
+
this.curve = settings.curve ?? 'bezier';
|
|
65
|
+
this.type = settings.type ?? 'default';
|
|
66
|
+
this.mode = settings.mode ?? 'strict';
|
|
67
|
+
const validatorsToRun = this.getValidators(settings);
|
|
68
|
+
this.validator = (connection) => validatorsToRun.every((v) => v(connection));
|
|
69
|
+
}
|
|
70
|
+
getValidators(settings) {
|
|
71
|
+
const validators = [];
|
|
72
|
+
validators.push(notSelfValidator);
|
|
73
|
+
if (this.mode === 'loose') {
|
|
74
|
+
validators.push(hasSourceAndTargetHandleValidator);
|
|
75
|
+
}
|
|
76
|
+
if (settings.validator) {
|
|
77
|
+
validators.push(settings.validator);
|
|
78
|
+
}
|
|
79
|
+
return validators;
|
|
67
80
|
}
|
|
68
81
|
}
|
|
82
|
+
/**
|
|
83
|
+
* Internal validator that not allows self connections
|
|
84
|
+
*/
|
|
85
|
+
const notSelfValidator = (connection) => {
|
|
86
|
+
return connection.source !== connection.target;
|
|
87
|
+
};
|
|
88
|
+
const hasSourceAndTargetHandleValidator = (connection) => {
|
|
89
|
+
return connection.sourceHandle !== undefined && connection.targetHandle !== undefined;
|
|
90
|
+
};
|
|
69
91
|
|
|
70
92
|
function hashCode(str) {
|
|
71
93
|
return str.split('').reduce((a, b) => {
|
|
@@ -97,7 +119,7 @@ class FlowEntitiesService {
|
|
|
97
119
|
markersMap.set(hash, e.edge.markers.end);
|
|
98
120
|
}
|
|
99
121
|
});
|
|
100
|
-
const connectionMarker = this.connection().
|
|
122
|
+
const connectionMarker = this.connection().settings.marker;
|
|
101
123
|
if (connectionMarker) {
|
|
102
124
|
const hash = hashCode(JSON.stringify(connectionMarker));
|
|
103
125
|
markersMap.set(hash, connectionMarker);
|
|
@@ -385,14 +407,14 @@ class FlowStatusService {
|
|
|
385
407
|
setIdleStatus() {
|
|
386
408
|
this.status.set({ state: 'idle', payload: null });
|
|
387
409
|
}
|
|
388
|
-
setConnectionStartStatus(
|
|
389
|
-
this.status.set({ state: 'connection-start', payload: {
|
|
410
|
+
setConnectionStartStatus(source, sourceHandle) {
|
|
411
|
+
this.status.set({ state: 'connection-start', payload: { source, sourceHandle } });
|
|
390
412
|
}
|
|
391
|
-
setConnectionValidationStatus(valid,
|
|
392
|
-
this.status.set({ state: 'connection-validation', payload: {
|
|
413
|
+
setConnectionValidationStatus(valid, source, target, sourceHandle, targetHandle) {
|
|
414
|
+
this.status.set({ state: 'connection-validation', payload: { source, target, sourceHandle, targetHandle, valid } });
|
|
393
415
|
}
|
|
394
|
-
setConnectionEndStatus(
|
|
395
|
-
this.status.set({ state: 'connection-end', payload: {
|
|
416
|
+
setConnectionEndStatus(source, target, sourceHandle, targetHandle) {
|
|
417
|
+
this.status.set({ state: 'connection-end', payload: { source, target, sourceHandle, targetHandle } });
|
|
396
418
|
}
|
|
397
419
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FlowStatusService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
398
420
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FlowStatusService }); }
|
|
@@ -415,6 +437,36 @@ function batchStatusChanges(...changes) {
|
|
|
415
437
|
}
|
|
416
438
|
}
|
|
417
439
|
|
|
440
|
+
/**
|
|
441
|
+
* This function contains a hack-y behavior.
|
|
442
|
+
* If the handles are of the same type (source-source or target-target),
|
|
443
|
+
* it returns nodes where source === target and
|
|
444
|
+
* handles where sourceHandle === targetHandle
|
|
445
|
+
*
|
|
446
|
+
* This leads to that notSelfValidator returns false for these cases,
|
|
447
|
+
* exactly what we need for strict connection type
|
|
448
|
+
*/
|
|
449
|
+
function adjustDirection(connection) {
|
|
450
|
+
const result = {};
|
|
451
|
+
if (connection.sourceHandle.rawHandle.type === 'source') {
|
|
452
|
+
result.source = connection.source;
|
|
453
|
+
result.sourceHandle = connection.sourceHandle;
|
|
454
|
+
}
|
|
455
|
+
else {
|
|
456
|
+
result.source = connection.target;
|
|
457
|
+
result.sourceHandle = connection.targetHandle;
|
|
458
|
+
}
|
|
459
|
+
if (connection.targetHandle.rawHandle.type === 'target') {
|
|
460
|
+
result.target = connection.target;
|
|
461
|
+
result.targetHandle = connection.targetHandle;
|
|
462
|
+
}
|
|
463
|
+
else {
|
|
464
|
+
result.target = connection.source;
|
|
465
|
+
result.targetHandle = connection.sourceHandle;
|
|
466
|
+
}
|
|
467
|
+
return result;
|
|
468
|
+
}
|
|
469
|
+
|
|
418
470
|
class ConnectionControllerDirective {
|
|
419
471
|
constructor() {
|
|
420
472
|
/**
|
|
@@ -431,18 +483,96 @@ class ConnectionControllerDirective {
|
|
|
431
483
|
this.connectEffect = effect(() => {
|
|
432
484
|
const status = this.statusService.status();
|
|
433
485
|
if (status.state === 'connection-end') {
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
486
|
+
let source = status.payload.source;
|
|
487
|
+
let target = status.payload.target;
|
|
488
|
+
let sourceHandle = status.payload.sourceHandle;
|
|
489
|
+
let targetHandle = status.payload.targetHandle;
|
|
490
|
+
if (this.isStrictMode()) {
|
|
491
|
+
const adjusted = adjustDirection({
|
|
492
|
+
source: status.payload.source,
|
|
493
|
+
sourceHandle: status.payload.sourceHandle,
|
|
494
|
+
target: status.payload.target,
|
|
495
|
+
targetHandle: status.payload.targetHandle
|
|
496
|
+
});
|
|
497
|
+
source = adjusted.source;
|
|
498
|
+
target = adjusted.target;
|
|
499
|
+
sourceHandle = adjusted.sourceHandle;
|
|
500
|
+
targetHandle = adjusted.targetHandle;
|
|
501
|
+
}
|
|
502
|
+
const sourceId = source.node.id;
|
|
503
|
+
const targetId = target.node.id;
|
|
504
|
+
const sourceHandleId = sourceHandle.rawHandle.id;
|
|
505
|
+
const targetHandleId = targetHandle.rawHandle.id;
|
|
506
|
+
const connectionModel = this.flowEntitiesService.connection();
|
|
507
|
+
const connection = {
|
|
508
|
+
source: sourceId, target: targetId,
|
|
509
|
+
sourceHandle: sourceHandleId, targetHandle: targetHandleId
|
|
510
|
+
};
|
|
511
|
+
if (connectionModel.validator(connection)) {
|
|
512
|
+
this.onConnect.emit(connection);
|
|
443
513
|
}
|
|
444
514
|
}
|
|
445
515
|
}, { allowSignalWrites: true });
|
|
516
|
+
this.isStrictMode = computed(() => this.flowEntitiesService.connection().mode === 'strict');
|
|
517
|
+
}
|
|
518
|
+
startConnection(handle) {
|
|
519
|
+
this.statusService.setConnectionStartStatus(handle.parentNode, handle);
|
|
520
|
+
}
|
|
521
|
+
validateConnection(handle) {
|
|
522
|
+
const status = this.statusService.status();
|
|
523
|
+
if (status.state === 'connection-start') {
|
|
524
|
+
let source = status.payload.source;
|
|
525
|
+
let target = handle.parentNode;
|
|
526
|
+
let sourceHandle = status.payload.sourceHandle;
|
|
527
|
+
let targetHandle = handle;
|
|
528
|
+
if (this.isStrictMode()) {
|
|
529
|
+
// swap direction (if needed) according to actual source and target of strict mode
|
|
530
|
+
const adjusted = adjustDirection({
|
|
531
|
+
source: status.payload.source,
|
|
532
|
+
sourceHandle: status.payload.sourceHandle,
|
|
533
|
+
target: handle.parentNode,
|
|
534
|
+
targetHandle: handle
|
|
535
|
+
});
|
|
536
|
+
source = adjusted.source;
|
|
537
|
+
target = adjusted.target;
|
|
538
|
+
sourceHandle = adjusted.sourceHandle;
|
|
539
|
+
targetHandle = adjusted.targetHandle;
|
|
540
|
+
}
|
|
541
|
+
const valid = this.flowEntitiesService.connection().validator({
|
|
542
|
+
source: source.node.id,
|
|
543
|
+
target: target.node.id,
|
|
544
|
+
sourceHandle: sourceHandle.rawHandle.id,
|
|
545
|
+
targetHandle: targetHandle.rawHandle.id
|
|
546
|
+
});
|
|
547
|
+
// TODO: check how react flow handles highlight of handle
|
|
548
|
+
// if direction changes
|
|
549
|
+
handle.state.set(valid ? 'valid' : 'invalid');
|
|
550
|
+
// status is about how we draw connection, so we don't need
|
|
551
|
+
// swapped diretion here
|
|
552
|
+
this.statusService.setConnectionValidationStatus(valid, status.payload.source, handle.parentNode, status.payload.sourceHandle, handle);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
resetValidateConnection(targetHandle) {
|
|
556
|
+
targetHandle.state.set('idle');
|
|
557
|
+
// drop back to start status
|
|
558
|
+
const status = this.statusService.status();
|
|
559
|
+
if (status.state === 'connection-validation') {
|
|
560
|
+
this.statusService.setConnectionStartStatus(status.payload.source, status.payload.sourceHandle);
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
endConnection(handle) {
|
|
564
|
+
const status = this.statusService.status();
|
|
565
|
+
if (status.state === 'connection-validation') {
|
|
566
|
+
const source = status.payload.source;
|
|
567
|
+
const sourceHandle = status.payload.sourceHandle;
|
|
568
|
+
const target = status.payload.target;
|
|
569
|
+
const targetHandle = status.payload.targetHandle;
|
|
570
|
+
batchStatusChanges(
|
|
571
|
+
// call to create connection
|
|
572
|
+
() => this.statusService.setConnectionEndStatus(source, target, sourceHandle, targetHandle),
|
|
573
|
+
// when connection created, we need go back to idle status
|
|
574
|
+
() => this.statusService.setIdleStatus());
|
|
575
|
+
}
|
|
446
576
|
}
|
|
447
577
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: ConnectionControllerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
448
578
|
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: ConnectionControllerDirective, isStandalone: true, selector: "[connectionController]", outputs: { onConnect: "onConnect" }, ngImport: i0 }); }
|
|
@@ -1040,6 +1170,79 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
|
|
|
1040
1170
|
type: Injectable
|
|
1041
1171
|
}] });
|
|
1042
1172
|
|
|
1173
|
+
class RootPointerDirective {
|
|
1174
|
+
constructor() {
|
|
1175
|
+
this.host = inject(ElementRef).nativeElement;
|
|
1176
|
+
this.initialTouch$ = new Subject();
|
|
1177
|
+
// TODO: do not emit if mouse not down
|
|
1178
|
+
this.mouseMovement$ = fromEvent(this.host, 'mousemove').pipe(map(event => ({
|
|
1179
|
+
x: event.clientX,
|
|
1180
|
+
y: event.clientY,
|
|
1181
|
+
originalEvent: event
|
|
1182
|
+
})), observeOn(animationFrameScheduler), share());
|
|
1183
|
+
this.touchMovement$ = merge(this.initialTouch$, fromEvent(this.host, 'touchmove')).pipe(tap((event) => event.preventDefault()), map((originalEvent) => {
|
|
1184
|
+
const x = originalEvent.touches[0]?.clientX ?? 0;
|
|
1185
|
+
const y = originalEvent.touches[0]?.clientY ?? 0;
|
|
1186
|
+
const target = document.elementFromPoint(x, y);
|
|
1187
|
+
return { x, y, target, originalEvent };
|
|
1188
|
+
}), observeOn(animationFrameScheduler), share());
|
|
1189
|
+
this.touchEnd$ = fromEvent(this.host, 'touchend').pipe(map((originalEvent) => {
|
|
1190
|
+
const x = originalEvent.changedTouches[0]?.clientX ?? 0;
|
|
1191
|
+
const y = originalEvent.changedTouches[0]?.clientY ?? 0;
|
|
1192
|
+
const target = document.elementFromPoint(x, y);
|
|
1193
|
+
return { x, y, target, originalEvent };
|
|
1194
|
+
}), share());
|
|
1195
|
+
this.pointerMovement$ = merge(this.mouseMovement$, this.touchMovement$);
|
|
1196
|
+
}
|
|
1197
|
+
/**
|
|
1198
|
+
* We should know when user started a touch in order to not
|
|
1199
|
+
* show old touch position when connection creation is started
|
|
1200
|
+
*/
|
|
1201
|
+
setInitialTouch(event) {
|
|
1202
|
+
this.initialTouch$.next(event);
|
|
1203
|
+
}
|
|
1204
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RootPointerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1205
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: RootPointerDirective, selector: "svg[rootPointer]", ngImport: i0 }); }
|
|
1206
|
+
}
|
|
1207
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RootPointerDirective, decorators: [{
|
|
1208
|
+
type: Directive,
|
|
1209
|
+
args: [{ selector: 'svg[rootPointer]' }]
|
|
1210
|
+
}] });
|
|
1211
|
+
|
|
1212
|
+
class SpacePointContextDirective {
|
|
1213
|
+
constructor() {
|
|
1214
|
+
this.pointerMovementDirective = inject(RootPointerDirective);
|
|
1215
|
+
this.rootSvg = inject(RootSvgReferenceDirective).element;
|
|
1216
|
+
this.host = inject(ElementRef).nativeElement;
|
|
1217
|
+
/**
|
|
1218
|
+
* Signal with current mouse position in svg space
|
|
1219
|
+
*/
|
|
1220
|
+
this.svgCurrentSpacePoint = computed(() => {
|
|
1221
|
+
const movement = this.pointerMovement();
|
|
1222
|
+
if (!movement) {
|
|
1223
|
+
return { x: 0, y: 0 };
|
|
1224
|
+
}
|
|
1225
|
+
return this.documentPointToFlowPoint({
|
|
1226
|
+
x: movement.x,
|
|
1227
|
+
y: movement.y
|
|
1228
|
+
});
|
|
1229
|
+
});
|
|
1230
|
+
this.pointerMovement = toSignal(this.pointerMovementDirective.pointerMovement$);
|
|
1231
|
+
}
|
|
1232
|
+
documentPointToFlowPoint(documentPoint) {
|
|
1233
|
+
const point = this.rootSvg.createSVGPoint();
|
|
1234
|
+
point.x = documentPoint.x;
|
|
1235
|
+
point.y = documentPoint.y;
|
|
1236
|
+
return point.matrixTransform(this.host.getScreenCTM().inverse());
|
|
1237
|
+
}
|
|
1238
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SpacePointContextDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1239
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: SpacePointContextDirective, selector: "g[spacePointContext]", ngImport: i0 }); }
|
|
1240
|
+
}
|
|
1241
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SpacePointContextDirective, decorators: [{
|
|
1242
|
+
type: Directive,
|
|
1243
|
+
args: [{ selector: 'g[spacePointContext]' }]
|
|
1244
|
+
}] });
|
|
1245
|
+
|
|
1043
1246
|
class HandleService {
|
|
1044
1247
|
constructor() {
|
|
1045
1248
|
this.node = signal(null);
|
|
@@ -1063,6 +1266,44 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
|
|
|
1063
1266
|
type: Injectable
|
|
1064
1267
|
}] });
|
|
1065
1268
|
|
|
1269
|
+
function resizable(elems) {
|
|
1270
|
+
return new Observable((subscriber) => {
|
|
1271
|
+
let ro = new ResizeObserver((entries) => {
|
|
1272
|
+
subscriber.next(entries);
|
|
1273
|
+
});
|
|
1274
|
+
elems.forEach(e => ro.observe(e));
|
|
1275
|
+
return () => ro.disconnect();
|
|
1276
|
+
});
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1279
|
+
function InjectionContext(target, key, descriptor) {
|
|
1280
|
+
const originalMethod = descriptor.value;
|
|
1281
|
+
descriptor.value = function (...args) {
|
|
1282
|
+
if (implementsWithInjector(this)) {
|
|
1283
|
+
return runInInjectionContext(this.injector, () => originalMethod.apply(this, args));
|
|
1284
|
+
}
|
|
1285
|
+
else {
|
|
1286
|
+
throw new Error('Class that contains decorated method must extends WithInjectorDirective class');
|
|
1287
|
+
}
|
|
1288
|
+
};
|
|
1289
|
+
// Return the modified descriptor
|
|
1290
|
+
return descriptor;
|
|
1291
|
+
}
|
|
1292
|
+
const implementsWithInjector = (instance) => {
|
|
1293
|
+
return 'injector' in instance && 'get' in instance.injector;
|
|
1294
|
+
};
|
|
1295
|
+
|
|
1296
|
+
function Microtask(target, key, descriptor) {
|
|
1297
|
+
const originalMethod = descriptor.value;
|
|
1298
|
+
descriptor.value = function (...args) {
|
|
1299
|
+
queueMicrotask(() => {
|
|
1300
|
+
originalMethod?.apply(this, args);
|
|
1301
|
+
});
|
|
1302
|
+
};
|
|
1303
|
+
// Return the modified descriptor
|
|
1304
|
+
return descriptor;
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1066
1307
|
class HandleModel {
|
|
1067
1308
|
constructor(rawHandle, parentNode) {
|
|
1068
1309
|
this.rawHandle = rawHandle;
|
|
@@ -1138,43 +1379,46 @@ class HandleModel {
|
|
|
1138
1379
|
}
|
|
1139
1380
|
}
|
|
1140
1381
|
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
}
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
}
|
|
1164
|
-
const implementsWithInjector = (instance) => {
|
|
1165
|
-
return 'injector' in instance && 'get' in instance.injector;
|
|
1166
|
-
};
|
|
1167
|
-
|
|
1168
|
-
function Microtask(target, key, descriptor) {
|
|
1169
|
-
const originalMethod = descriptor.value;
|
|
1170
|
-
descriptor.value = function (...args) {
|
|
1171
|
-
queueMicrotask(() => {
|
|
1172
|
-
originalMethod?.apply(this, args);
|
|
1173
|
-
});
|
|
1174
|
-
};
|
|
1175
|
-
// Return the modified descriptor
|
|
1176
|
-
return descriptor;
|
|
1382
|
+
class HandleComponent {
|
|
1383
|
+
constructor() {
|
|
1384
|
+
this.injector = inject(Injector);
|
|
1385
|
+
this.handleService = inject(HandleService);
|
|
1386
|
+
this.element = inject(ElementRef).nativeElement;
|
|
1387
|
+
}
|
|
1388
|
+
ngOnInit() {
|
|
1389
|
+
this.model = new HandleModel({
|
|
1390
|
+
position: this.position,
|
|
1391
|
+
type: this.type,
|
|
1392
|
+
id: this.id,
|
|
1393
|
+
parentReference: this.element.parentElement,
|
|
1394
|
+
template: this.template
|
|
1395
|
+
}, this.handleService.node());
|
|
1396
|
+
this.handleService.createHandle(this.model);
|
|
1397
|
+
requestAnimationFrame(() => this.model.updateParent());
|
|
1398
|
+
}
|
|
1399
|
+
ngOnDestroy() {
|
|
1400
|
+
this.handleService.destroyHandle(this.model);
|
|
1401
|
+
}
|
|
1402
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HandleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1403
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: HandleComponent, selector: "handle", inputs: { position: "position", type: "type", id: "id", template: "template" }, ngImport: i0, template: "", changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
1177
1404
|
}
|
|
1405
|
+
__decorate([
|
|
1406
|
+
InjectionContext
|
|
1407
|
+
], HandleComponent.prototype, "ngOnInit", null);
|
|
1408
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HandleComponent, decorators: [{
|
|
1409
|
+
type: Component,
|
|
1410
|
+
args: [{ selector: 'handle', changeDetection: ChangeDetectionStrategy.OnPush, template: "" }]
|
|
1411
|
+
}], propDecorators: { position: [{
|
|
1412
|
+
type: Input,
|
|
1413
|
+
args: [{ required: true }]
|
|
1414
|
+
}], type: [{
|
|
1415
|
+
type: Input,
|
|
1416
|
+
args: [{ required: true }]
|
|
1417
|
+
}], id: [{
|
|
1418
|
+
type: Input
|
|
1419
|
+
}], template: [{
|
|
1420
|
+
type: Input
|
|
1421
|
+
}], ngOnInit: [] } });
|
|
1178
1422
|
|
|
1179
1423
|
class HandleSizeControllerDirective {
|
|
1180
1424
|
constructor() {
|
|
@@ -1212,45 +1456,6 @@ function getChildStrokeWidth(element) {
|
|
|
1212
1456
|
return 0;
|
|
1213
1457
|
}
|
|
1214
1458
|
|
|
1215
|
-
class RootPointerDirective {
|
|
1216
|
-
constructor() {
|
|
1217
|
-
this.host = inject(ElementRef).nativeElement;
|
|
1218
|
-
this.initialTouch$ = new Subject();
|
|
1219
|
-
// TODO: do not emit if mouse not down
|
|
1220
|
-
this.mouseMovement$ = fromEvent(this.host, 'mousemove').pipe(map(event => ({
|
|
1221
|
-
x: event.clientX,
|
|
1222
|
-
y: event.clientY,
|
|
1223
|
-
originalEvent: event
|
|
1224
|
-
})), observeOn(animationFrameScheduler), share());
|
|
1225
|
-
this.touchMovement$ = merge(this.initialTouch$, fromEvent(this.host, 'touchmove')).pipe(tap((event) => event.preventDefault()), map((originalEvent) => {
|
|
1226
|
-
const x = originalEvent.touches[0]?.clientX ?? 0;
|
|
1227
|
-
const y = originalEvent.touches[0]?.clientY ?? 0;
|
|
1228
|
-
const target = document.elementFromPoint(x, y);
|
|
1229
|
-
return { x, y, target, originalEvent };
|
|
1230
|
-
}), observeOn(animationFrameScheduler), share());
|
|
1231
|
-
this.touchEnd$ = fromEvent(this.host, 'touchend').pipe(map((originalEvent) => {
|
|
1232
|
-
const x = originalEvent.changedTouches[0]?.clientX ?? 0;
|
|
1233
|
-
const y = originalEvent.changedTouches[0]?.clientY ?? 0;
|
|
1234
|
-
const target = document.elementFromPoint(x, y);
|
|
1235
|
-
return { x, y, target, originalEvent };
|
|
1236
|
-
}), share());
|
|
1237
|
-
this.pointerMovement$ = merge(this.mouseMovement$, this.touchMovement$);
|
|
1238
|
-
}
|
|
1239
|
-
/**
|
|
1240
|
-
* We should know when user started a touch in order to not
|
|
1241
|
-
* show old touch position when connection creation is started
|
|
1242
|
-
*/
|
|
1243
|
-
setInitialTouch(event) {
|
|
1244
|
-
this.initialTouch$.next(event);
|
|
1245
|
-
}
|
|
1246
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RootPointerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1247
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: RootPointerDirective, selector: "svg[rootPointer]", ngImport: i0 }); }
|
|
1248
|
-
}
|
|
1249
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RootPointerDirective, decorators: [{
|
|
1250
|
-
type: Directive,
|
|
1251
|
-
args: [{ selector: 'svg[rootPointer]' }]
|
|
1252
|
-
}] });
|
|
1253
|
-
|
|
1254
1459
|
class PointerDirective {
|
|
1255
1460
|
constructor() {
|
|
1256
1461
|
this.hostElement = inject(ElementRef).nativeElement;
|
|
@@ -1334,31 +1539,29 @@ class NodeComponent {
|
|
|
1334
1539
|
constructor() {
|
|
1335
1540
|
this.injector = inject(Injector);
|
|
1336
1541
|
this.handleService = inject(HandleService);
|
|
1337
|
-
this.zone = inject(NgZone);
|
|
1338
1542
|
this.draggableService = inject(DraggableService);
|
|
1339
1543
|
this.flowStatusService = inject(FlowStatusService);
|
|
1340
|
-
this.flowEntitiesService = inject(FlowEntitiesService);
|
|
1341
1544
|
this.nodeRenderingService = inject(NodeRenderingService);
|
|
1342
1545
|
this.flowSettingsService = inject(FlowSettingsService);
|
|
1343
1546
|
this.selectionService = inject(SelectionService);
|
|
1344
1547
|
this.hostRef = inject(ElementRef);
|
|
1548
|
+
this.connectionController = inject(ConnectionControllerDirective);
|
|
1345
1549
|
this.showMagnet = computed(() => this.flowStatusService.status().state === 'connection-start' ||
|
|
1346
1550
|
this.flowStatusService.status().state === 'connection-validation');
|
|
1347
1551
|
this.styleWidth = computed(() => `${this.nodeModel.size().width}px`);
|
|
1348
1552
|
this.styleHeight = computed(() => `${this.nodeModel.size().height}px`);
|
|
1349
|
-
this.subscription = new Subscription();
|
|
1350
1553
|
}
|
|
1351
1554
|
ngOnInit() {
|
|
1352
1555
|
this.handleService.node.set(this.nodeModel);
|
|
1353
1556
|
this.draggableService.toggleDraggable(this.hostRef.nativeElement, this.nodeModel);
|
|
1354
|
-
|
|
1355
|
-
.pipe(switchMap((handles) => resizable(handles.map(h => h.parentReference),
|
|
1356
|
-
|
|
1557
|
+
this.nodeModel.handles$
|
|
1558
|
+
.pipe(switchMap((handles) => resizable(handles.map(h => h.parentReference)).pipe(map(() => handles))), tap((handles) => {
|
|
1559
|
+
// TODO (performance) inspect how to avoid calls of this when flow initially rendered
|
|
1560
|
+
handles.forEach(h => h.updateParent());
|
|
1561
|
+
}), takeUntilDestroyed())
|
|
1357
1562
|
.subscribe();
|
|
1358
|
-
this.subscription.add(sub);
|
|
1359
1563
|
}
|
|
1360
1564
|
ngAfterViewInit() {
|
|
1361
|
-
this.setInitialHandles();
|
|
1362
1565
|
if (this.nodeModel.node.type === 'default') {
|
|
1363
1566
|
this.nodeModel.size.set({
|
|
1364
1567
|
width: this.nodeModel.node.width ?? NodeModel.defaultTypeSize.width,
|
|
@@ -1366,69 +1569,30 @@ class NodeComponent {
|
|
|
1366
1569
|
});
|
|
1367
1570
|
}
|
|
1368
1571
|
if (this.nodeModel.node.type === 'html-template' || this.nodeModel.isComponentType) {
|
|
1369
|
-
|
|
1572
|
+
resizable([this.htmlWrapperRef.nativeElement])
|
|
1370
1573
|
.pipe(startWith(null), tap(() => {
|
|
1371
1574
|
const width = this.htmlWrapperRef.nativeElement.clientWidth;
|
|
1372
1575
|
const height = this.htmlWrapperRef.nativeElement.clientHeight;
|
|
1373
1576
|
this.nodeModel.size.set({ width, height });
|
|
1374
|
-
})).subscribe();
|
|
1375
|
-
this.subscription.add(sub);
|
|
1577
|
+
}), takeUntilDestroyed()).subscribe();
|
|
1376
1578
|
}
|
|
1377
1579
|
}
|
|
1378
1580
|
ngOnDestroy() {
|
|
1379
1581
|
this.draggableService.destroy(this.hostRef.nativeElement);
|
|
1380
|
-
this.subscription.unsubscribe();
|
|
1381
1582
|
}
|
|
1382
1583
|
startConnection(event, handle) {
|
|
1383
1584
|
// ignore drag by stopping propagation
|
|
1384
1585
|
event.stopPropagation();
|
|
1385
|
-
this.
|
|
1586
|
+
this.connectionController.startConnection(handle);
|
|
1386
1587
|
}
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
if (status.state === 'connection-validation') {
|
|
1390
|
-
const sourceNode = status.payload.sourceNode;
|
|
1391
|
-
const targetNode = this.nodeModel;
|
|
1392
|
-
const sourceHandle = status.payload.sourceHandle;
|
|
1393
|
-
const targetHandle = status.payload.targetHandle;
|
|
1394
|
-
batchStatusChanges(
|
|
1395
|
-
// call to create connection
|
|
1396
|
-
() => this.flowStatusService.setConnectionEndStatus(sourceNode, targetNode, sourceHandle, targetHandle),
|
|
1397
|
-
// when connection created, we need go back to idle status
|
|
1398
|
-
() => this.flowStatusService.setIdleStatus());
|
|
1399
|
-
}
|
|
1588
|
+
validateConnection(handle) {
|
|
1589
|
+
this.connectionController.validateConnection(handle);
|
|
1400
1590
|
}
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
*/
|
|
1404
|
-
validateTargetHandle(targetHandle) {
|
|
1405
|
-
const status = this.flowStatusService.status();
|
|
1406
|
-
if (status.state === 'connection-start') {
|
|
1407
|
-
const sourceNode = status.payload.sourceNode;
|
|
1408
|
-
const sourceHandle = status.payload.sourceHandle;
|
|
1409
|
-
const source = sourceNode.node.id;
|
|
1410
|
-
const targetNode = this.nodeModel;
|
|
1411
|
-
const target = targetNode.node.id;
|
|
1412
|
-
const valid = this.flowEntitiesService.connection().validator({
|
|
1413
|
-
source,
|
|
1414
|
-
target,
|
|
1415
|
-
sourceHandle: sourceHandle.rawHandle.id,
|
|
1416
|
-
targetHandle: targetHandle.rawHandle.id
|
|
1417
|
-
});
|
|
1418
|
-
targetHandle.state.set(valid ? 'valid' : 'invalid');
|
|
1419
|
-
this.flowStatusService.setConnectionValidationStatus(valid, sourceNode, targetNode, sourceHandle, targetHandle);
|
|
1420
|
-
}
|
|
1591
|
+
resetValidateConnection(targetHandle) {
|
|
1592
|
+
this.connectionController.resetValidateConnection(targetHandle);
|
|
1421
1593
|
}
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
*/
|
|
1425
|
-
resetValidateTargetHandle(targetHandle) {
|
|
1426
|
-
targetHandle.state.set('idle');
|
|
1427
|
-
// drop back to start status
|
|
1428
|
-
const status = this.flowStatusService.status();
|
|
1429
|
-
if (status.state === 'connection-validation') {
|
|
1430
|
-
this.flowStatusService.setConnectionStartStatus(status.payload.sourceNode, status.payload.sourceHandle);
|
|
1431
|
-
}
|
|
1594
|
+
endConnection(handle) {
|
|
1595
|
+
this.connectionController.endConnection(handle);
|
|
1432
1596
|
}
|
|
1433
1597
|
pullNode() {
|
|
1434
1598
|
this.nodeRenderingService.pullNode(this.nodeModel);
|
|
@@ -1438,32 +1602,20 @@ class NodeComponent {
|
|
|
1438
1602
|
this.selectionService.select(this.nodeModel);
|
|
1439
1603
|
}
|
|
1440
1604
|
}
|
|
1441
|
-
setInitialHandles() {
|
|
1442
|
-
if (this.nodeModel.node.type === 'default') {
|
|
1443
|
-
this.handleService.createHandle(new HandleModel({
|
|
1444
|
-
position: this.nodeModel.sourcePosition(),
|
|
1445
|
-
type: 'source',
|
|
1446
|
-
parentReference: this.htmlWrapperRef.nativeElement
|
|
1447
|
-
}, this.nodeModel));
|
|
1448
|
-
this.handleService.createHandle(new HandleModel({
|
|
1449
|
-
position: this.nodeModel.targetPosition(),
|
|
1450
|
-
type: 'target',
|
|
1451
|
-
parentReference: this.htmlWrapperRef.nativeElement
|
|
1452
|
-
}, this.nodeModel));
|
|
1453
|
-
}
|
|
1454
|
-
}
|
|
1455
1605
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NodeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1456
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: NodeComponent, selector: "g[node]", inputs: { nodeModel: "nodeModel", nodeHtmlTemplate: "nodeHtmlTemplate" }, providers: [HandleService], viewQueries: [{ propertyName: "nodeContentRef", first: true, predicate: ["nodeContent"], descendants: true }, { propertyName: "htmlWrapperRef", first: true, predicate: ["htmlWrapper"], descendants: true }], ngImport: i0, template: "<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 [
|
|
1606
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: NodeComponent, selector: "g[node]", inputs: { nodeModel: "nodeModel", nodeHtmlTemplate: "nodeHtmlTemplate" }, providers: [HandleService], viewQueries: [{ propertyName: "nodeContentRef", first: true, predicate: ["nodeContent"], descendants: true }, { propertyName: "htmlWrapperRef", first: true, predicate: ["htmlWrapper"], descendants: true }], ngImport: i0, template: "<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.node.text ?? ''\"></div>\n\n <handle type=\"source\" [position]=\"nodeModel.sourcePosition()\" />\n <handle type=\"target\" [position]=\"nodeModel.targetPosition()\" />\n </div>\n</svg:foreignObject>\n\n<svg:foreignObject\n *ngIf=\"nodeModel.node.type === 'html-template' && nodeHtmlTemplate\"\n class=\"selectable\"\n [attr.width]=\"nodeModel.size().width\"\n [attr.height]=\"nodeModel.size().height\"\n (mousedown)=\"pullNode()\"\n>\n <div #htmlWrapper class=\"wrapper\">\n <ng-container\n [ngTemplateOutlet]=\"nodeHtmlTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: { node: nodeModel.node, selected: nodeModel.selected } }\"\n [ngTemplateOutletInjector]=\"injector\"\n />\n </div>\n</svg:foreignObject>\n\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 #htmlWrapper class=\"wrapper\">\n <ng-container\n [ngComponentOutlet]=\"$any(nodeModel.node.type)\"\n [ngComponentOutletInputs]=\"nodeModel.componentTypeInputs()\"\n [ngComponentOutletInjector]=\"injector\"\n />\n </div>\n</svg:foreignObject>\n\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: [".wrapper{width:max-content}.magnet{opacity:0}.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-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: "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 }); }
|
|
1457
1607
|
}
|
|
1458
1608
|
__decorate([
|
|
1459
|
-
|
|
1460
|
-
], NodeComponent.prototype, "
|
|
1609
|
+
InjectionContext
|
|
1610
|
+
], NodeComponent.prototype, "ngOnInit", null);
|
|
1461
1611
|
__decorate([
|
|
1612
|
+
Microtask // TODO (performance) check if we need microtask here
|
|
1613
|
+
,
|
|
1462
1614
|
InjectionContext
|
|
1463
|
-
], NodeComponent.prototype, "
|
|
1615
|
+
], NodeComponent.prototype, "ngAfterViewInit", null);
|
|
1464
1616
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NodeComponent, decorators: [{
|
|
1465
1617
|
type: Component,
|
|
1466
|
-
args: [{ selector: 'g[node]', changeDetection: ChangeDetectionStrategy.OnPush, providers: [HandleService], template: "<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 [
|
|
1618
|
+
args: [{ selector: 'g[node]', changeDetection: ChangeDetectionStrategy.OnPush, providers: [HandleService], template: "<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.node.text ?? ''\"></div>\n\n <handle type=\"source\" [position]=\"nodeModel.sourcePosition()\" />\n <handle type=\"target\" [position]=\"nodeModel.targetPosition()\" />\n </div>\n</svg:foreignObject>\n\n<svg:foreignObject\n *ngIf=\"nodeModel.node.type === 'html-template' && nodeHtmlTemplate\"\n class=\"selectable\"\n [attr.width]=\"nodeModel.size().width\"\n [attr.height]=\"nodeModel.size().height\"\n (mousedown)=\"pullNode()\"\n>\n <div #htmlWrapper class=\"wrapper\">\n <ng-container\n [ngTemplateOutlet]=\"nodeHtmlTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: { node: nodeModel.node, selected: nodeModel.selected } }\"\n [ngTemplateOutletInjector]=\"injector\"\n />\n </div>\n</svg:foreignObject>\n\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 #htmlWrapper class=\"wrapper\">\n <ng-container\n [ngComponentOutlet]=\"$any(nodeModel.node.type)\"\n [ngComponentOutletInputs]=\"nodeModel.componentTypeInputs()\"\n [ngComponentOutletInjector]=\"injector\"\n />\n </div>\n</svg:foreignObject>\n\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: [".wrapper{width:max-content}.magnet{opacity:0}.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-handle{stroke:#fff;fill:#1b262c}\n"] }]
|
|
1467
1619
|
}], propDecorators: { nodeModel: [{
|
|
1468
1620
|
type: Input
|
|
1469
1621
|
}], nodeHtmlTemplate: [{
|
|
@@ -1474,7 +1626,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
|
|
|
1474
1626
|
}], htmlWrapperRef: [{
|
|
1475
1627
|
type: ViewChild,
|
|
1476
1628
|
args: ['htmlWrapper']
|
|
1477
|
-
}],
|
|
1629
|
+
}], ngOnInit: [], ngAfterViewInit: [] } });
|
|
1478
1630
|
|
|
1479
1631
|
class EdgeLabelComponent {
|
|
1480
1632
|
constructor() {
|
|
@@ -1579,34 +1731,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
|
|
|
1579
1731
|
type: Input
|
|
1580
1732
|
}] } });
|
|
1581
1733
|
|
|
1582
|
-
class SpacePointContextDirective {
|
|
1583
|
-
constructor() {
|
|
1584
|
-
this.pointerMovementDirective = inject(RootPointerDirective);
|
|
1585
|
-
this.rootSvg = inject(RootSvgReferenceDirective).element;
|
|
1586
|
-
this.host = inject(ElementRef).nativeElement;
|
|
1587
|
-
/**
|
|
1588
|
-
* Signal with current mouse position in svg space
|
|
1589
|
-
*/
|
|
1590
|
-
this.svgCurrentSpacePoint = computed(() => {
|
|
1591
|
-
const movement = this.pointerMovement();
|
|
1592
|
-
if (!movement) {
|
|
1593
|
-
return { x: 0, y: 0 };
|
|
1594
|
-
}
|
|
1595
|
-
const point = this.rootSvg.createSVGPoint();
|
|
1596
|
-
point.x = movement.x;
|
|
1597
|
-
point.y = movement.y;
|
|
1598
|
-
return point.matrixTransform(this.host.getScreenCTM().inverse());
|
|
1599
|
-
});
|
|
1600
|
-
this.pointerMovement = toSignal(this.pointerMovementDirective.pointerMovement$);
|
|
1601
|
-
}
|
|
1602
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SpacePointContextDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1603
|
-
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: SpacePointContextDirective, selector: "g[spacePointContext]", ngImport: i0 }); }
|
|
1604
|
-
}
|
|
1605
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SpacePointContextDirective, decorators: [{
|
|
1606
|
-
type: Directive,
|
|
1607
|
-
args: [{ selector: 'g[spacePointContext]' }]
|
|
1608
|
-
}] });
|
|
1609
|
-
|
|
1610
1734
|
class ConnectionComponent {
|
|
1611
1735
|
constructor() {
|
|
1612
1736
|
this.flowStatusService = inject(FlowStatusService);
|
|
@@ -1644,7 +1768,7 @@ class ConnectionComponent {
|
|
|
1644
1768
|
return null;
|
|
1645
1769
|
});
|
|
1646
1770
|
this.markerUrl = computed(() => {
|
|
1647
|
-
const marker = this.model.
|
|
1771
|
+
const marker = this.model.settings.marker;
|
|
1648
1772
|
if (marker) {
|
|
1649
1773
|
return `url(#${hashCode(JSON.stringify(marker))})`;
|
|
1650
1774
|
}
|
|
@@ -1735,6 +1859,71 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
|
|
|
1735
1859
|
args: [{ required: true }]
|
|
1736
1860
|
}] } });
|
|
1737
1861
|
|
|
1862
|
+
function id() {
|
|
1863
|
+
const randomLetter = String.fromCharCode(65 + Math.floor(Math.random() * 26));
|
|
1864
|
+
return randomLetter + Date.now();
|
|
1865
|
+
}
|
|
1866
|
+
|
|
1867
|
+
const defaultBg = '#fff';
|
|
1868
|
+
const defaultGap = 20;
|
|
1869
|
+
const defaultDotSize = 2;
|
|
1870
|
+
const defaultDotColor = 'rgb(177, 177, 183)';
|
|
1871
|
+
class BackgroundComponent {
|
|
1872
|
+
set background(value) {
|
|
1873
|
+
this.backgroundSignal.set(value);
|
|
1874
|
+
}
|
|
1875
|
+
constructor() {
|
|
1876
|
+
this.viewportService = inject(ViewportService);
|
|
1877
|
+
this.rootSvg = inject(RootSvgReferenceDirective).element;
|
|
1878
|
+
this.backgroundSignal = signal({ type: 'solid', color: defaultBg });
|
|
1879
|
+
this.scaledGap = computed(() => {
|
|
1880
|
+
const background = this.backgroundSignal();
|
|
1881
|
+
if (background.type === 'dots') {
|
|
1882
|
+
const zoom = this.viewportService.readableViewport().zoom;
|
|
1883
|
+
return zoom * (background.gap ?? defaultGap);
|
|
1884
|
+
}
|
|
1885
|
+
return 0;
|
|
1886
|
+
});
|
|
1887
|
+
this.x = computed(() => this.viewportService.readableViewport().x % this.scaledGap());
|
|
1888
|
+
this.y = computed(() => this.viewportService.readableViewport().y % this.scaledGap());
|
|
1889
|
+
this.patternColor = computed(() => this.backgroundSignal().color ?? defaultDotColor);
|
|
1890
|
+
this.patternSize = computed(() => {
|
|
1891
|
+
const background = this.backgroundSignal();
|
|
1892
|
+
if (background.type === 'dots') {
|
|
1893
|
+
return (this.viewportService.readableViewport().zoom * (background.size ?? defaultDotSize)) / 2;
|
|
1894
|
+
}
|
|
1895
|
+
return 0;
|
|
1896
|
+
});
|
|
1897
|
+
// Without ID there will be pattern collision for several flows on the page
|
|
1898
|
+
// Later pattern ID may be exposed to API
|
|
1899
|
+
this.patternId = id();
|
|
1900
|
+
this.patternUrl = `url(#${this.patternId})`;
|
|
1901
|
+
effect(() => {
|
|
1902
|
+
const background = this.backgroundSignal();
|
|
1903
|
+
if (background.type === 'dots') {
|
|
1904
|
+
this.rootSvg.style.backgroundColor = background.backgroundColor ?? defaultBg;
|
|
1905
|
+
}
|
|
1906
|
+
if (background.type === 'solid') {
|
|
1907
|
+
this.rootSvg.style.backgroundColor = background.color;
|
|
1908
|
+
}
|
|
1909
|
+
});
|
|
1910
|
+
}
|
|
1911
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: BackgroundComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1912
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "16.1.0", version: "16.2.12", type: BackgroundComponent, selector: "g[background]", inputs: { background: ["background", "background", transform] }, ngImport: i0, template: "<ng-container *ngIf=\"backgroundSignal().type === 'dots'\">\n <svg:pattern\n [attr.id]=\"patternId\"\n [attr.x]=\"x()\"\n [attr.y]=\"y()\"\n [attr.width]=\"scaledGap()\"\n [attr.height]=\"scaledGap()\"\n patternUnits=\"userSpaceOnUse\"\n >\n <svg:circle\n [attr.cx]=\"patternSize()\"\n [attr.cy]=\"patternSize()\"\n [attr.r]=\"patternSize()\"\n [attr.fill]=\"patternColor()\"\n />\n </svg:pattern>\n\n <svg:rect\n x=\"0\"\n y=\"0\"\n width=\"100%\"\n height=\"100%\"\n [attr.fill]=\"patternUrl\"\n />\n</ng-container>\n", dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
1913
|
+
}
|
|
1914
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: BackgroundComponent, decorators: [{
|
|
1915
|
+
type: Component,
|
|
1916
|
+
args: [{ selector: 'g[background]', changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *ngIf=\"backgroundSignal().type === 'dots'\">\n <svg:pattern\n [attr.id]=\"patternId\"\n [attr.x]=\"x()\"\n [attr.y]=\"y()\"\n [attr.width]=\"scaledGap()\"\n [attr.height]=\"scaledGap()\"\n patternUnits=\"userSpaceOnUse\"\n >\n <svg:circle\n [attr.cx]=\"patternSize()\"\n [attr.cy]=\"patternSize()\"\n [attr.r]=\"patternSize()\"\n [attr.fill]=\"patternColor()\"\n />\n </svg:pattern>\n\n <svg:rect\n x=\"0\"\n y=\"0\"\n width=\"100%\"\n height=\"100%\"\n [attr.fill]=\"patternUrl\"\n />\n</ng-container>\n" }]
|
|
1917
|
+
}], ctorParameters: function () { return []; }, propDecorators: { background: [{
|
|
1918
|
+
type: Input,
|
|
1919
|
+
args: [{ required: true, transform }]
|
|
1920
|
+
}] } });
|
|
1921
|
+
function transform(background) {
|
|
1922
|
+
return typeof background === 'string'
|
|
1923
|
+
? { type: 'solid', color: background }
|
|
1924
|
+
: background;
|
|
1925
|
+
}
|
|
1926
|
+
|
|
1738
1927
|
// TODO: too general purpose nane
|
|
1739
1928
|
class RootSvgContextDirective {
|
|
1740
1929
|
constructor() {
|
|
@@ -1816,9 +2005,9 @@ class VflowComponent {
|
|
|
1816
2005
|
*/
|
|
1817
2006
|
this.maxZoom = 3;
|
|
1818
2007
|
/**
|
|
1819
|
-
* Background
|
|
2008
|
+
* Background for flow
|
|
1820
2009
|
*/
|
|
1821
|
-
this.background = '#
|
|
2010
|
+
this.background = '#fff';
|
|
1822
2011
|
this.nodeModels = computed(() => this.nodeRenderingService.nodes());
|
|
1823
2012
|
this.edgeModels = computed(() => this.flowEntitiesService.validEdges());
|
|
1824
2013
|
// #endregion
|
|
@@ -1958,6 +2147,12 @@ class VflowComponent {
|
|
|
1958
2147
|
getDetachedEdges() {
|
|
1959
2148
|
return this.flowEntitiesService.getDetachedEdges().map(e => e.edge);
|
|
1960
2149
|
}
|
|
2150
|
+
/**
|
|
2151
|
+
* Convert point received from document to point on the flow
|
|
2152
|
+
*/
|
|
2153
|
+
documentPointToFlowPoint(point) {
|
|
2154
|
+
return this.spacePointContext.documentPointToFlowPoint(point);
|
|
2155
|
+
}
|
|
1961
2156
|
// #endregion
|
|
1962
2157
|
trackNodes(idx, { node }) {
|
|
1963
2158
|
return node;
|
|
@@ -1977,7 +2172,7 @@ class VflowComponent {
|
|
|
1977
2172
|
SelectionService,
|
|
1978
2173
|
FlowSettingsService,
|
|
1979
2174
|
ComponentEventBusService
|
|
1980
|
-
], queries: [{ propertyName: "nodeHtmlDirective", first: true, predicate: NodeHtmlTemplateDirective, 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 }], 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 class=\"root-svg\"\n #flow\n [
|
|
2175
|
+
], queries: [{ propertyName: "nodeHtmlDirective", first: true, predicate: NodeHtmlTemplateDirective, 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 class=\"root-svg\"\n #flow\n [attr.width]=\"flowWidth()\"\n [attr.height]=\"flowHeight()\"\n>\n <defs [markers]=\"markers()\" flowDefs />\n\n <g [background]=\"background\"/>\n\n <svg:g\n mapContext\n spacePointContext\n [minZoom]=\"minZoom\"\n [maxZoom]=\"maxZoom\"\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 [nodeHtmlTemplate]=\"nodeHtmlDirective?.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", "nodeHtmlTemplate"] }, { 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]", inputs: ["minZoom", "maxZoom"] }, { kind: "directive", type: RootSvgReferenceDirective, selector: "svg[rootSvgRef]" }, { kind: "directive", type: RootSvgContextDirective, selector: "svg[rootSvgContext]" }, { kind: "directive", type: RootPointerDirective, selector: "svg[rootPointer]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
1981
2176
|
}
|
|
1982
2177
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: VflowComponent, decorators: [{
|
|
1983
2178
|
type: Component,
|
|
@@ -1995,7 +2190,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
|
|
|
1995
2190
|
], hostDirectives: [
|
|
1996
2191
|
connectionControllerHostDirective,
|
|
1997
2192
|
changesControllerHostDirective
|
|
1998
|
-
], template: "<svg:svg\n rootSvgRef\n rootSvgContext\n rootPointer\n class=\"root-svg\"\n #flow\n [
|
|
2193
|
+
], template: "<svg:svg\n rootSvgRef\n rootSvgContext\n rootPointer\n class=\"root-svg\"\n #flow\n [attr.width]=\"flowWidth()\"\n [attr.height]=\"flowHeight()\"\n>\n <defs [markers]=\"markers()\" flowDefs />\n\n <g [background]=\"background\"/>\n\n <svg:g\n mapContext\n spacePointContext\n [minZoom]=\"minZoom\"\n [maxZoom]=\"maxZoom\"\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 [nodeHtmlTemplate]=\"nodeHtmlDirective?.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"] }]
|
|
1999
2194
|
}], propDecorators: { view: [{
|
|
2000
2195
|
type: Input
|
|
2001
2196
|
}], minZoom: [{
|
|
@@ -2033,49 +2228,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
|
|
|
2033
2228
|
}], mapContext: [{
|
|
2034
2229
|
type: ViewChild,
|
|
2035
2230
|
args: [MapContextDirective]
|
|
2231
|
+
}], spacePointContext: [{
|
|
2232
|
+
type: ViewChild,
|
|
2233
|
+
args: [SpacePointContextDirective]
|
|
2036
2234
|
}] } });
|
|
2037
2235
|
|
|
2038
|
-
class HandleComponent {
|
|
2039
|
-
constructor() {
|
|
2040
|
-
this.injector = inject(Injector);
|
|
2041
|
-
this.handleService = inject(HandleService);
|
|
2042
|
-
this.element = inject(ElementRef).nativeElement;
|
|
2043
|
-
}
|
|
2044
|
-
ngOnInit() {
|
|
2045
|
-
this.model = new HandleModel({
|
|
2046
|
-
position: this.position,
|
|
2047
|
-
type: this.type,
|
|
2048
|
-
id: this.id,
|
|
2049
|
-
parentReference: this.element.parentElement,
|
|
2050
|
-
template: this.template
|
|
2051
|
-
}, this.handleService.node());
|
|
2052
|
-
this.handleService.createHandle(this.model);
|
|
2053
|
-
queueMicrotask(() => this.model.updateParent());
|
|
2054
|
-
}
|
|
2055
|
-
ngOnDestroy() {
|
|
2056
|
-
this.handleService.destroyHandle(this.model);
|
|
2057
|
-
}
|
|
2058
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HandleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2059
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: HandleComponent, selector: "handle", inputs: { position: "position", type: "type", id: "id", template: "template" }, ngImport: i0, template: "" }); }
|
|
2060
|
-
}
|
|
2061
|
-
__decorate([
|
|
2062
|
-
InjectionContext
|
|
2063
|
-
], HandleComponent.prototype, "ngOnInit", null);
|
|
2064
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HandleComponent, decorators: [{
|
|
2065
|
-
type: Component,
|
|
2066
|
-
args: [{ selector: 'handle', template: "" }]
|
|
2067
|
-
}], propDecorators: { position: [{
|
|
2068
|
-
type: Input,
|
|
2069
|
-
args: [{ required: true }]
|
|
2070
|
-
}], type: [{
|
|
2071
|
-
type: Input,
|
|
2072
|
-
args: [{ required: true }]
|
|
2073
|
-
}], id: [{
|
|
2074
|
-
type: Input
|
|
2075
|
-
}], template: [{
|
|
2076
|
-
type: Input
|
|
2077
|
-
}], ngOnInit: [] } });
|
|
2078
|
-
|
|
2079
2236
|
class SelectableDirective {
|
|
2080
2237
|
constructor() {
|
|
2081
2238
|
this.flowSettingsService = inject(FlowSettingsService);
|
|
@@ -2116,7 +2273,8 @@ const components = [
|
|
|
2116
2273
|
EdgeLabelComponent,
|
|
2117
2274
|
ConnectionComponent,
|
|
2118
2275
|
HandleComponent,
|
|
2119
|
-
DefsComponent
|
|
2276
|
+
DefsComponent,
|
|
2277
|
+
BackgroundComponent
|
|
2120
2278
|
];
|
|
2121
2279
|
const directives = [
|
|
2122
2280
|
SpacePointContextDirective,
|
|
@@ -2143,7 +2301,8 @@ class VflowModule {
|
|
|
2143
2301
|
EdgeLabelComponent,
|
|
2144
2302
|
ConnectionComponent,
|
|
2145
2303
|
HandleComponent,
|
|
2146
|
-
DefsComponent,
|
|
2304
|
+
DefsComponent,
|
|
2305
|
+
BackgroundComponent, SpacePointContextDirective,
|
|
2147
2306
|
MapContextDirective,
|
|
2148
2307
|
RootSvgReferenceDirective,
|
|
2149
2308
|
RootSvgContextDirective,
|