ngx-vflow 0.14.1 → 0.16.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 +72 -4
- package/esm2022/lib/vflow/components/connection/connection.component.mjs +6 -1
- package/esm2022/lib/vflow/components/custom-node-base/custom-node-base.component.mjs +5 -7
- package/esm2022/lib/vflow/components/handle/handle.component.mjs +16 -14
- package/esm2022/lib/vflow/components/node/node.component.mjs +8 -3
- package/esm2022/lib/vflow/components/vflow/vflow.component.mjs +12 -6
- package/esm2022/lib/vflow/directives/drag-handle.directive.mjs +27 -0
- package/esm2022/lib/vflow/directives/map-context.directive.mjs +24 -17
- package/esm2022/lib/vflow/interfaces/edge.interface.mjs +1 -1
- package/esm2022/lib/vflow/interfaces/optimization.interface.mjs +1 -1
- package/esm2022/lib/vflow/math/edge-path/smooth-step-path.mjs +170 -0
- package/esm2022/lib/vflow/models/edge.model.mjs +6 -1
- package/esm2022/lib/vflow/models/node.model.mjs +2 -1
- package/esm2022/lib/vflow/models/toolbar.model.mjs +36 -0
- package/esm2022/lib/vflow/public-components/minimap/minimap.component.mjs +8 -2
- package/esm2022/lib/vflow/public-components/node-toolbar/node-toolbar.component.mjs +66 -0
- package/esm2022/lib/vflow/services/draggable.service.mjs +13 -15
- package/esm2022/lib/vflow/services/node-rendering.service.mjs +8 -1
- package/esm2022/lib/vflow/services/overlays.service.mjs +34 -0
- package/esm2022/lib/vflow/testing-utils/provide-custom-node-mocks.mjs +67 -0
- package/esm2022/lib/vflow/types/background.type.mjs +1 -1
- package/esm2022/lib/vflow/utils/is-group-node.mjs +4 -0
- package/esm2022/lib/vflow/vflow.module.mjs +17 -5
- package/esm2022/public-api.mjs +5 -1
- package/fesm2022/ngx-vflow.mjs +554 -65
- package/fesm2022/ngx-vflow.mjs.map +1 -1
- package/lib/vflow/components/background/background.component.d.ts +13 -0
- package/lib/vflow/components/handle/handle.component.d.ts +3 -3
- package/lib/vflow/components/node/node.component.d.ts +2 -0
- package/lib/vflow/components/vflow/vflow.component.d.ts +2 -0
- package/lib/vflow/directives/drag-handle.directive.d.ts +8 -0
- package/lib/vflow/directives/map-context.directive.d.ts +3 -2
- package/lib/vflow/interfaces/edge.interface.d.ts +1 -1
- package/lib/vflow/interfaces/optimization.interface.d.ts +13 -0
- package/lib/vflow/math/edge-path/smooth-step-path.d.ts +5 -0
- package/lib/vflow/models/node.model.d.ts +1 -0
- package/lib/vflow/models/toolbar.model.d.ts +19 -0
- package/lib/vflow/public-components/node-toolbar/node-toolbar.component.d.ts +22 -0
- package/lib/vflow/services/draggable.service.d.ts +0 -5
- package/lib/vflow/services/node-rendering.service.d.ts +2 -0
- package/lib/vflow/services/overlays.service.d.ts +11 -0
- package/lib/vflow/testing-utils/provide-custom-node-mocks.d.ts +2 -0
- package/lib/vflow/types/background.type.d.ts +24 -1
- package/lib/vflow/utils/is-group-node.d.ts +2 -0
- package/lib/vflow/vflow.module.d.ts +14 -12
- package/package.json +3 -3
- package/public-api.d.ts +3 -0
package/fesm2022/ngx-vflow.mjs
CHANGED
|
@@ -4,7 +4,7 @@ import * as i0 from '@angular/core';
|
|
|
4
4
|
import { signal, computed, Injectable, inject, ElementRef, Directive, effect, untracked, TemplateRef, EventEmitter, Output, DestroyRef, Input, runInInjectionContext, Component, Injector, ChangeDetectionStrategy, HostListener, ViewChild, NgZone, ContentChild, NgModule } from '@angular/core';
|
|
5
5
|
import { select } from 'd3-selection';
|
|
6
6
|
import { zoomIdentity, zoom } from 'd3-zoom';
|
|
7
|
-
import { switchMap, merge, fromEvent, tap, Subject, observeOn, animationFrameScheduler, skip, map, pairwise, filter, distinctUntilChanged, asyncScheduler, zip, share, Observable, startWith } from 'rxjs';
|
|
7
|
+
import { switchMap, merge, fromEvent, tap, Subject, observeOn, animationFrameScheduler, skip, map, pairwise, filter, distinctUntilChanged, asyncScheduler, zip, share, Observable, startWith, of } from 'rxjs';
|
|
8
8
|
import { toObservable, takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';
|
|
9
9
|
import { drag } from 'd3-drag';
|
|
10
10
|
import { __decorate } from 'tslib';
|
|
@@ -406,30 +406,37 @@ class MapContextDirective {
|
|
|
406
406
|
this.viewportService.readableViewport.set(mapTransformToViewportState(transform));
|
|
407
407
|
this.zoomableSelection.attr('transform', transform.toString());
|
|
408
408
|
};
|
|
409
|
+
this.handleZoomStart = ({ transform }) => {
|
|
410
|
+
this.viewportForSelection = {
|
|
411
|
+
start: mapTransformToViewportState(transform)
|
|
412
|
+
};
|
|
413
|
+
};
|
|
414
|
+
this.handleZoomEnd = ({ transform, sourceEvent }) => {
|
|
415
|
+
this.viewportForSelection = {
|
|
416
|
+
...this.viewportForSelection,
|
|
417
|
+
end: mapTransformToViewportState(transform),
|
|
418
|
+
target: evTarget(sourceEvent)
|
|
419
|
+
};
|
|
420
|
+
this.selectionService.setViewport(this.viewportForSelection);
|
|
421
|
+
};
|
|
422
|
+
this.filterCondition = (event) => {
|
|
423
|
+
if (event.type === 'mousedown' || event.type === 'touchstart') {
|
|
424
|
+
return event.target.closest('.vflow-node') === null;
|
|
425
|
+
}
|
|
426
|
+
return true;
|
|
427
|
+
};
|
|
409
428
|
}
|
|
410
429
|
ngOnInit() {
|
|
411
430
|
this.zoomBehavior = zoom()
|
|
412
431
|
.scaleExtent([this.flowSettingsService.minZoom(), this.flowSettingsService.maxZoom()])
|
|
413
|
-
.
|
|
414
|
-
.on('
|
|
415
|
-
.on('
|
|
432
|
+
.filter(this.filterCondition)
|
|
433
|
+
.on('start', this.handleZoomStart)
|
|
434
|
+
.on('zoom', this.handleZoom)
|
|
435
|
+
.on('end', this.handleZoomEnd);
|
|
416
436
|
this.rootSvgSelection
|
|
417
437
|
.call(this.zoomBehavior)
|
|
418
438
|
.on('dblclick.zoom', null);
|
|
419
439
|
}
|
|
420
|
-
onD3zoomStart({ transform }) {
|
|
421
|
-
this.viewportForSelection = {
|
|
422
|
-
start: mapTransformToViewportState(transform)
|
|
423
|
-
};
|
|
424
|
-
}
|
|
425
|
-
onD3zoomEnd({ transform, sourceEvent }) {
|
|
426
|
-
this.viewportForSelection = {
|
|
427
|
-
...this.viewportForSelection,
|
|
428
|
-
end: mapTransformToViewportState(transform),
|
|
429
|
-
target: evTarget(sourceEvent)
|
|
430
|
-
};
|
|
431
|
-
this.selectionService.setViewport(this.viewportForSelection);
|
|
432
|
-
}
|
|
433
440
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: MapContextDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
434
441
|
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: MapContextDirective, selector: "g[mapContext]", ngImport: i0 }); }
|
|
435
442
|
}
|
|
@@ -458,8 +465,8 @@ class DraggableService {
|
|
|
458
465
|
* @param model model with data for this element
|
|
459
466
|
*/
|
|
460
467
|
enable(element, model) {
|
|
461
|
-
|
|
462
|
-
|
|
468
|
+
select(element)
|
|
469
|
+
.call(this.getDragBehavior(model));
|
|
463
470
|
}
|
|
464
471
|
/**
|
|
465
472
|
* Disable draggable behavior for element.
|
|
@@ -468,8 +475,8 @@ class DraggableService {
|
|
|
468
475
|
* @param model model with data for this element
|
|
469
476
|
*/
|
|
470
477
|
disable(element) {
|
|
471
|
-
|
|
472
|
-
|
|
478
|
+
select(element)
|
|
479
|
+
.call(drag().on('drag', null));
|
|
473
480
|
}
|
|
474
481
|
/**
|
|
475
482
|
* TODO: not shure if this work, need to check
|
|
@@ -488,7 +495,15 @@ class DraggableService {
|
|
|
488
495
|
getDragBehavior(model) {
|
|
489
496
|
let dragNodes = [];
|
|
490
497
|
let initialPositions = [];
|
|
498
|
+
const filterCondition = (event) => {
|
|
499
|
+
// if there is at least one drag handle, we should check if we are dragging it
|
|
500
|
+
if (model.dragHandlesCount()) {
|
|
501
|
+
return !!event.target.closest('.vflow-drag-handle');
|
|
502
|
+
}
|
|
503
|
+
return true;
|
|
504
|
+
};
|
|
491
505
|
return drag()
|
|
506
|
+
.filter(filterCondition)
|
|
492
507
|
.on('start', (event) => {
|
|
493
508
|
dragNodes = this.getDragNodes(model);
|
|
494
509
|
initialPositions = dragNodes.map(node => ({
|
|
@@ -506,16 +521,6 @@ class DraggableService {
|
|
|
506
521
|
});
|
|
507
522
|
});
|
|
508
523
|
}
|
|
509
|
-
/**
|
|
510
|
-
* Specify ignoring drag behavior. It's responsible for not moving the map when user tries to drag node
|
|
511
|
-
* with disabled drag behavior
|
|
512
|
-
*/
|
|
513
|
-
getIgnoreDragBehavior() {
|
|
514
|
-
return drag()
|
|
515
|
-
.on('drag', (event) => {
|
|
516
|
-
event.sourceEvent.stopPropagation();
|
|
517
|
-
});
|
|
518
|
-
}
|
|
519
524
|
getDragNodes(model) {
|
|
520
525
|
return model.selected()
|
|
521
526
|
? this.entitiesService
|
|
@@ -825,7 +830,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
|
|
|
825
830
|
|
|
826
831
|
class CustomNodeBaseComponent {
|
|
827
832
|
constructor() {
|
|
828
|
-
this.eventBus = inject(ComponentEventBusService
|
|
833
|
+
this.eventBus = inject(ComponentEventBusService);
|
|
829
834
|
this.destroyRef = inject(DestroyRef);
|
|
830
835
|
/**
|
|
831
836
|
* Signal with selected state of node
|
|
@@ -837,11 +842,9 @@ class CustomNodeBaseComponent {
|
|
|
837
842
|
this.selected.set(value);
|
|
838
843
|
}
|
|
839
844
|
ngOnInit() {
|
|
840
|
-
|
|
841
|
-
this.
|
|
842
|
-
|
|
843
|
-
.subscribe();
|
|
844
|
-
}
|
|
845
|
+
this.trackEvents()
|
|
846
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
847
|
+
.subscribe();
|
|
845
848
|
}
|
|
846
849
|
trackEvents() {
|
|
847
850
|
const props = Object.getOwnPropertyNames(this);
|
|
@@ -980,6 +983,7 @@ class NodeModel {
|
|
|
980
983
|
this.handles = signal([]);
|
|
981
984
|
this.handles$ = toObservable(this.handles);
|
|
982
985
|
this.draggable = signal(true);
|
|
986
|
+
this.dragHandlesCount = signal(0);
|
|
983
987
|
// disabled for configuration for now
|
|
984
988
|
this.magnetRadius = 20;
|
|
985
989
|
// TODO: not sure if we need to statically store it
|
|
@@ -1209,6 +1213,176 @@ function getPointOnBezier(sourcePoint, targetPoint, sourceControl, targetControl
|
|
|
1209
1213
|
return getPointOnLineByRatio(getPointOnLineByRatio(fromSourceToFirstControl, fromFirstControlToSecond, ratio), getPointOnLineByRatio(fromFirstControlToSecond, fromSecondControlToTarget, ratio), ratio);
|
|
1210
1214
|
}
|
|
1211
1215
|
|
|
1216
|
+
const handleDirections = {
|
|
1217
|
+
left: { x: -1, y: 0 },
|
|
1218
|
+
right: { x: 1, y: 0 },
|
|
1219
|
+
top: { x: 0, y: -1 },
|
|
1220
|
+
bottom: { x: 0, y: 1 },
|
|
1221
|
+
};
|
|
1222
|
+
function getEdgeCenter(source, target) {
|
|
1223
|
+
const xOffset = Math.abs(target.x - source.x) / 2;
|
|
1224
|
+
const centerX = target.x < source.x ? target.x + xOffset : target.x - xOffset;
|
|
1225
|
+
const yOffset = Math.abs(target.y - source.y) / 2;
|
|
1226
|
+
const centerY = target.y < source.y ? target.y + yOffset : target.y - yOffset;
|
|
1227
|
+
return [centerX, centerY, xOffset, yOffset];
|
|
1228
|
+
}
|
|
1229
|
+
const getDirection = ({ source, sourcePosition = 'bottom', target, }) => {
|
|
1230
|
+
if (sourcePosition === 'left' || sourcePosition === 'right') {
|
|
1231
|
+
return source.x < target.x ? { x: 1, y: 0 } : { x: -1, y: 0 };
|
|
1232
|
+
}
|
|
1233
|
+
return source.y < target.y ? { x: 0, y: 1 } : { x: 0, y: -1 };
|
|
1234
|
+
};
|
|
1235
|
+
const distance = (a, b) => Math.sqrt(Math.pow(b.x - a.x, 2) + Math.pow(b.y - a.y, 2));
|
|
1236
|
+
// ith this function we try to mimic a orthogonal edge routing behaviour
|
|
1237
|
+
// It's not as good as a real orthogonal edge routing but it's faster and good enough as a default for step and smooth step edges
|
|
1238
|
+
function getPoints({ source, sourcePosition = 'bottom', target, targetPosition = 'top', offset, }) {
|
|
1239
|
+
const sourceDir = handleDirections[sourcePosition];
|
|
1240
|
+
const targetDir = handleDirections[targetPosition];
|
|
1241
|
+
const sourceGapped = { x: source.x + sourceDir.x * offset, y: source.y + sourceDir.y * offset };
|
|
1242
|
+
const targetGapped = { x: target.x + targetDir.x * offset, y: target.y + targetDir.y * offset };
|
|
1243
|
+
const dir = getDirection({
|
|
1244
|
+
source: sourceGapped,
|
|
1245
|
+
sourcePosition,
|
|
1246
|
+
target: targetGapped,
|
|
1247
|
+
});
|
|
1248
|
+
const dirAccessor = dir.x !== 0 ? 'x' : 'y';
|
|
1249
|
+
const currDir = dir[dirAccessor];
|
|
1250
|
+
let points = [];
|
|
1251
|
+
let centerX, centerY;
|
|
1252
|
+
const sourceGapOffset = { x: 0, y: 0 };
|
|
1253
|
+
const targetGapOffset = { x: 0, y: 0 };
|
|
1254
|
+
const [defaultCenterX, defaultCenterY] = getEdgeCenter(source, target);
|
|
1255
|
+
// opposite handle positions, default case
|
|
1256
|
+
if (sourceDir[dirAccessor] * targetDir[dirAccessor] === -1) {
|
|
1257
|
+
centerX = defaultCenterX;
|
|
1258
|
+
centerY = defaultCenterY;
|
|
1259
|
+
// --->
|
|
1260
|
+
// |
|
|
1261
|
+
// >---
|
|
1262
|
+
const verticalSplit = [
|
|
1263
|
+
{ x: centerX, y: sourceGapped.y },
|
|
1264
|
+
{ x: centerX, y: targetGapped.y },
|
|
1265
|
+
];
|
|
1266
|
+
// |
|
|
1267
|
+
// ---
|
|
1268
|
+
// |
|
|
1269
|
+
const horizontalSplit = [
|
|
1270
|
+
{ x: sourceGapped.x, y: centerY },
|
|
1271
|
+
{ x: targetGapped.x, y: centerY },
|
|
1272
|
+
];
|
|
1273
|
+
if (sourceDir[dirAccessor] === currDir) {
|
|
1274
|
+
points = dirAccessor === 'x' ? verticalSplit : horizontalSplit;
|
|
1275
|
+
}
|
|
1276
|
+
else {
|
|
1277
|
+
points = dirAccessor === 'x' ? horizontalSplit : verticalSplit;
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
else {
|
|
1281
|
+
// sourceTarget means we take x from source and y from target, targetSource is the opposite
|
|
1282
|
+
const sourceTarget = [{ x: sourceGapped.x, y: targetGapped.y }];
|
|
1283
|
+
const targetSource = [{ x: targetGapped.x, y: sourceGapped.y }];
|
|
1284
|
+
// this handles edges with same handle positions
|
|
1285
|
+
if (dirAccessor === 'x') {
|
|
1286
|
+
points = sourceDir.x === currDir ? targetSource : sourceTarget;
|
|
1287
|
+
}
|
|
1288
|
+
else {
|
|
1289
|
+
points = sourceDir.y === currDir ? sourceTarget : targetSource;
|
|
1290
|
+
}
|
|
1291
|
+
if (sourcePosition === targetPosition) {
|
|
1292
|
+
const diff = Math.abs(source[dirAccessor] - target[dirAccessor]);
|
|
1293
|
+
// if an edge goes from right to right for example (sourcePosition === targetPosition) and the distance between source.x and target.x is less than the offset, the added point and the gapped source/target will overlap. This leads to a weird edge path. To avoid this we add a gapOffset to the source/target
|
|
1294
|
+
if (diff <= offset) {
|
|
1295
|
+
const gapOffset = Math.min(offset - 1, offset - diff);
|
|
1296
|
+
if (sourceDir[dirAccessor] === currDir) {
|
|
1297
|
+
sourceGapOffset[dirAccessor] = (sourceGapped[dirAccessor] > source[dirAccessor] ? -1 : 1) * gapOffset;
|
|
1298
|
+
}
|
|
1299
|
+
else {
|
|
1300
|
+
targetGapOffset[dirAccessor] = (targetGapped[dirAccessor] > target[dirAccessor] ? -1 : 1) * gapOffset;
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
// these are conditions for handling mixed handle positions like Right -> Bottom for example
|
|
1305
|
+
if (sourcePosition !== targetPosition) {
|
|
1306
|
+
const dirAccessorOpposite = dirAccessor === 'x' ? 'y' : 'x';
|
|
1307
|
+
const isSameDir = sourceDir[dirAccessor] === targetDir[dirAccessorOpposite];
|
|
1308
|
+
const sourceGtTargetOppo = sourceGapped[dirAccessorOpposite] > targetGapped[dirAccessorOpposite];
|
|
1309
|
+
const sourceLtTargetOppo = sourceGapped[dirAccessorOpposite] < targetGapped[dirAccessorOpposite];
|
|
1310
|
+
const flipSourceTarget = (sourceDir[dirAccessor] === 1 && ((!isSameDir && sourceGtTargetOppo) || (isSameDir && sourceLtTargetOppo))) ||
|
|
1311
|
+
(sourceDir[dirAccessor] !== 1 && ((!isSameDir && sourceLtTargetOppo) || (isSameDir && sourceGtTargetOppo)));
|
|
1312
|
+
if (flipSourceTarget) {
|
|
1313
|
+
points = dirAccessor === 'x' ? sourceTarget : targetSource;
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
const sourceGapPoint = { x: sourceGapped.x + sourceGapOffset.x, y: sourceGapped.y + sourceGapOffset.y };
|
|
1317
|
+
const targetGapPoint = { x: targetGapped.x + targetGapOffset.x, y: targetGapped.y + targetGapOffset.y };
|
|
1318
|
+
const maxXDistance = Math.max(Math.abs(sourceGapPoint.x - points[0].x), Math.abs(targetGapPoint.x - points[0].x));
|
|
1319
|
+
const maxYDistance = Math.max(Math.abs(sourceGapPoint.y - points[0].y), Math.abs(targetGapPoint.y - points[0].y));
|
|
1320
|
+
// we want to place the label on the longest segment of the edge
|
|
1321
|
+
if (maxXDistance >= maxYDistance) {
|
|
1322
|
+
centerX = (sourceGapPoint.x + targetGapPoint.x) / 2;
|
|
1323
|
+
centerY = points[0].y;
|
|
1324
|
+
}
|
|
1325
|
+
else {
|
|
1326
|
+
centerX = points[0].x;
|
|
1327
|
+
centerY = (sourceGapPoint.y + targetGapPoint.y) / 2;
|
|
1328
|
+
}
|
|
1329
|
+
}
|
|
1330
|
+
const pathPoints = [
|
|
1331
|
+
source,
|
|
1332
|
+
{ x: sourceGapped.x + sourceGapOffset.x, y: sourceGapped.y + sourceGapOffset.y },
|
|
1333
|
+
...points,
|
|
1334
|
+
{ x: targetGapped.x + targetGapOffset.x, y: targetGapped.y + targetGapOffset.y },
|
|
1335
|
+
target,
|
|
1336
|
+
];
|
|
1337
|
+
return [pathPoints, centerX, centerY];
|
|
1338
|
+
}
|
|
1339
|
+
function getBend(a, b, c, size) {
|
|
1340
|
+
const bendSize = Math.min(distance(a, b) / 2, distance(b, c) / 2, size);
|
|
1341
|
+
const { x, y } = b;
|
|
1342
|
+
// no bend
|
|
1343
|
+
if ((a.x === x && x === c.x) || (a.y === y && y === c.y)) {
|
|
1344
|
+
return `L${x} ${y}`;
|
|
1345
|
+
}
|
|
1346
|
+
// first segment is horizontal
|
|
1347
|
+
if (a.y === y) {
|
|
1348
|
+
const xDir = a.x < c.x ? -1 : 1;
|
|
1349
|
+
const yDir = a.y < c.y ? 1 : -1;
|
|
1350
|
+
return `L ${x + bendSize * xDir},${y}Q ${x},${y} ${x},${y + bendSize * yDir}`;
|
|
1351
|
+
}
|
|
1352
|
+
const xDir = a.x < c.x ? 1 : -1;
|
|
1353
|
+
const yDir = a.y < c.y ? -1 : 1;
|
|
1354
|
+
return `L ${x},${y + bendSize * yDir}Q ${x},${y} ${x + bendSize * xDir},${y}`;
|
|
1355
|
+
}
|
|
1356
|
+
function smoothStepPath(source, target, sourcePosition, targetPosition, borderRadius = 5) {
|
|
1357
|
+
const [points, labelX, labelY] = getPoints({
|
|
1358
|
+
source,
|
|
1359
|
+
sourcePosition,
|
|
1360
|
+
target,
|
|
1361
|
+
targetPosition,
|
|
1362
|
+
offset: 20
|
|
1363
|
+
});
|
|
1364
|
+
const path = points.reduce((res, p, i) => {
|
|
1365
|
+
let segment = '';
|
|
1366
|
+
if (i > 0 && i < points.length - 1) {
|
|
1367
|
+
segment = getBend(points[i - 1], p, points[i + 1], borderRadius);
|
|
1368
|
+
}
|
|
1369
|
+
else {
|
|
1370
|
+
segment = `${i === 0 ? 'M' : 'L'}${p.x} ${p.y}`;
|
|
1371
|
+
}
|
|
1372
|
+
res += segment;
|
|
1373
|
+
return res;
|
|
1374
|
+
}, '');
|
|
1375
|
+
return {
|
|
1376
|
+
path,
|
|
1377
|
+
points: {
|
|
1378
|
+
// TODO start and end points temporary unavailable for this path
|
|
1379
|
+
start: { x: labelX, y: labelY },
|
|
1380
|
+
center: { x: labelX, y: labelY },
|
|
1381
|
+
end: { x: labelX, y: labelY },
|
|
1382
|
+
}
|
|
1383
|
+
};
|
|
1384
|
+
}
|
|
1385
|
+
|
|
1212
1386
|
class EdgeModel {
|
|
1213
1387
|
constructor(edge) {
|
|
1214
1388
|
this.edge = edge;
|
|
@@ -1278,6 +1452,10 @@ class EdgeModel {
|
|
|
1278
1452
|
return straightPath(source.pointAbsolute(), target.pointAbsolute(), this.usingPoints);
|
|
1279
1453
|
case 'bezier':
|
|
1280
1454
|
return bezierPath(source.pointAbsolute(), target.pointAbsolute(), source.rawHandle.position, target.rawHandle.position, this.usingPoints);
|
|
1455
|
+
case 'smooth-step':
|
|
1456
|
+
return smoothStepPath(source.pointAbsolute(), target.pointAbsolute(), source.rawHandle.position, target.rawHandle.position);
|
|
1457
|
+
case 'step':
|
|
1458
|
+
return smoothStepPath(source.pointAbsolute(), target.pointAbsolute(), source.rawHandle.position, target.rawHandle.position, 0);
|
|
1281
1459
|
}
|
|
1282
1460
|
});
|
|
1283
1461
|
this.edgeLabels = {};
|
|
@@ -1554,6 +1732,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
|
|
|
1554
1732
|
args: ['onEdgesChange.select.many']
|
|
1555
1733
|
}] } });
|
|
1556
1734
|
|
|
1735
|
+
function isGroupNode(node) {
|
|
1736
|
+
return node.node.type === 'default-group' || node.node.type === 'template-group';
|
|
1737
|
+
}
|
|
1738
|
+
|
|
1557
1739
|
class NodeRenderingService {
|
|
1558
1740
|
constructor() {
|
|
1559
1741
|
this.flowEntitiesService = inject(FlowEntitiesService);
|
|
@@ -1561,6 +1743,12 @@ class NodeRenderingService {
|
|
|
1561
1743
|
return this.flowEntitiesService.nodes()
|
|
1562
1744
|
.sort((aNode, bNode) => aNode.renderOrder() - bNode.renderOrder());
|
|
1563
1745
|
});
|
|
1746
|
+
this.groups = computed(() => {
|
|
1747
|
+
return this.nodes().filter(n => isGroupNode(n));
|
|
1748
|
+
});
|
|
1749
|
+
this.nonGroups = computed(() => {
|
|
1750
|
+
return this.nodes().filter(n => !isGroupNode(n));
|
|
1751
|
+
});
|
|
1564
1752
|
this.maxOrder = computed(() => {
|
|
1565
1753
|
return Math.max(...this.flowEntitiesService.nodes().map((n) => n.renderOrder()));
|
|
1566
1754
|
});
|
|
@@ -1689,6 +1877,36 @@ function Microtask(target, key, descriptor) {
|
|
|
1689
1877
|
return descriptor;
|
|
1690
1878
|
}
|
|
1691
1879
|
|
|
1880
|
+
class OverlaysService {
|
|
1881
|
+
constructor() {
|
|
1882
|
+
this.toolbars = signal([]);
|
|
1883
|
+
this.nodeToolbars = computed(() => {
|
|
1884
|
+
const map = new Map();
|
|
1885
|
+
this.toolbars().forEach((toolbar) => {
|
|
1886
|
+
map.set(toolbar.node, toolbar);
|
|
1887
|
+
});
|
|
1888
|
+
return map;
|
|
1889
|
+
});
|
|
1890
|
+
}
|
|
1891
|
+
addToolbar(toolbar) {
|
|
1892
|
+
this.toolbars.update((toolbars) => [...toolbars, toolbar]);
|
|
1893
|
+
}
|
|
1894
|
+
removeToolbar(toolbar) {
|
|
1895
|
+
this.toolbars.update((toolbars) => toolbars.filter(t => t !== toolbar));
|
|
1896
|
+
}
|
|
1897
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: OverlaysService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1898
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: OverlaysService }); }
|
|
1899
|
+
}
|
|
1900
|
+
__decorate([
|
|
1901
|
+
Microtask
|
|
1902
|
+
], OverlaysService.prototype, "addToolbar", null);
|
|
1903
|
+
__decorate([
|
|
1904
|
+
Microtask
|
|
1905
|
+
], OverlaysService.prototype, "removeToolbar", null);
|
|
1906
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: OverlaysService, decorators: [{
|
|
1907
|
+
type: Injectable
|
|
1908
|
+
}], propDecorators: { addToolbar: [], removeToolbar: [] } });
|
|
1909
|
+
|
|
1692
1910
|
class HandleService {
|
|
1693
1911
|
constructor() {
|
|
1694
1912
|
this.node = signal(null);
|
|
@@ -1866,20 +2084,22 @@ class HandleComponent {
|
|
|
1866
2084
|
this.injector = inject(Injector);
|
|
1867
2085
|
this.handleService = inject(HandleService);
|
|
1868
2086
|
this.element = inject(ElementRef).nativeElement;
|
|
2087
|
+
this.destroyRef = inject(DestroyRef);
|
|
1869
2088
|
}
|
|
1870
2089
|
ngOnInit() {
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
2090
|
+
const node = this.handleService.node();
|
|
2091
|
+
if (node) {
|
|
2092
|
+
this.model = new HandleModel({
|
|
2093
|
+
position: this.position,
|
|
2094
|
+
type: this.type,
|
|
2095
|
+
id: this.id,
|
|
2096
|
+
parentReference: this.element.parentElement,
|
|
2097
|
+
template: this.template
|
|
2098
|
+
}, node);
|
|
2099
|
+
this.handleService.createHandle(this.model);
|
|
2100
|
+
requestAnimationFrame(() => this.model.updateParent());
|
|
2101
|
+
this.destroyRef.onDestroy(() => this.handleService.destroyHandle(this.model));
|
|
2102
|
+
}
|
|
1883
2103
|
}
|
|
1884
2104
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: HandleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1885
2105
|
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 }); }
|
|
@@ -2225,11 +2445,13 @@ class NodeComponent {
|
|
|
2225
2445
|
this.hostRef = inject(ElementRef);
|
|
2226
2446
|
this.connectionController = inject(ConnectionControllerDirective);
|
|
2227
2447
|
this.nodeAccessor = inject(NodeAccessorService);
|
|
2448
|
+
this.overlaysService = inject(OverlaysService);
|
|
2228
2449
|
this.zone = inject(NgZone);
|
|
2229
2450
|
this.showMagnet = computed(() => this.flowStatusService.status().state === 'connection-start' ||
|
|
2230
2451
|
this.flowStatusService.status().state === 'connection-validation');
|
|
2231
2452
|
this.styleWidth = computed(() => `${this.nodeModel.size().width}px`);
|
|
2232
2453
|
this.styleHeight = computed(() => `${this.nodeModel.size().height}px`);
|
|
2454
|
+
this.toolbar = computed(() => this.overlaysService.nodeToolbars().get(this.nodeModel));
|
|
2233
2455
|
}
|
|
2234
2456
|
ngOnInit() {
|
|
2235
2457
|
this.nodeAccessor.model.set(this.nodeModel);
|
|
@@ -2287,7 +2509,7 @@ class NodeComponent {
|
|
|
2287
2509
|
}
|
|
2288
2510
|
}
|
|
2289
2511
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NodeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2290
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: NodeComponent, selector: "g[node]", inputs: { nodeModel: "nodeModel", nodeTemplate: "nodeTemplate", groupNodeTemplate: "groupNodeTemplate" }, providers: [HandleService, NodeAccessorService], viewQueries: [{ propertyName: "nodeContentRef", first: true, predicate: ["nodeContent"], descendants: true }, { propertyName: "htmlWrapperRef", first: true, predicate: ["htmlWrapper"], descendants: true }], ngImport: i0, template: "<!-- Default node -->\n<svg:foreignObject\n *ngIf=\"nodeModel.node.type === 'default'\"\n class=\"selectable\"\n #nodeContent\n [attr.width]=\"nodeModel.size().width\"\n [attr.height]=\"nodeModel.size().height\"\n (pointerStart)=\"pullNode(); selectNode()\"\n>\n <default-node\n #htmlWrapper\n [selected]=\"nodeModel.selected()\"\n [style.width]=\"styleWidth()\"\n [style.height]=\"styleHeight()\"\n [style.max-width]=\"styleWidth()\"\n [style.max-height]=\"styleHeight()\"\n >\n <div [outerHTML]=\"nodeModel.text()\"></div>\n\n <handle type=\"source\" [position]=\"nodeModel.sourcePosition()\" />\n <handle type=\"target\" [position]=\"nodeModel.targetPosition()\" />\n </default-node>\n</svg:foreignObject>\n\n<!-- Template node -->\n<svg:foreignObject\n *ngIf=\"nodeModel.node.type === 'html-template' && nodeTemplate\"\n class=\"selectable\"\n [attr.width]=\"nodeModel.size().width\"\n [attr.height]=\"nodeModel.size().height\"\n (pointerStart)=\"pullNode()\"\n>\n <div\n #htmlWrapper\n class=\"wrapper\"\n [style.width]=\"styleWidth()\"\n [style.height]=\"styleHeight()\"\n >\n <ng-container\n [ngTemplateOutlet]=\"nodeTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: { node: nodeModel.node, selected: nodeModel.selected } }\"\n [ngTemplateOutletInjector]=\"injector\"\n />\n </div>\n</svg:foreignObject>\n\n<!-- Component node -->\n<svg:foreignObject\n *ngIf=\"nodeModel.isComponentType\"\n class=\"selectable\"\n [attr.width]=\"nodeModel.size().width\"\n [attr.height]=\"nodeModel.size().height\"\n (pointerStart)=\"pullNode()\"\n>\n <div\n #htmlWrapper\n class=\"wrapper\"\n [style.width]=\"styleWidth()\"\n [style.height]=\"styleHeight()\"\n >\n <ng-container\n [ngComponentOutlet]=\"$any(nodeModel.node.type)\"\n [ngComponentOutletInputs]=\"nodeModel.componentTypeInputs()\"\n [ngComponentOutletInjector]=\"injector\"\n />\n </div>\n</svg:foreignObject>\n\n<!-- Default group node -->\n<svg:rect\n *ngIf=\"nodeModel.node.type === 'default-group'\"\n [resizable]=\"nodeModel.resizable()\"\n [gap]=\"3\"\n [resizerColor]=\"nodeModel.color()\"\n class=\"default-group-node\"\n rx=\"5\"\n ry=\"5\"\n [class.default-group-node_selected]=\"nodeModel.selected()\"\n [attr.width]=\"nodeModel.size().width\"\n [attr.height]=\"nodeModel.size().height\"\n [style.stroke]=\"nodeModel.color()\"\n [style.fill]=\"nodeModel.color()\"\n (pointerStart)=\"pullNode(); selectNode()\"\n/>\n\n<!-- Template group node -->\n<svg:g\n *ngIf=\"nodeModel.node.type === 'template-group' && groupNodeTemplate\"\n class=\"selectable\"\n (pointerStart)=\"pullNode()\"\n>\n <ng-container\n [ngTemplateOutlet]=\"groupNodeTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: { node: nodeModel.node, selected: nodeModel.selected, width: nodeModel.width, height: nodeModel.height } }\"\n [ngTemplateOutletInjector]=\"injector\"\n />\n</svg:g>\n\n<!-- Resizer -->\n<ng-container *ngIf=\"nodeModel.resizerTemplate() as template\">\n <ng-container *ngIf=\"nodeModel.resizable()\">\n <ng-template [ngTemplateOutlet]=\"template\" />\n </ng-container>\n</ng-container>\n\n<!-- Handles -->\n<ng-container *ngFor=\"let handle of nodeModel.handles()\">\n <svg:circle\n *ngIf=\"!handle.template\"\n class=\"default-handle\"\n [attr.cx]=\"handle.offset().x\"\n [attr.cy]=\"handle.offset().y\"\n [attr.stroke-width]=\"handle.strokeWidth\"\n r=\"5\"\n (pointerStart)=\"startConnection($event, handle)\"\n (pointerEnd)=\"endConnection(handle)\"\n />\n\n <svg:g\n *ngIf=\"handle.template\"\n [handleSizeController]=\"handle\"\n (pointerStart)=\"startConnection($event, handle)\"\n (pointerEnd)=\"endConnection(handle)\"\n >\n <ng-container *ngTemplateOutlet=\"handle.template; context: handle.templateContext\" />\n </svg:g>\n\n <svg:circle\n *ngIf=\"showMagnet()\"\n class=\"magnet\"\n [attr.r]=\"nodeModel.magnetRadius\"\n [attr.cx]=\"handle.offset().x\"\n [attr.cy]=\"handle.offset().y\"\n (pointerEnd)=\"endConnection(handle); resetValidateConnection(handle)\"\n (pointerOver)=\"validateConnection(handle)\"\n (pointerOut)=\"resetValidateConnection(handle)\"\n />\n</ng-container>\n", styles: [".magnet{opacity:0}.wrapper{display:table-cell}.default-group-node{stroke-width:1.5px;fill-opacity:.05}.default-group-node_selected{stroke-width:2px}.default-handle{stroke:#fff;fill:#1b262c}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1.NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"] }, { kind: "component", type: DefaultNodeComponent, selector: "default-node", inputs: ["selected"] }, { kind: "component", type: HandleComponent, selector: "handle", inputs: ["position", "type", "id", "template"] }, { kind: "component", type: ResizableComponent, selector: "[resizable]", inputs: ["resizable", "resizerColor", "gap"] }, { kind: "directive", type: HandleSizeControllerDirective, selector: "[handleSizeController]", inputs: ["handleSizeController"] }, { kind: "directive", type: PointerDirective, selector: "[pointerStart], [pointerEnd], [pointerOver], [pointerOut]", outputs: ["pointerOver", "pointerOut", "pointerStart", "pointerEnd"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
2512
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: NodeComponent, selector: "g[node]", inputs: { nodeModel: "nodeModel", nodeTemplate: "nodeTemplate", groupNodeTemplate: "groupNodeTemplate" }, host: { classAttribute: "vflow-node" }, providers: [HandleService, NodeAccessorService], viewQueries: [{ propertyName: "nodeContentRef", first: true, predicate: ["nodeContent"], descendants: true }, { propertyName: "htmlWrapperRef", first: true, predicate: ["htmlWrapper"], descendants: true }], ngImport: i0, template: "<!-- Default node -->\n<svg:foreignObject\n *ngIf=\"nodeModel.node.type === 'default'\"\n class=\"selectable\"\n #nodeContent\n [attr.width]=\"nodeModel.size().width\"\n [attr.height]=\"nodeModel.size().height\"\n (pointerStart)=\"pullNode(); selectNode()\"\n>\n <default-node\n #htmlWrapper\n [selected]=\"nodeModel.selected()\"\n [style.width]=\"styleWidth()\"\n [style.height]=\"styleHeight()\"\n [style.max-width]=\"styleWidth()\"\n [style.max-height]=\"styleHeight()\"\n >\n <div [outerHTML]=\"nodeModel.text()\"></div>\n\n <handle type=\"source\" [position]=\"nodeModel.sourcePosition()\" />\n <handle type=\"target\" [position]=\"nodeModel.targetPosition()\" />\n </default-node>\n</svg:foreignObject>\n\n<!-- Template node -->\n<svg:foreignObject\n *ngIf=\"nodeModel.node.type === 'html-template' && nodeTemplate\"\n class=\"selectable\"\n [attr.width]=\"nodeModel.size().width\"\n [attr.height]=\"nodeModel.size().height\"\n (pointerStart)=\"pullNode()\"\n>\n <div\n #htmlWrapper\n class=\"wrapper\"\n [style.width]=\"styleWidth()\"\n [style.height]=\"styleHeight()\"\n >\n <ng-container\n [ngTemplateOutlet]=\"nodeTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: { node: nodeModel.node, selected: nodeModel.selected } }\"\n [ngTemplateOutletInjector]=\"injector\"\n />\n </div>\n</svg:foreignObject>\n\n<!-- Component node -->\n<svg:foreignObject\n *ngIf=\"nodeModel.isComponentType\"\n class=\"selectable\"\n [attr.width]=\"nodeModel.size().width\"\n [attr.height]=\"nodeModel.size().height\"\n (pointerStart)=\"pullNode()\"\n>\n <div\n #htmlWrapper\n class=\"wrapper\"\n [style.width]=\"styleWidth()\"\n [style.height]=\"styleHeight()\"\n >\n <ng-container\n [ngComponentOutlet]=\"$any(nodeModel.node.type)\"\n [ngComponentOutletInputs]=\"nodeModel.componentTypeInputs()\"\n [ngComponentOutletInjector]=\"injector\"\n />\n </div>\n</svg:foreignObject>\n\n<!-- Default group node -->\n<svg:rect\n *ngIf=\"nodeModel.node.type === 'default-group'\"\n [resizable]=\"nodeModel.resizable()\"\n [gap]=\"3\"\n [resizerColor]=\"nodeModel.color()\"\n class=\"default-group-node\"\n rx=\"5\"\n ry=\"5\"\n [class.default-group-node_selected]=\"nodeModel.selected()\"\n [attr.width]=\"nodeModel.size().width\"\n [attr.height]=\"nodeModel.size().height\"\n [style.stroke]=\"nodeModel.color()\"\n [style.fill]=\"nodeModel.color()\"\n (pointerStart)=\"pullNode(); selectNode()\"\n/>\n\n<!-- Template group node -->\n<svg:g\n *ngIf=\"nodeModel.node.type === 'template-group' && groupNodeTemplate\"\n class=\"selectable\"\n (pointerStart)=\"pullNode()\"\n>\n <ng-container\n [ngTemplateOutlet]=\"groupNodeTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: { node: nodeModel.node, selected: nodeModel.selected, width: nodeModel.width, height: nodeModel.height } }\"\n [ngTemplateOutletInjector]=\"injector\"\n />\n</svg:g>\n\n<!-- Resizer -->\n<ng-container *ngIf=\"nodeModel.resizerTemplate() as template\">\n <ng-container *ngIf=\"nodeModel.resizable()\">\n <ng-template [ngTemplateOutlet]=\"template\" />\n </ng-container>\n</ng-container>\n\n<!-- Handles -->\n<ng-container *ngFor=\"let handle of nodeModel.handles()\">\n <svg:circle\n *ngIf=\"!handle.template\"\n class=\"default-handle\"\n [attr.cx]=\"handle.offset().x\"\n [attr.cy]=\"handle.offset().y\"\n [attr.stroke-width]=\"handle.strokeWidth\"\n r=\"5\"\n (pointerStart)=\"startConnection($event, handle)\"\n (pointerEnd)=\"endConnection(handle)\"\n />\n\n <svg:g\n *ngIf=\"handle.template\"\n [handleSizeController]=\"handle\"\n (pointerStart)=\"startConnection($event, handle)\"\n (pointerEnd)=\"endConnection(handle)\"\n >\n <ng-container *ngTemplateOutlet=\"handle.template; context: handle.templateContext\" />\n </svg:g>\n\n <svg:circle\n *ngIf=\"showMagnet()\"\n class=\"magnet\"\n [attr.r]=\"nodeModel.magnetRadius\"\n [attr.cx]=\"handle.offset().x\"\n [attr.cy]=\"handle.offset().y\"\n (pointerEnd)=\"endConnection(handle); resetValidateConnection(handle)\"\n (pointerOver)=\"validateConnection(handle)\"\n (pointerOut)=\"resetValidateConnection(handle)\"\n />\n</ng-container>\n\n<!-- Toolbar -->\n<svg:foreignObject\n *ngIf=\"toolbar() as toolbar\"\n [attr.width]=\"toolbar.size().width\"\n [attr.height]=\"toolbar.size().height\"\n [attr.transform]=\"toolbar.transform()\"\n>\n <ng-container [ngTemplateOutlet]=\"toolbar.template()\" />\n</svg:foreignObject>\n", styles: [".magnet{opacity:0}.wrapper{display:table-cell}.default-group-node{stroke-width:1.5px;fill-opacity:.05}.default-group-node_selected{stroke-width:2px}.default-handle{stroke:#fff;fill:#1b262c}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1.NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"] }, { kind: "component", type: DefaultNodeComponent, selector: "default-node", inputs: ["selected"] }, { kind: "component", type: HandleComponent, selector: "handle", inputs: ["position", "type", "id", "template"] }, { kind: "component", type: ResizableComponent, selector: "[resizable]", inputs: ["resizable", "resizerColor", "gap"] }, { kind: "directive", type: HandleSizeControllerDirective, selector: "[handleSizeController]", inputs: ["handleSizeController"] }, { kind: "directive", type: PointerDirective, selector: "[pointerStart], [pointerEnd], [pointerOver], [pointerOut]", outputs: ["pointerOver", "pointerOut", "pointerStart", "pointerEnd"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
2291
2513
|
}
|
|
2292
2514
|
__decorate([
|
|
2293
2515
|
InjectionContext
|
|
@@ -2297,7 +2519,9 @@ __decorate([
|
|
|
2297
2519
|
], NodeComponent.prototype, "ngAfterViewInit", null);
|
|
2298
2520
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NodeComponent, decorators: [{
|
|
2299
2521
|
type: Component,
|
|
2300
|
-
args: [{ selector: 'g[node]', changeDetection: ChangeDetectionStrategy.OnPush, providers: [HandleService, NodeAccessorService],
|
|
2522
|
+
args: [{ selector: 'g[node]', changeDetection: ChangeDetectionStrategy.OnPush, providers: [HandleService, NodeAccessorService], host: {
|
|
2523
|
+
'class': 'vflow-node',
|
|
2524
|
+
}, template: "<!-- Default node -->\n<svg:foreignObject\n *ngIf=\"nodeModel.node.type === 'default'\"\n class=\"selectable\"\n #nodeContent\n [attr.width]=\"nodeModel.size().width\"\n [attr.height]=\"nodeModel.size().height\"\n (pointerStart)=\"pullNode(); selectNode()\"\n>\n <default-node\n #htmlWrapper\n [selected]=\"nodeModel.selected()\"\n [style.width]=\"styleWidth()\"\n [style.height]=\"styleHeight()\"\n [style.max-width]=\"styleWidth()\"\n [style.max-height]=\"styleHeight()\"\n >\n <div [outerHTML]=\"nodeModel.text()\"></div>\n\n <handle type=\"source\" [position]=\"nodeModel.sourcePosition()\" />\n <handle type=\"target\" [position]=\"nodeModel.targetPosition()\" />\n </default-node>\n</svg:foreignObject>\n\n<!-- Template node -->\n<svg:foreignObject\n *ngIf=\"nodeModel.node.type === 'html-template' && nodeTemplate\"\n class=\"selectable\"\n [attr.width]=\"nodeModel.size().width\"\n [attr.height]=\"nodeModel.size().height\"\n (pointerStart)=\"pullNode()\"\n>\n <div\n #htmlWrapper\n class=\"wrapper\"\n [style.width]=\"styleWidth()\"\n [style.height]=\"styleHeight()\"\n >\n <ng-container\n [ngTemplateOutlet]=\"nodeTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: { node: nodeModel.node, selected: nodeModel.selected } }\"\n [ngTemplateOutletInjector]=\"injector\"\n />\n </div>\n</svg:foreignObject>\n\n<!-- Component node -->\n<svg:foreignObject\n *ngIf=\"nodeModel.isComponentType\"\n class=\"selectable\"\n [attr.width]=\"nodeModel.size().width\"\n [attr.height]=\"nodeModel.size().height\"\n (pointerStart)=\"pullNode()\"\n>\n <div\n #htmlWrapper\n class=\"wrapper\"\n [style.width]=\"styleWidth()\"\n [style.height]=\"styleHeight()\"\n >\n <ng-container\n [ngComponentOutlet]=\"$any(nodeModel.node.type)\"\n [ngComponentOutletInputs]=\"nodeModel.componentTypeInputs()\"\n [ngComponentOutletInjector]=\"injector\"\n />\n </div>\n</svg:foreignObject>\n\n<!-- Default group node -->\n<svg:rect\n *ngIf=\"nodeModel.node.type === 'default-group'\"\n [resizable]=\"nodeModel.resizable()\"\n [gap]=\"3\"\n [resizerColor]=\"nodeModel.color()\"\n class=\"default-group-node\"\n rx=\"5\"\n ry=\"5\"\n [class.default-group-node_selected]=\"nodeModel.selected()\"\n [attr.width]=\"nodeModel.size().width\"\n [attr.height]=\"nodeModel.size().height\"\n [style.stroke]=\"nodeModel.color()\"\n [style.fill]=\"nodeModel.color()\"\n (pointerStart)=\"pullNode(); selectNode()\"\n/>\n\n<!-- Template group node -->\n<svg:g\n *ngIf=\"nodeModel.node.type === 'template-group' && groupNodeTemplate\"\n class=\"selectable\"\n (pointerStart)=\"pullNode()\"\n>\n <ng-container\n [ngTemplateOutlet]=\"groupNodeTemplate\"\n [ngTemplateOutletContext]=\"{ $implicit: { node: nodeModel.node, selected: nodeModel.selected, width: nodeModel.width, height: nodeModel.height } }\"\n [ngTemplateOutletInjector]=\"injector\"\n />\n</svg:g>\n\n<!-- Resizer -->\n<ng-container *ngIf=\"nodeModel.resizerTemplate() as template\">\n <ng-container *ngIf=\"nodeModel.resizable()\">\n <ng-template [ngTemplateOutlet]=\"template\" />\n </ng-container>\n</ng-container>\n\n<!-- Handles -->\n<ng-container *ngFor=\"let handle of nodeModel.handles()\">\n <svg:circle\n *ngIf=\"!handle.template\"\n class=\"default-handle\"\n [attr.cx]=\"handle.offset().x\"\n [attr.cy]=\"handle.offset().y\"\n [attr.stroke-width]=\"handle.strokeWidth\"\n r=\"5\"\n (pointerStart)=\"startConnection($event, handle)\"\n (pointerEnd)=\"endConnection(handle)\"\n />\n\n <svg:g\n *ngIf=\"handle.template\"\n [handleSizeController]=\"handle\"\n (pointerStart)=\"startConnection($event, handle)\"\n (pointerEnd)=\"endConnection(handle)\"\n >\n <ng-container *ngTemplateOutlet=\"handle.template; context: handle.templateContext\" />\n </svg:g>\n\n <svg:circle\n *ngIf=\"showMagnet()\"\n class=\"magnet\"\n [attr.r]=\"nodeModel.magnetRadius\"\n [attr.cx]=\"handle.offset().x\"\n [attr.cy]=\"handle.offset().y\"\n (pointerEnd)=\"endConnection(handle); resetValidateConnection(handle)\"\n (pointerOver)=\"validateConnection(handle)\"\n (pointerOut)=\"resetValidateConnection(handle)\"\n />\n</ng-container>\n\n<!-- Toolbar -->\n<svg:foreignObject\n *ngIf=\"toolbar() as toolbar\"\n [attr.width]=\"toolbar.size().width\"\n [attr.height]=\"toolbar.size().height\"\n [attr.transform]=\"toolbar.transform()\"\n>\n <ng-container [ngTemplateOutlet]=\"toolbar.template()\" />\n</svg:foreignObject>\n", styles: [".magnet{opacity:0}.wrapper{display:table-cell}.default-group-node{stroke-width:1.5px;fill-opacity:.05}.default-group-node_selected{stroke-width:2px}.default-handle{stroke:#fff;fill:#1b262c}\n"] }]
|
|
2301
2525
|
}], propDecorators: { nodeModel: [{
|
|
2302
2526
|
type: Input
|
|
2303
2527
|
}], nodeTemplate: [{
|
|
@@ -2430,6 +2654,8 @@ class ConnectionComponent {
|
|
|
2430
2654
|
switch (this.model.curve) {
|
|
2431
2655
|
case 'straight': return straightPath(sourcePoint, targetPoint).path;
|
|
2432
2656
|
case 'bezier': return bezierPath(sourcePoint, targetPoint, sourcePosition, targetPosition).path;
|
|
2657
|
+
case 'smooth-step': return smoothStepPath(sourcePoint, targetPoint, sourcePosition, targetPosition).path;
|
|
2658
|
+
case 'step': return smoothStepPath(sourcePoint, targetPoint, sourcePosition, targetPosition, 0).path;
|
|
2433
2659
|
}
|
|
2434
2660
|
}
|
|
2435
2661
|
if (status.state === 'connection-validation') {
|
|
@@ -2447,6 +2673,8 @@ class ConnectionComponent {
|
|
|
2447
2673
|
switch (this.model.curve) {
|
|
2448
2674
|
case 'straight': return straightPath(sourcePoint, targetPoint).path;
|
|
2449
2675
|
case 'bezier': return bezierPath(sourcePoint, targetPoint, sourcePosition, targetPosition).path;
|
|
2676
|
+
case 'smooth-step': return smoothStepPath(sourcePoint, targetPoint, sourcePosition, targetPosition).path;
|
|
2677
|
+
case 'step': return smoothStepPath(sourcePoint, targetPoint, sourcePosition, targetPosition, 0).path;
|
|
2450
2678
|
}
|
|
2451
2679
|
}
|
|
2452
2680
|
return null;
|
|
@@ -2552,12 +2780,15 @@ const defaultBg = '#fff';
|
|
|
2552
2780
|
const defaultGap = 20;
|
|
2553
2781
|
const defaultDotSize = 2;
|
|
2554
2782
|
const defaultDotColor = 'rgb(177, 177, 183)';
|
|
2783
|
+
const defaultImageScale = 0.1;
|
|
2784
|
+
const defaultRepeated = true;
|
|
2555
2785
|
class BackgroundComponent {
|
|
2556
2786
|
constructor() {
|
|
2557
2787
|
this.viewportService = inject(ViewportService);
|
|
2558
2788
|
this.rootSvg = inject(RootSvgReferenceDirective).element;
|
|
2559
2789
|
this.settingsService = inject(FlowSettingsService);
|
|
2560
2790
|
this.backgroundSignal = this.settingsService.background;
|
|
2791
|
+
// DOTS PATTERN
|
|
2561
2792
|
this.scaledGap = computed(() => {
|
|
2562
2793
|
const background = this.backgroundSignal();
|
|
2563
2794
|
if (background.type === 'dots') {
|
|
@@ -2568,7 +2799,13 @@ class BackgroundComponent {
|
|
|
2568
2799
|
});
|
|
2569
2800
|
this.x = computed(() => this.viewportService.readableViewport().x % this.scaledGap());
|
|
2570
2801
|
this.y = computed(() => this.viewportService.readableViewport().y % this.scaledGap());
|
|
2571
|
-
this.patternColor = computed(() =>
|
|
2802
|
+
this.patternColor = computed(() => {
|
|
2803
|
+
const bg = this.backgroundSignal();
|
|
2804
|
+
if (bg.type === 'dots') {
|
|
2805
|
+
return bg.color ?? defaultDotColor;
|
|
2806
|
+
}
|
|
2807
|
+
return defaultDotColor;
|
|
2808
|
+
});
|
|
2572
2809
|
this.patternSize = computed(() => {
|
|
2573
2810
|
const background = this.backgroundSignal();
|
|
2574
2811
|
if (background.type === 'dots') {
|
|
@@ -2576,6 +2813,56 @@ class BackgroundComponent {
|
|
|
2576
2813
|
}
|
|
2577
2814
|
return 0;
|
|
2578
2815
|
});
|
|
2816
|
+
// IMAGE PATTERN
|
|
2817
|
+
this.bgImageSrc = computed(() => {
|
|
2818
|
+
const background = this.backgroundSignal();
|
|
2819
|
+
return background.type === 'image' ? background.src : '';
|
|
2820
|
+
});
|
|
2821
|
+
this.imageSize = toSignal(toObservable(this.backgroundSignal).pipe(switchMap(() => createImage(this.bgImageSrc())), map((image) => ({ width: image.naturalWidth, height: image.naturalHeight }))), { initialValue: { width: 0, height: 0 } });
|
|
2822
|
+
this.scaledImageWidth = computed(() => {
|
|
2823
|
+
const background = this.backgroundSignal();
|
|
2824
|
+
if (background.type === 'image') {
|
|
2825
|
+
const zoom = background.fixed ? 1 : this.viewportService.readableViewport().zoom;
|
|
2826
|
+
return this.imageSize().width * zoom * (background.scale ?? defaultImageScale);
|
|
2827
|
+
}
|
|
2828
|
+
return 0;
|
|
2829
|
+
});
|
|
2830
|
+
this.scaledImageHeight = computed(() => {
|
|
2831
|
+
const background = this.backgroundSignal();
|
|
2832
|
+
if (background.type === 'image') {
|
|
2833
|
+
const zoom = background.fixed ? 1 : this.viewportService.readableViewport().zoom;
|
|
2834
|
+
return this.imageSize().height * zoom * (background.scale ?? defaultImageScale);
|
|
2835
|
+
}
|
|
2836
|
+
return 0;
|
|
2837
|
+
});
|
|
2838
|
+
this.imageX = computed(() => {
|
|
2839
|
+
const background = this.backgroundSignal();
|
|
2840
|
+
if (background.type === 'image') {
|
|
2841
|
+
if (!background.repeat) {
|
|
2842
|
+
return background.fixed ? 0 : this.viewportService.readableViewport().x;
|
|
2843
|
+
}
|
|
2844
|
+
return background.fixed
|
|
2845
|
+
? 0
|
|
2846
|
+
: this.viewportService.readableViewport().x % this.scaledImageWidth();
|
|
2847
|
+
}
|
|
2848
|
+
return 0;
|
|
2849
|
+
});
|
|
2850
|
+
this.imageY = computed(() => {
|
|
2851
|
+
const background = this.backgroundSignal();
|
|
2852
|
+
if (background.type === 'image') {
|
|
2853
|
+
if (!background.repeat) {
|
|
2854
|
+
return background.fixed ? 0 : this.viewportService.readableViewport().y;
|
|
2855
|
+
}
|
|
2856
|
+
return background.fixed
|
|
2857
|
+
? 0
|
|
2858
|
+
: this.viewportService.readableViewport().y % this.scaledImageHeight();
|
|
2859
|
+
}
|
|
2860
|
+
return 0;
|
|
2861
|
+
});
|
|
2862
|
+
this.repeated = computed(() => {
|
|
2863
|
+
const background = this.backgroundSignal();
|
|
2864
|
+
return background.type === 'image' && (background.repeat ?? defaultRepeated);
|
|
2865
|
+
});
|
|
2579
2866
|
// Without ID there will be pattern collision for several flows on the page
|
|
2580
2867
|
// Later pattern ID may be exposed to API
|
|
2581
2868
|
this.patternId = id();
|
|
@@ -2591,12 +2878,19 @@ class BackgroundComponent {
|
|
|
2591
2878
|
});
|
|
2592
2879
|
}
|
|
2593
2880
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: BackgroundComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2594
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: BackgroundComponent, selector: "g[background]", 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 }); }
|
|
2881
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: BackgroundComponent, selector: "g[background]", 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\n<ng-container *ngIf=\"backgroundSignal().type === 'image'\">\n <ng-container *ngIf=\"repeated()\">\n <svg:pattern\n [attr.id]=\"patternId\"\n [attr.x]=\"imageX()\"\n [attr.y]=\"imageY()\"\n [attr.width]=\"scaledImageWidth()\"\n [attr.height]=\"scaledImageHeight()\"\n patternUnits=\"userSpaceOnUse\"\n >\n <svg:image\n [attr.href]=\"bgImageSrc()\"\n [attr.width]=\"scaledImageWidth()\"\n [attr.height]=\"scaledImageHeight()\"\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\n <ng-container *ngIf=\"!repeated()\">\n <svg:image\n [attr.x]=\"imageX()\"\n [attr.y]=\"imageY()\"\n [attr.width]=\"scaledImageWidth()\"\n [attr.height]=\"scaledImageHeight()\"\n [attr.href]=\"bgImageSrc()\"\n />\n </ng-container>\n</ng-container>\n", dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
2595
2882
|
}
|
|
2596
2883
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: BackgroundComponent, decorators: [{
|
|
2597
2884
|
type: Component,
|
|
2598
|
-
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" }]
|
|
2885
|
+
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\n<ng-container *ngIf=\"backgroundSignal().type === 'image'\">\n <ng-container *ngIf=\"repeated()\">\n <svg:pattern\n [attr.id]=\"patternId\"\n [attr.x]=\"imageX()\"\n [attr.y]=\"imageY()\"\n [attr.width]=\"scaledImageWidth()\"\n [attr.height]=\"scaledImageHeight()\"\n patternUnits=\"userSpaceOnUse\"\n >\n <svg:image\n [attr.href]=\"bgImageSrc()\"\n [attr.width]=\"scaledImageWidth()\"\n [attr.height]=\"scaledImageHeight()\"\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\n <ng-container *ngIf=\"!repeated()\">\n <svg:image\n [attr.x]=\"imageX()\"\n [attr.y]=\"imageY()\"\n [attr.width]=\"scaledImageWidth()\"\n [attr.height]=\"scaledImageHeight()\"\n [attr.href]=\"bgImageSrc()\"\n />\n </ng-container>\n</ng-container>\n" }]
|
|
2599
2886
|
}], ctorParameters: function () { return []; } });
|
|
2887
|
+
function createImage(url) {
|
|
2888
|
+
const image = new Image();
|
|
2889
|
+
image.src = url;
|
|
2890
|
+
return new Promise(resolve => {
|
|
2891
|
+
image.onload = () => resolve(image);
|
|
2892
|
+
});
|
|
2893
|
+
}
|
|
2600
2894
|
|
|
2601
2895
|
// TODO: too general purpose nane
|
|
2602
2896
|
class RootSvgContextDirective {
|
|
@@ -2706,9 +3000,12 @@ class VflowComponent {
|
|
|
2706
3000
|
this.keyboardService = inject(KeyboardService);
|
|
2707
3001
|
this.injector = inject(Injector);
|
|
2708
3002
|
this.optimization = {
|
|
2709
|
-
computeLayersOnInit: true
|
|
3003
|
+
computeLayersOnInit: true,
|
|
3004
|
+
detachedGroupsLayer: false
|
|
2710
3005
|
};
|
|
2711
3006
|
this.nodeModels = computed(() => this.nodeRenderingService.nodes());
|
|
3007
|
+
this.groups = computed(() => this.nodeRenderingService.groups());
|
|
3008
|
+
this.nonGroups = computed(() => this.nodeRenderingService.nonGroups());
|
|
2712
3009
|
this.edgeModels = computed(() => this.flowEntitiesService.validEdges());
|
|
2713
3010
|
// #endregion
|
|
2714
3011
|
// #region OUTPUTS
|
|
@@ -2910,8 +3207,9 @@ class VflowComponent {
|
|
|
2910
3207
|
SelectionService,
|
|
2911
3208
|
FlowSettingsService,
|
|
2912
3209
|
ComponentEventBusService,
|
|
2913
|
-
KeyboardService
|
|
2914
|
-
|
|
3210
|
+
KeyboardService,
|
|
3211
|
+
OverlaysService
|
|
3212
|
+
], queries: [{ propertyName: "nodeTemplateDirective", first: true, predicate: NodeHtmlTemplateDirective, descendants: true }, { propertyName: "groupNodeTemplateDirective", first: true, predicate: GroupNodeTemplateDirective, descendants: true }, { propertyName: "edgeTemplateDirective", first: true, predicate: EdgeTemplateDirective, descendants: true }, { propertyName: "edgeLabelHtmlDirective", first: true, predicate: EdgeLabelHtmlTemplateDirective, descendants: true }, { propertyName: "connectionTemplateDirective", first: true, predicate: ConnectionTemplateDirective, descendants: true }], viewQueries: [{ propertyName: "mapContext", first: true, predicate: MapContextDirective, descendants: true }, { propertyName: "spacePointContext", first: true, predicate: SpacePointContextDirective, descendants: true }], hostDirectives: [{ directive: ConnectionControllerDirective, outputs: ["onConnect", "onConnect"] }, { directive: ChangesControllerDirective, outputs: ["onNodesChange", "onNodesChange", "onNodesChange.position", "onNodesChange.position", "onNodesChange.position.single", "onNodesChange.position.single", "onNodesChange.position.many", "onNodesChange.position.many", "onNodesChange.size", "onNodesChange.size", "onNodesChange.size.single", "onNodesChange.size.single", "onNodesChange.size.many", "onNodesChange.size.many", "onNodesChange.add", "onNodesChange.add", "onNodesChange.add.single", "onNodesChange.add.single", "onNodesChange.add.many", "onNodesChange.add.many", "onNodesChange.remove", "onNodesChange.remove", "onNodesChange.remove.single", "onNodesChange.remove.single", "onNodesChange.remove.many", "onNodesChange.remove.many", "onNodesChange.select", "onNodesChange.select", "onNodesChange.select.single", "onNodesChange.select.single", "onNodesChange.select.many", "onNodesChange.select.many", "onEdgesChange", "onEdgesChange", "onEdgesChange.detached", "onEdgesChange.detached", "onEdgesChange.detached.single", "onEdgesChange.detached.single", "onEdgesChange.detached.many", "onEdgesChange.detached.many", "onEdgesChange.add", "onEdgesChange.add", "onEdgesChange.add.single", "onEdgesChange.add.single", "onEdgesChange.add.many", "onEdgesChange.add.many", "onEdgesChange.remove", "onEdgesChange.remove", "onEdgesChange.remove.single", "onEdgesChange.remove.single", "onEdgesChange.remove.many", "onEdgesChange.remove.many", "onEdgesChange.select", "onEdgesChange.select", "onEdgesChange.select.single", "onEdgesChange.select.single", "onEdgesChange.select.many", "onEdgesChange.select.many"] }], ngImport: i0, template: "<svg:svg\n rootSvgRef\n rootSvgContext\n rootPointer\n flowSizeController\n class=\"root-svg\"\n #flow\n>\n <defs [markers]=\"markers()\" flowDefs />\n\n <g background />\n\n <svg:g\n mapContext\n spacePointContext\n >\n <!-- Connection -->\n <svg:g\n connection\n [model]=\"connection\"\n [template]=\"connectionTemplateDirective?.templateRef\"\n />\n\n <ng-container *ngIf=\"optimization.detachedGroupsLayer\">\n <!-- Groups -->\n <svg:g\n *ngFor=\"let model of groups(); trackBy: trackNodes\"\n node\n [nodeModel]=\"model\"\n [groupNodeTemplate]=\"groupNodeTemplateDirective?.templateRef\"\n [attr.transform]=\"model.pointTransform()\"\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 nonGroups(); trackBy: trackNodes\"\n node\n [nodeModel]=\"model\"\n [nodeTemplate]=\"nodeTemplateDirective?.templateRef\"\n [attr.transform]=\"model.pointTransform()\"\n />\n </ng-container>\n\n <ng-container *ngIf=\"!optimization.detachedGroupsLayer\">\n <!-- Edges -->\n <svg:g\n *ngFor=\"let model of edgeModels(); trackBy: trackEdges\"\n edge\n [model]=\"model\"\n [edgeTemplate]=\"edgeTemplateDirective?.templateRef\"\n [edgeLabelHtmlTemplate]=\"edgeLabelHtmlDirective?.templateRef\"\n />\n\n <!-- Nodes -->\n <svg:g\n *ngFor=\"let model of nodeModels(); trackBy: trackNodes\"\n node\n [nodeModel]=\"model\"\n [nodeTemplate]=\"nodeTemplateDirective?.templateRef\"\n [groupNodeTemplate]=\"groupNodeTemplateDirective?.templateRef\"\n [attr.transform]=\"model.pointTransform()\"\n />\n </ng-container>\n\n </svg:g>\n\n <!-- Minimap -->\n <ng-container *ngIf=\"minimap() as minimap\">\n <ng-container [ngTemplateOutlet]=\"minimap.template()\" />\n </ng-container>\n</svg:svg>\n\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.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: NodeComponent, selector: "g[node]", inputs: ["nodeModel", "nodeTemplate", "groupNodeTemplate"] }, { kind: "component", type: EdgeComponent, selector: "g[edge]", inputs: ["model", "edgeTemplate", "edgeLabelHtmlTemplate"] }, { kind: "component", type: ConnectionComponent, selector: "g[connection]", inputs: ["model", "template"] }, { kind: "component", type: DefsComponent, selector: "defs[flowDefs]", inputs: ["markers"] }, { kind: "component", type: BackgroundComponent, selector: "g[background]" }, { kind: "directive", type: SpacePointContextDirective, selector: "g[spacePointContext]" }, { kind: "directive", type: MapContextDirective, selector: "g[mapContext]" }, { kind: "directive", type: RootSvgReferenceDirective, selector: "svg[rootSvgRef]" }, { kind: "directive", type: RootSvgContextDirective, selector: "svg[rootSvgContext]" }, { kind: "directive", type: RootPointerDirective, selector: "svg[rootPointer]" }, { kind: "directive", type: FlowSizeControllerDirective, selector: "svg[flowSizeController]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
2915
3213
|
}
|
|
2916
3214
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: VflowComponent, decorators: [{
|
|
2917
3215
|
type: Component,
|
|
@@ -2926,11 +3224,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
|
|
|
2926
3224
|
SelectionService,
|
|
2927
3225
|
FlowSettingsService,
|
|
2928
3226
|
ComponentEventBusService,
|
|
2929
|
-
KeyboardService
|
|
3227
|
+
KeyboardService,
|
|
3228
|
+
OverlaysService
|
|
2930
3229
|
], hostDirectives: [
|
|
2931
3230
|
connectionControllerHostDirective,
|
|
2932
3231
|
changesControllerHostDirective
|
|
2933
|
-
], template: "<svg:svg\n rootSvgRef\n rootSvgContext\n rootPointer\n flowSizeController\n class=\"root-svg\"\n #flow\n>\n <defs [markers]=\"markers()\" flowDefs />\n\n <g background />\n\n <svg:g\n mapContext\n spacePointContext\n >\n <!-- Connection -->\n <svg:g\n connection\n [model]=\"connection\"\n [template]=\"connectionTemplateDirective?.templateRef\"\n />\n\n <!-- Edges -->\n
|
|
3232
|
+
], template: "<svg:svg\n rootSvgRef\n rootSvgContext\n rootPointer\n flowSizeController\n class=\"root-svg\"\n #flow\n>\n <defs [markers]=\"markers()\" flowDefs />\n\n <g background />\n\n <svg:g\n mapContext\n spacePointContext\n >\n <!-- Connection -->\n <svg:g\n connection\n [model]=\"connection\"\n [template]=\"connectionTemplateDirective?.templateRef\"\n />\n\n <ng-container *ngIf=\"optimization.detachedGroupsLayer\">\n <!-- Groups -->\n <svg:g\n *ngFor=\"let model of groups(); trackBy: trackNodes\"\n node\n [nodeModel]=\"model\"\n [groupNodeTemplate]=\"groupNodeTemplateDirective?.templateRef\"\n [attr.transform]=\"model.pointTransform()\"\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 nonGroups(); trackBy: trackNodes\"\n node\n [nodeModel]=\"model\"\n [nodeTemplate]=\"nodeTemplateDirective?.templateRef\"\n [attr.transform]=\"model.pointTransform()\"\n />\n </ng-container>\n\n <ng-container *ngIf=\"!optimization.detachedGroupsLayer\">\n <!-- Edges -->\n <svg:g\n *ngFor=\"let model of edgeModels(); trackBy: trackEdges\"\n edge\n [model]=\"model\"\n [edgeTemplate]=\"edgeTemplateDirective?.templateRef\"\n [edgeLabelHtmlTemplate]=\"edgeLabelHtmlDirective?.templateRef\"\n />\n\n <!-- Nodes -->\n <svg:g\n *ngFor=\"let model of nodeModels(); trackBy: trackNodes\"\n node\n [nodeModel]=\"model\"\n [nodeTemplate]=\"nodeTemplateDirective?.templateRef\"\n [groupNodeTemplate]=\"groupNodeTemplateDirective?.templateRef\"\n [attr.transform]=\"model.pointTransform()\"\n />\n </ng-container>\n\n </svg:g>\n\n <!-- Minimap -->\n <ng-container *ngIf=\"minimap() as minimap\">\n <ng-container [ngTemplateOutlet]=\"minimap.template()\" />\n </ng-container>\n</svg:svg>\n\n", styles: [":host{display:block;width:100%;height:100%;-webkit-user-select:none;user-select:none}:host ::ng-deep *{box-sizing:border-box}\n"] }]
|
|
2934
3233
|
}], propDecorators: { view: [{
|
|
2935
3234
|
type: Input
|
|
2936
3235
|
}], minZoom: [{
|
|
@@ -3043,7 +3342,13 @@ class MiniMapComponent {
|
|
|
3043
3342
|
}
|
|
3044
3343
|
return 0.2;
|
|
3045
3344
|
});
|
|
3046
|
-
this.viewportColor = computed(() =>
|
|
3345
|
+
this.viewportColor = computed(() => {
|
|
3346
|
+
const bg = this.flowSettingsService.background();
|
|
3347
|
+
if (bg.type === 'dots' || bg.type === 'solid') {
|
|
3348
|
+
return bg.color ?? '#fff';
|
|
3349
|
+
}
|
|
3350
|
+
return '#fff';
|
|
3351
|
+
});
|
|
3047
3352
|
this.hovered = signal(false);
|
|
3048
3353
|
this.minimapPoint = computed(() => {
|
|
3049
3354
|
switch (this.minimapPosition()) {
|
|
@@ -3131,6 +3436,125 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
|
|
|
3131
3436
|
args: ['minimap', { static: true }]
|
|
3132
3437
|
}] } });
|
|
3133
3438
|
|
|
3439
|
+
class ToolbarModel {
|
|
3440
|
+
constructor(node) {
|
|
3441
|
+
this.node = node;
|
|
3442
|
+
this.position = signal('top');
|
|
3443
|
+
this.template = signal(null);
|
|
3444
|
+
this.offset = signal(10);
|
|
3445
|
+
this.point = computed(() => {
|
|
3446
|
+
switch (this.position()) {
|
|
3447
|
+
case 'top':
|
|
3448
|
+
return {
|
|
3449
|
+
x: this.node.size().width / 2 - this.size().width / 2,
|
|
3450
|
+
y: -this.size().height - this.offset()
|
|
3451
|
+
};
|
|
3452
|
+
case 'bottom':
|
|
3453
|
+
return {
|
|
3454
|
+
x: this.node.size().width / 2 - this.size().width / 2,
|
|
3455
|
+
y: this.node.size().height + this.offset()
|
|
3456
|
+
};
|
|
3457
|
+
case 'left':
|
|
3458
|
+
return {
|
|
3459
|
+
x: -this.size().width - this.offset(),
|
|
3460
|
+
y: this.node.size().height / 2 - this.size().height / 2
|
|
3461
|
+
};
|
|
3462
|
+
case 'right':
|
|
3463
|
+
return {
|
|
3464
|
+
x: this.node.size().width + this.offset(),
|
|
3465
|
+
y: this.node.size().height / 2 - this.size().height / 2
|
|
3466
|
+
};
|
|
3467
|
+
}
|
|
3468
|
+
});
|
|
3469
|
+
this.transform = computed(() => `translate(${this.point().x}, ${this.point().y})`);
|
|
3470
|
+
this.size = signal({ width: 0, height: 0 });
|
|
3471
|
+
}
|
|
3472
|
+
}
|
|
3473
|
+
|
|
3474
|
+
class NodeToolbarComponent {
|
|
3475
|
+
constructor() {
|
|
3476
|
+
this.overlaysService = inject(OverlaysService);
|
|
3477
|
+
this.nodeService = inject(NodeAccessorService);
|
|
3478
|
+
this.model = new ToolbarModel(this.nodeService.model());
|
|
3479
|
+
}
|
|
3480
|
+
set position(value) {
|
|
3481
|
+
this.model.position.set(value);
|
|
3482
|
+
}
|
|
3483
|
+
ngOnInit() {
|
|
3484
|
+
this.model.template.set(this.toolbarContentTemplate);
|
|
3485
|
+
this.overlaysService.addToolbar(this.model);
|
|
3486
|
+
}
|
|
3487
|
+
ngOnDestroy() {
|
|
3488
|
+
this.overlaysService.removeToolbar(this.model);
|
|
3489
|
+
}
|
|
3490
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NodeToolbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3491
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: NodeToolbarComponent, selector: "node-toolbar", inputs: { position: "position" }, viewQueries: [{ propertyName: "toolbarContentTemplate", first: true, predicate: ["toolbar"], descendants: true, static: true }], ngImport: i0, template: `
|
|
3492
|
+
<ng-template #toolbar>
|
|
3493
|
+
<div class="wrapper" nodeToolbarWrapper [model]="model">
|
|
3494
|
+
<ng-content />
|
|
3495
|
+
</div>
|
|
3496
|
+
</ng-template>
|
|
3497
|
+
`, isInline: true, styles: [".wrapper{width:max-content}\n"], dependencies: [{ kind: "directive", type: i0.forwardRef(function () { return NodeToolbarWrapperDirective; }), selector: "[nodeToolbarWrapper]", inputs: ["model"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
3498
|
+
}
|
|
3499
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NodeToolbarComponent, decorators: [{
|
|
3500
|
+
type: Component,
|
|
3501
|
+
args: [{ selector: 'node-toolbar', template: `
|
|
3502
|
+
<ng-template #toolbar>
|
|
3503
|
+
<div class="wrapper" nodeToolbarWrapper [model]="model">
|
|
3504
|
+
<ng-content />
|
|
3505
|
+
</div>
|
|
3506
|
+
</ng-template>
|
|
3507
|
+
`, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".wrapper{width:max-content}\n"] }]
|
|
3508
|
+
}], propDecorators: { position: [{
|
|
3509
|
+
type: Input
|
|
3510
|
+
}], toolbarContentTemplate: [{
|
|
3511
|
+
type: ViewChild,
|
|
3512
|
+
args: ['toolbar', { static: true }]
|
|
3513
|
+
}] } });
|
|
3514
|
+
class NodeToolbarWrapperDirective {
|
|
3515
|
+
constructor() {
|
|
3516
|
+
this.element = inject(ElementRef);
|
|
3517
|
+
}
|
|
3518
|
+
ngOnInit() {
|
|
3519
|
+
this.model.size.set({
|
|
3520
|
+
width: this.element.nativeElement.clientWidth,
|
|
3521
|
+
height: this.element.nativeElement.clientHeight
|
|
3522
|
+
});
|
|
3523
|
+
}
|
|
3524
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NodeToolbarWrapperDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
3525
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: NodeToolbarWrapperDirective, selector: "[nodeToolbarWrapper]", inputs: { model: "model" }, ngImport: i0 }); }
|
|
3526
|
+
}
|
|
3527
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NodeToolbarWrapperDirective, decorators: [{
|
|
3528
|
+
type: Directive,
|
|
3529
|
+
args: [{ selector: '[nodeToolbarWrapper]' }]
|
|
3530
|
+
}], propDecorators: { model: [{
|
|
3531
|
+
type: Input
|
|
3532
|
+
}] } });
|
|
3533
|
+
|
|
3534
|
+
class DragHandleDirective {
|
|
3535
|
+
get model() {
|
|
3536
|
+
return this.nodeAccessor.model();
|
|
3537
|
+
}
|
|
3538
|
+
constructor() {
|
|
3539
|
+
this.nodeAccessor = inject(NodeAccessorService);
|
|
3540
|
+
this.model.dragHandlesCount.update((count) => count + 1);
|
|
3541
|
+
inject(DestroyRef).onDestroy(() => {
|
|
3542
|
+
this.model.dragHandlesCount.update(count => count - 1);
|
|
3543
|
+
});
|
|
3544
|
+
}
|
|
3545
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DragHandleDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
3546
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: DragHandleDirective, selector: "[dragHandle]", host: { classAttribute: "vflow-drag-handle" }, ngImport: i0 }); }
|
|
3547
|
+
}
|
|
3548
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DragHandleDirective, decorators: [{
|
|
3549
|
+
type: Directive,
|
|
3550
|
+
args: [{
|
|
3551
|
+
selector: '[dragHandle]',
|
|
3552
|
+
host: {
|
|
3553
|
+
'class': 'vflow-drag-handle'
|
|
3554
|
+
}
|
|
3555
|
+
}]
|
|
3556
|
+
}], ctorParameters: function () { return []; } });
|
|
3557
|
+
|
|
3134
3558
|
const components = [
|
|
3135
3559
|
VflowComponent,
|
|
3136
3560
|
NodeComponent,
|
|
@@ -3142,7 +3566,8 @@ const components = [
|
|
|
3142
3566
|
DefsComponent,
|
|
3143
3567
|
BackgroundComponent,
|
|
3144
3568
|
ResizableComponent,
|
|
3145
|
-
MiniMapComponent
|
|
3569
|
+
MiniMapComponent,
|
|
3570
|
+
NodeToolbarComponent
|
|
3146
3571
|
];
|
|
3147
3572
|
const directives = [
|
|
3148
3573
|
SpacePointContextDirective,
|
|
@@ -3151,9 +3576,11 @@ const directives = [
|
|
|
3151
3576
|
RootSvgContextDirective,
|
|
3152
3577
|
HandleSizeControllerDirective,
|
|
3153
3578
|
SelectableDirective,
|
|
3579
|
+
DragHandleDirective,
|
|
3154
3580
|
PointerDirective,
|
|
3155
3581
|
RootPointerDirective,
|
|
3156
3582
|
FlowSizeControllerDirective,
|
|
3583
|
+
NodeToolbarWrapperDirective
|
|
3157
3584
|
];
|
|
3158
3585
|
const templateDirectives = [
|
|
3159
3586
|
NodeHtmlTemplateDirective,
|
|
@@ -3175,15 +3602,18 @@ class VflowModule {
|
|
|
3175
3602
|
DefsComponent,
|
|
3176
3603
|
BackgroundComponent,
|
|
3177
3604
|
ResizableComponent,
|
|
3178
|
-
MiniMapComponent,
|
|
3605
|
+
MiniMapComponent,
|
|
3606
|
+
NodeToolbarComponent, SpacePointContextDirective,
|
|
3179
3607
|
MapContextDirective,
|
|
3180
3608
|
RootSvgReferenceDirective,
|
|
3181
3609
|
RootSvgContextDirective,
|
|
3182
3610
|
HandleSizeControllerDirective,
|
|
3183
3611
|
SelectableDirective,
|
|
3612
|
+
DragHandleDirective,
|
|
3184
3613
|
PointerDirective,
|
|
3185
3614
|
RootPointerDirective,
|
|
3186
|
-
FlowSizeControllerDirective,
|
|
3615
|
+
FlowSizeControllerDirective,
|
|
3616
|
+
NodeToolbarWrapperDirective, NodeHtmlTemplateDirective,
|
|
3187
3617
|
GroupNodeTemplateDirective,
|
|
3188
3618
|
EdgeLabelHtmlTemplateDirective,
|
|
3189
3619
|
EdgeTemplateDirective,
|
|
@@ -3192,7 +3622,9 @@ class VflowModule {
|
|
|
3192
3622
|
HandleComponent,
|
|
3193
3623
|
ResizableComponent,
|
|
3194
3624
|
SelectableDirective,
|
|
3195
|
-
MiniMapComponent,
|
|
3625
|
+
MiniMapComponent,
|
|
3626
|
+
NodeToolbarComponent,
|
|
3627
|
+
DragHandleDirective, NodeHtmlTemplateDirective,
|
|
3196
3628
|
GroupNodeTemplateDirective,
|
|
3197
3629
|
EdgeLabelHtmlTemplateDirective,
|
|
3198
3630
|
EdgeTemplateDirective,
|
|
@@ -3210,17 +3642,74 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
|
|
|
3210
3642
|
ResizableComponent,
|
|
3211
3643
|
SelectableDirective,
|
|
3212
3644
|
MiniMapComponent,
|
|
3645
|
+
NodeToolbarComponent,
|
|
3646
|
+
DragHandleDirective,
|
|
3213
3647
|
...templateDirectives
|
|
3214
3648
|
],
|
|
3215
3649
|
declarations: [...components, ...directives, ...templateDirectives],
|
|
3216
3650
|
}]
|
|
3217
3651
|
}] });
|
|
3218
3652
|
|
|
3653
|
+
const mockModel = () => new NodeModel({ id: 'mock', type: 'default', point: { x: 0, y: 0 } });
|
|
3654
|
+
function provideCustomNodeMocks() {
|
|
3655
|
+
return [
|
|
3656
|
+
{
|
|
3657
|
+
provide: ComponentEventBusService,
|
|
3658
|
+
useValue: {
|
|
3659
|
+
pushEvent: () => { }
|
|
3660
|
+
}
|
|
3661
|
+
},
|
|
3662
|
+
{
|
|
3663
|
+
provide: HandleService,
|
|
3664
|
+
useFactory: () => ({
|
|
3665
|
+
node: signal(mockModel()),
|
|
3666
|
+
createHandle: () => { },
|
|
3667
|
+
destroyHandle: () => { },
|
|
3668
|
+
})
|
|
3669
|
+
},
|
|
3670
|
+
{
|
|
3671
|
+
provide: RootPointerDirective,
|
|
3672
|
+
useValue: {
|
|
3673
|
+
pointerMovement$: of({
|
|
3674
|
+
x: 0,
|
|
3675
|
+
y: 0,
|
|
3676
|
+
movementX: 0,
|
|
3677
|
+
movementY: 0,
|
|
3678
|
+
target: null,
|
|
3679
|
+
originalEvent: null
|
|
3680
|
+
}),
|
|
3681
|
+
documentPointerEnd$: of(null)
|
|
3682
|
+
}
|
|
3683
|
+
},
|
|
3684
|
+
{
|
|
3685
|
+
provide: SpacePointContextDirective,
|
|
3686
|
+
useValue: {
|
|
3687
|
+
documentPointToFlowPoint: (point) => point
|
|
3688
|
+
}
|
|
3689
|
+
},
|
|
3690
|
+
{
|
|
3691
|
+
provide: NodeAccessorService,
|
|
3692
|
+
useFactory: () => ({
|
|
3693
|
+
model: signal(mockModel())
|
|
3694
|
+
})
|
|
3695
|
+
},
|
|
3696
|
+
{
|
|
3697
|
+
provide: SelectionService,
|
|
3698
|
+
useValue: {
|
|
3699
|
+
select: () => { },
|
|
3700
|
+
}
|
|
3701
|
+
},
|
|
3702
|
+
FlowSettingsService,
|
|
3703
|
+
FlowEntitiesService,
|
|
3704
|
+
ViewportService
|
|
3705
|
+
];
|
|
3706
|
+
}
|
|
3707
|
+
|
|
3219
3708
|
// Modules
|
|
3220
3709
|
|
|
3221
3710
|
/**
|
|
3222
3711
|
* Generated bundle index. Do not edit.
|
|
3223
3712
|
*/
|
|
3224
3713
|
|
|
3225
|
-
export { ChangesControllerDirective, ConnectionControllerDirective, ConnectionTemplateDirective, CustomDynamicNodeComponent, CustomNodeComponent, EdgeLabelHtmlTemplateDirective, EdgeTemplateDirective, GroupNodeTemplateDirective, HandleComponent, HandleTemplateDirective, MiniMapComponent, NodeHtmlTemplateDirective, ResizableComponent, SelectableDirective, VflowComponent, VflowModule, isComponentDynamicNode, isComponentStaticNode, isDefaultDynamicGroupNode, isDefaultDynamicNode, isDefaultStaticGroupNode, isDefaultStaticNode, isDynamicNode, isStaticNode, isTemplateDynamicGroupNode, isTemplateDynamicNode, isTemplateStaticGroupNode, isTemplateStaticNode };
|
|
3714
|
+
export { ChangesControllerDirective, ConnectionControllerDirective, ConnectionTemplateDirective, CustomDynamicNodeComponent, CustomNodeComponent, DragHandleDirective, EdgeLabelHtmlTemplateDirective, EdgeTemplateDirective, GroupNodeTemplateDirective, HandleComponent, HandleTemplateDirective, MiniMapComponent, NodeHtmlTemplateDirective, NodeToolbarComponent, NodeToolbarWrapperDirective, ResizableComponent, SelectableDirective, VflowComponent, VflowModule, isComponentDynamicNode, isComponentStaticNode, isDefaultDynamicGroupNode, isDefaultDynamicNode, isDefaultStaticGroupNode, isDefaultStaticNode, isDynamicNode, isStaticNode, isTemplateDynamicGroupNode, isTemplateDynamicNode, isTemplateStaticGroupNode, isTemplateStaticNode, provideCustomNodeMocks };
|
|
3226
3715
|
//# sourceMappingURL=ngx-vflow.mjs.map
|