From 795e957196edb6cd4d1cc0c8c4f1a27d83e60d60 Mon Sep 17 00:00:00 2001 From: minjibak Date: Thu, 4 Sep 2025 15:01:49 +0900 Subject: [PATCH 1/4] fix: Unwanted white gap between bar border and bar fill (chartjs#12094) --- src/elements/element.bar.js | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/elements/element.bar.js b/src/elements/element.bar.js index 6b0cfc70bc1..40ad5cdfe99 100644 --- a/src/elements/element.bar.js +++ b/src/elements/element.bar.js @@ -124,18 +124,29 @@ function addNormalRectPath(ctx, rect) { ctx.rect(rect.x, rect.y, rect.w, rect.h); } -function inflateRect(rect, amount, refRect = {}) { +function inflateRect(rect, amount, refRect = {}, snap = false) { const x = rect.x !== refRect.x ? -amount : 0; const y = rect.y !== refRect.y ? -amount : 0; const w = (rect.x + rect.w !== refRect.x + refRect.w ? amount : 0) - x; const h = (rect.y + rect.h !== refRect.y + refRect.h ? amount : 0) - y; - return { + + const result = { x: rect.x + x, y: rect.y + y, w: rect.w + w, h: rect.h + h, radius: rect.radius }; + + if (snap) { + const dpr = (typeof window !== 'undefined' && window.devicePixelRatio) ? window.devicePixelRatio : 1; + result.x = Math.round(result.x * dpr) / dpr; + result.y = Math.round(result.y * dpr) / dpr; + result.w = Math.round(result.w * dpr) / dpr; + result.h = Math.round(result.h * dpr) / dpr; + } + + return result; } export default class BarElement extends Element { @@ -185,15 +196,15 @@ export default class BarElement extends Element { if (outer.w !== inner.w || outer.h !== inner.h) { ctx.beginPath(); - addRectPath(ctx, inflateRect(outer, inflateAmount, inner)); + addRectPath(ctx, inflateRect(outer, inflateAmount, inner, true)); ctx.clip(); - addRectPath(ctx, inflateRect(inner, -inflateAmount, outer)); + addRectPath(ctx, inflateRect(inner, -inflateAmount, outer, true)); ctx.fillStyle = borderColor; ctx.fill('evenodd'); } ctx.beginPath(); - addRectPath(ctx, inflateRect(inner, inflateAmount)); + addRectPath(ctx, inflateRect(inner, inflateAmount, undefined, true)); ctx.fillStyle = backgroundColor; ctx.fill(); From c00bb8383bfef24474ba450da827620d576bbc64 Mon Sep 17 00:00:00 2001 From: minjibak Date: Wed, 17 Sep 2025 13:58:38 +0900 Subject: [PATCH 2/4] fix: Unwanted white gap between bar border and bar fill (chartjs#12094) - Added tests in element.bar.tests.js to verify pixel snapping fix --- src/elements/element.bar.js | 2 +- test/specs/element.bar.tests.js | 66 +++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/src/elements/element.bar.js b/src/elements/element.bar.js index 40ad5cdfe99..4435046ffc3 100644 --- a/src/elements/element.bar.js +++ b/src/elements/element.bar.js @@ -145,7 +145,7 @@ function inflateRect(rect, amount, refRect = {}, snap = false) { result.w = Math.round(result.w * dpr) / dpr; result.h = Math.round(result.h * dpr) / dpr; } - + return result; } diff --git a/test/specs/element.bar.tests.js b/test/specs/element.bar.tests.js index 128bdddc12e..f00d30c86e8 100644 --- a/test/specs/element.bar.tests.js +++ b/test/specs/element.bar.tests.js @@ -64,4 +64,70 @@ describe('Bar element tests', function() { expect(bar.getCenterPoint()).toEqual({x: 10, y: 7.5}); }); + + describe('unwanted white gap fix', () => { + it('should not produce white gap when borderWidth > 0', () => { + var chart = window.acquireChart({ + type: 'bar', + data: { + datasets: [{ + data: [50], + backgroundColor: 'pink', + borderColor: 'pink', + borderWidth: 15, + borderSkipped: false, + }], + labels: [] + }, + options: { + elements: { + bar: { + inflateAmount: 0, + } + }, + } + }); + + const meta = chart.getDatasetMeta(0); + const bar = meta.data[0]; + const props = bar.getProps(['width', 'height', 'borderWidth'], true); + + expect(props.borderWidth).toBe(15); + expect(props.width).toBeGreaterThan(props.borderWidth * 2); + expect(props.height).toBeGreaterThan(props.borderWidth * 2); + }); + + it('should handle borderRadius without creating a gap', () => { + var chart = window.acquireChart({ + type: 'bar', + data: { + datasets: [{ + data: [30], + backgroundColor: 'black', + borderColor: 'black', + borderWidth: 10, + borderRadius: 8, + borderSkipped: false, + }], + labels: [] + }, + options: { + elements: { + bar: { + inflateAmount: 0, + } + }, + } + }); + + const meta = chart.getDatasetMeta(0); + const bar = meta.data[0]; + const props = bar.getProps(['width', 'height', 'borderWidth', 'borderRadius'], true); + + expect(props.borderWidth).toBe(10); + expect(props.borderRadius).toBe(8); + expect(props.width).toBeGreaterThan(props.borderRadius + props.borderWidth); + expect(props.height).toBeGreaterThan(props.borderRadius + props.borderWidth); + }); + }); }); From 2d1ea458957697dce0eae643a88bc26685610d3a Mon Sep 17 00:00:00 2001 From: minjibak Date: Fri, 19 Sep 2025 14:17:41 +0900 Subject: [PATCH 3/4] fix: Unwanted white gap between bar border and bar fill (chartjs#12094) test: fix Bar element tests to use options.borderWidth (chartjs#12094) --- test/specs/element.bar.tests.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/test/specs/element.bar.tests.js b/test/specs/element.bar.tests.js index f00d30c86e8..08e43008f84 100644 --- a/test/specs/element.bar.tests.js +++ b/test/specs/element.bar.tests.js @@ -90,11 +90,11 @@ describe('Bar element tests', function() { const meta = chart.getDatasetMeta(0); const bar = meta.data[0]; - const props = bar.getProps(['width', 'height', 'borderWidth'], true); + const props = bar.getProps(['width', 'height'], true); - expect(props.borderWidth).toBe(15); - expect(props.width).toBeGreaterThan(props.borderWidth * 2); - expect(props.height).toBeGreaterThan(props.borderWidth * 2); + expect(bar.options.borderWidth).toBe(15); + expect(props.width).toBeGreaterThan(bar.options.borderWidth * 2); + expect(props.height).toBeGreaterThan(bar.options.borderWidth * 2); }); it('should handle borderRadius without creating a gap', () => { @@ -122,12 +122,12 @@ describe('Bar element tests', function() { const meta = chart.getDatasetMeta(0); const bar = meta.data[0]; - const props = bar.getProps(['width', 'height', 'borderWidth', 'borderRadius'], true); + const props = bar.getProps(['width', 'height'], true); - expect(props.borderWidth).toBe(10); - expect(props.borderRadius).toBe(8); - expect(props.width).toBeGreaterThan(props.borderRadius + props.borderWidth); - expect(props.height).toBeGreaterThan(props.borderRadius + props.borderWidth); + expect(bar.options.borderWidth).toBe(10); + expect(bar.options.borderRadius).toBe(8); + expect(props.width).toBeGreaterThan(bar.options.borderRadius + bar.options.borderWidth); + expect(props.height).toBeGreaterThan(bar.options.borderRadius + bar.options.borderWidth); }); }); }); From 756d861e50252734da151147e58c08c841900ef9 Mon Sep 17 00:00:00 2001 From: minjibak Date: Tue, 21 Oct 2025 17:25:18 +0900 Subject: [PATCH 4/4] fix: Unwanted white gap between bar border and bar fill (chartjs#12094) Apply pixel snapping only when snap option is enabled --- src/elements/element.bar.js | 11 ++++++----- test/specs/element.bar.tests.js | 2 ++ 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/elements/element.bar.js b/src/elements/element.bar.js index 4435046ffc3..3d8782e3e1f 100644 --- a/src/elements/element.bar.js +++ b/src/elements/element.bar.js @@ -161,7 +161,8 @@ export default class BarElement extends Element { borderWidth: 0, borderRadius: 0, inflateAmount: 'auto', - pointStyle: undefined + pointStyle: undefined, + snap: false, }; /** @@ -188,7 +189,7 @@ export default class BarElement extends Element { } draw(ctx) { - const {inflateAmount, options: {borderColor, backgroundColor}} = this; + const {inflateAmount, options: {borderColor, backgroundColor, snap}} = this; const {inner, outer} = boundingRects(this); const addRectPath = hasRadius(outer.radius) ? addRoundedRectPath : addNormalRectPath; @@ -196,15 +197,15 @@ export default class BarElement extends Element { if (outer.w !== inner.w || outer.h !== inner.h) { ctx.beginPath(); - addRectPath(ctx, inflateRect(outer, inflateAmount, inner, true)); + addRectPath(ctx, inflateRect(outer, inflateAmount, inner, snap)); ctx.clip(); - addRectPath(ctx, inflateRect(inner, -inflateAmount, outer, true)); + addRectPath(ctx, inflateRect(inner, -inflateAmount, outer, snap)); ctx.fillStyle = borderColor; ctx.fill('evenodd'); } ctx.beginPath(); - addRectPath(ctx, inflateRect(inner, inflateAmount, undefined, true)); + addRectPath(ctx, inflateRect(inner, inflateAmount, undefined, snap)); ctx.fillStyle = backgroundColor; ctx.fill(); diff --git a/test/specs/element.bar.tests.js b/test/specs/element.bar.tests.js index 08e43008f84..b10b7d212cd 100644 --- a/test/specs/element.bar.tests.js +++ b/test/specs/element.bar.tests.js @@ -83,6 +83,7 @@ describe('Bar element tests', function() { elements: { bar: { inflateAmount: 0, + snap: false, } }, } @@ -115,6 +116,7 @@ describe('Bar element tests', function() { elements: { bar: { inflateAmount: 0, + snap: false, } }, }