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 Dec 1, 2018
1 parent ecfa7b2 commit 33c9822
Show file tree
Hide file tree
Showing 21 changed files with 451 additions and 43 deletions.
49 changes: 36 additions & 13 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,7 +176,7 @@ module.exports = function(Chart) {
offset = {x: (max.x + min.x) * -0.5, y: (max.y + min.y) * -0.5};
}

chart.borderWidth = me.getMaxBorderWidth(meta.data);
chart.borderWidth = me.getMaxBorderWidth();
chart.outerRadius = Math.max((minSize - chart.borderWidth) / 2, 0);
chart.innerRadius = Math.max(cutoutPercentage ? (chart.outerRadius / 100) * (cutoutPercentage) : 0, 0);
chart.radiusLength = (chart.outerRadius - chart.innerRadius) / chart.getVisibleDatasetCount();
Expand Down Expand Up @@ -237,6 +236,7 @@ module.exports = function(Chart) {
model.backgroundColor = custom.backgroundColor ? custom.backgroundColor : valueOrDefault(dataset.backgroundColor, index, elementOpts.backgroundColor);
model.borderColor = custom.borderColor ? custom.borderColor : valueOrDefault(dataset.borderColor, index, elementOpts.borderColor);
model.borderWidth = custom.borderWidth ? custom.borderWidth : valueOrDefault(dataset.borderWidth, index, elementOpts.borderWidth);
model.borderAlign = custom.borderAlign ? custom.borderAlign : valueOrDefault(dataset.borderAlign, index, elementOpts.borderAlign);

// Set correct angles if not resetting
if (!reset || !animationOpts.animateRotate) {
Expand Down Expand Up @@ -282,18 +282,41 @@ module.exports = function(Chart) {

// gets the max border or hover width to properly scale pie charts
getMaxBorderWidth: function(arcs) {
var me = this;
var max = 0;
var index = this.index;
var length = arcs.length;
var borderWidth;
var hoverWidth;
var index = me.index;
var chart = me.chart;
var valueAtIndexOrDefault = helpers.valueAtIndexOrDefault;
var elementOpts = chart.options.elements.arc;
var i, ilen, dataset, custom, borderAlign, borderWidth, hoverWidth;

if (!arcs) {
// Find the outmost visible dataset
for (i = 0, ilen = chart.data.datasets.length; i < ilen; ++i) {
if (chart.isDatasetVisible(i)) {
arcs = chart.getDatasetMeta(i).data;
index = i;
break;
}
}
}

for (var i = 0; i < length; i++) {
borderWidth = arcs[i]._model ? arcs[i]._model.borderWidth : 0;
hoverWidth = arcs[i]._chart ? arcs[i]._chart.config.data.datasets[index].hoverBorderWidth : 0;
if (!arcs) {
return 0;
}

dataset = chart.data.datasets[index];

max = borderWidth > max ? borderWidth : max;
max = hoverWidth > max ? hoverWidth : max;
for (i = 0, ilen = arcs.length; i < ilen; ++i) {
custom = arcs[i].custom || {};
borderAlign = custom.borderAlign ? custom.borderAlign : valueAtIndexOrDefault(dataset.borderAlign, i, elementOpts.borderAlign);
if (borderAlign !== 'inner') {
borderWidth = custom.borderWidth ? custom.borderWidth : valueAtIndexOrDefault(dataset.borderWidth, i, elementOpts.borderWidth);
hoverWidth = custom.hoverBorderWidth ? custom.hoverBorderWidth : valueAtIndexOrDefault(dataset.hoverBorderWidth, i, borderWidth);

max = borderWidth > max ? borderWidth : max;
max = hoverWidth > max ? hoverWidth : max;
}
}
return max;
}
Expand Down
4 changes: 2 additions & 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 Expand Up @@ -207,6 +206,7 @@ module.exports = function(Chart) {
model.backgroundColor = custom.backgroundColor ? custom.backgroundColor : valueOrDefault(dataset.backgroundColor, index, elementOpts.backgroundColor);
model.borderColor = custom.borderColor ? custom.borderColor : valueOrDefault(dataset.borderColor, index, elementOpts.borderColor);
model.borderWidth = custom.borderWidth ? custom.borderWidth : valueOrDefault(dataset.borderWidth, index, elementOpts.borderWidth);
model.borderAlign = custom.borderAlign ? custom.borderAlign : valueOrDefault(dataset.borderAlign, index, elementOpts.borderAlign);

arc.pivot();
},
Expand Down
45 changes: 37 additions & 8 deletions src/elements/element.arc.js
Expand Up @@ -9,7 +9,8 @@ defaults._set('global', {
arc: {
backgroundColor: defaults.global.defaultColor,
borderColor: '#fff',
borderWidth: 2
borderWidth: 2,
borderAlign: 'center'
}
}
});
Expand Down Expand Up @@ -85,23 +86,51 @@ module.exports = Element.extend({
var vm = this._view;
var sA = vm.startAngle;
var eA = vm.endAngle;
var pixelMargin = (vm.borderAlign === 'inner') ? 0.33 : 0;
var angleMargin;

ctx.beginPath();
ctx.save();

ctx.arc(vm.x, vm.y, vm.outerRadius, sA, eA);
ctx.beginPath();
ctx.arc(vm.x, vm.y, vm.outerRadius - pixelMargin, sA, eA);
ctx.arc(vm.x, vm.y, vm.innerRadius, eA, sA, true);

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

ctx.fillStyle = vm.backgroundColor;

ctx.fill();
ctx.lineJoin = 'bevel';

if (vm.borderWidth) {
if (vm.borderAlign === 'inner') {
// Draw an inner border by cliping the arc and drawing a double-width border
// Enlarge the clipping arc by 0.33 pixels to eliminate glitches between borders
ctx.beginPath();
angleMargin = pixelMargin / vm.outerRadius;
ctx.arc(vm.x, vm.y, vm.outerRadius, sA - angleMargin, eA + angleMargin);
if (vm.innerRadius > pixelMargin) {
angleMargin = pixelMargin / vm.innerRadius;
ctx.arc(vm.x, vm.y, vm.innerRadius - pixelMargin, eA + angleMargin, sA - angleMargin, true);
} else {
ctx.arc(vm.x, vm.y, pixelMargin, eA + Math.PI / 2, sA - Math.PI / 2);
}
ctx.closePath();
ctx.clip();

ctx.beginPath();
ctx.arc(vm.x, vm.y, vm.outerRadius, sA, eA);
ctx.arc(vm.x, vm.y, vm.innerRadius, eA, sA, true);
ctx.closePath();

ctx.lineWidth = vm.borderWidth * 2;
ctx.lineJoin = 'round';
} else {
ctx.lineWidth = vm.borderWidth;
ctx.lineJoin = 'bevel';
}

ctx.strokeStyle = vm.borderColor;
ctx.stroke();
}

ctx.restore();
}
});
1 change: 1 addition & 0 deletions test/context.js
Expand Up @@ -79,6 +79,7 @@ Context.prototype._initMethods = function() {
beginPath: function() {},
bezierCurveTo: function() {},
clearRect: function() {},
clip: function() {},
closePath: function() {},
fill: function() {},
fillRect: function() {},
Expand Down
@@ -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.
32 changes: 32 additions & 0 deletions test/fixtures/controller.doughnut/doughnut-border-align-inner.json
@@ -0,0 +1,32 @@
{
"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)"
],
"borderAlign": "inner"
}]
},
"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-align-center.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.
32 changes: 32 additions & 0 deletions test/fixtures/controller.doughnut/pie-border-align-inner.json
@@ -0,0 +1,32 @@
{
"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)"
],
"borderAlign": "inner"
}]
},
"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-align-center.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.
42 changes: 42 additions & 0 deletions test/fixtures/controller.polarArea/border-align-inner.json
@@ -0,0 +1,42 @@
{
"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)"
],
"borderAlign": "inner"
}]
},
"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.

0 comments on commit 33c9822

Please sign in to comment.