From: Kit PANG Date: Wed, 23 Nov 2022 01:21:02 +0000 (+0800) Subject: fix: respect minBarLength in stacked bar chart (#10766) X-Git-Tag: v4.1.0~18 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=667b28beca55606a76d6fe724d83eede8a1355e4;p=thirdparty%2FChart.js.git fix: respect minBarLength in stacked bar chart (#10766) --- diff --git a/src/controllers/controller.bar.js b/src/controllers/controller.bar.js index 20e053cc0..1221b64c3 100644 --- a/src/controllers/controller.bar.js +++ b/src/controllers/controller.bar.js @@ -538,7 +538,7 @@ export default class BarController extends DatasetController { * @private */ _calculateBarValuePixels(index) { - const {_cachedMeta: {vScale, _stacked}, options: {base: baseValue, minBarLength}} = this; + const {_cachedMeta: {vScale, _stacked, index: datasetIndex}, options: {base: baseValue, minBarLength}} = this; const actualBase = baseValue || 0; const parsed = this.getParsed(index); const custom = parsed._custom; @@ -586,6 +586,11 @@ export default class BarController extends DatasetController { const max = Math.max(startPixel, endPixel); base = Math.max(Math.min(base, max), min); head = base + size; + + if (_stacked && !floating) { + // visual data coordinates after applying minBarLength + parsed._stacks[vScale.axis]._visualValues[datasetIndex] = vScale.getValueForPixel(head) - vScale.getValueForPixel(base); + } } if (base === vScale.getPixelForValue(actualBase)) { diff --git a/src/core/core.datasetController.js b/src/core/core.datasetController.js index d5b43da8d..108460e2a 100644 --- a/src/core/core.datasetController.js +++ b/src/core/core.datasetController.js @@ -158,6 +158,9 @@ function updateStacks(controller, parsed) { stack._top = getLastIndexInStack(stack, vScale, true, meta.type); stack._bottom = getLastIndexInStack(stack, vScale, false, meta.type); + + const visualValues = stack._visualValues || (stack._visualValues = {}); + visualValues[datasetIndex] = value; } } @@ -207,6 +210,9 @@ function clearStacks(meta, items) { return; } delete stacks[axis][datasetIndex]; + if (stacks[axis]._visualValues !== undefined && stacks[axis]._visualValues[datasetIndex] !== undefined) { + delete stacks[axis]._visualValues[datasetIndex]; + } } } @@ -578,7 +584,7 @@ export default class DatasetController { const value = parsed[scale.axis]; const stack = { keys: getSortedDatasetIndices(chart, true), - values: parsed._stacks[scale.axis] + values: parsed._stacks[scale.axis]._visualValues }; return applyStack(stack, value, meta.index, {mode}); } diff --git a/test/fixtures/controller.bar/minBarLength/horizontal-stacked-no-overlap.js b/test/fixtures/controller.bar/minBarLength/horizontal-stacked-no-overlap.js new file mode 100644 index 000000000..57b831456 --- /dev/null +++ b/test/fixtures/controller.bar/minBarLength/horizontal-stacked-no-overlap.js @@ -0,0 +1,55 @@ +const minBarLength = 50; + +module.exports = { + config: { + type: 'bar', + data: { + labels: [1, 2, 3, 4], + datasets: [ + { + data: [1, -1, 1, 20], + backgroundColor: '#bb000066', + minBarLength + }, + { + data: [1, -1, -1, -20], + backgroundColor: '#00bb0066', + minBarLength + }, + { + data: [1, -1, 1, 40], + backgroundColor: '#0000bb66', + minBarLength + }, + { + data: [1, -1, -1, -40], + backgroundColor: '#00000066', + minBarLength + } + ] + }, + options: { + indexAxis: 'y', + scales: { + x: { + display: false, + stacked: true + }, + y: { + type: 'linear', + position: 'left', + stacked: true, + ticks: { + display: false + } + } + } + } + }, + options: { + canvas: { + height: 512, + width: 512 + } + } +}; diff --git a/test/fixtures/controller.bar/minBarLength/horizontal-stacked-no-overlap.png b/test/fixtures/controller.bar/minBarLength/horizontal-stacked-no-overlap.png new file mode 100644 index 000000000..dfa3f87b4 Binary files /dev/null and b/test/fixtures/controller.bar/minBarLength/horizontal-stacked-no-overlap.png differ diff --git a/test/fixtures/controller.bar/minBarLength/vertical-stacked-no-overlap.js b/test/fixtures/controller.bar/minBarLength/vertical-stacked-no-overlap.js new file mode 100644 index 000000000..454e02735 --- /dev/null +++ b/test/fixtures/controller.bar/minBarLength/vertical-stacked-no-overlap.js @@ -0,0 +1,54 @@ +const minBarLength = 50; + +module.exports = { + config: { + type: 'bar', + data: { + labels: [1, 2, 3, 4], + datasets: [ + { + data: [1, -1, 1, 20], + backgroundColor: '#bb000066', + minBarLength + }, + { + data: [1, -1, -1, -20], + backgroundColor: '#00bb0066', + minBarLength + }, + { + data: [1, -1, 1, 40], + backgroundColor: '#0000bb66', + minBarLength + }, + { + data: [1, -1, -1, -40], + backgroundColor: '#00000066', + minBarLength + } + ] + }, + options: { + scales: { + x: { + display: false, + stacked: true + }, + y: { + type: 'linear', + position: 'left', + stacked: true, + ticks: { + display: false + } + } + } + } + }, + options: { + canvas: { + height: 512, + width: 512 + } + } +}; diff --git a/test/fixtures/controller.bar/minBarLength/vertical-stacked-no-overlap.png b/test/fixtures/controller.bar/minBarLength/vertical-stacked-no-overlap.png new file mode 100644 index 000000000..f6b917af3 Binary files /dev/null and b/test/fixtures/controller.bar/minBarLength/vertical-stacked-no-overlap.png differ diff --git a/test/specs/core.datasetController.tests.js b/test/specs/core.datasetController.tests.js index c3835bcaf..e10c33d11 100644 --- a/test/specs/core.datasetController.tests.js +++ b/test/specs/core.datasetController.tests.js @@ -768,12 +768,12 @@ describe('Chart.DatasetController', function() { expect(chart._stacks).toEqual({ 'x.y.1': { - 0: {0: 1, 2: 3, _top: 2, _bottom: null}, - 1: {0: 10, 2: 30, _top: 2, _bottom: null} + 0: {0: 1, 2: 3, _top: 2, _bottom: null, _visualValues: {0: 1, 2: 3}}, + 1: {0: 10, 2: 30, _top: 2, _bottom: null, _visualValues: {0: 10, 2: 30}} }, 'x.y.2': { - 0: {1: 2, _top: 1, _bottom: null}, - 1: {1: 20, _top: 1, _bottom: null} + 0: {1: 2, _top: 1, _bottom: null, _visualValues: {1: 2}}, + 1: {1: 20, _top: 1, _bottom: null, _visualValues: {1: 20}} } }); @@ -782,12 +782,12 @@ describe('Chart.DatasetController', function() { expect(chart._stacks).toEqual({ 'x.y.1': { - 0: {0: 1, _top: 2, _bottom: null}, - 1: {0: 10, _top: 2, _bottom: null} + 0: {0: 1, _top: 2, _bottom: null, _visualValues: {0: 1}}, + 1: {0: 10, _top: 2, _bottom: null, _visualValues: {0: 10}} }, 'x.y.2': { - 0: {1: 2, 2: 3, _top: 2, _bottom: null}, - 1: {1: 20, 2: 30, _top: 2, _bottom: null} + 0: {1: 2, 2: 3, _top: 2, _bottom: null, _visualValues: {1: 2, 2: 3}}, + 1: {1: 20, 2: 30, _top: 2, _bottom: null, _visualValues: {1: 20, 2: 30}} } }); }); @@ -812,12 +812,12 @@ describe('Chart.DatasetController', function() { expect(chart._stacks).toEqual({ 'x.y.1': { - 0: {0: 1, 2: 3, _top: 2, _bottom: null}, - 1: {0: 10, 2: 30, _top: 2, _bottom: null} + 0: {0: 1, 2: 3, _top: 2, _bottom: null, _visualValues: {0: 1, 2: 3}}, + 1: {0: 10, 2: 30, _top: 2, _bottom: null, _visualValues: {0: 10, 2: 30}} }, 'x.y.2': { - 0: {1: 2, _top: 1, _bottom: null}, - 1: {1: 20, _top: 1, _bottom: null} + 0: {1: 2, _top: 1, _bottom: null, _visualValues: {1: 2}}, + 1: {1: 20, _top: 1, _bottom: null, _visualValues: {1: 20}} } }); @@ -826,12 +826,12 @@ describe('Chart.DatasetController', function() { expect(chart._stacks).toEqual({ 'x.y.1': { - 0: {0: 1, 2: 4, _top: 2, _bottom: null}, - 1: {0: 10, _top: 2, _bottom: null} + 0: {0: 1, 2: 4, _top: 2, _bottom: null, _visualValues: {0: 1, 2: 4}}, + 1: {0: 10, _top: 2, _bottom: null, _visualValues: {0: 10}} }, 'x.y.2': { - 0: {1: 2, _top: 1, _bottom: null}, - 1: {1: 20, _top: 1, _bottom: null} + 0: {1: 2, _top: 1, _bottom: null, _visualValues: {1: 2}}, + 1: {1: 20, _top: 1, _bottom: null, _visualValues: {1: 20}} } }); }); @@ -947,7 +947,7 @@ describe('Chart.DatasetController', function() { }); var meta = chart.getDatasetMeta(0); - expect(meta._parsed[0]._stacks).toEqual(jasmine.objectContaining({y: {0: 10, 1: 20, _top: 1, _bottom: null}})); + expect(meta._parsed[0]._stacks).toEqual(jasmine.objectContaining({y: {0: 10, 1: 20, _top: 1, _bottom: null, _visualValues: {0: 10, 1: 20}}})); }); describe('resolveDataElementOptions', function() {