Merge "vnf-id Data Dictionary source has circular dependendy."
[ccsdk/cds.git] / cds-ui / client / JointJS-POC-In-Progress / app.component.ts
1 declare var require: any
2 import { Component, OnInit } from '@angular/core';
3 import * as $ from 'jquery';
4 import * as _ from 'lodash';
5 const joint = require('../../node_modules/jointjs/dist/joint.js');
6
7
8 @Component({
9   selector: 'app-root',
10   templateUrl: './app.component.html',
11   styleUrls: ['./app.component.scss']
12 })
13 export class AppComponent implements OnInit {
14   title = 'jointJS-designer';
15
16   public graph: any;
17   public paper: any;
18   public rect: any;
19   public rect2: any;
20   public link: any;
21
22   public stencilGraph: any;
23   public stencilPaper: any;
24
25   public selectedElement = {
26     attributes: {
27       attrs: {
28         label: {
29           text: 'abc'
30         }
31       }
32     }
33   };
34
35   grapJson: any;
36   sourceMode = false;
37
38   constructor() {
39
40   }
41
42   ngOnInit() {
43     // this.creatElementWithPorts();
44     // this.dragCopyPlainElements();
45     this.sourceMode = false;
46     this.dragCopyElementsWithPort();
47     // this.newDragCopy();
48
49     this.createContainerElements();
50   }
51
52   creatElementWithPorts() {
53     // working code
54
55     // create graph
56     let elementList: any[] = [];
57     // this.graph = new joint.dia.Graph;
58
59     // // create paper
60     // this.paper = new joint.dia.Paper({
61     //   el: document.getElementById('paper'),
62     //   width: 1000,
63     //   height: 1000,
64     //   model: this.graph,
65     //   gridSize: 2,
66     //   drawGrid: true
67     // });
68
69     // this.paper.setGrid({
70     //   name: 'dot',
71     //   args:
72     //     { color: 'black', thickness: 2, scaleFactor: 8 }
73
74     // }).drawGrid();
75
76     // create element
77     this.rect = new joint.shapes.basic.Rect({
78       position: { x: 100, y: 30 },
79       size: { width: 100, height: 100 },
80       attrs: { rect: { fill: 'white' }, text: { text: 'my box', fill: 'white' } }
81     });
82     this.rect.translate(100, 50);
83     elementList.push(this.rect);
84
85     this.rect.position(10, 10);
86     // clone element
87     // this.rect2 = this.rect.clone();
88     // this.rect2.translate(180);
89     // elementList.push(this.rect2);
90
91     // Create link
92     // this.link = new joint.dia.Link({
93     //   source: { id: this.rect.id },
94     //   target: { id: this.rect2.id }
95     // });
96
97
98     // create circle
99     var circle = new joint.shapes.standard.Circle();
100     circle.resize(100, 100);
101     circle.position(180, 10);
102     circle.attr('root/title', 'joint.shapes.standard.Circle');
103     circle.attr('label/text', 'Circle');
104     circle.attr('body/fill', 'lightblue');
105     elementList.push(circle);
106
107     // create link
108     var ellipse = new joint.shapes.standard.Ellipse();
109     ellipse.resize(150, 100);
110     ellipse.position(180, 150);
111     ellipse.attr('root/title', 'joint.shapes.standard.Ellipse');
112     ellipse.attr('label/text', 'Ellipse');
113     ellipse.attr('body/fill', 'lightblue');
114     elementList.push(ellipse);
115
116     // rectangle with header
117     var headeredRectangle = new joint.shapes.standard.HeaderedRectangle();
118     headeredRectangle.resize(150, 100);
119     headeredRectangle.position(10, 280);
120     headeredRectangle.attr('root/title', 'joint.shapes.standard.HeaderedRectangle');
121     headeredRectangle.attr('header/fill', 'lightgray');
122     headeredRectangle.attr('headerText/text', 'Header');
123     headeredRectangle.attr('bodyText/text', 'Headered\nRectangle');
124     elementList.push(headeredRectangle);
125
126     let m1 = new joint.shapes.devs.Model({
127       position: { x: 200, y: 280 },
128       size: { width: 90, height: 90 },
129       inPorts: ['in1', 'in2'],
130       outPorts: ['out', 'out2'],
131       ports: {
132         groups: {
133           'in': {
134             attrs: {
135               '.port-body': {
136                 fill: '#16A085'
137               }
138             }
139           },
140           'out': {
141             attrs: {
142               '.port-body': {
143                 fill: '#E74C3C'
144               }
145             }
146           }
147         }
148       },
149       attrs: {
150         '.label': { text: 'Model', 'ref-x': .5, 'ref-y': .2 },
151         rect: { fill: 'white' }
152       }
153     });
154     elementList.push(m1);
155
156     //container element
157     let c1 = new joint.shapes.devs.Coupled({
158       position: {
159           x: 150,
160           y: 470
161       },
162       size: {
163           width: 200,
164           height: 200
165       }
166     });
167
168     c1.set('inPorts', ['in']);
169   c1.set('outPorts', ['out 1', 'out 2']);
170   c1.attr({
171     '.body': {
172         'rx': 6,
173         'ry': 6
174     }
175 });
176   elementList.push(c1);
177   // circle.position(10, 150);
178   var a1 = new joint.shapes.devs.Atomic({
179     position: {
180         x: 10,
181         y: 150
182     },
183     inPorts: ['xy'],
184     outPorts: ['x', 'y']
185   });
186
187   a1.attr({
188     '.body': {
189         'rx': 6,
190         'ry': 6
191     }
192   });
193
194   elementList.push(a1);
195
196     
197     return elementList;
198   }
199
200   dragCopyPlainElements() {
201     // Canvas where sape are dropped
202     this.graph = new joint.dia.Graph,
203       this.paper = new joint.dia.Paper({
204         el: $('#paper'),
205         model: this.graph
206       });
207
208     // Canvas from which you take shapes
209     this.stencilGraph = new joint.dia.Graph,
210       this.stencilPaper = new joint.dia.Paper({
211         el: $('#stencil'),
212         height: 60,
213         model: this.stencilGraph,
214         interactive: false
215       });
216
217     var r1 = new joint.shapes.basic.Rect({
218       position: {
219         x: 10,
220         y: 10
221       },
222       size: {
223         width: 100,
224         height: 40
225       },
226       attrs: {
227         text: {
228           text: 'Rect1'
229         }
230       }
231     });
232     var r2 = new joint.shapes.basic.Rect({
233       position: {
234         x: 120,
235         y: 10
236       },
237       size: {
238         width: 100,
239         height: 40
240       },
241       attrs: {
242         text: {
243           text: 'Rect2'
244         }
245       }
246     });
247     this.stencilGraph.addCells([r1, r2]);
248
249     let _this = this;
250
251     this.stencilPaper.on('cell:pointerdown', function (cellView, e, x, y) {
252       $('body').append('<div id="flyPaper" style="position:fixed;z-index:100;opacity:.7;pointer-event:none;"></div>');
253       var flyGraph = new joint.dia.Graph,
254         flyPaper = new joint.dia.Paper({
255           el: $('#flyPaper'),
256           model: flyGraph,
257           interactive: false
258         }),
259         flyShape = cellView.model.clone(),
260         pos = cellView.model.position(),
261         offset = {
262           x: x - pos.x,
263           y: y - pos.y
264         };
265
266       flyShape.position(0, 0);
267       flyGraph.addCell(flyShape);
268       $("#flyPaper").offset({
269         left: e.pageX - offset.x,
270         top: e.pageY - offset.y
271       });
272       $('body').on('mousemove.fly', function (e) {
273         $("#flyPaper").offset({
274           left: e.pageX - offset.x,
275           top: e.pageY - offset.y
276         });
277       });
278       $('body').on('mouseup.fly', function (e) {
279         var x = e.pageX,
280           y = e.pageY,
281           target = _this.paper.$el.offset();
282
283         // Dropped over paper ?
284         if (x > target.left && x < target.left + _this.paper.$el.width() && y > target.top && y < target.top + _this.paper.$el.height()) {
285           var s = flyShape.clone();
286           s.position(x - target.left - offset.x, y - target.top - offset.y);
287           _this.graph.addCell(s);
288         }
289         $('body').off('mousemove.fly').off('mouseup.fly');
290         flyShape.remove();
291         $('#flyPaper').remove();
292       });
293     })
294   }
295
296   dragCopyElementsWithPort() {
297     // Canvas where sape are dropped
298     
299     this.graph = new joint.dia.Graph,
300       this.paper = new joint.dia.Paper({
301         el: $('#paper'),
302         model: this.graph,
303         height: 700,
304         width: 1000,
305         gridSize: 2,
306         drawGrid: true
307       });
308
309     // create paper
310     // this.paper = new joint.dia.Paper({
311     //   el: document.getElementById('paper'),
312     //   width: 1000,
313     //   height: 1000,
314     //   model: this.graph,
315     //   gridSize: 2,
316     //   drawGrid: true
317     // });
318
319     this.paper.setGrid({
320       name: 'dot',
321       args:
322         { color: 'black', thickness: 2, scaleFactor: 8 }
323
324     }).drawGrid();
325
326     // Canvas from which you take shapes
327     this.stencilGraph = new joint.dia.Graph,
328       this.stencilPaper = new joint.dia.Paper({
329         el: $('#stencil'),
330         height: 700,
331         width: 382,
332         model: this.stencilGraph,
333         interactive: false
334       });      
335     
336       let elementWithPort = this.creatElementWithPorts();
337       // let elementWithPort = this.createCustomElement();
338       // let elementWithPort = this.myCustomElementGenerator();
339
340       
341     
342     elementWithPort.forEach(element => {
343       this.stencilGraph.addCell(element);
344     });
345     
346     let _this = this;
347     this.stencilPaperEventListeners(_this);
348     this.drawAreapaperEventListerners();
349   }
350
351   resetAll(paper) {
352     this.paper.drawBackground({
353       color: 'white'
354     })
355
356     var elements = this.paper.model.getElements();
357     for (var i = 0, ii = elements.length; i < ii; i++) {
358       var currentElement = elements[i];
359       currentElement.attr('body/stroke', 'black');
360     }
361
362     var links = this.paper.model.getLinks();
363     for (var j = 0, jj = links.length; j < jj; j++) {
364       var currentLink = links[j];
365       currentLink.attr('line/stroke', 'black');
366       currentLink.label(0, {
367         attrs: {
368           body: {
369             stroke: 'black'
370           }
371         }
372       })
373     }
374   }
375
376   onDrag(evt) {
377     // transform client to paper coordinates
378     var p = evt.data.paper.snapToGrid({
379       x: evt.clientX,
380       y: evt.clientY
381     });
382     // manually execute the linkView mousemove handler
383     evt.data.view.pointermove(evt, p.x, p.y);
384   }
385
386   onDragEnd(evt) {
387     // manually execute the linkView mouseup handler
388     evt.data.view.pointerup(evt);
389     $(document).off('.example');
390   }
391
392   stencilPaperEventListeners(_this) {
393     this.stencilPaper.on('cell:pointerdown', function (cellView, e, x, y) {
394       $('body').append('<div id="flyPaper" style="position:fixed;z-index:100;opacity:.7;pointer-event:none;"></div>');
395       var flyGraph = new joint.dia.Graph,
396         flyPaper = new joint.dia.Paper({
397           el: $('#flyPaper'),
398           model: flyGraph,
399           interactive: true
400         }),
401         flyShape = cellView.model.clone(),
402         pos = cellView.model.position(),
403         offset = {
404           x: x - pos.x,
405           y: y - pos.y
406         };
407
408       flyShape.position(0, 0);
409       flyGraph.addCell(flyShape);
410       $("#flyPaper").offset({
411         left: e.pageX - offset.x,
412         top: e.pageY - offset.y
413       });
414       $('body').on('mousemove.fly', function (e) {
415         $("#flyPaper").offset({
416           left: e.pageX - offset.x,
417           top: e.pageY - offset.y
418         });
419       });
420       let elementabove, elementBelow;
421       $('body').on('mouseup.fly', function (e) {
422         console.log(this);        
423         var x = e.pageX,
424           y = e.pageY,
425           target = _this.paper.$el.offset();
426
427         // Dropped over paper ?
428         if (x > target.left && x < target.left + _this.paper.$el.width() && y > target.top && y < target.top + _this.paper.$el.height()) {
429           var s = flyShape.clone();
430
431           // var coordinates = new g.Point(x, y);
432           // elementabove = s;
433           // elementBelow =  _this.paper.model.findModelsFromPoint(coordinates).find(function(el) {
434           //   return (el.id !== elementabove.id);
435           // });
436           // elementBelow =_this.paper.findModelsFromPoint(coordinates).find(function(el) {
437           //     return (el.id !== elementabove.id);
438           //   });
439           // elementBelow.embed(elementabove);
440
441           s.position(x - target.left - offset.x, y - target.top - offset.y);
442           _this.graph.addCell(s);
443           // let elementssss = (_this.graph.getElements());
444           // console.log("elementsss", elementssss);
445           // let elementBelow = elementssss[0];
446           // let elementAbove;
447           // if(elementssss[1]) {
448           //   elementAbove = elementssss[1];
449           //   elementBelow.embed(elementabove);
450           // }
451         }
452         $('body').off('mousemove.fly').off('mouseup.fly');
453         flyShape.remove();
454         $('#flyPaper').remove();
455       });
456       _this.paper.on('mouse')
457     })
458   }
459
460   drawAreapaperEventListerners() {
461     // create event listerners
462     let _this = this;
463     this.paper.on('element:pointerdblclick', function (elementView) {
464       _this.resetAll(this);
465       _this.selectedElement = elementView.model;
466       var currentElement = elementView.model;
467       currentElement.attr('body/stroke', 'orange');
468       // currentElement.attr('label/text', "abc");
469     });
470
471     this.paper.on('blank:pointerdblclick', function () {
472       _this.resetAll(this);
473
474       this.drawBackground({
475         color: 'orange'
476       });
477     });
478
479     this.paper.on('link:pointerclick', function (linkView) {
480       _this.resetAll(this);
481       let currentElement = linkView.model;
482       currentElement.appendLabel({
483         attrs: {
484           text: {
485             text: "Hello to new link!"
486           }
487         }
488       });
489
490     });
491
492
493     this.paper.on('blank:pointerdown', function (evt, x, y) {
494       let linkView = this.getDefaultLink()
495         .set({
496           'source': { x: x, y: y },
497           'target': { x: x, y: y }
498         })
499         .addTo(this.model)
500         .findView(this);
501       linkView.startArrowheadMove('target');
502
503       $(document).on({
504         'mousemove.example': _this.onDrag,
505         'mouseup.example': _this.onDragEnd
506       }, {
507           // shared data between listeners
508           view: linkView,
509           paper: this
510         });
511     });
512
513     this.paper.on({
514       // 'element:pointerdown': function(elementView, evt) {
515
516       //   evt.data = elementView.model.position();
517       // },
518       'element:pointerup': function(elementView, evt, x, y) {
519         var coordinates = new g.Point(x, y);
520         var elementAbove = elementView.model;
521         var elementBelow = this.model.findModelsFromPoint(coordinates).find(function(el) {
522                 return (el.id !== elementAbove.id);
523             });
524         if(elementBelow) elementBelow.embed(elementAbove);
525       }
526
527     }); //end of my event
528   }
529
530   createCustomElement() {
531     joint.shapes.html = {};
532     joint.shapes.html.Element = joint.shapes.basic.Rect.extend({
533       defaults: joint.util.deepSupplement({
534           type: 'html.Element',
535           attrs: {
536               rect: { stroke: 'none', 'fill-opacity': 0 }
537           }
538       }, joint.shapes.basic.Rect.prototype.defaults)
539     });
540
541     // / Create a custom view for that element that displays an HTML div above it.
542     // -------------------------------------------------------------------------
543
544     joint.shapes.html.ElementView = joint.dia.ElementView.extend({
545
546           template: [
547             '<div class="html-element">',
548             '<button class="delete">x</button>',
549             '<label></label>',
550             '<span></span>', '<br/>',
551             '<select><option>--</option><option>one</option><option>two</option></select>',
552             '<input type="text" value="I\'m HTML input" />',
553             '</div>'
554         ].join(''),
555
556         initialize: function() {
557           _.bindAll(this, 'updateBox');
558           joint.dia.ElementView.prototype.initialize.apply(this, arguments);
559
560           this.$box = $(_.template(this.template)());
561           // Prevent paper from handling pointerdown.
562           this.$box.find('input,select').on('mousedown click', function(evt) {
563               evt.stopPropagation();
564           });
565           // This is an example of reacting on the input change and storing the input data in the cell model.
566           this.$box.find('input').on('change', _.bind(function(evt) {
567               this.model.set('input', $(evt.target).val());
568           }, this));
569           this.$box.find('select').on('change', _.bind(function(evt) {
570               this.model.set('select', $(evt.target).val());
571           }, this));
572           this.$box.find('select').val(this.model.get('select'));
573           this.$box.find('.delete').on('click', _.bind(this.model.remove, this.model));
574           // Update the box position whenever the underlying model changes.
575           this.model.on('change', this.updateBox, this);
576           // Remove the box when the model gets removed from the graph.
577           this.model.on('remove', this.removeBox, this);
578
579           this.updateBox();
580         },
581
582         render: function() {
583           joint.dia.ElementView.prototype.render.apply(this, arguments);
584           this.paper.$el.prepend(this.$box);
585           this.updateBox();
586           return this;
587         },
588
589       updateBox: function() {
590         // Set the position and dimension of the box so that it covers the JointJS element.
591         var bbox = this.model.getBBox();
592         // Example of updating the HTML with a data stored in the cell model.
593         this.$box.find('label').text(this.model.get('label'));
594         this.$box.find('span').text(this.model.get('select'));
595         this.$box.css({
596             width: bbox.width,
597             height: bbox.height,
598             left: bbox.x,
599             top: bbox.y,
600             transform: 'rotate(' + (this.model.get('angle') || 0) + 'deg)'
601         });
602       },
603
604       removeBox: function(evt) {
605         this.$box.remove();
606       }
607     });
608
609     // Create JointJS elements and add them to the graph as usual.
610         // -----------------------------------------------------------
611
612         var el1 = new joint.shapes.html.Element({
613           position: { x: 10, y: 10 },
614           size: { width: 170, height: 100 },
615           label: 'I am HTML',
616           select: 'one'
617       });
618
619       var el2 = new joint.shapes.html.Element({
620         position: { x: 370, y: 160 },
621         size: { width: 170, height: 100 },
622         label: 'Me too',
623         select: 'two'
624     });
625     var l = new joint.dia.Link({
626         source: { id: el1.id },
627         target: { id: el2.id },
628         attrs: { '.connection': { 'stroke-width': 5, stroke: '#34495E' }}
629     });
630
631     let elementArray : any[] = [];
632     elementArray.push(el1, el2);
633     return elementArray;
634   }
635
636   myCustomElementGenerator() {
637     var Ellipse = joint.dia.Element.define('examples.Ellipse', {
638       // default attributes
639       markup: [{
640           tagName: 'ellipse',
641           selector: 'ellipse' // not necessary but faster
642       }],
643       attrs: {
644           ellipse: {
645               fill: 'white',
646               stroke: 'black',
647               strokeWidth: 4,
648               refRx: .5,
649               refRy: .5,
650               refCx: .5,
651               refCy: .5
652           }
653       }
654   });
655
656     var Rectangle = joint.shapes.standard.Rectangle.define('examples.CustomRectangle', {
657       markup: [{
658         tagName: 'body',
659         selector: 'body' // not necessary but faster
660       },
661       {
662         tagName: 'label',
663         selector: 'label'
664       }],
665       attrs: {
666         body: {
667           rx: 10, // add a corner radius
668           ry: 10,
669           strokeWidth: 1,
670           fill: 'cornflowerblue'
671         },
672         label: {
673           textAnchor: 'left', // align text to left
674           refX: 10, // offset text from right edge of model bbox
675           fill: 'white',
676           fontSize: 18,
677           text: 'mad mad mad'
678         }
679       }
680     })
681   
682
683   var customElement = (new joint.dia.Element.examples.Ellipse()).position(100, 100).size(120, 50);
684     let elementsArray = [];
685     elementsArray.push(customElement);
686
687   var customRect = new Rectangle().position(100, 200).size(120, 120);
688   elementsArray.push(customRect);
689     return elementsArray;
690   }
691
692   convertGraphToJson() {
693     this.grapJson = JSON.stringify(this.graph.toJSON());
694     // this.grapJson = this.graph.toJSON();
695     console.log(this.graph.toJSON());
696     console.log(this.grapJson);
697     this.sourceMode = true;
698   }
699
700   setNewValue(event) {
701     // this.selectedElement.attr('label/text', event.currentTarget.value);
702   }
703
704   convertJsonToGraph() {
705     this.sourceMode = false;
706   }
707
708   zoomIn() {
709     var graphScale = 1;
710     graphScale += 0.1;
711     this.paper.scale(graphScale, graphScale);
712   }
713
714   zoomOut() {
715     var graphScale = 1;
716     graphScale -= 0.1;
717     this.paper.scale(graphScale, graphScale);
718   }
719
720   createContainerElements() {
721     this.graph = new joint.dia.Graph;
722
723     this.paper = new joint.dia.Paper({
724
725       el: document.getElementById('paper'),
726       width: 800,
727       height: 400,
728       gridSize: 1,
729       model: this.graph,
730       snapLinks: true,
731       linkPinning: false,
732       embeddingMode: true,
733       clickThreshold: 5,
734       defaultConnectionPoint: { name: 'boundary' },
735       highlighting: {
736           'default': {
737               name: 'stroke',
738               options: {
739                   padding: 6
740               }
741           },
742           'embedding': {
743               name: 'addClass',
744               options: {
745                   className: 'highlighted-parent'
746               }
747           }
748       },
749   
750       validateEmbedding: function(childView, parentView) {
751           return parentView.model instanceof joint.shapes.devs.Coupled;
752       },
753   
754       validateConnection: function(sourceView, sourceMagnet, targetView, targetMagnet) {
755           return sourceMagnet != targetMagnet;
756       }
757   });
758
759   let c1 = new joint.shapes.devs.Coupled({
760     position: {
761         x: 230,
762         y: 50
763     },
764     size: {
765         width: 300,
766         height: 300
767     }
768 });
769
770 c1.set('inPorts', ['in']);
771 c1.set('outPorts', ['out 1', 'out 2']);
772
773 var a1 = new joint.shapes.devs.Atomic({
774   position: {
775       x: 360,
776       y: 260
777   },
778   inPorts: ['xy'],
779   outPorts: ['x', 'y']
780 });
781
782 var a2 = new joint.shapes.devs.Atomic({
783   position: {
784       x: 50,
785       y: 160
786   },
787   outPorts: ['out']
788 });
789
790 var a3 = new joint.shapes.devs.Atomic({
791   position: {
792       x: 650,
793       y: 50
794   },
795   size: {
796       width: 100,
797       height: 300
798   },
799   inPorts: ['a', 'b']
800 });
801
802 [c1, a1, a2, a3].forEach(function(element) {
803   element.attr({
804       '.body': {
805           'rx': 6,
806           'ry': 6
807       }
808   });
809 });
810
811
812
813 this.graph.addCells([c1, a1, a2, a3]);
814
815 c1.embed(a1);
816
817 this.connect(a2, 'out', c1, 'in');
818 this.connect(c1, 'in', a1, 'xy');
819 this.connect(a1, 'x', c1, 'out 1');
820 this.connect(a1, 'y', c1, 'out 2');
821 this.connect(c1, 'out 1', a3, 'a');
822 this.connect(c1, 'out 2', a3, 'b');
823
824 var strokeDasharrayPath = '.body/strokeDasharray';
825 let _this = this;
826
827 this.paper.on('element:pointerdblclick', function(elementView) {
828     var element = elementView.model;
829     if (element.get('type') === 'devs.Atomic') {
830       _this.toggleDelegation(element);
831     }
832 });
833
834 this.paper.setInteractivity(function(elementView) {
835     return {
836         stopDelegation: !elementView.model.attr(strokeDasharrayPath)
837     };
838 });
839
840   
841 } // function end
842
843   // function
844   connect(source, sourcePort, target, targetPort) {
845
846     var link = new joint.shapes.devs.Link({
847         source: {
848             id: source.id,
849             port: sourcePort
850         },
851         target: {
852             id: target.id,
853             port: targetPort
854         }
855     });
856
857     link.addTo(this.graph).reparent();
858   }
859
860   toggleDelegation(element) {
861     var strokeDasharrayPath = '.body/strokeDasharray';
862     element.attr(strokeDasharrayPath, element.attr(strokeDasharrayPath) ? '' : '15,1');
863 }
864
865 createContainerElemnetsByDragDrop() {
866   
867
868 }
869 }