index.html
<!DOCTYPE html>
<html lang="en-GB">
<head>
<title>Histo-packing</title>
<script src="https://unpkg.com/d3"></script>
<script src="https://unpkg.com/d3-jetpack-module"></script>
<style>
body{background: #212121; margin: 20px;}
text{font-family: Avenir; font-size: 18px; fill:#fff;}
.domain{display: none;}
.y .tick#_0 line{stroke: #ccc;}
.tick line{stroke: #808080;}
.y text{display:none;}
</style>
</head>
<body>
<script type="text/javascript" charset="utf-8">
var width = 700,
height = 800,
margin = {top: 30, right: 20, bottom: 70, left: 5},
n = 5000,
radius = 2.6,
t = 6000;
var svg = d3.select("body")
.append("svg#svg")
.st({
'width':width,
'height':height
});
var x = d3.scaleLinear()
.range([margin.left, width - margin.right])
.domain([0,100]);
var xScale = d3.axisBottom()
.scale(x)
.ticks(10)
.tickSize(-(height - (margin.top + margin.bottom)));
var xAxis = svg.append("g.axis.x")
.translate([0,height-margin.bottom])
.call(xScale)
.selectAll(".tick")
.at({
id: d => "_" + d
})
.selectAll("text")
.at({
dy: 15
});
var y = d3.scaleLinear()
.range([height-margin.bottom, margin.top])
.domain([0,100]);
var yScale = d3.axisLeft()
.scale(y)
.ticks(10)
.tickSize(-(width - (margin.left + margin.right)));
var yAxis = svg.append("g.axis.y")
.translate([margin.left,0])
.call(yScale)
.selectAll(".tick")
.at({
id: d => "_" + d
})
.filter(d => d != 0)
.remove();
var colours = d3.scaleLinear()
.range(["#FCAB27", "#FF2B4F"])
.domain([0, 30]);
var circlesData = [];
d3.json("circleData.json", function(error, data){
data = data.filter(d => d >= 0 && d <= 100).slice(0,n).sort((a,b) => (Math.abs(a-50) - Math.abs(b-50)));
var circles = svg.appendMany(data, "circle")
.at({
cx: d => x(d),
cy: y(100)-radius-20,
r: radius-0.75,
fill: "#aaa",
stroke: "#aaa",
"stroke-width": 1,
"fill-opacity": 0.9
});
data.forEach((datum,index) => {
var thisCircle = data[index];
var xInRange = circlesData.filter(d => Math.abs(x(d.x) - x(thisCircle)) <= (2*radius)).sort(function(a,b){
if(a.y == b.y){
return Math.abs(b.x - thisCircle) - Math.abs(a.x - thisCircle)
}else{
return a.y - b.y
}
});
var cy = 0, it = 0;
if(xInRange.length >= 1){
for(var it=0; it < xInRange.length; it++){
if(((Math.pow(Math.pow((y(xInRange[it].y)-radius) - (y(cy)-radius),2)+Math.pow(x(thisCircle)-x(xInRange[it].x),2),0.5))) >= 1.99*radius && (((Math.pow(Math.pow((y(xInRange[d3.max([0,it-1])].y)-radius) - (y(cy)-radius),2)+Math.pow(x(thisCircle)-x(xInRange[d3.max([0,it-1])].x),2),0.5))) >= 1.99*radius) && (((Math.pow(Math.pow((y(xInRange[d3.min([xInRange.length-1,it+1])].y)-radius) - (y(cy)-radius),2)+Math.pow(x(thisCircle)-x(xInRange[d3.min([xInRange.length-1,it+1])].x),2),0.5))) >= 1.99*radius)){
break;
}else{
cy = y.invert(d3.min([d3.max([0, it-1]),it].map(d => y(xInRange[d].y) - ((Math.pow(Math.pow(2*radius,2)-Math.pow(x(thisCircle)-x(xInRange[d].x),2),0.5))))));
}
}
}
svg.selectAll("circle").filter((d,i) => i == index)
.transition()
.ease(d3.easeLinear)
.delay(index * (t/Math.pow(index+1,0.85)))
.duration((t/Math.pow(index+2,0.85)))
.attr("cy", y(cy)-radius)
.style("stroke", d => colours(Math.pow(Math.pow(thisCircle-50,2) + Math.pow(cy,2),0.5)))
.style("fill", d => colours(Math.pow(Math.pow(thisCircle-50,2) + Math.pow(cy,2),0.5)));
circlesData.push({x: thisCircle, y: cy});
});
});
</script>
</body>
</html>