ngx-vflow 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/lib/vflow/components/background/background.component.mjs +66 -0
- package/esm2022/lib/vflow/components/handle/handle.component.mjs +1 -1
- package/esm2022/lib/vflow/components/node/node.component.mjs +4 -5
- package/esm2022/lib/vflow/components/vflow/vflow.component.mjs +11 -10
- package/esm2022/lib/vflow/types/background.type.mjs +2 -0
- package/esm2022/lib/vflow/utils/id.mjs +5 -0
- package/esm2022/lib/vflow/utils/resizable.mjs +3 -3
- package/esm2022/lib/vflow/vflow.module.mjs +6 -3
- package/esm2022/public-api.mjs +2 -1
- package/fesm2022/ngx-vflow.mjs +78 -12
- package/fesm2022/ngx-vflow.mjs.map +1 -1
- package/lib/vflow/components/background/background.component.d.ts +20 -0
- package/lib/vflow/components/node/node.component.d.ts +0 -1
- package/lib/vflow/components/vflow/vflow.component.d.ts +3 -2
- package/lib/vflow/models/edge.model.d.ts +1 -17
- package/lib/vflow/types/background.type.d.ts +24 -0
- package/lib/vflow/utils/id.d.ts +1 -0
- package/lib/vflow/utils/resizable.d.ts +1 -2
- package/lib/vflow/vflow.module.d.ts +12 -11
- package/package.json +1 -1
- package/public-api.d.ts +1 -0
package/fesm2022/ngx-vflow.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as i1 from '@angular/common';
|
|
2
2
|
import { CommonModule } from '@angular/common';
|
|
3
3
|
import * as i0 from '@angular/core';
|
|
4
|
-
import { signal, Injectable, inject, ElementRef, Directive, computed, effect, untracked, Input, TemplateRef, EventEmitter, Output, DestroyRef, runInInjectionContext, HostListener, Injector,
|
|
4
|
+
import { signal, Injectable, inject, ElementRef, Directive, computed, effect, untracked, Input, TemplateRef, EventEmitter, Output, DestroyRef, runInInjectionContext, HostListener, Injector, Component, ChangeDetectionStrategy, ViewChild, ContentChild, NgModule } from '@angular/core';
|
|
5
5
|
import { select } from 'd3-selection';
|
|
6
6
|
import { zoomIdentity, zoom } from 'd3-zoom';
|
|
7
7
|
import { Subject, tap, merge, BehaviorSubject, observeOn, animationFrameScheduler, switchMap, skip, map, pairwise, filter, distinctUntilChanged, asyncScheduler, zip, Observable, fromEvent, share, Subscription, startWith } from 'rxjs';
|
|
@@ -1138,10 +1138,10 @@ class HandleModel {
|
|
|
1138
1138
|
}
|
|
1139
1139
|
}
|
|
1140
1140
|
|
|
1141
|
-
function resizable(elems
|
|
1141
|
+
function resizable(elems) {
|
|
1142
1142
|
return new Observable((subscriber) => {
|
|
1143
1143
|
let ro = new ResizeObserver((entries) => {
|
|
1144
|
-
|
|
1144
|
+
subscriber.next(entries);
|
|
1145
1145
|
});
|
|
1146
1146
|
elems.forEach(e => ro.observe(e));
|
|
1147
1147
|
return () => ro.disconnect();
|
|
@@ -1334,7 +1334,6 @@ class NodeComponent {
|
|
|
1334
1334
|
constructor() {
|
|
1335
1335
|
this.injector = inject(Injector);
|
|
1336
1336
|
this.handleService = inject(HandleService);
|
|
1337
|
-
this.zone = inject(NgZone);
|
|
1338
1337
|
this.draggableService = inject(DraggableService);
|
|
1339
1338
|
this.flowStatusService = inject(FlowStatusService);
|
|
1340
1339
|
this.flowEntitiesService = inject(FlowEntitiesService);
|
|
@@ -1352,7 +1351,7 @@ class NodeComponent {
|
|
|
1352
1351
|
this.handleService.node.set(this.nodeModel);
|
|
1353
1352
|
this.draggableService.toggleDraggable(this.hostRef.nativeElement, this.nodeModel);
|
|
1354
1353
|
const sub = this.nodeModel.handles$
|
|
1355
|
-
.pipe(switchMap((handles) => resizable(handles.map(h => h.parentReference)
|
|
1354
|
+
.pipe(switchMap((handles) => resizable(handles.map(h => h.parentReference))
|
|
1356
1355
|
.pipe(map(() => handles))), tap((handles) => handles.forEach(h => h.updateParent())))
|
|
1357
1356
|
.subscribe();
|
|
1358
1357
|
this.subscription.add(sub);
|
|
@@ -1366,7 +1365,7 @@ class NodeComponent {
|
|
|
1366
1365
|
});
|
|
1367
1366
|
}
|
|
1368
1367
|
if (this.nodeModel.node.type === 'html-template' || this.nodeModel.isComponentType) {
|
|
1369
|
-
const sub = resizable([this.htmlWrapperRef.nativeElement]
|
|
1368
|
+
const sub = resizable([this.htmlWrapperRef.nativeElement])
|
|
1370
1369
|
.pipe(startWith(null), tap(() => {
|
|
1371
1370
|
const width = this.htmlWrapperRef.nativeElement.clientWidth;
|
|
1372
1371
|
const height = this.htmlWrapperRef.nativeElement.clientHeight;
|
|
@@ -1735,6 +1734,71 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
|
|
|
1735
1734
|
args: [{ required: true }]
|
|
1736
1735
|
}] } });
|
|
1737
1736
|
|
|
1737
|
+
function id() {
|
|
1738
|
+
const randomLetter = String.fromCharCode(65 + Math.floor(Math.random() * 26));
|
|
1739
|
+
return randomLetter + Date.now();
|
|
1740
|
+
}
|
|
1741
|
+
|
|
1742
|
+
const defaultBg = '#fff';
|
|
1743
|
+
const defaultGap = 20;
|
|
1744
|
+
const defaultDotSize = 2;
|
|
1745
|
+
const defaultDotColor = 'rgb(177, 177, 183)';
|
|
1746
|
+
class BackgroundComponent {
|
|
1747
|
+
set background(value) {
|
|
1748
|
+
this.backgroundSignal.set(value);
|
|
1749
|
+
}
|
|
1750
|
+
constructor() {
|
|
1751
|
+
this.viewportService = inject(ViewportService);
|
|
1752
|
+
this.rootSvg = inject(RootSvgReferenceDirective).element;
|
|
1753
|
+
this.backgroundSignal = signal({ type: 'solid', color: defaultBg });
|
|
1754
|
+
this.scaledGap = computed(() => {
|
|
1755
|
+
const background = this.backgroundSignal();
|
|
1756
|
+
if (background.type === 'dots') {
|
|
1757
|
+
const zoom = this.viewportService.readableViewport().zoom;
|
|
1758
|
+
return zoom * (background.gap ?? defaultGap);
|
|
1759
|
+
}
|
|
1760
|
+
return 0;
|
|
1761
|
+
});
|
|
1762
|
+
this.x = computed(() => this.viewportService.readableViewport().x % this.scaledGap());
|
|
1763
|
+
this.y = computed(() => this.viewportService.readableViewport().y % this.scaledGap());
|
|
1764
|
+
this.patternColor = computed(() => this.backgroundSignal().color ?? defaultDotColor);
|
|
1765
|
+
this.patternSize = computed(() => {
|
|
1766
|
+
const background = this.backgroundSignal();
|
|
1767
|
+
if (background.type === 'dots') {
|
|
1768
|
+
return (this.viewportService.readableViewport().zoom * (background.size ?? defaultDotSize)) / 2;
|
|
1769
|
+
}
|
|
1770
|
+
return 0;
|
|
1771
|
+
});
|
|
1772
|
+
// Without ID there will be pattern collision for several flows on the page
|
|
1773
|
+
// Later pattern ID may be exposed to API
|
|
1774
|
+
this.patternId = id();
|
|
1775
|
+
this.patternUrl = `url(#${this.patternId})`;
|
|
1776
|
+
effect(() => {
|
|
1777
|
+
const background = this.backgroundSignal();
|
|
1778
|
+
if (background.type === 'dots') {
|
|
1779
|
+
this.rootSvg.style.backgroundColor = background.backgroundColor ?? defaultBg;
|
|
1780
|
+
}
|
|
1781
|
+
if (background.type === 'solid') {
|
|
1782
|
+
this.rootSvg.style.backgroundColor = background.color;
|
|
1783
|
+
}
|
|
1784
|
+
});
|
|
1785
|
+
}
|
|
1786
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: BackgroundComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1787
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "16.1.0", version: "16.2.12", type: BackgroundComponent, selector: "g[background]", inputs: { background: ["background", "background", transform] }, ngImport: i0, template: "<ng-container *ngIf=\"backgroundSignal().type === 'dots'\">\n <svg:pattern\n [attr.id]=\"patternId\"\n [attr.x]=\"x()\"\n [attr.y]=\"y()\"\n [attr.width]=\"scaledGap()\"\n [attr.height]=\"scaledGap()\"\n patternUnits=\"userSpaceOnUse\"\n >\n <svg:circle\n [attr.cx]=\"patternSize()\"\n [attr.cy]=\"patternSize()\"\n [attr.r]=\"patternSize()\"\n [attr.fill]=\"patternColor()\"\n />\n </svg:pattern>\n\n <svg:rect\n x=\"0\"\n y=\"0\"\n width=\"100%\"\n height=\"100%\"\n [attr.fill]=\"patternUrl\"\n />\n</ng-container>\n", dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] }); }
|
|
1788
|
+
}
|
|
1789
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: BackgroundComponent, decorators: [{
|
|
1790
|
+
type: Component,
|
|
1791
|
+
args: [{ selector: 'g[background]', 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" }]
|
|
1792
|
+
}], ctorParameters: function () { return []; }, propDecorators: { background: [{
|
|
1793
|
+
type: Input,
|
|
1794
|
+
args: [{ required: true, transform }]
|
|
1795
|
+
}] } });
|
|
1796
|
+
function transform(background) {
|
|
1797
|
+
return typeof background === 'string'
|
|
1798
|
+
? { type: 'solid', color: background }
|
|
1799
|
+
: background;
|
|
1800
|
+
}
|
|
1801
|
+
|
|
1738
1802
|
// TODO: too general purpose nane
|
|
1739
1803
|
class RootSvgContextDirective {
|
|
1740
1804
|
constructor() {
|
|
@@ -1816,9 +1880,9 @@ class VflowComponent {
|
|
|
1816
1880
|
*/
|
|
1817
1881
|
this.maxZoom = 3;
|
|
1818
1882
|
/**
|
|
1819
|
-
* Background
|
|
1883
|
+
* Background for flow
|
|
1820
1884
|
*/
|
|
1821
|
-
this.background = '#
|
|
1885
|
+
this.background = '#fff';
|
|
1822
1886
|
this.nodeModels = computed(() => this.nodeRenderingService.nodes());
|
|
1823
1887
|
this.edgeModels = computed(() => this.flowEntitiesService.validEdges());
|
|
1824
1888
|
// #endregion
|
|
@@ -1977,7 +2041,7 @@ class VflowComponent {
|
|
|
1977
2041
|
SelectionService,
|
|
1978
2042
|
FlowSettingsService,
|
|
1979
2043
|
ComponentEventBusService
|
|
1980
|
-
], queries: [{ propertyName: "nodeHtmlDirective", first: true, predicate: NodeHtmlTemplateDirective, descendants: true }, { propertyName: "edgeTemplateDirective", first: true, predicate: EdgeTemplateDirective, descendants: true }, { propertyName: "edgeLabelHtmlDirective", first: true, predicate: EdgeLabelHtmlTemplateDirective, descendants: true }, { propertyName: "connectionTemplateDirective", first: true, predicate: ConnectionTemplateDirective, descendants: true }], viewQueries: [{ propertyName: "mapContext", first: true, predicate: MapContextDirective, descendants: true }], hostDirectives: [{ directive: ConnectionControllerDirective, outputs: ["onConnect", "onConnect"] }, { directive: ChangesControllerDirective, outputs: ["onNodesChange", "onNodesChange", "onNodesChange.position", "onNodesChange.position", "onNodesChange.position.single", "onNodesChange.position.single", "onNodesChange.position.many", "onNodesChange.position.many", "onNodesChange.add", "onNodesChange.add", "onNodesChange.add.single", "onNodesChange.add.single", "onNodesChange.add.many", "onNodesChange.add.many", "onNodesChange.remove", "onNodesChange.remove", "onNodesChange.remove.single", "onNodesChange.remove.single", "onNodesChange.remove.many", "onNodesChange.remove.many", "onNodesChange.select", "onNodesChange.select", "onNodesChange.select.single", "onNodesChange.select.single", "onNodesChange.select.many", "onNodesChange.select.many", "onEdgesChange", "onEdgesChange", "onEdgesChange.detached", "onEdgesChange.detached", "onEdgesChange.detached.single", "onEdgesChange.detached.single", "onEdgesChange.detached.many", "onEdgesChange.detached.many", "onEdgesChange.add", "onEdgesChange.add", "onEdgesChange.add.single", "onEdgesChange.add.single", "onEdgesChange.add.many", "onEdgesChange.add.many", "onEdgesChange.remove", "onEdgesChange.remove", "onEdgesChange.remove.single", "onEdgesChange.remove.single", "onEdgesChange.remove.many", "onEdgesChange.remove.many", "onEdgesChange.select", "onEdgesChange.select", "onEdgesChange.select.single", "onEdgesChange.select.single", "onEdgesChange.select.many", "onEdgesChange.select.many"] }], ngImport: i0, template: "<svg:svg\n rootSvgRef\n rootSvgContext\n rootPointer\n class=\"root-svg\"\n #flow\n [
|
|
2044
|
+
], queries: [{ propertyName: "nodeHtmlDirective", first: true, predicate: NodeHtmlTemplateDirective, descendants: true }, { propertyName: "edgeTemplateDirective", first: true, predicate: EdgeTemplateDirective, descendants: true }, { propertyName: "edgeLabelHtmlDirective", first: true, predicate: EdgeLabelHtmlTemplateDirective, descendants: true }, { propertyName: "connectionTemplateDirective", first: true, predicate: ConnectionTemplateDirective, descendants: true }], viewQueries: [{ propertyName: "mapContext", first: true, predicate: MapContextDirective, descendants: true }], hostDirectives: [{ directive: ConnectionControllerDirective, outputs: ["onConnect", "onConnect"] }, { directive: ChangesControllerDirective, outputs: ["onNodesChange", "onNodesChange", "onNodesChange.position", "onNodesChange.position", "onNodesChange.position.single", "onNodesChange.position.single", "onNodesChange.position.many", "onNodesChange.position.many", "onNodesChange.add", "onNodesChange.add", "onNodesChange.add.single", "onNodesChange.add.single", "onNodesChange.add.many", "onNodesChange.add.many", "onNodesChange.remove", "onNodesChange.remove", "onNodesChange.remove.single", "onNodesChange.remove.single", "onNodesChange.remove.many", "onNodesChange.remove.many", "onNodesChange.select", "onNodesChange.select", "onNodesChange.select.single", "onNodesChange.select.single", "onNodesChange.select.many", "onNodesChange.select.many", "onEdgesChange", "onEdgesChange", "onEdgesChange.detached", "onEdgesChange.detached", "onEdgesChange.detached.single", "onEdgesChange.detached.single", "onEdgesChange.detached.many", "onEdgesChange.detached.many", "onEdgesChange.add", "onEdgesChange.add", "onEdgesChange.add.single", "onEdgesChange.add.single", "onEdgesChange.add.many", "onEdgesChange.add.many", "onEdgesChange.remove", "onEdgesChange.remove", "onEdgesChange.remove.single", "onEdgesChange.remove.single", "onEdgesChange.remove.many", "onEdgesChange.remove.many", "onEdgesChange.select", "onEdgesChange.select", "onEdgesChange.select.single", "onEdgesChange.select.single", "onEdgesChange.select.many", "onEdgesChange.select.many"] }], ngImport: i0, template: "<svg:svg\n rootSvgRef\n rootSvgContext\n rootPointer\n class=\"root-svg\"\n #flow\n [attr.width]=\"flowWidth()\"\n [attr.height]=\"flowHeight()\"\n>\n <defs [markers]=\"markers()\" flowDefs />\n\n <g [background]=\"background\"/>\n\n <svg:g\n mapContext\n spacePointContext\n [minZoom]=\"minZoom\"\n [maxZoom]=\"maxZoom\"\n >\n <!-- Connection -->\n <svg:g\n connection\n [model]=\"connection\"\n [template]=\"connectionTemplateDirective?.templateRef\"\n />\n\n <!-- Edges -->\n <svg:g\n *ngFor=\"let model of edgeModels(); trackBy: trackEdges\"\n edge\n [model]=\"model\"\n [edgeTemplate]=\"edgeTemplateDirective?.templateRef\"\n [edgeLabelHtmlTemplate]=\"edgeLabelHtmlDirective?.templateRef\"\n />\n\n <!-- Nodes -->\n <svg:g\n *ngFor=\"let model of nodeModels(); trackBy: trackNodes\"\n node\n [nodeModel]=\"model\"\n [nodeHtmlTemplate]=\"nodeHtmlDirective?.templateRef\"\n [attr.transform]=\"model.pointTransform()\"\n />\n </svg:g>\n\n</svg:svg>\n", styles: [":host{display:block;width:100%;height:100%;-webkit-user-select:none;user-select:none}:host ::ng-deep *{box-sizing:border-box}\n"], dependencies: [{ kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "component", type: NodeComponent, selector: "g[node]", inputs: ["nodeModel", "nodeHtmlTemplate"] }, { kind: "component", type: EdgeComponent, selector: "g[edge]", inputs: ["model", "edgeTemplate", "edgeLabelHtmlTemplate"] }, { kind: "component", type: ConnectionComponent, selector: "g[connection]", inputs: ["model", "template"] }, { kind: "component", type: DefsComponent, selector: "defs[flowDefs]", inputs: ["markers"] }, { kind: "component", type: BackgroundComponent, selector: "g[background]", inputs: ["background"] }, { kind: "directive", type: SpacePointContextDirective, selector: "g[spacePointContext]" }, { kind: "directive", type: MapContextDirective, selector: "g[mapContext]", inputs: ["minZoom", "maxZoom"] }, { kind: "directive", type: RootSvgReferenceDirective, selector: "svg[rootSvgRef]" }, { kind: "directive", type: RootSvgContextDirective, selector: "svg[rootSvgContext]" }, { kind: "directive", type: RootPointerDirective, selector: "svg[rootPointer]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
1981
2045
|
}
|
|
1982
2046
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: VflowComponent, decorators: [{
|
|
1983
2047
|
type: Component,
|
|
@@ -1995,7 +2059,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
|
|
|
1995
2059
|
], hostDirectives: [
|
|
1996
2060
|
connectionControllerHostDirective,
|
|
1997
2061
|
changesControllerHostDirective
|
|
1998
|
-
], template: "<svg:svg\n rootSvgRef\n rootSvgContext\n rootPointer\n class=\"root-svg\"\n #flow\n [
|
|
2062
|
+
], template: "<svg:svg\n rootSvgRef\n rootSvgContext\n rootPointer\n class=\"root-svg\"\n #flow\n [attr.width]=\"flowWidth()\"\n [attr.height]=\"flowHeight()\"\n>\n <defs [markers]=\"markers()\" flowDefs />\n\n <g [background]=\"background\"/>\n\n <svg:g\n mapContext\n spacePointContext\n [minZoom]=\"minZoom\"\n [maxZoom]=\"maxZoom\"\n >\n <!-- Connection -->\n <svg:g\n connection\n [model]=\"connection\"\n [template]=\"connectionTemplateDirective?.templateRef\"\n />\n\n <!-- Edges -->\n <svg:g\n *ngFor=\"let model of edgeModels(); trackBy: trackEdges\"\n edge\n [model]=\"model\"\n [edgeTemplate]=\"edgeTemplateDirective?.templateRef\"\n [edgeLabelHtmlTemplate]=\"edgeLabelHtmlDirective?.templateRef\"\n />\n\n <!-- Nodes -->\n <svg:g\n *ngFor=\"let model of nodeModels(); trackBy: trackNodes\"\n node\n [nodeModel]=\"model\"\n [nodeHtmlTemplate]=\"nodeHtmlDirective?.templateRef\"\n [attr.transform]=\"model.pointTransform()\"\n />\n </svg:g>\n\n</svg:svg>\n", styles: [":host{display:block;width:100%;height:100%;-webkit-user-select:none;user-select:none}:host ::ng-deep *{box-sizing:border-box}\n"] }]
|
|
1999
2063
|
}], propDecorators: { view: [{
|
|
2000
2064
|
type: Input
|
|
2001
2065
|
}], minZoom: [{
|
|
@@ -2116,7 +2180,8 @@ const components = [
|
|
|
2116
2180
|
EdgeLabelComponent,
|
|
2117
2181
|
ConnectionComponent,
|
|
2118
2182
|
HandleComponent,
|
|
2119
|
-
DefsComponent
|
|
2183
|
+
DefsComponent,
|
|
2184
|
+
BackgroundComponent
|
|
2120
2185
|
];
|
|
2121
2186
|
const directives = [
|
|
2122
2187
|
SpacePointContextDirective,
|
|
@@ -2143,7 +2208,8 @@ class VflowModule {
|
|
|
2143
2208
|
EdgeLabelComponent,
|
|
2144
2209
|
ConnectionComponent,
|
|
2145
2210
|
HandleComponent,
|
|
2146
|
-
DefsComponent,
|
|
2211
|
+
DefsComponent,
|
|
2212
|
+
BackgroundComponent, SpacePointContextDirective,
|
|
2147
2213
|
MapContextDirective,
|
|
2148
2214
|
RootSvgReferenceDirective,
|
|
2149
2215
|
RootSvgContextDirective,
|