Blazor Line Chart
A BlazorExpress.ChartJS line chart component is a graphical representation of data that uses a series of connected points to show how the data changes over time. It is a type of x-y chart, where the x-axis represents the independent variable, such as time, and the y-axis represents the dependent variable, such as the value.
How it works #
In the following example, a categorical 12-color palette is used.
TIP
For data visualization, you can use the predefined palettes
ColorUtility.CategoricalTwelveColors for a 12-color palette and ColorUtility.CategoricalSixColors for a 6-color palette.
These palettes offer a range of distinct and visually appealing colors that can be applied to represent different categories or data elements in your visualizations.
<div class="container-fluid overflow-x-auto">
<LineChart @ref="lineChart" Width="800" />
</div>
<div class="mt-5">
<Button Type="ButtonType.Button" Color="ButtonColor.Primary" Size="ButtonSize.Small" Class="my-1 mr-1" @onclick="async () => await RandomizeAsync()"> Randomize </Button>
<Button Type="ButtonType.Button" Color="ButtonColor.Primary" Size="ButtonSize.Small" Class="my-1 mr-1" @onclick="async () => await AddDatasetAsync()"> Add Dataset </Button>
<Button Type="ButtonType.Button" Color="ButtonColor.Primary" Size="ButtonSize.Small" Class="my-1 mr-1" @onclick="async () => await AddDataAsync()"> Add Data </Button>
<Button Type="ButtonType.Button" Color="ButtonColor.Primary" Size="ButtonSize.Small" Class="my-1 mr-1" @onclick="async () => await ShowHorizontalLineChartAsync()"> Horizontal Line Chart </Button>
<Button Type="ButtonType.Button" Color="ButtonColor.Primary" Size="ButtonSize.Small" Class="my-1 mr-1" @onclick="async () => await ShowVerticalLineChartAsync()"> Vertical Line Chart </Button>
</div>
@code {
private LineChart lineChart = default!;
private LineChartOptions lineChartOptions = default!;
private ChartData chartData = default!;
private int datasetsCount;
private int labelsCount;
private Random random = new();
protected override void OnInitialized()
{
chartData = new ChartData { Labels = GetDefaultDataLabels(6), Datasets = GetDefaultDataSets(3) };
lineChartOptions = new()
{
IndexAxis = "x",
Interaction = new Interaction { Mode = InteractionMode.Index, Intersect = false },
Responsive = true,
};
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await lineChart.InitializeAsync(chartData, lineChartOptions);
}
await base.OnAfterRenderAsync(firstRender);
}
private async Task RandomizeAsync()
{
if (chartData is null || chartData.Datasets is null || !chartData.Datasets.Any()) return;
var newDatasets = new List<IChartDataset>();
foreach (var dataset in chartData.Datasets)
{
if (dataset is LineChartDataset lineChartDataset
&& lineChartDataset is not null
&& lineChartDataset.Data is not null)
{
var count = lineChartDataset.Data.Count;
var newData = new List<double?>();
for (var i = 0; i < count; i++)
{
newData.Add(random.Next(200));
}
lineChartDataset.Data = newData;
newDatasets.Add(lineChartDataset);
}
}
chartData.Datasets = newDatasets;
await lineChart.UpdateAsync(chartData, lineChartOptions);
}
private async Task AddDatasetAsync()
{
if (chartData is null || chartData.Datasets is null) return;
var chartDataset = GetRandomLineChartDataset();
chartData = await lineChart.AddDatasetAsync(chartData, chartDataset, lineChartOptions);
}
private async Task AddDataAsync()
{
if (chartData is null || chartData.Datasets is null)
return;
var data = new List<IChartDatasetData>();
foreach (var dataset in chartData.Datasets)
{
if (dataset is LineChartDataset lineChartDataset)
data.Add(new LineChartDatasetData(lineChartDataset.Label, random.Next(200)));
}
chartData = await lineChart.AddDataAsync(chartData, GetNextDataLabel(), data);
}
private async Task ShowHorizontalLineChartAsync()
{
lineChartOptions.IndexAxis = "y";
await lineChart.UpdateAsync(chartData, lineChartOptions);
}
private async Task ShowVerticalLineChartAsync()
{
lineChartOptions.IndexAxis = "x";
await lineChart.UpdateAsync(chartData, lineChartOptions);
}
#region Data Preparation
private List<IChartDataset> GetDefaultDataSets(int numberOfDatasets)
{
var datasets = new List<IChartDataset>();
for (var index = 0; index < numberOfDatasets; index++)
{
datasets.Add(GetRandomLineChartDataset());
}
return datasets;
}
private LineChartDataset GetRandomLineChartDataset()
{
var c = ColorUtility.CategoricalTwelveColors[datasetsCount].ToChartColor();
datasetsCount += 1;
return new LineChartDataset
{
Label = $"Team {datasetsCount}",
Data = GetRandomData(),
BackgroundColor = c.ToChartRgbaString(),
BorderColor = c.ToChartRgbString(),
PointRadius = new List<double> { 5 },
PointHoverRadius = new List<double> { 8 },
};
}
private List<double?> GetRandomData()
{
var data = new List<double?>();
for (var index = 0; index < labelsCount; index++)
{
data.Add(random.Next(200));
}
return data;
}
private List<string> GetDefaultDataLabels(int numberOfLabels)
{
var labels = new List<string>();
for (var index = 0; index < numberOfLabels; index++)
{
labels.Add(GetNextDataLabel());
}
return labels;
}
private string GetNextDataLabel()
{
labelsCount += 1;
return $"Day {labelsCount}";
}
#endregion Data Preparation
}<div class="container-fluid overflow-x-auto">
<LineChart @ref="lineChart" Width="800" />
</div>
@code {
private LineChart lineChart = default!;
private LineChartOptions lineChartOptions = default!;
private ChartData chartData = default!;
protected override void OnInitialized()
{
var colors = ColorUtility.CategoricalTwelveColors;
var labels = new List<string> { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" };
var datasets = new List<IChartDataset>();
var dataset1 = new LineChartDataset
{
Label = "Windows",
Data = new List<double?> { 7265791, 5899643, 6317759, 6315641, 5338211, 8496306, 7568556, 8538933, 8274297, 8657298, 7548388, 7764845 },
BackgroundColor = colors[0],
BorderColor = colors[0],
BorderWidth = 2,
HoverBorderWidth = 4,
// PointBackgroundColor = colors[0],
// PointRadius = 0, // hide points
// PointHoverRadius = 4,
};
datasets.Add(dataset1);
var dataset2 = new LineChartDataset
{
Label = "macOS",
Data = new List<double?> { 1809499, 1816642, 2122410, 1809499, 1850793, 1846743, 1954797, 2391313, 1983430, 2469918, 2633303, 2821149 },
BackgroundColor = colors[1],
BorderColor = colors[1],
BorderWidth = 2,
HoverBorderWidth = 4,
// PointBackgroundColor = colors[1],
// PointRadius = 0, // hide points
// PointHoverRadius = 4,
};
datasets.Add(dataset2);
var dataset3 = new LineChartDataset
{
Label = "Other",
Data = new List<double?> { 1081241, 1100363, 1118136, 1073255, 1120315, 1395736, 1488788, 1489466, 1489947, 1414739, 1735811, 1820171 },
BackgroundColor = colors[2],
BorderColor = colors[2],
BorderWidth = 2,
HoverBorderWidth = 4,
// PointBackgroundColor = colors[2],
// PointRadius = 0, // hide points
// PointHoverRadius = 4,
};
datasets.Add(dataset3);
chartData = new ChartData { Labels = labels, Datasets = datasets };
lineChartOptions = new();
lineChartOptions.Responsive = true;
lineChartOptions.Interaction = new Interaction { Mode = InteractionMode.Index };
lineChartOptions.Scales.X!.Title = new ChartAxesTitle { Text = "2019", Display = true };
lineChartOptions.Scales.Y!.Title = new ChartAxesTitle { Text = "Visitors", Display = true };
lineChartOptions.Plugins.Title!.Text = "Operating system";
lineChartOptions.Plugins.Title.Display = true;
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await lineChart.InitializeAsync(chartData, lineChartOptions);
}
await base.OnAfterRenderAsync(firstRender);
}
}Locale #
By default, the chart is using the default locale of the platform on which it is running.
In the following example, you will see the chart in the German locale (de_DE).
<div class="container-fluid overflow-x-auto">
<LineChart @ref="lineChart" Width="800" />
</div>
@code {
private LineChart lineChart = default!;
private LineChartOptions lineChartOptions = default!;
private ChartData chartData = default!;
protected override void OnInitialized()
{
var colors = ColorUtility.CategoricalTwelveColors;
var labels = new List<string> { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" };
var datasets = new List<IChartDataset>();
var dataset1 = new LineChartDataset
{
Label = "Windows",
Data = new List<double?> { 7265791, 5899643, 6317759, 6315641, 5338211, 8496306, 7568556, 8538933, 8274297, 8657298, 7548388, 7764845 },
BackgroundColor = colors[0],
BorderColor = colors[0],
BorderWidth = 2,
HoverBorderWidth = 4,
// PointBackgroundColor = colors[0],
// PointRadius = 0, // hide points
// PointHoverRadius = 4,
};
datasets.Add(dataset1);
var dataset2 = new LineChartDataset
{
Label = "macOS",
Data = new List<double?> { 1809499, 1816642, 2122410, 1809499, 1850793, 1846743, 1954797, 2391313, 1983430, 2469918, 2633303, 2821149 },
BackgroundColor = colors[1],
BorderColor = colors[1],
BorderWidth = 2,
HoverBorderWidth = 4,
// PointBackgroundColor = colors[1],
// PointRadius = 0, // hide points
// PointHoverRadius = 4,
};
datasets.Add(dataset2);
var dataset3 = new LineChartDataset
{
Label = "Other",
Data = new List<double?> { 1081241, 1100363, 1118136, 1073255, 1120315, 1395736, 1488788, 1489466, 1489947, 1414739, 1735811, 1820171 },
BackgroundColor = colors[2],
BorderColor = colors[2],
BorderWidth = 2,
HoverBorderWidth = 4,
// PointBackgroundColor = colors[2],
// PointRadius = 0, // hide points
// PointHoverRadius = 4,
};
datasets.Add(dataset3);
chartData = new ChartData { Labels = labels, Datasets = datasets };
lineChartOptions = new();
lineChartOptions.Locale = "de-DE";
lineChartOptions.Responsive = true;
lineChartOptions.Interaction = new Interaction { Mode = InteractionMode.Index };
lineChartOptions.Scales.X!.Title = new ChartAxesTitle { Text = "2019", Display = true };
lineChartOptions.Scales.Y!.Title = new ChartAxesTitle { Text = "Visitors", Display = true };
lineChartOptions.Plugins.Title!.Text = "Operating system";
lineChartOptions.Plugins.Title.Display = true;
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await lineChart.InitializeAsync(chartData, lineChartOptions);
}
await base.OnAfterRenderAsync(firstRender);
}
}Add data dynamically for a specific dataset #
<div class="container-fluid overflow-x-auto">
<LineChart @ref="lineChart" Width="800" />
</div>
<div class="mt-5">
<Button Color="ButtonColor.Primary" Type="ButtonType.Button" Size="ButtonSize.Small" @onclick="UpdateIndiaNextOverRunsAsync"> India Next Over </Button>
<Button Color="ButtonColor.Primary" Type="ButtonType.Button" Size="ButtonSize.Small" @onclick="UpdateEnglandNextOverRunsAsync"> England Next Over </Button>
</div>
@code {
private LineChart lineChart = default!;
private LineChartOptions lineChartOptions = default!;
private ChartData chartData = default!;
private List<string> labels = default!;
private List<double> indiaRunsArray = new() { 9, 20, 29, 33, 50, 66, 75, 86, 91, 105, 120, 126, 141, 150, 156, 164, 177, 180, 184, 195 };
private List<double> englandRunsArray = new() { 1, 1, 8, 19, 24, 26, 39, 47, 56, 66, 75, 88, 95, 100, 109, 114, 124, 129, 140, 142 };
private int indiaCurrentOver;
private int englandCurrentOver;
protected override void OnInitialized()
{
labels = new List<string> { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20" };
lineChartOptions = GetLineChartOptions();
chartData = new ChartData { Labels = labels, Datasets = GetDefaultDatasets() };
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
await lineChart.InitializeAsync(chartData, lineChartOptions);
}
private async Task UpdateIndiaNextOverRunsAsync()
{
if (indiaCurrentOver > 0 && indiaCurrentOver > indiaRunsArray.Count - 1)
return;
chartData = await lineChart.AddDataAsync(chartData, $"{indiaCurrentOver + 1}", new LineChartDatasetData("India", indiaRunsArray[indiaCurrentOver]));
indiaCurrentOver++;
}
private async Task UpdateEnglandNextOverRunsAsync()
{
if (englandCurrentOver > 0 && englandCurrentOver > englandRunsArray.Count - 1)
return;
chartData = await lineChart.AddDataAsync(chartData, $"{englandCurrentOver + 1}", new LineChartDatasetData("England", englandRunsArray[englandCurrentOver]));
englandCurrentOver++;
}
private List<IChartDataset> GetDefaultDatasets()
{
var datasets = new List<IChartDataset>
{
new LineChartDataset
{
Label = "India",
Data = new List<double?>(),
BackgroundColor = "rgb(88, 80, 141)",
BorderColor = "rgb(88, 80, 141)",
BorderWidth = 2,
HoverBorderWidth = 4,
// PointBackgroundColor = "rgb(88, 80, 141)",
// PointBorderColor = "rgb(88, 80, 141)",
// PointRadius = 0, // hide points
// PointHoverRadius = 4,
},
new LineChartDataset
{
Label = "England",
Data = new List<double?>(),
BackgroundColor = "rgb(255, 166, 0)",
BorderColor = "rgb(255, 166, 0)",
BorderWidth = 2,
HoverBorderWidth = 4,
// PointBackgroundColor = "rgb(255, 166, 0)",
// PointBorderColor = "rgb(255, 166, 0)",
// PointRadius = 0, // hide points
// PointHoverRadius = 4,
}
};
return datasets;
}
private LineChartOptions GetLineChartOptions()
{
var options = new LineChartOptions();
options.Interaction.Mode = InteractionMode.Index;
options.Plugins.Title = new ChartPluginsTitle { Text = "WORM", Display = true, Font = new ChartFont { Size = 20 } };
options.Responsive = true;
options.Scales.X!.Title = new ChartAxesTitle { Text = "Overs", Display = true };
options.Scales.Y!.Title = new ChartAxesTitle { Text = "Runs", Display = true };
options.Scales.Y.SuggestedMax = 150;
return options;
}
}Data labels #
<div class="container-fluid overflow-x-auto">
<LineChart @ref="lineChart" Width="800" />
</div>
@code {
private LineChart lineChart = default!;
private LineChartOptions lineChartOptions = default!;
private ChartData chartData = default!;
protected override void OnInitialized()
{
var colors = ColorUtility.CategoricalTwelveColors;
var labels = new List<string> { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" };
var datasets = new List<IChartDataset>();
var dataset1 = new LineChartDataset
{
Label = "Windows",
Data = new List<double?> { 7265791, 5899643, 6317759, 6315641, 5338211, 8496306, 7568556, 8538933, 8274297, 8657298, 7548388, 7764845 },
BackgroundColor = colors[0],
BorderColor = colors[0],
BorderWidth = 2,
HoverBorderWidth = 4,
// PointBackgroundColor = colors[0],
// PointRadius = 3, // show points
// PointHoverRadius = 4,
// datalabels
Datalabels = new() { Alignment = Alignment.End, Anchor = Anchor.End }
};
datasets.Add(dataset1);
var dataset2 = new LineChartDataset
{
Label = "macOS",
Data = new List<double?> { 1809499, 1816642, 2122410, 1809499, 1850793, 1846743, 1954797, 2391313, 1983430, 2469918, 2633303, 2821149 },
BackgroundColor = colors[1],
BorderColor = colors[1],
BorderWidth = 2,
HoverBorderWidth = 4,
// PointBackgroundColor = colors[1],
// PointRadius = 3, // show points
// PointHoverRadius = 4,
// datalabels
Datalabels = new() { Alignment = Alignment.End, Anchor = Anchor.End }
};
datasets.Add(dataset2);
var dataset3 = new LineChartDataset
{
Label = "Other",
Data = new List<double?> { 1081241, 1100363, 1118136, 1073255, 1120315, 1395736, 1488788, 1489466, 1489947, 1414739, 1735811, 1820171 },
BackgroundColor = colors[2],
BorderColor = colors[2],
BorderWidth = 2,
HoverBorderWidth = 4,
// PointBackgroundColor = colors[2],
// PointRadius = 3, // show points
// PointHoverRadius = 4,
// datalabels
Datalabels = new() { Alignment = Alignment.Start, Anchor = Anchor.Start }
};
datasets.Add(dataset3);
chartData = new ChartData
{
Labels = labels,
Datasets = datasets
};
lineChartOptions = new();
lineChartOptions.Responsive = true;
lineChartOptions.Interaction = new Interaction { Mode = InteractionMode.Index };
lineChartOptions.Scales.X!.Title = new ChartAxesTitle { Text = "2019", Display = true };
lineChartOptions.Scales.Y!.Title = new ChartAxesTitle { Text = "Visitors", Display = true };
lineChartOptions.Plugins.Title!.Text = "Operating system";
lineChartOptions.Plugins.Title.Display = true;
// datalabels
lineChartOptions.Plugins.Datalabels.Color = "white";
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
// pass the plugin name to enable the data labels
await lineChart.InitializeAsync(chartData: chartData, chartOptions: lineChartOptions, plugins: new string[] { "ChartDataLabels" });
}
await base.OnAfterRenderAsync(firstRender);
}
}Tick Configuration #
<div class="container-fluid overflow-x-auto">
<LineChart @ref="lineChart" Width="800" />
</div>
<div class="mt-5">
<Button Type="ButtonType.Button" Color="ButtonColor.Primary" Size="ButtonSize.Small" Class="my-1 mr-1" @onclick="async () => await ChangeTicksAlignmentToStart()"> Alignment: start </Button>
<Button Type="ButtonType.Button" Color="ButtonColor.Primary" Size="ButtonSize.Small" Class="my-1 mr-1" @onclick="async () => await ChangeTicksAlignmentToCenter()"> Alignment: center (default) </Button>
<Button Type="ButtonType.Button" Color="ButtonColor.Primary" Size="ButtonSize.Small" Class="my-1 mr-1" @onclick="async () => await ChangeTicksAlignmentToEnd()"> Alignment: end </Button>
</div>
@code {
private LineChart lineChart = default!;
private LineChartOptions lineChartOptions = default!;
private ChartData chartData = default!;
private int datasetsCount;
private int labelsCount;
private Random random = new();
protected override void OnInitialized()
{
chartData = new ChartData { Labels = GetDefaultDataLabels(6), Datasets = GetDefaultDataSets(3) };
lineChartOptions = new() { Responsive = true, Interaction = new Interaction { Mode = InteractionMode.Index } };
// set ticks color
lineChartOptions.Scales.X!.Ticks = new ChartAxesTicks { Color = "red" };
lineChartOptions.Scales.Y!.Ticks = new ChartAxesTicks { Color = ColorUtility.CategoricalTwelveColors[4] };
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await lineChart.InitializeAsync(chartData, lineChartOptions);
}
await base.OnAfterRenderAsync(firstRender);
}
private async Task ChangeTicksAlignmentToStart()
{
lineChartOptions.Scales.X!.Ticks!.TicksAlignment = TicksAlignment.Start;
await lineChart.UpdateAsync(chartData, lineChartOptions);
}
private async Task ChangeTicksAlignmentToCenter()
{
lineChartOptions.Scales.X!.Ticks!.TicksAlignment = TicksAlignment.Center;
await lineChart.UpdateAsync(chartData, lineChartOptions);
}
private async Task ChangeTicksAlignmentToEnd()
{
lineChartOptions.Scales.X!.Ticks!.TicksAlignment = TicksAlignment.End;
await lineChart.UpdateAsync(chartData, lineChartOptions);
}
#region Data Preparation
private List<IChartDataset> GetDefaultDataSets(int numberOfDatasets)
{
var datasets = new List<IChartDataset>();
for (var index = 0; index < numberOfDatasets; index++)
{
datasets.Add(GetRandomLineChartDataset());
}
return datasets;
}
private LineChartDataset GetRandomLineChartDataset()
{
var c = ColorUtility.CategoricalTwelveColors[datasetsCount].ToChartColor();
datasetsCount += 1;
return new LineChartDataset
{
Label = $"Team {datasetsCount}",
Data = GetRandomData(),
BackgroundColor = c.ToChartRgbString(),
BorderColor = c.ToChartRgbString(),
BorderWidth = 2,
HoverBorderWidth = 4,
// PointBackgroundColor = c.ToChartRgbString(),
// PointRadius = 0, // hide points
// PointHoverRadius = 4,
};
}
private List<double?> GetRandomData()
{
var data = new List<double?>();
for (var index = 0; index < labelsCount; index++)
{
data.Add(random.Next(200));
}
return data;
}
private List<string> GetDefaultDataLabels(int numberOfLabels)
{
var labels = new List<string>();
for (var index = 0; index < numberOfLabels; index++)
{
labels.Add(GetNextDataLabel());
}
return labels;
}
private string GetNextDataLabel()
{
labelsCount += 1;
return $"Day {labelsCount}";
}
#endregion Data Preparation
}Interpolation modes #
Compare monotone cubic interpolation, regular cubic interpolation, and the default linear rendering to control how line segments are smoothed.
<div class="container-fluid overflow-x-auto">
<LineChart @ref="lineChart" Width="800" />
</div>
@code {
private LineChart lineChart = default!;
private LineChartOptions lineChartOptions = default!;
private ChartData chartData = default!;
private readonly int dataCount = 13;
private readonly List<double?> dataPoints = new() { 0, 20, 20, 60, 60, 120, null, 180, 120, 125, 105, 110, 170 };
protected override void OnInitialized()
{
chartData = new ChartData { Labels = GetDefaultDataLabels(), Datasets = GetDefaultDataSets() };
lineChartOptions = new LineChartOptions
{
IndexAxis = "x",
Interaction = new Interaction { Mode = InteractionMode.Index, Intersect = false },
Responsive = true
};
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
await lineChart.InitializeAsync(chartData, lineChartOptions);
await base.OnAfterRenderAsync(firstRender);
}
private List<string> GetDefaultDataLabels()
{
var labels = new List<string>();
for (var index = 0; index < dataCount; index++)
labels.Add(index.ToString());
return labels;
}
private List<IChartDataset> GetDefaultDataSets()
{
return new List<IChartDataset>
{
new LineChartDataset
{
Label = "Cubic interpolation (monotone)",
Data = dataPoints,
BorderColor = ColorUtility.CategoricalSixColors[0].ToChartColor().ToChartRgbString(),
CubicInterpolationMode = "monotone",
Fill = false,
Tension = 0.4
},
new LineChartDataset
{
Label = "Cubic interpolation",
Data = dataPoints,
BorderColor = ColorUtility.CategoricalSixColors[1].ToChartColor().ToChartRgbString(),
Fill = false,
Tension = 0.4
},
new LineChartDataset
{
Label = "Linear interpolation (default)",
Data = dataPoints,
BorderColor = ColorUtility.CategoricalSixColors[2].ToChartColor().ToChartRgbString(),
Fill = false
}
};
}
}Fill between datasets #
<LineChart Height="200" @ref="lineChart" Width="500" />
<div class="mt-5">
<Button Color="ButtonColor.Primary" Class="my-1 mr-1" @onclick="async () => await NoFillAsync()" Size="ButtonSize.Small" Type="ButtonType.Button"> No fill</Button>
<Button Color="ButtonColor.Primary" Class="my-1 mr-1" @onclick="async () => await FillToNextAsync()" Size="ButtonSize.Small" Type="ButtonType.Button"> Fill to next (relative index +1)</Button>
<Button Color="ButtonColor.Primary" Class="my-1 mr-1" @onclick="async () => await FillToZeroAsync()" Size="ButtonSize.Small" Type="ButtonType.Button"> Fill to specific (absolute index 0) </Button>
<Button Color="ButtonColor.Primary" Class="my-1 mr-1" @onclick="async () => await FillToReferenceAsync()" Size="ButtonSize.Small" Type="ButtonType.Button"> Fill to specific (by object reference)</Button>
<Button Color="ButtonColor.Primary" Class="my-1 mr-1" @onclick="async () => await FillToStartAsync()" Size="ButtonSize.Small" Type="ButtonType.Button"> Fill to start </Button>
<Button Color="ButtonColor.Primary" Class="my-1 mr-1" @onclick="async () => await FillToEndAsync()" Size="ButtonSize.Small" Type="ButtonType.Button"> Fill to end</Button>
<Button Color="ButtonColor.Primary" Class="my-1 mr-1" @onclick="async () => await FillToValueAsync()" Size="ButtonSize.Small" Type="ButtonType.Button"> Fill to value 50</Button>
</div>
@code {
private LineChart lineChart = default!;
private LineChartOptions lineChartOptions = default!;
private ChartData chartData = default!;
private int datasetsCount;
private int labelsCount;
private Random random = new();
protected override void OnInitialized()
{
chartData = new ChartData { Labels = GetDefaultDataLabels(6), Datasets = GetDefaultDataSets(4) };
lineChartOptions = new() { Responsive = true, Interaction = new Interaction { Mode = InteractionMode.Index } };
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await lineChart.InitializeAsync(chartData, lineChartOptions);
}
await base.OnAfterRenderAsync(firstRender);
}
public async Task NoFillAsync()
{
var middle = chartData.Datasets[1] as LineChartDataset;
middle!.Fill = null;
await lineChart.UpdateAsync(chartData, lineChartOptions);
}
public async Task FillToNextAsync()
{
var middle = chartData.Datasets[1] as LineChartDataset;
middle!.FillToDataset(1, true);
await lineChart.UpdateAsync(chartData, lineChartOptions);
}
public async Task FillToZeroAsync()
{
var middle = chartData.Datasets[1] as LineChartDataset;
middle!.FillToDataset(0, false);
await lineChart.UpdateAsync(chartData, lineChartOptions);
}
public async Task FillToReferenceAsync()
{
var middle = chartData.Datasets[1] as LineChartDataset;
var fillTo = chartData.Datasets[3] as LineChartDataset;
middle!.FillToDataset(chartData, fillTo!);
await lineChart.UpdateAsync(chartData, lineChartOptions);
}
public async Task FillToStartAsync()
{
var middle = chartData.Datasets[1] as LineChartDataset;
middle!.FillToStart();
await lineChart.UpdateAsync(chartData, lineChartOptions);
}
public async Task FillToEndAsync()
{
var middle = chartData.Datasets[1] as LineChartDataset;
middle!.FillToEnd();
await lineChart.UpdateAsync(chartData, lineChartOptions);
}
public async Task FillToValueAsync()
{
var middle = chartData.Datasets[1] as LineChartDataset;
middle!.FillToValue(50.0);
await lineChart.UpdateAsync(chartData, lineChartOptions);
}
#region Data Preparation
private List<IChartDataset> GetDefaultDataSets(int numberOfDatasets)
{
var datasets = new List<IChartDataset>();
for (var index = 0; index < numberOfDatasets; index++)
{
datasets.Add(GetRandomLineChartDataset());
}
return datasets;
}
private LineChartDataset GetRandomLineChartDataset()
{
var c = ColorUtility.CategoricalTwelveColors[datasetsCount].ToChartColor();
datasetsCount += 1;
return new LineChartDataset
{
Label = $"Team {datasetsCount}",
Data = GetRandomData(),
BackgroundColor = c.ToChartRgbaString(),
BorderCapStyle = "round",
BorderColor = c.ToChartRgbString(),
BorderWidth = 2,
HoverBorderWidth = 4,
PointBackgroundColor = new List<string>() { c.ToChartRgbString() },
// PointRadius = 0, // hide points
PointHoverRadius = new List<double>() { 4 },
};
}
private List<double?> GetRandomData()
{
var data = new List<double?>();
for (var index = 0; index < labelsCount; index++)
{
data.Add(random.Next(200));
}
return data;
}
private List<string> GetDefaultDataLabels(int numberOfLabels)
{
var labels = new List<string>();
for (var index = 0; index < numberOfLabels; index++)
{
labels.Add(GetNextDataLabel());
}
return labels;
}
private string GetNextDataLabel()
{
labelsCount += 1;
return $"Day {labelsCount}";
}
#endregion Data Preparation
}Combo bar/line #
Combine
LineChartDataset and BarChartDataset in a single line chart to compare forecast and actual values.
<div class="container-fluid overflow-x-auto">
<LineChart @ref="lineChart" Width="800" />
</div>
@code {
private LineChart lineChart = default!;
private LineChartOptions lineChartOptions = default!;
private ChartData chartData = default!;
protected override void OnInitialized()
{
var forecastColor = ColorUtility.CategoricalTwelveColors[2].ToChartColor();
var actualColor = ColorUtility.CategoricalTwelveColors[3].ToChartColor();
chartData = new ChartData
{
Labels = new List<string> { "January", "February", "March", "April", "May", "June" },
Datasets = new List<IChartDataset>
{
new LineChartDataset
{
Label = "Forecast",
Data = new List<double?> { 45, 52, 61, 66, 73, 79 },
BackgroundColor = forecastColor.ToChartRgbaString(),
BorderColor = forecastColor.ToChartRgbString(),
PointRadius = new List<double> { 4 },
PointHoverRadius = new List<double> { 6 }
},
new BarChartDataset
{
Label = "Actual",
Data = new List<double?> { 41, 49, 58, 70, 75, 82 },
BackgroundColor = new List<string> { actualColor.ToChartRgbaString() },
BorderColor = new List<string> { actualColor.ToChartRgbString() },
BorderWidth = new List<double> { 0 }
}
}
};
lineChartOptions = new LineChartOptions
{
Responsive = true,
Interaction = new Interaction { Mode = InteractionMode.Index, Intersect = false }
};
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
await lineChart.InitializeAsync(chartData, lineChartOptions);
await base.OnAfterRenderAsync(firstRender);
}
}Click event #
Set the
OnClick callback to react when a line data point is selected. The callback receives ChartClickEventArgs with the dataset, point index, label, and raw value.
<LineChart @ref="lineChart" Width="600" OnClick="HandleClickAsync" />
@if (selectedChartItem is not null)
{
<p class="mt-3 mb-0">
Selected: @selectedChartItem.DatasetLabel (dataset @selectedChartItem.DatasetIndex),
@FormatLabel(selectedChartItem) (index @selectedChartItem.Index),
value @FormatValue(selectedChartItem)
</p>
}
@code {
private LineChart lineChart = default!;
private LineChartOptions lineChartOptions = default!;
private ChartData chartData = default!;
private ChartClickEventArgs? selectedChartItem;
protected override void OnInitialized()
{
chartData = new ChartData
{
Labels = new List<string> { "Monday", "Tuesday", "Wednesday", "Thursday" },
Datasets = new List<IChartDataset>
{
new LineChartDataset
{
Label = "Visitors",
Data = new List<double?> { 120, 190, 150, 230 },
BackgroundColor = "rgba(54, 162, 235, 0.2)",
BorderColor = "rgb(54, 162, 235)",
PointRadius = new List<double> { 5 },
PointHoverRadius = new List<double> { 8 },
},
},
};
lineChartOptions = new LineChartOptions { Responsive = true };
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
await lineChart.InitializeAsync(chartData, lineChartOptions);
await base.OnAfterRenderAsync(firstRender);
}
private Task HandleClickAsync(ChartClickEventArgs eventArgs)
{
selectedChartItem = eventArgs;
return Task.CompletedTask;
}
private static string FormatLabel(ChartClickEventArgs eventArgs) => eventArgs.Label ?? $"item {eventArgs.Index}";
private static string FormatValue(ChartClickEventArgs eventArgs) => eventArgs.Value?.ToString() ?? "null";
}Chart Components — Dedicated Library
Chart components have been moved to the dedicated BlazorExpress.ChartJS library to support independent feature additions and easier maintenance. Complete the following steps in the Blazor project that renders the charts.
- Install the package used by these demos:
dotnet add package BlazorExpress.ChartJS --version 1.2.4 - Import the component namespace in
_Imports.razor:@using BlazorExpress.ChartJS - Load the browser scripts in this order from the host page, after the Blazor framework script.
The data-labels plugin is needed only when a chart uses data labels.
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.4.1/chart.umd.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-datalabels/2.2.0/chartjs-plugin-datalabels.min.js"></script> <script src="_content/BlazorExpress.ChartJS/blazorexpress.chartjs.js"></script>
See the BlazorExpress.ChartJS website and GitHub repository for current package documentation. We also recommend checking the original BlazorExpress.ChartJS demos when adapting advanced examples.
For a complete charts setup walkthrough, see the
Getting Started — Charts Setup section.