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');
10 templateUrl: './app.component.html',
11 styleUrls: ['./app.component.scss']
13 export class AppComponent implements OnInit {
14 title = 'jointJS-designer';
22 public stencilGraph: any;
23 public stencilPaper: any;
25 public selectedElement = {
43 // this.creatElementWithPorts();
44 // this.dragCopyPlainElements();
45 this.sourceMode = false;
46 this.dragCopyElementsWithPort();
47 // this.newDragCopy();
49 this.createContainerElements();
52 creatElementWithPorts() {
56 let elementList: any[] = [];
57 // this.graph = new joint.dia.Graph;
60 // this.paper = new joint.dia.Paper({
61 // el: document.getElementById('paper'),
69 // this.paper.setGrid({
72 // { color: 'black', thickness: 2, scaleFactor: 8 }
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' } }
82 this.rect.translate(100, 50);
83 elementList.push(this.rect);
85 this.rect.position(10, 10);
87 // this.rect2 = this.rect.clone();
88 // this.rect2.translate(180);
89 // elementList.push(this.rect2);
92 // this.link = new joint.dia.Link({
93 // source: { id: this.rect.id },
94 // target: { id: this.rect2.id }
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);
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);
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);
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'],
150 '.label': { text: 'Model', 'ref-x': .5, 'ref-y': .2 },
151 rect: { fill: 'white' }
154 elementList.push(m1);
157 let c1 = new joint.shapes.devs.Coupled({
168 c1.set('inPorts', ['in']);
169 c1.set('outPorts', ['out 1', 'out 2']);
176 elementList.push(c1);
177 // circle.position(10, 150);
178 var a1 = new joint.shapes.devs.Atomic({
194 elementList.push(a1);
200 dragCopyPlainElements() {
201 // Canvas where sape are dropped
202 this.graph = new joint.dia.Graph,
203 this.paper = new joint.dia.Paper({
208 // Canvas from which you take shapes
209 this.stencilGraph = new joint.dia.Graph,
210 this.stencilPaper = new joint.dia.Paper({
213 model: this.stencilGraph,
217 var r1 = new joint.shapes.basic.Rect({
232 var r2 = new joint.shapes.basic.Rect({
247 this.stencilGraph.addCells([r1, r2]);
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({
259 flyShape = cellView.model.clone(),
260 pos = cellView.model.position(),
266 flyShape.position(0, 0);
267 flyGraph.addCell(flyShape);
268 $("#flyPaper").offset({
269 left: e.pageX - offset.x,
270 top: e.pageY - offset.y
272 $('body').on('mousemove.fly', function (e) {
273 $("#flyPaper").offset({
274 left: e.pageX - offset.x,
275 top: e.pageY - offset.y
278 $('body').on('mouseup.fly', function (e) {
281 target = _this.paper.$el.offset();
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);
289 $('body').off('mousemove.fly').off('mouseup.fly');
291 $('#flyPaper').remove();
296 dragCopyElementsWithPort() {
297 // Canvas where sape are dropped
299 this.graph = new joint.dia.Graph,
300 this.paper = new joint.dia.Paper({
310 // this.paper = new joint.dia.Paper({
311 // el: document.getElementById('paper'),
314 // model: this.graph,
322 { color: 'black', thickness: 2, scaleFactor: 8 }
326 // Canvas from which you take shapes
327 this.stencilGraph = new joint.dia.Graph,
328 this.stencilPaper = new joint.dia.Paper({
332 model: this.stencilGraph,
336 let elementWithPort = this.creatElementWithPorts();
337 // let elementWithPort = this.createCustomElement();
338 // let elementWithPort = this.myCustomElementGenerator();
342 elementWithPort.forEach(element => {
343 this.stencilGraph.addCell(element);
347 this.stencilPaperEventListeners(_this);
348 this.drawAreapaperEventListerners();
352 this.paper.drawBackground({
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');
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, {
377 // transform client to paper coordinates
378 var p = evt.data.paper.snapToGrid({
382 // manually execute the linkView mousemove handler
383 evt.data.view.pointermove(evt, p.x, p.y);
387 // manually execute the linkView mouseup handler
388 evt.data.view.pointerup(evt);
389 $(document).off('.example');
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({
401 flyShape = cellView.model.clone(),
402 pos = cellView.model.position(),
408 flyShape.position(0, 0);
409 flyGraph.addCell(flyShape);
410 $("#flyPaper").offset({
411 left: e.pageX - offset.x,
412 top: e.pageY - offset.y
414 $('body').on('mousemove.fly', function (e) {
415 $("#flyPaper").offset({
416 left: e.pageX - offset.x,
417 top: e.pageY - offset.y
420 let elementabove, elementBelow;
421 $('body').on('mouseup.fly', function (e) {
425 target = _this.paper.$el.offset();
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();
431 // var coordinates = new g.Point(x, y);
433 // elementBelow = _this.paper.model.findModelsFromPoint(coordinates).find(function(el) {
434 // return (el.id !== elementabove.id);
436 // elementBelow =_this.paper.findModelsFromPoint(coordinates).find(function(el) {
437 // return (el.id !== elementabove.id);
439 // elementBelow.embed(elementabove);
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];
447 // if(elementssss[1]) {
448 // elementAbove = elementssss[1];
449 // elementBelow.embed(elementabove);
452 $('body').off('mousemove.fly').off('mouseup.fly');
454 $('#flyPaper').remove();
456 _this.paper.on('mouse')
460 drawAreapaperEventListerners() {
461 // create event listerners
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");
471 this.paper.on('blank:pointerdblclick', function () {
472 _this.resetAll(this);
474 this.drawBackground({
479 this.paper.on('link:pointerclick', function (linkView) {
480 _this.resetAll(this);
481 let currentElement = linkView.model;
482 currentElement.appendLabel({
485 text: "Hello to new link!"
493 this.paper.on('blank:pointerdown', function (evt, x, y) {
494 let linkView = this.getDefaultLink()
496 'source': { x: x, y: y },
497 'target': { x: x, y: y }
501 linkView.startArrowheadMove('target');
504 'mousemove.example': _this.onDrag,
505 'mouseup.example': _this.onDragEnd
507 // shared data between listeners
514 // 'element:pointerdown': function(elementView, evt) {
516 // evt.data = elementView.model.position();
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);
524 if(elementBelow) elementBelow.embed(elementAbove);
527 }); //end of my event
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',
536 rect: { stroke: 'none', 'fill-opacity': 0 }
538 }, joint.shapes.basic.Rect.prototype.defaults)
541 // / Create a custom view for that element that displays an HTML div above it.
542 // -------------------------------------------------------------------------
544 joint.shapes.html.ElementView = joint.dia.ElementView.extend({
547 '<div class="html-element">',
548 '<button class="delete">x</button>',
550 '<span></span>', '<br/>',
551 '<select><option>--</option><option>one</option><option>two</option></select>',
552 '<input type="text" value="I\'m HTML input" />',
556 initialize: function() {
557 _.bindAll(this, 'updateBox');
558 joint.dia.ElementView.prototype.initialize.apply(this, arguments);
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();
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());
569 this.$box.find('select').on('change', _.bind(function(evt) {
570 this.model.set('select', $(evt.target).val());
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);
583 joint.dia.ElementView.prototype.render.apply(this, arguments);
584 this.paper.$el.prepend(this.$box);
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'));
600 transform: 'rotate(' + (this.model.get('angle') || 0) + 'deg)'
604 removeBox: function(evt) {
609 // Create JointJS elements and add them to the graph as usual.
610 // -----------------------------------------------------------
612 var el1 = new joint.shapes.html.Element({
613 position: { x: 10, y: 10 },
614 size: { width: 170, height: 100 },
619 var el2 = new joint.shapes.html.Element({
620 position: { x: 370, y: 160 },
621 size: { width: 170, height: 100 },
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' }}
631 let elementArray : any[] = [];
632 elementArray.push(el1, el2);
636 myCustomElementGenerator() {
637 var Ellipse = joint.dia.Element.define('examples.Ellipse', {
638 // default attributes
641 selector: 'ellipse' // not necessary but faster
656 var Rectangle = joint.shapes.standard.Rectangle.define('examples.CustomRectangle', {
659 selector: 'body' // not necessary but faster
667 rx: 10, // add a corner radius
670 fill: 'cornflowerblue'
673 textAnchor: 'left', // align text to left
674 refX: 10, // offset text from right edge of model bbox
683 var customElement = (new joint.dia.Element.examples.Ellipse()).position(100, 100).size(120, 50);
684 let elementsArray = [];
685 elementsArray.push(customElement);
687 var customRect = new Rectangle().position(100, 200).size(120, 120);
688 elementsArray.push(customRect);
689 return elementsArray;
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;
701 // this.selectedElement.attr('label/text', event.currentTarget.value);
704 convertJsonToGraph() {
705 this.sourceMode = false;
711 this.paper.scale(graphScale, graphScale);
717 this.paper.scale(graphScale, graphScale);
720 createContainerElements() {
721 this.graph = new joint.dia.Graph;
723 this.paper = new joint.dia.Paper({
725 el: document.getElementById('paper'),
734 defaultConnectionPoint: { name: 'boundary' },
745 className: 'highlighted-parent'
750 validateEmbedding: function(childView, parentView) {
751 return parentView.model instanceof joint.shapes.devs.Coupled;
754 validateConnection: function(sourceView, sourceMagnet, targetView, targetMagnet) {
755 return sourceMagnet != targetMagnet;
759 let c1 = new joint.shapes.devs.Coupled({
770 c1.set('inPorts', ['in']);
771 c1.set('outPorts', ['out 1', 'out 2']);
773 var a1 = new joint.shapes.devs.Atomic({
782 var a2 = new joint.shapes.devs.Atomic({
790 var a3 = new joint.shapes.devs.Atomic({
802 [c1, a1, a2, a3].forEach(function(element) {
813 this.graph.addCells([c1, a1, a2, a3]);
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');
824 var strokeDasharrayPath = '.body/strokeDasharray';
827 this.paper.on('element:pointerdblclick', function(elementView) {
828 var element = elementView.model;
829 if (element.get('type') === 'devs.Atomic') {
830 _this.toggleDelegation(element);
834 this.paper.setInteractivity(function(elementView) {
836 stopDelegation: !elementView.model.attr(strokeDasharrayPath)
844 connect(source, sourcePort, target, targetPort) {
846 var link = new joint.shapes.devs.Link({
857 link.addTo(this.graph).reparent();
860 toggleDelegation(element) {
861 var strokeDasharrayPath = '.body/strokeDasharray';
862 element.attr(strokeDasharrayPath, element.attr(strokeDasharrayPath) ? '' : '15,1');
865 createContainerElemnetsByDragDrop() {