@visuallyjs/browser-ui-angular 1.2.0 → 1.2.2
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/index.mjs +6 -0
- package/esm2022/lib/background.component.mjs +38 -0
- package/esm2022/lib/base.group.component.mjs +3 -3
- package/esm2022/lib/base.node.component.mjs +3 -3
- package/esm2022/lib/base.port.component.mjs +4 -4
- package/esm2022/lib/base.vertex.component.mjs +33 -12
- package/esm2022/lib/browser-ui-angular.module.mjs +38 -8
- package/esm2022/lib/charts/area.chart.component.mjs +3 -3
- package/esm2022/lib/charts/bar.chart.component.mjs +3 -3
- package/esm2022/lib/charts/bubble.chart.component.mjs +3 -3
- package/esm2022/lib/charts/column.chart.component.mjs +3 -3
- package/esm2022/lib/charts/line.chart.component.mjs +3 -3
- package/esm2022/lib/charts/pie.chart.component.mjs +3 -3
- package/esm2022/lib/charts/sankey.chart.component.mjs +4 -4
- package/esm2022/lib/charts/scatter.chart.component.mjs +3 -3
- package/esm2022/lib/charts/series.based.chart.component.mjs +4 -4
- package/esm2022/lib/charts/xy.chart.component.mjs +3 -3
- package/esm2022/lib/color.tag.component.mjs +6 -6
- package/esm2022/lib/controls-component.mjs +4 -4
- package/esm2022/lib/decorator-component.mjs +3 -3
- package/esm2022/lib/default-group-component.mjs +3 -3
- package/esm2022/lib/default-node-component.mjs +3 -3
- package/esm2022/lib/diagram-component.mjs +34 -12
- package/esm2022/lib/diagram-palette-component.mjs +4 -4
- package/esm2022/lib/edge.type.picker.component.mjs +5 -5
- package/esm2022/lib/export-controls-component.mjs +3 -3
- package/esm2022/lib/grid-background.component.mjs +77 -0
- package/esm2022/lib/image-background.component.mjs +38 -0
- package/esm2022/lib/inspector.component.mjs +4 -4
- package/esm2022/lib/miniview-component.mjs +4 -4
- package/esm2022/lib/overlay-component.mjs +52 -1
- package/esm2022/lib/palette.component.mjs +4 -4
- package/esm2022/lib/paper-component.mjs +354 -0
- package/esm2022/lib/shape.component.mjs +4 -4
- package/esm2022/lib/shape.palette.component.mjs +4 -4
- package/esm2022/lib/surface-component.mjs +87 -16
- package/esm2022/lib/surface-popup-component.mjs +62 -0
- package/esm2022/lib/tiled-image-background.component.mjs +62 -0
- package/esm2022/lib/vjs-service.mjs +3 -3
- package/fesm2022/visuallyjs-browser-ui-angular.mjs +938 -144
- package/fesm2022/visuallyjs-browser-ui-angular.mjs.map +1 -1
- package/index.d.ts +6 -0
- package/lib/background.component.d.ts +13 -0
- package/lib/base.vertex.component.d.ts +29 -3
- package/lib/browser-ui-angular.module.d.ts +27 -21
- package/lib/diagram-component.d.ts +7 -5
- package/lib/grid-background.component.d.ts +81 -0
- package/lib/image-background.component.d.ts +18 -0
- package/lib/overlay-component.d.ts +32 -8
- package/lib/paper-component.d.ts +162 -0
- package/lib/surface-component.d.ts +25 -11
- package/lib/surface-popup-component.d.ts +62 -0
- package/lib/tiled-image-background.component.d.ts +72 -0
- package/package.json +2 -2
- package/visuallyjs-browser-ui-angular.tgz +0 -0
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
import { Component, ElementRef, EventEmitter, Input, NgZone, Output, ViewContainerRef, inject, reflectComponentType, input, effect } from "@angular/core";
|
|
2
|
+
import { EVENT_EDGE_UPDATED, EVENT_GROUP_UPDATED, EVENT_NODE_UPDATED, EVENT_PORT_ADDED, EVENT_PORT_UPDATED, extend, renderPaper, OVERLAY_TYPE_CUSTOM, isGroup, EVENT_INTERNAL_CONNECTION, EVENT_DATA_LOAD_END, ELEMENT_DIV, EVENT_EDGE_REMOVED, EVENT_EDGE_ADDED } from "@visuallyjs/browser-ui";
|
|
3
|
+
import { AngularComponentOverlayType, } from "./overlay-component";
|
|
4
|
+
import { DefaultGroupComponent } from "./default-group-component";
|
|
5
|
+
import { DefaultNodeComponent } from "./default-node-component";
|
|
6
|
+
import { BasePortComponent } from "./base.port.component";
|
|
7
|
+
import { VisuallyJsService } from "./vjs-service";
|
|
8
|
+
import { BrowserUIAngularModel } from "./model";
|
|
9
|
+
import * as i0 from "@angular/core";
|
|
10
|
+
|
|
11
|
+
export class PaperComponent {
|
|
12
|
+
constructor() {
|
|
13
|
+
|
|
14
|
+
this.data = input();
|
|
15
|
+
|
|
16
|
+
this.url = input();
|
|
17
|
+
|
|
18
|
+
this.vertexEvent = new EventEmitter();
|
|
19
|
+
this.$el = inject(ElementRef);
|
|
20
|
+
this.$viewContainerRef = inject(ViewContainerRef);
|
|
21
|
+
this.$ngZone = inject(NgZone);
|
|
22
|
+
this.$vjs = inject(VisuallyJsService);
|
|
23
|
+
this._dataEffect = effect(() => {
|
|
24
|
+
const currentData = this.data();
|
|
25
|
+
if (currentData) {
|
|
26
|
+
if (this.model) {
|
|
27
|
+
this.model.clear();
|
|
28
|
+
this.model.load({ data: currentData });
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
this._urlEffect = effect(() => {
|
|
33
|
+
const currentUrl = this.url();
|
|
34
|
+
if (currentUrl) {
|
|
35
|
+
// Respond to changes in the url here.
|
|
36
|
+
// For example, if you need to reload the model with new data:
|
|
37
|
+
if (this.model) {
|
|
38
|
+
this.model.clear();
|
|
39
|
+
this.model.load({ url: currentUrl });
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
getNativeElement(component) {
|
|
46
|
+
return component.location.nativeElement.childNodes[0];
|
|
47
|
+
}
|
|
48
|
+
_getComponent(el, tryParent) {
|
|
49
|
+
if (el == null) {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
let vjc = el._visuallyJsNgComponent;
|
|
54
|
+
if (vjc == null && tryParent && el.parentNode != null) {
|
|
55
|
+
vjc = el.parentNode._visuallyJsNgComponent;
|
|
56
|
+
}
|
|
57
|
+
return vjc;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
_getComponentThen(el, then, tryParent) {
|
|
61
|
+
const c = this._getComponent(el, tryParent);
|
|
62
|
+
if (c != null) {
|
|
63
|
+
then(c);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
nodeOrGroupUpdated(params) {
|
|
68
|
+
const info = this.paper.getObjectInfo(params.vertex, false);
|
|
69
|
+
this._getComponentThen(info.el, (component) => {
|
|
70
|
+
component.data = params.vertex.data;
|
|
71
|
+
component.$data?.set(component.data);
|
|
72
|
+
if (component.changeDetectorRef) {
|
|
73
|
+
component.changeDetectorRef.detectChanges();
|
|
74
|
+
}
|
|
75
|
+
}, false);
|
|
76
|
+
this._maybeUpdateEdgeOverlays(params.vertex);
|
|
77
|
+
}
|
|
78
|
+
portUpdated(params) {
|
|
79
|
+
const info = this.paper.getObjectInfo(params.port, false);
|
|
80
|
+
this._getComponentThen(info.el, (component) => {
|
|
81
|
+
if (component instanceof BasePortComponent) {
|
|
82
|
+
component.data = params.port.data;
|
|
83
|
+
if (component.changeDetectorRef) {
|
|
84
|
+
component.changeDetectorRef.detectChanges();
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}, true);
|
|
88
|
+
this._maybeUpdateEdgeOverlays(params.port);
|
|
89
|
+
}
|
|
90
|
+
_maybeUpdateEdgeOverlays(vertex) {
|
|
91
|
+
vertex.getAllEdges().forEach(e => this._handleEdgeUpdate(e.id));
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
_handleEdgeUpdate(edgeId) {
|
|
95
|
+
const connection = this.paper.getRenderedConnection(edgeId);
|
|
96
|
+
if (connection) {
|
|
97
|
+
for (let id in connection.overlays) {
|
|
98
|
+
const canvas = connection.overlays[id].contentElement;
|
|
99
|
+
this._getComponentThen(canvas, (component) => {
|
|
100
|
+
if (component.changeDetectorRef != null) {
|
|
101
|
+
component.changeDetectorRef.detectChanges();
|
|
102
|
+
}
|
|
103
|
+
}, false);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
edgeUpdated(params) {
|
|
109
|
+
this._handleEdgeUpdate(params.edge.id);
|
|
110
|
+
}
|
|
111
|
+
edgeAddedRemoved(params) {
|
|
112
|
+
const info = this.paper.getObjectInfo(params.edge.source, false);
|
|
113
|
+
if (info.el) {
|
|
114
|
+
this._getComponentThen(info.el, (component) => {
|
|
115
|
+
try {
|
|
116
|
+
;
|
|
117
|
+
component.$updateEdges();
|
|
118
|
+
if (component.changeDetectorRef) {
|
|
119
|
+
component.changeDetectorRef.detectChanges();
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
catch (e) { }
|
|
123
|
+
}, false);
|
|
124
|
+
}
|
|
125
|
+
const info2 = this.paper.getObjectInfo(params.edge.target, false);
|
|
126
|
+
if (info2.el && info.obj.getFullId() !== info2.obj.getFullId()) {
|
|
127
|
+
this._getComponentThen(info2.el, (component) => {
|
|
128
|
+
try {
|
|
129
|
+
;
|
|
130
|
+
component.$updateEdges();
|
|
131
|
+
// tslint:disable-next-line:align
|
|
132
|
+
if (component.changeDetectorRef) {
|
|
133
|
+
component.changeDetectorRef.detectChanges();
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
catch (e) { }
|
|
137
|
+
}, false);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
_processAngularOverlays(view) {
|
|
142
|
+
const self = this;
|
|
143
|
+
const edgeTypes = view.edges || {};
|
|
144
|
+
for (let edgeTypeId in edgeTypes) {
|
|
145
|
+
const edgeType = edgeTypes[edgeTypeId];
|
|
146
|
+
if (edgeType.overlays != null) {
|
|
147
|
+
edgeType.overlays = edgeType.overlays.map((o) => {
|
|
148
|
+
if (typeof o === "string") {
|
|
149
|
+
return o;
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
const fo = o;
|
|
153
|
+
if (fo.type === AngularComponentOverlayType) {
|
|
154
|
+
const newSpec = Object.assign(fo, {
|
|
155
|
+
type: OVERLAY_TYPE_CUSTOM,
|
|
156
|
+
});
|
|
157
|
+
newSpec.options = (newSpec.options || {});
|
|
158
|
+
newSpec.options.create = (connection) => {
|
|
159
|
+
const el = document.createElement(ELEMENT_DIV);
|
|
160
|
+
let createdComponent = self.$viewContainerRef.createComponent(newSpec.options.component);
|
|
161
|
+
let angularOverlayComponent = createdComponent.instance;
|
|
162
|
+
let nativeEl = createdComponent.location.nativeElement.childNodes[0];
|
|
163
|
+
el.appendChild(nativeEl);
|
|
164
|
+
el._visuallyJsNgComponent = angularOverlayComponent;
|
|
165
|
+
|
|
166
|
+
if (connection != null) {
|
|
167
|
+
const edge = connection.edge;
|
|
168
|
+
angularOverlayComponent.edge = edge;
|
|
169
|
+
angularOverlayComponent.data = edge.data;
|
|
170
|
+
}
|
|
171
|
+
angularOverlayComponent.model = self.model;
|
|
172
|
+
angularOverlayComponent.ui = self.paper;
|
|
173
|
+
createdComponent.changeDetectorRef.detectChanges();
|
|
174
|
+
return el;
|
|
175
|
+
};
|
|
176
|
+
return newSpec;
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
return fo;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return view;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
save(options) {
|
|
189
|
+
this.paper.save(options);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
exportData(options) {
|
|
193
|
+
return this.paper.model.exportData(options);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
dataLoadEnd() {
|
|
197
|
+
setTimeout(() => {
|
|
198
|
+
if (this.paper != null) {
|
|
199
|
+
this.paper.repaintEverything();
|
|
200
|
+
}
|
|
201
|
+
}, 0);
|
|
202
|
+
}
|
|
203
|
+
$removeNgElement(el) {
|
|
204
|
+
if (el._ref != null) {
|
|
205
|
+
el._ref.destroy();
|
|
206
|
+
}
|
|
207
|
+
if (el.parentNode != null) {
|
|
208
|
+
el.parentNode.removeChild(el);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
ngAfterViewInit() {
|
|
213
|
+
this.$ngZone.runOutsideAngular(() => {
|
|
214
|
+
const view = this._processAngularOverlays(this.viewOptions || {});
|
|
215
|
+
const self = this;
|
|
216
|
+
this.renderOptions = this.renderOptions || {};
|
|
217
|
+
const render = (directiveId, data, instance, objectType, paper, def, modelObject, eventInfo) => {
|
|
218
|
+
let component;
|
|
219
|
+
if (def.component == null) {
|
|
220
|
+
if (isGroup(modelObject)) {
|
|
221
|
+
component = DefaultGroupComponent;
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
component = DefaultNodeComponent;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
component = def.component;
|
|
229
|
+
}
|
|
230
|
+
let createdComponent = self.$viewContainerRef.createComponent(component);
|
|
231
|
+
let _componentRef = createdComponent.instance;
|
|
232
|
+
_componentRef.data = data || {};
|
|
233
|
+
_componentRef.model = model;
|
|
234
|
+
_componentRef.paper = paper;
|
|
235
|
+
_componentRef.ui = paper;
|
|
236
|
+
_componentRef.modelObject = modelObject;
|
|
237
|
+
// get the reflection data for the component
|
|
238
|
+
const componentInfo = reflectComponentType(component);
|
|
239
|
+
// ..and populate any declared inputs from data
|
|
240
|
+
componentInfo.inputs.forEach((pt) => {
|
|
241
|
+
const pv = _componentRef.data[pt.propName];
|
|
242
|
+
if (pv != null) {
|
|
243
|
+
_componentRef[pt.propName] = pv;
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
// map to any outputs
|
|
247
|
+
componentInfo.outputs.forEach((pt) => {
|
|
248
|
+
_componentRef[pt.propName].subscribe((d) => self.vertexEvent.emit({
|
|
249
|
+
vertex: modelObject,
|
|
250
|
+
event: pt.propName,
|
|
251
|
+
payload: d,
|
|
252
|
+
component: createdComponent,
|
|
253
|
+
}));
|
|
254
|
+
});
|
|
255
|
+
// if angular def has 'inputs' set, set them on the component. this is different to the mechanism above, in which values are extracted from
|
|
256
|
+
// each node's backing data. here we inject values either as a string or from some arbitrary function.
|
|
257
|
+
if (def.inputs != null) {
|
|
258
|
+
for (let k in def.inputs) {
|
|
259
|
+
const v = def.inputs[k];
|
|
260
|
+
const value = typeof v === "string" ? v : v(modelObject);
|
|
261
|
+
_componentRef[k] = value;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
createdComponent.changeDetectorRef.detectChanges();
|
|
265
|
+
// TODO this should not be necessary
|
|
266
|
+
const nativeElement = self.getNativeElement(createdComponent);
|
|
267
|
+
_componentRef._el = nativeElement;
|
|
268
|
+
_componentRef._el._visuallyJsNgComponent = _componentRef;
|
|
269
|
+
_componentRef._el._ref = createdComponent; // we store _ref so we can call `destroy` on it later if the node is removed.
|
|
270
|
+
paper.$vertexRendered(modelObject, nativeElement, def, eventInfo);
|
|
271
|
+
};
|
|
272
|
+
const templateRenderer = {
|
|
273
|
+
asynchronous: false,
|
|
274
|
+
reactive: true,
|
|
275
|
+
usesWrapperElement: false,
|
|
276
|
+
update: (el, data, v, renderer) => { },
|
|
277
|
+
render,
|
|
278
|
+
rerender: (directiveId, data, instance, objectType, paper, def, modelObject, eventInfo, originalElement) => {
|
|
279
|
+
this.$removeNgElement(originalElement);
|
|
280
|
+
render(directiveId, data, instance, objectType, paper, def, modelObject, eventInfo);
|
|
281
|
+
},
|
|
282
|
+
cleanupVertex: (objId, el) => {
|
|
283
|
+
this.$removeNgElement(el);
|
|
284
|
+
},
|
|
285
|
+
cleanupPort: (objId, el) => {
|
|
286
|
+
this.$removeNgElement(el);
|
|
287
|
+
},
|
|
288
|
+
};
|
|
289
|
+
const renderParams = extend(this.renderOptions || {}, {
|
|
290
|
+
view: view,
|
|
291
|
+
});
|
|
292
|
+
let model = this.inputModel || new BrowserUIAngularModel(this.modelOptions);
|
|
293
|
+
this.model = model;
|
|
294
|
+
this.paper = renderPaper(model, self.$el.nativeElement, templateRenderer, renderParams);
|
|
295
|
+
this.$vjs.$setPaper(this.paper);
|
|
296
|
+
// ----------------
|
|
297
|
+
this.nodeUpdateFn = this.nodeOrGroupUpdated.bind(this);
|
|
298
|
+
model.bind(EVENT_NODE_UPDATED, this.nodeUpdateFn);
|
|
299
|
+
model.bind(EVENT_PORT_ADDED, this.nodeUpdateFn);
|
|
300
|
+
model.bind(EVENT_GROUP_UPDATED, this.nodeUpdateFn);
|
|
301
|
+
this.dataLoadEndFn = this.dataLoadEnd.bind(this);
|
|
302
|
+
model.bind(EVENT_DATA_LOAD_END, this.dataLoadEndFn);
|
|
303
|
+
this.portUpdateFn = this.portUpdated.bind(this);
|
|
304
|
+
model.bind(EVENT_PORT_UPDATED, this.portUpdateFn);
|
|
305
|
+
this.edgeUpdateFn = this.edgeUpdated.bind(this);
|
|
306
|
+
model.bind(EVENT_EDGE_UPDATED, this.edgeUpdateFn);
|
|
307
|
+
this.edgeAddFn = this.edgeAddedRemoved.bind(this);
|
|
308
|
+
this.edgeRemoveFn = this.edgeAddedRemoved.bind(this);
|
|
309
|
+
model.bind(EVENT_EDGE_ADDED, this.edgeAddFn);
|
|
310
|
+
model.bind(EVENT_EDGE_REMOVED, this.edgeRemoveFn);
|
|
311
|
+
const initialData = this.data();
|
|
312
|
+
const initialUrl = this.url();
|
|
313
|
+
if (initialData) {
|
|
314
|
+
this.model.load({ data: initialData });
|
|
315
|
+
}
|
|
316
|
+
else if (initialUrl) {
|
|
317
|
+
this.model.load({ url: initialUrl });
|
|
318
|
+
}
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
ngOnDestroy() {
|
|
323
|
+
this.paper.destroy();
|
|
324
|
+
this.model.unbind(EVENT_NODE_UPDATED, this.nodeUpdateFn);
|
|
325
|
+
this.model.unbind(EVENT_GROUP_UPDATED, this.nodeUpdateFn);
|
|
326
|
+
this.model.unbind(EVENT_PORT_ADDED, this.nodeUpdateFn);
|
|
327
|
+
this.model.unbind(EVENT_PORT_UPDATED, this.portUpdateFn);
|
|
328
|
+
this.model.unbind(EVENT_EDGE_UPDATED, this.edgeUpdateFn);
|
|
329
|
+
this.model.unbind(EVENT_EDGE_ADDED, this.edgeAddFn);
|
|
330
|
+
this.model.unbind(EVENT_EDGE_REMOVED, this.edgeRemoveFn);
|
|
331
|
+
this.model.unbind(EVENT_DATA_LOAD_END, this.dataLoadEndFn);
|
|
332
|
+
this.paper.unbind(EVENT_INTERNAL_CONNECTION, this.edgeAddFn);
|
|
333
|
+
}
|
|
334
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: PaperComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
335
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "17.3.12", type: PaperComponent, selector: "vjs-paper", inputs: { inputModel: { classPropertyName: "inputModel", publicName: "model", isSignal: false, isRequired: false, transformFunction: null }, viewOptions: { classPropertyName: "viewOptions", publicName: "viewOptions", isSignal: false, isRequired: false, transformFunction: null }, renderOptions: { classPropertyName: "renderOptions", publicName: "renderOptions", isSignal: false, isRequired: false, transformFunction: null }, modelOptions: { classPropertyName: "modelOptions", publicName: "modelOptions", isSignal: false, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, url: { classPropertyName: "url", publicName: "url", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { vertexEvent: "vertexEvent" }, ngImport: i0, template: `<ng-content></ng-content>`, isInline: true }); }
|
|
336
|
+
}
|
|
337
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: PaperComponent, decorators: [{
|
|
338
|
+
type: Component,
|
|
339
|
+
args: [{
|
|
340
|
+
selector: "vjs-paper",
|
|
341
|
+
template: `<ng-content></ng-content>`
|
|
342
|
+
}]
|
|
343
|
+
}], propDecorators: { inputModel: [{
|
|
344
|
+
type: Input,
|
|
345
|
+
args: [{ alias: "model" }]
|
|
346
|
+
}], viewOptions: [{
|
|
347
|
+
type: Input
|
|
348
|
+
}], renderOptions: [{
|
|
349
|
+
type: Input
|
|
350
|
+
}], modelOptions: [{
|
|
351
|
+
type: Input
|
|
352
|
+
}], vertexEvent: [{
|
|
353
|
+
type: Output
|
|
354
|
+
}] } });
|
|
@@ -41,8 +41,8 @@ export class ShapeComponent {
|
|
|
41
41
|
ngOnChanges(changes) {
|
|
42
42
|
this._render();
|
|
43
43
|
}
|
|
44
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
45
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "
|
|
44
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ShapeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
45
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: ShapeComponent, selector: "vjs-shape", inputs: { obj: "obj", width: "width", height: "height", showLabels: "showLabels", labelProperty: "labelProperty", labelStrokeWidth: "labelStrokeWidth", label: "label", multilineLabels: "multilineLabels", labelFillRatio: "labelFillRatio", font: "font" }, usesOnChanges: true, ngImport: i0, template: `<svg:svg
|
|
46
46
|
[attr.stroke-width]="obj.outlineWidth || 2"
|
|
47
47
|
attr.fill="{{ obj.fill }}"
|
|
48
48
|
attr.stroke="{{ obj.outline }}"
|
|
@@ -51,7 +51,7 @@ export class ShapeComponent {
|
|
|
51
51
|
attr.viewBox="0 0 {{ width }} {{ height }}"
|
|
52
52
|
></svg:svg>`, isInline: true }); }
|
|
53
53
|
}
|
|
54
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
54
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ShapeComponent, decorators: [{
|
|
55
55
|
type: Component,
|
|
56
56
|
args: [{
|
|
57
57
|
template: `<svg:svg
|
|
@@ -64,7 +64,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
|
|
|
64
64
|
></svg:svg>`,
|
|
65
65
|
selector: `vjs-shape`,
|
|
66
66
|
}]
|
|
67
|
-
}], ctorParameters:
|
|
67
|
+
}], ctorParameters: () => [], propDecorators: { obj: [{
|
|
68
68
|
type: Input
|
|
69
69
|
}], width: [{
|
|
70
70
|
type: Input
|
|
@@ -48,16 +48,16 @@ export class ShapePaletteComponent {
|
|
|
48
48
|
}
|
|
49
49
|
});
|
|
50
50
|
}
|
|
51
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
52
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "
|
|
51
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ShapePaletteComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
52
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: ShapePaletteComponent, selector: "vjs-shape-palette", inputs: { initialSet: "initialSet", dragSize: "dragSize", iconSize: "iconSize", fill: "fill", outline: "outline", showAllMessage: "showAllMessage", selectAfterDrop: "selectAfterDrop", paletteStrokeWidth: "paletteStrokeWidth", onVertexAdded: "onVertexAdded", dataGenerator: "dataGenerator", preparedShapes: "preparedShapes" }, ngImport: i0, template: `<div></div>`, isInline: true }); }
|
|
53
53
|
}
|
|
54
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
54
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ShapePaletteComponent, decorators: [{
|
|
55
55
|
type: Component,
|
|
56
56
|
args: [{
|
|
57
57
|
template: `<div></div>`,
|
|
58
58
|
selector: `vjs-shape-palette`
|
|
59
59
|
}]
|
|
60
|
-
}], ctorParameters:
|
|
60
|
+
}], ctorParameters: () => [], propDecorators: { initialSet: [{
|
|
61
61
|
type: Input
|
|
62
62
|
}], dragSize: [{
|
|
63
63
|
type: Input
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Component, ElementRef, EventEmitter, Input, NgZone, Output, ViewContainerRef, inject, reflectComponentType } from "@angular/core";
|
|
2
|
-
import { EVENT_EDGE_UPDATED, EVENT_GROUP_UPDATED, EVENT_NODE_UPDATED, EVENT_PORT_ADDED, EVENT_PORT_UPDATED, extend, renderSurface, OVERLAY_TYPE_CUSTOM, isGroup, EVENT_INTERNAL_CONNECTION, EVENT_DATA_LOAD_END, ELEMENT_DIV } from "@visuallyjs/browser-ui";
|
|
1
|
+
import { Component, ElementRef, EventEmitter, Input, NgZone, Output, ViewContainerRef, inject, reflectComponentType, input, effect } from "@angular/core";
|
|
2
|
+
import { EVENT_EDGE_UPDATED, EVENT_GROUP_UPDATED, EVENT_NODE_UPDATED, EVENT_PORT_ADDED, EVENT_PORT_UPDATED, extend, renderSurface, OVERLAY_TYPE_CUSTOM, isGroup, EVENT_INTERNAL_CONNECTION, EVENT_DATA_LOAD_END, ELEMENT_DIV, EVENT_EDGE_REMOVED, EVENT_EDGE_ADDED } from "@visuallyjs/browser-ui";
|
|
3
3
|
import { AngularComponentOverlayType, } from "./overlay-component";
|
|
4
4
|
import { DefaultGroupComponent } from "./default-group-component";
|
|
5
5
|
import { DefaultNodeComponent } from "./default-node-component";
|
|
@@ -11,13 +11,36 @@ import * as i0 from "@angular/core";
|
|
|
11
11
|
export class SurfaceComponent {
|
|
12
12
|
constructor() {
|
|
13
13
|
|
|
14
|
+
this.data = input();
|
|
15
|
+
|
|
16
|
+
this.url = input();
|
|
17
|
+
|
|
14
18
|
this.vertexEvent = new EventEmitter();
|
|
15
19
|
this.$el = inject(ElementRef);
|
|
16
20
|
this.$viewContainerRef = inject(ViewContainerRef);
|
|
17
21
|
this.$ngZone = inject(NgZone);
|
|
18
22
|
this.$vjs = inject(VisuallyJsService);
|
|
23
|
+
this._dataEffect = effect(() => {
|
|
24
|
+
const currentData = this.data();
|
|
25
|
+
if (currentData) {
|
|
26
|
+
if (this.model) {
|
|
27
|
+
this.model.clear();
|
|
28
|
+
this.model.load({ data: currentData });
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
this._urlEffect = effect(() => {
|
|
33
|
+
const currentUrl = this.url();
|
|
34
|
+
if (currentUrl) {
|
|
35
|
+
// Respond to changes in the url here.
|
|
36
|
+
// For example, if you need to reload the model with new data:
|
|
37
|
+
if (this.model) {
|
|
38
|
+
this.model.clear();
|
|
39
|
+
this.model.load({ url: currentUrl });
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
});
|
|
19
43
|
}
|
|
20
|
-
// $vjsSignals = inject(VisuallyJsSignalService)
|
|
21
44
|
|
|
22
45
|
getNativeElement(component) {
|
|
23
46
|
return component.location.nativeElement.childNodes[0];
|
|
@@ -46,10 +69,16 @@ export class SurfaceComponent {
|
|
|
46
69
|
this._getComponentThen(info.el, (component) => {
|
|
47
70
|
component.data = params.vertex.data;
|
|
48
71
|
component.$data?.set(component.data);
|
|
72
|
+
try {
|
|
73
|
+
;
|
|
74
|
+
component.$updateEdges();
|
|
75
|
+
}
|
|
76
|
+
catch (e) { }
|
|
49
77
|
if (component.changeDetectorRef) {
|
|
50
78
|
component.changeDetectorRef.detectChanges();
|
|
51
79
|
}
|
|
52
80
|
}, false);
|
|
81
|
+
this._maybeUpdateEdgeOverlays(params.vertex);
|
|
53
82
|
}
|
|
54
83
|
portUpdated(params) {
|
|
55
84
|
const info = this.surface.getObjectInfo(params.port, false);
|
|
@@ -61,10 +90,14 @@ export class SurfaceComponent {
|
|
|
61
90
|
}
|
|
62
91
|
}
|
|
63
92
|
}, true);
|
|
93
|
+
this._maybeUpdateEdgeOverlays(params.port);
|
|
94
|
+
}
|
|
95
|
+
_maybeUpdateEdgeOverlays(vertex) {
|
|
96
|
+
vertex.getAllEdges().forEach(e => this._handleEdgeUpdate(e.id));
|
|
64
97
|
}
|
|
65
98
|
|
|
66
|
-
|
|
67
|
-
const connection = this.surface.getRenderedConnection(
|
|
99
|
+
_handleEdgeUpdate(edgeId) {
|
|
100
|
+
const connection = this.surface.getRenderedConnection(edgeId);
|
|
68
101
|
if (connection) {
|
|
69
102
|
for (let id in connection.overlays) {
|
|
70
103
|
const canvas = connection.overlays[id].contentElement;
|
|
@@ -77,6 +110,36 @@ export class SurfaceComponent {
|
|
|
77
110
|
}
|
|
78
111
|
}
|
|
79
112
|
|
|
113
|
+
edgeUpdated(params) {
|
|
114
|
+
this._handleEdgeUpdate(params.edge.id);
|
|
115
|
+
}
|
|
116
|
+
edgeAddedRemoved(params) {
|
|
117
|
+
const info = this.surface.getObjectInfo(params.edge.source, false);
|
|
118
|
+
if (info.el) {
|
|
119
|
+
this._getComponentThen(info.el, (component) => {
|
|
120
|
+
try {
|
|
121
|
+
component.$updateEdges();
|
|
122
|
+
if (component.changeDetectorRef) {
|
|
123
|
+
component.changeDetectorRef.detectChanges();
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
catch (e) { }
|
|
127
|
+
}, false);
|
|
128
|
+
}
|
|
129
|
+
const info2 = this.surface.getObjectInfo(params.edge.target, false);
|
|
130
|
+
if (info2.el && info.obj.getFullId() !== info2.obj.getFullId()) {
|
|
131
|
+
this._getComponentThen(info2.el, (component) => {
|
|
132
|
+
try {
|
|
133
|
+
component.$updateEdges();
|
|
134
|
+
if (component.changeDetectorRef) {
|
|
135
|
+
component.changeDetectorRef.detectChanges();
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
catch (e) { }
|
|
139
|
+
}, false);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
80
143
|
_processAngularOverlays(view) {
|
|
81
144
|
const self = this;
|
|
82
145
|
const edgeTypes = view.edges || {};
|
|
@@ -108,7 +171,10 @@ export class SurfaceComponent {
|
|
|
108
171
|
angularOverlayComponent.data = edge.data;
|
|
109
172
|
}
|
|
110
173
|
angularOverlayComponent.model = self.model;
|
|
174
|
+
// backwards compat: remove at some point
|
|
175
|
+
;
|
|
111
176
|
angularOverlayComponent.surface = self.surface;
|
|
177
|
+
angularOverlayComponent.ui = self.surface;
|
|
112
178
|
createdComponent.changeDetectorRef.detectChanges();
|
|
113
179
|
return el;
|
|
114
180
|
};
|
|
@@ -171,6 +237,7 @@ export class SurfaceComponent {
|
|
|
171
237
|
_componentRef.data = data || {};
|
|
172
238
|
_componentRef.model = model;
|
|
173
239
|
_componentRef.surface = surface;
|
|
240
|
+
_componentRef.ui = surface;
|
|
174
241
|
_componentRef.modelObject = modelObject;
|
|
175
242
|
// get the reflection data for the component
|
|
176
243
|
const componentInfo = reflectComponentType(component);
|
|
@@ -242,11 +309,17 @@ export class SurfaceComponent {
|
|
|
242
309
|
model.bind(EVENT_PORT_UPDATED, this.portUpdateFn);
|
|
243
310
|
this.edgeUpdateFn = this.edgeUpdated.bind(this);
|
|
244
311
|
model.bind(EVENT_EDGE_UPDATED, this.edgeUpdateFn);
|
|
245
|
-
|
|
246
|
-
|
|
312
|
+
this.edgeAddFn = this.edgeAddedRemoved.bind(this);
|
|
313
|
+
this.edgeRemoveFn = this.edgeAddedRemoved.bind(this);
|
|
314
|
+
model.bind(EVENT_EDGE_ADDED, this.edgeAddFn);
|
|
315
|
+
model.bind(EVENT_EDGE_REMOVED, this.edgeRemoveFn);
|
|
316
|
+
const initialData = this.data();
|
|
317
|
+
const initialUrl = this.url();
|
|
318
|
+
if (initialData) {
|
|
319
|
+
this.model.load({ data: initialData });
|
|
247
320
|
}
|
|
248
|
-
else if (
|
|
249
|
-
this.model.load({ url:
|
|
321
|
+
else if (initialUrl) {
|
|
322
|
+
this.model.load({ url: initialUrl });
|
|
250
323
|
}
|
|
251
324
|
});
|
|
252
325
|
}
|
|
@@ -258,13 +331,15 @@ export class SurfaceComponent {
|
|
|
258
331
|
this.model.unbind(EVENT_PORT_ADDED, this.nodeUpdateFn);
|
|
259
332
|
this.model.unbind(EVENT_PORT_UPDATED, this.portUpdateFn);
|
|
260
333
|
this.model.unbind(EVENT_EDGE_UPDATED, this.edgeUpdateFn);
|
|
334
|
+
this.model.unbind(EVENT_EDGE_ADDED, this.edgeAddFn);
|
|
335
|
+
this.model.unbind(EVENT_EDGE_REMOVED, this.edgeRemoveFn);
|
|
261
336
|
this.model.unbind(EVENT_DATA_LOAD_END, this.dataLoadEndFn);
|
|
262
337
|
this.surface.unbind(EVENT_INTERNAL_CONNECTION, this.edgeAddFn);
|
|
263
338
|
}
|
|
264
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "
|
|
265
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "
|
|
339
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SurfaceComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
340
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "17.3.12", type: SurfaceComponent, selector: "vjs-surface", inputs: { inputModel: { classPropertyName: "inputModel", publicName: "model", isSignal: false, isRequired: false, transformFunction: null }, viewOptions: { classPropertyName: "viewOptions", publicName: "viewOptions", isSignal: false, isRequired: false, transformFunction: null }, renderOptions: { classPropertyName: "renderOptions", publicName: "renderOptions", isSignal: false, isRequired: false, transformFunction: null }, modelOptions: { classPropertyName: "modelOptions", publicName: "modelOptions", isSignal: false, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, url: { classPropertyName: "url", publicName: "url", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { vertexEvent: "vertexEvent" }, ngImport: i0, template: `<ng-content></ng-content>`, isInline: true }); }
|
|
266
341
|
}
|
|
267
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "
|
|
342
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SurfaceComponent, decorators: [{
|
|
268
343
|
type: Component,
|
|
269
344
|
args: [{
|
|
270
345
|
selector: "vjs-surface",
|
|
@@ -279,10 +354,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImpo
|
|
|
279
354
|
type: Input
|
|
280
355
|
}], modelOptions: [{
|
|
281
356
|
type: Input
|
|
282
|
-
}], data: [{
|
|
283
|
-
type: Input
|
|
284
|
-
}], url: [{
|
|
285
|
-
type: Input
|
|
286
357
|
}], vertexEvent: [{
|
|
287
358
|
type: Output
|
|
288
359
|
}] } });
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { Component, Input, ContentChild, TemplateRef, ViewChild, inject, signal, computed, ChangeDetectorRef } from "@angular/core";
|
|
2
|
+
import { PopupHandler, CLASS_SURFACE_POPUP } from "@visuallyjs/browser-ui";
|
|
3
|
+
import { VisuallyJsService } from "./vjs-service";
|
|
4
|
+
import * as i0 from "@angular/core";
|
|
5
|
+
import * as i1 from "@angular/common";
|
|
6
|
+
|
|
7
|
+
export class SurfacePopupComponent {
|
|
8
|
+
constructor() {
|
|
9
|
+
this.cdr = inject(ChangeDetectorRef);
|
|
10
|
+
this.vjs = inject(VisuallyJsService);
|
|
11
|
+
this.initialized = false;
|
|
12
|
+
this.current = signal(null);
|
|
13
|
+
this.model = this.vjs.model;
|
|
14
|
+
this.ui = this.vjs.ui;
|
|
15
|
+
this.display = computed(() => (this.current() == null ? "none" : "block"));
|
|
16
|
+
}
|
|
17
|
+
ngAfterViewInit() {
|
|
18
|
+
this._hideFunction = function () {
|
|
19
|
+
this.popupHandler?.$hide();
|
|
20
|
+
}.bind(this);
|
|
21
|
+
this.vjs.getSurface((surface) => {
|
|
22
|
+
if (!this.initialized) {
|
|
23
|
+
this.initialized = true;
|
|
24
|
+
this.popupHandler = new PopupHandler(this.selector, this.container.nativeElement, surface, (v) => {
|
|
25
|
+
this.current.set(v);
|
|
26
|
+
requestAnimationFrame(() => this.cdr.detectChanges());
|
|
27
|
+
}, this.anchor);
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
ngOnDestroy() {
|
|
32
|
+
if (this.popupHandler) {
|
|
33
|
+
this.popupHandler.$destroy();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SurfacePopupComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
37
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: SurfacePopupComponent, selector: "vjs-surface-popup", inputs: { selector: "selector", anchor: "anchor" }, queries: [{ propertyName: "template", first: true, predicate: TemplateRef, descendants: true }], viewQueries: [{ propertyName: "container", first: true, predicate: ["container"], descendants: true }], ngImport: i0, template: "\n <div #container class=\"vjs-surface-popup\" [style.display]=\"display()\" style=\"position:absolute\">\n <ng-container *ngIf=\"current()\">\n <ng-container *ngTemplateOutlet=\"template; context: { vertex: current(), model: model(), ui: ui(), hide:_hideFunction }\"></ng-container>\n </ng-container>\n </div>\n ", isInline: true, dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] }); }
|
|
38
|
+
}
|
|
39
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SurfacePopupComponent, decorators: [{
|
|
40
|
+
type: Component,
|
|
41
|
+
args: [{
|
|
42
|
+
selector: "vjs-surface-popup",
|
|
43
|
+
template: `
|
|
44
|
+
<div #container class="${CLASS_SURFACE_POPUP}" [style.display]="display()" style="position:absolute">
|
|
45
|
+
<ng-container *ngIf="current()">
|
|
46
|
+
<ng-container *ngTemplateOutlet="template; context: { vertex: current(), model: model(), ui: ui(), hide:_hideFunction }"></ng-container>
|
|
47
|
+
</ng-container>
|
|
48
|
+
</div>
|
|
49
|
+
`
|
|
50
|
+
}]
|
|
51
|
+
}], propDecorators: { selector: [{
|
|
52
|
+
type: Input,
|
|
53
|
+
args: [{ required: true }]
|
|
54
|
+
}], anchor: [{
|
|
55
|
+
type: Input
|
|
56
|
+
}], template: [{
|
|
57
|
+
type: ContentChild,
|
|
58
|
+
args: [TemplateRef]
|
|
59
|
+
}], container: [{
|
|
60
|
+
type: ViewChild,
|
|
61
|
+
args: ["container"]
|
|
62
|
+
}] } });
|