From 122cdff9ef162ed7c1a5bfadffb8a9abcc7e6aa7 Mon Sep 17 00:00:00 2001 From: Robert Goldmann <deadlocker@gmx.de> Date: Sat, 27 Jul 2019 01:08:09 +0200 Subject: [PATCH] #437 - chart template: incomes/expenditures by categories (bar) --- .../budgetmaster/charts/DefaultCharts.java | 5 + .../IncomesAndExpendituresByCategoryBar.js | 118 ++++++++++++++++++ src/main/resources/languages/_de.properties | 2 + src/main/resources/languages/_en.properties | 2 + .../resources/templates/charts/charts.ftl | 2 +- 5 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 src/main/resources/charts/IncomesAndExpendituresByCategoryBar.js diff --git a/src/main/java/de/deadlocker8/budgetmaster/charts/DefaultCharts.java b/src/main/java/de/deadlocker8/budgetmaster/charts/DefaultCharts.java index 936f577b9..44424b926 100644 --- a/src/main/java/de/deadlocker8/budgetmaster/charts/DefaultCharts.java +++ b/src/main/java/de/deadlocker8/budgetmaster/charts/DefaultCharts.java @@ -29,6 +29,10 @@ public class DefaultCharts getChartFromFile("charts/IncomesAndExpendituresPerMonthLine.js"), ChartType.DEFAULT, 2); + private static final Chart CHART_INCOMES_AND_EXPENDITURES_BY_CATEGORY_BAR = new Chart("charts.default.incomesAndExpendituresByCategoryBar", + getChartFromFile("charts/IncomesAndExpendituresByCategoryBar.js"), + ChartType.DEFAULT, 11); + public static List<Chart> getDefaultCharts() { @@ -36,6 +40,7 @@ public class DefaultCharts charts.add(CHART_ACCOUNT_SUM_PER_DAY); charts.add(CHART_INCOMES_AND_EXPENDITURES_PER_MONTH_BAR); charts.add(CHART_INCOMES_AND_EXPENDITURES_PER_MONTH_LINE); + charts.add(CHART_INCOMES_AND_EXPENDITURES_BY_CATEGORY_BAR); charts.sort(Comparator.comparing(Chart::getName)); return charts; diff --git a/src/main/resources/charts/IncomesAndExpendituresByCategoryBar.js b/src/main/resources/charts/IncomesAndExpendituresByCategoryBar.js new file mode 100644 index 000000000..218f4d545 --- /dev/null +++ b/src/main/resources/charts/IncomesAndExpendituresByCategoryBar.js @@ -0,0 +1,118 @@ +/* This list will be dynamically filled with all the transactions between + * the start and and date you select on the "Show Chart" page + * and filtered according to your specified filter. + * An example entry for this list and tutorial about how to create custom charts ca be found in the BudgetMaster wiki: + * https://github.com/deadlocker8/BudgetMaster/wiki/How-to-create-custom-charts + */ +var transactionData = []; + +// Note: All variables starting with "localized" are only available inside default charts. + +var categoryNames = []; +var incomes = []; +var expenditures = []; + +for(var i = 0; i < transactionData.length; i++) +{ + var transaction = transactionData[i]; + + var categoryName = transaction.category.name; + // create new category is not already in dict + if(!categoryNames.includes(categoryName)) + { + categoryNames.push(categoryName); + incomes.push(0); + expenditures.push(0); + } + + // determine index of categoryName in list because the transactions are not ordered by category and some categories + // will be missing either for income or expenditures + var index = categoryNames.indexOf(categoryName); + + // add to income or expenditure sum + var amount = transaction.amount; + if(amount > 0) + { + incomes[index] = incomes[index] + amount; + } else + { + expenditures[index] = expenditures[index] + Math.abs(amount); + } +} + +// calculate total sums +var totalIncomes = 0; +var totalExpenditures = 0; + +incomes.forEach(function(value) +{ + totalIncomes += value; +}); + +expenditures.forEach(function(value) +{ + totalExpenditures += value; +}); + + +// Prepare your chart settings here (mandatory) +var plotlyData = []; + +for(var j = 0; j < categoryNames.length; j++) +{ + var percentageIncome = (100 / totalIncomes) * incomes[j]; + var percentageExpenditure = (100 / totalExpenditures) * expenditures[j]; + + var textIncome = prepareHoverText(percentageIncome, incomes[j]); + var textExpenditure = prepareHoverText(percentageExpenditure, expenditures[j]); + + plotlyData.push({ + x: [percentageExpenditure, percentageIncome], + y: [localizedData['label1'], localizedData['label2']], + orientation: 'h', + type: 'bar', + hoverinfo: 'text', + text: [textExpenditure, textIncome], + name: categoryNames[j] + }); +} + + +// Add your Plotly layout settings here (optional) +var plotlyLayout = { + title: { + text: localizedTitle + }, + xaxis: { + showgrid: false, + showticklabels: false + }, + yaxis: { + tickangle: 90, + tickfont: { + family: 'sans-serif', + size: 14, + color: 'black' + } + }, + barmode: 'stack', + hovermode: 'closest' +}; + +// Add your Plotly configuration settings here (optional) +var plotlyConfig = { + showSendToCloud: false, + displaylogo: false, + showLink: false, + responsive: true +}; + +// Don't touch this line +Plotly.newPlot('chart-canvas', plotlyData, plotlyLayout, plotlyConfig); + + +function prepareHoverText(percentage, value) +{ + value = value / 100; + return percentage.toFixed(1) + '% (' + value.toFixed(1) + ' ' + localizedCurrency + ')'; +} \ No newline at end of file diff --git a/src/main/resources/languages/_de.properties b/src/main/resources/languages/_de.properties index fe0810c49..edec359bd 100644 --- a/src/main/resources/languages/_de.properties +++ b/src/main/resources/languages/_de.properties @@ -335,6 +335,8 @@ charts.default.incomesAndExpendituresPerMonthBar=Eingaben/Ausgaben pro Monat (Ba charts.default.incomesAndExpendituresPerMonthBar.localization='{"axisY": "Summe in ", "traceName1": "Einnahmen", "traceName2": "Ausgaben"'} charts.default.incomesAndExpendituresPerMonthLine=Eingaben/Ausgaben pro Monat (Liniendiagramm) charts.default.incomesAndExpendituresPerMonthLine.localization='{"axisY": "Summe in ", "traceName1": "Einnahmen", "traceName2": "Ausgaben"'} +charts.default.incomesAndExpendituresByCategoryBar=Eingaben/Ausgaben nach Kategorien +charts.default.incomesAndExpendituresByCategoryBar.localization='{"label1": "Ausgaben", "label2": "Einnahmen"'} charts.default.categoryBudget=Verbrauch nach Kategorien chart.new.label.name=Name diff --git a/src/main/resources/languages/_en.properties b/src/main/resources/languages/_en.properties index 8d69f8452..a35b9dbd6 100644 --- a/src/main/resources/languages/_en.properties +++ b/src/main/resources/languages/_en.properties @@ -335,6 +335,8 @@ charts.default.incomesAndExpendituresPerMonthBar=Incomes/Expenditures per month charts.default.incomesAndExpendituresPerMonthBar.localization='{"axisY": "Sum in ", "traceName1": "Incomes", "traceName2": "Expenditures"'} charts.default.incomesAndExpendituresPerMonthLine=Incomes/Expenditures per month (Line chart) charts.default.incomesAndExpendituresPerMonthLine.localization='{"axisY": "Sum in ", "traceName1": "Incomes", "traceName2": "Expenditures"'} +charts.default.incomesAndExpendituresByCategoryBar=Incomes/Expenditures by categories +charts.default.incomesAndExpendituresByCategoryBar.localization='{"label1": "Expenditures", "label2": "Incomes"'} charts.default.categoryBudget=Consumption by categories chart.new.label.name=Name diff --git a/src/main/resources/templates/charts/charts.ftl b/src/main/resources/templates/charts/charts.ftl index a17fd5957..a23798e51 100644 --- a/src/main/resources/templates/charts/charts.ftl +++ b/src/main/resources/templates/charts/charts.ftl @@ -172,7 +172,7 @@ localizedData = JSON.parse('${locale.getString(chart.getName() + ".localization")}'); </#if> - ${chart.getScript()?replace("var transactionData = []", "var transactionData = ${transactionData};")} + ${chart.getScript()?replace("var transactionData = [];", "var transactionData = ${transactionData};")} </script> </#if> </body> -- GitLab