We find the data feed, and it is composed of nested objects. We'll need to manipulate the remote data quite a bit to get it in the format we need. We achieve this by executing the following steps:
donutRenderer
plugin file. With donut charts, we can use seriesColors
for each ring, so we create arrSeriesColors
to store the colors of our outer rings. Then, we create innerRingColors
to hold the matching colors for our inner ring wedges:<script src="../js/jqplot.donutRenderer.min.js"></script> <script src="../js/functions.js"></script> <script> var arrSeriesColors = "#4bb2c5", "#F4CA4A", "#EAA228", "#E4CAAB", "#00CC55", "#AED8D0", "#F2C185"]; var innerRingColors = [];
browsers
and versions
objects in variables to make our code a little easier to read. We pass the browser data to our parseBrowsers
function and do the same for our version data with parseVersions
. Once all the data is processed, we put it in data
and return it to jqPlot:function dataPull(remoteData,options) { var data = []; var b = remoteData.browsers, v = remoteData.versions; var browser = parseBrowsers(b); var version = parseVersions(v,browser); data = [browser, version]; return data; }
parseBrowsers
function does the same thing as our other functions that looped through the first level of our JSON object. We grab each name, and we add this and the number of visits to our data array. When we're done, we sort the array, and then pass back the browser data to dataPull
:function parseBrowsers(b) { var browsers = [], i = 0; for (var name in b) { if (b.hasOwnProperty(name)) { browsers[i] = [name, b[name]]; i++; } } browsers.sort(descendingSort); return browsers; }
parseVersions
function is a bit more detailed. First, we pass in both the versions
data and the new browser
array. We start by looping through our browser
array. We then use the name to find the corresponding object in our versions
object:function parseVersions(v,browser) { var versions = [], i = 0; for(i=0;i<browser.length;i++){ var name = browser[i][0];
innerRing
array. We also add the browser name as the third element in our data point array. With this done, we'll be able to add the browser to our tooltip later:var innerRing = []; if (v.hasOwnProperty(name)) { for (var ver in v[name]) { innerRing.push([ver, v[name][ver], name]);
arrSeriesColors
and add it to innerRingColors
. This way, the version wedge color will match the color of the browser it belongs to:innerRingColors.push(arrSeriesColors[i]); } }
innerRing
. Then, we loop through innerRing
and add the elements to our versions
array. This way, all the version wedges will be next to the browser wedge in the outer ring, and they will be arranged in descending order:innerRing.sort(descendingSort); for(var j=0;j<innerRing.length;j++){ versions.push(innerRing[j]); } } return versions; }
renderer
to DonutRenderer
. For this chart, we add in a couple of other renderer options. We set innerDiameter
to 50
so that our inner ring will be wider to accommodate our labels. We also assign our arrSeriesColors
array to seriesColors
:$(document).ready(function(){ var browser_plot = $.jqplot ('browser_plot', './data/browser_stats.json', { title: 'Web Browser Usage', seriesDefaults: { renderer:$.jqplot.DonutRenderer, rendererOptions: { showDataLabels: true, sliceMargin: 4, startAngle: -90, innerDiameter: 50, dataLabelThreshold: 0 } }, seriesColors: arrSeriesColors,
seriesColors
option is available within each series, so for our inner ring we assign it innerRingColors
so our wedges will match the outer ring. Since our inner ring will not appear on the legend, we will override the series defaults and set dataLabels
to label
. Also, we move the inner ring labels closer to the outer edge by setting dataLabelPositionFactor
to .75
. This option takes a percentage as a decimal, whereas dataLabelNudge
uses actual pixel values. So, with dataLabelPositionFactor
, the position of our labels will scale if we change the size of our chart:series: [ { }, { seriesColors: innerRingColors, rendererOptions: { dataLabels: 'label', dataLabelPositionFactor: .75 } } ],
dataRenderer: remoteDataCallback, dataRendererOptions: { dataCallback: dataPull }, legend: { show: true, placement: 'outside', location: 's', rendererOptions: { numberRows: 1 } }, });
jqplotDataHighlight
event. We want to display the percentage of usage as well as the browser and version names in our tooltip for our inner ring:$('#browser_plot').on('jqplotDataHighlight', function (ev, seriesIndex, pointIndex, data) { var total = 0;
series
data array for the highlighted series to get our total:for(var i=0;i<browser_plot.series[seriesIndex].data.length;i++) { total += browser_plot.series[seriesIndex].data[i][1]; }
if
statement to only display the browser and percentage:var percent = data[1] / total; percent = percent * 100; if(seriesIndex == 0) { $('#tooltip').html(data[0]+' - '+percent.toFixed(2)+'%'), } else { $('#tooltip').html(data[2]+': '+data[0]+' - '+percent.toFixed(2)+'%'), } } );
jqplotDataUnhighlight
event:$('#browser_plot').on('jqplotDataUnhighlight', function (ev, seriesIndex, pointIndex, data) { $('#tooltip').html(''), } ); }); </script>
<div id="browser_plot" style="width:800px;height:600px;margin-left:30px;"></div> <div id="tooltip"></div> <style> .jqplot-table-legend.jqplot-table-legend-label { white-space: nowrap; padding:3px;} .jqplot-table-legend { padding: 3px; font-size: 1.25em;} .jqplot-donut-series.jqplot-data-label { color: #fff; text-shadow: 2px 2px 2px #000;} #tooltip { float:left;position: absolute; top:50px;left:100px;} </style>
Once we complete our coding, we load the chart in our browser. We can see the results in the following screenshot. The chart matches what we originally conceived. Jeff should be happy!
We notice that one of the slices is so small that it isn't rendered even with dataLabelThreshold
set to 0
. Counting all the percentages of the inner ring, we determine that the percentage for Internet Explorer 7.0 is less than 1 percent. For our purposes, missing 1 percent will not make a huge difference.
Calvin stops by a few minutes later and we show him what we have. "Good work, let me call around and try and set up a quick meeting." Calvin steps out of the room, and 20 minutes later, we are sitting in the same conference room as this morning.
We walk them through the charts we created. When we show them the product category chart, Jeff says, "wow, that is a lot of data." After some discussion, everyone agrees that the product category chart is overwhelming. We decide we'll revisit the chart later.
They really like the divisional revenue chart. Someone mentions that the Nerd Corral chart works well, but the others are a bit jumbled. Finally, we show off Jeff's chart. Jeff likes it, especially since it shows that traffic for Internet Explorer 7 and 8 is not very high. We suggest it might work just as well as a bar chart.
Roshan speaks up, "I really like what you two have done. After seeing the charts, we have to agree with you on some of your concerns. I think the next step will be to take the charts you created and make them more interactive. When I move my mouse over a data point, can the data appear near my cursor instead of somewhere else on the page?"
We tell Roshan we should be able to do that. We head back to our office and gather our things to head home. We'll start on making the charts more interactive tomorrow.
3.133.148.105