Линейная диаграмма в реальном времени Syncfusion Flutter - данные из Streambuilder

Я пытаюсь создать диаграмму в реальном времени с помощью линейнуюpub.dev . Он хорошо зарекомендовал себя для построения графиков с использованием API и одновременного получения всех данных. Сейчас я пытаюсь построить график в реальном времени. В настоящее время мое приложение считывает удары сердца с устройства и отображает BPM, постоянно меняя значение каждую секунду. Что-то вроде следующего снимка экрана:

Изображение сердца выше - это анимация, которая бьется, и число меняется каждую секунду в зависимости от чтения. В приведенном ниже коде показано, как я этого добился.

      class Reading extends StatefulWidget {
  Reading({Key key, this.device, this.char, this.allTags});

  final BluetoothDevice device;
  final BluetoothCharacteristic char;
  final List allTags;

  @override
  ReadingState createState() => ReadingState();
}

class ReadingState extends State<Reading> with WidgetsBindingObserver {
  int percent;
  Timer _timer;
  double count = 0;
  int tempElapsed = 0;
  String tempByte = "";

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
    Wakelock.enable();
    _startTimer();
    // setup();
  }

  @override
  void dispose() {
    super.dispose();
    WidgetsBinding.instance.removeObserver(this);
  }

  stopReading(ctx, character) async {
    await character?.setNotifyValue(false);
    if ((widget?.allTags ?? []).length > 0) {
      sl<IDashboardProvider>().showTagPicker(context, widget?.allTags);
    } else {
      sl<IDashboardProvider>().navigateToAnalysis(context);
    }
  }

  incrementCount() {
    if (this.count + 1 == READING_DURTION_IN_SECOND) {
      setState(() {
        count = READING_DURTION_IN_SECOND.toDouble();
      });
      _timer.cancel();
      stopReading(context, widget.char);
    } else {
      setState(() {
        count = count + 1;
      });
    }
  }

  _startTimer() {
    _timer = Timer.periodic(
      Duration(seconds: 1),
      (Timer timer) => incrementCount(),
    );
  }

  _pauseTimer() {
    _timer.cancel();
  }

  showDialogFunction(context) {
    showDialog(
      context: context,
      builder: (BuildContext ctx) {
        return AlertDialog(
          title: new Text("Warning"),
          content: new Text(
              "Device disconnected, please try again connecting the device"),
          actions: <Widget>[
            new FlatButton(
              child: new Text("Ok"),
              onPressed: () {
                Navigator.of(ctx).pushAndRemoveUntil(
                    MaterialPageRoute(
                        builder: (context) => NewDevice(
                              deviceFor: 0,
                            )),
                    (Route<dynamic> route) => false);
              },
            ),
          ],
        );
      },
    );
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) async {
    super.didChangeAppLifecycleState(state);
    if (state == AppLifecycleState.resumed) {
      _startTimer();
    } else if (state == AppLifecycleState.paused) {
      _pauseTimer();
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        elevation: 0,
        automaticallyImplyLeading: false,
        centerTitle: true,
        title: Text("Activity"),
        backgroundColor: PRIMARY,
      ),
      body: Container(
        height: MediaQuery.of(context).size.height,
        child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: <Widget>[
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                SpinKitPumpingHeart(
                  color: PRIMARY,
                  size: 30,
                ),
                SizedBox(
                  width: 10,
                ),
                widget?.char?.value == null
                    ? Container()
                    : StreamBuilder<Map>(
                        stream: widget?.char?.value,
                        initialData: widget?.char?.lastValue,
                        builder: (c, mainSnapshot) {
                          var value;
                          print("NOTES - device print - ${mainSnapshot?.data}");
                          value = mainSnapshot.data != null
                              ? mainSnapshot.data["value"]
                              : 0;
                          if (this.count >= 10 &&
                              tempElapsed != mainSnapshot.data["elspsed"] &&
                              tempByte != mainSnapshot.data["byte"]) {
                            sl<IDashboardProvider>()
                                .recordedData
                                .add(mainSnapshot.data["byte"].trim());
                            tempElapsed = widget?.char?.lastValue["elapsed"];
                            tempByte = widget?.char?.lastValue["byte"];
                            print(
                                "NOTES - recorded data list Length - ${sl<IDashboardProvider>().recordedData.length}");
                            print(
                                "NOTES - recorded data list - ${sl<IDashboardProvider>().recordedData}");
                          }

                          return RichText(
                            text: TextSpan(
                              children: <TextSpan>[
                                TextSpan(
                                  text: value.toString(),
                                  style: TextStyle(
                                      fontSize: 20,
                                      color: DARK_GREY,
                                      fontFamily: "HRVFont"),
                                ),
                                TextSpan(
                                  text: " bpm",
                                  style: TextStyle(
                                      fontSize: 16,
                                      color: MEDIUM_GREY,
                                      fontFamily: "HRVFont"),
                                )
                              ],
                            ),
                          );
                        }),
                StreamBuilder<BluetoothDeviceState>(
                  stream: widget.device.state,
                  initialData: BluetoothDeviceState.CONNECTING,
                  builder: (c, snapshot) {
                    String text;
                    if (_timer.isActive)
                      switch (snapshot.data) {
                        case BluetoothDeviceState.DISCONNECTED:
                          text = "DISCONNECTED";
                          WidgetsBinding.instance.addPostFrameCallback(
                              (_) => showDialogFunction(context));
                          widget.device.disconnect();
                          _timer.cancel();
                          break;
                        default:
                          text = "UNKNOWN";
                          break;
                      }
                    return Container();
                  },
                ),
              ],
            ),
            Text(
              "We are getting your data",
              style: TextStyle(fontSize: 20, color: DARK_GREY),
            ),
            Stack(
              alignment: Alignment.center,
              children: <Widget>[
                CircularPercentIndicator(
                  radius: 100.0,
                  lineWidth: 8.0,
                  percent: (this.count / (READING_DURTION_IN_SECOND + 1)) * 1,
                  center: new Text(
                    ((this.count / (READING_DURTION_IN_SECOND + 1)) * 100)
                            .toInt()
                            .toString() +
                        "%",
                    style: new TextStyle(
                        fontWeight: FontWeight.bold, fontSize: 20.0),
                  ),
                  circularStrokeCap: CircularStrokeCap.round,
                  progressColor: PRIMARY,
                ),
                SpinKitPulse(
                  color: PRIMARY,
                  size: 80,
                ),

Контейнер (дочерний: SfCartesianChart (tooltipBehavior: TooltipBehavior (enable: true), primaryXAxis: DateTimeAxis(),series: <LineSeries<_ChartData, DateTime>>[LineSeries<_ChartData, DateTime>(dataSource: _ChartData, DateTime> (dataSource: _ChartData, x ) => data.x, yValueMapper: (_ChartData data, _) => data.y)]),)],)],),),); }}

Я не понимаю, как добавить линейную диаграмму в реальном времени вместо простого числа. Streambuilder предоставляет значение BPM. Я попытался создать диаграмму, пытаясь следовать этому: Пример Syncfusuion

В итоге я создал 2 переменные, которые, по моему мнению, были не самыми идеальными.

      Timer chartTimer;
int chartCount = 0;
List<_ChartData> chartData = <_ChartData>[];
Map<dynamic, dynamic> data;

void _updateDataSource(Timer chartTimer) {
    setState(() {
      chartData.add(_ChartData(
          x: DateTime.fromMillisecondsSinceEpoch(data['x']), y1: data['y1']));
      // if(chartData.length >= 20){
      //   chartData.removeAt(0);
      // }    
    });

    chartCount = chartCount + 1;
  }

А затем попытался добавить в streambuilder следующее:

      data = values[chartCount];
chartTimer = Timer.periodic(Duration(milliseconds: 3000), _updateDataSource); 

У меня ничего не получилось с этим и не было данных в диаграмме

1 ответ

Спасибо за интерес к нашим диаграммам Flutter. Мы проанализировали ваш запрос и подготовили образец линейной диаграммы с помощью StreamBuilder в качестве справки, и вы можете изменить его в соответствии с вашими требованиями. Вы также можете связаться с нами через наши форумы поддержки , Direct-Trac или портал обратной связи, если вам потребуется дополнительная помощь. Мы всегда рады Вам помочь!

Другие вопросы по тегам