Spaces:
Runtime error
Runtime error
| /* | |
| Flot plugin for rendering pie charts. The plugin assumes the data is | |
| 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 | |
| any sense and will cause strange effects). The data values do | |
| NOT need to be passed in as percentage values because it | |
| internally calculates the total and percentages. | |
| * Created by Brian Medendorp, June 2009 | |
| * Updated November 2009 with contributions from: btburnett3, Anthony Aragues and Xavi Ivars | |
| * Changes: | |
| 2009-10-22: lineJoin set to round | |
| 2009-10-23: IE full circle fix, donut | |
| 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-18: Added bug fix submitted by Xavi Ivars (issues with arrays when other JS libraries are included as well) | |
| Available options are: | |
| series: { | |
| pie: { | |
| show: true/false | |
| radius: 0-1 for percentage of fullsize, or a specified pixel length, or 'auto' | |
| innerRadius: 0-1 for percentage of fullsize or a specified pixel length, for creating a donut effect | |
| startAngle: 0-2 factor of PI used for starting angle (in radians) i.e 3/2 starts at the top, 0 and 2 have the same result | |
| tilt: 0-1 for percentage to tilt the pie, where 1 is no tilt, and 0 is completely flat (nothing will show) | |
| offset: { | |
| top: integer value to move the pie up or down | |
| left: integer value to move the pie left or right, or 'auto' | |
| }, | |
| stroke: { | |
| color: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#FFF') | |
| width: integer pixel width of the stroke | |
| }, | |
| label: { | |
| show: true/false, or 'auto' | |
| formatter: a user-defined function that modifies the text/style of the label text | |
| radius: 0-1 for percentage of fullsize, or a specified pixel length | |
| background: { | |
| color: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#000') | |
| opacity: 0-1 | |
| }, | |
| threshold: 0-1 for the percentage value at which to hide labels (if they're too small) | |
| }, | |
| combine: { | |
| threshold: 0-1 for the percentage value at which to combine slices (if they're too small) | |
| color: any hexidecimal color value (other formats may or may not work, so best to stick with something like '#CCC'), if null, the plugin will automatically use the color of the first slice to be combined | |
| label: any text value of what the combined slice should be labeled | |
| } | |
| highlight: { | |
| opacity: 0-1 | |
| } | |
| } | |
| } | |
| More detail and specific examples can be found in the included HTML file. | |
| */ | |
| (function ($) | |
| { | |
| function init(plot) // this is the "body" of the plugin | |
| { | |
| var canvas = null; | |
| var target = null; | |
| var maxRadius = null; | |
| var centerLeft = null; | |
| var centerTop = null; | |
| var total = 0; | |
| var redraw = true; | |
| var redrawAttempts = 10; | |
| var shrink = 0.95; | |
| var legendWidth = 0; | |
| var processed = false; | |
| var raw = false; | |
| // interactive variables | |
| var highlights = []; | |
| // add hook to determine if pie plugin in enabled, and then perform necessary operations | |
| plot.hooks.processOptions.push(checkPieEnabled); | |
| plot.hooks.bindEvents.push(bindEvents); | |
| // check to see if the pie plugin is enabled | |
| function checkPieEnabled(plot, options) | |
| { | |
| if (options.series.pie.show) | |
| { | |
| //disable grid | |
| options.grid.show = false; | |
| // set labels.show | |
| if (options.series.pie.label.show=='auto') | |
| if (options.legend.show) | |
| options.series.pie.label.show = false; | |
| else | |
| options.series.pie.label.show = true; | |
| // set radius | |
| if (options.series.pie.radius=='auto') | |
| if (options.series.pie.label.show) | |
| options.series.pie.radius = 3/4; | |
| else | |
| options.series.pie.radius = 1; | |
| // ensure sane tilt | |
| if (options.series.pie.tilt>1) | |
| options.series.pie.tilt=1; | |
| if (options.series.pie.tilt<0) | |
| options.series.pie.tilt=0; | |
| // add processData hook to do transformations on the data | |
| plot.hooks.processDatapoints.push(processDatapoints); | |
| plot.hooks.drawOverlay.push(drawOverlay); | |
| // add draw hook | |
| plot.hooks.draw.push(draw); | |
| } | |
| } | |
| // bind hoverable events | |
| function bindEvents(plot, eventHolder) | |
| { | |
| var options = plot.getOptions(); | |
| if (options.series.pie.show && options.grid.hoverable) | |
| eventHolder.unbind('mousemove').mousemove(onMouseMove); | |
| if (options.series.pie.show && options.grid.clickable) | |
| eventHolder.unbind('click').click(onClick); | |
| } | |
| // debugging function that prints out an object | |
| function alertObject(obj) | |
| { | |
| var msg = ''; | |
| function traverse(obj, depth) | |
| { | |
| if (!depth) | |
| depth = 0; | |
| for (var i = 0; i < obj.length; ++i) | |
| { | |
| for (var j=0; j<depth; j++) | |
| msg += '\t'; | |
| if( typeof obj[i] == "object") | |
| { // its an object | |
| msg += ''+i+':\n'; | |
| traverse(obj[i], depth+1); | |
| } | |
| else | |
| { // its a value | |
| msg += ''+i+': '+obj[i]+'\n'; | |
| } | |
| } | |
| } | |
| traverse(obj); | |
| alert(msg); | |
| } | |
| function calcTotal(data) | |
| { | |
| for (var i = 0; i < data.length; ++i) | |
| { | |
| var item = parseFloat(data[i].data[0][1]); | |
| if (item) | |
| total += item; | |
| } | |
| } | |
| function processDatapoints(plot, series, data, datapoints) | |
| { | |
| if (!processed) | |
| { | |
| processed = true; | |
| canvas = plot.getCanvas(); | |
| target = $(canvas).parent(); | |
| options = plot.getOptions(); | |
| plot.setData(combine(plot.getData())); | |
| } | |
| } | |
| function setupPie() | |
| { | |
| var placeholder = plot.getPlaceholder(), | |
| width = placeholder.width(), | |
| height = placeholder.height(); | |
| legendWidth = target.children().filter('.legend').children().width(); | |
| // calculate maximum radius and center point | |
| maxRadius = Math.min(width,(height/options.series.pie.tilt))/2; | |
| centerTop = (height/2)+options.series.pie.offset.top; | |
| centerLeft = (width/2); | |
| if (options.series.pie.offset.left=='auto') | |
| if (options.legend.position.match('w')) | |
| centerLeft += legendWidth/2; | |
| else | |
| centerLeft -= legendWidth/2; | |
| else | |
| centerLeft += options.series.pie.offset.left; | |
| if (centerLeft<maxRadius) | |
| centerLeft = maxRadius; | |
| else if (centerLeft>width-maxRadius) | |
| centerLeft = width-maxRadius; | |
| } | |
| function fixData(data) | |
| { | |
| for (var i = 0; i < data.length; ++i) | |
| { | |
| if (typeof(data[i].data)=='number') | |
| data[i].data = [[1,data[i].data]]; | |
| 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].data = [[1,0]]; | |
| } | |
| } | |
| return data; | |
| } | |
| function combine(data) | |
| { | |
| data = fixData(data); | |
| calcTotal(data); | |
| var combined = 0; | |
| var numCombined = 0; | |
| var color = options.series.pie.combine.color; | |
| var newdata = []; | |
| for (var i = 0; i < data.length; ++i) | |
| { | |
| // make sure its a number | |
| data[i].data[0][1] = parseFloat(data[i].data[0][1]); | |
| if (!data[i].data[0][1]) | |
| data[i].data[0][1] = 0; | |
| if (data[i].data[0][1]/total<=options.series.pie.combine.threshold) | |
| { | |
| combined += data[i].data[0][1]; | |
| numCombined++; | |
| if (!color) | |
| color = data[i].color; | |
| } | |
| else | |
| { | |
| newdata.push({ | |
| data: [[1,data[i].data[0][1]]], | |
| color: data[i].color, | |
| label: data[i].label, | |
| angle: (data[i].data[0][1]*(Math.PI*2))/total, | |
| percent: (data[i].data[0][1]/total*100) | |
| }); | |
| } | |
| } | |
| if (numCombined>0) | |
| newdata.push({ | |
| data: [[1,combined]], | |
| color: color, | |
| label: options.series.pie.combine.label, | |
| angle: (combined*(Math.PI*2))/total, | |
| percent: (combined/total*100) | |
| }); | |
| return newdata; | |
| } | |
| function draw(plot, newCtx) | |
| { | |
| if (!target) return; // if no series were passed | |
| ctx = newCtx; | |
| setupPie(); | |
| var slices = plot.getData(); | |
| var attempts = 0; | |
| while (redraw && attempts<redrawAttempts) | |
| { | |
| redraw = false; | |
| if (attempts>0) | |
| maxRadius *= shrink; | |
| attempts += 1; | |
| clear(); | |
| if (options.series.pie.tilt<=0.8) | |
| drawShadow(); | |
| drawPie(); | |
| } | |
| if (attempts >= redrawAttempts) { | |
| clear(); | |
| target.prepend('<div class="error">Could not draw pie with labels contained inside canvas</div>'); | |
| } | |
| if ( plot.setSeries && plot.insertLegend ) | |
| { | |
| plot.setSeries(slices); | |
| plot.insertLegend(); | |
| } | |
| // we're actually done at this point, just defining internal functions at this point | |
| function clear() | |
| { | |
| ctx.clearRect(0,0,canvas.width,canvas.height); | |
| target.children().filter('.pieLabel, .pieLabelBackground').remove(); | |
| } | |
| function drawShadow() | |
| { | |
| var shadowLeft = 5; | |
| var shadowTop = 15; | |
| var edge = 10; | |
| var alpha = 0.02; | |
| // set radius | |
| if (options.series.pie.radius>1) | |
| var radius = options.series.pie.radius; | |
| else | |
| var radius = maxRadius * options.series.pie.radius; | |
| if (radius>=(canvas.width/2)-shadowLeft || radius*options.series.pie.tilt>=(canvas.height/2)-shadowTop || radius<=edge) | |
| return; // shadow would be outside canvas, so don't draw it | |
| ctx.save(); | |
| ctx.translate(shadowLeft,shadowTop); | |
| ctx.globalAlpha = alpha; | |
| ctx.fillStyle = '#000'; | |
| // center and rotate to starting position | |
| ctx.translate(centerLeft,centerTop); | |
| ctx.scale(1, options.series.pie.tilt); | |
| //radius -= edge; | |
| for (var i=1; i<=edge; i++) | |
| { | |
| ctx.beginPath(); | |
| ctx.arc(0,0,radius,0,Math.PI*2,false); | |
| ctx.fill(); | |
| radius -= i; | |
| } | |
| ctx.restore(); | |
| } | |
| function drawPie() | |
| { | |
| startAngle = Math.PI*options.series.pie.startAngle; | |
| // set radius | |
| if (options.series.pie.radius>1) | |
| var radius = options.series.pie.radius; | |
| else | |
| var radius = maxRadius * options.series.pie.radius; | |
| // center and rotate to starting position | |
| ctx.save(); | |
| ctx.translate(centerLeft,centerTop); | |
| ctx.scale(1, options.series.pie.tilt); | |
| //ctx.rotate(startAngle); // start at top; -- This doesn't work properly in Opera | |
| // draw slices | |
| ctx.save(); | |
| var currentAngle = startAngle; | |
| for (var i = 0; i < slices.length; ++i) | |
| { | |
| slices[i].startAngle = currentAngle; | |
| drawSlice(slices[i].angle, slices[i].color, true); | |
| } | |
| ctx.restore(); | |
| // draw slice outlines | |
| ctx.save(); | |
| ctx.lineWidth = options.series.pie.stroke.width; | |
| currentAngle = startAngle; | |
| for (var i = 0; i < slices.length; ++i) | |
| drawSlice(slices[i].angle, options.series.pie.stroke.color, false); | |
| ctx.restore(); | |
| // draw donut hole | |
| drawDonutHole(ctx); | |
| // draw labels | |
| if (options.series.pie.label.show) | |
| drawLabels(); | |
| // restore to original state | |
| ctx.restore(); | |
| function drawSlice(angle, color, fill) | |
| { | |
| if (angle<=0) | |
| return; | |
| if (fill) | |
| ctx.fillStyle = color; | |
| else | |
| { | |
| ctx.strokeStyle = color; | |
| ctx.lineJoin = 'round'; | |
| } | |
| ctx.beginPath(); | |
| if (Math.abs(angle - Math.PI*2) > 0.000000001) | |
| ctx.moveTo(0,0); // Center of the pie | |
| else if ($.browser.msie) | |
| 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.closePath(); | |
| //ctx.rotate(angle); // This doesn't work properly in Opera | |
| currentAngle += angle; | |
| if (fill) | |
| ctx.fill(); | |
| else | |
| ctx.stroke(); | |
| } | |
| function drawLabels() | |
| { | |
| var currentAngle = startAngle; | |
| // set radius | |
| if (options.series.pie.label.radius>1) | |
| var radius = options.series.pie.label.radius; | |
| 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); | |
| currentAngle += slices[i].angle; | |
| } | |
| function drawLabel(slice, startAngle, index) | |
| { | |
| if (slice.data[0][1]==0) | |
| return; | |
| // format label text | |
| var lf = options.legend.labelFormatter, text, plf = options.series.pie.label.formatter; | |
| if (lf) | |
| text = lf(slice.label, slice); | |
| else | |
| text = slice.label; | |
| if (plf) | |
| text = plf(text, slice); | |
| var halfAngle = ((startAngle+slice.angle) + startAngle)/2; | |
| var x = centerLeft + Math.round(Math.cos(halfAngle) * radius); | |
| 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>"; | |
| target.append(html); | |
| var label = target.children('#pieLabel'+index); | |
| var labelTop = (y - label.height()/2); | |
| var labelLeft = (x - label.width()/2); | |
| label.css('top', labelTop); | |
| label.css('left', labelLeft); | |
| // check to make sure that the label is not outside the canvas | |
| if (0-labelTop>0 || 0-labelLeft>0 || canvas.height-(labelTop+label.height())<0 || canvas.width-(labelLeft+label.width())<0) | |
| redraw = true; | |
| if (options.series.pie.label.background.opacity != 0) { | |
| // put in the transparent background separately to avoid blended labels and label boxes | |
| var c = options.series.pie.label.background.color; | |
| if (c == null) { | |
| 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); | |
| } | |
| } // end individual label function | |
| } // end drawLabels function | |
| } // end drawPie function | |
| } // end draw function | |
| // Placed here because it needs to be accessed from multiple locations | |
| function drawDonutHole(layer) | |
| { | |
| // draw donut hole | |
| if(options.series.pie.innerRadius > 0) | |
| { | |
| // subtract the center | |
| layer.save(); | |
| 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.beginPath(); | |
| layer.fillStyle = options.series.pie.stroke.color; | |
| layer.arc(0,0,innerRadius,0,Math.PI*2,false); | |
| layer.fill(); | |
| layer.closePath(); | |
| layer.restore(); | |
| // add inner stroke | |
| layer.save(); | |
| layer.beginPath(); | |
| layer.strokeStyle = options.series.pie.stroke.color; | |
| layer.arc(0,0,innerRadius,0,Math.PI*2,false); | |
| layer.stroke(); | |
| layer.closePath(); | |
| layer.restore(); | |
| // TODO: add extra shadow inside hole (with a mask) if the pie is tilted. | |
| } | |
| } | |
| //-- Additional Interactive related functions -- | |
| function isPointInPoly(poly, pt) | |
| { | |
| 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])) | |
| && (pt[0] < (poly[j][0] - poly[i][0]) * (pt[1] - poly[i][1]) / (poly[j][1] - poly[i][1]) + poly[i][0]) | |
| && (c = !c); | |
| return c; | |
| } | |
| function findNearbySlice(mouseX, mouseY) | |
| { | |
| var slices = plot.getData(), | |
| options = plot.getOptions(), | |
| radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius; | |
| for (var i = 0; i < slices.length; ++i) | |
| { | |
| var s = slices[i]; | |
| if(s.pie.show) | |
| { | |
| ctx.save(); | |
| ctx.beginPath(); | |
| ctx.moveTo(0,0); // Center of the pie | |
| //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.closePath(); | |
| x = mouseX-centerLeft; | |
| y = mouseY-centerTop; | |
| if(ctx.isPointInPath) | |
| { | |
| if (ctx.isPointInPath(mouseX-centerLeft, mouseY-centerTop)) | |
| { | |
| //alert('found slice!'); | |
| ctx.restore(); | |
| return {datapoint: [s.percent, s.data], dataIndex: 0, series: s, seriesIndex: i}; | |
| } | |
| } | |
| else | |
| { | |
| // excanvas for IE doesn;t support isPointInPath, this is a workaround. | |
| p1X = (radius * Math.cos(s.startAngle)); | |
| p1Y = (radius * Math.sin(s.startAngle)); | |
| p2X = (radius * Math.cos(s.startAngle+(s.angle/4))); | |
| p2Y = (radius * Math.sin(s.startAngle+(s.angle/4))); | |
| p3X = (radius * Math.cos(s.startAngle+(s.angle/2))); | |
| p3Y = (radius * Math.sin(s.startAngle+(s.angle/2))); | |
| p4X = (radius * Math.cos(s.startAngle+(s.angle/1.5))); | |
| p4Y = (radius * Math.sin(s.startAngle+(s.angle/1.5))); | |
| p5X = (radius * Math.cos(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]]; | |
| arrPoint = [x,y]; | |
| // TODO: perhaps do some mathmatical trickery here with the Y-coordinate to compensate for pie tilt? | |
| if(isPointInPoly(arrPoly, arrPoint)) | |
| { | |
| ctx.restore(); | |
| return {datapoint: [s.percent, s.data], dataIndex: 0, series: s, seriesIndex: i}; | |
| } | |
| } | |
| ctx.restore(); | |
| } | |
| } | |
| return null; | |
| } | |
| function onMouseMove(e) | |
| { | |
| triggerClickHoverEvent('plothover', e); | |
| } | |
| function onClick(e) | |
| { | |
| triggerClickHoverEvent('plotclick', e); | |
| } | |
| // trigger click or hover event (they send the same parameters so we share their code) | |
| function triggerClickHoverEvent(eventname, e) | |
| { | |
| var offset = plot.offset(), | |
| canvasX = parseInt(e.pageX - offset.left), | |
| canvasY = parseInt(e.pageY - offset.top), | |
| item = findNearbySlice(canvasX, canvasY); | |
| if (options.grid.autoHighlight) | |
| { | |
| // clear auto-highlights | |
| for (var i = 0; i < highlights.length; ++i) | |
| { | |
| var h = highlights[i]; | |
| if (h.auto == eventname && !(item && h.series == item.series)) | |
| unhighlight(h.series); | |
| } | |
| } | |
| // highlight the slice | |
| if (item) | |
| highlight(item.series, eventname); | |
| // trigger any hover bind events | |
| var pos = { pageX: e.pageX, pageY: e.pageY }; | |
| target.trigger(eventname, [ pos, item ]); | |
| } | |
| function highlight(s, auto) | |
| { | |
| if (typeof s == "number") | |
| s = series[s]; | |
| var i = indexOfHighlight(s); | |
| if (i == -1) | |
| { | |
| highlights.push({ series: s, auto: auto }); | |
| plot.triggerRedrawOverlay(); | |
| } | |
| else if (!auto) | |
| highlights[i].auto = false; | |
| } | |
| function unhighlight(s) | |
| { | |
| if (s == null) | |
| { | |
| highlights = []; | |
| plot.triggerRedrawOverlay(); | |
| } | |
| if (typeof s == "number") | |
| s = series[s]; | |
| var i = indexOfHighlight(s); | |
| if (i != -1) | |
| { | |
| highlights.splice(i, 1); | |
| plot.triggerRedrawOverlay(); | |
| } | |
| } | |
| function indexOfHighlight(s) | |
| { | |
| for (var i = 0; i < highlights.length; ++i) | |
| { | |
| var h = highlights[i]; | |
| if (h.series == s) | |
| return i; | |
| } | |
| return -1; | |
| } | |
| function drawOverlay(plot, octx) | |
| { | |
| //alert(options.series.pie.radius); | |
| 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; | |
| octx.save(); | |
| octx.translate(centerLeft, centerTop); | |
| octx.scale(1, options.series.pie.tilt); | |
| for (i = 0; i < highlights.length; ++i) | |
| drawHighlight(highlights[i].series); | |
| drawDonutHole(octx); | |
| octx.restore(); | |
| function drawHighlight(series) | |
| { | |
| if (series.angle < 0) return; | |
| //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.beginPath(); | |
| if (Math.abs(series.angle - Math.PI*2) > 0.000000001) | |
| octx.moveTo(0,0); // Center of the pie | |
| octx.arc(0,0,radius,series.startAngle,series.startAngle+series.angle,false); | |
| octx.closePath(); | |
| octx.fill(); | |
| } | |
| } | |
| } // end init (plugin body) | |
| // define pie specific options and their default values | |
| var options = { | |
| series: { | |
| pie: { | |
| show: false, | |
| radius: 'auto', // actual radius of the visible pie (based on full calculated radius if <=1, or hard pixel value) | |
| innerRadius:0, /* for donut */ | |
| startAngle: 3/2, | |
| tilt: 1, | |
| offset: { | |
| top: 0, | |
| left: 'auto' | |
| }, | |
| stroke: { | |
| color: '#FFF', | |
| width: 1 | |
| }, | |
| label: { | |
| show: 'auto', | |
| 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>'; | |
| }, // formatter function | |
| radius: 1, // radius at which to place the labels (based on full calculated radius if <=1, or hard pixel value) | |
| background: { | |
| color: null, | |
| opacity: 0 | |
| }, | |
| threshold: 0 // percentage at which to hide the label (i.e. the slice is too narrow) | |
| }, | |
| combine: { | |
| 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) | |
| label: 'Other' // label to give the new slice | |
| }, | |
| highlight: { | |
| //color: '#FFF', // will add this functionality once parseColor is available | |
| opacity: 0.5 | |
| } | |
| } | |
| } | |
| }; | |
| $.plot.plugins.push({ | |
| init: init, | |
| options: options, | |
| name: "pie", | |
| version: "1.0" | |
| }); | |
| })(jQuery); | |