feat: stacked columns graph
This commit is contained in:
parent
1d63360e80
commit
7c00ff585d
1 changed files with 66 additions and 28 deletions
|
@ -17,6 +17,7 @@ import com.vaadin.flow.router.Route;
|
||||||
import jakarta.annotation.security.PermitAll;
|
import jakarta.annotation.security.PermitAll;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.time.Month;
|
||||||
import java.time.Year;
|
import java.time.Year;
|
||||||
import java.time.YearMonth;
|
import java.time.YearMonth;
|
||||||
import java.time.format.TextStyle;
|
import java.time.format.TextStyle;
|
||||||
|
@ -114,45 +115,82 @@ public class DashboardView extends Div {
|
||||||
private String generateBarChartScript() {
|
private String generateBarChartScript() {
|
||||||
List<Expense> expenses = expenseService.fetchExpensesForDashboard(loggedPerson, Year.now());
|
List<Expense> expenses = expenseService.fetchExpensesForDashboard(loggedPerson, Year.now());
|
||||||
|
|
||||||
// Prepare data for Highcharts
|
// Create a map to store data by month and category
|
||||||
Map<String, Double> monthlyData = new LinkedHashMap<>();
|
Map<String, Map<String, Double>> monthlyCategoryData = new LinkedHashMap<>();
|
||||||
YearMonth currentYearMonth = YearMonth.now().withMonth(1); // Start from January
|
|
||||||
|
|
||||||
|
// Initialize all months (from January to December) for each category
|
||||||
|
List<String> monthNames = new ArrayList<>();
|
||||||
for (int i = 1; i <= 12; i++) {
|
for (int i = 1; i <= 12; i++) {
|
||||||
String monthName = currentYearMonth.getMonth().getDisplayName(TextStyle.SHORT, Locale.ENGLISH);
|
String monthName = Month.of(i).getDisplayName(TextStyle.SHORT, Locale.ENGLISH);
|
||||||
monthlyData.put(monthName, 0.0);
|
monthNames.add(monthName);
|
||||||
currentYearMonth = currentYearMonth.plusMonths(1); // Move to the next month
|
monthlyCategoryData.putIfAbsent(monthName, new LinkedHashMap<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Populate map with actual data
|
// Populate the map with actual expense data
|
||||||
for (Expense expense : expenses) {
|
for (Expense expense : expenses) {
|
||||||
String monthName = expense.getDate().getMonth().getDisplayName(TextStyle.SHORT, Locale.ENGLISH);
|
String monthName = expense.getDate().getMonth().getDisplayName(TextStyle.SHORT, Locale.ENGLISH);
|
||||||
|
String categoryName = expense.getCategory().getName();
|
||||||
Double amount = expense.getCost().doubleValue();
|
Double amount = expense.getCost().doubleValue();
|
||||||
monthlyData.put(monthName, monthlyData.get(monthName) + amount);
|
|
||||||
|
monthlyCategoryData.putIfAbsent(monthName, new LinkedHashMap<>());
|
||||||
|
Map<String, Double> categoryData = monthlyCategoryData.get(monthName);
|
||||||
|
categoryData.put(categoryName, categoryData.getOrDefault(categoryName, 0.0) + amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare series data for Highcharts
|
// Prepare series data for Highcharts, with each category being a separate series
|
||||||
StringBuilder data = new StringBuilder("[");
|
Map<String, Map<String, Double>> categoryMonthlyData = new LinkedHashMap<>();
|
||||||
for (Map.Entry<String, Double> entry : monthlyData.entrySet()) {
|
for (String monthName : monthNames) {
|
||||||
data.append(entry.getValue()).append(",");
|
Map<String, Double> monthData = monthlyCategoryData.getOrDefault(monthName, new LinkedHashMap<>());
|
||||||
}
|
for (Map.Entry<String, Double> entry : monthData.entrySet()) {
|
||||||
data.setCharAt(data.length() - 1, ']'); // Replace last comma with closing bracket
|
String categoryName = entry.getKey();
|
||||||
|
Double amount = entry.getValue();
|
||||||
|
|
||||||
// Generate JavaScript initialization
|
categoryMonthlyData.putIfAbsent(categoryName, new LinkedHashMap<>());
|
||||||
|
categoryMonthlyData.get(categoryName).put(monthName, amount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build the series data for each category
|
||||||
|
StringBuilder seriesData = new StringBuilder("[");
|
||||||
|
for (Map.Entry<String, Map<String, Double>> entry : categoryMonthlyData.entrySet()) {
|
||||||
|
String categoryName = entry.getKey();
|
||||||
|
Map<String, Double> monthData = entry.getValue();
|
||||||
|
|
||||||
|
seriesData.append("{");
|
||||||
|
seriesData.append("name: '").append(categoryName).append("',");
|
||||||
|
seriesData.append("data: [");
|
||||||
|
|
||||||
|
for (String monthName : monthNames) {
|
||||||
|
seriesData.append(monthData.getOrDefault(monthName, 0.0)).append(",");
|
||||||
|
}
|
||||||
|
|
||||||
|
seriesData.setLength(seriesData.length() - 1); // Remove trailing comma
|
||||||
|
seriesData.append("], stack: 'expenses'");
|
||||||
|
seriesData.append("},");
|
||||||
|
}
|
||||||
|
seriesData.setLength(seriesData.length() - 1); // Remove trailing comma
|
||||||
|
seriesData.append("]");
|
||||||
|
|
||||||
|
// Generate the JavaScript for the stacked column chart
|
||||||
return "Highcharts.chart('barChart', {" +
|
return "Highcharts.chart('barChart', {" +
|
||||||
"chart: {" +
|
"chart: { type: 'column' }, " +
|
||||||
"type: 'column'" +
|
"title: { text: 'Monthly Expenses by Category for " + Year.now().getValue() + "' }, " +
|
||||||
"}," +
|
"xAxis: { categories: " + new Gson().toJson(monthNames) + " }, " +
|
||||||
"title: {" +
|
"yAxis: { " +
|
||||||
"text: 'Monthly Expenses for " + Year.now().getValue() + "'" +
|
"min: 0, " +
|
||||||
"}," +
|
"title: { text: 'Total Expense' }, " +
|
||||||
"xAxis: {" +
|
"stackLabels: { " +
|
||||||
"categories: " + new Gson().toJson(monthlyData.keySet()) + // Categories are the month names
|
"enabled: true, " +
|
||||||
"}," +
|
"style: { fontWeight: 'bold', color: 'gray' } " +
|
||||||
"series: [{" +
|
"} " +
|
||||||
"name: 'Expenses'," +
|
"}, " +
|
||||||
"data: " + data + // Use the data fetched from DB
|
"plotOptions: { " +
|
||||||
"}]" +
|
"column: { " +
|
||||||
|
"stacking: 'normal', " +
|
||||||
|
"dataLabels: { enabled: true } " +
|
||||||
|
"} " +
|
||||||
|
"}, " +
|
||||||
|
"series: " + seriesData.toString() + " " +
|
||||||
"});";
|
"});";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue