block by nbremer 5a801d9153059b226bbd

Circle Packing at its most Basic - Canvas only

Full Screen

This is the second step of my first attempt to learn canvas. I want to improve a piece a made a few weeks ago about the division of occupations. The d3.js version has so many DOM elements due to all the small bar charts that it is very slow. Therefore, I hope that a canvas version might improve things.

In this block I create a static circle pack layout that only uses D3 for the initialization, scales and such. But the visual is drawn with pure canvas, based on the data supplied by the d3 pack layout

I wrote a more extensive tutorial around what I learned while doing this project in my blog Learnings from a D3.js addict on starting with Canvas in which this can be seen as step 2. See the previous step in which d3.js still played a much bigger role here and the next step that has become a zoomable circle pack (but with a jitter) here

If you want to see the final result, with everything up and running in canvas look here

index.html

<!DOCTYPE html>
<head>
	<meta charset="utf-8">

	<!-- D3.js -->
	<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js" charset="utf-8"></script>
	
</head>
<body>

	<div id="chart"></div>
	<script>
		////////////////////////////////////////////////////////////// 
		////////////////// Create Set-up variables  ////////////////// 
		////////////////////////////////////////////////////////////// 

		var width = Math.max(document.getElementById("chart").offsetWidth,350) - 20,
			height = (window.innerWidth < 768 ? width : window.innerHeight - 20);
		
		//Size of the circle pack layout
		var diameter = Math.min(width*0.9, height*0.9);

		//The grey colors of the circles depend on the depth
		var colorCircle = d3.scale.ordinal()
				.domain([0,1,2,3])
				.range(['#bfbfbf','#838383','#4c4c4c','#1c1c1c']);

		//Initialize the circle pack layout
		var pack = d3.layout.pack()
			.padding(1)
			.size([diameter, diameter])
			.value(function(d) { return d.size; })
			.sort(function(d) { return d.ID; }); //Creates a more interesting visual I think
			
		////////////////////////////////////////////////////////////// 
		/////////////////////// Create Canvas //////////////////////// 
		////////////////////////////////////////////////////////////// 
		
		//Create the canvas and context
		var canvas  = d3.select("#chart").append("canvas")
			.attr("id", "canvas")
			.attr("width", width)
			.attr("height", height);
			
		var context = canvas.node().getContext("2d");
			context.clearRect(0, 0, width, height);

		////////////////////////////////////////////////////////////// 
		////////////////// Create Circle Packing /////////////////////
		////////////////////////////////////////////////////////////// 
			
		d3.json("occupation.json", function(error, dataset) {

			var nodes = pack.nodes(dataset);
			
			//Loop over the nodes dataset and draw each circle to the canvas
			for (var i = 0; i < nodes.length; i++) {
				//Select one of the nodes/circles
				var node = nodes[i];

				//Draw each circle
				context.fillStyle = node.children ? colorCircle(node.depth) : "white";
				context.beginPath();
				context.arc(node.x, node.y, node.r, 0,  2 * Math.PI, true);
				context.fill();
				context.closePath();
			};	
			
		});
				
	</script>
	
</body>
</html>