Skip to content

fix: disable anti aliasing for chart area#470

Merged
behnam-deriv merged 1 commit intomasterfrom
set-anti-alias-false-for-chart-area
Mar 26, 2026
Merged

fix: disable anti aliasing for chart area#470
behnam-deriv merged 1 commit intomasterfrom
set-anti-alias-false-for-chart-area

Conversation

@behnam-deriv
Copy link
Copy Markdown
Collaborator

@behnam-deriv behnam-deriv commented Mar 26, 2026

fix: reduce CPU usage on line chart area fill during Y-axis zoom

Problem

High CPU usage was observed on the line chart when the Y-axis was zoomed in (vertical padding at minimum). The effect was noticeably worse the more zoomed in the chart was, and improved significantly when zoomed out to maximum padding.

Root cause

The investigation traced the bottleneck to canvas.drawPath in LinePainter.onPaintData, specifically the area fill drawn beneath the line series.

The area fill path is closed all the way down to the bottom of the canvas (size.height). This means the filled polygon covers a pixel area proportional to how much vertical space the line occupies:

  • Zoomed in (min padding): the line spreads across most of the canvas height → the filled polygon covers nearly the entire canvas → maximum GPU fill work.
  • Zoomed out (max padding): the line is compressed into a small band near the centre → the filled polygon covers very few pixels → minimal GPU fill work.

canvas.drawPath with PaintingStyle.fill must rasterise every pixel inside the polygon. The cost scales directly with the number of pixels covered, so CPU usage rose and fell with the zoom level.

Anti-aliasing compounded the cost. Flutter's rasteriser computes sub-pixel edge coverage for every boundary pixel of the filled polygon. For a large filled shape spanning hundreds of pixels vertically this is significant overhead.

The area fill edges are not visible to the user — they sit directly beneath the stroked line drawn on top — so anti-aliased edges on the fill provide no visual benefit.

Solution

Disabling anti-aliasing on the area fill paint:

final Paint areaPaint = Paint()
  ..style = PaintingStyle.fill
  ..isAntiAlias = false   // added
  ..shader = ui.Gradient.linear(...);

Setting isAntiAlias = false tells the rasteriser to skip sub-pixel edge computation entirely and fill pixels with a hard cutoff. Since the stroke line already covers the fill boundary, the visual result is identical to the user while the per-frame GPU cost is substantially reduced regardless of zoom level.

@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai bot commented Mar 26, 2026

Reviewer's guide (collapsed on small PRs)

Reviewer's Guide

Disables anti-aliasing on the filled chart area gradient in the line series painter to adjust rendering behavior/performance.

Class diagram for LinePainter change disabling anti aliasing on chart area

classDiagram
  class DataPainter {
  }

  class LinePainter {
    +paint(canvas, size)
    -createAreaPaint(size) Paint
  }

  class Paint {
    +PaintingStyle style
    +bool isAntiAlias
    +Shader shader
  }

  DataPainter <|-- LinePainter
  LinePainter ..> Paint : uses

  %% Specific configuration for the chart area fill
  class AreaPaintConfiguration {
    +PaintingStyle style = fill
    +bool isAntiAlias = false
    +Shader gradientShader
  }

  LinePainter ..> AreaPaintConfiguration : configures
Loading

File-Level Changes

Change Details Files
Disable anti-aliasing for the line-series chart area fill paint.
  • Set isAntiAlias to false on the Paint used for the chart area when style.hasArea is true
  • Keep existing PaintingStyle.fill and vertical gradient shader configuration unchanged
lib/src/deriv_chart/chart/data_visualization/chart_series/line_series/line_painter.dart

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@github-actions
Copy link
Copy Markdown

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Snapshot Warnings

⚠️: No snapshots were found for the head SHA 73af956.
Ensure that dependencies are being submitted on PR branches and consider enabling retry-on-snapshot-warnings. See the documentation for more information and troubleshooting advice.

OpenSSF Scorecard

PackageVersionScoreDetails

Scanned Manifest Files

@claude
Copy link
Copy Markdown

claude bot commented Mar 26, 2026

Claude finished @behnam-deriv's task —— View job


PR Review Complete ✅

Summary

This PR adds a single line to disable anti-aliasing for the line chart area fill. The change is minimal and focused, but there are some considerations worth discussing.


Review Findings

Correctness & Implementation

Location: lib/src/deriv_chart/chart/data_visualization/chart_series/line_series/line_painter.dart:41

The change is technically correct:

final Paint areaPaint = Paint()
  ..style = PaintingStyle.fill
  ..isAntiAlias = false  // ← Added line
  ..shader = ui.Gradient.linear(...)

What this does: Disables anti-aliasing only for the area fill beneath line charts, not for the line itself (the line stroke still has anti-aliasing enabled by default).


🤔 Code Quality & Design Considerations

Medium Priority Issues:

  1. Inconsistent Anti-Aliasing Strategy

    • The line stroke (linePaint at line 29-32) keeps anti-aliasing enabled (Flutter's default)
    • The area fill (areaPaint at line 39-49) now has it disabled
    • This creates visual inconsistency: sharp-edged fill with smooth line edges

    Question: Is this intentional? Usually you'd want consistent rendering between related elements.

  2. Missing Documentation

    • No comment explaining why anti-aliasing is disabled
    • The commit message mentions "unwanted smoothing artifacts" but doesn't describe:
      • What artifacts were occurring?
      • Why disabling AA fixes them?
      • Are there trade-offs (e.g., jagged edges on diagonal gradients)?

    Recommendation: Add an inline comment:

    final Paint areaPaint = Paint()
      ..style = PaintingStyle.fill
      // Disable anti-aliasing to prevent smoothing artifacts at area boundaries
      ..isAntiAlias = false
      ..shader = ui.Gradient.linear(...)
  3. No Configuration Option

    • This is hardcoded, not configurable via LineStyle
    • If users want anti-aliased area fills, they can't enable it

    Question: Should this be a property in LineStyle class instead? Something like:

    class LineStyle {
      final bool areaAntiAlias;
      // ...
    }

🧪 Testing

Low Priority:

  • No existing tests for LinePainter rendering found
  • No visual regression tests for this change
  • This is a visual/rendering change that's difficult to unit test

Note: Visual changes like this typically require manual testing or golden file tests. Given the project doesn't have painter tests currently, this is consistent with the existing test coverage strategy.


Performance

Positive Impact:

  • Disabling anti-aliasing should slightly improve rendering performance
  • Gradient fills with AA can be computationally expensive
  • Good for financial charts with frequent redraws

🔒 Security

No security concerns.


Recommendations

High Priority

None - the change works as intended.

Medium Priority

  1. Add inline documentation explaining why anti-aliasing is disabled (helps future maintainers)
  2. Consider consistency: Either document why line vs area have different AA settings, or make them consistent

Low Priority

  1. Consider making this configurable if different use cases need different AA settings
  2. Add before/after screenshots to the PR description showing the artifact fix

Verdict

Approval Recommendation: ✅ Approve with suggestions

The change is safe and likely improves rendering quality based on the PR description. The code functions correctly and follows the project's patterns. The medium-priority suggestions are about maintainability and configurability, not correctness.

Quick Win: Add this comment at line 41:

// Disable anti-aliasing to prevent smoothing artifacts at area boundaries
..isAntiAlias = false

Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey - I've left some high level feedback:

  • Disabling isAntiAlias on the area Paint is a non-obvious choice that can affect visual quality, so it would be helpful to document the rationale (e.g. performance, artifact workaround) near this line to make the intent clear for future maintainers.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Disabling `isAntiAlias` on the area `Paint` is a non-obvious choice that can affect visual quality, so it would be helpful to document the rationale (e.g. performance, artifact workaround) near this line to make the intent clear for future maintainers.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@claude
Copy link
Copy Markdown

claude bot commented Mar 26, 2026

Claude finished @behnam-deriv's task —— View job


PR Review Complete ✅

This PR adds a single line to disable anti-aliasing for the line chart area fill. I've analyzed the change against correctness, code quality, performance, security, and testing criteria.


Review Findings

Correctness & Implementation

Location: lib/src/deriv_chart/chart/data_visualization/chart_series/line_series/line_painter.dart:41

The change is correct and solves the stated performance problem:

final Paint areaPaint = Paint()
  ..style = PaintingStyle.fill
  ..isAntiAlias = false  // ← Added line
  ..shader = ui.Gradient.linear(...)

Why this works:

  • The area fill is drawn first (line 59), then the line stroke is drawn on top (line 36)
  • The stroke line completely covers the top edge of the area fill
  • The left/right edges extend to size.height (bottom of canvas) where they're typically not visible
  • Disabling AA on hidden edges removes unnecessary GPU work with zero visual impact

No regressions identified:

  • Change is scoped only to area fill when style.hasArea == true
  • Line stroke retains default anti-aliasing (smooth line rendering)
  • No behavioral changes to path calculation or rendering order

📊 Performance Impact

HIGH PRIORITY - POSITIVE

The PR description's analysis is sound:

  1. Root cause correctly identified: Area fill path covers pixel area proportional to vertical zoom. When zoomed in (min padding), the gradient fills most of the canvas height, maximizing rasterization cost.

  2. Anti-aliasing overhead: Flutter's rasterizer computes sub-pixel edge coverage for every boundary pixel. For a tall filled polygon this is significant overhead.

  3. Solution effectiveness: Setting isAntiAlias = false eliminates sub-pixel edge computation. Since the area edges are hidden beneath the stroke line, this is pure performance gain with no visual cost.

Expected impact: Substantial reduction in frame rendering time when Y-axis is zoomed in, with the improvement scaling proportionally to the visible vertical range.


🔍 Code Quality & Documentation

MEDIUM PRIORITY

Issue: Missing inline documentation

The change lacks a comment explaining the rationale. This is a non-obvious optimization that future maintainers might question or accidentally revert.

Recommendation:

final Paint areaPaint = Paint()
  ..style = PaintingStyle.fill
  // Disable anti-aliasing to reduce GPU fill cost. The area edges are
  // hidden beneath the stroke line, so AA provides no visual benefit.
  ..isAntiAlias = false
  ..shader = ui.Gradient.linear(

This addresses the feedback from both Sourcery-AI and the previous Claude review. Per CLAUDE.md contribution guidelines: "Document non-obvious implementation decisions."


🎨 Design Considerations

LOW PRIORITY

Observation: No configurability

The anti-aliasing setting is now hardcoded. While this is appropriate for the common case (area beneath line), there's no way for users to override it if needed.

Current state:

  • LineStyle class has properties for color, thickness, hasArea, markerRadius, areaGradientColors
  • No property for area anti-aliasing control

Analysis:

  • Adding configurability would require modifying LineStyle class and handling JSON serialization
  • No evidence in the codebase that users need configurable AA for area fills
  • Performance benefit applies universally when the area is beneath a stroke line

Verdict: Hardcoding is acceptable. Configuration can be added later if use cases emerge.


🧪 Testing

LOW PRIORITY

Findings:

  • No test file exists for LinePainter (confirmed via glob search)
  • This is a visual/rendering change that's difficult to unit test
  • Per CLAUDE.md: The project uses flutter test for testing

Observation:
Visual rendering changes like this typically require:

  • Manual visual inspection (likely done during development)
  • Golden file tests (screenshot comparisons)
  • Performance profiling

Recommendation:
While adding visual regression tests would be ideal, this is consistent with the current test coverage strategy. No test changes required for this PR, but the project would benefit from painter tests in the future.


🔒 Security

No concerns. This is a rendering optimization with no security implications.


Summary & Recommendations

✅ High Priority (Must Address)

None - the implementation is correct and safe to merge.

⚠️ Medium Priority (Should Address)

  1. Add inline documentation explaining why anti-aliasing is disabled
    • Helps future maintainers understand the optimization
    • Prevents accidental reversion
    • Aligns with CLAUDE.md contribution guidelines
    • Suggested addition at line 41:
      // Disable anti-aliasing to reduce GPU fill cost. The area edges are
      // hidden beneath the stroke line, so AA provides no visual benefit.
      ..isAntiAlias = false

💡 Low Priority (Consider for Future)

  1. Performance validation: Consider adding before/after profiling data to the PR description to quantify the improvement
  2. Consider configurability if future use cases require AA control for area fills (not needed now)

Verdict

✅ APPROVE with suggestion

This is a well-researched performance optimization with a clear rationale and no visual or functional impact. The code is correct and achieves the stated goal of reducing CPU usage during Y-axis zoom.

Quick win: Add the suggested 2-line comment to document the rationale for maintainability.

The PR description is excellent—it clearly explains the problem, root cause analysis, and solution. This context should ideally be reflected in the code as well via inline comments.


@behnam-deriv behnam-deriv merged commit 8eef98f into master Mar 26, 2026
9 checks passed
@behnam-deriv behnam-deriv deleted the set-anti-alias-false-for-chart-area branch March 26, 2026 10:39
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.

1 participant