Skip to content

Commit 23d0878

Browse files
committed
Refactor chart interop and introduce bubble chart support
Updated interop classes for various chart types to use correct prefixes. Removed `BubbleData` and restructured bubble chart data handling with new `BubbleChart`, `BubbleChartDataPoint`, and `BubbleChartDatasetData` classes. Introduced `BubbleChartInterop` for JavaScript interop methods and `BubbleChartOptions` for configuration. Overall, these changes enhance the bubble chart functionality in the BlazorExpress.ChartJS library. NOTE: This commit message is auto-generated using GitHub Copilot.
1 parent bb9ce12 commit 23d0878

14 files changed

Lines changed: 316 additions & 44 deletions
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
@namespace BlazorExpress.ChartJS
2+
@inherits ChartComponentBase
3+
4+
<div class="@ContainerClassNames" style="@ContainerStyleNames">
5+
<canvas @ref="@Element" id="@Id" class="@Class" style="@Style" width="@Width" height="@Height" @attributes="@AdditionalAttributes"></canvas>
6+
</div>
Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
namespace BlazorExpress.ChartJS;
2+
3+
public partial class BubbleChart : ChartComponentBase
4+
{
5+
#region Constructors
6+
7+
public BubbleChart()
8+
{
9+
_chartType = ChartType.Bubble;
10+
}
11+
12+
#endregion
13+
14+
#region Methods
15+
16+
/// <summary>
17+
/// Asynchronously adds a new data entry to the specified chart data.
18+
/// </summary>
19+
/// <param name="chartData">The chart data to which the new entry will be added.</param>
20+
/// <param name="dataLabel">The label associated with the new data entry.</param>
21+
/// <param name="data">The dataset containing the data to be added.</param>
22+
/// <returns>A task representing the asynchronous operation, with a result of the updated <see cref="ChartData"/>.</returns>
23+
[AddedVersion("1.0.0")]
24+
[Description("Asynchronously adds a new data entry to the specified chart data.")]
25+
[MethodReturnTypeName($"Task<{nameof(ChartData)}>")]
26+
public override async Task<ChartData> AddDataAsync(ChartData chartData, string dataLabel, IChartDatasetData data)
27+
{
28+
if (chartData is null)
29+
throw new ArgumentNullException(nameof(chartData));
30+
31+
if (chartData.Datasets is null)
32+
throw new ArgumentNullException(nameof(chartData.Datasets));
33+
34+
if (data is null)
35+
throw new ArgumentNullException(nameof(data));
36+
37+
foreach (var dataset in chartData.Datasets)
38+
if (dataset is BubbleChartDataset bubbleChartDataset && bubbleChartDataset.Label == dataLabel)
39+
if (data is BubbleChartDatasetData bubbleChartDatasetData && bubbleChartDatasetData.Data is BubbleChartDataPoint bubbleChartDataPoint)
40+
bubbleChartDataset.Data?.Add(bubbleChartDataPoint);
41+
42+
await JSRuntime.InvokeVoidAsync(BubbleChartInterop.AddDatasetData, Id, dataLabel, data);
43+
44+
return chartData;
45+
}
46+
47+
/// <summary>
48+
/// Asynchronously adds a new dataset to the specified chart data.
49+
/// </summary>
50+
/// <param name="chartData">The chart data to which the dataset will be added.</param>
51+
/// <param name="dataLabel">The label for the new dataset.</param>
52+
/// <param name="data">A read-only collection of data points to be included in the new dataset.</param>
53+
/// <returns>A task that represents the asynchronous operation. The task result contains the updated chart data with the new
54+
/// dataset added.</returns>
55+
[AddedVersion("1.0.0")]
56+
[Description("Asynchronously adds a new dataset to the specified chart data.")]
57+
[MethodReturnTypeName($"Task<{nameof(ChartData)}>")]
58+
public override async Task<ChartData> AddDataAsync(ChartData chartData, string dataLabel, IReadOnlyCollection<IChartDatasetData> data)
59+
{
60+
if (chartData is null)
61+
throw new ArgumentNullException(nameof(chartData));
62+
63+
if (chartData.Datasets is null)
64+
throw new ArgumentException("chartData.Datasets must not be null", nameof(chartData));
65+
66+
if (chartData.Labels is null)
67+
throw new ArgumentException("chartData.Labels must not be null", nameof(chartData));
68+
69+
if (dataLabel is null)
70+
throw new ArgumentNullException(nameof(dataLabel));
71+
72+
if (string.IsNullOrWhiteSpace(dataLabel))
73+
throw new Exception($"{nameof(dataLabel)} cannot be empty.");
74+
75+
if (data is null)
76+
throw new ArgumentNullException(nameof(data));
77+
78+
if (!data.Any())
79+
throw new ArgumentException($"{nameof(data)} cannot be empty.", nameof(data));
80+
81+
if (chartData.Datasets.Count != data.Count)
82+
throw new InvalidDataException("The chart dataset count and the new data points count do not match.");
83+
84+
if (chartData.Labels.Contains(dataLabel))
85+
throw new Exception($"{dataLabel} already exists.");
86+
87+
chartData.Labels.Add(dataLabel);
88+
89+
foreach (var dataset in chartData.Datasets)
90+
if (dataset is BubbleChartDataset bubbleChartDataset)
91+
{
92+
var chartDatasetData = data.FirstOrDefault(x => x is BubbleChartDatasetData bubbleChartDatasetData && bubbleChartDatasetData.DatasetLabel == bubbleChartDataset.Label);
93+
94+
if (chartDatasetData is BubbleChartDatasetData bubbleChartDatasetData && bubbleChartDatasetData.Data is BubbleChartDataPoint bubbleChartDataPoint)
95+
bubbleChartDataset.Data?.Add(bubbleChartDataPoint);
96+
}
97+
98+
await JSRuntime.InvokeVoidAsync(BubbleChartInterop.AddDatasetsData, Id, dataLabel, data?.Select(x => (BubbleChartDatasetData)x));
99+
100+
return chartData;
101+
}
102+
103+
/// <summary>
104+
/// Asynchronously adds a dataset to the specified chart data.
105+
/// </summary>
106+
/// <param name="chartData">The chart data to which the dataset will be added.</param>
107+
/// <param name="chartDataset">The dataset to add to the chart data.</param>
108+
/// <param name="chartOptions">The options that configure the chart's appearance and behavior.</param>
109+
/// <returns>A task that represents the asynchronous operation. The task result contains the updated chart data with the new
110+
/// dataset added.</returns>
111+
[AddedVersion("1.0.0")]
112+
[Description("Asynchronously adds a dataset to the specified chart data.")]
113+
[MethodReturnTypeName($"Task<{nameof(ChartData)}>")]
114+
public override async Task<ChartData> AddDatasetAsync(ChartData chartData, IChartDataset chartDataset, IChartOptions chartOptions)
115+
{
116+
if (chartData is null)
117+
throw new ArgumentNullException(nameof(chartData));
118+
119+
if (chartData.Datasets is null)
120+
throw new ArgumentNullException(nameof(chartData.Datasets));
121+
122+
if (chartDataset is null)
123+
throw new ArgumentNullException(nameof(chartDataset));
124+
125+
if (chartDataset is BubbleChartDataset)
126+
{
127+
chartData.Datasets.Add(chartDataset);
128+
await JSRuntime.InvokeVoidAsync(BubbleChartInterop.AddDataset, Id, (BubbleChartDataset)chartDataset);
129+
}
130+
131+
return chartData;
132+
}
133+
134+
/// <summary>
135+
/// Asynchronously initializes the chart with the specified data and options.
136+
/// </summary>
137+
/// <remarks>This method prepares the chart for rendering by invoking the necessary JavaScript functions
138+
/// to set up the chart with the provided data and options. Ensure that <paramref name="chartData"/> contains valid
139+
/// datasets before calling this method.</remarks>
140+
/// <param name="chartData">The data to be used for the chart. Must contain at least one dataset.</param>
141+
/// <param name="chartOptions">The options to configure the chart's appearance and behavior.</param>
142+
/// <param name="plugins">An optional array of plugin identifiers to enhance the chart's functionality.</param>
143+
/// <returns>A task that represents the asynchronous initialization operation.</returns>
144+
[AddedVersion("1.0.0")]
145+
[Description("Asynchronously initializes the chart with the specified data and options.")]
146+
[MethodReturnTypeName(nameof(Task))]
147+
public override async Task InitializeAsync(ChartData chartData, IChartOptions chartOptions, string[]? plugins = null)
148+
{
149+
if (chartData is null)
150+
throw new ArgumentNullException(nameof(chartData));
151+
152+
if (chartData.Datasets is null)
153+
throw new ArgumentNullException(nameof(chartData.Datasets));
154+
155+
if (chartOptions is null)
156+
throw new ArgumentNullException(nameof(chartOptions));
157+
158+
var datasets = chartData.Datasets.OfType<BubbleChartDataset>();
159+
var data = new { chartData.Labels, Datasets = datasets };
160+
await JSRuntime.InvokeVoidAsync(BubbleChartInterop.Initialize, Id, GetChartType(), data, (BubbleChartOptions)chartOptions, plugins);
161+
}
162+
163+
/// <summary>
164+
/// Asynchronously updates the chart with the specified data and options.
165+
/// </summary>
166+
/// <remarks>This method updates the chart by invoking a JavaScript function to render the new data and
167+
/// options. Ensure that <paramref name="chartData"/> contains valid datasets to avoid no operation.</remarks>
168+
/// <param name="chartData">The data to be displayed on the chart. Must not be null and must contain at least one dataset.</param>
169+
/// <param name="chartOptions">The options to configure the chart's appearance and behavior.</param>
170+
/// <returns></returns>
171+
[AddedVersion("1.0.0")]
172+
[Description("Asynchronously updates the chart with the specified data and options.")]
173+
[MethodReturnTypeName(nameof(Task))]
174+
public override async Task UpdateAsync(ChartData chartData, IChartOptions chartOptions)
175+
{
176+
if (chartData is null)
177+
throw new ArgumentNullException(nameof(chartData));
178+
179+
if (chartData.Datasets is null)
180+
throw new ArgumentNullException(nameof(chartData.Datasets));
181+
182+
if (chartOptions is null)
183+
throw new ArgumentNullException(nameof(chartOptions));
184+
185+
var datasets = chartData.Datasets.OfType<BubbleChartDataset>();
186+
var data = new { chartData.Labels, Datasets = datasets };
187+
await JSRuntime.InvokeVoidAsync(BubbleChartInterop.Update, Id, GetChartType(), data, (BubbleChartOptions)chartOptions);
188+
}
189+
190+
#endregion
191+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
namespace BlazorExpress.ChartJS;
2+
3+
public class BubbleChartInterop
4+
{
5+
#region Fields and Constants
6+
7+
private const string Prefix = "window.blazorexpress.chartjs.bubble.";
8+
9+
public const string AddDatasetData = Prefix + "addDatasetData";
10+
11+
public const string AddDatasetsData = Prefix + "addDatasetsData";
12+
13+
public const string AddDataset = Prefix + "addDataset";
14+
15+
public const string Initialize = Prefix + "initialize";
16+
17+
public const string Update = Prefix + "update";
18+
19+
#endregion
20+
}

BlazorExpress.ChartJS/Interop/DoughnutChartInterop.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ public class DoughnutChartInterop
44
{
55
#region Fields and Constants
66

7-
private const string Prefix = "window.blazorexpress.chartjs.bar.";
7+
private const string Prefix = "window.blazorexpress.chartjs.doughnut.";
88

99
public const string AddDatasetData = Prefix + "addDatasetData";
1010

BlazorExpress.ChartJS/Interop/LineChartInterop.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ public class LineChartInterop
44
{
55
#region Fields and Constants
66

7-
private const string Prefix = "window.blazorexpress.chartjs.bar.";
7+
private const string Prefix = "window.blazorexpress.chartjs.line.";
88

99
public const string AddDatasetData = Prefix + "addDatasetData";
1010

BlazorExpress.ChartJS/Interop/PieChartInterop.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ public class PieChartInterop
44
{
55
#region Fields and Constants
66

7-
private const string Prefix = "window.blazorexpress.chartjs.bar.";
7+
private const string Prefix = "window.blazorexpress.chartjs.pie.";
88

99
public const string AddDatasetData = Prefix + "addDatasetData";
1010

BlazorExpress.ChartJS/Interop/PolarAreaChartInterop.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ public class PolarAreaChartInterop
44
{
55
#region Fields and Constants
66

7-
private const string Prefix = "window.blazorexpress.chartjs.bar.";
7+
private const string Prefix = "window.blazorexpress.chartjs.polarArea.";
88

99
public const string AddDatasetData = Prefix + "addDatasetData";
1010

BlazorExpress.ChartJS/Interop/RadarChartInterop.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ public class RadarChartInterop
44
{
55
#region Fields and Constants
66

7-
private const string Prefix = "window.blazorexpress.chartjs.bar.";
7+
private const string Prefix = "window.blazorexpress.chartjs.radar.";
88

99
public const string AddDatasetData = Prefix + "addDatasetData";
1010

BlazorExpress.ChartJS/Interop/ScatterChartInterop.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ public class ScatterChartInterop
44
{
55
#region Fields and Constants
66

7-
private const string Prefix = "window.blazorexpress.chartjs.bar.";
7+
private const string Prefix = "window.blazorexpress.chartjs.scatter.";
88

99
public const string AddDatasetData = Prefix + "addDatasetData";
1010

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
namespace BlazorExpress.ChartJS;
2+
3+
/// <summary>
4+
/// <see href="https://www.chartjs.org/docs/latest/charts/bubble.html#data-structure" />
5+
/// </summary>
6+
public record BubbleChartDataPoint(double X, double Y, double R);

0 commit comments

Comments
 (0)