Skip to content

Instantly share code, notes, and snippets.

@jwilber
Last active October 14, 2018 06:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jwilber/9de15b7b0fcab02eab32011554d7106f to your computer and use it in GitHub Desktop.
Save jwilber/9de15b7b0fcab02eab32011554d7106f to your computer and use it in GitHub Desktop.
force drop-down histogram
license: mit

Circle-packing tweets

d3.forceExtent = function(extent) {
var nodes;
if (extent == null) extent=[[0,800], [0,500]];
function force() {
var i,
n = nodes.length,
node,
r = 0;
for (i = 0; i < n; ++i) {
node = nodes[i];
r = (node.radius || 0);
node.x = Math.max(Math.min(node.x, extent[0][1]-r), extent[0][0]+r);
node.y = Math.max(Math.min(node.y, extent[1][1]-r), extent[1][0]+r);
}
}
force.initialize = function(_) { nodes = _; };
force.extent = function(_) {
return arguments.length ? (extent = _, force) : extent;
};
return force;
};
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="d3-forceextent.js"></script>
<style>
body { margin: 0; position: fixed; top: 0; right: 0; bottom: 0; left: 0; }
body {
font-family: monospace;
}
circle {
fill: teal;
stroke-width: 0;
}
.coin-text {
opacity: 0.5;
}
.counter {
font-size: 20px;
}
.animate {
color: black;
position: absolute;
top: 10px;
left: 10px;
}
</style>
</head>
<body>
<script>
var margin = { top: 50, right: 50, bottom: 50, left: 50 };
var width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var noOfCirclesA = 10;
noOfCirclesB =100;
var aPos = width / 7;
bPos = width - width / 4;
var te = d3.easeBounce;
var radius = 15;
var dataA = d3.range(noOfCirclesA);
dataA = dataA.map(function(d) {
return {
id: d
}
});
var dataB = d3.range(noOfCirclesB);
dataB = dataB.map(function(d) {
return {
id: d
}
});
var extent = [[0, width], [0, height]];
var simulationA = d3.forceSimulation(dataA)
.force("x", d3.forceX(aPos))
.force("y", d3.forceY(height))
.force("extent", d3.forceExtent(extent))
.force("collide", d3.forceCollide(radius + 2))
.stop();
var simulationB = d3.forceSimulation(dataB)
.force("x", d3.forceX(bPos))
.force("y", d3.forceY(height))
.force("extent", d3.forceExtent(extent))
.force("collide", d3.forceCollide(radius + 2))
.stop();
for (var i = 0; i < 120; ++i) simulationA.tick();
for (var i = 0; i < 120; ++i) simulationB.tick();
var counterA = 0,
counterB = 0;
var legendA = svg.append("g")
.append("text")
.attr("class", "counter")
.attr("x", aPos)
.attr("text-anchor", "middle")
.text(0);
var legendB = svg.append("g")
.append("text")
.attr("class", "counter")
.attr("x", bPos)
.attr("text-anchor", "middle")
.text(0);
function increment(pile) {
if (pile === "a") {
counterA++;
legendA.text(counterA);
} else {
counterB++;
legendB.text(counterB);
}
}
addCircles(dataA, "a");
addCircles(dataB, "b");
function addCircles(data, pile) {
var circle = svg.append("g")
.attr("class", "circles")
.selectAll("g").data(data)
.enter().append("g")
.attr("transform", function(d) {
return "translate(" + d.x + "," + (-margin.top - radius * 2) + ")"
});
circle.append("circle")
.attr("r", radius)
circle.append("text")
.attr("class", "coin-text")
.attr("text-anchor", "middle")
.attr("dy", radius / 3)
.text("£");
circle.transition()
.duration(750)
.delay(function(d, i) {
return (height - d.y) * 20;
})
// .ease(te)
.attr("transform", function(d) {
return "translate(" + d.x + ", " + d.y + ")";
})
.on("end", function() {
increment(pile);
});
}
</script>
</body>
{
"tweets": [
{"user": "Al", "content": "I really love seafood.", "timestamp": " Mon Dec 23 2013 21:30 GMT-0800 (PST)", "retweets": ["Raj","Pris","Roy"], "favorites": ["Sam"]},
{"user": "Al", "content": "I take that back, this doesn't taste so good.", "timestamp": "Mon Dec 23 2013 21:55 GMT-0800 (PST)", "retweets": ["Roy"], "favorites": []},
{"user": "Al", "content": "From now on, I'm only eating cheese sandwiches.", "timestamp": "Mon Dec 23 2013 22:22 GMT-0800 (PST)", "retweets": [], "favorites": ["Roy","Sam"]},
{"user": "Roy", "content": "Great workout!", "timestamp": " Mon Dec 23 2013 7:20 GMT-0800 (PST)", "retweets": [], "favorites": []},
{"user": "Roy", "content": "Spectacular oatmeal!", "timestamp": " Mon Dec 23 2013 7:23 GMT-0800 (PST)", "retweets": [], "favorites": []},
{"user": "Roy", "content": "Amazing traffic!", "timestamp": " Mon Dec 23 2013 7:47 GMT-0800 (PST)", "retweets": [], "favorites": []},
{"user": "Roy", "content": "Just got a ticket for texting and driving!", "timestamp": " Mon Dec 23 2013 8:05 GMT-0800 (PST)", "retweets": [], "favorites": ["Sam", "Sally", "Pris"]},
{"user": "Pris", "content": "Going to have some boiled eggs.", "timestamp": " Mon Dec 23 2013 18:23 GMT-0800 (PST)", "retweets": [], "favorites": ["Sally"]},
{"user": "Pris", "content": "Maybe practice some gymnastics.", "timestamp": " Mon Dec 23 2013 19:47 GMT-0800 (PST)", "retweets": [], "favorites": ["Sally"]},
{"user": "Sam", "content": "@Roy Let's get lunch", "timestamp": " Mon Dec 23 2013 11:05 GMT-0800 (PST)", "retweets": ["Pris"], "favorites": ["Sally", "Pris"]}
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment