Skip to content

40 · 图表与数据可视化 ​

一句话定位:图表选型是"数据形状 × 交互需求 × 性能预算"的三角决策,对应前端 ECharts / Recharts 的选型。能源 App 满是曲线、饼图、柱状图,本篇给出 Flutter 侧的完整选型矩阵与落地套路。

开篇速览 ​

问题答案
前端对应物ECharts / Recharts / D3;Canvas 自绘
三条路线库(fl_chart)、自绘(CustomPainter)、WebView 内嵌 ECharts
能源典型图发电曲线、负荷曲线、电量构成饼图、设备统计柱状图
一句话红线"图表库画不出来"多半是选型错,不是能力不足;先按"静态 / 交互 / 大屏 / 高性能"四条线定路线

代码来源说明:HaierEnergy 已有自研图表组件(HeLineChart、HeChartPanel),基于 fl_chart 封装并扩展了 tooltip 与横屏展开。 本篇讲选型框架,落地实现对照 11 · 组件与主题 与 28 · 自定义渲染实战。


一、四条路线怎么选 ​

需求推荐优点代价
常规折线/柱状/饼图,标准交互fl_chart成熟、类型丰富、主题可控复杂交互要自己扩展
极简/性能敏感(大量点、实时刷新)CustomPainter 自绘零依赖、帧率高、尺寸自由无现成交互,全手写
超复杂图表(桑基、3D、GIS)WebView + ECharts前端生态全覆盖桥接成本、体验割裂、首屏慢
设计高度定制的品牌图表fl_chart 二次封装兼顾效率与定制要建组件层

二、fl_chart:80% 场景的默认解 ​

2.1 基本用法 ​

dart
LineChart(
  LineChartData(
    minX: 0,
    maxX: 23,
    minY: 0,
    maxY: 100,
    lineBarsData: [
      LineChartBarData(
        spots: [for (var i = 0; i < 24; i++) FlSpot(i.toDouble(), power[i])],
        color: AppColors.primary,
        isCurved: true,
        barWidth: 2,
      ),
    ],
    titlesData: ..., // X/Y 轴标题
    gridData: ...,   // 网格线
    lineTouchData: LineTouchData(enabled: true), // 触摸 tooltip
  ),
)

2.2 交互三件套 ​

  • tooltip:lineTouchData 返回触摸位置,自绘气泡(项目 HeLineChart 已做);
  • 横屏展开:图表在全屏时用 RotatedBox 伪横屏,禁止全局系统横屏(见 11 篇 的相关说明);
  • 空态/加载态:图表数据为空时要给占位,不能画一条假线。

三、CustomPainter:什么时候自绘 ​

当"每帧数据量大"或"要完全控制视觉"时自绘:

dart
class _AreaChartPainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    final path = Path();
    // 根据数据点构造曲线路径
    for (var i = 0; i < points.length; i++) {
      final dx = i / (points.length - 1) * size.width;
      final dy = size.height - points[i] * size.height;
      i == 0 ? path.moveTo(dx, dy) : path.lineTo(dx, dy);
    }
    // 填充面积 + 描边
    canvas.drawPath(path, areaPaint);
    canvas.drawPath(path, linePaint);
  }

  @override
  bool shouldRepaint(covariant _AreaChartPainter old) =>
      old.points != points;
}

自绘红线:shouldRepaint 必须基于数据比较返回,否则每帧全量重绘会卡;动画用 AnimationController 驱动渐变进度,别在 paint 里开循环。


四、WebView + ECharts:什么时候才用 ​

以下情况才值得付出桥接成本:

  • 图表类型 fl_chart 没有(桑基/3D/地图);
  • 已有大屏 H5 图表可直接复用;
  • 需要成熟的数据缩放、联动等复杂交互。

代价清单:WebView 内存大、首屏慢、与 Flutter 主题不一致、双向通信要维护(JavascriptChannel)。能源 App 的常规统计图不要走这条路。


五、主题与设计系统统一 ​

图表不是独立存在的,要接入 AppTokens(见 11 篇):

  • 颜色:直接用设计 token 的图表系列色(项目已有 defaultChartPalette);
  • 字号:坐标轴、图例、tooltip 用小字号 token;
  • 暗色模式:图表配色要随主题切换,不能硬编码。

六、性能与测试 ​

6.1 性能 ​

场景手段
大量数据点降采样(抽点/平滑),超过阈值减少显示点
实时刷新用 CustomPainter 增量重绘,避免重建 Widget 树
滚动页面里的图表延迟加载(VisibilityDetector),不可见不绘制
横屏全屏只加载一个图表实例,离开即销毁

6.2 测试 ​

图表重点测数据映射(点坐标、颜色、空态),不是测像素。用 Widget test 断言渲染不抛异常 + 空态显示;视觉回归用 golden(见 19 篇 · 4.4 Golden)。


动手练习 ​

  1. 用 fl_chart 画一个 24 点发电曲线(含 tooltip + 空态占位);
  2. 用 CustomPainter 画一个面积图,验证 shouldRepaint 只按数据变化触发;
  3. 给图表接 AppTokens 配色,写一个"深色模式下颜色切换"的 Widget test。

自检清单 ​

  • [ ] 能按"静态 / 交互 / 大屏 / 高性能"四线选型
  • [ ] 会配 fl_chart 的坐标轴、网格、tooltip
  • [ ] 知道 CustomPainter 自绘的性能红线(shouldRepaint、避免 paint 循环)
  • [ ] 知道 WebView + ECharts 的真实代价,不滥用
  • [ ] 会让图表接设计 token 与暗色模式

常见误区 ​

  • "所有图表都上 WebView ECharts":桥接成本与体验损失远超收益,常规图用 fl_chart;
  • "fl_chart 画不了就手绘":先确认是不是缺配置,手绘前要有明确性能/定制理由;
  • "shouldRepaint 返回 true 就行":会导致滚动时每帧全量重绘,卡顿元凶;
  • "图表配色单独一套":不接 AppTokens,暗色/改版会漏改。

相关文档 ​