Skip to content

erossini/BlazorChartjs

Repository files navigation

ChartJs component for Blazor

This library is a wrap around Chart.js for using it with Blazor WebAssembly and Blazor Server. The component was built with NET6 until the version 6.0.44. The version 7.0 is for NET7. The version 8.x is for NET8.

Links

Articles

Installation

First, you have to add the component from NuGet. Then, open your index.html or _Host and add at the end of the page the following scripts:

<script src="_content/PSC.Blazor.Components.Chartjs/lib/Chart.js/chart.js"></script>
<script src="_content/PSC.Blazor.Components.Chartjs/Chart.js" type="module"></script>

The first script is the Chart.js library version 3.7.1 because I'm using this version to create the components. You can use other sources for it but maybe you can face issues in other versions.

Then, open your _Imports.razor and add the following:

@using PSC.Blazor.Components.Chartjs
@using PSC.Blazor.Components.Chartjs.Enums
@using PSC.Blazor.Components.Chartjs.Models
@using PSC.Blazor.Components.Chartjs.Models.Common
@using PSC.Blazor.Components.Chartjs.Models.Bar
@using PSC.Blazor.Components.Chartjs.Models.Bubble
@using PSC.Blazor.Components.Chartjs.Models.Doughnut
@using PSC.Blazor.Components.Chartjs.Models.Line
@using PSC.Blazor.Components.Chartjs.Models.Pie
@using PSC.Blazor.Components.Chartjs.Models.Polar
@using PSC.Blazor.Components.Chartjs.Models.Radar
@using PSC.Blazor.Components.Chartjs.Models.Scatter

There is a namespace for each chart plus the common namespaces (Enum, Models and the base).

Add a new chart

On your page you can create a new chart by adding this code

<Chart Config="_config1" @ref="_chart1"></Chart>

In the code section you have to define the variables:

private BarChartConfig _config1;
private Chart _chart1;

Then, you can pass the configuration for the chart into _config1 (in the example code above). For a bar chart, the configuration is

_config1 = new BarChartConfig()
{
    Options = new Options()
    {
        Plugins = new Plugins()
        {
            Legend = new Legend()
            {
                Align = LegendAlign.Center,
                Display = false,
                Position = LegendPosition.Right
            }
        },
        Scales = new Dictionary<string, Axis>()
        {
            {
                Scales.XAxisId, new Axis()
                {
                    Stacked = true,
                    Ticks = new Ticks()
                    {
                        MaxRotation = 0,
                        MinRotation = 0
                    }
                }
            },
            {
                Scales.YAxisId, new Axis()
                {
                    Stacked = true
                }
            }
        }
    }
};

Then, you have to define the Labels and the Datasets like that

_config1.Data.Labels = BarDataExamples.SimpleBarText;
_config1.Data.Datasets.Add(new Dataset()
{
    Label = "Value",
    Data = BarDataExamples.SimpleBar.Select(l => l.Value).ToList(),
    BackgroundColor = Colors.Palette1,
    BorderColor = Colors.PaletteBorder1,
    BorderWidth = 1
});

The result of the code above is this chart

image

Implemented charts

  • Bar chart
  • Line chart
  • Area
  • Other charts
    • Scatter
    • Scatter - Multi axis
    • Doughnut
    • Pie
    • Multi Series Pie
    • Polar area
    • Radar
    • Radar skip points
    • Combo bar/line
    • Stacked bar/line

Add new values

When a graph is created, it means that the configuration is already defined and the datasets are passed to the chart engine. Without recreating the graph, it is possible to add a new value to a specific dataset and/or add a completely new dataset to the graph.

On your page, create a new chart by adding this code

<Chart Config="_config1" @ref="_chart1"></Chart>

In the code section you have to define the variables:

private LineChartConfig _config1;
private Chart _chart1;

chart1 is the reference to the Chart component and from it, you can access all the functions and properties the component has to offer.

Add a new value

In an existing graph, it is possible to add a single new value to a specific dataset calling AddData function that is available on the chart.

Now, the function AddData allows to add a new value in a specific existing dataset. The definition of AddData is the following

AddData(List<string> labels, int datasetIndex, List<decimal?> data)

For example, using _chart1, the following code adds a new label Test1 to the list of labels, and for the dataset 0 adds a random number.

_chart1.AddData(new List<string?>() { "Test1" }, 0, new List<decimal?>() { rd.Next(0, 200) });

The result is visible in the following screenshot.

chart-addnewdata

Add a new dataset

It is also possible to add a completely new dataset to the graph. For that, there is the function AddDataset. This function requires a new dataset of the same format as the others already existing in the chart.

For example, this code adds a new dataset using LineDataset using some of the properties this dataset has.

private void AddNewDataset()
{
    Random rd = new Random();
    List<decimal?> addDS = new List<decimal?>();
    for (int i = 0; i < 8; i++)
    {
        addDS.Add(rd.Next(i, 200));
    }

    var color = String.Format("#{0:X6}", rd.Next(0x1000000));

    _chart1.AddDataset<LineDataset>(new LineDataset()
        {
            Label = $"Dataset {DateTime.Now}",
            Data = addDS,
            BorderColor = color,
            Fill = false
        });
}

The result of this code is the following screenshot.

chart-addnewdataset

Callbacks

The component has a few callbacks (more in development) to customize your chart. The callbacks are ready to use are:

  • Tooltip
    • Labels
    • Titles

How to use it

In the configuration of the chart in your Blazor page, you can add your custom code for each callback. For an example, see the following code.

protected override async Task OnInitializedAsync()
{
    _config1 = new BarChartConfig()
        {
            Options = new Options()
            {
                Responsive = true,
                MaintainAspectRatio = false,
                Plugins = new Plugins()
                {
                    Legend = new Legend()
                    {
                        Align = Align.Center,
                        Display = true,
                        Position = LegendPosition.Right
                    },
                    Tooltip = new Tooltip()
                    {
                        Callbacks = new Callbacks()
                        {
                            Label = (ctx) =>
                            {
                                return new[] { 
                                    $"DataIndex: {ctx.DataIndex}\nDatasetIndex: {ctx.DatasetIndex}" };
                            },
                            Title = (ctx) =>
                            {
                                return new[] { $"This is the value {ctx.Value}" };
                            }
                        }
                    }
                },
                Scales = new Dictionary<string, Axis>()
                {
                    {
                        Scales.XAxisId, new Axis()
                        {
                            Stacked = true,
                            Ticks = new Ticks()
                            {
                                MaxRotation = 0,
                                MinRotation = 0
                            }
                        }
                    },
                    {
                        Scales.YAxisId, new Axis()
                        {
                            Stacked = true
                        }
                    }
                }
            }
        };

For more info, please see my posts on PureSourceCode.com.

Add labels to the chart

I added the chartjs-plugin-datalabels plugin in the component. This plugin shows the labels for each point in each graph. For more details about this plugin, visit its website.

image

First, in the index.html, we have to add after the chart.js script, another script for this component. It is important to add the script for chartjs-plugin-datalabels after chart.js. If the order is different, the plugin could not work. For example

<script src="_content/PSC.Blazor.Components.Chartjs/lib/Chart.js/chart.js"></script>
<script src="_content/PSC.Blazor.Components.Chartjs/lib/hammer.js/hammer.js"></script>
<script src="_content/PSC.Blazor.Components.Chartjs/lib/chartjs-plugin-zoom/chartjs-plugin-zoom.js"></script>
<script src="_content/PSC.Blazor.Components.Chartjs/lib/chartjs-plugin-datalabels/chartjs-plugin-datalabels.js"></script>

In the code, you have to change the property RegisterDataLabels under Options to true. That asks to the component to register the library if the library is added to the page and there is data to show. For example, if I define a LineChartConfig the code is

_config1 = new LineChartConfig()
{
    Options = new Options()
    {
        RegisterDataLabels = true,
        Plugins = new Plugins()
        {
            DataLabels = new DataLabels()
            {
                Align = DatalabelsAlign.Start,
                Anchor = DatalabelsAnchor.Start,
            }
        }
    }
};

With this code, the component will register the library in chart.js. It is possible to define a DataLabels for the entire chart. Also, each dataset can have its own DataLabels that rewrites the common settings.

OnClickAsync

When a user click on a point on the chart with a value, it is possible to add in the chart configuration a specific function to receive the data for that point ad in particular the index of the dataset, the index of the value in the dataset and the value.

<Chart Config="_config1" @ref="_chart1" Height="400px"></Chart>

In the configuration, under Options, there is OnClickAsync. Here, specified the function that has to receive the values (in this case clickAsync).

_config1 = new LineChartConfig()
    {
        Options = new Options()
        {
            OnClickAsync = clickAsync,
            ...
        }
    }

The function clickAsync receives as a parameter a CallbackGenericContext that contains the 3 values: DatasetIndex and DataIndex as int and the Value as decimal.

In the following example, the function changes the string ClickString using values.

public ValueTask clickAsync(CallbackGenericContext value)
{
    ClickString = $"Dataset index: {value.DatasetIndex} - " +
                    $"Value index: {value.DataIndex} - " + 
                    $"Value: {value.Value}";
    StateHasChanged();

    return ValueTask.CompletedTask;
}

With this code, if the user clicks on a point, the function writes the values on the page.

image

OnHoverAsync

This function returns the position of the cursor on the chart. Define a new chart as usual.

<Chart Config="_config1" @ref="_chart1" Height="400px"></Chart>

In the configuration, under Options, there is OnHoverAsync. This provides the position of the cursor on the chart.

_config1 = new LineChartConfig()
    {
        Options = new Options()
        {
            OnHoverAsync = hoverAsync,
            ...
        }
    }

The function hoverAsync receives as parameter a HoverContext that contains the 2 values: DataX and DataY as decimal.

In the following example, the function changes the string HoverString using values.

private ValueTask hoverAsync(HoverContext ctx)
{
    HoverString = $"X: {ctx.DataX} - Y: {ctx.DataY}";
    StateHasChanged();

    return ValueTask.CompletedTask;
}

With this code, if the user moves the mouse on the chart, the function writes the values in the page.

chart-hover

Contribution

  • macias for adding the crosshair line to the components
  • Heitor Eleutério de Rezende for the migration to NET7 and adding:
    • Legend Labels Filtering
    • Support to Ticks' AutoSkip and Font properties
    • Tooltip Callback Label problem fixed.
    • Ticks callback

PureSourceCode.com

PureSourceCode.com is my personal blog where I publish posts about technologies and in particular source code and projects in .NET.

In the last few months, I created a lot of components for Blazor WebAssembly and Blazor Server.

My name is Enrico Rossini and you can contact me via:

Blazor Components

Component name Forum NuGet Website Description
AnchorLink Forum NuGet badge An anchor link is a web link that allows users to leapfrog to a specific point on a website page. It saves them the need to scroll and skim read and makes navigation easier. This component is for Blazor WebAssembly and Blazor Server
Autocomplete for Blazor Forum NuGet badge Simple and flexible autocomplete type-ahead functionality for Blazor WebAssembly and Blazor Server
Browser Detect for Blazor Forum NuGet badge Demo Browser detect for Blazor WebAssembly and Blazor Server
ChartJs for Blazor Forum NuGet badge Demo Add beautiful graphs based on ChartJs in your Blazor application
Clippy for Blazor Forum NuGet badge Demo Do you miss Clippy? Here the implementation for Blazor
CodeSnipper for Blazor Forum NuGet badge Add code snippet in your Blazor pages for 196 programming languages with 243 styles
Copy To Clipboard Forum NuGet badge Add a button to copy text in the clipboard
DataTable for Blazor Forum NuGet badge Demo DataTable component for Blazor WebAssembly and Blazor Server
Google Tag Manager [Forum]() NuGet badge Demo Adds Google Tag Manager to the application and manages communication with GTM JavaScript (data layer).
Icons and flags for Blazor Forum NuGet badge Library with a lot of SVG icons and SVG flags to use in your Razor pages
ImageSelect for Blazor Forum NuGet badge This is a Blazor component to display a dropdown list with images based on ms-Dropdown by Marghoob Suleman. This component is built with NET7 for Blazor WebAssembly and Blazor Server
Markdown editor for Blazor Forum NuGet badge Demo This is a Markdown Editor for use in Blazor. It contains a live preview as well as an embeded help guide for users.
Modal dialog for Blazor Forum NuGet badge Simple Modal Dialog for Blazor WebAssembly
Modal windows for Blazor Forum NuGet badge Modal Windows for Blazor WebAssembly
Quill for Blazor Forum NuGet badge Quill Component is a custom reusable control that allows us to easily consume Quill and place multiple instances of it on a single page in our Blazor application
ScrollTabs NuGet badge Tabs with nice scroll (no scrollbar) and responsive
Segment for Blazor Forum NuGet badge This is a Segment component for Blazor Web Assembly and Blazor Server
Tabs for Blazor Forum NuGet badge This is a Tabs component for Blazor Web Assembly and Blazor Server
Timeline for Blazor Forum NuGet badge This is a new responsive timeline for Blazor Web Assembly and Blazor Server
Toast for Blazor Forum NuGet badge Toast notification for Blazor applications
Tours for Blazor Forum NuGet badge Guide your users in your Blazor applications
TreeView for Blazor Forum NuGet badge This component is a native Blazor TreeView component for Blazor WebAssembly and Blazor Server. The component is built with .NET7.
WorldMap for Blazor Forum NuGet badge Demo Show world maps with your data

C# libraries for .NET6

Component name Forum NuGet Description
PSC.Evaluator Forum NuGet badge PSC.Evaluator is a mathematical expressions evaluator library written in C#. Allows to evaluate mathematical, boolean, string and datetime expressions.
PSC.Extensions Forum NuGet badge A lot of functions for .NET5 in a NuGet package that you can download for free. We collected in this package functions for everyday work to help you with claim, strings, enums, date and time, expressions...

More examples and documentation

Blazor

Blazor & NET8