From 3ac6a86c49b487bdfc37670f4ce4db5bfb6cd57a Mon Sep 17 00:00:00 2001 From: alettsy Date: Wed, 9 Jul 2025 11:22:29 +0200 Subject: [PATCH 1/5] Add shrink wrap for bar chart when overflow When shrinkWrapOnWidthOverflow is set to true, the first and last bars in the chart should be touching the sides instead of having space at the start/end. The bars should still be spaced evenly. Fixes #1952 --- lib/src/chart/bar_chart/bar_chart_data.dart | 10 ++++++++++ lib/src/extensions/bar_chart_data_extension.dart | 15 +++++++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/lib/src/chart/bar_chart/bar_chart_data.dart b/lib/src/chart/bar_chart/bar_chart_data.dart index 82e875244..3c5906ce2 100644 --- a/lib/src/chart/bar_chart/bar_chart_data.dart +++ b/lib/src/chart/bar_chart/bar_chart_data.dart @@ -49,6 +49,7 @@ class BarChartData extends AxisChartData with EquatableMixin { ExtraLinesData? extraLinesData, super.rotationQuarterTurns, this.errorIndicatorData = const FlErrorIndicatorData(), + this.shrinkWrapOnWidthOverflow = false, }) : barGroups = barGroups ?? const [], groupsSpace = groupsSpace ?? 16, alignment = alignment ?? BarChartAlignment.spaceEvenly, @@ -73,6 +74,10 @@ class BarChartData extends AxisChartData with EquatableMixin { /// Apply space between the [barGroups]. final double groupsSpace; + /// If width of chart would overflow the container, then space evenly without + /// adding space at the start and end of the chart. + final bool shrinkWrapOnWidthOverflow; + /// Arrange the [barGroups], see [BarChartAlignment]. final BarChartAlignment alignment; @@ -89,6 +94,7 @@ class BarChartData extends AxisChartData with EquatableMixin { BarChartData copyWith({ List? barGroups, double? groupsSpace, + bool? shrinkWrapOnWidthOverflow, BarChartAlignment? alignment, FlTitlesData? titlesData, RangeAnnotations? rangeAnnotations, @@ -107,6 +113,8 @@ class BarChartData extends AxisChartData with EquatableMixin { BarChartData( barGroups: barGroups ?? this.barGroups, groupsSpace: groupsSpace ?? this.groupsSpace, + shrinkWrapOnWidthOverflow: + shrinkWrapOnWidthOverflow ?? this.shrinkWrapOnWidthOverflow, alignment: alignment ?? this.alignment, titlesData: titlesData ?? this.titlesData, rangeAnnotations: rangeAnnotations ?? this.rangeAnnotations, @@ -129,6 +137,8 @@ class BarChartData extends AxisChartData with EquatableMixin { return BarChartData( barGroups: lerpBarChartGroupDataList(a.barGroups, b.barGroups, t), groupsSpace: lerpDouble(a.groupsSpace, b.groupsSpace, t), + shrinkWrapOnWidthOverflow: + t < 0.5 ? a.shrinkWrapOnWidthOverflow : b.shrinkWrapOnWidthOverflow, alignment: b.alignment, titlesData: FlTitlesData.lerp(a.titlesData, b.titlesData, t), rangeAnnotations: diff --git a/lib/src/extensions/bar_chart_data_extension.dart b/lib/src/extensions/bar_chart_data_extension.dart index e381c6d89..98477fc85 100644 --- a/lib/src/extensions/bar_chart_data_extension.dart +++ b/lib/src/extensions/bar_chart_data_extension.dart @@ -10,10 +10,21 @@ extension BarChartDataExtension on BarChartData { final spaceAvailable = viewWidth - sumWidth; void spaceEvenly() { - final eachSpace = spaceAvailable / (barGroups.length + 1); + var eachSpace = 0.0; + + if (shrinkWrapOnWidthOverflow) { + eachSpace = spaceAvailable / (barGroups.length - 1); + } else { + eachSpace = spaceAvailable / (barGroups.length + 1); + } + var tempX = 0.0; barGroups.asMap().forEach((i, group) { - tempX += eachSpace; + if (!shrinkWrapOnWidthOverflow || + (shrinkWrapOnWidthOverflow && i != 0)) { + tempX += eachSpace; + } + tempX += group.width / 2; groupsX[i] = tempX; tempX += group.width / 2; From 9bddf3c36531cd6f5315ae6545d31c706845689c Mon Sep 17 00:00:00 2001 From: alettsy Date: Thu, 7 Aug 2025 10:35:53 +0200 Subject: [PATCH 2/5] fix: divide by zero and reduce shrink if statement --- lib/src/extensions/bar_chart_data_extension.dart | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/src/extensions/bar_chart_data_extension.dart b/lib/src/extensions/bar_chart_data_extension.dart index 98477fc85..ae556935b 100644 --- a/lib/src/extensions/bar_chart_data_extension.dart +++ b/lib/src/extensions/bar_chart_data_extension.dart @@ -10,6 +10,11 @@ extension BarChartDataExtension on BarChartData { final spaceAvailable = viewWidth - sumWidth; void spaceEvenly() { + if (barGroups.length == 1) { + groupsX[0] = viewWidth / 2; + return; + } + var eachSpace = 0.0; if (shrinkWrapOnWidthOverflow) { @@ -20,8 +25,7 @@ extension BarChartDataExtension on BarChartData { var tempX = 0.0; barGroups.asMap().forEach((i, group) { - if (!shrinkWrapOnWidthOverflow || - (shrinkWrapOnWidthOverflow && i != 0)) { + if (!shrinkWrapOnWidthOverflow || i != 0) { tempX += eachSpace; } From a02bee112f2938280a90f8362e24ac77acbbcc71 Mon Sep 17 00:00:00 2001 From: alettsy Date: Thu, 21 Aug 2025 16:22:17 +0200 Subject: [PATCH 3/5] fix: add shrinkWrapOnWidthOverflow to props --- lib/src/chart/bar_chart/bar_chart_data.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/src/chart/bar_chart/bar_chart_data.dart b/lib/src/chart/bar_chart/bar_chart_data.dart index 3c5906ce2..891ed31f4 100644 --- a/lib/src/chart/bar_chart/bar_chart_data.dart +++ b/lib/src/chart/bar_chart/bar_chart_data.dart @@ -182,6 +182,7 @@ class BarChartData extends AxisChartData with EquatableMixin { extraLinesData, rotationQuarterTurns, errorIndicatorData, + shrinkWrapOnWidthOverflow, ]; } From 31108e53c36d0c1c12dd5834d13a56a829223277 Mon Sep 17 00:00:00 2001 From: alettsy Date: Mon, 25 Aug 2025 21:06:36 +0200 Subject: [PATCH 4/5] test: add test for shrinkWrapOnWidthOverflow --- test/extensions/bar_chart_data_extensions_test.dart | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/extensions/bar_chart_data_extensions_test.dart b/test/extensions/bar_chart_data_extensions_test.dart index 00796049c..33cdc5f5f 100644 --- a/test/extensions/bar_chart_data_extensions_test.dart +++ b/test/extensions/bar_chart_data_extensions_test.dart @@ -75,5 +75,14 @@ void main() { throwsAssertionError, ); }); + + test('Test shrinkWrapOnWidthOverflow calcualtes spacing correctly', () { + expect( + MockData.barChartData1 + .copyWith(shrinkWrapOnWidthOverflow: true) + .calculateGroupsX(100), + [9.0, 50.0, 91.0], + ); + }); }); } From c4c6fb7b32db65657639538c092eb28d1b68c25f Mon Sep 17 00:00:00 2001 From: alettsy Date: Sun, 31 Aug 2025 16:47:39 +0200 Subject: [PATCH 5/5] feat: auto calculate spacing without shrinkWrapOnWidthOverflow property --- lib/src/chart/bar_chart/bar_chart_data.dart | 11 ------- .../extensions/bar_chart_data_extension.dart | 10 ++----- .../bar_chart/bar_chart_painter_test.dart | 2 +- .../bar_chart_data_extensions_test.dart | 30 +++++++++---------- 4 files changed, 18 insertions(+), 35 deletions(-) diff --git a/lib/src/chart/bar_chart/bar_chart_data.dart b/lib/src/chart/bar_chart/bar_chart_data.dart index 891ed31f4..82e875244 100644 --- a/lib/src/chart/bar_chart/bar_chart_data.dart +++ b/lib/src/chart/bar_chart/bar_chart_data.dart @@ -49,7 +49,6 @@ class BarChartData extends AxisChartData with EquatableMixin { ExtraLinesData? extraLinesData, super.rotationQuarterTurns, this.errorIndicatorData = const FlErrorIndicatorData(), - this.shrinkWrapOnWidthOverflow = false, }) : barGroups = barGroups ?? const [], groupsSpace = groupsSpace ?? 16, alignment = alignment ?? BarChartAlignment.spaceEvenly, @@ -74,10 +73,6 @@ class BarChartData extends AxisChartData with EquatableMixin { /// Apply space between the [barGroups]. final double groupsSpace; - /// If width of chart would overflow the container, then space evenly without - /// adding space at the start and end of the chart. - final bool shrinkWrapOnWidthOverflow; - /// Arrange the [barGroups], see [BarChartAlignment]. final BarChartAlignment alignment; @@ -94,7 +89,6 @@ class BarChartData extends AxisChartData with EquatableMixin { BarChartData copyWith({ List? barGroups, double? groupsSpace, - bool? shrinkWrapOnWidthOverflow, BarChartAlignment? alignment, FlTitlesData? titlesData, RangeAnnotations? rangeAnnotations, @@ -113,8 +107,6 @@ class BarChartData extends AxisChartData with EquatableMixin { BarChartData( barGroups: barGroups ?? this.barGroups, groupsSpace: groupsSpace ?? this.groupsSpace, - shrinkWrapOnWidthOverflow: - shrinkWrapOnWidthOverflow ?? this.shrinkWrapOnWidthOverflow, alignment: alignment ?? this.alignment, titlesData: titlesData ?? this.titlesData, rangeAnnotations: rangeAnnotations ?? this.rangeAnnotations, @@ -137,8 +129,6 @@ class BarChartData extends AxisChartData with EquatableMixin { return BarChartData( barGroups: lerpBarChartGroupDataList(a.barGroups, b.barGroups, t), groupsSpace: lerpDouble(a.groupsSpace, b.groupsSpace, t), - shrinkWrapOnWidthOverflow: - t < 0.5 ? a.shrinkWrapOnWidthOverflow : b.shrinkWrapOnWidthOverflow, alignment: b.alignment, titlesData: FlTitlesData.lerp(a.titlesData, b.titlesData, t), rangeAnnotations: @@ -182,7 +172,6 @@ class BarChartData extends AxisChartData with EquatableMixin { extraLinesData, rotationQuarterTurns, errorIndicatorData, - shrinkWrapOnWidthOverflow, ]; } diff --git a/lib/src/extensions/bar_chart_data_extension.dart b/lib/src/extensions/bar_chart_data_extension.dart index ae556935b..b5a931cbf 100644 --- a/lib/src/extensions/bar_chart_data_extension.dart +++ b/lib/src/extensions/bar_chart_data_extension.dart @@ -15,17 +15,11 @@ extension BarChartDataExtension on BarChartData { return; } - var eachSpace = 0.0; - - if (shrinkWrapOnWidthOverflow) { - eachSpace = spaceAvailable / (barGroups.length - 1); - } else { - eachSpace = spaceAvailable / (barGroups.length + 1); - } + final eachSpace = spaceAvailable / (barGroups.length - 1); var tempX = 0.0; barGroups.asMap().forEach((i, group) { - if (!shrinkWrapOnWidthOverflow || i != 0) { + if (i != 0) { tempX += eachSpace; } diff --git a/test/chart/bar_chart/bar_chart_painter_test.dart b/test/chart/bar_chart/bar_chart_painter_test.dart index c3595ba45..ede6323cd 100644 --- a/test/chart/bar_chart/bar_chart_painter_test.dart +++ b/test/chart/bar_chart/bar_chart_painter_test.dart @@ -615,7 +615,7 @@ void main() { expect(callWithAlignment(BarChartAlignment.end), [80.0, 122.5, 172.5]); expect( callWithAlignment(BarChartAlignment.spaceEvenly), - [40, 92.5, 152.5], + [20.0, 92.5, 172.5], ); expect( callWithAlignment(BarChartAlignment.spaceAround), diff --git a/test/extensions/bar_chart_data_extensions_test.dart b/test/extensions/bar_chart_data_extensions_test.dart index 33cdc5f5f..1891bfce6 100644 --- a/test/extensions/bar_chart_data_extensions_test.dart +++ b/test/extensions/bar_chart_data_extensions_test.dart @@ -7,46 +7,48 @@ import '../chart/data_pool.dart'; void main() { group('BarChartDataExtension.calculateGroupsX', () { test('calculates correct positions for basic alignments', () { + const width = 200.0; + expect( MockData.barChartData1 .copyWith(alignment: BarChartAlignment.start) - .calculateGroupsX(100), + .calculateGroupsX(width), [9.0, 43.0, 77.0], ); expect( MockData.barChartData1 .copyWith(alignment: BarChartAlignment.end) - .calculateGroupsX(100), - [23.0, 57.0, 91.0], + .calculateGroupsX(width), + [123.0, 157.0, 191.0], ); expect( MockData.barChartData1 .copyWith(alignment: BarChartAlignment.center) - .calculateGroupsX(100), - [16.0, 50.0, 84.0], + .calculateGroupsX(width), + [66.0, 100.0, 134.0], ); expect( MockData.barChartData1 .copyWith(alignment: BarChartAlignment.spaceBetween) - .calculateGroupsX(100), - [9.0, 50.0, 91.0], + .calculateGroupsX(width), + [9.0, 100.0, 191.0], ); expect( MockData.barChartData1 .copyWith(alignment: BarChartAlignment.spaceAround) - .calculateGroupsX(100), - [16.666666666666668, 50.0, 83.33333333333334], + .calculateGroupsX(width), + [33.33333333333333, 99.99999999999999, 166.66666666666666], ); expect( MockData.barChartData1 .copyWith(alignment: BarChartAlignment.spaceEvenly) - .calculateGroupsX(100), - [20.5, 50.0, 79.5], + .calculateGroupsX(width), + [9.0, 100.0, 191.0], ); }); @@ -62,7 +64,7 @@ void main() { MockData.barChartData1 .copyWith(alignment: alignment) .calculateGroupsX(60), - [10.5, 30.0, 49.5], + [9.0, 30.0, 51.0], ); }, ); @@ -78,9 +80,7 @@ void main() { test('Test shrinkWrapOnWidthOverflow calcualtes spacing correctly', () { expect( - MockData.barChartData1 - .copyWith(shrinkWrapOnWidthOverflow: true) - .calculateGroupsX(100), + MockData.barChartData1.calculateGroupsX(100), [9.0, 50.0, 91.0], ); });