Skip to content

Instantly share code, notes, and snippets.

@bobbydavid
Last active December 18, 2015 15:59
Show Gist options
  • Save bobbydavid/5808079 to your computer and use it in GitHub Desktop.
Save bobbydavid/5808079 to your computer and use it in GitHub Desktop.
d3 meta-visualization
<!doctype html>
<meta charset="utf-8">
<!-- author: Robert Martin -->
<style>
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
margin: auto;
position: relative;
width: 960px;
}
form {
position: absolute;
right: 10px;
top: 10px;
}
#breadcrumb {
position: absolute;
left: 10px;
top: 10px;
}
.node {
border: solid 1px white;
font: 10px sans-serif;
line-height: 12px;
overflow: hidden;
position: absolute;
text-indent: 2px;
}
</style>
<form>
<label><input type="radio" name="mode" value="min" checked> d3.v3.min.js</label>
<label><input type="radio" name="mode" value="full"> d3.v3.js</label>
</form>
<div id="breadcrumb"></div>
<div id="container"></div>
<script src="http://d3js.org/d3.v3.js"></script>
<script>
var d3Full = d3;
</script>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
var svgMarginTop = 40;
var svgWidth = 960, svgHeight = 500 - svgMarginTop;
var globalIndex = 0;
var getRecursiveSize = function(key, val) {
var node = { name: key, index: globalIndex++ };
switch (typeof(val)) {
case 'object':
var children = [];
for (i in val) {
children.push(getRecursiveSize(i, val[i]));
}
if (children.length == 0) {
node.size = 2;
} else {
node.children = children;
}
break;
case 'boolean':
case 'number':
case 'string':
node.size = val.toString().length;
break;
case 'function':
node.name += '()';
node.size = val.toString().length;
break;
default:
console.log('cannot handle type: ' + typeof(val));
throw new Error();
}
return node;
}
var recursiveAdd = function(minNode, fullNode) {
if (minNode.children) {
minNode.children.forEach(function(child, index) {
recursiveAdd(child, fullNode.children[index]);
});
} else {
minNode.minSize = minNode.size;
minNode.fullSize = fullNode.size;
delete minNode.size;
}
};
var root = getRecursiveSize('d3', d3);
recursiveAdd(root, getRecursiveSize('d3', d3Full));
// Create d3 elements.
var treemap = d3.layout.treemap()
.sticky(true)
.value(function(d) { return d.minSize; })
.size([svgWidth, svgHeight]);
// Create visual elements.
var div = d3.select('#container')
.style('position', 'relative')
.style('width', svgWidth + 'px')
.style('height', svgHeight + 'px')
.style('top', svgMarginTop + 'px');
var color = d3.scale.category20c();
var node = div.datum(root).selectAll('.node')
.data(treemap.nodes)
.enter().append('div')
.attr('class', 'node')
.call(position)
.style('background', function(d) { return d.children ? color(d.index) : null; })
.text(function(d) {
return d.children ?
null : d.name + ' ' + Math.round(d.value / root.value * 1000) / 10 + '%';
});
var breadcrumb = d3.select('#breadcrumb');
// Create interaction.
d3.selectAll('input').on('change', function() {
var getValue = (this.value == 'min') ? function(d) { return d.minSize; } :
function(d) { return d.fullSize; };
treemap.value(getValue);
node.data(treemap.nodes)
.transition()
.duration(1000)
.call(position);
});
node.on('mouseover', function(node) {
var ancestors = [node];
var breadcrumbText = node.name;
while (node.parent) {
ancestors.push(node.parent);
node = node.parent;
breadcrumbText = node.name + ' > ' + breadcrumbText;
}
div.selectAll('.node')
.data(ancestors, function(d) { return d.index; })
.style('background', function(d) { return color(d.index); })
.style('opacity', '1.0')
.text(function(d) {
return d.name + ' ' + Math.round(d.value / root.value * 1000) / 10 + '%'
})
.exit()
.style('background', null)
.style('opacity', '0.0');
breadcrumb.text(breadcrumbText);
});
node.on('mouseout', function() {
div.selectAll('.node')
.style('background', function(d) { return d.children ? color(d.index) : null; })
.style('opacity', '1.0')
.text(function(d) {
return d.children ?
null : d.name + ' ' + Math.round(d.value / root.value * 1000) / 10 + '%';
});
breadcrumb.text('');
});
function position() {
this.style('left', function(d) { return d.x + 'px'; })
.style('top', function(d) { return d.y + 'px'; })
.style('width', function(d) { return Math.max(0, d.dx - 1) + 'px'; })
.style('height', function(d) { return Math.max(0, d.dy - 1) + 'px'; });
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment