declare var require: any import { Component, OnInit } from '@angular/core'; import * as $ from 'jquery'; import * as _ from 'lodash'; const joint = require('../../node_modules/jointjs/dist/joint.js'); @Component({ selector: 'app-root', templateUrl: './app.component.html', styleUrls: ['./app.component.scss'] }) export class AppComponent implements OnInit { title = 'jointJS-designer'; public graph: any; public paper: any; public rect: any; public rect2: any; public link: any; public stencilGraph: any; public stencilPaper: any; public selectedElement = { attributes: { attrs: { label: { text: 'abc' } } } }; grapJson: any; sourceMode = false; constructor() { } ngOnInit() { // this.creatElementWithPorts(); // this.dragCopyPlainElements(); this.sourceMode = false; this.dragCopyElementsWithPort(); // this.newDragCopy(); this.createContainerElements(); } creatElementWithPorts() { // working code // create graph let elementList: any[] = []; // this.graph = new joint.dia.Graph; // // create paper // this.paper = new joint.dia.Paper({ // el: document.getElementById('paper'), // width: 1000, // height: 1000, // model: this.graph, // gridSize: 2, // drawGrid: true // }); // this.paper.setGrid({ // name: 'dot', // args: // { color: 'black', thickness: 2, scaleFactor: 8 } // }).drawGrid(); // create element this.rect = new joint.shapes.basic.Rect({ position: { x: 100, y: 30 }, size: { width: 100, height: 100 }, attrs: { rect: { fill: 'white' }, text: { text: 'my box', fill: 'white' } } }); this.rect.translate(100, 50); elementList.push(this.rect); this.rect.position(10, 10); // clone element // this.rect2 = this.rect.clone(); // this.rect2.translate(180); // elementList.push(this.rect2); // Create link // this.link = new joint.dia.Link({ // source: { id: this.rect.id }, // target: { id: this.rect2.id } // }); // create circle var circle = new joint.shapes.standard.Circle(); circle.resize(100, 100); circle.position(180, 10); circle.attr('root/title', 'joint.shapes.standard.Circle'); circle.attr('label/text', 'Circle'); circle.attr('body/fill', 'lightblue'); elementList.push(circle); // create link var ellipse = new joint.shapes.standard.Ellipse(); ellipse.resize(150, 100); ellipse.position(180, 150); ellipse.attr('root/title', 'joint.shapes.standard.Ellipse'); ellipse.attr('label/text', 'Ellipse'); ellipse.attr('body/fill', 'lightblue'); elementList.push(ellipse); // rectangle with header var headeredRectangle = new joint.shapes.standard.HeaderedRectangle(); headeredRectangle.resize(150, 100); headeredRectangle.position(10, 280); headeredRectangle.attr('root/title', 'joint.shapes.standard.HeaderedRectangle'); headeredRectangle.attr('header/fill', 'lightgray'); headeredRectangle.attr('headerText/text', 'Header'); headeredRectangle.attr('bodyText/text', 'Headered\nRectangle'); elementList.push(headeredRectangle); let m1 = new joint.shapes.devs.Model({ position: { x: 200, y: 280 }, size: { width: 90, height: 90 }, inPorts: ['in1', 'in2'], outPorts: ['out', 'out2'], ports: { groups: { 'in': { attrs: { '.port-body': { fill: '#16A085' } } }, 'out': { attrs: { '.port-body': { fill: '#E74C3C' } } } } }, attrs: { '.label': { text: 'Model', 'ref-x': .5, 'ref-y': .2 }, rect: { fill: 'white' } } }); elementList.push(m1); //container element let c1 = new joint.shapes.devs.Coupled({ position: { x: 150, y: 470 }, size: { width: 200, height: 200 } }); c1.set('inPorts', ['in']); c1.set('outPorts', ['out 1', 'out 2']); c1.attr({ '.body': { 'rx': 6, 'ry': 6 } }); elementList.push(c1); // circle.position(10, 150); var a1 = new joint.shapes.devs.Atomic({ position: { x: 10, y: 150 }, inPorts: ['xy'], outPorts: ['x', 'y'] }); a1.attr({ '.body': { 'rx': 6, 'ry': 6 } }); elementList.push(a1); return elementList; } dragCopyPlainElements() { // Canvas where sape are dropped this.graph = new joint.dia.Graph, this.paper = new joint.dia.Paper({ el: $('#paper'), model: this.graph }); // Canvas from which you take shapes this.stencilGraph = new joint.dia.Graph, this.stencilPaper = new joint.dia.Paper({ el: $('#stencil'), height: 60, model: this.stencilGraph, interactive: false }); var r1 = new joint.shapes.basic.Rect({ position: { x: 10, y: 10 }, size: { width: 100, height: 40 }, attrs: { text: { text: 'Rect1' } } }); var r2 = new joint.shapes.basic.Rect({ position: { x: 120, y: 10 }, size: { width: 100, height: 40 }, attrs: { text: { text: 'Rect2' } } }); this.stencilGraph.addCells([r1, r2]); let _this = this; this.stencilPaper.on('cell:pointerdown', function (cellView, e, x, y) { $('body').append('
'); var flyGraph = new joint.dia.Graph, flyPaper = new joint.dia.Paper({ el: $('#flyPaper'), model: flyGraph, interactive: false }), flyShape = cellView.model.clone(), pos = cellView.model.position(), offset = { x: x - pos.x, y: y - pos.y }; flyShape.position(0, 0); flyGraph.addCell(flyShape); $("#flyPaper").offset({ left: e.pageX - offset.x, top: e.pageY - offset.y }); $('body').on('mousemove.fly', function (e) { $("#flyPaper").offset({ left: e.pageX - offset.x, top: e.pageY - offset.y }); }); $('body').on('mouseup.fly', function (e) { var x = e.pageX, y = e.pageY, target = _this.paper.$el.offset(); // Dropped over paper ? if (x > target.left && x < target.left + _this.paper.$el.width() && y > target.top && y < target.top + _this.paper.$el.height()) { var s = flyShape.clone(); s.position(x - target.left - offset.x, y - target.top - offset.y); _this.graph.addCell(s); } $('body').off('mousemove.fly').off('mouseup.fly'); flyShape.remove(); $('#flyPaper').remove(); }); }) } dragCopyElementsWithPort() { // Canvas where sape are dropped this.graph = new joint.dia.Graph, this.paper = new joint.dia.Paper({ el: $('#paper'), model: this.graph, height: 700, width: 1000, gridSize: 2, drawGrid: true }); // create paper // this.paper = new joint.dia.Paper({ // el: document.getElementById('paper'), // width: 1000, // height: 1000, // model: this.graph, // gridSize: 2, // drawGrid: true // }); this.paper.setGrid({ name: 'dot', args: { color: 'black', thickness: 2, scaleFactor: 8 } }).drawGrid(); // Canvas from which you take shapes this.stencilGraph = new joint.dia.Graph, this.stencilPaper = new joint.dia.Paper({ el: $('#stencil'), height: 700, width: 382, model: this.stencilGraph, interactive: false }); let elementWithPort = this.creatElementWithPorts(); // let elementWithPort = this.createCustomElement(); // let elementWithPort = this.myCustomElementGenerator(); elementWithPort.forEach(element => { this.stencilGraph.addCell(element); }); let _this = this; this.stencilPaperEventListeners(_this); this.drawAreapaperEventListerners(); } resetAll(paper) { this.paper.drawBackground({ color: 'white' }) var elements = this.paper.model.getElements(); for (var i = 0, ii = elements.length; i < ii; i++) { var currentElement = elements[i]; currentElement.attr('body/stroke', 'black'); } var links = this.paper.model.getLinks(); for (var j = 0, jj = links.length; j < jj; j++) { var currentLink = links[j]; currentLink.attr('line/stroke', 'black'); currentLink.label(0, { attrs: { body: { stroke: 'black' } } }) } } onDrag(evt) { // transform client to paper coordinates var p = evt.data.paper.snapToGrid({ x: evt.clientX, y: evt.clientY }); // manually execute the linkView mousemove handler evt.data.view.pointermove(evt, p.x, p.y); } onDragEnd(evt) { // manually execute the linkView mouseup handler evt.data.view.pointerup(evt); $(document).off('.example'); } stencilPaperEventListeners(_this) { this.stencilPaper.on('cell:pointerdown', function (cellView, e, x, y) { $('body').append('
'); var flyGraph = new joint.dia.Graph, flyPaper = new joint.dia.Paper({ el: $('#flyPaper'), model: flyGraph, interactive: true }), flyShape = cellView.model.clone(), pos = cellView.model.position(), offset = { x: x - pos.x, y: y - pos.y }; flyShape.position(0, 0); flyGraph.addCell(flyShape); $("#flyPaper").offset({ left: e.pageX - offset.x, top: e.pageY - offset.y }); $('body').on('mousemove.fly', function (e) { $("#flyPaper").offset({ left: e.pageX - offset.x, top: e.pageY - offset.y }); }); let elementabove, elementBelow; $('body').on('mouseup.fly', function (e) { console.log(this); var x = e.pageX, y = e.pageY, target = _this.paper.$el.offset(); // Dropped over paper ? if (x > target.left && x < target.left + _this.paper.$el.width() && y > target.top && y < target.top + _this.paper.$el.height()) { var s = flyShape.clone(); // var coordinates = new g.Point(x, y); // elementabove = s; // elementBelow = _this.paper.model.findModelsFromPoint(coordinates).find(function(el) { // return (el.id !== elementabove.id); // }); // elementBelow =_this.paper.findModelsFromPoint(coordinates).find(function(el) { // return (el.id !== elementabove.id); // }); // elementBelow.embed(elementabove); s.position(x - target.left - offset.x, y - target.top - offset.y); _this.graph.addCell(s); // let elementssss = (_this.graph.getElements()); // console.log("elementsss", elementssss); // let elementBelow = elementssss[0]; // let elementAbove; // if(elementssss[1]) { // elementAbove = elementssss[1]; // elementBelow.embed(elementabove); // } } $('body').off('mousemove.fly').off('mouseup.fly'); flyShape.remove(); $('#flyPaper').remove(); }); _this.paper.on('mouse') }) } drawAreapaperEventListerners() { // create event listerners let _this = this; this.paper.on('element:pointerdblclick', function (elementView) { _this.resetAll(this); _this.selectedElement = elementView.model; var currentElement = elementView.model; currentElement.attr('body/stroke', 'orange'); // currentElement.attr('label/text', "abc"); }); this.paper.on('blank:pointerdblclick', function () { _this.resetAll(this); this.drawBackground({ color: 'orange' }); }); this.paper.on('link:pointerclick', function (linkView) { _this.resetAll(this); let currentElement = linkView.model; currentElement.appendLabel({ attrs: { text: { text: "Hello to new link!" } } }); }); this.paper.on('blank:pointerdown', function (evt, x, y) { let linkView = this.getDefaultLink() .set({ 'source': { x: x, y: y }, 'target': { x: x, y: y } }) .addTo(this.model) .findView(this); linkView.startArrowheadMove('target'); $(document).on({ 'mousemove.example': _this.onDrag, 'mouseup.example': _this.onDragEnd }, { // shared data between listeners view: linkView, paper: this }); }); this.paper.on({ // 'element:pointerdown': function(elementView, evt) { // evt.data = elementView.model.position(); // }, 'element:pointerup': function(elementView, evt, x, y) { var coordinates = new g.Point(x, y); var elementAbove = elementView.model; var elementBelow = this.model.findModelsFromPoint(coordinates).find(function(el) { return (el.id !== elementAbove.id); }); if(elementBelow) elementBelow.embed(elementAbove); } }); //end of my event } createCustomElement() { joint.shapes.html = {}; joint.shapes.html.Element = joint.shapes.basic.Rect.extend({ defaults: joint.util.deepSupplement({ type: 'html.Element', attrs: { rect: { stroke: 'none', 'fill-opacity': 0 } } }, joint.shapes.basic.Rect.prototype.defaults) }); // / Create a custom view for that element that displays an HTML div above it. // ------------------------------------------------------------------------- joint.shapes.html.ElementView = joint.dia.ElementView.extend({ template: [ '
', '', '', '', '
', '', '', '
' ].join(''), initialize: function() { _.bindAll(this, 'updateBox'); joint.dia.ElementView.prototype.initialize.apply(this, arguments); this.$box = $(_.template(this.template)()); // Prevent paper from handling pointerdown. this.$box.find('input,select').on('mousedown click', function(evt) { evt.stopPropagation(); }); // This is an example of reacting on the input change and storing the input data in the cell model. this.$box.find('input').on('change', _.bind(function(evt) { this.model.set('input', $(evt.target).val()); }, this)); this.$box.find('select').on('change', _.bind(function(evt) { this.model.set('select', $(evt.target).val()); }, this)); this.$box.find('select').val(this.model.get('select')); this.$box.find('.delete').on('click', _.bind(this.model.remove, this.model)); // Update the box position whenever the underlying model changes. this.model.on('change', this.updateBox, this); // Remove the box when the model gets removed from the graph. this.model.on('remove', this.removeBox, this); this.updateBox(); }, render: function() { joint.dia.ElementView.prototype.render.apply(this, arguments); this.paper.$el.prepend(this.$box); this.updateBox(); return this; }, updateBox: function() { // Set the position and dimension of the box so that it covers the JointJS element. var bbox = this.model.getBBox(); // Example of updating the HTML with a data stored in the cell model. this.$box.find('label').text(this.model.get('label')); this.$box.find('span').text(this.model.get('select')); this.$box.css({ width: bbox.width, height: bbox.height, left: bbox.x, top: bbox.y, transform: 'rotate(' + (this.model.get('angle') || 0) + 'deg)' }); }, removeBox: function(evt) { this.$box.remove(); } }); // Create JointJS elements and add them to the graph as usual. // ----------------------------------------------------------- var el1 = new joint.shapes.html.Element({ position: { x: 10, y: 10 }, size: { width: 170, height: 100 }, label: 'I am HTML', select: 'one' }); var el2 = new joint.shapes.html.Element({ position: { x: 370, y: 160 }, size: { width: 170, height: 100 }, label: 'Me too', select: 'two' }); var l = new joint.dia.Link({ source: { id: el1.id }, target: { id: el2.id }, attrs: { '.connection': { 'stroke-width': 5, stroke: '#34495E' }} }); let elementArray : any[] = []; elementArray.push(el1, el2); return elementArray; } myCustomElementGenerator() { var Ellipse = joint.dia.Element.define('examples.Ellipse', { // default attributes markup: [{ tagName: 'ellipse', selector: 'ellipse' // not necessary but faster }], attrs: { ellipse: { fill: 'white', stroke: 'black', strokeWidth: 4, refRx: .5, refRy: .5, refCx: .5, refCy: .5 } } }); var Rectangle = joint.shapes.standard.Rectangle.define('examples.CustomRectangle', { markup: [{ tagName: 'body', selector: 'body' // not necessary but faster }, { tagName: 'label', selector: 'label' }], attrs: { body: { rx: 10, // add a corner radius ry: 10, strokeWidth: 1, fill: 'cornflowerblue' }, label: { textAnchor: 'left', // align text to left refX: 10, // offset text from right edge of model bbox fill: 'white', fontSize: 18, text: 'mad mad mad' } } }) var customElement = (new joint.dia.Element.examples.Ellipse()).position(100, 100).size(120, 50); let elementsArray = []; elementsArray.push(customElement); var customRect = new Rectangle().position(100, 200).size(120, 120); elementsArray.push(customRect); return elementsArray; } convertGraphToJson() { this.grapJson = JSON.stringify(this.graph.toJSON()); // this.grapJson = this.graph.toJSON(); console.log(this.graph.toJSON()); console.log(this.grapJson); this.sourceMode = true; } setNewValue(event) { // this.selectedElement.attr('label/text', event.currentTarget.value); } convertJsonToGraph() { this.sourceMode = false; } zoomIn() { var graphScale = 1; graphScale += 0.1; this.paper.scale(graphScale, graphScale); } zoomOut() { var graphScale = 1; graphScale -= 0.1; this.paper.scale(graphScale, graphScale); } createContainerElements() { this.graph = new joint.dia.Graph; this.paper = new joint.dia.Paper({ el: document.getElementById('paper'), width: 800, height: 400, gridSize: 1, model: this.graph, snapLinks: true, linkPinning: false, embeddingMode: true, clickThreshold: 5, defaultConnectionPoint: { name: 'boundary' }, highlighting: { 'default': { name: 'stroke', options: { padding: 6 } }, 'embedding': { name: 'addClass', options: { className: 'highlighted-parent' } } }, validateEmbedding: function(childView, parentView) { return parentView.model instanceof joint.shapes.devs.Coupled; }, validateConnection: function(sourceView, sourceMagnet, targetView, targetMagnet) { return sourceMagnet != targetMagnet; } }); let c1 = new joint.shapes.devs.Coupled({ position: { x: 230, y: 50 }, size: { width: 300, height: 300 } }); c1.set('inPorts', ['in']); c1.set('outPorts', ['out 1', 'out 2']); var a1 = new joint.shapes.devs.Atomic({ position: { x: 360, y: 260 }, inPorts: ['xy'], outPorts: ['x', 'y'] }); var a2 = new joint.shapes.devs.Atomic({ position: { x: 50, y: 160 }, outPorts: ['out'] }); var a3 = new joint.shapes.devs.Atomic({ position: { x: 650, y: 50 }, size: { width: 100, height: 300 }, inPorts: ['a', 'b'] }); [c1, a1, a2, a3].forEach(function(element) { element.attr({ '.body': { 'rx': 6, 'ry': 6 } }); }); this.graph.addCells([c1, a1, a2, a3]); c1.embed(a1); this.connect(a2, 'out', c1, 'in'); this.connect(c1, 'in', a1, 'xy'); this.connect(a1, 'x', c1, 'out 1'); this.connect(a1, 'y', c1, 'out 2'); this.connect(c1, 'out 1', a3, 'a'); this.connect(c1, 'out 2', a3, 'b'); var strokeDasharrayPath = '.body/strokeDasharray'; let _this = this; this.paper.on('element:pointerdblclick', function(elementView) { var element = elementView.model; if (element.get('type') === 'devs.Atomic') { _this.toggleDelegation(element); } }); this.paper.setInteractivity(function(elementView) { return { stopDelegation: !elementView.model.attr(strokeDasharrayPath) }; }); } // function end // function connect(source, sourcePort, target, targetPort) { var link = new joint.shapes.devs.Link({ source: { id: source.id, port: sourcePort }, target: { id: target.id, port: targetPort } }); link.addTo(this.graph).reparent(); } toggleDelegation(element) { var strokeDasharrayPath = '.body/strokeDasharray'; element.attr(strokeDasharrayPath, element.attr(strokeDasharrayPath) ? '' : '15,1'); } createContainerElemnetsByDragDrop() { } }