diff --git a/CHANGELOG.md b/CHANGELOG.md index ea5f69a..42b4075 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ * Edit Bucket Dialog shows now a calculated next applying target date for Bucket type `Expense every X Months` and `Save X until Y date` [#201](https://github.com/TheAxelander/OpenBudgeteer/issues/201) * File content preview on Import Page no longer wraps, instead it uses horizontal scrolling [#227](https://github.com/TheAxelander/OpenBudgeteer/issues/227) +* Migrated reports from ChartJs.Blazor to Blazor-ApexCharts ## 1.8.3 (2024-05-20) diff --git a/LICENSE-3RD-PARTY b/LICENSE-3RD-PARTY index 727a6aa..80b86f9 100644 --- a/LICENSE-3RD-PARTY +++ b/LICENSE-3RD-PARTY @@ -3,7 +3,7 @@ applies to: - aspnet-api-versioning, Copyright (c) .NET Foundation and contributors - BlazorFileReader, Copyright (c) 2018 Tor - - ChartJs.Blazor, Copyright (c) 2019 Marius Muntean + - Blazor-ApexCharts, Copyright (c) 2020 Joakim Dangården - efcore, Copyright (c) .NET Foundation and Contributors - Pomelo.EntityFrameworkCore.MySql, Copyright (c) 2017 Pomelo Foundation - Swashbuckle.AspNetCore, Copyright (c) 2016 Richard Morris diff --git a/OpenBudgeteer.Blazor/Common/ApexHelper.cs b/OpenBudgeteer.Blazor/Common/ApexHelper.cs new file mode 100644 index 0000000..0db15c0 --- /dev/null +++ b/OpenBudgeteer.Blazor/Common/ApexHelper.cs @@ -0,0 +1,13 @@ +using ApexCharts; + +namespace OpenBudgeteer.Blazor.Common; + +public class ApexHelper +{ + public static void BalanceChartMutator(DataPoint point) + { + point.FillColor = point.Y > 0 + ? System.Drawing.Color.Green.ToHexString() + : System.Drawing.Color.DarkRed.ToHexString(); + } +} \ No newline at end of file diff --git a/OpenBudgeteer.Blazor/Common/ColorExtensions.cs b/OpenBudgeteer.Blazor/Common/ColorExtensions.cs new file mode 100644 index 0000000..3b6f706 --- /dev/null +++ b/OpenBudgeteer.Blazor/Common/ColorExtensions.cs @@ -0,0 +1,11 @@ +using System.Drawing; + +namespace OpenBudgeteer.Blazor.Common; + +public static class ColorExtensions +{ + public static string ToHexString(this Color color) + { + return $"#{color.R:X2}{color.G:X2}{color.B:X2}"; + } +} \ No newline at end of file diff --git a/OpenBudgeteer.Blazor/Common/ReportRecord.cs b/OpenBudgeteer.Blazor/Common/ReportRecord.cs new file mode 100644 index 0000000..a74a09d --- /dev/null +++ b/OpenBudgeteer.Blazor/Common/ReportRecord.cs @@ -0,0 +1,5 @@ +using System; + +namespace OpenBudgeteer.Blazor.Common; + +public record ReportRecord(string Label, decimal Value); diff --git a/OpenBudgeteer.Blazor/OpenBudgeteer.Blazor.csproj b/OpenBudgeteer.Blazor/OpenBudgeteer.Blazor.csproj index 8f6c401..351824a 100644 --- a/OpenBudgeteer.Blazor/OpenBudgeteer.Blazor.csproj +++ b/OpenBudgeteer.Blazor/OpenBudgeteer.Blazor.csproj @@ -10,7 +10,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/OpenBudgeteer.Blazor/Pages/Report.razor b/OpenBudgeteer.Blazor/Pages/Report.razor index a721882..1a940e3 100644 --- a/OpenBudgeteer.Blazor/Pages/Report.razor +++ b/OpenBudgeteer.Blazor/Pages/Report.razor @@ -1,17 +1,37 @@ @page "/report" -@using ChartJs.Blazor.Charts +@using ApexCharts +@using OpenBudgeteer.Blazor.Common +

Month Balances

- + + +

Bank Balances

- + + +
@@ -19,13 +39,47 @@

Income & Expenses per Month

- + + + +

Income & Expenses per Year

- + + + +
@@ -33,24 +87,36 @@

Bucket Monthly Expenses

- @foreach (var config in _monthBucketExpensesConfigsLeft) + @foreach (var chart in _monthBucketExpensesConfigsLeft) { -
@config.Item1
-
- -
+ + + }

Bucket Monthly Expenses

- @foreach (var config in _monthBucketExpensesConfigsRight) + @foreach (var chart in _monthBucketExpensesConfigsRight) { -
@config.Item1
-
- -
+ + + }
diff --git a/OpenBudgeteer.Blazor/Pages/Report.razor.cs b/OpenBudgeteer.Blazor/Pages/Report.razor.cs index 42049f0..6070010 100644 --- a/OpenBudgeteer.Blazor/Pages/Report.razor.cs +++ b/OpenBudgeteer.Blazor/Pages/Report.razor.cs @@ -2,8 +2,9 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; -using ChartJs.Blazor.ChartJS.BarChart; +using ApexCharts; using Microsoft.AspNetCore.Components; +using OpenBudgeteer.Blazor.Common; using OpenBudgeteer.Blazor.ViewModels; using OpenBudgeteer.Core.Data.Contracts.Services; @@ -12,21 +13,54 @@ namespace OpenBudgeteer.Blazor.Pages; public partial class Report : ComponentBase { [Inject] private IServiceManager ServiceManager { get; set; } = null!; - - private BlazorReportPageViewModel _dataContext = null!; - private List> _monthBucketExpensesConfigsLeft = null!; - private List> _monthBucketExpensesConfigsRight = null!; + + private ApexChart MonthBalanceChart; + private ApexChart BankBalanceChart; + private ApexChart MonthIncomeExpensesChart; + private ApexChart YearIncomeExpensesChart; + private List> MonthBucketExpensesCharts = new(); + private ApexChart InjectMonthBucketExpensesChart + { + set => MonthBucketExpensesCharts.Add(value); + } + + private ApexChartOptions MonthIncomeExpensesChartOptions = new() + { + Legend = new() { Show = false } + }; + private ApexChartOptions YearIncomeExpensesChartOptions = new() + { + Legend = new() { Show = false } + }; + + private ApexReportViewModel _apexContext = null!; + private List>> _monthBucketExpensesConfigsLeft = null!; + private List>> _monthBucketExpensesConfigsRight = null!; protected override async Task OnInitializedAsync() { - _monthBucketExpensesConfigsLeft = new List>(); - _monthBucketExpensesConfigsRight = new List>(); - - _dataContext = new BlazorReportPageViewModel(ServiceManager); - await _dataContext.LoadDataAsync(); + _monthBucketExpensesConfigsLeft = new List>>(); + _monthBucketExpensesConfigsRight = new List>>(); + MonthBucketExpensesCharts = new(); + + _apexContext = new ApexReportViewModel(ServiceManager); + await _apexContext.LoadDataAsync(); + + var halfIndex = _apexContext.MonthBucketExpenses.Count / 2; + _monthBucketExpensesConfigsLeft.AddRange(_apexContext.MonthBucketExpenses.GetRange(0,halfIndex)); + _monthBucketExpensesConfigsRight.AddRange(_apexContext.MonthBucketExpenses.GetRange(halfIndex,_apexContext.MonthBucketExpenses.Count - halfIndex)); + + StateHasChanged(); + var tasks = new List() + { + MonthBalanceChart.UpdateSeriesAsync(true), + BankBalanceChart.UpdateSeriesAsync(true), + MonthIncomeExpensesChart.UpdateSeriesAsync(true), + YearIncomeExpensesChart.UpdateSeriesAsync(true) + }; + tasks.AddRange(MonthBucketExpensesCharts + .Select(monthBucketExpensesChart => monthBucketExpensesChart.UpdateSeriesAsync())); - var halfIndex = _dataContext.MonthBucketExpensesConfigs.Count / 2; - _monthBucketExpensesConfigsLeft.AddRange(_dataContext.MonthBucketExpensesConfigs.ToList().GetRange(0,halfIndex)); - _monthBucketExpensesConfigsRight.AddRange(_dataContext.MonthBucketExpensesConfigs.ToList().GetRange(halfIndex,_dataContext.MonthBucketExpensesConfigs.Count - halfIndex)); + await Task.WhenAll(tasks); } } \ No newline at end of file diff --git a/OpenBudgeteer.Blazor/Shared/BucketDetailsDialog.razor b/OpenBudgeteer.Blazor/Shared/BucketDetailsDialog.razor index dce5878..f5cbdd5 100644 --- a/OpenBudgeteer.Blazor/Shared/BucketDetailsDialog.razor +++ b/OpenBudgeteer.Blazor/Shared/BucketDetailsDialog.razor @@ -1,6 +1,5 @@ -@using ChartJs.Blazor -@using ChartJs.Blazor.ChartJS.BarChart -@using ChartJs.Blazor.Charts +@using ApexCharts +@using OpenBudgeteer.Blazor.Common @using OpenBudgeteer.Blazor.ViewModels @using System.Globalization @@ -61,13 +60,39 @@

Month Balances

- + + +

Input & Output

- + + + +
@@ -75,7 +100,16 @@

Balance Progression

- + + +
@@ -107,12 +141,33 @@ [Parameter] public EventCallback OnClickCallback { get; set; } + + private ApexChart MonthBalanceChart; + private ApexChart MonthInputOutputChart; + private ApexChart BucketProgressionChart; + + private ApexChartOptions MonthInputOutputChartOptions = new() + { + Legend = new() { Show = false } + }; + + private ApexChartOptions BucketProgressionChartOptions = new() + { + Yaxis = [ new YAxis() { Min = 0 } ] + }; private async void HideBucketMovementCheckboxClicked(ChangeEventArgs? eventArgs) { if (eventArgs?.Value == null) return; await DataContext.LoadBucketMovementsDataAsync((bool)eventArgs.Value); StateHasChanged(); + var tasks = new List() + { + MonthBalanceChart.UpdateSeriesAsync(true), + MonthInputOutputChart.UpdateSeriesAsync(true), + BucketProgressionChart.UpdateSeriesAsync(true), + }; + + await Task.WhenAll(tasks); } - } diff --git a/OpenBudgeteer.Blazor/Shared/MainLayout.razor b/OpenBudgeteer.Blazor/Shared/MainLayout.razor index d0b44d2..36b0fba 100644 --- a/OpenBudgeteer.Blazor/Shared/MainLayout.razor +++ b/OpenBudgeteer.Blazor/Shared/MainLayout.razor @@ -16,7 +16,7 @@ OpenBudgeteer Database: @CurrentDatabase - Version: 1.9 (Change Log) + Version: 1.9.0 (Change Log)
diff --git a/OpenBudgeteer.Blazor/ViewModels/ApexReportViewModel.cs b/OpenBudgeteer.Blazor/ViewModels/ApexReportViewModel.cs new file mode 100644 index 0000000..4f853f8 --- /dev/null +++ b/OpenBudgeteer.Blazor/ViewModels/ApexReportViewModel.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Threading.Tasks; +using OpenBudgeteer.Blazor.Common; +using OpenBudgeteer.Core.Data.Contracts.Services; +using OpenBudgeteer.Core.ViewModels.PageViewModels; + +namespace OpenBudgeteer.Blazor.ViewModels; + +public class ApexReportViewModel : ReportPageViewModel +{ + public List MonthBalances { get; private set; } = new(); + public List BankBalances { get; private set; } = new(); + public List MonthIncome { get; private set; } = new(); + public List MonthExpenses { get; private set; } = new(); + public List YearIncome { get; private set; } = new(); + public List YearExpenses { get; private set; } = new(); + public List>> MonthBucketExpenses { get; private set; } = new(); + + public ApexReportViewModel(IServiceManager serviceManager) : base(serviceManager) + { + } + + public async Task LoadDataAsync() + { + var loadTasks = new List() + { + LoadMonthBalancesReportAsync(), + LoadBankBalancesReportAsync(), + LoadMonthIncomeExpensesReportAsync(), + LoadYearIncomeExpensesReportAsync(), + LoadMonthExpensesBucketReportAsync() + }; + await Task.WhenAll(loadTasks); + } + + private async Task LoadMonthBalancesReportAsync() + { + MonthBalances.Clear(); + foreach (var (month, balance) in await LoadMonthBalancesAsync()) + { + MonthBalances.Add(new ReportRecord(month.ToString("yyyy-MM"), balance)); + } + } + + private async Task LoadBankBalancesReportAsync() + { + BankBalances.Clear(); + foreach (var (month, balance) in await LoadBankBalancesAsync()) + { + BankBalances.Add(new ReportRecord(month.ToString("yyyy-MM"), balance)); + } + } + + private async Task LoadMonthIncomeExpensesReportAsync() + { + MonthIncome.Clear(); + MonthExpenses.Clear(); + foreach (var (month, income, expenses) in await LoadMonthIncomeExpensesAsync()) + { + MonthIncome.Add(new ReportRecord(month.ToString("yyyy-MM"), income)); + MonthExpenses.Add(new ReportRecord(month.ToString("yyyy-MM"), expenses)); + } + } + + private async Task LoadYearIncomeExpensesReportAsync() + { + YearIncome.Clear(); + YearExpenses.Clear(); + foreach (var (year, income, expenses) in await LoadYearIncomeExpensesAsync()) + { + YearIncome.Add(new ReportRecord(year.ToString("yyyy"), income)); + YearExpenses.Add(new ReportRecord(year.ToString("yyyy"), expenses)); + } + } + + private async Task LoadMonthExpensesBucketReportAsync() + { + MonthBucketExpenses.Clear(); + foreach (var item in await LoadMonthExpensesBucketAsync()) + { + var data = item.MonthlyResults + .Select(i => new ReportRecord(i.Item1.ToString("yyyy-MM"), i.Item2)) + .ToList(); + MonthBucketExpenses.Add(new(item.BucketName, data)); + } + } +} \ No newline at end of file diff --git a/OpenBudgeteer.Blazor/ViewModels/BlazorBucketStatisticsViewModel.cs b/OpenBudgeteer.Blazor/ViewModels/BlazorBucketStatisticsViewModel.cs index 9523d9a..418d1d0 100644 --- a/OpenBudgeteer.Blazor/ViewModels/BlazorBucketStatisticsViewModel.cs +++ b/OpenBudgeteer.Blazor/ViewModels/BlazorBucketStatisticsViewModel.cs @@ -1,118 +1,23 @@ -using ChartJs.Blazor.ChartJS.BarChart; -using ChartJs.Blazor.ChartJS.Common.Axes; -using ChartJs.Blazor.ChartJS.Common.Axes.Ticks; -using ChartJs.Blazor.ChartJS.Common.Enums; -using ChartJs.Blazor.ChartJS.Common.Handlers; -using ChartJs.Blazor.ChartJS.Common.Properties; -using ChartJs.Blazor.ChartJS.Common.Time; -using ChartJs.Blazor.ChartJS.LineChart; -using ChartJs.Blazor.Util; -using System; +using System; using System.Collections.Generic; -using System.Drawing; using System.Threading.Tasks; +using OpenBudgeteer.Blazor.Common; using OpenBudgeteer.Core.Data.Contracts.Services; -using OpenBudgeteer.Core.Data.Entities.Models; -using OpenBudgeteer.Core.ViewModels.EntityViewModels; using OpenBudgeteer.Core.ViewModels.Helper; namespace OpenBudgeteer.Blazor.ViewModels { public class BlazorBucketStatisticsViewModel : BucketDetailsViewModel { - private BarConfig _monthBalancesConfig; - public BarConfig MonthBalancesConfig - { - get => _monthBalancesConfig; - private set => Set(ref _monthBalancesConfig, value); - } - - private BarConfig _monthInputOutputConfig; - public BarConfig MonthInputOutputConfig - { - get => _monthInputOutputConfig; - private set => Set(ref _monthInputOutputConfig, value); - } - - private LineConfig _bucketProgressionConfig; - public LineConfig BucketProgressionConfig - { - get => _bucketProgressionConfig; - private set => Set(ref _bucketProgressionConfig, value); - } - - private BarConfig DefaultBarConfig => new() - { - Options = new BarOptions - { - Title = new OptionsTitle - { - Display = false - }, - Animation = new ArcAnimation - { - AnimateRotate = true, - AnimateScale = true - }, - Legend = new Legend - { - Display = false - } - } - }; - - private LineConfig DefaultTimeLineConfig => new() - { - Options = new LineOptions - { - Title = new OptionsTitle - { - Display = false - }, - Legend = new Legend - { - Display = false - }, - Tooltips = new Tooltips - { - Mode = InteractionMode.Nearest, - Intersect = false - }, - Scales = new Scales - { - xAxes = new List - { - new TimeAxis - { - Distribution = TimeDistribution.Linear, - Ticks = new TimeTicks - { - Source = TickSource.Data - }, - Time = new TimeOptions - { - Unit = TimeMeasurement.Month, - Round = TimeMeasurement.Month, - TooltipFormat = "MM.YYYY", - DisplayFormats = TimeDisplayFormats.DE_CH - } - } - } - }, - Hover = new LineOptionsHover - { - Intersect = true, - Mode = InteractionMode.Y - } - } - }; - + public List MonthBalances { get; private set; } = new(); + public List MonthInput { get; private set; } = new(); + public List MonthOutput { get; private set; } = new(); + public List BucketProgression { get; private set; } = new(); + + public BlazorBucketStatisticsViewModel(IServiceManager serviceManager, YearMonthSelectorViewModel yearMonthViewModel, Guid bucketId) : base(serviceManager, yearMonthViewModel, bucketId) { - _monthBalancesConfig = DefaultBarConfig; - _bucketProgressionConfig = DefaultTimeLineConfig; - _monthInputOutputConfig = DefaultBarConfig; } public async Task LoadDataAsync(bool withMovements) @@ -129,101 +34,31 @@ public async Task LoadDataAsync(bool withMovements) private async Task LoadMonthBalancesReportAsync() { - MonthBalancesConfig.Options.Title.Text = "Month Balances"; - - var backgroundColors = new List(); - var hoverColors = new List(); - var data = new List(); - - var monthBalanceData = await LoadBucketMonthBalancesAsync(12); - foreach (var balanceData in monthBalanceData) + MonthBalances.Clear(); + foreach (var (month, balance) in await LoadBucketMonthBalancesAsync(12)) { - data.Add(balanceData.Item2); - MonthBalancesConfig.Data.Labels.Add(balanceData.Item1.ToString("MM.yyyy")); - if (balanceData.Item2 < 0) - { - backgroundColors.Add(ColorUtil.FromDrawingColor(Color.DarkRed)); - hoverColors.Add(ColorUtil.FromDrawingColor(Color.LightCoral)); - } - else - { - backgroundColors.Add(ColorUtil.FromDrawingColor(Color.Green)); - hoverColors.Add(ColorUtil.FromDrawingColor(Color.LightGreen)); - } + MonthBalances.Add(new ReportRecord(month.ToString("yyyy-MM"), balance)); } - - var barDataSet = new BarDataset - { - BackgroundColor = backgroundColors.ToArray(), - BorderWidth = 0, - HoverBackgroundColor = hoverColors.ToArray(), - HoverBorderWidth = 0 - }; - - barDataSet.AddRange(data); - - MonthBalancesConfig.Data.Datasets.Add(barDataSet); } private async Task LoadMonthInputOutputReportAsync() { - MonthInputOutputConfig.Options.Title.Text = "Input & Output"; - - var incomeResults = new List(); - var expensesResults = new List(); - + MonthInput.Clear(); + MonthOutput.Clear(); foreach (var (month, input, output) in await LoadBucketMonthInOutAsync(12)) { - incomeResults.Add(input); - expensesResults.Add(output); - MonthInputOutputConfig.Data.Labels.Add(month.ToString("MM.yyyy")); + MonthInput.Add(new ReportRecord(month.ToString("yyyy-MM"), input)); + MonthOutput.Add(new ReportRecord(month.ToString("yyyy-MM"), output)); } - - var incomeBarDataSet = new BarDataset - { - BackgroundColor = ColorUtil.FromDrawingColor(Color.Green), - BorderWidth = 0, - HoverBackgroundColor = ColorUtil.FromDrawingColor(Color.LightGreen), - HoverBorderWidth = 0 - }; - - var expensesBarDataSet = new BarDataset - { - BackgroundColor = ColorUtil.FromDrawingColor(Color.DarkRed), - BorderWidth = 0, - HoverBackgroundColor = ColorUtil.FromDrawingColor(Color.LightCoral), - HoverBorderWidth = 0 - }; - - incomeBarDataSet.AddRange(incomeResults); - expensesBarDataSet.AddRange(expensesResults); - - MonthInputOutputConfig.Data.Datasets.Add(incomeBarDataSet); - MonthInputOutputConfig.Data.Datasets.Add(expensesBarDataSet); } private async Task LoadBucketBalanceProgressionReportAsync() { - BucketProgressionConfig.Options.Title.Text = "Balance Progression"; - - var lineDataSet = new LineDataset> - { - BackgroundColor = ColorUtil.FromDrawingColor(Color.Green), - BorderColor = ColorUtil.FromDrawingColor(Color.LightGreen), - Label = "Bucket Balance", - Fill = true, - BorderWidth = 2, - PointRadius = 3, - PointBorderWidth = 1, - SteppedLine = SteppedLine.False - }; - + BucketProgression.Clear(); foreach (var (month, balance) in await LoadBucketBalanceProgressionAsync()) { - lineDataSet.Add(new TimeTuple(new Moment(month), Convert.ToDouble(balance))); + BucketProgression.Add(new ReportRecord(month.ToString("yyyy-MM"), balance)); } - - BucketProgressionConfig.Data.Datasets.Add(lineDataSet); } } } diff --git a/OpenBudgeteer.Blazor/ViewModels/BlazorReportPageViewModel.cs b/OpenBudgeteer.Blazor/ViewModels/BlazorReportPageViewModel.cs deleted file mode 100644 index 318c33d..0000000 --- a/OpenBudgeteer.Blazor/ViewModels/BlazorReportPageViewModel.cs +++ /dev/null @@ -1,324 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Drawing; -using System.Linq; -using System.Threading.Tasks; -using ChartJs.Blazor.ChartJS.BarChart; -using ChartJs.Blazor.ChartJS.BarChart.Axes; -using ChartJs.Blazor.ChartJS.Common.Axes; -using ChartJs.Blazor.ChartJS.Common.Axes.Ticks; -using ChartJs.Blazor.ChartJS.Common.Enums; -using ChartJs.Blazor.ChartJS.Common.Handlers; -using ChartJs.Blazor.ChartJS.Common.Properties; -using ChartJs.Blazor.ChartJS.Common.Time; -using ChartJs.Blazor.ChartJS.LineChart; -using ChartJs.Blazor.Util; -using OpenBudgeteer.Core.Data.Contracts.Services; -using OpenBudgeteer.Core.ViewModels.PageViewModels; - -namespace OpenBudgeteer.Blazor.ViewModels; - -public class BlazorReportPageViewModel : ReportPageViewModel -{ - public readonly BarConfig MonthBalancesConfig; - - public readonly LineConfig BankBalancesConfig; - - public readonly BarConfig MonthIncomeExpensesConfig; - public readonly BarConfig YearIncomeExpensesConfig; - - public readonly ObservableCollection> MonthBucketExpensesConfigs; - - private BarConfig DefaultBarConfig => new() - { - Options = new BarOptions - { - Title = new OptionsTitle - { - Display = false - }, - Animation = new ArcAnimation - { - AnimateRotate = true, - AnimateScale = true - }, - Legend = new Legend - { - Display = false - } - } - }; - - private BarConfig DefaultZeroBasedBarConfig - { - get - { - var result = this.DefaultBarConfig; - result.Options.Scales = new BarScales - { - YAxes = new List - { - new BarLinearCartesianAxis - { - Ticks = new LinearCartesianTicks - { - Min = 0 - } - } - } - }; - return result; - } - } - - private LineConfig DefaultTimeLineConfig => new() - { - Options = new LineOptions - { - Title = new OptionsTitle - { - Display = false - }, - Legend = new Legend - { - Display = false - }, - Tooltips = new Tooltips - { - Mode = InteractionMode.Nearest, - Intersect = false - }, - Scales = new Scales - { - xAxes = new List - { - new TimeAxis - { - Distribution = TimeDistribution.Linear, - Ticks = new TimeTicks - { - Source = TickSource.Data - }, - Time = new TimeOptions - { - Unit = TimeMeasurement.Month, - Round = TimeMeasurement.Month, - TooltipFormat = "MM.YYYY", - DisplayFormats = TimeDisplayFormats.DE_CH - } - } - } - }, - Hover = new LineOptionsHover - { - Intersect = true, - Mode = InteractionMode.Y - } - } - }; - - public BlazorReportPageViewModel(IServiceManager serviceManager) : base(serviceManager) - { - MonthBalancesConfig = DefaultBarConfig; - BankBalancesConfig = DefaultTimeLineConfig; - MonthIncomeExpensesConfig = DefaultZeroBasedBarConfig; - YearIncomeExpensesConfig = DefaultZeroBasedBarConfig; - MonthBucketExpensesConfigs = new ObservableCollection>(); - } - - public async Task LoadDataAsync() - { - var loadTasks = new List() - { - LoadMonthBalancesReportAsync(), - LoadMonthIncomeExpensesReportAsync(), - LoadYearIncomeExpensesReportAsync(), - LoadBankBalancesReportAsync(), - LoadMonthExpensesBucketReportAsync() - }; - await Task.WhenAll(loadTasks); - } - - private async Task LoadMonthBalancesReportAsync() - { - MonthBalancesConfig.Options.Title.Text = "Month Balances"; - - var backgroundColors = new List(); - var hoverColors = new List(); - var data = new List(); - - var monthBalanceData = await LoadMonthBalancesAsync(); - foreach (var balanceData in monthBalanceData) - { - data.Add(balanceData.Item2); - MonthBalancesConfig.Data.Labels.Add(balanceData.Item1.ToString("MM.yyyy")); - if (balanceData.Item2 < 0) - { - backgroundColors.Add(ColorUtil.FromDrawingColor(Color.DarkRed)); - hoverColors.Add(ColorUtil.FromDrawingColor(Color.LightCoral)); - } - else - { - backgroundColors.Add(ColorUtil.FromDrawingColor(Color.Green)); - hoverColors.Add(ColorUtil.FromDrawingColor(Color.LightGreen)); - } - } - - var barDataSet = new BarDataset - { - BackgroundColor = backgroundColors.ToArray(), - BorderWidth = 0, - HoverBackgroundColor = hoverColors.ToArray(), - HoverBorderWidth = 0 - }; - - barDataSet.AddRange(data); - - MonthBalancesConfig.Data.Datasets.Add(barDataSet); - } - - private async Task LoadMonthIncomeExpensesReportAsync() - { - MonthIncomeExpensesConfig.Options.Title.Text = "Income & Expenses per Month"; - - var incomeResults = new List(); - var expensesResults = new List(); - - foreach (var (month, income, expenses) in await LoadMonthIncomeExpensesAsync()) - { - incomeResults.Add(income); - expensesResults.Add(expenses); - MonthIncomeExpensesConfig.Data.Labels.Add(month.ToString("MM.yyyy")); - } - - var incomeBarDataSet = new BarDataset - { - BackgroundColor = ColorUtil.FromDrawingColor(Color.Green), - BorderWidth = 0, - HoverBackgroundColor = ColorUtil.FromDrawingColor(Color.LightGreen), - HoverBorderWidth = 0 - }; - - var expensesBarDataSet = new BarDataset - { - BackgroundColor = ColorUtil.FromDrawingColor(Color.DarkRed), - BorderWidth = 0, - HoverBackgroundColor = ColorUtil.FromDrawingColor(Color.LightCoral), - HoverBorderWidth = 0 - }; - - incomeBarDataSet.AddRange(incomeResults); - expensesBarDataSet.AddRange(expensesResults); - - MonthIncomeExpensesConfig.Data.Datasets.Add(incomeBarDataSet); - MonthIncomeExpensesConfig.Data.Datasets.Add(expensesBarDataSet); - } - - private async Task LoadYearIncomeExpensesReportAsync() - { - YearIncomeExpensesConfig.Options.Title.Text = "Income & Expenses per Year"; - - var incomeResults = new List(); - var expensesResults = new List(); - - foreach (var (month, income, expenses) in await LoadYearIncomeExpensesAsync()) - { - incomeResults.Add(income); - expensesResults.Add(expenses); - YearIncomeExpensesConfig.Data.Labels.Add(month.ToString("yyyy")); - } - - var incomeBarDataSet = new BarDataset - { - BackgroundColor = ColorUtil.FromDrawingColor(Color.Green), - BorderWidth = 0, - HoverBackgroundColor = ColorUtil.FromDrawingColor(Color.LightGreen), - HoverBorderWidth = 0 - }; - - var expensesBarDataSet = new BarDataset - { - BackgroundColor = ColorUtil.FromDrawingColor(Color.DarkRed), - BorderWidth = 0, - HoverBackgroundColor = ColorUtil.FromDrawingColor(Color.LightCoral), - HoverBorderWidth = 0 - }; - - incomeBarDataSet.AddRange(incomeResults); - expensesBarDataSet.AddRange(expensesResults); - - YearIncomeExpensesConfig.Data.Datasets.Add(incomeBarDataSet); - YearIncomeExpensesConfig.Data.Datasets.Add(expensesBarDataSet); - } - - private async Task LoadBankBalancesReportAsync() - { - BankBalancesConfig.Options.Title.Text = "Bank Balances"; - - var lineDataSet = new LineDataset> - { - BackgroundColor = ColorUtil.FromDrawingColor(Color.Green), - BorderColor = ColorUtil.FromDrawingColor(Color.LightGreen), - Label = "Bank Balance", - Fill = true, - BorderWidth = 2, - PointRadius = 3, - PointBorderWidth = 1, - SteppedLine = SteppedLine.False - }; - - foreach (var (month, balance) in await LoadBankBalancesAsync()) - { - lineDataSet.Add(new TimeTuple(new Moment(month), Convert.ToDouble(balance))); - } - - // Set yAxes min value to 0 in case there is no negative Bank Balance existing - if (!lineDataSet.Data.Any(i => i.YValue < 0)) - { - BankBalancesConfig.Options.Scales.yAxes = new List - { - new LinearCartesianAxis - { - Ticks = new LinearCartesianTicks - { - Min = 0 - } - } - }; - } - - BankBalancesConfig.Data.Datasets.Add(lineDataSet); - } - - private async Task LoadMonthExpensesBucketReportAsync() - { - MonthBucketExpensesConfigs.Clear(); - foreach (var result in await LoadMonthExpensesBucketAsync()) - { - var newConfig = DefaultZeroBasedBarConfig; - newConfig.Options.Title.Display = false; - - var expensesResults = new List(); - foreach (var monthlyResult in result.MonthlyResults) - { - expensesResults.Add(monthlyResult.Item2); - newConfig.Data.Labels.Add(monthlyResult.Item1.ToString("MM.yyyy")); - } - - var newDataSet = new BarDataset() - { - BackgroundColor = ColorUtil.FromDrawingColor(Color.DarkRed), - BorderWidth = 0, - HoverBackgroundColor = ColorUtil.FromDrawingColor(Color.LightCoral), - HoverBorderWidth = 0 - }; - newDataSet.AddRange(expensesResults); - newConfig.Data.Datasets.Add(newDataSet); - - MonthBucketExpensesConfigs.Add(new Tuple( - result.BucketName, - newConfig)); - } - } -}