ngx-vflow 0.2.2 → 0.4.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/edge/edge.component.mjs +18 -6
- package/esm2022/lib/vflow/components/edge-label/edge-label.component.mjs +13 -10
- package/esm2022/lib/vflow/components/handle/handle.component.mjs +21 -24
- package/esm2022/lib/vflow/components/node/node.component.mjs +69 -20
- package/esm2022/lib/vflow/components/vflow/vflow.component.mjs +35 -22
- package/esm2022/lib/vflow/decorators/microtask.decorator.mjs +11 -0
- package/esm2022/lib/vflow/decorators/run-in-injection-context.decorator.mjs +18 -0
- package/esm2022/lib/vflow/directives/handle-size-controller.directive.mjs +38 -0
- package/esm2022/lib/vflow/directives/map-context.directive.mjs +31 -4
- package/esm2022/lib/vflow/directives/root-svg-context.directive.mjs +1 -1
- package/esm2022/lib/vflow/directives/selectable.directive.mjs +39 -0
- package/esm2022/lib/vflow/interfaces/flow-entity.interface.mjs +2 -0
- package/esm2022/lib/vflow/interfaces/template-context.interface.mjs +1 -1
- package/esm2022/lib/vflow/models/edge.model.mjs +17 -11
- package/esm2022/lib/vflow/models/handle.model.mjs +32 -3
- package/esm2022/lib/vflow/models/node.model.mjs +11 -33
- package/esm2022/lib/vflow/services/edge-changes.service.mjs +7 -3
- package/esm2022/lib/vflow/services/flow-entities.service.mjs +6 -2
- package/esm2022/lib/vflow/services/flow-settings.service.mjs +25 -0
- package/esm2022/lib/vflow/services/handle.service.mjs +3 -4
- package/esm2022/lib/vflow/services/node-changes.service.mjs +7 -3
- package/esm2022/lib/vflow/services/node-rendering.service.mjs +22 -0
- package/esm2022/lib/vflow/services/selection.service.mjs +45 -0
- package/esm2022/lib/vflow/types/edge-change.type.mjs +1 -1
- package/esm2022/lib/vflow/types/node-change.type.mjs +1 -1
- package/esm2022/lib/vflow/utils/add-nodes-to-edges.mjs +3 -3
- package/esm2022/lib/vflow/utils/resizable.mjs +11 -0
- package/esm2022/lib/vflow/vflow.module.mjs +11 -3
- package/esm2022/public-api.mjs +2 -1
- package/fesm2022/ngx-vflow.mjs +536 -253
- package/fesm2022/ngx-vflow.mjs.map +1 -1
- package/lib/vflow/components/edge/edge.component.d.ts +5 -2
- package/lib/vflow/components/handle/handle.component.d.ts +6 -4
- package/lib/vflow/components/node/node.component.d.ts +13 -6
- package/lib/vflow/components/vflow/vflow.component.d.ts +13 -7
- package/lib/vflow/decorators/microtask.decorator.d.ts +1 -0
- package/lib/vflow/decorators/run-in-injection-context.decorator.d.ts +5 -0
- package/lib/vflow/directives/handle-size-controller.directive.d.ts +10 -0
- package/lib/vflow/directives/map-context.directive.d.ts +5 -0
- package/lib/vflow/directives/selectable.directive.d.ts +11 -0
- package/lib/vflow/interfaces/flow-entity.interface.d.ts +4 -0
- package/lib/vflow/interfaces/template-context.interface.d.ts +1 -0
- package/lib/vflow/models/edge.model.d.ts +7 -3
- package/lib/vflow/models/handle.model.d.ts +30 -2
- package/lib/vflow/models/node.model.d.ts +8 -11
- package/lib/vflow/services/edge-changes.service.d.ts +5 -0
- package/lib/vflow/services/flow-entities.service.d.ts +5 -2
- package/lib/vflow/services/flow-settings.service.d.ts +20 -0
- package/lib/vflow/services/handle.service.d.ts +3 -6
- package/lib/vflow/services/node-changes.service.d.ts +5 -0
- package/lib/vflow/services/node-rendering.service.d.ts +9 -0
- package/lib/vflow/services/selection.service.d.ts +19 -0
- package/lib/vflow/types/edge-change.type.d.ts +5 -1
- package/lib/vflow/types/node-change.type.d.ts +5 -1
- package/lib/vflow/utils/resizable.d.ts +3 -0
- package/lib/vflow/vflow.module.d.ts +5 -3
- package/package.json +3 -3
- package/public-api.d.ts +1 -0
- package/esm2022/lib/vflow/models/flow.model.mjs +0 -18
- package/lib/vflow/models/flow.model.d.ts +0 -16
package/fesm2022/ngx-vflow.mjs
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
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, effect, Input, TemplateRef,
|
|
4
|
+
import { signal, Injectable, inject, ElementRef, Directive, computed, effect, Input, TemplateRef, EventEmitter, Output, untracked, runInInjectionContext, Injector, NgZone, Component, ChangeDetectionStrategy, ViewChild, HostListener, ContentChild, NgModule } from '@angular/core';
|
|
5
5
|
import { select } from 'd3-selection';
|
|
6
6
|
import { zoomIdentity, zoom } from 'd3-zoom';
|
|
7
|
+
import { Subject, tap, switchMap, merge, skip, map, pairwise, filter, distinctUntilChanged, observeOn, asyncScheduler, zip, Observable, Subscription, startWith, fromEvent } from 'rxjs';
|
|
8
|
+
import { takeUntilDestroyed, toObservable, toSignal } from '@angular/core/rxjs-interop';
|
|
7
9
|
import { drag } from 'd3-drag';
|
|
8
|
-
import { toObservable, takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';
|
|
9
|
-
import { switchMap, merge, skip, map, pairwise, filter, observeOn, asyncScheduler, zip, distinctUntilChanged, tap, fromEvent } from 'rxjs';
|
|
10
10
|
import { path } from 'd3-path';
|
|
11
|
+
import { __decorate } from 'tslib';
|
|
11
12
|
|
|
12
13
|
class ViewportService {
|
|
13
14
|
constructor() {
|
|
@@ -57,13 +58,123 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
|
|
|
57
58
|
}]
|
|
58
59
|
}] });
|
|
59
60
|
|
|
61
|
+
class ConnectionModel {
|
|
62
|
+
constructor(connection) {
|
|
63
|
+
this.connection = connection;
|
|
64
|
+
this.curve = connection.curve ?? 'bezier';
|
|
65
|
+
this.type = connection.type ?? 'default';
|
|
66
|
+
this.validator = connection.validator ?? (() => true);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function hashCode(str) {
|
|
71
|
+
return str.split('').reduce((a, b) => {
|
|
72
|
+
a = ((a << 5) - a) + b.charCodeAt(0);
|
|
73
|
+
return a & a;
|
|
74
|
+
}, 0);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
class FlowEntitiesService {
|
|
78
|
+
constructor() {
|
|
79
|
+
this.nodes = signal([], {
|
|
80
|
+
// empty arrays considered equal, other arrays may not be equal
|
|
81
|
+
equal: (a, b) => !a.length && !b.length ? true : a === b
|
|
82
|
+
});
|
|
83
|
+
this.edges = signal([], {
|
|
84
|
+
// empty arrays considered equal, other arrays may not be equal
|
|
85
|
+
equal: (a, b) => !a.length && !b.length ? true : a === b
|
|
86
|
+
});
|
|
87
|
+
this.connection = signal(new ConnectionModel({}));
|
|
88
|
+
this.markers = computed(() => {
|
|
89
|
+
const markersMap = new Map();
|
|
90
|
+
this.validEdges().forEach(e => {
|
|
91
|
+
if (e.edge.markers?.start) {
|
|
92
|
+
const hash = hashCode(JSON.stringify(e.edge.markers.start));
|
|
93
|
+
markersMap.set(hash, e.edge.markers.start);
|
|
94
|
+
}
|
|
95
|
+
if (e.edge.markers?.end) {
|
|
96
|
+
const hash = hashCode(JSON.stringify(e.edge.markers.end));
|
|
97
|
+
markersMap.set(hash, e.edge.markers.end);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
const connectionMarker = this.connection().connection.marker;
|
|
101
|
+
if (connectionMarker) {
|
|
102
|
+
const hash = hashCode(JSON.stringify(connectionMarker));
|
|
103
|
+
markersMap.set(hash, connectionMarker);
|
|
104
|
+
}
|
|
105
|
+
return markersMap;
|
|
106
|
+
});
|
|
107
|
+
this.validEdges = computed(() => {
|
|
108
|
+
const nodes = this.nodes();
|
|
109
|
+
return this.edges().filter(e => nodes.includes(e.source()) && nodes.includes(e.target()));
|
|
110
|
+
});
|
|
111
|
+
this.entities = computed(() => [
|
|
112
|
+
...this.nodes(),
|
|
113
|
+
...this.edges()
|
|
114
|
+
]);
|
|
115
|
+
}
|
|
116
|
+
getNode(id) {
|
|
117
|
+
return this.nodes().find(({ node }) => node.id === id);
|
|
118
|
+
}
|
|
119
|
+
getDetachedEdges() {
|
|
120
|
+
return this.edges().filter(e => e.detached());
|
|
121
|
+
}
|
|
122
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FlowEntitiesService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
123
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FlowEntitiesService }); }
|
|
124
|
+
}
|
|
125
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FlowEntitiesService, decorators: [{
|
|
126
|
+
type: Injectable
|
|
127
|
+
}] });
|
|
128
|
+
|
|
129
|
+
class SelectionService {
|
|
130
|
+
constructor() {
|
|
131
|
+
this.flowEntitiesService = inject(FlowEntitiesService);
|
|
132
|
+
this.viewport$ = new Subject();
|
|
133
|
+
this.resetSelection = this.viewport$.pipe(tap(({ start, end, target }) => {
|
|
134
|
+
if (start && end) {
|
|
135
|
+
const delta = SelectionService.delta;
|
|
136
|
+
const diffX = Math.abs(end.x - start.x);
|
|
137
|
+
const diffY = Math.abs(end.y - start.y);
|
|
138
|
+
// click (not drag)
|
|
139
|
+
const isClick = diffX < delta && diffY < delta;
|
|
140
|
+
// do not reset if event chain contains selectable elems
|
|
141
|
+
const isNotSelectable = !target.closest('.selectable');
|
|
142
|
+
if (isClick && isNotSelectable) {
|
|
143
|
+
this.select(null);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}), takeUntilDestroyed()).subscribe();
|
|
147
|
+
}
|
|
148
|
+
static { this.delta = 6; }
|
|
149
|
+
setViewport(viewport) {
|
|
150
|
+
this.viewport$.next(viewport);
|
|
151
|
+
}
|
|
152
|
+
select(entity) {
|
|
153
|
+
// undo select for previously selected nodes
|
|
154
|
+
this.flowEntitiesService.entities()
|
|
155
|
+
.filter(n => n.selected)
|
|
156
|
+
.forEach(n => n.selected.set(false));
|
|
157
|
+
if (entity) {
|
|
158
|
+
// select passed entity
|
|
159
|
+
entity.selected.set(true);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SelectionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
163
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SelectionService }); }
|
|
164
|
+
}
|
|
165
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SelectionService, decorators: [{
|
|
166
|
+
type: Injectable
|
|
167
|
+
}] });
|
|
168
|
+
|
|
60
169
|
class MapContextDirective {
|
|
61
170
|
constructor() {
|
|
62
171
|
this.rootSvg = inject(RootSvgReferenceDirective).element;
|
|
63
172
|
this.host = inject(ElementRef).nativeElement;
|
|
173
|
+
this.selectionService = inject(SelectionService);
|
|
64
174
|
this.viewportService = inject(ViewportService);
|
|
65
175
|
this.rootSvgSelection = select(this.rootSvg);
|
|
66
176
|
this.zoomableSelection = select(this.host);
|
|
177
|
+
this.viewportForSelection = {};
|
|
67
178
|
// under the hood this effect triggers handleZoom, so error throws without this flag
|
|
68
179
|
// TODO: hack with timer fixes wrong node scaling (handle positions not matched with content size)
|
|
69
180
|
this.manualViewportChangeEffect = effect(() => setTimeout(() => {
|
|
@@ -90,15 +201,32 @@ class MapContextDirective {
|
|
|
90
201
|
}), { allowSignalWrites: true });
|
|
91
202
|
this.handleZoom = ({ transform }) => {
|
|
92
203
|
// update public signal for user to read
|
|
93
|
-
this.viewportService.readableViewport.set(
|
|
204
|
+
this.viewportService.readableViewport.set(mapTransformToViewportState(transform));
|
|
94
205
|
this.zoomableSelection.attr('transform', transform.toString());
|
|
95
206
|
};
|
|
96
207
|
}
|
|
97
208
|
ngOnInit() {
|
|
98
209
|
this.zoomBehavior = zoom()
|
|
99
210
|
.scaleExtent([this.minZoom, this.maxZoom])
|
|
100
|
-
.on('
|
|
101
|
-
|
|
211
|
+
.on('start', (event) => this.onD3zoomStart(event))
|
|
212
|
+
.on('zoom', (event) => this.handleZoom(event))
|
|
213
|
+
.on('end', (event) => this.onD3zoomEnd(event));
|
|
214
|
+
this.rootSvgSelection
|
|
215
|
+
.call(this.zoomBehavior)
|
|
216
|
+
.on('dblclick.zoom', null);
|
|
217
|
+
}
|
|
218
|
+
onD3zoomStart({ transform }) {
|
|
219
|
+
this.viewportForSelection = {
|
|
220
|
+
start: mapTransformToViewportState(transform)
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
onD3zoomEnd({ transform, sourceEvent }) {
|
|
224
|
+
this.viewportForSelection = {
|
|
225
|
+
...this.viewportForSelection,
|
|
226
|
+
end: mapTransformToViewportState(transform),
|
|
227
|
+
target: evTarget(sourceEvent)
|
|
228
|
+
};
|
|
229
|
+
this.selectionService.setViewport(this.viewportForSelection);
|
|
102
230
|
}
|
|
103
231
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: MapContextDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
104
232
|
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: MapContextDirective, selector: "g[mapContext]", inputs: { minZoom: "minZoom", maxZoom: "maxZoom" }, ngImport: i0 }); }
|
|
@@ -111,6 +239,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
|
|
|
111
239
|
}], maxZoom: [{
|
|
112
240
|
type: Input
|
|
113
241
|
}] } });
|
|
242
|
+
const mapTransformToViewportState = (transform) => ({ zoom: transform.k, x: transform.x, y: transform.y });
|
|
243
|
+
const evTarget = (anyEvent) => {
|
|
244
|
+
if (anyEvent instanceof Event && anyEvent.target instanceof Element) {
|
|
245
|
+
return anyEvent.target;
|
|
246
|
+
}
|
|
247
|
+
return undefined;
|
|
248
|
+
};
|
|
114
249
|
|
|
115
250
|
const round = (num) => Math.round(num * 100) / 100;
|
|
116
251
|
|
|
@@ -237,28 +372,11 @@ function addNodesToEdges(nodes, edges) {
|
|
|
237
372
|
return acc;
|
|
238
373
|
}, {});
|
|
239
374
|
edges.forEach(e => {
|
|
240
|
-
e.source
|
|
241
|
-
e.target
|
|
375
|
+
e.source.set(nodesById[e.edge.source]);
|
|
376
|
+
e.target.set(nodesById[e.edge.target]);
|
|
242
377
|
});
|
|
243
378
|
}
|
|
244
379
|
|
|
245
|
-
class FlowModel {
|
|
246
|
-
constructor() {
|
|
247
|
-
/**
|
|
248
|
-
* Global setting with handle positions. Nodes derive this value
|
|
249
|
-
*
|
|
250
|
-
* @deprecated
|
|
251
|
-
*/
|
|
252
|
-
this.handlePositions = signal({ source: 'right', target: 'left' });
|
|
253
|
-
/**
|
|
254
|
-
* @see {VflowComponent.view}
|
|
255
|
-
*/
|
|
256
|
-
this.view = signal([400, 400]);
|
|
257
|
-
this.flowWidth = computed(() => this.view() === 'auto' ? '100%' : this.view()[0]);
|
|
258
|
-
this.flowHeight = computed(() => this.view() === 'auto' ? '100%' : this.view()[1]);
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
|
|
262
380
|
class FlowStatusService {
|
|
263
381
|
constructor() {
|
|
264
382
|
this.status = signal({ state: 'idle', payload: null });
|
|
@@ -296,70 +414,6 @@ function batchStatusChanges(...changes) {
|
|
|
296
414
|
}
|
|
297
415
|
}
|
|
298
416
|
|
|
299
|
-
class ConnectionModel {
|
|
300
|
-
constructor(connection) {
|
|
301
|
-
this.connection = connection;
|
|
302
|
-
this.curve = connection.curve ?? 'bezier';
|
|
303
|
-
this.type = connection.type ?? 'default';
|
|
304
|
-
this.validator = connection.validator ?? (() => true);
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
function hashCode(str) {
|
|
309
|
-
return str.split('').reduce((a, b) => {
|
|
310
|
-
a = ((a << 5) - a) + b.charCodeAt(0);
|
|
311
|
-
return a & a;
|
|
312
|
-
}, 0);
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
class FlowEntitiesService {
|
|
316
|
-
constructor() {
|
|
317
|
-
this.nodes = signal([], {
|
|
318
|
-
// empty arrays considered equal, other arrays may not be equal
|
|
319
|
-
equal: (a, b) => !a.length && !b.length ? true : a === b
|
|
320
|
-
});
|
|
321
|
-
this.edges = signal([], {
|
|
322
|
-
// empty arrays considered equal, other arrays may not be equal
|
|
323
|
-
equal: (a, b) => !a.length && !b.length ? true : a === b
|
|
324
|
-
});
|
|
325
|
-
this.connection = signal(new ConnectionModel({}));
|
|
326
|
-
this.markers = computed(() => {
|
|
327
|
-
const markersMap = new Map();
|
|
328
|
-
this.validEdges().forEach(e => {
|
|
329
|
-
if (e.edge.markers?.start) {
|
|
330
|
-
const hash = hashCode(JSON.stringify(e.edge.markers.start));
|
|
331
|
-
markersMap.set(hash, e.edge.markers.start);
|
|
332
|
-
}
|
|
333
|
-
if (e.edge.markers?.end) {
|
|
334
|
-
const hash = hashCode(JSON.stringify(e.edge.markers.end));
|
|
335
|
-
markersMap.set(hash, e.edge.markers.end);
|
|
336
|
-
}
|
|
337
|
-
});
|
|
338
|
-
const connectionMarker = this.connection().connection.marker;
|
|
339
|
-
if (connectionMarker) {
|
|
340
|
-
const hash = hashCode(JSON.stringify(connectionMarker));
|
|
341
|
-
markersMap.set(hash, connectionMarker);
|
|
342
|
-
}
|
|
343
|
-
return markersMap;
|
|
344
|
-
});
|
|
345
|
-
this.validEdges = computed(() => {
|
|
346
|
-
const nodes = this.nodes();
|
|
347
|
-
return this.edges().filter(e => nodes.includes(e.source) && nodes.includes(e.target));
|
|
348
|
-
});
|
|
349
|
-
}
|
|
350
|
-
getNode(id) {
|
|
351
|
-
return this.nodes().find(({ node }) => node.id === id);
|
|
352
|
-
}
|
|
353
|
-
getDetachedEdges() {
|
|
354
|
-
return this.edges().filter(e => e.detached());
|
|
355
|
-
}
|
|
356
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FlowEntitiesService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
357
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FlowEntitiesService }); }
|
|
358
|
-
}
|
|
359
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FlowEntitiesService, decorators: [{
|
|
360
|
-
type: Injectable
|
|
361
|
-
}] });
|
|
362
|
-
|
|
363
417
|
class ConnectionControllerDirective {
|
|
364
418
|
constructor() {
|
|
365
419
|
/**
|
|
@@ -402,84 +456,45 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
|
|
|
402
456
|
type: Output
|
|
403
457
|
}] } });
|
|
404
458
|
|
|
405
|
-
class
|
|
406
|
-
constructor(
|
|
407
|
-
this.
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
});
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
case 'right': return {
|
|
421
|
-
x: this.parentNode.size().width,
|
|
422
|
-
y: this.parentPosition().y + (this.parentSize().height / 2)
|
|
423
|
-
};
|
|
424
|
-
case 'top': return {
|
|
425
|
-
x: this.parentPosition().x + (this.parentSize().width / 2),
|
|
426
|
-
y: 0
|
|
427
|
-
};
|
|
428
|
-
case 'bottom': return {
|
|
429
|
-
x: this.parentPosition().x + this.parentSize().width / 2,
|
|
430
|
-
y: this.parentNode.size().height
|
|
431
|
-
};
|
|
432
|
-
}
|
|
433
|
-
});
|
|
434
|
-
this.sizeOffset = computed(() => {
|
|
435
|
-
switch (this.rawHandle.position) {
|
|
436
|
-
case 'left': return { x: -(this.size().width / 2), y: 0 };
|
|
437
|
-
case 'right': return { x: this.size().width / 2, y: 0 };
|
|
438
|
-
case 'top': return { x: 0, y: -(this.size().height / 2) };
|
|
439
|
-
case 'bottom': return { x: 0, y: this.size().height / 2 };
|
|
440
|
-
}
|
|
441
|
-
});
|
|
442
|
-
this.pointAbsolute = computed(() => {
|
|
443
|
-
return {
|
|
444
|
-
x: this.parentNode.point().x + this.offset().x + this.sizeOffset().x,
|
|
445
|
-
y: this.parentNode.point().y + this.offset().y + this.sizeOffset().y,
|
|
446
|
-
};
|
|
447
|
-
});
|
|
448
|
-
this.parentSize = signal(this.rawHandle.parentSize);
|
|
449
|
-
this.parentPosition = signal(this.rawHandle.parentPosition);
|
|
459
|
+
class FlowSettingsService {
|
|
460
|
+
constructor() {
|
|
461
|
+
this.entitiesSelectable = signal(true);
|
|
462
|
+
/**
|
|
463
|
+
* Global setting with handle positions. Nodes derive this value
|
|
464
|
+
*
|
|
465
|
+
* @deprecated
|
|
466
|
+
*/
|
|
467
|
+
this.handlePositions = signal({ source: 'right', target: 'left' });
|
|
468
|
+
/**
|
|
469
|
+
* @see {VflowComponent.view}
|
|
470
|
+
*/
|
|
471
|
+
this.view = signal([400, 400]);
|
|
472
|
+
this.flowWidth = computed(() => this.view() === 'auto' ? '100%' : this.view()[0]);
|
|
473
|
+
this.flowHeight = computed(() => this.view() === 'auto' ? '100%' : this.view()[1]);
|
|
450
474
|
}
|
|
475
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FlowSettingsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
476
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FlowSettingsService }); }
|
|
451
477
|
}
|
|
478
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: FlowSettingsService, decorators: [{
|
|
479
|
+
type: Injectable
|
|
480
|
+
}] });
|
|
452
481
|
|
|
453
482
|
class NodeModel {
|
|
454
483
|
constructor(node) {
|
|
455
484
|
this.node = node;
|
|
485
|
+
this.flowSettingsService = inject(FlowSettingsService);
|
|
456
486
|
this.point = signal({ x: 0, y: 0 });
|
|
457
487
|
this.point$ = toObservable(this.point);
|
|
458
488
|
this.size = signal({ width: 0, height: 0 });
|
|
489
|
+
this.renderOrder = signal(0);
|
|
490
|
+
this.selected = signal(false);
|
|
491
|
+
this.selected$ = toObservable(this.selected);
|
|
459
492
|
this.pointTransform = computed(() => `translate(${this.point().x}, ${this.point().y})`);
|
|
460
493
|
// Now source and handle positions derived from parent flow
|
|
461
|
-
this.sourcePosition = computed(() => this.
|
|
462
|
-
this.targetPosition = computed(() => this.
|
|
463
|
-
this.handles =
|
|
464
|
-
|
|
465
|
-
return this.rawHandles();
|
|
466
|
-
}
|
|
467
|
-
return [
|
|
468
|
-
new HandleModel({
|
|
469
|
-
position: this.sourcePosition(),
|
|
470
|
-
type: 'source',
|
|
471
|
-
parentPosition: { x: 0, y: 0 },
|
|
472
|
-
parentSize: this.size()
|
|
473
|
-
}, this),
|
|
474
|
-
new HandleModel({
|
|
475
|
-
position: this.targetPosition(),
|
|
476
|
-
type: 'target',
|
|
477
|
-
parentPosition: { x: 0, y: 0 },
|
|
478
|
-
parentSize: this.size()
|
|
479
|
-
}, this),
|
|
480
|
-
];
|
|
481
|
-
});
|
|
482
|
-
this.rawHandles = signal([]);
|
|
494
|
+
this.sourcePosition = computed(() => this.flowSettingsService.handlePositions().source);
|
|
495
|
+
this.targetPosition = computed(() => this.flowSettingsService.handlePositions().target);
|
|
496
|
+
this.handles = signal([]);
|
|
497
|
+
this.handles$ = toObservable(this.handles);
|
|
483
498
|
this.draggable = true;
|
|
484
499
|
// disabled for configuration for now
|
|
485
500
|
this.magnetRadius = 20;
|
|
@@ -487,14 +502,6 @@ class NodeModel {
|
|
|
487
502
|
if (isDefined(node.draggable))
|
|
488
503
|
this.draggable = node.draggable;
|
|
489
504
|
}
|
|
490
|
-
/**
|
|
491
|
-
* Bind parent flow model to node
|
|
492
|
-
*
|
|
493
|
-
* @param flow parent flow
|
|
494
|
-
*/
|
|
495
|
-
bindFlow(flow) {
|
|
496
|
-
this.flow = flow;
|
|
497
|
-
}
|
|
498
505
|
}
|
|
499
506
|
|
|
500
507
|
class EdgeLabelModel {
|
|
@@ -610,26 +617,32 @@ function getPointOnBezier(sourcePoint, targetPoint, controlPoint1, controlPoint2
|
|
|
610
617
|
class EdgeModel {
|
|
611
618
|
constructor(edge) {
|
|
612
619
|
this.edge = edge;
|
|
620
|
+
this.source = signal(undefined);
|
|
621
|
+
this.target = signal(undefined);
|
|
622
|
+
this.selected = signal(false);
|
|
623
|
+
this.selected$ = toObservable(this.selected);
|
|
613
624
|
this.detached = computed(() => {
|
|
614
|
-
|
|
625
|
+
const source = this.source();
|
|
626
|
+
const target = this.target();
|
|
627
|
+
if (!source || !target) {
|
|
615
628
|
return true;
|
|
616
629
|
}
|
|
617
630
|
let existsSourceHandle = false;
|
|
618
631
|
let existsTargetHandle = false;
|
|
619
632
|
if (this.edge.sourceHandle) {
|
|
620
|
-
existsSourceHandle = !!
|
|
633
|
+
existsSourceHandle = !!source.handles()
|
|
621
634
|
.find(handle => handle.rawHandle.id === this.edge.sourceHandle);
|
|
622
635
|
}
|
|
623
636
|
else {
|
|
624
|
-
existsSourceHandle = !!
|
|
637
|
+
existsSourceHandle = !!source.handles()
|
|
625
638
|
.find(handle => handle.rawHandle.type === 'source');
|
|
626
639
|
}
|
|
627
640
|
if (this.edge.targetHandle) {
|
|
628
|
-
existsTargetHandle = !!
|
|
641
|
+
existsTargetHandle = !!target.handles()
|
|
629
642
|
.find(handle => handle.rawHandle.id === this.edge.targetHandle);
|
|
630
643
|
}
|
|
631
644
|
else {
|
|
632
|
-
existsTargetHandle = !!
|
|
645
|
+
existsTargetHandle = !!target.handles()
|
|
633
646
|
.find(handle => handle.rawHandle.type === 'target');
|
|
634
647
|
}
|
|
635
648
|
return !existsSourceHandle || !existsTargetHandle;
|
|
@@ -638,20 +651,20 @@ class EdgeModel {
|
|
|
638
651
|
this.path = computed(() => {
|
|
639
652
|
let source;
|
|
640
653
|
if (this.edge.sourceHandle) {
|
|
641
|
-
source = this.source
|
|
654
|
+
source = this.source()?.handles()
|
|
642
655
|
.find(handle => handle.rawHandle.id === this.edge.sourceHandle);
|
|
643
656
|
}
|
|
644
657
|
else {
|
|
645
|
-
source = this.source
|
|
658
|
+
source = this.source()?.handles()
|
|
646
659
|
.find(handle => handle.rawHandle.type === 'source');
|
|
647
660
|
}
|
|
648
661
|
let target;
|
|
649
662
|
if (this.edge.targetHandle) {
|
|
650
|
-
target = this.target
|
|
663
|
+
target = this.target()?.handles()
|
|
651
664
|
.find(handle => handle.rawHandle.id === this.edge.targetHandle);
|
|
652
665
|
}
|
|
653
666
|
else {
|
|
654
|
-
target = this.target
|
|
667
|
+
target = this.target()?.handles()
|
|
655
668
|
.find(handle => handle.rawHandle.type === 'target');
|
|
656
669
|
}
|
|
657
670
|
// TODO: don't like this
|
|
@@ -732,7 +745,11 @@ class NodesChangeService {
|
|
|
732
745
|
.pipe(pairwise(), map(([oldList, newList]) => newList.filter(node => !oldList.includes(node))), filter((nodes) => !!nodes.length), map((nodes) => nodes.map(node => ({ type: 'add', id: node.node.id }))));
|
|
733
746
|
this.nodeRemoveChange$ = toObservable(this.entitiesService.nodes)
|
|
734
747
|
.pipe(pairwise(), map(([oldList, newList]) => oldList.filter(node => !newList.includes(node))), filter((nodes) => !!nodes.length), map((nodes) => nodes.map(node => ({ type: 'remove', id: node.node.id }))));
|
|
735
|
-
this.
|
|
748
|
+
this.nodeSelectedChange$ = toObservable(this.entitiesService.nodes)
|
|
749
|
+
.pipe(switchMap((nodes) => merge(...nodes.map(node => node.selected$.pipe(distinctUntilChanged(), skip(1), map(() => node))))), map((changedNode) => [
|
|
750
|
+
{ type: 'select', id: changedNode.node.id, selected: changedNode.selected() }
|
|
751
|
+
]));
|
|
752
|
+
this.changes$ = merge(this.nodesPositionChange$, this.nodeAddChange$, this.nodeRemoveChange$, this.nodeSelectedChange$).pipe(
|
|
736
753
|
// this fixes a bug when on fire node event change,
|
|
737
754
|
// you can't get valid list of detached edges
|
|
738
755
|
observeOn(asyncScheduler));
|
|
@@ -752,7 +769,7 @@ class EdgeChangesService {
|
|
|
752
769
|
this.edgeDetachedChange$ = merge(toObservable(computed(() => {
|
|
753
770
|
const nodes = this.entitiesService.nodes();
|
|
754
771
|
const edges = untracked(this.entitiesService.edges);
|
|
755
|
-
return edges.filter(({ source, target }) => !nodes.includes(source) || !nodes.includes(target));
|
|
772
|
+
return edges.filter(({ source, target }) => !nodes.includes(source()) || !nodes.includes(target()));
|
|
756
773
|
})), toObservable(this.entitiesService.edges).pipe(switchMap((edges) => {
|
|
757
774
|
return zip(...edges.map(e => e.detached$.pipe(map(() => e))));
|
|
758
775
|
}), map((edges) => edges.filter(e => e.detached())),
|
|
@@ -769,7 +786,11 @@ class EdgeChangesService {
|
|
|
769
786
|
.pipe(pairwise(), map(([oldList, newList]) => {
|
|
770
787
|
return oldList.filter(edge => !newList.includes(edge));
|
|
771
788
|
}), filter(edges => !!edges.length), map((edges) => edges.map(({ edge }) => ({ type: 'remove', id: edge.id }))));
|
|
772
|
-
this.
|
|
789
|
+
this.edgeSelectChange$ = toObservable(this.entitiesService.edges)
|
|
790
|
+
.pipe(switchMap((edges) => merge(...edges.map(edge => edge.selected$.pipe(distinctUntilChanged(), skip(1), map(() => edge))))), map((changedEdge) => [
|
|
791
|
+
{ type: 'select', id: changedEdge.edge.id, selected: changedEdge.selected() }
|
|
792
|
+
]));
|
|
793
|
+
this.changes$ = merge(this.edgeDetachedChange$, this.edgeAddChange$, this.edgeRemoveChange$, this.edgeSelectChange$)
|
|
773
794
|
.pipe(
|
|
774
795
|
// this fixes the case when user gets 'deteched' changes
|
|
775
796
|
// and tries to delete these edges inside stream
|
|
@@ -818,6 +839,25 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
|
|
|
818
839
|
type: Output
|
|
819
840
|
}] } });
|
|
820
841
|
|
|
842
|
+
class NodeRenderingService {
|
|
843
|
+
constructor() {
|
|
844
|
+
this.flowEntitiesService = inject(FlowEntitiesService);
|
|
845
|
+
this.nodes = computed(() => {
|
|
846
|
+
return this.flowEntitiesService.nodes()
|
|
847
|
+
.sort((aNode, bNode) => aNode.renderOrder() - bNode.renderOrder());
|
|
848
|
+
});
|
|
849
|
+
}
|
|
850
|
+
pullNode(node) {
|
|
851
|
+
const maxOrder = Math.max(...this.flowEntitiesService.nodes().map((n) => n.renderOrder()));
|
|
852
|
+
node.renderOrder.set(maxOrder + 1);
|
|
853
|
+
}
|
|
854
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NodeRenderingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
855
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NodeRenderingService }); }
|
|
856
|
+
}
|
|
857
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NodeRenderingService, decorators: [{
|
|
858
|
+
type: Injectable
|
|
859
|
+
}] });
|
|
860
|
+
|
|
821
861
|
class HandleService {
|
|
822
862
|
constructor() {
|
|
823
863
|
this.node = signal(null);
|
|
@@ -825,14 +865,13 @@ class HandleService {
|
|
|
825
865
|
createHandle(newHandle) {
|
|
826
866
|
const node = this.node();
|
|
827
867
|
if (node) {
|
|
828
|
-
node.
|
|
868
|
+
node.handles.update(handles => [...handles, newHandle]);
|
|
829
869
|
}
|
|
830
870
|
}
|
|
831
871
|
destroyHandle(handleToDestoy) {
|
|
832
872
|
const node = this.node();
|
|
833
|
-
// TODO: microtask
|
|
834
873
|
if (node) {
|
|
835
|
-
|
|
874
|
+
node.handles.update(handles => handles.filter(handle => handle !== handleToDestoy));
|
|
836
875
|
}
|
|
837
876
|
}
|
|
838
877
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HandleService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
@@ -842,39 +881,199 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
|
|
|
842
881
|
type: Injectable
|
|
843
882
|
}] });
|
|
844
883
|
|
|
884
|
+
class HandleModel {
|
|
885
|
+
constructor(rawHandle, parentNode) {
|
|
886
|
+
this.rawHandle = rawHandle;
|
|
887
|
+
this.parentNode = parentNode;
|
|
888
|
+
this.strokeWidth = 2;
|
|
889
|
+
/**
|
|
890
|
+
* Pre-computed size for default handle, changed dynamically
|
|
891
|
+
* for custom handles
|
|
892
|
+
*/
|
|
893
|
+
this.size = signal({
|
|
894
|
+
width: 10 + (2 * this.strokeWidth),
|
|
895
|
+
height: 10 + (2 * this.strokeWidth)
|
|
896
|
+
});
|
|
897
|
+
this.offset = computed(() => {
|
|
898
|
+
switch (this.rawHandle.position) {
|
|
899
|
+
case 'left': return {
|
|
900
|
+
x: 0,
|
|
901
|
+
y: this.parentPosition().y + (this.parentSize().height / 2)
|
|
902
|
+
};
|
|
903
|
+
case 'right': return {
|
|
904
|
+
x: this.parentNode.size().width,
|
|
905
|
+
y: this.parentPosition().y + (this.parentSize().height / 2)
|
|
906
|
+
};
|
|
907
|
+
case 'top': return {
|
|
908
|
+
x: this.parentPosition().x + (this.parentSize().width / 2),
|
|
909
|
+
y: 0
|
|
910
|
+
};
|
|
911
|
+
case 'bottom': return {
|
|
912
|
+
x: this.parentPosition().x + this.parentSize().width / 2,
|
|
913
|
+
y: this.parentNode.size().height
|
|
914
|
+
};
|
|
915
|
+
}
|
|
916
|
+
});
|
|
917
|
+
this.sizeOffset = computed(() => {
|
|
918
|
+
switch (this.rawHandle.position) {
|
|
919
|
+
case 'left': return { x: -(this.size().width / 2), y: 0 };
|
|
920
|
+
case 'right': return { x: this.size().width / 2, y: 0 };
|
|
921
|
+
case 'top': return { x: 0, y: -(this.size().height / 2) };
|
|
922
|
+
case 'bottom': return { x: 0, y: this.size().height / 2 };
|
|
923
|
+
}
|
|
924
|
+
});
|
|
925
|
+
this.pointAbsolute = computed(() => {
|
|
926
|
+
return {
|
|
927
|
+
x: this.parentNode.point().x + this.offset().x + this.sizeOffset().x,
|
|
928
|
+
y: this.parentNode.point().y + this.offset().y + this.sizeOffset().y,
|
|
929
|
+
};
|
|
930
|
+
});
|
|
931
|
+
this.state = signal('idle');
|
|
932
|
+
this.updateParentSizeAndPosition$ = new Subject();
|
|
933
|
+
this.parentSize = toSignal(this.updateParentSizeAndPosition$.pipe(map(() => ({
|
|
934
|
+
width: this.parentReference.offsetWidth,
|
|
935
|
+
height: this.parentReference.offsetHeight
|
|
936
|
+
}))), {
|
|
937
|
+
initialValue: { width: 0, height: 0 }
|
|
938
|
+
});
|
|
939
|
+
this.parentPosition = toSignal(this.updateParentSizeAndPosition$.pipe(map(() => ({
|
|
940
|
+
x: this.parentReference.offsetLeft,
|
|
941
|
+
y: this.parentReference.offsetTop
|
|
942
|
+
}))), {
|
|
943
|
+
initialValue: { x: 0, y: 0 }
|
|
944
|
+
});
|
|
945
|
+
this.parentReference = this.rawHandle.parentReference;
|
|
946
|
+
this.template = this.rawHandle.template;
|
|
947
|
+
this.templateContext = {
|
|
948
|
+
$implicit: {
|
|
949
|
+
point: this.offset,
|
|
950
|
+
state: this.state
|
|
951
|
+
}
|
|
952
|
+
};
|
|
953
|
+
}
|
|
954
|
+
updateParent() {
|
|
955
|
+
this.updateParentSizeAndPosition$.next();
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
function resizable(elems, zone) {
|
|
960
|
+
return new Observable((subscriber) => {
|
|
961
|
+
let ro = new ResizeObserver((entries) => {
|
|
962
|
+
zone.run(() => subscriber.next(entries));
|
|
963
|
+
});
|
|
964
|
+
elems.forEach(e => ro.observe(e));
|
|
965
|
+
return () => ro.disconnect();
|
|
966
|
+
});
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
function InjectionContext(target, key, descriptor) {
|
|
970
|
+
const originalMethod = descriptor.value;
|
|
971
|
+
descriptor.value = function (...args) {
|
|
972
|
+
if (implementsWithInjector(this)) {
|
|
973
|
+
return runInInjectionContext(this.injector, () => originalMethod.apply(this, args));
|
|
974
|
+
}
|
|
975
|
+
else {
|
|
976
|
+
throw new Error('Class that contains decorated method must extends WithInjectorDirective class');
|
|
977
|
+
}
|
|
978
|
+
};
|
|
979
|
+
// Return the modified descriptor
|
|
980
|
+
return descriptor;
|
|
981
|
+
}
|
|
982
|
+
const implementsWithInjector = (instance) => {
|
|
983
|
+
return 'injector' in instance && 'get' in instance.injector;
|
|
984
|
+
};
|
|
985
|
+
|
|
986
|
+
function Microtask(target, key, descriptor) {
|
|
987
|
+
const originalMethod = descriptor.value;
|
|
988
|
+
descriptor.value = function (...args) {
|
|
989
|
+
queueMicrotask(() => {
|
|
990
|
+
originalMethod?.apply(this, args);
|
|
991
|
+
});
|
|
992
|
+
};
|
|
993
|
+
// Return the modified descriptor
|
|
994
|
+
return descriptor;
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
class HandleSizeControllerDirective {
|
|
998
|
+
constructor() {
|
|
999
|
+
this.handleWrapper = inject(ElementRef);
|
|
1000
|
+
}
|
|
1001
|
+
ngAfterViewInit() {
|
|
1002
|
+
const element = this.handleWrapper.nativeElement;
|
|
1003
|
+
const rect = element.getBBox();
|
|
1004
|
+
const stroke = getChildStrokeWidth(element);
|
|
1005
|
+
this.handleModel.size.set({
|
|
1006
|
+
width: rect.width + stroke,
|
|
1007
|
+
height: rect.height + stroke
|
|
1008
|
+
});
|
|
1009
|
+
}
|
|
1010
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HandleSizeControllerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1011
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: HandleSizeControllerDirective, selector: "[handleSizeController]", inputs: { handleModel: ["handleSizeController", "handleModel"] }, ngImport: i0 }); }
|
|
1012
|
+
}
|
|
1013
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HandleSizeControllerDirective, decorators: [{
|
|
1014
|
+
type: Directive,
|
|
1015
|
+
args: [{ selector: '[handleSizeController]' }]
|
|
1016
|
+
}], propDecorators: { handleModel: [{
|
|
1017
|
+
type: Input,
|
|
1018
|
+
args: [{ required: true, alias: 'handleSizeController' }]
|
|
1019
|
+
}] } });
|
|
1020
|
+
function getChildStrokeWidth(element) {
|
|
1021
|
+
const child = element.firstElementChild;
|
|
1022
|
+
if (child) {
|
|
1023
|
+
const stroke = getComputedStyle(child).strokeWidth;
|
|
1024
|
+
const strokeAsNumber = Number(stroke.replace('px', ''));
|
|
1025
|
+
if (isNaN(strokeAsNumber)) {
|
|
1026
|
+
return 0;
|
|
1027
|
+
}
|
|
1028
|
+
return strokeAsNumber;
|
|
1029
|
+
}
|
|
1030
|
+
return 0;
|
|
1031
|
+
}
|
|
1032
|
+
|
|
845
1033
|
class NodeComponent {
|
|
846
1034
|
constructor() {
|
|
847
|
-
this.handleService = inject(HandleService);
|
|
848
1035
|
this.injector = inject(Injector);
|
|
1036
|
+
this.handleService = inject(HandleService);
|
|
1037
|
+
this.zone = inject(NgZone);
|
|
849
1038
|
this.draggableService = inject(DraggableService);
|
|
850
1039
|
this.flowStatusService = inject(FlowStatusService);
|
|
851
1040
|
this.flowEntitiesService = inject(FlowEntitiesService);
|
|
1041
|
+
this.nodeRenderingService = inject(NodeRenderingService);
|
|
1042
|
+
this.flowSettingsService = inject(FlowSettingsService);
|
|
1043
|
+
this.selectionService = inject(SelectionService);
|
|
852
1044
|
this.hostRef = inject(ElementRef);
|
|
853
1045
|
this.showMagnet = computed(() => this.flowStatusService.status().state === 'connection-start' ||
|
|
854
1046
|
this.flowStatusService.status().state === 'connection-validation');
|
|
855
|
-
this.
|
|
856
|
-
this.targetHandleState = signal('idle');
|
|
1047
|
+
this.subscription = new Subscription();
|
|
857
1048
|
}
|
|
858
1049
|
ngOnInit() {
|
|
859
1050
|
this.handleService.node.set(this.nodeModel);
|
|
860
1051
|
this.draggableService.toggleDraggable(this.hostRef.nativeElement, this.nodeModel);
|
|
1052
|
+
const sub = this.nodeModel.handles$
|
|
1053
|
+
.pipe(switchMap((handles) => resizable(handles.map(h => h.parentReference), this.zone)
|
|
1054
|
+
.pipe(map(() => handles))), tap((handles) => handles.forEach(h => h.updateParent())))
|
|
1055
|
+
.subscribe();
|
|
1056
|
+
this.subscription.add(sub);
|
|
861
1057
|
}
|
|
862
1058
|
ngAfterViewInit() {
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
1059
|
+
this.setInitialHandles();
|
|
1060
|
+
if (this.nodeModel.node.type === 'default') {
|
|
1061
|
+
const { width, height } = this.nodeContentRef.nativeElement.getBBox();
|
|
1062
|
+
this.nodeModel.size.set({ width, height });
|
|
1063
|
+
}
|
|
1064
|
+
if (this.nodeModel.node.type === 'html-template') {
|
|
1065
|
+
const sub = resizable([this.htmlWrapperRef.nativeElement], this.zone)
|
|
1066
|
+
.pipe(startWith(null), tap(() => {
|
|
870
1067
|
const width = this.htmlWrapperRef.nativeElement.clientWidth;
|
|
871
1068
|
const height = this.htmlWrapperRef.nativeElement.clientHeight;
|
|
872
1069
|
this.nodeModel.size.set({ width, height });
|
|
873
|
-
}
|
|
874
|
-
|
|
1070
|
+
})).subscribe();
|
|
1071
|
+
this.subscription.add(sub);
|
|
1072
|
+
}
|
|
875
1073
|
}
|
|
876
1074
|
ngOnDestroy() {
|
|
877
1075
|
this.draggableService.destroy(this.hostRef.nativeElement);
|
|
1076
|
+
this.subscription.unsubscribe();
|
|
878
1077
|
}
|
|
879
1078
|
startConnection(event, handle) {
|
|
880
1079
|
// ignore drag by stopping propagation
|
|
@@ -912,27 +1111,55 @@ class NodeComponent {
|
|
|
912
1111
|
sourceHandle: sourceHandle.rawHandle.id,
|
|
913
1112
|
targetHandle: targetHandle.rawHandle.id
|
|
914
1113
|
});
|
|
915
|
-
|
|
1114
|
+
targetHandle.state.set(valid ? 'valid' : 'invalid');
|
|
916
1115
|
this.flowStatusService.setConnectionValidationStatus(valid, sourceNode, targetNode, sourceHandle, targetHandle);
|
|
917
1116
|
}
|
|
918
1117
|
}
|
|
919
1118
|
/**
|
|
920
1119
|
* TODO srp
|
|
921
1120
|
*/
|
|
922
|
-
resetValidateTargetHandle() {
|
|
923
|
-
|
|
1121
|
+
resetValidateTargetHandle(targetHandle) {
|
|
1122
|
+
targetHandle.state.set('idle');
|
|
924
1123
|
// drop back to start status
|
|
925
1124
|
const status = this.flowStatusService.status();
|
|
926
1125
|
if (status.state === 'connection-validation') {
|
|
927
1126
|
this.flowStatusService.setConnectionStartStatus(status.payload.sourceNode, status.payload.sourceHandle);
|
|
928
1127
|
}
|
|
929
1128
|
}
|
|
1129
|
+
pullNode() {
|
|
1130
|
+
this.nodeRenderingService.pullNode(this.nodeModel);
|
|
1131
|
+
}
|
|
1132
|
+
selectNode() {
|
|
1133
|
+
if (this.flowSettingsService.entitiesSelectable()) {
|
|
1134
|
+
this.selectionService.select(this.nodeModel);
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
setInitialHandles() {
|
|
1138
|
+
if (this.nodeModel.node.type === 'default') {
|
|
1139
|
+
this.handleService.createHandle(new HandleModel({
|
|
1140
|
+
position: this.nodeModel.sourcePosition(),
|
|
1141
|
+
type: 'source',
|
|
1142
|
+
parentReference: this.htmlWrapperRef.nativeElement
|
|
1143
|
+
}, this.nodeModel));
|
|
1144
|
+
this.handleService.createHandle(new HandleModel({
|
|
1145
|
+
position: this.nodeModel.targetPosition(),
|
|
1146
|
+
type: 'target',
|
|
1147
|
+
parentReference: this.htmlWrapperRef.nativeElement
|
|
1148
|
+
}, this.nodeModel));
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
930
1151
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NodeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
931
|
-
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 #nodeContent\n width=\"100\"\n height=\"50\"\n>\n <div
|
|
1152
|
+
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 width=\"100\"\n height=\"50\"\n (mousedown)=\"pullNode(); selectNode()\"\n>\n <div\n #htmlWrapper\n class=\"default-node\"\n [class.default-node_selected]=\"nodeModel.selected()\"\n [innerHTML]=\"nodeModel.node.text ?? ''\"\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<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 (mousedown)=\"handle.rawHandle.type === 'source' ? startConnection($event, handle) : null\"\n (mouseup)=\"handle.rawHandle.type === 'target' ? endConnection() : null\"\n />\n\n <svg:g\n *ngIf=\"handle.template\"\n [handleSizeController]=\"handle\"\n (mousedown)=\"handle.rawHandle.type === 'source' ? startConnection($event, handle) : null\"\n (mouseup)=\"handle.rawHandle.type === 'target' ? endConnection() : null\"\n >\n <ng-container *ngTemplateOutlet=\"handle.template; context: handle.templateContext\" />\n </svg:g>\n\n <svg:circle\n *ngIf=\"handle.rawHandle.type === 'target' && showMagnet()\"\n class=\"magnet\"\n [attr.r]=\"nodeModel.magnetRadius\"\n [attr.cx]=\"handle.offset().x\"\n [attr.cy]=\"handle.offset().y\"\n (mouseup)=\"endConnection(); resetValidateTargetHandle(handle)\"\n (mouseover)=\"validateTargetHandle(handle)\"\n (mouseout)=\"resetValidateTargetHandle(handle)\"\n />\n</ng-container>\n\n", styles: [".wrapper{width:max-content}.magnet{opacity:0}.default-node{max-width:100px;max-height:100px;width:100px;height:50px;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.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: "directive", type: HandleSizeControllerDirective, selector: "[handleSizeController]", inputs: ["handleSizeController"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
932
1153
|
}
|
|
1154
|
+
__decorate([
|
|
1155
|
+
Microtask
|
|
1156
|
+
], NodeComponent.prototype, "ngAfterViewInit", null);
|
|
1157
|
+
__decorate([
|
|
1158
|
+
InjectionContext
|
|
1159
|
+
], NodeComponent.prototype, "setInitialHandles", null);
|
|
933
1160
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NodeComponent, decorators: [{
|
|
934
1161
|
type: Component,
|
|
935
|
-
args: [{ selector: 'g[node]', changeDetection: ChangeDetectionStrategy.OnPush, providers: [HandleService], template: "<svg:foreignObject\n *ngIf=\"nodeModel.node.type === 'default'\"\n #nodeContent\n width=\"100\"\n height=\"50\"\n>\n <div
|
|
1162
|
+
args: [{ selector: 'g[node]', changeDetection: ChangeDetectionStrategy.OnPush, providers: [HandleService], template: "<svg:foreignObject\n *ngIf=\"nodeModel.node.type === 'default'\"\n class=\"selectable\"\n #nodeContent\n width=\"100\"\n height=\"50\"\n (mousedown)=\"pullNode(); selectNode()\"\n>\n <div\n #htmlWrapper\n class=\"default-node\"\n [class.default-node_selected]=\"nodeModel.selected()\"\n [innerHTML]=\"nodeModel.node.text ?? ''\"\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<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 (mousedown)=\"handle.rawHandle.type === 'source' ? startConnection($event, handle) : null\"\n (mouseup)=\"handle.rawHandle.type === 'target' ? endConnection() : null\"\n />\n\n <svg:g\n *ngIf=\"handle.template\"\n [handleSizeController]=\"handle\"\n (mousedown)=\"handle.rawHandle.type === 'source' ? startConnection($event, handle) : null\"\n (mouseup)=\"handle.rawHandle.type === 'target' ? endConnection() : null\"\n >\n <ng-container *ngTemplateOutlet=\"handle.template; context: handle.templateContext\" />\n </svg:g>\n\n <svg:circle\n *ngIf=\"handle.rawHandle.type === 'target' && showMagnet()\"\n class=\"magnet\"\n [attr.r]=\"nodeModel.magnetRadius\"\n [attr.cx]=\"handle.offset().x\"\n [attr.cy]=\"handle.offset().y\"\n (mouseup)=\"endConnection(); resetValidateTargetHandle(handle)\"\n (mouseover)=\"validateTargetHandle(handle)\"\n (mouseout)=\"resetValidateTargetHandle(handle)\"\n />\n</ng-container>\n\n", styles: [".wrapper{width:max-content}.magnet{opacity:0}.default-node{max-width:100px;max-height:100px;width:100px;height:50px;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"] }]
|
|
936
1163
|
}], propDecorators: { nodeModel: [{
|
|
937
1164
|
type: Input
|
|
938
1165
|
}], nodeHtmlTemplate: [{
|
|
@@ -943,7 +1170,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
|
|
|
943
1170
|
}], htmlWrapperRef: [{
|
|
944
1171
|
type: ViewChild,
|
|
945
1172
|
args: ['htmlWrapper']
|
|
946
|
-
}] } });
|
|
1173
|
+
}], ngAfterViewInit: [], setInitialHandles: [] } });
|
|
947
1174
|
|
|
948
1175
|
class EdgeLabelComponent {
|
|
949
1176
|
constructor() {
|
|
@@ -964,14 +1191,12 @@ class EdgeLabelComponent {
|
|
|
964
1191
|
}
|
|
965
1192
|
set point(point) { this.pointSignal.set(point); }
|
|
966
1193
|
ngAfterViewInit() {
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
this.model.size.set({ width, height });
|
|
974
|
-
});
|
|
1194
|
+
// this is a fix for visual artifact in chrome that for some reason adresses only for edge label.
|
|
1195
|
+
// the bug reproduces if edgeLabelWrapperRef size fully matched the size of parent foreignObject
|
|
1196
|
+
const MAGIC_VALUE_TO_FIX_GLITCH_IN_CHROME = 2;
|
|
1197
|
+
const width = this.edgeLabelWrapperRef.nativeElement.clientWidth + MAGIC_VALUE_TO_FIX_GLITCH_IN_CHROME;
|
|
1198
|
+
const height = this.edgeLabelWrapperRef.nativeElement.clientHeight + MAGIC_VALUE_TO_FIX_GLITCH_IN_CHROME;
|
|
1199
|
+
this.model.size.set({ width, height });
|
|
975
1200
|
}
|
|
976
1201
|
getLabelContext() {
|
|
977
1202
|
return {
|
|
@@ -984,6 +1209,9 @@ class EdgeLabelComponent {
|
|
|
984
1209
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: EdgeLabelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
985
1210
|
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: EdgeLabelComponent, selector: "g[edgeLabel]", inputs: { model: "model", edgeModel: "edgeModel", point: "point", htmlTemplate: "htmlTemplate" }, viewQueries: [{ propertyName: "edgeLabelWrapperRef", first: true, predicate: ["edgeLabelWrapper"], descendants: true }], ngImport: i0, template: "<svg:foreignObject\n [attr.x]=\"edgeLabelPoint().x\"\n [attr.y]=\"edgeLabelPoint().y\"\n [attr.width]=\"model.size().width\"\n [attr.height]=\"model.size().height\"\n *ngIf=\"model.edgeLabel.type === 'html-template' && htmlTemplate\"\n>\n <div #edgeLabelWrapper class=\"edge-label-wrapper\">\n <ng-container\n *ngTemplateOutlet=\"htmlTemplate; context: getLabelContext()\"\n />\n </div>\n</svg:foreignObject>\n", styles: [".edge-label-wrapper{width:max-content;margin-top:1px;margin-left:1px}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
986
1211
|
}
|
|
1212
|
+
__decorate([
|
|
1213
|
+
Microtask
|
|
1214
|
+
], EdgeLabelComponent.prototype, "ngAfterViewInit", null);
|
|
987
1215
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: EdgeLabelComponent, decorators: [{
|
|
988
1216
|
type: Component,
|
|
989
1217
|
args: [{ selector: 'g[edgeLabel]', changeDetection: ChangeDetectionStrategy.OnPush, template: "<svg:foreignObject\n [attr.x]=\"edgeLabelPoint().x\"\n [attr.y]=\"edgeLabelPoint().y\"\n [attr.width]=\"model.size().width\"\n [attr.height]=\"model.size().height\"\n *ngIf=\"model.edgeLabel.type === 'html-template' && htmlTemplate\"\n>\n <div #edgeLabelWrapper class=\"edge-label-wrapper\">\n <ng-container\n *ngTemplateOutlet=\"htmlTemplate; context: getLabelContext()\"\n />\n </div>\n</svg:foreignObject>\n", styles: [".edge-label-wrapper{width:max-content;margin-top:1px;margin-left:1px}\n"] }]
|
|
@@ -998,10 +1226,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
|
|
|
998
1226
|
}], edgeLabelWrapperRef: [{
|
|
999
1227
|
type: ViewChild,
|
|
1000
1228
|
args: ['edgeLabelWrapper']
|
|
1001
|
-
}] } });
|
|
1229
|
+
}], ngAfterViewInit: [] } });
|
|
1002
1230
|
|
|
1003
1231
|
class EdgeComponent {
|
|
1004
1232
|
constructor() {
|
|
1233
|
+
this.injector = inject(Injector);
|
|
1234
|
+
this.selectionService = inject(SelectionService);
|
|
1235
|
+
this.flowSettingsService = inject(FlowSettingsService);
|
|
1005
1236
|
this.markerStartUrl = computed(() => {
|
|
1006
1237
|
const marker = this.model.edge.markers?.start;
|
|
1007
1238
|
return marker ? `url(#${hashCode(JSON.stringify(marker))})` : '';
|
|
@@ -1010,7 +1241,6 @@ class EdgeComponent {
|
|
|
1010
1241
|
const marker = this.model.edge.markers?.end;
|
|
1011
1242
|
return marker ? `url(#${hashCode(JSON.stringify(marker))})` : '';
|
|
1012
1243
|
});
|
|
1013
|
-
this.defaultColor = 'rgb(177, 177, 183)';
|
|
1014
1244
|
}
|
|
1015
1245
|
ngOnInit() {
|
|
1016
1246
|
this.edgeContext = {
|
|
@@ -1019,16 +1249,24 @@ class EdgeComponent {
|
|
|
1019
1249
|
edge: this.model.edge,
|
|
1020
1250
|
path: computed(() => this.model.path().path),
|
|
1021
1251
|
markerStart: this.markerStartUrl,
|
|
1022
|
-
markerEnd: this.markerEndUrl
|
|
1252
|
+
markerEnd: this.markerEndUrl,
|
|
1253
|
+
selected: this.model.selected.asReadonly()
|
|
1023
1254
|
}
|
|
1024
1255
|
};
|
|
1025
1256
|
}
|
|
1257
|
+
onEdgeMouseDown() {
|
|
1258
|
+
if (this.flowSettingsService.entitiesSelectable()) {
|
|
1259
|
+
this.selectionService.select(this.model);
|
|
1260
|
+
}
|
|
1261
|
+
}
|
|
1026
1262
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: EdgeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1027
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: EdgeComponent, selector: "g[edge]", inputs: { model: "model", edgeTemplate: "edgeTemplate", edgeLabelHtmlTemplate: "edgeLabelHtmlTemplate" }, ngImport: i0, template: "<svg:path\n *ngIf=\"model.type === 'default'\"\n [attr.d]=\"model.path().path\"\n [attr.marker-start]=\"markerStartUrl()\"\n [attr.marker-end]=\"markerEndUrl()\"\n
|
|
1263
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: EdgeComponent, selector: "g[edge]", inputs: { model: "model", edgeTemplate: "edgeTemplate", edgeLabelHtmlTemplate: "edgeLabelHtmlTemplate" }, host: { classAttribute: "selectable" }, ngImport: i0, template: "<svg:path\n *ngIf=\"model.type === 'default'\"\n (mousedown)=\"onEdgeMouseDown()\"\n [attr.d]=\"model.path().path\"\n [attr.marker-start]=\"markerStartUrl()\"\n [attr.marker-end]=\"markerEndUrl()\"\n class=\"edge\"\n [class.edge_selected]=\"model.selected()\"\n/>\n\n<ng-container *ngIf=\"model.type === 'template' && edgeTemplate\">\n <ng-container\n [ngTemplateOutlet]=\"edgeTemplate\"\n [ngTemplateOutletContext]=\"edgeContext\"\n [ngTemplateOutletInjector]=\"injector\"\n ></ng-container>\n</ng-container>\n\n<ng-container *ngIf=\"model.edgeLabels?.start as label\">\n <svg:g edgeLabel\n [model]=\"label\"\n [point]=\"model.path().points.start\"\n [edgeModel]=\"model\"\n [htmlTemplate]=\"edgeLabelHtmlTemplate\"\n />\n</ng-container>\n\n<ng-container *ngIf=\"model.edgeLabels?.center as label\">\n <svg:g edgeLabel\n [model]=\"label\"\n [point]=\"model.path().points.center\"\n [edgeModel]=\"model\"\n [htmlTemplate]=\"edgeLabelHtmlTemplate\"\n />\n</ng-container>\n\n<ng-container *ngIf=\"model.edgeLabels?.end as label\">\n <svg:g edgeLabel\n [model]=\"label\"\n [point]=\"model.path().points.end\"\n [edgeModel]=\"model\"\n [htmlTemplate]=\"edgeLabelHtmlTemplate\"\n />\n</ng-container>\n", styles: [".edge{fill:none;stroke-width:2;stroke:#b1b1b7}.edge_selected{stroke-width:2.5;stroke:#0f4c75}\n"], dependencies: [{ 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: EdgeLabelComponent, selector: "g[edgeLabel]", inputs: ["model", "edgeModel", "point", "htmlTemplate"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
1028
1264
|
}
|
|
1029
1265
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: EdgeComponent, decorators: [{
|
|
1030
1266
|
type: Component,
|
|
1031
|
-
args: [{ selector: 'g[edge]', changeDetection: ChangeDetectionStrategy.OnPush,
|
|
1267
|
+
args: [{ selector: 'g[edge]', changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
1268
|
+
'class': 'selectable'
|
|
1269
|
+
}, template: "<svg:path\n *ngIf=\"model.type === 'default'\"\n (mousedown)=\"onEdgeMouseDown()\"\n [attr.d]=\"model.path().path\"\n [attr.marker-start]=\"markerStartUrl()\"\n [attr.marker-end]=\"markerEndUrl()\"\n class=\"edge\"\n [class.edge_selected]=\"model.selected()\"\n/>\n\n<ng-container *ngIf=\"model.type === 'template' && edgeTemplate\">\n <ng-container\n [ngTemplateOutlet]=\"edgeTemplate\"\n [ngTemplateOutletContext]=\"edgeContext\"\n [ngTemplateOutletInjector]=\"injector\"\n ></ng-container>\n</ng-container>\n\n<ng-container *ngIf=\"model.edgeLabels?.start as label\">\n <svg:g edgeLabel\n [model]=\"label\"\n [point]=\"model.path().points.start\"\n [edgeModel]=\"model\"\n [htmlTemplate]=\"edgeLabelHtmlTemplate\"\n />\n</ng-container>\n\n<ng-container *ngIf=\"model.edgeLabels?.center as label\">\n <svg:g edgeLabel\n [model]=\"label\"\n [point]=\"model.path().points.center\"\n [edgeModel]=\"model\"\n [htmlTemplate]=\"edgeLabelHtmlTemplate\"\n />\n</ng-container>\n\n<ng-container *ngIf=\"model.edgeLabels?.end as label\">\n <svg:g edgeLabel\n [model]=\"label\"\n [point]=\"model.path().points.end\"\n [edgeModel]=\"model\"\n [htmlTemplate]=\"edgeLabelHtmlTemplate\"\n />\n</ng-container>\n", styles: [".edge{fill:none;stroke-width:2;stroke:#b1b1b7}.edge_selected{stroke-width:2.5;stroke:#0f4c75}\n"] }]
|
|
1032
1270
|
}], propDecorators: { model: [{
|
|
1033
1271
|
type: Input
|
|
1034
1272
|
}], edgeTemplate: [{
|
|
@@ -1227,6 +1465,8 @@ class VflowComponent {
|
|
|
1227
1465
|
this.flowEntitiesService = inject(FlowEntitiesService);
|
|
1228
1466
|
this.nodesChangeService = inject(NodesChangeService);
|
|
1229
1467
|
this.edgesChangeService = inject(EdgeChangesService);
|
|
1468
|
+
this.nodeRenderingService = inject(NodeRenderingService);
|
|
1469
|
+
this.flowSettingsService = inject(FlowSettingsService);
|
|
1230
1470
|
this.injector = inject(Injector);
|
|
1231
1471
|
/**
|
|
1232
1472
|
* Minimum zoom value
|
|
@@ -1240,6 +1480,8 @@ class VflowComponent {
|
|
|
1240
1480
|
* Background color for flow
|
|
1241
1481
|
*/
|
|
1242
1482
|
this.background = '#FFFFFF';
|
|
1483
|
+
this.nodeModels = computed(() => this.nodeRenderingService.nodes());
|
|
1484
|
+
this.edgeModels = computed(() => this.flowEntitiesService.validEdges());
|
|
1243
1485
|
// #endregion
|
|
1244
1486
|
// #region SIGNAL_API
|
|
1245
1487
|
/**
|
|
@@ -1270,8 +1512,8 @@ class VflowComponent {
|
|
|
1270
1512
|
*/
|
|
1271
1513
|
this.edgesChange$ = this.edgesChangeService.changes$;
|
|
1272
1514
|
// #endregion
|
|
1273
|
-
|
|
1274
|
-
this.
|
|
1515
|
+
this.flowWidth = this.flowSettingsService.flowWidth;
|
|
1516
|
+
this.flowHeight = this.flowSettingsService.flowHeight;
|
|
1275
1517
|
this.markers = this.flowEntitiesService.markers;
|
|
1276
1518
|
}
|
|
1277
1519
|
// #endregion
|
|
@@ -1284,7 +1526,7 @@ class VflowComponent {
|
|
|
1284
1526
|
* - 'auto' to compute size based on parent element size
|
|
1285
1527
|
*/
|
|
1286
1528
|
set view(view) {
|
|
1287
|
-
this.
|
|
1529
|
+
this.flowSettingsService.view.set(view);
|
|
1288
1530
|
}
|
|
1289
1531
|
/**
|
|
1290
1532
|
* Object that controls flow direction.
|
|
@@ -1295,7 +1537,13 @@ class VflowComponent {
|
|
|
1295
1537
|
* @deprecated
|
|
1296
1538
|
*/
|
|
1297
1539
|
set handlePositions(handlePositions) {
|
|
1298
|
-
this.
|
|
1540
|
+
this.flowSettingsService.handlePositions.set(handlePositions);
|
|
1541
|
+
}
|
|
1542
|
+
/**
|
|
1543
|
+
* Global rule if you can or can't select entities
|
|
1544
|
+
*/
|
|
1545
|
+
set entitiesSelectable(value) {
|
|
1546
|
+
this.flowSettingsService.entitiesSelectable.set(value);
|
|
1299
1547
|
}
|
|
1300
1548
|
/**
|
|
1301
1549
|
* Settings for connection (it renders when user tries to create edge between nodes)
|
|
@@ -1311,23 +1559,19 @@ class VflowComponent {
|
|
|
1311
1559
|
*/
|
|
1312
1560
|
set nodes(newNodes) {
|
|
1313
1561
|
const newModels = runInInjectionContext(this.injector, () => ReferenceKeeper.nodes(newNodes, this.flowEntitiesService.nodes()));
|
|
1314
|
-
// TODO better to solve this by DI
|
|
1315
|
-
bindFlowToNodes(this.flowModel, newModels);
|
|
1316
1562
|
// quick and dirty binding nodes to edges
|
|
1317
1563
|
addNodesToEdges(newModels, this.flowEntitiesService.edges());
|
|
1318
1564
|
this.flowEntitiesService.nodes.set(newModels);
|
|
1319
1565
|
}
|
|
1320
|
-
get nodeModels() { return this.flowEntitiesService.nodes(); }
|
|
1321
1566
|
/**
|
|
1322
1567
|
* Edges to render
|
|
1323
1568
|
*/
|
|
1324
1569
|
set edges(newEdges) {
|
|
1325
1570
|
const newModels = runInInjectionContext(this.injector, () => ReferenceKeeper.edges(newEdges, this.flowEntitiesService.edges()));
|
|
1326
1571
|
// quick and dirty binding nodes to edges
|
|
1327
|
-
addNodesToEdges(this.nodeModels, newModels);
|
|
1572
|
+
addNodesToEdges(this.nodeModels(), newModels);
|
|
1328
1573
|
this.flowEntitiesService.edges.set(newModels);
|
|
1329
1574
|
}
|
|
1330
|
-
get edgeModels() { return this.flowEntitiesService.validEdges(); }
|
|
1331
1575
|
// #region METHODS_API
|
|
1332
1576
|
/**
|
|
1333
1577
|
* Change viewport to specified state
|
|
@@ -1369,20 +1613,23 @@ class VflowComponent {
|
|
|
1369
1613
|
}
|
|
1370
1614
|
// #endregion
|
|
1371
1615
|
trackNodes(idx, { node }) {
|
|
1372
|
-
return node
|
|
1616
|
+
return node;
|
|
1373
1617
|
}
|
|
1374
1618
|
trackEdges(idx, { edge }) {
|
|
1375
|
-
return edge
|
|
1619
|
+
return edge;
|
|
1376
1620
|
}
|
|
1377
1621
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: VflowComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1378
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "16.1.0", version: "16.2.12", type: VflowComponent, selector: "vflow", inputs: { view: "view", minZoom: "minZoom", maxZoom: "maxZoom", handlePositions: "handlePositions", background: "background", connection: ["connection", "connection", (settings) => new ConnectionModel(settings)], nodes: "nodes", edges: "edges" }, providers: [
|
|
1622
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "16.1.0", version: "16.2.12", type: VflowComponent, selector: "vflow", inputs: { view: "view", minZoom: "minZoom", maxZoom: "maxZoom", handlePositions: "handlePositions", background: "background", entitiesSelectable: "entitiesSelectable", connection: ["connection", "connection", (settings) => new ConnectionModel(settings)], nodes: "nodes", edges: "edges" }, providers: [
|
|
1379
1623
|
DraggableService,
|
|
1380
1624
|
ViewportService,
|
|
1381
1625
|
FlowStatusService,
|
|
1382
1626
|
FlowEntitiesService,
|
|
1383
1627
|
NodesChangeService,
|
|
1384
|
-
EdgeChangesService
|
|
1385
|
-
|
|
1628
|
+
EdgeChangesService,
|
|
1629
|
+
NodeRenderingService,
|
|
1630
|
+
SelectionService,
|
|
1631
|
+
FlowSettingsService
|
|
1632
|
+
], 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", "onEdgesChange", "onEdgesChange"] }], ngImport: i0, template: "<svg:svg\n rootSvgRef\n rootSvgContext\n class=\"root-svg\"\n #flow\n [style.backgroundColor]=\"background\"\n [attr.width]=\"flowWidth()\"\n [attr.height]=\"flowHeight()\"\n>\n <defs [markers]=\"markers()\" flowDefs />\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: "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]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
1386
1633
|
}
|
|
1387
1634
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: VflowComponent, decorators: [{
|
|
1388
1635
|
type: Component,
|
|
@@ -1392,11 +1639,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
|
|
|
1392
1639
|
FlowStatusService,
|
|
1393
1640
|
FlowEntitiesService,
|
|
1394
1641
|
NodesChangeService,
|
|
1395
|
-
EdgeChangesService
|
|
1642
|
+
EdgeChangesService,
|
|
1643
|
+
NodeRenderingService,
|
|
1644
|
+
SelectionService,
|
|
1645
|
+
FlowSettingsService
|
|
1396
1646
|
], hostDirectives: [
|
|
1397
1647
|
connectionControllerHostDirective,
|
|
1398
1648
|
changesControllerHostDirective
|
|
1399
|
-
], template: "<svg:svg\n rootSvgRef\n rootSvgContext\n class=\"root-svg\"\n #flow\n [style.backgroundColor]=\"background\"\n [attr.width]=\"
|
|
1649
|
+
], template: "<svg:svg\n rootSvgRef\n rootSvgContext\n class=\"root-svg\"\n #flow\n [style.backgroundColor]=\"background\"\n [attr.width]=\"flowWidth()\"\n [attr.height]=\"flowHeight()\"\n>\n <defs [markers]=\"markers()\" flowDefs />\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"] }]
|
|
1400
1650
|
}], propDecorators: { view: [{
|
|
1401
1651
|
type: Input
|
|
1402
1652
|
}], minZoom: [{
|
|
@@ -1407,6 +1657,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
|
|
|
1407
1657
|
type: Input
|
|
1408
1658
|
}], background: [{
|
|
1409
1659
|
type: Input
|
|
1660
|
+
}], entitiesSelectable: [{
|
|
1661
|
+
type: Input
|
|
1410
1662
|
}], connection: [{
|
|
1411
1663
|
type: Input,
|
|
1412
1664
|
args: [{ transform: (settings) => new ConnectionModel(settings) }]
|
|
@@ -1431,43 +1683,33 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
|
|
|
1431
1683
|
type: ViewChild,
|
|
1432
1684
|
args: [MapContextDirective]
|
|
1433
1685
|
}] } });
|
|
1434
|
-
function bindFlowToNodes(flow, nodes) {
|
|
1435
|
-
nodes.forEach(n => n.bindFlow(flow));
|
|
1436
|
-
}
|
|
1437
1686
|
|
|
1438
1687
|
class HandleComponent {
|
|
1439
1688
|
constructor() {
|
|
1689
|
+
this.injector = inject(Injector);
|
|
1440
1690
|
this.handleService = inject(HandleService);
|
|
1441
1691
|
this.element = inject(ElementRef).nativeElement;
|
|
1442
1692
|
}
|
|
1443
1693
|
ngOnInit() {
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
this.
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
this.handleService.createHandle(this.model);
|
|
1454
|
-
});
|
|
1694
|
+
this.model = new HandleModel({
|
|
1695
|
+
position: this.position,
|
|
1696
|
+
type: this.type,
|
|
1697
|
+
id: this.id,
|
|
1698
|
+
parentReference: this.element.parentElement,
|
|
1699
|
+
template: this.template
|
|
1700
|
+
}, this.handleService.node());
|
|
1701
|
+
this.handleService.createHandle(this.model);
|
|
1702
|
+
queueMicrotask(() => this.model.updateParent());
|
|
1455
1703
|
}
|
|
1456
1704
|
ngOnDestroy() {
|
|
1457
1705
|
this.handleService.destroyHandle(this.model);
|
|
1458
1706
|
}
|
|
1459
|
-
parentRect() {
|
|
1460
|
-
const parent = this.element.parentElement;
|
|
1461
|
-
return {
|
|
1462
|
-
x: parent.offsetLeft,
|
|
1463
|
-
y: parent.offsetTop,
|
|
1464
|
-
width: parent.clientWidth,
|
|
1465
|
-
height: parent.clientHeight
|
|
1466
|
-
};
|
|
1467
|
-
}
|
|
1468
1707
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HandleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1469
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: HandleComponent, selector: "handle", inputs: { position: "position", type: "type", id: "id" }, ngImport: i0, template: "" }); }
|
|
1708
|
+
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: "" }); }
|
|
1470
1709
|
}
|
|
1710
|
+
__decorate([
|
|
1711
|
+
InjectionContext
|
|
1712
|
+
], HandleComponent.prototype, "ngOnInit", null);
|
|
1471
1713
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HandleComponent, decorators: [{
|
|
1472
1714
|
type: Component,
|
|
1473
1715
|
args: [{ selector: 'handle', template: "" }]
|
|
@@ -1479,6 +1721,41 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
|
|
|
1479
1721
|
args: [{ required: true }]
|
|
1480
1722
|
}], id: [{
|
|
1481
1723
|
type: Input
|
|
1724
|
+
}], template: [{
|
|
1725
|
+
type: Input
|
|
1726
|
+
}], ngOnInit: [] } });
|
|
1727
|
+
|
|
1728
|
+
class SelectableDirective {
|
|
1729
|
+
constructor() {
|
|
1730
|
+
this.flowSettingsService = inject(FlowSettingsService);
|
|
1731
|
+
this.selectionService = inject(SelectionService);
|
|
1732
|
+
this.parentEdge = inject(EdgeComponent, { optional: true });
|
|
1733
|
+
this.parentNode = inject(NodeComponent, { optional: true });
|
|
1734
|
+
}
|
|
1735
|
+
onMousedown() {
|
|
1736
|
+
const entity = this.entity();
|
|
1737
|
+
if (entity && this.flowSettingsService.entitiesSelectable()) {
|
|
1738
|
+
this.selectionService.select(entity);
|
|
1739
|
+
}
|
|
1740
|
+
}
|
|
1741
|
+
entity() {
|
|
1742
|
+
if (this.parentNode) {
|
|
1743
|
+
return this.parentNode.nodeModel;
|
|
1744
|
+
}
|
|
1745
|
+
else if (this.parentEdge) {
|
|
1746
|
+
return this.parentEdge.model;
|
|
1747
|
+
}
|
|
1748
|
+
return null;
|
|
1749
|
+
}
|
|
1750
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SelectableDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
1751
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: SelectableDirective, selector: "[selectable]", host: { listeners: { "mousedown": "onMousedown()" } }, ngImport: i0 }); }
|
|
1752
|
+
}
|
|
1753
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: SelectableDirective, decorators: [{
|
|
1754
|
+
type: Directive,
|
|
1755
|
+
args: [{ selector: '[selectable]' }]
|
|
1756
|
+
}], propDecorators: { onMousedown: [{
|
|
1757
|
+
type: HostListener,
|
|
1758
|
+
args: ['mousedown']
|
|
1482
1759
|
}] } });
|
|
1483
1760
|
|
|
1484
1761
|
const components = [
|
|
@@ -1495,6 +1772,8 @@ const directives = [
|
|
|
1495
1772
|
MapContextDirective,
|
|
1496
1773
|
RootSvgReferenceDirective,
|
|
1497
1774
|
RootSvgContextDirective,
|
|
1775
|
+
HandleSizeControllerDirective,
|
|
1776
|
+
SelectableDirective
|
|
1498
1777
|
];
|
|
1499
1778
|
const templateDirectives = [
|
|
1500
1779
|
NodeHtmlTemplateDirective,
|
|
@@ -1514,12 +1793,15 @@ class VflowModule {
|
|
|
1514
1793
|
DefsComponent, SpacePointContextDirective,
|
|
1515
1794
|
MapContextDirective,
|
|
1516
1795
|
RootSvgReferenceDirective,
|
|
1517
|
-
RootSvgContextDirective,
|
|
1796
|
+
RootSvgContextDirective,
|
|
1797
|
+
HandleSizeControllerDirective,
|
|
1798
|
+
SelectableDirective, NodeHtmlTemplateDirective,
|
|
1518
1799
|
EdgeLabelHtmlTemplateDirective,
|
|
1519
1800
|
EdgeTemplateDirective,
|
|
1520
1801
|
ConnectionTemplateDirective,
|
|
1521
1802
|
HandleTemplateDirective], imports: [CommonModule], exports: [VflowComponent,
|
|
1522
|
-
HandleComponent,
|
|
1803
|
+
HandleComponent,
|
|
1804
|
+
SelectableDirective, NodeHtmlTemplateDirective,
|
|
1523
1805
|
EdgeLabelHtmlTemplateDirective,
|
|
1524
1806
|
EdgeTemplateDirective,
|
|
1525
1807
|
ConnectionTemplateDirective,
|
|
@@ -1533,6 +1815,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
|
|
|
1533
1815
|
exports: [
|
|
1534
1816
|
VflowComponent,
|
|
1535
1817
|
HandleComponent,
|
|
1818
|
+
SelectableDirective,
|
|
1536
1819
|
...templateDirectives
|
|
1537
1820
|
],
|
|
1538
1821
|
declarations: [...components, ...directives, ...templateDirectives],
|
|
@@ -1545,5 +1828,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
|
|
|
1545
1828
|
* Generated bundle index. Do not edit.
|
|
1546
1829
|
*/
|
|
1547
1830
|
|
|
1548
|
-
export { ChangesControllerDirective, ConnectionControllerDirective, ConnectionTemplateDirective, EdgeLabelHtmlTemplateDirective, EdgeTemplateDirective, HandleComponent, HandleTemplateDirective, NodeHtmlTemplateDirective, VflowComponent, VflowModule };
|
|
1831
|
+
export { ChangesControllerDirective, ConnectionControllerDirective, ConnectionTemplateDirective, EdgeLabelHtmlTemplateDirective, EdgeTemplateDirective, HandleComponent, HandleTemplateDirective, NodeHtmlTemplateDirective, SelectableDirective, VflowComponent, VflowModule };
|
|
1549
1832
|
//# sourceMappingURL=ngx-vflow.mjs.map
|