Commit 0a601d03 authored by David Schnur's avatar David Schnur

Cleaned up whitespace, braces and strings.

parent 2f7cfcb5
/* /*
Flot plugin for rendering pie charts. The plugin assumes the data is Flot plugin for rendering pie charts.
coming is as a single data value for each series, and each of those
values is a positive value or zero (negative numbers don't make Copyright (c) 2007-2012 IOLA and Ole Laursen.
any sense and will cause strange effects). The data values do Licensed under the MIT license.
NOT need to be passed in as percentage values because it
internally calculates the total and percentages. The plugin assumes that each series has a single data value, and that
each value is a positive integer or zero. Negative numbers don't make
sense for a pie chart, and have unpredictable results. The values do
NOT need to be passed in as percentages; the plugin will calculate the
total and per-slice percentages internally.
* Created by Brian Medendorp, June 2009 * Created by Brian Medendorp, June 2009
* Updated November 2009 with contributions from: btburnett3, Anthony Aragues and Xavi Ivars * Updated November 2009 with contributions from: btburnett3, Anthony Aragues and Xavi Ivars
...@@ -15,7 +19,6 @@ internally calculates the total and percentages. ...@@ -15,7 +19,6 @@ internally calculates the total and percentages.
2009-11-11: Added basic hover from btburnett3 - does not work in IE, and center is off in Chrome and Opera 2009-11-11: Added basic hover from btburnett3 - does not work in IE, and center is off in Chrome and Opera
2009-11-17: Added IE hover capability submitted by Anthony Aragues 2009-11-17: Added IE hover capability submitted by Anthony Aragues
2009-11-18: Added bug fix submitted by Xavi Ivars (issues with arrays when other JS libraries are included as well) 2009-11-18: Added bug fix submitted by Xavi Ivars (issues with arrays when other JS libraries are included as well)
Available options are: Available options are:
series: { series: {
...@@ -58,10 +61,10 @@ More detail and specific examples can be found in the included HTML file. ...@@ -58,10 +61,10 @@ More detail and specific examples can be found in the included HTML file.
*/ */
(function ($) (function ($) {
{
function init(plot) // this is the "body" of the plugin function init(plot) {
{
var canvas = null; var canvas = null;
var canvasWidth = 0; var canvasWidth = 0;
var canvasHeight = 0; var canvasHeight = 0;
...@@ -76,301 +79,313 @@ More detail and specific examples can be found in the included HTML file. ...@@ -76,301 +79,313 @@ More detail and specific examples can be found in the included HTML file.
var legendWidth = 0; var legendWidth = 0;
var processed = false; var processed = false;
var raw = false; var raw = false;
// interactive variables // interactive variables
var highlights = [];
var highlights = [];
// add hook to determine if pie plugin in enabled, and then perform necessary operations // add hook to determine if pie plugin in enabled, and then perform necessary operations
plot.hooks.processOptions.push(checkPieEnabled); plot.hooks.processOptions.push(checkPieEnabled);
plot.hooks.bindEvents.push(bindEvents); plot.hooks.bindEvents.push(bindEvents);
// check to see if the pie plugin is enabled // check to see if the pie plugin is enabled
function checkPieEnabled(plot, options)
{ function checkPieEnabled(plot, options) {
if (options.series.pie.show) if (options.series.pie.show) {
{
//disable grid //disable grid
options.grid.show = false; options.grid.show = false;
// set labels.show // set labels.show
if (options.series.pie.label.show=='auto')
if (options.legend.show) if (options.series.pie.label.show == "auto") {
if (options.legend.show) {
options.series.pie.label.show = false; options.series.pie.label.show = false;
else } else {
options.series.pie.label.show = true; options.series.pie.label.show = true;
}
}
// set radius // set radius
if (options.series.pie.radius=='auto')
if (options.series.pie.label.show) if (options.series.pie.radius == "auto") {
if (options.series.pie.label.show) {
options.series.pie.radius = 3/4; options.series.pie.radius = 3/4;
else } else {
options.series.pie.radius = 1; options.series.pie.radius = 1;
}
}
// ensure sane tilt // ensure sane tilt
if (options.series.pie.tilt>1)
options.series.pie.tilt=1; if (options.series.pie.tilt > 1) {
if (options.series.pie.tilt<0) options.series.pie.tilt = 1;
options.series.pie.tilt=0; } else if (options.series.pie.tilt < 0) {
options.series.pie.tilt = 0;
}
// add processData hook to do transformations on the data // add processData hook to do transformations on the data
plot.hooks.processDatapoints.push(processDatapoints); plot.hooks.processDatapoints.push(processDatapoints);
plot.hooks.drawOverlay.push(drawOverlay); plot.hooks.drawOverlay.push(drawOverlay);
// add draw hook // draw hook
plot.hooks.draw.push(draw); plot.hooks.draw.push(draw);
} }
} }
// bind hoverable events // bind hoverable events
function bindEvents(plot, eventHolder)
{ function bindEvents(plot, eventHolder) {
var options = plot.getOptions(); var options = plot.getOptions();
if (options.series.pie.show) {
if (options.series.pie.show && options.grid.hoverable) if (options.grid.hoverable) {
eventHolder.unbind('mousemove').mousemove(onMouseMove); eventHolder.unbind("mousemove").mousemove(onMouseMove);
}
if (options.series.pie.show && options.grid.clickable) if (options.grid.clickable) {
eventHolder.unbind('click').click(onClick); eventHolder.unbind("click").click(onClick);
} }
}
}
// debugging function that prints out an object // debugging function that prints out an object
function alertObject(obj)
{ function alertObject(obj) {
var msg = '';
function traverse(obj, depth) var msg = "";
{
if (!depth) function traverse(obj, depth) {
if (!depth) {
depth = 0; depth = 0;
}
for (var i = 0; i < obj.length; ++i) for (var i = 0; i < obj.length; ++i)
{ {
for (var j=0; j<depth; j++) for (var j = 0; j < depth; j++) {
msg += '\t'; msg += "\t";
if( typeof obj[i] == "object")
{ // its an object
msg += ''+i+':\n';
traverse(obj[i], depth+1);
} }
else
{ // its a value if( typeof obj[i] == "object") {
msg += ''+i+': '+obj[i]+'\n'; msg += "" + i + ":\n";
traverse(obj[i], depth + 1);
} else {
msg += "" + i + ": " + obj[i] + "\n";
} }
} }
} }
traverse(obj); traverse(obj);
alert(msg); alert(msg);
} }
function calcTotal(data) function calcTotal(data) {
{ for (var i = 0; i < data.length; ++i) {
for (var i = 0; i < data.length; ++i)
{
var item = parseFloat(data[i].data[0][1]); var item = parseFloat(data[i].data[0][1]);
if (item) if (item) {
total += item; total += item;
}
} }
} }
function processDatapoints(plot, series, data, datapoints)
{
if (!processed)
{
processed = true;
function processDatapoints(plot, series, data, datapoints) {
if (!processed) {
processed = true;
canvas = plot.getCanvas(); canvas = plot.getCanvas();
target = $(canvas).parent(); target = $(canvas).parent();
options = plot.getOptions(); options = plot.getOptions();
canvasWidth = plot.getPlaceholder().width();
canvasWidth = plot.getPlaceholder().width(); canvasHeight = plot.getPlaceholder().height();
canvasHeight = plot.getPlaceholder().height();
plot.setData(combine(plot.getData())); plot.setData(combine(plot.getData()));
} }
} }
function setupPie() function setupPie() {
{
legendWidth = target.children().filter('.legend').children().width() || 0; legendWidth = target.children().filter(".legend").children().width() || 0;
// calculate maximum radius and center point // calculate maximum radius and center point
maxRadius = Math.min(canvasWidth,(canvasHeight/options.series.pie.tilt))/2;
centerTop = (canvasHeight/2)+options.series.pie.offset.top; maxRadius = Math.min(canvasWidth, canvasHeight / options.series.pie.tilt) / 2;
centerLeft = (canvasWidth/2); centerTop = canvasHeight / 2 + options.series.pie.offset.top;
centerLeft = canvasWidth / 2;
if (options.series.pie.offset.left=='auto')
if (options.legend.position.match('w')) if (options.series.pie.offset.left == "auto") {
centerLeft += legendWidth/2; if (options.legend.position.match("w")) {
else centerLeft += legendWidth / 2;
centerLeft -= legendWidth/2; } else {
else centerLeft -= legendWidth / 2;
}
} else {
centerLeft += options.series.pie.offset.left; centerLeft += options.series.pie.offset.left;
}
if (centerLeft<maxRadius)
if (centerLeft < maxRadius) {
centerLeft = maxRadius; centerLeft = maxRadius;
else if (centerLeft>canvasWidth-maxRadius) } else if (centerLeft > canvasWidth - maxRadius) {
centerLeft = canvasWidth-maxRadius; centerLeft = canvasWidth - maxRadius;
}
} }
function fixData(data) function fixData(data) {
{ for (var i = 0; i < data.length; ++i) {
for (var i = 0; i < data.length; ++i) if (typeof(data[i].data) == "number") {
{ data[i].data = [[1, data[i].data]];
if (typeof(data[i].data)=='number') } else if (typeof(data[i].data) == "undefined" || typeof(data[i].data[0]) == "undefined") {
data[i].data = [[1,data[i].data]]; if (typeof(data[i].data) != "undefined" && typeof(data[i].data.label) != "undefined") {
else if (typeof(data[i].data)=='undefined' || typeof(data[i].data[0])=='undefined')
{
if (typeof(data[i].data)!='undefined' && typeof(data[i].data.label)!='undefined')
data[i].label = data[i].data.label; // fix weirdness coming from flot data[i].label = data[i].data.label; // fix weirdness coming from flot
data[i].data = [[1,0]]; }
data[i].data = [[1, 0]];
} }
} }
return data; return data;
} }
function combine(data) function combine(data) {
{
data = fixData(data); data = fixData(data);
calcTotal(data); calcTotal(data);
var combined = 0; var combined = 0;
var numCombined = 0; var numCombined = 0;
var color = options.series.pie.combine.color; var color = options.series.pie.combine.color;
var newdata = []; var newdata = [];
for (var i = 0; i < data.length; ++i)
{ for (var i = 0; i < data.length; ++i) {
// make sure its a number // make sure its a number
data[i].data[0][1] = parseFloat(data[i].data[0][1]); data[i].data[0][1] = parseFloat(data[i].data[0][1]);
if (!data[i].data[0][1])
if (!data[i].data[0][1]) {
data[i].data[0][1] = 0; data[i].data[0][1] = 0;
}
if (data[i].data[0][1]/total<=options.series.pie.combine.threshold)
{ if (data[i].data[0][1] / total <= options.series.pie.combine.threshold) {
combined += data[i].data[0][1]; combined += data[i].data[0][1];
numCombined++; numCombined++;
if (!color) if (!color) {
color = data[i].color; color = data[i].color;
} }
else } else {
{
newdata.push({ newdata.push({
data: [[1,data[i].data[0][1]]], data: [[1, data[i].data[0][1]]],
color: data[i].color, color: data[i].color,
label: data[i].label, label: data[i].label,
angle: (data[i].data[0][1]*(Math.PI*2))/total, angle: data[i].data[0][1] * Math.PI * 2 / total,
percent: (data[i].data[0][1]/total*100) percent: data[i].data[0][1] / total * 100
}); });
} }
} }
if (numCombined>0)
if (numCombined > 0) {
newdata.push({ newdata.push({
data: [[1,combined]], data: [[1, combined]],
color: color, color: color,
label: options.series.pie.combine.label, label: options.series.pie.combine.label,
angle: (combined*(Math.PI*2))/total, angle: combined * Math.PI * 2 / total,
percent: (combined/total*100) percent: combined / total * 100
}); });
return newdata; return newdata;
} }
function draw(plot, newCtx) function draw(plot, newCtx) {
{
if (!target) return; // if no series were passed if (!target) {
return; // if no series were passed
}
ctx = newCtx; ctx = newCtx;
setupPie(); setupPie();
var slices = plot.getData(); var slices = plot.getData();
var attempts = 0; var attempts = 0;
while (redraw && attempts<redrawAttempts)
{ while (redraw && attempts<redrawAttempts) {
redraw = false; redraw = false;
if (attempts>0) if (attempts > 0) {
maxRadius *= shrink; maxRadius *= shrink;
}
attempts += 1; attempts += 1;
clear(); clear();
if (options.series.pie.tilt<=0.8) if (options.series.pie.tilt <= 0.8) {
drawShadow(); drawShadow();
}
drawPie(); drawPie();
} }
if (attempts >= redrawAttempts) { if (attempts >= redrawAttempts) {
clear(); clear();
target.prepend('<div class="error">Could not draw pie with labels contained inside canvas</div>'); target.prepend("<div class='error'>Could not draw pie with labels contained inside canvas</div>");
} }
if ( plot.setSeries && plot.insertLegend ) if (plot.setSeries && plot.insertLegend) {
{
plot.setSeries(slices); plot.setSeries(slices);
plot.insertLegend(); plot.insertLegend();
} }
// we're actually done at this point, just defining internal functions at this point // we're actually done at this point, just defining internal functions at this point
function clear() function clear() {
{ ctx.clearRect(0, 0, canvasWidth, canvasHeight);
ctx.clearRect(0,0,canvasWidth,canvasHeight); target.children().filter(".pieLabel, .pieLabelBackground").remove();
target.children().filter('.pieLabel, .pieLabelBackground').remove();
} }
function drawShadow() function drawShadow() {
{
var shadowLeft = options.series.pie.shadow.left; var shadowLeft = options.series.pie.shadow.left;
var shadowTop = options.series.pie.shadow.top; var shadowTop = options.series.pie.shadow.top;
var edge = 10; var edge = 10;
var alpha = options.series.pie.shadow.alpha; var alpha = options.series.pie.shadow.alpha;
var radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius;
// set radius
if (options.series.pie.radius>1) if (radius >= canvasWidth / 2 - shadowLeft || radius * options.series.pie.tilt >= canvasHeight / 2 - shadowTop || radius <= edge) {
var radius = options.series.pie.radius;
else
var radius = maxRadius * options.series.pie.radius;
if (radius>=(canvasWidth/2)-shadowLeft || radius*options.series.pie.tilt>=(canvasHeight/2)-shadowTop || radius<=edge)
return; // shadow would be outside canvas, so don't draw it return; // shadow would be outside canvas, so don't draw it
}
ctx.save(); ctx.save();
ctx.translate(shadowLeft,shadowTop); ctx.translate(shadowLeft,shadowTop);
ctx.globalAlpha = alpha; ctx.globalAlpha = alpha;
ctx.fillStyle = '#000'; ctx.fillStyle = "#000";
// center and rotate to starting position // center and rotate to starting position
ctx.translate(centerLeft,centerTop); ctx.translate(centerLeft,centerTop);
ctx.scale(1, options.series.pie.tilt); ctx.scale(1, options.series.pie.tilt);
//radius -= edge; //radius -= edge;
for (var i=1; i<=edge; i++)
{ for (var i = 1; i <= edge; i++) {
ctx.beginPath(); ctx.beginPath();
ctx.arc(0,0,radius,0,Math.PI*2,false); ctx.arc(0, 0, radius, 0, Math.PI * 2, false);
ctx.fill(); ctx.fill();
radius -= i; radius -= i;
} }
ctx.restore(); ctx.restore();
} }
function drawPie()
{
var startAngle = Math.PI * options.series.pie.startAngle;
var radius;
// set radius function drawPie() {
if (options.series.pie.radius > 1)
radius = options.series.pie.radius; var startAngle = Math.PI * options.series.pie.startAngle;
else radius = maxRadius * options.series.pie.radius; var radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius;
// center and rotate to starting position // center and rotate to starting position
ctx.save(); ctx.save();
ctx.translate(centerLeft,centerTop); ctx.translate(centerLeft,centerTop);
ctx.scale(1, options.series.pie.tilt); ctx.scale(1, options.series.pie.tilt);
//ctx.rotate(startAngle); // start at top; -- This doesn't work properly in Opera //ctx.rotate(startAngle); // start at top; -- This doesn't work properly in Opera
// draw slices // draw slices
ctx.save(); ctx.save();
var currentAngle = startAngle; var currentAngle = startAngle;
for (var i = 0; i < slices.length; ++i) for (var i = 0; i < slices.length; ++i) {
{
slices[i].startAngle = currentAngle; slices[i].startAngle = currentAngle;
drawSlice(slices[i].angle, slices[i].color, true); drawSlice(slices[i].angle, slices[i].color, true);
} }
...@@ -382,286 +397,313 @@ More detail and specific examples can be found in the included HTML file. ...@@ -382,286 +397,313 @@ More detail and specific examples can be found in the included HTML file.
ctx.save(); ctx.save();
ctx.lineWidth = options.series.pie.stroke.width; ctx.lineWidth = options.series.pie.stroke.width;
currentAngle = startAngle; currentAngle = startAngle;
for (var i = 0; i < slices.length; ++i) for (var i = 0; i < slices.length; ++i) {
drawSlice(slices[i].angle, options.series.pie.stroke.color, false); drawSlice(slices[i].angle, options.series.pie.stroke.color, false);
}
ctx.restore(); ctx.restore();
} }
// draw donut hole // draw donut hole
drawDonutHole(ctx); drawDonutHole(ctx);
// draw labels // draw labels
if (options.series.pie.label.show)
if (options.series.pie.label.show) {
drawLabels(); drawLabels();
}
// restore to original state // restore to original state
ctx.restore(); ctx.restore();
function drawSlice(angle, color, fill) function drawSlice(angle, color, fill) {
{
if (angle <= 0 || isNaN(angle)) if (angle <= 0 || isNaN(angle)) {
return; return;
}
if (fill)
if (fill) {
ctx.fillStyle = color; ctx.fillStyle = color;
else } else {
{
ctx.strokeStyle = color; ctx.strokeStyle = color;
ctx.lineJoin = 'round'; ctx.lineJoin = "round";
} }
ctx.beginPath(); ctx.beginPath();
if (Math.abs(angle - Math.PI*2) > 0.000000001) if (Math.abs(angle - Math.PI * 2) > 0.000000001) {
ctx.moveTo(0,0); // Center of the pie ctx.moveTo(0, 0); // Center of the pie
else if ($.browser.msie) } else if ($.browser.msie) {
angle -= 0.0001; angle -= 0.0001;
//ctx.arc(0,0,radius,0,angle,false); // This doesn't work properly in Opera }
ctx.arc(0,0,radius,currentAngle,currentAngle+angle,false);
//ctx.arc(0, 0, radius, 0, angle, false); // This doesn't work properly in Opera
ctx.arc(0, 0, radius,currentAngle, currentAngle + angle, false);
ctx.closePath(); ctx.closePath();
//ctx.rotate(angle); // This doesn't work properly in Opera //ctx.rotate(angle); // This doesn't work properly in Opera
currentAngle += angle; currentAngle += angle;
if (fill) if (fill) {
ctx.fill(); ctx.fill();
else } else {
ctx.stroke(); ctx.stroke();
}
} }
function drawLabels() function drawLabels() {
{
var currentAngle = startAngle; var currentAngle = startAngle;
var radius = options.series.pie.label.radius > 1 ? options.series.pie.label.radius : maxRadius * options.series.pie.label.radius;
// set radius
if (options.series.pie.label.radius>1) for (var i = 0; i < slices.length; ++i) {
var radius = options.series.pie.label.radius; if (slices[i].percent >= options.series.pie.label.threshold * 100) {
else
var radius = maxRadius * options.series.pie.label.radius;
for (var i = 0; i < slices.length; ++i)
{
if (slices[i].percent >= options.series.pie.label.threshold*100)
drawLabel(slices[i], currentAngle, i); drawLabel(slices[i], currentAngle, i);
}
currentAngle += slices[i].angle; currentAngle += slices[i].angle;
} }
function drawLabel(slice, startAngle, index) function drawLabel(slice, startAngle, index) {
{ if (slice.data[0][1] == 0) {
if (slice.data[0][1]==0)
return; return;
}
// format label text // format label text
var lf = options.legend.labelFormatter, text, plf = options.series.pie.label.formatter; var lf = options.legend.labelFormatter, text, plf = options.series.pie.label.formatter;
if (lf)
if (lf) {
text = lf(slice.label, slice); text = lf(slice.label, slice);
else } else {
text = slice.label; text = slice.label;
if (plf) }
if (plf) {
text = plf(text, slice); text = plf(text, slice);
}
var halfAngle = ((startAngle+slice.angle) + startAngle)/2;
var halfAngle = ((startAngle + slice.angle) + startAngle) / 2;
var x = centerLeft + Math.round(Math.cos(halfAngle) * radius); var x = centerLeft + Math.round(Math.cos(halfAngle) * radius);
var y = centerTop + Math.round(Math.sin(halfAngle) * radius) * options.series.pie.tilt; var y = centerTop + Math.round(Math.sin(halfAngle) * radius) * options.series.pie.tilt;
var html = '<span class="pieLabel" id="pieLabel'+index+'" style="position:absolute;top:' + y + 'px;left:' + x + 'px;">' + text + "</span>"; var html = "<span class='pieLabel' id='pieLabel" + index + "' style='position:absolute;top:" + y + "px;left:" + x + "px;'>" + text + "</span>";
target.append(html); target.append(html);
var label = target.children('#pieLabel'+index);
var labelTop = (y - label.height()/2); var label = target.children("#pieLabel" + index);
var labelLeft = (x - label.width()/2); var labelTop = (y - label.height() / 2);
label.css('top', labelTop); var labelLeft = (x - label.width() / 2);
label.css('left', labelLeft);
label.css("top", labelTop);
label.css("left", labelLeft);
// check to make sure that the label is not outside the canvas // check to make sure that the label is not outside the canvas
if (0-labelTop>0 || 0-labelLeft>0 || canvasHeight-(labelTop+label.height())<0 || canvasWidth-(labelLeft+label.width())<0)
if (0 - labelTop > 0 || 0 - labelLeft > 0 || canvasHeight - (labelTop + label.height()) < 0 || canvasWidth - (labelLeft + label.width()) < 0) {
redraw = true; redraw = true;
}
if (options.series.pie.label.background.opacity != 0) { if (options.series.pie.label.background.opacity != 0) {
// put in the transparent background separately to avoid blended labels and label boxes // put in the transparent background separately to avoid blended labels and label boxes
var c = options.series.pie.label.background.color; var c = options.series.pie.label.background.color;
if (c == null) { if (c == null) {
c = slice.color; c = slice.color;
} }
var pos = 'top:'+labelTop+'px;left:'+labelLeft+'px;';
$('<div class="pieLabelBackground" style="position:absolute;width:' + label.width() + 'px;height:' + label.height() + 'px;' + pos +'background-color:' + c + ';"> </div>').insertBefore(label).css('opacity', options.series.pie.label.background.opacity); var pos = "top:" + labelTop + "px;left:" + labelLeft + "px;";
$("<div class='pieLabelBackground' style='position:absolute;width:" + label.width() + "px;height:" + label.height() + "px;" + pos + "background-color:" + c + ";'></div>")
.css("opacity", options.series.pie.label.background.opacity)
.insertBefore(label);
} }
} // end individual label function } // end individual label function
} // end drawLabels function } // end drawLabels function
} // end drawPie function } // end drawPie function
} // end draw function } // end draw function
// Placed here because it needs to be accessed from multiple locations // Placed here because it needs to be accessed from multiple locations
function drawDonutHole(layer)
{ function drawDonutHole(layer) {
// draw donut hole if (options.series.pie.innerRadius > 0) {
if(options.series.pie.innerRadius > 0)
{
// subtract the center // subtract the center
layer.save(); layer.save();
innerRadius = options.series.pie.innerRadius > 1 ? options.series.pie.innerRadius : maxRadius * options.series.pie.innerRadius; innerRadius = options.series.pie.innerRadius > 1 ? options.series.pie.innerRadius : maxRadius * options.series.pie.innerRadius;
layer.globalCompositeOperation = 'destination-out'; // this does not work with excanvas, but it will fall back to using the stroke color layer.globalCompositeOperation = "destination-out"; // this does not work with excanvas, but it will fall back to using the stroke color
layer.beginPath(); layer.beginPath();
layer.fillStyle = options.series.pie.stroke.color; layer.fillStyle = options.series.pie.stroke.color;
layer.arc(0,0,innerRadius,0,Math.PI*2,false); layer.arc(0, 0, innerRadius, 0, Math.PI * 2, false);
layer.fill(); layer.fill();
layer.closePath(); layer.closePath();
layer.restore(); layer.restore();
// add inner stroke // add inner stroke
layer.save(); layer.save();
layer.beginPath(); layer.beginPath();
layer.strokeStyle = options.series.pie.stroke.color; layer.strokeStyle = options.series.pie.stroke.color;
layer.arc(0,0,innerRadius,0,Math.PI*2,false); layer.arc(0, 0, innerRadius, 0, Math.PI * 2, false);
layer.stroke(); layer.stroke();
layer.closePath(); layer.closePath();
layer.restore(); layer.restore();
// TODO: add extra shadow inside hole (with a mask) if the pie is tilted. // TODO: add extra shadow inside hole (with a mask) if the pie is tilted.
} }
} }
//-- Additional Interactive related functions -- //-- Additional Interactive related functions --
function isPointInPoly(poly, pt) function isPointInPoly(poly, pt) {
{
for(var c = false, i = -1, l = poly.length, j = l - 1; ++i < l; j = i) for(var c = false, i = -1, l = poly.length, j = l - 1; ++i < l; j = i)
((poly[i][1] <= pt[1] && pt[1] < poly[j][1]) || (poly[j][1] <= pt[1] && pt[1]< poly[i][1])) ((poly[i][1] <= pt[1] && pt[1] < poly[j][1]) || (poly[j][1] <= pt[1] && pt[1]< poly[i][1]))
&& (pt[0] < (poly[j][0] - poly[i][0]) * (pt[1] - poly[i][1]) / (poly[j][1] - poly[i][1]) + poly[i][0]) && (pt[0] < (poly[j][0] - poly[i][0]) * (pt[1] - poly[i][1]) / (poly[j][1] - poly[i][1]) + poly[i][0])
&& (c = !c); && (c = !c);
return c; return c;
} }
function findNearbySlice(mouseX, mouseY) function findNearbySlice(mouseX, mouseY) {
{
var slices = plot.getData(), var slices = plot.getData();
options = plot.getOptions(), var options = plot.getOptions();
radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius; var radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius;
for (var i = 0; i < slices.length; ++i) for (var i = 0; i < slices.length; ++i) {
{
var s = slices[i]; var s = slices[i];
if(s.pie.show) if (s.pie.show) {
{
ctx.save(); ctx.save();
ctx.beginPath(); ctx.beginPath();
ctx.moveTo(0,0); // Center of the pie ctx.moveTo(0, 0); // Center of the pie
//ctx.scale(1, options.series.pie.tilt); // this actually seems to break everything when here. //ctx.scale(1, options.series.pie.tilt); // this actually seems to break everything when here.
ctx.arc(0,0,radius,s.startAngle,s.startAngle+s.angle,false); ctx.arc(0, 0, radius, s.startAngle, s.startAngle + s.angle, false);
ctx.closePath(); ctx.closePath();
x = mouseX-centerLeft; x = mouseX - centerLeft;
y = mouseY-centerTop; y = mouseY - centerTop;
if(ctx.isPointInPath)
{ if (ctx.isPointInPath) {
if (ctx.isPointInPath(mouseX-centerLeft, mouseY-centerTop)) if (ctx.isPointInPath(mouseX - centerLeft, mouseY - centerTop)) {
{
//alert('found slice!');
ctx.restore(); ctx.restore();
return {datapoint: [s.percent, s.data], dataIndex: 0, series: s, seriesIndex: i}; return {
datapoint: [s.percent, s.data],
dataIndex: 0,
series: s,
seriesIndex: i
};
} }
} } else {
else
{ // excanvas for IE doesn;t support isPointInPath, this is a workaround.
// excanvas for IE doesn;t support isPointInPath, this is a workaround.
p1X = (radius * Math.cos(s.startAngle)); p1X = radius * Math.cos(s.startAngle);
p1Y = (radius * Math.sin(s.startAngle)); p1Y = radius * Math.sin(s.startAngle);
p2X = (radius * Math.cos(s.startAngle+(s.angle/4))); p2X = radius * Math.cos(s.startAngle + s.angle / 4);
p2Y = (radius * Math.sin(s.startAngle+(s.angle/4))); p2Y = radius * Math.sin(s.startAngle + s.angle / 4);
p3X = (radius * Math.cos(s.startAngle+(s.angle/2))); p3X = radius * Math.cos(s.startAngle + s.angle / 2);
p3Y = (radius * Math.sin(s.startAngle+(s.angle/2))); p3Y = radius * Math.sin(s.startAngle + s.angle / 2);
p4X = (radius * Math.cos(s.startAngle+(s.angle/1.5))); p4X = radius * Math.cos(s.startAngle + s.angle / 1.5);
p4Y = (radius * Math.sin(s.startAngle+(s.angle/1.5))); p4Y = radius * Math.sin(s.startAngle + s.angle / 1.5);
p5X = (radius * Math.cos(s.startAngle+s.angle)); p5X = radius * Math.cos(s.startAngle + s.angle);
p5Y = (radius * Math.sin(s.startAngle+s.angle)); p5Y = radius * Math.sin(s.startAngle + s.angle);
arrPoly = [[0,0],[p1X,p1Y],[p2X,p2Y],[p3X,p3Y],[p4X,p4Y],[p5X,p5Y]]; arrPoly = [[0, 0], [p1X, p1Y], [p2X, p2Y], [p3X, p3Y], [p4X, p4Y], [p5X, p5Y]];
arrPoint = [x,y]; arrPoint = [x, y];
// TODO: perhaps do some mathmatical trickery here with the Y-coordinate to compensate for pie tilt? // TODO: perhaps do some mathmatical trickery here with the Y-coordinate to compensate for pie tilt?
if(isPointInPoly(arrPoly, arrPoint))
{ if (isPointInPoly(arrPoly, arrPoint)) {
ctx.restore(); ctx.restore();
return {datapoint: [s.percent, s.data], dataIndex: 0, series: s, seriesIndex: i}; return {
} datapoint: [s.percent, s.data],
dataIndex: 0,
series: s,
seriesIndex: i
};
}
} }
ctx.restore(); ctx.restore();
} }
} }
return null; return null;
} }
function onMouseMove(e) function onMouseMove(e) {
{ triggerClickHoverEvent("plothover", e);
triggerClickHoverEvent('plothover', e);
} }
function onClick(e) function onClick(e) {
{ triggerClickHoverEvent("plotclick", e);
triggerClickHoverEvent('plotclick', e);
} }
// trigger click or hover event (they send the same parameters so we share their code) // trigger click or hover event (they send the same parameters so we share their code)
function triggerClickHoverEvent(eventname, e)
{ function triggerClickHoverEvent(eventname, e) {
var offset = plot.offset(), var offset = plot.offset();
canvasX = parseInt(e.pageX - offset.left), var canvasX = parseInt(e.pageX - offset.left);
canvasY = parseInt(e.pageY - offset.top), var canvasY = parseInt(e.pageY - offset.top);
item = findNearbySlice(canvasX, canvasY); var item = findNearbySlice(canvasX, canvasY);
if (options.grid.autoHighlight) if (options.grid.autoHighlight) {
{
// clear auto-highlights // clear auto-highlights
for (var i = 0; i < highlights.length; ++i)
{ for (var i = 0; i < highlights.length; ++i) {
var h = highlights[i]; var h = highlights[i];
if (h.auto == eventname && !(item && h.series == item.series)) if (h.auto == eventname && !(item && h.series == item.series)) {
unhighlight(h.series); unhighlight(h.series);
}
} }
} }
// highlight the slice // highlight the slice
if (item)
if (item) {
highlight(item.series, eventname); highlight(item.series, eventname);
}
// trigger any hover bind events // trigger any hover bind events
var pos = { pageX: e.pageX, pageY: e.pageY }; var pos = { pageX: e.pageX, pageY: e.pageY };
target.trigger(eventname, [ pos, item ]); target.trigger(eventname, [pos, item]);
} }
function highlight(s, auto) function highlight(s, auto) {
{ if (typeof s == "number") {
if (typeof s == "number")
s = series[s]; s = series[s];
}
var i = indexOfHighlight(s); var i = indexOfHighlight(s);
if (i == -1)
{ if (i == -1) {
highlights.push({ series: s, auto: auto }); highlights.push({ series: s, auto: auto });
plot.triggerRedrawOverlay(); plot.triggerRedrawOverlay();
} } else if (!auto) {
else if (!auto)
highlights[i].auto = false; highlights[i].auto = false;
}
} }
function unhighlight(s) function unhighlight(s) {
{ if (s == null) {
if (s == null)
{
highlights = []; highlights = [];
plot.triggerRedrawOverlay(); plot.triggerRedrawOverlay();
} }
if (typeof s == "number") if (typeof s == "number") {
s = series[s]; s = series[s];
}
var i = indexOfHighlight(s); var i = indexOfHighlight(s);
if (i != -1)
{ if (i != -1) {
highlights.splice(i, 1); highlights.splice(i, 1);
plot.triggerRedrawOverlay(); plot.triggerRedrawOverlay();
} }
} }
function indexOfHighlight(s) function indexOfHighlight(s) {
{ for (var i = 0; i < highlights.length; ++i) {
for (var i = 0; i < highlights.length; ++i)
{
var h = highlights[i]; var h = highlights[i];
if (h.series == s) if (h.series == s)
return i; return i;
...@@ -669,52 +711,50 @@ More detail and specific examples can be found in the included HTML file. ...@@ -669,52 +711,50 @@ More detail and specific examples can be found in the included HTML file.
return -1; return -1;
} }
function drawOverlay(plot, octx) function drawOverlay(plot, octx) {
{
//alert(options.series.pie.radius);
var options = plot.getOptions(); var options = plot.getOptions();
//alert(options.series.pie.radius);
var radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius; var radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius;
octx.save(); octx.save();
octx.translate(centerLeft, centerTop); octx.translate(centerLeft, centerTop);
octx.scale(1, options.series.pie.tilt); octx.scale(1, options.series.pie.tilt);
for (i = 0; i < highlights.length; ++i) for (i = 0; i < highlights.length; ++i) {
drawHighlight(highlights[i].series); drawHighlight(highlights[i].series);
}
drawDonutHole(octx); drawDonutHole(octx);
octx.restore(); octx.restore();
function drawHighlight(series) function drawHighlight(series) {
{
if (series.angle <= 0 || isNaN(series.angle)) if (series.angle <= 0 || isNaN(series.angle)) {
return; return;
}
//octx.fillStyle = parseColor(options.series.pie.highlight.color).scale(null, null, null, options.series.pie.highlight.opacity).toString(); //octx.fillStyle = parseColor(options.series.pie.highlight.color).scale(null, null, null, options.series.pie.highlight.opacity).toString();
octx.fillStyle = "rgba(255, 255, 255, "+options.series.pie.highlight.opacity+")"; // this is temporary until we have access to parseColor octx.fillStyle = "rgba(255, 255, 255, " + options.series.pie.highlight.opacity + ")"; // this is temporary until we have access to parseColor
octx.beginPath(); octx.beginPath();
if (Math.abs(series.angle - Math.PI*2) > 0.000000001) if (Math.abs(series.angle - Math.PI * 2) > 0.000000001) {
octx.moveTo(0,0); // Center of the pie octx.moveTo(0, 0); // Center of the pie
octx.arc(0,0,radius,series.startAngle,series.startAngle+series.angle,false); }
octx.arc(0, 0, radius, series.startAngle, series.startAngle + series.angle, false);
octx.closePath(); octx.closePath();
octx.fill(); octx.fill();
} }
}
}
} // end init (plugin body) } // end init (plugin body)
// define pie specific options and their default values // define pie specific options and their default values
var options = { var options = {
series: { series: {
pie: { pie: {
show: false, show: false,
radius: 'auto', // actual radius of the visible pie (based on full calculated radius if <=1, or hard pixel value) radius: "auto", // actual radius of the visible pie (based on full calculated radius if <=1, or hard pixel value)
innerRadius:0, /* for donut */ innerRadius: 0, /* for donut */
startAngle: 3/2, startAngle: 3/2,
tilt: 1, tilt: 1,
shadow: { shadow: {
...@@ -724,16 +764,16 @@ More detail and specific examples can be found in the included HTML file. ...@@ -724,16 +764,16 @@ More detail and specific examples can be found in the included HTML file.
}, },
offset: { offset: {
top: 0, top: 0,
left: 'auto' left: "auto"
}, },
stroke: { stroke: {
color: '#FFF', color: "#fff",
width: 1 width: 1
}, },
label: { label: {
show: 'auto', show: "auto",
formatter: function(label, slice){ formatter: function(label, slice) {
return '<div style="font-size:x-small;text-align:center;padding:2px;color:'+slice.color+';">'+label+'<br/>'+Math.round(slice.percent)+'%</div>'; return "<div style='font-size:x-small;text-align:center;padding:2px;color:" + slice.color + ";'>" + label + "<br/>" + Math.round(slice.percent) + "%</div>";
}, // formatter function }, // formatter function
radius: 1, // radius at which to place the labels (based on full calculated radius if <=1, or hard pixel value) radius: 1, // radius at which to place the labels (based on full calculated radius if <=1, or hard pixel value)
background: { background: {
...@@ -745,20 +785,21 @@ More detail and specific examples can be found in the included HTML file. ...@@ -745,20 +785,21 @@ More detail and specific examples can be found in the included HTML file.
combine: { combine: {
threshold: -1, // percentage at which to combine little slices into one larger slice threshold: -1, // percentage at which to combine little slices into one larger slice
color: null, // color to give the new slice (auto-generated if null) color: null, // color to give the new slice (auto-generated if null)
label: 'Other' // label to give the new slice label: "Other" // label to give the new slice
}, },
highlight: { highlight: {
//color: '#FFF', // will add this functionality once parseColor is available //color: "#fff", // will add this functionality once parseColor is available
opacity: 0.5 opacity: 0.5
} }
} }
} }
}; };
$.plot.plugins.push({ $.plot.plugins.push({
init: init, init: init,
options: options, options: options,
name: "pie", name: "pie",
version: "1.0" version: "1.1"
}); });
})(jQuery); })(jQuery);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment