From 7ed4b73e894452656324f308c3a651de1f8bf939 Mon Sep 17 00:00:00 2001
From: Robert Goldmann <deadlocker@gmx.de>
Date: Thu, 8 Dec 2022 23:20:49 +0100
Subject: [PATCH] #683 - added click feature for default charts

---
 .../budgetmaster/charts/ChartController.java  | 22 +++++++++----------
 .../budgetmaster/charts/DefaultCharts.java    | 16 +++++++-------
 ...hlyIncomesAndExpendituresPerCategoryBar.js | 21 ++++++++++++++++++
 ...MonthlyIncomesAndExpendituresPerYearBar.js | 19 ++++++++++++++++
 .../AverageTransactionAmountPerCategoryBar.js | 21 ++++++++++++++++++
 .../IncomesAndExpendituresByCategoryPie.js    | 13 +++++++++++
 .../IncomesAndExpendituresPerMonthBar.js      | 21 +++++++++++++++++-
 ...omesAndExpendituresPerMonthByCategories.js | 21 ++++++++++++++++++
 .../IncomesAndExpendituresPerYearBar.js       | 22 ++++++++++++++++++-
 ...comesAndExpendituresPerYearByCategories.js | 21 ++++++++++++++++++
 10 files changed, 176 insertions(+), 21 deletions(-)

diff --git a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/charts/ChartController.java b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/charts/ChartController.java
index 969528dd3..f13b83849 100644
--- a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/charts/ChartController.java
+++ b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/charts/ChartController.java
@@ -273,11 +273,20 @@ public class ChartController extends BaseController
 	{
 		String title;
 		final String clickedCategory = chartSettings.getClickedCategory();
-		if(clickedCategory == null)
+		if(chartSettings.getClickedAmountType() == null)
+		{
+			for(FilterObject filterCategory : chartSettings.getFilterConfiguration().getFilterCategories())
+			{
+				filterCategory.setInclude(filterCategory.getName().equals(clickedCategory));
+			}
+
+			title = Localization.getString("chart.matching.transactions.title.category", clickedCategory);
+		}
+		else
 		{
 			if(chartSettings.getClickedAmountType() == ChartAmountType.INCOME)
 			{
-				title = Localization.getString("titles.incomes");
+				title = Localization.getString("title.incomes");
 				chartSettings.getFilterConfiguration().setIncludeIncome(true);
 				chartSettings.getFilterConfiguration().setIncludeExpenditure(false);
 			}
@@ -288,15 +297,6 @@ public class ChartController extends BaseController
 				chartSettings.getFilterConfiguration().setIncludeExpenditure(true);
 			}
 		}
-		else
-		{
-			for(FilterObject filterCategory : chartSettings.getFilterConfiguration().getFilterCategories())
-			{
-				filterCategory.setInclude(filterCategory.getName().equals(clickedCategory));
-			}
-
-			title = Localization.getString("chart.matching.transactions.title.category", clickedCategory);
-		}
 
 		final List<Transaction> transactions = transactionService.getTransactionsForAccount(helpers.getCurrentAccount(), chartSettings.getStartDate(), chartSettings.getEndDate(), chartSettings.getFilterConfiguration());
 		final List<Transaction> convertedTransactions = convertTransferAmounts(transactions);
diff --git a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/charts/DefaultCharts.java b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/charts/DefaultCharts.java
index 53f935e1c..b67257ca1 100644
--- a/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/charts/DefaultCharts.java
+++ b/BudgetMasterServer/src/main/java/de/deadlocker8/budgetmaster/charts/DefaultCharts.java
@@ -24,7 +24,7 @@ public class DefaultCharts
 
 	private static final Chart CHART_INCOMES_AND_EXPENDITURES_PER_MONTH_BAR = new Chart("charts.default.incomesAndExpendituresPerMonthBar",
 			getChartFromFile("charts/IncomesAndExpendituresPerMonthBar.js"),
-			ChartType.DEFAULT, 12, ChartDisplayType.BAR, ChartGroupType.MONTH, "incomesAndExpendituresPerMonthBar.png");
+			ChartType.DEFAULT, 13, ChartDisplayType.BAR, ChartGroupType.MONTH, "incomesAndExpendituresPerMonthBar.png");
 
 	private static final Chart CHART_INCOMES_AND_EXPENDITURES_PER_MONTH_LINE = new Chart("charts.default.incomesAndExpendituresPerMonthLine",
 			getChartFromFile("charts/IncomesAndExpendituresPerMonthLine.js"),
@@ -36,11 +36,11 @@ public class DefaultCharts
 
 	private static final Chart CHART_INCOMES_AND_EXPENDITURES_BY_CATEGORY_PIE = new Chart("charts.default.incomesAndExpendituresByCategoryPie",
 			getChartFromFile("charts/IncomesAndExpendituresByCategoryPie.js"),
-			ChartType.DEFAULT, 9, ChartDisplayType.PIE, ChartGroupType.NONE, "incomesAndExpendituresByCategoryPie.png");
+			ChartType.DEFAULT, 12, ChartDisplayType.PIE, ChartGroupType.NONE, "incomesAndExpendituresByCategoryPie.png");
 
 	private static final Chart CHART_INCOMES_AND_EXPENDITURES_PER_MONTH_BY_CATEGORIES = new Chart("charts.default.incomesAndExpendituresPerMonthByCategories",
 			getChartFromFile("charts/IncomesAndExpendituresPerMonthByCategories.js"),
-			ChartType.DEFAULT, 24, ChartDisplayType.BAR, ChartGroupType.MONTH, "incomesAndExpendituresPerMonthByCategories.png");
+			ChartType.DEFAULT, 25, ChartDisplayType.BAR, ChartGroupType.MONTH, "incomesAndExpendituresPerMonthByCategories.png");
 
 	private static final Chart CHART_REST_PER_MONTH = new Chart("charts.default.restPerMonth",
 			getChartFromFile("charts/RestPerMonth.js"),
@@ -48,23 +48,23 @@ public class DefaultCharts
 
 	private static final Chart CHART_INCOMES_AND_EXPENDITURES_PER_YEAR_BAR = new Chart("charts.default.incomesAndExpendituresPerYearBar",
 			getChartFromFile("charts/IncomesAndExpendituresPerYearBar.js"),
-			ChartType.DEFAULT, 7, ChartDisplayType.BAR, ChartGroupType.YEAR, "incomesAndExpendituresPerYearBar.png");
+			ChartType.DEFAULT, 10, ChartDisplayType.BAR, ChartGroupType.YEAR, "incomesAndExpendituresPerYearBar.png");
 
 	private static final Chart CHART_INCOMES_AND_EXPENDITURES_PER_YEAR_BY_CATEGORIES = new Chart("charts.default.incomesAndExpendituresPerYearByCategories",
 			getChartFromFile("charts/IncomesAndExpendituresPerYearByCategories.js"),
-			ChartType.DEFAULT, 4, ChartDisplayType.BAR, ChartGroupType.YEAR, "incomesAndExpendituresPerYearByCategories.png");
+			ChartType.DEFAULT, 5, ChartDisplayType.BAR, ChartGroupType.YEAR, "incomesAndExpendituresPerYearByCategories.png");
 
 	private static final Chart CHART_AVERAGE_TRANSACTION_AMOUNT_PER_CATEGORY = new Chart("charts.default.averageTransactionAmountPerCategory",
 			getChartFromFile("charts/AverageTransactionAmountPerCategoryBar.js"),
-			ChartType.DEFAULT, 10, ChartDisplayType.BAR, ChartGroupType.NONE, "averageTransactionAmountPerCategory.png");
+			ChartType.DEFAULT, 11, ChartDisplayType.BAR, ChartGroupType.NONE, "averageTransactionAmountPerCategory.png");
 
 	private static final Chart CHART_AVERAGE_MONTHLY_INCOMES_AND_EXPENDITURES_PER_YEAR_BAR = new Chart("charts.default.averageMonthlyIncomesAndExpendituresPerYearBar",
 			getChartFromFile("charts/AverageMonthlyIncomesAndExpendituresPerYearBar.js"),
-			ChartType.DEFAULT, 10, ChartDisplayType.BAR, ChartGroupType.YEAR, "averageMonthlyIncomesAndExpendituresPerYearBar.png");
+			ChartType.DEFAULT, 12, ChartDisplayType.BAR, ChartGroupType.YEAR, "averageMonthlyIncomesAndExpendituresPerYearBar.png");
 
 	private static final Chart CHART_AVERAGE_MONTHLY_INCOMES_AND_EXPENDITURES_PER_CATEGORY_BAR = new Chart("charts.default.averageMonthlyIncomesAndExpendituresPerCategoryBar",
 			getChartFromFile("charts/AverageMonthlyIncomesAndExpendituresPerCategoryBar.js"),
-			ChartType.DEFAULT, 2, ChartDisplayType.BAR, ChartGroupType.NONE, "averageMonthlyIncomesAndExpendituresPerCategoryBar.png");
+			ChartType.DEFAULT, 8, ChartDisplayType.BAR, ChartGroupType.NONE, "averageMonthlyIncomesAndExpendituresPerCategoryBar.png");
 
 	private DefaultCharts()
 	{
diff --git a/BudgetMasterServer/src/main/resources/charts/AverageMonthlyIncomesAndExpendituresPerCategoryBar.js b/BudgetMasterServer/src/main/resources/charts/AverageMonthlyIncomesAndExpendituresPerCategoryBar.js
index b09348d31..e4652d885 100644
--- a/BudgetMasterServer/src/main/resources/charts/AverageMonthlyIncomesAndExpendituresPerCategoryBar.js
+++ b/BudgetMasterServer/src/main/resources/charts/AverageMonthlyIncomesAndExpendituresPerCategoryBar.js
@@ -105,6 +105,27 @@ var plotlyConfig = {
 Plotly.newPlot("containerID", plotlyData, plotlyLayout, plotlyConfig);
 
 
+REGEX_CATGEORY_NAME = new RegExp("(.*)\\s-?\\d+.\\d\\s€");
+
+var plotContainer = document.getElementById('containerID');
+plotContainer.on('plotly_click', function(data){
+    if(data.event.shiftKey !== true)
+    {
+        return;
+    }
+
+    let index = data.points.length - 1;
+    let hoverText = data.points[index].hovertext;
+    let match = hoverText.match(REGEX_CATGEORY_NAME);
+    if(match === null)
+    {
+        console.error('could not extract category name from: "' + hoverText + '"');
+        return;
+    }
+
+    getAndShowMatchingTransactions(null, match[1]);
+});
+
 function addDPlotlyData(plotlyData, averageValue, categoryName, color, showLegend)
 {
     // add border if category color is white
diff --git a/BudgetMasterServer/src/main/resources/charts/AverageMonthlyIncomesAndExpendituresPerYearBar.js b/BudgetMasterServer/src/main/resources/charts/AverageMonthlyIncomesAndExpendituresPerYearBar.js
index 47470435b..dd149b1dc 100644
--- a/BudgetMasterServer/src/main/resources/charts/AverageMonthlyIncomesAndExpendituresPerYearBar.js
+++ b/BudgetMasterServer/src/main/resources/charts/AverageMonthlyIncomesAndExpendituresPerYearBar.js
@@ -128,6 +128,25 @@ var plotlyConfig = {
 Plotly.newPlot("containerID", plotlyData, plotlyLayout, plotlyConfig);
 
 
+var plotContainer = document.getElementById('containerID');
+plotContainer.on('plotly_click', function(data){
+    if(data.event.shiftKey !== true)
+    {
+        return;
+    }
+
+    let index = data.points.length - 1;
+    let amountTypeText = data.points[index].data.name;
+
+    let amountType = 'EXPENDITURE';
+    if(amountTypeText === localizedData['traceName1'])
+    {
+        amountType = 'INCOME';
+    }
+
+    getAndShowMatchingTransactions(amountType, null);
+});
+
 function prepareHoverText(value)
 {
     return value.toFixed(1) + ' ' + localizedCurrency;
diff --git a/BudgetMasterServer/src/main/resources/charts/AverageTransactionAmountPerCategoryBar.js b/BudgetMasterServer/src/main/resources/charts/AverageTransactionAmountPerCategoryBar.js
index b604e7b75..ac1f4718f 100644
--- a/BudgetMasterServer/src/main/resources/charts/AverageTransactionAmountPerCategoryBar.js
+++ b/BudgetMasterServer/src/main/resources/charts/AverageTransactionAmountPerCategoryBar.js
@@ -97,6 +97,27 @@ var plotlyConfig = {
 Plotly.newPlot("containerID", plotlyData, plotlyLayout, plotlyConfig);
 
 
+REGEX_CATGEORY_NAME = new RegExp("(.*)\\s-?\\d+.\\d\\s€");
+
+var plotContainer = document.getElementById('containerID');
+plotContainer.on('plotly_click', function(data){
+    if(data.event.shiftKey !== true)
+    {
+        return;
+    }
+
+    let index = data.points.length - 1;
+    let hoverText = data.points[index].hovertext;
+    let match = hoverText.match(REGEX_CATGEORY_NAME);
+    if(match === null)
+    {
+        console.error('could not extract category name from: "' + hoverText + '"');
+        return;
+    }
+
+    getAndShowMatchingTransactions(null, match[1]);
+});
+
 function calculateAverage(values)
 {
     var sum = 0;
diff --git a/BudgetMasterServer/src/main/resources/charts/IncomesAndExpendituresByCategoryPie.js b/BudgetMasterServer/src/main/resources/charts/IncomesAndExpendituresByCategoryPie.js
index 66d12bb48..f8193d0ff 100644
--- a/BudgetMasterServer/src/main/resources/charts/IncomesAndExpendituresByCategoryPie.js
+++ b/BudgetMasterServer/src/main/resources/charts/IncomesAndExpendituresByCategoryPie.js
@@ -159,6 +159,19 @@ var plotlyConfig = {
 Plotly.newPlot("containerID", plotlyData, plotlyLayout, plotlyConfig);
 
 
+
+var plotContainer = document.getElementById('containerID');
+plotContainer.on('plotly_click', function(data){
+    if(data.event.shiftKey !== true)
+    {
+        return;
+    }
+
+    let index = data.points.length - 1;
+    getAndShowMatchingTransactions(null, data.points[index].label);
+});
+
+
 function addSeries(sumHandler, column)
 {
     var plotlyData = [];
diff --git a/BudgetMasterServer/src/main/resources/charts/IncomesAndExpendituresPerMonthBar.js b/BudgetMasterServer/src/main/resources/charts/IncomesAndExpendituresPerMonthBar.js
index b0f0a346b..91515689c 100644
--- a/BudgetMasterServer/src/main/resources/charts/IncomesAndExpendituresPerMonthBar.js
+++ b/BudgetMasterServer/src/main/resources/charts/IncomesAndExpendituresPerMonthBar.js
@@ -102,4 +102,23 @@ var plotlyConfig = {
 };
 
 // Don't touch this line
-Plotly.newPlot("containerID", plotlyData, plotlyLayout, plotlyConfig);
\ No newline at end of file
+Plotly.newPlot("containerID", plotlyData, plotlyLayout, plotlyConfig);
+
+var plotContainer = document.getElementById('containerID');
+plotContainer.on('plotly_click', function(data){
+    if(data.event.shiftKey !== true)
+    {
+        return;
+    }
+
+    let index = data.points.length - 1;
+    let amountTypeText = data.points[index].data.name;
+
+    let amountType = 'EXPENDITURE';
+    if(amountTypeText === localizedData['traceName1'])
+    {
+        amountType = 'INCOME';
+    }
+
+    getAndShowMatchingTransactions(amountType, null);
+});
\ No newline at end of file
diff --git a/BudgetMasterServer/src/main/resources/charts/IncomesAndExpendituresPerMonthByCategories.js b/BudgetMasterServer/src/main/resources/charts/IncomesAndExpendituresPerMonthByCategories.js
index 4bd71aea8..5d6acc00f 100644
--- a/BudgetMasterServer/src/main/resources/charts/IncomesAndExpendituresPerMonthByCategories.js
+++ b/BudgetMasterServer/src/main/resources/charts/IncomesAndExpendituresPerMonthByCategories.js
@@ -198,6 +198,27 @@ var plotlyConfig = {
 Plotly.newPlot("containerID", plotlyData, plotlyLayout, plotlyConfig);
 
 
+REGEX_CATGEORY_NAME = new RegExp("(.*)\\s\\d+.\\d%");
+
+var plotContainer = document.getElementById('containerID');
+plotContainer.on('plotly_click', function(data){
+    if(data.event.shiftKey !== true)
+    {
+        return;
+    }
+
+    let index = data.points.length - 1;
+    let hoverText = data.points[index].hovertext;
+    let match = hoverText.match(REGEX_CATGEORY_NAME);
+    if(match === null)
+    {
+        console.error('could not extract category name from: "' + hoverText + '"');
+        return;
+    }
+
+    getAndShowMatchingTransactions(null, match[1]);
+});
+
 function prepareHoverText(categoryName, percentage, value)
 {
     value = value / 100;
diff --git a/BudgetMasterServer/src/main/resources/charts/IncomesAndExpendituresPerYearBar.js b/BudgetMasterServer/src/main/resources/charts/IncomesAndExpendituresPerYearBar.js
index d03e7f05f..674fb55fd 100644
--- a/BudgetMasterServer/src/main/resources/charts/IncomesAndExpendituresPerYearBar.js
+++ b/BudgetMasterServer/src/main/resources/charts/IncomesAndExpendituresPerYearBar.js
@@ -102,4 +102,24 @@ var plotlyConfig = {
 };
 
 // Don't touch this line
-Plotly.newPlot("containerID", plotlyData, plotlyLayout, plotlyConfig);
\ No newline at end of file
+Plotly.newPlot("containerID", plotlyData, plotlyLayout, plotlyConfig);
+
+
+var plotContainer = document.getElementById('containerID');
+plotContainer.on('plotly_click', function(data){
+    if(data.event.shiftKey !== true)
+    {
+        return;
+    }
+
+    let index = data.points.length - 1;
+    let amountTypeText = data.points[index].data.name;
+
+    let amountType = 'EXPENDITURE';
+    if(amountTypeText === localizedData['traceName1'])
+    {
+        amountType = 'INCOME';
+    }
+
+    getAndShowMatchingTransactions(amountType, null);
+});
\ No newline at end of file
diff --git a/BudgetMasterServer/src/main/resources/charts/IncomesAndExpendituresPerYearByCategories.js b/BudgetMasterServer/src/main/resources/charts/IncomesAndExpendituresPerYearByCategories.js
index dcb1e0b4c..ff3413d9a 100644
--- a/BudgetMasterServer/src/main/resources/charts/IncomesAndExpendituresPerYearByCategories.js
+++ b/BudgetMasterServer/src/main/resources/charts/IncomesAndExpendituresPerYearByCategories.js
@@ -198,6 +198,27 @@ var plotlyConfig = {
 Plotly.newPlot("containerID", plotlyData, plotlyLayout, plotlyConfig);
 
 
+REGEX_CATGEORY_NAME = new RegExp("(.*)\\s\\d+.\\d%");
+
+var plotContainer = document.getElementById('containerID');
+plotContainer.on('plotly_click', function(data){
+    if(data.event.shiftKey !== true)
+    {
+        return;
+    }
+
+    let index = data.points.length - 1;
+    let hoverText = data.points[index].hovertext;
+    let match = hoverText.match(REGEX_CATGEORY_NAME);
+    if(match === null)
+    {
+        console.error('could not extract category name from: "' + hoverText + '"');
+        return;
+    }
+
+    getAndShowMatchingTransactions(null, match[1]);
+});
+
 function prepareHoverText(categoryName, percentage, value)
 {
     value = value / 100;
-- 
GitLab