From ef067a4a6ba0e8e12311a32f8e1d7d622fa6baef Mon Sep 17 00:00:00 2001 From: generaltony007 <191973953+hakarrr@users.noreply.github.com> Date: Mon, 26 Oct 2026 22:06:26 +0530 Subject: [PATCH 1/2] Refactor visibility check for bar size calculation Co-authored-by: generaltony007 <144252170+GeneralTony007@users.noreply.github.com> --- src/controllers/controller.bar.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/controllers/controller.bar.js b/src/controllers/controller.bar.js index 554497b3053..5facd88bc79 100644 --- a/src/controllers/controller.bar.js +++ b/src/controllers/controller.bar.js @@ -589,7 +589,8 @@ export default class BarController extends DatasetController { const startValue = !isNullOrUndef(baseValue) && !floating ? baseValue : start; let base = vScale.getPixelForValue(startValue); - if (this.chart.getDataVisibility(index)) { + const visible = this.chart.getDataVisibility(index); + if (visible) { head = vScale.getPixelForValue(start + length); } else { // When not visible, no height @@ -598,7 +599,7 @@ export default class BarController extends DatasetController { size = head - base; - if (Math.abs(size) < minBarLength) { + if (visible && Math.abs(size) < minBarLength) { size = barSign(size, vScale, actualBase) * minBarLength; if (value === actualBase) { base -= size / 2; From 77fb777ba99a39815f1e88af673846b371659e71 Mon Sep 17 00:00:00 2001 From: generaltony007 <191973953+hakarrr@users.noreply.github.com> Date: Mon, 26 Oct 2026 22:06:44 +0530 Subject: [PATCH 2/2] Add tests for bar data visibility and minimum lengths Co-authored-by: generaltony007 <144252170+GeneralTony007@users.noreply.github.com> --- test/specs/controller.bar.tests.js | 99 ++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) diff --git a/test/specs/controller.bar.tests.js b/test/specs/controller.bar.tests.js index 128ef241d00..059fe59253b 100644 --- a/test/specs/controller.bar.tests.js +++ b/test/specs/controller.bar.tests.js @@ -1851,3 +1851,102 @@ describe('Chart.controllers.bar', function() { }]); }); }); + + +describe('Bar data visibility with minimum lengths', function() { + ['x', 'y'].forEach(function(indexAxis) { + [false, true].forEach(function(reverse) { + [false, true].forEach(function(stacked) { + [0, 0.01, -0.01, [2, 3]].forEach(function(value) { + it('collapses hidden bars for ' + [indexAxis, reverse, stacked, value].join(', '), function() { + var valueAxis = indexAxis === 'x' ? 'y' : 'x'; + var chart = window.acquireChart({ + type: 'bar', + data: { + labels: ['A', 'B'], + datasets: [{data: [value, 8], minBarLength: 30, backgroundColor: 'red'}] + }, + options: { + indexAxis, + animation: false, + plugins: {legend: false}, + scales: { + x: {display: false, stacked}, + y: {display: false, stacked}, + [valueAxis]: {display: false, stacked, reverse, min: -10, max: 10} + } + } + }); + var bar = chart.getDatasetMeta(0).data[0]; + var original = bar[valueAxis]; + expect(Math.abs(bar[valueAxis] - bar.base)).toBeGreaterThan(29); + chart.toggleDataVisibility(0); + chart.update(); + expect(chart.getDataVisibility(0)).toBe(false); + var pixelX = indexAxis === 'x' ? bar.x : bar.base + 15; + var pixelY = indexAxis === 'x' ? bar.base - 15 : bar.y; + expect(chart.ctx.getImageData(pixelX, pixelY, 1, 1).data[3]).toEqual(0); + expect(bar[valueAxis]).toEqual(bar.base); + expect(valueAxis === 'y' ? bar.height : bar.width).toEqual(0); + chart.update(); + expect(bar[valueAxis]).toEqual(bar.base); + chart.toggleDataVisibility(0); + chart.update(); + expect(bar[valueAxis]).toEqual(original); + }); + }); + }); + }); + }); +}); + + +describe('Bar visibility minimum-length controls', function() { + ['x', 'y'].forEach(function(indexAxis) { + [0, 30].forEach(function(minBarLength) { + [false, true].forEach(function(stacked) { + it('preserves other bars and restores multiple datasets for ' + [indexAxis, minBarLength, stacked].join(', '), function() { + var valueAxis = indexAxis === 'x' ? 'y' : 'x'; + var chart = window.acquireChart({ + type: 'bar', + data: { + labels: ['A', 'B'], + datasets: [ + {data: [0.01, 2], minBarLength}, + {data: [0.02, 3], minBarLength} + ] + }, + options: { + indexAxis, + animation: false, + scales: { + x: {display: false, stacked}, + y: {display: false, stacked}, + [valueAxis]: {display: false, stacked, min: 0, max: 10} + } + } + }); + var initial = chart.data.datasets.map(function(dataset, i) { + var bars = chart.getDatasetMeta(i).data; + return bars.map(function(bar) { + return [bar.base, bar[valueAxis]]; + }); + }); + chart.toggleDataVisibility(0); + chart.update(); + chart.data.datasets.forEach(function(dataset, i) { + var bars = chart.getDatasetMeta(i).data; + expect(bars[0][valueAxis]).toEqual(bars[0].base); + expect([bars[1].base, bars[1][valueAxis]]).toEqual(initial[i][1]); + }); + chart.toggleDataVisibility(0); + chart.update(); + chart.data.datasets.forEach(function(dataset, i) { + var bars = chart.getDatasetMeta(i).data; + expect([bars[0].base, bars[0][valueAxis]]).toEqual(initial[i][0]); + }); + }); + }); + }); + }); +});