加速 "charts_flutter" 折线图渲染
Speed up "charts_flutter" LineChart Rendering
我目前正在开发一个 flutter 应用程序,该应用程序将在折线图上实时绘制来自 BLE 设备的数据(其中数据将以示波器样式格式显示)。作为实时 BLE 数据的占位符,我使用定时器回调生成并绘制带有“charts_flutter”包的正弦波。到目前为止,一切似乎都在工作。然而,当更新周期小于 500 毫秒时,图表渲染似乎难以跟上(例如,将其设置为 200 毫秒会导致一切冻结)。在我开始尝试不同的包之前,我想看看是否有人有提示或建议来尝试加快速度。有可能我只是在状态管理等方面做错了,因为我对 flutter 没有那么多经验。代码很短,所以我在下面包含了两个项目文件。谢谢
main.dart
import 'package:flutter/material.dart';
import 'package:charts_flutter/flutter.dart';
import 'package:provider/provider.dart';
import 'package:tuple/tuple.dart';
import 'models/graph_data_model.dart';
void main() => runApp(new GraphDataApp());
class GraphDataApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider<GraphDataModel>(
create: (context) => GraphDataModel()),
],
child: MaterialApp(
title: 'Data Plotter',
theme: ThemeData(
primarySwatch: Colors.blue,
),
initialRoute: '/',
routes: {
'/': (context) => MyApp(),
},
),
);
}
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Data Plotter")),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
GraphDataWidget(),
],
),
),
);
}
}
class GraphDataWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.all(5.0),
child: SizedBox(
height: 400.0,
child: Selector<GraphDataModel, Tuple2<GraphDataModel, double>>(
selector: (_, graphDataModel) {
return Tuple2(graphDataModel, graphDataModel.elapsedTime);
},
builder: (context, selectorTuple, child) {
GraphDataModel graphDataModel = selectorTuple.item1;
return LineChart(
graphDataModel.series.toList(),
animate: false,
domainAxis: NumericAxisSpec(
viewport: NumericExtents(graphDataModel.domainStart, graphDataModel.domainEnd))
);
},
),
),
);
}
}
graph_data_model.dart
import 'dart:async';
import 'dart:math';
import 'package:charts_flutter/flutter.dart';
import 'package:flutter/material.dart';
const UPDATE_INTERVAL = 500;
const MAX_TIME_INTERVAL = 10.0;
const MAX_DATA_POINTS = ((MAX_TIME_INTERVAL * 1000) / UPDATE_INTERVAL);
class GraphDataModel extends ChangeNotifier {
bool _running = false;
int _startTime;
double elapsedTime;
List<Series<PlotPoint, double>> series;
GraphDataModel() {
// initialize the data series
series = [
Series<PlotPoint, double>(
id: 'Sine',
colorFn: (_, __) => MaterialPalette.blue.shadeDefault,
domainFn: (PlotPoint point, _) => point.time,
measureFn: (PlotPoint point, _) => point.value,
data: <PlotPoint>[PlotPoint(0, 0)],
),
];
// initialize the start time and start the timer
_startTime = DateTime.now().millisecondsSinceEpoch;
Timer.periodic(Duration(milliseconds: UPDATE_INTERVAL), _timerCallback);
}
// getters
num get domainStart => _running ? (series.first.data.first.time) : 0;
num get domainEnd => _running ? (series.first.data.last.time) : 1;
void _timerCallback(Timer t) {
final currentTime = DateTime.now().millisecondsSinceEpoch;
// find the elapsed time in seconds
elapsedTime = (currentTime - _startTime).toDouble() / 1000.0;
// find the sine value based on the elapsed time
final yVal = sin((2.0 * pi * elapsedTime) / 10.0);
// add the latest data point to the series
series.first.data.add(PlotPoint(elapsedTime, yVal));
// remove the first element in the list to create oscilloscope scrolling effect
if(series.first.data.length > MAX_DATA_POINTS.toInt() || !_running) {
series.first.data.removeAt(0);
}
_running = true;
notifyListeners();
}
}
class PlotPoint {
final double time;
final double value;
PlotPoint(this.time, this.value);
}
我得出的结论是“charts_flutter”根本不适合实时数据。我最终通过扩展自定义画家编写了自己的示波器小部件,并且没有明显的性能问题。
我目前正在开发一个 flutter 应用程序,该应用程序将在折线图上实时绘制来自 BLE 设备的数据(其中数据将以示波器样式格式显示)。作为实时 BLE 数据的占位符,我使用定时器回调生成并绘制带有“charts_flutter”包的正弦波。到目前为止,一切似乎都在工作。然而,当更新周期小于 500 毫秒时,图表渲染似乎难以跟上(例如,将其设置为 200 毫秒会导致一切冻结)。在我开始尝试不同的包之前,我想看看是否有人有提示或建议来尝试加快速度。有可能我只是在状态管理等方面做错了,因为我对 flutter 没有那么多经验。代码很短,所以我在下面包含了两个项目文件。谢谢
main.dart
import 'package:flutter/material.dart';
import 'package:charts_flutter/flutter.dart';
import 'package:provider/provider.dart';
import 'package:tuple/tuple.dart';
import 'models/graph_data_model.dart';
void main() => runApp(new GraphDataApp());
class GraphDataApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider<GraphDataModel>(
create: (context) => GraphDataModel()),
],
child: MaterialApp(
title: 'Data Plotter',
theme: ThemeData(
primarySwatch: Colors.blue,
),
initialRoute: '/',
routes: {
'/': (context) => MyApp(),
},
),
);
}
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Data Plotter")),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
GraphDataWidget(),
],
),
),
);
}
}
class GraphDataWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.all(5.0),
child: SizedBox(
height: 400.0,
child: Selector<GraphDataModel, Tuple2<GraphDataModel, double>>(
selector: (_, graphDataModel) {
return Tuple2(graphDataModel, graphDataModel.elapsedTime);
},
builder: (context, selectorTuple, child) {
GraphDataModel graphDataModel = selectorTuple.item1;
return LineChart(
graphDataModel.series.toList(),
animate: false,
domainAxis: NumericAxisSpec(
viewport: NumericExtents(graphDataModel.domainStart, graphDataModel.domainEnd))
);
},
),
),
);
}
}
graph_data_model.dart
import 'dart:async';
import 'dart:math';
import 'package:charts_flutter/flutter.dart';
import 'package:flutter/material.dart';
const UPDATE_INTERVAL = 500;
const MAX_TIME_INTERVAL = 10.0;
const MAX_DATA_POINTS = ((MAX_TIME_INTERVAL * 1000) / UPDATE_INTERVAL);
class GraphDataModel extends ChangeNotifier {
bool _running = false;
int _startTime;
double elapsedTime;
List<Series<PlotPoint, double>> series;
GraphDataModel() {
// initialize the data series
series = [
Series<PlotPoint, double>(
id: 'Sine',
colorFn: (_, __) => MaterialPalette.blue.shadeDefault,
domainFn: (PlotPoint point, _) => point.time,
measureFn: (PlotPoint point, _) => point.value,
data: <PlotPoint>[PlotPoint(0, 0)],
),
];
// initialize the start time and start the timer
_startTime = DateTime.now().millisecondsSinceEpoch;
Timer.periodic(Duration(milliseconds: UPDATE_INTERVAL), _timerCallback);
}
// getters
num get domainStart => _running ? (series.first.data.first.time) : 0;
num get domainEnd => _running ? (series.first.data.last.time) : 1;
void _timerCallback(Timer t) {
final currentTime = DateTime.now().millisecondsSinceEpoch;
// find the elapsed time in seconds
elapsedTime = (currentTime - _startTime).toDouble() / 1000.0;
// find the sine value based on the elapsed time
final yVal = sin((2.0 * pi * elapsedTime) / 10.0);
// add the latest data point to the series
series.first.data.add(PlotPoint(elapsedTime, yVal));
// remove the first element in the list to create oscilloscope scrolling effect
if(series.first.data.length > MAX_DATA_POINTS.toInt() || !_running) {
series.first.data.removeAt(0);
}
_running = true;
notifyListeners();
}
}
class PlotPoint {
final double time;
final double value;
PlotPoint(this.time, this.value);
}
我得出的结论是“charts_flutter”根本不适合实时数据。我最终通过扩展自定义画家编写了自己的示波器小部件,并且没有明显的性能问题。