Skip to content
Snippets Groups Projects
BarChart.tsx 5.26 KiB
Newer Older
  • Learn to ignore specific revisions
  • import React, { useContext, useEffect } from 'react'
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
    import { scaleBand, ScaleBand, scaleLinear, ScaleLinear } from 'd3-scale'
    import {
      IDataload,
      IChartData,
      TimeStep,
      ITimePeriod,
    } from 'services/dataConsumptionContracts'
    import { FluidType } from 'enum/fluid.enum'
    import Bar from 'components/ContentComponents/Charts/Bar'
    import Hash from 'components/ContentComponents/Charts/Hash'
    import AxisBottom from 'components/ContentComponents/Charts/AxisBottom'
    import AxisRight from 'components/ContentComponents/Charts/AxisRight'
    import { DateTime } from 'luxon'
    
    Romain CREY's avatar
    Romain CREY committed
    import { AppContext } from 'components/Contexts/AppContextProvider'
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
    
    export interface BarChartProps {
      chartData: IChartData
      fluidTypes: FluidType[]
      timeStep: TimeStep
      multiFluid: boolean
      selectedDate: DateTime
      showCompare: boolean
      challengePeriod: ITimePeriod | null
      handleClickData: (
        dataload: IDataload,
        compareDataload: IDataload | null
      ) => void
      width?: number
      height?: number
      marginLeft?: number
      marginRight?: number
      marginTop?: number
      marginBottom?: number
    
      isSwitching: boolean
    
    Romain CREY's avatar
    Romain CREY committed
      isHome: boolean
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
    }
    
    interface DefaultProps {
      width: number
      height: number
      marginLeft: number
      marginRight: number
      marginTop: number
      marginBottom: number
    }
    
    type PropsWithDefaults = BarChartProps & DefaultProps
    
    const BarChart: React.FC<BarChartProps> = (props: BarChartProps) => {
      const {
        chartData,
        fluidTypes,
        timeStep,
        multiFluid,
        selectedDate,
        showCompare,
        challengePeriod,
        handleClickData,
        width,
        height,
        marginLeft,
        marginRight,
        marginTop,
        marginBottom,
    
    Romain CREY's avatar
    Romain CREY committed
        isHome,
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
      } = props as PropsWithDefaults
    
    Romain CREY's avatar
    Romain CREY committed
      const { setChartIsLoaded, maxLoads } = useContext(AppContext)
    
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
      const getContentWidth = () => {
        return width - marginLeft - marginRight
      }
    
      const getContentHeight = () => {
        return height - marginTop - marginBottom
      }
    
      const getMaxLoad = () => {
    
          (timeStep === TimeStep.DAY && !showCompare) ||
          timeStep === TimeStep.HALF_AN_HOUR
    
    Romain CREY's avatar
    Romain CREY committed
          const actualMonth = selectedDate.startOf('week').month
          const actualYear = selectedDate.startOf('week').year
          const key = `${actualMonth}/${actualYear}-${isHome}-${fluidTypes
            .sort()
    
            .join('-')}-${timeStep}`
    
          if (DateTime.local() < selectedDate && !maxLoads[key]) {
            maxLoads[key] = 15
          }
    
    
    Romain CREY's avatar
    Romain CREY committed
          return maxLoads[key] > 0 ? maxLoads[key] : 15
        } else {
          let max = chartData.actualData
            ? Math.max(...chartData.actualData.map(d => d.value))
            : 0
          const maxCompare = chartData.comparisonData
            ? Math.max(...chartData.comparisonData.map(d => d.value))
            : 0
          max = max <= 0 ? 15 : max
          return showCompare ? Math.max(max, maxCompare) : max
        }
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
      }
    
      const xScale: ScaleBand<string> = scaleBand()
        .domain(
          chartData.actualData.map(d =>
            d.date.toLocaleString(DateTime.DATETIME_SHORT)
          )
        )
        .range([0, getContentWidth()])
        .padding(0.2)
    
      const xScaleWithoutPadding: ScaleBand<string> = scaleBand()
        .domain(
          chartData.actualData.map(d =>
            d.date.toLocaleString(DateTime.DATETIME_SHORT)
          )
        )
        .range([0, getContentWidth()])
    
      const yScale: ScaleLinear<number, number> = scaleLinear()
        .domain([0, getMaxLoad()])
        .range([getContentHeight(), 0])
    
    Romain CREY's avatar
    Romain CREY committed
      useEffect(() => {
    
        if (Object.keys(maxLoads).length > 0) {
    
    Romain CREY's avatar
    Romain CREY committed
          setChartIsLoaded(true)
        }
    
      }, [maxLoads])
    
    Romain CREY's avatar
    Romain CREY committed
      useEffect(() => {
        setChartIsLoaded(true)
      }, [])
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
    
      return (
        <svg width={width} height={height}>
    
          {timeStep === TimeStep.DAY && (
            <g transform={`translate(${marginLeft},${marginTop})`}>
              <Hash
                challengePeriod={challengePeriod}
                multiFluid={multiFluid}
                xScale={xScale}
                padding={
                  (xScaleWithoutPadding.bandwidth() - xScale.bandwidth()) / 2
                }
                width={getContentWidth()}
                height={getContentHeight()}
                chartData={chartData}
              />
            </g>
          )}
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
          <AxisRight
            fluidTypes={fluidTypes}
            yScale={yScale}
            width={width}
            marginRight={marginRight}
            marginTop={marginTop}
          />
          <g transform={`translate(${marginLeft},${marginTop})`}>
            {chartData.actualData.map((d, index) => (
              <Bar
                key={index}
                index={index}
                dataload={d}
                compareDataload={
                  chartData.comparisonData ? chartData.comparisonData[index] : null
                }
                fluidTypes={fluidTypes}
                timeStep={timeStep}
                multiFluid={multiFluid}
                selectedDate={selectedDate}
                showCompare={showCompare}
                handleClickData={handleClickData}
                xScale={xScale}
                yScale={yScale}
                height={getContentHeight()}
    
                isSwitching={isSwitching}
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
              />
            ))}
          </g>
          <AxisBottom
            data={chartData.actualData}
            timeStep={timeStep}
            xScale={xScale}
            height={height}
            marginLeft={marginLeft}
            marginBottom={marginBottom}
            selectedDate={selectedDate}
          />
        </svg>
      )
    }
    
    BarChart.defaultProps = {
      width: 600,
      height: 400,
      marginLeft: 10,
      marginRight: 60,
      marginTop: 20,
      marginBottom: 50,
    }
    
    export default BarChart