From 7d8526f691c13d065fbf24f574b2cb628ed57c91 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 02f080614..328b1df0e 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 0736cf6e1..aa8b06a2c 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 cf1fb281e..7fccd4d4a 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 a2199b66e..c9ce8709d 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 fd67f0b19..3e9b2849f 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 000000000..c54dea9ce --- /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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 Z)As(2mm=_EyK1#%#tK%%KLJw3<)Z)q literal 0 Hc-jL100001 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 000000000..8322ef472 --- /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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 T9PdakfPcL8&g-t&^AG(4ZU`=W literal 0 Hc-jL100001 diff --git a/test/fixtures/controller.bar/floatBar/float-bar-stacked.json b/test/fixtures/controller.bar/floatBar/float-bar-stacked.json new file mode 100644 index 000000000..d91b61f1b --- /dev/null +++ b/test/fixtures/controller.bar/floatBar/float-bar-stacked.json @@ -0,0 +1,43 @@ +{ + "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, + "stacked": true, + "ticks": { + "min": -8, + "max": 12 + } + }], + "yAxes": [{ + "display": false, + "stacked": true + }] + } + } + }, + "debug": false, + "options": { + "canvas": { + "height": 256, + "width": 512 + } + } +} diff --git a/test/fixtures/controller.bar/floatBar/float-bar-stacked.png b/test/fixtures/controller.bar/floatBar/float-bar-stacked.png new file mode 100644 index 0000000000000000000000000000000000000000..c9c02ea2f7b4136a9107bebc0b3512fcce66731a GIT binary patch literal 5396 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 literal 0 Hc-jL100001 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 000000000..caeaa2396 --- /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 zc-rk(dr(v7693L2iAfNO5P=qvs1*=YpjaY`dY}ksON`cAyr>wT1uG9JAQ*&0)!x>E z;#ErlHK{LX@c{)yfk0?^6j5HWf+!@mg@C+LLLexQZbH4cOlR)Q{iF9WV`ehv%=v!1 z`|W<;{&x3M9@pD|`5F@;WU$7^a|1#+ykdw>gGWVj?fVEBFI?m4zA-wWx79r>!28u{ z$`2balrN?*j_%6Hx_;yVt05NOKPU6n-s#5QbLh4opFT|)rG9(2dvxNi0in zZ7ru+6C}cLiZxX-pRIdkP+8=WFD+8FU+K1}PxmzPu@#}$r?-BulO?dQX_GoUFe-a{ zr`MzsCb@i4nK9EAG2Y_5p_AmH$GRswnMYtg=7lF2T1m-MJbTOS$f#v*OPh`;pL9J} zwPwAN))V}$4r)a34`H`rRnM0Aa?;Faam_j&HTAvu@X-~Wc{WMnMr_Y{T0JOX14b2X zysLV-@^aMJkGS9Fx#g5>qt6u~3M0JViA9PldcDC$Fz`e03Td$~=3|oY&M>0e0m5MDQq=~; z^>2O-*&X%`&XiO?`}j~1Zsg*Bcm_M!6Efd;@WD+uB5Xflpw{{qnKQnzbAUeGWtke2f zj^PEAcqT<^%qHY2Ed}MQC9q8uduD)@!WleN`00+Thi%c$_VzpwQW}uUvp*&AY{tbD zh><9j3`J=TC&W3pV^kb>9k3TwV!3I)2wmNg`w19r1*5H=P7mB!WX?diKai7VIqH*G zgM-$I0Ui*JJ$MNg=(TF7k|}8(aa{pcS?B=&4461}Z!X{?=7~^*NyVmV>rv&Mnji>| zydT}tO9#d2jt3clPh)6kqF2Y7E$q=wg<^1$G86s+ChS~3gOjXJBJp}()=o=L%-r4~ zV?IHWrFwG1eRJ#I#x#|oD>WTo1>G*L<{fo#J=?KOJob}wyxo?L{W!(NSg9yAY~-NG zxFEmb4d{HSs!U&1{5W_<`8RjXWW^C3XG{f;PN9UL0Yzz_sjUuYkEEB-CGj||9}X>3 z-vi53yC70qWdG4w_ZcGD9E9-tO$bq^aA`x8?V2ISY%#`Os)-E zLLNH>`1`*(y9mRQyl&E}M1lt>>^~3RJe)jKeukSL7?Jk%Yz4KlC*z>GK zA8CF}DNz=z8t<%`2+S#1!7x(F@Jz8D+(CY$TFfFZjaFI{{0(TYLjumT{~|(+CohTK zY0~Ky&v%z-Ixaik*jW5+BOBzC*-1{PwHr^tc~3IXMmcr! z*NCEjf9YG=EjTSeGvk;9H6Z&klgK8LoR4Usr~Z$iQYBSBdTzMXxlVO&*~gJtDZ6hE zJ-D19(?qKWYAZ6XoLCvVr#0QqZ_%{=TE#ZOje$j<`_UJMPRP5ZgXO)){H|_0_*9vq z$}JVdjOkx}-SG-pH*sR(N$$8RUW3=yhqro?M_*M0r$22H?Q zz$tn7#kg^MWU=+(dIyQuPXYsAiAHAPvymHUU&L;2F|tVNe^c9(**iW}l;YV9XDrqD zz9l71TH3$%n?k>+{}qMttFc?^)*#o>fb??VXvJu^a4i2`+X-3ZNX>Am%b22C=;A8< zs$D(u&@W!LD>U7hoy_HrR9{nE338R~QrdJhDN^Fchph!xIYEVZy-7)~u7ixjYueMB zGJ*|dh^g)%Du=5X8 zErWd@F$R%D={gjLH~&)j@EAB2hbv7aClB!dC^uw63ekf$%WiG64h6T_iMtBZF!)v7 zd+fDEk|ELRQM&5p0jCl?ApN2c?fALBA6*?Y;e%iIsI{_~iRCIc*}nbByZ?G!9NE>y zS=lCtQT+I>)Z1#M^v7A!aAjZYc>eIvW5Mn4?w*L~u#mbH69rA*Nrx3hepX8!KL5nm zdyL_Ob#|G$>SOq7yiPVEKN=IzXS%4R^U3a1hmx4CyY?31+7D=^JVZ0BYhW0eze`}| z&IN%P@1YCx_s)hM!3=tY6SfuDOp@hf@pqJP9w_sC)8L4rKzkIe;2bVD)boSj~*hEC2wgKQBR zO#aAOLz7r)Z*eW0SFQY}%0M?fCCmovvp0m%WY8l_wsBuVU383?XQG?Vs5+tl*px=< zTuS!h|8@Y^t0k|jlL`9+4%KV(G&&Ig{*!>;hPCOjOSgUzx~-^5yFRJ(4amY&Dd)L@ z8mlMgYSDzQbv!Xggl6eg&!f=G!TgS&1CIrR^TD&kM^OR>ZX|qE6uQ_=E{c6bR%;Jn>qV+@5jFIC8@;=@)^$0 z--bUic`w3DaS9ij)urnL9IV~}>_W$?`2=4K{a#z`ooJ|y#qaofl9Cw^=PY+Q+#R{g zOPBxKE+@3#xt1$^Qg+)~>gIMRzC@sQKP3)cD|f