Last active
March 29, 2019 02:26
-
-
Save itamarhaber/e9a87c39467075e2ba76 to your computer and use it in GitHub Desktop.
Red is Beautiful: A Visualization of Redis Commands
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<!-- | |
Red is Beautiful: A Visualization of Redis Commands | |
By Itamar Haber, Redis Labs | |
Adopted from Mike Bostock's Zoomable Pack Layout example: http://mbostock.github.io/d3/talk/20111116/pack-hierarchy.html | |
!--> | |
<html> | |
<head> | |
<style> | |
.node { | |
cursor: pointer; | |
} | |
.node:hover { | |
stroke: #fff; | |
stroke-width: 10px; | |
} | |
.node--leaf:hover { | |
stroke: hsl(7,83%,39%); | |
stroke-width: 5px; | |
} | |
.label { | |
font: 14px Arial, sans-serif; | |
font-weight: 700; | |
text-anchor: middle; | |
fill: white; | |
text-shadow: 1px 0 9px hsl(7,83%,16%), 1px 0 9px hsl(7,83%,16%), 1px 0 9px hsl(7,83%,16%), 1px 0 9px hsl(7,83%,16%); | |
cursor: pointer; | |
stroke: black 10px; | |
} | |
label, | |
.node--root { | |
pointer-events: none; | |
} | |
</style> | |
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script> | |
</head> | |
<body> | |
<script> | |
var margin = 10, | |
diameter = 625; | |
var color = d3.scale.ordinal() | |
.domain([-1, 0, 1, 2]) | |
.range(["hsl(100,100%,100%)", "hsl(7,83%,39%)", "hsl(100,100%,100%)", "hsl(7,83%,39%)"]); | |
var pack = d3.layout.pack() | |
.padding(5) | |
.size([diameter - margin, diameter - margin]) | |
.value(function(d) { return d.size; }) | |
var svg = d3.select("body").append("svg") | |
.attr("width", diameter) | |
.attr("height", diameter) | |
.append("g") | |
.attr("transform", "translate(" + diameter / 2 + "," + diameter / 2 + ")"); | |
d3.json("https://cdn.rawgit.com/antirez/redis-doc/master/commands.json", function(error, root) { | |
if (error) return console.error(error); | |
// transform Redis commands.json to an hierarchical structure based on group | |
var bygroup = []; | |
for (var i in root) { | |
group = root[i]["group"].toUpperCase().replace("_"," "); | |
if(bygroup[group] == null) { | |
bygroup[group] = []; | |
} | |
// naively set size based on command complexity | |
complexity = String(root[i]["complexity"]).split(/[ .]/)[0]; | |
switch(complexity) { | |
case "O(1)": | |
size = 1; | |
break; | |
case "O(log(N))": | |
size = 2; | |
case "O(log(N)+M)": | |
size = 4; | |
case "O(N)": | |
size = 5; | |
break; | |
case "O(N+M)": | |
case "O(S+N)": | |
size = 8; | |
break; | |
case "O(N+M*log(M))": | |
size = 9; | |
break; | |
case "O(M*log(N))": | |
size = 10; | |
case "O(N*M)": | |
size = 16; | |
break; | |
case "O(N)+O(M": // O(N)+O(M log(M))? | |
case "O(N)+O(M*log(M))": | |
complexity = "O(N)+O(M*log(M))"; | |
size = 20; | |
break; | |
case "O(N*K)+O(M*log(M))": | |
size = 32; | |
break; | |
default: | |
complexity = ""; | |
size = 0.5; | |
} | |
bygroup[group].push({ "name": i, "size": size, "complexity": complexity }); | |
} | |
// build a JSON from transformed data | |
var groot = { "name": "Redis Commands", "children": [] }; | |
for (var i in bygroup) { | |
t = []; | |
for (var j in bygroup[i]) { | |
t.push({ "name": bygroup[i][j]["name"], "size": bygroup[i][j]["size"], "complexity": bygroup[i][j]["complexity"] }); | |
} | |
groot["children"].push({ "name": i, "children": t }); | |
} | |
var focus = groot, | |
nodes = pack.nodes(groot), | |
view; | |
var circle = svg.selectAll("circle") | |
.data(nodes) | |
.enter().append("circle") | |
.attr("class", function(d) { return d.parent ? d.children ? "node" : "node node--leaf" : "node node--root"; }) | |
.style("fill", function(d) { return color(d.depth); }) | |
.on("click", function(d) { if (focus !== d && d.children) | |
zoom(d); | |
else if (!d.children) | |
if (focus === d.parent) | |
window.open("http://redis.io/commands/" + d.name.replace(" ", "-"), "_blank"); | |
else | |
zoom(d.parent); | |
d3.event.stopPropagation();}); | |
var text = svg.selectAll("text") | |
.data(nodes) | |
.enter().append("text") | |
.attr("class", "label") | |
.style("fill-opacity", function(d) { return d.parent === groot ? 1 : 0; }) | |
.style("display", function(d) { return d.parent === groot ? null : "none"; }) | |
.on("click", function(d) { if (focus !== d && d.children) | |
zoom(d); | |
else if (!d.children) | |
if (focus === d.parent) | |
window.open("http://redis.io/commands/" + d.name.replace(" ", "-"), "_blank"); | |
else | |
zoom(d.parent); | |
d3.event.stopPropagation();}); | |
var names = text.append("tspan") | |
.text(function (d) { return d.name; }); | |
var complexities = text.append("tspan") | |
.attr("x", "0") | |
.attr("y", "1.4em") | |
.text(function (d) { return (d.complexity != "" && d.complexity) ? d.complexity : ""; }); | |
var node = svg.selectAll("circle,text"); | |
d3.select("body") | |
.style("background", color(-1)) | |
.on("click", function() { zoom(groot); }); | |
zoomTo([groot.x, groot.y, groot.r * 2 + margin]); | |
function zoom(d) { | |
var focus0 = focus; focus = d; | |
var transition = d3.transition() | |
.duration(d3.event.altKey ? 7500 : 750) | |
.tween("zoom", function(d) { | |
var i = d3.interpolateZoom(view, [focus.x, focus.y, focus.r * 2 + margin]); | |
return function(t) { zoomTo(i(t)); }; | |
}); | |
transition.selectAll("text") | |
.filter(function(d) { return d.parent === focus || this.style.display === "inline"; }) | |
.style("fill-opacity", function(d) { return d.parent === focus ? 1 : 0; }) | |
.each("start", function(d) { if (d.parent === focus) this.style.display = "inline"; }) | |
.each("end", function(d) { if (d.parent !== focus) this.style.display = "none"; }); | |
} | |
function zoomTo(v) { | |
var k = diameter / v[2]; view = v; | |
node.attr("transform", function(d) { return "translate(" + (d.x - v[0]) * k + "," + (d.y - v[1]) * k + ")"; }); | |
circle.attr("r", function(d) { return d.r * k; }); | |
} | |
}); | |
d3.select(self.frameElement).style("height", diameter + "px"); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
To view: http://bl.ocks.org/itamarhaber/e9a87c39467075e2ba76