Skip to content
Snippets Groups Projects
Select Git revision
  • b0b4c81f4d02b8e28317101d08638b733594a603
  • develop default
  • master protected
  • feature/frontend-tests
  • 0.110
  • 0.109
  • 0.108
  • 0.107
  • 0.106
  • 0.105
  • 0.104
  • 0.103
  • 0.102
  • 0.101
  • 0.100
  • 0.99
  • 0.98
  • 0.97
  • 0.96
  • 0.95
  • 0.94
  • 0.93
  • 0.92
  • 0.91
24 results

survey-bundle.js

Blame
  • FundingSource.tsx 6.03 KiB
    import React, {useEffect, useMemo, useState} from 'react';
    import {Bar} from 'react-chartjs-2';
    import {Col, Row} from "react-bootstrap";
    import {Chart as ChartJS} from 'chart.js';
    import ChartDataLabels from 'chartjs-plugin-datalabels';
    
    import {FilterSelection, FundingSource} from "../Schema";
    import {
      createFundingSourceDataset,
      getYearsAndNrens,
      loadDataWithFilterSelectionFallback
    } from "../helpers/dataconversion";
    import DataPage from '../components/DataPage';
    import Filter from "../components/graphing/Filter"
    import {ExportType, Sections} from '../helpers/constants';
    import ColorBadge from '../components/ColorBadge';
    import DownloadDataButton from "../components/DownloadDataButton";
    
    export const chartOptions = {
      maintainAspectRatio: false,
      layout: {
        padding: {
            right: 60
        }
      },
      animation: {
        duration: 0,
      },
      plugins: {
        legend: {
          display: false
        }
      },
      scales: {
        x: {
          position: "top" as const,
          ticks: {
            callback: (value: string | number) => {
              if (typeof value === "number") {
                return `${value}%`;
              }
              return value;
            },
          },
        },
        xBottom: {
          ticks: {
            callback: (value: string | number) => {
              if (typeof value === "number") {
                return `${value}%`;
              }
              return value;
            }
          },
          grid: {
            drawOnChartArea: false
          },
          afterDataLimits: function (axis) {
            const indices = Object.keys(ChartJS.instances)
    
            // initial values should be far outside possible range
            let max = -999999
            let min = 999999
    
            for (const index of indices) {
              if (ChartJS.instances[index] && axis.chart.scales.xBottom) {
                min = Math.min(ChartJS.instances[index].scales.x.min, min);
                max = Math.max(ChartJS.instances[index].scales.x.max, max);
              }
            }
    
            axis.chart.scales.xBottom.options.min = min;
            axis.chart.scales.xBottom.options.max = max;
            axis.chart.scales.xBottom.min = min;
            axis.chart.scales.xBottom.max = max;
          },
        },
        y: {
          ticks: {
            autoSkip: false
          },
        }
      },
      indexAxis: "y" as const,
    };
    
    function FundingSourceLegend() {
      return (
        <div className="d-flex justify-content-center bold-grey-12pt">
          <Row xs="auto" className="border rounded-3 border-1 my-5 justify-content-center">
            <Col className="d-flex align-items-center">
              <ColorBadge key={0} index={0} />Client Institutions
            </Col>
            <Col className="d-flex align-items-center">
              <ColorBadge key={1} index={1} />Commercial
            </Col>
            <Col className="d-flex align-items-center">
              <ColorBadge key={2} index={2} />European Funding
            </Col>
            <Col className="d-flex align-items-center">
              <ColorBadge key={3} index={3} />Gov/Public Bodies
            </Col>
            <Col className="d-flex align-items-center">
              <ColorBadge key={4} index={4} />Other
            </Col>
          </Row>
        </div>
      );
    }
    
    
    interface inputProps {
      filterSelection: FilterSelection
      setFilterSelection: React.Dispatch<React.SetStateAction<FilterSelection>>
    }
    
    function FundingSourcePage({ filterSelection, setFilterSelection }: inputProps) {
      const [fundingSourceData, setFundingSourceData] = useState<FundingSource[]>([]);
    
      const { years, nrens } = useMemo(
        () => getYearsAndNrens(fundingSourceData),
        [fundingSourceData]
      );
      const fundingSourceDataset = createFundingSourceDataset(fundingSourceData);
    
      fundingSourceDataset.datasets.forEach(dataset => {
        dataset.hidden = !filterSelection.selectedYears.includes(parseInt(dataset.stack));
      });
    
      // remove the datapoints and labels for the nrens that aren't selected
      // unfortunately we cannot just hide them because graph.js doesn't want
      // to create a stack from a single dataset
      fundingSourceDataset.datasets.forEach(dataset => {
        dataset.data = dataset.data.filter((e, i) => {
          return filterSelection.selectedNrens.includes(fundingSourceDataset.labels[i]);
        });
      });
      fundingSourceDataset.labels = fundingSourceDataset.labels.filter((e) => filterSelection.selectedNrens.includes(e));
    
      useEffect(() => {
        loadDataWithFilterSelectionFallback('/api/funding/', setFundingSourceData, setFilterSelection);
      }, [setFilterSelection]);
    
      const filterNode = <Filter
        filterOptions={{ availableYears: [...years], availableNrens: [...nrens.values()] }}
        filterSelection={filterSelection}
        setFilterSelection={setFilterSelection}
      />
    
      const numNrens = filterSelection.selectedNrens.length;
      const numYears = filterSelection.selectedYears.length;
      const heightPerBar = 2; // every added bar should give this much additional height
    
      // set a minimum height of 20rem, additional years need some more space
      const height = numNrens * numYears * heightPerBar + 5;
      return (
        <DataPage title="Income Source Of NRENs per Year"
          description='The graph shows the percentage share of their income that individual NRENs derived from different sources.
            On hovering over the graphs will give income share in that year.  This can be used to compare selecting multiple years to see how the 
            share has changed between the years.'
          category={Sections.Organisation} filter={filterNode}>
            <>
                <Row>
                    <DownloadDataButton data={fundingSourceData} filename="income_source_of_nren_per_year.csv" exportType={ExportType.CSV}/>
                    <DownloadDataButton data={fundingSourceData} filename="income_source_of_nren_per_year.xlsx" exportType={ExportType.EXCEL}/>
                </Row>
                <div>
                    <FundingSourceLegend/>
                    <div className="chart-container" style={{'height': `${height}rem`}}>
                        <Bar
                            plugins={[ChartDataLabels]}
                            data={fundingSourceDataset}
                            options={chartOptions}
                        />
                    </div>
                    <FundingSourceLegend/>
                </div>
            </>
        </DataPage>
      );
    }
    export default FundingSourcePage;