From dc8a10f8490670e0c9dc9d1290c53ba2fd369b50 Mon Sep 17 00:00:00 2001 From: Vincent-Ip Date: Tue, 1 Jan 2019 23:18:14 -0500 Subject: [PATCH 01/18] Added functionality to give pie & doughnut datasets a weight attribute. Weight affects the relative thickness of the dataset when there are multiple datasets in pie & doughnut charts. The default weight of each dataset is 1. Providing any other numerical value will allow the pie or doughnut dataset to be drawn with a thickness relative to its default size. For example a weight of 2 will allow the dataset to be drawn double its typical dataset thickness. NOTE: The weight attribute will only have an affect on a pie or doughnut chart if there is more than one visible dataset. Using weight on a pie or doughnut dataset when there is only one dataset on the chart will have no affect. --- src/controllers/controller.doughnut.js | 21 +++++++++++++-------- src/core/core.controller.js | 14 ++++++++++++++ 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/src/controllers/controller.doughnut.js b/src/controllers/controller.doughnut.js index f2a55d84e90..0a984b9be88 100644 --- a/src/controllers/controller.doughnut.js +++ b/src/controllers/controller.doughnut.js @@ -125,17 +125,21 @@ module.exports = DatasetController.extend({ linkScales: helpers.noop, - // Get index of the dataset in relation to the visible datasets. This allows determining the inner and outer radius correctly - getRingIndex: function(datasetIndex) { - var ringIndex = 0; + // Get radius length offset of the dataset in relation to the visible datasets weights. This allows determining the inner and outer radius correctly + getRingWeightOffset: function(datasetIndex) { + var ringWeightOffset = 0; for (var j = 0; j < datasetIndex; ++j) { if (this.chart.isDatasetVisible(j)) { - ++ringIndex; + var ringWeight = this.chart.data.datasets[j].weight; + if (!ringWeight) { + ringWeight = 1; + } + ringWeightOffset += ringWeight; } } - return ringIndex; + return ringWeightOffset; }, update: function(reset) { @@ -151,6 +155,7 @@ module.exports = DatasetController.extend({ var arcs = meta.data; var cutoutPercentage = opts.cutoutPercentage; var circumference = opts.circumference; + var chartWeight = (chart.data.datasets[me.index].weight) ? chart.data.datasets[me.index].weight : 1; 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 @@ -179,14 +184,14 @@ module.exports = DatasetController.extend({ 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(); + chart.radiusLength = (chart.outerRadius - chart.innerRadius) / chart.getVisibleDatasetWeight(); chart.offsetX = offset.x * chart.outerRadius; chart.offsetY = offset.y * chart.outerRadius; meta.total = me.calculateTotal(); - me.outerRadius = chart.outerRadius - (chart.radiusLength * me.getRingIndex(me.index)); - me.innerRadius = Math.max(me.outerRadius - chart.radiusLength, 0); + me.outerRadius = chart.outerRadius - (chart.radiusLength * me.getRingWeightOffset(me.index)); + me.innerRadius = Math.max(me.outerRadius - (chart.radiusLength * chartWeight), 0); for (i = 0, ilen = arcs.length; i < ilen; ++i) { me.updateElement(arcs[i], i, reset); diff --git a/src/core/core.controller.js b/src/core/core.controller.js index 117a6d576ea..3ac5c5ee98b 100644 --- a/src/core/core.controller.js +++ b/src/core/core.controller.js @@ -726,6 +726,20 @@ module.exports = function(Chart) { return count; }, + getVisibleDatasetWeight: function() { + var totalWeight = 0; + for (var i = 0, ilen = this.data.datasets.length; i < ilen; ++i) { + if (this.isDatasetVisible(i)) { + var currWeight = this.data.datasets[i].weight; + if (!currWeight) { + currWeight = 1; + } + totalWeight += currWeight; + } + } + return totalWeight; + }, + isDatasetVisible: function(datasetIndex) { var meta = this.getDatasetMeta(datasetIndex); From 1c2f11e073b1fd8b83e034f1b0f735564961f955 Mon Sep 17 00:00:00 2001 From: Vincent-Ip Date: Tue, 1 Jan 2019 23:34:18 -0500 Subject: [PATCH 02/18] Updated the doughnut documentation --- docs/charts/doughnut.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/charts/doughnut.md b/docs/charts/doughnut.md index 9fda1bbf719..ed3865fba58 100644 --- a/docs/charts/doughnut.md +++ b/docs/charts/doughnut.md @@ -62,6 +62,7 @@ The doughnut/pie chart allows a number of properties to be specified for each da | `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. +| `weight` | `Number` | The relative thickness of the dataset when there are multiple datasets provided. The default weight of each dataset is 1. Providing any other numerical value will allow the pie or doughnut dataset to be drawn with a thickness relative to the default size. For example a weight of 2 will allow the dataset to be drawn double its typical dataset thickness. NOTE: The weight attribute will only have an affect on a pie or doughnut chart if there is more than one dataset. Using weight on a pie or doughnut dataset when there is only one dataset in the chart will have no affect. ### Border Alignment From a97719615534ea8aee111bf2f144fb3df1f59214 Mon Sep 17 00:00:00 2001 From: Vincent-Ip Date: Wed, 2 Jan 2019 01:13:51 -0500 Subject: [PATCH 03/18] trying to reduce the Cognitive Complexity of getRingWeightOffset --- src/controllers/controller.doughnut.js | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/controllers/controller.doughnut.js b/src/controllers/controller.doughnut.js index 0a984b9be88..b78c185f346 100644 --- a/src/controllers/controller.doughnut.js +++ b/src/controllers/controller.doughnut.js @@ -131,17 +131,21 @@ module.exports = DatasetController.extend({ for (var j = 0; j < datasetIndex; ++j) { if (this.chart.isDatasetVisible(j)) { - var ringWeight = this.chart.data.datasets[j].weight; - if (!ringWeight) { - ringWeight = 1; - } - ringWeightOffset += ringWeight; + ringWeightOffset += this.getRingWeight(j); } } return ringWeightOffset; }, + getRingWeight: function(dataSetIndex) { + var ringWeight = this.chart.data.datasets[dataSetIndex].weight; + if (!ringWeight) { + ringWeight = 1; + } + return ringWeight; + }, + update: function(reset) { var me = this; var chart = me.chart; From f3518840da81139e9cfde196756fbcc52ccfe7d0 Mon Sep 17 00:00:00 2001 From: Vincent-Ip Date: Thu, 3 Jan 2019 18:51:26 -0500 Subject: [PATCH 04/18] Updated the description for the weight attribute to make it simpler. --- docs/charts/doughnut.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/charts/doughnut.md b/docs/charts/doughnut.md index ed3865fba58..1d052dd98ad 100644 --- a/docs/charts/doughnut.md +++ b/docs/charts/doughnut.md @@ -62,7 +62,7 @@ The doughnut/pie chart allows a number of properties to be specified for each da | `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. -| `weight` | `Number` | The relative thickness of the dataset when there are multiple datasets provided. The default weight of each dataset is 1. Providing any other numerical value will allow the pie or doughnut dataset to be drawn with a thickness relative to the default size. For example a weight of 2 will allow the dataset to be drawn double its typical dataset thickness. NOTE: The weight attribute will only have an affect on a pie or doughnut chart if there is more than one dataset. Using weight on a pie or doughnut dataset when there is only one dataset in the chart will have no affect. +| `weight` | `Number` | The relative thickness of the dataset. The default weight of each dataset is 1. Providing a value for weight will allow the pie or doughnut dataset to be drawn with a thickness relative to the sum of all the dataset weights. ### Border Alignment From eeb3f107e3c849f8732a3a241df450ba3e1f508a Mon Sep 17 00:00:00 2001 From: Vincent-Ip Date: Thu, 3 Jan 2019 19:17:15 -0500 Subject: [PATCH 05/18] made changes as suggested by benmccann. - added back getRingIndex function to doughnut controller. - moved getVisibleDatasetTotalWeight from the base controller file to the doughnut controller. - removed parentheses from the chartWeight assignment statement. - Also, slightly renamed the new functions --- src/controllers/controller.doughnut.js | 35 +++++++++++++++++++++++--- src/core/core.controller.js | 14 ----------- 2 files changed, 31 insertions(+), 18 deletions(-) diff --git a/src/controllers/controller.doughnut.js b/src/controllers/controller.doughnut.js index b78c185f346..155b984eb77 100644 --- a/src/controllers/controller.doughnut.js +++ b/src/controllers/controller.doughnut.js @@ -125,8 +125,21 @@ module.exports = DatasetController.extend({ linkScales: helpers.noop, + // Get index of the dataset in relation to the visible datasets. This allows determining the inner and outer radius correctly + getRingIndex: function(datasetIndex) { + var ringIndex = 0; + + for (var j = 0; j < datasetIndex; ++j) { + if (this.chart.isDatasetVisible(j)) { + ++ringIndex; + } + } + + return ringIndex; + }, + // Get radius length offset of the dataset in relation to the visible datasets weights. This allows determining the inner and outer radius correctly - getRingWeightOffset: function(datasetIndex) { + getRingWeightedOffset: function(datasetIndex) { var ringWeightOffset = 0; for (var j = 0; j < datasetIndex; ++j) { @@ -146,6 +159,20 @@ module.exports = DatasetController.extend({ return ringWeight; }, + getVisibleDatasetTotalWeight: function() { + var totalWeight = 0; + for (var i = 0, ilen = this.chart.data.datasets.length; i < ilen; ++i) { + if (this.chart.isDatasetVisible(i)) { + var currWeight = this.chart.data.datasets[i].weight; + if (!currWeight) { + currWeight = 1; + } + totalWeight += currWeight; + } + } + return totalWeight; + }, + update: function(reset) { var me = this; var chart = me.chart; @@ -159,7 +186,7 @@ module.exports = DatasetController.extend({ var arcs = meta.data; var cutoutPercentage = opts.cutoutPercentage; var circumference = opts.circumference; - var chartWeight = (chart.data.datasets[me.index].weight) ? chart.data.datasets[me.index].weight : 1; + var chartWeight = chart.data.datasets[me.index].weight ? chart.data.datasets[me.index].weight : 1; 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 @@ -188,13 +215,13 @@ module.exports = DatasetController.extend({ 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.getVisibleDatasetWeight(); + chart.radiusLength = (chart.outerRadius - chart.innerRadius) / me.getVisibleDatasetTotalWeight(); chart.offsetX = offset.x * chart.outerRadius; chart.offsetY = offset.y * chart.outerRadius; meta.total = me.calculateTotal(); - me.outerRadius = chart.outerRadius - (chart.radiusLength * me.getRingWeightOffset(me.index)); + me.outerRadius = chart.outerRadius - (chart.radiusLength * me.getRingWeightedOffset(me.index)); me.innerRadius = Math.max(me.outerRadius - (chart.radiusLength * chartWeight), 0); for (i = 0, ilen = arcs.length; i < ilen; ++i) { diff --git a/src/core/core.controller.js b/src/core/core.controller.js index 3ac5c5ee98b..117a6d576ea 100644 --- a/src/core/core.controller.js +++ b/src/core/core.controller.js @@ -726,20 +726,6 @@ module.exports = function(Chart) { return count; }, - getVisibleDatasetWeight: function() { - var totalWeight = 0; - for (var i = 0, ilen = this.data.datasets.length; i < ilen; ++i) { - if (this.isDatasetVisible(i)) { - var currWeight = this.data.datasets[i].weight; - if (!currWeight) { - currWeight = 1; - } - totalWeight += currWeight; - } - } - return totalWeight; - }, - isDatasetVisible: function(datasetIndex) { var meta = this.getDatasetMeta(datasetIndex); From 83afbc6f418ffdbc43cebcb9d3c4fcbe9f4da069 Mon Sep 17 00:00:00 2001 From: Vincent-Ip Date: Thu, 3 Jan 2019 19:28:24 -0500 Subject: [PATCH 06/18] refactored the getVisibleDatasetTotalWeight function --- src/controllers/controller.doughnut.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/controllers/controller.doughnut.js b/src/controllers/controller.doughnut.js index 155b984eb77..75d2d23a2d3 100644 --- a/src/controllers/controller.doughnut.js +++ b/src/controllers/controller.doughnut.js @@ -163,11 +163,7 @@ module.exports = DatasetController.extend({ var totalWeight = 0; for (var i = 0, ilen = this.chart.data.datasets.length; i < ilen; ++i) { if (this.chart.isDatasetVisible(i)) { - var currWeight = this.chart.data.datasets[i].weight; - if (!currWeight) { - currWeight = 1; - } - totalWeight += currWeight; + totalWeight += this.getRingWeight(i); } } return totalWeight; From 66767c3b39f44d3786811c17966877f578bdf7aa Mon Sep 17 00:00:00 2001 From: Vincent-Ip Date: Thu, 3 Jan 2019 21:40:57 -0500 Subject: [PATCH 07/18] made the new doughnut methods private and made suggested code simplicfications. --- src/controllers/controller.doughnut.js | 65 +++++++++++++------------- 1 file changed, 32 insertions(+), 33 deletions(-) diff --git a/src/controllers/controller.doughnut.js b/src/controllers/controller.doughnut.js index 75d2d23a2d3..02c987f056e 100644 --- a/src/controllers/controller.doughnut.js +++ b/src/controllers/controller.doughnut.js @@ -138,37 +138,6 @@ module.exports = DatasetController.extend({ return ringIndex; }, - // Get radius length offset of the dataset in relation to the visible datasets weights. This allows determining the inner and outer radius correctly - getRingWeightedOffset: function(datasetIndex) { - var ringWeightOffset = 0; - - for (var j = 0; j < datasetIndex; ++j) { - if (this.chart.isDatasetVisible(j)) { - ringWeightOffset += this.getRingWeight(j); - } - } - - return ringWeightOffset; - }, - - getRingWeight: function(dataSetIndex) { - var ringWeight = this.chart.data.datasets[dataSetIndex].weight; - if (!ringWeight) { - ringWeight = 1; - } - return ringWeight; - }, - - getVisibleDatasetTotalWeight: function() { - var totalWeight = 0; - for (var i = 0, ilen = this.chart.data.datasets.length; i < ilen; ++i) { - if (this.chart.isDatasetVisible(i)) { - totalWeight += this.getRingWeight(i); - } - } - return totalWeight; - }, - update: function(reset) { var me = this; var chart = me.chart; @@ -211,13 +180,13 @@ module.exports = DatasetController.extend({ 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) / me.getVisibleDatasetTotalWeight(); + chart.radiusLength = (chart.outerRadius - chart.innerRadius) / me._getVisibleDatasetTotalWeight(); chart.offsetX = offset.x * chart.outerRadius; chart.offsetY = offset.y * chart.outerRadius; meta.total = me.calculateTotal(); - me.outerRadius = chart.outerRadius - (chart.radiusLength * me.getRingWeightedOffset(me.index)); + me.outerRadius = chart.outerRadius - (chart.radiusLength * me._getRingWeightedOffset(me.index)); me.innerRadius = Math.max(me.outerRadius - (chart.radiusLength * chartWeight), 0); for (i = 0, ilen = arcs.length; i < ilen; ++i) { @@ -362,5 +331,35 @@ module.exports = DatasetController.extend({ borderWidth: custom.borderWidth ? custom.borderWidth : valueAtIndexOrDefault(dataset.borderWidth, index, options.borderWidth), borderAlign: custom.borderAlign ? custom.borderAlign : valueAtIndexOrDefault(dataset.borderAlign, index, options.borderAlign) }; + }, + + /** + * Get radius length offset of the dataset in relation to the visible datasets weights. This allows determining the inner and outer radius correctly + * @private + */ + _getRingWeightedOffset: function(datasetIndex) { + var ringWeightOffset = 0; + + for (var i = 0; i < datasetIndex; ++i) { + if (this.chart.isDatasetVisible(i)) { + ringWeightOffset += this._getRingWeight(i); + } + } + + return ringWeightOffset; + }, + + /** + * @private + */ + _getRingWeight: function(dataSetIndex) { + return this.chart.data.datasets[dataSetIndex].weight || 1; + }, + + /** + * @private + */ + _getVisibleDatasetTotalWeight: function() { + return this._getRingWeightedOffset(this.chart.data.datasets.length); } }); From e442a733b0d18a588094142ccec51cd1f009c318 Mon Sep 17 00:00:00 2001 From: Vincent-Ip Date: Thu, 3 Jan 2019 22:07:57 -0500 Subject: [PATCH 08/18] simplified chartWeight assignment --- src/controllers/controller.doughnut.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/controller.doughnut.js b/src/controllers/controller.doughnut.js index 02c987f056e..b321f755422 100644 --- a/src/controllers/controller.doughnut.js +++ b/src/controllers/controller.doughnut.js @@ -151,7 +151,7 @@ module.exports = DatasetController.extend({ var arcs = meta.data; var cutoutPercentage = opts.cutoutPercentage; var circumference = opts.circumference; - var chartWeight = chart.data.datasets[me.index].weight ? chart.data.datasets[me.index].weight : 1; + var chartWeight = chart.data.datasets[me.index].weight || 1; 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 From 5647b782888b40bc837d9eabbc6f2b4884fca1a8 Mon Sep 17 00:00:00 2001 From: Vincent-Ip Date: Thu, 3 Jan 2019 22:44:37 -0500 Subject: [PATCH 09/18] more simplifications for chartWeight assignment --- src/controllers/controller.doughnut.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/controller.doughnut.js b/src/controllers/controller.doughnut.js index b321f755422..aeeb738554d 100644 --- a/src/controllers/controller.doughnut.js +++ b/src/controllers/controller.doughnut.js @@ -151,7 +151,7 @@ module.exports = DatasetController.extend({ var arcs = meta.data; var cutoutPercentage = opts.cutoutPercentage; var circumference = opts.circumference; - var chartWeight = chart.data.datasets[me.index].weight || 1; + var chartWeight = me._getRingWeight(me.index); 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 From aab7d6c9fae0efbd57181c8f2dc9f31b222cb00a Mon Sep 17 00:00:00 2001 From: Vincent-Ip Date: Wed, 9 Jan 2019 14:34:33 -0500 Subject: [PATCH 10/18] Changed new property name from weight to flex --- docs/charts/doughnut.md | 2 +- src/controllers/controller.doughnut.js | 24 ++++++++++++------------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/charts/doughnut.md b/docs/charts/doughnut.md index 1d052dd98ad..7b5b9f66911 100644 --- a/docs/charts/doughnut.md +++ b/docs/charts/doughnut.md @@ -62,7 +62,7 @@ The doughnut/pie chart allows a number of properties to be specified for each da | `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. -| `weight` | `Number` | The relative thickness of the dataset. The default weight of each dataset is 1. Providing a value for weight will allow the pie or doughnut dataset to be drawn with a thickness relative to the sum of all the dataset weights. +| `flex` | `Number` | The relative thickness of the dataset. The default flex value of each dataset is 1. Providing a value for flex will allow the pie or doughnut dataset to be drawn with a thickness relative to the sum of all the dataset flex values. ### Border Alignment diff --git a/src/controllers/controller.doughnut.js b/src/controllers/controller.doughnut.js index aeeb738554d..73cd3e1afa4 100644 --- a/src/controllers/controller.doughnut.js +++ b/src/controllers/controller.doughnut.js @@ -151,7 +151,7 @@ module.exports = DatasetController.extend({ var arcs = meta.data; var cutoutPercentage = opts.cutoutPercentage; var circumference = opts.circumference; - var chartWeight = me._getRingWeight(me.index); + var chartFlex = me._getRingFlex(me.index); 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 @@ -180,14 +180,14 @@ module.exports = DatasetController.extend({ 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) / me._getVisibleDatasetTotalWeight(); + chart.radiusLength = (chart.outerRadius - chart.innerRadius) / me._getVisibleDatasetFlexTotal(); chart.offsetX = offset.x * chart.outerRadius; chart.offsetY = offset.y * chart.outerRadius; meta.total = me.calculateTotal(); - me.outerRadius = chart.outerRadius - (chart.radiusLength * me._getRingWeightedOffset(me.index)); - me.innerRadius = Math.max(me.outerRadius - (chart.radiusLength * chartWeight), 0); + me.outerRadius = chart.outerRadius - (chart.radiusLength * me._getRingFlexOffset(me.index)); + me.innerRadius = Math.max(me.outerRadius - (chart.radiusLength * chartFlex), 0); for (i = 0, ilen = arcs.length; i < ilen; ++i) { me.updateElement(arcs[i], i, reset); @@ -337,29 +337,29 @@ module.exports = DatasetController.extend({ * Get radius length offset of the dataset in relation to the visible datasets weights. This allows determining the inner and outer radius correctly * @private */ - _getRingWeightedOffset: function(datasetIndex) { - var ringWeightOffset = 0; + _getRingFlexOffset: function(datasetIndex) { + var ringFlexOffset = 0; for (var i = 0; i < datasetIndex; ++i) { if (this.chart.isDatasetVisible(i)) { - ringWeightOffset += this._getRingWeight(i); + ringFlexOffset += this._getRingFlex(i); } } - return ringWeightOffset; + return ringFlexOffset; }, /** * @private */ - _getRingWeight: function(dataSetIndex) { - return this.chart.data.datasets[dataSetIndex].weight || 1; + _getRingFlex: function(dataSetIndex) { + return this.chart.data.datasets[dataSetIndex].flex || 1; }, /** * @private */ - _getVisibleDatasetTotalWeight: function() { - return this._getRingWeightedOffset(this.chart.data.datasets.length); + _getVisibleDatasetFlexTotal: function() { + return this._getRingFlexOffset(this.chart.data.datasets.length); } }); From ccb5bd426d0873173ad65a530e3118fcd6933464 Mon Sep 17 00:00:00 2001 From: Vincent-Ip Date: Mon, 14 Jan 2019 09:22:49 -0500 Subject: [PATCH 11/18] changed the new feature name from flex to weight. --- docs/charts/doughnut.md | 4 ++-- src/controllers/controller.doughnut.js | 24 ++++++++++++------------ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/charts/doughnut.md b/docs/charts/doughnut.md index 897b641813d..5c24f4dd470 100644 --- a/docs/charts/doughnut.md +++ b/docs/charts/doughnut.md @@ -60,10 +60,10 @@ The doughnut/pie chart allows a number of properties to be specified for each da | [`borderColor`](#styling) | [`Color`](../general/colors.md) | Yes | Yes | `'#fff'` | [`borderWidth`](#styling) | `Number` | Yes | Yes | `2` | [`data`](#data-structure) | `Number[]` | - | - | **required** -| [`flex`](#styling) | `Number` | No | No | `1` | [`hoverBackgroundColor`](#interations) | [`Color`](../general/colors.md) | Yes | Yes | `undefined` | [`hoverBorderColor`](#interactions) | [`Color`](../general/colors.md) | Yes | Yes | `undefined` | [`hoverBorderWidth`](#interactions) | `Number` | Yes | Yes | `undefined` +| [`weight`](#styling) | `Number` | No | No | `1` ### Styling @@ -74,7 +74,7 @@ The style of each arc can be controlled with the following properties: | `backgroundColor` | arc background color. | `borderColor` | arc border color. | `borderWidth` | arc border width (in pixels). -| `flex` | The relative thickness of the dataset. Providing a value for flex will allow the pie or doughnut dataset to be drawn with a thickness relative to the sum of all the dataset flex values. +| `weight` | The relative thickness of the dataset. Providing a value for weight will allow the pie or doughnut dataset to be drawn with a thickness relative to the sum of all the dataset weight values. All these values, if `undefined`, fallback to the associated [`elements.arc.*`](../configuration/elements.md#arc-configuration) options. diff --git a/src/controllers/controller.doughnut.js b/src/controllers/controller.doughnut.js index 4981eba6286..156caad6398 100644 --- a/src/controllers/controller.doughnut.js +++ b/src/controllers/controller.doughnut.js @@ -152,7 +152,7 @@ module.exports = DatasetController.extend({ var arcs = meta.data; var cutoutPercentage = opts.cutoutPercentage; var circumference = opts.circumference; - var chartFlex = me._getRingFlex(me.index); + var chartWeight = me._getRingWeight(me.index); 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 @@ -181,14 +181,14 @@ module.exports = DatasetController.extend({ 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) / me._getVisibleDatasetFlexTotal(); + chart.radiusLength = (chart.outerRadius - chart.innerRadius) / me._getVisibleDatasetWeightTotal(); chart.offsetX = offset.x * chart.outerRadius; chart.offsetY = offset.y * chart.outerRadius; meta.total = me.calculateTotal(); - me.outerRadius = chart.outerRadius - (chart.radiusLength * me._getRingFlexOffset(me.index)); - me.innerRadius = Math.max(me.outerRadius - (chart.radiusLength * chartFlex), 0); + me.outerRadius = chart.outerRadius - (chart.radiusLength * me._getRingWeightOffset(me.index)); + me.innerRadius = Math.max(me.outerRadius - (chart.radiusLength * chartWeight), 0); for (i = 0, ilen = arcs.length; i < ilen; ++i) { me.updateElement(arcs[i], i, reset); @@ -382,29 +382,29 @@ module.exports = DatasetController.extend({ * Get radius length offset of the dataset in relation to the visible datasets weights. This allows determining the inner and outer radius correctly * @private */ - _getRingFlexOffset: function(datasetIndex) { - var ringFlexOffset = 0; + _getRingWeightOffset: function(datasetIndex) { + var ringWeightOffset = 0; for (var i = 0; i < datasetIndex; ++i) { if (this.chart.isDatasetVisible(i)) { - ringFlexOffset += this._getRingFlex(i); + ringWeightOffset += this._getRingWeight(i); } } - return ringFlexOffset; + return ringWeightOffset; }, /** * @private */ - _getRingFlex: function(dataSetIndex) { - return this.chart.data.datasets[dataSetIndex].flex || 1; + _getRingWeight: function(dataSetIndex) { + return this.chart.data.datasets[dataSetIndex].weight || 1; }, /** * @private */ - _getVisibleDatasetFlexTotal: function() { - return this._getRingFlexOffset(this.chart.data.datasets.length); + _getVisibleDatasetWeightTotal: function() { + return this._getRingWeightOffset(this.chart.data.datasets.length); } }); From 78aacf241eb0b5edee0f875fa00b4ea4c760e3bf Mon Sep 17 00:00:00 2001 From: Vincent-Ip Date: Fri, 18 Jan 2019 10:46:09 -0500 Subject: [PATCH 12/18] update to allow a weight of 0, treat negative weights as 0, and prevent div/0 err when a 0 is returned by _getVisibleDatasetWeightTotal --- docs/charts/doughnut.md | 2 +- src/controllers/controller.doughnut.js | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/charts/doughnut.md b/docs/charts/doughnut.md index 5c24f4dd470..9792506c7fe 100644 --- a/docs/charts/doughnut.md +++ b/docs/charts/doughnut.md @@ -63,7 +63,7 @@ The doughnut/pie chart allows a number of properties to be specified for each da | [`hoverBackgroundColor`](#interations) | [`Color`](../general/colors.md) | Yes | Yes | `undefined` | [`hoverBorderColor`](#interactions) | [`Color`](../general/colors.md) | Yes | Yes | `undefined` | [`hoverBorderWidth`](#interactions) | `Number` | Yes | Yes | `undefined` -| [`weight`](#styling) | `Number` | No | No | `1` +| [`weight`](#styling) | `Number` | - | - | `1` ### Styling diff --git a/src/controllers/controller.doughnut.js b/src/controllers/controller.doughnut.js index 156caad6398..2155821fa4c 100644 --- a/src/controllers/controller.doughnut.js +++ b/src/controllers/controller.doughnut.js @@ -181,7 +181,7 @@ module.exports = DatasetController.extend({ 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) / me._getVisibleDatasetWeightTotal(); + chart.radiusLength = (chart.outerRadius - chart.innerRadius) / (me._getVisibleDatasetWeightTotal() || 1); chart.offsetX = offset.x * chart.outerRadius; chart.offsetY = offset.y * chart.outerRadius; @@ -398,10 +398,11 @@ module.exports = DatasetController.extend({ * @private */ _getRingWeight: function(dataSetIndex) { - return this.chart.data.datasets[dataSetIndex].weight || 1; + return Math.max((this.chart.data.datasets[dataSetIndex].weight === undefined) ? 1 : this.chart.data.datasets[dataSetIndex].weight, 0); }, /** + * Returns the sum of all visibile data set weights. This value can be 0. * @private */ _getVisibleDatasetWeightTotal: function() { From 9b03ca424559a4edb8bb64ce5300266de7a24566 Mon Sep 17 00:00:00 2001 From: Vincent-Ip Date: Mon, 28 Jan 2019 23:05:54 -0500 Subject: [PATCH 13/18] added valueOrDefault function to new methods in doughnut controller --- src/controllers/controller.doughnut.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controllers/controller.doughnut.js b/src/controllers/controller.doughnut.js index 2155821fa4c..6c133041be5 100644 --- a/src/controllers/controller.doughnut.js +++ b/src/controllers/controller.doughnut.js @@ -6,6 +6,7 @@ var elements = require('../elements/index'); var helpers = require('../helpers/index'); var resolve = helpers.options.resolve; +var valueOrDefault = helpers.valueOrDefault; defaults._set('doughnut', { animation: { @@ -323,7 +324,6 @@ module.exports = DatasetController.extend({ var model = arc._model; var options = arc._options; var getHoverColor = helpers.getHoverColor; - var valueOrDefault = helpers.valueOrDefault; arc.$previousStyle = { backgroundColor: model.backgroundColor, @@ -398,7 +398,7 @@ module.exports = DatasetController.extend({ * @private */ _getRingWeight: function(dataSetIndex) { - return Math.max((this.chart.data.datasets[dataSetIndex].weight === undefined) ? 1 : this.chart.data.datasets[dataSetIndex].weight, 0); + return Math.max(valueOrDefault(this.chart.data.datasets[dataSetIndex].weight, 1), 0); }, /** From 919206f2605b46b5283cf78679eaa90711dd6e8e Mon Sep 17 00:00:00 2001 From: Vincent-Ip Date: Tue, 29 Jan 2019 12:36:54 -0500 Subject: [PATCH 14/18] Added test for new ring weight functions --- test/specs/controller.doughnut.tests.js | 77 +++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/test/specs/controller.doughnut.tests.js b/test/specs/controller.doughnut.tests.js index 2a4ae8f43c3..f991dd94f6c 100644 --- a/test/specs/controller.doughnut.tests.js +++ b/test/specs/controller.doughnut.tests.js @@ -325,6 +325,83 @@ describe('Chart.controllers.doughnut', function() { expect(controller.innerRadius).toBe(126); }); + it('should create arcs with widths based on the weight value of the dataset', function() { + var chart = window.acquireChart({ + type: 'doughnut', + data: { + datasets: [{ + // default weight of 1 + data: [1, 1], + borderWidth: 0 + }, { + // default weight of 1 but hidden + data: [2, 1], + hidden: true, + borderWidth: 0 + }, { + // explicit weight of 3 + data: [3, 3], + weight: 3, + borderWidth: 0 + }, { + // explicit weight of 0 + data: [4, 0], + weight: 0, + borderWidth: 0 + }, { + // explicit weight of -2 (treated as 0) + data: [5, 0], + weight: -2, + borderWidth: 0 + }], + labels: ['label0', 'label1'] + }, + options: { + legend: false, + title: false + } + }); + + chart.update(); + + expect(chart.radiusLength).toBe(32); + + var controller = chart.getDatasetMeta(0).controller; + expect(controller._getVisibleDatasetWeightTotal()).toBe(4); + expect(controller._getRingWeight(controller.index)).toBe(1); + expect(controller._getRingWeightOffset(controller.index)).toBe(0); + expect(controller.outerRadius).toBe(256); + expect(controller.innerRadius).toBe(224); + + controller = chart.getDatasetMeta(1).controller; + expect(controller._getVisibleDatasetWeightTotal()).toBe(4); + expect(controller._getRingWeight(controller.index)).toBe(1); + expect(controller._getRingWeightOffset(controller.index)).toBe(1); + expect(controller.outerRadius).toBe(224); + expect(controller.innerRadius).toBe(192); + + controller = chart.getDatasetMeta(2).controller; + expect(controller._getVisibleDatasetWeightTotal()).toBe(4); + expect(controller._getRingWeight(controller.index)).toBe(3); + expect(controller._getRingWeightOffset(controller.index)).toBe(1); + expect(controller.outerRadius).toBe(224); + expect(controller.innerRadius).toBe(128); + + controller = chart.getDatasetMeta(3).controller; + expect(controller._getVisibleDatasetWeightTotal()).toBe(4); + expect(controller._getRingWeight(controller.index)).toBe(0); + expect(controller._getRingWeightOffset(controller.index)).toBe(4); + expect(controller.outerRadius).toBe(128); + expect(controller.innerRadius).toBe(128); + + controller = chart.getDatasetMeta(4).controller; + expect(controller._getVisibleDatasetWeightTotal()).toBe(4); + expect(controller._getRingWeight(controller.index)).toBe(0); + expect(controller._getRingWeightOffset(controller.index)).toBe(4); + expect(controller.outerRadius).toBe(128); + expect(controller.innerRadius).toBe(128); + }); + describe('Interactions', function() { beforeEach(function() { this.chart = window.acquireChart({ From 8dd7034093cb397753671fdb9075b49ba9ecd05c Mon Sep 17 00:00:00 2001 From: Vincent-Ip Date: Fri, 22 Feb 2019 11:59:36 -0500 Subject: [PATCH 15/18] Added image tests for pie / doughnut weight feature --- .../controller.doughnut/doughnut-weight.json | 50 +++++++++++++++++ .../controller.doughnut/doughnut-weight.png | Bin 0 -> 35512 bytes .../controller.doughnut/pie-weight.json | 52 ++++++++++++++++++ .../controller.doughnut/pie-weight.png | Bin 0 -> 28314 bytes 4 files changed, 102 insertions(+) create mode 100644 test/fixtures/controller.doughnut/doughnut-weight.json create mode 100644 test/fixtures/controller.doughnut/doughnut-weight.png create mode 100644 test/fixtures/controller.doughnut/pie-weight.json create mode 100644 test/fixtures/controller.doughnut/pie-weight.png diff --git a/test/fixtures/controller.doughnut/doughnut-weight.json b/test/fixtures/controller.doughnut/doughnut-weight.json new file mode 100644 index 00000000000..769814b0ccb --- /dev/null +++ b/test/fixtures/controller.doughnut/doughnut-weight.json @@ -0,0 +1,50 @@ +{ + "config": { + "type": "doughnut", + "data": { + "datasets": [{ + "data": [ 1, 1 ], + "backgroundColor": [ + "rgba(255, 99, 132, 0.8)", + "rgba(54, 162, 235, 0.8)" + ], + "borderWidth": 0 + }, + { + "data": [ 2, 1 ], + "hidden": true, + "borderWidth": 0 + }, + { + "data": [ 3, 3 ], + "weight": 3, + "backgroundColor": [ + "rgba(255, 206, 86, 0.8)", + "rgba(75, 192, 192, 0.8)" + ], + "borderWidth": 0 + }, + { + "data": [ 4, 0 ], + "weight": 0, + "borderWidth": 0 + }, + { + "data": [ 5, 0 ], + "weight": -2, + "borderWidth": 0 + }], + "labels": [ "label0", "label1" ] + }, + "options": { + "legend": false, + "title": false + } + }, + "options": { + "canvas": { + "height": 500, + "width": 500 + } + } +} \ No newline at end of file diff --git a/test/fixtures/controller.doughnut/doughnut-weight.png b/test/fixtures/controller.doughnut/doughnut-weight.png new file mode 100644 index 0000000000000000000000000000000000000000..d6ab34c8a9af80411801c8bc1cd856413811e1e6 GIT binary patch literal 35512 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 literal 0 HcmV?d00001 diff --git a/test/fixtures/controller.doughnut/pie-weight.json b/test/fixtures/controller.doughnut/pie-weight.json new file mode 100644 index 00000000000..91d6c110ba9 --- /dev/null +++ b/test/fixtures/controller.doughnut/pie-weight.json @@ -0,0 +1,52 @@ +{ + "config": { + "type": "pie", + "data": { + "datasets": [ + { + "data": [ 1, 1 ], + "backgroundColor": [ + "rgba(255, 99, 132, 0.8)", + "rgba(54, 162, 235, 0.8)" + ], + "borderWidth": 0 + }, + { + "data": [ 2, 1 ], + "hidden": true, + "borderWidth": 0 + }, + { + "data": [ 3, 3 ], + "weight": 3, + "backgroundColor": [ + "rgba(255, 206, 86, 0.8)", + "rgba(75, 192, 192, 0.8)" + ], + "borderWidth": 0 + }, + { + "data": [ 4, 0 ], + "weight": 0, + "borderWidth": 0 + }, + { + "data": [ 5, 0 ], + "weight": -2, + "borderWidth": 0 + } + ], + "labels": [ "label0", "label1" ] + }, + "options": { + "legend": false, + "title": false + } + }, + "options": { + "canvas": { + "height": 500, + "width": 500 + } + } +} \ No newline at end of file diff --git a/test/fixtures/controller.doughnut/pie-weight.png b/test/fixtures/controller.doughnut/pie-weight.png new file mode 100644 index 0000000000000000000000000000000000000000..606ae0ebc59fe78c76af278b60b36029424024e4 GIT binary patch literal 28314 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%0A!_F%|a?ZY_F(f^&-Yv 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

!MM(KVXyqLl1E~uhg5&Z<8SsG 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 literal 0 HcmV?d00001 From 2ca836e53325d53d9043c9523f73cef7543b09aa Mon Sep 17 00:00:00 2001 From: Vincent-Ip Date: Sat, 23 Feb 2019 15:22:09 -0500 Subject: [PATCH 16/18] updated weight description in documentation --- docs/charts/doughnut.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/charts/doughnut.md b/docs/charts/doughnut.md index 4c08f0d8587..65c8767fa9f 100644 --- a/docs/charts/doughnut.md +++ b/docs/charts/doughnut.md @@ -74,7 +74,7 @@ The style of each arc can be controlled with the following properties: | `backgroundColor` | arc background color. | `borderColor` | arc border color. | `borderWidth` | arc border width (in pixels). -| `weight` | The relative thickness of the dataset. Providing a value for weight will allow the pie or doughnut dataset to be drawn with a thickness relative to the sum of all the dataset weight values. +| `weight` | The relative thickness of the dataset. Providing a value for weight will cause the pie or doughnut dataset to be drawn with a thickness relative to the sum of all the dataset weight values. All these values, if `undefined`, fallback to the associated [`elements.arc.*`](../configuration/elements.md#arc-configuration) options. From 94bbb9b98cf97ba9117e4aabf6c1f673f1af01b4 Mon Sep 17 00:00:00 2001 From: Vincent-Ip Date: Sat, 23 Feb 2019 15:26:39 -0500 Subject: [PATCH 17/18] removed unnecessary parens from new controller.doughnut.js code --- src/controllers/controller.doughnut.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/controllers/controller.doughnut.js b/src/controllers/controller.doughnut.js index 2a1e3aa9076..a6d4a63775a 100644 --- a/src/controllers/controller.doughnut.js +++ b/src/controllers/controller.doughnut.js @@ -188,8 +188,8 @@ module.exports = DatasetController.extend({ meta.total = me.calculateTotal(); - me.outerRadius = chart.outerRadius - (chart.radiusLength * me._getRingWeightOffset(me.index)); - me.innerRadius = Math.max(me.outerRadius - (chart.radiusLength * chartWeight), 0); + me.outerRadius = chart.outerRadius - chart.radiusLength * me._getRingWeightOffset(me.index); + me.innerRadius = Math.max(me.outerRadius - chart.radiusLength * chartWeight, 0); for (i = 0, ilen = arcs.length; i < ilen; ++i) { me.updateElement(arcs[i], i, reset); From 619f66723059b0666fa27f820bc6a5543a72a5cf Mon Sep 17 00:00:00 2001 From: Vincent-Ip Date: Wed, 27 Feb 2019 15:28:58 -0500 Subject: [PATCH 18/18] removed pixel based testing for doughnut weight --- test/specs/controller.doughnut.tests.js | 77 ------------------------- 1 file changed, 77 deletions(-) diff --git a/test/specs/controller.doughnut.tests.js b/test/specs/controller.doughnut.tests.js index f991dd94f6c..2a4ae8f43c3 100644 --- a/test/specs/controller.doughnut.tests.js +++ b/test/specs/controller.doughnut.tests.js @@ -325,83 +325,6 @@ describe('Chart.controllers.doughnut', function() { expect(controller.innerRadius).toBe(126); }); - it('should create arcs with widths based on the weight value of the dataset', function() { - var chart = window.acquireChart({ - type: 'doughnut', - data: { - datasets: [{ - // default weight of 1 - data: [1, 1], - borderWidth: 0 - }, { - // default weight of 1 but hidden - data: [2, 1], - hidden: true, - borderWidth: 0 - }, { - // explicit weight of 3 - data: [3, 3], - weight: 3, - borderWidth: 0 - }, { - // explicit weight of 0 - data: [4, 0], - weight: 0, - borderWidth: 0 - }, { - // explicit weight of -2 (treated as 0) - data: [5, 0], - weight: -2, - borderWidth: 0 - }], - labels: ['label0', 'label1'] - }, - options: { - legend: false, - title: false - } - }); - - chart.update(); - - expect(chart.radiusLength).toBe(32); - - var controller = chart.getDatasetMeta(0).controller; - expect(controller._getVisibleDatasetWeightTotal()).toBe(4); - expect(controller._getRingWeight(controller.index)).toBe(1); - expect(controller._getRingWeightOffset(controller.index)).toBe(0); - expect(controller.outerRadius).toBe(256); - expect(controller.innerRadius).toBe(224); - - controller = chart.getDatasetMeta(1).controller; - expect(controller._getVisibleDatasetWeightTotal()).toBe(4); - expect(controller._getRingWeight(controller.index)).toBe(1); - expect(controller._getRingWeightOffset(controller.index)).toBe(1); - expect(controller.outerRadius).toBe(224); - expect(controller.innerRadius).toBe(192); - - controller = chart.getDatasetMeta(2).controller; - expect(controller._getVisibleDatasetWeightTotal()).toBe(4); - expect(controller._getRingWeight(controller.index)).toBe(3); - expect(controller._getRingWeightOffset(controller.index)).toBe(1); - expect(controller.outerRadius).toBe(224); - expect(controller.innerRadius).toBe(128); - - controller = chart.getDatasetMeta(3).controller; - expect(controller._getVisibleDatasetWeightTotal()).toBe(4); - expect(controller._getRingWeight(controller.index)).toBe(0); - expect(controller._getRingWeightOffset(controller.index)).toBe(4); - expect(controller.outerRadius).toBe(128); - expect(controller.innerRadius).toBe(128); - - controller = chart.getDatasetMeta(4).controller; - expect(controller._getVisibleDatasetWeightTotal()).toBe(4); - expect(controller._getRingWeight(controller.index)).toBe(0); - expect(controller._getRingWeightOffset(controller.index)).toBe(4); - expect(controller.outerRadius).toBe(128); - expect(controller.innerRadius).toBe(128); - }); - describe('Interactions', function() { beforeEach(function() { this.chart = window.acquireChart({