apexcharts / Blazor-ApexCharts

A blazor wrapper for ApexCharts.js
https://apexcharts.github.io/Blazor-ApexCharts
MIT License
837 stars 92 forks source link

Real-time chart losing it's drawn lines #509

Open horrorhound opened 2 months ago

horrorhound commented 2 months ago

I'll try and get a sample project for this together to demo this but for now here is the issue:

Razor page with ApexChart injects a Blazor Server Service Service is Singleton Service which Raises Events with a int value. Razor page accepts the raised event from singleton service OnEvent Method adds Timestamp h:mm:ss format to XValue and the int value to YValue If an event executes to "quickly" the lines in the chart disappears.

Thoughts Maybe some type of collision in threads so I've tried adding locks and delays in the events. I think maybe the chart is trying to re-write data for the same Timestamp value which it just wrote might cause the problem.

To recover I have to re-load the page or call RenderAsync(). Once the lines disappear I can still write to the Chart and the tool tips update and new XValues are added, but the YValue lines fail to ever display until I perform a recovery step.

```

<ApexChart @ref=_apexChart TItem="ChartDataPoint" Title="Checkins" Options=_apexOptions>

</ApexChart>

private class ChartDataPoint { public DateTime Timestamp { get; set; } public int Value { get; set; } } private ApexChart _apexChart; private ApexChartOptions _apexOptions = new ApexChartOptions { Colors = new List { "rgba(119,107,231,1)" }, Theme = new Theme {

    Mode = Mode.Dark,
    Palette = PaletteType.Palette10  // Palette doesn't seem to change at all.
  },
  Chart = new Chart
  {
    Animations = new Animations
    {
      Enabled = true,
      Easing = Easing.Linear,
      DynamicAnimation = new DynamicAnimation
      {
        Speed = 950
      }
    },
    Height = 350,
    Toolbar = new Toolbar
    {
      Show = false
    },
    Type = ApexCharts.ChartType.Line,
    Background = "rgb(55, 55, 64)",
    Zoom = new Zoom
    {
      Enabled = false
    }
  },
  Yaxis = new()
  {
      new()
      {
          TickAmount = 10,
          Min = 0,
          Max = 50
      }
  },
  Xaxis = new()
  {
    Range = 10 // number of datapoints to display.
  },
  Stroke = new Stroke { Curve = Curve.Straight },
};

private void HandleOnChanged { await _apexChart.AppendDataAsync(dataToAppend); }

joadan commented 1 month ago

Sorry but I would recomend with a simple example and try to reproduce. Have you looked at the sample at https://apexcharts.github.io/Blazor-ApexCharts/methods/update-series#realtime

horrorhound commented 1 month ago

Yes, I've seen that and my code works fine also; but the issue is when the XValue already exists and you try and update it. So that's a good idea though; maybe I'll take their sample code and re-create the issue without changing the date on the XValue in their sample.

What I have working at the moment is this...

Event: Queue up the data to be processed by Apexchart; cause processing the data immediately if there's already the same timestamp data on the chart causes failure.

private void HandleStatsChanged(Data.ProductStats productStat)
  {
    Log.Information("Entered HandleStatsChanged...");
    lock (_pendingData)
    {
      var timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
      // Append to existing entry or add new one if it doesn't exist
      if (_pendingData.ContainsKey(timestamp))
      {
        _pendingData[timestamp] += 1;
      }
      else
      {
        _pendingData[timestamp] = 1;
      }

      Task.Delay(5);  // Can probably remove
    }
 }

Timer: Update the chart based off a timer event every 3seconds.

private void OnTimerElapsed(object state)
{
  lock (_pendingData)
  {
    // Collect the data accumulated in the last second and append it to the chart
    if (_pendingData.Count > 0)
    {
      var dataToAppend = _pendingData.Select(kvp => new ChartDataPoint
        {
          Timestamp = DateTime.Parse(kvp.Key),
          Value = kvp.Value
        }).ToList();

      // Clear the pending data
      _pendingData.Clear();

      // Update the chart on a different thread
      InvokeAsync(async () =>
      {
        await _apexChart.AppendDataAsync(dataToAppend);
      });
    }
  }
}