I'm trying to make a linear chart in flutter with syncfusion charts using realtimadb from firebase. I'm storing the data in a List then use it as the data source, the problem is that I don't know how to add all the data when it's changing ( It's considered as one point in the chart even if the value has changed )
<
class InitState extends State{
String? data;
Map,dynamic>? convertedData;
DatabaseReference ref=FirebaseDatabase.instance.refFromURL('https://system-d-arrosage-default-rtdb.firebaseio.com');
@override
void initState() {
ref.onValue.listen((event) {
setState(() {
print(event.snapshot.value);
data=jsonEncode(event.snapshot.value);
convertedData=jsonDecode(data!);
});
});
super.initState();
}
@override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
appBar: AppBar(
title: Text(
'Données',
style: TextStyle(
fontFamily: 'VeronaSerial',
color: Color(0xFFF4F3E9)
),
),
centerTitle: true,
leading: IconButton(
icon: Icon(Icons.arrow_back_outlined),
color: Colors.black,
onPressed: () {
},
),
actions: [
IconButton(
icon : Icon(Icons.settings_outlined),
color: Colors.black,
onPressed: () {
},
)
],
backgroundColor: Color(0xFF00C1C4),
),
backgroundColor: Color(0xFFF4F3E9),
body: StreamBuilder(
stream: ref.onValue,
builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
Widget widget;
if(snapshot.hasData) {
print('snapshot data : ${snapshot.data.snapshot.value.toString()}');
var _data = Data.fromJson(snapshot.data.snapshot.value['Data']);
List chartData = [
//Data(Time:1, Humidity: 10),
];
chartData.add(Data.fromJson(snapshot.data.snapshot.value['Data'])); //the problem is here I need to fetch all the data
widget = Container(
child: SfCartesianChart(
primaryXAxis: DateTimeAxis(),
primaryYAxis: NumericAxis(),
series:, dynamic>>[
LineSeries, dynamic>(
dataSource: chartData,
xValueMapper: (Data data, _) => DateTime.fromMillisecondsSinceEpoch(data.Time.toInt()),
yValueMapper: (Data data, _) => data.Humidity)
],
),
);
return widget;
}
else {
return Container(
height: 220,
child: Text('text'),
);
}
return Container();
},
),
),
);
}
}
class Data {
Data({required this.Humidity, /*required this.Moisture, required this.Temperature,*/ required this.Time});
final double Humidity;
final double Time;
factory Data.fromJson(Map<dynamic, dynamic> json) {
double parser(dynamic source) {
try {
return double.parse(source.toString());
} on FormatException {
return -1;
}
}
return Data(
Humidity: parser(json['Humidity']),
Time: parser(json['Time']));
}
}
>
Hi Mei,
Greetings from Syncfusion. We have tried to reproduce the reported issue with the help of the attached code snippet, but it is not in a runnable state. So, we have attached the KB documentation. It will explain how to get from firebase and map the data with the chart. We hope it will help you to achieve your requirement.
If you are still facing any issues, please get back to us with the sample to reproduce the issue.
Regards,
Yuvaraj.
I followed it before posting my problem but I didn't work because of uncompatible types in the for of loadSlaesData
import 'dart:convert';
import 'dart:async';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_charts/charts.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:json_annotation/json_annotation.dart';
import 'bilanpage.dart';
import 'package:http/http.dart' as http;
class Bilanpage extends StatefulWidget {
@override
State<StatefulWidget> createState() => InitState();
}
class InitState extends State<Bilanpage> {
Future<String> getJsonFromFirebaseRestAPI() async {
String url = "https://system-d-arrosage-default-rtdb.firebaseio.com/Data.json";
http.Response response = await http.get(Uri.parse(url));
return response.body;
}
List<ChartData> chartData = [];
Future loadChartData() async {
String jsonString = await getJsonFromFirebaseRestAPI();
final jsonResponse = json.decode(jsonString);
setState(() {
for (Map<String, dynamic> i in jsonResponse)
chartData.add(ChartData.fromJson(i));
});
}
@override
void initState() {
loadChartData();
super.initState();
}
@override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
appBar: AppBar(
title: Text(
'Données',
style: TextStyle(
fontFamily: 'VeronaSerial',
color: Color(0xFFF4F3E9)
),
),
centerTitle: true,
leading: IconButton(
icon: Icon(Icons.arrow_back_outlined),
color: Colors.black,
onPressed: () {
},
),
actions: [
IconButton(
icon : Icon(Icons.settings_outlined),
color: Colors.black,
onPressed: () {
},
)
],
backgroundColor: Color(0xFF00C1C4),
),
backgroundColor: Color(0xFFF4F3E9),
body : FutureBuilder(
future: getJsonFromFirebaseRestAPI(),
builder: (context, snapShot) {
if (snapShot.hasData) {
return SfCartesianChart(
primaryXAxis: CategoryAxis(),
title: ChartTitle(text: 'Humidity changes'),
series: <ChartSeries<ChartData, String>>[
LineSeries<ChartData, String>(
dataSource: chartData,
xValueMapper: (ChartData data, _) => data.Time,
yValueMapper: (ChartData data, _) => data.Humidity,
)
]
);
}
else{
return CircularProgressIndicator();
}
}
),
),
);
}
}
class ChartData {
ChartData(this.Time, this.Humidity);
final String Time;
final int Humidity;
factory ChartData.fromJson(Map<String, dynamic> parsedJson) {
return ChartData(
parsedJson['Time'].toString(),
parsedJson['Humidity'],
);
}
}
Hi Mei,
We have analyzed your code snippet and found that the JSON data is already in the type of Map<String, dynamic>. So, you cannot to the loop and get the data, this is a reason why you get the error. If you have multiple that is a list of data in the JSON, then your JSON structure should be as follow. In this case, you can have a loop for fetching the data.
|
[ { “key”: “value” }, { “key”: “value” }, { “key”: “value” } ] |
So, you need to change your JSON format like above or just pass the decoded data directly to the class like below.
|
Future loadChartData() async { String jsonString = await getJsonFromFirebaseRestAPI(); final jsonResponse = json.decode(jsonString); setState(() { chartData.add(ChartData.fromJson(jsonResponse)); }); } |
Regards,
Yuvaraj.
Hi , I changed it and nothing appears in the chart it's like it's storing only the first value that's been read
Hi Mei,
You have only one data in the JSON file and have a series type as a LineSeries. So, if you want to show the data point having only one data, please enable the marker in the series. We have attached the code snippet below for your reference.
Code snippet:
|
LineSeries<dynamic, num>( markerSettings: MarkerSettings( isVisible: true, ), // Other required properties ), |
Regards,
Yuvaraj.
Hey , you said that I have only one data in the JSON file but how can I make it read many data ( i need to show many points not only one ) :(
Hi Mei,
You have used for the loop in loadChartData method, but your JSON is not a list, so the exception throws since you have only one data. In our previous update we asked to have the JSON as a list to use for the loop else you can directly bind the data from JSON to the chart and for this only we have shared a code snippet. If you may have more than a data means, kindly have the resultant JSON as a list of your data, so that your existing code (loadChartData method with for loop) will work properly.
Regards,
Yuvaraj.