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> 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> 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; } }