Chart.PolarArea.js 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. (function(){
  2. "use strict";
  3. var root = this,
  4. Chart = root.Chart,
  5. //Cache a local reference to Chart.helpers
  6. helpers = Chart.helpers;
  7. var defaultConfig = {
  8. //Boolean - Show a backdrop to the scale label
  9. scaleShowLabelBackdrop : true,
  10. //String - The colour of the label backdrop
  11. scaleBackdropColor : "rgba(255,255,255,0.75)",
  12. // Boolean - Whether the scale should begin at zero
  13. scaleBeginAtZero : true,
  14. //Number - The backdrop padding above & below the label in pixels
  15. scaleBackdropPaddingY : 2,
  16. //Number - The backdrop padding to the side of the label in pixels
  17. scaleBackdropPaddingX : 2,
  18. //Boolean - Show line for each value in the scale
  19. scaleShowLine : true,
  20. //Boolean - Stroke a line around each segment in the chart
  21. segmentShowStroke : true,
  22. //String - The colour of the stroke on each segement.
  23. segmentStrokeColor : "#fff",
  24. //Number - The width of the stroke value in pixels
  25. segmentStrokeWidth : 2,
  26. //Number - Amount of animation steps
  27. animationSteps : 100,
  28. //String - Animation easing effect.
  29. animationEasing : "easeOutBounce",
  30. //Boolean - Whether to animate the rotation of the chart
  31. animateRotate : true,
  32. //Boolean - Whether to animate scaling the chart from the centre
  33. animateScale : false,
  34. //String - A legend template
  35. legendTemplate : "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<segments.length; i++){%><li><span style=\"background-color:<%=segments[i].fillColor%>\"></span><%if(segments[i].label){%><%=segments[i].label%><%}%></li><%}%></ul>"
  36. };
  37. Chart.Type.extend({
  38. //Passing in a name registers this chart in the Chart namespace
  39. name: "PolarArea",
  40. //Providing a defaults will also register the deafults in the chart namespace
  41. defaults : defaultConfig,
  42. //Initialize is fired when the chart is initialized - Data is passed in as a parameter
  43. //Config is automatically merged by the core of Chart.js, and is available at this.options
  44. initialize: function(data){
  45. this.segments = [];
  46. //Declare segment class as a chart instance specific class, so it can share props for this instance
  47. this.SegmentArc = Chart.Arc.extend({
  48. showStroke : this.options.segmentShowStroke,
  49. strokeWidth : this.options.segmentStrokeWidth,
  50. strokeColor : this.options.segmentStrokeColor,
  51. ctx : this.chart.ctx,
  52. innerRadius : 0,
  53. x : this.chart.width/2,
  54. y : this.chart.height/2
  55. });
  56. this.scale = new Chart.RadialScale({
  57. display: this.options.showScale,
  58. fontStyle: this.options.scaleFontStyle,
  59. fontSize: this.options.scaleFontSize,
  60. fontFamily: this.options.scaleFontFamily,
  61. fontColor: this.options.scaleFontColor,
  62. showLabels: this.options.scaleShowLabels,
  63. showLabelBackdrop: this.options.scaleShowLabelBackdrop,
  64. backdropColor: this.options.scaleBackdropColor,
  65. backdropPaddingY : this.options.scaleBackdropPaddingY,
  66. backdropPaddingX: this.options.scaleBackdropPaddingX,
  67. lineWidth: (this.options.scaleShowLine) ? this.options.scaleLineWidth : 0,
  68. lineColor: this.options.scaleLineColor,
  69. lineArc: true,
  70. width: this.chart.width,
  71. height: this.chart.height,
  72. xCenter: this.chart.width/2,
  73. yCenter: this.chart.height/2,
  74. ctx : this.chart.ctx,
  75. templateString: this.options.scaleLabel,
  76. valuesCount: data.length
  77. });
  78. this.updateScaleRange(data);
  79. this.scale.update();
  80. helpers.each(data,function(segment,index){
  81. this.addData(segment,index,true);
  82. },this);
  83. //Set up tooltip events on the chart
  84. if (this.options.showTooltips){
  85. helpers.bindEvents(this, this.options.tooltipEvents, function(evt){
  86. var activeSegments = (evt.type !== 'mouseout') ? this.getSegmentsAtEvent(evt) : [];
  87. helpers.each(this.segments,function(segment){
  88. segment.restore(["fillColor"]);
  89. });
  90. helpers.each(activeSegments,function(activeSegment){
  91. activeSegment.fillColor = activeSegment.highlightColor;
  92. });
  93. this.showTooltip(activeSegments);
  94. });
  95. }
  96. this.render();
  97. },
  98. getSegmentsAtEvent : function(e){
  99. var segmentsArray = [];
  100. var location = helpers.getRelativePosition(e);
  101. helpers.each(this.segments,function(segment){
  102. if (segment.inRange(location.x,location.y)) segmentsArray.push(segment);
  103. },this);
  104. return segmentsArray;
  105. },
  106. addData : function(segment, atIndex, silent){
  107. var index = atIndex || this.segments.length;
  108. this.segments.splice(index, 0, new this.SegmentArc({
  109. fillColor: segment.color,
  110. highlightColor: segment.highlight || segment.color,
  111. label: segment.label,
  112. value: segment.value,
  113. outerRadius: (this.options.animateScale) ? 0 : this.scale.calculateCenterOffset(segment.value),
  114. circumference: (this.options.animateRotate) ? 0 : this.scale.getCircumference(),
  115. startAngle: Math.PI * 1.5
  116. }));
  117. if (!silent){
  118. this.reflow();
  119. this.update();
  120. }
  121. },
  122. removeData: function(atIndex){
  123. var indexToDelete = (helpers.isNumber(atIndex)) ? atIndex : this.segments.length-1;
  124. this.segments.splice(indexToDelete, 1);
  125. this.reflow();
  126. this.update();
  127. },
  128. calculateTotal: function(data){
  129. this.total = 0;
  130. helpers.each(data,function(segment){
  131. this.total += segment.value;
  132. },this);
  133. this.scale.valuesCount = this.segments.length;
  134. },
  135. updateScaleRange: function(datapoints){
  136. var valuesArray = [];
  137. helpers.each(datapoints,function(segment){
  138. valuesArray.push(segment.value);
  139. });
  140. var scaleSizes = (this.options.scaleOverride) ?
  141. {
  142. steps: this.options.scaleSteps,
  143. stepValue: this.options.scaleStepWidth,
  144. min: this.options.scaleStartValue,
  145. max: this.options.scaleStartValue + (this.options.scaleSteps * this.options.scaleStepWidth)
  146. } :
  147. helpers.calculateScaleRange(
  148. valuesArray,
  149. helpers.min([this.chart.width, this.chart.height])/2,
  150. this.options.scaleFontSize,
  151. this.options.scaleBeginAtZero,
  152. this.options.scaleIntegersOnly
  153. );
  154. helpers.extend(
  155. this.scale,
  156. scaleSizes,
  157. {
  158. size: helpers.min([this.chart.width, this.chart.height]),
  159. xCenter: this.chart.width/2,
  160. yCenter: this.chart.height/2
  161. }
  162. );
  163. },
  164. update : function(){
  165. this.calculateTotal(this.segments);
  166. helpers.each(this.segments,function(segment){
  167. segment.save();
  168. });
  169. this.reflow();
  170. this.render();
  171. },
  172. reflow : function(){
  173. helpers.extend(this.SegmentArc.prototype,{
  174. x : this.chart.width/2,
  175. y : this.chart.height/2
  176. });
  177. this.updateScaleRange(this.segments);
  178. this.scale.update();
  179. helpers.extend(this.scale,{
  180. xCenter: this.chart.width/2,
  181. yCenter: this.chart.height/2
  182. });
  183. helpers.each(this.segments, function(segment){
  184. segment.update({
  185. outerRadius : this.scale.calculateCenterOffset(segment.value)
  186. });
  187. }, this);
  188. },
  189. draw : function(ease){
  190. var easingDecimal = ease || 1;
  191. //Clear & draw the canvas
  192. this.clear();
  193. helpers.each(this.segments,function(segment, index){
  194. segment.transition({
  195. circumference : this.scale.getCircumference(),
  196. outerRadius : this.scale.calculateCenterOffset(segment.value)
  197. },easingDecimal);
  198. segment.endAngle = segment.startAngle + segment.circumference;
  199. // If we've removed the first segment we need to set the first one to
  200. // start at the top.
  201. if (index === 0){
  202. segment.startAngle = Math.PI * 1.5;
  203. }
  204. //Check to see if it's the last segment, if not get the next and update the start angle
  205. if (index < this.segments.length - 1){
  206. this.segments[index+1].startAngle = segment.endAngle;
  207. }
  208. segment.draw();
  209. }, this);
  210. this.scale.draw();
  211. }
  212. });
  213. }).call(this);