* @param {int} r - radius
* @param {Array} values
* @param {Object} opts options
- * cut : after this meany items - do not show a pie element?
- *
- *
- *
+ * background (string) : background color
+ * start_angle (number) : the angle of the starting position of the first pie
+ * barwidth (number) : width of a pie
+ * colors (array) : colors of the pies
+ * cut (number) : after showing this number of elements using this number of pies, merge and show the rest of the elements using one pie (maximum 'cut' + 1 pies in total)
+ * others (string) : legend label labelling the pie for the merged elements (*required if there are merged elements)
+ * no_sort (boolean) : sort the values in descending order if it is not set
+ * labels (array) : labels on the pie
+ * labelfont (string) : font family of the labels
+ * labelsize (number) : font size of the labels
+ * labelweight (string)(number) : font weight of the labels
+ * labelcolor (string) : font color of the labels
+ * showlabel (number) : only show label if the value >= 'showlabel'% of total
+ * legend (array) : legend
+ * legendpos (string) : position of the legend ('right' / 'bottom')
+ * legendkeyshape (string) : shape of the legend keys ('circle' / 'rect')
+ * legendkeysize (number) : size of the legend keys (diameter for 'circle' and width for 'rect')
+ * legendfont (string) : font family of the legend labels
+ * legendfontsize (number) : font size of the legend labels
+ * legendfontcolor (string) : font color of the legend colors
+ * lineheight (number) : distance between two legend labels
+ * legendcolumn (number) : number of columns used to show legend (1 / 2)
*/
function Piesectorchart(paper, width, height, cx, cy, r, values, opts) {
-
+
opts = opts || {};
var chartinst = this,
chart = paper.set(),
len = values.length,
- angle = opts.start_angle || 90,
total = 0,
- others = 0,
+ angle = opts.start_angle || 90,
cut = opts.cut || 9,
- defcut = true;
+ defcut = true,
+ labels = opts.labels || false, // default no labels
+ labelFont = opts.labelfont || "'Fontin Sans', Fontin-Sans, sans-serif",
+ labelSize = opts.labelsize || 18,
+ labelWeight = opts.labelweight || 'normal',
+ labelColor = opts.labelcolor || '#FFFFFF',
+ showLabel = typeof(opts.showlabel) != 'undefined' ? opts.showlabel : 5; // default show label if value >= 5% of total
opts.barwidth = opts.barwidth || 80;
return {path: path, stroke: color};
};
+
+ for (var i = 0; i < len; i++) {
+ total += values[i] * 1;
+ values[i] = {
+ value: values[i],
+ origin: i,
+ valueOf: function () { return this.value; }
+ };
+ }
if (len == 1) {
- total = values[0];
- paper.circle(cx, cy, r + opts.barwidth / 2).attr({ fill: opts.colors && opts.colors[0] || chartinst.colors[0] || "#3E66BC" });
- paper.circle(cx, cy, r - opts.barwidth / 2).attr({ fill: opts.background || "#F0F4F7" });
+ paper.circle(cx, cy, r + opts.barwidth / 2).attr({ fill: opts.colors && opts.colors[0] || chartinst.colors[0] || "#3E66BC", "stroke": "#fff" });
+ paper.circle(cx, cy, r - opts.barwidth / 2).attr({ fill: opts.background || "#F0F4F7", "stroke": "#fff" });
} else {
- for (var i = 0; i < len; i++) {
- total += values[i] * 1;
- values[i] = {
- value: values[i],
- valueOf: function () { return this.value; }
- };
- }
-
if (!opts.no_sort) {
values.sort(function (a, b) {
return b.value - a.value;
}
for (i = 0; i < len; i++) {
- if (defcut && values[i] * 360 / total <= 1.5) {
- cut = i;
- defcut = false;
- }
-
if (i > cut) {
defcut = false;
values[cut].value += values[i];
values[cut].others = true;
}
+
+ // minimum degree of a pie shown
+ if (defcut && values[i] * 360 / total <= 1.5) {
+ cut = i;
+ defcut = false;
+ }
}
len = Math.min(cut + 1, values.length);
+
+ var a = angle;
for (i = 0; i < len; i++) {
-
- var p = paper.path().attr({
+ paper.path().attr({
"stroke": "#fff",
"stroke-width": opts.barwidth
- }).attr({sector: [cx, cy, angle, angle -= 360 * values[i] / total, opts.colors && opts.colors[i] || chartinst.colors[i], r]});
-
+ }).attr({sector: [cx, cy, a, a -= 360 * values[i] / total, opts.colors && opts.colors[i] || chartinst.colors[i], r]});
}
}
+
+ // labels
+ var rad = Math.PI / 180;
+
+ var a = angle;
+
+ for (i = 0; i < len; i++) {
+
+ a -= 360 * values[i] / total;
+
+ // show the label only if the values >= 5% of total
+ if(labels && values[i] / total >= (showLabel / 100)) {
+ var text = labels[values[i].origin];
+
+ if(text.indexOf('#qty#') !== -1) {
+ text = text.replace('#qty#', Roo.util.Format.number(Math.round(values[i]), 0));
+ }
+
+ if(text.indexOf('#%#') !== -1) {
+ text = text.replace('#%#', Math.round(values[i] / total * 100) + '%');
+ }
+
+ var tx = cx + r * Math.cos(-(a + 180 * values[i] / total) * rad),
+ ty = cy + r * Math.sin(-(a + 180 * values[i] / total) * rad);
+
+ paper.text(tx, ty, text).attr({
+ "font-size": labelSize,
+ "font-family": labelFont,
+ "font-weight" : labelWeight,
+ "text-anchor": "middle",
+ fill : labelColor
+ });
+ }
+ }
+
- var ix = cx + r + opts.barwidth / 2 + 30,
+ legend(paper, cx, cy, r, values, opts, total, len);
+
+ chart.cx = cx;
+ chart.cy = cy;
+ chart.r = r;
+ return chart;
+ }
+
+ // draw legend
+ function legend(paper, cx, cy, r, values, opts, total, len)
+ {
+ var chartinst = this,
+ legendPos = opts.legendpos || 'right',
+ legendKeyShape = opts.legendkeyshape || 'circle',
+ legendKeySize = opts.legendkeysize || 12,
+ legendFont = opts.legendfont || "'Fontin Sans', Fontin-Sans, sans-serif",
+ legendFontSize = opts.legendfontsize || 18,
+ legendFontColor = opts.legendfontcolor || '#0C014F',
+ lineHeight = opts.lineheight || 30,
+ legendColumn = opts.legendcolumn || 1;
+
+ // default 'legendPos' is 'right'
+ // ix, iy: center position of legend key
+ var ix = cx + r + opts.barwidth / 2 + 30, // 30 pixels away from right of the chart
iy = cy - r - 30;
-
+
+ if(legendPos == 'bottom') {
+ ix = cx - r - opts.barwidth / 2 - 30; // 30 pixels away from left of the chart
+ iy = cy + r + opts.barwidth / 2 + 30; // 30 pixels away from bottom of the chart
+
+ // default 'legendColumn' is 1
+ if(legendColumn == 2) {
+ ix = cx - r - opts.barwidth / 2 - 90; // 90 pixels away from left of the chart
+ }
+ }
+
for (var i = 0; i < len; i++) {
- paper.circle(ix, iy, 6).attr({ fill: opts.colors && opts.colors[i] || chartinst.colors[i] || "#3E66BC" });
-
- var text = (values[i].others) ? opts.others : opts.legend[i] || values[i];
+ if(legendKeyShape == 'rect') {
+ // pass top left position for 'rect'
+ paper.rect(ix - (legendKeySize / 2), iy - (legendKeySize / 2), legendKeySize, legendKeySize, 0).attr({ fill: opts.colors && opts.colors[i] || chartinst.colors[i] || "#3E66BC", "stroke": "#fff" });
+ }
+ else {
+ // pass center position for 'circle'
+ paper.circle(ix, iy, legendKeySize / 2).attr({ fill: opts.colors && opts.colors[i] || chartinst.colors[i] || "#3E66BC", "stroke": "#fff" });
+ }
+
+ var text = (values[i].others) ? opts.others : opts.legend[values[i].origin] || values[i];
if(text.indexOf('#qty#') !== -1) {
- text = text.replace('#qty#', Math.round(values[i]));
+ text = text.replace('#qty#', Roo.util.Format.number(Math.round(values[i]), 0));
}
-
+
if(text.indexOf('#%#') !== -1) {
text = text.replace('#%#', Math.round(values[i] / total * 100) + '%');
}
+
+ var ty = iy - legendFontSize / 10;
+
+ if(text.indexOf("\n")> -1) {
+ var ty = iy - legendFontSize / 10 + legendFontSize / 2;
+ }
- paper.text(ix + 20, iy, text).attr({
- "font-size": "18",
- "font-family": "'Fontin Sans', Fontin-Sans, sans-serif",
+ // 12 pixels away from the right of legend key
+ // align legend key and text horizontally
+ paper.text(ix + legendKeySize / 2 + 12, ty, text).attr({
+ "font-size": legendFontSize,
+ "font-family": legendFont,
"text-anchor": "start",
- fill : "#0C014F"
+ fill : legendFontColor
});
-
- iy += 30;
-
+
+ if(legendColumn == 2) {
+ if(i % 2 == 0) {
+ ix += r + opts.barwidth / 2 + 120;
+ iy -= lineHeight;
+ }
+ else {
+ ix -= r + opts.barwidth / 2 + 120;
+ }
+ }
+
+ iy += lineHeight;
}
+ }
- chart.cx = cx;
- chart.cy = cy;
- chart.r = r;
- return chart;
- };
-
//inheritance
var F = function() {};
F.prototype = Raphael.g;