// Vertex Class Declaration class Vertex { constructor() { this.pos = []; this.disp = []; this.value; } } // Graph Class Declaration class Graph { constructor() { this.AdjList = new Map(); this.vertexMap = new Map(); } // Function to create and add Vertex object in the Graph addVertex(vertex, rand) { if (this.AdjList.get(vertex) == undefined) { var v = new Vertex(); v.value = vertex; v.pos[0] = rand * scaleW; v.pos[1] = rand * scaleH; this.AdjList.set(vertex, []); this.vertexMap.set(vertex, v); } } // Function to add edge correspond to particular Vertex addEdge(v, w) { // Get the list for Vertex v and put the // Vertex w denoting Edge betweeen v and w this.AdjList.get(v).push(w); } // To print Graph in the form Adjacency List printGraph() { var get_keys = this.AdjList.keys(); for (var i of get_keys) { var get_values = this.AdjList.get(i); var conc = ""; for (var j of get_values) conc += j + " "; print(i + " -> " + conc); } } } // Global variable declarations var result; var k; var widthA = 1000; var length = 800; var scaleW = 0.01 * widthA / 2; var scaleH = 0.01 * length / 2; var temp = widthA / 10; var graph = new Graph(); var area = widthA * length; var maxIter = 100; function fa(x) { return (x * x) / k; } function fr(x) { return (k * k) / x; } // Takes the file name from Url (GET parameter) and loads file in result variable function preload() { // var queryString = window.location.search; // var fileName = queryString.split('='); result = loadStrings('3980.edges'); } // Use data in the file to create Graph object function setup() { createCanvas(widthA + 50, length + 50); var ind = result.length; var rand; for (var i = 0; i < ind; i++) { var splitString = split(result[i], ' '); rand = Math.floor(Math.random() * 1200); graph.addVertex(splitString[0], rand); rand = Math.floor(Math.random() * 1200); graph.addVertex(splitString[1], rand); graph.addEdge(splitString[0], splitString[1]); } // graph.printGraph(); } function draw() { background(255); k = Math.sqrt(area / graph.AdjList.size); // Outermost loop runs till it reaches maxIterations for (var curIter = 0; curIter < maxIter; curIter++) { var vertex_keys = graph.vertexMap.keys(); // ****** Calculate repulsion ****** for (var outerVertexKey of vertex_keys) { var outerVertex = graph.vertexMap.get(outerVertexKey); outerVertex.disp[0] = 0; outerVertex.disp[1] = 0; var inner_vertex_keys = graph.vertexMap.keys(); for (var innerVertexKey of inner_vertex_keys) { if(outerVertexKey != innerVertexKey) { var innerVertex = graph.vertexMap.get(innerVertexKey); var xDelta = outerVertex.pos[0] - innerVertex.pos[0]; var yDelta = outerVertex.pos[1] - innerVertex.pos[1]; var deltaLength = Math.max(0.000001, Math.sqrt(xDelta * xDelta + yDelta * yDelta)); var force = fr(deltaLength); outerVertex.disp[0] += (xDelta / deltaLength) * force; outerVertex.disp[1] += (yDelta / deltaLength) * force; } } } // ****** Calculate attraction ****** var adjListKeys = graph.AdjList.keys(); for (var edgeStartVertex of adjListKeys) { var vertexA = graph.vertexMap.get(edgeStartVertex); var edgeEndVertices = graph.AdjList.get(edgeStartVertex); for (var edgeEndVertex of edgeEndVertices) { var vertexB = graph.vertexMap.get(edgeEndVertex); var xDelta = vertexA.pos[0] - vertexB.pos[0]; var yDelta = vertexA.pos[1] - vertexB.pos[1]; var deltaLength = Math.max(0.000001, Math.sqrt(xDelta*xDelta + yDelta*yDelta)); var force = fa(deltaLength); var xDisp = (xDelta/deltaLength) * force; var yDisp = (yDelta/deltaLength) * force; vertexA.disp[0] -= xDisp; vertexA.disp[1] -= yDisp; vertexB.disp[0] += xDisp; vertexB.disp[1] += yDisp; } } // ****** Calculate position ****** var vertexKeys = graph.vertexMap.keys(); for (var vertextKey of vertexKeys) { var vertex = graph.vertexMap.get(vertextKey); var deltaLength = Math.max(0.000001, Math.sqrt(vertex.disp[0]*vertex.disp[0] + vertex.disp[1]*vertex.disp[1])); var xDisp = vertex.disp[0]/deltaLength * Math.min(deltaLength, temp); var yDisp = vertex.disp[1]/deltaLength * Math.min(deltaLength, temp); vertex.pos[0] += xDisp; vertex.pos[1] += yDisp; // Don't let nodes leave the display var borderWidth = widthA / 50.0; var x = vertex.pos[0]; if (x < 0 + borderWidth) { x = 0 + borderWidth + borderWidth * 2.0; } else if (x > (1000 - borderWidth)) { x = 1000 - borderWidth - borderWidth * 2.0; } var y = vertex.pos[1]; if (y < 0 + borderWidth) { y = 0 + borderWidth + borderWidth * 2.0; } else if (y > (800 - borderWidth)) { y = 800 - borderWidth - borderWidth * 2.0; } vertex.pos[0] = x; vertex.pos[1] = y; } // Cool the temperature temp *= (1.0 - curIter / maxIter); temp = Math.min(temp, widthA); } // Draw Force Directed Layout using calculated var newVertexKeys = graph.vertexMap.keys(); for (var vertextKey of newVertexKeys) { var vertex = graph.vertexMap.get(vertextKey); var xPosition = vertex.pos[0]; var yPosition = vertex.pos[1]; if (sq(mouseX - xPosition) + sq(mouseY - yPosition) < 80) { fill(255, 0, 102); textSize(15); text(vertex.value, mouseX + 20, mouseY - 10); } else { fill(51, 204, 204); } ellipse(xPosition, yPosition, 10, 10); } var r = 0; var g = 0; var b = 0; var adjListKeysPrint = graph.AdjList.keys(); for (var edgeStartVertexPrint of adjListKeysPrint) { if(g >= 255) { b = b + 10; r = r + 60 g = 0; } else if(b >= 255) { g = g + 30; r = r + 40; b = 0; } else if(r >= 255) { b = b + 70; g = g + 50; r = 0; } else { r += 50; g += 30; b += 100; } var vertexAPrint = graph.vertexMap.get(edgeStartVertexPrint); var edgeEndVerticesPrint = graph.AdjList.get(edgeStartVertexPrint); for (var edgeEndVertexPrint of edgeEndVerticesPrint) { var vertexBPrint = graph.vertexMap.get(edgeEndVertexPrint); push(); stroke(r, g, b); line(vertexAPrint.pos[0], vertexAPrint.pos[1], vertexBPrint.pos[0], vertexBPrint.pos[1]); pop(); } } }