g.pie.js 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. /*
  2. * g.Raphael 0.5 - Charting library, based on Raphaël
  3. *
  4. * Copyright (c) 2009 Dmitry Baranovskiy (http://g.raphaeljs.com)
  5. * Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license.
  6. */
  7. (function () {
  8. function Piechart(paper, cx, cy, r, values, opts) {
  9. opts = opts || {};
  10. var chartinst = this,
  11. sectors = [],
  12. covers = paper.set(),
  13. chart = paper.set(),
  14. series = paper.set(),
  15. order = [],
  16. len = values.length,
  17. angle = 0,
  18. total = 0,
  19. others = 0,
  20. cut = 9,
  21. defcut = true;
  22. function sector(cx, cy, r, startAngle, endAngle, fill) {
  23. var rad = Math.PI / 180,
  24. x1 = cx + r * Math.cos(-startAngle * rad),
  25. x2 = cx + r * Math.cos(-endAngle * rad),
  26. xm = cx + r / 2 * Math.cos(-(startAngle + (endAngle - startAngle) / 2) * rad),
  27. y1 = cy + r * Math.sin(-startAngle * rad),
  28. y2 = cy + r * Math.sin(-endAngle * rad),
  29. ym = cy + r / 2 * Math.sin(-(startAngle + (endAngle - startAngle) / 2) * rad),
  30. res = [
  31. "M", cx, cy,
  32. "L", x1, y1,
  33. "A", r, r, 0, +(Math.abs(endAngle - startAngle) > 180), 1, x2, y2,
  34. "z"
  35. ];
  36. res.middle = { x: xm, y: ym };
  37. return res;
  38. }
  39. chart.covers = covers;
  40. if (len == 1) {
  41. series.push(paper.circle(cx, cy, r).attr({ fill: chartinst.colors[0], stroke: opts.stroke || "#fff", "stroke-width": opts.strokewidth == null ? 1 : opts.strokewidth }));
  42. covers.push(paper.circle(cx, cy, r).attr(chartinst.shim));
  43. total = values[0];
  44. values[0] = { value: values[0], order: 0, valueOf: function () { return this.value; } };
  45. series[0].middle = {x: cx, y: cy};
  46. series[0].mangle = 180;
  47. } else {
  48. for (var i = 0; i < len; i++) {
  49. total += values[i];
  50. values[i] = { value: values[i], order: i, valueOf: function () { return this.value; } };
  51. }
  52. values.sort(function (a, b) {
  53. return b.value - a.value;
  54. });
  55. for (i = 0; i < len; i++) {
  56. if (defcut && values[i] * 360 / total <= 1.5) {
  57. cut = i;
  58. defcut = false;
  59. }
  60. if (i > cut) {
  61. defcut = false;
  62. values[cut].value += values[i];
  63. values[cut].others = true;
  64. others = values[cut].value;
  65. }
  66. }
  67. len = Math.min(cut + 1, values.length);
  68. others && values.splice(len) && (values[cut].others = true);
  69. for (i = 0; i < len; i++) {
  70. var mangle = angle - 360 * values[i] / total / 2;
  71. if (!i) {
  72. angle = 90 - mangle;
  73. mangle = angle - 360 * values[i] / total / 2;
  74. }
  75. if (opts.init) {
  76. var ipath = sector(cx, cy, 1, angle, angle - 360 * values[i] / total).join(",");
  77. }
  78. var path = sector(cx, cy, r, angle, angle -= 360 * values[i] / total);
  79. var p = paper.path(opts.init ? ipath : path).attr({ fill: opts.colors && opts.colors[i] || chartinst.colors[i] || "#666", stroke: opts.stroke || "#fff", "stroke-width": (opts.strokewidth == null ? 1 : opts.strokewidth), "stroke-linejoin": "round" });
  80. p.value = values[i];
  81. p.middle = path.middle;
  82. p.mangle = mangle;
  83. sectors.push(p);
  84. series.push(p);
  85. opts.init && p.animate({ path: path.join(",") }, (+opts.init - 1) || 1000, ">");
  86. }
  87. for (i = 0; i < len; i++) {
  88. p = paper.path(sectors[i].attr("path")).attr(chartinst.shim);
  89. p.attr = function () {};
  90. opts.href && opts.href[i] && p.attr({ href: opts.href[i] });
  91. covers.push(p);
  92. series.push(p);
  93. }
  94. }
  95. chart.hover = function (fin, fout) {
  96. fout = fout || function () {};
  97. var that = this;
  98. for (var i = 0; i < len; i++) {
  99. (function (sector, cover, j) {
  100. var o = {
  101. sector: sector,
  102. cover: cover,
  103. cx: cx,
  104. cy: cy,
  105. mx: sector.middle.x,
  106. my: sector.middle.y,
  107. mangle: sector.mangle,
  108. r: r,
  109. value: values[j],
  110. total: total,
  111. label: that.labels && that.labels[j]
  112. };
  113. cover.mouseover(function () {
  114. fin.call(o);
  115. }).mouseout(function () {
  116. fout.call(o);
  117. });
  118. })(series[i], covers[i], i);
  119. }
  120. return this;
  121. };
  122. // x: where label could be put
  123. // y: where label could be put
  124. // value: value to show
  125. // total: total number to count %
  126. chart.each = function (f) {
  127. var that = this;
  128. for (var i = 0; i < len; i++) {
  129. (function (sector, cover, j) {
  130. var o = {
  131. sector: sector,
  132. cover: cover,
  133. cx: cx,
  134. cy: cy,
  135. x: sector.middle.x,
  136. y: sector.middle.y,
  137. mangle: sector.mangle,
  138. r: r,
  139. value: values[j],
  140. total: total,
  141. label: that.labels && that.labels[j]
  142. };
  143. f.call(o);
  144. })(series[i], covers[i], i);
  145. }
  146. return this;
  147. };
  148. chart.click = function (f) {
  149. var that = this;
  150. for (var i = 0; i < len; i++) {
  151. (function (sector, cover, j) {
  152. var o = {
  153. sector: sector,
  154. cover: cover,
  155. cx: cx,
  156. cy: cy,
  157. mx: sector.middle.x,
  158. my: sector.middle.y,
  159. mangle: sector.mangle,
  160. r: r,
  161. value: values[j],
  162. total: total,
  163. label: that.labels && that.labels[j]
  164. };
  165. cover.click(function () { f.call(o); });
  166. })(series[i], covers[i], i);
  167. }
  168. return this;
  169. };
  170. chart.inject = function (element) {
  171. element.insertBefore(covers[0]);
  172. };
  173. var legend = function (labels, otherslabel, mark, dir) {
  174. var x = cx + r + r / 5,
  175. y = cy,
  176. h = y + 10;
  177. labels = labels || [];
  178. dir = (dir && dir.toLowerCase && dir.toLowerCase()) || "east";
  179. mark = paper[mark && mark.toLowerCase()] || "circle";
  180. chart.labels = paper.set();
  181. for (var i = 0; i < len; i++) {
  182. var clr = series[i].attr("fill"),
  183. j = values[i].order,
  184. txt;
  185. values[i].others && (labels[j] = otherslabel || "Others");
  186. labels[j] = chartinst.labelise(labels[j], values[i], total);
  187. chart.labels.push(paper.set());
  188. chart.labels[i].push(paper[mark](x + 5, h, 5).attr({ fill: clr, stroke: "none" }));
  189. chart.labels[i].push(txt = paper.text(x + 20, h, labels[j] || values[j]).attr(chartinst.txtattr).attr({ fill: opts.legendcolor || "#000", "text-anchor": "start"}));
  190. covers[i].label = chart.labels[i];
  191. h += txt.getBBox().height * 1.2;
  192. }
  193. var bb = chart.labels.getBBox(),
  194. tr = {
  195. east: [0, -bb.height / 2],
  196. west: [-bb.width - 2 * r - 20, -bb.height / 2],
  197. north: [-r - bb.width / 2, -r - bb.height - 10],
  198. south: [-r - bb.width / 2, r + 10]
  199. }[dir];
  200. chart.labels.translate.apply(chart.labels, tr);
  201. chart.push(chart.labels);
  202. };
  203. if (opts.legend) {
  204. legend(opts.legend, opts.legendothers, opts.legendmark, opts.legendpos);
  205. }
  206. chart.push(series, covers);
  207. chart.series = series;
  208. chart.covers = covers;
  209. return chart;
  210. };
  211. //inheritance
  212. var F = function() {};
  213. F.prototype = Raphael.g;
  214. Piechart.prototype = new F;
  215. //public
  216. Raphael.fn.piechart = function(cx, cy, r, values, opts) {
  217. return new Piechart(this, cx, cy, r, values, opts);
  218. }
  219. })();