2015-05-27 06:02:41 +02:00
|
|
|
(function() {
|
2015-06-13 15:51:28 +02:00
|
|
|
"use strict";
|
|
|
|
|
|
|
|
var root = this,
|
|
|
|
Chart = root.Chart,
|
|
|
|
//Cache a local reference to Chart.helpers
|
|
|
|
helpers = Chart.helpers;
|
|
|
|
|
2015-06-16 08:39:04 +02:00
|
|
|
|
|
|
|
Chart.defaults.polarArea = {
|
2015-06-13 15:51:28 +02:00
|
|
|
|
|
|
|
scale: {
|
|
|
|
type: "radialLinear",
|
2015-06-13 20:16:01 +02:00
|
|
|
lineArc: true, // so that lines are circular
|
2015-06-13 15:51:28 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
//Boolean - Whether to animate the rotation of the chart
|
|
|
|
animateRotate: true,
|
2015-06-19 20:36:22 +02:00
|
|
|
animateScale: true,
|
2015-10-31 02:04:45 +01:00
|
|
|
|
2015-12-06 18:53:45 +01:00
|
|
|
aspectRatio: 1,
|
|
|
|
legendCallback: function(chart) {
|
|
|
|
var text = [];
|
|
|
|
text.push('<ul class="' + chart.id + '-legend">');
|
|
|
|
|
|
|
|
if (chart.data.datasets.length) {
|
|
|
|
for (var i = 0; i < chart.data.datasets[0].data.length; ++i) {
|
|
|
|
text.push('<li><span style="background-color:' + chart.data.datasets[0].backgroundColor[i] + '">');
|
|
|
|
if (chart.data.labels[i]) {
|
|
|
|
text.push(chart.data.labels[i]);
|
|
|
|
}
|
|
|
|
text.push('</span></li>');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
text.push('</ul>');
|
|
|
|
return text.join("");
|
|
|
|
},
|
|
|
|
legend: {
|
|
|
|
labels: {
|
|
|
|
generateLabels: function(data) {
|
2015-12-08 01:11:54 +01:00
|
|
|
return data.labels.map(function(label, i) {
|
|
|
|
return {
|
|
|
|
text: label,
|
|
|
|
fillStyle: data.datasets[0].backgroundColor[i],
|
2015-12-08 03:42:58 +01:00
|
|
|
hidden: isNaN(data.datasets[0].data[i]),
|
2015-12-08 01:11:54 +01:00
|
|
|
|
|
|
|
// Extra data used for toggling the correct item
|
|
|
|
index: i
|
|
|
|
};
|
|
|
|
});
|
2015-12-06 18:53:45 +01:00
|
|
|
}
|
2015-12-08 02:36:44 +01:00
|
|
|
},
|
2015-12-08 03:42:58 +01:00
|
|
|
onClick: function(e, legendItem) {
|
|
|
|
helpers.each(this.chart.data.datasets, function(dataset) {
|
|
|
|
dataset.metaHiddenData = dataset.metaHiddenData || [];
|
|
|
|
var idx = legendItem.index;
|
|
|
|
|
|
|
|
if (!isNaN(dataset.data[idx])) {
|
|
|
|
dataset.metaHiddenData[idx] = dataset.data[idx];
|
|
|
|
dataset.data[idx] = NaN;
|
|
|
|
} else if (!isNaN(dataset.metaHiddenData[idx])) {
|
|
|
|
dataset.data[idx] = dataset.metaHiddenData[idx];
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
this.chart.update();
|
|
|
|
}
|
2015-12-06 18:53:45 +01:00
|
|
|
},
|
|
|
|
|
2015-10-31 02:04:45 +01:00
|
|
|
// Need to override these to give a nice default
|
|
|
|
tooltips: {
|
|
|
|
callbacks: {
|
2015-10-31 23:09:11 +01:00
|
|
|
title: function() { return ''; },
|
2015-10-31 02:04:45 +01:00
|
|
|
label: function(tooltipItem, data) {
|
|
|
|
return data.labels[tooltipItem.index] + ': ' + tooltipItem.yLabel;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-06-13 15:51:28 +02:00
|
|
|
};
|
|
|
|
|
2015-06-16 08:39:04 +02:00
|
|
|
Chart.controllers.polarArea = function(chart, datasetIndex) {
|
|
|
|
this.initialize.call(this, chart, datasetIndex);
|
|
|
|
};
|
2015-06-13 15:51:28 +02:00
|
|
|
|
2015-06-16 08:39:04 +02:00
|
|
|
helpers.extend(Chart.controllers.polarArea.prototype, {
|
2015-06-13 15:51:28 +02:00
|
|
|
|
2015-06-16 08:39:04 +02:00
|
|
|
initialize: function(chart, datasetIndex) {
|
|
|
|
this.chart = chart;
|
|
|
|
this.index = datasetIndex;
|
|
|
|
this.linkScales();
|
|
|
|
this.addElements();
|
2015-06-13 15:51:28 +02:00
|
|
|
},
|
2015-06-17 04:04:52 +02:00
|
|
|
updateIndex: function(datasetIndex) {
|
|
|
|
this.index = datasetIndex;
|
|
|
|
},
|
2015-06-16 08:39:04 +02:00
|
|
|
|
|
|
|
linkScales: function() {
|
|
|
|
// no scales for doughnut
|
2015-06-13 15:51:28 +02:00
|
|
|
},
|
|
|
|
|
2015-06-16 08:39:04 +02:00
|
|
|
getDataset: function() {
|
|
|
|
return this.chart.data.datasets[this.index];
|
|
|
|
},
|
2015-06-13 15:51:28 +02:00
|
|
|
|
2015-06-16 08:39:04 +02:00
|
|
|
getScaleForId: function(scaleID) {
|
|
|
|
return this.chart.scales[scaleID];
|
|
|
|
},
|
2015-06-13 15:51:28 +02:00
|
|
|
|
2015-06-16 08:39:04 +02:00
|
|
|
addElements: function() {
|
|
|
|
this.getDataset().metaData = this.getDataset().metaData || [];
|
|
|
|
helpers.each(this.getDataset().data, function(value, index) {
|
|
|
|
this.getDataset().metaData[index] = this.getDataset().metaData[index] || new Chart.elements.Arc({
|
|
|
|
_chart: this.chart.chart,
|
|
|
|
_datasetIndex: this.index,
|
2015-06-13 15:51:28 +02:00
|
|
|
_index: index,
|
|
|
|
});
|
|
|
|
}, this);
|
|
|
|
},
|
2015-06-19 20:36:22 +02:00
|
|
|
addElementAndReset: function(index) {
|
|
|
|
this.getDataset().metaData = this.getDataset().metaData || [];
|
|
|
|
var arc = new Chart.elements.Arc({
|
|
|
|
_chart: this.chart.chart,
|
|
|
|
_datasetIndex: this.index,
|
|
|
|
_index: index,
|
|
|
|
});
|
|
|
|
|
|
|
|
// Reset the point
|
|
|
|
this.updateElement(arc, index, true);
|
|
|
|
|
|
|
|
// Add to the points array
|
|
|
|
this.getDataset().metaData.splice(index, 0, arc);
|
|
|
|
},
|
|
|
|
removeElement: function(index) {
|
|
|
|
this.getDataset().metaData.splice(index, 1);
|
|
|
|
},
|
2015-06-13 15:51:28 +02:00
|
|
|
|
2015-06-16 08:39:04 +02:00
|
|
|
reset: function() {
|
|
|
|
this.update(true);
|
|
|
|
},
|
|
|
|
|
2015-09-22 02:59:53 +02:00
|
|
|
buildOrUpdateElements: function buildOrUpdateElements() {
|
|
|
|
// Handle the number of data points changing
|
|
|
|
var numData = this.getDataset().data.length;
|
|
|
|
var numPoints = this.getDataset().metaData.length;
|
|
|
|
|
|
|
|
// Make sure that we handle number of datapoints changing
|
|
|
|
if (numData < numPoints) {
|
|
|
|
// Remove excess bars for data points that have been removed
|
2015-10-21 02:33:51 +02:00
|
|
|
this.getDataset().metaData.splice(numData, numPoints - numData);
|
2015-09-22 02:59:53 +02:00
|
|
|
} else if (numData > numPoints) {
|
|
|
|
// Add new elements
|
|
|
|
for (var index = numPoints; index < numData; ++index) {
|
|
|
|
this.addElementAndReset(index);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2015-10-08 01:54:11 +02:00
|
|
|
getVisibleDatasetCount: function getVisibleDatasetCount() {
|
|
|
|
return helpers.where(this.chart.data.datasets, function(ds) { return helpers.isDatasetVisible(ds); }).length;
|
|
|
|
},
|
|
|
|
|
2015-09-22 02:59:53 +02:00
|
|
|
update: function update(reset) {
|
2015-12-06 16:19:09 +01:00
|
|
|
var minSize = Math.min(this.chart.chartArea.right - this.chart.chartArea.left, this.chart.chartArea.bottom - this.chart.chartArea.top);
|
|
|
|
this.chart.outerRadius = Math.max((minSize - this.chart.options.elements.arc.borderWidth / 2) / 2, 0);
|
2015-09-20 16:33:36 +02:00
|
|
|
this.chart.innerRadius = Math.max(this.chart.options.cutoutPercentage ? (this.chart.outerRadius / 100) * (this.chart.options.cutoutPercentage) : 1, 0);
|
2015-10-08 01:54:11 +02:00
|
|
|
this.chart.radiusLength = (this.chart.outerRadius - this.chart.innerRadius) / this.getVisibleDatasetCount();
|
2015-06-16 08:39:04 +02:00
|
|
|
|
|
|
|
this.getDataset().total = 0;
|
|
|
|
helpers.each(this.getDataset().data, function(value) {
|
|
|
|
this.getDataset().total += Math.abs(value);
|
|
|
|
}, this);
|
|
|
|
|
|
|
|
this.outerRadius = this.chart.outerRadius - (this.chart.radiusLength * this.index);
|
|
|
|
this.innerRadius = this.outerRadius - this.chart.radiusLength;
|
|
|
|
|
|
|
|
helpers.each(this.getDataset().metaData, function(arc, index) {
|
2015-06-19 20:36:22 +02:00
|
|
|
this.updateElement(arc, index, reset);
|
|
|
|
}, this);
|
|
|
|
},
|
2015-12-08 03:42:58 +01:00
|
|
|
|
2015-06-19 20:36:22 +02:00
|
|
|
updateElement: function(arc, index, reset) {
|
2015-12-08 03:42:58 +01:00
|
|
|
var circumference = this.calculateCircumference(this.getDataset().data[index]);
|
2015-12-06 16:19:09 +01:00
|
|
|
var centerX = (this.chart.chartArea.left + this.chart.chartArea.right) / 2;
|
|
|
|
var centerY = (this.chart.chartArea.top + this.chart.chartArea.bottom) / 2;
|
|
|
|
|
2015-12-08 03:42:58 +01:00
|
|
|
// 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 notNullIndex = 0;
|
|
|
|
for (var i = 0; i < index; ++i) {
|
|
|
|
if (!isNaN(this.getDataset().data[i])) {
|
|
|
|
++notNullIndex;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var startAngle = (-0.5 * Math.PI) + (circumference * notNullIndex);
|
|
|
|
var endAngle = startAngle + circumference;
|
2015-06-19 20:36:22 +02:00
|
|
|
|
|
|
|
var resetModel = {
|
2015-12-06 16:19:09 +01:00
|
|
|
x: centerX,
|
|
|
|
y: centerY,
|
2015-06-19 20:36:22 +02:00
|
|
|
innerRadius: 0,
|
|
|
|
outerRadius: this.chart.options.animateScale ? 0 : this.chart.scale.getDistanceFromCenterForValue(this.getDataset().data[index]),
|
|
|
|
startAngle: this.chart.options.animateRotate ? Math.PI * -0.5 : startAngle,
|
|
|
|
endAngle: this.chart.options.animateRotate ? Math.PI * -0.5 : endAngle,
|
|
|
|
|
|
|
|
backgroundColor: arc.custom && arc.custom.backgroundColor ? arc.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().backgroundColor, index, this.chart.options.elements.arc.backgroundColor),
|
|
|
|
hoverBackgroundColor: arc.custom && arc.custom.hoverBackgroundColor ? arc.custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().hoverBackgroundColor, index, this.chart.options.elements.arc.hoverBackgroundColor),
|
|
|
|
borderWidth: arc.custom && arc.custom.borderWidth ? arc.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.getDataset().borderWidth, index, this.chart.options.elements.arc.borderWidth),
|
|
|
|
borderColor: arc.custom && arc.custom.borderColor ? arc.custom.borderColor : helpers.getValueAtIndexOrDefault(this.getDataset().borderColor, index, this.chart.options.elements.arc.borderColor),
|
|
|
|
|
|
|
|
label: helpers.getValueAtIndexOrDefault(this.chart.data.labels, index, this.chart.data.labels[index])
|
|
|
|
};
|
|
|
|
|
|
|
|
helpers.extend(arc, {
|
|
|
|
// Utility
|
|
|
|
_chart: this.chart.chart,
|
|
|
|
_datasetIndex: this.index,
|
|
|
|
_index: index,
|
2015-10-31 02:04:45 +01:00
|
|
|
_scale: this.chart.scale,
|
2015-06-19 20:36:22 +02:00
|
|
|
|
|
|
|
// Desired view properties
|
|
|
|
_model: reset ? resetModel : {
|
2015-12-06 16:19:09 +01:00
|
|
|
x: centerX,
|
|
|
|
y: centerY,
|
2015-06-16 08:39:04 +02:00
|
|
|
innerRadius: 0,
|
2015-06-19 20:36:22 +02:00
|
|
|
outerRadius: this.chart.scale.getDistanceFromCenterForValue(this.getDataset().data[index]),
|
|
|
|
startAngle: startAngle,
|
|
|
|
endAngle: endAngle,
|
2015-06-13 15:51:28 +02:00
|
|
|
|
2015-06-16 08:39:04 +02:00
|
|
|
backgroundColor: arc.custom && arc.custom.backgroundColor ? arc.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().backgroundColor, index, this.chart.options.elements.arc.backgroundColor),
|
|
|
|
hoverBackgroundColor: arc.custom && arc.custom.hoverBackgroundColor ? arc.custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().hoverBackgroundColor, index, this.chart.options.elements.arc.hoverBackgroundColor),
|
|
|
|
borderWidth: arc.custom && arc.custom.borderWidth ? arc.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.getDataset().borderWidth, index, this.chart.options.elements.arc.borderWidth),
|
|
|
|
borderColor: arc.custom && arc.custom.borderColor ? arc.custom.borderColor : helpers.getValueAtIndexOrDefault(this.getDataset().borderColor, index, this.chart.options.elements.arc.borderColor),
|
2015-06-13 15:51:28 +02:00
|
|
|
|
2015-06-16 08:39:04 +02:00
|
|
|
label: helpers.getValueAtIndexOrDefault(this.chart.data.labels, index, this.chart.data.labels[index])
|
2015-06-19 20:36:22 +02:00
|
|
|
},
|
|
|
|
});
|
2015-06-16 08:39:04 +02:00
|
|
|
|
2015-06-19 20:36:22 +02:00
|
|
|
arc.pivot();
|
2015-06-13 15:51:28 +02:00
|
|
|
},
|
2015-06-16 08:39:04 +02:00
|
|
|
|
2015-06-13 15:51:28 +02:00
|
|
|
draw: function(ease) {
|
|
|
|
var easingDecimal = ease || 1;
|
2015-06-16 08:39:04 +02:00
|
|
|
helpers.each(this.getDataset().metaData, function(arc, index) {
|
|
|
|
arc.transition(easingDecimal).draw();
|
2015-06-13 15:51:28 +02:00
|
|
|
}, this);
|
|
|
|
},
|
|
|
|
|
2015-06-16 08:39:04 +02:00
|
|
|
setHoverStyle: function(arc) {
|
|
|
|
var dataset = this.chart.data.datasets[arc._datasetIndex];
|
|
|
|
var index = arc._index;
|
2015-06-13 15:51:28 +02:00
|
|
|
|
2015-06-16 08:39:04 +02:00
|
|
|
arc._model.backgroundColor = arc.custom && arc.custom.hoverBackgroundColor ? arc.custom.hoverBackgroundColor : helpers.getValueAtIndexOrDefault(dataset.hoverBackgroundColor, index, helpers.color(arc._model.backgroundColor).saturate(0.5).darken(0.1).rgbString());
|
|
|
|
arc._model.borderColor = arc.custom && arc.custom.hoverBorderColor ? arc.custom.hoverBorderColor : helpers.getValueAtIndexOrDefault(dataset.hoverBorderColor, index, helpers.color(arc._model.borderColor).saturate(0.5).darken(0.1).rgbString());
|
|
|
|
arc._model.borderWidth = arc.custom && arc.custom.hoverBorderWidth ? arc.custom.hoverBorderWidth : helpers.getValueAtIndexOrDefault(dataset.borderWidth, index, arc._model.borderWidth);
|
|
|
|
},
|
2015-06-13 15:51:28 +02:00
|
|
|
|
2015-06-16 08:39:04 +02:00
|
|
|
removeHoverStyle: function(arc) {
|
|
|
|
var dataset = this.chart.data.datasets[arc._datasetIndex];
|
|
|
|
var index = arc._index;
|
2015-06-13 15:51:28 +02:00
|
|
|
|
2015-06-16 08:39:04 +02:00
|
|
|
arc._model.backgroundColor = arc.custom && arc.custom.backgroundColor ? arc.custom.backgroundColor : helpers.getValueAtIndexOrDefault(this.getDataset().backgroundColor, index, this.chart.options.elements.arc.backgroundColor);
|
|
|
|
arc._model.borderColor = arc.custom && arc.custom.borderColor ? arc.custom.borderColor : helpers.getValueAtIndexOrDefault(this.getDataset().borderColor, index, this.chart.options.elements.arc.borderColor);
|
|
|
|
arc._model.borderWidth = arc.custom && arc.custom.borderWidth ? arc.custom.borderWidth : helpers.getValueAtIndexOrDefault(this.getDataset().borderWidth, index, this.chart.options.elements.arc.borderWidth);
|
|
|
|
},
|
2015-06-13 15:51:28 +02:00
|
|
|
|
2015-06-16 08:39:04 +02:00
|
|
|
calculateCircumference: function(value) {
|
2015-12-08 03:42:58 +01:00
|
|
|
if (isNaN(value)) {
|
2015-06-16 08:39:04 +02:00
|
|
|
return 0;
|
2015-12-08 03:42:58 +01:00
|
|
|
} else {
|
|
|
|
// Count the number of NaN values
|
|
|
|
var numNaN = helpers.where(this.getDataset().data, function(data) {
|
|
|
|
return isNaN(data);
|
|
|
|
}).length;
|
|
|
|
|
|
|
|
return (2 * Math.PI) / (this.getDataset().data.length - numNaN);
|
2015-06-13 15:51:28 +02:00
|
|
|
}
|
2015-06-16 08:39:04 +02:00
|
|
|
},
|
|
|
|
updateScaleRange: function() {
|
|
|
|
helpers.extend(this.chart.scale, {
|
|
|
|
size: helpers.min([this.chart.width, this.chart.height]),
|
|
|
|
xCenter: this.chart.width / 2,
|
|
|
|
yCenter: this.chart.height / 2
|
|
|
|
});
|
|
|
|
},
|
2015-06-13 15:51:28 +02:00
|
|
|
|
2015-06-16 08:39:04 +02:00
|
|
|
});
|
2015-05-05 10:11:29 +02:00
|
|
|
}).call(this);
|