Skip to content

feat: chart interactivity, non-finite robustness, and full API docs (0.3.0) - #2

Merged
AndroidPoet merged 3 commits into
mainfrom
feat/interactivity-and-robustness
Jun 28, 2026
Merged

AndroidPoet merged 3 commits into
mainfrom
feat/interactivity-and-robustness

Conversation

@AndroidPoet

Copy link
Copy Markdown
Owner

Summary

Makes the Flutter charting library interactive and hardens it to ship-grade. Three pillars: interactivity (opt-in, no new deps), non-finite robustness (real crash fixes), and complete public-API docs + a much larger test suite. Bumps to 0.3.0.

Interactivity

Render-only charts can now be made interactive by wrapping any cartesian renderer:

InteractiveChart(
  renderer: LineChartRenderer(points: data),
  interaction: ChartInteraction(
    tooltip: true,
    selection: true,
    rangeSelection: true,
    onSelected: (sel) => ...,
    onRangeSelected: (range) => ...,
  ),
)
  • New InteractiveChart wrapper + ChartInteraction config β€” trackball/tooltip, tap-to-select, drag range-select, all painted on the same Canvas (reuses the reveal animation, zero new dependencies).
  • New retained-geometry layer: InteractiveRenderer interface, ChartScene/PlotMark, reversible CartesianScale, ChartHitTest, and a LabelLayout de-overlap helper. Paint geometry and hit-test geometry share one scale so they can't drift.
  • Cartesian renderers implement buildScene(). ChartRenderer/InteractiveRenderer are re-exported, and a duration knob was added to every chart widget (defaults preserve prior behavior).
  • Non-interactive / non-cartesian renderers degrade gracefully (no-op).

Robustness

  • Added drafterFinite / drafterFiniteOrNull sanitizers applied at value ingestion across all renderers. This fixes release-mode crashes where NaN/Infinity reached .toInt() (histogram bins, bubble nice-number rounding, axis steps), plus 5 bar-chart buildScene non-finite centers caught by the new tests.
  • InteractiveChart.didUpdateWidget resets the cached scene + interaction state on renderer swap (no stale highlight); _publish is guarded against post-dispose pointer events; hit-test + CartesianScale.nearestIndex guard non-finite pixels.

Docs & quality

  • Documented every public member and enabled public_member_api_docs as an enforced gate β€” a clean analyze now proves doc completeness.
  • @immutable on all data classes (intentionally not on renderers that hold size-keyed memo caches).
  • Tests 57 β†’ 196 (robustness_test.dart matrix: empty/single/all-equal/negative/NaN/Inf across every renderer + all widgets; interaction_behavior_test.dart: hover/tap/drag/dispose/renderer-swap/scene-cache). Line coverage 96.3%.

Verification

  • flutter analyze β€” No issues found (with public_member_api_docs on)
  • flutter test β€” 196/196 pass
  • dart format β€” clean
  • dart pub publish --dry-run β€” only the benign uncommitted-files notice

Interactivity (opt-in, zero new deps):
- InteractiveChart wrapper + ChartInteraction config (tooltip/trackball,
  tap-select, drag range-select) painted on the same Canvas
- InteractiveRenderer interface + ChartScene/PlotMark retained geometry,
  reversible CartesianScale, ChartHitTest, LabelLayout de-overlap
- cartesian renderers implement buildScene(); ChartRenderer/InteractiveRenderer
  re-exported; duration param added to every chart widget

Robustness:
- drafterFinite/drafterFiniteOrNull sanitizers applied at value ingestion
  across all renderers; fixes release-mode crashes where NaN/Infinity reached
  .toInt() (histogram bins, bubble nice-numbers, axis steps) and 5 bar-chart
  buildScene non-finite centers
- InteractiveChart.didUpdateWidget resets cached scene/state on renderer swap;
  _publish guarded against post-dispose pointer events; hit-test guards non-finite

Docs & quality:
- documented every public member; enabled public_member_api_docs as the gate
- @immutable on all data classes
- tests 57 -> 196 (robustness matrix + interaction behavior); line coverage 96.3%
A theme-aware legend for multi-series charts. Build from explicit
LegendItems or from labels (DrafterLegend.fromLabels, colored by the
active theme palette). Horizontal (wrapping) or vertical layout;
square/circle/line markers; optional onItemTap for series toggling.

Exported from package:drafter/drafter.dart; documented under the
public_member_api_docs gate; 11 widget/unit tests; README + CHANGELOG
+ example gallery tile.
@AndroidPoet
AndroidPoet merged commit 75d81bf into main Jun 28, 2026
1 check failed
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