159 lines
4.8 KiB
Dart
159 lines
4.8 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:intl/intl.dart';
|
|
import 'dart:ui' as ui;
|
|
|
|
class LineChart extends StatelessWidget {
|
|
final int startTime;
|
|
final int endTime;
|
|
final double minValue;
|
|
final double maxValue;
|
|
final List<Map<String, dynamic>> dataPoints;
|
|
|
|
LineChart({
|
|
required this.startTime,
|
|
required this.endTime,
|
|
required this.minValue,
|
|
required this.maxValue,
|
|
required this.dataPoints,
|
|
});
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return CustomPaint(
|
|
size: Size(double.infinity, 300),
|
|
painter: LineChartPainter(
|
|
startTime: startTime,
|
|
endTime: endTime,
|
|
minValue: minValue,
|
|
maxValue: maxValue,
|
|
dataPoints: dataPoints,
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class LineChartPainter extends CustomPainter {
|
|
final int startTime;
|
|
final int endTime;
|
|
final double minValue;
|
|
final double maxValue;
|
|
final List<Map<String, dynamic>> dataPoints;
|
|
|
|
LineChartPainter({
|
|
required this.startTime,
|
|
required this.endTime,
|
|
required this.minValue,
|
|
required this.maxValue,
|
|
required this.dataPoints,
|
|
});
|
|
|
|
@override
|
|
void paint(Canvas canvas, Size size) {
|
|
Paint paint = Paint()..style = PaintingStyle.stroke;
|
|
double chartWidth = size.width;
|
|
double chartHeight = size.height;
|
|
|
|
// 时间轴刻度设置
|
|
DateFormat timeFormatStartEnd = DateFormat('HH:mm');
|
|
DateFormat timeFormatMiddle = DateFormat('h');
|
|
|
|
// 绘制Y轴刻度
|
|
double yAxisHeight = chartHeight - 40; // 留一些空间给X轴
|
|
double yAxisStep = yAxisHeight / 4;
|
|
paint.color = Colors.grey;
|
|
paint.strokeWidth = 1;
|
|
canvas.drawLine(Offset(30, 0), Offset(30, chartHeight), paint); // Y轴
|
|
|
|
// 绘制Y轴的刻度线
|
|
paint.color = Colors.grey;
|
|
for (int i = 0; i < 5; i++) {
|
|
double y = i * yAxisStep;
|
|
if (i == 0) {
|
|
paint.color = Colors.grey; // 0线
|
|
canvas.drawLine(Offset(25, y), Offset(35, y), paint);
|
|
} else if (i == 1) {
|
|
paint.color = Colors.red; // 最小值线
|
|
paint.style = PaintingStyle.stroke;
|
|
paint.strokeWidth = 1;
|
|
canvas.drawLine(Offset(25, y), Offset(35, y), paint);
|
|
} else if (i == 2) {
|
|
paint.color = Colors.grey; // 最大值与最小值中间线
|
|
paint.style = PaintingStyle.stroke;
|
|
paint.strokeWidth = 1;
|
|
_drawDashedLine(canvas, paint, 25, y, 35, y); // Custom dashed line
|
|
} else {
|
|
paint.color = Colors.red; // 最大值线
|
|
canvas.drawLine(Offset(25, y), Offset(35, y), paint);
|
|
}
|
|
}
|
|
|
|
// 绘制X轴时间刻度
|
|
DateTime startDate = DateTime.fromMillisecondsSinceEpoch(startTime);
|
|
DateTime endDate = DateTime.fromMillisecondsSinceEpoch(endTime);
|
|
double xAxisStep = (chartWidth - 60) /
|
|
(endDate.millisecondsSinceEpoch - startDate.millisecondsSinceEpoch);
|
|
|
|
for (DateTime date = startDate;
|
|
date.isBefore(endDate);
|
|
date = date.add(Duration(hours: 1))) {
|
|
String timeLabel = (date == startDate || date == endDate)
|
|
? timeFormatStartEnd.format(date)
|
|
: timeFormatMiddle.format(date);
|
|
paint.color = Colors.black;
|
|
|
|
// Draw text using TextPainter
|
|
_drawText(
|
|
canvas, timeLabel, Offset(30, yAxisHeight)); // Position dynamically
|
|
}
|
|
|
|
// 绘制折线图数据点
|
|
Path path = Path();
|
|
for (var i = 0; i < dataPoints.length; i++) {
|
|
var point = dataPoints[i];
|
|
DateTime pointTime = DateTime.fromMillisecondsSinceEpoch(point['time']);
|
|
double x = (pointTime.millisecondsSinceEpoch -
|
|
startDate.millisecondsSinceEpoch) *
|
|
xAxisStep +
|
|
30;
|
|
double y = chartHeight -
|
|
(point['value'] - minValue) * yAxisHeight / (maxValue - minValue);
|
|
path.lineTo(x, y);
|
|
}
|
|
|
|
paint.color = Colors.green; // Line color based on range
|
|
paint.strokeWidth = 2;
|
|
canvas.drawPath(path, paint);
|
|
}
|
|
|
|
// Custom method to draw dashed line
|
|
void _drawDashedLine(Canvas canvas, Paint paint, double startX, double startY,
|
|
double endX, double endY) {
|
|
double dashWidth = 5;
|
|
double dashSpace = 3;
|
|
double distance = (endX - startX).abs();
|
|
double dashCount = (distance / (dashWidth + dashSpace)).floorToDouble();
|
|
for (int i = 0; i < dashCount; i++) {
|
|
double startXDash = startX + (i * (dashWidth + dashSpace));
|
|
double endXDash = startXDash + dashWidth;
|
|
canvas.drawLine(
|
|
Offset(startXDash, startY), Offset(endXDash, endY), paint);
|
|
}
|
|
}
|
|
|
|
// Custom method to draw text
|
|
void _drawText(Canvas canvas, String text, Offset offset) {
|
|
TextPainter textPainter = TextPainter(
|
|
text: TextSpan(
|
|
text: text, style: TextStyle(color: Colors.black, fontSize: 12)),
|
|
textDirection: ui.TextDirection.ltr,
|
|
)..layout();
|
|
|
|
textPainter.paint(canvas, offset);
|
|
}
|
|
|
|
@override
|
|
bool shouldRepaint(CustomPainter oldDelegate) {
|
|
return false;
|
|
}
|
|
}
|