|
<!DOCTYPE html> |
|
<meta charset="utf-8"> |
|
<style> |
|
|
|
body { |
|
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; |
|
margin: auto; |
|
} |
|
|
|
form { |
|
position: absolute; |
|
right: 10px; |
|
top: 10px; |
|
} |
|
|
|
.node { |
|
border: solid 1px white; |
|
font: 10px sans-serif; |
|
line-height: 12px; |
|
overflow: hidden; |
|
position: absolute; |
|
text-indent: 2px; |
|
} |
|
|
|
</style> |
|
<body> |
|
<p id="filename"></p> |
|
</body> |
|
<script src="http://d3js.org/d3.v3.min.js"></script> |
|
<script> |
|
|
|
var margin = {top: 10, right: 10, bottom: 10, left: 10}, |
|
width = window.innerWidth - margin.left - margin.right, |
|
height = window.innerHeight - margin.top - margin.bottom; |
|
|
|
var greenToRed = d3.scale.linear().domain([0, 1]).range([120, 0]); |
|
var saturation = d3.scale.linear().domain([0, 1]).range([.5, 1]); |
|
var brightness = d3.scale.linear().domain([0, 1]).range([.8, .5]); |
|
|
|
var color = function(file) { |
|
var ratio = (file.changes || 0) / file.size; |
|
if (ratio > 1) console.log(ratio, file); |
|
ratio = Math.min(1, ratio); |
|
return d3.hsl(greenToRed(ratio), saturation(ratio), brightness(ratio)).toString(); |
|
} |
|
|
|
var treemap = d3.layout.treemap() |
|
.size([width, height]) |
|
.sticky(true) |
|
// .padding(5) |
|
.value(function(d) { return d.size; }); |
|
|
|
var div = d3.select("body").append("div") |
|
.style("position", "relative") |
|
.style("width", (width + margin.left + margin.right) + "px") |
|
.style("height", (height + margin.top + margin.bottom) + "px") |
|
.style("left", margin.left + "px") |
|
.style("top", margin.top + "px"); |
|
|
|
function updateTree(root, files, key) { |
|
for (var i = 0; i < files.length; i++) { |
|
var file = files[i]; |
|
var extension = (/\.([^\.]+)$/.exec(file.filename) || [])[1]; |
|
|
|
var excluded = ["js", "css", "graffle", "in", "txt", "less", "svg"]; |
|
|
|
if (excluded.indexOf(extension) !== -1) { |
|
continue; |
|
} |
|
var segments = file.filename.split("/"); |
|
var node = root; |
|
for (var d = 0; d < segments.length; d++) { |
|
var segment = segments[d]; |
|
if (!node.children) { |
|
node.children = []; |
|
} |
|
var child = node.children.filter(function (child) { return child.name === segment; })[0]; |
|
if (!child) { |
|
node.children.push(child = { name: segment } ); |
|
} |
|
node = child; |
|
} |
|
node[key] = file.changes; |
|
node.file = file; |
|
} |
|
} |
|
|
|
var hashParams = function() { |
|
var list = window.location.hash.substr(1).split("&"); |
|
var map = {}; |
|
for (var i = 0; i < list.length; i++) { |
|
var tokens = list[i].split("="); |
|
map[tokens[0]] = tokens[1]; |
|
} |
|
return map; |
|
}(); |
|
|
|
var initialCommit = hashParams["initial"]; |
|
var startCommit = hashParams["start"]; |
|
var endCommit = hashParams["end"]; |
|
|
|
|
|
// 9c4f3c010b03070098c2102d46d347bac809f4e5 |
|
|
|
function getCachedJson(uri, callback) { |
|
var cached = window.localStorage.getItem(uri); |
|
console.log(uri) |
|
if (cached) { |
|
callback(null, JSON.parse(cached)); |
|
} else { |
|
d3.json(uri, function(error, data) { |
|
var simplified = data.files.map(function(file) { return { filename: file.filename, changes: file.changes }; }); |
|
window.localStorage.setItem(uri, JSON.stringify(simplified)); |
|
callback(error, simplified); |
|
}); |
|
} |
|
} |
|
getCachedJson("https://api.github.com/repos/neo4j/neo4j/compare/" + initialCommit + "..." + endCommit, function(error, files) { |
|
var root = {}; |
|
|
|
updateTree(root, files, "size"); |
|
|
|
getCachedJson("https://api.github.com/repos/neo4j/neo4j/compare/" + startCommit + "..." + endCommit, function(error, files) { |
|
|
|
updateTree(root, files, "changes"); |
|
|
|
console.log(root); |
|
|
|
var node = div.datum(root).selectAll(".node") |
|
.data(treemap.nodes) |
|
.enter().append("div") |
|
.attr("class", "node") |
|
.call(position) |
|
.style("background", function(d) { return color(d); }) |
|
.text(function(d) { return d.children ? null : d.name; }) |
|
.on("mouseover", function(d) { d3.select("#filename").text(d.file.filename); }); |
|
}); |
|
}); |
|
|
|
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> |