Flutter实时刷新折线图实现

背景:

最近有个项目需求,需要以图表的方式展示实时采集的脑神经数据。数据比较多,以1k的采样率来算,乘以采集通道数,大致需要每秒刷新万级以上的数据点。

正常这种图表一般都是在matlab上展示分析的。不过为了一些其它功能吧,需要在pad上也实现这个功能。之前在ipad上使用三方库有实现过差不多的需求功能,不过这次的项目要求是在android pad上使用。本人不喜欢android原生开发,但对flutter还是比较喜欢的,自然就采用了flutter开发。

工具调研

欲先成其事,必先利其器。磨刀不误砍柴功,遂先找了找flutter的图表库。寻了一遍,flutter图表库用的比较多的着实比较少,只有两个fl_chart和graphic,还有个syncfusion_officechart,不过这个是付费版的(也能免费用,但是条件限制很苛刻)。剩下还有一些用的人不太多的库,没有太多研究。

直接上手模拟生成了一堆数据,然后丢进了fl_chart。然后图是出来了,在50ms刷新频率,上万数据点的显示下,图表卡成了幻灯片。一看fps在10左右徘徊。换成graphic,效果稍微好了些,but依旧很卡,看了下cpu消耗。大多数cpu都消耗在了x轴取title的操作上,这里因为graphic数据格式定义的关系,当数据多了还有个性能bug。比如1w个点,就要做1w次循环从1w的数据里找title。直接炸裂,做个map,从map里取应该会提升很多吧。不过我的需求比较简单,不需要显示这么复杂的x轴title。于是直接改库源码,换成index作为x title。性能提升到了25左右的fps。看着满载的cpu和raster负荷。我陷入了沉思。

自己动手丰衣足食

我的需求只需要展示出数据变动的曲线,而交互什么的在这么高的频率刷新下是没有需求的。于是决定自己画个图表。

看了下flutter的canvas绘制,貌似还挺简单。甚至提供了直接通过points画线的功能。

arduino 复制代码
void drawPoints(PointMode pointMode, List<Offset> points, Paint paint);

enum PointMode {
  points,
  lines,
  polygon,
}

于是一切都简单了,改吧改吧,一个简单的手写版折线图就出来了。 大致贴个代码

scala 复制代码
class WSChartView extends StatelessWidget {

  const WSChartView(this.config, this.points, {super.key});

  final List<Offset> points;

  final ChartConfig config;

  @override

  Widget build(BuildContext context) {

    return Stack(

      children: [

        if (config.yTitles != null)

          SizedBox(

            width: 32,

            child: Column(

                mainAxisAlignment: MainAxisAlignment.spaceBetween,

                children: config.yTitles!.map((e) => Text(e)).toList()),

          ),

        if (config.yTitles != null)

          SizedBox.expand(

              child: RepaintBoundary(

                  child: CustomPaint(

            painter: ChartXYPainter(ChartXYConfig(yTitles: config.yTitles)),

          ))),

        SizedBox.expand(

            child: Container(

                padding: EdgeInsets.fromLTRB(

                    config.yTitles != null ? 32 : 8, 8, 8, 8),

                child: RepaintBoundary(

                  child: CustomPaint(

                    painter: _WSPainter(points, config),

                  ),

                )))

      ],

    );

  }

}

class _WSPainter extends CustomPainter {

  _WSPainter(this.points, this.config) {

    _paint = Paint();

    _paint.strokeWidth = 1;

    _paint.color = config.color;

  }

  

  final List<Offset> points;

  final ChartConfig config;

  late Paint _paint;

  

  @override

  void paint(Canvas canvas, Size size) {

    var length = points.length;

    var data = <Offset>[];

    final lastX = points.last.dx;

    var xPercent = size.width / lastX;

    var yPercent = size.height / 2 / config.yMax;

    for (var i = 0; i < length; i++) {

      var point = points[i];

      data.add(

          Offset(point.dx * xPercent, (config.yMax - point.dy) * yPercent));

    }

    canvas.drawPoints(PointMode.polygon, data, _paint);

  }

  

  @override

  bool shouldRepaint(covariant _WSPainter oldDelegate) {

    return true;

  }

}

class ChartXYPainter extends CustomPainter {

  ChartXYPainter(this.config) {

    _paint = Paint();

    _paint.strokeWidth = 2;

    _paint.color = Colors.black;

  }

  

  late Paint _paint;

  

  final ChartXYConfig config;

  

  @override

  void paint(Canvas canvas, Size size) {

    final edge = (

      8.0,

      8.0,

      config.xTitles != null ? 32.0 : 8.0,

      config.yTitles != null ? 32.0 : 8.0

    );

    canvas.drawLine(Offset(edge.$4, size.height - edge.$3),

        Offset(size.width - edge.$2, size.height - edge.$3), _paint);

    canvas.drawLine(Offset(edge.$4, size.height - edge.$3),

        Offset(edge.$4, edge.$1), _paint);

  }

  

  @override

  bool shouldRepaint(covariant ChartXYPainter oldDelegate) {

    return false;

  }

}

ChartXYPainter 对应的是画xy轴的功能。

代码简洁,功能也挺简单,后续有对应的刷新实时要求高的图表都可以用这种方式实现。性能会好很多。

相关推荐
风华圆舞10 小时前
在 Flutter 鸿蒙项目里接入语音识别的完整思路
flutter·语音识别·harmonyos
风华圆舞12 小时前
鸿蒙 + Flutter 下如何让 HarmonyOS 能力真正服务于 AI 体验
人工智能·flutter·harmonyos
BreezeDove13 小时前
【Android】Flutter3.35项目启动超时问题
android·flutter
风华圆舞13 小时前
鸿蒙 MICROPHONE 权限在 Flutter 项目里怎么处理
flutter·华为·harmonyos
愚者Pro1 天前
切换本地 Flutter SDK 版本
flutter
TT_Close1 天前
别再复制旧 Flutter 工程了,真正拖慢你的不是业务代码
flutter·npm·visual studio code
风华圆舞1 天前
鸿蒙 + Flutter 下 AI 助手为什么要支持流式输出
人工智能·flutter·harmonyos
风华圆舞1 天前
鸿蒙 + Flutter 下 AI 页面的状态协同设计
人工智能·flutter·harmonyos
风华圆舞1 天前
鸿蒙语音播报功能 的 Flutter 侧封装思路
flutter·华为·harmonyos
brycegao3211 天前
Flutter 国际化富文本解决方案:基于双层占位符的轻量化图文混排方案
flutter·国际化·i18n·富文本·rtl·移动端工程架构