当前位置: 首页 > news >正文

flutter 雷达图

通过CustomPainter自定义雷达图

效果如下

 主要代码

import 'package:flutter/material.dart';
import 'dart:math';
import 'dash_painter.dart';
import 'model/charts_model.dart';class RadarChart extends StatelessWidget {final List<ChartModel> list;final double maxValue;final Color radarColor;final Color dataColor;const RadarChart({super.key,required this.list,this.maxValue = 100,this.radarColor = Colors.grey,this.dataColor = Colors.green,});@overrideWidget build(BuildContext context) {return CustomPaint(painter: RadarChartPainter(list: list,maxValue: maxValue,radarColor: radarColor,dataColor: dataColor,numLayers: 4,),);}
}class RadarChartPainter extends CustomPainter {final int numLayers;final List<ChartModel> list;final double maxValue;final Color radarColor;final Color dataColor;List<Offset> startList = []; //存放第一层的点List<Offset> endList = []; //存放最外层的点List<Offset> textOffsetList = [];final int _offsetDy = 20;final int _offsetDx = 5;RadarChartPainter({required this.numLayers,required this.list,required this.maxValue,required this.radarColor,required this.dataColor,});@overridevoid paint(Canvas canvas, Size size) {final center = Offset(size.width / 2, size.height / 2);final radius = size.width / 2;final dataPoints = <Offset>[];final radarPaint = Paint()..color = radarColor..style = PaintingStyle.stroke;final bgPaint = Paint()..color = const Color(0xFFCAD0E8).withOpacity(.4)..style = PaintingStyle.fill;//画背景颜色for (var layer = 1; layer <= numLayers; layer++) {if (layer == 3) {final layerRadius = radius * (layer / numLayers);final radarPath = Path();for (var i = 0; i < 6; i++) {//每一层的6个点final angle = (2 * pi / 6) * i - (pi / 2);final x = center.dx + layerRadius * cos(angle);final y = center.dy + layerRadius * sin(angle);final point = Offset(x, y);if (i == 0) {radarPath.moveTo(point.dx, point.dy);} else {radarPath.lineTo(point.dx, point.dy);}}radarPath.close();canvas.drawPath(radarPath, bgPaint);}}//连接每一层的6个点和文字for (var layer = 1; layer <= numLayers; layer++) {final layerRadius = radius * (layer / numLayers);final radarPath = Path();for (var i = 0; i < 6; i++) {final angle = (2 * pi / 6) * i - (pi / 2);final x = center.dx + layerRadius * cos(angle);final y = center.dy + layerRadius * sin(angle);final point = Offset(x, y);if (i == 0) {radarPath.moveTo(point.dx, point.dy);} else {radarPath.lineTo(point.dx, point.dy);}//保存第一层的点if (layer == 1) {startList.add(point);}//保存最外层的点,用于后面画第一层的最外层点的连线if (layer == 4) {endList.add(point);//画label文字const textStyle = TextStyle(fontSize: 12, fontWeight: FontWeight.bold, color: Color(0XFF999999));final textSpan = TextSpan(text: list[i].label, style: textStyle);final textPainter = TextPainter(text: textSpan,textDirection: TextDirection.ltr,);textPainter.layout();double w = textPainter.width;Offset off = const Offset(0, 0);if (i == 0) {off = Offset(point.dx - w * 0.5, point.dy - _offsetDy);} else if (i == 1 || i == 2) {off = Offset(point.dx + _offsetDx, point.dy);} else if (i == 4 || i == 5) {off = Offset(point.dx - _offsetDx - w, point.dy);} else if (i == 3) {off = Offset(point.dx - w * 0.5, point.dy);}textPainter.paint(canvas, off);}}radarPath.close();const DashPainter(span: 3, step: 3).paint(canvas, radarPath, radarPaint);}//画第一层的点到最外层的点的连线for (var i = 0; i < 6; i++) {final path = Path();path.moveTo(startList[i].dx, startList[i].dy);path.lineTo(endList[i].dx, endList[i].dy);const DashPainter(span: 4, step: 9).paint(canvas, path, radarPaint);}//画数据区域final dataPaint = Paint()..color = dataColor..style = PaintingStyle.stroke..strokeWidth = 2.0;final dataFillPaint = Paint()..color = dataColor.withOpacity(.3)..style = PaintingStyle.fill..strokeWidth = 2.0;final dataPath = Path();for (var i = 0; i < 6; i++) {final angle = (2 * pi / 6) * i - (pi / 2);final value = list[i].y;final normalizedValue = value / maxValue;final dataRadius = radius * 0.75 * normalizedValue + radius * 0.25;final x = center.dx + dataRadius * cos(angle);final y = center.dy + dataRadius * sin(angle);final point = Offset(x, y);if (i == 0) {dataPath.moveTo(point.dx, point.dy);} else {dataPath.lineTo(point.dx, point.dy);}dataPoints.add(point);}dataPath.close();canvas.drawPath(dataPath, dataFillPaint);canvas.drawPath(dataPath, dataPaint);final dataPointPaint = Paint()..color = dataColor;for (var point in dataPoints) {canvas.drawCircle(point, 4.0, dataPointPaint);}}@overridebool shouldRepaint(covariant CustomPainter oldDelegate) {return true;}
}

项目地址 : flutter_radar: flutter 雷达图

http://www.lryc.cn/news/138225.html

相关文章:

  • 机器学习之损失函数(Loss Function)
  • 创邻科技张晨:图数据库,激活数据要素的新基建
  • 使用端口映射实现Spring Boot服务端接口的公网远程调试:详细配置与步骤解析
  • stm32之点亮LED
  • SA8000认证的难点及注意事项
  • Java可视化物联网智慧工地SaaS平台源码:人脸识别考勤
  • 告别数字化系统“物理叠加”,华为云推动智慧门店价值跃迁
  • k8s 常用命令(四)
  • 大语言模型的分布式训练
  • 【JavaEE】Spring全家桶实现AOP-统一处理
  • HQL解决连续三天登陆问题
  • (一)Docker简介(一篇足以)
  • RK3568 安卓源码编译
  • 第4篇:vscode+platformio搭建esp32 arduino开发环境
  • 2023前端面试笔记 —— CSS3
  • iOS 如何对整张图分别局部磨砂,并完全贴合
  • Packet_Tracer的使用
  • WPF如果未定义绑定的属性,程序如何处理
  • 韩国留学生生活之-租房篇,柯桥韩语培训留学韩语需要学到什么程度
  • 论文笔记:基于概念漂移的在线类非平衡学习系统研究
  • ubuntu22.04下rv1109 rootfs编译问题处理
  • Spring Boot Dubbo Zookeeper
  • 线程池的概念及实现原理
  • iOS App逆向之:iOS应用砸壳技术
  • 【高性能计算】opencl安装及相关概念
  • 盛最多水的容器——力扣11
  • 2023年高教社杯数学建模思路 - 复盘:校园消费行为分析
  • Flink_state 的优化与 remote_state 的探索
  • Kdab QML (part9)自由缩放时钟
  • Java网络编程(二)经典案例[粘包拆包]