smooth_line_chart 0.0.6
smooth_line_chart: ^0.0.6 copied to clipboard
The simplest way to add stunning line charts to your Flutter app. Smooth bezier curves, tap/hover tooltips, dark mode, gradient fill, async data loading — all with zero dependencies.
smooth_line_chart #
Interactive line + area chart for Flutter. Built with CustomPainter — zero external dependencies.
| Light | Dark | Async + range |
|---|---|---|
![]() |
![]() |
![]() |
Features #
- Smooth bezier curves (Catmull-Rom)
- Tap & drag tooltips (mobile) + hover (desktop/web)
- Tap active point again to dismiss tooltip
- Animated range selector (1W / 1M / 3M / etc.)
- Async data loading with built-in loading & error states
- Gradient fill, dots, value labels above each point
- Fully themeable — colors, line style, grid, font styles
- Dark mode preset
onPointTapcallback — open bottom sheets, navigate, etc.yMinfor high-baseline data- Custom empty state widget
- Fixed
heightoraspectRatio
Installation #
dependencies:
smooth_line_chart: ^0.0.4
import 'package:smooth_line_chart/smooth_line_chart.dart';
Usage #
Basic #
SmoothLineChart(
xValues: const ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'],
yValues: const [120000, 340000, 210000, 480000, 390000, 520000],
title: 'Monthly Revenue',
labelFormatter: (v) => 'Rp ${shortNumber(v)}',
)
onPointTap — open a bottom sheet #
Requires a BuildContext, so use it inside a StatefulWidget or Builder.
SmoothLineChart(
xValues: xValues,
yValues: yValues,
qtyValues: qtyValues,
labelFormatter: (v) => 'Rp ${shortNumber(v)}',
onPointTap: (index, x, y, qty, dateRange) {
showModalBottomSheet(
context: context,
builder: (_) => Padding(
padding: const EdgeInsets.all(24),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(x, style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
Text('Rp ${shortNumber(y)}'),
if (qty != null) Text('Orders: $qty'),
],
),
),
);
},
)
Async data + range selector #
SmoothLineChartAsync(
title: 'Sales',
initialRange: '1M',
rangeOptions: const [
RangeOption(label: '1W', value: '1W'),
RangeOption(label: '1M', value: '1M'),
RangeOption(label: '3M', value: '3M'),
RangeOption(label: '6M', value: '6M'),
RangeOption(label: '1Y', value: '1Y'),
],
dataLoader: (range) async {
final json = await api.fetchChart(range);
return ChartData.fromPayload(json);
},
onRangeChanged: (range) => print('switched to $range'),
labelFormatter: (v) => 'Rp ${shortNumber(v)}',
)
Gradient fill + dots + value labels #
SmoothLineChart(
xValues: xValues,
yValues: yValues,
theme: const ChartTheme(
lineColor: Color(0xFF6366F1),
fillGradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [Color(0x556366F1), Colors.transparent],
),
showDots: true,
dotRadius: 4,
showValueLabels: true,
),
)
yMin — zoom in on high-baseline data #
// Without yMin: chart looks flat because baseline is 0
// With yMin: variations are clearly visible
SmoothLineChart(
xValues: xValues,
yValues: const [400000, 420000, 390000, 450000, 430000, 470000],
yMin: 350000,
labelFormatter: (v) => shortNumber(v),
)
Custom empty state #
SmoothLineChart(
xValues: const [],
yValues: const [],
emptyWidget: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.bar_chart_outlined, size: 32, color: Colors.grey),
Text('No data yet'),
],
),
),
)
Card styling + padding #
SmoothLineChart(
xValues: xValues,
yValues: yValues,
backgroundColor: const Color(0xFFF0F0FF),
borderRadius: 16,
padding: const EdgeInsets.all(16),
)
Dark mode #
SmoothLineChart(
xValues: xValues,
yValues: yValues,
theme: ChartTheme.dark,
backgroundColor: const Color(0xFF111827),
borderRadius: 16,
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
)
Custom Y-axis labels #
SmoothLineChart(
xValues: xValues,
yValues: yValues,
yTickValues: const [0, 500000, 1000000, 1500000],
yAxisLabels: const ['0', '500 Rb', '1 Jt', '1.5 Jt'],
)
Fixed height #
SmoothLineChart(
xValues: xValues,
yValues: yValues,
height: 200, // ignores aspectRatio when set
)
Custom tooltip #
ChartCard(
xValues: xValues,
yValues: yValues,
tooltipBuilder: (index, x, y, qty, range) => MyTooltip(label: x, value: y),
)
ChartData — JSON parsing #
// Direct
ChartData(
xValues: ['Jan', 'Feb', 'Mar'],
yValues: [120000.0, 340000.0, 210000.0],
)
// From a plain map
ChartData.fromMap({'Jan': 120000, 'Feb': 340000, 'Mar': 210000})
// From a list of maps
ChartData.fromList(rows, xKey: 'month', yKey: 'revenue', qtyKey: 'orders')
// From any nested API response
// Accepts: { "data": { "record": [...] } } or a flat list directly
ChartData.fromPayload(jsonResponse)
API reference #
SmoothLineChart #
| Parameter | Type | Default | Description |
|---|---|---|---|
xValues |
List<String> |
required | X-axis labels |
yValues |
List<double> |
required | Data points |
qtyValues |
List<int>? |
— | Secondary metric shown in tooltip |
dateRanges |
List<String>? |
— | Subtitle per point in tooltip |
title |
String? |
— | Title above the chart |
theme |
ChartTheme? |
default | Colors, grid, font styles |
yMin |
double? |
0 |
Minimum Y value (useful for high-baseline data) |
yMaxOverride |
double? |
auto | Override Y-axis maximum |
yTickValues |
List<num>? |
auto | Custom Y tick positions |
yAxisLabels |
List<String>? |
auto | Custom Y tick labels |
yLabelOverlay |
bool |
false |
Float Y labels inside the chart area |
tooltipArrow |
bool |
false |
Show downward arrow on tooltip |
backgroundColor |
Color? |
transparent | Card background color |
borderRadius |
double |
0 |
Card corner radius |
padding |
EdgeInsets |
EdgeInsets.zero |
Inner padding around the chart |
emptyWidget |
Widget? |
"No data" text | Widget shown when yValues is empty |
onPointTap |
void Function(int, String, double, int?, String?)? |
— | Called on first tap of a point |
labelFormatter |
String Function(double)? |
v.toString() |
Format Y-axis values |
qtyFormatter |
String Function(int)? |
'Qty: $n' |
Format qty in tooltip |
tooltipBuilder |
Widget Function(...)? |
built-in | Replace tooltip with a custom widget |
aspectRatio |
double |
2.9 |
Width ÷ height ratio (ignored when height is set) |
height |
double? |
— | Fixed height in pixels |
SmoothLineChartAsync (extra params) #
| Parameter | Type | Default | Description |
|---|---|---|---|
dataLoader |
Future<ChartData> Function(String) |
required | Called on mount and on range change |
rangeOptions |
List<RangeOption> |
required | Pills shown in the range selector |
initialRange |
String? |
first option | Range selected on mount |
onRangeChanged |
void Function(String)? |
— | Called when user switches range |
showRangeSelector |
bool |
true |
Show/hide the pill row |
loadingWidget |
Widget? |
spinner | Widget shown while loading |
errorBuilder |
Widget Function(Object)? |
red text | Widget shown on error |
ChartTheme #
| Property | Type | Default | Description |
|---|---|---|---|
lineColor |
Color |
indigo | Line stroke color |
fillColor |
Color |
indigo 20% | Area fill (used when fillGradient is null) |
fillGradient |
Gradient? |
— | Gradient fill below the line |
gridColor |
Color |
dark 12% | Dashed grid line color |
labelColor |
Color |
grey | Fallback label + empty-state text color |
tooltipBackground |
Color |
white | Tooltip card background |
tooltipBorder |
Color |
light grey | Tooltip card border |
tooltipTextColor |
Color |
dark | Tooltip text color |
lineWidth |
double |
3.2 |
Stroke width |
curveSmoothness |
double |
0.22 |
Bezier tension (0 = straight, 0.5 = max curve) |
ySteps |
int |
5 |
Number of auto Y-axis ticks |
showGrid |
bool |
true |
Show/hide dashed grid lines |
showDots |
bool |
false |
Show dots at every data point |
dotRadius |
double |
3.5 |
Dot size |
showValueLabels |
bool |
false |
Show Y value text above each point |
valueLabelStyle |
TextStyle? |
— | Style for value labels |
yLabelStyle |
TextStyle? |
— | Y-axis label font style |
xLabelStyle |
TextStyle? |
— | X-axis label font style |
ChartTheme.dark is a ready-to-use dark mode preset.
Utility functions #
shortNumber(1500000) // '1.5 Jt'
shortNumber(1500) // '1.5 K'
formatThousands(1500000) // '1.500.000'
License #
MIT



