Как передать данные полученые с апи в график?
Не получается распарсить json
, чтобы создать модели SensorTable
и передать их в график. Не могу разобраться, в чем проблема.
import 'package:dio/dio.dart';
import 'dart:convert';
import 'package:untitled35/view/Screens/SensorInfo.dart';
int? id;
class SensorData {
List<SensorTable> sensorTable;
SensorData({
required this.sensorTable,
});
factory SensorData.fromJson(Map<String, dynamic> json) => SensorData(
sensorTable: List<SensorTable>.from(
json["sensorTable"].map((x) => SensorTable.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"sensorTable": List<dynamic>.from(sensorTable.map((x) => x.toJson())),
};
}
class SensorTable {
final availability;
final avgTemp;
final day;
final hour;
final maxTemp;
final minTemp;
SensorTable({
required this.availability,
required this.avgTemp,
required this.day,
required this.hour,
required this.maxTemp,
required this.minTemp,
});
DateTime get date {
List<String> dateSegments = this.day.split('-');
int year = int.parse(dateSegments[0]);
int month = int.parse(dateSegments[1]);
int day = int.parse(dateSegments[2]);
int hours = int.parse(hour);
return DateTime(year, month, day, hours);
}
factory SensorTable.fromJson(Map<String, dynamic> json) => SensorTable(
availability: json["availability"],
avgTemp: json["avgTemp"],
day: json["day"],
hour: json["hour"],
maxTemp: json["maxTemp"],
minTemp: json["minTemp"],
);
Map<String, dynamic> toJson() => {
"availability": availability,
"avgTemp": avgTemp,
"day": day,
"hour": hour,
"maxTemp": maxTemp,
"minTemp": minTemp,
};
}
Get() async {
Dio dio = Dio();
final response = await dio.get('http://1c.unduty.ru:3014/api/v1/sensorTable?token=c21bf03d52654a66&sensorId=${id.toString()}');
String jsonStr = await response.data;
Map<String, dynamic> json = jsonDecode(jsonStr);
SensorData sensorData = SensorData.fromJson(json);
list = sensorData.sensorTable;
}
А вот код графика
class SensorDataChart extends StatelessWidget {
final List<SensorData> sensorData;
const SensorDataChart({
required this.sensorData,
super.key,
});
@override
Widget build(BuildContext context) {
if (sensorData.isEmpty) {
return const Center(
child: Text('Данные с сенсоров не получены'),
);
}
return CustomPaint(
painter: _SensorDataChartPainter(sensorData),
);
}
}
class _SensorDataChartPainter extends CustomPainter {
static const _celsiusSymbol = '°C';
static const _textPadding = 10;
static const _dataPointCircleRadius = 4.0;
static const _textStyleDeg = TextStyle(
fontSize: 10,
color: Colors.black,
);
static const _textStyleDate = TextStyle(
fontSize: 10,
color: Colors.black,
);
final List<SensorData> sensorData;
_SensorDataChartPainter(this.sensorData);
@override
void paint(Canvas canvas, Size size) {
Paint paint = Paint();
paint.color = Colors.black.withOpacity(0.1);
paint.strokeCap = StrokeCap.round;
paint.strokeWidth = 1.0;
paint.style = PaintingStyle.fill;
/// Sort by date
sensorData.sort((e1, e2) => e1.date.compareTo(e2.date));
/// Find highest and lowest avgTemp
final firstSensorData = sensorData.first;
double highestAvgTemp = firstSensorData.avgTemp;
double lowestAvgTemp = firstSensorData.avgTemp;
for (final sensorData in sensorData) {
if (highestAvgTemp < sensorData.avgTemp) {
highestAvgTemp = sensorData.avgTemp;
} else if (lowestAvgTemp > sensorData.avgTemp) {
lowestAvgTemp = sensorData.avgTemp;
}
}
/// Find temp delimiter height in chart
int highestTempInChart = highestAvgTemp.ceil();
int lowestTempInChart = lowestAvgTemp.floor();
int degreesInChart = highestTempInChart - lowestTempInChart;
double heightPerDegree = size.height / degreesInChart;
/// Find day/hour width in chart
final lastSensorData = sensorData.last;
final hoursInChart = firstSensorData.date.difference(lastSensorData.date).inHours.abs();
final daysInChart = (firstSensorData.date.difference(lastSensorData.date).inHours / 24).abs();
final widthPerHour = size.width / hoursInChart;
final widthPerDay = size.width / daysInChart;
_drawTempDelimiters(
canvas,
paint,
size,
degreesInChart,
heightPerDegree,
lowestTempInChart,
);
_drawDayDelimiters(
canvas,
paint,
size,
firstSensorData,
daysInChart,
widthPerDay,
);
paint.color = Colors.black;
_drawChart(
canvas,
size,
paint,
firstSensorData,
lowestTempInChart,
widthPerHour,
heightPerDegree,
);
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
void _drawTempDelimiters(
Canvas canvas,
Paint paint,
Size size,
int degreesInChart,
double heightPerDegree,
int lowestTempInChart,
) {
for (int nextDeg = 0; nextDeg <= degreesInChart; nextDeg++) {
final nextDegY = size.height - nextDeg * heightPerDegree;
TextSpan degreeText = TextSpan(
style: _textStyleDeg,
text: '${lowestTempInChart + nextDeg}$_celsiusSymbol',
);
TextPainter textPainter = TextPainter(
text: degreeText,
textAlign: TextAlign.left,
textDirection: TextDirection.ltr,
);
textPainter.layout();
textPainter.paint(
canvas,
Offset(
-textPainter.width - _textPadding,
nextDegY - textPainter.height * 0.5,
),
);
canvas.drawLine(
Offset(0, nextDegY),
Offset(size.width, nextDegY),
paint,
);
}
}
void _drawDayDelimiters(
Canvas canvas,
Paint paint,
Size size,
SensorData firstSensorData,
double daysInChart,
double widthPerDay,
) {
for (int nextDay = 0; nextDay <= daysInChart; nextDay++) {
final nextDayX = nextDay * widthPerDay;
final delimiterDate = firstSensorData.date.add(Duration(days: nextDay));
TextSpan dateText = TextSpan(
style: _textStyleDate,
text: delimiterDate.toIso8601String().split('T')[0],
);
TextPainter textPainter = TextPainter(
text: dateText,
textAlign: TextAlign.center,
textDirection: TextDirection.ltr,
);
textPainter.layout(maxWidth: widthPerDay);
textPainter.paint(
canvas,
Offset(
nextDayX - textPainter.width * 0.5,
size.height + _textPadding,
),
);
canvas.drawLine(
Offset(nextDayX, 0),
Offset(nextDayX, size.height),
paint,
);
}
}
void _drawChart(
Canvas canvas,
Size size,
Paint paint,
SensorData firstSensorData,
int lowestTempInChart,
double widthPerHour,
double heightPerDegree,
) {
for (int i = 0; i < sensorData.length - 1; i++) {
SensorData sensorDataCurrent = sensorData[i];
SensorData sensorDataNext = sensorData[i + 1];
final chartXInHours = sensorDataCurrent.date.difference(firstSensorData.date).inHours.abs();
final chartYInDegrees = sensorDataCurrent.avgTemp - lowestTempInChart;
final chartXInHoursNext = sensorDataNext.date.difference(firstSensorData.date).inHours.abs();
final chartYInDegreesNext = sensorDataNext.avgTemp - lowestTempInChart;
final offsetCurrent = Offset(
chartXInHours * widthPerHour,
size.height - chartYInDegrees * heightPerDegree,
);
final offsetNext = Offset(
chartXInHoursNext * widthPerHour,
size.height - chartYInDegreesNext * heightPerDegree,
);
canvas.drawCircle(offsetCurrent, _dataPointCircleRadius, paint);
canvas.drawCircle(offsetNext, _dataPointCircleRadius, paint);
canvas.drawLine(offsetCurrent, offsetNext, paint);
}
}
}
@override
Widget build(BuildContext context) {
return Center(
child: SizedBox(
width: 700,
height: 400,
child: SensorDataChart(
sensorData: [
SensorData(10, 29.7, "2022-04-12", "00", 45.6, 30.1),
SensorData(10, 45.1, "2022-04-13", "00", 45.1, 30.1),
SensorData(10, 33.3, "2022-04-16", "00", 45.1, 30.1),
SensorData(10, 36.4, "2022-04-17", "23", 45.1, 30.1),
SensorData(10, 32.1, "2022-04-22", "01", 45.1, 30.1),
],
),
),
);
}
Источник: Stack Overflow на русском