save_points_chart
A modern Flutter charting library with canvas-based rendering, Material 3–friendly themes, smooth animations, and zero third-party runtime dependencies (Flutter SDK only).
Features
- 15+ chart types — line, bar, area, pie/donut, scatter, radar, gauge, sparkline, stacked area, waterfall, funnel, bubble, heatmap, candlestick, and timeline
- Unified API — every chart uses
ChartConfig+ a typed widget (LineChart,BarChart, …) - Interactions — tooltips, crosshair, tap selection, pinch zoom & pan (where applicable)
- Theming —
ChartTheme.light(),ChartTheme.dark(),ChartTheme.dashboard(), or fully custom colors - Templates —
ChartTemplateStyle.dashboard(title, legend, grid) orplain(minimal chrome) - Animations — configurable duration and curve tension for smooth line/area transitions
- Export — snapshot charts as PNG; optional PDF reports via
ChartWidgetController/ChartCard - Accessibility —
semanticLabelonChartConfigfor screen readers - Extensible engine — layer stack, render pipeline, and
ChartRendererplugins for custom charts
Installation
Add to pubspec.yaml:
dependencies:
save_points_chart: ^1.9.1
Import the public API:
import 'package:save_points_chart/save_points_charts.dart';
Quick start
import 'package:flutter/material.dart';
import 'package:save_points_chart/save_points_charts.dart';
class TrafficChart extends StatelessWidget {
const TrafficChart({super.key});
@override
Widget build(BuildContext context) {
final config = ChartConfig(
title: 'Traffic trend',
subtitle: 'Desktop vs mobile',
xAxisTitle: 'Month',
yAxisTitle: 'Users',
showLegend: true,
template: ChartTemplateStyle.dashboard,
series: [
ChartSeries(
id: 'desktop',
name: 'Desktop',
points: const [
ChartPoint(x: 0, y: 220, label: 'Jan'),
ChartPoint(x: 1, y: 260, label: 'Feb'),
ChartPoint(x: 2, y: 240, label: 'Mar'),
],
),
ChartSeries(
id: 'mobile',
name: 'Mobile',
points: const [
ChartPoint(x: 0, y: 140, label: 'Jan'),
ChartPoint(x: 1, y: 180, label: 'Feb'),
ChartPoint(x: 2, y: 200, label: 'Mar'),
],
),
],
);
return SizedBox(
height: 280,
child: LineChart(config: config),
);
}
}
Chart types
| Widget | Description | Notable options |
|---|---|---|
LineChart |
Cartesian line series | LineChartMode.straight / smooth, fillArea |
BarChart |
Vertical or horizontal bars | BarChartOrientation, BarChartLayout.grouped / stacked |
AreaChart |
Filled area under lines | Shares line renderer with fill |
PieChart |
Pie or donut slices | isDonut, explodedIndex |
ScatterChart |
XY scatter plot | — |
RadarChart |
Spider / radar chart | Label per point |
GaugeChart |
Single-value gauge | First point y = value |
SparklineChart |
Compact line (no axes chrome) | — |
StackedAreaChart |
Stacked filled areas | Multiple series |
WaterfallChart |
Running totals / P&L steps | kWaterfallTypeKey metadata |
FunnelChart |
Conversion funnel | Decreasing y values |
BubbleChart |
Sized bubbles in XY space | toBubblePoints() extension |
HeatmapChart |
Grid heatmap | — |
CandlestickChart |
OHLC-style financial bars | — |
TimelineChart |
Event timeline | — |
Data model
ChartPoint
A single (x, y) value with optional label and metadata (used for waterfall types, bubble size, etc.).
const ChartPoint(x: 0, y: 72, label: 'CPU');
ChartSeries
Named list of points with optional SeriesStyle (color, stroke, markers, gradient).
ChartSeries(
id: 'sales',
name: 'Sales',
points: [20, 25, 30, 28, 35].toChartPoints(),
style: const SeriesStyle(showMarkers: true),
);
ChartConfig
Global settings shared by all chart widgets:
| Property | Purpose |
|---|---|
series |
One or more ChartSeries |
title / subtitle |
Header text (dashboard template) |
xAxisTitle / yAxisTitle |
Axis labels |
theme |
Override ChartTheme |
template |
dashboard or plain |
showGrid / showAxis |
Cartesian chrome |
showLegend / legendPosition |
Legend placement |
animate / animationDuration |
Entry animation |
curveTension |
Smooth line curvature (0–1) |
viewport |
Zoom/pan bounds (ChartViewport) |
semanticLabel |
Accessibility label |
Convenience extensions
// Iterable<num> → List<ChartPoint>
[20, 25, 30].toChartPoints();
// List<ChartPoint> → ChartSeries
points.toSeries(id: 'a', name: 'Product A');
// (x, y, size) tuples → bubble points
[(10, 20, 40), (25, 35, 80)].toBubblePoints();
Waterfall metadata
Use kWaterfallTypeKey in point metadata for special bars:
ChartPoint(
x: 0,
y: 100,
label: 'Start',
metadata: {kWaterfallTypeKey: 'absolute'},
),
ChartPoint(
x: 3,
y: 0,
label: 'Subtotal',
metadata: {kWaterfallTypeKey: 'subtotal'},
),
Supported values: delta (default), absolute, subtotal, total.
Theming
ChartConfig(
theme: ChartTheme.dark(),
// or ChartTheme.light(), ChartTheme.dashboard()
series: [...],
);
ChartTheme controls background, grid, axis, tooltip, crosshair, selection highlight, series palette, shadows, and typography. Per-series colors can override the palette via SeriesStyle.color.
Interactions
ChartWidget (used internally by every chart) supports:
- Tooltip — hover/tap hit testing (
enableTooltip, defaulttrue) - Crosshair — follows pointer on cartesian charts (
enableCrosshair) - Zoom & pan — pinch/drag on cartesian charts (
enableZoomPan) - Selection —
onSelection: (ChartHitResult hit) { ... }
Pie, gauge, heatmap, and similar charts disable zoom/crosshair where it does not apply.
Export (PNG / PDF)
Attach a ChartWidgetController and optionally wrap with ChartCard for toolbar buttons:
final controller = ChartWidgetController();
ChartCard(
config: config,
controller: controller,
child: LineChart(config: config, controller: controller),
);
// Programmatic export
final pngBytes = await controller.exportPng();
final pdfBytes = await controller.exportPdfFromConfig(config);
Low-level API without a controller:
final bytes = await ChartExport.toPng(globalKey);
Charts render inside a RepaintBoundary; exports capture the canvas (tooltips overlay is excluded).
Custom charts
Build on the engine layer exported from save_points_charts.dart:
- Implement
ChartRendererwith adraw(Canvas, Size, ChartContext)method. - Pass your renderer to
ChartWidget(config: ..., renderers: [MyRenderer()]). - Optionally register plugins via
PluginRegistryand compose layers (GridLayer,AxisLayer,SeriesLayer, …).
Architecture
ChartWidget
└── ChartEngine (config + theme + renderers)
└── RenderPipeline / LayerStack
└── ChartPainter (CustomPaint)
Models live under lib/models/, canvas renderers under lib/charts/, and shared infrastructure (axis, gestures, tooltips, zoom) under lib/core/.
Example app
cd example
flutter run
The demo includes a dashboard layout and an “All charts” gallery with export buttons.
Links
License
Apache License 2.0 — see LICENSE.
Libraries
- charts/area_chart/area_chart_renderer
- charts/bar_chart/bar_chart_renderer
- charts/bubble_chart/bubble_chart_renderer
- charts/candlestick_chart/candlestick_chart_renderer
- charts/funnel_chart/funnel_chart_renderer
- charts/gauge_chart/gauge_chart_renderer
- charts/heatmap_chart/heatmap_chart_renderer
- charts/line_chart/line_chart_renderer
- charts/pie_chart/pie_chart_renderer
- charts/radar_chart/radar_chart_renderer
- charts/scatter_chart/scatter_chart_renderer
- charts/sparkline_chart/sparkline_chart_renderer
- charts/stacked_area_chart/stacked_area_chart_renderer
- charts/timeline_chart/timeline_chart_renderer
- charts/waterfall_chart/waterfall_chart_renderer
- core/animations/chart_animation_controller
- core/animations/interpolation
- core/axis/axis_engine
- core/canvas/chart_exporter
- core/chrome/chart_chrome
- core/coordinates/chart_bounds
- core/coordinates/coordinate_transformer
- core/engine/chart_context
- core/engine/chart_engine
- core/engine/chart_renderer
- core/engine/plugin_registry
- core/engine/render_pipeline
- core/gestures/gesture_engine
- core/interactions/hit_test_engine
- core/interactions/hit_test_result
- core/layers/axis_layer
- core/layers/background_layer
- core/layers/chart_layer
- core/layers/chrome_layer
- core/layers/grid_layer
- core/layers/interaction_layer
- core/layers/layer_stack
- core/layers/overlay_layer
- core/layers/series_layer
- core/painters/chart_painter
- core/scaling/zoom_pan_controller
- core/theme/chart_template
- core/theme/chart_theme
- core/tooltip/tooltip_controller
- core/tooltip/tooltip_data
- core/tooltip/tooltip_overlay
- core/utils/bezier
- core/utils/paint_cache
- core/utils/rounded_bar
- extensions/chart_extensions
- models/chart_config
- models/chart_data
- models/chart_point
- models/chart_series
- models/chart_template_style
- models/legend_position
- models/viewport
- save_points_charts
- widgets/area_chart
- widgets/bar_chart
- widgets/bubble_chart
- widgets/candlestick_chart
- widgets/chart_card
- widgets/chart_widget
- widgets/chart_widget_controller
- widgets/funnel_chart
- widgets/gauge_chart
- widgets/heatmap_chart
- widgets/line_chart
- widgets/pie_chart
- widgets/radar_chart
- widgets/scatter_chart
- widgets/sparkline_chart
- widgets/stacked_area_chart
- widgets/timeline_chart
- widgets/waterfall_chart