更新
This commit is contained in:
158
lib/pages/sleep_report/chart/LineChart.dart
Normal file
158
lib/pages/sleep_report/chart/LineChart.dart
Normal file
@@ -0,0 +1,158 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user