From 0470ce1a04fd4ec3dd4cad581523dfc939f44f28 Mon Sep 17 00:00:00 2001 From: gwyneblaidd Date: Tue, 21 May 2019 11:54:13 +0300 Subject: [PATCH] Add support for floating bar chart ([start, end]) (#6056) --- docs/charts/bar.md | 5 ++ src/controllers/controller.bar.js | 24 ++++++---- src/core/core.scale.js | 40 ++++++++++++++++ src/scales/scale.linear.js | 34 +++++++------- src/scales/scale.logarithmic.js | 28 +++++------- .../floatBar/float-bar-horizontal.json | 41 +++++++++++++++++ .../floatBar/float-bar-horizontal.png | Bin 0 -> 4774 bytes .../float-bar-stacked-horizontal.json | 43 ++++++++++++++++++ .../floatBar/float-bar-stacked-horizontal.png | Bin 0 -> 5070 bytes .../floatBar/float-bar-stacked.json | 43 ++++++++++++++++++ .../floatBar/float-bar-stacked.png | Bin 0 -> 5396 bytes .../controller.bar/floatBar/float-bar.json | 41 +++++++++++++++++ .../controller.bar/floatBar/float-bar.png | Bin 0 -> 4709 bytes 13 files changed, 259 insertions(+), 40 deletions(-) create mode 100644 test/fixtures/controller.bar/floatBar/float-bar-horizontal.json create mode 100644 test/fixtures/controller.bar/floatBar/float-bar-horizontal.png create mode 100644 test/fixtures/controller.bar/floatBar/float-bar-stacked-horizontal.json create mode 100644 test/fixtures/controller.bar/floatBar/float-bar-stacked-horizontal.png create mode 100644 test/fixtures/controller.bar/floatBar/float-bar-stacked.json create mode 100644 test/fixtures/controller.bar/floatBar/float-bar-stacked.png create mode 100644 test/fixtures/controller.bar/floatBar/float-bar.json create mode 100644 test/fixtures/controller.bar/floatBar/float-bar.png diff --git a/docs/charts/bar.md b/docs/charts/bar.md index 02f080614a1..328b1df0e19 100644 --- a/docs/charts/bar.md +++ b/docs/charts/bar.md @@ -213,6 +213,11 @@ You can also specify the dataset as x/y coordinates when using the [time scale]( data: [{x:'2016-12-25', y:20}, {x:'2016-12-26', y:10}] ``` +You can also specify the dataset for a bar chart as arrays of two numbers. This will force rendering of bars with gaps between them (floating-bars). First and second numbers in array will correspond the start and the end point of a bar respectively. +```javascript +data: [[5,6], [-3,-6]] +``` + ## Stacked Bar Chart Bar charts can be configured into stacked bar charts by changing the settings on the X and Y axes to enable stacking. Stacked bar charts can be used to show how one data series is made up of a number of smaller pieces. diff --git a/src/controllers/controller.bar.js b/src/controllers/controller.bar.js index 0736cf6e1e0..aa8b06a2cbc 100644 --- a/src/controllers/controller.bar.js +++ b/src/controllers/controller.bar.js @@ -170,6 +170,10 @@ module.exports = DatasetController.extend({ label: me.chart.data.labels[index] }; + if (helpers.isArray(dataset.data[index])) { + rectangle._model.borderSkipped = null; + } + me._updateElementGeometry(rectangle, index, reset); rectangle.pivot(); @@ -293,12 +297,13 @@ module.exports = DatasetController.extend({ var scale = me._getValueScale(); var isHorizontal = scale.isHorizontal(); var datasets = chart.data.datasets; - var value = +scale.getRightValue(datasets[datasetIndex].data[index]); + var value = scale._parseValue(datasets[datasetIndex].data[index]); var minBarLength = scale.options.minBarLength; var stacked = scale.options.stacked; var stack = meta.stack; - var start = 0; - var i, imeta, ivalue, base, head, size; + var start = value.start === undefined ? 0 : value.max >= 0 && value.min >= 0 ? value.min : value.max; + var length = value.start === undefined ? value.end : value.max >= 0 && value.min >= 0 ? value.max - value.min : value.min - value.max; + var i, imeta, ivalue, base, head, size, stackLength; if (stacked || (stacked === undefined && stack !== undefined)) { for (i = 0; i < datasetIndex; ++i) { @@ -309,8 +314,10 @@ module.exports = DatasetController.extend({ imeta.controller._getValueScaleId() === scale.id && chart.isDatasetVisible(i)) { - ivalue = +scale.getRightValue(datasets[i].data[index]); - if ((value < 0 && ivalue < 0) || (value >= 0 && ivalue > 0)) { + stackLength = scale._parseValue(datasets[i].data[index]); + ivalue = stackLength.start === undefined ? stackLength.end : stackLength.min >= 0 && stackLength.max >= 0 ? stackLength.max : stackLength.min; + + if ((value.min < 0 && ivalue < 0) || (value.max >= 0 && ivalue > 0)) { start += ivalue; } } @@ -318,12 +325,12 @@ module.exports = DatasetController.extend({ } base = scale.getPixelForValue(start); - head = scale.getPixelForValue(start + value); + head = scale.getPixelForValue(start + length); size = head - base; if (minBarLength !== undefined && Math.abs(size) < minBarLength) { size = minBarLength; - if (value >= 0 && !isHorizontal || value < 0 && isHorizontal) { + if (length >= 0 && !isHorizontal || length < 0 && isHorizontal) { head = base - minBarLength; } else { head = base + minBarLength; @@ -374,7 +381,8 @@ module.exports = DatasetController.extend({ helpers.canvas.clipArea(chart.ctx, chart.chartArea); for (; i < ilen; ++i) { - if (!isNaN(scale.getRightValue(dataset.data[i]))) { + var val = scale._parseValue(dataset.data[i]); + if (!isNaN(val.min) && !isNaN(val.max)) { rects[i].draw(); } } diff --git a/src/core/core.scale.js b/src/core/core.scale.js index cf1fb281e88..7fccd4d4a15 100644 --- a/src/core/core.scale.js +++ b/src/core/core.scale.js @@ -586,6 +586,7 @@ var Scale = Element.extend({ if ((typeof rawValue === 'number' || rawValue instanceof Number) && !isFinite(rawValue)) { return NaN; } + // If it is in fact an object, dive in one more level if (rawValue) { if (this.isHorizontal()) { @@ -601,6 +602,45 @@ var Scale = Element.extend({ return rawValue; }, + /** + * @private + */ + _parseValue: function(value) { + var start, end, min, max; + + if (helpers.isArray(value)) { + start = +this.getRightValue(value[0]); + end = +this.getRightValue(value[1]); + min = Math.min(start, end); + max = Math.max(start, end); + } else { + value = +this.getRightValue(value); + start = undefined; + end = value; + min = value; + max = value; + } + + return { + min: min, + max: max, + start: start, + end: end + }; + }, + + /** + * @private + */ + _getScaleLabel: function(rawValue) { + var v = this._parseValue(rawValue); + if (v.start !== undefined) { + return '[' + v.start + ', ' + v.end + ']'; + } + + return +this.getRightValue(rawValue); + }, + /** * Used to get the value to display in the tooltip for the data at the given index * @param index diff --git a/src/scales/scale.linear.js b/src/scales/scale.linear.js index a2199b66e78..c9ce8709ded 100644 --- a/src/scales/scale.linear.js +++ b/src/scales/scale.linear.js @@ -70,20 +70,25 @@ module.exports = LinearScaleBase.extend({ if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) { helpers.each(dataset.data, function(rawValue, index) { - var value = +me.getRightValue(rawValue); - if (isNaN(value) || meta.data[index].hidden) { + var value = me._parseValue(rawValue); + + if (isNaN(value.min) || isNaN(value.max) || meta.data[index].hidden) { return; } positiveValues[index] = positiveValues[index] || 0; negativeValues[index] = negativeValues[index] || 0; + if (value.min === 0 && !opts.ticks.beginAtZero) { + value.min = value.max; + } + if (opts.relativePoints) { positiveValues[index] = 100; - } else if (value < 0) { - negativeValues[index] += value; + } else if (value.min < 0 || value.max < 0) { + negativeValues[index] += value.min; } else { - positiveValues[index] += value; + positiveValues[index] += value.max; } }); } @@ -102,21 +107,18 @@ module.exports = LinearScaleBase.extend({ var meta = chart.getDatasetMeta(datasetIndex); if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) { helpers.each(dataset.data, function(rawValue, index) { - var value = +me.getRightValue(rawValue); - if (isNaN(value) || meta.data[index].hidden) { + var value = me._parseValue(rawValue); + + if (isNaN(value.min) || isNaN(value.max) || meta.data[index].hidden) { return; } - if (me.min === null) { - me.min = value; - } else if (value < me.min) { - me.min = value; + if (me.min === null || value.min < me.min) { + me.min = value.min; } - if (me.max === null) { - me.max = value; - } else if (value > me.max) { - me.max = value; + if (me.max === null || me.max < value.max) { + me.max = value.max; } }); } @@ -151,7 +153,7 @@ module.exports = LinearScaleBase.extend({ }, getLabelForIndex: function(index, datasetIndex) { - return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]); + return this._getScaleLabel(this.chart.data.datasets[datasetIndex].data[index]); }, // Utils diff --git a/src/scales/scale.logarithmic.js b/src/scales/scale.logarithmic.js index fd67f0b19a4..3e9b2849f0b 100644 --- a/src/scales/scale.logarithmic.js +++ b/src/scales/scale.logarithmic.js @@ -118,13 +118,13 @@ module.exports = Scale.extend({ helpers.each(dataset.data, function(rawValue, index) { var values = valuesPerStack[key]; - var value = +me.getRightValue(rawValue); + var value = me._parseValue(rawValue); // invalid, hidden and negative values are ignored - if (isNaN(value) || meta.data[index].hidden || value < 0) { + if (isNaN(value.min) || isNaN(value.max) || meta.data[index].hidden || value.min < 0 || value.max < 0) { return; } values[index] = values[index] || 0; - values[index] += value; + values[index] += value.max; }); } }); @@ -143,26 +143,22 @@ module.exports = Scale.extend({ var meta = chart.getDatasetMeta(datasetIndex); if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) { helpers.each(dataset.data, function(rawValue, index) { - var value = +me.getRightValue(rawValue); + var value = me._parseValue(rawValue); // invalid, hidden and negative values are ignored - if (isNaN(value) || meta.data[index].hidden || value < 0) { + if (isNaN(value.min) || isNaN(value.max) || meta.data[index].hidden || value.min < 0 || value.max < 0) { return; } - if (me.min === null) { - me.min = value; - } else if (value < me.min) { - me.min = value; + if (me.min === null || value.min < me.min) { + me.min = value.min; } - if (me.max === null) { - me.max = value; - } else if (value > me.max) { - me.max = value; + if (me.max === null || me.max < value.max) { + me.max = value.max; } - if (value !== 0 && (me.minNotZero === null || value < me.minNotZero)) { - me.minNotZero = value; + if (value.min !== 0 && (me.minNotZero === null || value.min < me.minNotZero)) { + me.minNotZero = value.min; } }); } @@ -247,7 +243,7 @@ module.exports = Scale.extend({ // Get the correct tooltip label getLabelForIndex: function(index, datasetIndex) { - return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]); + return this._getScaleLabel(this.chart.data.datasets[datasetIndex].data[index]); }, getPixelForTick: function(index) { diff --git a/test/fixtures/controller.bar/floatBar/float-bar-horizontal.json b/test/fixtures/controller.bar/floatBar/float-bar-horizontal.json new file mode 100644 index 00000000000..c54dea9ce96 --- /dev/null +++ b/test/fixtures/controller.bar/floatBar/float-bar-horizontal.json @@ -0,0 +1,41 @@ +{ + "config": { + "type": "horizontalBar", + "data": { + "labels": ["2030", "2034", "2038", "2042"], + "datasets": [{ + "backgroundColor": "#FF6384", + "data": [11, [6,2], [-4,-7], -2] + }, { + "backgroundColor": "#36A2EB", + "data": [[1,2], [3,4], [-2,-3], [1,4]] + }, { + "backgroundColor": "#FFCE56", + "data": [[0,1], [1,2], [-2,-1], [1,-7]] + }] + }, + "options": { + "title": false, + "legend": false, + "scales": { + "xAxes": [{ + "display": false, + "ticks": { + "min": -8, + "max": 12 + } + }], + "yAxes": [{ + "display": false + }] + } + } + }, + "debug": false, + "options": { + "canvas": { + "height": 256, + "width": 512 + } + } +} diff --git a/test/fixtures/controller.bar/floatBar/float-bar-horizontal.png b/test/fixtures/controller.bar/floatBar/float-bar-horizontal.png new file mode 100644 index 0000000000000000000000000000000000000000..3293dc8877fa3bf83c97b3fb307ff7ada271f8a8 GIT binary patch literal 4774 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 LyWS#wH7nwuQpM$? literal 0 HcmV?d00001 diff --git a/test/fixtures/controller.bar/floatBar/float-bar-stacked-horizontal.json b/test/fixtures/controller.bar/floatBar/float-bar-stacked-horizontal.json new file mode 100644 index 00000000000..8322ef472e4 --- /dev/null +++ b/test/fixtures/controller.bar/floatBar/float-bar-stacked-horizontal.json @@ -0,0 +1,43 @@ +{ + "config": { + "type": "horizontalBar", + "data": { + "labels": ["2030", "2034", "2038", "2042"], + "datasets": [{ + "backgroundColor": "#FF6384", + "data": [11, [6,2], [-4,-7], -2] + }, { + "backgroundColor": "#36A2EB", + "data": [[1,2], [3,4], [-2,-3], [1,4]] + }, { + "backgroundColor": "#FFCE56", + "data": [[0,1], [1,2], [-2,-1], [1,-7]] + }] + }, + "options": { + "title": false, + "legend": false, + "scales": { + "xAxes": [{ + "display": false, + "stacked": true + }], + "yAxes": [{ + "display": false, + "stacked": true, + "ticks": { + "min": -8, + "max": 12 + } + }] + } + } + }, + "debug": false, + "options": { + "canvas": { + "height": 256, + "width": 512 + } + } +} diff --git a/test/fixtures/controller.bar/floatBar/float-bar-stacked-horizontal.png b/test/fixtures/controller.bar/floatBar/float-bar-stacked-horizontal.png new file mode 100644 index 0000000000000000000000000000000000000000..5df57310985aac9a184543beed66eb856ac5c229 GIT binary patch literal 5070 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 OTDR8Gy1>dS=HCF`JO$wZ literal 0 HcmV?d00001 diff --git a/test/fixtures/controller.bar/floatBar/float-bar.json b/test/fixtures/controller.bar/floatBar/float-bar.json new file mode 100644 index 00000000000..caeaa239668 --- /dev/null +++ b/test/fixtures/controller.bar/floatBar/float-bar.json @@ -0,0 +1,41 @@ +{ + "config": { + "type": "bar", + "data": { + "labels": ["2030", "2034", "2038", "2042"], + "datasets": [{ + "backgroundColor": "#FF6384", + "data": [11, [6,2], [-4,-7], -2] + }, { + "backgroundColor": "#36A2EB", + "data": [[1,2], [3,4], [-2,-3], [1,4]] + }, { + "backgroundColor": "#FFCE56", + "data": [[0,1], [1,2], [-2,-1], [1,-7]] + }] + }, + "options": { + "title": false, + "legend": false, + "scales": { + "xAxes": [{ + "display": false, + "ticks": { + "min": -8, + "max": 12 + } + }], + "yAxes": [{ + "display": false + }] + } + } + }, + "debug": false, + "options": { + "canvas": { + "height": 256, + "width": 512 + } + } +} diff --git a/test/fixtures/controller.bar/floatBar/float-bar.png b/test/fixtures/controller.bar/floatBar/float-bar.png new file mode 100644 index 0000000000000000000000000000000000000000..eaff55a63edde02a5bae1a65096b81025f1d94b8 GIT binary patch literal 4709 zcmeHLc~Dd57XR)giAfL|Ap$KTQ7a&*K(Ry=^+FNQmWb9@e5e@Lf|W%I2nOL&wXe0H z@u{VNn$!(iT%dp`5C|S{S z@0^p*eR*C6%r}?_A%j)k9_tXo;Soc08XV=qnhy~&n!n1!ZGCh=Pm5b-fY<9&R3A5- zD_clm9Nv+hdG*jec6}_qcUH!Y-BXQzH)taA`t3ha_fLUo6Ihcl&BPd+_Rh_jsi4^HC869onu`4uF;bnF)Ub5w^}>02tOKk$9aCd%J}P zW@cxfK9?ZL5 zY~Z5ExFElwb?9t~x>R3X^e}i@*>|^1K-F?UyfjqVO#+&yeUr4)Pl`5;l2Zq{52euS2`-6L4R8Wg$pxp_h7xr-BCvX0EHH$P3hWE|1lVZal=WE&@VfM%@=?hDg|&ifA< z>k|8gW!~nJQid*xUike&QmbMjw_muu!80^$B3WN}{a>r~gDEl<_u?BQNz#6$Wt_mD zH@Y<~|5WkLn7whmKP9jBi#aRpz?YAA8LdaQBVX<;*0x`Cy0*UP`vwlgOvp)cJgHMW z8TWmZj@B!v8^1*q{kx0b(FNXd9-1DqqpM|$G_h*YMcDn`x>l{nR^ z?=1N=GBbJS&B1#Y)8*P|O@B>!`lVybV|TTr+4?P*(pRJ0BDmJS;7dRH{Lpblmu#S{ z=ZN3sE&CszXt}G|rTI z4(+(BpH;67cn2^g7e602W{1o--(PDl_54L(04UMGOnfqY4eg28=_NttNquhvPI%in zJXV(AS@owZH29uH#f<=IoGZ^5`bGV(FpOV`-O#iIxr_v)m5D~mN4i9#d3Rcm$s>oW zhf17Bl~p2V7uh#$n&JC?@$wy^X+|6&k3U>>MR_U6MZQC2-QK87jvpJc5?E#j72tKo z#W@obWE@`Ime!aaRFEw{Dr)WwD{zn(M_sFGWfE(;YXF)tT%d1*MAL^1q^;b#IPe#z z4lvCZrEYQs8888F!~kFd1$sR^9kmZ2H&t9!o-+^JP0xi6#U`(F>w5pHiwQi+ccYb3 zozN32_8)bFz+cDDj}UR9So{=4PUF_Qc!xEz+yi78 zY%`4|`lwO|*m?UZmw>^CjNnS5Yz>OTn|>>}e*`=dhpUXG$M^C7d~eX06rp>q7G0nO z3mR^dBX0$!W$-JzcG&?hEdvk|Zo5qE1CGUbK-zf`+V*Q-AG$nh%m=&fP;2Bd<4e`9 z@;!TnJO6%F64}|wUEV5)QU3hC%*%4Q?B^M>a8+;YSl-a!L&44PuI`BFu#nniad3bdv38{!f%}7W&lLh93ncR8Hui zl{Fzg4(*rTdR+v4ZWA4h>z*%0-BUvfD`Cr7NP`eX0rx0c{ux|hsGBLKKm+>+`*bOH za(8!A<4Now{4Ab{xlTl2>!^CHXyr|@7{UA#8H-ts-5o$pXNm*7ia-fOM7 z6%Dko?og`T)Tj1td?WD|w?hjIO{ czcfyj4V=xByuQQ|{ysvhR`NWqy7NEz9muh;rT_o{ literal 0 HcmV?d00001