Nested Pie Chart in Pure JavaScript

MindFusion
6 min readOct 29, 2019

--

In this article we will extend the functionality of the PieChart control and render a nested pie chart. We will use an additional PieRenderer which will draw the outer part of the chart e.g. the doughnut.

Here is the final chart:

A nested pie chart created with MindFusion JS Chart library

You can see the sample online at: https://mindfusion.eu/javascript-demo.html?sample=NestedPieChart

I. Setup

Our project will use two files — a web page and a JavaScript file that will contain the code. In addition to this, we need two *.js files for the Charting library — MindFusion.Charting.js and MindFusion.Common.js. We place those files in a directory called Scripts at the same level where the other files are located. We reference them at the end of the web page, before the closing </BODY> tag:

<script type=”text/javascript” src=”Scripts/MindFusion.Common.js”></script>
<script type=”text/javascript” src=”Scripts/MindFusion.Charting.js”></script>

Under them we reference the code behind file, which we’ve called NestedPieChart.js:

<script type=”text/javascript” src=”NestedPieChart.js”></script>

Now, in the <BODY> of the web page we need to initialize and HTML Canvas element and provide it with an id:

<canvas id=”pieChart” width=”600" height=”500"></canvas>

The size of the Canvas element determines the size of the chart. We need the id to access the Canvas later in code. And that’s all we need to do in the web page, let’s go to writing the code.

II. General Chart Settings

First, we make a few mappings to the classes and namespaces that we’ll need in our nested pie chart:

var Charting = MindFusion.Charting;
var Controls = MindFusion.Charting.Controls;
var Collections = MindFusion.Charting.Collections;
var Drawing = MindFusion.Charting.Drawing;
var LabelKinds = MindFusion.Charting.LabelKinds;
var ToolTip = MindFusion.Charting.ToolTip;

Then we create the pie chart. We need to get the HTMLElement that represents the Canvas and use it to create the PieChart control:

// create the chart
var pieChartEl = document.getElementById(‘pieChart’);
pieChartEl.width = pieChartEl.offsetParent.clientWidth;
pieChartEl.height = pieChartEl.offsetParent.clientHeight;
var pieChart = new Controls.PieChart(pieChartEl);

Then we add some initial settings. We make the chart start from an angle of 45 degrees and give it a title:

pieChart.startAngle = 45;
pieChart.title = “Sales By Year”;

II. The Pie Series

The first series is the traditional PieSeries that the PieChart renders. Here we just create an instance of the PieSeries class:

// create data for the first series
var values = new Collections.List([10, 7, 6, 8, 6, 12, 8, 4, 7, 3]);
var series = new Charting.PieSeries(values, null, [10, 7, 6, 8, 6, 12, 8, 4, 7, 3]);
pieChart.series = series;

We want our PieSeries to render tooltips and we want the outer labels to appear in the legend as labels for the pie pieces. That’s why we set the supportedLabels property to ToolTips and OuterLabel this way:

series.supportedLabels = LabelKinds.ToolTip | LabelKinds.OuterLabel;

We will make the tooltips of our PieSeries render the percentage value of each piece. We need to know what is the total sum of the data values:

var total = 0;for(var i = 0; i < values.count(); i++)
total += values.items()[i];

Then, we use the getLabel method to return the correct percent. getLabel is a powerful method. It is called by the control every time a series label needs to be drawn. Inside the method we get the chance to return the value that we want overriding the default behavior:

series.getLabel = function (index, kind)
{
if (kind == LabelKinds.ToolTip)
return (values.items()[index]/total * 100).toFixed(2) + “ %”;
if (kind == LabelKinds.OuterLabel)
return this.outerLabels.items()[index];

return null;
};

As you see in our version of getLabel we return the percentage value of the piece instead of the corresponding array member as we do for the outer labels. The value of the ‘kind’ argument depends on the supportedLabels value. In our case we’ve set that we want to support tool tips and outer labels and the control asks for them in getLabel.

III. The Doughnut Series

The doughnut series will render inner labels. It consists of just 3 pieces and we set the lists with data and labels directly in the PieSeries constructor:

//doughnut series, use a renderer
var series1 = new Charting.PieSeries([23, 14, 34], [“2018”, “2017”, “2016”]);
var p_renderer = new Charting.PieRenderer();
p_renderer.doughnut = true;
p_renderer.series = series1;

We create an instance of the PieRenderer class, which is responsible for rendering pies from the series that are assigned to its series property. We add this PieRenderer to the seriesRenderers collection of the plot:

pieChart.plot.seriesRenderers.add(p_renderer);

Now we have two PieRenderer the default one, which renders the pie chart and the second one, which renders the doughnut ring.

IV. Styling

We style the series with instances of the PerElementSeriesStyle class. This class assigns the subsequent brush and stroke from its fills and strokes properties to the corresponding pie element. The fills and strokes are lists with brush collections — that is needed because the chart might have multiple series. So, we put our brushes in a list and add use those nested lists to create an instance of the PerElementSeriesStyle class:

//styling the pie series
var brushes = new Collections.List([
new Drawing.Brush(“#f57088”),
new Drawing.Brush(“#f8a0b0”),
new Drawing.Brush(“#fccfd7”),
new Drawing.Brush(“#a1bbde”),
new Drawing.Brush(“#c6d6eb”),
new Drawing.Brush(“#88c392”),
new Drawing.Brush(“#99cca2”),
new Drawing.Brush(“#aad4b1”),
new Drawing.Brush(“#bbddc1”),
new Drawing.Brush(“#cce5d0”)

]);
var seriesBrushes = new Collections.List();
seriesBrushes.add(brushes);
var strokes = new Collections.List([
new Drawing.Brush(“#ffffff”)
]);
var seriesStrokes = new Collections.List();
seriesStrokes.add(strokes);

The thicknesses for each stroke are also a nested array. After we initialize it, we build a new instance of the PerElementSeriesStyle class. We assign this style instance to the seriesStyle property o the plot:

var thicknesses = new Collections.List([
6.0
]);
var seriesThicknesses = new Collections.List();
seriesThicknesses.add(thicknesses);
pieChart.plot.seriesStyle = new Charting.PerElementSeriesStyle(seriesBrushes, seriesStrokes, seriesThicknesses);

The style for the doughnut part of the nested pie diagram is also an instance of PerElementSeriesStyle but we assign it to the seriesStyle property of the PieRenderer instance:

//styling the doughnut series
var brushes1 = new Collections.List([
new Drawing.Brush(“#F24162”),
new Drawing.Brush(“#4B7DBF”),
new Drawing.Brush(“#66b273”)
]);
var seriesBrushes1 = new Collections.List();
seriesBrushes1.add(brushes1);
var strokes1 = new Collections.List([
new Drawing.Brush(“#ffffff”)
]);
var seriesStrokes1 = new Collections.List();
seriesStrokes1.add(strokes1);
var thicknesses1 = new Collections.List([
6.0
]);
var seriesThicknesses1 = new Collections.List();
seriesThicknesses1.add(thicknesses1);

We create nested lists of brushes, strokes and thicknesses and use them to create a style that we assign to PieRenderer.seriesStyle:

p_renderer.seriesStyle = new Charting.PerElementSeriesStyle(seriesBrushes1, seriesStrokes1, seriesThicknesses1);

V. Legend

Each chart has an instance of the LegendRenderer class that is responsible for rendering the legend. We will use this instance to customize the legend for the nested pie chart.

As we mentioned earlier, we want the outer labels from the first PieSeries to render as legend labels. We do this by setting the elementLabelKind property to LabelKinds .OuterLabel.

pieChart.legendRenderer.elementLabelKind = LabelKinds.OuterLabel;

Then we set showSeriesElements to true. This is needed because by default the legend renders the title of the chart series as a legend item. We want the legend labels to be bound to the elements !inside! the series, not to its title.

pieChart.legendRenderer.showSeriesElements = true;

We also need to tell the PieChart that we want the legend to be rendered:

pieChart.showLegend = true;

and do some styling:

pieChart.legendRenderer.titleBrush = new Drawing.Brush(“#ffffff”);
pieChart.theme.legendBackground = new Drawing.Brush(“#035e96”);

The legend uses the font settings from the dataLabels*** fields of the theme property. So, we make the legend labels be drawn with font size 12 and a white brush:

pieChart.theme.dataLabelsFontSize = 12;
pieChart.theme.dataLabelsBrush = new Drawing.Brush(“#ffffff”);

Now that we’ve finished building the chart let us not forget to render it:

pieChart.draw();

And that was everything. We’ve just made a beautiful pie chart with two nested series, a legend, tooltips and labels.

You can download the full source code for this sample together with the JavaScript Charting libraries used from this link: http://mindfusion.eu/samples/javascript/chart/NestedPieChart.zip

About MindFusion Charting for JavaScript: MindFusion library for interactive charts and gauges. It supports all common chart types including 3D bar charts. Charts can have a grid, a legend, unlimitd number of axes and series. Scroll, zoom and pan are supported out of the box. You can easily create your own chart series by implementing the Series interface.
The gauges library is part of Charting for JavaScript. It supports oval and linear gauge with several types of labels and ticks. Various samples show you how the implement the gauges to create and customize all popular gauge types: car dashboard, clock, thermometer, compass etc. Learn more about Charting and Gauges for JavaScript at
https://mindfusion.eu/javascript-chart.html.

About MindFusion: An independent vendor of programming components for web, desktop and mobile. We have nearly two decade-experience in providing libraries that empower developers worldwide to build better software, faster and easier.

--

--

MindFusion

Independent vendor of programming components and libraries for web, desktop and mobile.