'How to create two dynamic SfCartesianChart in Flutter?
I am trying to create multiple dynamic charts (SfCartesianChart from syncfusion), the data is extracted every 1 second from a dynamic json file. I tried to create two charts; the first one works fine but the second one remains the same , it does not change.
This is what I am getting.
Here is my code
import 'dart:ui';
import 'dart:async';
import 'package:syncfusion_flutter_gauges/gauges.dart';
import 'package:flutter/material.dart';
import 'package:applicationv1/constants.dart';
import 'package:http/http.dart' as http;
import 'package:syncfusion_flutter_charts/charts.dart';
import 'package:applicationv1/classDonnee.dart';
import 'dart:convert';
Future<Donnee> fetchDonnee() async {
print('fetch0');
final response = await http.get(Uri.parse('uri'));
if (response.statusCode == 200) {
print('fecth1');
// If the server did return a 200 OK response, then parse the JSON.
return Donnee.fromJson(jsonDecode(response.body));
} else {
// If the server did not return a 200 OK response, then throw an exception.
throw Exception('Failed to load album');
}
}
class depart1 extends StatefulWidget{
const depart1({Key? key}) : super(key: key);
@override
_depart1State createState() => _depart1State();
}
class _depart1State extends State<depart1> with SingleTickerProviderStateMixin{
late List<LiveData> chartData;
late List<LiveData2> chartData2;
ChartSeriesController? _chartSeriesController;
ChartSeriesController? _chartSeriesController2;
late Future<Donnee> futureDonnee;
Timer? timer;
@override
void initState() {
print('initstate');
futureDonnee=fetchDonnee();
chartData = getChartData();
chartData2 = getChartData2();
//super.initState();
timer= Timer.periodic(const Duration(seconds:1), (Timer t){
futureDonnee=fetchDonnee();
setState(() {
});
print('initstate1');
});
super.initState();
}
@override
Widget build(BuildContext context){
Size size = MediaQuery.of(context).size;
FutureBuilder f1;
//TabController _tabController;
print('build');
Center(child: f1=FutureBuilder<Donnee>(
future: futureDonnee,
builder: (context, snapshot) {
if (snapshot.hasData){
updateDataSource(snapshot.data!.w1);
updateDataSource2(snapshot.data!.va1)
return Center(
child:SingleChildScrollView(
child: Column(
children: <Widget>[
//chart 1
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colors.white
),
margin: const EdgeInsets.fromLTRB(20,10,20,0),
padding: EdgeInsets.fromLTRB(2, 7, 2, 7),
//color: Colors.white,
child: Column(
children:[
Text('puissance Active de phase 1 (W)'),
SizedBox(height: 5,),
SfCartesianChart(
series: <LineSeries<LiveData, int>>[
LineSeries<LiveData, int>(
onRendererCreated: (ChartSeriesController controller) {
_chartSeriesController = controller;
},
dataSource: chartData,
color: Colors.blue,
xValueMapper: (LiveData sales, _) => sales.time,
yValueMapper: (LiveData sales, _) => sales.speed,
dataLabelSettings: DataLabelSettings(isVisible: true)
)
],
primaryXAxis: NumericAxis(
majorGridLines: const MajorGridLines(width: 0),
edgeLabelPlacement: EdgeLabelPlacement.shift,
interval: 3,
title: AxisTitle(text: 'Temps (secondes)')),
primaryYAxis: NumericAxis(
axisLine: const AxisLine(width: 0),
majorTickLines: const MajorTickLines(size: 0),
//title: AxisTitle(text: 'puissance Active de pahse 1 (W)')
)
),]
),),
////////////////////chart2
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colors.white
),
margin: const EdgeInsets.fromLTRB(20,10,20,0),
padding: EdgeInsets.fromLTRB(2, 7, 2, 7),
child: Column(
children:[
Text('puissance Apparente de phase 1 (VA)'),
SizedBox(height: 5,),
SfCartesianChart(
series: <LineSeries<LiveData2, int>>[
LineSeries<LiveData2, int>(
onRendererCreated: (ChartSeriesController controller2) {
_chartSeriesController2 = controller2;
},
dataSource: chartData2,
color: Colors.yellow,
xValueMapper: (LiveData2 sales, _) => sales.time,
yValueMapper: (LiveData2 sales, _) => sales.speed,
dataLabelSettings: DataLabelSettings(isVisible: true)
)
],
primaryXAxis: NumericAxis(
majorGridLines: const MajorGridLines(width: 0),
edgeLabelPlacement: EdgeLabelPlacement.shift,
interval: 3,
title: AxisTitle(text: 'Temps (secondes)')),
primaryYAxis: NumericAxis(
axisLine: const AxisLine(width: 0),
majorTickLines: const MajorTickLines(size: 0),
//title: AxisTitle(text: 'puissance Active de pahse 1 (W)')
)
),]
),),
],
),
)
);
//);
}
else if (snapshot.hasError) {
//return const Text('Please wait');
return Text('${snapshot.error}');
}
// By default, show a loading spinner.
return Container(
height: 20,
width:20,
child: const CircularProgressIndicator());
},
)
);
return f1;
}
int time = 19;
void updateDataSource(String val) {
ChartSeriesController controller;
var snapshot;
chartData.add(LiveData(time++, double.parse(val)));
//math.Random().nextInt(60) + 30
chartData.removeAt(0);
_chartSeriesController?.updateDataSource(
addedDataIndex: chartData.length - 1, removedDataIndex: 0);
print('update chart');
}
List<LiveData> getChartData() {
return <LiveData>[
LiveData(0, 0),
LiveData(1, 0),
LiveData(2, 0),
LiveData(3, 0),
LiveData(4, 0),
LiveData(5, 0),
LiveData(6, 0),
LiveData(7, 0),
LiveData(8, 0),
LiveData(9, 0),
LiveData(10, 0),
LiveData(11, 0),
LiveData(12, 0),
LiveData(13, 0),
LiveData(14, 0),
LiveData(15, 0),
LiveData(16, 0),
LiveData(17, 0),
LiveData(18, 0)
];
}
//coube2
int time2 = 19;
void updateDataSource2(String val) {
ChartSeriesController controller2;
var snapshot;
chartData2.add(LiveData2(time2++, double.parse(val)));
chartData2.removeAt(0);
_chartSeriesController2?.updateDataSource(
addedDataIndex: chartData2.length - 1, removedDataIndex: 0);
print('update chart2');
}
List<LiveData2> getChartData2() {
return <LiveData2>[
LiveData2(0, 0),
LiveData2(1, 0),
LiveData2(2, 0),
LiveData2(3, 0),
LiveData2(4, 0),
LiveData2(5, 0),
LiveData2(6, 0),
LiveData2(7, 0),
LiveData2(8, 0),
LiveData2(9, 0),
LiveData2(10, 0),
LiveData2(11, 0),
LiveData2(12, 0),
LiveData2(13, 0),
LiveData2(14, 0),
LiveData2(15, 0),
LiveData2(16, 0),
LiveData2(17, 0),
LiveData2(18, 0)
];
}
}
class LiveData {
LiveData(this.time, this.speed);
final int time;
final num speed;
}
class LiveData2 {
LiveData2(this.time, this.speed);
final int time;
final num speed;
}
Any help is much appreciated
Solution 1:[1]
I tried to replicate your scenario with the provided code, but both the charts are not updating with your code. Instead of JSON data, we created data dynamically. And we found that, in the timer, you have called the setstate, and in the builder, you have called the updateDataSource method. You have processed setstate and updateDataSource simultaneously. If you comment on the updateDataaSource method, due to the setstate method you have called, the chart is getting updated. But for live update cases, we suggest using the updateDataSource method. In the timer, you can call the updateDataSource method, so that chart will get updated properly. And we are not sure why you have used both methods simultaneously. As of now, we have modified your code snippet by updating the random data at each time by calling the updateDataSource method and ensured that it updates the data properly and attached it below. You can modify the sample as per your requirement.
Code snippet:
import 'dart:math';
import 'dart:ui';
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:flutter/services.dart';
import 'package:http/http.dart' as http;
import 'package:syncfusion_flutter_charts/charts.dart';
import 'dart:convert';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const Depart1(),
);
}
}
class Depart1 extends StatefulWidget {
const Depart1({Key? key}) : super(key: key);
@override
_Depart1State createState() => _Depart1State();
}
class _Depart1State extends State<Depart1> with SingleTickerProviderStateMixin {
late List<LiveData> chartData;
late List<LiveData2> chartData2;
ChartSeriesController? _chartSeriesController;
ChartSeriesController? _chartSeriesController2;
Timer? timer;
@override
void initState() {
chartData = getChartData();
chartData2 = getChartData2();
timer = Timer.periodic(const Duration(seconds: 1), (Timer t) {
updateDataSource('val');
updateDataSource2('val');
});
super.initState();
}
Future<String> getJsonData() async {
return await rootBundle.loadString('assets/data.json');
}
Future loadData() async {
String response = await getJsonData();
final dynamic responseData = json.decode(response);}
@override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
FutureBuilder f1;
Center(
child: f1 = FutureBuilder(
future: getJsonData(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return Center(
child: SingleChildScrollView(
child: Column(
children: <Widget>[
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colors.white),
margin: const EdgeInsets.fromLTRB(20, 10, 20, 0),
padding: EdgeInsets.fromLTRB(2, 7, 2, 7),
child: Column(children: [
Text('puissance Active de phase 1 (W)'),
SizedBox(
height: 5,
),
SfCartesianChart(
series: <LineSeries<LiveData, DateTime>>[
LineSeries<LiveData, DateTime>(
onRendererCreated:
(ChartSeriesController controller) {
_chartSeriesController = controller;
},
dataSource: chartData,
color: Colors.blue,
xValueMapper: (LiveData sales, _) => sales.time,
yValueMapper: (LiveData sales, _) => sales.speed,
dataLabelSettings:
DataLabelSettings(isVisible: true))
],
primaryXAxis: DateTimeAxis(
majorGridLines: const MajorGridLines(width: 0),
edgeLabelPlacement: EdgeLabelPlacement.shift,
interval: 3,
title: AxisTitle(text: 'Temps (secondes)')),
primaryYAxis: NumericAxis(
axisLine: const AxisLine(width: 0),
majorTickLines: const MajorTickLines(size: 0),
)),
]),
),
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Colors.white),
margin: const EdgeInsets.fromLTRB(20, 10, 20, 0),
padding: EdgeInsets.fromLTRB(2, 7, 2, 7),
child: Column(children: [
Text('puissance Apparente de phase 1 (VA)'),
SizedBox(
height: 5,
),
SfCartesianChart(
series: <LineSeries<LiveData2, DateTime>>[
LineSeries<LiveData2, DateTime>(
onRendererCreated:
(ChartSeriesController controller2) {
_chartSeriesController2 = controller2;
},
dataSource: chartData2,
color: Colors.yellow,
xValueMapper: (LiveData2 sales, _) => sales.time,
yValueMapper: (LiveData2 sales, _) => sales.speed,
dataLabelSettings:
DataLabelSettings(isVisible: true))
],
primaryXAxis: DateTimeAxis(
majorGridLines: const MajorGridLines(width: 0),
edgeLabelPlacement: EdgeLabelPlacement.shift,
interval: 3,
title: AxisTitle(text: 'Temps (secondes)')),
primaryYAxis: NumericAxis(
axisLine: const AxisLine(width: 0),
majorTickLines: const MajorTickLines(size: 0),
)),
]),
),
],
),
));
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
return Container(
height: 20, width: 20, child: const CircularProgressIndicator());
},
));
return Scaffold(appBar: AppBar(), body: f1);
}
int time = 19;
void updateDataSource(String val) {
ChartSeriesController controller;
var snapshot;
chartData.add(LiveData(chartData2.last.time.add(const Duration(days: 1)),
_getRandomInt(10, 100)));
chartData.removeAt(0);
_chartSeriesController?.updateDataSource(
addedDataIndex: chartData.length - 1, removedDataIndex: 0);
print('update chart');
}
List<LiveData> getChartData() {
return <LiveData>[
LiveData(DateTime(2022, 01, 00), 0),
LiveData(DateTime(2022, 01, 01), 0),
LiveData(DateTime(2022, 01, 02), 0),
LiveData(DateTime(2022, 01, 03), 0),
LiveData(DateTime(2022, 01, 04), 0),
LiveData(DateTime(2022, 01, 05), 0),
LiveData(DateTime(2022, 01, 06), 0),
LiveData(DateTime(2022, 01, 07), 0),
LiveData(DateTime(2022, 01, 08), 0),
LiveData(DateTime(2022, 01, 09), 0),
LiveData(DateTime(2022, 01, 10), 0),
LiveData(DateTime(2022, 01, 11), 0),
LiveData(DateTime(2022, 01, 12), 0),
LiveData(DateTime(2022, 01, 13), 0),
LiveData(DateTime(2022, 01, 14), 0),
LiveData(DateTime(2022, 01, 15), 0),
LiveData(DateTime(2022, 01, 16), 0),
LiveData(DateTime(2022, 01, 17), 0),
LiveData(DateTime(2022, 01, 18), 0)
];
}
int time2 = 19;
void updateDataSource2(String val) {
ChartSeriesController controller2;
var snapshot;
chartData2.add(LiveData2(chartData2.last.time.add(const Duration(days: 1)),
_getRandomInt(10, 100)));
chartData2.removeAt(0);
_chartSeriesController2?.updateDataSource(
addedDataIndex: chartData2.length - 1, removedDataIndex: 0);
}
List<LiveData2> getChartData2() {
return <LiveData2>[
LiveData2(DateTime(2022, 01, 31), 0),
LiveData2(DateTime(2022, 01, 01), 0),
LiveData2(DateTime(2022, 01, 02), 0),
LiveData2(DateTime(2022, 01, 03), 0),
LiveData2(DateTime(2022, 01, 04), 0),
LiveData2(DateTime(2022, 01, 05), 0),
LiveData2(DateTime(2022, 01, 06), 0),
LiveData2(DateTime(2022, 01, 07), 0),
LiveData2(DateTime(2022, 01, 08), 0),
LiveData2(DateTime(2022, 01, 09), 0),
LiveData2(DateTime(2022, 01, 10), 0),
LiveData2(DateTime(2022, 01, 11), 0),
LiveData2(DateTime(2022, 01, 12), 0),
LiveData2(DateTime(2022, 01, 13), 0),
LiveData2(DateTime(2022, 01, 14), 0),
LiveData2(DateTime(2022, 01, 15), 0),
LiveData2(DateTime(2022, 01, 16), 0),
LiveData2(DateTime(2022, 01, 17), 0),
LiveData2(DateTime(2022, 01, 18), 0)
];
}
int _getRandomInt(int min, int max) {
return Random().nextInt(max - min);
}
}
class LiveData {
LiveData(this.time, this.speed);
final DateTime time;
final num speed;
}
class LiveData2 {
LiveData2(this.time, this.speed);
final DateTime time;
final num speed;
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | yuva |
