56 lines
10 KiB
JavaScript
56 lines
10 KiB
JavaScript
|
/* Flot plugin for rendering pie charts.
|
||
|
|
||
|
Copyright (c) 2007-2013 IOLA and Ole Laursen.
|
||
|
Licensed under the MIT license.
|
||
|
|
||
|
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
|
||
|
|
||
|
* Updated with contributions from btburnett3, Anthony Aragues and Xavi Ivars
|
||
|
|
||
|
The plugin supports these options:
|
||
|
|
||
|
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(e){function r(r){function p(t,n,r){if(!l){l=!0;s=t.getCanvas();o=e(s).parent();i=t.getOptions();t.setData(d(t.getData()))}}function d(t){var n=0,r=0,s=0,o=i.series.pie.combine.color,u=[];for(var a=0;a<t.length;++a){var f=t[a].data;e.isArray(f)&&f.length==1&&(f=f[0]);e.isArray(f)?!isNaN(parseFloat(f[1]))&&isFinite(f[1])?f[1]=+f[1]:f[1]=0:!isNaN(parseFloat(f))&&isFinite(f)?f=[1,+f]:f=[1,0];t[a].data=[f]}for(var a=0;a<t.length;++a)n+=t[a].data[0][1];for(var a=0;a<t.length;++a){var f=t[a].data[0][1];if(f/n<=i.series.pie.combine.threshold){r+=f;s++;o||(o=t[a].color)}}for(var a=0;a<t.length;++a){var f=t[a].data[0][1];(s<2||f/n>i.series.pie.combine.threshold)&&u.push({data:[[1,f]],color:t[a].color,label:t[a].label,angle:f*Math.PI*2/n,percent:f/(n/100)})}s>1&&u.push({data:[[1,r]],color:o,label:i.series.pie.combine.label,angle:r*Math.PI*2/n,percent:r/(n/100)});return u}function v(r,s){function y(){c.clearRect(0,0,h,p);o.children().filter(".pieLabel, .pieLabelBackground").remove()}function b(){var e=i.series.pie.shadow.left,t=i.series.pie.shadow.top,n=10,r=i.series.pie.shadow.alpha,s=i.series.pie.radius>1?i.series.pie.radius:u*i.series.pie.radius;if(s>=h/2-e||s*i.series.pie.tilt>=p/2-t||s<=n)return;c.save();c.translate(e,t);c.globalAlpha=r;c.fillStyle="#000";c.translate(a,f);c.scale(1,i.series.pie.tilt);for(var o=1;o<=n;o++){c.beginPath();c.arc(0,0,s,0,Math.PI*2,!1);c.fill();s-=o}c.restore()}function w(){function l(e,t,i){if(e<=0||isNaN(e))return;if(i)c.fillStyle=t;else{c.strokeStyle=t;c.lineJoin="round"}c.beginPath();Math.abs(e-Math.PI*2)>1e-9&&c.moveTo(0,0);c.arc(0,0,n,r,r+e/2,!1);c.arc(0,0,n,r+e/2,r+e,!1);c.closePath();r+=e;i?c.fill():c.stroke()}function d(){function l(t,n,s){if(t.data[0][1]==0)return!0;var u=i.legend.labelFormatter,l,c=i.series.pie.label.formatter;u?l=u(t.label,t):l=t.label;c&&(l=c(l,t));var d=(n+t.angle+n)/2,v=a+Math.round(Math.cos(d)*r),m=f+Math.round(Math.sin(d)*r)*i.series.pie.tilt,g="<span class='pieLabel' id='pieLabel"+s+"' style='position:absolute;top:"+m+"px;left:"+v+"px;'>"+l+"</span>";o.append(g);var y=o.children("#pieLabel"+s),b=m-y.height()/2,w=v-y.width()/2;y.css("top",b);y.css("left",w);if(0-b>0||0-w>0||p-(b+y.height())<0||h-(w+y.width())<0)return!1;if(i.series.pie.label.background.opacity!=0){var E=i.series.pie.label.background.color;E==null&&(E=t.color);var S="top:"+b+"px;left:"+w+"px;";e("<div class='pieLabelBackground' style='position:absolute;width:"+y.width()+"px;height:"+y.height()+"px;"+S+"background-color:"+E+";'></div>").css("opacity",i.series.pie.label.background.opacity).insertBefore(y)}return!0}var n=t,r=i.series.pie.label.radius>1?i.series.pie.label.radius:u*i.series.pie.label.radius;for(var s=0;s<v.length;++s){if(v[s].percent>=i.series.pie.label.threshold*100&&!l(v[s],n,s))return!1;n+=v[s].angle}return!0}var t=Math.PI*i.series.pie.startAngle,n=i.series.pie.radius>1?i.series.pie.radius:u*i.series.pie.radius;c.save();c.translate(a,f);c.scale(1,i.series.pie.tilt);c.save();var r=t;for(var s=0;s<v.length;++s){v[s].startAngle=r;l(v[s].angle,v[s].color,!0)}c.restore();if(i.series.pie.stroke.width>0){c.save();c.lineWidth=i.series.pie.stroke.width;r=t;for(var s=0;s<v.length;++s)l(v[s].angle,i.series.pie.stroke.color,!1);c.restore()}m(c);c.restore();return i.series.pie.label.show?d():!0}if(!o)return;var h=r.getPlaceholder().width(),p=r.getPlaceholder().height(),d=o.children().filter(".legend").children().width()||0;c=s;l=!1;u=Math.min(h,p/i.series.pie.tilt)/2;f=p/2+i.series.pie.offset.top;a=h/2;i.series.pie.offset.left=="auto"?i.legend.position.match("w")?a+=d/2:a-=d/2:a+=i.series.pie.offset.left;a<u?a=u:a>h-u&&(a=h-u);var v=r.getData(),g=0;do{g>0&&(u*=n);g+=1;y();i.series.pie.tilt<=.8&&b()}while(!w()&&g<t);if(g>=t){y();o.prepend("<div class='error'>Could not draw pie with labels contained inside canvas</div>")}if(r.setSeries&&r.insertLegend){r.setSeries(v);r.insertLegend()}}function m(e){if(i.series.pie.innerRadius>0){e.save();var t=i.series.pie.innerRadius>1?i.series.pie.innerRadius:u*i.series.pie.innerRadius;e.globalCompositeOperation="destination-out";e.beginPath();e.fillSty
|