block by johnburnmurdoch bb151fe2b01894f94ce375eadea00855

bb151fe2b01894f94ce3

Full Screen

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 = 1000,
		// radius = 5.5,
		// t = 3000;
		// n = 2500,
		// radius = 3.6,
		// t = 4000;
		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)));

		// Run the line below if you want to bin the data, in this case by rounding to the nearest whole number
		// data = data.map(d => +d3.format(".0f")(d));

		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});
		});

	});

	// After your data-points have been programmatically positioned once, simply open the web inspector, type copy(circlesData) into the console, then paste from the clipboard into a text editor, save the file as positionedCircles.json, comment out the d3.json... block above, and run the block below to instantly render your predetermined layout.

	// d3.json("positionedCircles.json", function(error, data){

	// 	var circles = svg.appendMany(data, "circle")
	// 		.at({
	// 			cx: d => x(d.x),
	// 			cy: d => y(d.y)-radius,
	// 			r: radius-0.75,
	// 			fill: d => colours(Math.pow(Math.pow(d.x-50,2) + Math.pow(d.y,2),0.5)),
	// 			stroke: d => colours(Math.pow(Math.pow(d.x-50,2) + Math.pow(d.y,2),0.5)),
	// 			"stroke-width": 1,
	// 			"fill-opacity": 0.9
	// 		});

	// });

	</script>
</body>
</html>