diff --git a/lib/src/chart/line_chart/line_chart_data.dart b/lib/src/chart/line_chart/line_chart_data.dart index 22ee479f5..ca0d933df 100644 --- a/lib/src/chart/line_chart/line_chart_data.dart +++ b/lib/src/chart/line_chart/line_chart_data.dart @@ -246,6 +246,8 @@ class LineChartBarData with EquatableMixin { this.isCurved = false, this.curveSmoothness = 0.35, this.preventCurveOverShooting = false, + this.preventCurveOverShootingX = false, + this.preventCurveOverShootingY = false, this.preventCurveOvershootingThreshold = 10.0, this.isStrokeCapRound = false, this.isStrokeJoinRound = false, @@ -262,7 +264,13 @@ class LineChartBarData with EquatableMixin { }) : color = color ?? ((color == null && gradient == null) ? Colors.cyan : null), belowBarData = belowBarData ?? BarAreaData(), - aboveBarData = aboveBarData ?? BarAreaData() { + aboveBarData = aboveBarData ?? BarAreaData(), + assert( + !(preventCurveOverShooting && + (preventCurveOverShootingX || preventCurveOverShootingY)), + 'preventCurveOverShooting cannot be used together with preventCurveOverShootingX or preventCurveOverShootingY. ' + 'Use either preventCurveOverShooting for both axes, or the specific axis variants.', + ) { FlSpot? mostLeft; FlSpot? mostTop; FlSpot? mostRight; @@ -353,6 +361,16 @@ class LineChartBarData with EquatableMixin { /// check this [issue](https://github.com/imaNNeo/fl_chart/issues/25) final bool preventCurveOverShooting; + /// Prevent overshooting when draw curve line on the X-axis only. + /// When true, prevents control points from extending beyond data points horizontally, + /// while allowing natural Y-axis curve smoothing. + final bool preventCurveOverShootingX; + + /// Prevent overshooting when draw curve line on the Y-axis only. + /// When true, prevents control points from extending beyond data points vertically, + /// while allowing natural X-axis curve smoothing. + final bool preventCurveOverShootingY; + /// Applies threshold for [preventCurveOverShooting] algorithm. final double preventCurveOvershootingThreshold; @@ -411,6 +429,8 @@ class LineChartBarData with EquatableMixin { b.preventCurveOvershootingThreshold, t, )!, + preventCurveOverShootingX: b.preventCurveOverShootingX, + preventCurveOverShootingY: b.preventCurveOverShootingY, dotData: FlDotData.lerp(a.dotData, b.dotData, t), errorIndicatorData: FlErrorIndicatorData.lerp( a.errorIndicatorData, @@ -442,6 +462,8 @@ class LineChartBarData with EquatableMixin { double? curveSmoothness, bool? preventCurveOverShooting, double? preventCurveOvershootingThreshold, + bool? preventCurveOverShootingX, + bool? preventCurveOverShootingY, bool? isStrokeCapRound, bool? isStrokeJoinRound, BarAreaData? belowBarData, @@ -468,6 +490,10 @@ class LineChartBarData with EquatableMixin { preventCurveOverShooting ?? this.preventCurveOverShooting, preventCurveOvershootingThreshold: preventCurveOvershootingThreshold ?? this.preventCurveOvershootingThreshold, + preventCurveOverShootingX: + preventCurveOverShootingX ?? this.preventCurveOverShootingX, + preventCurveOverShootingY: + preventCurveOverShootingY ?? this.preventCurveOverShootingY, isStrokeCapRound: isStrokeCapRound ?? this.isStrokeCapRound, isStrokeJoinRound: isStrokeJoinRound ?? this.isStrokeJoinRound, belowBarData: belowBarData ?? this.belowBarData, @@ -494,6 +520,8 @@ class LineChartBarData with EquatableMixin { curveSmoothness, preventCurveOverShooting, preventCurveOvershootingThreshold, + preventCurveOverShootingX, + preventCurveOverShootingY, isStrokeCapRound, isStrokeJoinRound, belowBarData, diff --git a/lib/src/chart/line_chart/line_chart_painter.dart b/lib/src/chart/line_chart/line_chart_painter.dart index 6f47aee2d..a5abda432 100644 --- a/lib/src/chart/line_chart/line_chart_painter.dart +++ b/lib/src/chart/line_chart/line_chart_painter.dart @@ -603,7 +603,18 @@ class LineChartPainter extends AxisChartPainter { getPixelY(barSpots[i + 1 < size ? i + 1 : i].y, viewSize, holder), ); - final controlPoint1 = previous + temp; + /// Determine which axes to prevent overshooting on + final preventCurveOverShootingY = + barData.preventCurveOverShooting || barData.preventCurveOverShootingY; + final preventCurveOverShootingX = + barData.preventCurveOverShooting || barData.preventCurveOverShootingX; + + var controlPoint1 = previous + temp; + + /// Prevent controlPoint1 overshooting in the x-axis + if (preventCurveOverShootingX && controlPoint1.dx > current.dx) { + controlPoint1 = Offset(current.dx, controlPoint1.dy); + } /// if the isCurved is false, we set 0 for smoothness, /// it means we should not have any smoothness then we face with @@ -611,13 +622,15 @@ class LineChartPainter extends AxisChartPainter { final smoothness = barData.isCurved ? barData.curveSmoothness : 0.0; temp = ((next - previous) / 2) * smoothness; - if (barData.preventCurveOverShooting) { + if (preventCurveOverShootingY) { if ((next - current).dy <= barData.preventCurveOvershootingThreshold || (current - previous).dy <= barData.preventCurveOvershootingThreshold) { temp = Offset(temp.dx, 0); } + } + if (preventCurveOverShootingX) { if ((next - current).dx <= barData.preventCurveOvershootingThreshold || (current - previous).dx <= barData.preventCurveOvershootingThreshold) { @@ -625,7 +638,12 @@ class LineChartPainter extends AxisChartPainter { } } - final controlPoint2 = current - temp; + var controlPoint2 = current - temp; + + /// Prevent controlPoint2 overshooting in the x-axis + if (preventCurveOverShootingX && controlPoint2.dx < previous.dx) { + controlPoint2 = Offset(previous.dx, controlPoint2.dy); + } path.cubicTo( controlPoint1.dx,