Fixing jqPlot chart to toggle (show and hide) slices in Pie charts.

I found a question on stackoverflow where one guy found out that the enhancedLegendRenderer plugin didn’t work with jqPlot Pie Charts. He also posted a jsFiddle example where you can show/hide lines in the Line chart by clicking on legend items, but it doesn’t work with the Pie chart. I decided to investigate why it happens.

By looking at jqPlot source code I found out that the EnhancedLegendRenderer generates items 1:1 to chart series.

    if (idx < series.length) {
        s = series[idx];

Let’s look at the example. The Line chart with 6 lines has 6 series (series.length = 6).

data.push([[1,1.0] , [2,6.0] , [3,9.0] , [4,8.0]]); // #1
data.push([[1,4.0] , [2,3.0] , [3,1.0] , [4,2.0]]); // #2
data.push([[1,6.0] , [2,2.0] , [3,4.0] , [4,1.0]]); // #3
data.push([[1,1.0] , [2,2.0] , [3,3.0] , [4,4.0]]); // #4
data.push([[1,4.0] , [2,3.0] , [3,2.0] , [4,1.0]]); // #5
data.push([[1,8.0] , [2,2.0] , [3,6.0] , [4,3.0]]); // #6

But the Pie chart has only 1 series (series.length = 1).

[['Sony',7], ['Samsung',13.3], ['LG',14.7], ['Vizio',5.2], ['Insignia', 1.2]]; // #1

The EnhancedLegendRenderer would generate only 1 item for the Pie chart. This wouldn’t look good,and jqPlot automatically disabled EnhancedLegendRenderer and applied PieLegendRenderer instead which doesn’t have much functionality.

I rewrote this renderer for Pie charts and called it EnhancedPieLegendRenderer. Here is the final result:

jqplot pie chart with enhanced legend

The link to fixed *.js files will be posted at the end of this article.

At first I created a new file, copy-pasted the code of enhancedLegendRenderer, renamed the class name, and then I replaced all “series.length” by “series[0].data.length” because as I described, Pie charts have only 1 series, but many items.
For example, I replaced the code that calculates the number of rows and columns, it looked so before:

if (this.numberRows) {
    nr = this.numberRows;
    if (!this.numberColumns){
        nc = Math.ceil(series.length/nr);
    }
    else{
        nc = this.numberColumns;
    }
}
else if (this.numberColumns) {
    nc = this.numberColumns;
    nr = Math.ceil(series.length/this.numberColumns);
}
else {
    nr = series.length;
    nc = 1;
}

I replaced it for Pie charts so:

var pd = series[0].data;

if (this.numberRows) {
    nr = this.numberRows;
    if (!this.numberColumns){
        nc = Math.ceil(pd.length/nr);
    }
    else{
        nc = this.numberColumns;
    }
}
else if (this.numberColumns) {
    nc = this.numberColumns;
    nr = Math.ceil(pd.length/this.numberColumns);
}
else {
    nr = pd.length;
    nc = 1;
}

And in a similar way the rest of the code.

Then I fixed one line in the “preInit” function of “pieRenderer” from

options.legend.renderer = $.jqplot.PieLegendRenderer;

to

options.legend.renderer = options.legend.renderer || $.jqplot.PieLegendRenderer;

Then I applied the new renderer in the Main html page:

legend: {
    renderer: $.jqplot.EnhancedPieLegendRenderer,
    rendererOptions: {
        numberColumns: 3
    },
    show: true
}

—————
After this it started to show the legend, but the show/hide functionality didn’t work.
I decided to add a 3rd parameter to the data array which determines whether the slice is visible or not.
From

[['Sony',7], ['Samsung',13.3], ['LG',14.7], ['Vizio',5.2], ['Insignia', 1.2]];

to

[['Sony',7,true], ['Samsung',13.3,true], ['LG',14.7,true], ['Vizio',5.2,true], ['Insignia', 1.2,true]];

(I added 3rd parameter “visibility=true” for every item)

Then I replaced “handleToogle” function of EnhancedPieLegendRenderer to show/hide correctly. Here it sets the 3rd parameter above, for example, from “[‘Sony’,7,true]” to “[‘Sony’,7,false]”, and then redraws the chart:

series[0].data[i][2] = (series[0].data[i][2] === false ? true : false);
plot.replot();

And then I changed some functions in “pieRenderer” so that they don’t draw items like “[‘Sony’,7,false]” but draw with “true” 3rd parameter:

for (var i=0; i<gd.length; i++) {
    if (this.data[i][2] === false) {
	// Do not draw anything for "false"
	continue;
    }
	
    // Else draw the chart segment
    this.renderer.drawSlice.call(...

I also did some minor changes, and after this showing and hiding slices for Pie charts started to work.

<script type="text/javascript" src="jquery.jqplot.js"></script>
<script type="text/javascript" src="extendedPieRenderer.js"></script>
<script type="text/javascript" src="enhancedPieLegendRenderer.js"></script>
<script type="text/javascript">
var plot = $.jqplot('chart', data, {
	seriesDefaults: {
	  renderer: $.jqplot.PieRenderer
	},
	legend: {
	    renderer: $.jqplot.EnhancedPieLegendRenderer
	}
});
</script>

Download both files below and use it in a similar way as HTML code above or jsFiddle showcase below.
EnhancedPieLegendRenderer: enhancedPieLegendRenderer.js
ExtendedPieRenderer: extendedPieRenderer.js
Showcase example of jqPlot Pie chart: https://jsfiddle.net/19vzL5h2/

Advertisements

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

%d bloggers like this: