Skip to content
Snippets Groups Projects
FundingSource.tsx 11.88 KiB
import React, {ReactElement, useEffect, useState} from 'react';
import {ChartOptions, scales, Tick} from 'chart.js';
import {Bar} from 'react-chartjs-2';
import { cartesianProduct } from 'cartesian-product-multiple-arrays';

import {
    Chart as ChartJS,
    CategoryScale,
    LinearScale,
    BarElement,
    Title,
    Tooltip,
    Legend,
} from 'chart.js';
import {
    Budget,
    BudgetMatrix,
    DataEntrySection,
    FundingSource,
    FS, FundingGraphMatrix
} from "../Schema";
// import _default from "chart.js/dist/plugins/plugin.tooltip";
// import numbers = _default.defaults.animations.numbers;


ChartJS.register(
    CategoryScale,
    LinearScale,
    BarElement,
    Title,
    Tooltip,
    Legend
);


const data = {
    labels: ['NREN A', 'NREN B', 'NREN C', 'NREN D'],
    datasets: [
        {
            label: 'CLIENT INSTITUTIONS (2018)',
            data: [25, 25, 75],
            backgroundColor: '#FF6384',
            borderRadius:10,
            borderSkipped:false,
            barPercentage:0.5,
            stack: '2018',
        },
        {
            label: 'EUROPEAN FUNDING (2018)',
            data: [75, 50, 25],
            backgroundColor: '#36A2EB',
            borderRadius:10,
            borderSkipped:false,
            barPercentage:0.5,
            stack: '2018',
        },
        {
            label: 'GOV/PUBLIC_BODIES (2018)',
            data: [40, 20, 60],
            backgroundColor: '#FFCE56',
            borderRadius:10,
            borderSkipped:false,
            barPercentage:0.5,
            stack: '2018',
        },
        {
            label: 'COMMERCIAL (2018)',
            data: [60, 80, 40],
            backgroundColor: '#7FFF00',
            borderRadius:10,
            borderSkipped:false,
            barPercentage:0.5,
            stack: '2018',
        },
        {
            label: 'OTHER (2018)',
            data: [60, 80, 40],
            backgroundColor: '#BD34EB',
            borderRadius:10,
            borderSkipped:false,
            barPercentage:0.5,
            stack: '2018',
        },
        {
            label: 'CLIENT INSTITUTIONS (2019)',
            data: [35, 25, 65],
            backgroundColor: '#7363ff',
            borderRadius:10,
            borderSkipped:false,
            barPercentage:0.5,
            stack: '2019',
        },
        {
            label: 'EUROPEAN FUNDING (2019)',
            data: [45, 45, 15],
            backgroundColor: '#36ebbb',
            borderRadius:10,
            borderSkipped:false,
            barPercentage:0.5,
            stack: '2019',
        },
        {
            label: 'GOV/PUBLIC_BODIES (2019)',
            data: [50, 50, 40],
            backgroundColor: '#ffbb56',
            borderRadius:10,
            borderSkipped:false,
            barPercentage:0.5,
            stack: '2019',
        },
        {
            label: 'COMMERCIAL (2019)',
            data: [60, 50, 80],
            backgroundColor: '#ddff00',
            borderRadius:10,
            borderSkipped:false,
            barPercentage:0.5,
            borderWidth: 1,
            stack: '2019',
        },
        {
            label: 'OTHER (2019)',
            data: [70, 85, 40],
            backgroundColor: '#eb34a2',
            borderRadius:10,
            borderSkipped:false,
            barPercentage:0.5,
            stack: '2019',
        },
    ],
};



export const option ={
    plugins:{
        legend:{
            labels:{
                boxWidth:20,
                boxHeight:30,
                pointStyle:"rectRounded",
                borderRadius:6,
                useBorderRadius:true,
            },
        },
    },
    scales:{
        x: {
            stacked: true,
            ticks: {
                callback: (value: string | number) => {
                    if (typeof value === 'number') {
                        return value.toFixed(2);
                    }
                    return value;
                },
            },
        },
        y: {
            stacked: true,
        },
    },
    indexAxis: 'y',
};




function FundingSourcePage(): ReactElement {
    function api<T>(url: string, options: RequestInit | undefined = undefined): Promise<T> {
        return fetch(url, options)
            .then((response) => {
                if (!response.ok) {
                    return response.text().then((message) => {
                        console.error(`Failed to load datax: ${message}`, response.status);
                        throw new Error("The data could not be loaded, check the logs for details.");
                    });
                }

                return response.json() as Promise<T>;
            })
    }

    const [fundingMatrixResponse, setFundingMatrixResponse] = useState<FundingGraphMatrix>();
    const [fundingSourceResponse, setFundingSource] = useState<FundingSource[]>();
    const [dataEntrySection, setDataEntrySection] = useState<DataEntrySection>();
    const [selectedDataEntry, setSelectedDataEntry] = useState<number>(0);

    useEffect(() =>{
        const loadData = async () => {
            if (fundingSourceResponse == undefined) {
                api<FS>('/api/funding/', {})
                    .then((fundingSources: FS) => {
                        console.log('fundingSource:', fundingSources)
                        const entry = dataEntrySection?.items.find(i => i.id == selectedDataEntry)
                        console.log(selectedDataEntry, dataEntrySection, entry)
                        if (entry)
                            console.log("hello")
                            // options.plugins.title.text = entry.title;
                        setFundingSource(fundingSources.data)
                        convertToFundingSourcePerYearDataResponse(fundingSources.data)
                    })
                    .catch(error => {
                        console.log(`Error fetching from API: ${error}`);
                    })
            } else {
                convertToFundingSourcePerYearDataResponse(fundingSourceResponse)
            }

        }
        loadData()
    } ,[])

    const empty_funding_source_response = [
        {
            "CLIENT_INSTITUTIONS": "0.0",
            "COMMERCIAL": "0.0",
            "EUROPEAN_FUNDING": "0.0",
            "GOV_PUBLIC_BODIES": "0.0",
            "NREN": "",
            "OTHER": "0.0",
            "YEAR": 0,
            "id": 0
        }]

    const convertToFundingSourcePerYearDataResponse = (fundingSourcesResponse: FundingSource[]) => {
        const fsResponse = fundingSourcesResponse != undefined ? fundingSourcesResponse : empty_funding_source_response;
        const labelsYear = [...new Set(fsResponse.map((item:FundingSource) => item.YEAR))];
        const labelsNREN = [...new Set(fsResponse.map((item:FundingSource) => item.NREN))];
        const fundingComposition=[
            "CLIENT INSTITUTIONS",
            "COMMERCIAL",
            "EUROPEAN FUNDING",
            "GOV/PUBLIC_BODIES",
            "OTHER"
        ]
        const  dataSetKey = cartesianProduct(fundingComposition,labelsYear)
        console.log("Nrens : ",labelsNREN)
        console.log("Years : ",labelsYear)
        console.log(dataSetKey);

        function getRandomColor() {
            const red = Math.floor(Math.random() * 256).toString(16).padStart(2, '0'); // generates a value between 00 and ff
            const green = Math.floor(Math.random() * 256).toString(16).padStart(2, '0');
            const blue = Math.floor(Math.random() * 256).toString(16).padStart(2, '0');
            return `#${red}${green}${blue}`;
        }

        const rgbToHex = (r:number, g:number, b:number) => '#' + [r, g, b].map(x => {
            const hex = x.toString(16)
            return hex.length === 1 ? '0' + hex : hex
        }).join('')

        let colorMap = new Map<string, string>();
        colorMap.set("CLIENT INSTITUTIONS", rgbToHex(157,40,114))
        colorMap.set("COMMERCIAL", rgbToHex(241,224,79))
        colorMap.set("EUROPEAN FUNDING", rgbToHex(219,42,76))
        colorMap.set("GOV/PUBLIC_BODIES", rgbToHex(237,141,24))
        colorMap.set("OTHER", rgbToHex(137,166,121))


        const datasetFunding  = dataSetKey.map(function (entry) {

            // const randomColor = getRandomColor();
            const color:string = colorMap.get(entry[0])!;
            console.log(color)
            return {
                backgroundColor: color,
                label: entry[0]+"("+entry[1]+")",//composition+year
                data: labelsNREN.map(nren => dataPerCompositionPerYear(entry[1], nren,entry[0])),
                stack:entry[1],
                borderRadius:10,
                borderSkipped:false,
                barPercentage:0.5,
                borderWidth: 0.5,
                categoryPercentage:0.8

            }
            })

        function dataPerCompositionPerYear(year: number, nren: string, composition:string) {
            let compValue =""
            fsResponse.find(function (entry, index) {
                if (entry.YEAR == year && entry.NREN == nren) {
                    if(composition==="CLIENT INSTITUTIONS")
                        compValue= String(entry.CLIENT_INSTITUTIONS);
                    if(composition==="COMMERCIAL")
                        compValue= entry.COMMERCIAL;
                    if(composition==="EUROPEAN FUNDING")
                        compValue= entry.EUROPEAN_FUNDING;
                    if(composition==="GOV/PUBLIC_BODIES")
                        compValue= entry.GOV_PUBLIC_BODIES;
                    if(composition==="OTHER")
                        compValue= entry.OTHER;
                }
            })
            console.log(compValue)
            return compValue;
        }
        console.log(datasetFunding)

        const dataResponse: FundingGraphMatrix = {
            // datasets:  datasetFunding,
            datasets: datasetFunding,
            labels: labelsNREN.map(l => l.toString())
        }
        setFundingMatrixResponse(dataResponse);
    }
    const empty_bar_response = {
        datasets: [
            {
                backgroundColor: '',
                data: [],
                label: '',
                borderRadius:0,
                borderSkipped:false,
                barPercentage:0,
                borderWidth: 0,
                stack: '0',
                categoryPercentage:0.5
            }],
        labels: []
    }
    const fundingAPIResponse: FundingGraphMatrix = fundingMatrixResponse !== undefined
        ? fundingMatrixResponse : empty_bar_response;
    return (
        <div id="canvas_container" >
            <h1>Income Source</h1>
            <Bar data={fundingAPIResponse}
                 width={80}
                 height={300}
                 options={{
                     plugins:{
                         legend:{
                             display:false,
                             labels:{
                                 boxWidth:20,
                                 boxHeight:30,
                                 pointStyle:"rectRounded",
                                 borderRadius:6,
                                 useBorderRadius:true,

                             },
                         },
                     },
                     scales:{
                         x: {
                             stacked: true,
                             ticks: {
                                 callback: (value: string | number) => {
                                     if (typeof value === 'number') {
                                         return value.toFixed(2);
                                     }
                                     return value;
                                 },
                             },
                         },
                         y: {
                             stacked: true,
                         },
                     },
                     indexAxis: "y",
                     // maintainAspectRatio: false
                 }}
            ></Bar>
        </div>
    );
}
export default FundingSourcePage;