Related
I have to get a List from Realtime Database (Firebase). I have no problem to get first time my list but if I go back and return on the future builder activity I get no data.
This is my code:
import 'package:cleverpot/Utily/Constants.dart';
import 'package:cleverpot/Utily/Function.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_charts/charts.dart';
class AxisChart extends StatelessWidget {
AxisChart(this.title);
final String title;
final FirebaseDatabase db =
FirebaseDatabase(databaseURL: Constans.url_database);
final FirebaseAuth _auth = FirebaseAuth.instance;
List records = [];
Future getData() async {
Map data = {};
db
.reference()
.child(_auth.currentUser.uid)
.child("records")
.once()
.then((value) {
data = Map.of(value.value);
records = data[FunctionHelper.selectFolder(title)];
});
}
#override
Widget build(BuildContext context) {
return FutureBuilder<dynamic>(
future: getData(),
builder: (context, snapshot) {
return Center(
child: SfCartesianChart(
title: ChartTitle(text: "Ultima settimana"),
primaryXAxis: CategoryAxis(),
series: <LineSeries<Records, int>>[
LineSeries(
dataSource: <Records>[
Records(1, records[0]),
Records(2, records[1]),
Records(3, records[2]),
Records(4, records[3]),
Records(5, records[4]),
Records(6, records[5]),
Records(7, records[6]),
],
xValueMapper: (Records records, _) => records.day,
yValueMapper: (Records records, _) => records.records)
],
),
);
});
}
}
class Records {
Records(this.day, this.records);
final int day;
final int records;
}
If I use listen method in getData() function instead of once I resolve the problem but i don't want to stay on listen for the data. Anyone can help me? Thanks a lot!
For this example, I will use firebase firestore but I think the procedure is similar
1. Creating a stream
stream = FirebaseFirestore.instance.collection('users').snapshots();
2. Real-time read using StreamBuilder
return StreamBuilder<QuerySnapshot>(
stream: stream,
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return Text('Something went wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Text("Loading"); // this will prevent from null error
}
//when succeedeed to get data, you can make some list to show them
//
return ListView(
children: snapshot.data!.docs.map((DocumentSnapshot document) {
Map<String, dynamic> data = document.data()! as Map<String, dynamic>;
return ListTile(
title: Text(data['full_name']),
subtitle: Text(data['company']),
);
}).toList(),
);
source code from here
The code reads a firebase database then add each read in a list of objects (SalesData class), chartdata.
The problem is when I update the list (chartdata) in the function readData() I can print it inside databaseReference.once().then((DataSnapshot snapshot) {}, but when it out of this bracket it is always empty. I an wondering how I could use this list in the chart constructor "dataSource: "
P.S if I hot reload the chart builds fine!!
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
// próximo passo: colocar os valores lidos do firebase em uma lista que seja
class _HomeState extends State<Home> {
List<SalesData> chartdata = [];
#override
Widget build(BuildContext context) {
// here I try to update the list chartdata, in order to build the chart
readData();
return Scaffold(
appBar: AppBar(
title: Text('Home'),
),
body: Column(
children: <Widget>[
RaisedButton(
child: Text('Read Data'),
onPressed: () {
readData();
},
),
SfCartesianChart(
primaryXAxis: CategoryAxis(),
series: <LineSeries<SalesData, double>>[
LineSeries<SalesData, double>(
// Bind data source
dataSource: chartdata,
xValueMapper: (SalesData sales, _) => sales.year,
yValueMapper: (SalesData sales, _) => sales.sales)
])
],
));
}
final databaseReference =
FirebaseDatabase.instance.reference().child("UID/Esp_32");
void readData() {
databaseReference.once().then((DataSnapshot snapshot) {
Map<dynamic, dynamic> dados = snapshot.value;
dados.forEach((key, value) {
chartdata.add(SalesData(value['VoltageIn'], value['Sensor40']));
});
});
}
}
class SalesData {
SalesData(this.year, this.sales);
final double year;
final double sales;
}
First remove the method readData() at the beginning of the build method this could cause an infinite loop, you can call in the initState method.
So in your readData method you need to call setState to update the screen, like this:
void readData() {
databaseReference.once().then((DataSnapshot snapshot) {
Map<dynamic, dynamic> dados = snapshot.value;
dados.forEach((key, value) {
chartdata.add(SalesData(value['VoltageIn'], value['Sensor40']));
});
setState((){});
});
}
But I think that you should study some architecture to improve your code, like MVVM.
i've got stuck at this problem for nearly 3 days. Already post it in another questions but, got minus instead an answer.
Let me make it clear the questions.
I would like to put my api data using models into chart flutter, here is my code
First is my model here is my age model
ages.dart
Ages agesFromJson(String str) => Ages.fromJson(json.decode(str));
String agesToJson(Ages data) => json.encode(data.toJson());
class Ages {
Ages({
this.entity,
this.code,
this.year,
this.underAge15,
this.age1564,
this.age65Over,
});
String entity;
String code;
int year;
String underAge15;
String age1564;
String age65Over;
factory Ages.fromJson(Map<String, dynamic> json) => Ages(
entity: json["entity"],
code: json["code"],
year: json["year"],
underAge15: json["under_age_15"],
age1564: json["age_15_64"],
age65Over: json["age_65_over"],
);
Map<String, dynamic> toJson() => {
"entity": entity,
"code": code,
"year": year,
"under_age_15": underAge15,
"age_15_64": age1564,
"age_65_over": age65Over,
};
}
and here i make the ages chart that given me the url from api and put into future builder
ages_chart.dart
class AgeCharts extends StatefulWidget {
final String url;
const AgeCharts({this.url});
#override
_AgeChartsState createState() => _AgeChartsState();
}
class _AgeChartsState extends State<AgeCharts> {
var chart;
#override
void initState() {
// TODO: implement initState
super.initState();
}
#override
Widget build(BuildContext context) {
print(widget.url);
return SafeArea(
child: Scaffold(
appBar: AppBar(
title: Text('Japanese Age Working Populations'),
),
body: Container(
height: 400,
child: FutureBuilder<List>(
future: getChartData(widget),
builder: (context, dataapi) {
if (dataapi.hasError) print(dataapi.error);
print(dataapi);
return dataapi.hasData
? ShowChart(
data: dataapi.data,
)
: Center(
child: CircularProgressIndicator(),
);
},
),
),
),
);
}
}
after ages dart, i make a function to get an api.
Future<List> getChartData(widget) async {
final response = await http.get(widget.url);
return json.decode(response.body)['data'];
}
and here is my show chart when i already get an url
class ShowChart extends StatelessWidget {
final List data;
ShowChart({this.data});
static List<charts.Series<Ages, dynamic>> _createSampleData(dataAPI) {
return [
new charts.Series<Ages, dynamic>(
id: 'Desktop',
// colorFn specifies that the line will be blue.
colorFn: (_, __) => charts.MaterialPalette.blue.shadeDefault,
// areaColorFn specifies that the area skirt will be light blue.
areaColorFn: (_, __) =>
charts.MaterialPalette.blue.shadeDefault.lighter,
domainFn: (Ages ages, _) => ages.year,
measureFn: (Ages ages, _) => int.parse(ages.underAge15),
data: dataAPI,
),
new charts.Series<Ages, dynamic>(
id: 'Tablet',
// colorFn specifies that the line will be red.
colorFn: (_, __) => charts.MaterialPalette.red.shadeDefault,
// areaColorFn specifies that the area skirt will be light red.
areaColorFn: (_, __) => charts.MaterialPalette.red.shadeDefault.lighter,
domainFn: (Ages ages, _) => ages.year,
measureFn: (Ages ages, _) => int.parse(ages.age1564),
data: dataAPI,
),
new charts.Series<Ages, dynamic>(
id: 'Mobile',
// colorFn specifies that the line will be green.
colorFn: (_, __) => charts.MaterialPalette.green.shadeDefault,
// areaColorFn specifies that the area skirt will be light green.
areaColorFn: (_, __) =>
charts.MaterialPalette.green.shadeDefault.lighter,
domainFn: (Ages ages, _) => ages.year,
measureFn: (Ages ages, _) => int.parse(ages.age65Over),
data: dataAPI,
),
];
}
#override
Widget build(BuildContext context) {
print('showchart');
print(data);
return Container(
child: charts.LineChart(
_createSampleData(data),
defaultRenderer:
new charts.LineRendererConfig(includeArea: true, stacked: true),
animate: true,
),
);
}
}
this is my JSON Structure. but i get the data when using json.decode(response.body)
{
"status": true,
"message": "Chart found",
"data": [
{
"entity": "Japan",
"code": "JPN",
"year": 1950,
"under_age_15": "29288.106",
"age_15_64": "49447.555",
"age_65_over": "4066.423"
},
{
"entity": "Japan",
"code": "JPN",
"year": 1951,
"under_age_15": "29652.515",
"age_15_64": "50461.828",
"age_65_over": "4201.922"
},
]
}
and the i got an error like this
type 'List<dynamic>' is not a subtype of type 'List<Ages>'
help me solve the problem, please
Problems within your code:
You are explicitly casting your series data as charts.Series<Ages, dynamic> while it should be charts.Series<Ages, num>
You are trying to parse double as int. If you want doubles, use double.parse(x) otherwise, double.parse(x).round() will give you a int. (or .floor() or .ceil())
You should probably also specify your domain axis as not being zeroBound:
charts.LineChart(
_createSampleData(data),
defaultRenderer: charts.LineRendererConfig(includeArea: true, stacked: true),
animate: true,
domainAxis: charts.NumericAxisSpec(
tickProviderSpec: charts.BasicNumericTickProviderSpec(zeroBound: false),
),
),
Working Solution
Full source code for easy copy-paste
import 'dart:math' as math;
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';
import 'package:charts_flutter/flutter.dart' as charts;
void main() {
runApp(
MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Charts Demo',
home:
AgeCharts(url: 'http://udacoding-task-api.herokuapp.com/api/charts'),
),
);
}
// MAIN WIDGET
class AgeCharts extends StatefulWidget {
final String url;
const AgeCharts({this.url});
#override
_AgeChartsState createState() => _AgeChartsState();
}
class _AgeChartsState extends State<AgeCharts> {
var chart;
Future<List<Ages>> getChartData(widget) async {
final response = await http.get(widget.url);
final List<dynamic> jsonData = jsonDecode(response.body)['data'];
return jsonData.map((data) => Ages.fromJson(data)).toList();
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
appBar: AppBar(
title: Text('Japanese Age Working Populations'),
),
body: Padding(
padding: EdgeInsets.all(8.0),
child: FutureBuilder<List>(
future: getChartData(widget),
builder: (context, dataapi) {
if (dataapi.hasError) print(dataapi.error);
return dataapi.hasData
? ShowChart(data: dataapi.data)
: Center(child: CircularProgressIndicator());
},
),
),
),
);
}
}
// CHART
class ShowChart extends StatelessWidget {
final List<Ages> data;
ShowChart({this.data});
static List<charts.Series<Ages, num>> _createSampleData(dataAPI) {
return [
new charts.Series<Ages, num>(
id: 'underAge15',
colorFn: (_, __) => charts.MaterialPalette.blue.shadeDefault,
areaColorFn: (_, __) =>
charts.MaterialPalette.blue.shadeDefault.lighter,
domainFn: (Ages ages, _) => ages.year,
measureFn: (Ages ages, _) => double.parse(ages.underAge15).round(),
data: dataAPI,
),
new charts.Series<Ages, num>(
id: 'age1564',
colorFn: (_, __) => charts.MaterialPalette.red.shadeDefault,
areaColorFn: (_, __) => charts.MaterialPalette.red.shadeDefault.lighter,
domainFn: (Ages ages, _) => ages.year,
measureFn: (Ages ages, _) => double.parse(ages.age1564).round(),
data: dataAPI,
),
new charts.Series<Ages, num>(
id: 'age65Over',
colorFn: (_, __) => charts.MaterialPalette.green.shadeDefault,
areaColorFn: (_, __) =>
charts.MaterialPalette.green.shadeDefault.lighter,
domainFn: (Ages ages, _) => ages.year,
measureFn: (Ages ages, _) => double.parse(ages.age65Over).round(),
data: dataAPI,
),
];
}
#override
Widget build(BuildContext context) {
return Container(
child: charts.LineChart(
_createSampleData(data),
defaultRenderer:
new charts.LineRendererConfig(includeArea: true, stacked: true),
animate: true,
domainAxis: charts.NumericAxisSpec(
tickProviderSpec:
charts.BasicNumericTickProviderSpec(zeroBound: false),
),
),
);
}
}
// DOMAIN
class Ages {
Ages({
this.entity,
this.code,
this.year,
this.underAge15,
this.age1564,
this.age65Over,
});
String entity;
String code;
int year;
String underAge15;
String age1564;
String age65Over;
factory Ages.fromJson(Map<String, dynamic> json) => Ages(
entity: json["entity"],
code: json["code"],
year: json["year"],
underAge15: json["under_age_15"],
age1564: json["age_15_64"],
age65Over: json["age_65_over"],
);
Map<String, dynamic> toJson() => {
"entity": entity,
"code": code,
"year": year,
"under_age_15": underAge15,
"age_15_64": age1564,
"age_65_over": age65Over,
};
}
// DATA
math.Random random = math.Random();
final Map<String, dynamic> data = {
"status": true,
"message": "Chart found",
"data": List.generate(
20,
(index) => {
"entity": "Japan",
"code": "JPN",
"year": 1950 + index,
"under_age_15": (25000 + random.nextInt(5000)).toString(),
"age_15_64": (40000 + random.nextInt(5000)).toString(),
"age_65_over": (3000 + random.nextInt(2000)).toString(),
}).toList(),
};
BEFORE ANSWER UPDATE:
Try this:
Future<List<Ages>> getChartData(widget) async {
final response = await http.get(widget.url);
return json.decode(response.body)['data'].map((jsonData) => Ages.fromJson(jsonData)).toList();
}
I'm not 100% sure, since I don't know the structure of your JSON Data.
I have a flutter project where I am using Syncfusion to render the JSON data into charts. I don't get any error when I debug my code but the chart is not rendering when the build is complete. I am not sure if there are mistakes in the codes but it worked fine for other charts.
In addition, some of the reasons I feel responsible for the chart not being rendered could be:
There is too much data to plot. (This may not be the problem since I also tried after reducing data)
The values to plot are too small since they mostly range from some negative values to some positive values and also the values are in decimal (eg 0.7, -0.6, and so on).
These are just my assumption on what could have gone wrong. Please correct me if I am mistaken.
Any ideas to resolve or at least help me understand what is wrong would be great. And yes please help me out :)). Below is the code that I have.
import 'package:flutter/material.dart';
import 'package:fyp/model/rainApiCall.dart';
import 'package:syncfusion_flutter_charts/charts.dart';
class Past extends StatefulWidget{
#override
_Past createState() => _Past();
}
class _Past extends State<Past>{
List<String> t = [];
List<String> ampA = [];
List<String> ampB = [];
List<String> ampC = [];
#override
void initState() {
fetchEQData();
super.initState();
}
#override
Widget build(BuildContext context) {
return Container(
child: Center(
child: FutureBuilder(
future: fetchEQData(),
builder: (context, snapshot){
if(snapshot.hasData) {
var stationID = '4853';
for(int i=0; i<snapshot.data.length; i++){
if(snapshot.data[i].stationId==stationID){
t.add(snapshot.data[i].recordLength);
ampA.add(snapshot.data[i].amplitudemaxa);
ampB.add(snapshot.data[i].amplitudemaxb);
ampC.add(snapshot.data[i].amplitudemaxc);
}
}
return Card(
child: SfCartesianChart(
series: <ChartSeries>[
StackedLineSeries<EqAmpData, double>(
dataSource: getColumnData(t, ampA, ampB, ampC),
dashArray: <double>[5,5],
xValueMapper: (EqAmpData eqdata, _) => double.parse(eqdata.x),
yValueMapper: (EqAmpData eqdata, _) => int.parse(eqdata.y1),
),
StackedLineSeries<EqAmpData, double>(
dataSource: getColumnData(t, ampA, ampB, ampC),
dashArray: <double>[5,5],
xValueMapper: (EqAmpData eqdata, _) => double.parse(eqdata.x),
yValueMapper: (EqAmpData eqdata, _) => int.parse(eqdata.y2),
),
StackedLineSeries<EqAmpData, double>(
dataSource: getColumnData(t, ampA, ampB, ampC),
dashArray: <double>[5,5],
xValueMapper: (EqAmpData eqdata, _) => double.parse(eqdata.x),
yValueMapper: (EqAmpData eqdata, _) => int.parse(eqdata.y3),
),
]
)
);
}
return CircularProgressIndicator();
},
),),);}}
class EqAmpData{
String x;
String y1;
String y2;
String y3;
EqAmpData(this.x, this.y1, this.y2, this.y3);
}
dynamic getColumnData(List xval, List yval1, List yval2, List yval3) {
List rtime = xval;
List y1 = yval1;
List y2 = yval2;
List y3 = yval3;
List<EqAmpData> columnData = <EqAmpData>[];
for (int i = 0; i < rtime.length; i++) {
columnData.add(EqAmpData(rtime[i], y1[i], y2[i], y3[i]));
}
return columnData;
}
Screen after build:
enter image description here
Screenshot of the data I have:
enter image description here
When you define your StackedLineSeries, your yValueMapper should provide double instead of int:
StackedLineSeries<EqAmpData, double>(
dataSource: getColumnData(t, ampA, ampB, ampC),
dashArray: <double>[5, 5],
xValueMapper: (EqAmpData eqdata, _) => double.parse(eqdata.x),
yValueMapper: (EqAmpData eqdata, _) => double.parse(eqdata.y1),
),
Full source code for easy copy-paste
import 'dart:math' as math;
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_charts/charts.dart';
void main() {
runApp(
MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Charts Demo',
home: Past(),
),
);
}
class Past extends StatefulWidget {
#override
_Past createState() => _Past();
}
class _Past extends State<Past> {
List<String> t = [];
List<String> ampA = [];
List<String> ampB = [];
List<String> ampC = [];
#override
void initState() {
fetchEQData();
super.initState();
}
Future<List<RawData>> fetchEQData() async {
await Future.delayed(Duration(seconds: 2));
return data;
}
StackedLineSeries<EqAmpData, double> prepareSerie({
List<EqAmpData> dataSource,
num Function(EqAmpData, int) yValueMapper,
}) {
return StackedLineSeries<EqAmpData, double>(
dataSource: dataSource,
dashArray: <double>[5, 5],
xValueMapper: (EqAmpData eqdata, _) => double.parse(eqdata.x),
yValueMapper: yValueMapper,
);
}
#override
Widget build(BuildContext context) {
return Container(
child: Center(
child: FutureBuilder<List<RawData>>(
future: fetchEQData(),
builder: (context, snapshot) {
if (snapshot.hasData) {
snapshot.data
.where((item) => item.stationId == '4853')
.forEach((item) {
t.add(item.recordLength);
ampA.add(item.amplitudemaxa);
ampB.add(item.amplitudemaxb);
ampC.add(item.amplitudemaxc);
});
final dataSource = getColumnData(t, ampA, ampB, ampC);
return Card(
child: SfCartesianChart(
series: <ChartSeries>[
prepareSerie(
dataSource: dataSource,
yValueMapper: (eqdata, _) => double.parse(eqdata.y1),
),
prepareSerie(
dataSource: dataSource,
yValueMapper: (eqdata, _) => double.parse(eqdata.y2),
),
prepareSerie(
dataSource: dataSource,
yValueMapper: (eqdata, _) => double.parse(eqdata.y3),
),
],
),
);
}
return CircularProgressIndicator();
},
),
),
);
}
}
// DOMAIN
class EqAmpData {
final String x;
final String y1;
final String y2;
final String y3;
EqAmpData(this.x, this.y1, this.y2, this.y3);
}
dynamic getColumnData(List rtime, List y1, List y2, List y3) {
return List.generate(
rtime.length,
(i) => EqAmpData(rtime[i], y1[i], y2[i], y3[i]),
);
}
class RawData {
final String stationId;
final String recordLength;
final String amplitudemaxa;
final String amplitudemaxb;
final String amplitudemaxc;
RawData(
this.stationId,
this.recordLength,
this.amplitudemaxa,
this.amplitudemaxb,
this.amplitudemaxc,
);
}
// DATA
final random = math.Random();
final data = List.generate(
100,
(index) => RawData(
"4853",
(index * 0.01).toString(),
((random.nextInt(100) - 50) / 500).toString(),
((random.nextInt(100) - 50) / 1000).toString(),
((random.nextInt(100) - 50) / 1000).toString(),
),
);
i will display linechart from the database using datajson with flutter. but the reference that I can use is hardcode data. Please help
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:charts_flutter/flutter.dart' as charts;
int dataTotal = 0;
class GrafikSpbj extends StatefulWidget {
final List<charts.Series> seriesList;
final bool animate;
GrafikSpbj(this.seriesList, {this.animate});
/// Creates a [LineChart] with sample data and no transition.
factory GrafikSpbj.withSampleData() {
return new GrafikSpbj(
_createSampleData(),
// Disable animations for image tests.
animate: false,
);
}
#override
_GrafikSpbjState createState() => _GrafikSpbjState();
/// Create one series with sample hard coded data.
static List<charts.Series<LinearSales, int>> _createSampleData() {
print(dataTotal);
final desktopSalesData = [
new LinearSales(0, 10),
new LinearSales(1, 50),
new LinearSales(2, 70),
new LinearSales(3, 100),
];
final tableSalesData = [
new LinearSales(0, 20),
new LinearSales(1, 40),
new LinearSales(2, 80),
new LinearSales(3, 100),
];
return [
new charts.Series<LinearSales, int>(
id: 'Desktop',
colorFn: (_, __) => charts.MaterialPalette.blue.shadeDefault,
domainFn: (LinearSales sales, _) => sales.year,
measureFn: (LinearSales sales, _) => sales.sales,
data: desktopSalesData,
),
new charts.Series<LinearSales, int>(
id: 'Tablet',
colorFn: (_, __) => charts.MaterialPalette.red.shadeDefault,
domainFn: (LinearSales sales, _) => sales.year,
measureFn: (LinearSales sales, _) => sales.sales,
data: tableSalesData,
),
];
}
}
class _GrafikSpbjState extends State<GrafikSpbj> {
List data;
Timer timer;
int jumlahData = 0;
Future<List> _getData() async {
final response = await http.get("xxxxxxxxxxxxx");
setState(() {
data = json.decode(response.body);
jumlahData =data.length;
print(data[0]['id_spbj']);
print(data[0]['minggu_ke']);
print(data[0]['hasil']);
print(data[0]['target_grafik']);
});
return json.decode(response.body);
}
// makeRequest() async {
// var response = await http.get(
// 'xxxxxxxxxxxxxxxxxxxxxxx',
// headers: {'Accept': 'application/json'},
// );
// setState(() {
// data = json.decode(response.body);
// jumlahData =data.length;
// });
// }
#override
void initState() {
_getData();
dataTotal = jumlahData;
super.initState();
}
#override
void dispose() {
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: new Text("Input Pelanggan hal 2"),
),
body: Column(
children: <Widget>[
SizedBox(
width: 600.0,
height: 250.0,
child: new charts.NumericComboChart(widget.seriesList,
animate: widget.animate,
defaultRenderer: new charts.LineRendererConfig(),
customSeriesRenderers: [
new charts.PointRendererConfig(customRendererId: 'customPoint')
]),
),
new Text("data"),
new Text("data"),
new Text("data")
],
),
);
}
}
/// Sample linear data type.
class LinearSales {
final int year;
final int sales;
LinearSales(this.year, this.sales);
}
values
[{"id_spbj":"1","minggu_ke":"1","hasil":"13.4353337","target_grafik":"25.00"},{"id_spbj":"1","minggu_ke":"2","hasil":"28.2629147","target_grafik":"25.00"},{"id_spbj":"1","minggu_ke":"3","hasil":"85.3285762","target_grafik":"25.00"},{"id_spbj":"2","minggu_ke":"1","hasil":"32.0184122","target_grafik":"25.00"},{"id_spbj":"2","minggu_ke":"2","hasil":"53.5296934","target_grafik":"25.00"}]
You can use FL_chart plugin library in flutter, where you draw all types of charts.
please find guideline to use FL_Chart