-
Saket Agrahari authoredSaket Agrahari authored
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;