diff --git a/BlazorBootstrap.Demo.RCL/Components/Pages/Charts/LineCharts/LineChart_Demo_01_A_Examples.razor b/BlazorBootstrap.Demo.RCL/Components/Pages/Charts/LineCharts/LineChart_Demo_01_A_Examples.razor index 6d1ab9b6d..d648c7e52 100644 --- a/BlazorBootstrap.Demo.RCL/Components/Pages/Charts/LineCharts/LineChart_Demo_01_A_Examples.razor +++ b/BlazorBootstrap.Demo.RCL/Components/Pages/Charts/LineCharts/LineChart_Demo_01_A_Examples.razor @@ -1,11 +1,13 @@ - +
+ +
- - - - - + + + + +
@code { @@ -22,6 +24,7 @@ { chartData = new ChartData { Labels = GetDefaultDataLabels(6), Datasets = GetDefaultDataSets(3) }; lineChartOptions = new() { Responsive = true, Interaction = new Interaction { Mode = InteractionMode.Index } }; + lineChartOptions.Scales.Y!.Max = 250; } protected override async Task OnAfterRenderAsync(bool firstRender) @@ -60,7 +63,7 @@ chartData.Datasets = newDatasets; - await lineChart.UpdateAsync(chartData, lineChartOptions); + await lineChart.UpdateValuesAsync(chartData); } private async Task AddDatasetAsync() diff --git a/BlazorBootstrap.Demo.RCL/Components/Pages/Charts/LineCharts/LineChart_Demo_01_B_Examples.razor b/BlazorBootstrap.Demo.RCL/Components/Pages/Charts/LineCharts/LineChart_Demo_01_B_Examples.razor index c625740f5..ede26b2dc 100644 --- a/BlazorBootstrap.Demo.RCL/Components/Pages/Charts/LineCharts/LineChart_Demo_01_B_Examples.razor +++ b/BlazorBootstrap.Demo.RCL/Components/Pages/Charts/LineCharts/LineChart_Demo_01_B_Examples.razor @@ -1,4 +1,6 @@ - +
+ +
@code { private LineChart lineChart = default!; diff --git a/BlazorBootstrap.Demo.RCL/Components/Pages/Charts/LineCharts/LineChart_Demo_02_Locale.razor b/BlazorBootstrap.Demo.RCL/Components/Pages/Charts/LineCharts/LineChart_Demo_02_Locale.razor index 88842fcdb..b7f880816 100644 --- a/BlazorBootstrap.Demo.RCL/Components/Pages/Charts/LineCharts/LineChart_Demo_02_Locale.razor +++ b/BlazorBootstrap.Demo.RCL/Components/Pages/Charts/LineCharts/LineChart_Demo_02_Locale.razor @@ -1,4 +1,6 @@ - +
+ +
@code { private LineChart lineChart = default!; diff --git a/BlazorBootstrap.Demo.RCL/Components/Pages/Charts/LineCharts/LineChart_Demo_03_Dynamically_add_data.razor b/BlazorBootstrap.Demo.RCL/Components/Pages/Charts/LineCharts/LineChart_Demo_03_Dynamically_add_data.razor index 82b01ca52..6d0bdb41f 100644 --- a/BlazorBootstrap.Demo.RCL/Components/Pages/Charts/LineCharts/LineChart_Demo_03_Dynamically_add_data.razor +++ b/BlazorBootstrap.Demo.RCL/Components/Pages/Charts/LineCharts/LineChart_Demo_03_Dynamically_add_data.razor @@ -1,4 +1,6 @@ - +
+ +
diff --git a/BlazorBootstrap.Demo.RCL/Components/Pages/Charts/LineCharts/LineChart_Demo_04_Datalabels.razor b/BlazorBootstrap.Demo.RCL/Components/Pages/Charts/LineCharts/LineChart_Demo_04_Datalabels.razor index de3e27d6f..90f429671 100644 --- a/BlazorBootstrap.Demo.RCL/Components/Pages/Charts/LineCharts/LineChart_Demo_04_Datalabels.razor +++ b/BlazorBootstrap.Demo.RCL/Components/Pages/Charts/LineCharts/LineChart_Demo_04_Datalabels.razor @@ -1,4 +1,6 @@ - +
+ +
@code { private LineChart lineChart = default!; diff --git a/BlazorBootstrap.Demo.RCL/Components/Pages/Charts/LineCharts/LineChart_Demo_05_Tick_Configuration.razor b/BlazorBootstrap.Demo.RCL/Components/Pages/Charts/LineCharts/LineChart_Demo_05_Tick_Configuration.razor index 6aac80f71..9b47f9c5c 100644 --- a/BlazorBootstrap.Demo.RCL/Components/Pages/Charts/LineCharts/LineChart_Demo_05_Tick_Configuration.razor +++ b/BlazorBootstrap.Demo.RCL/Components/Pages/Charts/LineCharts/LineChart_Demo_05_Tick_Configuration.razor @@ -1,4 +1,6 @@ - +
+ +
diff --git a/blazorbootstrap/Components/Charts/BlazorBootstrapChart.cs b/blazorbootstrap/Components/Charts/BlazorBootstrapChart.cs index d44b96f39..0bfa8781d 100644 --- a/blazorbootstrap/Components/Charts/BlazorBootstrapChart.cs +++ b/blazorbootstrap/Components/Charts/BlazorBootstrapChart.cs @@ -74,7 +74,8 @@ public async Task ResizeAsync(int width, int height, Unit widthUnit = Unit.Px, U } /// - /// Update chart. + /// Update chart by reapplying all chart data and options. + /// If animation is enabled, this will animate the datasets from scratch. /// /// /// @@ -82,14 +83,34 @@ public virtual async Task UpdateAsync(ChartData chartData, IChartOptions chartOp { if (chartData is not null && chartData.Datasets is not null && chartData.Datasets.Any()) { - var _data = GetChartDataObject(chartData); + var data = GetChartDataObject(chartData); + + if (chartType == ChartType.Bar) + await JSRuntime.InvokeVoidAsync("window.blazorChart.bar.update", Id, GetChartType(), data, (BarChartOptions)chartOptions); + else if (chartType == ChartType.Line) + await JSRuntime.InvokeVoidAsync("window.blazorChart.line.update", Id, GetChartType(), data, (LineChartOptions)chartOptions); + else + await JSRuntime.InvokeVoidAsync("window.blazorChart.update", Id, GetChartType(), data, chartOptions); + } + } + + /// + /// Update only data labels and values. If animation is enabled, this will animate the datapoints. + /// Changes to the options will not be applied. + /// + /// The updated chart data. Only dataset labels and values will be applied. + public virtual async Task UpdateValuesAsync(ChartData chartData) + { + if (chartData is not null && chartData.Datasets is not null && chartData.Datasets.Any()) + { + var data = GetChartDataObject(chartData); if (chartType == ChartType.Bar) - await JSRuntime.InvokeVoidAsync("window.blazorChart.bar.update", Id, GetChartType(), _data, (BarChartOptions)chartOptions); + await JSRuntime.InvokeVoidAsync("window.blazorChart.bar.updateDataValues", Id, data); else if (chartType == ChartType.Line) - await JSRuntime.InvokeVoidAsync("window.blazorChart.line.update", Id, GetChartType(), _data, (LineChartOptions)chartOptions); + await JSRuntime.InvokeVoidAsync("window.blazorChart.line.updateDataValues", Id, data); else - await JSRuntime.InvokeVoidAsync("window.blazorChart.update", Id, GetChartType(), _data, chartOptions); + await JSRuntime.InvokeVoidAsync("window.blazorChart.updateDataValues", Id, data); } } diff --git a/blazorbootstrap/wwwroot/blazor.bootstrap.js b/blazorbootstrap/wwwroot/blazor.bootstrap.js index 533fbf83b..4948598a6 100644 --- a/blazorbootstrap/wwwroot/blazor.bootstrap.js +++ b/blazorbootstrap/wwwroot/blazor.bootstrap.js @@ -845,6 +845,23 @@ window.blazorChart = { console.warn(`The chart is not initialized. Initialize it and then call update.`); } }, + updateDataValues: (elementId, data) => { + let chart = window.blazorChart.line.get(elementId); + if (chart) { + chart.data.datasets.splice(data.datasets.length); + + for (var datasetIndex = 0; datasetIndex < chart.data.datasets.length; ++datasetIndex) { + chart.data.datasets[datasetIndex].data = data.datasets[datasetIndex].data; + chart.data.labels = data.labels; + } + + for (var datasetIndex = chart.data.datasets.length; datasetIndex < data.datasets.length; ++datasetIndex) { + chart.data.datasets.push(data.datasets[datasetIndex]); + } + + chart.update(); + } + } } window.blazorChart.bar = { @@ -957,6 +974,23 @@ window.blazorChart.bar = { console.warn(`The chart is not initialized. Initialize it and then call update.`); } }, + updateDataValues: (elementId, data) => { + let chart = window.blazorChart.line.get(elementId); + if (chart) { + chart.data.datasets.splice(data.datasets.length); + + for (var datasetIndex = 0; datasetIndex < chart.data.datasets.length; ++datasetIndex) { + chart.data.datasets[datasetIndex].data = data.datasets[datasetIndex].data; + chart.data.labels = data.labels; + } + + for (var datasetIndex = chart.data.datasets.length; datasetIndex < data.datasets.length; ++datasetIndex) { + chart.data.datasets.push(data.datasets[datasetIndex]); + } + + chart.update(); + } + } } window.blazorChart.doughnut = { @@ -1075,6 +1109,23 @@ window.blazorChart.doughnut = { console.warn(`The chart is not initialized. Initialize it and then call update.`); } }, + updateDataValues: (elementId, data) => { + let chart = window.blazorChart.line.get(elementId); + if (chart) { + chart.data.datasets.splice(data.datasets.length); + + for (var datasetIndex = 0; datasetIndex < chart.data.datasets.length; ++datasetIndex) { + chart.data.datasets[datasetIndex].data = data.datasets[datasetIndex].data; + chart.data.labels = data.labels; + } + + for (var datasetIndex = chart.data.datasets.length; datasetIndex < data.datasets.length; ++datasetIndex) { + chart.data.datasets.push(data.datasets[datasetIndex]); + } + + chart.update(); + } + } } window.blazorChart.line = { @@ -1227,6 +1278,23 @@ window.blazorChart.line = { console.warn(`The chart is not initialized. Initialize it and then call update.`); } }, + updateDataValues: (elementId, data) => { + let chart = window.blazorChart.line.get(elementId); + if (chart) { + chart.data.datasets.splice(data.datasets.length); + + for (var datasetIndex = 0; datasetIndex < chart.data.datasets.length; ++datasetIndex) { + chart.data.datasets[datasetIndex].data = data.datasets[datasetIndex].data; + chart.data.labels = data.labels; + } + + for (var datasetIndex = chart.data.datasets.length; datasetIndex < data.datasets.length; ++datasetIndex) { + chart.data.datasets.push(data.datasets[datasetIndex]); + } + + chart.update(); + } + } } window.blazorChart.pie = { @@ -1345,6 +1413,23 @@ window.blazorChart.pie = { console.warn(`The chart is not initialized. Initialize it and then call update.`); } }, + updateDataValues: (elementId, data) => { + let chart = window.blazorChart.line.get(elementId); + if (chart) { + chart.data.datasets.splice(data.datasets.length); + + for (var datasetIndex = 0; datasetIndex < chart.data.datasets.length; ++datasetIndex) { + chart.data.datasets[datasetIndex].data = data.datasets[datasetIndex].data; + chart.data.labels = data.labels; + } + + for (var datasetIndex = chart.data.datasets.length; datasetIndex < data.datasets.length; ++datasetIndex) { + chart.data.datasets.push(data.datasets[datasetIndex]); + } + + chart.update(); + } + } } window.blazorChart.polarArea = { @@ -1464,6 +1549,23 @@ window.blazorChart.polarArea = { console.warn(`The chart is not initialized. Initialize it and then call update.`); } }, + updateDataValues: (elementId, data) => { + let chart = window.blazorChart.line.get(elementId); + if (chart) { + chart.data.datasets.splice(data.datasets.length); + + for (var datasetIndex = 0; datasetIndex < chart.data.datasets.length; ++datasetIndex) { + chart.data.datasets[datasetIndex].data = data.datasets[datasetIndex].data; + chart.data.labels = data.labels; + } + + for (var datasetIndex = chart.data.datasets.length; datasetIndex < data.datasets.length; ++datasetIndex) { + chart.data.datasets.push(data.datasets[datasetIndex]); + } + + chart.update(); + } + } } window.blazorChart.radar = { @@ -1582,6 +1684,23 @@ window.blazorChart.radar = { console.warn(`The chart is not initialized. Initialize it and then call update.`); } }, + updateDataValues: (elementId, data) => { + let chart = window.blazorChart.line.get(elementId); + if (chart) { + chart.data.datasets.splice(data.datasets.length); + + for (var datasetIndex = 0; datasetIndex < chart.data.datasets.length; ++datasetIndex) { + chart.data.datasets[datasetIndex].data = data.datasets[datasetIndex].data; + chart.data.labels = data.labels; + } + + for (var datasetIndex = chart.data.datasets.length; datasetIndex < data.datasets.length; ++datasetIndex) { + chart.data.datasets.push(data.datasets[datasetIndex]); + } + + chart.update(); + } + } } window.blazorChart.scatter = { @@ -1700,4 +1819,21 @@ window.blazorChart.scatter = { console.warn(`The chart is not initialized. Initialize it and then call update.`); } }, + updateDataValues: (elementId, data) => { + let chart = window.blazorChart.line.get(elementId); + if (chart) { + chart.data.datasets.splice(data.datasets.length); + + for (var datasetIndex = 0; datasetIndex < chart.data.datasets.length; ++datasetIndex) { + chart.data.datasets[datasetIndex].data = data.datasets[datasetIndex].data; + chart.data.labels = data.labels; + } + + for (var datasetIndex = chart.data.datasets.length; datasetIndex < data.datasets.length; ++datasetIndex) { + chart.data.datasets.push(data.datasets[datasetIndex]); + } + + chart.update(); + } + } } diff --git a/docs/docs/06-data-visualization/line-chart.mdx b/docs/docs/06-data-visualization/line-chart.mdx index f07277740..6cc5e71e6 100644 --- a/docs/docs/06-data-visualization/line-chart.mdx +++ b/docs/docs/06-data-visualization/line-chart.mdx @@ -35,7 +35,8 @@ A Blazor Bootstrap line chart component is a graphical representation of data th | AddDatasetAsync(ChartData chartData, IChartDataset chartDataset, IChartOptions chartOptions) | `Task` | Adds dataset to chart. | 1.10.0 || InitializeAsync | Task | Initialize Bar Chart. | 1.0.0 | | InitializeAsync(ChartData chartData, IChartOptions chartOptions, `string[]?` plugins = null) | Task | Initialize the chat. | 1.0.0 | | ResizeAsync(int width, int height, Unit widthUnit = Unit.Px, Unit heightUnit = Unit.Px) | Task | Resize the chart. | 1.0.0 | -| UpdateAsync(ChartData chartData, IChartOptions chartOptions) | Task | Update the chart. | 1.0.0 | +| UpdateAsync(ChartData chartData, IChartOptions chartOptions) | Task | Update chart by reapplying all chart data and options. If animation is enabled, this will animate the datasets from scratch. | 1.0.0 | +| UpdateValuesAsync(ChartData chartData) | Task | Update only data labels and values. If animation is enabled, this will animate the datapoints. Changes to the options will not be applied. | 3.0.0 | ## ChartData Members @@ -141,16 +142,17 @@ These palettes offer a range of distinct and visually appealing colors that can Blazor Bootstrap: Line Chart Component - How it works ```cshtml {} showLineNumbers -@using BlazorBootstrap.Extensions -@using Color = System.Drawing.Color - - - - - - - - +
+ +
+ +
+ + + + + +
``` ```cs {} showLineNumbers @@ -159,8 +161,8 @@ These palettes offer a range of distinct and visually appealing colors that can private LineChartOptions lineChartOptions = default!; private ChartData chartData = default!; - private int datasetsCount = 0; - private int labelsCount = 0; + private int datasetsCount; + private int labelsCount; private Random random = new(); @@ -168,6 +170,7 @@ These palettes offer a range of distinct and visually appealing colors that can { chartData = new ChartData { Labels = GetDefaultDataLabels(6), Datasets = GetDefaultDataSets(3) }; lineChartOptions = new() { Responsive = true, Interaction = new Interaction { Mode = InteractionMode.Index } }; + lineChartOptions.Scales.Y!.Max = 250; } protected override async Task OnAfterRenderAsync(bool firstRender) @@ -193,7 +196,7 @@ These palettes offer a range of distinct and visually appealing colors that can { var count = lineChartDataset.Data.Count; - var newData = new List(); + var newData = new List(); for (var i = 0; i < count; i++) { newData.Add(random.Next(200)); @@ -206,7 +209,7 @@ These palettes offer a range of distinct and visually appealing colors that can chartData.Datasets = newDatasets; - await lineChart.UpdateAsync(chartData, lineChartOptions); + await lineChart.UpdateValuesAsync(chartData); } private async Task AddDatasetAsync() @@ -260,27 +263,27 @@ These palettes offer a range of distinct and visually appealing colors that can private LineChartDataset GetRandomLineChartDataset() { - var c = ColorBuilder.CategoricalTwelveColors[datasetsCount].ToColor(); + var c = ColorUtility.CategoricalTwelveColors[datasetsCount].ToColor(); datasetsCount += 1; - return new LineChartDataset() + return new LineChartDataset { Label = $"Team {datasetsCount}", Data = GetRandomData(), - BackgroundColor = new List { c.ToRgbString() }, - BorderColor = new List { c.ToRgbString() }, - BorderWidth = new List { 2 }, - HoverBorderWidth = new List { 4 }, - PointBackgroundColor = new List { c.ToRgbString() }, - PointRadius = new List { 0 }, // hide points - PointHoverRadius = new List { 4 }, + BackgroundColor = c.ToRgbString(), + BorderColor = c.ToRgbString(), + BorderWidth = 2, + HoverBorderWidth = 4, + // PointBackgroundColor = c.ToRgbString(), + // PointRadius = 0, // hide points + // PointHoverRadius = 4, }; } - private List GetRandomData() + private List GetRandomData() { - var data = new List(); + var data = new List(); for (var index = 0; index < labelsCount; index++) { data.Add(random.Next(200)); @@ -307,6 +310,7 @@ These palettes offer a range of distinct and visually appealing colors that can } #endregion Data Preparation + } ```