var resolve = helpers.options.resolve;
var valueOrDefault = helpers.valueOrDefault;
+var PI = Math.PI;
+var DOUBLE_PI = PI * 2;
+var HALF_PI = PI / 2;
+
defaults._set('doughnut', {
animation: {
// Boolean - Whether we animate the rotation of the Doughnut
cutoutPercentage: 50,
// The rotation of the chart, where the first data arc begins.
- rotation: Math.PI * -0.5,
+ rotation: -HALF_PI,
// The total circumference of the chart.
- circumference: Math.PI * 2.0,
+ circumference: DOUBLE_PI,
// Need to override these to give a nice default
tooltips: {
var chart = me.chart;
var chartArea = chart.chartArea;
var opts = chart.options;
- var availableWidth = chartArea.right - chartArea.left;
- var availableHeight = chartArea.bottom - chartArea.top;
- var minSize = Math.min(availableWidth, availableHeight);
- var offset = {x: 0, y: 0};
+ var ratioX = 1;
+ var ratioY = 1;
+ var offsetX = 0;
+ var offsetY = 0;
var meta = me.getMeta();
var arcs = meta.data;
- var cutoutPercentage = opts.cutoutPercentage;
+ var cutout = opts.cutoutPercentage / 100 || 0;
var circumference = opts.circumference;
var chartWeight = me._getRingWeight(me.index);
- var i, ilen;
+ var maxWidth, maxHeight, i, ilen;
- // If the chart's circumference isn't a full circle, calculate minSize as a ratio of the width/height of the arc
- if (circumference < Math.PI * 2.0) {
- var startAngle = opts.rotation % (Math.PI * 2.0);
- startAngle += Math.PI * 2.0 * (startAngle >= Math.PI ? -1 : startAngle < -Math.PI ? 1 : 0);
+ // If the chart's circumference isn't a full circle, calculate size as a ratio of the width/height of the arc
+ if (circumference < DOUBLE_PI) {
+ var startAngle = opts.rotation % DOUBLE_PI;
+ startAngle += startAngle >= PI ? -DOUBLE_PI : startAngle < -PI ? DOUBLE_PI : 0;
var endAngle = startAngle + circumference;
- var start = {x: Math.cos(startAngle), y: Math.sin(startAngle)};
- var end = {x: Math.cos(endAngle), y: Math.sin(endAngle)};
- var contains0 = (startAngle <= 0 && endAngle >= 0) || (startAngle <= Math.PI * 2.0 && Math.PI * 2.0 <= endAngle);
- var contains90 = (startAngle <= Math.PI * 0.5 && Math.PI * 0.5 <= endAngle) || (startAngle <= Math.PI * 2.5 && Math.PI * 2.5 <= endAngle);
- var contains180 = (startAngle <= -Math.PI && -Math.PI <= endAngle) || (startAngle <= Math.PI && Math.PI <= endAngle);
- var contains270 = (startAngle <= -Math.PI * 0.5 && -Math.PI * 0.5 <= endAngle) || (startAngle <= Math.PI * 1.5 && Math.PI * 1.5 <= endAngle);
- var cutout = cutoutPercentage / 100.0;
- var min = {x: contains180 ? -1 : Math.min(start.x * (start.x < 0 ? 1 : cutout), end.x * (end.x < 0 ? 1 : cutout)), y: contains270 ? -1 : Math.min(start.y * (start.y < 0 ? 1 : cutout), end.y * (end.y < 0 ? 1 : cutout))};
- var max = {x: contains0 ? 1 : Math.max(start.x * (start.x > 0 ? 1 : cutout), end.x * (end.x > 0 ? 1 : cutout)), y: contains90 ? 1 : Math.max(start.y * (start.y > 0 ? 1 : cutout), end.y * (end.y > 0 ? 1 : cutout))};
- var size = {width: (max.x - min.x) * 0.5, height: (max.y - min.y) * 0.5};
- minSize = Math.min(availableWidth / size.width, availableHeight / size.height);
- offset = {x: (max.x + min.x) * -0.5, y: (max.y + min.y) * -0.5};
+ var startX = Math.cos(startAngle);
+ var startY = Math.sin(startAngle);
+ var endX = Math.cos(endAngle);
+ var endY = Math.sin(endAngle);
+ var contains0 = (startAngle <= 0 && endAngle >= 0) || endAngle >= DOUBLE_PI;
+ var contains90 = (startAngle <= HALF_PI && endAngle >= HALF_PI) || endAngle >= DOUBLE_PI + HALF_PI;
+ var contains180 = startAngle === -PI || endAngle >= PI;
+ var contains270 = (startAngle <= -HALF_PI && endAngle >= -HALF_PI) || endAngle >= PI + HALF_PI;
+ var minX = contains180 ? -1 : Math.min(startX, startX * cutout, endX, endX * cutout);
+ var minY = contains270 ? -1 : Math.min(startY, startY * cutout, endY, endY * cutout);
+ var maxX = contains0 ? 1 : Math.max(startX, startX * cutout, endX, endX * cutout);
+ var maxY = contains90 ? 1 : Math.max(startY, startY * cutout, endY, endY * cutout);
+ ratioX = (maxX - minX) / 2;
+ ratioY = (maxY - minY) / 2;
+ offsetX = -(maxX + minX) / 2;
+ offsetY = -(maxY + minY) / 2;
}
for (i = 0, ilen = arcs.length; i < ilen; ++i) {
}
chart.borderWidth = me.getMaxBorderWidth();
- chart.outerRadius = Math.max((minSize - chart.borderWidth) / 2, 0);
- chart.innerRadius = Math.max(cutoutPercentage ? (chart.outerRadius / 100) * (cutoutPercentage) : 0, 0);
+ maxWidth = (chartArea.right - chartArea.left - chart.borderWidth) / ratioX;
+ maxHeight = (chartArea.bottom - chartArea.top - chart.borderWidth) / ratioY;
+ chart.outerRadius = Math.max(Math.min(maxWidth, maxHeight) / 2, 0);
+ chart.innerRadius = Math.max(chart.outerRadius * cutout, 0);
chart.radiusLength = (chart.outerRadius - chart.innerRadius) / (me._getVisibleDatasetWeightTotal() || 1);
- chart.offsetX = offset.x * chart.outerRadius;
- chart.offsetY = offset.y * chart.outerRadius;
+ chart.offsetX = offsetX * chart.outerRadius;
+ chart.offsetY = offsetY * chart.outerRadius;
meta.total = me.calculateTotal();
var startAngle = opts.rotation; // non reset case handled later
var endAngle = opts.rotation; // non reset case handled later
var dataset = me.getDataset();
- var circumference = reset && animationOpts.animateRotate ? 0 : arc.hidden ? 0 : me.calculateCircumference(dataset.data[index]) * (opts.circumference / (2.0 * Math.PI));
+ var circumference = reset && animationOpts.animateRotate ? 0 : arc.hidden ? 0 : me.calculateCircumference(dataset.data[index]) * (opts.circumference / DOUBLE_PI);
var innerRadius = reset && animationOpts.animateScale ? 0 : me.innerRadius;
var outerRadius = reset && animationOpts.animateScale ? 0 : me.outerRadius;
var options = arc._options || {};
calculateCircumference: function(value) {
var total = this.getMeta().total;
if (total > 0 && !isNaN(value)) {
- return (Math.PI * 2.0) * (Math.abs(value) / total);
+ return DOUBLE_PI * (Math.abs(value) / total);
}
return 0;
},