c# - 我在 Blazor 应用程序中使用 Chart.js 和 JSInterop。当数据集中有新数据时,如何更新图表?

标签 c# chart.js blazor blazor-server-side blazor-jsinterop

我有一个 Blazor 服务器应用程序,我在其中通过 JSInterop 将 Chart.js 库用于我的图表。 在折线图中我显示了 20 个测量值 当所有 20 个值都存在并且我打开图表时,图表工作正常。 该图表绘制了 20 个值的曲线。

但我想使用该图表作为实时图表。这意味着当每秒有一个新的数据值进入数据数组时,我想更新图表。这怎么可能?

这是我的代码:

图表所在的我的 Razor 页面

@page "/wmi_performance2"
@inject TagService TagService
@using System.IO
@inject IJSRuntime JSRuntime
<Chart Id="bar1" Type="@Chart.ChartType.Bar"
   Data="@CPU_Load_array"
   
   Labels="@Measuring_points_array">
</Chart>

共享/组件文件夹中的我的 Chart.razor

@using System.IO
@inject IJSRuntime JSRuntime
@using Microsoft.JSInterop;
@inject IJSRuntime jsInvoker

<canvas id="@Id"></canvas>
@code {
public enum ChartType    
    {
        Pie,
        Bar
    }
    [Parameter]
    public string Id { get; set; }
    [Parameter]
    public ChartType Type { get; set; }
    [Parameter]
    public string[] Data { get; set; }
    [Parameter]
    public string[] BackgroundColor { get; set; }
    [Parameter]
    public string[] Labels { get; set; }
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        // Here we create an anonymous type with all the options
        // that need to be sent to Chart.js
        
        try{

        var config = new
        {
            Type = Type.ToString().ToLower(),
            Options = new
            {
                Responsive = true,
                Scales = new
                {
                    YAxes = new[]
                {
                    new { Ticks = new {
                        BeginAtZero=true
                    } }
            }
                }
            },
            Data = new
            {
                Datasets = new[]
            {
                new { Data = Data, BackgroundColor = BackgroundColor}
        },
                Labels = Labels
            }
        };

        await JSRuntime.InvokeVoidAsync("setup", Id, config);
        
        }

        catch(Exception e)
        {
        using (StreamWriter sw = File.AppendText((Pages.CommonClass.error_path)))
        {
            sw.WriteLine("Chart.JS Error: " + e + Environment.NewLine);
        }
        }
        
        
    }
}

我的chart.js在wwwroot下

window.setup = (id, config) => {
var ctx = document.getElementById(id).getContext('2d');
new Chart(ctx, config);
}

最佳答案

通常,您会像所有其他 JS 互操作调用一样使用 JSRuntime 的 InvokeAsnycInvokeVoidAsync 方法。这是一个简单的例子。

JavaScript 部分:

window.setupChart = (id, config) => {
    var ctx = document.getElementById(id).getContext('2d');
    new Chart(ctx, config);
}

Blazor C# 部分:

[Inject]
public IJSRuntime JSRunTime { get; set; }
public string id = "chartCanvas";  // ID for canvas: <canvas id="@Id"></canvas>

protected override async Task OnAfterRenderAsync(bool firstRender)
{
    if (firstRender)
    {
        var config = new
        {
            Type = "line",
            Options = new { ... },
            Data = new { ... }
        }
        await JSRuntime.InvokeVoidAsync("setupChart", id, config);
    }
}

它工作正常,但您无法更新图表或无法向其中添加任何内容。

解决方案是 Blazor 中的 IJSObjectReference。这正是这个函数的用途。

您需要将之前的代码更改为以下内容:

JavaScript 部分:

window.setupChart = (id, config) => {
    var ctx = document.getElementById(id).getContext('2d');
    return new Chart(ctx, config);
},
window.updateChart = (chartRef, visible) => {
    // Example: make visible/hidden the 4th dataset in the chart
    chartRef.data.datasets[3].hidden = visible;
    chartRef.update();
}

Blazor C# 部分:

[Inject]
public IJSRuntime JSRunTime { get; set; }
private IJSObjectReference? chartInstance;
public string id = "chartCanvas";

protected override async Task OnAfterRenderAsync(bool firstRender)
{
    if (firstRender)
    {
        var config = new
        {
            Type = "line",
            Options = new { ... },
            Data = new { ... }
        }
        chartInstance = await JSRuntime.InvokeAsync<IJSObjectReference>("setupChart", id, config);
    }
}
public async Task UpdateChart()
{
    await JSRuntime.InvokeVoidAsync("updateChart", chartInstance, false);
}

就这样,您可以更新现有图表。

并且不要忘记在您的 razor 组件中实现 @implements IAsyncDisposable 并处置它:

async ValueTask IAsyncDisposable.DisposeAsync()
{
    if (chartInstance is not null)
    {
        await chartInstance.DisposeAsync();
    }
}

关于c# - 我在 Blazor 应用程序中使用 Chart.js 和 JSInterop。当数据集中有新数据时,如何更新图表?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74232991/

相关文章:

c# - 在 C++ 中使用非常 C# 的 DLL

c# - 平台不支持异常 : The following constructor parameters did not have matching fixture data

c# - Linq 用整数列表连接对象列表

c# - 什么是 C# 中的透明类或透明方法?`

vue.js - 使用 VueJS 在图表上绘制异步信息

c# - Blazor - 将函数传递给动态组件

Azure 应用服务为 Blazor 应用程序设置环境吗?

javascript - 根据窗口宽度更改 Chart.js 选项

ruby-on-rails - 图表未与 wicked_pdf 一起显示

blazor - 如何使用 asp.net core blazor web assembly 显示 google adsense 广告