Controlling SVG Pie Chart with a slider control

I have already talked about creating a simple HTML5 – SVG pie chart in one of my earlier post. This time, I thought of adding some interactivity to the pie chart and came up with controlling the number of pie slices on the fly with a slider control. This tutorial will describe how to increase or decrease the number of pie slices/sectors in the pie chart by scrolling a slider control. I do not know why I tried this but this example might come to your rescue someday and then do not forget to thank me. Check out the demo,

Demo: http://jbk404.site50.net/html5/svgpie/

In Mozilla Firefox the slider control is not displayed, instead a text input is displayed. It works though, you can enter the value and press Enter to see the changes in the pie chart. Google Chrome and Safari works fine. This is how it looks in Chrome,

There is nothing much to describe here other than the code. You must have seen the demo till now. Let’s dive into the code.

Creating the SVG Pie Chart
I have already shared a detailed tutorial on this. So I will not go into the details once again. You can refer my earlier post. Just to give you a hint, the pie chart has been created using HTML5 SVG (Scalable Vector Graphics) API since HTML5 supports inline SVG and vector graphics. I have used Raphael  java script library in my code to actually draw the curves and the pie slices.  You can use normal java script also to create SVG graphics (see my earlier post on this).

Adding interactivity to the chart
As you have seen in the demo app, I have a slider control added to the bottom of the chart. The slider control is an HTML5 range control. Maximum value is 8 since the pie chart has a maximum of 8 sectors. When you drag the slider the current value of the slider decides the number of sectors in the pie chart. Let’s look at the necessary HTML code below,

<div id="pieHolder" style="width:600px; height:400px;">
</div>
<div id="sliderHolder">
  <label style="font-weight: bold; font-family: Arial; font-size: 11px;">Number Of Sectors</label>
  <label style="font-weight: bold; font-family: Arial; font-size: 12px; color:#1695A3;" id="meter">8</label>
  <br />
  <input onchange="handleSliderChange(this);" type="range" id="ran" min="1" max="8" value="8" step="1" style="width: 200px; position: relative;" />
</div>

pieHolder is the div element where the SVG chart is drawn. I also have a sliderHolder which holds the current slider value label and the slider range control. Some styles have also been added to the label and the range control. This is pretty easy stuff.
Now, let’s move on to actually controlling the number of sectors in the chart. For that I have added an onchange event to the slider range control. So, whenever the user drags the slider knob to change the current value/position the handleSliderChange() function is called. I am also passing on the slider object as a parameter so that I can read its value inside the function.

function handleSliderChange(sliderObj) {
  currSliderValue = sliderObj.value;
  meterObj.innerText = currSliderValue;
  tempPieData = pieData.concat();
  tempPieData = tempPieData.slice(0,currSliderValue);
  drawArcs(tempPieData);
}

Inside the function I get the current slider value and store it in currSliderValue variable. This value is then printed on the meter label (in blue text) above the slider.  I have created a temporary array that holds the values of pieData array. If you have gone through my post on creating the SVG pie chart, you will know that pieData is the main array which holds the data for the pie sectors and based on each data value we calculate the angles swiped by each of the pie sectors. Here in this example I have created a temporary array tempPieData which holds the values of the original array and then make changes to the temporary array. I do not dare to change my original array and original data, so keep it as it is. In the third line I copy the values of the original array to my temp array. And then based on the current slider value I slice out the portion of the array. For eg. If slider is dragged to 2, then I slice out only 2 items from the array so the array looks like tempPieData = [48, 87]. These two data items in the array now correspond to the two sectors in the pie chart.
The 3rd and the 4th line inside the function are very important as these two lines act in both increase and decrease in the slider value. As you can see I do not have any if-else statements to check if the slider value is increasing or decreasing from the current value. What I have done is that, first copied the data of original array into the temp array and then slice out the values needed. So, every time user drags the slider the original array values are first copied and then I determine the new array that will actually draw the pie sectors. So whether you drag the slider knob to a higher range or lower it always acts the same. And then finally, I call the drawArcs() function which does all the SVG drawings passing it the temporary data array. The drawArcs() function should be quite familiar to you by now, if you have gone through the earlier post that I recommended. But there is couple of small changes made to it which I shall talk about next. First of all the drawArcs() function is now taking a parameter – the temporary data array values which are selected instantaneously based on the slider range value.  Let’s look at it once, and then talk in detail,

function drawArcs(pieData) {
  paper.clear();
  total = 0;
  startAngle = 0;
  endAngle = 0;
  sectorAngleArr = [];

  for (var k = 0; k < pieData.length; k++) {
    total += pieData[k];
  }
  //CALCULATE THE ANGLES THAT EACH SECTOR SWIPES AND STORE IN AN ARRAY
  for (var i = 0; i < pieData.length; i++) {
    var angle = Math.ceil(360 * pieData[i] / total);
    sectorAngleArr.push(angle);
  }
  for (var i = 0; i < sectorAngleArr.length; i++) {
    startAngle = endAngle;
    endAngle = startAngle + sectorAngleArr[i];
    var flag = (endAngle - startAngle) > 180;
    x1 = parseInt(200 + 150 * Math.cos(Math.PI * startAngle / 180));
    y1 = parseInt(200 + 150 * Math.sin(Math.PI * startAngle / 180));

    x2 = parseInt(200 + 150 * Math.cos(Math.PI * endAngle / 180));
    y2 = parseInt(200 + 150 * Math.sin(Math.PI * endAngle / 180));
    //console.log("FlasG: " + +flag);
    var d = "M200,200 L" + x1 + "," + y1 + " A150,150 0 " + +flag + ",1 " + x2 + "," + y2 + " z"; //1 means clockwise
    //alert(d);
    arc = paper.path(d);
    arc.attr("fill", colorArr[i]);
    //arc.attr("stroke-width", 2);
  }
}

The first line inside the function – paper.clear() clears the drawing canvas (not HTML5 canvas element, I am just referring to a drawing canvas) and resets it every time the function is called. This is important, otherwise it will not clear the previous vector graphics and draw on top of that. We want a fresh pie every time we move the slider isn’t it.
The next four lines just resets the variables as I have used the += operator with some of them to add values. There after the for loops are similar to the pie chart example tutorial from my earlier post. Just refer that. The only thing new here is that I have added a flag variable.

var flag = (endAngle - startAngle) > 180;
var d = "M200,200 L" + x1 + "," + y1 + " A150,150 0 " + +flag + ",1 " + x2 + "," + y2 + " z"; //1 means clockwise

The flag variable checks if the angle swiped by a sector is more than 180 degrees or not. If it is less than 180, flag is false and +flag is 0, so the large-arc-flag value is zero and hence one of the smaller arc sweeps will be chosen. There are actually four different arcs (two different ellipses, each with two different arc sweeps) that can be drawn between two points at a time. So the large-arc-flag determines which to choose. This is a bit confusing and for your help a very good tutorial is there. You can have a look at: http://www.itk.ilstu.edu/faculty/javila/SVG/SVG_drawing1/elliptical_curve.htm. Check out the diagram in the tutorial link which shows all the four different arc conditions. Now, coming back to the flag variable, when the angle of a sector gets larger than 180 degree (this happens when no. of sectors is less than 3 in our demo app), then we want a larger arc sweep to be chosen. So flag becomes true and +flag is 1. Otherwise the result is shown in the image below, it chooses a smaller arc swipe to draw between the two points.

When flag is 0 and angle swiped by a sector is > 180

Finally we draw the arc and then apply fill color to each sector and our freshly drawn pie chart is ready.

Here is the link to the demo once again. Check out in Google Chrome or Safari if possible.
http://jbk404.site50.net/html5/svgpie/

For the full code check the source of the demo app. Hope you like it!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s