Blazor WebAssembly: Using C3.js to Create Charts in Blazor WebAssembly Application

In this tutorial, we will see the way of creating Charts in Blazor WebAssembly by integrating with C3.js in it. Please note that, the implementation is completely my thought which I have suggested to one of my client. In this tutorial, the implementation is done g JavaScript interoperability.

One of the great features of the Blazor Application is that, it has an interoperability with JavaScript. I have already written an article on JavaScript interoperability on my blog. You can read steps of JavaScript interoperability from here.  In Blazor Application, there is no default support for Charts are available. So to provide charts in Blazor some other alternatives must be planned. Recently, when I was  discussing about the Blazor WebAssembly to one of my customer, he raised query on creating Charts. I demoed him and then I thought to write a small tutorial on it. 

C3.js

C3.js is JavaScript library based on D3.js. This enables deeper integration of charts into the application. This is a small customizable library that is used to create charts in the application. C3.js generates charts using the generate() method. This method accepts object as an input parameter. This object consists of the properties those are used to act as a data source to generate chart, e.g. data, axis bindto, etc. using these properties the charts is generated and bind to the HTML element on the browser. You can read all details of C3.js from this link.

An Implementation     

The application is implemented using Visual Studio 2022 Enterprise  Preview. You can implement this application using Visual Studio 2019 with .NET 5 SDK.

Step 1: Open Visual Studio and create a new Blazor WebAssembly application. Name this application as Blazor_Charts. 

Step 2: To use the C3.js in the application, download the latest source-code of C3.js from this link. Download this zip and extract it. Once you extract the zip, from the extracted folder add c3.js, d3-5.8.2.min.js and c3.css files in the wwwroot folder of the Blazor_Charts project.

Step 3: Lets create a hard-coded data to generate chart in the project. (Note: You can use API to receive data for generating chart. I have already written an article on this link for accessing API in Blazor App). In the project, add a new folder and name it as Models. In this folder add a new class file and name it as Population.cs. In this class file, add the code as shown in listing 1

using System.Collections.Generic;

namespace Blzor_Charts.Models
{
    public class Population
    {
        public string State { get; set; }
        public int Count { get; set; }
    }

    public class PopulationData : List<Population>
    {
        public PopulationData()
        {
            Add(new Population { State = "MH", Count = 34000});
            Add(new Population { State = "AP", Count = 14000 });
            Add(new Population { State = "GJ", Count = 24000 });
            Add(new Population { State = "KR", Count = 28000 });
            Add(new Population { State = "AP", Count = 26000 });
            Add(new Population { State = "PB", Count = 30000 });
            Add(new Population { State = "UP", Count = 64000 });
            Add(new Population { State = "JK", Count = 4000 });
            Add(new Population { State = "RJ", Count = 15000 });
            Add(new Population { State = "MP", Count = 64000 });
            Add(new Population { State = "TN", Count = 34000 });
            Add(new Population { State = "TS", Count = 16000 });
            Add(new Population { State = "OR", Count = 38000 });
            Add(new Population { State = "UK", Count = 14000 });
        }
    }
}


Listing 1: The Population data 

Step 4: In the wwwroot, add a new JavaScript file and name it as drawChart.js. In this file, we will add code for generating chart using C3.js. The code for generating charts is provide in listing 2     

function populationLineChart([]) {
    let data = [];
    let labels = [];
    // data points for chart range on Y-Axis
    data = arguments[0];
    // labels on X-Axis
    labels = arguments[1];
    var chart1 = c3.generate({
        bindto: '#population',
        data: {
            columns: [
                data
            ]
        },
        axis: {
            x: {
                type: 'category',
                categories: labels,
                label: {
                    text: 'States',
                    position: 'outer-center'
                }
            },
            y: {
                label: {
                    text: 'Population',
                    position: 'outer-center'
                }
            }
        }
    });
}

function populationBarChart([]) {
    let data = [];
    let labels = [];
    data = arguments[0];
    labels = arguments[1];
    var chart = c3.generate({
        bindto: '#population',
        data: {
            columns: [
                data
            ],
            type: 'bar'
        },
        bar: {
            width: {
                ratio: 0.5  
            }
        
        },
        axis: {
            x: {
                type: 'category',
                categories: labels,
                 label: {
                    text: 'States',
                    position: 'outer-center'
                }
            },
            y: {
                label: {
                    text: 'Population',
                    position: 'outer-center'
                }
            }
        }
    });
}


           

Listing 2: The code to generate charts

The code in listing 2, contains two JavaScript function to create LineChart and BarChart. The  populationLineChart() function accepts an array as input parameter. This array represent the data that is required to generate chart. The method reads Label and Data required top generate chart from the input array. The generate() method of c3 object, accepts the JSON object as input parameter. THis object has several properties. The bindto property represents the HTML element where the chart will be generated. In our case, the bindto property is assigned #population. This means that the chart will be rendered in the HTML element with id as population. The data object is a complex object, this object has the columns property. This property accepts an array of arrays . These array is represents the data used to generate chart data points and labels on chart axis. The axis property represents the X and Y axis. This property is a complex JSON object. This object contains x and y axis configurations to show data range, labels, text, etc. The generate() method of the c3  generates Line chart by default. The populationBarChart() method has the similar implementation like populationLineChart() method, except that the type property of the data object contains value as bar to generate bar chart. This method also defines width for each bar in chart. 

Step 5: To load the C3.js with all its dependencies in the browser, modify index.html in wwwroot folder and css and script references in head section as shown in listing 3

  <!-- Load c3.css -->
    <link href="./c3.css" rel="stylesheet">

    <!-- Load d3.js and c3.js -->
    <script src="./d3-5.8.2.min.js" charset="utf-8"></script>
    <script src="./c3.min.js"></script>
    

Listing 3: The Script and css references               

Add script reference of drawChart.js in index.html before closing body tag as shown in Listing 4 
<script src="./drawChart.js"></script>


Listing 4: Reference for ndrawChart.js

Step 6: Modify app.css to define dimension for chart by adding a new class in it as shown in listing 5

.c1 {
    height:400px; width:800px
}

Listing 5: The CSS class in app.css 

Step 7: In the Pages folder, add a new Razor Component and name it as PopulationChartComponent.razor. In this component add the code shown in listing 6

@page "/populationchart"
@using Blzor_Charts.Models
@inject IJSRuntime js
<h3>Population Chart Component</h3>

<div class="container">
    <table class="table table-bordered table-striped">
        <tbody>
            <tr>
                <td>
                    <button class="btn btn-success"
                    @onclick="@generateLineChartTask">Line Chart</button>
                </td>
                 <td>
                    <button class="btn btn-danger" 
                    @onclick="@generateBarChartTask">Bar Chart</button>
                </td>
            </tr>
        </tbody>
    </table>
    <div id="population"></div>
</div>
@code {
    private PopulationData dataSource;
    private  List<string> xSource;
    private  List<int> ySource;
    private List<object> source; 
    protected override Task OnInitializedAsync()
    {
        dataSource = new PopulationData();
        xSource = new List<string>();
        ySource = new List<int>();
        source = new List<object>();  
        foreach (var p in dataSource)
        {
            xSource.Add(p.State);
            ySource.Add(p.Count);
        }
        source.Add(ySource);
        source.Add(xSource);
        return base.OnInitializedAsync();
    }

    async Task  generateLineChartTask()
    {   
       await js.InvokeAsync<object>("populationLineChart", source.ToArray());
    }
    async Task  generateBarChartTask()
    {
       
       await js.InvokeAsync<object>("populationBarChart", source.ToArray());
    }
}


Listing 6: The PopulationChartComponent.razor
The code in listing 6 shows that the component  is injected with IJSRuntime interface. This will be used to access JavaScript methods in Blazor component. The component contains div tag which is having id as population. The chart will be generated in this div tag. The component uses the population array stored in the PopulationData class which we have created in listing 1 to pass chart data to methods from JavaSCript file. In the OnInitializedAsync() method, the population data is read and stored in xSource and ySource list object. These objects contains data to be shown on X and Y axis of the chart. The source list will be used to pass the xSource and ySource to the JavaScript methods to generate chart. The component contains generateLineChartTask() and generateBarChartTask() methods. These methods using IJSRuntime object to invoke methods from the JavaScript file and pass the source object to it. These method are bound to HTML buttons.

Step 8: Modify the NavMenu.razor file to add Route link for PopulationChartComponent as shown in listing 7


 <li class="nav-item px-3">
            <NavLink class="nav-link" href="populationchart">
                <span class="oi oi-list-rich" aria-hidden="true"></span> Population Chart
            </NavLink>
        </li>
Listing 7: Route link for PopulationChartComponent    

Run the application. The application will be loaded in the browser, once the application is loaded, click on Population Chart link. This will load component as shown in Figure 1



Figure 1: The Component loaded
Click on Line Chart  button, the Line Chart will be displayed as shown in Figure 2



Figure 2: Line Chart
Click on Bar Chart button, the bar chart will be displayed as shown in Figure 3



Figure 3: Bar Chart

You can use other chart types in the application. 
The code for this article can be downloaded from this link.

Conclusion: The Blazor application does not have default support for the Charts but using Chart JavaScript libraries charts can be easily created. 

Comments

Popular posts from this blog

Understanding Token Based Authentication in ASP.NET Core 3.1 using JSON WEB TOKENS

Using Model Binders in ASP.NET Core

Using Session State in ASP.NET Core