Flutterのfl_chartのBarChartについて
Flutter の fl_chart の BarChart を使用して UI を実装する機会があったので、その際調べたことについてです。
fl_chart?
Flutter でグラフを表現する際に使用するライブラリで、様々な形式に対応しています。
- Line Chart
- Bar Chart
- Pie Chart
- Scatter Chart
- Radar Chart
公式のドキュメントを見ると、それぞれについてのドキュメントがあります。動画もアップロードされていて、50 分くらいの長さなので動画を見るとより実装イメージが湧くかもしれません。こちらのページには、実際に fl_chart を使用した例が載っています。
また、他の選択肢はどうか?
過去には、charts_flutterというライブラリが、Google から出てたみたいですが、現在はメンテナスされていないようです。
現状だと、以下のライブラリ達が選択肢として上がりそうです。
- fl_chart
- syncfusion_flutter_charts
- graphic
fl_chart 以外の 2 つは実際に使ったことがないので、使いやすさなどは分かりませんが、syncfusion_flutter_charts・graphic のどちらも、カスタマイズ性が高く実装できるようです。
今回、fl_chart を使用した理由としては、pub.dev の LIKE 数が一番多かったのと、そこまで複雑な条件でチャートを表示する必要がなかったので、fl_chart を使用しました。
(こちらの記事を参考に比較させていただきました。)
使い方
BarChart
とBarChartData
を使用して、実際にチャートを表示します。
BarChart
は以下のように定義されています。
class BarChart extends ImplicitlyAnimatedWidget {
/// [data] determines how the [BarChart] should be look like,
/// when you make any change in the [BarChartData], it updates
/// new values with animation, and duration is [duration].
/// also you can change the [curve]
/// which default is [Curves.linear].
BarChart(
this.data, {
this.chartRendererKey,
super.key,
('Please use [duration] instead')
Duration? swapAnimationDuration,
Duration duration = const Duration(milliseconds: 150),
('Please use [curve] instead') Curve? swapAnimationCurve,
Curve curve = Curves.linear,
this.transformationConfig = const FlTransformationConfig(),
}) : assert(
switch (data.alignment) {
BarChartAlignment.center ||
BarChartAlignment.end ||
BarChartAlignment.start =>
transformationConfig.scaleAxis != FlScaleAxis.horizontal &&
transformationConfig.scaleAxis != FlScaleAxis.free,
_ => true,
},
'Can not scale horizontally when BarChartAlignment is center, '
'end or start',
),
super(
duration: swapAnimationDuration ?? duration,
curve: swapAnimationCurve ?? curve,
);
/// Determines how the [BarChart] should be look like.
final BarChartData data;
/// {@macro fl_chart.AxisChartScaffoldWidget.transformationConfig}
final FlTransformationConfig transformationConfig;
/// We pass this key to our renderers which are supposed to
/// render the chart itself (without anything around the chart).
final Key? chartRendererKey;
/// Creates a [_BarChartState]
_BarChartState createState() => _BarChartState();
}
data
というプロパティに、BarChartData
を渡します。ここで渡すBarChartData
にカラーなどの設定をしていくイメージです。
そのほかのduration
やcurve
を使うと、アニメーションを扱うことができるみたいです。
BarChart(
BarChartData(
// ....
),
duration: Duration(milliseconds: 150), // Durationを指定
curve: Curves.linear, // Curvesを指定
);
肝心のBarChartData
は以下のように定義されています。
class BarChartData extends AxisChartData with EquatableMixin {
BarChartData({
List<BarChartGroupData>? barGroups,
double? groupsSpace,
BarChartAlignment? alignment,
FlTitlesData? titlesData,
BarTouchData? barTouchData,
double? maxY,
double? minY,
super.baselineY,
FlGridData? gridData,
super.borderData,
RangeAnnotations? rangeAnnotations,
super.backgroundColor,
ExtraLinesData? extraLinesData,
super.rotationQuarterTurns,
}) : barGroups = barGroups ?? const [],
groupsSpace = groupsSpace ?? 16,
alignment = alignment ?? BarChartAlignment.spaceEvenly,
barTouchData = barTouchData ?? BarTouchData(),
super(
titlesData: titlesData ??
const FlTitlesData(
topTitles: AxisTitles(),
),
gridData: gridData ?? const FlGridData(),
rangeAnnotations: rangeAnnotations ?? const RangeAnnotations(),
touchData: barTouchData ?? BarTouchData(),
extraLinesData: extraLinesData ?? const ExtraLinesData(),
minX: 0,
maxX: 1,
maxY: maxY ?? double.nan,
minY: minY ?? double.nan,
);
/// [BarChart] draws [barGroups] that each of them contains a list of [BarChartRodData].
final List<BarChartGroupData> barGroups;
/// Apply space between the [barGroups].
final double groupsSpace;
/// Arrange the [barGroups], see [BarChartAlignment].
final BarChartAlignment alignment;
/// Handles touch behaviors and responses.
final BarTouchData barTouchData;
/// Copies current [BarChartData] to a new [BarChartData],
/// and replaces provided values.
BarChartData copyWith({
List<BarChartGroupData>? barGroups,
double? groupsSpace,
BarChartAlignment? alignment,
FlTitlesData? titlesData,
RangeAnnotations? rangeAnnotations,
BarTouchData? barTouchData,
FlGridData? gridData,
FlBorderData? borderData,
double? maxY,
double? minY,
double? baselineY,
Color? backgroundColor,
ExtraLinesData? extraLinesData,
int? rotationQuarterTurns,
}) =>
BarChartData(
barGroups: barGroups ?? this.barGroups,
groupsSpace: groupsSpace ?? this.groupsSpace,
alignment: alignment ?? this.alignment,
titlesData: titlesData ?? this.titlesData,
rangeAnnotations: rangeAnnotations ?? this.rangeAnnotations,
barTouchData: barTouchData ?? this.barTouchData,
gridData: gridData ?? this.gridData,
borderData: borderData ?? this.borderData,
maxY: maxY ?? this.maxY,
minY: minY ?? this.minY,
baselineY: baselineY ?? this.baselineY,
backgroundColor: backgroundColor ?? this.backgroundColor,
extraLinesData: extraLinesData ?? this.extraLinesData,
rotationQuarterTurns: rotationQuarterTurns ?? this.rotationQuarterTurns,
);
/// Lerps a [BaseChartData] based on [t] value, check [Tween.lerp].
BarChartData lerp(BaseChartData a, BaseChartData b, double t) {
if (a is BarChartData && b is BarChartData) {
return BarChartData(
barGroups: lerpBarChartGroupDataList(a.barGroups, b.barGroups, t),
groupsSpace: lerpDouble(a.groupsSpace, b.groupsSpace, t),
alignment: b.alignment,
titlesData: FlTitlesData.lerp(a.titlesData, b.titlesData, t),
rangeAnnotations:
RangeAnnotations.lerp(a.rangeAnnotations, b.rangeAnnotations, t),
barTouchData: b.barTouchData,
gridData: FlGridData.lerp(a.gridData, b.gridData, t),
borderData: FlBorderData.lerp(a.borderData, b.borderData, t),
maxY: lerpDouble(a.maxY, b.maxY, t),
minY: lerpDouble(a.minY, b.minY, t),
baselineY: lerpDouble(a.baselineY, b.baselineY, t),
backgroundColor: Color.lerp(a.backgroundColor, b.backgroundColor, t),
extraLinesData:
ExtraLinesData.lerp(a.extraLinesData, b.extraLinesData, t),
rotationQuarterTurns: b.rotationQuarterTurns,
);
} else {
throw Exception('Illegal State');
}
}
/// Used for equality check, see [EquatableMixin].
List<Object?> get props => [
barGroups,
groupsSpace,
alignment,
titlesData,
barTouchData,
maxY,
minY,
baselineY,
gridData,
borderData,
rangeAnnotations,
backgroundColor,
extraLinesData,
rotationQuarterTurns,
];
}
今回実際プロジェクトで使用した際に、使用したプロパティは以下のプロパティだったので、それぞれまとめておきます。
-
barGroups
: 棒グラフをグループごとにまとめて表示する際に使用します。BarChartGroupData
で棒のカラーや高さを指定するプロパティがあり、それらを指定して実際に表示していきます。 -
groupsSpace
: グループごとのスペースを指定します。alignment
が、BarChartAlignment.start
、BarChartAlignment.center
、BarChartAlignment.end
の場合に適用されます。 -
alignment
:Column
などで使用するMainAxisAlignment
と同じような感じで、使用します。 -
titlesData
: チャートのタイトルの部分を指定するFlTitlesData
を指定します。top、right、bottom、left それぞれのタイトルを表示するかどうかや、実際に表示する内容を、FlTitlesData
に定義します。 -
maxY
: 縦軸の最大値を指定します。 -
barTouchData
: チャートをタップした時の挙動を定義します。BarTouchData(enabled: false)
を指定すると、タップした時に何も挙動を起こさないようになります。 -
borderData
: top、right、left、bottom それぞれで、ボーダーを表示するかどうかを定義します。
実際に使用してみてどうだったか?
アニメーションをリッチにしたり、特殊なチャート形式だったりすると、fl_chart 以外の選択肢も出てくるのかもしれませんが、今回はそこまで複雑な UI ではなかったこともあり、fl_chart でも十分対応することができました。
基本的には、fl_chart でほとんどのケースを対応できるのではないでしょうか。
ぜひ使ってみてください。
参考
Discussion