controller.polarArea.js 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. 'use strict';
  2. module.exports = function(Chart) {
  3. var helpers = Chart.helpers;
  4. Chart.defaults.polarArea = {
  5. scale: {
  6. type: 'radialLinear',
  7. lineArc: true, // so that lines are circular
  8. ticks: {
  9. beginAtZero: true
  10. }
  11. },
  12. // Boolean - Whether to animate the rotation of the chart
  13. animation: {
  14. animateRotate: true,
  15. animateScale: true
  16. },
  17. startAngle: -0.5 * Math.PI,
  18. aspectRatio: 1,
  19. legendCallback: function(chart) {
  20. var text = [];
  21. text.push('<ul class="' + chart.id + '-legend">');
  22. var data = chart.data;
  23. var datasets = data.datasets;
  24. var labels = data.labels;
  25. if (datasets.length) {
  26. for (var i = 0; i < datasets[0].data.length; ++i) {
  27. text.push('<li><span style="background-color:' + datasets[0].backgroundColor[i] + '"></span>');
  28. if (labels[i]) {
  29. text.push(labels[i]);
  30. }
  31. text.push('</li>');
  32. }
  33. }
  34. text.push('</ul>');
  35. return text.join('');
  36. },
  37. legend: {
  38. labels: {
  39. generateLabels: function(chart) {
  40. var data = chart.data;
  41. if (data.labels.length && data.datasets.length) {
  42. return data.labels.map(function(label, i) {
  43. var meta = chart.getDatasetMeta(0);
  44. var ds = data.datasets[0];
  45. var arc = meta.data[i];
  46. var custom = arc.custom || {};
  47. var getValueAtIndexOrDefault = helpers.getValueAtIndexOrDefault;
  48. var arcOpts = chart.options.elements.arc;
  49. var fill = custom.backgroundColor ? custom.backgroundColor : getValueAtIndexOrDefault(ds.backgroundColor, i, arcOpts.backgroundColor);
  50. var stroke = custom.borderColor ? custom.borderColor : getValueAtIndexOrDefault(ds.borderColor, i, arcOpts.borderColor);
  51. var bw = custom.borderWidth ? custom.borderWidth : getValueAtIndexOrDefault(ds.borderWidth, i, arcOpts.borderWidth);
  52. return {
  53. text: label,
  54. fillStyle: fill,
  55. strokeStyle: stroke,
  56. lineWidth: bw,
  57. hidden: isNaN(ds.data[i]) || meta.data[i].hidden,
  58. // Extra data used for toggling the correct item
  59. index: i
  60. };
  61. });
  62. }
  63. return [];
  64. }
  65. },
  66. onClick: function(e, legendItem) {
  67. var index = legendItem.index;
  68. var chart = this.chart;
  69. var i, ilen, meta;
  70. for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) {
  71. meta = chart.getDatasetMeta(i);
  72. meta.data[index].hidden = !meta.data[index].hidden;
  73. }
  74. chart.update();
  75. }
  76. },
  77. // Need to override these to give a nice default
  78. tooltips: {
  79. callbacks: {
  80. title: function() {
  81. return '';
  82. },
  83. label: function(tooltipItem, data) {
  84. return data.labels[tooltipItem.index] + ': ' + tooltipItem.yLabel;
  85. }
  86. }
  87. }
  88. };
  89. Chart.controllers.polarArea = Chart.DatasetController.extend({
  90. dataElementType: Chart.elements.Arc,
  91. linkScales: helpers.noop,
  92. update: function(reset) {
  93. var me = this;
  94. var chart = me.chart;
  95. var chartArea = chart.chartArea;
  96. var meta = me.getMeta();
  97. var opts = chart.options;
  98. var arcOpts = opts.elements.arc;
  99. var minSize = Math.min(chartArea.right - chartArea.left, chartArea.bottom - chartArea.top);
  100. chart.outerRadius = Math.max((minSize - arcOpts.borderWidth / 2) / 2, 0);
  101. chart.innerRadius = Math.max(opts.cutoutPercentage ? (chart.outerRadius / 100) * (opts.cutoutPercentage) : 1, 0);
  102. chart.radiusLength = (chart.outerRadius - chart.innerRadius) / chart.getVisibleDatasetCount();
  103. me.outerRadius = chart.outerRadius - (chart.radiusLength * me.index);
  104. me.innerRadius = me.outerRadius - chart.radiusLength;
  105. meta.count = me.countVisibleElements();
  106. helpers.each(meta.data, function(arc, index) {
  107. me.updateElement(arc, index, reset);
  108. });
  109. },
  110. updateElement: function(arc, index, reset) {
  111. var me = this;
  112. var chart = me.chart;
  113. var dataset = me.getDataset();
  114. var opts = chart.options;
  115. var animationOpts = opts.animation;
  116. var scale = chart.scale;
  117. var getValueAtIndexOrDefault = helpers.getValueAtIndexOrDefault;
  118. var labels = chart.data.labels;
  119. var circumference = me.calculateCircumference(dataset.data[index]);
  120. var centerX = scale.xCenter;
  121. var centerY = scale.yCenter;
  122. // If there is NaN data before us, we need to calculate the starting angle correctly.
  123. // We could be way more efficient here, but its unlikely that the polar area chart will have a lot of data
  124. var visibleCount = 0;
  125. var meta = me.getMeta();
  126. for (var i = 0; i < index; ++i) {
  127. if (!isNaN(dataset.data[i]) && !meta.data[i].hidden) {
  128. ++visibleCount;
  129. }
  130. }
  131. // var negHalfPI = -0.5 * Math.PI;
  132. var datasetStartAngle = opts.startAngle;
  133. var distance = arc.hidden ? 0 : scale.getDistanceFromCenterForValue(dataset.data[index]);
  134. var startAngle = datasetStartAngle + (circumference * visibleCount);
  135. var endAngle = startAngle + (arc.hidden ? 0 : circumference);
  136. var resetRadius = animationOpts.animateScale ? 0 : scale.getDistanceFromCenterForValue(dataset.data[index]);
  137. helpers.extend(arc, {
  138. // Utility
  139. _datasetIndex: me.index,
  140. _index: index,
  141. _scale: scale,
  142. // Desired view properties
  143. _model: {
  144. x: centerX,
  145. y: centerY,
  146. innerRadius: 0,
  147. outerRadius: reset ? resetRadius : distance,
  148. startAngle: reset && animationOpts.animateRotate ? datasetStartAngle : startAngle,
  149. endAngle: reset && animationOpts.animateRotate ? datasetStartAngle : endAngle,
  150. label: getValueAtIndexOrDefault(labels, index, labels[index])
  151. }
  152. });
  153. // Apply border and fill style
  154. me.removeHoverStyle(arc);
  155. arc.pivot();
  156. },
  157. removeHoverStyle: function(arc) {
  158. Chart.DatasetController.prototype.removeHoverStyle.call(this, arc, this.chart.options.elements.arc);
  159. },
  160. countVisibleElements: function() {
  161. var dataset = this.getDataset();
  162. var meta = this.getMeta();
  163. var count = 0;
  164. helpers.each(meta.data, function(element, index) {
  165. if (!isNaN(dataset.data[index]) && !element.hidden) {
  166. count++;
  167. }
  168. });
  169. return count;
  170. },
  171. calculateCircumference: function(value) {
  172. var count = this.getMeta().count;
  173. if (count > 0 && !isNaN(value)) {
  174. return (2 * Math.PI) / count;
  175. }
  176. return 0;
  177. }
  178. });
  179. };