From 0eacea3d509fcc62a66701efd08866efcdab435f Mon Sep 17 00:00:00 2001
From: Mathis Neumann <mathis@simpletechs.net>
Date: Mon, 25 Apr 2016 18:49:49 +0200
Subject: [PATCH] more node and change graph every several seconds to simulate
 socket updates

---
 app/components/architecture-visualisation.js |  45 ++++++-
 app/router.js                                |   1 +
 app/routes/architecture.js                   | 121 ++++++++++++++++++-
 app/styles/app.scss                          |  25 +---
 app/styles/components/_architecture.scss     |  49 ++++++--
 app/templates/application.hbs                |   5 +-
 6 files changed, 204 insertions(+), 42 deletions(-)

diff --git a/app/components/architecture-visualisation.js b/app/components/architecture-visualisation.js
index 999db59..95031c2 100644
--- a/app/components/architecture-visualisation.js
+++ b/app/components/architecture-visualisation.js
@@ -4,6 +4,36 @@ import klay from 'npm:klayjs-d3';
 import _ from 'npm:lodash';
 
 export default Ember.Component.extend({
+    init: function() {
+        this._super();
+        const self = this;
+        const log = self.debug.bind(self);
+        this.interval = setInterval(function() {
+            const graph = self.get('graph');
+
+            log('update interval called', graph);
+
+            if(!graph) {
+                return; // eventual consistent
+            }
+            const edges = graph.edges || [];
+            const index = Math.floor(Math.random()*edges.length);
+            if(Math.random() > 0.5) {
+                edges.splice(index, 1);
+            } else { // FIXME: does not render updates
+                const children = _.get(graph, 'children', []);
+                const randomNodeIndex = Math.floor(Math.random()*children.length);
+                const randomNodeId = children[randomNodeIndex].id;
+                graph.edges = _.set(edges, `${index}.target`, randomNodeId);
+                log(`updating random edge (${index}) to target a random node id ${randomNodeId}`, randomNodeIndex, edges);
+            }
+            self.set('graph', graph);
+            self.renderGraph();
+        }, 1000);
+    },
+    willDestroyElement() {
+        clearInterval(this.interval);
+    },
     didInsertElement: function() {
         const log = this.debug.bind(this);
         const width = window.innerWidth;
@@ -17,10 +47,11 @@ export default Ember.Component.extend({
             .attr("width", width)
             .attr("height", height)
             .attr('class', 'architectureVisualisation')
-            // .call(zoom)
+            .call(zoom)
             .append("g");
-        const root = svg.append("g");
+        const root = svg.append('g').attr('class', 'root');
 
+        this.svg = svg;
         this.layouter = klay.d3kgraph()
             .size([width, height])
             .transformGroup(root)
@@ -46,6 +77,9 @@ export default Ember.Component.extend({
                 .append('g')
                 .attr('class', d => d.children? 'node compound' : 'node leaf');
 
+            nodeData.exit()
+                .remove();
+
             const atoms = node.append('rect')
                 .attr('width', 10)
                 .attr('height', 10)
@@ -63,6 +97,7 @@ export default Ember.Component.extend({
                 .attr('font-size', '4px');
 
 
+            // FIXME does not handle updates (neither enter() nor exit())
             const linkData = root.selectAll('.link')
                 .data(links, p => p.id);
             const link = linkData.enter()
@@ -70,6 +105,9 @@ export default Ember.Component.extend({
                 .attr('class', 'link')
                 .attr('d', 'M0 0');
 
+            linkData.exit()
+                .remove();
+
             // apply edge routes
             link.transition().attr('d', (d) => {
               let path = '';
@@ -88,6 +126,9 @@ export default Ember.Component.extend({
               .attr('height', (d) => d.height);
         };
         this.layouter.on('finish', onFinish);
+        this.renderGraph();
+    },
+    renderGraph() {
         this.layouter.kgraph(this.get('graph'));
     }
 });
diff --git a/app/router.js b/app/router.js
index 42acc41..f6c0454 100644
--- a/app/router.js
+++ b/app/router.js
@@ -6,6 +6,7 @@ const Router = Ember.Router.extend({
 });
 
 Router.map(function() {
+    this.route('home', {path: '/'});
     this.route('architecture', {path: '/architecture'});
 });
 
diff --git a/app/routes/architecture.js b/app/routes/architecture.js
index ac893ce..d78a1ba 100644
--- a/app/routes/architecture.js
+++ b/app/routes/architecture.js
@@ -5,12 +5,41 @@ export default Ember.Route.extend({
     return {
         id: 'root',
         labels: [{text: 'My Architecture'}],
+        'properties': {
+            'direction': 'RIGHT',
+            'spacing': 10
+        },
         children: [{
+            id: 'VM_Profile',
+            children: [{
+                id: 'VM_Profile>Database',
+                labels: [{text: 'Profile DB'}],
+                width: 20,
+                height: 20
+            }]
+        },
+        {
             id: 'VM_Big',
             children: [{
-                id: 'VM_Big>Auth'
+                id: 'VM_Big>Auth',
+                width: 20,
+                height: 20
             }, {
-                id: 'VM_Big>User'
+                id: 'VM_Big>User',
+                width: 20,
+                height: 20
+            }, {
+                id: 'VM_Big>User2',
+                width: 20,
+                height: 20
+            }, {
+                id: 'VM_Big>User3',
+                width: 20,
+                height: 20
+            }, {
+                id: 'VM_Big>User4',
+                width: 20,
+                height: 20
             }],
             edges: [{
                 id: 'VM_Big>Auth->VM_Big>User',
@@ -23,28 +52,72 @@ export default Ember.Route.extend({
             id: 'VM_1',
             children: [{
                 id: 'VM_1>Auth',
-                labels: [{text: "Auth 1"}]
+                labels: [{text: 'Auth 1'}],
+                width: 20,
+                height: 20
             }]
         },
         {
             id: 'VM_2',
             children: [{
                 id: 'VM_2>Auth',
-                labels: [{text: "Auth 2"}]
+                labels: [{text: 'Auth 2'}],
+                width: 20,
+                height: 20
             }]
         },
         {
             id: 'VM_3',
             children: [{
                 id: 'VM_3>User',
-                labels: [{text: "User 1"}]
+                labels: [{text: 'User 1'}],
+                width: 20,
+                height: 20
             }]
         },
         {
             id: 'VM_4',
             children: [{
                 id: 'VM_4>User',
-                labels: [{text: "User 2"}]
+                labels: [{text: 'User 2'}],
+                width: 20,
+                height: 20
+            }]
+        },
+        {
+            id: 'VM_5',
+            children: [{
+                id: 'VM_5>User',
+                labels: [{text: 'User 2'}],
+                width: 20,
+                height: 20
+            }]
+        },
+        {
+            id: 'VM_6',
+            children: [{
+                id: 'VM_6>User',
+                labels: [{text: 'User 2'}],
+                width: 20,
+                height: 20
+            }]
+        },
+        {
+            id: 'VM_7',
+            children: [{
+                id: 'VM_7>User',
+                labels: [{text: 'User 2'}],
+                width: 20,
+                height: 20
+            }]
+        },
+        {
+            id: 'VM_8',
+            children: [{
+                id: 'VM_8>User',
+                labels: [{text: 'User 2'}],
+                width: 20,
+                height: 20
             }]
         }],
         edges: [{
@@ -55,6 +128,42 @@ export default Ember.Route.extend({
             id: 'VM_2>Auth->VM_4>User',
             source: 'VM_2>Auth',
             target: 'VM_4>User',
+        }, {
+            id: 'VM_Big>User->VM_Profile>Database',
+            source: 'VM_Big>User',
+            target: 'VM_Profile>Database',
+        }, {
+            id: 'VM_2>Auth->VM_Profile>Database',
+            source: 'VM_2>Auth',
+            target: 'VM_Profile>Database',
+        }, {
+            id: 'VM_1>Auth->VM_Profile>Database',
+            source: 'VM_1>Auth',
+            target: 'VM_Profile>Database',
+        }, {
+            id: 'VM_3>User->VM_Profile>Database',
+            source: 'VM_3>User',
+            target: 'VM_Profile>Database',
+        }, {
+            id: 'VM_4>User->VM_Profile>Database',
+            source: 'VM_4>User',
+            target: 'VM_Profile>Database',
+        }, {
+            id: 'VM_5>User->VM_Profile>Database',
+            source: 'VM_5>User',
+            target: 'VM_Profile>Database',
+        }, {
+            id: 'VM_6>User->VM_Profile>Database',
+            source: 'VM_6>User',
+            target: 'VM_Profile>Database',
+        }, {
+            id: 'VM_7>User->VM_Profile>Database',
+            source: 'VM_7>User',
+            target: 'VM_Profile>Database',
+        }, {
+            id: 'VM_8>User->VM_Profile>Database',
+            source: 'VM_8>User',
+            target: 'VM_Profile>Database',
         }]
     };
   }
diff --git a/app/styles/app.scss b/app/styles/app.scss
index 22c865c..1c11d30 100644
--- a/app/styles/app.scss
+++ b/app/styles/app.scss
@@ -1,29 +1,6 @@
-@import "components/_architecture";
-
 body {
     font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
 }
-g.leaf > rect {
-  stroke: #fff;
-  stroke-width: 1px;
-  opacity: .5;
-}
-
-g.compound > rect {
-  opacity: 0.1;
-}
 
-.node {
-}
-
-.link {
-  stroke: #999;
-  stroke-opacity: .6;
-  fill: none;
-}
+@import "components/_architecture";
 
-.port {
-  stroke: #000;
-  width: 1px;
-  opacity: .6;
-}
diff --git a/app/styles/components/_architecture.scss b/app/styles/components/_architecture.scss
index e7d390a..4a98a5e 100644
--- a/app/styles/components/_architecture.scss
+++ b/app/styles/components/_architecture.scss
@@ -1,12 +1,43 @@
 svg.architectureVisualisation {
-    g.compound > rect:hover {
-        stroke: white;
-        stroke-opacity: 1;
-        fill: red;
-    }
-    .link:hover {
-      stroke: #A000;
-      stroke-opacity: 1;
-      fill: black;
+    .root {
+        g.compound {
+            &:first-child rect { // hide root compound
+                opacity: 0;
+            }
+
+            & > rect {
+                opacity: 0.1;
+
+                &:hover {
+                    stroke: white;
+                    stroke-opacity: 1;
+                    fill: red;
+                }
+            }
+        }
+    }
+    .link {
+        stroke: #999;
+        stroke-opacity: .6;
+        fill: none;
+        stroke-width: 2px;
+
+        &:hover {
+          stroke: #A000;
+          stroke-opacity: 1;
+        }
+    }
+    g.leaf > rect {
+      stroke: #fff;
+      stroke-width: 1px;
+      opacity: .5;
+    }
+
+    // .node {}
+
+    .port {
+      stroke: #000;
+      width: 1px;
+      opacity: .6;
     }
 }
\ No newline at end of file
diff --git a/app/templates/application.hbs b/app/templates/application.hbs
index 3f1cdac..c009e1f 100644
--- a/app/templates/application.hbs
+++ b/app/templates/application.hbs
@@ -1,4 +1,7 @@
 <h2 id="title">Welcome to Ember</h2>
-<h3>Go to {{#link-to 'architecture'}}Klay-based Architecture{{/link-to}}</h3>
+<ul>
+    <li>Go to {{#link-to 'home'}}Home{{/link-to}}</li>
+    <li>Go to {{#link-to 'architecture'}}Klay-based Architecture{{/link-to}}</li>
+</ul>
 
 {{outlet}}
-- 
GitLab