Last active
August 29, 2015 14:15
-
-
Save tzellman/4456d09c7fcc0fb26cbc to your computer and use it in GitHub Desktop.
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> | |
<meta charset="utf-8"> | |
<style> | |
svg circle { | |
cursor: pointer; | |
fill-opacity: 0.2; | |
} | |
svg text { | |
fill: darkgreen; | |
font-size: 30px; | |
font-weight: 700; | |
} | |
</style> | |
<body> | |
<script src="http://d3js.org/d3.v3.min.js"></script> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.1.0/lodash.min.js"></script> | |
<script src="http://marak.com/faker.js/js/faker.min.js"></script> | |
<script> | |
// assume these are passed in from somewhere (e.g in an Ember component) | |
var width = 1024, | |
data = [ | |
{label: "1", value: 10}, | |
{label: "2", value: 20}, | |
{label: "3", value: 15}, | |
{label: "4", value: 5}, | |
{label: "5", value: 5}, | |
{label: "5", value: 5}, | |
{label: "5", value: 5}, | |
{label: "5", value: 5}, | |
{label: "5", value: 5} | |
], | |
height = 800, | |
rows = 1, | |
strokeWidth = 3; | |
data.forEach(function (d) { | |
d.terms = faker.lorem.words(5); | |
}); | |
var bound = Math.min(width, height), | |
nodes = [], | |
foci = [], | |
fill = d3.scale.category10(), | |
_id = 0, | |
padding = 5, | |
cols = Math.ceil((data.length) / rows), | |
radius = ((width - (padding * data.length + 1)) / data.length) / 2; | |
var svg = d3.select("body").append("svg") | |
.attr("height", height) | |
.attr("width", width); | |
data.forEach(function (d, i) { | |
d.foci = i; | |
d._id = _id++; | |
nodes.push(d); | |
var row = Math.floor(i / cols), | |
col = Math.floor(i % cols), | |
yCenter = (row * (radius * 2 + padding)) + radius + padding, | |
xCenter = (col * (radius * 2 + padding)) + radius + padding; | |
var point = {x: xCenter, y: yCenter}; | |
foci.push(point); | |
d.x = foci[d.foci].x; | |
d.y = foci[d.foci].y; | |
}); | |
var node = svg.selectAll('g.entity') | |
.data(nodes) | |
.enter() | |
.append('g') | |
.attr('class', 'entity') | |
.attr("transform", function (d) { | |
return "translate(" + d.x + "," + d.y + ")"; | |
}); | |
function updateCircle() { | |
d3.select(this) | |
.transition().duration(300) | |
.ease("linear") | |
.attr("r", function (d) { | |
return radius; | |
}); | |
} | |
node.append('circle') | |
.style("stroke", function (d) { | |
return d3.rgb(fill(d.foci)).darker(2); | |
}) | |
.style("fill", function (d) { | |
return d3.rgb(fill(d.foci)); | |
}) | |
.style("stroke-width", function (d) { | |
return strokeWidth; | |
}) | |
.each(updateCircle); | |
// Suppose the image is square, and is centered in a circle with radius r. | |
// Then, the square image should hit at 45 degrees, meaning that the width | |
// and height should be 2*sin(tao/8) * r | |
var imageWH = function (d) { | |
return 2 * Math.sin(6.28 / 8) * (radius - strokeWidth); | |
}; | |
function updateImage() { | |
d3.select(this).transition().duration(300) | |
.ease("linear") | |
.attr("x", function (d) { | |
return -imageWH(d) / 2; | |
}) | |
.attr("y", function (d) { | |
return -imageWH(d) / 2; | |
}) | |
.attr("width", imageWH) | |
.attr("height", imageWH); | |
} | |
node.append("image") | |
.attr("xlink:href", function (d) { | |
return faker.internet.avatar(); | |
}).each(updateImage); | |
node.on('click', function (n) { | |
selectNode(n._id); | |
}); | |
var currentId = -1; | |
function selectNode(id) { | |
currentId = id; | |
// first move old center back | |
var others = d3.selectAll("g.entity") | |
.filter(function (d) { | |
return d._id !== id; | |
}); | |
others.each(function (d, i) { | |
d.x = foci[d.foci].x; | |
d.y = foci[d.foci].y; | |
d3.select(this) | |
.transition().duration(300).ease("linear") | |
.attr("transform", function (d) { | |
return "translate(" + d.x + "," + d.y + ")"; | |
}); | |
}).each(function (d, i) { | |
d3.select(this).select("circle") | |
.transition().duration(300).ease("linear") | |
.attr("r", radius); | |
}); | |
others.select("text").remove(); | |
// now, move to the center | |
var selected = d3.selectAll("g.entity") | |
.filter(function (d) { | |
return d._id === id; | |
}); | |
selected.each(function (d, i) { | |
d.x = width / 2 - radius; | |
d.y = height / 2 - radius; | |
d3.select(this) | |
.transition().duration(300).ease("linear") | |
.attr("transform", function (d) { | |
return "translate(" + d.x + "," + d.y + ")"; | |
}); | |
}).each(function (d, i) { | |
d3.select(this).select("circle") | |
.transition().duration(300).ease("linear") | |
.attr("r", radius * 1.5); | |
}); | |
// add text | |
var text = selected.append('text') | |
.text(function (d) { | |
return d.terms.join(" "); | |
}) | |
.each(function (d) { | |
// need to get the text width | |
var box = this.getBBox(); | |
d3.select(this) | |
.attr("x", -box.width / 2) | |
.attr("y", radius * 1.5 + box.height); | |
}); | |
} | |
setInterval(function () { | |
selectNode((currentId + 1) % data.length); | |
}, 2000); | |
</script> | |
</body> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment