Skip to content

feat: Enhanced line chart curve function#2000

Open
huanghui1998hhh wants to merge 12 commits intoimaNNeo:mainfrom
huanghui1998hhh:feature/line_smooth
Open

feat: Enhanced line chart curve function#2000
huanghui1998hhh wants to merge 12 commits intoimaNNeo:mainfrom
huanghui1998hhh:feature/line_smooth

Conversation

@huanghui1998hhh
Copy link
Copy Markdown
Contributor

@huanghui1998hhh huanghui1998hhh commented Sep 17, 2025

This PR enhances the curve API:

  1. Keeps the existing curve algorithm.
  2. Add a new curve algorithm copied from ECharts.
  3. Allows users to provide their own curve drawing logic in whatever way they prefer.
  4. Fully preserved the existing implicit animation when toggling between curved and straight lines.
  5. The old API has not been removed. It is marked as deprecated and remains backward-compatible.
Before (old params) After (new param)
isCurved: false curve: LineChartCurve.noCurve
isCurved: true curve: const LineChartCubicTensionCurve()
isCurved: true, curveSmoothness: S, preventCurveOverShooting: P, preventCurveOvershootingThreshold: T curve: const LineChartCubicTensionCurve(smoothness: S, preventCurveOverShooting: P, preventCurveOvershootingThreshold: T)

I’m not entirely sure whether these decisions align with your original vision, please give me some advice. I'll complete the follow-up work.
@imaNNeo

@codecov
Copy link
Copy Markdown

codecov bot commented Sep 17, 2025

Codecov Report

❌ Patch coverage is 99.31973% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 92.97%. Comparing base (af78a41) to head (3c31543).
⚠️ Report is 10 commits behind head on main.

Files with missing lines Patch % Lines
lib/src/chart/line_chart/line_chart_curve.dart 99.29% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2000      +/-   ##
==========================================
+ Coverage   92.55%   92.97%   +0.41%     
==========================================
  Files          50       51       +1     
  Lines        3760     3884     +124     
==========================================
+ Hits         3480     3611     +131     
+ Misses        280      273       -7     
Flag Coverage Δ
flutter 92.97% <99.31%> (+0.41%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@imaNNeo
Copy link
Copy Markdown
Owner

imaNNeo commented Oct 25, 2025

It looks good!
Can you please write the needed unit-tests and update the documentation? both in our dart code and markdown files.

@huanghui1998hhh
Copy link
Copy Markdown
Contributor Author

huanghui1998hhh commented Oct 28, 2025

@imaNNeo Done! Please review.

@afijal
Copy link
Copy Markdown

afijal commented Feb 23, 2026

This works a lot better than og algo, any chance of merging it?

@huanghui1998hhh
Copy link
Copy Markdown
Contributor Author

@imaNNeo Hi~ Any work on it?

}
}

static LineChartCurve _resovleCurve(
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a typo in _resovleCurve

preventCurveOvershootingThreshold: preventCurveOvershootingThreshold,
);

static Offset _flag = Offset.zero;
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to keep a mutable static field inside our const LineChartCubicTensionCurve()?
Is it needed? Can we remove that?

tinyThresholdSquared: tinyThresholdSquared,
);

static Offset? _flag;
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same for here


static const noCurve = LineChartNoCurve();

static LineChartCubicTensionCurve cubicTension({
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we remove these static functions? Because it's not scalable, for every new type we should add a new function here.
(We can keep the noCurve, but let's not add others).

I see that we use them only for testing. So we can use the constructor LineChartCubicTensionCurve() instead.

preventCurveOvershootingThreshold: preventCurveOvershootingThreshold,
);

static LineChartCubicMonotoneCurve cubicMonotone({
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The same for here

}

class LineChartCubicTensionCurve
extends LineChartCurve<LineChartCubicTensionCurve> with EquatableMixin {
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think with EquatableMixin is redundant here (we can remove it)

return b;
}

abstract class LineChartCurve<T extends LineChartCurve<T>> with EquatableMixin {
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand why we need to have this Generic type here? <T extends LineChartCurve<T>>

We can have the lerp function like this:

LineChartCurve lerp(covariant LineChartCurve other, double t);

And it already works well! (without the need to have a generic type)

lineChartStepData: lineChartStepData ?? this.lineChartStepData,
);

LineChartCurve? _resolveCopyWithCurve(
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The logic that we have in this method is a bit complicated. And it seems it silently ignores deprecated params when the current curve is not LineChartCubicTensionCurve.

I think we can have it simpler like this:

LineChartBarData copyWith({
  ...
}) =>
    LineChartBarData(
      ...
      curve: curve ?? _resolveCopyWithCurve(
        isCurved,
        curveSmoothness,
        preventCurveOverShooting,
        preventCurveOvershootingThreshold,
      ),
      ...
    );

LineChartCurve _resolveCopyWithCurve(
  bool? isCurved,
  double? curveSmoothness,
  bool? preventCurveOverShooting,
  double? preventCurveOvershootingThreshold,
) {
  final thisCurve = curve;
  if (isCurved == null) return thisCurve;
  if (!isCurved) return LineChartCurve.noCurve;
  if (thisCurve is LineChartCubicTensionCurve) {
    return LineChartCubicTensionCurve(
      smoothness: curveSmoothness ?? thisCurve.smoothness,
      preventCurveOverShooting:
      preventCurveOverShooting ?? thisCurve.preventCurveOverShooting,
      preventCurveOvershootingThreshold:
      preventCurveOvershootingThreshold ??
          thisCurve.preventCurveOvershootingThreshold,
    );
  }
  return LineChartCubicTensionCurve(
    smoothness: curveSmoothness ?? 0.35,
    preventCurveOverShooting: preventCurveOverShooting ?? false,
    preventCurveOvershootingThreshold: preventCurveOvershootingThreshold ?? 10.0,
  );
}

(I also double checked it with an LLM, and it seems it covers all the edge cases)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And it would be very nice if you could write some unit tests that cover the backward compatibility for the constructor and copyWith functions. (For example, construct with deprecated params, and use copyWith using the new implementation, or the other way around)

Thanks!

@imaNNeo imaNNeo changed the title feat: enhanced line chart curve function feat: Enhanced line chart curve function Mar 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants