Skip to content

Commit df9c75f

Browse files
author
Artshooter
committed
fix: wrong bar chart color with small value
1 parent 32e75f5 commit df9c75f

File tree

2 files changed

+115
-2
lines changed

2 files changed

+115
-2
lines changed

lib/src/chart/bar_chart/bar_chart_painter.dart

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -305,10 +305,28 @@ class BarChartPainter extends AxisChartPainter<BarChartData> {
305305

306306
// draw rod stack
307307
if (barRod.rodStackItems.isNotEmpty) {
308+
// Calculate scale factor to ensure minimum height for corner radius
309+
final totalHeightPixels = (
310+
getPixelY(barRod.fromY, viewSize, holder) -
311+
getPixelY(barRod.toY, viewSize, holder)
312+
).abs();
313+
314+
final scaleFactor = totalHeightPixels < cornerHeight
315+
? cornerHeight / totalHeightPixels
316+
: 1.0;
317+
308318
for (var i = 0; i < barRod.rodStackItems.length; i++) {
309319
final stackItem = barRod.rodStackItems[i];
310-
final stackFromY = getPixelY(stackItem.fromY, viewSize, holder);
311-
final stackToY = getPixelY(stackItem.toY, viewSize, holder);
320+
321+
var stackFromY = getPixelY(stackItem.fromY, viewSize, holder);
322+
var stackToY = getPixelY(stackItem.toY, viewSize, holder);
323+
324+
// Apply scale factor only when needed
325+
if (scaleFactor > 1.0) {
326+
final basePixelY = getPixelY(barRod.fromY, viewSize, holder);
327+
stackFromY = basePixelY - (basePixelY - stackFromY) * scaleFactor;
328+
stackToY = basePixelY - (basePixelY - stackToY) * scaleFactor;
329+
}
312330

313331
final isNegative = stackItem.toY < stackItem.fromY;
314332
final rect = isNegative

test/chart/bar_chart/bar_chart_painter_test.dart

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1562,6 +1562,101 @@ void main() {
15621562

15631563
expect(HelperMethods.equalsPaths(expectedPath, currentPath), true);
15641564
});
1565+
1566+
test('test small bar values with large border radius (issue #1757)', () {
1567+
const viewSize = Size(200, 200);
1568+
1569+
// Test case: bar height (2) is smaller than corner height (16)
1570+
// This should trigger the scale factor logic
1571+
final barGroups = [
1572+
BarChartGroupData(
1573+
x: 0,
1574+
barRods: [
1575+
BarChartRodData(
1576+
toY: 2,
1577+
width: 40,
1578+
rodStackItems: [
1579+
BarChartRodStackItem(
1580+
0,
1581+
1,
1582+
Colors.amber,
1583+
),
1584+
BarChartRodStackItem(
1585+
1,
1586+
2,
1587+
Colors.red,
1588+
),
1589+
],
1590+
borderRadius: const BorderRadius.only(
1591+
topLeft: Radius.circular(8),
1592+
topRight: Radius.circular(8),
1593+
),
1594+
),
1595+
],
1596+
),
1597+
];
1598+
1599+
final data = BarChartData(
1600+
barGroups: barGroups,
1601+
minY: 0,
1602+
maxY: 100,
1603+
);
1604+
1605+
final barChartPainter = BarChartPainter();
1606+
final holder =
1607+
PaintHolder<BarChartData>(data, data, TextScaler.noScaling);
1608+
1609+
final mockCanvasWrapper = MockCanvasWrapper();
1610+
when(mockCanvasWrapper.size).thenAnswer((realInvocation) => viewSize);
1611+
when(mockCanvasWrapper.canvas).thenReturn(MockCanvas());
1612+
1613+
final groupsX = data.calculateGroupsX(viewSize.width);
1614+
final barGroupsPosition = barChartPainter.calculateGroupAndBarsPosition(
1615+
viewSize,
1616+
groupsX,
1617+
barGroups,
1618+
);
1619+
1620+
final clipRectResults = <Rect>[];
1621+
when(mockCanvasWrapper.clipRect(captureAny)).thenAnswer((inv) {
1622+
final rect = inv.positionalArguments[0] as Rect;
1623+
clipRectResults.add(rect);
1624+
});
1625+
1626+
when(mockCanvasWrapper.save()).thenReturn(null);
1627+
when(mockCanvasWrapper.restore()).thenReturn(null);
1628+
when(mockCanvasWrapper.drawRRect(any, any)).thenReturn(null);
1629+
1630+
barChartPainter.drawBars(mockCanvasWrapper, barGroupsPosition, holder);
1631+
1632+
// Verify that clipRect was called for each stack item
1633+
expect(clipRectResults.length, 2,
1634+
reason: 'Should have clipped for 2 stack items');
1635+
1636+
// Verify that the clip rectangles have been scaled properly
1637+
// The total bar height in pixels would be very small (2% of 200 = 4px)
1638+
// But corner height is 8, so scale factor should be 8/4 = 2.0
1639+
// Each stack item should be scaled proportionally
1640+
final rect1 = clipRectResults[0];
1641+
final rect2 = clipRectResults[1];
1642+
1643+
// Debug: print actual values
1644+
// print('rect1: $rect1, height: ${rect1.height}');
1645+
// print('rect2: $rect2, height: ${rect2.height}');
1646+
1647+
// Stack items should not overlap and should be adjacent
1648+
expect(rect2.bottom, closeTo(rect1.top, tolerance),
1649+
reason: 'Stack items should be adjacent without gaps (rect2.bottom should equal rect1.top)');
1650+
1651+
// The combined height should equal the scaled total height (cornerHeight)
1652+
final totalScaledHeight = rect1.height + rect2.height;
1653+
expect(totalScaledHeight, closeTo(8.0, tolerance),
1654+
reason: 'Total scaled height should equal corner height (8px)');
1655+
1656+
// Heights should be proportional to data values (1:1 ratio)
1657+
expect(rect1.height, closeTo(rect2.height, tolerance),
1658+
reason: 'Stack items with equal data heights (1) should have equal pixel heights');
1659+
});
15651660
});
15661661

15671662
group('drawBars() - label tests', () {

0 commit comments

Comments
 (0)