| 'use strict'; |
| |
| var defaults = require('../core/core.defaults'); |
| var elements = require('../elements/index'); |
| var helpers = require('../helpers/index'); |
| |
| defaults._set('polarArea', { |
| scale: { |
| type: 'radialLinear', |
| angleLines: { |
| display: false |
| }, |
| gridLines: { |
| circular: true |
| }, |
| pointLabels: { |
| display: false |
| }, |
| ticks: { |
| beginAtZero: true |
| } |
| }, |
| |
| // Boolean - Whether to animate the rotation of the chart |
| animation: { |
| animateRotate: true, |
| animateScale: true |
| }, |
| |
| startAngle: -0.5 * Math.PI, |
| legendCallback: function(chart) { |
| var text = []; |
| text.push('<ul class="' + chart.id + '-legend">'); |
| |
| var data = chart.data; |
| var datasets = data.datasets; |
| var labels = data.labels; |
| |
| if (datasets.length) { |
| for (var i = 0; i < datasets[0].data.length; ++i) { |
| text.push('<li><span style="background-color:' + datasets[0].backgroundColor[i] + '"></span>'); |
| if (labels[i]) { |
| text.push(labels[i]); |
| } |
| text.push('</li>'); |
| } |
| } |
| |
| text.push('</ul>'); |
| return text.join(''); |
| }, |
| legend: { |
| labels: { |
| generateLabels: function(chart) { |
| var data = chart.data; |
| if (data.labels.length && data.datasets.length) { |
| return data.labels.map(function(label, i) { |
| var meta = chart.getDatasetMeta(0); |
| var ds = data.datasets[0]; |
| var arc = meta.data[i]; |
| var custom = arc.custom || {}; |
| var valueAtIndexOrDefault = helpers.valueAtIndexOrDefault; |
| var arcOpts = chart.options.elements.arc; |
| var fill = custom.backgroundColor ? custom.backgroundColor : valueAtIndexOrDefault(ds.backgroundColor, i, arcOpts.backgroundColor); |
| var stroke = custom.borderColor ? custom.borderColor : valueAtIndexOrDefault(ds.borderColor, i, arcOpts.borderColor); |
| var bw = custom.borderWidth ? custom.borderWidth : valueAtIndexOrDefault(ds.borderWidth, i, arcOpts.borderWidth); |
| |
| return { |
| text: label, |
| fillStyle: fill, |
| strokeStyle: stroke, |
| lineWidth: bw, |
| hidden: isNaN(ds.data[i]) || meta.data[i].hidden, |
| |
| // Extra data used for toggling the correct item |
| index: i |
| }; |
| }); |
| } |
| return []; |
| } |
| }, |
| |
| onClick: function(e, legendItem) { |
| var index = legendItem.index; |
| var chart = this.chart; |
| var i, ilen, meta; |
| |
| for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) { |
| meta = chart.getDatasetMeta(i); |
| meta.data[index].hidden = !meta.data[index].hidden; |
| } |
| |
| chart.update(); |
| } |
| }, |
| |
| // Need to override these to give a nice default |
| tooltips: { |
| callbacks: { |
| title: function() { |
| return ''; |
| }, |
| label: function(item, data) { |
| return data.labels[item.index] + ': ' + item.yLabel; |
| } |
| } |
| } |
| }); |
| |
| module.exports = function(Chart) { |
| |
| Chart.controllers.polarArea = Chart.DatasetController.extend({ |
| |
| dataElementType: elements.Arc, |
| |
| linkScales: helpers.noop, |
| |
| update: function(reset) { |
| var me = this; |
| var chart = me.chart; |
| var chartArea = chart.chartArea; |
| var meta = me.getMeta(); |
| var opts = chart.options; |
| var arcOpts = opts.elements.arc; |
| var minSize = Math.min(chartArea.right - chartArea.left, chartArea.bottom - chartArea.top); |
| chart.outerRadius = Math.max((minSize - arcOpts.borderWidth / 2) / 2, 0); |
| chart.innerRadius = Math.max(opts.cutoutPercentage ? (chart.outerRadius / 100) * (opts.cutoutPercentage) : 1, 0); |
| chart.radiusLength = (chart.outerRadius - chart.innerRadius) / chart.getVisibleDatasetCount(); |
| |
| me.outerRadius = chart.outerRadius - (chart.radiusLength * me.index); |
| me.innerRadius = me.outerRadius - chart.radiusLength; |
| |
| meta.count = me.countVisibleElements(); |
| |
| helpers.each(meta.data, function(arc, index) { |
| me.updateElement(arc, index, reset); |
| }); |
| }, |
| |
| updateElement: function(arc, index, reset) { |
| var me = this; |
| var chart = me.chart; |
| var dataset = me.getDataset(); |
| var opts = chart.options; |
| var animationOpts = opts.animation; |
| var scale = chart.scale; |
| var labels = chart.data.labels; |
| |
| var circumference = me.calculateCircumference(dataset.data[index]); |
| var centerX = scale.xCenter; |
| var centerY = scale.yCenter; |
| |
| // If there is NaN data before us, we need to calculate the starting angle correctly. |
| // We could be way more efficient here, but its unlikely that the polar area chart will have a lot of data |
| var visibleCount = 0; |
| var meta = me.getMeta(); |
| for (var i = 0; i < index; ++i) { |
| if (!isNaN(dataset.data[i]) && !meta.data[i].hidden) { |
| ++visibleCount; |
| } |
| } |
| |
| // var negHalfPI = -0.5 * Math.PI; |
| var datasetStartAngle = opts.startAngle; |
| var distance = arc.hidden ? 0 : scale.getDistanceFromCenterForValue(dataset.data[index]); |
| var startAngle = datasetStartAngle + (circumference * visibleCount); |
| var endAngle = startAngle + (arc.hidden ? 0 : circumference); |
| |
| var resetRadius = animationOpts.animateScale ? 0 : scale.getDistanceFromCenterForValue(dataset.data[index]); |
| |
| helpers.extend(arc, { |
| // Utility |
| _datasetIndex: me.index, |
| _index: index, |
| _scale: scale, |
| |
| // Desired view properties |
| _model: { |
| x: centerX, |
| y: centerY, |
| innerRadius: 0, |
| outerRadius: reset ? resetRadius : distance, |
| startAngle: reset && animationOpts.animateRotate ? datasetStartAngle : startAngle, |
| endAngle: reset && animationOpts.animateRotate ? datasetStartAngle : endAngle, |
| label: helpers.valueAtIndexOrDefault(labels, index, labels[index]) |
| } |
| }); |
| |
| // Apply border and fill style |
| me.removeHoverStyle(arc); |
| |
| arc.pivot(); |
| }, |
| |
| removeHoverStyle: function(arc) { |
| Chart.DatasetController.prototype.removeHoverStyle.call(this, arc, this.chart.options.elements.arc); |
| }, |
| |
| countVisibleElements: function() { |
| var dataset = this.getDataset(); |
| var meta = this.getMeta(); |
| var count = 0; |
| |
| helpers.each(meta.data, function(element, index) { |
| if (!isNaN(dataset.data[index]) && !element.hidden) { |
| count++; |
| } |
| }); |
| |
| return count; |
| }, |
| |
| calculateCircumference: function(value) { |
| var count = this.getMeta().count; |
| if (count > 0 && !isNaN(value)) { |
| return (2 * Math.PI) / count; |
| } |
| return 0; |
| } |
| }); |
| }; |