“Stunning and Flexible Charts for Your Apps”

Are you looking to add beautiful, interactive charts to your Flutter app? Look no further than fl_chart! In this week’s Flutter Package Spotlight, we’re diving into fl_chart, a powerful and flexible charting library that allows you to create stunning visualizations with ease.
What is fl_chart?
fl_chart is a highly customizable Flutter chart library that provides a wide range of chart types, including line charts, bar charts, pie charts, scatter charts, and more. It offers a rich set of features and customization options, allowing you to create visually appealing and interactive charts that perfectly fit your app’s design.


Why Use fl_chart?
Flutter developers, here’s why fl_chart should be your go-to package for data visualization:
- Variety of Chart Types: Supports multiple chart types out of the box.
- High Customizability: Easily customize colors, styles, labels, and animations.
- Responsive Design: Charts automatically adjust to different screen sizes.
- Interactive Features: Implement touch interactions, tooltips, and legends with ease.
- Performance: Optimized for smooth performance, even with large datasets.


Key Features of fl_chart
- Line, Bar, Pie, Scatter, and Radar charts
- Customizable axes, gridlines, and labels
- Touch interactions and tooltips
- Animations and transitions
- Ability to combine different chart types
- Support for positive and negative values


Installation Guide
Let’s get fl_chart up and running in your Flutter project:
- Add fl_chart to your
pubspec.yaml
file:
dependencies:
flutter:
sdk: flutter
fl_chart: ^0.62.0
Run flutter pub get
to fetch the package.
Example Use Cases
Let’s dive into some practical examples to showcase fl_chart’s capabilities!
Example 1: Line Chart
Here’s an example of creating a simple line chart with fl_chart:
import 'package:flutter/material.dart';
import 'package:fl_chart/fl_chart.dart';
class SimpleLineChart extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Simple Line Chart')),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: LineChart(
LineChartData(
gridData: FlGridData(show: false),
titlesData: FlTitlesData(show: false),
borderData: FlBorderData(show: false),
minX: 0,
maxX: 7,
minY: 0,
maxY: 6,
lineBarsData: [
LineChartBarData(
spots: [
FlSpot(0, 3),
FlSpot(1, 1),
FlSpot(2, 4),
FlSpot(3, 2),
FlSpot(4, 5),
FlSpot(5, 1),
FlSpot(6, 4),
],
isCurved: true,
color: Colors.blue,
barWidth: 4,
isStrokeCapRound: true,
dotData: FlDotData(show: false),
belowBarData: BarAreaData(show: false),
),
],
),
),
),
);
}
}
This example creates a basic line chart with a curved line and no grid or titles, demonstrating the simplicity of creating charts with fl_chart.
Example 2: Bar Chart with Custom Styling
Let’s create a more complex bar chart with custom styling and interactivity:
import 'package:flutter/material.dart';
import 'package:fl_chart/fl_chart.dart';
class CustomBarChart extends StatefulWidget {
@override
_CustomBarChartState createState() => _CustomBarChartState();
}
class _CustomBarChartState extends State<CustomBarChart> {
final Color barBackgroundColor = const Color(0xff72d8bf);
final Duration animDuration = const Duration(milliseconds: 250);
int touchedIndex = -1;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Custom Bar Chart')),
body: Padding(
padding: const EdgeInsets.all(16),
child: BarChart(
mainBarData(),
swapAnimationDuration: animDuration,
),
),
);
}
BarChartGroupData makeGroupData(
int x,
double y, {
bool isTouched = false,
Color barColor = Colors.white,
double width = 22,
List<int> showTooltips = const [],
}) {
return BarChartGroupData(
x: x,
barRods: [
BarChartRodData(
toY: isTouched ? y + 1 : y,
color: isTouched ? Colors.yellow : barColor,
width: width,
backDrawRodData: BackgroundBarChartRodData(
show: true,
toY: 20,
color: barBackgroundColor,
),
),
],
showingTooltipIndicators: showTooltips,
);
}
List<BarChartGroupData> showingGroups() => List.generate(7, (i) {
switch (i) {
case 0:
return makeGroupData(0, 5, isTouched: i == touchedIndex);
case 1:
return makeGroupData(1, 6.5, isTouched: i == touchedIndex);
case 2:
return makeGroupData(2, 5, isTouched: i == touchedIndex);
case 3:
return makeGroupData(3, 7.5, isTouched: i == touchedIndex);
case 4:
return makeGroupData(4, 9, isTouched: i == touchedIndex);
case 5:
return makeGroupData(5, 11.5, isTouched: i == touchedIndex);
case 6:
return makeGroupData(6, 6.5, isTouched: i == touchedIndex);
default:
return throw Error();
}
});
BarChartData mainBarData() {
return BarChartData(
barTouchData: BarTouchData(
touchTooltipData: BarTouchTooltipData(
tooltipBgColor: Colors.blueGrey,
getTooltipItem: (group, groupIndex, rod, rodIndex) {
String weekDay;
switch (group.x.toInt()) {
case 0:
weekDay = 'Monday';
break;
case 1:
weekDay = 'Tuesday';
break;
case 2:
weekDay = 'Wednesday';
break;
case 3:
weekDay = 'Thursday';
break;
case 4:
weekDay = 'Friday';
break;
case 5:
weekDay = 'Saturday';
break;
case 6:
weekDay = 'Sunday';
break;
default:
throw Error();
}
return BarTooltipItem(
weekDay + '\n',
TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 18,
),
children: <TextSpan>[
TextSpan(
text: (rod.toY - 1).toString(),
style: TextStyle(
color: Colors.yellow,
fontSize: 16,
fontWeight: FontWeight.w500,
),
),
],
);
},
),
touchCallback: (FlTouchEvent event, barTouchResponse) {
setState(() {
if (!event.isInterestedForInteractions ||
barTouchResponse == null ||
barTouchResponse.spot == null) {
touchedIndex = -1;
return;
}
touchedIndex = barTouchResponse.spot!.touchedBarGroupIndex;
});
},
),
titlesData: FlTitlesData(
show: true,
bottomTitles: AxisTitles(
sideTitles: SideTitles(
showTitles: true,
getTitlesWidget: getTitles,
reservedSize: 38,
),
),
leftTitles: AxisTitles(
sideTitles: SideTitles(showTitles: false),
),
topTitles: AxisTitles(
sideTitles: SideTitles(showTitles: false),
),
rightTitles: AxisTitles(
sideTitles: SideTitles(showTitles: false),
),
),
borderData: FlBorderData(
show: false,
),
barGroups: showingGroups(),
gridData: FlGridData(show: false),
);
}
Widget getTitles(double value, TitleMeta meta) {
const style = TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 14,
);
Widget text;
switch (value.toInt()) {
case 0:
text = const Text('M', style: style);
break;
case 1:
text = const Text('T', style: style);
break;
case 2:
text = const Text('W', style: style);
break;
case 3:
text = const Text('T', style: style);
break;
case 4:
text = const Text('F', style: style);
break;
case 5:
text = const Text('S', style: style);
break;
case 6:
text = const Text('S', style: style);
break;
default:
text = const Text('', style: style);
break;
}
return SideTitleWidget(
axisSide: meta.axisSide,
space: 16,
child: text,
);
}
}
This example demonstrates a more complex bar chart with custom styling, animations, and interactive tooltips. It shows weekly data with each bar representing a day of the week.
Example 3: Pie Chart with Sections
Let’s create a pie chart with interactive sections:
import 'package:fl_chart/fl_chart.dart';
import 'package:flutter/material.dart';
class InteractivePieChart extends StatefulWidget {
@override
State<StatefulWidget> createState() => PieChartState();
}
class PieChartState extends State {
int touchedIndex = -1;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Interactive Pie Chart')),
body: AspectRatio(
aspectRatio: 1.3,
child: Card(
color: Colors.white,
child: Row(
children: <Widget>[
const SizedBox(
height: 18,
),
Expanded(
child: AspectRatio(
aspectRatio: 1,
child: PieChart(
PieChartData(
pieTouchData: PieTouchData(
touchCallback: (FlTouchEvent event, pieTouchResponse) {
setState(() {
if (!event.isInterestedForInteractions ||
pieTouchResponse == null ||
pieTouchResponse.touchedSection == null) {
touchedIndex = -1;
return;
}
touchedIndex = pieTouchResponse.touchedSection!.touchedSectionIndex;
});
},
),
borderData: FlBorderData(
show: false,
),
sectionsSpace: 0,
centerSpaceRadius: 40,
sections: showingSections(),
),
),
),
),
Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.start,
children: const <Widget>[
Indicator(
color: Color(0xff0293ee),
text: 'First',
isSquare: true,
),
SizedBox(
height: 4,
),
Indicator(
color: Color(0xfff8b250),
text: 'Second',
isSquare: true,
),
SizedBox(
height: 4,
),
Indicator(
color: Color(0xff845bef),
text: 'Third',
isSquare: true,
),
SizedBox(
height: 4,
),
Indicator(
color: Color(0xff13d38e),
text: 'Fourth',
isSquare: true,
),
SizedBox(
height: 18,
),
],
),
const SizedBox(
width: 28,
),
],
),
),
),
);
}
List<PieChartSectionData> showingSections() {
return List.generate(4, (i) {
final isTouched = i == touchedIndex;
final fontSize = isTouched ? 25.0 : 16.0;
final radius = isTouched ? 60.0 : 50.0;
switch (i) {
case 0:
return PieChartSectionData(
color: const Color(0xff0293ee),
value: 40,
title: '40%',
radius: radius,
titleStyle: TextStyle(
fontSize: fontSize,
fontWeight: FontWeight.bold,
color: const Color(0xffffffff),
),
);
case 1:
return PieChartSectionData(
color: const Color(0xfff8b250),
value: 30,
title: '30%',
radius: radius,
titleStyle: TextStyle(
fontSize: fontSize,
fontWeight: FontWeight.bold,
color: const Color(0xffffffff),
),
);
case 2:
return PieChartSectionData(
color: const Color(0xff845bef),
value: 15,
title: '15%',
radius: radius,
titleStyle: TextStyle(
fontSize: fontSize,
fontWeight: FontWeight.bold,
color: const Color(0xffffffff),
),
);
case 3:
return PieChartSectionData(
color: const Color(0xff13d38e),
value: 15,
title: '15%',
radius: radius,
titleStyle: TextStyle(
fontSize: fontSize,
fontWeight: FontWeight.bold,
color: const Color(0xffffffff),
),
);
default:
throw Error();
}
});
}
}
class Indicator extends StatelessWidget {
final Color color;
final String text;
final bool isSquare;
final double size;
final Color textColor;
const Indicator({
Key? key,
required this.color,
required this.text,
required this.isSquare,
this.size = 16,
this.textColor = const Color(0xff505050),
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Row(
children: <Widget>[
Container(
width: size,
height: size,
decoration: BoxDecoration(
shape: isSquare ? BoxShape.rectangle : BoxShape.circle,
color: color,
),
),
const SizedBox(
width: 4,
),
Text(
text,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: textColor,
),
)
],
);
}
}
This example showcases an interactive pie chart with custom colors, labels, and a legend. When a section is tapped, it enlarges slightly for emphasis.
Conclusion
fl_chart is more than just a charting package — it’s a powerful tool that can significantly enhance the data visualization capabilities of your Flutter applications. By providing a wide range of chart types and extensive customization options, fl_chart empowers you to create stunning, interactive charts that can bring your data to life. Whether you’re building a simple app with basic charts or a complex data-driven application with intricate visualizations, fl_chart offers the flexibility and features you need to create impactful data presentations. Have you used fl_chart in your projects? Share your experiences or any cool customizations you’ve made in the comments below! And don’t forget to tune in next week for another exciting Flutter Package Spotlight. Happy coding, Flutter enthusiasts!