A reference example for implementing treemaps in D3.js, showing the flare software package hierarchy.
This example is intentionally basic, and it lacks many important features such as labels or interaction.
# layout, behaviors and scales | |
SCALE = 400 | |
PADDING = 8 | |
TIP = 10 | |
treemap = d3.layout.treemap() | |
.size([SCALE, SCALE]) | |
.value((node) -> node.size) | |
svg = d3.select('svg') | |
width = svg.node().getBoundingClientRect().width | |
height = svg.node().getBoundingClientRect().height | |
# translate the viewBox to have (0,0) at the center of the vis | |
svg | |
.attr | |
viewBox: "#{-width/2} #{-height/2} #{width} #{height}" | |
# append a group for zoomable content | |
zoomable_layer = svg.append('g') | |
# define a zoom behavior | |
zoom = d3.behavior.zoom() | |
.scaleExtent([1,10]) # min-max zoom | |
.on 'zoom', () -> | |
# GEOMETRIC ZOOM | |
zoomable_layer | |
.attr | |
transform: "translate(#{zoom.translate()})scale(#{zoom.scale()})" | |
# bind the zoom behavior to the main SVG | |
svg.call(zoom) | |
# group the visualization | |
vis = zoomable_layer.append('g') | |
.attr | |
transform: "translate(#{-SCALE/2},#{-SCALE/2})" | |
d3.json 'http://wafi.iit.cnr.it/webvis/tmp/flare.json', (tree) -> | |
nodes_data = treemap.nodes(tree) | |
nodes = vis.selectAll('.node') | |
.data(nodes_data) | |
enter_nodes = nodes.enter().insert('rect','rect') | |
.attr | |
class: 'node' | |
x: (node) -> node.x | |
y: (node) -> node.y | |
width: (node) -> node.dx | |
height: (node) -> node.dy | |
stroke: (node) -> | |
switch node.depth | |
when 0 then '#333' | |
when 1 then '#999' | |
else '#DDD' | |
'stroke-width': (node) -> | |
switch node.depth | |
when 0 then 3 | |
when 1 then 2 | |
else 1 | |
enter_nodes.append('title') | |
.text((node) -> node.name) | |
svg { | |
background: white; | |
} | |
.node { | |
shape-rendering: crispEdges; | |
vector-effect: non-scaling-stroke; | |
fill: none; | |
} | |
.label { | |
text-anchor: middle; | |
font-family: sans-serif; | |
/*text-shadow: -1px 0 white, 0 1px white, 1px 0 white, 0 -1px white;*/ | |
text-shadow: -2px 0 white, 0 2px white, 2px 0 white, 0 -2px white, -1px -1px white, 1px -1px white, 1px 1px white, -1px 1px white; | |
} |
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<meta name="description" content="Basic treemap (flare)" /> | |
<title>Basic treemap (flare)</title> | |
<link type="text/css" href="index.css" rel="stylesheet"/> | |
<script src="http://d3js.org/d3.v3.min.js"></script> | |
</head> | |
<body> | |
<svg height="500" width="960"></svg> | |
<script src="index.js"></script> | |
</body> | |
</html> |
(function() { | |
var PADDING, SCALE, TIP, height, svg, treemap, vis, width, zoom, zoomable_layer; | |
SCALE = 400; | |
PADDING = 8; | |
TIP = 10; | |
treemap = d3.layout.treemap().size([SCALE, SCALE]).value(function(node) { | |
return node.size; | |
}); | |
svg = d3.select('svg'); | |
width = svg.node().getBoundingClientRect().width; | |
height = svg.node().getBoundingClientRect().height; | |
svg.attr({ | |
viewBox: "" + (-width / 2) + " " + (-height / 2) + " " + width + " " + height | |
}); | |
zoomable_layer = svg.append('g'); | |
zoom = d3.behavior.zoom().scaleExtent([1, 10]).on('zoom', function() { | |
return zoomable_layer.attr({ | |
transform: "translate(" + (zoom.translate()) + ")scale(" + (zoom.scale()) + ")" | |
}); | |
}); | |
svg.call(zoom); | |
vis = zoomable_layer.append('g').attr({ | |
transform: "translate(" + (-SCALE / 2) + "," + (-SCALE / 2) + ")" | |
}); | |
d3.json('http://wafi.iit.cnr.it/webvis/tmp/flare.json', function(tree) { | |
var enter_nodes, nodes, nodes_data; | |
nodes_data = treemap.nodes(tree); | |
nodes = vis.selectAll('.node').data(nodes_data); | |
enter_nodes = nodes.enter().insert('rect', 'rect').attr({ | |
"class": 'node', | |
x: function(node) { | |
return node.x; | |
}, | |
y: function(node) { | |
return node.y; | |
}, | |
width: function(node) { | |
return node.dx; | |
}, | |
height: function(node) { | |
return node.dy; | |
}, | |
stroke: function(node) { | |
switch (node.depth) { | |
case 0: | |
return '#333'; | |
case 1: | |
return '#999'; | |
default: | |
return '#DDD'; | |
} | |
}, | |
'stroke-width': function(node) { | |
switch (node.depth) { | |
case 0: | |
return 3; | |
case 1: | |
return 2; | |
default: | |
return 1; | |
} | |
} | |
}); | |
return enter_nodes.append('title').text(function(node) { | |
return node.name; | |
}); | |
}); | |
}).call(this); |