@esfaenza/es-diagrams 12.2.13 → 13.1.3

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.
Files changed (50) hide show
  1. package/esfaenza-es-diagrams.d.ts +1 -5
  2. package/esm2020/esfaenza-es-diagrams.mjs +5 -0
  3. package/esm2020/lib/components/es-diagram.component.mjs +519 -0
  4. package/esm2020/lib/esdiagram.module.mjs +33 -0
  5. package/esm2020/lib/extensions/ReactiveExtensions.mjs +36 -0
  6. package/{esm2015/lib/extensions/ResizeSensor.js → esm2020/lib/extensions/ResizeSensor.mjs} +0 -0
  7. package/{esm2015/lib/models/EsDiagramModuleConfig.js → esm2020/lib/models/EsDiagramModuleConfig.mjs} +0 -0
  8. package/{esm2015/lib/models/component/contextmenu/ContextMenuCommand.js → esm2020/lib/models/component/contextmenu/ContextMenuCommand.mjs} +0 -0
  9. package/{esm2015/lib/models/component/contextmenu/ContextMenuOptions.js → esm2020/lib/models/component/contextmenu/ContextMenuOptions.mjs} +0 -0
  10. package/{esm2015/lib/models/component/grouping/ExpandCollapseOptions.js → esm2020/lib/models/component/grouping/ExpandCollapseOptions.mjs} +0 -0
  11. package/{esm2015/lib/models/component/nodes/NodeHTMLTemplate.js → esm2020/lib/models/component/nodes/NodeHTMLTemplate.mjs} +0 -0
  12. package/{esm2015/lib/models/component/nodes/NodeTemplate.js → esm2020/lib/models/component/nodes/NodeTemplate.mjs} +0 -0
  13. package/{esm2015/lib/models/component/nodes/ZoomLevelBasedTemplate.js → esm2020/lib/models/component/nodes/ZoomLevelBasedTemplate.mjs} +0 -0
  14. package/{esm2015/lib/models/layouts/BreadthFirstLayoutOptionsImpl.js → esm2020/lib/models/layouts/BreadthFirstLayoutOptionsImpl.mjs} +0 -0
  15. package/{esm2015/lib/models/layouts/CircleLayoutOptionsImpl.js → esm2020/lib/models/layouts/CircleLayoutOptionsImpl.mjs} +0 -0
  16. package/{esm2015/lib/models/layouts/ConcentricLayoutOptionsImpl.js → esm2020/lib/models/layouts/ConcentricLayoutOptionsImpl.mjs} +0 -0
  17. package/{esm2015/lib/models/layouts/CoseLayoutOptionsImpl.js → esm2020/lib/models/layouts/CoseLayoutOptionsImpl.mjs} +0 -0
  18. package/{esm2015/lib/models/layouts/DagreLayoutOptionsImpl.js → esm2020/lib/models/layouts/DagreLayoutOptionsImpl.mjs} +0 -0
  19. package/{esm2015/lib/models/layouts/GridLayoutOptionsImpl.js → esm2020/lib/models/layouts/GridLayoutOptionsImpl.mjs} +0 -0
  20. package/{esm2015/lib/models/layouts/NullLayoutOptionsImpl.js → esm2020/lib/models/layouts/NullLayoutOptionsImpl.mjs} +0 -0
  21. package/{esm2015/lib/models/layouts/PresetLayoutOptionsImpl.js → esm2020/lib/models/layouts/PresetLayoutOptionsImpl.mjs} +0 -0
  22. package/{esm2015/lib/models/layouts/RandomLayoutOptionsImpl.js → esm2020/lib/models/layouts/RandomLayoutOptionsImpl.mjs} +0 -0
  23. package/{esm2015/lib/models/layouts/base/AnimateLayoutOptionsImpl.js → esm2020/lib/models/layouts/base/AnimateLayoutOptionsImpl.mjs} +0 -0
  24. package/{esm2015/lib/models/layouts/base/BaseLayoutOptionsImpl.js → esm2020/lib/models/layouts/base/BaseLayoutOptionsImpl.mjs} +0 -0
  25. package/{esm2015/lib/models/layouts/base/ShapedLayoutOptionsImpl.js → esm2020/lib/models/layouts/base/ShapedLayoutOptionsImpl.mjs} +0 -0
  26. package/esm2020/lib/services/es-diagram.dispatcher.mjs +89 -0
  27. package/{esm2015/lib/services/es-diagram.loc.js → esm2020/lib/services/es-diagram.loc.mjs} +0 -0
  28. package/esm2020/lib/services/es-diagram.service.mjs +112 -0
  29. package/{esm2015/lib/tokens.js → esm2020/lib/tokens.mjs} +0 -0
  30. package/{esm2015/public-api.js → esm2020/public-api.mjs} +0 -0
  31. package/fesm2015/{esfaenza-es-diagrams.js → esfaenza-es-diagrams.mjs} +180 -136
  32. package/fesm2015/esfaenza-es-diagrams.mjs.map +1 -0
  33. package/fesm2020/esfaenza-es-diagrams.mjs +1391 -0
  34. package/fesm2020/esfaenza-es-diagrams.mjs.map +1 -0
  35. package/lib/components/es-diagram.component.d.ts +3 -0
  36. package/lib/esdiagram.module.d.ts +7 -0
  37. package/lib/extensions/ReactiveExtensions.d.ts +3 -0
  38. package/lib/services/es-diagram.dispatcher.d.ts +3 -0
  39. package/lib/services/es-diagram.service.d.ts +3 -0
  40. package/package.json +21 -9
  41. package/bundles/esfaenza-es-diagrams.umd.js +0 -1856
  42. package/bundles/esfaenza-es-diagrams.umd.js.map +0 -1
  43. package/esfaenza-es-diagrams.metadata.json +0 -1
  44. package/esm2015/esfaenza-es-diagrams.js +0 -10
  45. package/esm2015/lib/components/es-diagram.component.js +0 -503
  46. package/esm2015/lib/esdiagram.module.js +0 -28
  47. package/esm2015/lib/extensions/ReactiveExtensions.js +0 -34
  48. package/esm2015/lib/services/es-diagram.dispatcher.js +0 -86
  49. package/esm2015/lib/services/es-diagram.service.js +0 -106
  50. package/fesm2015/esfaenza-es-diagrams.js.map +0 -1
@@ -0,0 +1,1391 @@
1
+ import * as i0 from '@angular/core';
2
+ import { InjectionToken, Injectable, Optional, Inject, EventEmitter, Component, ViewChild, Input, Output, NgModule } from '@angular/core';
3
+ import * as cy_ from 'cytoscape';
4
+ import { FormsModule, ReactiveFormsModule } from '@angular/forms';
5
+ import { CommonModule } from '@angular/common';
6
+
7
+ /**
8
+ * Definizione di un comando del Context menù
9
+ */
10
+ class ContextMenuCommand {
11
+ }
12
+
13
+ /**
14
+ * Opzioni che gestiscono il context menu. Quando una di queste opzioni non viene assegnata viene mantenuto il default, assicurarsi quindi di modificare solo
15
+ * le proprietà che si vogliono effettivamente cambiare rispetto ai default
16
+ */
17
+ class ContextMenuOptions {
18
+ }
19
+
20
+ /**
21
+ * Opzioni native per l'estensione expand-collapse di cytoscape
22
+ */
23
+ class ExpandCollapseOptions {
24
+ }
25
+
26
+ /**
27
+ * Classe che indica per una data query quali template applicare
28
+ */
29
+ class NodeHTMLTemplate {
30
+ }
31
+
32
+ /**
33
+ * Classe che rappresenta un template HTML applicabile ad un nodo
34
+ */
35
+ class NodeTemplate {
36
+ }
37
+
38
+ /**
39
+ * Classe che rappresenta il template HTML di un nodo da utilizzare per un certo livello di zoom
40
+ */
41
+ class ZoomLevelBasedTemplate {
42
+ }
43
+
44
+ /**
45
+ * Opzioni di layout di base che si collegano al **ready** e allo **stop** eventualmente per aggiungere del log addizionale
46
+ */
47
+ class BaseLayoutOptionsImpl {
48
+ /**
49
+ * Per ora ignoro lato documentale dato che sono placholder
50
+ * @ignore
51
+ */
52
+ ready(e) {
53
+ }
54
+ /**
55
+ * Per ora ignoro lato documentale dato che sono placholder
56
+ * @ignore
57
+ */
58
+ stop(e) {
59
+ }
60
+ }
61
+
62
+ /**
63
+ * Classe base con le opzioni di layout valide per tutti i layout animati
64
+ */
65
+ class AnimateLayoutOptionsImpl extends BaseLayoutOptionsImpl {
66
+ /** @ignore */
67
+ constructor() {
68
+ super();
69
+ /**
70
+ * Livello di zoom da impostare (si consiglia fit = **false** se viene impostato)
71
+ */
72
+ this.zoom = null;
73
+ /**
74
+ * Livello di pan da impostare (si consiglia fit = **false** se viene impostato)
75
+ */
76
+ this.pan = null;
77
+ /**
78
+ * Indica se animare il cambio di posizione dei nodi
79
+ */
80
+ this.animate = false;
81
+ /**
82
+ * Con **animate** a true indica la durata dell'animazione
83
+ */
84
+ this.animationDuration = 500;
85
+ /**
86
+ * Abilita o no l'easing dell'animazione, può essere una stringa come ad esempio "ease-in-out-cubic" o altre funzioni scritte allo stesso modo prese da https://easings.net/
87
+ */
88
+ this.animationEasing = undefined;
89
+ /**
90
+ * Funzione che indica se un nodo dev'essere animato o no.
91
+ * Tutti i nodi sono animati di default.
92
+ * Tutti i nodi che non vengono animati verranno posizionati appena inizia l'animazione
93
+ *
94
+ * @param {any} node Nodo per cui decidere se abilitare l'animazione o no
95
+ * @param {number} i Indice del nodo corrente
96
+ *
97
+ * @returns {boolean} **true** se il nodo dev'essere animato, **false** altrimenti
98
+ */
99
+ this.animateFilter = (node, i) => true;
100
+ }
101
+ }
102
+
103
+ /**
104
+ * Classe base per gli algoritmi "Shaped"
105
+ */
106
+ class ShapedLayoutOptionsImpl extends AnimateLayoutOptionsImpl {
107
+ /** @ignore */
108
+ constructor() {
109
+ super();
110
+ /**
111
+ * Indica se adattare al contenitore
112
+ */
113
+ this.fit = true;
114
+ /**
115
+ * Padding rispetto al contenitore
116
+ */
117
+ this.padding = 30;
118
+ /**
119
+ * Specifica le dimensioni esatte al cui interno effettuare il layouting, specificato come **{ x1, y1, x2, y2 }** o **{ x1, y1, w, h }**
120
+ */
121
+ this.boundingBox = null;
122
+ /**
123
+ * Fa in modo che i nodi non si accavallino, ma se il contenitore non ha abbastanza spazio potrebbero andare in overflow
124
+ */
125
+ this.avoidOverlap = true;
126
+ /**
127
+ * Include o esclude le dimensioni delle label dei nodi nel calcolo delle posizioni
128
+ */
129
+ this.nodeDimensionsIncludeLabels = false;
130
+ /**
131
+ * Moltiplicatore delle dimensioni per espandere/restringere le dimensioni globali del diagramma
132
+ */
133
+ this.spacingFactor = 1;
134
+ /**
135
+ * Funzione di ordinamento per ordinare i nodi
136
+ */
137
+ this.sort = null;
138
+ /**
139
+ * Funzione per la trasformazione delle posizioni dei nodi
140
+ *
141
+ * @param {any} node Nodo
142
+ * @param {any} position Posizione iniziale
143
+ *
144
+ * @returns {any} Posizione finale
145
+ */
146
+ this.transform = (node, position) => position;
147
+ }
148
+ }
149
+
150
+ /**
151
+ * Default per l'implementazione dell'algoritmo Breadth First
152
+ */
153
+ class BreadthFirstLayoutOptionsImpl extends ShapedLayoutOptionsImpl {
154
+ /** @ignore */
155
+ constructor() {
156
+ super();
157
+ /**
158
+ * Nome dell'algoritmo di layouting
159
+ */
160
+ this.name = 'breadthfirst';
161
+ /**
162
+ * Indica se l'albero è diretto in basso. Se false i collegamenti fra i nodi possono andare in qualsiasi direzione
163
+ */
164
+ this.directed = false;
165
+ /**
166
+ * Se **true** i livelli vengono ordinati in cerchi concentrici, se **false** vengono oridnati dall'alto al basso
167
+ */
168
+ this.circle = false;
169
+ /**
170
+ * Indica che i nodi verranno shiftati in base al proprio livello in modo da evitare collegamenti inversi (solo per i DAG)
171
+ */
172
+ this.maximal = false;
173
+ /**
174
+ * Indica se creare una griglia in cui ordinare i nodi del DAG (Solo quando la proprietà **circle** è a **false**)
175
+ */
176
+ this.grid = false;
177
+ /**
178
+ * Indica se escludere le label dei nodi quando vengono calcolati i limiti del layout
179
+ */
180
+ this.nodeDimensionsIncludeLabels = false;
181
+ }
182
+ }
183
+
184
+ /**
185
+ * Default per l'implementazione dell'algoritmo Circle
186
+ */
187
+ class CircleLayoutOptionsImpl extends ShapedLayoutOptionsImpl {
188
+ /** @ignore */
189
+ constructor() {
190
+ super();
191
+ /**
192
+ * Nome dell'algoritmo di layouting
193
+ */
194
+ this.name = 'circle';
195
+ /**
196
+ * Angolo da cui i nodi partono, in radianti (Default: **3 / 2 * Math.PI**)
197
+ */
198
+ this.startAngle = 3 / 2 * Math.PI;
199
+ /**
200
+ * Numero di radianti fra il primo e l'ultimo nodo. Di default viene utilizzata l'intera circonferenza
201
+ */
202
+ this.sweep = null;
203
+ /**
204
+ * Indica se andare in senso orario (**true**) o antiorario (**false**)
205
+ */
206
+ this.clockwise = true; // whether the layout should go clockwise (true) or counterclockwise/anticlockwise (false)
207
+ }
208
+ }
209
+
210
+ /**
211
+ * Default per l'implementazione dell'algoritmo Concentric
212
+ */
213
+ class ConcentricLayoutOptionsImpl {
214
+ constructor() {
215
+ /**
216
+ * Nome dell'algoritmo di layouting
217
+ */
218
+ this.name = 'concentric';
219
+ /**
220
+ * Angolo da cui i nodi partono, in radianti (Default: **3 / 2 * Math.PI**)
221
+ */
222
+ this.startAngle = 3 / 2 * Math.PI;
223
+ /**
224
+ * Include o esclude le dimensioni delle label dei nodi nel calcolo delle posizioni
225
+ */
226
+ this.nodeDimensionsIncludeLabels = true;
227
+ /**
228
+ * Indica se i livelli devono essere o non essere equidistanti, potrebbe causare overflow dal contenitore
229
+ */
230
+ this.equidistant = false;
231
+ /**
232
+ * Distanza minima dall'esterno dei nodi, utilizzato per aggiustare il raggio
233
+ */
234
+ this.minNodeSpacingnumber = 10;
235
+ /**
236
+ * Specifica le dimensioni esatte al cui interno effettuare il layouting, specificato come **{ x1, y1, x2, y2 }** o **{ x1, y1, w, h }**
237
+ */
238
+ this.boundingBox = null;
239
+ /**
240
+ * Altezza dell'area di layout (sovrascrive quella del contenitore)
241
+ */
242
+ this.height = null;
243
+ /**
244
+ * Larghezza dell'area di layout (sovrascrive quella del contenitore)
245
+ */
246
+ this.width = null;
247
+ /**
248
+ * Moltiplicatore delle dimensioni per espandere/restringere le dimensioni globali del diagramma
249
+ */
250
+ this.spacingFactor = 1;
251
+ }
252
+ /**
253
+ * Funzione di cui si può fare override per assegnare un valore ad ogni nodo. I nodi con valore più alto saranno piazzati verso il centro
254
+ *
255
+ * @param {any} node Nodo
256
+ *
257
+ * @returns {number} Valore su cui ordinare i nodi verso il centro
258
+ */
259
+ concentric(node) {
260
+ return node.degree();
261
+ }
262
+ /**
263
+ * Funzione di cui si può fare override per calcolare la variazione dei valori concentrici per ogni livello
264
+ *
265
+ * @param {any} nodes Gruppo di nodi del livello
266
+ *
267
+ * @returns {number} Variazione dei valori concentrici
268
+ */
269
+ levelWidth(nodes) {
270
+ return nodes.maxDegree() / 4;
271
+ }
272
+ }
273
+
274
+ /**
275
+ * Default per l'implementazione dell'algoritmo Cose
276
+ */
277
+ class CoseLayoutOptionsImpl extends ShapedLayoutOptionsImpl {
278
+ /** @ignore */
279
+ constructor() {
280
+ super();
281
+ /**
282
+ * Nome dell'algoritmo di layouting
283
+ */
284
+ this.name = 'cose';
285
+ /**
286
+ * Se **animate** è **true**, l'animazione parte solo dopo questo numero di millisecondi (Evita flickering su animazioni veloci)
287
+ */
288
+ this.animationThreshold = 250;
289
+ /**
290
+ * Numero di iterazioni fra aggiornamenti consecutivi della posizione a schermo
291
+ */
292
+ this.refresh = 20;
293
+ /**
294
+ * Se **true** la posizione iniziale dei nodi è casuale, se **false** utilizza la posizione originale
295
+ */
296
+ this.randomize = false;
297
+ /**
298
+ * Spazio extra fra i componenti di un grafo non-compound
299
+ */
300
+ this.componentSpacing = 40;
301
+ /**
302
+ * Moltiplicatore della repulsione fra nodi in caso di overlap
303
+ */
304
+ this.nodeOverlap = 4;
305
+ /**
306
+ * Moltiplicatore di nesting per il calcolo della lunghezza ideale dei collegamenti nested
307
+ */
308
+ this.nestingFactor = 1.2;
309
+ /**
310
+ * Costante di gravità
311
+ */
312
+ this.gravity = 1;
313
+ /**
314
+ * Numero massimo di iterazioni da eseguire
315
+ */
316
+ this.numIter = 1000;
317
+ /**
318
+ * Temperatura iniziale (massima distanza fra i nodi)
319
+ */
320
+ this.initialTemp = 1000;
321
+ /**
322
+ * Fattore di raffreddamento. Ad ogni iterazione verrà sottratto ad **initialTemp**
323
+ */
324
+ this.coolingFactor = 0.99;
325
+ /**
326
+ * Soglia minima di temperatura. Una volta raggiunta il layout si considera terminato
327
+ */
328
+ this.minTemp = 1.0;
329
+ /**
330
+ * Moltiplicatore della repulsione fra nodi in caso di assenza di overlap. Funzione overrideabile per ogni node
331
+ *
332
+ * @param {any} node Nodo
333
+ *
334
+ * @returns {number} Moltiplicazione di repulsione
335
+ */
336
+ this.nodeRepulsion = (node) => 2048;
337
+ /**
338
+ * Lunghezza ideale dei collegamenti non nested. Funzione overrideabile per ogni collegamento
339
+ *
340
+ * @param {any} edge Collegamento
341
+ *
342
+ * @returns {number} Lunghezza ideale
343
+ */
344
+ this.idealEdgeLength = (edge) => 32;
345
+ /**
346
+ * Divisore per calcolare le forze applicate ad un collegamento. Funzione overrideabile per ogni collegamento
347
+ *
348
+ * @param {any} edge Collegamento
349
+ *
350
+ * @returns {number} Indice di elasticità
351
+ */
352
+ this.edgeElasticity = (edge) => 32;
353
+ }
354
+ }
355
+
356
+ /**
357
+ * Default per l'implementazione dell'algoritmo Dagre
358
+ */
359
+ class DagreLayoutOptionsImpl extends ShapedLayoutOptionsImpl {
360
+ /** @ignore */
361
+ constructor() {
362
+ super();
363
+ /**
364
+ * Nome dell'algoritmo di layouting
365
+ */
366
+ this.name = 'dagre';
367
+ /**
368
+ * Distanza fra nodi adiacenti dello stesso rango
369
+ */
370
+ this.nodeSep = null;
371
+ /**
372
+ * Distanza fra collegamenti adiacenti nello stesso rango
373
+ */
374
+ this.edgeSep = null;
375
+ /**
376
+ * Distanza fra ogni rango
377
+ */
378
+ this.rankSep = null;
379
+ // TB for top to bottom flow, 'LR' for left to right
380
+ /**
381
+ * Direzione di disegno: LR = Sinistra a Destra, TB = Sopra a Sotto
382
+ */
383
+ this.rankDir = 'TB';
384
+ /**
385
+ * Algoritmo che si occupa di assegnare un rango ad ogni nodo
386
+ */
387
+ this.ranker = null;
388
+ /**
389
+ * Numero di ranghi fra la sorgente e la destinazione di un collegamento
390
+ *
391
+ * @param {any} edge Collegamento di cui calcolare la differenza di rango
392
+ *
393
+ * @returns {number} Differenza di rango
394
+ */
395
+ this.minLen = (edge) => 1;
396
+ /**
397
+ * Peso del collegamento, più è alto più generalmente risulterà corto
398
+ *
399
+ * @param {any} edge Collegamento di cui calcolare il peso
400
+ *
401
+ * @returns {number} Peso
402
+ */
403
+ this.edgeWeight = (edge) => 1;
404
+ }
405
+ }
406
+
407
+ /**
408
+ * Default per l'implementazione dell'algoritmo Grid
409
+ */
410
+ class GridLayoutOptionsImpl extends ShapedLayoutOptionsImpl {
411
+ /** @ignore */
412
+ constructor() {
413
+ super();
414
+ /**
415
+ * Nome dell'algoritmo di layouting
416
+ */
417
+ this.name = 'grid';
418
+ /**
419
+ * Spazio extra attorno ai nodi quando **avoidOverlap** è **true**
420
+ */
421
+ this.avoidOverlapPadding = 10;
422
+ /**
423
+ * Se **true** cerca di utilizzare il minor spazio possibile, se **false** usa tutto lo spazio che ha a disposizione
424
+ */
425
+ this.condense = false;
426
+ /**
427
+ * Forzatura del numero di righe della griglia
428
+ */
429
+ this.rows = null;
430
+ /**
431
+ * Forzatura del numero di colonne della griglia
432
+ */
433
+ this.cols = null;
434
+ /**
435
+ * Dato un nodo restituisce un indice di riga e di colonna della griglia in cui metterlo
436
+ *
437
+ * @param {NodeSingular} node Nodo
438
+ * @returns {{ row: number, col: number }} Oggetto che identifica una posizione della griglia
439
+ */
440
+ this.position = null;
441
+ }
442
+ }
443
+
444
+ /**
445
+ * Pseudo implementazione di un algoritmo vuoto che non fa nulla
446
+ */
447
+ class NullLayoutOptionsImpl extends BaseLayoutOptionsImpl {
448
+ /** @ignore */
449
+ constructor() {
450
+ super();
451
+ /**
452
+ * Nome dell'algoritmo di layouting
453
+ */
454
+ this.name = 'null';
455
+ }
456
+ }
457
+
458
+ /**
459
+ * Default per l'implementazione dell'algoritmo Preset (Posiziona i nodi in base alla loro proprietà **position**)
460
+ */
461
+ class PresetLayoutOptionsImpl extends AnimateLayoutOptionsImpl {
462
+ /** @ignore */
463
+ constructor() {
464
+ super();
465
+ /**
466
+ * Nome dell'algoritmo di layouting
467
+ */
468
+ this.name = 'preset';
469
+ /**
470
+ * Funzione per la trasformazione delle posizioni dei nodi
471
+ *
472
+ * @param {any} node Nodo
473
+ * @param {any} position Posizione iniziale
474
+ *
475
+ * @returns {any} Posizione finale
476
+ */
477
+ this.transform = (node, position) => position;
478
+ }
479
+ }
480
+
481
+ /**
482
+ * Default per l'implementazione dell'algoritmo Random
483
+ */
484
+ class RandomLayoutOptionsImpl extends AnimateLayoutOptionsImpl {
485
+ /** @ignore */
486
+ constructor() {
487
+ super();
488
+ /**
489
+ * Nome dell'algoritmo di layouting
490
+ */
491
+ this.name = 'random';
492
+ /**
493
+ * Indica se adattare al contenitore
494
+ */
495
+ this.fit = true;
496
+ /**
497
+ * Padding rispetto al contenitore
498
+ */
499
+ this.padding = 20;
500
+ /**
501
+ * Specifica le dimensioni esatte al cui interno effettuare il layouting, specificato come **{ x1, y1, x2, y2 }** o **{ x1, y1, w, h }**
502
+ */
503
+ this.boundingBox = null;
504
+ /**
505
+ * Funzione per la trasformazione delle posizioni dei nodi
506
+ *
507
+ * @param {any} node Nodo
508
+ * @param {any} position Posizione iniziale
509
+ *
510
+ * @returns {any} Posizione finale
511
+ */
512
+ this.transform = (node, position) => position;
513
+ }
514
+ }
515
+
516
+ /**
517
+ * Classe di configurazione per il Modulo
518
+ */
519
+ class EsDiagramModuleConfig {
520
+ }
521
+
522
+ // Grabbata felicemente da amcharts, rimuovendo helper interni, cose strane e instupidendola un po':
523
+ // https://github.com/amcharts/amcharts4/blob/7fbb61e90363a2373e6130800dee06b8a62f3aab/src/.internal/core/utils/ResizeSensor.ts
524
+ /**
525
+ * Classe di utilità che tiene d'occhio i cambiamenti di dimensione di un elemento. Un **ResizeSensor** può controllare al massimo un elemento
526
+ */
527
+ class ResizeSensor {
528
+ /**
529
+ * Costruttore
530
+ *
531
+ * @param {HTMLElement} element Elemento HTML da controllare
532
+ * @param {Function} callback Callback da chiamare quando le dimensioni di **element** cambiano
533
+ */
534
+ constructor(element, callback) {
535
+ /**
536
+ * Riferimento all'observer nativo
537
+ */
538
+ this.observer = null;
539
+ /**
540
+ * Indica se questo oggetto è stato distrutto o no
541
+ */
542
+ this.Disposed = false;
543
+ /**
544
+ * Elemento da controllare e callback da chiamare quando le dimensioni dell'elemento cambiano
545
+ */
546
+ this.target = null;
547
+ this.makeSensor();
548
+ this.addTarget(element, callback);
549
+ }
550
+ /**
551
+ * Distruttore
552
+ */
553
+ dispose() {
554
+ if (!this.Disposed) {
555
+ this.Disposed = true;
556
+ this.removeTarget();
557
+ }
558
+ }
559
+ /**
560
+ * Creazione del sensore che sarà collegato all'elemento da osservare dal metodo **addTarget**
561
+ */
562
+ makeSensor() {
563
+ if (typeof ResizeObserver == "undefined")
564
+ throw "Resize Observer non è definito. Si prega di utilizzare un browser vero";
565
+ this.observer = new ResizeObserver((entries) => {
566
+ for (let i = 0; i < entries.length; ++i) {
567
+ if (this.target && this.target.targetEl === entries[i].target)
568
+ this.target.callback();
569
+ }
570
+ });
571
+ }
572
+ /**
573
+ * Dice al sensore di osservare l'elemento **targetEl**, richiamando **callback** qualora le dimensioni cambino
574
+ *
575
+ * @param {HTMLElement} targetEl Elemento HTML da controllare
576
+ * @param {Function} callback Callback da chiamare quando le dimensioni di **element** cambiano
577
+ */
578
+ addTarget(targetEl, callback) {
579
+ this.observer.observe(targetEl, { box: "content-box" });
580
+ this.target = { targetEl, callback };
581
+ }
582
+ /**
583
+ * Rimuove l'elemento HTML attuale dall'osservazione del **ResizeObserver**
584
+ */
585
+ removeTarget() {
586
+ if (!this.target)
587
+ return;
588
+ this.observer.unobserve(this.target.targetEl);
589
+ this.target = null;
590
+ }
591
+ }
592
+
593
+ /**
594
+ * Token che indica la lingua da utilizzare, sono supportate "it-IT" ed "en-US"
595
+ */
596
+ const DIA_LOCALE = new InjectionToken('DIA_LOCALE');
597
+ /**
598
+ * Token che indica se attivare la modalità di debug (messaggi a console)
599
+ */
600
+ const DIA_DEBUG_MODE = new InjectionToken('DIA_DEBUG_MODE');
601
+
602
+ /**
603
+ * Oggetto statico di localizzazione per i messaggi
604
+ */
605
+ const Loc = {
606
+ "Module": { "en-US": "Module", "it-IT": "Il Modulo" },
607
+ "Received an undefined module. Make sure you are correctly loading it": { "en-US": "Received an undefined module. Make sure you are correctly loading it", "it-IT": "Ricevuto modulo non definito. Assicurati di caricarlo correttamente" },
608
+ "Module not available. Loading it now": { "en-US": "Module not available. Loading it now", "it-IT": "Modulo non disponibile. Lo carico ora" },
609
+ "Module already loaded": { "en-US": "Module already loaded", "it-IT": "Modulo già caricato" },
610
+ "Diagram container size has changed, redrawing": { "en-US": "Diagram container size has changed, redrawing", "it-IT": "La dimensione del contenitore del diagramma è cambiata, ridisegno" },
611
+ "Module cannot be loaded": { "en-US": "Module cannot be loaded", "it-IT": "Impossibile caricare il modulo" },
612
+ "Redraw based on dynamic Input change is supported only for 'Elements' and 'Layout' inputs, please destroy the component and recreate it with the new settings": { "en-US": "Redraw based on dynamic Input change is supported only for 'Elements' and 'Layout' inputs, please destroy the component and recreate it with the new settings", "it-IT": "Il cambio e aggiornamento dinamico degli Input è supportato solo per gli Input 'Elements' e 'Layout', distruggi il componente e ricrealo con le nuove impostazioni", },
613
+ "is loaded and managed directly by this library. You don't need to import it or use it directly, just be sure to set the relative options": { "en-US": "is loaded and managed directly by this library. You don't need to import it or use it directly, just be sure to set the relative options", "it-IT": "viene caricato e gestito nativamente dalla libreria. Non c'è bisogno di reimportarlo, né di configurarlo (usare le opzioni specifiche)" },
614
+ "If you don't specify a source and a target for an edge you have to write its id in the format {source}-{target}": { "en-US": "If you don't specify a source and a target for an edge you have to write its id in the format {source}-{target}", "it-IT": "Se non è specificata una sorgente e una destinazione per il collegamento è opportuno scriverne l'id nel formato {sorgente}-{destinazione}" },
615
+ "Elements have been changed after diagram initialization": { "en-US": "Elements have been changed after diagram initialization", "it-IT": "Rilevato un cambio di Elementi dopo l'inizializzazione del Diagramma" },
616
+ "Layout have been changed after diagram initialization": { "en-US": "Layout have been changed after diagram initialization", "it-IT": "Rilevato un cambio di Layout dopo l'inizializzazione del Diagramma" },
617
+ "Cannot update NodeHTMLTemplates as they don't seem to be used": { "en-US": "Cannot update NodeHTMLTemplates as they don't seem to be used", "it-IT": "Impossibile aggiornare i NodeHTMLTemplates dato che non sembra siano utilizzati" }
618
+ };
619
+
620
+ /** @ignore */ const cytoscape$1 = cy_;
621
+ /**
622
+ * Loader dei moduli di Cytoscape. Utilizza una cache per tenerseli in memoria a livello di applicazione
623
+ * in modo da non dover ricaricare nulla dopo avere usato un modulo almeno una volta
624
+ */
625
+ class EsDiagramService {
626
+ /**
627
+ * Costruttore
628
+ *
629
+ * @ignore
630
+ */
631
+ constructor(DIA_LOCALE, DIA_DEBUG_MODE) {
632
+ this.DIA_LOCALE = DIA_LOCALE;
633
+ this.DIA_DEBUG_MODE = DIA_DEBUG_MODE;
634
+ /**
635
+ * Cache dei moduli caricati
636
+ */
637
+ this.modulesCache = {};
638
+ }
639
+ /**
640
+ * Permette di importare, se serve un dato tema o localizzazione
641
+ *
642
+ * @param {'cytoscape-expand-collapse' | 'cytoscape-cxtmenu' | 'cytoscape-html-node' | 'cytoscape-dagre'} moduleId Nome del modulo di Cytoscape da importare (dev'essere il nome della cartella in node_modules)
643
+ *
644
+ * @returns {Promise<void | cytoscape.Ext>} Funzione di estensione per Cytoscape presa dal modulo richiesto
645
+ */
646
+ async importIfNeeded(moduleId) {
647
+ // Ognuno esporta il modulo un po' come cazzo gli pare quindi ocio.
648
+ // Notare che tutti i "moudle" dopo lo then sono castati ad <any> e che l'oggetto recuperato ogni tanto è "default", altre volte è il "register", altre è l'"ext", eccetera...
649
+ if (!this.modulesCache[moduleId]) {
650
+ this.log("I", this.loc("Module not available. Loading it now") + ": " + moduleId, false);
651
+ switch (moduleId) {
652
+ case "cytoscape-cxtmenu": return import('cytoscape-cxtmenu').then((module) => this.modulesCache[moduleId] = module.default).catch(err => this.handleError(moduleId, err));
653
+ case "cytoscape-expand-collapse": return import('cytoscape-expand-collapse').then((module) => this.modulesCache[moduleId] = module.default).catch(err => this.handleError(moduleId, err));
654
+ case "cytoscape-html-node": return import('@esfaenza/cytoscape-html-node').then((module) => this.modulesCache[moduleId] = module.register).catch(err => this.handleError(moduleId, err));
655
+ case "cytoscape-dagre":
656
+ await import('dagre').catch(err => this.handleError("dagre", err));
657
+ return import('cytoscape-dagre').then((module) => this.modulesCache[moduleId] = module.default).catch(err => this.handleError(moduleId, err));
658
+ }
659
+ }
660
+ else {
661
+ // I moduli non devono mai essere ricaricati nel globale, quindi invece che restituire la copia della cache restituisco vuoto
662
+ this.log("I", this.loc("Module already loaded") + ": " + moduleId, false);
663
+ return new Promise((resolve) => { resolve(null); });
664
+ }
665
+ }
666
+ /**
667
+ * Gestione degli errori di caricamento dei moduli qualora qualcuno utilizzasse un modulo non installato
668
+ *
669
+ * @param {string} moduleId Nome del modulo che si è cercato di caricare
670
+ * @param {any} err Errore restituito dalla promise di caricamento
671
+ */
672
+ handleError(moduleId, err) {
673
+ this.log("E", this.loc("Module cannot be loaded") + ": " + moduleId + " - " + err, false);
674
+ }
675
+ /**
676
+ * Scrittore di log a console. Attivo solo quando la libreria è in modalità di Debug
677
+ *
678
+ * @param {'E' | 'I' | 'W'} severity Tipo di messaggio (Errore, Info, Warning)
679
+ * @param {string} text Testo da tradurre
680
+ * @param {boolean} requiresTranslation Indica se **text** è una frase già tradotta o se è da tradurre
681
+ */
682
+ log(severity, text, requiresTranslation = true) {
683
+ if (!this.DIA_DEBUG_MODE)
684
+ return;
685
+ var message = "@esfaenza/diagrams: " + (requiresTranslation ? this.loc(text) : text);
686
+ switch (severity) {
687
+ case 'E':
688
+ console.error(message);
689
+ break;
690
+ case 'I':
691
+ console.info(message);
692
+ break;
693
+ case 'W':
694
+ console.warn(message);
695
+ break;
696
+ }
697
+ }
698
+ /**
699
+ * Metodo di localizzazione dei messaggi
700
+ *
701
+ * @param {string} text Messaggio da tradurre
702
+ *
703
+ * @returns {string} Messaggio tradotto
704
+ */
705
+ loc(text) {
706
+ return Loc[text][this.DIA_LOCALE];
707
+ }
708
+ }
709
+ EsDiagramService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: EsDiagramService, deps: [{ token: DIA_LOCALE, optional: true }, { token: DIA_DEBUG_MODE, optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
710
+ EsDiagramService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: EsDiagramService });
711
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: EsDiagramService, decorators: [{
712
+ type: Injectable
713
+ }], ctorParameters: function () { return [{ type: undefined, decorators: [{
714
+ type: Optional
715
+ }, {
716
+ type: Inject,
717
+ args: [DIA_LOCALE]
718
+ }] }, { type: undefined, decorators: [{
719
+ type: Optional
720
+ }, {
721
+ type: Inject,
722
+ args: [DIA_DEBUG_MODE]
723
+ }] }]; } });
724
+
725
+ /**
726
+ * Classe che si occupa del dispatch delle operazioni di rendering degli oggetti utilizzando una coda
727
+ */
728
+ class EsDiagramDispatcher {
729
+ /**
730
+ * @ignore
731
+ */
732
+ constructor(logs) {
733
+ this.logs = logs;
734
+ /**
735
+ * Coda di inizializzazioni ancora da eseguire. Quando questa è vuota significa che nessuno sta creando oggetti
736
+ */
737
+ this.Initializations = [];
738
+ /**
739
+ * Lista degli oggetti inizializzati e attivi in un dato momento (viene registrata la proprietà **name**). Non è possibile registrare due grafici con lo stesso identificativo
740
+ */
741
+ this.Initialized = [];
742
+ }
743
+ /**
744
+ * Registra un oggetto da visualizzare insieme alla propria funzione di creazione. Quest'ultima sarà differita fino a che tutti gli oggetti
745
+ * precedentemente registati non hanno finito la fase di inizializzazione
746
+ *
747
+ * @param {string} name Identificativo dell'oggetto da registrare
748
+ * @param {Function} creationFunction Funzione che fisicamente dovrà occuparsi della creazione dell'oggetto
749
+ */
750
+ register(name, creationFunction) {
751
+ if (this.Initialized.indexOf(name) != -1)
752
+ throw "Attempting to register a duplicate object '" + name + "'. Make sure the 'name' properties of your diagram are univoque";
753
+ this.log("DISPATCHER: Registering diagram creation function execution for " + name);
754
+ this.Initializations.push({ name: name, function: creationFunction });
755
+ if (this.Initializations.length == 1) {
756
+ this.log("DISPATCHER: Initial drain started");
757
+ this.drainInitQueues();
758
+ }
759
+ }
760
+ /**
761
+ * Deregistra un oggetto presente. Chiamata generalmente al dispose dell'oggetto in questione quando non dev'essere più mostrato nella pagina corrente
762
+ *
763
+ * @param {string} name Identificativo dell'oggetto da deregistrare
764
+ */
765
+ deregister(name) {
766
+ let index = this.Initialized.indexOf(name);
767
+ if (index == -1) {
768
+ //Questo succede quando si cerca di distruggere l'oggetto mentre sta venendo graficato
769
+ this.log("DISPATCHER: Registration missing for object " + name + " it was probably destroyed during load");
770
+ return;
771
+ }
772
+ this.log("DISPATCHER: Object deregistered " + name);
773
+ this.Initialized.splice(index, 1);
774
+ }
775
+ /**
776
+ * Metodo che esegue in maniera sequenziale le funzioni di inizializzazione degli oggetti finché presenti
777
+ * in modo che nessun oggetto possa essere inizializzato contemporaneamente ad un altro
778
+ */
779
+ drainInitQueues() {
780
+ let toExecute = this.Initializations[0];
781
+ this.log("DISPATCHER: Executing initialization function for object " + toExecute.name);
782
+ toExecute.function().then(() => {
783
+ this.log("DISPATCHER: initialization for object " + toExecute.name + " is done");
784
+ this.Initialized.push(toExecute.name);
785
+ this.Initializations.splice(0, 1);
786
+ if (this.Initializations.length >= 1) {
787
+ this.log("DISPATCHER: Found queued initializations. Continuing");
788
+ this.drainInitQueues();
789
+ }
790
+ else
791
+ this.log("DISPATCHER: queue is over, nothing more to do");
792
+ });
793
+ }
794
+ /**
795
+ * @ignore
796
+ */
797
+ log(text) {
798
+ if (this.logs)
799
+ console.log("@esfaenza/es-diagrams: " + text);
800
+ }
801
+ }
802
+ EsDiagramDispatcher.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: EsDiagramDispatcher, deps: [{ token: DIA_DEBUG_MODE }], target: i0.ɵɵFactoryTarget.Injectable });
803
+ EsDiagramDispatcher.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: EsDiagramDispatcher });
804
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: EsDiagramDispatcher, decorators: [{
805
+ type: Injectable
806
+ }], ctorParameters: function () { return [{ type: undefined, decorators: [{
807
+ type: Inject,
808
+ args: [DIA_DEBUG_MODE]
809
+ }] }]; } });
810
+
811
+ /**
812
+ * Classe che fornisce metodi reattivi di estensione. Per ora implementato solo uno pseudo-throttle
813
+ */
814
+ class ReactiveExtensions {
815
+ constructor() {
816
+ /**
817
+ * Cache di tutti i timer in esecuzione
818
+ */
819
+ this.executionTimers = {};
820
+ }
821
+ /**
822
+ * Esecuzione deleyata di una funzione. Se viene richiamata nuovamente prima di venire eseguita dopo il delay, il delay viene resettato
823
+ *
824
+ * @param {string} id Id per aiutare il servizio a distinguere funzioni con nome uguale chiamate da componenti diversi
825
+ * @param {Function} func Funzione da chiamare al termine del throttle
826
+ * @param {number} throttleTime Tempo di throttling in millisecondi
827
+ */
828
+ throttle(id, func, throttleTime = 0) {
829
+ let key = func.name + "_" + id;
830
+ //Se ho la funzione che vuole eseguire ripulisco quel timeout
831
+ if (this.executionTimers[key])
832
+ clearTimeout(this.executionTimers[key]);
833
+ //Ricreo il timeout per eseguire quella funzione dopo throttleTime millisecondi
834
+ var executionTimer = setTimeout(() => { func(); this.executionTimers[key] = null; }, throttleTime);
835
+ this.executionTimers[key] = executionTimer;
836
+ }
837
+ }
838
+ ReactiveExtensions.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: ReactiveExtensions, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
839
+ ReactiveExtensions.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: ReactiveExtensions, providedIn: "root" });
840
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: ReactiveExtensions, decorators: [{
841
+ type: Injectable,
842
+ args: [{ providedIn: "root" }]
843
+ }] });
844
+
845
+ /** @ignore */ const cytoscape = cy_;
846
+ /**
847
+ * Componente che si occupa di graficare un diagramma e di gestirne il ciclo di vita
848
+ */
849
+ class EsDiagramComponent {
850
+ /**
851
+ * Costruttore
852
+ *
853
+ * @ignore
854
+ */
855
+ constructor(service, dispatcher, exts) {
856
+ this.service = service;
857
+ this.dispatcher = dispatcher;
858
+ this.exts = exts;
859
+ /**
860
+ * Nome del diagramma, fondamentale assegnarlo per permettere alla libreria di schedularne la creazione
861
+ */
862
+ this.name = "";
863
+ /**
864
+ * Indica se utilizzare il menù contestuale a ruota attorno ad ogni nodo
865
+ */
866
+ this.UseContextMenu = false;
867
+ /**
868
+ * Dice al componente se il diagramma deve utilizzare il sistema di estensione per l'expand e collapse dei gruppi
869
+ */
870
+ this.UseExpandCollapse = false;
871
+ /**
872
+ * Blocco completo delle opzioni, alternativo all'assegnazione di **Elements**, **NodeStyles**, **EdgeStyles**, e **Layout**.
873
+ *
874
+ * Qualora entrambe venissero specificate verrà effettuata un'unione fra queste opzioni e quelle specificate, dando priorità alle specificate
875
+ */
876
+ this.NativeOptions = {};
877
+ /**
878
+ * Aggiorna automaticamente le dimensioni del diagramma quando cambiano le dimensioni della finestra
879
+ */
880
+ this.AutoupdateSize = true;
881
+ /**
882
+ * Indica di mantenere la posizione dei nodi qualora venissero cambiati dall'Input **Elements**.
883
+ *
884
+ * Se l'ID di un nodo è uguale all'ID di un nodo presente in precedenza, il nuovo nodo ne erediterà la posizione
885
+ */
886
+ this.PreserveElementsPosition = true;
887
+ /**
888
+ * Qualora venisse modificato l'Input **Elements**, piuttosto che mettere semplicemente il nuovo Elemento in base al Layout precedente, applica anche un'animazione
889
+ *
890
+ * Funziona solamente se il **Layout** corrente del diagramma supporta le animazioni
891
+ */
892
+ this.AnimateLayoutChanges = true;
893
+ /**
894
+ * Attiva una modalità di selezione "smart"... o perlomeno "smarter" del default di Cytoscape.
895
+ *
896
+ * - Il click di un elemento non selezionato lo seleziona
897
+ * - Il click di un elemento selezionato lo deseleziona
898
+ * - Lo stato di selezione viene persistito sull'oggetto originale invece di rimanere in un internal
899
+ * - All'assegnazione di oggetti selezionati, questi vengono marcati correttamente con l'overlay di selezione
900
+ *
901
+ * N.B: la chiamata all'evento **onNodeClick** avviene **DOPO** la gestione della selezione
902
+ */
903
+ this.SmartSelection = false;
904
+ /**
905
+ * CSS per la graficazione della selezione dei nodi. Quando un nodo verrà selezionato avrà sopra di se un overlay che 'sborda' di **overlay-padding** pixel,
906
+ * di colore **overlay-color** e con un opacità **overlay-opacity**
907
+ *
908
+ * Assegnando "{}" a questo input, la Smart selection viene gestita ma la gestione grafica è affidata all'utente,
909
+ * ad esempio usando dei **NodeHTMLTemplates** che definiscano selettori su nodi ":selected"
910
+ *
911
+ * @default {'overlay-color':'blue','overlay-opacity':0.5,'overlay-padding':7}
912
+ */
913
+ this.SmartSelectionStyles = null;
914
+ /**
915
+ * Periodo di throttle da quando viene effettuato un resize a quando ricalcolare le dimensioni del diagramma.
916
+ *
917
+ * Può essere tenuto a 0 (redraw istantaneo) finché non ci sono problemi di prestazioni con eventualmente tanti resize a poca distanza l'uno dall'altro.
918
+ */
919
+ this.ResizeThrottleTime = 0;
920
+ /**
921
+ * Fornisce il global della libreria (namespace **cytoscape**) e si aspetta che dopo operazioni di importazione
922
+ * lasciate all'utente vengano aggiunti tutti i moduli desiderati.
923
+ *
924
+ * È **fondamentale** che il primo parametro (il nome del modulo) sia uguale a ciò di cui viene fatto il require in modo che la libreria
925
+ * possa controllare che il modulo importato non sia già stato importato in precedenza
926
+ *
927
+ * ## Esempio:
928
+ *
929
+ * ```typescript
930
+ * (global) => {
931
+ * return import("cytoscape-extension-library").then(module => global.use("cytoscape-extension-library", module.default));
932
+ *
933
+ * ...
934
+ * }
935
+ * ```
936
+ */
937
+ this.ExtensionModulesImporter = null;
938
+ /**
939
+ * Fornisce l'istanza attuale di Cytoscape da cui è possibile prendere le librerie di estensione caricate in **ExtensionModulesImporter**
940
+ * e configurarle in base ai comportamenti specifici
941
+ *
942
+ * ## Esempio:
943
+ *
944
+ * ```typescript
945
+ * (cytoscapeCore) => {
946
+ * // Fare questo lavoro per ogni estensione caricata
947
+ * let extensionConfiguration = { ... };
948
+ * let extensionInstance = cytoscapeCore.extensionLibrary(extensionConfiguration);
949
+ * extensionInstance.doSomethingSpecificToThisExtension();
950
+ *
951
+ * ...
952
+ * }
953
+ * ```
954
+ */
955
+ this.ExtensionModulesApplyer = null;
956
+ /**
957
+ * Evento lanciato al click di un nodo, contiene l'oggetto **data** del nodo in questione
958
+ */
959
+ this.onNodeClick = new EventEmitter();
960
+ /**
961
+ * Evento lanciato alla selezione o deselezione di un nodo, contiene l'oggetto **data** del nodo in questione e informazioni sul suo stato di selezione
962
+ */
963
+ this.onNodeSelection = new EventEmitter();
964
+ /**
965
+ * Evento lanciato al termine del Layouting. Se si vuole eseguire codice dopo che il Layout è fatto e completamente graficato, questo è il punto
966
+ */
967
+ this.onLayoutDone = new EventEmitter();
968
+ /**
969
+ * Evento lanciato al termine del caricamento del diagramma
970
+ */
971
+ this.onLoaded = new EventEmitter();
972
+ /**
973
+ * Indica se il rendering del diagramma è terminato
974
+ */
975
+ this.Rendered = false;
976
+ /**
977
+ * Api dell'estensione expand-collapse per permettere di effettuare operazioni dall'esterno del diagramma. Vengono valorizzate se **UseExpandCollapse** è **true**
978
+ */
979
+ this.ExpandCollapseApi = null;
980
+ /**
981
+ * Api dell'estensione html-node per permettere di effettuare operazioni dall'esterno del diagramma. Vengono valorizzate se sono impostati dei **NodeHTMLTemplates**
982
+ */
983
+ this.HtmlNodeApi = null;
984
+ }
985
+ /**
986
+ * @ignore
987
+ *
988
+ * Angular Pipeline
989
+ */
990
+ ngAfterViewInit() {
991
+ if (!this.service || !this.dispatcher)
992
+ throw "Il modulo @esfaenza/diagrams non è stato importato con il forRoot();";
993
+ this.dispatchLoadChart();
994
+ }
995
+ /**
996
+ * All'onDestroy ripulisco la memoria dal diagramma
997
+ */
998
+ ngOnDestroy() {
999
+ this.resizeObserver.dispose();
1000
+ this.resizeObserver = null;
1001
+ if (this.cy) {
1002
+ this.service.log("I", "Diagram" + " " + this.name + ": Unloading destroyed diagram", false);
1003
+ this.cy.destroy();
1004
+ this.dispatcher.deregister(this.name);
1005
+ }
1006
+ else
1007
+ this.service.log("I", "Chart " + this.name + ": Unloading uncreated chart component. It probably was a duplicated", false);
1008
+ }
1009
+ /**
1010
+ * Registra il diagramma attuale nel Dispatcher in modo che venga caricato appena possibile
1011
+ */
1012
+ dispatchLoadChart() {
1013
+ this.dispatcher.register(this.name, () => { return this.render(); });
1014
+ }
1015
+ /**
1016
+ * @ignore
1017
+ *
1018
+ * Angular Pipeline: Gestione ri-graficazione del diagramma, se possibile
1019
+ */
1020
+ ngOnChanges(changes) {
1021
+ let toCheck = ["Templates", "UseContextMenu", "ContextMenuOptions", "UseExpandCollapse", "ExpandCollapseOptions", "NodeStyles", "EdgeStyles", "NativeOptions"];
1022
+ if (this.Rendered && toCheck.some(t => changes[t]))
1023
+ this.service.log("W", "Redraw based on dynamic Input change is supported only for 'Elements' and 'Layout' inputs, please destroy the component and recreate it with the new settings");
1024
+ let elementChanges = changes["Elements"];
1025
+ let layoutChanges = changes["Layout"];
1026
+ if (elementChanges && !elementChanges.firstChange) {
1027
+ this.service.log("I", "Elements have been changed after diagram initialization");
1028
+ // Cambiamento agli Elementi: ripulisco gli elementi vecchi, prendo i nuovi, li sistemo e li riassegno.
1029
+ // Se il nuovo Input Elements è roba strana mi limito a ripulire il diagramma
1030
+ // Se cytoscape aveva già degli elementi precedentemente ne prendo le posizioni in modo da ridisegnarli partendo dallo stesso punto (carino per le animazioni)
1031
+ let elements = elementChanges?.currentValue;
1032
+ let previous_elements = this.PreserveElementsPosition ? this.cy.nodes() : null;
1033
+ this.cy.elements().remove();
1034
+ if (elements && elements.length && elements.length > 0) {
1035
+ this.reviewCytoscapeElements(elements, previous_elements);
1036
+ this.cy.add(elements);
1037
+ if (this.SmartSelection)
1038
+ this.setupElementsSelectionIfNeeded();
1039
+ // Se solo gli elementi cambiano, riapplico il Layout precedente
1040
+ if (!layoutChanges && this.LastLayout) {
1041
+ // Se devo animare le modifche al layout forzo il parametro relativo
1042
+ if (this.AnimateLayoutChanges)
1043
+ this.LastLayout.animate = true;
1044
+ this.cy.layout(this.LastLayout).run();
1045
+ }
1046
+ }
1047
+ }
1048
+ // Se il layout cambia lo applico e me lo salvo come layout precedente per il futuro
1049
+ if (layoutChanges && !layoutChanges.firstChange) {
1050
+ this.service.log("I", "Layout have been changed after diagram initialization");
1051
+ this.LastLayout = JSON.parse(JSON.stringify(layoutChanges.currentValue));
1052
+ this.cy.layout(this.LastLayout).run();
1053
+ }
1054
+ }
1055
+ /**
1056
+ * Effettua il rendering del diagramma
1057
+ */
1058
+ async render() {
1059
+ // Tiro fuori le opzioni con cui generare il diagramma
1060
+ let cyOptions = this.getCompletedOptions();
1061
+ this.NodesHierarchy = cyOptions.elements && cyOptions.elements.some(t => t.data.parent);
1062
+ // Carico eventuali classi di estensione che servono
1063
+ await this.performModulesLoading();
1064
+ // Genero il diagramma
1065
+ this.cy = cytoscape(cyOptions);
1066
+ // Collego gli eventi al componente
1067
+ this.bindCytoscapeEvents();
1068
+ // Utilizzo le classi di estensione caricate precedentemente per fare il resto delle mie operazioni
1069
+ this.performOperationsWithLoadedModules();
1070
+ // Imposto la variabile Rendered a true in modo che se da adesso vengono fatte modifiche che dovrebbero causare un redraw posso accorgermene
1071
+ // e mandare a cagare lo stronzo di turno
1072
+ this.Rendered = true;
1073
+ // Se devo aggiornare in automatico in base alla dimensione del contenitore collego il ResizeObserver
1074
+ if (this.AutoupdateSize)
1075
+ this.listenOnChanges();
1076
+ if (this.SmartSelection) {
1077
+ this.setupSelectionStyles();
1078
+ this.setupElementsSelectionIfNeeded();
1079
+ }
1080
+ this.onLoaded.emit();
1081
+ }
1082
+ /**
1083
+ * Prende tutti gli elementi appena assegnati, e se qualcuno era selezionato la situazione viene persistita su cytoscape
1084
+ */
1085
+ setupElementsSelectionIfNeeded() {
1086
+ for (let i = 0; i < this.Elements.length; i++) {
1087
+ let eldata = this.Elements[i].data;
1088
+ if (eldata.__selected) {
1089
+ let el = this.cy.$id(eldata.id);
1090
+ el.select();
1091
+ }
1092
+ }
1093
+ }
1094
+ /**
1095
+ * Carica gli stili per mostrare carina la selezione dei nodi
1096
+ */
1097
+ setupSelectionStyles() {
1098
+ let cssItem = this.SmartSelectionStyles || {
1099
+ 'overlay-color': 'blue',
1100
+ 'overlay-opacity': 0.5,
1101
+ 'overlay-padding': 7
1102
+ };
1103
+ // Backdoor per poter assegnare "{}" a SmartSelectionStyles in modo di utilizzare la smart selection ma senza che nessuno stile venga applicato
1104
+ // ad esempio qualora si volesse utilizzare l'htmlnode per gestire la grafica degli elementi selezionati
1105
+ if (cssItem['overlay-color'] && cssItem['overlay-opacity'] && cssItem['overlay-padding'])
1106
+ this.cy.style().selector('node:selected').css(cssItem);
1107
+ }
1108
+ /**
1109
+ * Registra l'ascolto al contenitore del grafico e in caso di modifiche alla dimensione, al massimo una volta ogni 500 millisecondi, lo ridisegna
1110
+ */
1111
+ listenOnChanges() {
1112
+ this.resizeObserver = new ResizeSensor(this.cyGraph.nativeElement, () => {
1113
+ this.exts.throttle(this.name, this.onContainerSizeChanged.bind(this), this.ResizeThrottleTime);
1114
+ });
1115
+ }
1116
+ /**
1117
+ * Funzione che si occupa di gestire il repaint del diagramma
1118
+ */
1119
+ onContainerSizeChanged() {
1120
+ this.service.log("I", "Diagram container size has changed, redrawing");
1121
+ this.cy.resize();
1122
+ this.cy.fit();
1123
+ }
1124
+ /**
1125
+ * Collega tutti gli eventi che mi possono servire e li espone in output
1126
+ */
1127
+ bindCytoscapeEvents() {
1128
+ this.cy.bind('click', 'node', (event) => {
1129
+ let targetData = event.target.data();
1130
+ if (this.SmartSelection) {
1131
+ let id = targetData.id;
1132
+ let el = this.cy.$id(id);
1133
+ let selected = el.selected();
1134
+ el.selectify();
1135
+ if (selected)
1136
+ el.unselect();
1137
+ else
1138
+ el.select();
1139
+ el.unselectify();
1140
+ // Questo va anche nella lista degli elementi originali (this.Elements) dato che cytoscape li prende per riferimento (bbbbbravo cyto-chan)
1141
+ el.data("__selected", !selected);
1142
+ }
1143
+ this.onNodeClick.emit({ data: targetData });
1144
+ });
1145
+ this.cy.bind('select', 'node', (event) => {
1146
+ let targetData = event.target.data();
1147
+ this.onNodeSelection.emit({ data: targetData, selected: true });
1148
+ });
1149
+ this.cy.bind('layoutstop', (event) => {
1150
+ this.onLayoutDone.emit();
1151
+ });
1152
+ this.cy.bind('unselect', 'node', (event) => {
1153
+ let targetData = event.target.data();
1154
+ this.onNodeSelection.emit({ data: targetData, selected: false });
1155
+ });
1156
+ // Altri eventi...
1157
+ }
1158
+ /**
1159
+ * Metodo che serve per caricare tutte le estensioni della libreria in base a ciò che viene utilizzato
1160
+ */
1161
+ async performModulesLoading() {
1162
+ if (this.Layout.name == 'dagre')
1163
+ await this.loadInternal("cytoscape-dagre");
1164
+ if (this.NodeHTMLTemplates && this.NodeHTMLTemplates.length > 0)
1165
+ await this.loadInternal("cytoscape-html-node");
1166
+ if (this.UseContextMenu)
1167
+ await this.loadInternal("cytoscape-cxtmenu");
1168
+ if (this.NodesHierarchy && this.UseExpandCollapse)
1169
+ await this.loadInternal("cytoscape-expand-collapse");
1170
+ if (this.ExtensionModulesImporter) {
1171
+ // Wrappo il namespace in modo che possa dire la mia sul fatto che l'utente aggiunga un modulo o meno :D
1172
+ var wrappedCytoscape = {
1173
+ use: (moduleName, module) => {
1174
+ if (!module)
1175
+ this.service.log("E", this.service.loc("Received an undefined module. Make sure you are correctly loading it") + ": " + moduleName, false);
1176
+ if (["cytoscape-dagre", "cytoscape-html-node", "cytoscape-cxtmenu", "cytoscape-expand-collapse"].includes(moduleName))
1177
+ this.service.log("W", this.service.loc("Module") + " " + moduleName + " " + this.service.loc("is loaded and managed directly by this library. You don't need to import it or use it directly, just be sure to set the relative options"), false);
1178
+ else
1179
+ cytoscape.use(module);
1180
+ }
1181
+ };
1182
+ await this.ExtensionModulesImporter(wrappedCytoscape);
1183
+ }
1184
+ }
1185
+ /**
1186
+ * Metodo che serve per caricare tutte le estensioni della libreria in base a ciò che viene utilizzato con le opzioni definite dagli Input
1187
+ */
1188
+ performOperationsWithLoadedModules() {
1189
+ let anyCy = this.cy;
1190
+ // Utilizzo del layout, lo salvo per poterlo riutilizzare in futuro
1191
+ if (this.Layout) {
1192
+ this.LastLayout = JSON.parse(JSON.stringify(this.Layout));
1193
+ this.cy.layout(this.LastLayout).run();
1194
+ }
1195
+ // Utilizzo dell'HTML node
1196
+ if (this.NodeHTMLTemplates && this.NodeHTMLTemplates.length > 0) {
1197
+ this.HtmlNodeApi = anyCy.htmlnode();
1198
+ this.HtmlNodeApi.createHtmlNode(cytoscape, this.cy, this.NodeHTMLTemplates);
1199
+ }
1200
+ // Utilizzo del Context Menu
1201
+ if (this.UseContextMenu)
1202
+ this.ContextMenuOptions.forEach(o => { anyCy.cxtmenu(o); });
1203
+ // Utilizzo dell'expand collapse solo quando c'è una gerarchia di nodi
1204
+ if (this.NodesHierarchy && this.UseExpandCollapse)
1205
+ this.ExpandCollapseApi = anyCy.expandCollapse(this.ExpandCollapseOptions);
1206
+ // Utilizzo di estensioni extra, implementazione affidata al programmatore
1207
+ if (this.ExtensionModulesApplyer)
1208
+ this.ExtensionModulesApplyer(this.cy);
1209
+ }
1210
+ updateCardData() {
1211
+ if (!this.HtmlNodeApi) {
1212
+ this.service.log("E", "Cannot update NodeHTMLTemplates as they don't seem to be used");
1213
+ return;
1214
+ }
1215
+ this.HtmlNodeApi.update();
1216
+ }
1217
+ /**
1218
+ * Metodo interno per il caricamento dei moduli di estensione
1219
+ *
1220
+ * @param {'cytoscape-expand-collapse' | 'cytoscape-cxtmenu' | 'cytoscape-html-node' | 'cytoscape-dagre'} moduleId Modulo da caricare
1221
+ */
1222
+ async loadInternal(moduleId) {
1223
+ let toLoad = await this.service.importIfNeeded(moduleId);
1224
+ if (toLoad)
1225
+ cytoscape.use(toLoad);
1226
+ }
1227
+ /**
1228
+ * Metodo che basandosi sulle opzioni native eventualmente assegnate le completa con gli Input addizionali
1229
+ *
1230
+ * @returns {cy_.CytoscapeOptions} Opzioni finali unite da Input ed opzioni native
1231
+ */
1232
+ getCompletedOptions() {
1233
+ var opts = this.NativeOptions || {};
1234
+ opts.container = this.cyGraph.nativeElement;
1235
+ opts.style = opts.style || [];
1236
+ // Per tutte le cose per cui gli Input hanno priorità sovrascrivo gli originali delle opzioni
1237
+ if (this.NodeStyles || this.EdgeStyles) {
1238
+ opts.style = [];
1239
+ if (this.NodeStyles)
1240
+ opts.style.push({ selector: 'node', css: this.NodeStyles });
1241
+ if (this.EdgeStyles)
1242
+ opts.style.push({ selector: 'edge', css: this.EdgeStyles });
1243
+ }
1244
+ if (this.Elements)
1245
+ opts.elements = this.Elements;
1246
+ this.reviewCytoscapeElements(opts.elements);
1247
+ if (this.Layout)
1248
+ opts.layout = this.Layout;
1249
+ if (this.Readonly) {
1250
+ // Questo coso fa effetti strani....
1251
+ //opts.autolock = true;
1252
+ opts.autoungrabify = true;
1253
+ opts.autounselectify = false;
1254
+ opts.boxSelectionEnabled = true;
1255
+ opts.userZoomingEnabled = false;
1256
+ opts.userPanningEnabled = false;
1257
+ }
1258
+ return opts;
1259
+ }
1260
+ /**
1261
+ * Aggiustamenti degli elementi di Cytoscape.
1262
+ *
1263
+ * I nodi non vengono toccati.
1264
+ *
1265
+ * Per ogni edge viene controllato se è specificata una sorgente ed una destinazione, in caso contrario si cerca di dedurli dall'ID
1266
+ *
1267
+ * @param {cytoscape.ElementDefinition[]} elements Elementi da sistemare
1268
+ */
1269
+ reviewCytoscapeElements(elements, prevPositions) {
1270
+ let hasPreviousPositions = prevPositions && prevPositions.length > 0;
1271
+ let positionCache = {};
1272
+ if (hasPreviousPositions) {
1273
+ for (let i = 0; i < prevPositions.length; i++) {
1274
+ let item = prevPositions[i];
1275
+ if (!positionCache[item.data().id])
1276
+ positionCache[item.data().id] = item.position();
1277
+ }
1278
+ }
1279
+ for (let i = 0; i < elements.length; i++) {
1280
+ let el = elements[i];
1281
+ if (el.group == "edges" && (!el.data.source && !el.data.target)) {
1282
+ if (!el.data.id.includes("-"))
1283
+ this.service.log("E", "If you don't specify a source and a target for an edge you have to write its id in the format {source}-{target}");
1284
+ else {
1285
+ var sourceTarget = el.data.id.split('-');
1286
+ el.data.source = sourceTarget[0].trim();
1287
+ el.data.target = sourceTarget[1].trim();
1288
+ }
1289
+ }
1290
+ if (hasPreviousPositions && el.group == "nodes")
1291
+ el.position = positionCache[el.data.id];
1292
+ }
1293
+ }
1294
+ }
1295
+ EsDiagramComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: EsDiagramComponent, deps: [{ token: EsDiagramService, optional: true }, { token: EsDiagramDispatcher, optional: true }, { token: ReactiveExtensions }], target: i0.ɵɵFactoryTarget.Component });
1296
+ EsDiagramComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.1.1", type: EsDiagramComponent, selector: "es-diagram", inputs: { name: "name", UseContextMenu: "UseContextMenu", ContextMenuOptions: "ContextMenuOptions", UseExpandCollapse: "UseExpandCollapse", ExpandCollapseOptions: "ExpandCollapseOptions", NativeOptions: "NativeOptions", Elements: "Elements", NodeStyles: "NodeStyles", EdgeStyles: "EdgeStyles", Readonly: "Readonly", AutoupdateSize: "AutoupdateSize", PreserveElementsPosition: "PreserveElementsPosition", AnimateLayoutChanges: "AnimateLayoutChanges", SmartSelection: "SmartSelection", SmartSelectionStyles: "SmartSelectionStyles", ResizeThrottleTime: "ResizeThrottleTime", Layout: "Layout", NodeHTMLTemplates: "NodeHTMLTemplates", ExtensionModulesImporter: "ExtensionModulesImporter", ExtensionModulesApplyer: "ExtensionModulesApplyer" }, outputs: { onNodeClick: "onNodeClick", onNodeSelection: "onNodeSelection", onLayoutDone: "onLayoutDone", onLoaded: "onLoaded" }, viewQueries: [{ propertyName: "cyGraph", first: true, predicate: ["graph"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div #graph class=\"graph-wrapper {{name}}\"></div>", styles: [".graph-wrapper{height:100%;width:100%}.html-node-notransition{transition:none!important;transform:none!important}\n"] });
1297
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: EsDiagramComponent, decorators: [{
1298
+ type: Component,
1299
+ args: [{ selector: 'es-diagram', template: "<div #graph class=\"graph-wrapper {{name}}\"></div>", styles: [".graph-wrapper{height:100%;width:100%}.html-node-notransition{transition:none!important;transform:none!important}\n"] }]
1300
+ }], ctorParameters: function () { return [{ type: EsDiagramService, decorators: [{
1301
+ type: Optional
1302
+ }] }, { type: EsDiagramDispatcher, decorators: [{
1303
+ type: Optional
1304
+ }] }, { type: ReactiveExtensions }]; }, propDecorators: { cyGraph: [{
1305
+ type: ViewChild,
1306
+ args: ['graph']
1307
+ }], name: [{
1308
+ type: Input
1309
+ }], UseContextMenu: [{
1310
+ type: Input
1311
+ }], ContextMenuOptions: [{
1312
+ type: Input
1313
+ }], UseExpandCollapse: [{
1314
+ type: Input
1315
+ }], ExpandCollapseOptions: [{
1316
+ type: Input
1317
+ }], NativeOptions: [{
1318
+ type: Input
1319
+ }], Elements: [{
1320
+ type: Input
1321
+ }], NodeStyles: [{
1322
+ type: Input
1323
+ }], EdgeStyles: [{
1324
+ type: Input
1325
+ }], Readonly: [{
1326
+ type: Input
1327
+ }], AutoupdateSize: [{
1328
+ type: Input
1329
+ }], PreserveElementsPosition: [{
1330
+ type: Input
1331
+ }], AnimateLayoutChanges: [{
1332
+ type: Input
1333
+ }], SmartSelection: [{
1334
+ type: Input
1335
+ }], SmartSelectionStyles: [{
1336
+ type: Input
1337
+ }], ResizeThrottleTime: [{
1338
+ type: Input
1339
+ }], Layout: [{
1340
+ type: Input
1341
+ }], NodeHTMLTemplates: [{
1342
+ type: Input
1343
+ }], ExtensionModulesImporter: [{
1344
+ type: Input
1345
+ }], ExtensionModulesApplyer: [{
1346
+ type: Input
1347
+ }], onNodeClick: [{
1348
+ type: Output
1349
+ }], onNodeSelection: [{
1350
+ type: Output
1351
+ }], onLayoutDone: [{
1352
+ type: Output
1353
+ }], onLoaded: [{
1354
+ type: Output
1355
+ }] } });
1356
+
1357
+ class EsDiagramModule {
1358
+ static forRoot(config) {
1359
+ return {
1360
+ ngModule: EsDiagramModule,
1361
+ providers: [
1362
+ EsDiagramService,
1363
+ EsDiagramDispatcher,
1364
+ { provide: DIA_LOCALE, useValue: config?.locale || 'it-IT' },
1365
+ { provide: DIA_DEBUG_MODE, useValue: config?.debugMode || false },
1366
+ ]
1367
+ };
1368
+ }
1369
+ }
1370
+ EsDiagramModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: EsDiagramModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
1371
+ EsDiagramModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: EsDiagramModule, declarations: [EsDiagramComponent], imports: [CommonModule, FormsModule, ReactiveFormsModule, CommonModule], exports: [EsDiagramComponent] });
1372
+ EsDiagramModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: EsDiagramModule, imports: [[CommonModule, FormsModule, ReactiveFormsModule, CommonModule]] });
1373
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.1.1", ngImport: i0, type: EsDiagramModule, decorators: [{
1374
+ type: NgModule,
1375
+ args: [{
1376
+ declarations: [EsDiagramComponent],
1377
+ imports: [CommonModule, FormsModule, ReactiveFormsModule, CommonModule],
1378
+ exports: [EsDiagramComponent]
1379
+ }]
1380
+ }] });
1381
+
1382
+ /*
1383
+ * Public API Surface of cytoscape-angular
1384
+ */
1385
+
1386
+ /**
1387
+ * Generated bundle index. Do not edit.
1388
+ */
1389
+
1390
+ export { BaseLayoutOptionsImpl, BreadthFirstLayoutOptionsImpl, CircleLayoutOptionsImpl, ConcentricLayoutOptionsImpl, ContextMenuCommand, ContextMenuOptions, CoseLayoutOptionsImpl, DagreLayoutOptionsImpl, EsDiagramComponent, EsDiagramModule, EsDiagramModuleConfig, ExpandCollapseOptions, GridLayoutOptionsImpl, NodeHTMLTemplate, NodeTemplate, NullLayoutOptionsImpl, PresetLayoutOptionsImpl, RandomLayoutOptionsImpl, ShapedLayoutOptionsImpl, ZoomLevelBasedTemplate };
1391
+ //# sourceMappingURL=esfaenza-es-diagrams.mjs.map