Skip to content

Commit

Permalink
Migrated reports from ChartJs.Blazor to Blazor-ApexCharts
Browse files Browse the repository at this point in the history
  • Loading branch information
TheAxelander committed May 25, 2024
1 parent 7e3dda7 commit 6897292
Show file tree
Hide file tree
Showing 13 changed files with 330 additions and 544 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
2 changes: 1 addition & 1 deletion LICENSE-3RD-PARTY
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
13 changes: 13 additions & 0 deletions OpenBudgeteer.Blazor/Common/ApexHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using ApexCharts;

namespace OpenBudgeteer.Blazor.Common;

public class ApexHelper
{
public static void BalanceChartMutator(DataPoint<ReportRecord> point)
{
point.FillColor = point.Y > 0
? System.Drawing.Color.Green.ToHexString()
: System.Drawing.Color.DarkRed.ToHexString();
}
}
11 changes: 11 additions & 0 deletions OpenBudgeteer.Blazor/Common/ColorExtensions.cs
Original file line number Diff line number Diff line change
@@ -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}";
}
}
5 changes: 5 additions & 0 deletions OpenBudgeteer.Blazor/Common/ReportRecord.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
using System;

namespace OpenBudgeteer.Blazor.Common;

public record ReportRecord(string Label, decimal Value);
2 changes: 1 addition & 1 deletion OpenBudgeteer.Blazor/OpenBudgeteer.Blazor.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="ChartJs.Blazor" Version="1.1.0" />
<PackageReference Include="Blazor-ApexCharts" Version="3.2.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
Expand Down
96 changes: 81 additions & 15 deletions OpenBudgeteer.Blazor/Pages/Report.razor
Original file line number Diff line number Diff line change
@@ -1,56 +1,122 @@
@page "/report"
@using ChartJs.Blazor.Charts
@using ApexCharts
@using OpenBudgeteer.Blazor.Common


<div class="row">
<div class="col-md-6 col-sm-12 p-1">
<div class="report-chart-box">
<h4 class="report-chart-header">Month Balances</h4>
<ChartJsBarChart Config="@_dataContext.MonthBalancesConfig"/>
<ApexChart @ref="MonthBalanceChart" TItem="ReportRecord">
<ApexPointSeries
TItem="ReportRecord"
Items="_apexContext.MonthBalances"
Name="Balance"
SeriesType="SeriesType.Bar"
XValue="i => i.Label"
YValue="i => i.Value"
DataPointMutator="ApexHelper.BalanceChartMutator"/>
</ApexChart>
</div>
</div>
<div class="col-md-6 col-sm-12 p-1">
<div class="report-chart-box">
<h4 class="report-chart-header">Bank Balances</h4>
<ChartJsLineChart Config="@_dataContext.BankBalancesConfig"/>
<ApexChart @ref="BankBalanceChart" TItem="ReportRecord">
<ApexPointSeries
TItem="ReportRecord"
Items="_apexContext.BankBalances"
Name="Balance"
SeriesType="SeriesType.Area"
XValue="i => i.Label"
YValue="i => i.Value"
Color=@System.Drawing.Color.Green.ToHexString()/>
</ApexChart>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6 col-sm-12 p-1">
<div class="report-chart-box">
<h4 class="report-chart-header">Income & Expenses per Month</h4>
<ChartJsBarChart Config="@_dataContext.MonthIncomeExpensesConfig"/>
<ApexChart @ref="MonthIncomeExpensesChart" TItem="ReportRecord" Options="MonthIncomeExpensesChartOptions">
<ApexPointSeries
TItem="ReportRecord"
Items="_apexContext.MonthIncome"
Name="Income"
SeriesType="SeriesType.Bar"
XValue="i => i.Label"
YValue="i => i.Value"
Color=@System.Drawing.Color.Green.ToHexString()/>
<ApexPointSeries
TItem="ReportRecord"
Items="_apexContext.MonthExpenses"
Name="Expenses"
SeriesType="SeriesType.Bar"
XValue="i => i.Label"
YValue="i => i.Value"
Color=@System.Drawing.Color.DarkRed.ToHexString()/>
</ApexChart>
</div>
</div>
<div class="col-md-6 col-sm-12 p-1">
<div class="report-chart-box">
<h4 class="report-chart-header">Income & Expenses per Year</h4>
<ChartJsBarChart Config="@_dataContext.YearIncomeExpensesConfig"/>
<ApexChart @ref="YearIncomeExpensesChart" TItem="ReportRecord" Options="YearIncomeExpensesChartOptions">
<ApexPointSeries
TItem="ReportRecord"
Items="_apexContext.YearIncome"
Name="Income"
SeriesType="SeriesType.Bar"
XValue="i => i.Label"
YValue="i => i.Value"
Color=@System.Drawing.Color.Green.ToHexString()/>
<ApexPointSeries
TItem="ReportRecord"
Items="_apexContext.YearExpenses"
Name="Expenses"
SeriesType="SeriesType.Bar"
XValue="i => i.Label"
YValue="i => i.Value"
Color=@System.Drawing.Color.DarkRed.ToHexString()/>
</ApexChart>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6 col-sm-12 p-1">
<div class="report-chart-box">
<h4 class="report-chart-header">Bucket Monthly Expenses</h4>
@foreach (var config in _monthBucketExpensesConfigsLeft)
@foreach (var chart in _monthBucketExpensesConfigsLeft)
{
<h5 class="report-chart-subheader">@config.Item1</h5>
<div>
<ChartJsBarChart Config="@config.Item2" Height="50"/>
</div>
<ApexChart @ref="InjectMonthBucketExpensesChart" Title="@chart.Item1" TItem="ReportRecord" Height="150">
<ApexPointSeries
TItem="ReportRecord"
Items="chart.Item2"
Name="Expenses"
SeriesType="SeriesType.Bar"
XValue="i => i.Label"
YValue="i => i.Value"
Color=@System.Drawing.Color.DarkRed.ToHexString()/>
</ApexChart>
}
</div>
</div>
<div class="col-md-6 col-sm-12 p-1">
<div class="report-chart-box">
<h4 class="report-chart-header">Bucket Monthly Expenses</h4>
@foreach (var config in _monthBucketExpensesConfigsRight)
@foreach (var chart in _monthBucketExpensesConfigsRight)
{
<h5 class="report-chart-subheader">@config.Item1</h5>
<div>
<ChartJsBarChart Config="@config.Item2" Height="50"/>
</div>
<ApexChart @ref="InjectMonthBucketExpensesChart" Title="@chart.Item1" TItem="ReportRecord" Height="150">
<ApexPointSeries
TItem="ReportRecord"
Items="chart.Item2"
Name="Expenses"
SeriesType="SeriesType.Bar"
XValue="i => i.Label"
YValue="i => i.Value"
Color=@System.Drawing.Color.DarkRed.ToHexString()/>
</ApexChart>
}
</div>
</div>
Expand Down
60 changes: 47 additions & 13 deletions OpenBudgeteer.Blazor/Pages/Report.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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<Tuple<string, BarConfig>> _monthBucketExpensesConfigsLeft = null!;
private List<Tuple<string, BarConfig>> _monthBucketExpensesConfigsRight = null!;

private ApexChart<ReportRecord> MonthBalanceChart;

Check warning on line 17 in OpenBudgeteer.Blazor/Pages/Report.razor.cs

View workflow job for this annotation

GitHub Actions / Run Test Cases

Non-nullable field 'MonthBalanceChart' must contain a non-null value when exiting constructor. Consider declaring the field as nullable.
private ApexChart<ReportRecord> BankBalanceChart;

Check warning on line 18 in OpenBudgeteer.Blazor/Pages/Report.razor.cs

View workflow job for this annotation

GitHub Actions / Run Test Cases

Non-nullable field 'BankBalanceChart' must contain a non-null value when exiting constructor. Consider declaring the field as nullable.
private ApexChart<ReportRecord> MonthIncomeExpensesChart;

Check warning on line 19 in OpenBudgeteer.Blazor/Pages/Report.razor.cs

View workflow job for this annotation

GitHub Actions / Run Test Cases

Non-nullable field 'MonthIncomeExpensesChart' must contain a non-null value when exiting constructor. Consider declaring the field as nullable.
private ApexChart<ReportRecord> YearIncomeExpensesChart;

Check warning on line 20 in OpenBudgeteer.Blazor/Pages/Report.razor.cs

View workflow job for this annotation

GitHub Actions / Run Test Cases

Non-nullable field 'YearIncomeExpensesChart' must contain a non-null value when exiting constructor. Consider declaring the field as nullable.
private List<ApexChart<ReportRecord>> MonthBucketExpensesCharts = new();
private ApexChart<ReportRecord> InjectMonthBucketExpensesChart
{
set => MonthBucketExpensesCharts.Add(value);
}

private ApexChartOptions<ReportRecord> MonthIncomeExpensesChartOptions = new()
{
Legend = new() { Show = false }
};
private ApexChartOptions<ReportRecord> YearIncomeExpensesChartOptions = new()
{
Legend = new() { Show = false }
};

private ApexReportViewModel _apexContext = null!;
private List<Tuple<string, List<ReportRecord>>> _monthBucketExpensesConfigsLeft = null!;
private List<Tuple<string, List<ReportRecord>>> _monthBucketExpensesConfigsRight = null!;

protected override async Task OnInitializedAsync()
{
_monthBucketExpensesConfigsLeft = new List<Tuple<string, BarConfig>>();
_monthBucketExpensesConfigsRight = new List<Tuple<string, BarConfig>>();

_dataContext = new BlazorReportPageViewModel(ServiceManager);
await _dataContext.LoadDataAsync();
_monthBucketExpensesConfigsLeft = new List<Tuple<string, List<ReportRecord>>>();
_monthBucketExpensesConfigsRight = new List<Tuple<string, List<ReportRecord>>>();
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<Task>()
{
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);
}
}
69 changes: 62 additions & 7 deletions OpenBudgeteer.Blazor/Shared/BucketDetailsDialog.razor
Original file line number Diff line number Diff line change
@@ -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

Expand Down Expand Up @@ -61,21 +60,56 @@
<div class="col-md-6 col-sm-12 p-1">
<div class="report-chart-box">
<h4 class="report-chart-header">Month Balances</h4>
<ChartJsBarChart Config="@DataContext.MonthBalancesConfig"/>
<ApexChart @ref="MonthBalanceChart" TItem="ReportRecord">
<ApexPointSeries
TItem="ReportRecord"
Items="DataContext.MonthBalances"
Name="Balance"
SeriesType="SeriesType.Bar"
XValue="i => i.Label"
YValue="i => i.Value"
DataPointMutator="ApexHelper.BalanceChartMutator"/>
</ApexChart>
</div>
</div>
<div class="col-md-6 col-sm-12 p-1">
<div class="report-chart-box">
<h4 class="report-chart-header">Input & Output</h4>
<ChartJsBarChart Config="@DataContext.MonthInputOutputConfig"/>
<ApexChart @ref="MonthInputOutputChart" TItem="ReportRecord" Options="MonthInputOutputChartOptions">
<ApexPointSeries
TItem="ReportRecord"
Items="DataContext.MonthInput"
Name="Input"
SeriesType="SeriesType.Bar"
XValue="i => i.Label"
YValue="i => i.Value"
Color=@System.Drawing.Color.Green.ToHexString()/>
<ApexPointSeries
TItem="ReportRecord"
Items="DataContext.MonthOutput"
Name="Output"
SeriesType="SeriesType.Bar"
XValue="i => i.Label"
YValue="i => i.Value"
Color=@System.Drawing.Color.DarkRed.ToHexString()/>
</ApexChart>
</div>
</div>
</div>
<div class="row">
<div class="col p-1">
<div class="report-chart-box">
<h4 class="report-chart-header">Balance Progression</h4>
<ChartJsLineChart Config="@DataContext.BucketProgressionConfig"/>
<ApexChart @ref="BucketProgressionChart" TItem="ReportRecord" Height="300">
<ApexPointSeries
TItem="ReportRecord"
Items="DataContext.BucketProgression"
Name="Balance"
SeriesType="SeriesType.Area"
XValue="i => i.Label"
YValue="i => i.Value"
Color=@System.Drawing.Color.Green.ToHexString()/>
</ApexChart>
</div>
</div>
</div>
Expand Down Expand Up @@ -107,12 +141,33 @@

[Parameter]
public EventCallback<MouseEventArgs> OnClickCallback { get; set; }

private ApexChart<ReportRecord> MonthBalanceChart;

Check warning on line 145 in OpenBudgeteer.Blazor/Shared/BucketDetailsDialog.razor

View workflow job for this annotation

GitHub Actions / Run Test Cases

Non-nullable field 'MonthBalanceChart' must contain a non-null value when exiting constructor. Consider declaring the field as nullable.

Check warning on line 145 in OpenBudgeteer.Blazor/Shared/BucketDetailsDialog.razor

View workflow job for this annotation

GitHub Actions / Run Test Cases

Non-nullable field 'MonthBalanceChart' must contain a non-null value when exiting constructor. Consider declaring the field as nullable.
private ApexChart<ReportRecord> MonthInputOutputChart;

Check warning on line 146 in OpenBudgeteer.Blazor/Shared/BucketDetailsDialog.razor

View workflow job for this annotation

GitHub Actions / Run Test Cases

Non-nullable field 'MonthInputOutputChart' must contain a non-null value when exiting constructor. Consider declaring the field as nullable.

Check warning on line 146 in OpenBudgeteer.Blazor/Shared/BucketDetailsDialog.razor

View workflow job for this annotation

GitHub Actions / Run Test Cases

Non-nullable field 'MonthInputOutputChart' must contain a non-null value when exiting constructor. Consider declaring the field as nullable.
private ApexChart<ReportRecord> BucketProgressionChart;

Check warning on line 147 in OpenBudgeteer.Blazor/Shared/BucketDetailsDialog.razor

View workflow job for this annotation

GitHub Actions / Run Test Cases

Non-nullable field 'BucketProgressionChart' must contain a non-null value when exiting constructor. Consider declaring the field as nullable.

Check warning on line 147 in OpenBudgeteer.Blazor/Shared/BucketDetailsDialog.razor

View workflow job for this annotation

GitHub Actions / Run Test Cases

Non-nullable field 'BucketProgressionChart' must contain a non-null value when exiting constructor. Consider declaring the field as nullable.

private ApexChartOptions<ReportRecord> MonthInputOutputChartOptions = new()
{
Legend = new() { Show = false }
};

private ApexChartOptions<ReportRecord> 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<Task>()
{
MonthBalanceChart.UpdateSeriesAsync(true),
MonthInputOutputChart.UpdateSeriesAsync(true),
BucketProgressionChart.UpdateSeriesAsync(true),
};

await Task.WhenAll(tasks);
}

}
2 changes: 1 addition & 1 deletion OpenBudgeteer.Blazor/Shared/MainLayout.razor
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
</button>
<span class="navbar-brand flex-fill ms-2 fs-5">OpenBudgeteer</span>
<span class="navbar-text ms-3 d-none d-md-block">Database: @CurrentDatabase</span>
<span class="navbar-text ms-3 d-none d-md-block">Version: 1.9 (<a href="https://github.com/TheAxelander/OpenBudgeteer/blob/master/CHANGELOG.md" target="_blank">Change Log</a>)</span>
<span class="navbar-text ms-3 d-none d-md-block">Version: 1.9.0 (<a href="https://github.com/TheAxelander/OpenBudgeteer/blob/master/CHANGELOG.md" target="_blank">Change Log</a>)</span>
</div>
</header>
<div class="container-fluid">
Expand Down
Loading

0 comments on commit 6897292

Please sign in to comment.