Skip to content

Commit b798fbc

Browse files
committed
Draw inner border for arc elements
1 parent ecf64d3 commit b798fbc

14 files changed

+147
-25
lines changed

src/controllers/controller.doughnut.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -149,9 +149,8 @@ module.exports = function(Chart) {
149149
var chart = me.chart;
150150
var chartArea = chart.chartArea;
151151
var opts = chart.options;
152-
var arcOpts = opts.elements.arc;
153-
var availableWidth = chartArea.right - chartArea.left - arcOpts.borderWidth;
154-
var availableHeight = chartArea.bottom - chartArea.top - arcOpts.borderWidth;
152+
var availableWidth = chartArea.right - chartArea.left;
153+
var availableHeight = chartArea.bottom - chartArea.top;
155154
var minSize = Math.min(availableWidth, availableHeight);
156155
var offset = {x: 0, y: 0};
157156
var meta = me.getMeta();
@@ -177,8 +176,10 @@ module.exports = function(Chart) {
177176
offset = {x: (max.x + min.x) * -0.5, y: (max.y + min.y) * -0.5};
178177
}
179178

179+
// This is no longer used, but left for backward compatibility
180180
chart.borderWidth = me.getMaxBorderWidth(meta.data);
181-
chart.outerRadius = Math.max((minSize - chart.borderWidth) / 2, 0);
181+
182+
chart.outerRadius = Math.max(minSize / 2, 0);
182183
chart.innerRadius = Math.max(cutoutPercentage ? (chart.outerRadius / 100) * (cutoutPercentage) : 0, 0);
183184
chart.radiusLength = (chart.outerRadius - chart.innerRadius) / chart.getVisibleDatasetCount();
184185
chart.offsetX = offset.x * chart.outerRadius;

src/controllers/controller.polarArea.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,10 +149,9 @@ module.exports = function(Chart) {
149149
var chart = me.chart;
150150
var chartArea = chart.chartArea;
151151
var opts = chart.options;
152-
var arcOpts = opts.elements.arc;
153152
var minSize = Math.min(chartArea.right - chartArea.left, chartArea.bottom - chartArea.top);
154153

155-
chart.outerRadius = Math.max((minSize - arcOpts.borderWidth / 2) / 2, 0);
154+
chart.outerRadius = Math.max(minSize / 2, 0);
156155
chart.innerRadius = Math.max(opts.cutoutPercentage ? (chart.outerRadius / 100) * (opts.cutoutPercentage) : 1, 0);
157156
chart.radiusLength = (chart.outerRadius - chart.innerRadius) / chart.getVisibleDatasetCount();
158157

src/elements/element.arc.js

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ defaults._set('global', {
99
arc: {
1010
backgroundColor: defaults.global.defaultColor,
1111
borderColor: '#fff',
12-
borderWidth: 2
12+
borderWidth: 1
1313
}
1414
}
1515
});
@@ -85,22 +85,39 @@ module.exports = Element.extend({
8585
var vm = this._view;
8686
var sA = vm.startAngle;
8787
var eA = vm.endAngle;
88+
var cA = eA - sA;
89+
var outerRadius = vm.outerRadius;
90+
var innerRadius = vm.innerRadius;
91+
var width = outerRadius - innerRadius;
92+
var minBorderWidth = outerRadius / (1 / Math.sin(Math.min(cA / 2, Math.PI / 2)) + 1);
93+
var borderWidth = Math.min(Math.min(vm.borderWidth, minBorderWidth), width / 2) || 0;
94+
var halfStroke = borderWidth / 2;
95+
var outerHalfStrokeAngle = Math.atan2(halfStroke, Math.sqrt(outerRadius * (outerRadius - halfStroke * 2)));
96+
var innerHalfStrokeAngle = Math.atan2(halfStroke, Math.sqrt(innerRadius * (innerRadius + halfStroke * 2)));
97+
var r;
8898

8999
ctx.beginPath();
90100

91-
ctx.arc(vm.x, vm.y, vm.outerRadius, sA, eA);
92-
ctx.arc(vm.x, vm.y, vm.innerRadius, eA, sA, true);
101+
ctx.arc(vm.x, vm.y, outerRadius - halfStroke, sA + outerHalfStrokeAngle, eA - outerHalfStrokeAngle);
102+
if (innerRadius > 0 || cA > Math.PI) {
103+
innerHalfStrokeAngle = Math.min(innerHalfStrokeAngle, cA / 2 - 0.0001);
104+
ctx.arc(vm.x, vm.y, innerRadius + halfStroke, eA - innerHalfStrokeAngle, sA + innerHalfStrokeAngle, true);
105+
} else {
106+
r = halfStroke / Math.sin(cA / 2);
107+
ctx.lineTo(vm.x + r * Math.cos((sA + eA) / 2), vm.y + r * Math.sin((sA + eA) / 2));
108+
}
93109

94110
ctx.closePath();
95111
ctx.strokeStyle = vm.borderColor;
96-
ctx.lineWidth = vm.borderWidth;
112+
ctx.lineWidth = borderWidth;
97113

98114
ctx.fillStyle = vm.backgroundColor;
99115

100116
ctx.fill();
101-
ctx.lineJoin = 'bevel';
117+
ctx.lineJoin = 'miter';
118+
ctx.miterLimit = 1E+38;
102119

103-
if (vm.borderWidth) {
120+
if (borderWidth) {
104121
ctx.stroke();
105122
}
106123
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"config": {
3+
"type": "doughnut",
4+
"data": {
5+
"labels": ["A", "B", "C", "D", "E"],
6+
"datasets": [{
7+
"data": [1, 5, 10, 50, 100],
8+
"backgroundColor": [
9+
"rgba(255, 99, 132, 0.8)",
10+
"rgba(54, 162, 235, 0.8)",
11+
"rgba(255, 206, 86, 0.8)",
12+
"rgba(75, 192, 192, 0.8)",
13+
"rgba(153, 102, 255, 0.8)"
14+
],
15+
"borderWidth": 20,
16+
"borderColor": [
17+
"rgb(255, 99, 132)",
18+
"rgb(54, 162, 235)",
19+
"rgb(255, 206, 86)",
20+
"rgb(75, 192, 192)",
21+
"rgb(153, 102, 255)"
22+
]
23+
}]
24+
},
25+
"options": {
26+
"responsive": false,
27+
"legend": false,
28+
"title": false
29+
}
30+
}
31+
}
Loading
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"config": {
3+
"type": "pie",
4+
"data": {
5+
"labels": ["A", "B", "C", "D", "E"],
6+
"datasets": [{
7+
"data": [1, 5, 10, 50, 100],
8+
"backgroundColor": [
9+
"rgba(255, 99, 132, 0.8)",
10+
"rgba(54, 162, 235, 0.8)",
11+
"rgba(255, 206, 86, 0.8)",
12+
"rgba(75, 192, 192, 0.8)",
13+
"rgba(153, 102, 255, 0.8)"
14+
],
15+
"borderWidth": 20,
16+
"borderColor": [
17+
"rgb(255, 99, 132)",
18+
"rgb(54, 162, 235)",
19+
"rgb(255, 206, 86)",
20+
"rgb(75, 192, 192)",
21+
"rgb(153, 102, 255)"
22+
]
23+
}]
24+
},
25+
"options": {
26+
"responsive": false,
27+
"legend": false,
28+
"title": false
29+
}
30+
}
31+
}
Loading
Loading
Loading
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
{
2+
"config": {
3+
"type": "polarArea",
4+
"data": {
5+
"labels": ["A", "B", "C", "D", "E"],
6+
"datasets": [{
7+
"data": [11, 16, 21, 1, 10],
8+
"backgroundColor": [
9+
"rgba(255, 99, 132, 0.8)",
10+
"rgba(54, 162, 235, 0.8)",
11+
"rgba(255, 206, 86, 0.8)",
12+
"rgba(75, 192, 192, 0.8)",
13+
"rgba(153, 102, 255, 0.8)"
14+
],
15+
"borderWidth": 20,
16+
"borderColor": [
17+
"rgb(255, 99, 132)",
18+
"rgb(54, 162, 235)",
19+
"rgb(255, 206, 86)",
20+
"rgb(75, 192, 192)",
21+
"rgb(153, 102, 255)"
22+
]
23+
}]
24+
},
25+
"options": {
26+
"elements": {
27+
"arc": {
28+
"angle": [
29+
0.0378, 0.1892, 0.3786, 1.8925, 3.7849
30+
]
31+
}
32+
},
33+
"responsive": false,
34+
"legend": false,
35+
"title": false,
36+
"scale": {
37+
"display": false
38+
}
39+
}
40+
}
41+
}
Loading

test/specs/controller.doughnut.tests.js

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
describe('Chart.controllers.doughnut', function() {
2+
describe('auto', jasmine.fixture.specs('controller.doughnut'));
3+
24
it('should be constructed', function() {
35
var chart = window.acquireChart({
46
type: 'doughnut',
@@ -101,8 +103,8 @@ describe('Chart.controllers.doughnut', function() {
101103
].forEach(function(expected, i) {
102104
expect(meta.data[i]._model.x).toBeCloseToPixel(256);
103105
expect(meta.data[i]._model.y).toBeCloseToPixel(256);
104-
expect(meta.data[i]._model.outerRadius).toBeCloseToPixel(254);
105-
expect(meta.data[i]._model.innerRadius).toBeCloseToPixel(190);
106+
expect(meta.data[i]._model.outerRadius).toBeCloseToPixel(256);
107+
expect(meta.data[i]._model.innerRadius).toBeCloseToPixel(192);
106108
expect(meta.data[i]._model.circumference).toBeCloseTo(expected.c, 8);
107109
expect(meta.data[i]._model).toEqual(jasmine.objectContaining({
108110
startAngle: Math.PI * -0.5,
@@ -124,8 +126,8 @@ describe('Chart.controllers.doughnut', function() {
124126
].forEach(function(expected, i) {
125127
expect(meta.data[i]._model.x).toBeCloseToPixel(256);
126128
expect(meta.data[i]._model.y).toBeCloseToPixel(256);
127-
expect(meta.data[i]._model.outerRadius).toBeCloseToPixel(254);
128-
expect(meta.data[i]._model.innerRadius).toBeCloseToPixel(190);
129+
expect(meta.data[i]._model.outerRadius).toBeCloseToPixel(256);
130+
expect(meta.data[i]._model.innerRadius).toBeCloseToPixel(192);
129131
expect(meta.data[i]._model.circumference).toBeCloseTo(expected.c, 8);
130132
expect(meta.data[i]._model.startAngle).toBeCloseTo(expected.s, 8);
131133
expect(meta.data[i]._model.endAngle).toBeCloseTo(expected.e, 8);
@@ -197,8 +199,8 @@ describe('Chart.controllers.doughnut', function() {
197199
].forEach(function(expected, i) {
198200
expect(meta.data[i]._model.x).toBeCloseToPixel(510);
199201
expect(meta.data[i]._model.y).toBeCloseToPixel(510);
200-
expect(meta.data[i]._model.outerRadius).toBeCloseToPixel(509);
201-
expect(meta.data[i]._model.innerRadius).toBeCloseToPixel(381);
202+
expect(meta.data[i]._model.outerRadius).toBeCloseToPixel(512);
203+
expect(meta.data[i]._model.innerRadius).toBeCloseToPixel(384);
202204
expect(meta.data[i]._model.circumference).toBeCloseTo(expected.c, 8);
203205
expect(meta.data[i]._model.startAngle).toBeCloseTo(expected.s, 8);
204206
expect(meta.data[i]._model.endAngle).toBeCloseTo(expected.e, 8);

test/specs/core.tooltip.tests.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -941,7 +941,7 @@ describe('Core.Tooltip', function() {
941941
if (model.width <= chart.width) {
942942
expect(model.x + model.width).toBeLessThanOrEqual(chart.width);
943943
}
944-
expect(model.caretX).toBe(tooltipPosition.x);
944+
expect(model.caretX).toBeCloseToPixel(tooltipPosition.x);
945945
// if tooltip is longer than chart area then all tests done
946946
if (model.width > chart.width) {
947947
break;

test/specs/element.arc.tests.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ describe('Arc element tests', function() {
142142
args: ['rgb(255, 0, 0)']
143143
}, {
144144
name: 'setLineWidth',
145-
args: [undefined]
145+
args: [0]
146146
}, {
147147
name: 'setFillStyle',
148148
args: ['rgb(0, 0, 255)']
@@ -151,7 +151,7 @@ describe('Arc element tests', function() {
151151
args: []
152152
}, {
153153
name: 'setLineJoin',
154-
args: ['bevel']
154+
args: ['miter']
155155
}]);
156156
});
157157

@@ -186,10 +186,10 @@ describe('Arc element tests', function() {
186186
args: []
187187
}, {
188188
name: 'arc',
189-
args: [10, 5, 3, 0, Math.PI / 2]
189+
args: [10, 5, 2.5, Math.atan2(0.5, Math.sqrt(6)), Math.PI / 2 - Math.atan2(0.5, Math.sqrt(6))]
190190
}, {
191191
name: 'arc',
192-
args: [10, 5, 1, Math.PI / 2, 0, true]
192+
args: [10, 5, 1.5, Math.PI / 2 - Math.atan2(0.5, Math.sqrt(2)), Math.atan2(0.5, Math.sqrt(2)), true]
193193
}, {
194194
name: 'closePath',
195195
args: []
@@ -198,7 +198,7 @@ describe('Arc element tests', function() {
198198
args: ['rgb(255, 0, 0)']
199199
}, {
200200
name: 'setLineWidth',
201-
args: [5]
201+
args: [1]
202202
}, {
203203
name: 'setFillStyle',
204204
args: ['rgb(0, 0, 255)']
@@ -207,7 +207,7 @@ describe('Arc element tests', function() {
207207
args: []
208208
}, {
209209
name: 'setLineJoin',
210-
args: ['bevel']
210+
args: ['miter']
211211
}, {
212212
name: 'stroke',
213213
args: []

0 commit comments

Comments
 (0)