mirror of
https://github.com/chartjs/Chart.js.git
synced 2025-12-08 20:36:08 +00:00
Add support for 'inner' border for arc elements (#5841)
This commit is contained in:
parent
4fb259e3ac
commit
db8f6c38dc
@ -55,12 +55,21 @@ The doughnut/pie chart allows a number of properties to be specified for each da
|
||||
|
||||
| Name | Type | Description
|
||||
| ---- | ---- | -----------
|
||||
| `backgroundColor` | `Color[]` | The fill color of the arcs in the dataset. See [Colors](../general/colors.md#colors).
|
||||
| `borderColor` | `Color[]` | The border color of the arcs in the dataset. See [Colors](../general/colors.md#colors).
|
||||
| `borderWidth` | `Number[]` | The border width of the arcs in the dataset.
|
||||
| `hoverBackgroundColor` | `Color[]` | The fill colour of the arcs when hovered.
|
||||
| `hoverBorderColor` | `Color[]` | The stroke colour of the arcs when hovered.
|
||||
| `hoverBorderWidth` | `Number[]` | The stroke width of the arcs when hovered.
|
||||
| `backgroundColor` | `Color/Color[]` | The fill color of the arcs in the dataset. See [Colors](../general/colors.md#colors).
|
||||
| `borderColor` | `Color/Color[]` | The border color of the arcs in the dataset. See [Colors](../general/colors.md#colors).
|
||||
| `borderWidth` | `Number/Number[]` | The border width of the arcs in the dataset.
|
||||
| `borderAlign` | `String/String[]` | The border alignment of the arcs in the dataset. [more...](#border-alignment)
|
||||
| `hoverBackgroundColor` | `Color/Color[]` | The fill colour of the arcs when hovered.
|
||||
| `hoverBorderColor` | `Color/Color[]` | The stroke colour of the arcs when hovered.
|
||||
| `hoverBorderWidth` | `Number/Number[]` | The stroke width of the arcs when hovered.
|
||||
|
||||
### Border Alignment
|
||||
|
||||
The following values are supported for `borderAlign`.
|
||||
* `'center'` (default)
|
||||
* `'inner'`
|
||||
|
||||
When `'center'` is set, the borders of arcs next to each other will overlap. When `'inner'` is set, it is guaranteed that all the borders are not overlap.
|
||||
|
||||
## Config Options
|
||||
|
||||
|
||||
@ -46,12 +46,21 @@ The following options can be included in a polar area chart dataset to configure
|
||||
|
||||
| Name | Type | Description
|
||||
| ---- | ---- | -----------
|
||||
| `backgroundColor` | `Color[]` | The fill color of the arcs in the dataset. See [Colors](../general/colors.md#colors).
|
||||
| `borderColor` | `Color[]` | The border color of the arcs in the dataset. See [Colors](../general/colors.md#colors).
|
||||
| `borderWidth` | `Number[]` | The border width of the arcs in the dataset.
|
||||
| `hoverBackgroundColor` | `Color[]` | The fill colour of the arcs when hovered.
|
||||
| `hoverBorderColor` | `Color[]` | The stroke colour of the arcs when hovered.
|
||||
| `hoverBorderWidth` | `Number[]` | The stroke width of the arcs when hovered.
|
||||
| `backgroundColor` | `Color/Color[]` | The fill color of the arcs in the dataset. See [Colors](../general/colors.md#colors).
|
||||
| `borderColor` | `Color/Color[]` | The border color of the arcs in the dataset. See [Colors](../general/colors.md#colors).
|
||||
| `borderWidth` | `Number/Number[]` | The border width of the arcs in the dataset.
|
||||
| `borderAlign` | `String/String[]` | The border alignment of the arcs in the dataset. [more...](#border-alignment)
|
||||
| `hoverBackgroundColor` | `Color/Color[]` | The fill colour of the arcs when hovered.
|
||||
| `hoverBorderColor` | `Color/Color[]` | The stroke colour of the arcs when hovered.
|
||||
| `hoverBorderWidth` | `Number/Number[]` | The stroke width of the arcs when hovered.
|
||||
|
||||
### Border Alignment
|
||||
|
||||
The following values are supported for `borderAlign`.
|
||||
* `'center'` (default)
|
||||
* `'inner'`
|
||||
|
||||
When `'center'` is set, the borders of arcs next to each other will overlap. When `'inner'` is set, it is guaranteed that all the borders are not overlap.
|
||||
|
||||
## Config Options
|
||||
|
||||
|
||||
@ -143,14 +143,15 @@ module.exports = DatasetController.extend({
|
||||
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();
|
||||
var arcs = meta.data;
|
||||
var cutoutPercentage = opts.cutoutPercentage;
|
||||
var circumference = opts.circumference;
|
||||
var 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) {
|
||||
@ -171,7 +172,11 @@ module.exports = DatasetController.extend({
|
||||
offset = {x: (max.x + min.x) * -0.5, y: (max.y + min.y) * -0.5};
|
||||
}
|
||||
|
||||
chart.borderWidth = me.getMaxBorderWidth(meta.data);
|
||||
for (i = 0, ilen = arcs.length; i < ilen; ++i) {
|
||||
arcs[i]._options = me._resolveElementOptions(arcs[i], i, reset);
|
||||
}
|
||||
|
||||
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();
|
||||
@ -183,9 +188,9 @@ module.exports = DatasetController.extend({
|
||||
me.outerRadius = chart.outerRadius - (chart.radiusLength * me.getRingIndex(me.index));
|
||||
me.innerRadius = Math.max(me.outerRadius - chart.radiusLength, 0);
|
||||
|
||||
helpers.each(meta.data, function(arc, index) {
|
||||
me.updateElement(arc, index, reset);
|
||||
});
|
||||
for (i = 0, ilen = arcs.length; i < ilen; ++i) {
|
||||
me.updateElement(arcs[i], i, reset);
|
||||
}
|
||||
},
|
||||
|
||||
updateElement: function(arc, index, reset) {
|
||||
@ -202,7 +207,7 @@ module.exports = DatasetController.extend({
|
||||
var circumference = reset && animationOpts.animateRotate ? 0 : arc.hidden ? 0 : me.calculateCircumference(dataset.data[index]) * (opts.circumference / (2.0 * Math.PI));
|
||||
var innerRadius = reset && animationOpts.animateScale ? 0 : me.innerRadius;
|
||||
var outerRadius = reset && animationOpts.animateScale ? 0 : me.outerRadius;
|
||||
var valueAtIndexOrDefault = helpers.valueAtIndexOrDefault;
|
||||
var options = arc._options || {};
|
||||
|
||||
helpers.extend(arc, {
|
||||
// Utility
|
||||
@ -211,6 +216,10 @@ module.exports = DatasetController.extend({
|
||||
|
||||
// Desired view properties
|
||||
_model: {
|
||||
backgroundColor: options.backgroundColor,
|
||||
borderColor: options.borderColor,
|
||||
borderWidth: options.borderWidth,
|
||||
borderAlign: options.borderAlign,
|
||||
x: centerX + chart.offsetX,
|
||||
y: centerY + chart.offsetY,
|
||||
startAngle: startAngle,
|
||||
@ -218,20 +227,12 @@ module.exports = DatasetController.extend({
|
||||
circumference: circumference,
|
||||
outerRadius: outerRadius,
|
||||
innerRadius: innerRadius,
|
||||
label: valueAtIndexOrDefault(dataset.label, index, chart.data.labels[index])
|
||||
label: helpers.valueAtIndexOrDefault(dataset.label, index, chart.data.labels[index])
|
||||
}
|
||||
});
|
||||
|
||||
var model = arc._model;
|
||||
|
||||
// Resets the visual styles
|
||||
var custom = arc.custom || {};
|
||||
var valueOrDefault = helpers.valueAtIndexOrDefault;
|
||||
var elementOpts = this.chart.options.elements.arc;
|
||||
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);
|
||||
|
||||
// Set correct angles if not resetting
|
||||
if (!reset || !animationOpts.animateRotate) {
|
||||
if (index === 0) {
|
||||
@ -276,19 +277,58 @@ module.exports = DatasetController.extend({
|
||||
|
||||
// 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 chart = me.chart;
|
||||
var i, ilen, meta, arc, controller, options, borderWidth, hoverWidth;
|
||||
|
||||
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) {
|
||||
// Find the outmost visible dataset
|
||||
for (i = 0, ilen = chart.data.datasets.length; i < ilen; ++i) {
|
||||
if (chart.isDatasetVisible(i)) {
|
||||
meta = chart.getDatasetMeta(i);
|
||||
arcs = meta.data;
|
||||
if (i !== me.index) {
|
||||
controller = meta.controller;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!arcs) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0, ilen = arcs.length; i < ilen; ++i) {
|
||||
arc = arcs[i];
|
||||
options = controller ? controller._resolveElementOptions(arc, i) : arc._options;
|
||||
if (options.borderAlign !== 'inner') {
|
||||
borderWidth = options.borderWidth;
|
||||
hoverWidth = options.hoverBorderWidth;
|
||||
|
||||
max = borderWidth > max ? borderWidth : max;
|
||||
max = hoverWidth > max ? hoverWidth : max;
|
||||
}
|
||||
}
|
||||
return max;
|
||||
},
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_resolveElementOptions: function(arc, index) {
|
||||
var me = this;
|
||||
var dataset = me.getDataset();
|
||||
var custom = arc.custom || {};
|
||||
var options = me.chart.options.elements.arc;
|
||||
var valueAtIndexOrDefault = helpers.valueAtIndexOrDefault;
|
||||
|
||||
return {
|
||||
backgroundColor: custom.backgroundColor ? custom.backgroundColor : valueAtIndexOrDefault(dataset.backgroundColor, index, options.backgroundColor),
|
||||
borderColor: custom.borderColor ? custom.borderColor : valueAtIndexOrDefault(dataset.borderColor, index, options.borderColor),
|
||||
borderWidth: custom.borderWidth ? custom.borderWidth : valueAtIndexOrDefault(dataset.borderWidth, index, options.borderWidth),
|
||||
borderAlign: custom.borderAlign ? custom.borderAlign : valueAtIndexOrDefault(dataset.borderAlign, index, options.borderAlign)
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
@ -148,10 +148,9 @@ module.exports = DatasetController.extend({
|
||||
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();
|
||||
|
||||
@ -206,6 +205,7 @@ module.exports = DatasetController.extend({
|
||||
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();
|
||||
},
|
||||
|
||||
@ -9,7 +9,8 @@ defaults._set('global', {
|
||||
arc: {
|
||||
backgroundColor: defaults.global.defaultColor,
|
||||
borderColor: '#fff',
|
||||
borderWidth: 2
|
||||
borderWidth: 2,
|
||||
borderAlign: 'center'
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -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.save();
|
||||
|
||||
ctx.beginPath();
|
||||
|
||||
ctx.arc(vm.x, vm.y, vm.outerRadius, sA, eA);
|
||||
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();
|
||||
}
|
||||
});
|
||||
|
||||
@ -79,6 +79,7 @@ Context.prototype._initMethods = function() {
|
||||
beginPath: function() {},
|
||||
bezierCurveTo: function() {},
|
||||
clearRect: function() {},
|
||||
clip: function() {},
|
||||
closePath: function() {},
|
||||
fill: function() {},
|
||||
fillRect: function() {},
|
||||
|
||||
31
test/fixtures/controller.doughnut/doughnut-border-align-center.json
vendored
Normal file
31
test/fixtures/controller.doughnut/doughnut-border-align-center.json
vendored
Normal file
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
test/fixtures/controller.doughnut/doughnut-border-align-center.png
vendored
Normal file
BIN
test/fixtures/controller.doughnut/doughnut-border-align-center.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 28 KiB |
32
test/fixtures/controller.doughnut/doughnut-border-align-inner.json
vendored
Normal file
32
test/fixtures/controller.doughnut/doughnut-border-align-inner.json
vendored
Normal file
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
test/fixtures/controller.doughnut/doughnut-border-align-inner.png
vendored
Normal file
BIN
test/fixtures/controller.doughnut/doughnut-border-align-inner.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
31
test/fixtures/controller.doughnut/pie-border-align-center.json
vendored
Normal file
31
test/fixtures/controller.doughnut/pie-border-align-center.json
vendored
Normal file
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
test/fixtures/controller.doughnut/pie-border-align-center.png
vendored
Normal file
BIN
test/fixtures/controller.doughnut/pie-border-align-center.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
32
test/fixtures/controller.doughnut/pie-border-align-inner.json
vendored
Normal file
32
test/fixtures/controller.doughnut/pie-border-align-inner.json
vendored
Normal file
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
test/fixtures/controller.doughnut/pie-border-align-inner.png
vendored
Normal file
BIN
test/fixtures/controller.doughnut/pie-border-align-inner.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
41
test/fixtures/controller.polarArea/border-align-center.json
vendored
Normal file
41
test/fixtures/controller.polarArea/border-align-center.json
vendored
Normal file
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
test/fixtures/controller.polarArea/border-align-center.png
vendored
Normal file
BIN
test/fixtures/controller.polarArea/border-align-center.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
42
test/fixtures/controller.polarArea/border-align-inner.json
vendored
Normal file
42
test/fixtures/controller.polarArea/border-align-inner.json
vendored
Normal file
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
test/fixtures/controller.polarArea/border-align-inner.png
vendored
Normal file
BIN
test/fixtures/controller.polarArea/border-align-inner.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.8 KiB |
@ -1,4 +1,6 @@
|
||||
describe('Chart.controllers.doughnut', function() {
|
||||
describe('auto', jasmine.fixture.specs('controller.doughnut'));
|
||||
|
||||
it('should be registered as dataset controller', function() {
|
||||
expect(typeof Chart.controllers.doughnut).toBe('function');
|
||||
expect(Chart.controllers.doughnut).toBe(Chart.controllers.pie);
|
||||
@ -106,8 +108,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,
|
||||
@ -129,8 +131,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);
|
||||
@ -200,10 +202,10 @@ describe('Chart.controllers.doughnut', function() {
|
||||
{c: Math.PI / 8, s: Math.PI, e: Math.PI + Math.PI / 8},
|
||||
{c: 3 * Math.PI / 8, s: Math.PI + Math.PI / 8, e: Math.PI + Math.PI / 2}
|
||||
].forEach(function(expected, i) {
|
||||
expect(meta.data[i]._model.x).toBeCloseToPixel(511);
|
||||
expect(meta.data[i]._model.y).toBeCloseToPixel(511);
|
||||
expect(meta.data[i]._model.outerRadius).toBeCloseToPixel(510);
|
||||
expect(meta.data[i]._model.innerRadius).toBeCloseToPixel(382);
|
||||
expect(meta.data[i]._model.x).toBeCloseToPixel(512);
|
||||
expect(meta.data[i]._model.y).toBeCloseToPixel(512);
|
||||
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);
|
||||
@ -405,4 +407,52 @@ describe('Chart.controllers.doughnut', function() {
|
||||
expect(arc._model.borderColor).toBe('rgb(17, 17, 17)');
|
||||
expect(arc._model.borderWidth).toBe(3.14159);
|
||||
});
|
||||
|
||||
it ('should calculate radiuses based on the border widths of the visible outermost dataset', function() {
|
||||
var chart = window.acquireChart({
|
||||
type: 'doughnut',
|
||||
data: {
|
||||
datasets: [{
|
||||
data: [2, 4],
|
||||
borderWidth: 4,
|
||||
hidden: true
|
||||
}, {
|
||||
data: [1, 3],
|
||||
borderWidth: 8
|
||||
}, {
|
||||
data: [1, 0],
|
||||
borderWidth: 12
|
||||
}],
|
||||
labels: ['label0', 'label1']
|
||||
},
|
||||
options: {
|
||||
legend: false,
|
||||
title: false
|
||||
}
|
||||
});
|
||||
|
||||
chart.update();
|
||||
|
||||
expect(chart.chartArea.bottom - chart.chartArea.top).toBe(512);
|
||||
expect(chart.borderWidth).toBe(8);
|
||||
expect(chart.outerRadius).toBe(252);
|
||||
expect(chart.innerRadius).toBe(126);
|
||||
expect(chart.radiusLength).toBe(63);
|
||||
|
||||
var controller = chart.getDatasetMeta(0).controller;
|
||||
expect(controller.getMaxBorderWidth()).toBe(8);
|
||||
expect(controller.outerRadius).toBe(252);
|
||||
expect(controller.innerRadius).toBe(189);
|
||||
|
||||
controller = chart.getDatasetMeta(1).controller;
|
||||
expect(controller.getMaxBorderWidth()).toBe(8);
|
||||
expect(controller.outerRadius).toBe(252);
|
||||
expect(controller.innerRadius).toBe(189);
|
||||
|
||||
controller = chart.getDatasetMeta(2).controller;
|
||||
expect(controller.getMaxBorderWidth()).toBe(8);
|
||||
expect(controller.outerRadius).toBe(189);
|
||||
expect(controller.innerRadius).toBe(126);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@ -943,7 +943,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;
|
||||
|
||||
@ -126,6 +126,9 @@ describe('Arc element tests', function() {
|
||||
arc.draw();
|
||||
|
||||
expect(mockContext.getCalls()).toEqual([{
|
||||
name: 'save',
|
||||
args: []
|
||||
}, {
|
||||
name: 'beginPath',
|
||||
args: []
|
||||
}, {
|
||||
@ -137,12 +140,6 @@ describe('Arc element tests', function() {
|
||||
}, {
|
||||
name: 'closePath',
|
||||
args: []
|
||||
}, {
|
||||
name: 'setStrokeStyle',
|
||||
args: ['rgb(255, 0, 0)']
|
||||
}, {
|
||||
name: 'setLineWidth',
|
||||
args: [undefined]
|
||||
}, {
|
||||
name: 'setFillStyle',
|
||||
args: ['rgb(0, 0, 255)']
|
||||
@ -150,8 +147,8 @@ describe('Arc element tests', function() {
|
||||
name: 'fill',
|
||||
args: []
|
||||
}, {
|
||||
name: 'setLineJoin',
|
||||
args: ['bevel']
|
||||
name: 'restore',
|
||||
args: []
|
||||
}]);
|
||||
});
|
||||
|
||||
@ -182,6 +179,9 @@ describe('Arc element tests', function() {
|
||||
arc.draw();
|
||||
|
||||
expect(mockContext.getCalls()).toEqual([{
|
||||
name: 'save',
|
||||
args: []
|
||||
}, {
|
||||
name: 'beginPath',
|
||||
args: []
|
||||
}, {
|
||||
@ -194,23 +194,119 @@ describe('Arc element tests', function() {
|
||||
name: 'closePath',
|
||||
args: []
|
||||
}, {
|
||||
name: 'setStrokeStyle',
|
||||
args: ['rgb(255, 0, 0)']
|
||||
name: 'setFillStyle',
|
||||
args: ['rgb(0, 0, 255)']
|
||||
}, {
|
||||
name: 'fill',
|
||||
args: []
|
||||
}, {
|
||||
name: 'setLineWidth',
|
||||
args: [5]
|
||||
}, {
|
||||
name: 'setLineJoin',
|
||||
args: ['bevel']
|
||||
}, {
|
||||
name: 'setStrokeStyle',
|
||||
args: ['rgb(255, 0, 0)']
|
||||
}, {
|
||||
name: 'stroke',
|
||||
args: []
|
||||
}, {
|
||||
name: 'restore',
|
||||
args: []
|
||||
}]);
|
||||
});
|
||||
|
||||
it ('should draw correctly with an inner border', function() {
|
||||
var mockContext = window.createMockContext();
|
||||
var arc = new Chart.elements.Arc({
|
||||
_datasetIndex: 2,
|
||||
_index: 1,
|
||||
_chart: {
|
||||
ctx: mockContext,
|
||||
}
|
||||
});
|
||||
|
||||
// Mock out the view as if the controller put it there
|
||||
arc._view = {
|
||||
startAngle: 0,
|
||||
endAngle: Math.PI / 2,
|
||||
x: 10,
|
||||
y: 5,
|
||||
innerRadius: 1,
|
||||
outerRadius: 3,
|
||||
|
||||
backgroundColor: 'rgb(0, 0, 255)',
|
||||
borderColor: 'rgb(255, 0, 0)',
|
||||
borderWidth: 5,
|
||||
borderAlign: 'inner'
|
||||
};
|
||||
|
||||
arc.draw();
|
||||
|
||||
expect(mockContext.getCalls()).toEqual([{
|
||||
name: 'save',
|
||||
args: []
|
||||
}, {
|
||||
name: 'beginPath',
|
||||
args: []
|
||||
}, {
|
||||
name: 'arc',
|
||||
args: [10, 5, 2.67, 0, Math.PI / 2]
|
||||
}, {
|
||||
name: 'arc',
|
||||
args: [10, 5, 1, Math.PI / 2, 0, true]
|
||||
}, {
|
||||
name: 'closePath',
|
||||
args: []
|
||||
}, {
|
||||
name: 'setFillStyle',
|
||||
args: ['rgb(0, 0, 255)']
|
||||
}, {
|
||||
name: 'fill',
|
||||
args: []
|
||||
}, {
|
||||
name: 'beginPath',
|
||||
args: []
|
||||
}, {
|
||||
name: 'arc',
|
||||
args: [10, 5, 3, -0.11, Math.PI / 2 + 0.11]
|
||||
}, {
|
||||
name: 'arc',
|
||||
args: [10, 5, 1 - 0.33, Math.PI / 2 + 0.33, -0.33, true]
|
||||
}, {
|
||||
name: 'closePath',
|
||||
args: []
|
||||
}, {
|
||||
name: 'clip',
|
||||
args: []
|
||||
}, {
|
||||
name: 'beginPath',
|
||||
args: []
|
||||
}, {
|
||||
name: 'arc',
|
||||
args: [10, 5, 3, 0, Math.PI / 2]
|
||||
}, {
|
||||
name: 'arc',
|
||||
args: [10, 5, 1, Math.PI / 2, 0, true]
|
||||
}, {
|
||||
name: 'closePath',
|
||||
args: []
|
||||
}, {
|
||||
name: 'setLineWidth',
|
||||
args: [10]
|
||||
}, {
|
||||
name: 'setLineJoin',
|
||||
args: ['bevel']
|
||||
args: ['round']
|
||||
}, {
|
||||
name: 'setStrokeStyle',
|
||||
args: ['rgb(255, 0, 0)']
|
||||
}, {
|
||||
name: 'stroke',
|
||||
args: []
|
||||
}, {
|
||||
name: 'restore',
|
||||
args: []
|
||||
}]);
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user