#flutter #dart #syncfusion #syncfusion-chart
Вопрос:
Я пытаюсь создать линейный график в реальном времени с помощью 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 amp;amp;
tempElapsed != mainSnapshot.data["elspsed"] amp;amp;
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(включить: true),
первичная ось: ось времени(),
серия: <LineSeries<_ChartData, DateTime><_ChartData, DateTime>>[
LineSeries<_ChartData, Типа Datetime>(
источник данных: chartData,
xValueMapper: (сведения _ChartData, _) => сведения.х,
yValueMapper: (сведения _ChartData, _) => сведения.г)
]),
)
],
)
],
),
),
);
}
}
Я запутался в том, как добавить график в реальном времени вместо простого числа. Streambuilder предоставляет значение BPM. Я попытался создать диаграмму, пытаясь следовать этому: Пример синхронизации
В итоге получилось создать 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;
}
And then tried adding the following to streambuilder:
data = values[chartCount];
chartTimer = Timer.periodic(Duration(milliseconds: 3000), _updateDataSource);
I never got anywhere with this and had no data in the chart