From 026482a0cf2e6141f69e75d16ee4db587c398f86 Mon Sep 17 00:00:00 2001 From: Jukka Kurkela Date: Wed, 10 Jun 2020 00:15:05 +0300 Subject: [PATCH] Correctly determine min/max for Float Bar (#7398) --- src/controllers/controller.bar.js | 13 ++++++++ src/core/core.datasetController.js | 50 +++++++++++++++++------------- src/core/core.scale.js | 8 ++--- src/scales/scale.linear.js | 4 +-- src/scales/scale.logarithmic.js | 4 +-- src/scales/scale.radialLinear.js | 4 +-- test/specs/controller.bar.tests.js | 16 ++++++++++ 7 files changed, 64 insertions(+), 35 deletions(-) diff --git a/src/controllers/controller.bar.js b/src/controllers/controller.bar.js index 0b21e96b3..d7acc836b 100644 --- a/src/controllers/controller.bar.js +++ b/src/controllers/controller.bar.js @@ -220,6 +220,19 @@ export default class BarController extends DatasetController { return parsed; } + /** + * @protected + */ + updateRangeFromParsed(range, scale, parsed, stack) { + super.updateRangeFromParsed(range, scale, parsed, stack); + const custom = parsed._custom; + if (custom) { + // float bar: only one end of the bar is considered by `super` + range.min = Math.min(range.min, custom.min); + range.max = Math.max(range.max, custom.max); + } + } + /** * @protected */ diff --git a/src/core/core.datasetController.js b/src/core/core.datasetController.js index 48b2c7968..1f16ec89b 100644 --- a/src/core/core.datasetController.js +++ b/src/core/core.datasetController.js @@ -584,35 +584,39 @@ export default class DatasetController { return applyStack(stack, value, meta.index); } + /** + * @protected + */ + updateRangeFromParsed(range, scale, parsed, stack) { + let value = parsed[scale.axis]; + const values = stack && parsed._stacks[scale.axis]; + if (stack && values) { + stack.values = values; + // Need to consider individual stack values for data range, + // in addition to the stacked value + range.min = Math.min(range.min, value); + range.max = Math.max(range.max, value); + value = applyStack(stack, value, this._cachedMeta.index, true); + } + range.min = Math.min(range.min, value); + range.max = Math.max(range.max, value); + } + /** * @protected */ getMinMax(scale, canStack) { - const meta = this._cachedMeta; + const me = this; + const meta = me._cachedMeta; const _parsed = meta._parsed; const sorted = meta._sorted && scale === meta.iScale; const ilen = _parsed.length; - const otherScale = this._getOtherScale(scale); - const stack = canStack && meta._stacked && {keys: getSortedDatasetIndices(this.chart, true), values: null}; - let min = Number.POSITIVE_INFINITY; - let max = Number.NEGATIVE_INFINITY; + const otherScale = me._getOtherScale(scale); + const stack = canStack && meta._stacked && {keys: getSortedDatasetIndices(me.chart, true), values: null}; + const range = {min: Number.POSITIVE_INFINITY, max: Number.NEGATIVE_INFINITY}; const {min: otherMin, max: otherMax} = getUserBounds(otherScale); let i, value, parsed, otherValue; - function _compute() { - const values = stack && parsed._stacks[scale.axis]; - if (stack && values) { - stack.values = values; - // Need to consider individual stack values for data range, - // in addition to the stacked value - min = Math.min(min, value); - max = Math.max(max, value); - value = applyStack(stack, value, meta.index, true); - } - min = Math.min(min, value); - max = Math.max(max, value); - } - function _skip() { parsed = _parsed[i]; value = parsed[scale.axis]; @@ -624,21 +628,23 @@ export default class DatasetController { if (_skip()) { continue; } - _compute(); + me.updateRangeFromParsed(range, scale, parsed, stack); if (sorted) { + // if the data is sorted, we don't need to check further from this end of array break; } } if (sorted) { + // in the sorted case, find first non-skipped value from other end of array for (i = ilen - 1; i >= 0; --i) { if (_skip()) { continue; } - _compute(); + me.updateRangeFromParsed(range, scale, parsed, stack); break; } } - return {min, max}; + return range; } getAllParsedValues(scale) { diff --git a/src/core/core.scale.js b/src/core/core.scale.js index 7f8a0d5aa..5e3640856 100644 --- a/src/core/core.scale.js +++ b/src/core/core.scale.js @@ -411,7 +411,7 @@ export default class Scale extends Element { const me = this; // eslint-disable-next-line prefer-const let {min, max, minDefined, maxDefined} = me.getUserBounds(); - let minmax; + let range; if (minDefined && maxDefined) { return {min, max}; @@ -419,12 +419,12 @@ export default class Scale extends Element { const metas = me.getMatchingVisibleMetas(); for (let i = 0, ilen = metas.length; i < ilen; ++i) { - minmax = metas[i].controller.getMinMax(me, canStack); + range = metas[i].controller.getMinMax(me, canStack); if (!minDefined) { - min = Math.min(min, minmax.min); + min = Math.min(min, range.min); } if (!maxDefined) { - max = Math.max(max, minmax.max); + max = Math.max(max, range.max); } } diff --git a/src/scales/scale.linear.js b/src/scales/scale.linear.js index f6392e5e6..de3ec340a 100644 --- a/src/scales/scale.linear.js +++ b/src/scales/scale.linear.js @@ -13,9 +13,7 @@ class LinearScale extends LinearScaleBase { determineDataLimits() { const me = this; const options = me.options; - const minmax = me.getMinMax(true); - const min = minmax.min; - const max = minmax.max; + const {min, max} = me.getMinMax(true); me.min = isFinite(min) ? min : valueOrDefault(options.suggestedMin, 0); me.max = isFinite(max) ? max : valueOrDefault(options.suggestedMax, 1); diff --git a/src/scales/scale.logarithmic.js b/src/scales/scale.logarithmic.js index 7efc88ceb..e0cce4182 100644 --- a/src/scales/scale.logarithmic.js +++ b/src/scales/scale.logarithmic.js @@ -81,9 +81,7 @@ class LogarithmicScale extends Scale { determineDataLimits() { const me = this; - const minmax = me.getMinMax(true); - const min = minmax.min; - const max = minmax.max; + const {min, max} = me.getMinMax(true); me.min = isFinite(min) ? Math.max(0, min) : null; me.max = isFinite(max) ? Math.max(0, max) : null; diff --git a/src/scales/scale.radialLinear.js b/src/scales/scale.radialLinear.js index 0273394f8..bb1497295 100644 --- a/src/scales/scale.radialLinear.js +++ b/src/scales/scale.radialLinear.js @@ -323,9 +323,7 @@ class RadialLinearScale extends LinearScaleBase { determineDataLimits() { const me = this; - const minmax = me.getMinMax(false); - const min = minmax.min; - const max = minmax.max; + const {min, max} = me.getMinMax(false); me.min = isFinite(min) && !isNaN(min) ? min : 0; me.max = isFinite(max) && !isNaN(max) ? max : 0; diff --git a/test/specs/controller.bar.tests.js b/test/specs/controller.bar.tests.js index 7ea64528f..c1a8f9bb8 100644 --- a/test/specs/controller.bar.tests.js +++ b/test/specs/controller.bar.tests.js @@ -1629,4 +1629,20 @@ describe('Chart.controllers.bar', function() { expect(data[0].base + minBarLength).toEqual(data[0].x); expect(data[1].base - minBarLength).toEqual(data[1].x); }); + + describe('Float bar', function() { + it('Should return correct values from getMinMax', function() { + var chart = window.acquireChart({ + type: 'bar', + data: { + labels: ['a'], + datasets: [{ + data: [[10, -10]] + }] + } + }); + + expect(chart.scales.y.getMinMax()).toEqual({min: -10, max: 10}); + }); + }); }); -- 2.47.2