Skip to content
Snippets Groups Projects
Select Git revision
  • 0e00d6bb3403899e4c31c9237f2570d71465e2a4
  • master default
  • renovate/opencsv.version
  • renovate/org.springframework.boot-spring-boot-starter-parent-3.x
  • renovate/junit-jupiter-engine.version
  • renovate/selenium.version
  • renovate/testcontainer.version
  • demo
  • v1_8_1
  • v2.18.1
  • v2.18.0
  • v2.17.2
  • v2.17.1
  • v2.17.0
  • v2.16.1
  • v2.16.0
  • v2.15.1
  • v2.15.0
  • v2.14.0
  • v2.13.0
  • v2.12.0
  • v2.11.0
  • v2.10.0
  • v2.9.2
  • v2.9.1
  • v2.9.0
  • v2.8.0
  • testPipeline2
  • v2.7.0
29 results

IncomesAndExpendituresPerMonthByCategories.js

Blame
  • IncomesAndExpendituresPerMonthByCategories.js 6.01 KiB
    /* 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.
    
    transactionData = transactionData.reverse();
    
    moment.locale('de');
    
    const NAME = 0;
    const COLOR = 1;
    const INCOME = 2;
    const EXPENDITURE = 3;
    
    var categoryNames = [];
    var categoryColors = [];
    
    for(var i = 0; i < transactionData.length; i++)
    {
        var currentTransaction = transactionData[i];
        if(!categoryNames.includes(currentTransaction.category.name))
        {
            categoryNames.push(currentTransaction.category.name);
            categoryColors.push(currentTransaction.category.color);
        }
    }
    
    var dates = [];
    var values = [];
    
    for(var i = 0; i < transactionData.length; i++)
    {
        var transaction = transactionData[i];
    
        var date = moment(transaction.date).startOf('month').format('MMM YY');
        if(!dates.includes(date))
        {
            dates.push(date);
            values.push([
                categoryNames, // NAME
                categoryColors, // COLOR
                new Array(categoryNames.length).fill(0), // INCOME
                new Array(categoryNames.length).fill(0)  // EXPENDITURE
            ]);
        }
    
        // determine index of category name in list
        var lastIndex = values.length - 1;
    
        var categoryName = transaction.category.name;
        // create new category if not already in dict
        if(!values[lastIndex][NAME].includes(categoryName))
        {
            values[lastIndex][NAME].push(categoryName);
            values[lastIndex][COLOR].push(transaction.category.color);
            values[lastIndex][INCOME].push(0);
            values[lastIndex][EXPENDITURE].push(0);
        }
    
        // determine index of category in current last values
        var index = values[lastIndex][NAME].indexOf(categoryName);
    
        // add to income or expenditure sum
        var amount = transaction.amount;
        if(amount > 0)
        {
            values[lastIndex][INCOME][index] = values[lastIndex][INCOME][index] + amount;
        }
        else
        {
            values[lastIndex][EXPENDITURE][index] = values[lastIndex][EXPENDITURE][index] + Math.abs(amount);
        }
    }
    
    var totalIncomeSums = [];
    var totalExpenditureSums = [];
    
    // calculate total sums for all months
    for(var i = 0; i < dates.length; i++)
    {
        var totalIncomes = 0;
        var totalExpenditures = 0;
    
        values[i][INCOME].forEach(function(value)
        {
            totalIncomes += value;
        });
    
        values[i][EXPENDITURE].forEach(function(value)
        {
            totalExpenditures += value;
        });
    
        totalIncomeSums.push(totalIncomes);
        totalExpenditureSums.push(totalExpenditures);
    }
    
    // Prepare your chart settings here (mandatory)
    var plotlyData = [];
    var plotlyLayout = {
        title: {
            text: localizedTitle
        },
        barmode: "stack",
        hovermode: 'closest', // show hover popup only for hovered item
        yaxis: {
            rangemode: 'tozero',
            tickformat: '.0f',
            ticksuffix: localizedCurrency,
            showline: true
        }
    };
    
    // create one stacked bar for incomes and one for expenditures for every month and group them by month
    for(var i = 0; i < dates.length; i++)
    {
        for(var j = 0; j < values[i][NAME].length; j++)
        {
            var currentValues = values[i];
            var currentName = currentValues[NAME][j];
    
            var currentIncomeValue = currentValues[INCOME][j];
            var percentageIncome = (100 / totalIncomeSums[i]) * currentIncomeValue;
            var textIncome = prepareHoverText(currentName, percentageIncome, currentIncomeValue);
    
            var currentExpenditureValue = currentValues[EXPENDITURE][j];
            var percentageExpenditure = (100 / totalExpenditureSums[i]) * currentExpenditureValue;
            var textExpenditure = prepareHoverText(currentName, percentageExpenditure, currentExpenditureValue);
    
            // add border if category color is white
            var borderWidth = 0;
            if(currentValues[COLOR][j] === '#FFFFFF')
            {
                borderWidth = 1;
            }
    
            plotlyData.push({
                x: [localizedData['label2'], localizedData['label1']],
                y: [currentIncomeValue / 100.0, currentExpenditureValue / 100.0],
                type: 'bar',
                hoverinfo: 'text',
                text: [textIncome, textExpenditure],
                name: currentName,
                xaxis: 'x' + (i + 1),  // for grouping incomes and expenditure bar by month
                barmode: 'stack',
                showlegend: i === 0,
                legendgroup: currentName,
                marker: {
                    color: currentValues[COLOR][j],  // use the category's color
                    line: {
                        color: '#212121',
                        width: borderWidth
                    }
                }
            });
        }
    
        // axis number inside layout uses a different counting in comparison to xaxis definition in plotlyDate
        var axisNumber = i + 1;
        if(i === 0)
        {
            axisNumber = '';
        }
    
        // calculate subplot start and end position (relative between 0 and 1)
        var width = 1 / dates.length;
        var start = i * width;
        var end = (i + 1) * width;
    
        plotlyLayout['xaxis' + axisNumber] = {
            domain: [start, end],
            anchor: 'x' + axisNumber,
            title: dates[i],
        }
    }
    
    // Add your Plotly configuration settings here (optional)
    var plotlyConfig = {
        showSendToCloud: false,
        displaylogo: false,
        showLink: false,
        responsive: true,
        displayModeBar: true,
        toImageButtonOptions: {
            format: 'png',
            filename: 'BudgetMaster_chart_export',
            height: 1080,
            width: 1920,
        }
    };
    
    // Don't touch this line
    Plotly.newPlot("containerID", plotlyData, plotlyLayout, plotlyConfig);
    
    
    function prepareHoverText(categoryName, percentage, value)
    {
        value = value / 100;
        return categoryName + ' ' + percentage.toFixed(1) + '% (' + value.toFixed(1) + ' ' + localizedCurrency + ')';
    }