Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I draw a graph or tree structure in JavaScript? [closed]

I need to be able to draw graphs like the following in JavaScript:

crazy graph picture

I know about the Raphael library, but it's only for drawing arbitrary shapes.

I have a few predefined node types (the colored nodes on the image) and text nearby/inside every node. This library doesn't seem to handle that case. How do I do this in JavaScript? If this has been accomplished already by another library, how can I use that library to solve this problem?

like image 581
Alexey Avatar asked Apr 17 '13 10:04

Alexey


People also ask

Does JavaScript have tree data structure?

In this article, we would be implementing the Binary Search Tree data structure in Javascript. A tree is a collection of nodes connected by some edges. A tree is a non linear data structure.

What is treenode in JavaScript?

A tree is a data structure where a node can have zero or more children. Each node contains a value. Like graphs, the connection between nodes is called edges. A tree is a type of graph, but not all graphs are trees (more on that later).

Is the DOM a tree or graph?

A real world example of a tree data structure is the HTML Document Object Model (DOM) structure.


1 Answers

The web is a fast moving world, and so this answer was somewhat out of date. With that in mind, I've refreshed this answer to make it applicable in 2016.

  • D3.js - This would still be my recommendation. It's under active development and has a vibrant community.
  • Vega - An expressive language (less powerful than D3)
  • Cytoscape.js
  • Spring.js
  • cola.js

I would add that I've only used D3.js in this new list, it's power and flexibility are such that I've never needed to find an alternative. Here is an example implementation of a force directed.

var width = 960,      height = 500;    var color = d3.scale.category20();    var force = d3.layout.force()      .charge(-120)      .linkDistance(30)      .size([width, height]);    var svg = d3.select("body").append("svg")      .attr("width", width)      .attr("height", height);    d3.json("https://gist.githubusercontent.com/mbostock/4062045/raw/4176c7d0c0c5ce15630d16072da0af67bb50eb6a/miserables.json", function(error, graph) {    if (error) throw error;      force        .nodes(graph.nodes)        .links(graph.links)        .start();      var link = svg.selectAll(".link")        .data(graph.links)      .enter().append("line")        .attr("class", "link")        .style("stroke-width", function(d) { return Math.sqrt(d.value); });      var node = svg.selectAll(".node")        .data(graph.nodes)      .enter().append("circle")        .attr("class", "node")        .attr("r", 5)        .style("fill", function(d) { return color(d.group); })        .call(force.drag);      node.append("title")        .text(function(d) { return d.name; });      force.on("tick", function() {      link.attr("x1", function(d) { return d.source.x; })          .attr("y1", function(d) { return d.source.y; })          .attr("x2", function(d) { return d.target.x; })          .attr("y2", function(d) { return d.target.y; });        node.attr("cx", function(d) { return d.x; })          .attr("cy", function(d) { return d.y; });    });  });
.node {    stroke: #fff;    stroke-width: 1.5px;  }    .link {    stroke: #999;    stroke-opacity: .6;  }
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>

There are a number of libraries for drawing this sort of output in a browser, you've mentioned Raphael, others include:

  • Sigma.js
  • Processing.js
  • jit.js - Sold to SenchaLabs. The solo developer appeared to stop working on it.
  • D3.js
  • Raphael.js - Seems to have disappeared, their main site has gone

I personally would recommend the latter, D3 depending on the number of items you wish to display and the browser support you need as it's well documented, powerful and faily easy to use. Check out this Github project for an example of a force-directed library.

The changes that you would need to make to accomplish the task you've set out would be to:

1) Change where the data is coming from by modifying the following function:

d3.json("flare.json", function(json) {    root = json;    root.fixed = true;    root.x = w / 2;    root.y = h / 2 - 80;    update();  }); 

Change the d3.json("flare.json") to point to a different file/URL on your server. It is possible to do the same thing with jQuery if you wished and use a similar callback approach.

2) To colour your nodes based on different categories you'll want to change the following section:

// Update the nodes…   node = vis.selectAll("circle.node")       .data(nodes, function(d) { return d.id; })       .style("fill", color); 

Change the .style("fill", color); to something along the lines of:

.style("fill", function(d) {      switch(d.category) {        case A: return "#FF0000";        case B: return "#00FF00";        default: return "#0000FF";     } }); 

Where category is a property on the JSON data object that you want to vary by.

like image 71
Ian Avatar answered Sep 21 '22 17:09

Ian