@things-factory/integration-ui 6.1.103 → 6.1.105

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.
@@ -0,0 +1,1516 @@
1
+ import * as d3 from 'd3';
2
+ export class GraphViewer {
3
+ constructor(_selector, _options) {
4
+ this.classes2colors = {};
5
+ this.justLoaded = false;
6
+ this.numClasses = 0;
7
+ this.options = {
8
+ arrowSize: 4,
9
+ colors: this.colors(),
10
+ highlight: undefined,
11
+ iconMap: this.fontAwesomeIcons(),
12
+ icons: undefined,
13
+ imageMap: {},
14
+ images: undefined,
15
+ infoPanel: true,
16
+ minCollision: undefined,
17
+ graphData: undefined,
18
+ dataUrl: undefined,
19
+ nodeOutlineFillColor: undefined,
20
+ nodeRadius: 25,
21
+ relationshipColor: '#a5abb6',
22
+ zoomFit: false
23
+ };
24
+ this.init(_selector, _options);
25
+ }
26
+ appendGraph(container) {
27
+ this.svg = container
28
+ .append('svg')
29
+ .attr('width', '100%')
30
+ .attr('height', '100%')
31
+ .attr('class', 'graph-viewer')
32
+ .call(d3.zoom().on('zoom', (event, d) => {
33
+ var scale = event.transform.k, translate = [event.transform.x, event.transform.y];
34
+ if (this.svgTranslate) {
35
+ translate[0] += this.svgTranslate[0];
36
+ translate[1] += this.svgTranslate[1];
37
+ }
38
+ if (this.svgScale) {
39
+ scale *= this.svgScale;
40
+ }
41
+ this.svg.attr('transform', 'translate(' + translate[0] + ', ' + translate[1] + ') scale(' + scale + ')');
42
+ }))
43
+ .on('dblclick.zoom', null)
44
+ .append('g')
45
+ .attr('width', '100%')
46
+ .attr('height', '100%');
47
+ this.svgRelationships = this.svg.append('g').attr('class', 'relationships');
48
+ this.svgNodes = this.svg.append('g').attr('class', 'nodes');
49
+ }
50
+ appendImageToNode(node) {
51
+ return node
52
+ .append('image')
53
+ .attr('height', d => {
54
+ return this.icon(d) ? '24px' : '30px';
55
+ })
56
+ .attr('x', d => {
57
+ return this.icon(d) ? '5px' : '-15px';
58
+ })
59
+ .attr('xlink:href', d => {
60
+ return this.image(d);
61
+ })
62
+ .attr('y', d => {
63
+ return this.icon(d) ? '5px' : '-16px';
64
+ })
65
+ .attr('width', d => {
66
+ return this.icon(d) ? '24px' : '30px';
67
+ });
68
+ }
69
+ appendInfoPanel(container) {
70
+ return container.append('div').attr('class', 'graph-info');
71
+ }
72
+ appendInfoElement(cls, isNode, property, value) {
73
+ var elem = this.info.append('a');
74
+ elem
75
+ .attr('href', '#')
76
+ .attr('class', cls)
77
+ .html('<strong>' + property + '</strong>' + (value ? ': ' + value : ''));
78
+ if (!value) {
79
+ elem
80
+ .style('background-color', d => {
81
+ return this.options.nodeOutlineFillColor
82
+ ? this.options.nodeOutlineFillColor
83
+ : isNode
84
+ ? this.class2color(property)
85
+ : this.defaultColor();
86
+ })
87
+ .style('border-color', d => {
88
+ return this.options.nodeOutlineFillColor
89
+ ? this.class2darkenColor(this.options.nodeOutlineFillColor)
90
+ : isNode
91
+ ? this.class2darkenColor(property)
92
+ : this.defaultDarkenColor();
93
+ })
94
+ .style('color', d => {
95
+ return this.options.nodeOutlineFillColor ? this.class2darkenColor(this.options.nodeOutlineFillColor) : '#fff';
96
+ });
97
+ }
98
+ }
99
+ appendInfoElementClass(cls, node) {
100
+ this.appendInfoElement(cls, true, node);
101
+ }
102
+ appendInfoElementProperty(cls, property, value) {
103
+ this.appendInfoElement(cls, false, property, value);
104
+ }
105
+ appendInfoElementRelationship(cls, relationship) {
106
+ this.appendInfoElement(cls, false, relationship);
107
+ }
108
+ appendNode() {
109
+ return this.node
110
+ .enter()
111
+ .append('g')
112
+ .attr('class', d => {
113
+ var highlight, i, classes = 'node', label = d.labels[0];
114
+ if (this.icon(d)) {
115
+ classes += ' node-icon';
116
+ }
117
+ if (this.image(d)) {
118
+ classes += ' node-image';
119
+ }
120
+ if (this.options.highlight) {
121
+ for (i = 0; i < this.options.highlight.length; i++) {
122
+ highlight = this.options.highlight[i];
123
+ if (d.labels[0] === highlight.class && d.properties[highlight.property] === highlight.value) {
124
+ classes += ' node-highlighted';
125
+ break;
126
+ }
127
+ }
128
+ }
129
+ return classes;
130
+ })
131
+ .on('click', (event, d) => {
132
+ d.fx = d.fy = null;
133
+ if (typeof this.options.onNodeClick === 'function') {
134
+ this.options.onNodeClick(d);
135
+ }
136
+ })
137
+ .on('dblclick', (event, d) => {
138
+ this.stickNode(d, event);
139
+ if (typeof this.options.onNodeDoubleClick === 'function') {
140
+ this.options.onNodeDoubleClick(d);
141
+ }
142
+ })
143
+ .on('mouseenter', (event, d) => {
144
+ if (this.info) {
145
+ this.updateInfo(d);
146
+ }
147
+ if (typeof this.options.onNodeMouseEnter === 'function') {
148
+ this.options.onNodeMouseEnter(d);
149
+ }
150
+ })
151
+ .on('mouseleave', (event, d) => {
152
+ if (this.info) {
153
+ this.clearInfo();
154
+ }
155
+ if (typeof this.options.onNodeMouseLeave === 'function') {
156
+ this.options.onNodeMouseLeave(d);
157
+ }
158
+ })
159
+ .call(d3
160
+ .drag()
161
+ .on('start', this.dragStarted.bind(this))
162
+ .on('drag', this.dragged.bind(this))
163
+ .on('end', this.dragEnded.bind(this)));
164
+ }
165
+ appendNodeToGraph() {
166
+ var n = this.appendNode();
167
+ this.appendRingToNode(n);
168
+ // this.appendBoxToNode(n)
169
+ this.appendOutlineToNode(n);
170
+ if (this.options.icons) {
171
+ this.appendTextToNode(n);
172
+ }
173
+ if (this.options.images) {
174
+ this.appendImageToNode(n);
175
+ }
176
+ return n;
177
+ }
178
+ appendOutlineToNode(node) {
179
+ return node
180
+ .append('circle')
181
+ .attr('class', 'outline')
182
+ .attr('r', this.options.nodeRadius)
183
+ .style('fill', d => {
184
+ return this.options.nodeOutlineFillColor ? this.options.nodeOutlineFillColor : this.class2color(d.labels[0]);
185
+ })
186
+ .style('stroke', d => {
187
+ return this.options.nodeOutlineFillColor
188
+ ? this.class2darkenColor(this.options.nodeOutlineFillColor)
189
+ : this.class2darkenColor(d.labels[0]);
190
+ })
191
+ .append('title')
192
+ .text(d => {
193
+ return this.toString(d);
194
+ });
195
+ }
196
+ appendBoxToNode(node) {
197
+ const rect = node
198
+ .append('rect')
199
+ .attr('class', 'node-rect')
200
+ .attr('width', 160) // 사각형의 너비
201
+ .attr('height', 30) // 사각형의 높이
202
+ .attr('x', -80) // 사각형의 중심을 기준으로 x 위치 조정
203
+ .attr('y', -15) // 사각형의 중심을 기준으로 y 위치 조정
204
+ .style('fill', d => {
205
+ return this.options.nodeOutlineFillColor ? this.options.nodeOutlineFillColor : this.class2color(d.labels[0]);
206
+ })
207
+ .style('stroke', d => {
208
+ return this.options.nodeOutlineFillColor
209
+ ? this.class2darkenColor(this.options.nodeOutlineFillColor)
210
+ : this.class2darkenColor(d.labels[0]);
211
+ })
212
+ .append('title')
213
+ .text(d => {
214
+ return this.toString(d);
215
+ });
216
+ node
217
+ .append('text')
218
+ .attr('class', 'node-text')
219
+ .attr('x', 0)
220
+ .attr('y', 4)
221
+ .attr('text-anchor', 'middle') // 텍스트 중앙 정렬
222
+ .attr('fill', 'black') // 텍스트 색상을 검은색으로 변경
223
+ .text(d => d.text);
224
+ return rect;
225
+ }
226
+ appendRingToNode(node) {
227
+ return node
228
+ .append('circle')
229
+ .attr('class', 'ring')
230
+ .attr('r', this.options.nodeRadius * 1.16)
231
+ .append('title')
232
+ .text(d => {
233
+ return this.toString(d);
234
+ });
235
+ }
236
+ appendTextToNode(node) {
237
+ return node
238
+ .append('text')
239
+ .attr('class', d => {
240
+ return 'text' + (this.icon(d) ? ' icon' : '');
241
+ })
242
+ .attr('fill', '#ffffff')
243
+ .attr('font-size', d => {
244
+ return this.icon(d) ? this.options.nodeRadius + 'px' : '10px';
245
+ })
246
+ .attr('pointer-events', 'none')
247
+ .attr('text-anchor', 'middle')
248
+ .attr('y', d => {
249
+ return this.icon(d) ? Math.round(this.options.nodeRadius * 0.32) + 'px' : '4px';
250
+ })
251
+ .html(d => {
252
+ var _icon = this.icon(d);
253
+ return _icon ? '&#x' + _icon : d.text;
254
+ });
255
+ }
256
+ appendRandomDataToNode(d, maxNodesToGenerate) {
257
+ var data = this.randomD3Data(d, maxNodesToGenerate);
258
+ this.updateWithGraphData(data);
259
+ }
260
+ appendRelationship() {
261
+ return this.relationship
262
+ .enter()
263
+ .append('g')
264
+ .attr('class', 'relationship')
265
+ .on('dblclick', (event, d) => {
266
+ if (typeof this.options.onRelationshipDoubleClick === 'function') {
267
+ this.options.onRelationshipDoubleClick(d);
268
+ }
269
+ })
270
+ .on('mouseenter', (event, d) => {
271
+ if (this.info) {
272
+ this.updateInfo(d);
273
+ }
274
+ });
275
+ }
276
+ appendOutlineToRelationship(r) {
277
+ return r.append('path').attr('class', 'outline').attr('fill', '#a5abb6').attr('stroke', 'none');
278
+ }
279
+ appendOverlayToRelationship(r) {
280
+ return r.append('path').attr('class', 'overlay');
281
+ }
282
+ appendTextToRelationship(r) {
283
+ return r
284
+ .append('text')
285
+ .attr('class', 'text')
286
+ .attr('fill', '#000000')
287
+ .attr('font-size', '8px')
288
+ .attr('pointer-events', 'none')
289
+ .attr('text-anchor', 'middle')
290
+ .text(d => {
291
+ return d.type;
292
+ });
293
+ }
294
+ appendRelationshipToGraph() {
295
+ var relationship = this.appendRelationship(), text = this.appendTextToRelationship(relationship), outline = this.appendOutlineToRelationship(relationship), overlay = this.appendOverlayToRelationship(relationship);
296
+ return {
297
+ outline: outline,
298
+ overlay: overlay,
299
+ relationship: relationship,
300
+ text: text
301
+ };
302
+ }
303
+ class2color(cls) {
304
+ var color = this.classes2colors[cls];
305
+ if (!color) {
306
+ // color = this.options.colors[Math.min(numClasses, this.options.colors.length - 1)];
307
+ color = this.options.colors[this.numClasses % this.options.colors.length];
308
+ this.classes2colors[cls] = color;
309
+ this.numClasses++;
310
+ }
311
+ return color;
312
+ }
313
+ class2darkenColor(cls) {
314
+ return d3.rgb(this.class2color(cls)).darker(1);
315
+ }
316
+ clearInfo() {
317
+ this.info.html('');
318
+ }
319
+ color() {
320
+ return this.options.colors[(this.options.colors.length * Math.random()) << 0];
321
+ }
322
+ colors() {
323
+ // d3.schemeCategory10,
324
+ // d3.schemeCategory20,
325
+ return [
326
+ '#68bdf6',
327
+ '#6dce9e',
328
+ '#faafc2',
329
+ '#f2baf6',
330
+ '#ff928c',
331
+ '#fcea7e',
332
+ '#ffc766',
333
+ '#405f9e',
334
+ '#a5abb6',
335
+ '#78cecb',
336
+ '#b88cbb',
337
+ '#ced2d9',
338
+ '#e84646',
339
+ '#fa5f86',
340
+ '#ffab1a',
341
+ '#fcda19',
342
+ '#797b80',
343
+ '#c9d96f',
344
+ '#47991f',
345
+ '#70edee',
346
+ '#ff75ea' // pink
347
+ ];
348
+ }
349
+ contains(array, id) {
350
+ var filter = array.filter(function (elem) {
351
+ return elem.id === id;
352
+ });
353
+ return filter.length > 0;
354
+ }
355
+ defaultColor() {
356
+ return this.options.relationshipColor;
357
+ }
358
+ defaultDarkenColor() {
359
+ return d3.rgb(this.options.colors[this.options.colors.length - 1]).darker(1);
360
+ }
361
+ dragEnded(d, event) {
362
+ if (!event.active) {
363
+ this.simulation.alphaTarget(0);
364
+ }
365
+ if (typeof this.options.onNodeDragEnd === 'function') {
366
+ this.options.onNodeDragEnd(d);
367
+ }
368
+ }
369
+ dragged(d, event) {
370
+ this.stickNode(d, event);
371
+ }
372
+ dragStarted(d, event) {
373
+ if (!event.active) {
374
+ this.simulation.alphaTarget(0.3).restart();
375
+ }
376
+ d.fx = d.x;
377
+ d.fy = d.y;
378
+ if (typeof this.options.onNodeDragStart === 'function') {
379
+ this.options.onNodeDragStart(d);
380
+ }
381
+ }
382
+ extend(obj1, obj2) {
383
+ var obj = {};
384
+ this.merge(obj, obj1);
385
+ this.merge(obj, obj2);
386
+ return obj;
387
+ }
388
+ fontAwesomeIcons() {
389
+ return {
390
+ glass: 'f000',
391
+ music: 'f001',
392
+ search: 'f002',
393
+ 'envelope-o': 'f003',
394
+ heart: 'f004',
395
+ star: 'f005',
396
+ 'star-o': 'f006',
397
+ user: 'f007',
398
+ film: 'f008',
399
+ 'th-large': 'f009',
400
+ th: 'f00a',
401
+ 'th-list': 'f00b',
402
+ check: 'f00c',
403
+ 'remove,close,times': 'f00d',
404
+ 'search-plus': 'f00e',
405
+ 'search-minus': 'f010',
406
+ 'power-off': 'f011',
407
+ signal: 'f012',
408
+ 'gear,cog': 'f013',
409
+ 'trash-o': 'f014',
410
+ home: 'f015',
411
+ 'file-o': 'f016',
412
+ 'clock-o': 'f017',
413
+ road: 'f018',
414
+ download: 'f019',
415
+ 'arrow-circle-o-down': 'f01a',
416
+ 'arrow-circle-o-up': 'f01b',
417
+ inbox: 'f01c',
418
+ 'play-circle-o': 'f01d',
419
+ 'rotate-right,repeat': 'f01e',
420
+ refresh: 'f021',
421
+ 'list-alt': 'f022',
422
+ lock: 'f023',
423
+ flag: 'f024',
424
+ headphones: 'f025',
425
+ 'volume-off': 'f026',
426
+ 'volume-down': 'f027',
427
+ 'volume-up': 'f028',
428
+ qrcode: 'f029',
429
+ barcode: 'f02a',
430
+ tag: 'f02b',
431
+ tags: 'f02c',
432
+ book: 'f02d',
433
+ bookmark: 'f02e',
434
+ print: 'f02f',
435
+ camera: 'f030',
436
+ font: 'f031',
437
+ bold: 'f032',
438
+ italic: 'f033',
439
+ 'text-height': 'f034',
440
+ 'text-width': 'f035',
441
+ 'align-left': 'f036',
442
+ 'align-center': 'f037',
443
+ 'align-right': 'f038',
444
+ 'align-justify': 'f039',
445
+ list: 'f03a',
446
+ 'dedent,outdent': 'f03b',
447
+ indent: 'f03c',
448
+ 'video-camera': 'f03d',
449
+ 'photo,image,picture-o': 'f03e',
450
+ pencil: 'f040',
451
+ 'map-marker': 'f041',
452
+ adjust: 'f042',
453
+ tint: 'f043',
454
+ 'edit,pencil-square-o': 'f044',
455
+ 'share-square-o': 'f045',
456
+ 'check-square-o': 'f046',
457
+ arrows: 'f047',
458
+ 'step-backward': 'f048',
459
+ 'fast-backward': 'f049',
460
+ backward: 'f04a',
461
+ play: 'f04b',
462
+ pause: 'f04c',
463
+ stop: 'f04d',
464
+ forward: 'f04e',
465
+ 'fast-forward': 'f050',
466
+ 'step-forward': 'f051',
467
+ eject: 'f052',
468
+ 'chevron-left': 'f053',
469
+ 'chevron-right': 'f054',
470
+ 'plus-circle': 'f055',
471
+ 'minus-circle': 'f056',
472
+ 'times-circle': 'f057',
473
+ 'check-circle': 'f058',
474
+ 'question-circle': 'f059',
475
+ 'info-circle': 'f05a',
476
+ crosshairs: 'f05b',
477
+ 'times-circle-o': 'f05c',
478
+ 'check-circle-o': 'f05d',
479
+ ban: 'f05e',
480
+ 'arrow-left': 'f060',
481
+ 'arrow-right': 'f061',
482
+ 'arrow-up': 'f062',
483
+ 'arrow-down': 'f063',
484
+ 'mail-forward,share': 'f064',
485
+ expand: 'f065',
486
+ compress: 'f066',
487
+ plus: 'f067',
488
+ minus: 'f068',
489
+ asterisk: 'f069',
490
+ 'exclamation-circle': 'f06a',
491
+ gift: 'f06b',
492
+ leaf: 'f06c',
493
+ fire: 'f06d',
494
+ eye: 'f06e',
495
+ 'eye-slash': 'f070',
496
+ 'warning,exclamation-triangle': 'f071',
497
+ plane: 'f072',
498
+ calendar: 'f073',
499
+ random: 'f074',
500
+ comment: 'f075',
501
+ magnet: 'f076',
502
+ 'chevron-up': 'f077',
503
+ 'chevron-down': 'f078',
504
+ retweet: 'f079',
505
+ 'shopping-cart': 'f07a',
506
+ folder: 'f07b',
507
+ 'folder-open': 'f07c',
508
+ 'arrows-v': 'f07d',
509
+ 'arrows-h': 'f07e',
510
+ 'bar-chart-o,bar-chart': 'f080',
511
+ 'twitter-square': 'f081',
512
+ 'facebook-square': 'f082',
513
+ 'camera-retro': 'f083',
514
+ key: 'f084',
515
+ 'gears,cogs': 'f085',
516
+ comments: 'f086',
517
+ 'thumbs-o-up': 'f087',
518
+ 'thumbs-o-down': 'f088',
519
+ 'star-half': 'f089',
520
+ 'heart-o': 'f08a',
521
+ 'sign-out': 'f08b',
522
+ 'linkedin-square': 'f08c',
523
+ 'thumb-tack': 'f08d',
524
+ 'external-link': 'f08e',
525
+ 'sign-in': 'f090',
526
+ trophy: 'f091',
527
+ 'github-square': 'f092',
528
+ upload: 'f093',
529
+ 'lemon-o': 'f094',
530
+ phone: 'f095',
531
+ 'square-o': 'f096',
532
+ 'bookmark-o': 'f097',
533
+ 'phone-square': 'f098',
534
+ twitter: 'f099',
535
+ 'facebook-f,facebook': 'f09a',
536
+ github: 'f09b',
537
+ unlock: 'f09c',
538
+ 'credit-card': 'f09d',
539
+ 'feed,rss': 'f09e',
540
+ 'hdd-o': 'f0a0',
541
+ bullhorn: 'f0a1',
542
+ bell: 'f0f3',
543
+ certificate: 'f0a3',
544
+ 'hand-o-right': 'f0a4',
545
+ 'hand-o-left': 'f0a5',
546
+ 'hand-o-up': 'f0a6',
547
+ 'hand-o-down': 'f0a7',
548
+ 'arrow-circle-left': 'f0a8',
549
+ 'arrow-circle-right': 'f0a9',
550
+ 'arrow-circle-up': 'f0aa',
551
+ 'arrow-circle-down': 'f0ab',
552
+ globe: 'f0ac',
553
+ wrench: 'f0ad',
554
+ tasks: 'f0ae',
555
+ filter: 'f0b0',
556
+ briefcase: 'f0b1',
557
+ 'arrows-alt': 'f0b2',
558
+ 'group,users': 'f0c0',
559
+ 'chain,link': 'f0c1',
560
+ cloud: 'f0c2',
561
+ flask: 'f0c3',
562
+ 'cut,scissors': 'f0c4',
563
+ 'copy,files-o': 'f0c5',
564
+ paperclip: 'f0c6',
565
+ 'save,floppy-o': 'f0c7',
566
+ square: 'f0c8',
567
+ 'navicon,reorder,bars': 'f0c9',
568
+ 'list-ul': 'f0ca',
569
+ 'list-ol': 'f0cb',
570
+ strikethrough: 'f0cc',
571
+ underline: 'f0cd',
572
+ table: 'f0ce',
573
+ magic: 'f0d0',
574
+ truck: 'f0d1',
575
+ pinterest: 'f0d2',
576
+ 'pinterest-square': 'f0d3',
577
+ 'google-plus-square': 'f0d4',
578
+ 'google-plus': 'f0d5',
579
+ money: 'f0d6',
580
+ 'caret-down': 'f0d7',
581
+ 'caret-up': 'f0d8',
582
+ 'caret-left': 'f0d9',
583
+ 'caret-right': 'f0da',
584
+ columns: 'f0db',
585
+ 'unsorted,sort': 'f0dc',
586
+ 'sort-down,sort-desc': 'f0dd',
587
+ 'sort-up,sort-asc': 'f0de',
588
+ envelope: 'f0e0',
589
+ linkedin: 'f0e1',
590
+ 'rotate-left,undo': 'f0e2',
591
+ 'legal,gavel': 'f0e3',
592
+ 'dashboard,tachometer': 'f0e4',
593
+ 'comment-o': 'f0e5',
594
+ 'comments-o': 'f0e6',
595
+ 'flash,bolt': 'f0e7',
596
+ sitemap: 'f0e8',
597
+ umbrella: 'f0e9',
598
+ 'paste,clipboard': 'f0ea',
599
+ 'lightbulb-o': 'f0eb',
600
+ exchange: 'f0ec',
601
+ 'cloud-download': 'f0ed',
602
+ 'cloud-upload': 'f0ee',
603
+ 'user-md': 'f0f0',
604
+ stethoscope: 'f0f1',
605
+ suitcase: 'f0f2',
606
+ 'bell-o': 'f0a2',
607
+ coffee: 'f0f4',
608
+ cutlery: 'f0f5',
609
+ 'file-text-o': 'f0f6',
610
+ 'building-o': 'f0f7',
611
+ 'hospital-o': 'f0f8',
612
+ ambulance: 'f0f9',
613
+ medkit: 'f0fa',
614
+ 'fighter-jet': 'f0fb',
615
+ beer: 'f0fc',
616
+ 'h-square': 'f0fd',
617
+ 'plus-square': 'f0fe',
618
+ 'angle-double-left': 'f100',
619
+ 'angle-double-right': 'f101',
620
+ 'angle-double-up': 'f102',
621
+ 'angle-double-down': 'f103',
622
+ 'angle-left': 'f104',
623
+ 'angle-right': 'f105',
624
+ 'angle-up': 'f106',
625
+ 'angle-down': 'f107',
626
+ desktop: 'f108',
627
+ laptop: 'f109',
628
+ tablet: 'f10a',
629
+ 'mobile-phone,mobile': 'f10b',
630
+ 'circle-o': 'f10c',
631
+ 'quote-left': 'f10d',
632
+ 'quote-right': 'f10e',
633
+ spinner: 'f110',
634
+ circle: 'f111',
635
+ 'mail-reply,reply': 'f112',
636
+ 'github-alt': 'f113',
637
+ 'folder-o': 'f114',
638
+ 'folder-open-o': 'f115',
639
+ 'smile-o': 'f118',
640
+ 'frown-o': 'f119',
641
+ 'meh-o': 'f11a',
642
+ gamepad: 'f11b',
643
+ 'keyboard-o': 'f11c',
644
+ 'flag-o': 'f11d',
645
+ 'flag-checkered': 'f11e',
646
+ terminal: 'f120',
647
+ code: 'f121',
648
+ 'mail-reply-all,reply-all': 'f122',
649
+ 'star-half-empty,star-half-full,star-half-o': 'f123',
650
+ 'location-arrow': 'f124',
651
+ crop: 'f125',
652
+ 'code-fork': 'f126',
653
+ 'unlink,chain-broken': 'f127',
654
+ question: 'f128',
655
+ info: 'f129',
656
+ exclamation: 'f12a',
657
+ superscript: 'f12b',
658
+ subscript: 'f12c',
659
+ eraser: 'f12d',
660
+ 'puzzle-piece': 'f12e',
661
+ microphone: 'f130',
662
+ 'microphone-slash': 'f131',
663
+ shield: 'f132',
664
+ 'calendar-o': 'f133',
665
+ 'fire-extinguisher': 'f134',
666
+ rocket: 'f135',
667
+ maxcdn: 'f136',
668
+ 'chevron-circle-left': 'f137',
669
+ 'chevron-circle-right': 'f138',
670
+ 'chevron-circle-up': 'f139',
671
+ 'chevron-circle-down': 'f13a',
672
+ html5: 'f13b',
673
+ css3: 'f13c',
674
+ anchor: 'f13d',
675
+ 'unlock-alt': 'f13e',
676
+ bullseye: 'f140',
677
+ 'ellipsis-h': 'f141',
678
+ 'ellipsis-v': 'f142',
679
+ 'rss-square': 'f143',
680
+ 'play-circle': 'f144',
681
+ ticket: 'f145',
682
+ 'minus-square': 'f146',
683
+ 'minus-square-o': 'f147',
684
+ 'level-up': 'f148',
685
+ 'level-down': 'f149',
686
+ 'check-square': 'f14a',
687
+ 'pencil-square': 'f14b',
688
+ 'external-link-square': 'f14c',
689
+ 'share-square': 'f14d',
690
+ compass: 'f14e',
691
+ 'toggle-down,caret-square-o-down': 'f150',
692
+ 'toggle-up,caret-square-o-up': 'f151',
693
+ 'toggle-right,caret-square-o-right': 'f152',
694
+ 'euro,eur': 'f153',
695
+ gbp: 'f154',
696
+ 'dollar,usd': 'f155',
697
+ 'rupee,inr': 'f156',
698
+ 'cny,rmb,yen,jpy': 'f157',
699
+ 'ruble,rouble,rub': 'f158',
700
+ 'won,krw': 'f159',
701
+ 'bitcoin,btc': 'f15a',
702
+ file: 'f15b',
703
+ 'file-text': 'f15c',
704
+ 'sort-alpha-asc': 'f15d',
705
+ 'sort-alpha-desc': 'f15e',
706
+ 'sort-amount-asc': 'f160',
707
+ 'sort-amount-desc': 'f161',
708
+ 'sort-numeric-asc': 'f162',
709
+ 'sort-numeric-desc': 'f163',
710
+ 'thumbs-up': 'f164',
711
+ 'thumbs-down': 'f165',
712
+ 'youtube-square': 'f166',
713
+ youtube: 'f167',
714
+ xing: 'f168',
715
+ 'xing-square': 'f169',
716
+ 'youtube-play': 'f16a',
717
+ dropbox: 'f16b',
718
+ 'stack-overflow': 'f16c',
719
+ instagram: 'f16d',
720
+ flickr: 'f16e',
721
+ adn: 'f170',
722
+ bitbucket: 'f171',
723
+ 'bitbucket-square': 'f172',
724
+ tumblr: 'f173',
725
+ 'tumblr-square': 'f174',
726
+ 'long-arrow-down': 'f175',
727
+ 'long-arrow-up': 'f176',
728
+ 'long-arrow-left': 'f177',
729
+ 'long-arrow-right': 'f178',
730
+ apple: 'f179',
731
+ windows: 'f17a',
732
+ android: 'f17b',
733
+ linux: 'f17c',
734
+ dribbble: 'f17d',
735
+ skype: 'f17e',
736
+ foursquare: 'f180',
737
+ trello: 'f181',
738
+ female: 'f182',
739
+ male: 'f183',
740
+ 'gittip,gratipay': 'f184',
741
+ 'sun-o': 'f185',
742
+ 'moon-o': 'f186',
743
+ archive: 'f187',
744
+ bug: 'f188',
745
+ vk: 'f189',
746
+ weibo: 'f18a',
747
+ renren: 'f18b',
748
+ pagelines: 'f18c',
749
+ 'stack-exchange': 'f18d',
750
+ 'arrow-circle-o-right': 'f18e',
751
+ 'arrow-circle-o-left': 'f190',
752
+ 'toggle-left,caret-square-o-left': 'f191',
753
+ 'dot-circle-o': 'f192',
754
+ wheelchair: 'f193',
755
+ 'vimeo-square': 'f194',
756
+ 'turkish-lira,try': 'f195',
757
+ 'plus-square-o': 'f196',
758
+ 'space-shuttle': 'f197',
759
+ slack: 'f198',
760
+ 'envelope-square': 'f199',
761
+ wordpress: 'f19a',
762
+ openid: 'f19b',
763
+ 'institution,bank,university': 'f19c',
764
+ 'mortar-board,graduation-cap': 'f19d',
765
+ yahoo: 'f19e',
766
+ google: 'f1a0',
767
+ reddit: 'f1a1',
768
+ 'reddit-square': 'f1a2',
769
+ 'stumbleupon-circle': 'f1a3',
770
+ stumbleupon: 'f1a4',
771
+ delicious: 'f1a5',
772
+ digg: 'f1a6',
773
+ 'pied-piper-pp': 'f1a7',
774
+ 'pied-piper-alt': 'f1a8',
775
+ drupal: 'f1a9',
776
+ joomla: 'f1aa',
777
+ language: 'f1ab',
778
+ fax: 'f1ac',
779
+ building: 'f1ad',
780
+ child: 'f1ae',
781
+ paw: 'f1b0',
782
+ spoon: 'f1b1',
783
+ cube: 'f1b2',
784
+ cubes: 'f1b3',
785
+ behance: 'f1b4',
786
+ 'behance-square': 'f1b5',
787
+ steam: 'f1b6',
788
+ 'steam-square': 'f1b7',
789
+ recycle: 'f1b8',
790
+ 'automobile,car': 'f1b9',
791
+ 'cab,taxi': 'f1ba',
792
+ tree: 'f1bb',
793
+ spotify: 'f1bc',
794
+ deviantart: 'f1bd',
795
+ soundcloud: 'f1be',
796
+ database: 'f1c0',
797
+ 'file-pdf-o': 'f1c1',
798
+ 'file-word-o': 'f1c2',
799
+ 'file-excel-o': 'f1c3',
800
+ 'file-powerpoint-o': 'f1c4',
801
+ 'file-photo-o,file-picture-o,file-image-o': 'f1c5',
802
+ 'file-zip-o,file-archive-o': 'f1c6',
803
+ 'file-sound-o,file-audio-o': 'f1c7',
804
+ 'file-movie-o,file-video-o': 'f1c8',
805
+ 'file-code-o': 'f1c9',
806
+ vine: 'f1ca',
807
+ codepen: 'f1cb',
808
+ jsfiddle: 'f1cc',
809
+ 'life-bouy,life-buoy,life-saver,support,life-ring': 'f1cd',
810
+ 'circle-o-notch': 'f1ce',
811
+ 'ra,resistance,rebel': 'f1d0',
812
+ 'ge,empire': 'f1d1',
813
+ 'git-square': 'f1d2',
814
+ git: 'f1d3',
815
+ 'y-combinator-square,yc-square,hacker-news': 'f1d4',
816
+ 'tencent-weibo': 'f1d5',
817
+ qq: 'f1d6',
818
+ 'wechat,weixin': 'f1d7',
819
+ 'send,paper-plane': 'f1d8',
820
+ 'send-o,paper-plane-o': 'f1d9',
821
+ history: 'f1da',
822
+ 'circle-thin': 'f1db',
823
+ header: 'f1dc',
824
+ paragraph: 'f1dd',
825
+ sliders: 'f1de',
826
+ 'share-alt': 'f1e0',
827
+ 'share-alt-square': 'f1e1',
828
+ bomb: 'f1e2',
829
+ 'soccer-ball-o,futbol-o': 'f1e3',
830
+ tty: 'f1e4',
831
+ binoculars: 'f1e5',
832
+ plug: 'f1e6',
833
+ slideshare: 'f1e7',
834
+ twitch: 'f1e8',
835
+ yelp: 'f1e9',
836
+ 'newspaper-o': 'f1ea',
837
+ wifi: 'f1eb',
838
+ calculator: 'f1ec',
839
+ paypal: 'f1ed',
840
+ 'google-wallet': 'f1ee',
841
+ 'cc-visa': 'f1f0',
842
+ 'cc-mastercard': 'f1f1',
843
+ 'cc-discover': 'f1f2',
844
+ 'cc-amex': 'f1f3',
845
+ 'cc-paypal': 'f1f4',
846
+ 'cc-stripe': 'f1f5',
847
+ 'bell-slash': 'f1f6',
848
+ 'bell-slash-o': 'f1f7',
849
+ trash: 'f1f8',
850
+ copyright: 'f1f9',
851
+ at: 'f1fa',
852
+ eyedropper: 'f1fb',
853
+ 'paint-brush': 'f1fc',
854
+ 'birthday-cake': 'f1fd',
855
+ 'area-chart': 'f1fe',
856
+ 'pie-chart': 'f200',
857
+ 'line-chart': 'f201',
858
+ lastfm: 'f202',
859
+ 'lastfm-square': 'f203',
860
+ 'toggle-off': 'f204',
861
+ 'toggle-on': 'f205',
862
+ bicycle: 'f206',
863
+ bus: 'f207',
864
+ ioxhost: 'f208',
865
+ angellist: 'f209',
866
+ cc: 'f20a',
867
+ 'shekel,sheqel,ils': 'f20b',
868
+ meanpath: 'f20c',
869
+ buysellads: 'f20d',
870
+ connectdevelop: 'f20e',
871
+ dashcube: 'f210',
872
+ forumbee: 'f211',
873
+ leanpub: 'f212',
874
+ sellsy: 'f213',
875
+ shirtsinbulk: 'f214',
876
+ simplybuilt: 'f215',
877
+ skyatlas: 'f216',
878
+ 'cart-plus': 'f217',
879
+ 'cart-arrow-down': 'f218',
880
+ diamond: 'f219',
881
+ ship: 'f21a',
882
+ 'user-secret': 'f21b',
883
+ motorcycle: 'f21c',
884
+ 'street-view': 'f21d',
885
+ heartbeat: 'f21e',
886
+ venus: 'f221',
887
+ mars: 'f222',
888
+ mercury: 'f223',
889
+ 'intersex,transgender': 'f224',
890
+ 'transgender-alt': 'f225',
891
+ 'venus-double': 'f226',
892
+ 'mars-double': 'f227',
893
+ 'venus-mars': 'f228',
894
+ 'mars-stroke': 'f229',
895
+ 'mars-stroke-v': 'f22a',
896
+ 'mars-stroke-h': 'f22b',
897
+ neuter: 'f22c',
898
+ genderless: 'f22d',
899
+ 'facebook-official': 'f230',
900
+ 'pinterest-p': 'f231',
901
+ whatsapp: 'f232',
902
+ server: 'f233',
903
+ 'user-plus': 'f234',
904
+ 'user-times': 'f235',
905
+ 'hotel,bed': 'f236',
906
+ viacoin: 'f237',
907
+ train: 'f238',
908
+ subway: 'f239',
909
+ medium: 'f23a',
910
+ 'yc,y-combinator': 'f23b',
911
+ 'optin-monster': 'f23c',
912
+ opencart: 'f23d',
913
+ expeditedssl: 'f23e',
914
+ 'battery-4,battery-full': 'f240',
915
+ 'battery-3,battery-three-quarters': 'f241',
916
+ 'battery-2,battery-half': 'f242',
917
+ 'battery-1,battery-quarter': 'f243',
918
+ 'battery-0,battery-empty': 'f244',
919
+ 'mouse-pointer': 'f245',
920
+ 'i-cursor': 'f246',
921
+ 'object-group': 'f247',
922
+ 'object-ungroup': 'f248',
923
+ 'sticky-note': 'f249',
924
+ 'sticky-note-o': 'f24a',
925
+ 'cc-jcb': 'f24b',
926
+ 'cc-diners-club': 'f24c',
927
+ clone: 'f24d',
928
+ 'balance-scale': 'f24e',
929
+ 'hourglass-o': 'f250',
930
+ 'hourglass-1,hourglass-start': 'f251',
931
+ 'hourglass-2,hourglass-half': 'f252',
932
+ 'hourglass-3,hourglass-end': 'f253',
933
+ hourglass: 'f254',
934
+ 'hand-grab-o,hand-rock-o': 'f255',
935
+ 'hand-stop-o,hand-paper-o': 'f256',
936
+ 'hand-scissors-o': 'f257',
937
+ 'hand-lizard-o': 'f258',
938
+ 'hand-spock-o': 'f259',
939
+ 'hand-pointer-o': 'f25a',
940
+ 'hand-peace-o': 'f25b',
941
+ trademark: 'f25c',
942
+ registered: 'f25d',
943
+ 'creative-commons': 'f25e',
944
+ gg: 'f260',
945
+ 'gg-circle': 'f261',
946
+ tripadvisor: 'f262',
947
+ odnoklassniki: 'f263',
948
+ 'odnoklassniki-square': 'f264',
949
+ 'get-pocket': 'f265',
950
+ 'wikipedia-w': 'f266',
951
+ safari: 'f267',
952
+ chrome: 'f268',
953
+ firefox: 'f269',
954
+ opera: 'f26a',
955
+ 'internet-explorer': 'f26b',
956
+ 'tv,television': 'f26c',
957
+ contao: 'f26d',
958
+ '500px': 'f26e',
959
+ amazon: 'f270',
960
+ 'calendar-plus-o': 'f271',
961
+ 'calendar-minus-o': 'f272',
962
+ 'calendar-times-o': 'f273',
963
+ 'calendar-check-o': 'f274',
964
+ industry: 'f275',
965
+ 'map-pin': 'f276',
966
+ 'map-signs': 'f277',
967
+ 'map-o': 'f278',
968
+ map: 'f279',
969
+ commenting: 'f27a',
970
+ 'commenting-o': 'f27b',
971
+ houzz: 'f27c',
972
+ vimeo: 'f27d',
973
+ 'black-tie': 'f27e',
974
+ fonticons: 'f280',
975
+ 'reddit-alien': 'f281',
976
+ edge: 'f282',
977
+ 'credit-card-alt': 'f283',
978
+ codiepie: 'f284',
979
+ modx: 'f285',
980
+ 'fort-awesome': 'f286',
981
+ usb: 'f287',
982
+ 'product-hunt': 'f288',
983
+ mixcloud: 'f289',
984
+ scribd: 'f28a',
985
+ 'pause-circle': 'f28b',
986
+ 'pause-circle-o': 'f28c',
987
+ 'stop-circle': 'f28d',
988
+ 'stop-circle-o': 'f28e',
989
+ 'shopping-bag': 'f290',
990
+ 'shopping-basket': 'f291',
991
+ hashtag: 'f292',
992
+ bluetooth: 'f293',
993
+ 'bluetooth-b': 'f294',
994
+ percent: 'f295',
995
+ gitlab: 'f296',
996
+ wpbeginner: 'f297',
997
+ wpforms: 'f298',
998
+ envira: 'f299',
999
+ 'universal-access': 'f29a',
1000
+ 'wheelchair-alt': 'f29b',
1001
+ 'question-circle-o': 'f29c',
1002
+ blind: 'f29d',
1003
+ 'audio-description': 'f29e',
1004
+ 'volume-control-phone': 'f2a0',
1005
+ braille: 'f2a1',
1006
+ 'assistive-listening-systems': 'f2a2',
1007
+ 'asl-interpreting,american-sign-language-interpreting': 'f2a3',
1008
+ 'deafness,hard-of-hearing,deaf': 'f2a4',
1009
+ glide: 'f2a5',
1010
+ 'glide-g': 'f2a6',
1011
+ 'signing,sign-language': 'f2a7',
1012
+ 'low-vision': 'f2a8',
1013
+ viadeo: 'f2a9',
1014
+ 'viadeo-square': 'f2aa',
1015
+ snapchat: 'f2ab',
1016
+ 'snapchat-ghost': 'f2ac',
1017
+ 'snapchat-square': 'f2ad',
1018
+ 'pied-piper': 'f2ae',
1019
+ 'first-order': 'f2b0',
1020
+ yoast: 'f2b1',
1021
+ themeisle: 'f2b2',
1022
+ 'google-plus-circle,google-plus-official': 'f2b3',
1023
+ 'fa,font-awesome': 'f2b4'
1024
+ };
1025
+ }
1026
+ icon(d) {
1027
+ var code;
1028
+ if (this.options.iconMap && this.options.showIcons && this.options.icons) {
1029
+ if (this.options.icons[d.labels[0]] && this.options.iconMap[this.options.icons[d.labels[0]]]) {
1030
+ code = this.options.iconMap[this.options.icons[d.labels[0]]];
1031
+ }
1032
+ else if (this.options.iconMap[d.labels[0]]) {
1033
+ code = this.options.iconMap[d.labels[0]];
1034
+ }
1035
+ else if (this.options.icons[d.labels[0]]) {
1036
+ code = this.options.icons[d.labels[0]];
1037
+ }
1038
+ }
1039
+ return code;
1040
+ }
1041
+ image(d) {
1042
+ var i, imagesForLabel, img, imgLevel, label, labelPropertyValue, property, value;
1043
+ if (this.options.images) {
1044
+ imagesForLabel = this.options.imageMap[d.labels[0]];
1045
+ if (imagesForLabel) {
1046
+ imgLevel = 0;
1047
+ for (i = 0; i < imagesForLabel.length; i++) {
1048
+ labelPropertyValue = imagesForLabel[i].split('|');
1049
+ switch (labelPropertyValue.length) {
1050
+ case 3:
1051
+ value = labelPropertyValue[2];
1052
+ /* falls through */
1053
+ case 2:
1054
+ property = labelPropertyValue[1];
1055
+ /* falls through */
1056
+ case 1:
1057
+ label = labelPropertyValue[0];
1058
+ }
1059
+ if (d.labels[0] === label &&
1060
+ (!property || d.properties[property] !== undefined) &&
1061
+ (!value || d.properties[property] === value)) {
1062
+ if (labelPropertyValue.length > imgLevel) {
1063
+ img = this.options.images[imagesForLabel[i]];
1064
+ imgLevel = labelPropertyValue.length;
1065
+ }
1066
+ }
1067
+ }
1068
+ }
1069
+ }
1070
+ return img;
1071
+ }
1072
+ init(_selector, _options) {
1073
+ this.initIconMap();
1074
+ this.merge(this.options, _options);
1075
+ if (this.options.icons) {
1076
+ this.options.showIcons = true;
1077
+ }
1078
+ if (!this.options.minCollision) {
1079
+ this.options.minCollision = this.options.nodeRadius * 2;
1080
+ }
1081
+ this.initImageMap();
1082
+ this.selector = _selector;
1083
+ this.container = d3.select(this.selector);
1084
+ // this.container.attr('class', 'graph-container').html('')
1085
+ if (this.options.infoPanel) {
1086
+ this.info = this.appendInfoPanel(this.container);
1087
+ }
1088
+ this.appendGraph(this.container);
1089
+ this.simulation = this.initSimulation();
1090
+ if (this.options.graphData) {
1091
+ this.loadGraphData();
1092
+ }
1093
+ else if (this.options.dataUrl) {
1094
+ this.loadGraphDataFromUrl(this.options.dataUrl);
1095
+ }
1096
+ else {
1097
+ console.error('Error: both graphData and dataUrl are empty!');
1098
+ }
1099
+ }
1100
+ initIconMap() {
1101
+ Object.keys(this.options.iconMap).forEach((key, index) => {
1102
+ var keys = key.split(','), value = this.options.iconMap[key];
1103
+ keys.forEach(key => {
1104
+ this.options.iconMap[key] = value;
1105
+ });
1106
+ });
1107
+ }
1108
+ initImageMap() {
1109
+ var key, keys, selector;
1110
+ const images = this.options.images;
1111
+ for (key in images) {
1112
+ if (images.hasOwnProperty(key)) {
1113
+ keys = key.split('|');
1114
+ if (!this.options.imageMap[keys[0]]) {
1115
+ this.options.imageMap[keys[0]] = [key];
1116
+ }
1117
+ else {
1118
+ this.options.imageMap[keys[0]].push(key);
1119
+ }
1120
+ }
1121
+ }
1122
+ }
1123
+ initSimulation() {
1124
+ const x = this.svg.node().parentElement.parentElement.clientWidth / 2;
1125
+ const y = this.svg.node().parentElement.parentElement.clientHeight / 2;
1126
+ var simulation = d3
1127
+ .forceSimulation()
1128
+ // .velocityDecay(0.8)
1129
+ // .force('x', d3.force().strength(0.002))
1130
+ // .force('y', d3.force().strength(0.002))
1131
+ .force('collide', d3
1132
+ .forceCollide()
1133
+ .radius(d => {
1134
+ return this.options.minCollision;
1135
+ })
1136
+ .iterations(2))
1137
+ .force('charge', d3.forceManyBody())
1138
+ .force('link', d3.forceLink().id(d => {
1139
+ return d.id;
1140
+ }))
1141
+ .force('center', d3.forceCenter(x, y))
1142
+ .on('tick', () => {
1143
+ this.tick();
1144
+ })
1145
+ .on('end', () => {
1146
+ if (this.options.zoomFit && !this.justLoaded) {
1147
+ this.justLoaded = true;
1148
+ this.zoomFit(2);
1149
+ }
1150
+ });
1151
+ return simulation;
1152
+ }
1153
+ loadGraphData() {
1154
+ this.nodes = [];
1155
+ this.relationships = [];
1156
+ this.updateWithGraphData(this.options.graphData);
1157
+ }
1158
+ loadGraphDataFromUrl(dataUrl) {
1159
+ this.nodes = [];
1160
+ this.relationships = [];
1161
+ d3.json(dataUrl, (error, data) => {
1162
+ if (error) {
1163
+ throw error;
1164
+ }
1165
+ this.updateWithGraphData(data);
1166
+ });
1167
+ }
1168
+ merge(target, source) {
1169
+ Object.keys(source).forEach(property => {
1170
+ target[property] = source[property];
1171
+ });
1172
+ }
1173
+ graphDataToD3Data(data) {
1174
+ var graph = {
1175
+ nodes: [],
1176
+ relationships: []
1177
+ };
1178
+ data.results.forEach(result => {
1179
+ result.data.forEach(data => {
1180
+ data.graph.nodes.forEach(node => {
1181
+ if (!this.contains(graph.nodes, node.id)) {
1182
+ graph.nodes.push(node);
1183
+ }
1184
+ });
1185
+ data.graph.relationships.forEach(function (relationship) {
1186
+ relationship.source = relationship.startNode;
1187
+ relationship.target = relationship.endNode;
1188
+ graph.relationships.push(relationship);
1189
+ });
1190
+ data.graph.relationships.sort(function (a, b) {
1191
+ if (a.source > b.source) {
1192
+ return 1;
1193
+ }
1194
+ else if (a.source < b.source) {
1195
+ return -1;
1196
+ }
1197
+ else {
1198
+ if (a.target > b.target) {
1199
+ return 1;
1200
+ }
1201
+ if (a.target < b.target) {
1202
+ return -1;
1203
+ }
1204
+ else {
1205
+ return 0;
1206
+ }
1207
+ }
1208
+ });
1209
+ for (var i = 0; i < data.graph.relationships.length; i++) {
1210
+ if (i !== 0 &&
1211
+ data.graph.relationships[i].source === data.graph.relationships[i - 1].source &&
1212
+ data.graph.relationships[i].target === data.graph.relationships[i - 1].target) {
1213
+ data.graph.relationships[i].linknum = data.graph.relationships[i - 1].linknum + 1;
1214
+ }
1215
+ else {
1216
+ data.graph.relationships[i].linknum = 1;
1217
+ }
1218
+ }
1219
+ });
1220
+ });
1221
+ return graph;
1222
+ }
1223
+ randomD3Data(d, maxNodesToGenerate) {
1224
+ var data = {
1225
+ nodes: [],
1226
+ relationships: []
1227
+ }, i, label, node, numNodes = ((maxNodesToGenerate * Math.random()) << 0) + 1, relationship, s = this.size();
1228
+ for (i = 0; i < numNodes; i++) {
1229
+ label = this.randomLabel();
1230
+ node = {
1231
+ id: s.nodes + 1 + i,
1232
+ labels: [label],
1233
+ properties: {
1234
+ random: label
1235
+ },
1236
+ x: d.x,
1237
+ y: d.y
1238
+ };
1239
+ data.nodes[data.nodes.length] = node;
1240
+ relationship = {
1241
+ id: s.relationships + 1 + i,
1242
+ type: label.toUpperCase(),
1243
+ startNode: d.id,
1244
+ endNode: s.nodes + 1 + i,
1245
+ properties: {
1246
+ from: Date.now()
1247
+ },
1248
+ source: d.id,
1249
+ target: s.nodes + 1 + i,
1250
+ linknum: s.relationships + 1 + i
1251
+ };
1252
+ data.relationships[data.relationships.length] = relationship;
1253
+ }
1254
+ return data;
1255
+ }
1256
+ randomLabel() {
1257
+ var icons = Object.keys(this.options.iconMap);
1258
+ return icons[(icons.length * Math.random()) << 0];
1259
+ }
1260
+ rotate(cx, cy, x, y, angle) {
1261
+ var radians = (Math.PI / 180) * angle, cos = Math.cos(radians), sin = Math.sin(radians), nx = cos * (x - cx) + sin * (y - cy) + cx, ny = cos * (y - cy) - sin * (x - cx) + cy;
1262
+ return { x: nx, y: ny };
1263
+ }
1264
+ rotatePoint(c, p, angle) {
1265
+ return this.rotate(c.x, c.y, p.x, p.y, angle);
1266
+ }
1267
+ rotation(source, target) {
1268
+ return (Math.atan2(target.y - source.y, target.x - source.x) * 180) / Math.PI;
1269
+ }
1270
+ size() {
1271
+ return {
1272
+ nodes: this.nodes.length,
1273
+ relationships: this.relationships.length
1274
+ };
1275
+ }
1276
+ /*
1277
+ function smoothTransform(elem, translate, scale) {
1278
+ var animationMilliseconds = 5000,
1279
+ timeoutMilliseconds = 50,
1280
+ steps = parseInt(animationMilliseconds / timeoutMilliseconds);
1281
+
1282
+ setTimeout(function() {
1283
+ smoothTransformStep(elem, translate, scale, timeoutMilliseconds, 1, steps);
1284
+ }, timeoutMilliseconds);
1285
+ }
1286
+
1287
+ function smoothTransformStep(elem, translate, scale, timeoutMilliseconds, step, steps) {
1288
+ var progress = step / steps;
1289
+
1290
+ elem.attr('transform', 'translate(' + (translate[0] * progress) + ', ' + (translate[1] * progress) + ') scale(' + (scale * progress) + ')');
1291
+
1292
+ if (step < steps) {
1293
+ setTimeout(function() {
1294
+ smoothTransformStep(elem, translate, scale, timeoutMilliseconds, step + 1, steps);
1295
+ }, timeoutMilliseconds);
1296
+ }
1297
+ }
1298
+ */
1299
+ stickNode(d, event) {
1300
+ d.fx = event.x;
1301
+ d.fy = event.y;
1302
+ }
1303
+ tick() {
1304
+ this.tickNodes();
1305
+ this.tickRelationships();
1306
+ }
1307
+ tickNodes() {
1308
+ if (this.node) {
1309
+ this.node.attr('transform', d => {
1310
+ return 'translate(' + d.x + ', ' + d.y + ')';
1311
+ });
1312
+ }
1313
+ }
1314
+ tickRelationships() {
1315
+ if (this.relationship) {
1316
+ this.relationship.attr('transform', d => {
1317
+ var angle = this.rotation(d.source, d.target);
1318
+ return 'translate(' + d.source.x + ', ' + d.source.y + ') rotate(' + angle + ')';
1319
+ });
1320
+ this.tickRelationshipsTexts();
1321
+ this.tickRelationshipsOutlines();
1322
+ this.tickRelationshipsOverlays();
1323
+ }
1324
+ }
1325
+ tickRelationshipsOutlines() {
1326
+ const self = this;
1327
+ this.relationship.each(function (relationship) {
1328
+ var rel = d3.select(this);
1329
+ var outline = rel.select('.outline'), text = rel.select('.text'), bbox = text.node().getBBox(), padding = 3;
1330
+ outline.attr('d', d => {
1331
+ var center = { x: 0, y: 0 }, angle = self.rotation(d.source, d.target), textBoundingBox = text.node().getBBox(), textPadding = 5, u = self.unitaryVector(d.source, d.target), textMargin = {
1332
+ x: (d.target.x - d.source.x - (textBoundingBox.width + textPadding) * u.x) * 0.5,
1333
+ y: (d.target.y - d.source.y - (textBoundingBox.width + textPadding) * u.y) * 0.5
1334
+ }, n = self.unitaryNormalVector(d.source, d.target), rotatedPointA1 = self.rotatePoint(center, { x: 0 + (self.options.nodeRadius + 1) * u.x - n.x, y: 0 + (self.options.nodeRadius + 1) * u.y - n.y }, angle), rotatedPointB1 = self.rotatePoint(center, { x: textMargin.x - n.x, y: textMargin.y - n.y }, angle), rotatedPointC1 = self.rotatePoint(center, { x: textMargin.x, y: textMargin.y }, angle), rotatedPointD1 = self.rotatePoint(center, { x: 0 + (self.options.nodeRadius + 1) * u.x, y: 0 + (self.options.nodeRadius + 1) * u.y }, angle), rotatedPointA2 = self.rotatePoint(center, { x: d.target.x - d.source.x - textMargin.x - n.x, y: d.target.y - d.source.y - textMargin.y - n.y }, angle), rotatedPointB2 = self.rotatePoint(center, {
1335
+ x: d.target.x - d.source.x - (self.options.nodeRadius + 1) * u.x - n.x - u.x * self.options.arrowSize,
1336
+ y: d.target.y - d.source.y - (self.options.nodeRadius + 1) * u.y - n.y - u.y * self.options.arrowSize
1337
+ }, angle), rotatedPointC2 = self.rotatePoint(center, {
1338
+ x: d.target.x -
1339
+ d.source.x -
1340
+ (self.options.nodeRadius + 1) * u.x -
1341
+ n.x +
1342
+ (n.x - u.x) * self.options.arrowSize,
1343
+ y: d.target.y -
1344
+ d.source.y -
1345
+ (self.options.nodeRadius + 1) * u.y -
1346
+ n.y +
1347
+ (n.y - u.y) * self.options.arrowSize
1348
+ }, angle), rotatedPointD2 = self.rotatePoint(center, {
1349
+ x: d.target.x - d.source.x - (self.options.nodeRadius + 1) * u.x,
1350
+ y: d.target.y - d.source.y - (self.options.nodeRadius + 1) * u.y
1351
+ }, angle), rotatedPointE2 = self.rotatePoint(center, {
1352
+ x: d.target.x - d.source.x - (self.options.nodeRadius + 1) * u.x + (-n.x - u.x) * self.options.arrowSize,
1353
+ y: d.target.y - d.source.y - (self.options.nodeRadius + 1) * u.y + (-n.y - u.y) * self.options.arrowSize
1354
+ }, angle), rotatedPointF2 = self.rotatePoint(center, {
1355
+ x: d.target.x - d.source.x - (self.options.nodeRadius + 1) * u.x - u.x * self.options.arrowSize,
1356
+ y: d.target.y - d.source.y - (self.options.nodeRadius + 1) * u.y - u.y * self.options.arrowSize
1357
+ }, angle), rotatedPointG2 = self.rotatePoint(center, { x: d.target.x - d.source.x - textMargin.x, y: d.target.y - d.source.y - textMargin.y }, angle);
1358
+ return ('M ' +
1359
+ rotatedPointA1.x +
1360
+ ' ' +
1361
+ rotatedPointA1.y +
1362
+ ' L ' +
1363
+ rotatedPointB1.x +
1364
+ ' ' +
1365
+ rotatedPointB1.y +
1366
+ ' L ' +
1367
+ rotatedPointC1.x +
1368
+ ' ' +
1369
+ rotatedPointC1.y +
1370
+ ' L ' +
1371
+ rotatedPointD1.x +
1372
+ ' ' +
1373
+ rotatedPointD1.y +
1374
+ ' Z M ' +
1375
+ rotatedPointA2.x +
1376
+ ' ' +
1377
+ rotatedPointA2.y +
1378
+ ' L ' +
1379
+ rotatedPointB2.x +
1380
+ ' ' +
1381
+ rotatedPointB2.y +
1382
+ ' L ' +
1383
+ rotatedPointC2.x +
1384
+ ' ' +
1385
+ rotatedPointC2.y +
1386
+ ' L ' +
1387
+ rotatedPointD2.x +
1388
+ ' ' +
1389
+ rotatedPointD2.y +
1390
+ ' L ' +
1391
+ rotatedPointE2.x +
1392
+ ' ' +
1393
+ rotatedPointE2.y +
1394
+ ' L ' +
1395
+ rotatedPointF2.x +
1396
+ ' ' +
1397
+ rotatedPointF2.y +
1398
+ ' L ' +
1399
+ rotatedPointG2.x +
1400
+ ' ' +
1401
+ rotatedPointG2.y +
1402
+ ' Z');
1403
+ });
1404
+ });
1405
+ }
1406
+ tickRelationshipsOverlays() {
1407
+ this.relationshipOverlay.attr('d', d => {
1408
+ var center = { x: 0, y: 0 }, angle = this.rotation(d.source, d.target), n1 = this.unitaryNormalVector(d.source, d.target), n = this.unitaryNormalVector(d.source, d.target, 50), rotatedPointA = this.rotatePoint(center, { x: 0 - n.x, y: 0 - n.y }, angle), rotatedPointB = this.rotatePoint(center, { x: d.target.x - d.source.x - n.x, y: d.target.y - d.source.y - n.y }, angle), rotatedPointC = this.rotatePoint(center, { x: d.target.x - d.source.x + n.x - n1.x, y: d.target.y - d.source.y + n.y - n1.y }, angle), rotatedPointD = this.rotatePoint(center, { x: 0 + n.x - n1.x, y: 0 + n.y - n1.y }, angle);
1409
+ return ('M ' +
1410
+ rotatedPointA.x +
1411
+ ' ' +
1412
+ rotatedPointA.y +
1413
+ ' L ' +
1414
+ rotatedPointB.x +
1415
+ ' ' +
1416
+ rotatedPointB.y +
1417
+ ' L ' +
1418
+ rotatedPointC.x +
1419
+ ' ' +
1420
+ rotatedPointC.y +
1421
+ ' L ' +
1422
+ rotatedPointD.x +
1423
+ ' ' +
1424
+ rotatedPointD.y +
1425
+ ' Z');
1426
+ });
1427
+ }
1428
+ tickRelationshipsTexts() {
1429
+ this.relationshipText.attr('transform', d => {
1430
+ var angle = (this.rotation(d.source, d.target) + 360) % 360, mirror = angle > 90 && angle < 270, center = { x: 0, y: 0 }, n = this.unitaryNormalVector(d.source, d.target), nWeight = mirror ? 2 : -3, point = {
1431
+ x: (d.target.x - d.source.x) * 0.5 + n.x * nWeight,
1432
+ y: (d.target.y - d.source.y) * 0.5 + n.y * nWeight
1433
+ }, rotatedPoint = this.rotatePoint(center, point, angle);
1434
+ return 'translate(' + rotatedPoint.x + ', ' + rotatedPoint.y + ') rotate(' + (mirror ? 180 : 0) + ')';
1435
+ });
1436
+ }
1437
+ toString(d) {
1438
+ var s = d.labels ? d.labels[0] : d.type;
1439
+ s += ' (<id>: ' + d.id;
1440
+ Object.keys(d.properties).forEach(function (property) {
1441
+ s += ', ' + property + ': ' + JSON.stringify(d.properties[property]);
1442
+ });
1443
+ s += ')';
1444
+ return s;
1445
+ }
1446
+ unitaryNormalVector(source, target, newLength) {
1447
+ var center = { x: 0, y: 0 }, vector = this.unitaryVector(source, target, newLength);
1448
+ return this.rotatePoint(center, vector, 90);
1449
+ }
1450
+ unitaryVector(source, target, newLength) {
1451
+ var length = Math.sqrt(Math.pow(target.x - source.x, 2) + Math.pow(target.y - source.y, 2)) / Math.sqrt(newLength || 1);
1452
+ return {
1453
+ x: (target.x - source.x) / length,
1454
+ y: (target.y - source.y) / length
1455
+ };
1456
+ }
1457
+ updateWithD3Data(d3Data) {
1458
+ this.updateNodesAndRelationships(d3Data.nodes, d3Data.relationships);
1459
+ }
1460
+ updateWithGraphData(graphData) {
1461
+ var d3Data = this.graphDataToD3Data(graphData);
1462
+ this.updateWithD3Data(d3Data);
1463
+ }
1464
+ updateInfo(d) {
1465
+ this.clearInfo();
1466
+ if (d.labels) {
1467
+ this.appendInfoElementClass('class', d.labels[0]);
1468
+ }
1469
+ else {
1470
+ this.appendInfoElementRelationship('class', d.type);
1471
+ }
1472
+ this.appendInfoElementProperty('property', '&lt;id&gt;', d.id);
1473
+ Object.keys(d.properties).forEach(property => {
1474
+ this.appendInfoElementProperty('property', property, JSON.stringify(d.properties[property]));
1475
+ });
1476
+ }
1477
+ updateNodes(n) {
1478
+ Array.prototype.push.apply(this.nodes, n);
1479
+ this.node = this.svgNodes.selectAll('.node').data(this.nodes, d => {
1480
+ return d.id;
1481
+ });
1482
+ var nodeEnter = this.appendNodeToGraph();
1483
+ this.node = nodeEnter.merge(this.node);
1484
+ }
1485
+ updateNodesAndRelationships(n, r) {
1486
+ this.updateRelationships(r);
1487
+ this.updateNodes(n);
1488
+ this.simulation.nodes(this.nodes);
1489
+ this.simulation.force('link').links(this.relationships);
1490
+ }
1491
+ updateRelationships(r) {
1492
+ Array.prototype.push.apply(this.relationships, r);
1493
+ this.relationship = this.svgRelationships.selectAll('.relationship').data(this.relationships, d => {
1494
+ return d.id;
1495
+ });
1496
+ var relationshipEnter = this.appendRelationshipToGraph();
1497
+ this.relationship = relationshipEnter.relationship.merge(this.relationship);
1498
+ this.relationshipOutline = this.svg.selectAll('.relationship .outline');
1499
+ this.relationshipOutline = relationshipEnter.outline.merge(this.relationshipOutline);
1500
+ this.relationshipOverlay = this.svg.selectAll('.relationship .overlay');
1501
+ this.relationshipOverlay = relationshipEnter.overlay.merge(this.relationshipOverlay);
1502
+ this.relationshipText = this.svg.selectAll('.relationship .text');
1503
+ this.relationshipText = relationshipEnter.text.merge(this.relationshipText);
1504
+ }
1505
+ zoomFit(transitionDuration) {
1506
+ var bounds = this.svg.node().getBBox(), parent = this.svg.node().parentElement.parentElement, fullWidth = parent.clientWidth, fullHeight = parent.clientHeight, width = bounds.width, height = bounds.height, midX = bounds.x + width / 2, midY = bounds.y + height / 2;
1507
+ if (width === 0 || height === 0) {
1508
+ return; // nothing to fit
1509
+ }
1510
+ this.svgScale = 0.85 / Math.max(width / fullWidth, height / fullHeight);
1511
+ this.svgTranslate = [fullWidth / 2 - this.svgScale * midX, fullHeight / 2 - this.svgScale * midY];
1512
+ this.svg.attr('transform', 'translate(' + this.svgTranslate[0] + ', ' + this.svgTranslate[1] + ') scale(' + this.svgScale + ')');
1513
+ // smoothTransform(this.svgTranslate, this.svgScale);
1514
+ }
1515
+ }
1516
+ //# sourceMappingURL=graph-viewer.js.map