diff --git a/BlazorBootstrap.Demo/Pages/Charts/BarCharts/Charts_Demo_01_BarChart_Examples.razor b/BlazorBootstrap.Demo/Pages/Charts/BarCharts/Charts_Demo_01_BarChart_Examples.razor index 0a7d586fb..fe67a93ca 100644 --- a/BlazorBootstrap.Demo/Pages/Charts/BarCharts/Charts_Demo_01_BarChart_Examples.razor +++ b/BlazorBootstrap.Demo/Pages/Charts/BarCharts/Charts_Demo_01_BarChart_Examples.razor @@ -1,81 +1,150 @@ @using BlazorBootstrap.Extensions @using Color = System.Drawing.Color - + - + + + @code { - private BarChart barChart; - - private ChartData chartData; - private BarChartOptions chartOptions; + private BarChart barChart = default!; + private BarChartOptions barChartOptions = default!; + private ChartData chartData = default!; + int datasetsCount = 0; + int labelsCount = 0; + string[] months = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; Random random = new Random(); protected override void OnInitialized() { - chartData = new ChartData - { - Labels = new List { "January", "February", "March", "April", "May", "June", "July" }, - Datasets = new List() - }; - - chartData.Datasets.Add(GetRandomBarChartDataset()); - chartData.Datasets.Add(GetRandomBarChartDataset()); - chartData.Datasets.Add(GetRandomBarChartDataset()); - - chartOptions = new BarChartOptions - { - Responsive = true, - Interaction = new Interaction { Mode = InteractionMode.Index } - }; + chartData = new ChartData { Labels = GetDefaultDataLabels(6), Datasets = GetDefaultDataSets(3) }; + barChartOptions = new BarChartOptions { Responsive = true, Interaction = new Interaction { Mode = InteractionMode.Index } }; } protected override async Task OnAfterRenderAsync(bool firstRender) { if (firstRender) { - await barChart.InitializeAsync(chartData, chartOptions); + await barChart.InitializeAsync(chartData, barChartOptions); } await base.OnAfterRenderAsync(firstRender); } - private async Task AddDataAsync() + private async Task RandomizeAsync() + { + if (chartData is null || chartData.Datasets is null || !chartData.Datasets.Any()) return; + + var newDatasets = new List(); + + foreach (var dataset in chartData.Datasets) + { + if (dataset is BarChartDataset barChartDataset + && barChartDataset is not null + && barChartDataset.Data is not null) + { + var count = barChartDataset.Data.Count; + + var newData = new List(); + for (var i = 0; i < count; i++) + { + newData.Add(random.Next(200)); + } + + barChartDataset.Data = newData; + newDatasets.Add(barChartDataset); + } + } + + chartData.Datasets = newDatasets; + + await barChart.UpdateAsync(chartData, barChartOptions); + } + + private async Task AddDatasetAsync() { if (chartData is null || chartData.Datasets is null) return; + } + + private async Task AddDataAsync() + { + if (chartData is null || chartData.Datasets is null) + return; chartData.Datasets.Add(GetRandomBarChartDataset()); - await barChart.UpdateAsync(chartData, chartOptions); + await barChart.UpdateAsync(chartData, barChartOptions); } private async Task ShowHorizontalBarChartAsync() { - chartOptions.IndexAxis = "y"; - await barChart.UpdateAsync(chartData, chartOptions); + barChartOptions.IndexAxis = "y"; + await barChart.UpdateAsync(chartData, barChartOptions); } private async Task ShowVerticalBarChartAsync() { - chartOptions.IndexAxis = "x"; - await barChart.UpdateAsync(chartData, chartOptions); + barChartOptions.IndexAxis = "x"; + await barChart.UpdateAsync(chartData, barChartOptions); + } + + private List GetDefaultDataSets(int numberOfDatasets) + { + var datasets = new List(); + + for (var index = 0; index < numberOfDatasets; index++) + { + datasets.Add(GetRandomBarChartDataset()); + } + + return datasets; } private BarChartDataset GetRandomBarChartDataset() { + datasetsCount += 1; + // random color var c = Color.FromArgb(random.Next(256), random.Next(256), random.Next(256)); Console.WriteLine($"Bar Chart: Color Name: {c.Name}, HEX: {c.ToHexString()}, RGB: {c.ToRgbString()}, IsNamedColor: {c.IsNamedColor}"); return new BarChartDataset() { - Label = $"Bar chart dataset {chartData.Datasets.Count + 1}", - Data = new List { random.Next(120), random.Next(120), random.Next(120), random.Next(120), random.Next(120), random.Next(120), random.Next(120) }, + Label = $"Product {datasetsCount}", + Data = GetRandomData(), BackgroundColor = new List { c.ToRgbString() }, BorderColor = new List { c.ToRgbString() }, BorderWidth = new List { 0 }, }; } + + private List GetRandomData() + { + var data = new List(); + for (var index = 0; index < labelsCount; index++) + { + data.Add(random.Next(200)); + } + + return data; + } + + private List GetDefaultDataLabels(int numberOfLabels) + { + var labels = new List(); + for (var index = 0; index < numberOfLabels; index++) + { + labels.Add(GetNextDataLabel()); + } + + return labels; + } + + private string GetNextDataLabel() + { + labelsCount += 1; + return months[labelsCount]; + } } diff --git a/BlazorBootstrap.Demo/Pages/Charts/LineCharts/Charts_Demo_01_LineChart_Examples.razor b/BlazorBootstrap.Demo/Pages/Charts/LineCharts/Charts_Demo_01_LineChart_Examples.razor index fa098712d..ae6df3ef6 100644 --- a/BlazorBootstrap.Demo/Pages/Charts/LineCharts/Charts_Demo_01_LineChart_Examples.razor +++ b/BlazorBootstrap.Demo/Pages/Charts/LineCharts/Charts_Demo_01_LineChart_Examples.razor @@ -21,7 +21,7 @@ protected override void OnInitialized() { - chartData = new ChartData { Labels = GetDefaultChartLabels(6), Datasets = GetDefaultDataSets(3) }; + chartData = new ChartData { Labels = GetDefaultDataLabels(6), Datasets = GetDefaultDataSets(3) }; lineChartOptions = new() { Responsive = true, Interaction = new Interaction { Mode = InteractionMode.Index } }; } @@ -144,7 +144,7 @@ return data; } - private List GetDefaultChartLabels(int numberOfLabels) + private List GetDefaultDataLabels(int numberOfLabels) { var labels = new List(); for (var index = 0; index < numberOfLabels; index++) diff --git a/blazorbootstrap/Components/Charts/BarChart.razor.cs b/blazorbootstrap/Components/Charts/BarChart.razor.cs index 3a9f1917d..041a0e94a 100644 --- a/blazorbootstrap/Components/Charts/BarChart.razor.cs +++ b/blazorbootstrap/Components/Charts/BarChart.razor.cs @@ -17,6 +17,108 @@ public BarChart() #region Methods + public override async Task AddDataAsync(ChartData chartData, string dataLabel, string datasetLabel, double data) + { + if (chartData is null) + throw new ArgumentNullException(nameof(chartData)); + + if (chartData.Datasets is null) + throw new ArgumentNullException(nameof(chartData.Datasets)); + + if (datasetLabel is null) + throw new ArgumentNullException(nameof(datasetLabel)); + + if (string.IsNullOrWhiteSpace(datasetLabel)) + throw new Exception($"{nameof(datasetLabel)} cannot be empty."); + + if (dataLabel is null) + throw new ArgumentNullException(nameof(datasetLabel)); + + if (string.IsNullOrWhiteSpace(dataLabel)) + throw new Exception($"{nameof(dataLabel)} cannot be empty."); + + foreach (var dataset in chartData.Datasets) + { + if (dataset is LineChartDataset lineChartDataset && lineChartDataset.Label == dataLabel) + { + lineChartDataset.Data?.Add(data); + } + } + + await JS.InvokeVoidAsync("window.blazorChart.bar.addDatasetData", ElementId, dataLabel, datasetLabel, data); + + return chartData; + } + + public override async Task AddDataAsync(ChartData chartData, string dataLabel, List data) + { + if (chartData is null) + throw new ArgumentNullException(nameof(chartData)); + + if (chartData.Datasets is null) + throw new ArgumentNullException(nameof(chartData.Datasets)); + + if (chartData.Labels is null) + throw new ArgumentNullException(nameof(chartData.Labels)); + + if (dataLabel is null) + throw new ArgumentNullException(nameof(dataLabel)); + + if (string.IsNullOrWhiteSpace(dataLabel)) + throw new Exception($"{nameof(dataLabel)} cannot be empty."); + + if (data is null) + throw new ArgumentNullException(nameof(data)); + + if (!data.Any()) + throw new Exception($"{nameof(data)} cannot be empty."); + + if (chartData.Datasets.Count != data.Count) + throw new InvalidDataException("The chart dataset count and the new data points count do not match."); + + if (chartData.Labels.Contains(dataLabel)) + throw new Exception($"{dataLabel} already exists."); + + chartData.Labels.Add(dataLabel); + + foreach (var dataset in chartData.Datasets) + { + if (dataset is LineChartDataset lineChartDataset) + { + var chartDatasetData = data.FirstOrDefault(x => x.DatasetLabel == lineChartDataset.Label); + if (chartDatasetData is null) + continue; + + lineChartDataset.Data?.Add(chartDatasetData.Data); + } + } + + await JS.InvokeVoidAsync("window.blazorChart.bar.addDatasetsData", ElementId, dataLabel, data); + + return chartData; + } + + public override async Task AddDatasetAsync(ChartData chartData, IChartDataset chartDataset, IChartOptions chartOptions) + { + if (chartData is null) + throw new ArgumentNullException(nameof(chartData)); + + if (chartData.Datasets is null) + throw new ArgumentNullException(nameof(chartData.Datasets)); + + if (chartDataset is null) + throw new ArgumentNullException(nameof(chartDataset)); + + if (chartDataset is LineChartDataset) + { + chartData.Datasets.Add(chartDataset); + await JS.InvokeVoidAsync("window.blazorChart.bar.addDataset", ElementId, (LineChartDataset)chartDataset); + } + + return chartData; + } + + public override async Task InitializeAsync(ChartData chartData, IChartOptions chartOptions) { if (chartData is not null && chartData.Datasets is not null) diff --git a/blazorbootstrap/Components/Charts/LineChart.razor.cs b/blazorbootstrap/Components/Charts/LineChart.razor.cs index 27e47f6be..5ce5cbe90 100644 --- a/blazorbootstrap/Components/Charts/LineChart.razor.cs +++ b/blazorbootstrap/Components/Charts/LineChart.razor.cs @@ -1,6 +1,4 @@ -using System.Reflection.Emit; - -namespace BlazorBootstrap; +namespace BlazorBootstrap; public partial class LineChart : BaseChart { diff --git a/blazorbootstrap/wwwroot/blazor.bootstrap.js b/blazorbootstrap/wwwroot/blazor.bootstrap.js index 8120d552f..1dccbc146 100644 --- a/blazorbootstrap/wwwroot/blazor.bootstrap.js +++ b/blazorbootstrap/wwwroot/blazor.bootstrap.js @@ -582,6 +582,50 @@ window.blazorChart = { } window.blazorChart.bar = { + addDatasetData: (elementId, dataLabel, datasetLabel, data) => { + let chart = window.blazorChart.get(elementId); + if (chart) { + const chartData = chart.data; + + if (!chartData.labels.includes(dataLabel)) + chartData.labels.push(dataLabel); + + const chartDatasets = chartData.datasets; + + if (chartDatasets.length > 0) { + let datasetIndex = chartDatasets.findIndex(dataset => dataset.label === datasetLabel); + if (datasetIndex > -1) { + chartDatasets[datasetIndex].data.push(data); + chart.update(); + } + } + } + }, + addDatasetsData: (elementId, dataLabel, data) => { + let chart = window.blazorChart.get(elementId); + if (chart && data) { + const chartData = chart.data; + + if (!chartData.labels.includes(dataLabel)) { + chartData.labels.push(dataLabel); + + if (chartData.datasets.length > 0 && chartData.datasets.length === data.length) { + data.forEach(chartDatasetData => { + let datasetIndex = chartData.datasets.findIndex(dataset => dataset.label === chartDatasetData.datasetLabel); + chartData.datasets[datasetIndex].data.push(chartDatasetData.data); + }); + chart.update(); + } + } + } + }, + addDataset: (elementId, newDataset) => { + let chart = window.blazorChart.get(elementId); + if (chart) { + chart.data.datasets.push(newDataset); + chart.update(); + } + }, create: (elementId, type, data, options) => { let chartEl = document.getElementById(elementId);