110 lines
2.9 KiB
Dart
110 lines
2.9 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'dart:ui' as ui;
|
|
import 'dart:math';
|
|
|
|
class RadarChart extends StatelessWidget {
|
|
final List<List<double>> data; // 存储多个数据集
|
|
final List<String> labels; // 每个角的标签
|
|
final double maxValue; // 数据的最大值,用来统一尺度
|
|
|
|
const RadarChart({
|
|
Key? key,
|
|
required this.data,
|
|
required this.labels,
|
|
this.maxValue = 100,
|
|
}) : super(key: key);
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return CustomPaint(
|
|
size: Size(300, 300), // 图表的大小
|
|
painter: RadarChartPainter(
|
|
data: data,
|
|
labels: labels,
|
|
maxValue: maxValue,
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
class RadarChartPainter extends CustomPainter {
|
|
final List<List<double>> data;
|
|
final List<String> labels;
|
|
final double maxValue;
|
|
|
|
RadarChartPainter({
|
|
required this.data,
|
|
required this.labels,
|
|
required this.maxValue,
|
|
});
|
|
|
|
@override
|
|
void paint(Canvas canvas, Size size) {
|
|
Paint paintLine = Paint()
|
|
..color = Colors.blue
|
|
..style = PaintingStyle.stroke
|
|
..strokeWidth = 2;
|
|
|
|
Paint axisPaint = Paint()
|
|
..color = Colors.grey.withOpacity(0.5)
|
|
..strokeWidth = 1;
|
|
|
|
double centerX = size.width / 2;
|
|
double centerY = size.height / 2;
|
|
double radius = size.width / 2;
|
|
|
|
int numOfPoints = labels.length;
|
|
|
|
// 绘制雷达图的轴线
|
|
for (int i = 0; i < numOfPoints; i++) {
|
|
double angle = (2 * pi / numOfPoints) * i;
|
|
double x = centerX + radius * cos(angle);
|
|
double y = centerY + radius * sin(angle);
|
|
|
|
// 画轴线
|
|
canvas.drawLine(Offset(centerX, centerY), Offset(x, y), axisPaint);
|
|
|
|
// 绘制标签
|
|
TextPainter tp = TextPainter(
|
|
text: TextSpan(
|
|
text: labels[i],
|
|
style: TextStyle(color: Colors.black, fontSize: 12),
|
|
),
|
|
textDirection: ui.TextDirection.ltr,
|
|
);
|
|
tp.layout();
|
|
tp.paint(canvas, Offset(x + 8, y - 8)); // 设置标签位置
|
|
}
|
|
|
|
// 绘制多个数据集
|
|
for (int i = 0; i < data.length; i++) {
|
|
Paint fillPaint = Paint()
|
|
..color = Colors.primaries[i % Colors.primaries.length].withOpacity(0.3)
|
|
..style = PaintingStyle.fill;
|
|
|
|
Paint linePaint = Paint()
|
|
..color = Colors.primaries[i % Colors.primaries.length]
|
|
..style = PaintingStyle.stroke
|
|
..strokeWidth = 2;
|
|
|
|
List<Offset> points = [];
|
|
for (int j = 0; j < numOfPoints; j++) {
|
|
double angle = (2 * pi / numOfPoints) * j;
|
|
double pointRadius = (data[i][j] / maxValue) * radius;
|
|
double x = centerX + pointRadius * cos(angle);
|
|
double y = centerY + pointRadius * sin(angle);
|
|
|
|
points.add(Offset(x, y));
|
|
}
|
|
|
|
// 画出数据连接线
|
|
Path path = Path()..addPolygon(points, true);
|
|
canvas.drawPath(path, linePaint);
|
|
canvas.drawPath(path, fillPaint);
|
|
}
|
|
}
|
|
|
|
@override
|
|
bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
|
|
}
|