Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pull Back Issue while getting the live data from websocket #2318

Open
BARSHA-ABHILASHA opened this issue Mar 25, 2025 · 1 comment
Open

Pull Back Issue while getting the live data from websocket #2318

BARSHA-ABHILASHA opened this issue Mar 25, 2025 · 1 comment
Labels
charts Charts component waiting for customer response Cannot make further progress until the customer responds.

Comments

@BARSHA-ABHILASHA
Copy link

I am fetching real-time data via WebSockets from ThingsBoard and have fixed time window (10s), the timewindow is not depended to data points due to live it scrolling from right to left continuously without any interruption , if any data comes it should show in time window if not it will not affect the time window and time window will runs as usual without data.

ISSUE I AM FACING

The background time window is working correctly but while having the data ( as I am geeting the 200 of data in 1 chunk and it is also the time between the 2 chunks is not fixed so may be in 10sec i am getting 2 chunks * 200 data = 400 data or sometime i am getting 1 chunk * 200 data = 200 data ), So while the first chunk of data is coming looks good but while next chunk is coming and the 1st chunk is moving towards Y -axis while touching the Y-axis it looks like the 1st chunk is throwing the lines of graph to the 2nd chunk of graph to feed it (Looks like 2nd chunk is Pulling back the graphs from the 1st chunk which is actually not in window, I don't know may be the issue is in UI or backend)
Below is the actual flutter code implementation where i am getting the values and the issue i have explained above i captured a video of that, Please see the video and my code and review it where is the actuall issue Please suggest me I am waiting for the reply from you guys.

screen-20250325-201100.mp4

CODE

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:smarty/features/login/thingsboard_service.dart';
import 'package:syncfusion_flutter_charts/charts.dart';
import 'package:intl/intl.dart';
import 'package:web_socket_channel/io.dart';

class StatsHomeScreen extends StatefulWidget {
@OverRide
_StatsHomeScreenState createState() => _StatsHomeScreenState();
}

class _StatsHomeScreenState extends State {
List dataPoints = [];
late Timer timer;
int visibleDuration = 10; // Keep last 10 seconds visible
DateTime startTime = DateTime.now(); // Base time to move timeline
final ThingsBoardAuthService authService = ThingsBoardAuthService();

late IOWebSocketChannel channel; // WebSocket connection

@OverRide
void initState() {
super.initState();

// Initialize WebSocket connection
connectWebSocket();

// Timer for moving timeline every 500ms
timer = Timer.periodic(const Duration(milliseconds: 500), (timer) {
  setState(() {
    // Shift the start time forward to create a scrolling effect
    startTime = startTime.add(const Duration(milliseconds: 500));

    // Remove old data beyond visible range
//     dataPoints.removeWhere((point) =>
//   point.time.isBefore(startTime.subtract(Duration(seconds: visibleDuration)))
// );
    dataPoints.removeWhere((point) =>
        DateTime.now().difference(point.time).inSeconds > visibleDuration);
  });


});

}

Future connectWebSocket() async {
print("🔌 Connecting to WebSocket...");
String? accesstoken = await authService.getValidToken();
channel = IOWebSocketChannel.connect(
"ws://localhost/api/ws/plugins/telemetry?token=$accesstoken",
);

// Send subscription request to ThingsBoard
channel.sink.add(jsonEncode({
  "tsSubCmds": [
    {
      "entityType": "DEVICE",
      "entityId": "707970f0-ef6f-11ef-b7bb-93f364633065",
      "scope": "LATEST_TELEMETRY",
      "cmdId": 1
    }
  ],
  "historyCmds": [],
  "attrSubCmds": []
}));

// Listen for new telemetry data
channel.stream.listen(
  (message) {
    // print("📩 Received WebSocket Message: $message");

    try {
      var data = jsonDecode(message);
      var adcData = data["data"]["ADC Values CH_0"];
      if (adcData != null && adcData is List && adcData.isNotEmpty) {
        var timestamp = int.parse(
            adcData[0][0].toString()); // First item in list is timestamp
        var value = double.parse(
            adcData[0][1].toString()); // Second item is the value (string)
        setState(() {
          dataPoints.add(LiveData(
              DateTime.fromMillisecondsSinceEpoch(timestamp), value));
        });
      } else {
        print("⚠️ No valid ADC Values CH_0 data found.");
      }
    } catch (e) {
      print("❌ Error parsing WebSocket data: $e");
    }
  },
  onDone: () {
    print("❌ WebSocket Connection Closed.");
  },
  onError: (error) {
    print("🚨 WebSocket Error: $error");
  },
);

}

@OverRide
void dispose() {
timer.cancel();
channel.sink.close(); // Close WebSocket connection
print("🔌 WebSocket Disconnected.");
super.dispose();
}

@OverRide
Widget build(BuildContext context) {
DateTime minTime = startTime.subtract(Duration(seconds: visibleDuration));
DateTime maxTime = startTime;

return Scaffold(
  appBar: AppBar(title: const Text("Live Timeline Chart")),
  body: Padding(
    padding: const EdgeInsets.all(16.0),
    child: SfCartesianChart(

      zoomPanBehavior: ZoomPanBehavior(
                enablePinching: true,
                zoomMode: ZoomMode.xy,
                enablePanning: true,
              ),
              trackballBehavior: TrackballBehavior(
                enable: true,
                activationMode: ActivationMode.singleTap,
              ),
      primaryXAxis: DateTimeAxis(
        minimum: minTime,
        maximum: maxTime,
        intervalType: DateTimeIntervalType.seconds,
        interval: 1, // Keep 1-second grid lines
        dateFormat: DateFormat.Hms(),
        // majorGridLines: const MajorGridLines(width: 1, color: Colors.grey),
      ),
      primaryYAxis: NumericAxis(
        isVisible: dataPoints.isNotEmpty, // Hide Y-axis if no data
      ),
      series: <LineSeries<LiveData, DateTime>>[
        LineSeries<LiveData, DateTime>(
          dataSource: dataPoints,
          xValueMapper: (LiveData data, _) => data.time,
          yValueMapper: (LiveData data, _) => data.value,
          color: Colors.blue,
          width: 3,
        ),
      ],
    ),
  ),
);

}
}

// Data model for time-series points
class LiveData {
final DateTime time;
final double? value;
LiveData(this.time, this.value);
}

@LavanyaGowtham2021 LavanyaGowtham2021 added charts Charts component open Open labels Mar 26, 2025
@PreethikaSelvam
Copy link
Contributor

Hi @BARSHA-ABHILASHA,

Thank you for sharing the details and the video demonstrating the issue you're experiencing. Based on our analysis, we observed that the chart appears to "stretch" or "pull" data when new chunks arrive. This is likely due to the default animation applied during chart updates with new data points.

To resolve this, we recommend disabling animation by setting animationDuration to 0 in series. This will ensure smooth and immediate updates without distortion, providing a consistent real-time scrolling experience without visual glitches.

If you prefer to keep animation, we suggest using FastLineSeries, which is optimized for rendering large volumes of data efficiently. We have shared a code snippet and demo using both FastLineSeries and LineSeries, with and without animation, for your reference.

Code snippet using FastLineSeries with animation disabled:

          series: < FastLineSeries <LiveData, DateTime>>[
            FastLineSeries<LiveData, DateTime>(
              animationDuration: 0,
              dataSource: _dataPoints,
              xValueMapper: (LiveData data, _) => data.time,
              yValueMapper: (LiveData data, _) => data.value,
              width: 3,
              color: Colors.blue,
            ),
          ]

UG Links:
https://help.syncfusion.com/flutter/cartesian-charts/series-customization#animation
https://help.syncfusion.com/flutter/cartesian-charts/chart-types/fast-line-chart

Additionally, to boost the performance of the chart when there is a need to plot high volume data. We suggest following the key points below that can be used to boost the performance of the chart when there is a need to plot high volume data:

• Load and store the required data points in the initState method itself and then set the data points to the chart series.
• Use NumericAxis or DateTimeAxis instead of CategoryAxis.
• When there are large number of points to load in line series, you can use FastLineSeries series instead of LineSeries.
• Instead of enabling data markers and labels when there are large number of data points, you can use Trackball to view the point information.
• Set series animationDuration as 0 to disable the animation while loading large number of data points.
• Use updateDataSource method while updating dynamic data points instead of calling setState. For more details refer ug - https://help.syncfusion.com/flutter/cartesian-charts/methods#updatedatasource.
• Use On-demand loading while rendering large data points, it can be used to load more data to the chart when the visible range reaches the end on dragging in the chart. https://help.syncfusion.com/flutter/cartesian-charts/on-demand-loading
• Use autoScrollingDelta property in the Axis, to show the number of dataPoints always visible in the SfCartesianChart.

If you still face the issue, we kindly request you to try to replicate the reported issue in the below attached test sample and revert us so that it will help us assist you in a better way.

Please let us know if you need any further assistance.

gh2318.zip
FastLineSeriesDemo (1).zip
LineSeriesDemos.zip

Regards,
Preethika Selvam.

@Saravanan-Madhesh Saravanan-Madhesh added waiting for customer response Cannot make further progress until the customer responds. and removed open Open labels Apr 9, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
charts Charts component waiting for customer response Cannot make further progress until the customer responds.
Projects
None yet
Development

No branches or pull requests

4 participants