JointJS Prototype 16/96916/1
authorArundathi Patil <arundpil@in.ibm.com>
Fri, 11 Oct 2019 07:03:57 +0000 (12:33 +0530)
committerArundathi Patil <arundpil@in.ibm.com>
Fri, 11 Oct 2019 07:04:29 +0000 (12:34 +0530)
Added JointJS POC

Issue-ID: CCSDK-1765
Change-Id: Ia8a6e913e3d4f10f3fdc0e1ec377304e49879240
Signed-off-by: Arundathi Patil <arundpil@in.ibm.com>
cds-ui/client/JointJS-POC-In-Progress/app-routing.module.ts [new file with mode: 0644]
cds-ui/client/JointJS-POC-In-Progress/app.component.html [new file with mode: 0644]
cds-ui/client/JointJS-POC-In-Progress/app.component.scss [new file with mode: 0644]
cds-ui/client/JointJS-POC-In-Progress/app.component.spec.ts [new file with mode: 0644]
cds-ui/client/JointJS-POC-In-Progress/app.component.ts [new file with mode: 0644]
cds-ui/client/JointJS-POC-In-Progress/app.module.ts [new file with mode: 0644]

diff --git a/cds-ui/client/JointJS-POC-In-Progress/app-routing.module.ts b/cds-ui/client/JointJS-POC-In-Progress/app-routing.module.ts
new file mode 100644 (file)
index 0000000..d425c6f
--- /dev/null
@@ -0,0 +1,10 @@
+import { NgModule } from '@angular/core';
+import { Routes, RouterModule } from '@angular/router';
+
+const routes: Routes = [];
+
+@NgModule({
+  imports: [RouterModule.forRoot(routes)],
+  exports: [RouterModule]
+})
+export class AppRoutingModule { }
diff --git a/cds-ui/client/JointJS-POC-In-Progress/app.component.html b/cds-ui/client/JointJS-POC-In-Progress/app.component.html
new file mode 100644 (file)
index 0000000..da05dd5
--- /dev/null
@@ -0,0 +1,31 @@
+<!-- <div id="myholder"></div> -->
+<div style="background-color: black; color: white; height: 75px; width:100%; font-size: 2em; margin-bottom: 3px">
+  CDS DESIGNER POC
+  <button (click)="convertGraphToJson()">Save</button>
+</div>
+<div style="display: flex;flex-direction:row; height: 700PX">
+  <div id="stencil" style="width: 30%;height: 100%;border: 1px solid; border-radius:0.5em; background-color: gainsboro"></div>
+  <div style="width: 70%; height: 100%;">
+    <div style="position: fixed;width: 200px;background-color: gainsboro;height: 36px;z-index: 2;">
+    <button *ngIf="!sourceMode" style="border-radius: 0.5em;width: 6em;height: 2.5em;border: 2px solid black;" (click)="convertGraphToJson()">Source</button>
+    <button  *ngIf="sourceMode" style="border-radius: 0.5em;width: 6em;height: 2.5em;border: 2px solid black;" (click)="convertJsonToGraph()">Graph</button>
+    <i (click) ="zoomIn()" class="fa fa-search-plus" aria-hidden="true"></i>
+    <i (click) ="zoomOut()" class="fa fa-search-minus" aria-hidden="true"></i>
+    </div>    
+    <div [hidden]="sourceMode" id="paper" style="height: 100%;"></div>
+    <div id="sourceJson" [hidden]="!sourceMode"style="width: 100%; height: 100%;"><textarea style="margin-top: 4em;
+      width: 100%;
+      height: 100%;">{{grapJson}}</textarea></div>
+  </div> 
+  <div id="propertyPanel" style="width: 20%; height: 100%; background-color: white">
+    <div style="background-color: gainsboro;height:28px">Attributes</div>
+    <div style="height: 100px;padding: 10px">
+      Action Name<br/>
+      <input type="text" [(ngModel)]="selectedElement.attributes.attrs.label.text" (change)="setNewValue($event)"/>
+    </div>
+    <div>
+      <div style="background-color: gainsboro;height:28px">Input</div>
+
+    </div>
+  </div>
+</div>
diff --git a/cds-ui/client/JointJS-POC-In-Progress/app.component.scss b/cds-ui/client/JointJS-POC-In-Progress/app.component.scss
new file mode 100644 (file)
index 0000000..68d06fb
--- /dev/null
@@ -0,0 +1,81 @@
+#stencil {
+    position: relative;
+    border: 1px solid gray;
+    display: inline-block;
+    background: transparent;
+    overflow: hidden;
+}
+#stencil svg {
+    background: transparent;
+}
+#stencil svg .link {
+    z-index: 2;
+}
+.html-element {
+    position: absolute;
+    background: #3498DB;
+    /* Make sure events are propagated to the JointJS element so, e.g. dragging works.*/
+    pointer-events: none;
+    -webkit-user-select: none;
+    border-radius: 4px;
+    border: 2px solid #2980B9;
+    box-shadow: inset 0 0 5px black, 2px 2px 1px gray;
+    padding: 5px;
+    box-sizing: border-box;
+    z-index: 2;
+}
+.html-element select,
+.html-element input,
+.html-element button {
+    /* Enable interacting with inputs only. */
+    pointer-events: auto;
+}
+.html-element button.delete {
+    color: white;
+    border: none;
+    background-color: #C0392B;
+    border-radius: 20px;
+    width: 15px;
+    height: 15px;
+    line-height: 15px;
+    text-align: middle;
+    position: absolute;
+    top: -15px;
+    left: -15px;
+    padding: 0;
+    margin: 0;
+    font-weight: bold;
+    cursor: pointer;
+}
+.html-element button.delete:hover {
+    width: 20px;
+    height: 20px;
+    line-height: 20px;
+}
+.html-element select {
+    position: absolute;
+    right: 2px;
+    bottom: 28px;
+}
+.html-element input {
+    position: absolute;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    border: none;
+    color: #333;
+    padding: 5px;
+    height: 16px;
+}
+.html-element label {
+    color: #333;
+    text-shadow: 1px 0 0 lightgray;
+    font-weight: bold;
+}
+.html-element span {
+    position: absolute;
+    top: 2px;
+    right: 9px;
+    color: white;
+    font-size: 10px;
+}
\ No newline at end of file
diff --git a/cds-ui/client/JointJS-POC-In-Progress/app.component.spec.ts b/cds-ui/client/JointJS-POC-In-Progress/app.component.spec.ts
new file mode 100644 (file)
index 0000000..8de310a
--- /dev/null
@@ -0,0 +1,35 @@
+import { TestBed, async } from '@angular/core/testing';
+import { RouterTestingModule } from '@angular/router/testing';
+import { AppComponent } from './app.component';
+
+describe('AppComponent', () => {
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      imports: [
+        RouterTestingModule
+      ],
+      declarations: [
+        AppComponent
+      ],
+    }).compileComponents();
+  }));
+
+  it('should create the app', () => {
+    const fixture = TestBed.createComponent(AppComponent);
+    const app = fixture.debugElement.componentInstance;
+    expect(app).toBeTruthy();
+  });
+
+  it(`should have as title 'jointJS-designer'`, () => {
+    const fixture = TestBed.createComponent(AppComponent);
+    const app = fixture.debugElement.componentInstance;
+    expect(app.title).toEqual('jointJS-designer');
+  });
+
+  it('should render title in a h1 tag', () => {
+    const fixture = TestBed.createComponent(AppComponent);
+    fixture.detectChanges();
+    const compiled = fixture.debugElement.nativeElement;
+    expect(compiled.querySelector('h1').textContent).toContain('Welcome to jointJS-designer!');
+  });
+});
diff --git a/cds-ui/client/JointJS-POC-In-Progress/app.component.ts b/cds-ui/client/JointJS-POC-In-Progress/app.component.ts
new file mode 100644 (file)
index 0000000..289a577
--- /dev/null
@@ -0,0 +1,869 @@
+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('<div id="flyPaper" style="position:fixed;z-index:100;opacity:.7;pointer-event:none;"></div>');
+      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('<div id="flyPaper" style="position:fixed;z-index:100;opacity:.7;pointer-event:none;"></div>');
+      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: [
+            '<div class="html-element">',
+            '<button class="delete">x</button>',
+            '<label></label>',
+            '<span></span>', '<br/>',
+            '<select><option>--</option><option>one</option><option>two</option></select>',
+            '<input type="text" value="I\'m HTML input" />',
+            '</div>'
+        ].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() {
+  
+
+}
+}
diff --git a/cds-ui/client/JointJS-POC-In-Progress/app.module.ts b/cds-ui/client/JointJS-POC-In-Progress/app.module.ts
new file mode 100644 (file)
index 0000000..15eb6d5
--- /dev/null
@@ -0,0 +1,24 @@
+import { BrowserModule } from '@angular/platform-browser';
+import { NgModule } from '@angular/core';
+import { FormsModule } from '@angular/forms';
+import { CommonModule } from '@angular/common';  
+
+import { AppRoutingModule } from './app-routing.module';
+import { AppComponent } from './app.component';
+import { DragCopyComponent } from './drag-copy/drag-copy.component';
+
+@NgModule({
+  declarations: [
+    AppComponent,
+    DragCopyComponent
+  ],
+  imports: [
+    BrowserModule,
+    AppRoutingModule,
+    FormsModule,
+    CommonModule
+  ],
+  providers: [],
+  bootstrap: [AppComponent]
+})
+export class AppModule { }