Skip to content

Commit

Permalink
Draw inner border for arc elements
Browse files Browse the repository at this point in the history
  • Loading branch information
nagix committed Nov 15, 2018
1 parent ecf64d3 commit b798fbc
Show file tree
Hide file tree
Showing 14 changed files with 147 additions and 25 deletions.
9 changes: 5 additions & 4 deletions src/controllers/controller.doughnut.js
Expand Up @@ -149,9 +149,8 @@ module.exports = function(Chart) {
var chart = me.chart;
var chartArea = chart.chartArea;
var opts = chart.options;
var arcOpts = opts.elements.arc;
var availableWidth = chartArea.right - chartArea.left - arcOpts.borderWidth;
var availableHeight = chartArea.bottom - chartArea.top - arcOpts.borderWidth;
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 meta = me.getMeta();
Expand All @@ -177,8 +176,10 @@ module.exports = function(Chart) {
offset = {x: (max.x + min.x) * -0.5, y: (max.y + min.y) * -0.5};
}

// This is no longer used, but left for backward compatibility
chart.borderWidth = me.getMaxBorderWidth(meta.data);
chart.outerRadius = Math.max((minSize - chart.borderWidth) / 2, 0);

chart.outerRadius = Math.max(minSize / 2, 0);
chart.innerRadius = Math.max(cutoutPercentage ? (chart.outerRadius / 100) * (cutoutPercentage) : 0, 0);
chart.radiusLength = (chart.outerRadius - chart.innerRadius) / chart.getVisibleDatasetCount();
chart.offsetX = offset.x * chart.outerRadius;
Expand Down
3 changes: 1 addition & 2 deletions src/controllers/controller.polarArea.js
Expand Up @@ -149,10 +149,9 @@ module.exports = function(Chart) {
var chart = me.chart;
var chartArea = chart.chartArea;
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.outerRadius = Math.max(minSize / 2, 0);
chart.innerRadius = Math.max(opts.cutoutPercentage ? (chart.outerRadius / 100) * (opts.cutoutPercentage) : 1, 0);
chart.radiusLength = (chart.outerRadius - chart.innerRadius) / chart.getVisibleDatasetCount();

Expand Down
29 changes: 23 additions & 6 deletions src/elements/element.arc.js
Expand Up @@ -9,7 +9,7 @@ defaults._set('global', {
arc: {
backgroundColor: defaults.global.defaultColor,
borderColor: '#fff',
borderWidth: 2
borderWidth: 1
}
}
});
Expand Down Expand Up @@ -85,22 +85,39 @@ module.exports = Element.extend({
var vm = this._view;
var sA = vm.startAngle;
var eA = vm.endAngle;
var cA = eA - sA;
var outerRadius = vm.outerRadius;
var innerRadius = vm.innerRadius;
var width = outerRadius - innerRadius;
var minBorderWidth = outerRadius / (1 / Math.sin(Math.min(cA / 2, Math.PI / 2)) + 1);
var borderWidth = Math.min(Math.min(vm.borderWidth, minBorderWidth), width / 2) || 0;
var halfStroke = borderWidth / 2;
var outerHalfStrokeAngle = Math.atan2(halfStroke, Math.sqrt(outerRadius * (outerRadius - halfStroke * 2)));
var innerHalfStrokeAngle = Math.atan2(halfStroke, Math.sqrt(innerRadius * (innerRadius + halfStroke * 2)));
var r;

ctx.beginPath();

ctx.arc(vm.x, vm.y, vm.outerRadius, sA, eA);
ctx.arc(vm.x, vm.y, vm.innerRadius, eA, sA, true);
ctx.arc(vm.x, vm.y, outerRadius - halfStroke, sA + outerHalfStrokeAngle, eA - outerHalfStrokeAngle);
if (innerRadius > 0 || cA > Math.PI) {
innerHalfStrokeAngle = Math.min(innerHalfStrokeAngle, cA / 2 - 0.0001);
ctx.arc(vm.x, vm.y, innerRadius + halfStroke, eA - innerHalfStrokeAngle, sA + innerHalfStrokeAngle, true);
} else {
r = halfStroke / Math.sin(cA / 2);
ctx.lineTo(vm.x + r * Math.cos((sA + eA) / 2), vm.y + r * Math.sin((sA + eA) / 2));
}

ctx.closePath();
ctx.strokeStyle = vm.borderColor;
ctx.lineWidth = vm.borderWidth;
ctx.lineWidth = borderWidth;

ctx.fillStyle = vm.backgroundColor;

ctx.fill();
ctx.lineJoin = 'bevel';
ctx.lineJoin = 'miter';
ctx.miterLimit = 1E+38;

if (vm.borderWidth) {
if (borderWidth) {
ctx.stroke();
}
}
Expand Down
31 changes: 31 additions & 0 deletions test/fixtures/controller.doughnut/doughnut-border-width.json
@@ -0,0 +1,31 @@
{
"config": {
"type": "doughnut",
"data": {
"labels": ["A", "B", "C", "D", "E"],
"datasets": [{
"data": [1, 5, 10, 50, 100],
"backgroundColor": [
"rgba(255, 99, 132, 0.8)",
"rgba(54, 162, 235, 0.8)",
"rgba(255, 206, 86, 0.8)",
"rgba(75, 192, 192, 0.8)",
"rgba(153, 102, 255, 0.8)"
],
"borderWidth": 20,
"borderColor": [
"rgb(255, 99, 132)",
"rgb(54, 162, 235)",
"rgb(255, 206, 86)",
"rgb(75, 192, 192)",
"rgb(153, 102, 255)"
]
}]
},
"options": {
"responsive": false,
"legend": false,
"title": false
}
}
}
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
31 changes: 31 additions & 0 deletions test/fixtures/controller.doughnut/pie-border-width.json
@@ -0,0 +1,31 @@
{
"config": {
"type": "pie",
"data": {
"labels": ["A", "B", "C", "D", "E"],
"datasets": [{
"data": [1, 5, 10, 50, 100],
"backgroundColor": [
"rgba(255, 99, 132, 0.8)",
"rgba(54, 162, 235, 0.8)",
"rgba(255, 206, 86, 0.8)",
"rgba(75, 192, 192, 0.8)",
"rgba(153, 102, 255, 0.8)"
],
"borderWidth": 20,
"borderColor": [
"rgb(255, 99, 132)",
"rgb(54, 162, 235)",
"rgb(255, 206, 86)",
"rgb(75, 192, 192)",
"rgb(153, 102, 255)"
]
}]
},
"options": {
"responsive": false,
"legend": false,
"title": false
}
}
}
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/fixtures/controller.polarArea/angle-array.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified test/fixtures/controller.polarArea/angle-undefined.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
41 changes: 41 additions & 0 deletions test/fixtures/controller.polarArea/border-width.json
@@ -0,0 +1,41 @@
{
"config": {
"type": "polarArea",
"data": {
"labels": ["A", "B", "C", "D", "E"],
"datasets": [{
"data": [11, 16, 21, 1, 10],
"backgroundColor": [
"rgba(255, 99, 132, 0.8)",
"rgba(54, 162, 235, 0.8)",
"rgba(255, 206, 86, 0.8)",
"rgba(75, 192, 192, 0.8)",
"rgba(153, 102, 255, 0.8)"
],
"borderWidth": 20,
"borderColor": [
"rgb(255, 99, 132)",
"rgb(54, 162, 235)",
"rgb(255, 206, 86)",
"rgb(75, 192, 192)",
"rgb(153, 102, 255)"
]
}]
},
"options": {
"elements": {
"arc": {
"angle": [
0.0378, 0.1892, 0.3786, 1.8925, 3.7849
]
}
},
"responsive": false,
"legend": false,
"title": false,
"scale": {
"display": false
}
}
}
}
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 8 additions & 6 deletions test/specs/controller.doughnut.tests.js
@@ -1,4 +1,6 @@
describe('Chart.controllers.doughnut', function() {
describe('auto', jasmine.fixture.specs('controller.doughnut'));

it('should be constructed', function() {
var chart = window.acquireChart({
type: 'doughnut',
Expand Down Expand Up @@ -101,8 +103,8 @@ describe('Chart.controllers.doughnut', function() {
].forEach(function(expected, i) {
expect(meta.data[i]._model.x).toBeCloseToPixel(256);
expect(meta.data[i]._model.y).toBeCloseToPixel(256);
expect(meta.data[i]._model.outerRadius).toBeCloseToPixel(254);
expect(meta.data[i]._model.innerRadius).toBeCloseToPixel(190);
expect(meta.data[i]._model.outerRadius).toBeCloseToPixel(256);
expect(meta.data[i]._model.innerRadius).toBeCloseToPixel(192);
expect(meta.data[i]._model.circumference).toBeCloseTo(expected.c, 8);
expect(meta.data[i]._model).toEqual(jasmine.objectContaining({
startAngle: Math.PI * -0.5,
Expand All @@ -124,8 +126,8 @@ describe('Chart.controllers.doughnut', function() {
].forEach(function(expected, i) {
expect(meta.data[i]._model.x).toBeCloseToPixel(256);
expect(meta.data[i]._model.y).toBeCloseToPixel(256);
expect(meta.data[i]._model.outerRadius).toBeCloseToPixel(254);
expect(meta.data[i]._model.innerRadius).toBeCloseToPixel(190);
expect(meta.data[i]._model.outerRadius).toBeCloseToPixel(256);
expect(meta.data[i]._model.innerRadius).toBeCloseToPixel(192);
expect(meta.data[i]._model.circumference).toBeCloseTo(expected.c, 8);
expect(meta.data[i]._model.startAngle).toBeCloseTo(expected.s, 8);
expect(meta.data[i]._model.endAngle).toBeCloseTo(expected.e, 8);
Expand Down Expand Up @@ -197,8 +199,8 @@ describe('Chart.controllers.doughnut', function() {
].forEach(function(expected, i) {
expect(meta.data[i]._model.x).toBeCloseToPixel(510);
expect(meta.data[i]._model.y).toBeCloseToPixel(510);
expect(meta.data[i]._model.outerRadius).toBeCloseToPixel(509);
expect(meta.data[i]._model.innerRadius).toBeCloseToPixel(381);
expect(meta.data[i]._model.outerRadius).toBeCloseToPixel(512);
expect(meta.data[i]._model.innerRadius).toBeCloseToPixel(384);
expect(meta.data[i]._model.circumference).toBeCloseTo(expected.c, 8);
expect(meta.data[i]._model.startAngle).toBeCloseTo(expected.s, 8);
expect(meta.data[i]._model.endAngle).toBeCloseTo(expected.e, 8);
Expand Down
2 changes: 1 addition & 1 deletion test/specs/core.tooltip.tests.js
Expand Up @@ -941,7 +941,7 @@ describe('Core.Tooltip', function() {
if (model.width <= chart.width) {
expect(model.x + model.width).toBeLessThanOrEqual(chart.width);
}
expect(model.caretX).toBe(tooltipPosition.x);
expect(model.caretX).toBeCloseToPixel(tooltipPosition.x);
// if tooltip is longer than chart area then all tests done
if (model.width > chart.width) {
break;
Expand Down
12 changes: 6 additions & 6 deletions test/specs/element.arc.tests.js
Expand Up @@ -142,7 +142,7 @@ describe('Arc element tests', function() {
args: ['rgb(255, 0, 0)']
}, {
name: 'setLineWidth',
args: [undefined]
args: [0]
}, {
name: 'setFillStyle',
args: ['rgb(0, 0, 255)']
Expand All @@ -151,7 +151,7 @@ describe('Arc element tests', function() {
args: []
}, {
name: 'setLineJoin',
args: ['bevel']
args: ['miter']
}]);
});

Expand Down Expand Up @@ -186,10 +186,10 @@ describe('Arc element tests', function() {
args: []
}, {
name: 'arc',
args: [10, 5, 3, 0, Math.PI / 2]
args: [10, 5, 2.5, Math.atan2(0.5, Math.sqrt(6)), Math.PI / 2 - Math.atan2(0.5, Math.sqrt(6))]
}, {
name: 'arc',
args: [10, 5, 1, Math.PI / 2, 0, true]
args: [10, 5, 1.5, Math.PI / 2 - Math.atan2(0.5, Math.sqrt(2)), Math.atan2(0.5, Math.sqrt(2)), true]
}, {
name: 'closePath',
args: []
Expand All @@ -198,7 +198,7 @@ describe('Arc element tests', function() {
args: ['rgb(255, 0, 0)']
}, {
name: 'setLineWidth',
args: [5]
args: [1]
}, {
name: 'setFillStyle',
args: ['rgb(0, 0, 255)']
Expand All @@ -207,7 +207,7 @@ describe('Arc element tests', function() {
args: []
}, {
name: 'setLineJoin',
args: ['bevel']
args: ['miter']
}, {
name: 'stroke',
args: []
Expand Down

0 comments on commit b798fbc

Please sign in to comment.