Enable link functionality in GUI2 Topology View

Change-Id: I1b88080ecdf8c9b6f8a60af4832a12441186d508
diff --git a/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/models/force-directed-graph.ts b/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/models/force-directed-graph.ts
index 46d3ba7..b511886 100644
--- a/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/models/force-directed-graph.ts
+++ b/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/models/force-directed-graph.ts
@@ -16,12 +16,35 @@
 import { EventEmitter } from '@angular/core';
 import { Link } from './link';
 import { Node } from './node';
-import * as d3 from 'd3';
+import * as d3 from 'd3-force';
+import {LogService} from 'gui2-fw-lib';
 
 const FORCES = {
     LINKS: 1 / 50,
     COLLISION: 1,
-    CHARGE: -10
+    GRAVITY: 0.4,
+    FRICTION: 0.7
+};
+
+const CHARGES = {
+    device: -80,
+    host: -200,
+    region: -80,
+    _def_: -120
+};
+
+const LINK_DISTANCE = {
+    // note: key is link.type
+    direct: 100,
+    optical: 120,
+    UiEdgeLink: 100,
+    _def_: 50,
+};
+
+const LINK_STRENGTH = {
+    // note: key is link.type
+    // range: {0.0 ... 1.0}
+    _def_: 0.1
 };
 
 export interface Options {
@@ -36,7 +59,7 @@
     public nodes: Node[] = [];
     public links: Link[] = [];
 
-    constructor(options: Options) {
+    constructor(options: Options, public log: LogService) {
         this.initSimulation(options);
     }
 
@@ -56,10 +79,26 @@
         // Initializing the links force simulation
         this.simulation.force('links',
             d3.forceLink(this.links)
-                .strength(FORCES.LINKS)
+                .strength(this.strength.bind(this))
+                .distance(this.distance.bind(this))
         );
     }
 
+    charges(node) {
+        const nodeType = node.nodeType;
+        return CHARGES[nodeType] || CHARGES._def_;
+    }
+
+    distance(node) {
+        const nodeType = node.nodeType;
+        return LINK_DISTANCE[nodeType] || LINK_DISTANCE._def_;
+    }
+
+    strength(node) {
+        const nodeType = node.nodeType;
+        return LINK_STRENGTH[nodeType] || LINK_STRENGTH._def_;
+    }
+
     initSimulation(options: Options) {
         if (!options || !options.width || !options.height) {
             throw new Error('missing options when initializing simulation');
@@ -72,9 +111,12 @@
             // Creating the force simulation and defining the charges
             this.simulation = d3.forceSimulation()
                 .force('charge',
-                    d3.forceManyBody()
-                        .strength(FORCES.CHARGE)
-                );
+                    d3.forceManyBody().strength(this.charges.bind(this)))
+                        // .distanceMin(100).distanceMax(500))
+                .force('gravity',
+                    d3.forceManyBody().strength(FORCES.GRAVITY))
+                .force('friction',
+                    d3.forceManyBody().strength(FORCES.FRICTION));
 
             // Connecting the d3 ticker to an angular event emitter
             this.simulation.on('tick', function () {
@@ -82,7 +124,7 @@
             });
 
             this.initNodes();
-            this.initLinks();
+            // this.initLinks();
         }
 
         /** Updating the central force of the simulation */
@@ -94,5 +136,11 @@
 
     stopSimulation() {
         this.simulation.stop();
+        this.log.debug('Simulation stopped');
+    }
+
+    restartSimulation() {
+        this.simulation.restart();
+        this.log.debug('Simulation restarted');
     }
 }