Interactive network graphs in JavaScript with CanvasXpress

JavaScript
CanvasXpress
network
visualization
Build a draggable, force-directed network in the browser from nodes and edges — interactive and reproducible from one portable spec.
Author

Isaac Neuhaus

Published

October 31, 2026

A network graph shows relationships: nodes connected by edges, laid out so connected things sit near each other. In the browser the common answer is to hand-roll a force simulation in D3 — a few hundred lines. CanvasXpress is a JavaScript library at heart, so the whole thing is a data object of nodes and edges plus a config.

Load the library

<link href="https://cdn.jsdelivr.net/gh/neuhausi/canvasXpress@73.3.0/inst/htmlwidgets/lib/canvasXpress/canvasXpress.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/gh/neuhausi/canvasXpress@73.3.0/inst/htmlwidgets/lib/canvasXpress/canvasXpress.min.js"></script>

The markup and the spec

Nodes carry id, name, group; edges carry id1, id2, value. colorNodeBy colours by community and networkLayoutType: "forceDirected" runs the physics.

<canvas id="network" width="650" height="500"></canvas>
<script>
  var groups = ["Alpha", "Beta", "Gamma"], nodes = [], byGroup = {}, k = 0;
  groups.forEach(function (g) {
    byGroup[g] = [];
    for (var i = 0; i < 7; i++) {
      var nid = "n" + k; nodes.push({ id: nid, name: g + (i + 1), group: g });
      byGroup[g].push(nid); k++;
    }
  });

  var edges = [];
  groups.forEach(function (g) {                         // dense within a community
    var m = byGroup[g];
    for (var i = 0; i < m.length; i++)
      for (var j = i + 1; j < m.length; j++)
        if (Math.random() < 0.5)
          edges.push({ id1: m[i], id2: m[j], value: 1 + Math.floor(Math.random() * 5) });
  });
  for (var e = 0; e < 6; e++) {                         // a few cross-community links
    var pair = groups.slice().sort(function () { return Math.random() - 0.5; }).slice(0, 2);
    var a = byGroup[pair[0]], b = byGroup[pair[1]];
    edges.push({ id1: a[Math.floor(Math.random() * a.length)],
                 id2: b[Math.floor(Math.random() * b.length)], value: 1 });
  }

  var config = {
    graphType: "Network",
    networkLayoutType: "forceDirected",
    colorNodeBy: "group",
    nodeSize: 25,
    showAnimation: true,
    title: "A small community network"
  };

  new CanvasXpress("network", { nodes: nodes, edges: edges }, config);
</script>

Live result

Drag any node and the layout settles around it; hover to read the label. The three communities separate on their own because within-group edges outnumber the cross-group ones.

Why “reproducible”

The nodes, edges and config are the figure — one portable JSON spec that renders the same from R, Python, or a web page.

Next