I am trying to display a bar chart in my app with the syncfusion library. It contains 6 bars where the height is defined by a score and the name is a player name. I have the following methods: getBanditBarData()
which gets the data from a database in creates a list of BanditData-objects (BanditData class shown below), and barChart()
which creates a List of ChartSeries that I can return in the series
parameter of my SfCartesianChart
.
My problem is that the item of the dataSource: item
-line in my barChart()
-method gives the following exception:
_TypeError (type 'BanditData' is not a subtype of type 'List<BanditData>')
I've tried nesting an additional List around each BanditData
object in the list, and even removing the for-loop of the method. Both changes result in similar errors somewhere in the same method.
Future<List<BanditData>> getBanditBarData() async {
var scores = await database.totalScore();
List<BanditData> banditData = [];
for (var score in scores) {
BanditData bandit = BanditData(score['name'], "", score['score']);
banditData.add(bandit);
}
return banditData;
}
List<ChartSeries> barChart(data) {
var barList = <ChartSeries>[];
for (var item in data) {
barList.add(BarSeries<BanditData, String>(
dataSource: item,
xValueMapper: (BanditData b, _) => removeBanditSuffix(b.name),
yValueMapper: (BanditData b, _) => b.score,
animationDuration: 2000));
}
return barList;
}
The BanditData
-class is very simple and looks like this:
class BanditData {
BanditData(this.name, this.date, this.score);
final String name;
final String date;
final int score;
}
The setup shown above works when I render my line chart. The methods are very similar:
Future<List<List<BanditData>>> getBanditLineData() async {
var dates = await database.getDistinctDatesList();
var scores = await database.createScoreDataStruct();
List<List<BanditData>> banditData = [];
for (var i = 0; i < scores.length; i++) {
List<BanditData> temp = [];
var intList = scores[i]['scores'];
for (var j = 0; j < scores[i]['scores'].length; j++) {
BanditData bandit = BanditData(scores[i]['name'], dates[j], intList[j]);
temp.add(bandit);
}
banditData.add(temp);
}
return banditData;
}
List<ChartSeries> lineChart(data) {
var lineList = <ChartSeries>[];
for (var item in data) {
lineList.add(LineSeries<BanditData, String>(
dataSource: item,
xValueMapper: (BanditData b, _) => b.date,
yValueMapper: (BanditData b, _) => b.score,
enableTooltip: true,
name: removeBanditSuffix(item[1].name),
width: 3.0,
animationDuration: 2000,
));
}
return lineList;
}
If necessary, here is some more code showing how I build the chart. The above methods is placed inside MyStatsPageState
, but figured it would be better to split it up for readability.
Ideally, I should be able to replace series: lineChart(lineData)
with series: barChart(barData)
:
import 'database.dart';
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_charts/charts.dart';
class MyStatsPage extends StatefulWidget {
const MyStatsPage({Key? key}) : super(key: key);
@override
MyStatsPageState createState() {
return MyStatsPageState();
}
}
class MyStatsPageState extends State<MyStatsPage> {
late Future<List<List<BanditData>>> _banditLineData;
late Future<List<BanditData>> _banditBarData;
final database = Database();
bool displayLineChart = true;
@override
void initState() {
_banditLineData = getBanditLineData();
_banditBarData = getBanditBarData();
super.initState();
getBanditBarData();
}
@override
Widget build(BuildContext context) {
const appTitle = "Stats";
return Scaffold(
appBar: AppBar(
title: const Text(
appTitle,
style: TextStyle(fontSize: 25, fontWeight: FontWeight.w700),
)),
body: FutureBuilder(
future: Future.wait([_banditLineData, _banditBarData]),
builder: (context, AsyncSnapshot snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(
child: CircularProgressIndicator(),
);
} else {
if (snapshot.hasError) {
return ErrorWidget(Exception(
'Error occured when fetching data from database'));
} else if (!snapshot.hasData) {
return const Center(child: Text('No data found.'));
} else {
final lineData = snapshot.data![0];
final barData = snapshot.data![1];
return Padding(
padding: const EdgeInsets.all(5.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Expanded(
child: SfCartesianChart(
primaryXAxis: CategoryAxis(),
enableAxisAnimation: true,
series: lineChart(lineData),
)),
],
));
}
}
}));
}