Skip to content

Instantly share code, notes, and snippets.

@mbostock
Forked from mbostock/.block
Last active October 17, 2017 17:20
Show Gist options
  • Save mbostock/3180395 to your computer and use it in GitHub Desktop.
Save mbostock/3180395 to your computer and use it in GitHub Desktop.
Force Layout with Canvas
license: gpl-3.0

This example demonstrates rendering a D3 force-directed graph using Canvas rather than SVG. The performance is slightly better than SVG, but unlike the SVG version, the nodes in this one are not draggable.

{"nodes":[{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{},{}],"links":[{"source":0,"target":0},{"source":1,"target":0},{"source":15,"target":0},{"source":16,"target":0},{"source":17,"target":0},{"source":31,"target":0},{"source":64,"target":0},{"source":65,"target":0},{"source":79,"target":0},{"source":1,"target":1},{"source":2,"target":1},{"source":16,"target":1},{"source":17,"target":1},{"source":18,"target":1},{"source":64,"target":1},{"source":65,"target":1},{"source":66,"target":1},{"source":2,"target":2},{"source":3,"target":2},{"source":17,"target":2},{"source":18,"target":2},{"source":19,"target":2},{"source":65,"target":2},{"source":66,"target":2},{"source":67,"target":2},{"source":3,"target":3},{"source":4,"target":3},{"source":18,"target":3},{"source":19,"target":3},{"source":20,"target":3},{"source":66,"target":3},{"source":67,"target":3},{"source":68,"target":3},{"source":4,"target":4},{"source":5,"target":4},{"source":19,"target":4},{"source":20,"target":4},{"source":21,"target":4},{"source":67,"target":4},{"source":68,"target":4},{"source":69,"target":4},{"source":5,"target":5},{"source":6,"target":5},{"source":20,"target":5},{"source":21,"target":5},{"source":22,"target":5},{"source":68,"target":5},{"source":69,"target":5},{"source":70,"target":5},{"source":6,"target":6},{"source":7,"target":6},{"source":21,"target":6},{"source":22,"target":6},{"source":23,"target":6},{"source":69,"target":6},{"source":70,"target":6},{"source":71,"target":6},{"source":7,"target":7},{"source":8,"target":7},{"source":22,"target":7},{"source":23,"target":7},{"source":24,"target":7},{"source":70,"target":7},{"source":71,"target":7},{"source":72,"target":7},{"source":8,"target":8},{"source":9,"target":8},{"source":23,"target":8},{"source":24,"target":8},{"source":25,"target":8},{"source":71,"target":8},{"source":72,"target":8},{"source":73,"target":8},{"source":9,"target":9},{"source":10,"target":9},{"source":24,"target":9},{"source":25,"target":9},{"source":26,"target":9},{"source":72,"target":9},{"source":73,"target":9},{"source":74,"target":9},{"source":10,"target":10},{"source":11,"target":10},{"source":25,"target":10},{"source":26,"target":10},{"source":27,"target":10},{"source":73,"target":10},{"source":74,"target":10},{"source":75,"target":10},{"source":11,"target":11},{"source":12,"target":11},{"source":26,"target":11},{"source":27,"target":11},{"source":28,"target":11},{"source":74,"target":11},{"source":75,"target":11},{"source":76,"target":11},{"source":12,"target":12},{"source":13,"target":12},{"source":27,"target":12},{"source":28,"target":12},{"source":29,"target":12},{"source":75,"target":12},{"source":76,"target":12},{"source":77,"target":12},{"source":13,"target":13},{"source":14,"target":13},{"source":28,"target":13},{"source":29,"target":13},{"source":30,"target":13},{"source":76,"target":13},{"source":77,"target":13},{"source":78,"target":13},{"source":14,"target":14},{"source":15,"target":14},{"source":29,"target":14},{"source":30,"target":14},{"source":31,"target":14},{"source":77,"target":14},{"source":78,"target":14},{"source":79,"target":14},{"source":15,"target":15},{"source":16,"target":15},{"source":30,"target":15},{"source":31,"target":15},{"source":64,"target":15},{"source":78,"target":15},{"source":79,"target":15},{"source":16,"target":16},{"source":17,"target":16},{"source":31,"target":16},{"source":32,"target":16},{"source":33,"target":16},{"source":47,"target":16},{"source":17,"target":17},{"source":18,"target":17},{"source":32,"target":17},{"source":33,"target":17},{"source":34,"target":17},{"source":18,"target":18},{"source":19,"target":18},{"source":33,"target":18},{"source":34,"target":18},{"source":35,"target":18},{"source":19,"target":19},{"source":20,"target":19},{"source":34,"target":19},{"source":35,"target":19},{"source":36,"target":19},{"source":20,"target":20},{"source":21,"target":20},{"source":35,"target":20},{"source":36,"target":20},{"source":37,"target":20},{"source":21,"target":21},{"source":22,"target":21},{"source":36,"target":21},{"source":37,"target":21},{"source":38,"target":21},{"source":22,"target":22},{"source":23,"target":22},{"source":37,"target":22},{"source":38,"target":22},{"source":39,"target":22},{"source":23,"target":23},{"source":24,"target":23},{"source":38,"target":23},{"source":39,"target":23},{"source":40,"target":23},{"source":24,"target":24},{"source":25,"target":24},{"source":39,"target":24},{"source":40,"target":24},{"source":41,"target":24},{"source":25,"target":25},{"source":26,"target":25},{"source":40,"target":25},{"source":41,"target":25},{"source":42,"target":25},{"source":26,"target":26},{"source":27,"target":26},{"source":41,"target":26},{"source":42,"target":26},{"source":43,"target":26},{"source":27,"target":27},{"source":28,"target":27},{"source":42,"target":27},{"source":43,"target":27},{"source":44,"target":27},{"source":28,"target":28},{"source":29,"target":28},{"source":43,"target":28},{"source":44,"target":28},{"source":45,"target":28},{"source":29,"target":29},{"source":30,"target":29},{"source":44,"target":29},{"source":45,"target":29},{"source":46,"target":29},{"source":30,"target":30},{"source":31,"target":30},{"source":45,"target":30},{"source":46,"target":30},{"source":47,"target":30},{"source":31,"target":31},{"source":32,"target":31},{"source":46,"target":31},{"source":47,"target":31},{"source":32,"target":32},{"source":33,"target":32},{"source":47,"target":32},{"source":48,"target":32},{"source":49,"target":32},{"source":63,"target":32},{"source":33,"target":33},{"source":34,"target":33},{"source":48,"target":33},{"source":49,"target":33},{"source":50,"target":33},{"source":34,"target":34},{"source":35,"target":34},{"source":49,"target":34},{"source":50,"target":34},{"source":51,"target":34},{"source":35,"target":35},{"source":36,"target":35},{"source":50,"target":35},{"source":51,"target":35},{"source":52,"target":35},{"source":36,"target":36},{"source":37,"target":36},{"source":51,"target":36},{"source":52,"target":36},{"source":53,"target":36},{"source":37,"target":37},{"source":38,"target":37},{"source":52,"target":37},{"source":53,"target":37},{"source":54,"target":37},{"source":38,"target":38},{"source":39,"target":38},{"source":53,"target":38},{"source":54,"target":38},{"source":55,"target":38},{"source":39,"target":39},{"source":40,"target":39},{"source":54,"target":39},{"source":55,"target":39},{"source":56,"target":39},{"source":40,"target":40},{"source":41,"target":40},{"source":55,"target":40},{"source":56,"target":40},{"source":57,"target":40},{"source":41,"target":41},{"source":42,"target":41},{"source":56,"target":41},{"source":57,"target":41},{"source":58,"target":41},{"source":42,"target":42},{"source":43,"target":42},{"source":57,"target":42},{"source":58,"target":42},{"source":59,"target":42},{"source":43,"target":43},{"source":44,"target":43},{"source":58,"target":43},{"source":59,"target":43},{"source":60,"target":43},{"source":44,"target":44},{"source":45,"target":44},{"source":59,"target":44},{"source":60,"target":44},{"source":61,"target":44},{"source":45,"target":45},{"source":46,"target":45},{"source":60,"target":45},{"source":61,"target":45},{"source":62,"target":45},{"source":46,"target":46},{"source":47,"target":46},{"source":61,"target":46},{"source":62,"target":46},{"source":63,"target":46},{"source":47,"target":47},{"source":48,"target":47},{"source":62,"target":47},{"source":63,"target":47},{"source":48,"target":48},{"source":49,"target":48},{"source":63,"target":48},{"source":49,"target":49},{"source":50,"target":49},{"source":50,"target":50},{"source":51,"target":50},{"source":51,"target":51},{"source":52,"target":51},{"source":52,"target":52},{"source":53,"target":52},{"source":53,"target":53},{"source":54,"target":53},{"source":54,"target":54},{"source":55,"target":54},{"source":55,"target":55},{"source":56,"target":55},{"source":56,"target":56},{"source":57,"target":56},{"source":57,"target":57},{"source":58,"target":57},{"source":58,"target":58},{"source":59,"target":58},{"source":59,"target":59},{"source":60,"target":59},{"source":60,"target":60},{"source":61,"target":60},{"source":61,"target":61},{"source":62,"target":61},{"source":62,"target":62},{"source":63,"target":62},{"source":63,"target":63},{"source":64,"target":64},{"source":65,"target":64},{"source":79,"target":64},{"source":80,"target":64},{"source":81,"target":64},{"source":95,"target":64},{"source":65,"target":65},{"source":66,"target":65},{"source":80,"target":65},{"source":81,"target":65},{"source":82,"target":65},{"source":66,"target":66},{"source":67,"target":66},{"source":81,"target":66},{"source":82,"target":66},{"source":83,"target":66},{"source":67,"target":67},{"source":68,"target":67},{"source":82,"target":67},{"source":83,"target":67},{"source":84,"target":67},{"source":68,"target":68},{"source":69,"target":68},{"source":83,"target":68},{"source":84,"target":68},{"source":85,"target":68},{"source":69,"target":69},{"source":70,"target":69},{"source":84,"target":69},{"source":85,"target":69},{"source":86,"target":69},{"source":70,"target":70},{"source":71,"target":70},{"source":85,"target":70},{"source":86,"target":70},{"source":87,"target":70},{"source":71,"target":71},{"source":72,"target":71},{"source":86,"target":71},{"source":87,"target":71},{"source":88,"target":71},{"source":72,"target":72},{"source":73,"target":72},{"source":87,"target":72},{"source":88,"target":72},{"source":89,"target":72},{"source":73,"target":73},{"source":74,"target":73},{"source":88,"target":73},{"source":89,"target":73},{"source":90,"target":73},{"source":74,"target":74},{"source":75,"target":74},{"source":89,"target":74},{"source":90,"target":74},{"source":91,"target":74},{"source":75,"target":75},{"source":76,"target":75},{"source":90,"target":75},{"source":91,"target":75},{"source":92,"target":75},{"source":76,"target":76},{"source":77,"target":76},{"source":91,"target":76},{"source":92,"target":76},{"source":93,"target":76},{"source":77,"target":77},{"source":78,"target":77},{"source":92,"target":77},{"source":93,"target":77},{"source":94,"target":77},{"source":78,"target":78},{"source":79,"target":78},{"source":93,"target":78},{"source":94,"target":78},{"source":95,"target":78},{"source":79,"target":79},{"source":80,"target":79},{"source":94,"target":79},{"source":95,"target":79},{"source":80,"target":80},{"source":81,"target":80},{"source":95,"target":80},{"source":96,"target":80},{"source":97,"target":80},{"source":111,"target":80},{"source":81,"target":81},{"source":82,"target":81},{"source":96,"target":81},{"source":97,"target":81},{"source":98,"target":81},{"source":82,"target":82},{"source":83,"target":82},{"source":97,"target":82},{"source":98,"target":82},{"source":99,"target":82},{"source":83,"target":83},{"source":84,"target":83},{"source":98,"target":83},{"source":99,"target":83},{"source":100,"target":83},{"source":84,"target":84},{"source":85,"target":84},{"source":99,"target":84},{"source":100,"target":84},{"source":101,"target":84},{"source":85,"target":85},{"source":86,"target":85},{"source":100,"target":85},{"source":101,"target":85},{"source":102,"target":85},{"source":86,"target":86},{"source":87,"target":86},{"source":101,"target":86},{"source":102,"target":86},{"source":103,"target":86},{"source":87,"target":87},{"source":88,"target":87},{"source":102,"target":87},{"source":103,"target":87},{"source":104,"target":87},{"source":88,"target":88},{"source":89,"target":88},{"source":103,"target":88},{"source":104,"target":88},{"source":105,"target":88},{"source":89,"target":89},{"source":90,"target":89},{"source":104,"target":89},{"source":105,"target":89},{"source":106,"target":89},{"source":90,"target":90},{"source":91,"target":90},{"source":105,"target":90},{"source":106,"target":90},{"source":107,"target":90},{"source":91,"target":91},{"source":92,"target":91},{"source":106,"target":91},{"source":107,"target":91},{"source":108,"target":91},{"source":92,"target":92},{"source":93,"target":92},{"source":107,"target":92},{"source":108,"target":92},{"source":109,"target":92},{"source":93,"target":93},{"source":94,"target":93},{"source":108,"target":93},{"source":109,"target":93},{"source":110,"target":93},{"source":94,"target":94},{"source":95,"target":94},{"source":109,"target":94},{"source":110,"target":94},{"source":111,"target":94},{"source":95,"target":95},{"source":96,"target":95},{"source":110,"target":95},{"source":111,"target":95},{"source":96,"target":96},{"source":97,"target":96},{"source":111,"target":96},{"source":112,"target":96},{"source":113,"target":96},{"source":127,"target":96},{"source":97,"target":97},{"source":98,"target":97},{"source":112,"target":97},{"source":113,"target":97},{"source":114,"target":97},{"source":98,"target":98},{"source":99,"target":98},{"source":113,"target":98},{"source":114,"target":98},{"source":115,"target":98},{"source":99,"target":99},{"source":100,"target":99},{"source":114,"target":99},{"source":115,"target":99},{"source":116,"target":99},{"source":100,"target":100},{"source":101,"target":100},{"source":115,"target":100},{"source":116,"target":100},{"source":117,"target":100},{"source":101,"target":101},{"source":102,"target":101},{"source":116,"target":101},{"source":117,"target":101},{"source":118,"target":101},{"source":102,"target":102},{"source":103,"target":102},{"source":117,"target":102},{"source":118,"target":102},{"source":119,"target":102},{"source":103,"target":103},{"source":104,"target":103},{"source":118,"target":103},{"source":119,"target":103},{"source":120,"target":103},{"source":104,"target":104},{"source":105,"target":104},{"source":119,"target":104},{"source":120,"target":104},{"source":121,"target":104},{"source":105,"target":105},{"source":106,"target":105},{"source":120,"target":105},{"source":121,"target":105},{"source":122,"target":105},{"source":106,"target":106},{"source":107,"target":106},{"source":121,"target":106},{"source":122,"target":106},{"source":123,"target":106},{"source":107,"target":107},{"source":108,"target":107},{"source":122,"target":107},{"source":123,"target":107},{"source":124,"target":107},{"source":108,"target":108},{"source":109,"target":108},{"source":123,"target":108},{"source":124,"target":108},{"source":125,"target":108},{"source":109,"target":109},{"source":110,"target":109},{"source":124,"target":109},{"source":125,"target":109},{"source":126,"target":109},{"source":110,"target":110},{"source":111,"target":110},{"source":125,"target":110},{"source":126,"target":110},{"source":127,"target":110},{"source":111,"target":111},{"source":112,"target":111},{"source":126,"target":111},{"source":127,"target":111},{"source":112,"target":112},{"source":113,"target":112},{"source":127,"target":112},{"source":128,"target":112},{"source":129,"target":112},{"source":143,"target":112},{"source":113,"target":113},{"source":114,"target":113},{"source":128,"target":113},{"source":129,"target":113},{"source":130,"target":113},{"source":114,"target":114},{"source":115,"target":114},{"source":129,"target":114},{"source":130,"target":114},{"source":131,"target":114},{"source":115,"target":115},{"source":116,"target":115},{"source":130,"target":115},{"source":131,"target":115},{"source":132,"target":115},{"source":116,"target":116},{"source":117,"target":116},{"source":131,"target":116},{"source":132,"target":116},{"source":133,"target":116},{"source":117,"target":117},{"source":118,"target":117},{"source":132,"target":117},{"source":133,"target":117},{"source":134,"target":117},{"source":118,"target":118},{"source":119,"target":118},{"source":133,"target":118},{"source":134,"target":118},{"source":135,"target":118},{"source":119,"target":119},{"source":120,"target":119},{"source":134,"target":119},{"source":135,"target":119},{"source":136,"target":119},{"source":120,"target":120},{"source":121,"target":120},{"source":135,"target":120},{"source":136,"target":120},{"source":137,"target":120},{"source":121,"target":121},{"source":122,"target":121},{"source":136,"target":121},{"source":137,"target":121},{"source":138,"target":121},{"source":122,"target":122},{"source":123,"target":122},{"source":137,"target":122},{"source":138,"target":122},{"source":139,"target":122},{"source":123,"target":123},{"source":124,"target":123},{"source":138,"target":123},{"source":139,"target":123},{"source":140,"target":123},{"source":124,"target":124},{"source":125,"target":124},{"source":139,"target":124},{"source":140,"target":124},{"source":141,"target":124},{"source":125,"target":125},{"source":126,"target":125},{"source":140,"target":125},{"source":141,"target":125},{"source":142,"target":125},{"source":126,"target":126},{"source":127,"target":126},{"source":141,"target":126},{"source":142,"target":126},{"source":143,"target":126},{"source":127,"target":127},{"source":128,"target":127},{"source":142,"target":127},{"source":143,"target":127},{"source":128,"target":128},{"source":129,"target":128},{"source":143,"target":128},{"source":144,"target":128},{"source":145,"target":128},{"source":159,"target":128},{"source":129,"target":129},{"source":130,"target":129},{"source":144,"target":129},{"source":145,"target":129},{"source":146,"target":129},{"source":130,"target":130},{"source":131,"target":130},{"source":145,"target":130},{"source":146,"target":130},{"source":147,"target":130},{"source":131,"target":131},{"source":132,"target":131},{"source":146,"target":131},{"source":147,"target":131},{"source":148,"target":131},{"source":132,"target":132},{"source":133,"target":132},{"source":147,"target":132},{"source":148,"target":132},{"source":149,"target":132},{"source":133,"target":133},{"source":134,"target":133},{"source":148,"target":133},{"source":149,"target":133},{"source":150,"target":133},{"source":134,"target":134},{"source":135,"target":134},{"source":149,"target":134},{"source":150,"target":134},{"source":151,"target":134},{"source":135,"target":135},{"source":136,"target":135},{"source":150,"target":135},{"source":151,"target":135},{"source":152,"target":135},{"source":136,"target":136},{"source":137,"target":136},{"source":151,"target":136},{"source":152,"target":136},{"source":153,"target":136},{"source":137,"target":137},{"source":138,"target":137},{"source":152,"target":137},{"source":153,"target":137},{"source":154,"target":137},{"source":138,"target":138},{"source":139,"target":138},{"source":153,"target":138},{"source":154,"target":138},{"source":155,"target":138},{"source":139,"target":139},{"source":140,"target":139},{"source":154,"target":139},{"source":155,"target":139},{"source":156,"target":139},{"source":140,"target":140},{"source":141,"target":140},{"source":155,"target":140},{"source":156,"target":140},{"source":157,"target":140},{"source":141,"target":141},{"source":142,"target":141},{"source":156,"target":141},{"source":157,"target":141},{"source":158,"target":141},{"source":142,"target":142},{"source":143,"target":142},{"source":157,"target":142},{"source":158,"target":142},{"source":159,"target":142},{"source":143,"target":143},{"source":144,"target":143},{"source":158,"target":143},{"source":159,"target":143},{"source":144,"target":144},{"source":145,"target":144},{"source":159,"target":144},{"source":160,"target":144},{"source":145,"target":145},{"source":146,"target":145},{"source":160,"target":145},{"source":146,"target":146},{"source":147,"target":146},{"source":160,"target":146},{"source":147,"target":147},{"source":148,"target":147},{"source":160,"target":147},{"source":148,"target":148},{"source":149,"target":148},{"source":160,"target":148},{"source":149,"target":149},{"source":150,"target":149},{"source":160,"target":149},{"source":150,"target":150},{"source":151,"target":150},{"source":160,"target":150},{"source":151,"target":151},{"source":152,"target":151},{"source":160,"target":151},{"source":152,"target":152},{"source":153,"target":152},{"source":160,"target":152},{"source":153,"target":153},{"source":154,"target":153},{"source":160,"target":153},{"source":154,"target":154},{"source":155,"target":154},{"source":160,"target":154},{"source":155,"target":155},{"source":156,"target":155},{"source":160,"target":155},{"source":156,"target":156},{"source":157,"target":156},{"source":160,"target":156},{"source":157,"target":157},{"source":158,"target":157},{"source":160,"target":157},{"source":158,"target":158},{"source":159,"target":158},{"source":160,"target":158},{"source":159,"target":159},{"source":160,"target":159},{"source":160,"target":160}]}
<!DOCTYPE html>
<meta charset="utf-8">
<body>
<script src="//d3js.org/d3.v3.min.js"></script>
<script>
var width = 960,
height = 500;
var canvas = d3.select("body").append("canvas")
.attr("width", width)
.attr("height", height);
var force = d3.layout.force()
.size([width, height]);
d3.json("graph.json", function(error, graph) {
if (error) throw error;
var context = canvas.node().getContext("2d");
force
.nodes(graph.nodes)
.links(graph.links)
.on("tick", tick)
.start();
function tick() {
context.clearRect(0, 0, width, height);
// draw links
context.strokeStyle = "#ccc";
context.beginPath();
graph.links.forEach(function(d) {
context.moveTo(d.source.x, d.source.y);
context.lineTo(d.target.x, d.target.y);
});
context.stroke();
// draw nodes
context.fillStyle = "steelblue";
context.beginPath();
graph.nodes.forEach(function(d) {
context.moveTo(d.x, d.y);
context.arc(d.x, d.y, 4.5, 0, 2 * Math.PI);
});
context.fill();
}
});
</script>
@chandram
Copy link

This is awesome Mike. I am looking for one to my current force layout (SVG based has poor performance in FF). But how to make the nodes clickable & drag able.

Thanks.

@sirusb
Copy link

sirusb commented Jul 3, 2014

You can combine sigma.js (to draw the graph and canvas events) and d3js to do the layout

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment