css 颤动_颤动的实时图表

css 颤动

What you will learn:

您将学到什么:

  • How to cut out a chart from the mp_chart package example and integrate it into your app.

    如何从mp_chart包示例中切出图表并将其集成到您的应用程序中。
  • How to use Dart DevTools to ensure that there is no memory leak.

    如何使用Dart DevTools确保没有内存泄漏。

Since January I’m experimenting with some private Flutter Apps. Especially I’m investigating how Flutter can be used to control bluetooth devices, develop Desktop Apps, Web Apps, and much more.

从一月份开始,我正在尝试一些Flutter私人应用程序。 尤其是我正在研究如何将Flutter用于控制蓝牙设备,开发桌面应用程序,Web应用程序等等。

For a bluetooth project, I needed to visualise two values in realtime, like on an oscilloscope. I checked the packages on pub.dev and chose the mp_chart package. That package has a nice animated realtime chart on the README page.

对于蓝牙项目,我需要像示波器一样实时可视化两个值。 我检查了pub.dev上的软件包,然后选择了mp_chart软件包。 该软件包在README页面上有一个漂亮的实时动画图表。

Flutter makes it easy to develop the separate widgets of an app in isolation and then stick them together. This can be done with all languages, but the ‘everything is a widget’ principle makes it really easy, without fuss.

Flutter使您可以轻松地单独开发应用程序的各个小部件,然后将它们粘贴在一起。 可以使用所有语言完成此操作,但是“一切都是小部件”原理使此操作非常容易,没有大惊小怪。

On the other side, it is easy to cut out interesting parts (widgets) from an app and work on it further. This is my procedure when I begin using a new package. I look whether it has an example app on github and cut out what I need.

另一方面,很容易从应用程序中剪切出有趣的部分(小部件)并进一步进行处理。 当我开始使用新程序包时,这就是我的过程。 我看它是否在github上有一个示例应用程序,并切出我需要的内容。

The mp_charts package has a showcase of all supported chart types. There are so many different widgets and I had to find the right one:

mp_charts包展示了所有受支持的图表类型。 有很多不同的小部件,我不得不找到合适的小部件:

  • BarChartBasic

    条形图基本
  • BarChartBasic2

    条形图基本2
  • BarChartHorizontal

    横条图
  • BarChartMultiple

    条形图
  • BarChartNegative

    条形图负
  • BarChartSine

    条形图
  • BarChartStacked

    条形图堆积
  • BarChartStacked2

    条形图堆积2
  • EvenMoreDynamic

    更动态
  • EvenMoreHourly

    更小时
  • EvenMoreRealtime

    更实时

  • LineChartBasic

    LineChartBasic
  • LineChartColorful

    LineChartColorful
  • LineChartCubic

    线图立方
  • LineChartDualAxis

    LineChartDualAxis
  • LineChartFilled

    LineChartFilled
  • LineChartInvertAxis

    LineChartInvertAxis
  • LineChartMultiple

    LineChartMultiple
  • LineChartPerformance

    LineChartPerformance
  • OtherChartBubble

    其他图表气泡
  • OtherChartCandlestick

    其他图表烛台
  • OtherChartCombined

    其他图表合并
  • OtherChartRadar

    其他图表雷达
  • OtherChartScatterPlot

    其他图表散点​​图
  • PieChartBasic

    饼图基本
  • PieChartHalfPie

    饼图半饼
  • PieChartValueLines

    PieChartValueLines
  • ScrollingChartManyBar

    ScrollingChartManyBar
  • ScrollingChartMultiple

    ScrollingChartMultiple
  • ScrollingChartTallBar

    ScrollingChartTallBar
  • ScrollingChartViewPager

    ScrollingChartViewPager

I found the widget EvenMoreRealtime in the source file mp_chart/example/lib/demo/even_more/realtime.dart. But: this widget has several dependencies on the demo app. To make it independent from the showcase frame I had to do the following changes:

我在源文件mp_chart/example/lib/demo/even_more/realtime.dart找到了EvenMoreRealtime小部件。 但是 :此小部件对演示应用程序具有若干依赖性。 为了使其脱离展示框架,我必须进行以下更改:

  1. My version no longer extends ActionState but just extends a standard State<>.

    我的版本不再扩展ActionState,而仅扩展了标准State <>。
  2. I removed all overridden methods which are defined in the ActionState class.

    我删除了ActionState类中定义的所有重写方法。
  3. The code in the overridden getBody() method is moved into the standard overridden build() method.

    覆盖的getBody()方法中的代码被移到标准的覆盖的build()方法中。
  4. No longer needed imports are removed

    不再需要的进口被删除

After these changes and a rename of the widget to RealTimeChart I could use it in a screen called PulsarScreen, which is the body of the Scaffold of my test app. The following code builds the RealTimeChart on the top of a column.

完成这些更改并将小部件重命名为RealTimeChart之后,我可以在名为PulsarScreen的屏幕中使用它,该屏幕是测试应用程序的Scaffold的主体。 以下代码将RealTimeChart构建在列顶部。

class _PulsarScreenState extends State<PulsarScreen> {


  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        children: <Widget>[
          Container(height: 150, child: RealtimeChart()),
          SizedBox(
            height: 10,
          ),
          ConfigurationWidget(),
        ],
      ),
    );
  }
}

A ConfigurationWidget below the chart contains a range slider to set the upper and lower limit of the generated values and a slider for the frequency of the generated sinus values. These settings are stored in the class RealtimeDataServiceImpl.

图表下方的ConfigurationWidget包含一个范围滑块,用于设置生成值的上限和下限;以及一个滑块,用于生成正弦值的频率。 这些设置存储在RealtimeDataServiceImpl类中。

The following snippet shows the original code of the demo example:

以下代码段显示了演示示例的原始代码:

class EvenMoreRealtimeState extends ActionState<EvenMoreRealtime>
    implements OnChartValueSelectedListener {
  LineChartController controller;
  var random = Random(1);
  var isMultipleRun = false;


  @override
  void initState() {
    _initController();
    super.initState();
  }


  @override
  Widget getBody() {
    return Stack(
      children: <Widget>[
        Positioned(
          right: 0,
          left: 0,
          top: 0,
          bottom: 0,
          child: LineChart(controller),
        ),
      ],
    );
  }
  ...

And here is the corresponding part of my cut out widget, which can run without the demo frame:

这是我切出的小部件的对应部分,可以在没有演示框架的情况下运行:

class RealtimeChartState extends State<RealtimeChart>
    implements OnChartValueSelectedListener {
  LineChartController controller;


  static const int VISIBLE_COUNT = 60;
  int _removalCounter = 0;
  Stream<DataSet> _dataStream = locator<RealtimeDataService>().dataStream;
  StreamSubscription<DataSet> _streamSubscription;


  @override
  Widget build(BuildContext context) {
    return Stack(
      children: <Widget>[
        Positioned(
          right: 0,
          left: 0,
          top: 0,
          bottom: 0,
          child: LineChart(controller),
        ),
      ],
    );
  }


  @override
  void initState() {
    print("initState RealtimeChartState");
    _initController();
    _streamSubscription = _dataStream.listen((dataSet) {
      //print("dataSet: ${dataSet.y0}");
      addEntry(dataSet.y0, dataSet.y1);
    });
    super.initState();
  }
  ...

I made some more changes to adapt the widget to my requirements:

我进行了一些更改,以使小部件适应我的要求:

The _initController method configures all the colors, text styles, limits of the axes, and much more. All in all, there are x properties you can adjust to your requirements.

_initController方法可配置所有颜色,文本样式,轴的限制等等。 总而言之,您可以根据需要调整x个属性。

The demo widget just calls 1000 times _addEntry() periodically in _updateEntry(). I replaced this with a listen on a — maybe endless — _dataStream.

演示小部件仅在_updateEntry()中定期调用1000次_addEntry()。 我将它替换为对_dataStream的监听(也许无休止)。

@override
  void initState() {
    print("initState RealtimeChartState");
    _initController();
    _streamSubscription = _dataStream.listen((dataSet) {
      //print("dataSet: ${dataSet.y0}");
      addEntry(dataSet.y0, dataSet.y1);
    });
    super.initState();
  }

This _dataStream is provided by an instance of RealtimeDataService, which is injected using the locator of the get_it package. The service ist configured by two sliders and it feeds the stream with two sinus waves.

_dataStream由RealtimeDataService的实例提供,该实例使用get_it包的定位符注入。 由两个滑块配置的维修员,通过两个正弦波向水流供水。

Stream<DataSet> _dataStream = locator<RealtimeDataService>().dataStream;

Stream<DataSet> _dataStream = locator<RealtimeDataService>().dataStream;

For this simple test app, this would be overkill, but I use the same architecture in an app, which also will use this RealtimeChart widget.

对于这个简单的测试应用程序,这可能会有些过头,但是我在一个应用程序中使用了相同的架构,该架构也将使用此RealtimeChart小部件。

The original demo example creates a limited number of new entries with each call of _addMultiple() in memory. For a 'real' realtime app, which runs longer, this would be a remarkable memory leak. Searching google for mpandroidchart realtime chart remove I found a solution in stackoverflow. I searched for mpandroidchart because the README of the package states:

原始的演示示例在内存中每次调用_addMultiple()都会创建有限数量的新条目。 对于运行时间更长的“实时”实时应用程序,这将是内存泄漏。 在谷歌搜索mpandroidchart realtime chart remove我在stackoverflow中找到了解决方案。 我搜索了mpandroidchart因为该程序包的自述文件指出:

flutter charts just like MPAndroidChart

flutter charts just like MPAndroidChart

It’s a big advantage of the mp_charts package, that any problems can probably been solved the same way as with MPAndroidChart. This is good to know if any problems occur or any special case is to be configured.

mp_charts软件包的一大优点是,可以通过与MPAndroidChart.相同的方式解决任何问题MPAndroidChart. 很高兴知道是否发生任何问题或是否要配置任何特殊情况。

The solution I found is implemented in the method addWithRemove(). It removes entries as soon as they are no longer visible.

我找到的解决方案是在方法addWithRemove(). 一旦条目不再可见,它将删除条目。

void addWithRemove(ILineDataSet set0, LineData data, double y0, double y1) {
    double x = (set0.getEntryCount() + _removalCounter).toDouble();
    //print("x0: $x  entryCount: ${set0.getEntryCount()}: $y0 $y1 ");
    data.addEntry(
        Entry(
          x: x,
          y: y0,
        ),
        0);
    data.addEntry(
        Entry(
          x: x,
          y: y1,
        ),
        1);
    //remove entry which is out of visible range
    if (set0.getEntryCount() > VISIBLE_COUNT) {
      data.removeEntry2(_removalCounter.toDouble(), 0);
      data.removeEntry2(_removalCounter.toDouble(), 1);
      _removalCounter++;
    }
  }

The difference can be checked in the memory view of the Dart DevTools. The following screenshot shows the memory if the calls to removeEntry2 are commented out in addWithRemove():

可以在Dart DevTools的内存视图中检查差异。 下面的截图显示,如果呼叫使用的内存removeEntry2在addWithRemove被注释掉():

Image for post
3290 objects and 154 kB memory are consumed in one minute
一分钟内将消耗3290个对象和154 kB内存

Note: To get viable results you have to execute the garbage collector with a click on the gc icon. After that a click on Snapshot shows the count of all objects. Special interest is on the object count of class Entry.

注意 :要获得可行的结果,您必须单击gc图标来执行垃圾收集器。 之后,单击“快照”将显示所有对象的计数。 对Entry类的对象计数特别感兴趣。

And here are the counts if removeEntry2 ist called:

以下是removeEntry2 ist的计数:

Image for post
Only 120 objects and 15 kB are consumed, no matter how long the app runs
无论应用运行多长时间,仅消耗120个对象和15 kB

结论 (Conclusion)

The mp_chart package is really useful for realtime charts — and many more chart types. There are so many configurable properties. With little effort, other widgets of the mp_charts package can be cut out from the example and used in own apps. I used also the widget OtherChartRadar as in the following animation. The cut out process is quite similar to the above described steps.

mp_chart包对于实时图表和其他更多图表类型非常有用。 有太多可配置的属性。 毫不费力地,可以从示例中删除mp_charts包的其他小部件,并在自己的应用程序中使用。 我还在以下动画中使用了小部件OtherChartRadar。 切出过程与上述步骤非常相似。

Image for post
The radar chart of the mp_chart package
mp_chart软件包的雷达图

The full source of my test app is on Github.

我的测试应用程序的完整源代码在Github上

翻译自: https://levelup.gitconnected.com/a-realtime-chart-with-flutter-75d1840b7789

css 颤动

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值