Skip to content
Snippets Groups Projects
Bar.tsx 8.94 KiB
Newer Older
  • Learn to ignore specific revisions
  • Hugo NOUTS's avatar
    Hugo NOUTS committed
    import { ScaleBand, ScaleLinear } from 'd3-scale'
    
    Romain CREY's avatar
    Romain CREY committed
    import { detect } from 'detect-browser'
    
    import { FluidType, TimeStep } from 'enums'
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
    import { DateTime } from 'luxon'
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    import { Dataload } from 'models'
    
    import React, { useEffect, useState } from 'react'
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    import DateChartService from 'services/dateChart.service'
    
    import {
    
      setCurrentDataChartIndex,
    
      setSelectedDate,
    
    } from 'store/chart/chart.slice'
    
    import { useAppDispatch, useAppSelector } from 'store/hooks'
    
    Yoan VALLET's avatar
    Yoan VALLET committed
    
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
    interface BarProps {
      index: number
    
    Yoan VALLET's avatar
    Yoan VALLET committed
      dataload: Dataload
      compareDataload: Dataload | null
    
      fluidType: FluidType
    
      timeStep: TimeStep
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
      xScale: ScaleBand<string>
      yScale: ScaleLinear<number, number>
      height: number
    
      isSwitching: boolean
    
    Rémi PAPIN's avatar
    Rémi PAPIN committed
      isDuel?: boolean
    
      isMultiMissingFluid?: boolean
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
    }
    
    
    const Bar = ({
      index,
      dataload,
      compareDataload,
    
      fluidType,
    
      timeStep,
    
      xScale,
      yScale,
      height,
      isSwitching,
    
    Rémi PAPIN's avatar
    Rémi PAPIN committed
      isDuel,
    
    }: BarProps) => {
    
      const dispatch = useAppDispatch()
      const { selectedDate } = useAppSelector(state => state.ecolyo.chart)
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
      const [clicked, setClicked] = useState(false)
      const [animationEnded, setAnimationEnded] = useState(false)
      const [compareAnimationEnded, setCompareAnimationEnded] = useState(false)
    
    Romain CREY's avatar
    Romain CREY committed
      const browser = detect()
    
    
      const fluidStyle =
        fluidType === FluidType.MULTIFLUID ? 'MULTIFLUID' : FluidType[fluidType]
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
      const handleClick = () => {
    
        if (!isSwitching && !isDuel && clickable) {
    
          setClicked(true)
    
          dispatch(setSelectedDate(dataload.date))
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
      }
    
      const onAnimationEnd = () => {
        setClicked(false)
        setAnimationEnded(true)
      }
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
      const onCompareAnimationEnd = () => {
        setClicked(false)
        setCompareAnimationEnded(true)
      }
    
    
      const tempYScale: number | undefined = yScale(dataload.value)
      const yScaleValue: number = tempYScale ? tempYScale : 0
    
      const tempCompareYScale: number | undefined = yScale(
        compareDataload ? compareDataload.value : 0
      )
      const yScaleCompareValue: number = tempCompareYScale ? tempCompareYScale : 0
    
      const tempXScale: number | undefined = xScale(
        dataload.date.toLocaleString(DateTime.DATETIME_SHORT)
      )
      const xScaleValue: number = tempXScale ? tempXScale : 0
    
    
    Yoan VALLET's avatar
    Yoan VALLET committed
      const isSelectedDate = isDuel
        ? false
        : new DateChartService().compareStepDate(
            timeStep,
            selectedDate,
            dataload.date
          )
    
    Romain CREY's avatar
    Romain CREY committed
    
    
      const delayIndex = index % 13
      const edgeBrowser = browser && browser.name !== 'edge'
      const selected = isSelectedDate ? ' selected' : ''
      const bounce = edgeBrowser ? '1' : '3'
    
      const disabled = `${clickable ? '' : 'disabled'}`
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
    
    
      const getBarClass = () => {
        const bounceDelay = ` bounce-${bounce} delay--${delayIndex}`
        const fluidWeekdays = `bar-${fluidStyle} ${weekdays}`
    
        if (clicked) {
          return `${fluidWeekdays}${selected} bounce-2 delay`
        } else if (animationEnded) {
    
          return `${fluidWeekdays}${selected} ${disabled}`
    
        return `${fluidWeekdays}${bounceDelay}${selected} ${disabled}`
    
      }
    
      const getCompareBarClass = () => {
        const bounceValue = clicked ? (edgeBrowser ? '2' : '3') : bounce
        const bounceDelay = ` bounce-${bounceValue} delay--${
          clicked ? 0 : delayIndex
        }`
        const fluidStyleClass = `bar-compare-${fluidStyle}`
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
    
    
        if (clicked) {
          return `${fluidStyleClass} ${selected}${bounceDelay}`
        }
        if (isSelectedDate) {
          return compareAnimationEnded
            ? `${fluidStyleClass} ${selected}`
            : `${fluidStyleClass} ${selected}${bounceDelay}`
        }
        return compareAnimationEnded
          ? fluidStyleClass
          : `${fluidStyleClass} ${bounceDelay}`
      }
    
      const compareBarClass = getCompareBarClass()
      const barClass = getBarClass()
    
      const barBackgroundClass = isSelectedDate
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
    
      const getBandWidth = (): number => {
    
        return compare ? xScale.bandwidth() / 2 : xScale.bandwidth()
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
      }
    
      const topRoundedRect = (
    
        _x: number,
        _y: number,
        _width: number,
        _height: number
      ): string => {
        const radius = _height > 4 ? 4 : _height / 4
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
        return (
          'M' +
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
          ',' +
    
          (_y + radius) +
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
          ' a' +
          radius +
          ',' +
          radius +
          ' 0 0 1 ' +
          radius +
          ',' +
          -radius +
          'h' +
    
          (_width - 2 * radius) +
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
          'a' +
          radius +
          ',' +
          radius +
          ' 0 0 1 ' +
          radius +
          ',' +
          radius +
          'v' +
    
          (_height - radius) +
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
          'h' +
    
          -_width +
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
          'z'
        )
      }
    
      useEffect(() => {
    
    Yoan VALLET's avatar
    Yoan VALLET committed
        if (isSelectedDate && !isDuel) {
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
          setClicked(true)
    
          dispatch(setCurrentDataChartIndex(index))
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
        }
    
    Yoan VALLET's avatar
    Yoan VALLET committed
      }, [dispatch, isSelectedDate, isDuel, index])
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
    
      return (
        <g>
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
          {height > 0 && (
    
            <g
              transform={`translate(${xScaleValue}, -40)`}
    
              className={`barContainer ${disabled}`}
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
              <rect
    
                onClick={!weekdays ? handleClick : () => undefined}
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
                x="0"
                y="0"
    
                width={compare ? getBandWidth() * 2 : getBandWidth()}
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
                height={height + 40}
                className={`background-${barBackgroundClass}`}
    
    Romain CREY's avatar
    Romain CREY committed
                fill="#E0E0E0"
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
              />
            </g>
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
          {height > 0 && dataload.value >= 0 && isMultiMissingFluid ? (
    
            <g
              transform={`translate(${xScaleValue}, ${yScaleValue})`}
              fill="#00000"
    
              className="barFill"
    
              <defs>
                <linearGradient
                  id="gradient"
                  className={barClass}
                  x1="0"
                  x2="0"
                  y1="0"
                  y2="1"
                >
                  <stop id="stop-color-1" offset="0%" />
                  <stop id="stop-color-2" offset="100%" />
                </linearGradient>
                <pattern
                  id="diagonalHatch"
                  patternUnits="userSpaceOnUse"
    
    Guilhem CARRON's avatar
    Guilhem CARRON committed
                  width="8"
                  height="8"
    
                  <rect x="0" y="0" width="100%" height="100%" fill="#121212" />
    
    Guilhem CARRON's avatar
    Guilhem CARRON committed
                  <path d="M0 8h20z" strokeWidth="3" stroke="#71612E" fill="none" />
    
                </pattern>
                <pattern
                  id="diagonalHatchSelected"
                  patternUnits="userSpaceOnUse"
    
    Guilhem CARRON's avatar
    Guilhem CARRON committed
                  width="8"
                  height="8"
    
                  <rect x="0" y="0" width="100%" height="100%" fill="#121212" />
    
    Guilhem CARRON's avatar
    Guilhem CARRON committed
                  <path d="M0 8h20z" strokeWidth="3" stroke="#E3B82A" fill="none" />
    
                </pattern>
              </defs>
              <path
                d={topRoundedRect(
    
                  compare ? getBandWidth() : 0,
    
                  0,
                  getBandWidth(),
                  height - yScaleValue
                )}
    
                stroke={!isSelectedDate ? '#71612E' : '#e3b82a'}
    
                fill={
                  isSelectedDate
                    ? 'url(#diagonalHatchSelected)'
                    : 'url(#diagonalHatch)'
                }
                // className={isDuel ? 'bar-duel' : barClass}
    
                onClick={!weekdays ? handleClick : () => undefined}
    
                onAnimationEnd={onAnimationEnd}
              />
            </g>
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
          ) : (
            height > 0 &&
            dataload.value &&
            dataload.value >= 0 && (
              <g transform={`translate(${xScaleValue}, ${yScaleValue})`}>
                <defs>
                  <linearGradient
                    id="gradient"
                    className={barClass}
                    x1="0"
                    x2="0"
                    y1="0"
                    y2="1"
                  >
                    <stop id="stop-color-1" offset="0%" />
                    <stop id="stop-color-2" offset="100%" />
                  </linearGradient>
                </defs>
                <path
                  d={topRoundedRect(
    
                    compare ? getBandWidth() : 0,
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
                    0,
                    weekdays ? 3 : getBandWidth(),
                    height - yScaleValue
                  )}
                  fill="url(#gradient)"
                  className={isDuel ? 'bar-duel' : barClass}
    
                  onClick={!weekdays ? handleClick : () => undefined}
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
                  onAnimationEnd={onAnimationEnd}
                />
              </g>
            )
          )}
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
    
    
          {compare && compareDataload && compareDataload.value >= 0 && (
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
            <g transform={`translate(${xScaleValue}, ${yScaleCompareValue})`}>
              <defs>
                <linearGradient
                  id="gradient-compare"
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
                  className={compareBarClass}
    
    Bastien DUMONT's avatar
    Bastien DUMONT committed
                  x1="0"
                  x2="0"
                  y1="0"
                  y2="1"
                >
                  <stop id="stop-compare-color-1" offset="0%" />
                  <stop id="stop-compare-color-2" offset="100%" />
                </linearGradient>
              </defs>
              <path
                d={topRoundedRect(
                  0,
                  0,
                  getBandWidth(),
                  height - yScaleCompareValue
                )}
                fill="url(#gradient-compare)"
                className={compareBarClass}
                onClick={handleClick}
                onAnimationEnd={onCompareAnimationEnd}
              />
            </g>
          )}
    
    Hugo NOUTS's avatar
    Hugo NOUTS committed
        </g>
      )
    }
    
    export default Bar