William Leme

Software Engineer

Chart.js + Blazor

Posted at — Jun 12, 2020

In this tutorial we will be creating a blazor component that receives the chart data and passes it to the Chart js library. This component will be limited to a Pie and Bar types but the idea is the same in case you want to implement other types.

Adding Chart.js to the project

Go to index html and add the Chart.js library from their cdn

1
2
<!--index.html-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.bundle.min.js"></script>

Creating a Chart blazor component

We are going to create a new file called Chart.razor. Our component will receive all the data from the parent and pass it down to the Chart.js library via Javascript interop. It will have the following properties: Id, Type, Data, BackgroundColor and Labels. Usage example: <Chart Id="pie1" Type="@Chart.ChartType.Pie" Data="@(new[] { "1", "2" })" BackgroundColor="@(new[] { "blue","green"})" Labels="@(new[] { "Fail","Ok"})"></Chart>.
Since we have to have the canvas html element rendered in the page before invoking the library we use OnAfterRenderAsync to do our logic and call the js library.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
@*//Chart.razor*@
@inject IJSRuntime JSRuntime

<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
        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);
    }
}

Calling setup()

We create a new javascript file called chart.js which initializes our Chart js component in a function called setup(). It receives the canvas Id and the config options from the blazor component.

1
2
3
4
5
//chart.js
window.setup = (id,config) => {
    var ctx = document.getElementById(id).getContext('2d');
    new Chart(ctx, config);
}

and then we add chart.js to index.html

1
2
3
<!--index.html-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.bundle.min.js"></script>
<script src="chart.js"></script>

Using the new component

Now we have our <Chart> component ready to be used. Simply add the tag to a new page/component E.g.

1
2
<Chart Id="pie1" Type="@Chart.ChartType.Pie" Data="@(new[] { "1", "2" })" BackgroundColor="@(new[] { "blue","green"})" Labels="@(new[] { "Fail","Ok"})"></Chart>
<Chart Id="bar1" Type="@Chart.ChartType.Bar" Data="@(new[] { "10", "9" })" BackgroundColor="@(new[] { "yellow","red"})" Labels="@(new[] { "Fail","Ok"})"></Chart>

alt text

Our component is not setting the dataset label option therefore undefined is rendered.

Conclusion

This is a bare bone implementation that can be used as a blueprint if you want to extend it. Chart.js offers many different options to render the charts and they just need to be mapped in our anonymous class. E.g. If we want to create a property that holds the dataset label (and remove undefined from our rendered object) we would have something like this

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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, 
                    Label=YourNewLabelProperty}
        },
        Labels = Labels
    }
};

Happy Coding!! :smiley::computer:
William Leme