From 91db5b2b043bd4741c816dce56b2c3ba2660d46d Mon Sep 17 00:00:00 2001 From: Vikram Reddy Date: Tue, 14 Jul 2026 00:10:18 +0530 Subject: [PATCH 1/6] Add support for chart item click event handling Introduced `DotNetObjectReference` in `ChartComponentBase` and updated all chart components to handle click events on chart data items. Added `HandleClickAsync` method and `OnClick` parameter for callback support. Implemented `ChartClickEventArgs` to encapsulate click metadata. Enhanced JavaScript interop in `blazorexpress.chartjs.js` to attach click handlers and dispatch events to .NET. Updated `Dispose` method to clean up resources. Added versioning and descriptions for new features. --- .../ChartComponents/BarChart.razor.cs | 2 +- .../ChartComponents/BubbleChart.razor.cs | 2 +- .../Core/ChartComponentBase.cs | 41 ++++++- .../ChartComponents/DoughnutChart.razor.cs | 2 +- .../ChartComponents/LineChart.razor.cs | 2 +- .../ChartComponents/PieChart.razor.cs | 2 +- .../ChartComponents/PolarAreaChart.razor.cs | 2 +- .../ChartComponents/RadarChart.razor.cs | 2 +- .../ChartComponents/ScatterChart.razor.cs | 2 +- .../Models/ChartClickEventArgs.cs | 49 +++++++++ BlazorExpress.ChartJS/Usings.cs | 1 + .../wwwroot/blazorexpress.chartjs.js | 104 +++++++++++++----- 12 files changed, 173 insertions(+), 38 deletions(-) create mode 100644 BlazorExpress.ChartJS/Models/ChartClickEventArgs.cs diff --git a/BlazorExpress.ChartJS/ChartComponents/BarChart.razor.cs b/BlazorExpress.ChartJS/ChartComponents/BarChart.razor.cs index 13118e35..1951554a 100644 --- a/BlazorExpress.ChartJS/ChartComponents/BarChart.razor.cs +++ b/BlazorExpress.ChartJS/ChartComponents/BarChart.razor.cs @@ -177,7 +177,7 @@ public override async Task InitializeAsync(ChartData chartData, IChartOptions ch { var datasets = BarLineChartSupport.GetSupportedDatasets(chartData); var data = new { chartData.Labels, Datasets = datasets }; - await JSRuntime.InvokeVoidAsync(BarChartInterop.Initialize, Id, GetChartType(), data, (BarChartOptions)chartOptions, plugins); + await JSRuntime.InvokeVoidAsync(BarChartInterop.Initialize, Id, GetChartType(), data, (BarChartOptions)chartOptions, plugins, DotNetObjectReference); } } diff --git a/BlazorExpress.ChartJS/ChartComponents/BubbleChart.razor.cs b/BlazorExpress.ChartJS/ChartComponents/BubbleChart.razor.cs index 1547854e..6d3d770c 100644 --- a/BlazorExpress.ChartJS/ChartComponents/BubbleChart.razor.cs +++ b/BlazorExpress.ChartJS/ChartComponents/BubbleChart.razor.cs @@ -157,7 +157,7 @@ public override async Task InitializeAsync(ChartData chartData, IChartOptions ch var datasets = chartData.Datasets.OfType(); var data = new { chartData.Labels, Datasets = datasets }; - await JSRuntime.InvokeVoidAsync(BubbleChartInterop.Initialize, Id, GetChartType(), data, (BubbleChartOptions)chartOptions, plugins); + await JSRuntime.InvokeVoidAsync(BubbleChartInterop.Initialize, Id, GetChartType(), data, (BubbleChartOptions)chartOptions, plugins, DotNetObjectReference); } /// diff --git a/BlazorExpress.ChartJS/ChartComponents/Core/ChartComponentBase.cs b/BlazorExpress.ChartJS/ChartComponents/Core/ChartComponentBase.cs index ff37ca5c..b9e6859d 100644 --- a/BlazorExpress.ChartJS/ChartComponents/Core/ChartComponentBase.cs +++ b/BlazorExpress.ChartJS/ChartComponents/Core/ChartComponentBase.cs @@ -12,6 +12,8 @@ public abstract class ChartComponentBase : BlazorExpressComponentCore, IDisposab internal ChartType _chartType; + private DotNetObjectReference? dotNetObjectReference; + #endregion #region Methods @@ -76,10 +78,24 @@ public virtual async Task InitializeAsync(ChartData chartData, IChartOptions cha if (chartData is not null && chartData.Datasets is not null && chartData.Datasets.Any()) { var _data = GetChartDataObject(chartData); - await JSRuntime.InvokeVoidAsync(ChartInterop.Initialize, Id, GetChartType(), _data, chartOptions, plugins); + await JSRuntime.InvokeVoidAsync(ChartInterop.Initialize, Id, GetChartType(), _data, chartOptions, plugins, DotNetObjectReference); } } + /// + /// Dispatches a chart-item click to the configured callback. + /// + /// The selected chart data-item metadata. + /// A task that represents the asynchronous callback dispatch operation. + [JSInvokable] + [AddedVersion("1.2.4")] + [Description("Dispatches a chart-item click to the configured callback.")] + public async Task HandleClickAsync(ChartClickEventArgs eventArgs) + { + if (OnClick.HasDelegate) + await OnClick.InvokeAsync(eventArgs); + } + //public async Task Render() { } //public async Task Reset() { } @@ -139,6 +155,9 @@ protected string GetChartType() => protected string ContainerClassNames => ContainerClass!; + protected DotNetObjectReference DotNetObjectReference => + dotNetObjectReference ??= Microsoft.JSInterop.DotNetObjectReference.Create(this); + protected string ContainerStyleNames => BuildStyleNames( ContainerStyle, @@ -241,6 +260,18 @@ private object GetChartDataObject(ChartData chartData) protected bool IsRenderComplete { get; private set; } + /// + /// Gets or sets the callback that is invoked when a chart data item is selected. + /// + /// Default value is . + /// + /// + [AddedVersion("1.2.4")] + [DefaultValue(null)] + [Description("Gets or sets the callback that is invoked when a chart data item is selected.")] + [Parameter] + public EventCallback OnClick { get; set; } + /// /// Gets or sets chart container width. /// The default unit of measure is . @@ -272,6 +303,14 @@ private object GetChartDataObject(ChartData chartData) #region Other + protected override void Dispose(bool disposing) + { + if (disposing) + dotNetObjectReference?.Dispose(); + + base.Dispose(disposing); + } + ~ChartComponentBase() { Dispose(false); diff --git a/BlazorExpress.ChartJS/ChartComponents/DoughnutChart.razor.cs b/BlazorExpress.ChartJS/ChartComponents/DoughnutChart.razor.cs index 1bce4978..573007a1 100644 --- a/BlazorExpress.ChartJS/ChartComponents/DoughnutChart.razor.cs +++ b/BlazorExpress.ChartJS/ChartComponents/DoughnutChart.razor.cs @@ -156,7 +156,7 @@ public override async Task InitializeAsync(ChartData chartData, IChartOptions ch { var datasets = chartData.Datasets.OfType(); var data = new { chartData.Labels, Datasets = datasets }; - await JSRuntime.InvokeVoidAsync(DoughnutChartInterop.Initialize, Id, GetChartType(), data, (DoughnutChartOptions)chartOptions, plugins); + await JSRuntime.InvokeVoidAsync(DoughnutChartInterop.Initialize, Id, GetChartType(), data, (DoughnutChartOptions)chartOptions, plugins, DotNetObjectReference); } } diff --git a/BlazorExpress.ChartJS/ChartComponents/LineChart.razor.cs b/BlazorExpress.ChartJS/ChartComponents/LineChart.razor.cs index 8c9c7f0d..5ef99166 100644 --- a/BlazorExpress.ChartJS/ChartComponents/LineChart.razor.cs +++ b/BlazorExpress.ChartJS/ChartComponents/LineChart.razor.cs @@ -184,7 +184,7 @@ public override async Task InitializeAsync(ChartData chartData, IChartOptions ch var datasets = BarLineChartSupport.GetSupportedDatasets(chartData); var data = new { chartData.Labels, Datasets = datasets }; - await JSRuntime.InvokeVoidAsync(LineChartInterop.Initialize, Id, GetChartType(), data, (LineChartOptions)chartOptions, plugins); + await JSRuntime.InvokeVoidAsync(LineChartInterop.Initialize, Id, GetChartType(), data, (LineChartOptions)chartOptions, plugins, DotNetObjectReference); } /// diff --git a/BlazorExpress.ChartJS/ChartComponents/PieChart.razor.cs b/BlazorExpress.ChartJS/ChartComponents/PieChart.razor.cs index bf303122..2aa9c019 100644 --- a/BlazorExpress.ChartJS/ChartComponents/PieChart.razor.cs +++ b/BlazorExpress.ChartJS/ChartComponents/PieChart.razor.cs @@ -156,7 +156,7 @@ public override async Task InitializeAsync(ChartData chartData, IChartOptions ch { var datasets = chartData.Datasets.OfType(); var data = new { chartData.Labels, Datasets = datasets }; - await JSRuntime.InvokeVoidAsync(PieChartInterop.Initialize, Id, GetChartType(), data, (PieChartOptions)chartOptions, plugins); + await JSRuntime.InvokeVoidAsync(PieChartInterop.Initialize, Id, GetChartType(), data, (PieChartOptions)chartOptions, plugins, DotNetObjectReference); } } diff --git a/BlazorExpress.ChartJS/ChartComponents/PolarAreaChart.razor.cs b/BlazorExpress.ChartJS/ChartComponents/PolarAreaChart.razor.cs index e97ae02a..e258b800 100644 --- a/BlazorExpress.ChartJS/ChartComponents/PolarAreaChart.razor.cs +++ b/BlazorExpress.ChartJS/ChartComponents/PolarAreaChart.razor.cs @@ -150,7 +150,7 @@ public override async Task InitializeAsync(ChartData chartData, IChartOptions ch { var datasets = chartData.Datasets.OfType(); var data = new { chartData.Labels, Datasets = datasets }; - await JSRuntime.InvokeVoidAsync(PolarAreaChartInterop.Initialize, Id, GetChartType(), data, (PolarAreaChartOptions)chartOptions, plugins); + await JSRuntime.InvokeVoidAsync(PolarAreaChartInterop.Initialize, Id, GetChartType(), data, (PolarAreaChartOptions)chartOptions, plugins, DotNetObjectReference); } } diff --git a/BlazorExpress.ChartJS/ChartComponents/RadarChart.razor.cs b/BlazorExpress.ChartJS/ChartComponents/RadarChart.razor.cs index fe27d8da..a92ca63f 100644 --- a/BlazorExpress.ChartJS/ChartComponents/RadarChart.razor.cs +++ b/BlazorExpress.ChartJS/ChartComponents/RadarChart.razor.cs @@ -150,7 +150,7 @@ public override async Task InitializeAsync(ChartData chartData, IChartOptions ch { var datasets = chartData.Datasets.OfType(); var data = new { chartData.Labels, Datasets = datasets }; - await JSRuntime.InvokeVoidAsync(RadarChartInterop.Initialize, Id, GetChartType(), data, (RadarChartOptions)chartOptions, plugins); + await JSRuntime.InvokeVoidAsync(RadarChartInterop.Initialize, Id, GetChartType(), data, (RadarChartOptions)chartOptions, plugins, DotNetObjectReference); } } diff --git a/BlazorExpress.ChartJS/ChartComponents/ScatterChart.razor.cs b/BlazorExpress.ChartJS/ChartComponents/ScatterChart.razor.cs index 2321dcf1..fb68f974 100644 --- a/BlazorExpress.ChartJS/ChartComponents/ScatterChart.razor.cs +++ b/BlazorExpress.ChartJS/ChartComponents/ScatterChart.razor.cs @@ -157,7 +157,7 @@ public override async Task InitializeAsync(ChartData chartData, IChartOptions ch var datasets = chartData.Datasets.OfType(); var data = new { chartData.Labels, Datasets = datasets }; - await JSRuntime.InvokeVoidAsync(ScatterChartInterop.Initialize, Id, GetChartType(), data, (ScatterChartOptions)chartOptions, plugins); + await JSRuntime.InvokeVoidAsync(ScatterChartInterop.Initialize, Id, GetChartType(), data, (ScatterChartOptions)chartOptions, plugins, DotNetObjectReference); } /// diff --git a/BlazorExpress.ChartJS/Models/ChartClickEventArgs.cs b/BlazorExpress.ChartJS/Models/ChartClickEventArgs.cs new file mode 100644 index 00000000..d2f25c0d --- /dev/null +++ b/BlazorExpress.ChartJS/Models/ChartClickEventArgs.cs @@ -0,0 +1,49 @@ +namespace BlazorExpress.ChartJS; + +/// +/// Provides information about a selected chart data item. +/// +public class ChartClickEventArgs +{ + #region Properties, Indexers + + /// + /// Gets or sets the index of the selected dataset. + /// + [AddedVersion("1.2.4")] + [Description("Gets or sets the index of the selected dataset.")] + public int DatasetIndex { get; set; } + + /// + /// Gets or sets the label of the selected dataset. + /// + [AddedVersion("1.2.4")] + [DefaultValue(null)] + [Description("Gets or sets the label of the selected dataset.")] + public string? DatasetLabel { get; set; } + + /// + /// Gets or sets the index of the selected data item. + /// + [AddedVersion("1.2.4")] + [Description("Gets or sets the index of the selected data item.")] + public int Index { get; set; } + + /// + /// Gets or sets the label of the selected data item. + /// + [AddedVersion("1.2.4")] + [DefaultValue(null)] + [Description("Gets or sets the label of the selected data item.")] + public string? Label { get; set; } + + /// + /// Gets or sets the raw value of the selected data item. + /// + [AddedVersion("1.2.4")] + [DefaultValue(null)] + [Description("Gets or sets the raw value of the selected data item.")] + public JsonElement? Value { get; set; } + + #endregion +} diff --git a/BlazorExpress.ChartJS/Usings.cs b/BlazorExpress.ChartJS/Usings.cs index 7f28513a..55872776 100644 --- a/BlazorExpress.ChartJS/Usings.cs +++ b/BlazorExpress.ChartJS/Usings.cs @@ -4,4 +4,5 @@ global using System.ComponentModel; global using System.Drawing; global using System.Globalization; +global using System.Text.Json; global using System.Text.Json.Serialization; diff --git a/BlazorExpress.ChartJS/wwwroot/blazorexpress.chartjs.js b/BlazorExpress.ChartJS/wwwroot/blazorexpress.chartjs.js index c8746fd6..6ba5fdbb 100644 --- a/BlazorExpress.ChartJS/wwwroot/blazorexpress.chartjs.js +++ b/BlazorExpress.ChartJS/wwwroot/blazorexpress.chartjs.js @@ -39,6 +39,26 @@ if (!window.blazorexpress.chartjs.scatter) { } window.blazorexpress.chartjs = { + addClickHandler: (chart, dotNetObjectReference) => { + if (!chart || !chart.canvas || !dotNetObjectReference || chart.blazorExpressClickHandler) return; + + chart.blazorExpressClickHandler = true; + chart.canvas.addEventListener('click', (event) => { + const activeElements = chart.getElementsAtEventForMode(event, 'nearest', { intersect: true }, true); + if (!activeElements || activeElements.length === 0) return; + + const activeElement = activeElements[0]; + const dataset = chart.data.datasets?.[activeElement.datasetIndex]; + + dotNetObjectReference.invokeMethodAsync('HandleClickAsync', { + datasetIndex: activeElement.datasetIndex, + datasetLabel: dataset?.label ?? null, + index: activeElement.index, + label: chart.data.labels?.[activeElement.index] ?? null, + value: dataset?.data?.[activeElement.index] ?? null + }).catch(() => { }); + }); + }, create: (elementId, type, data, options, plugins) => { let chartEl = document.getElementById(elementId); let _plugins = []; @@ -72,11 +92,14 @@ window.blazorexpress.chartjs = { return chart; }, - initialize: (elementId, type, data, options, plugins) => { + initialize: (elementId, type, data, options, plugins, dotNetObjectReference) => { let chart = window.blazorexpress.chartjs.get(elementId); - if (chart) return; - else + if (!chart) { window.blazorexpress.chartjs.create(elementId, type, data, options, plugins); + chart = window.blazorexpress.chartjs.get(elementId); + } + + window.blazorexpress.chartjs.addClickHandler(chart, dotNetObjectReference); }, resize: (elementId, width, height) => { let chart = window.blazorexpress.chartjs.get(elementId); @@ -201,11 +224,14 @@ window.blazorexpress.chartjs.bar = { return chart; }, - initialize: (elementId, type, data, options, plugins) => { + initialize: (elementId, type, data, options, plugins, dotNetObjectReference) => { let chart = window.blazorexpress.chartjs.bar.get(elementId); - if (chart) return; - else + if (!chart) { window.blazorexpress.chartjs.bar.create(elementId, type, data, options, plugins); + chart = window.blazorexpress.chartjs.bar.get(elementId); + } + + window.blazorexpress.chartjs.addClickHandler(chart, dotNetObjectReference); }, resize: (elementId, width, height) => { let chart = window.blazorexpress.chartjs.bar.get(elementId); @@ -313,11 +339,14 @@ window.blazorexpress.chartjs.bubble = { return chart; }, - initialize: (elementId, type, data, options, plugins) => { + initialize: (elementId, type, data, options, plugins, dotNetObjectReference) => { let chart = window.blazorexpress.chartjs.bubble.get(elementId); - if (chart) return; - else + if (!chart) { window.blazorexpress.chartjs.bubble.create(elementId, type, data, options, plugins); + chart = window.blazorexpress.chartjs.bubble.get(elementId); + } + + window.blazorexpress.chartjs.addClickHandler(chart, dotNetObjectReference); }, resize: (elementId, width, height) => { let chart = window.blazorexpress.chartjs.bubble.get(elementId); @@ -431,11 +460,14 @@ window.blazorexpress.chartjs.doughnut = { return chart; }, - initialize: (elementId, type, data, options, plugins) => { + initialize: (elementId, type, data, options, plugins, dotNetObjectReference) => { let chart = window.blazorexpress.chartjs.doughnut.get(elementId); - if (chart) return; - else + if (!chart) { window.blazorexpress.chartjs.doughnut.create(elementId, type, data, options, plugins); + chart = window.blazorexpress.chartjs.doughnut.get(elementId); + } + + window.blazorexpress.chartjs.addClickHandler(chart, dotNetObjectReference); }, resize: (elementId, width, height) => { let chart = window.blazorexpress.chartjs.doughnut.get(elementId); @@ -581,12 +613,14 @@ window.blazorexpress.chartjs.line = { return chart; }, - initialize: (elementId, type, data, options, plugins) => { + initialize: (elementId, type, data, options, plugins, dotNetObjectReference) => { let chart = window.blazorexpress.chartjs.line.get(elementId); - if (chart) - return; - else + if (!chart) { window.blazorexpress.chartjs.line.create(elementId, type, data, options, plugins); + chart = window.blazorexpress.chartjs.line.get(elementId); + } + + window.blazorexpress.chartjs.addClickHandler(chart, dotNetObjectReference); }, resize: (elementId, width, height) => { let chart = window.blazorexpress.chartjs.line.get(elementId); @@ -701,11 +735,14 @@ window.blazorexpress.chartjs.pie = { return chart; }, - initialize: (elementId, type, data, options, plugins) => { + initialize: (elementId, type, data, options, plugins, dotNetObjectReference) => { let chart = window.blazorexpress.chartjs.pie.get(elementId); - if (chart) return; - else + if (!chart) { window.blazorexpress.chartjs.pie.create(elementId, type, data, options, plugins); + chart = window.blazorexpress.chartjs.pie.get(elementId); + } + + window.blazorexpress.chartjs.addClickHandler(chart, dotNetObjectReference); }, resize: (elementId, width, height) => { let chart = window.blazorexpress.chartjs.pie.get(elementId); @@ -820,11 +857,14 @@ window.blazorexpress.chartjs.polarArea = { return chart; }, - initialize: (elementId, type, data, options, plugins) => { + initialize: (elementId, type, data, options, plugins, dotNetObjectReference) => { let chart = window.blazorexpress.chartjs.polarArea.get(elementId); - if (chart) return; - else + if (!chart) { window.blazorexpress.chartjs.polarArea.create(elementId, type, data, options, plugins); + chart = window.blazorexpress.chartjs.polarArea.get(elementId); + } + + window.blazorexpress.chartjs.addClickHandler(chart, dotNetObjectReference); }, resize: (elementId, width, height) => { let chart = window.blazorexpress.chartjs.polarArea.get(elementId); @@ -938,11 +978,14 @@ window.blazorexpress.chartjs.radar = { return chart; }, - initialize: (elementId, type, data, options, plugins) => { + initialize: (elementId, type, data, options, plugins, dotNetObjectReference) => { let chart = window.blazorexpress.chartjs.radar.get(elementId); - if (chart) return; - else + if (!chart) { window.blazorexpress.chartjs.radar.create(elementId, type, data, options, plugins); + chart = window.blazorexpress.chartjs.radar.get(elementId); + } + + window.blazorexpress.chartjs.addClickHandler(chart, dotNetObjectReference); }, resize: (elementId, width, height) => { let chart = window.blazorexpress.chartjs.radar.get(elementId); @@ -1073,11 +1116,14 @@ window.blazorexpress.chartjs.scatter = { return chart; }, - initialize: (elementId, type, data, options, plugins) => { + initialize: (elementId, type, data, options, plugins, dotNetObjectReference) => { let chart = window.blazorexpress.chartjs.scatter.get(elementId); - if (chart) return; - else + if (!chart) { window.blazorexpress.chartjs.scatter.create(elementId, type, data, options, plugins); + chart = window.blazorexpress.chartjs.scatter.get(elementId); + } + + window.blazorexpress.chartjs.addClickHandler(chart, dotNetObjectReference); }, resize: (elementId, width, height) => { let chart = window.blazorexpress.chartjs.scatter.get(elementId); @@ -1121,4 +1167,4 @@ window.blazorexpress.chartjs.scatter = { chart.update(); } } -} \ No newline at end of file +} From a7735fe343a4b5ee7a5a8eaae77d2722ab1d09e7 Mon Sep 17 00:00:00 2001 From: Vikram Reddy Date: Tue, 14 Jul 2026 00:27:23 +0530 Subject: [PATCH 2/6] Demos updated --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 8a30d258..c83793c2 100644 --- a/.gitignore +++ b/.gitignore @@ -396,3 +396,4 @@ FodyWeavers.xsd # JetBrains Rider *.sln.iml +/output From aa3e951230daa31f284042136a8d77d7a75650d9 Mon Sep 17 00:00:00 2001 From: Vikram Reddy Date: Tue, 14 Jul 2026 00:27:46 +0530 Subject: [PATCH 3/6] Demos updated --- .../BarChart/BarChartDocumentation.razor | 7 ++ .../BarChart/BarChart_Demo_01_Examples.razor | 16 +++- .../ChartClickEventArgsTests.cs | 87 +++++++++++++++++++ 3 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 BlazorExpress.ChartJS.MCP.Tests/ChartClickEventArgsTests.cs diff --git a/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/BarChart/BarChartDocumentation.razor b/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/BarChart/BarChartDocumentation.razor index 38de563b..5cd89605 100644 --- a/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/BarChart/BarChartDocumentation.razor +++ b/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/BarChart/BarChartDocumentation.razor @@ -32,6 +32,13 @@ +
+ + Set the OnClick callback to react when a chart data item is selected. The callback receives ChartClickEventArgs with the dataset index and label, data-item index and label, and raw value. + The basic Bar Chart demo displays the selected item below the chart. + +
+
The Combo bar/line demo mixes BarChartDataset and LineChartDataset in the same BarChart. diff --git a/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/BarChart/BarChart_Demo_01_Examples.razor b/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/BarChart/BarChart_Demo_01_Examples.razor index c66b5d30..34fc7b61 100644 --- a/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/BarChart/BarChart_Demo_01_Examples.razor +++ b/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/BarChart/BarChart_Demo_01_Examples.razor @@ -1,4 +1,11 @@ - + + +@if (selectedChartItem is not null) +{ +

+ Selected: @selectedChartItem.DatasetLabel (dataset @selectedChartItem.DatasetIndex), @selectedChartItem.Label (index @selectedChartItem.Index), value @selectedChartItem.Value +

+}
@@ -12,6 +19,7 @@ private BarChart barChart = default!; private BarChartOptions barChartOptions = default!; private ChartData chartData = default!; + private ChartClickEventArgs? selectedChartItem; private int datasetsCount = 0; private int labelsCount = 0; @@ -33,6 +41,12 @@ await base.OnAfterRenderAsync(firstRender); } + private Task HandleClickAsync(ChartClickEventArgs eventArgs) + { + selectedChartItem = eventArgs; + return Task.CompletedTask; + } + private async Task RandomizeAsync() { if (chartData is null || chartData.Datasets is null || !chartData.Datasets.Any()) return; diff --git a/BlazorExpress.ChartJS.MCP.Tests/ChartClickEventArgsTests.cs b/BlazorExpress.ChartJS.MCP.Tests/ChartClickEventArgsTests.cs new file mode 100644 index 00000000..8e5c78da --- /dev/null +++ b/BlazorExpress.ChartJS.MCP.Tests/ChartClickEventArgsTests.cs @@ -0,0 +1,87 @@ +using BlazorExpress.ChartJS; +using Microsoft.AspNetCore.Components; +using System.Text.Json; + +namespace BlazorExpress.ChartJS.MCP.Tests; + +public class ChartClickEventArgsTests +{ + [Fact] + public async Task HandleClickAsync_Invokes_Configured_Callback_With_Selected_Item_Metadata() + { + var component = new TestChartComponent(); + ChartClickEventArgs? receivedEventArgs = null; + component.ConfigureOnClick(EventCallback.Factory.Create(new object(), eventArgs => receivedEventArgs = eventArgs)); + + using var document = JsonDocument.Parse("""{"value":42}"""); + var eventArgs = new ChartClickEventArgs + { + DatasetIndex = 1, + DatasetLabel = "Revenue", + Index = 2, + Label = "March", + Value = document.RootElement.Clone() + }; + + await component.HandleClickAsync(eventArgs); + + Assert.NotNull(receivedEventArgs); + Assert.Equal(1, receivedEventArgs.DatasetIndex); + Assert.Equal("Revenue", receivedEventArgs.DatasetLabel); + Assert.Equal(2, receivedEventArgs.Index); + Assert.Equal("March", receivedEventArgs.Label); + Assert.Equal(42, receivedEventArgs.Value?.GetProperty("value").GetInt32()); + } + + [Fact] + public async Task HandleClickAsync_Without_Callback_Completes_Without_Throwing() + { + var component = new TestChartComponent(); + + var exception = await Record.ExceptionAsync(() => component.HandleClickAsync(new ChartClickEventArgs + { + DatasetIndex = 0, + Index = 0, + Value = null + })); + + Assert.Null(exception); + } + + [Fact] + public void JavaScript_Click_Bridge_Maps_Selected_Item_And_Protects_No_Item_Path() + { + var source = File.ReadAllText(GetRepositoryFile("BlazorExpress.ChartJS", "wwwroot", "blazorexpress.chartjs.js")); + + Assert.Equal(9, source.Split("initialize: (elementId, type, data, options, plugins, dotNetObjectReference)").Length - 1); + Assert.Contains("chart.getElementsAtEventForMode(event, 'nearest', { intersect: true }, true)", source); + Assert.Contains("if (!activeElements || activeElements.length === 0) return;", source); + Assert.Contains("dotNetObjectReference.invokeMethodAsync('HandleClickAsync'", source); + Assert.Contains("datasetIndex: activeElement.datasetIndex", source); + Assert.Contains("datasetLabel: dataset?.label ?? null", source); + Assert.Contains("index: activeElement.index", source); + Assert.Contains("label: chart.data.labels?.[activeElement.index] ?? null", source); + Assert.Contains("value: dataset?.data?.[activeElement.index] ?? null", source); + Assert.DoesNotContain("options.onClick", source); + } + + private static string GetRepositoryFile(params string[] pathSegments) + { + var directory = new DirectoryInfo(AppContext.BaseDirectory); + + while (directory is not null) + { + if (File.Exists(Path.Combine(directory.FullName, "BlazorExpress.ChartJS.sln"))) + return Path.Combine([directory.FullName, .. pathSegments]); + + directory = directory.Parent; + } + + throw new DirectoryNotFoundException("The ChartJS repository root could not be located."); + } + + private sealed class TestChartComponent : ChartComponentBase + { + public void ConfigureOnClick(EventCallback onClick) => OnClick = onClick; + } +} From 1f7345e61a80ed31d4d670aeabaeb7ba0f7ab580 Mon Sep 17 00:00:00 2001 From: Vikram Reddy Date: Tue, 14 Jul 2026 11:32:19 +0530 Subject: [PATCH 4/6] Remove ChartClickEventArgsTests and related code Removed the `ChartClickEventArgsTests` class and its test methods, including `HandleClickAsync` tests and JavaScript bridge validation. Deleted the `GetRepositoryFile` helper method and the `TestChartComponent` class. Cleaned up unused `using` directives and namespace declaration. --- .../ChartClickEventArgsTests.cs | 87 ------------------- 1 file changed, 87 deletions(-) delete mode 100644 BlazorExpress.ChartJS.MCP.Tests/ChartClickEventArgsTests.cs diff --git a/BlazorExpress.ChartJS.MCP.Tests/ChartClickEventArgsTests.cs b/BlazorExpress.ChartJS.MCP.Tests/ChartClickEventArgsTests.cs deleted file mode 100644 index 8e5c78da..00000000 --- a/BlazorExpress.ChartJS.MCP.Tests/ChartClickEventArgsTests.cs +++ /dev/null @@ -1,87 +0,0 @@ -using BlazorExpress.ChartJS; -using Microsoft.AspNetCore.Components; -using System.Text.Json; - -namespace BlazorExpress.ChartJS.MCP.Tests; - -public class ChartClickEventArgsTests -{ - [Fact] - public async Task HandleClickAsync_Invokes_Configured_Callback_With_Selected_Item_Metadata() - { - var component = new TestChartComponent(); - ChartClickEventArgs? receivedEventArgs = null; - component.ConfigureOnClick(EventCallback.Factory.Create(new object(), eventArgs => receivedEventArgs = eventArgs)); - - using var document = JsonDocument.Parse("""{"value":42}"""); - var eventArgs = new ChartClickEventArgs - { - DatasetIndex = 1, - DatasetLabel = "Revenue", - Index = 2, - Label = "March", - Value = document.RootElement.Clone() - }; - - await component.HandleClickAsync(eventArgs); - - Assert.NotNull(receivedEventArgs); - Assert.Equal(1, receivedEventArgs.DatasetIndex); - Assert.Equal("Revenue", receivedEventArgs.DatasetLabel); - Assert.Equal(2, receivedEventArgs.Index); - Assert.Equal("March", receivedEventArgs.Label); - Assert.Equal(42, receivedEventArgs.Value?.GetProperty("value").GetInt32()); - } - - [Fact] - public async Task HandleClickAsync_Without_Callback_Completes_Without_Throwing() - { - var component = new TestChartComponent(); - - var exception = await Record.ExceptionAsync(() => component.HandleClickAsync(new ChartClickEventArgs - { - DatasetIndex = 0, - Index = 0, - Value = null - })); - - Assert.Null(exception); - } - - [Fact] - public void JavaScript_Click_Bridge_Maps_Selected_Item_And_Protects_No_Item_Path() - { - var source = File.ReadAllText(GetRepositoryFile("BlazorExpress.ChartJS", "wwwroot", "blazorexpress.chartjs.js")); - - Assert.Equal(9, source.Split("initialize: (elementId, type, data, options, plugins, dotNetObjectReference)").Length - 1); - Assert.Contains("chart.getElementsAtEventForMode(event, 'nearest', { intersect: true }, true)", source); - Assert.Contains("if (!activeElements || activeElements.length === 0) return;", source); - Assert.Contains("dotNetObjectReference.invokeMethodAsync('HandleClickAsync'", source); - Assert.Contains("datasetIndex: activeElement.datasetIndex", source); - Assert.Contains("datasetLabel: dataset?.label ?? null", source); - Assert.Contains("index: activeElement.index", source); - Assert.Contains("label: chart.data.labels?.[activeElement.index] ?? null", source); - Assert.Contains("value: dataset?.data?.[activeElement.index] ?? null", source); - Assert.DoesNotContain("options.onClick", source); - } - - private static string GetRepositoryFile(params string[] pathSegments) - { - var directory = new DirectoryInfo(AppContext.BaseDirectory); - - while (directory is not null) - { - if (File.Exists(Path.Combine(directory.FullName, "BlazorExpress.ChartJS.sln"))) - return Path.Combine([directory.FullName, .. pathSegments]); - - directory = directory.Parent; - } - - throw new DirectoryNotFoundException("The ChartJS repository root could not be located."); - } - - private sealed class TestChartComponent : ChartComponentBase - { - public void ConfigureOnClick(EventCallback onClick) => OnClick = onClick; - } -} From 58ebc8e115d328479a003ec3c7b39360de9bfc7c Mon Sep 17 00:00:00 2001 From: Vikram Reddy Date: Tue, 14 Jul 2026 12:11:02 +0530 Subject: [PATCH 5/6] Add Prerequisites section to Prerequisites.razor Added a new namespace declaration `BlazorExpress.ChartJS.Demo.RCL`. Introduced a `
` component for the "Prerequisites" section. Included a `` with a link to the "Getting Started guide". Added a `PageUrl` parameter for dynamic URL handling. --- .../Components/Shared/Prerequisites.razor | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 BlazorExpress.ChartJS.Demo.RCL/Components/Shared/Prerequisites.razor diff --git a/BlazorExpress.ChartJS.Demo.RCL/Components/Shared/Prerequisites.razor b/BlazorExpress.ChartJS.Demo.RCL/Components/Shared/Prerequisites.razor new file mode 100644 index 00000000..edae0aea --- /dev/null +++ b/BlazorExpress.ChartJS.Demo.RCL/Components/Shared/Prerequisites.razor @@ -0,0 +1,12 @@ +@namespace BlazorExpress.ChartJS.Demo.RCL + +
+ + Refer to the Getting Started guide for setting up charts. + +
+ +@code { + [Parameter] + public string? PageUrl { get; set; } +} From 8b96107d5313b3cee1aca8e5ce7413e8712a75c1 Mon Sep 17 00:00:00 2001 From: Vikram Reddy Date: Tue, 14 Jul 2026 22:29:55 +0530 Subject: [PATCH 6/6] Add "Click event" support and demos for all chart types Added "Click event" sections to documentation for BarChart, BubbleChart, DoughnutChart, LineChart, PieChart, PolarAreaChart, RadarChart, and ScatterChart. These sections explain the use of the `OnClick` callback to handle user interactions with chart elements. Created new demo files for each chart type to showcase the "Click event" functionality. Demos include event handling, chart data initialization, and displaying selected item details. --- .../BarChart/BarChartDocumentation.razor | 3 +- .../BarChart_Demo_11_Click_Event.razor | 47 ++++++++++++++++ .../BubbleChartDocumentation.razor | 7 +++ .../BubbleChart_Demo_02_Click_Event.razor | 54 ++++++++++++++++++ .../DoughnutChartDocumentation.razor | 9 ++- .../DoughnutChart_Demo_03_Click_Event.razor | 47 ++++++++++++++++ .../LineChart/LineChartDocumentation.razor | 7 +++ .../LineChart_Demo_08_Click_Event.razor | 50 +++++++++++++++++ .../PieChart/PieChartDocumentation.razor | 7 +++ .../PieChart_Demo_04_Click_Event.razor | 47 ++++++++++++++++ .../PolarAreaChartDocumentation.razor | 7 +++ .../PolarAreaChart_Demo_02_Click_Event.razor | 53 ++++++++++++++++++ .../RadarChart/RadarChartDocumentation.razor | 7 +++ .../RadarChart_Demo_02_Click_Event.razor | 50 +++++++++++++++++ .../ScatterChartDocumentation.razor | 7 +++ .../ScatterChart_Demo_03_Click_Event.razor | 55 +++++++++++++++++++ 16 files changed, 455 insertions(+), 2 deletions(-) create mode 100644 BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/BarChart/BarChart_Demo_11_Click_Event.razor create mode 100644 BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/BubbleChart/BubbleChart_Demo_02_Click_Event.razor create mode 100644 BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/DoughnutChart/DoughnutChart_Demo_03_Click_Event.razor create mode 100644 BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/LineChart/LineChart_Demo_08_Click_Event.razor create mode 100644 BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/PieChart/PieChart_Demo_04_Click_Event.razor create mode 100644 BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/PolarAreaChart/PolarAreaChart_Demo_02_Click_Event.razor create mode 100644 BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/RadarChart/RadarChart_Demo_02_Click_Event.razor create mode 100644 BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/ScatterChart/ScatterChart_Demo_03_Click_Event.razor diff --git a/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/BarChart/BarChartDocumentation.razor b/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/BarChart/BarChartDocumentation.razor index 5cd89605..c882e6fa 100644 --- a/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/BarChart/BarChartDocumentation.razor +++ b/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/BarChart/BarChartDocumentation.razor @@ -35,8 +35,9 @@
Set the OnClick callback to react when a chart data item is selected. The callback receives ChartClickEventArgs with the dataset index and label, data-item index and label, and raw value. - The basic Bar Chart demo displays the selected item below the chart. + The dedicated demo displays the selected item below the chart. +
diff --git a/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/BarChart/BarChart_Demo_11_Click_Event.razor b/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/BarChart/BarChart_Demo_11_Click_Event.razor new file mode 100644 index 00000000..60f97778 --- /dev/null +++ b/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/BarChart/BarChart_Demo_11_Click_Event.razor @@ -0,0 +1,47 @@ + + +@if (selectedChartItem is not null) +{ +

+ Selected: @selectedChartItem.DatasetLabel (dataset @selectedChartItem.DatasetIndex), @selectedChartItem.Label (index @selectedChartItem.Index), value @selectedChartItem.Value +

+} + +@code { + private BarChart barChart = default!; + private BarChartOptions barChartOptions = default!; + private ChartData chartData = default!; + private ChartClickEventArgs? selectedChartItem; + + protected override void OnInitialized() + { + chartData = new ChartData + { + Labels = new List { "January", "February", "March" }, + Datasets = new List + { + new BarChartDataset + { + Label = "Orders", + Data = new List { 45, 68, 54 }, + BackgroundColor = new List { "#36A2EB" }, + }, + }, + }; + barChartOptions = new BarChartOptions { Responsive = true }; + } + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + await barChart.InitializeAsync(chartData, barChartOptions); + + await base.OnAfterRenderAsync(firstRender); + } + + private Task HandleClickAsync(ChartClickEventArgs eventArgs) + { + selectedChartItem = eventArgs; + return Task.CompletedTask; + } +} diff --git a/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/BubbleChart/BubbleChartDocumentation.razor b/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/BubbleChart/BubbleChartDocumentation.razor index dc7e3963..748e3325 100644 --- a/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/BubbleChart/BubbleChartDocumentation.razor +++ b/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/BubbleChart/BubbleChartDocumentation.razor @@ -34,6 +34,13 @@
+
+ + Set the OnClick callback to react when a bubble is selected. The callback receives ChartClickEventArgs with the dataset, point index, and raw value; the demo displays the selected item below the chart. + + +
+ @code { private const string pageUrl = DemoRouteConstants.Demos_BubbleChart; private const string pageTitle = "Bubble Chart"; diff --git a/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/BubbleChart/BubbleChart_Demo_02_Click_Event.razor b/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/BubbleChart/BubbleChart_Demo_02_Click_Event.razor new file mode 100644 index 00000000..3180aa8c --- /dev/null +++ b/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/BubbleChart/BubbleChart_Demo_02_Click_Event.razor @@ -0,0 +1,54 @@ + + +@if (selectedChartItem is not null) +{ +

+ Selected: @selectedChartItem.DatasetLabel (dataset @selectedChartItem.DatasetIndex), @selectedChartItem.Label (index @selectedChartItem.Index), value @selectedChartItem.Value +

+} + +@code { + private BubbleChart bubbleChart = default!; + private BubbleChartOptions bubbleChartOptions = default!; + private ChartData chartData = default!; + private ChartClickEventArgs? selectedChartItem; + + protected override void OnInitialized() + { + chartData = new ChartData + { + Labels = new List { "January", "February", "March" }, + Datasets = new List + { + new BubbleChartDataset + { + Label = "Projects", + Data = new List + { + new(10, 20, 8), + new(15, 12, 12), + new(8, 25, 6), + }, + BackgroundColor = new List { "rgba(255, 99, 132, 0.5)" }, + BorderColor = new List { "rgb(255, 99, 132)" }, + BorderWidth = 1, + }, + }, + }; + bubbleChartOptions = new BubbleChartOptions { Responsive = true }; + } + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + await bubbleChart.InitializeAsync(chartData, bubbleChartOptions); + + await base.OnAfterRenderAsync(firstRender); + } + + private Task HandleClickAsync(ChartClickEventArgs eventArgs) + { + selectedChartItem = eventArgs; + return Task.CompletedTask; + } +} diff --git a/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/DoughnutChart/DoughnutChartDocumentation.razor b/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/DoughnutChart/DoughnutChartDocumentation.razor index d5a939dd..1228666d 100644 --- a/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/DoughnutChart/DoughnutChartDocumentation.razor +++ b/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/DoughnutChart/DoughnutChartDocumentation.razor @@ -50,6 +50,13 @@
+
+ + Set the OnClick callback to react when a doughnut segment is selected. The callback receives ChartClickEventArgs with the dataset, item index, label, and raw value; the demo displays the selected item below the chart. + + +
+ @code { private const string pageUrl = DemoRouteConstants.Demos_DoughnutChart; private const string pageTitle = "Doughnut Chart"; @@ -57,4 +64,4 @@ private const string metaTitle = "Blazor Doughnut Chart Demo & Examples"; private const string metaDescription = "Explore interactive Blazor Doughnut Chart demos with real-world examples. Learn how to visualize data, customize chart options, and implement data labels using the Blazor Doughnut Chart component."; private const string imageUrl = DemoImageSrcConstants.DoughnutChart; -} \ No newline at end of file +} diff --git a/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/DoughnutChart/DoughnutChart_Demo_03_Click_Event.razor b/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/DoughnutChart/DoughnutChart_Demo_03_Click_Event.razor new file mode 100644 index 00000000..ff8c8512 --- /dev/null +++ b/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/DoughnutChart/DoughnutChart_Demo_03_Click_Event.razor @@ -0,0 +1,47 @@ + + +@if (selectedChartItem is not null) +{ +

+ Selected: @selectedChartItem.DatasetLabel (dataset @selectedChartItem.DatasetIndex), @selectedChartItem.Label (index @selectedChartItem.Index), value @selectedChartItem.Value +

+} + +@code { + private DoughnutChart doughnutChart = default!; + private DoughnutChartOptions doughnutChartOptions = default!; + private ChartData chartData = default!; + private ChartClickEventArgs? selectedChartItem; + + protected override void OnInitialized() + { + chartData = new ChartData + { + Labels = new List { "Direct", "Referral", "Social" }, + Datasets = new List + { + new DoughnutChartDataset + { + Label = "Visitors", + Data = new List { 55, 30, 15 }, + BackgroundColor = new List { "#36A2EB", "#FF6384", "#FFCE56" }, + }, + }, + }; + doughnutChartOptions = new DoughnutChartOptions { Responsive = true }; + } + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + await doughnutChart.InitializeAsync(chartData, doughnutChartOptions); + + await base.OnAfterRenderAsync(firstRender); + } + + private Task HandleClickAsync(ChartClickEventArgs eventArgs) + { + selectedChartItem = eventArgs; + return Task.CompletedTask; + } +} diff --git a/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/LineChart/LineChartDocumentation.razor b/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/LineChart/LineChartDocumentation.razor index e760ad2d..d0bd58b4 100644 --- a/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/LineChart/LineChartDocumentation.razor +++ b/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/LineChart/LineChartDocumentation.razor @@ -144,6 +144,13 @@
+
+ + 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; the demo displays the selected item below the chart. + + +
+ @code { private const string pageUrl = DemoRouteConstants.Demos_LineChart; private const string pageTitle = "Line Chart"; diff --git a/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/LineChart/LineChart_Demo_08_Click_Event.razor b/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/LineChart/LineChart_Demo_08_Click_Event.razor new file mode 100644 index 00000000..7c6101c7 --- /dev/null +++ b/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/LineChart/LineChart_Demo_08_Click_Event.razor @@ -0,0 +1,50 @@ + + +@if (selectedChartItem is not null) +{ +

+ Selected: @selectedChartItem.DatasetLabel (dataset @selectedChartItem.DatasetIndex), @selectedChartItem.Label (index @selectedChartItem.Index), value @selectedChartItem.Value +

+} + +@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 { "Monday", "Tuesday", "Wednesday", "Thursday" }, + Datasets = new List + { + new LineChartDataset + { + Label = "Visitors", + Data = new List { 120, 190, 150, 230 }, + BackgroundColor = "rgba(54, 162, 235, 0.2)", + BorderColor = "rgb(54, 162, 235)", + PointRadius = new List { 5 }, + PointHoverRadius = new List { 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; + } +} diff --git a/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/PieChart/PieChartDocumentation.razor b/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/PieChart/PieChartDocumentation.razor index fe47d712..fc51bf1a 100644 --- a/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/PieChart/PieChartDocumentation.razor +++ b/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/PieChart/PieChartDocumentation.razor @@ -70,6 +70,13 @@ +
+ + Set the OnClick callback to react when a pie slice is selected. The callback receives ChartClickEventArgs with the dataset, item index, label, and raw value; the demo displays the selected item below the chart. + + +
+ @code { private const string pageUrl = DemoRouteConstants.Demos_PieChart; private const string pageTitle = "Pie Chart"; diff --git a/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/PieChart/PieChart_Demo_04_Click_Event.razor b/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/PieChart/PieChart_Demo_04_Click_Event.razor new file mode 100644 index 00000000..843abe64 --- /dev/null +++ b/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/PieChart/PieChart_Demo_04_Click_Event.razor @@ -0,0 +1,47 @@ + + +@if (selectedChartItem is not null) +{ +

+ Selected: @selectedChartItem.DatasetLabel (dataset @selectedChartItem.DatasetIndex), @selectedChartItem.Label (index @selectedChartItem.Index), value @selectedChartItem.Value +

+} + +@code { + private PieChart pieChart = default!; + private PieChartOptions pieChartOptions = default!; + private ChartData chartData = default!; + private ChartClickEventArgs? selectedChartItem; + + protected override void OnInitialized() + { + chartData = new ChartData + { + Labels = new List { "Desktop", "Tablet", "Mobile" }, + Datasets = new List + { + new PieChartDataset + { + Label = "Sessions", + Data = new List { 62, 18, 20 }, + BackgroundColor = new List { "#4BC0C0", "#9966FF", "#FF9F40" }, + }, + }, + }; + pieChartOptions = new PieChartOptions { Responsive = true }; + } + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + await pieChart.InitializeAsync(chartData, pieChartOptions); + + await base.OnAfterRenderAsync(firstRender); + } + + private Task HandleClickAsync(ChartClickEventArgs eventArgs) + { + selectedChartItem = eventArgs; + return Task.CompletedTask; + } +} diff --git a/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/PolarAreaChart/PolarAreaChartDocumentation.razor b/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/PolarAreaChart/PolarAreaChartDocumentation.razor index b7c24236..22bb743d 100644 --- a/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/PolarAreaChart/PolarAreaChartDocumentation.razor +++ b/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/PolarAreaChart/PolarAreaChartDocumentation.razor @@ -33,6 +33,13 @@ +
+ + Set the OnClick callback to react when a polar-area segment is selected. The callback receives ChartClickEventArgs with the dataset, item index, label, and raw value; the demo displays the selected item below the chart. + + +
+ @code { private const string pageUrl = DemoRouteConstants.Demos_PolarAreaChart; private const string pageTitle = "PolarArea Chart"; diff --git a/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/PolarAreaChart/PolarAreaChart_Demo_02_Click_Event.razor b/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/PolarAreaChart/PolarAreaChart_Demo_02_Click_Event.razor new file mode 100644 index 00000000..9da1b9f1 --- /dev/null +++ b/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/PolarAreaChart/PolarAreaChart_Demo_02_Click_Event.razor @@ -0,0 +1,53 @@ + + +@if (selectedChartItem is not null) +{ +

+ Selected: @selectedChartItem.DatasetLabel (dataset @selectedChartItem.DatasetIndex), @selectedChartItem.Label (index @selectedChartItem.Index), value @selectedChartItem.Value +

+} + +@code { + private PolarAreaChart polarAreaChart = default!; + private PolarAreaChartOptions polarAreaChartOptions = default!; + private ChartData chartData = default!; + private ChartClickEventArgs? selectedChartItem; + + protected override void OnInitialized() + { + chartData = new ChartData + { + Labels = new List { "North", "South", "East", "West" }, + Datasets = new List + { + new PolarAreaChartDataset + { + Label = "Sales", + Data = new List { 35, 55, 40, 25 }, + BackgroundColor = new List + { + "rgba(255, 99, 132, 0.5)", + "rgba(54, 162, 235, 0.5)", + "rgba(255, 206, 86, 0.5)", + "rgba(75, 192, 192, 0.5)", + }, + }, + }, + }; + polarAreaChartOptions = new PolarAreaChartOptions { Responsive = true }; + } + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + await polarAreaChart.InitializeAsync(chartData, polarAreaChartOptions); + + await base.OnAfterRenderAsync(firstRender); + } + + private Task HandleClickAsync(ChartClickEventArgs eventArgs) + { + selectedChartItem = eventArgs; + return Task.CompletedTask; + } +} diff --git a/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/RadarChart/RadarChartDocumentation.razor b/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/RadarChart/RadarChartDocumentation.razor index 8ef6443e..b43a6de2 100644 --- a/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/RadarChart/RadarChartDocumentation.razor +++ b/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/RadarChart/RadarChartDocumentation.razor @@ -33,6 +33,13 @@ +
+ + Set the OnClick callback to react when a radar data point is selected. The callback receives ChartClickEventArgs with the dataset, point index, label, and raw value; the demo displays the selected item below the chart. + + +
+ @code { private const string pageUrl = DemoRouteConstants.Demos_RadarChart; private const string pageTitle = "Radar Chart"; diff --git a/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/RadarChart/RadarChart_Demo_02_Click_Event.razor b/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/RadarChart/RadarChart_Demo_02_Click_Event.razor new file mode 100644 index 00000000..7f697f74 --- /dev/null +++ b/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/RadarChart/RadarChart_Demo_02_Click_Event.razor @@ -0,0 +1,50 @@ + + +@if (selectedChartItem is not null) +{ +

+ Selected: @selectedChartItem.DatasetLabel (dataset @selectedChartItem.DatasetIndex), @selectedChartItem.Label (index @selectedChartItem.Index), value @selectedChartItem.Value +

+} + +@code { + private RadarChart radarChart = default!; + private RadarChartOptions radarChartOptions = default!; + private ChartData chartData = default!; + private ChartClickEventArgs? selectedChartItem; + + protected override void OnInitialized() + { + chartData = new ChartData + { + Labels = new List { "Speed", "Reliability", "Comfort", "Safety", "Efficiency" }, + Datasets = new List + { + new RadarChartDataset + { + Label = "Vehicle A", + Data = new List { 80, 72, 65, 90, 78 }, + BackgroundColor = "rgba(153, 102, 255, 0.2)", + BorderColor = "rgba(153, 102, 255, 0.8)", + BorderWidth = 2, + Fill = true, + }, + }, + }; + radarChartOptions = new RadarChartOptions { Responsive = true }; + } + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + await radarChart.InitializeAsync(chartData, radarChartOptions); + + await base.OnAfterRenderAsync(firstRender); + } + + private Task HandleClickAsync(ChartClickEventArgs eventArgs) + { + selectedChartItem = eventArgs; + return Task.CompletedTask; + } +} diff --git a/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/ScatterChart/ScatterChartDocumentation.razor b/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/ScatterChart/ScatterChartDocumentation.razor index c1431bdc..98f61ff1 100644 --- a/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/ScatterChart/ScatterChartDocumentation.razor +++ b/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/ScatterChart/ScatterChartDocumentation.razor @@ -52,6 +52,13 @@ +
+ + Set the OnClick callback to react when a scatter point is selected. The callback receives ChartClickEventArgs with the dataset, point index, and raw coordinates; the demo displays the selected item below the chart. + + +
+ @code { private const string pageUrl = DemoRouteConstants.Demos_ScatterChart; private const string pageTitle = "Scatter Chart"; diff --git a/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/ScatterChart/ScatterChart_Demo_03_Click_Event.razor b/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/ScatterChart/ScatterChart_Demo_03_Click_Event.razor new file mode 100644 index 00000000..e3b65ac6 --- /dev/null +++ b/BlazorExpress.ChartJS.Demo.RCL/Pages/Demos/ScatterChart/ScatterChart_Demo_03_Click_Event.razor @@ -0,0 +1,55 @@ + + +@if (selectedChartItem is not null) +{ +

+ Selected: @selectedChartItem.DatasetLabel (dataset @selectedChartItem.DatasetIndex), @(selectedChartItem.Label ?? $"point {selectedChartItem.Index}") (index @selectedChartItem.Index), value @selectedChartItem.Value +

+} + +@code { + private ScatterChart scatterChart = default!; + private ScatterChartOptions scatterChartOptions = default!; + private ChartData chartData = default!; + private ChartClickEventArgs? selectedChartItem; + + protected override void OnInitialized() + { + chartData = new ChartData + { + Labels = new List { "First", "Second", "Third", "Fourth" }, + Datasets = new List + { + new ScatterChartDataset + { + Label = "Measurements", + Data = new List + { + new(10, 25), + new(25, 15), + new(35, 40), + new(50, 30), + }, + BackgroundColor = "rgba(255, 159, 64, 0.6)", + BorderColor = "rgb(255, 159, 64)", + BorderWidth = 2, + }, + }, + }; + scatterChartOptions = new ScatterChartOptions { Responsive = true }; + } + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + await scatterChart.InitializeAsync(chartData, scatterChartOptions); + + await base.OnAfterRenderAsync(firstRender); + } + + private Task HandleClickAsync(ChartClickEventArgs eventArgs) + { + selectedChartItem = eventArgs; + return Task.CompletedTask; + } +}