DEV Community

Cover image for Creating Stunning Charts for Your ASP.NET Applications
S. Olusegun Ojo
S. Olusegun Ojo

Posted on

Creating Stunning Charts for Your ASP.NET Applications

Introduction

Charts are fast becoming an essential part of user interfaces as more and more software requires users to be able to view/visualize data. While the most obvious examples are financial and numerical data, apps in other fields such as health, fitness, transportation, blogging and even social media feature graphical means of displaying data.

There have, consequently, been an increase in the number and quality of charting software and add-ons. Microsoft's Charts Helper was a relatively convenient means of creating graphs in ASP.NET applications; however, it is no longer the recommended means of creating charts.

Newer frontend libraries such as ChartsJS and Highcharts provide robust means of creating charts. They can be used with ASP.NET conveniently, with the data simply being supplied to these charting libraries on the frontend.

Using ChartsJS in .NET

With over 60k stars on GitHub and over 2 million npm downloads (as at the time of writing), ChartsJS is the most popular charting library for Javascript. It works with the HTML5 Canvas element, allowing data and configuration be passed in as regular Javascript.

Plus ChartJS has nice animations (which you can turn off if you don't want) that make the charts look and feel even nicer. 😁

Here's an example from the ChartsJS documentation:

new Chart(ctx, {
    type: 'bar',
    data: {
      labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
      datasets: [{
        label: '# of Votes',
        data: [12, 19, 3, 5, 2, 3],
        borderWidth: 1
      }]
    },
    options: {
      scales: {
        y: {
          beginAtZero: true
        }
      }
    }
  });
Enter fullscreen mode Exit fullscreen mode

The labels are supplied as an array of strings, the chart data values are also an array of numbers. The colours can also be provided so.

To use ChartsJS with our ASP.NET application simply requires us to provide the data from our backend to ChartsJS as arrays of values.

Demo

In this demo, available on GitHub at https://github.com/shegzee/dotnet-charts, I use ASP.NET's Razor pages to disiplay sample data in a bar chart and a pie chart.

Models/BankData.cs

In the data I will be charting, I include the bank name, colour for bar or pie slice and transactions count (the actual data value to be charted).

namespace TransChartDemo.Models
{
    public class BankData
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Colour { get; set; }
        public int Year { get; set; }
        public int TransactionsCount { get; set; }
    }
}

Enter fullscreen mode Exit fullscreen mode

Repositories/IBankDataRepository.cs

using TransChartDemo.Models;

namespace TransChartDemo.Repositories
{
    public interface IBankDataRepository
    {
        BankData GetBankData(int id);
        void AddBankData(BankData bankData);
        void UpdateBankData(BankData bankData);
        void DeleteBankData(int id);
        List<BankData> GetAllBankData();

    }
}
Enter fullscreen mode Exit fullscreen mode

Repositories/BankDataRepository.cs

Here's the actual implementation of the IBankDataRepository. I simply have a list of BankData objects containing the relevant values.

using TransChartDemo.Models;

namespace TransChartDemo.Repositories
{
    public class BankDataRepository : IBankDataRepository
    {
        List<BankData> sampleBankData = new List<BankData>
        {
            new BankData { Id = 1, Name = "GTB", Colour = "Orange", TransactionsCount = 1923 },
            new BankData { Id = 2, Name = "UBA", Colour = "Red", TransactionsCount = 2011 },
            new BankData { Id = 3, Name = "FBN", Colour = "LightBlue", TransactionsCount = 1820 },
            new BankData { Id = 4, Name = "ZIB", Colour = "Black", TransactionsCount = 1500 },
            new BankData { Id = 4, Name = "ACC", Colour = "LightGreen", TransactionsCount = 1947 }
        };
        public void AddBankData(BankData bankData)
        {
            sampleBankData.Add(bankData);
        }

        public void DeleteBankData(int id)
        {
            sampleBankData.Remove(sampleBankData.FirstOrDefault(b => b.Id == id));
        }

        public List<BankData> GetAllBankData()
        {
            return sampleBankData;
        }

        public BankData GetBankData(int id)
        {
            return sampleBankData.FirstOrDefault(b => b.Id == id);
        }

        public void UpdateBankData(BankData bankData)
        {
            var oldBankData = sampleBankData.FirstOrDefault();
            if (oldBankData != null)
            {
                sampleBankData.Remove(oldBankData);
                sampleBankData.Add(bankData);
            }
        }
    }
}

Enter fullscreen mode Exit fullscreen mode

Program.cs

In additional to the boilerplate, I configured Dependency Injection for IBankDataRepository.

using TransChartDemo.Repositories;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddRazorPages();

builder.Services.AddScoped<IBankDataRepository, BankDataRepository>();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.MapRazorPages();

app.Run();

Enter fullscreen mode Exit fullscreen mode

Pages/ChartArrayBasic.cshtml.cs

In this file, I'm simply adding the data (the list of BankData objects I manually created in BankDataRepository.cs) to the ViewData dictionary so it is accessible from ChartArrayBasic.cshtml. I went the route of using these almost redundant repository interface and implementation to demonstrate how easy it is to use ChartsJS with any ASP.NET application.

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System.Text.Json;
using TransChartDemo.Repositories;

namespace TransChartDemo.Pages
{
    public class ChartArrayBasicModel : PageModel
    {
        private readonly IBankDataRepository bankDataRepository;

        public ChartArrayBasicModel(IBankDataRepository _bankDataRepository)
        {
            bankDataRepository = _bankDataRepository;
        }

        public void OnGet()
        {
            var bankData = bankDataRepository.GetAllBankData();
            ViewData["allBankData"] = JsonSerializer.Serialize(bankData);
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Here, the bank data is serialized as a JSON string and passed to the ViewData dictionary in the line:

...
ViewData["allBankData"] = JsonSerializer.Serialize(bankData);
...
Enter fullscreen mode Exit fullscreen mode

Pages/ChartArrayBasic.cshtml

This is the Razor Page containing the frontend.

@page
@model TransChartDemo.Pages.ChartArrayBasicModel
@{

}
<div class="text-center">
    <h1 class="display-4">Charts.js Demo</h1>
    <p>Integrating Charts.js in ASP.NET Core</a>.</p>

    <div class="row">
        <div class="col-sm-6">
            <div class="card">
                <div class="card-header">
                    Bar Chart
                </div>
                <div class="card-body">
                    <canvas id="bar" class="my-4 h-25"></canvas>
                </div>
                <div class="card-footer">
                    Transactions across top-tier banks
                </div>
            </div>
        </div>

        <div class="col-sm-6">
            <div class="card">
                <div class="card-header">
                    Pie Chart
                </div>
                <div class="card-body">
                    <canvas id="pie" class="my-4 h-25"></canvas>
                </div>
                <div class="card-footer">
                    Transactions among top-tier banks ;-)
                </div>
            </div>
        </div>
    </div>
</div>

@section Scripts {
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.min.js"></script>
<script type="text/javascript">
    var jsonData = '@Html.Raw(ViewData["allBankData"])';
    var values = JSON.parse(jsonData);
    //var arr = [];
    // $.each(values, function (i, val) {
    //     var bankData = {};
    //     bankData.color = val.color;
    //     bankData.value = val.value;
    //     bankData.label = val.label;
    //     arr.push(bankData);
    // });

    var colours = {
        'GTB': 'rgba(200, 100, 0, 0.5)',
        'UBA': 'rgba(200, 50, 50, 0.5)',
        'ZIB': 'rgba(100, 50, 50, 0.5)',
        'FBN': 'rgba(50, 50, 200, 0.5)',
        'ACC': 'rgba(50, 200, 100, 0.5)',
    }

    var barChartCanvas = document.getElementById('bar').getContext('2d');
    //var barChart = new Chart(barChartCanvas).Bar(arr);

    var barChart = new Chart(barChartCanvas, {
        type: 'bar',
        data: {
            labels: values.map(x => x.Name),
            datasets: [{
                barThickness: 10,
                label: 'Bar Chart',
                data: values.map(x => 
                    x.TransactionsCount
                ),
                backgroundColor: values.map(x =>
                    x.Colour
                )
            }]
        },
        options: {
            scales: {
                yAxes: [{
                    ticks: {
                        beginAtZero: true
                    }
                }]
            }
        }
    });

    var pieChartCanvas = document.getElementById('pie').getContext('2d');
    var pieChart = new Chart(pieChartCanvas, {
        type: 'pie',
        data: {
            labels: values.map(x => x.Name),
            datasets: [{
                label: 'Pie Chart',
                    data: values.map(x =>
                        x.TransactionsCount
                    ),
                    backgroundColor: values.map(x =>
                        colours[x.Name]
                    )
            }]
        },
        options: {
            scales: {
                yAxes: [{
                    ticks: {
                        beginAtZero: false
                    }
                }]
            }
        }
    })

</script>
}
Enter fullscreen mode Exit fullscreen mode

Here is the breakdown of this file:

In the main section of the page, we have two HTML5 Canvas elements.

<canvas id="bar" class="my-4 h-25"></canvas>
Enter fullscreen mode Exit fullscreen mode

This canvas element is what will be used for the ChartsJS bar chart.

...
var barChartCanvas = document.getElementById('bar').getContext('2d');
var barChart = new Chart(barChartCanvas, {
    type: 'bar',
        data: {
...
Enter fullscreen mode Exit fullscreen mode
...
<canvas id="pie" class="my-4 h-25"></canvas>
...
Enter fullscreen mode Exit fullscreen mode

This element is used to render the ChartsJS pie chart.

...
var pieChartCanvas = document.getElementById('pie').getContext('2d');
var pieChart = new Chart(pieChartCanvas, {
    type: 'pie',
    data: {
...
Enter fullscreen mode Exit fullscreen mode

The data passed in the ViewData dictionary is output as a JSON string

...
var jsonData = '@Html.Raw(ViewData["allBankData"])';
...
Enter fullscreen mode Exit fullscreen mode

It is then parsed as a Javascript object.

...
var values = JSON.parse(jsonData);
...
Enter fullscreen mode Exit fullscreen mode

Next, I created a dictionary of colours (for use in the pie chart).

...
var colours = {
    'GTB': 'rgba(200, 100, 0, 0.5)',
    'UBA': 'rgba(200, 50, 50, 0.5)',
    'ZIB': 'rgba(100, 50, 50, 0.5)',
    'FBN': 'rgba(50, 50, 200, 0.5)',
    'ACC': 'rgba(50, 200, 100, 0.5)',
}
...
Enter fullscreen mode Exit fullscreen mode

Next, I created an instance of a Chart, configuring it as a bar chart.

...
var barChart = new Chart(barChartCanvas, {
    type: 'bar',
    data: {
...        
Enter fullscreen mode Exit fullscreen mode

Next, I supplied the labels, using the values sent from the JSON data.

...
labels: values.map(x => x.Name),
...
Enter fullscreen mode Exit fullscreen mode

The labels are a list of the bank names.

Here is the complete section creating the bar chart:

...
var barChart = new Chart(barChartCanvas, {
    type: 'bar',
    data: {
        labels: values.map(x => x.Name),
        datasets: [{
            barThickness: 10,
            label: 'Bar Chart',
            data: values.map(x => 
                x.TransactionsCount
            ),
            backgroundColor: values.map(x =>
                x.Colour
            )
        }]
    },
    options: {
        scales: {
            yAxes: [{
                ticks: {
                    beginAtZero: true
                }
            }]
        }
    }
});
...
Enter fullscreen mode Exit fullscreen mode

The next property, datasets contains the datasets. For a mixed chart, this property can contain multiple datasets of different types to be rendered together.

...
data: values.map(x => 
    x.TransactionsCount
),
...
Enter fullscreen mode Exit fullscreen mode

For the data property of the dataset, I pass an array containing values of the TransactionsCount field in the bankData list.

For the backgroundColor property, I also passed an array from the bankData list from the backend. I did something different for the pie chart.

Here is what the result looks like:

Bar chart demo

For the Pie chart, I did something similar.

...
var pieChartCanvas = document.getElementById('pie').getContext('2d');
var pieChart = new Chart(pieChartCanvas, {
    type: 'pie',
    data: {
        labels: values.map(x => x.Name),
        datasets: [{
            label: 'Pie Chart',
                data: values.map(x =>
                    x.TransactionsCount
                ),
                backgroundColor: values.map(x =>
                    colours[x.Name]
                )
        }]
    },
    options: {
        scales: {
            yAxes: [{
                ticks: {
                    beginAtZero: false
                }
            }]
        }
    }
})
...
Enter fullscreen mode Exit fullscreen mode

The main difference, here, is that I used the colours dictionary I created earlier, using the bank names as keys, to populate the backgroundColor property of the dataset.

Here is the result:

Pie chart demo

Conclusion

In this post, I detailed how I used ChartsJS to display data in a Razor page in ASP.NET.

Hopefully, this demonstrated how easily this can be done and how to go about it.

The code for this demo is available at https://github.com/shegzee/dotnet-charts.

I would appreciate feedback about this post, questions, comments and suggestions.

Thanks a lot for reading!

(This post was originally posted on LinkedIn)

Top comments (0)