HTML, CSS, & jQuery Radial Graph
May 25, 2013 / 14686 Views

I built this radial graph using HTML 5, CSS 3, and jQuery. This technique does not use canvas, and so is fully scale-able. The radial graph basically works by taking two sets of data (names and numbers) and matches them in the order they appear. So the first item from the names list corresponds with the first item in the numbers list.

How it Works

The first step is reordering the number list from the largest to smallest number and then reordering the names list in the same way so that the values still match but both lists are now ordered from largest to smallest. We then call the function that generates the radial graph and the labels are generated with their corresponding colors.

The next step is to tally the total from the numbers list. We then loop through each separate item and divide its number by the total to get the percentage from the whole.

Now for the fun part. Because we’re working with HTML5 and CSS3 we’re unable to create true vector circular shapes. We could use Canvas, but then we’ve rendered a non-vector shape. This method  makes use of border-radius, overflow:hidden, and most importantly the transform: skewX property. This allows us to skew the shape of a div – which can be used to give the appearance of an angle.

We setup the dimensions of the radial graph at 200px square as an example. We then create a div container that is the same size as the radial graph, right on top of it so that it’s rotational axis is directly in the center of the graph. Then we place our green square div inside the container so that its upper right corner is centered in the middle of the radial graph shape. This way when we rotate the container div – the green div inside of it rotates with its upper right corner always in the center of the radial graph (see 1 Below).

In the image above, diagram 2 shows a second div. This one has be rotated 90deg and has the skewX property set to 20deg. If we set the overflow of the radial graph to hidden and create a box-shadow overlay in the center of the graph to hide the meeting point of the divs we successfully create the illusion of a complex shape. And because box-shadow, border-radius, and overflow hidden are fully CSS3 properties – they remain crisp and clear even when the page is zoomed in or viewed on a retina screen.

The only issue now is that skewing a square only holds up within a 90 degree area or the square will fold in on itself and disappear. Because of this we have to break up each section of the radial graph into 90 degree segments or smaller.

We return to our loop that goes through each item and calculates its percentage of the whole. From the percentage we can then check if the item is greater that 75% (or greater than ¾ of the graph), if it is greater than 50% and less than or equal to 75%, if it is greater than 25% but less than or equal to half, or if it is less than 25% or one quarter.

This allows us to treat each segment separately to know how many 90deg or unaltered squares to create (if any) and how to calculate the skew degree of the final div. I’ll break it down.

So let’s suppose – like the code example provided above, that the first segment is 4 items and it is out of a total of 10 items. We divide 4 by 10 and get 0.4. This is greater than 0.25 or 25% and so our if statement catches it at the greater than 25% but less than 50%. This determines that we need to create two separate segments for this section of the graph to give the proper illusion.

The first div is left as a square with no skewX value and its container is simply rotated to the correct starting point. In the example this is -45deg, as I feel the offset starting point gives the graph a neater look. This portion accounts for the first 25% or 90 degrees of this first segment. The second div is created and is rotated 90 degrees so that its starting point matches the ending point of the initial square piece.

We then find the proper skewX degree value which is the percentage of the item (0.4) multiplied by 360 (144) minus the degree value of both of the segments as full squares which is 180 degrees. This gives us -36 degrees which we then convert to a positive value.

Once this has been generated the function loops through again for each item and adds up the initial rotation starting point for each item so that the new items follow after the earlier ones. If everything is done correctly, the graph fills out.

Now there is a lot more detail to this and a lot more than can be done such as animating the graph to spin out when it loads and causing each item to be a different opacity or a different color – but I’ll leave that for another tutorial.

Please let me know if you have any questions or if I made any obvious mistakes. I’m always open to correction.