Added d3 force graph to GUI2 topology

Change-Id: I6860472efaf51ea27fad74e630e687f0c6abad3d
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
new file mode 100644
index 0000000..3db25ae
--- /dev/null
+++ b/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/models/force-directed-graph.ts
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the 'License');
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an 'AS IS' BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import { EventEmitter } from '@angular/core';
+import { Link } from './link';
+import { Node } from './node';
+import * as d3 from 'd3';
+
+const FORCES = {
+    LINKS: 1 / 50,
+    COLLISION: 1,
+    CHARGE: -1
+};
+
+export interface Options {
+    width: number;
+    height: number;
+}
+
+export class ForceDirectedGraph {
+    public ticker: EventEmitter<d3.Simulation<Node, Link>> = new EventEmitter();
+    public simulation: d3.Simulation<any, any>;
+
+    public nodes: Node[] = [];
+    public links: Link[] = [];
+
+    constructor(options: Options) {
+        this.initSimulation(options);
+    }
+
+    initNodes() {
+        if (!this.simulation) {
+            throw new Error('simulation was not initialized yet');
+        }
+
+        this.simulation.nodes(this.nodes);
+    }
+
+    initLinks() {
+        if (!this.simulation) {
+            throw new Error('simulation was not initialized yet');
+        }
+
+        // Initializing the links force simulation
+        this.simulation.force('links',
+            d3.forceLink(this.links)
+                .strength(FORCES.LINKS)
+        );
+    }
+
+    initSimulation(options: Options) {
+        if (!options || !options.width || !options.height) {
+            throw new Error('missing options when initializing simulation');
+        }
+
+        /** Creating the simulation */
+        if (!this.simulation) {
+            const ticker = this.ticker;
+
+            // Creating the force simulation and defining the charges
+            this.simulation = d3.forceSimulation()
+                .force('charge',
+                    d3.forceManyBody()
+                        .strength(FORCES.CHARGE)
+                );
+
+            // Connecting the d3 ticker to an angular event emitter
+            this.simulation.on('tick', function () {
+                ticker.emit(this);
+            });
+
+            this.initNodes();
+            this.initLinks();
+        }
+
+        /** Updating the central force of the simulation */
+        this.simulation.force('centers', d3.forceCenter(options.width / 2, options.height / 2));
+
+        /** Restarting the simulation internal timer */
+        this.simulation.restart();
+    }
+
+    stopSimulation() {
+        this.simulation.stop();
+    }
+}