ZAYTS.COM
Menu
  • About
  • Contact
Menu

Circle Charts #1 — Pie Chart

Posted on June 7, 2018June 13, 2018 by Zayts

Let’s start with one of the most popular chart in data visualization — circle chart. This circle shaped graph is divided into slices to illustrate proportion. They have those super sweet names like pie chart and donut/doughnuts chart, which is just the variation of pie chart with  blank center.

But before we start you should know that despite those cute names and their popularity circle charts in fact… suck! You can check this hateful article here for more info.

In spite of that I like to use them as progress bar where I have only one value to present, like in the example below:

Let’s start with preparing our html, css and js file with the basic code.

HTML:

<div class='progress-bar'></div>

JavaScript:

var element = document.querySelectorAll('.pie-kpi')[0];
var roundChart = pieChart(element);
roundChart.update(74);

I prepared container for my graphs in HTML. In JavaScript I want to pass my container to pieChart function and later update my my new object (roundChart) with proper value.

Now we have to write this pieChart function that takes HTML element and returns update function to manage the progress. Just see the below the basic structure of this function:

var pieChart = function (element) {
  //here we will write code to create chart
  return {
    update: function (progress) {
    //here we will update chart to present progress
    }
  }
}

Here’s where D3 begins!

Firstly, we need to draw all necessary elements of the chart: svg, background arc, progress arc and progress label. The last two will be set to 0 at the creation of the chart and later changed by the update function.

var size = {
  width: 200,
  height: 200
};

var svg = d3
  .select(element)
  .append("svg")
  .attr("width", size.width)
  .attr("height", size.height)
  .append("g")
  .attr("transform", "translate(" + size.width / 2 + "," + size.height / 2 + ")");

var color_progress = '#4ecdc4';
var color_background = '#c7f465';
var color_label = '#556370';

var radius = Math.min(size.width, size.height) * 0.35;
var tau_end = 2 * Math.PI;
var tau_start = 0 * Math.PI;

Firstly we create svg and append g element to the center of it, to make sure that all following elements we create will be positioned relative to the center of the graph.

I prepared two colors; first one for the background, and second one for the progress. I also set the radius of the circle to be shorter than either height or width. Here we don’t need to use Math.min() function since width and height has the same value, but this practice is very useful when we want to create resize function and we don’t set height and width by default. I will make post about this someday:)

About the tau you can read more here, but as we go forward this will hopefully click in your head just as did in mine.

const arc = d3.arc()
  .startAngle(tau_start)
  .innerRadius(0)
  .outerRadius(radius);

const backgroundArc = svg.append("path")
  .datum({endAngle: tau_end})
  .attr('fill', color_background)
  .attr('d', arc);

const progressArc = svg.append("path")
  .datum({endAngle: tau_start})
  .attr('fill', color_progress);

To create our arc we use d3.arc function. We only need to set up startAngle and if you read tau manifesto you know that if we want our arcs to start from the top of the graph (and this is exactly what we want to achieve here) we need to set our startAngle to Math.PI * 0 or just 0.

We also set our innerRadius to 0 (in pie chart this is always 0), and outerRadius to the value of our previously defined radius.

We are not providing endAngle in origin arc function as this will be different for our backgroundArc and  progressArc. To create path and progress in our chart we need to append to our svg path element that has d attribute set to arc function. Before we do this we set for both endAngle using datum. For our backgroundArc which is whole circle we set the endAngle to tau_end (Math.PI * 2) for the progressArc that at the beginning is always equal to 0 we set it to the same value as our startAngle (Math.PI * 0), so that it will not be visible until we update the chart with progress value. Apart from all the arcs creation we also fixed their colors using fill attribute.

We also need to create  progressLabel, using transform we set its position to be half the height lower than center of our graph, we make sure that it indicates 0% before any update, we define its color, font and text-anchor using proper attributes.

const progressLabel = svg.append("text")
  .attr('transform', `translate(0,${size.height/2})`)
  .text('0' + '%')
  .attr('fill',color_label)
  .attr('font-family','Open Sans')
  .attr('text-anchor','middle')
  .attr('font-size', '22px');

How is your progress?

To display the progress we refer to our progressArc and progressLabel in the update function returned from pieChart function and redraw them to indicate proper value.

1.progressArc:

const transitionDuration = 1500

function arcTween(newAngle) {
  return function(d) {
    var interpolate = d3.interpolate(d.endAngle, newAngle);
    return function(t) {
      d.endAngle = interpolate(t);
      return arc(d);
    };
  };
};

progressArc.transition().duration(transitionDuration).attrTween('d', arcTween(progress / 100 * 2 * Math.PI));

We set the transition value to 1500 and we pass arcTween function with newAngle to attrTween, attrTween returned value will set and update d attribute of our progressArc. We can transition selected arc from their current angle in our case is the same as startAngle (Math.PI * 0) to the specified newAngle. In order to create newAngle we need to find the exact part that our progress (progress/100) takes from the whole circle (2 * Math.PI).

Did the tau clicked already? No worries it will click later, when we will discuss charts that are not presented as a whole circle but has some part cut-out;)

Inside arcTween we use interpolation, the returned value of this function will be set to the d.endAngle at every ‘tick’ until our arc will get from startAngle to the calculated newAngle.

If this is not clear console.log t and d.endAngle in the last returned function to understand what just has happened (this helped me;) and check this post by Mike Bostock.

2.progressLabel:

progressLabel.transition().duration(transitionDuration).tween('bla', function () {
  return function (t) {
    progressLabel.text(Math.round(progress * t)+ '%');
  }
});

Using tween we can use our previously created t to update progressLabel from 0 to our defined progress value.

That’s all! Any comments? Please feel free!

 

1 thought on “Circle Charts #1 — Pie Chart”

  1. PS says:
    June 7, 2018 at 7:17 pm

    ^_^

    Reply

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Recent Posts

  • Circle Charts #2 — Donut Chart
  • Circle Charts #1 — Pie Chart

Archives

  • June 2018
© 2019 ZAYTS.COM | Theme by Superbthemes