From 40c268575e122872e2bbbd7d0323d189801714a1 Mon Sep 17 00:00:00 2001 From: Rachele Morino Date: Tue, 28 Feb 2023 14:14:54 -0500 Subject: [PATCH 1/6] Add animated progress by time bar --- src/app/src/components/AnimatedMap.tsx | 86 +++++++++++++--------- src/app/src/components/TimeControlIcon.tsx | 21 ++++++ 2 files changed, 72 insertions(+), 35 deletions(-) create mode 100644 src/app/src/components/TimeControlIcon.tsx diff --git a/src/app/src/components/AnimatedMap.tsx b/src/app/src/components/AnimatedMap.tsx index 53a87ef..df31ecf 100644 --- a/src/app/src/components/AnimatedMap.tsx +++ b/src/app/src/components/AnimatedMap.tsx @@ -4,12 +4,11 @@ import { Heading, Spacer, HStack, - Slider, Box, - SliderTrack, - SliderFilledTrack, - SliderThumb, - SliderMark, + IconButton, + Progress, + Tag, + TagLabel, } from '@chakra-ui/react'; import L from 'leaflet'; @@ -17,6 +16,7 @@ import UsaMapContainer from './UsaMapContainer'; import { StateGeometry, StateProperties } from './states.geojson'; import StatesLayer from './StatesLayer'; +import TimeControlIcon from './TimeControlIcon'; import { MonthlySpendingOverTimeResponse, @@ -68,9 +68,12 @@ function StatesAndSliderLayer({ }) { const SLIDER_PRESENT_STEP = 26; const map = useMap(); + const [timeValue, setTimeValue] = useState(0); const [spendingAtTimeByState, setSpendingAtTimeByState] = useState(() => getSpendingByStateAtTime(1, spending) ); + const [playButtonDisabled, setPlayButtonDisabled] = useState(false); + const [restartTimeControl, setRestartTimeControl] = useState(false); useEffect(() => { map && @@ -95,8 +98,30 @@ function StatesAndSliderLayer({ }); }, [map, spendingAtTimeByState]); - function onSliderChange(timeValue: number) { - setSpendingAtTimeByState(getSpendingByStateAtTime(timeValue, spending)); + useEffect(() => { + if(playButtonDisabled){ + const monthlyInterval = setInterval(() => { + setTimeValue(timeValue + 1); + spending && setSpendingAtTimeByState(getSpendingByStateAtTime(timeValue, spending)); + }, + 250 + ); + return () => { + clearInterval(monthlyInterval); + if(timeValue === SLIDER_PRESENT_STEP-1){ + setPlayButtonDisabled(false); + setRestartTimeControl(true); + } + }; + } + }, [playButtonDisabled, timeValue, spending]); + + function onSelectTimeAnimation(){ + if(restartTimeControl){ + setTimeValue(0); + setRestartTimeControl(false); + } + setPlayButtonDisabled(true); } return ( @@ -118,34 +143,25 @@ function StatesAndSliderLayer({ }); }} /> - onSliderChange(val)} - step={1} - mt='575px' - width='50%' - ml='20%' - > - - - 2021 - - - present - - - - - + + } mr='25px' background='none' onClick={onSelectTimeAnimation} isDisabled={playButtonDisabled} /> + + 2021 + + Now + + ); } diff --git a/src/app/src/components/TimeControlIcon.tsx b/src/app/src/components/TimeControlIcon.tsx new file mode 100644 index 0000000..90a2475 --- /dev/null +++ b/src/app/src/components/TimeControlIcon.tsx @@ -0,0 +1,21 @@ +import { Icon } from '@chakra-ui/react'; + +export default function TimeControlIcon({ restart }: { restart: boolean }) { + return restart ? ( + + + + ) : ( + + + + ); +} From 0086f94fcfcab380a4fdd478e1f872e2065b162d Mon Sep 17 00:00:00 2001 From: Rachele Morino Date: Tue, 28 Feb 2023 14:31:33 -0500 Subject: [PATCH 2/6] Move legend above map --- src/app/src/components/AnimatedMap.tsx | 50 ++++++++++++++------------ 1 file changed, 27 insertions(+), 23 deletions(-) diff --git a/src/app/src/components/AnimatedMap.tsx b/src/app/src/components/AnimatedMap.tsx index df31ecf..e90bb80 100644 --- a/src/app/src/components/AnimatedMap.tsx +++ b/src/app/src/components/AnimatedMap.tsx @@ -31,32 +31,36 @@ export default function AnimatedMap() { Allocation of announced award funding over time + + + + + ≥1% BIL + + + ≥2% BIL + + + - - - - ≥1% BIL - - - ≥2% BIL - - ); } From 355682b1817b356f2c099f22d778ae4f1f600b39 Mon Sep 17 00:00:00 2001 From: Rachele Morino Date: Tue, 28 Feb 2023 14:56:20 -0500 Subject: [PATCH 3/6] Progres bar UI and smooth transitions --- src/app/src/components/AnimatedMap.tsx | 13 +++++++------ src/app/src/theme.ts | 5 ++++- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/app/src/components/AnimatedMap.tsx b/src/app/src/components/AnimatedMap.tsx index e90bb80..b52a37c 100644 --- a/src/app/src/components/AnimatedMap.tsx +++ b/src/app/src/components/AnimatedMap.tsx @@ -105,14 +105,14 @@ function StatesAndSliderLayer({ useEffect(() => { if(playButtonDisabled){ const monthlyInterval = setInterval(() => { - setTimeValue(timeValue + 1); - spending && setSpendingAtTimeByState(getSpendingByStateAtTime(timeValue, spending)); + setTimeValue(Math.round((timeValue + 0.1)*10)/10); + (timeValue % 1 === 0) && spending && setSpendingAtTimeByState(getSpendingByStateAtTime(timeValue, spending)); }, - 250 + 25 ); return () => { clearInterval(monthlyInterval); - if(timeValue === SLIDER_PRESENT_STEP-1){ + if(timeValue === SLIDER_PRESENT_STEP){ setPlayButtonDisabled(false); setRestartTimeControl(true); } @@ -149,16 +149,17 @@ function StatesAndSliderLayer({ /> } mr='25px' background='none' onClick={onSelectTimeAnimation} isDisabled={playButtonDisabled} /> - + 2021 Date: Tue, 28 Feb 2023 15:12:55 -0500 Subject: [PATCH 4/6] Make present value name more clear --- src/app/src/components/AnimatedMap.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/src/components/AnimatedMap.tsx b/src/app/src/components/AnimatedMap.tsx index b52a37c..5251e22 100644 --- a/src/app/src/components/AnimatedMap.tsx +++ b/src/app/src/components/AnimatedMap.tsx @@ -70,7 +70,7 @@ function StatesAndSliderLayer({ }: { spending: MonthlySpendingOverTimeResponse; }) { - const SLIDER_PRESENT_STEP = 26; + const PROGRESS_FINAL_MONTH = 26; const map = useMap(); const [timeValue, setTimeValue] = useState(0); const [spendingAtTimeByState, setSpendingAtTimeByState] = useState(() => @@ -112,7 +112,7 @@ function StatesAndSliderLayer({ ); return () => { clearInterval(monthlyInterval); - if(timeValue === SLIDER_PRESENT_STEP){ + if(timeValue === PROGRESS_FINAL_MONTH){ setPlayButtonDisabled(false); setRestartTimeControl(true); } @@ -157,7 +157,7 @@ function StatesAndSliderLayer({ colorScheme={'progress'} aria-label='date-time-progress-bar' min={0} - max={SLIDER_PRESENT_STEP} + max={PROGRESS_FINAL_MONTH} width='100%' maxWidth={'750px'} height='20px' From 63329f8e4d61ae109389cdea5a18c69b9bd4844b Mon Sep 17 00:00:00 2001 From: Rachele Morino Date: Wed, 1 Mar 2023 11:39:53 -0500 Subject: [PATCH 5/6] Refactor interval to be called once per play --- src/app/src/components/AnimatedMap.tsx | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/app/src/components/AnimatedMap.tsx b/src/app/src/components/AnimatedMap.tsx index 5251e22..67f4412 100644 --- a/src/app/src/components/AnimatedMap.tsx +++ b/src/app/src/components/AnimatedMap.tsx @@ -76,7 +76,7 @@ function StatesAndSliderLayer({ const [spendingAtTimeByState, setSpendingAtTimeByState] = useState(() => getSpendingByStateAtTime(1, spending) ); - const [playButtonDisabled, setPlayButtonDisabled] = useState(false); + const [animationEnabled, setAnimationEnabled] = useState(false); const [restartTimeControl, setRestartTimeControl] = useState(false); useEffect(() => { @@ -103,29 +103,32 @@ function StatesAndSliderLayer({ }, [map, spendingAtTimeByState]); useEffect(() => { - if(playButtonDisabled){ + (timeValue % 1 === 0) && spending && setSpendingAtTimeByState(getSpendingByStateAtTime(timeValue, spending)); + if(timeValue === PROGRESS_FINAL_MONTH){ + setAnimationEnabled(false); + setRestartTimeControl(true); + } + }, [timeValue, spending]) + + useEffect(() => { + if(animationEnabled){ const monthlyInterval = setInterval(() => { - setTimeValue(Math.round((timeValue + 0.1)*10)/10); - (timeValue % 1 === 0) && spending && setSpendingAtTimeByState(getSpendingByStateAtTime(timeValue, spending)); + setTimeValue(currentTimeValue => Math.round((currentTimeValue + 0.1)*10)/10); }, 25 ); return () => { clearInterval(monthlyInterval); - if(timeValue === PROGRESS_FINAL_MONTH){ - setPlayButtonDisabled(false); - setRestartTimeControl(true); - } }; } - }, [playButtonDisabled, timeValue, spending]); + }, [animationEnabled]); function onSelectTimeAnimation(){ if(restartTimeControl){ setTimeValue(0); setRestartTimeControl(false); } - setPlayButtonDisabled(true); + setAnimationEnabled(true); } return ( @@ -148,7 +151,7 @@ function StatesAndSliderLayer({ }} /> - } mr='25px' background='none' onClick={onSelectTimeAnimation} isDisabled={playButtonDisabled} /> + } mr='25px' background='none' onClick={onSelectTimeAnimation} isDisabled={animationEnabled} /> 2021 Date: Wed, 1 Mar 2023 12:07:50 -0500 Subject: [PATCH 6/6] Simplify animated map legend --- src/app/src/components/AnimatedMap.tsx | 30 ++------------------ src/app/src/components/AnimatedMapLegend.tsx | 29 +++++++++++++++++++ 2 files changed, 31 insertions(+), 28 deletions(-) create mode 100644 src/app/src/components/AnimatedMapLegend.tsx diff --git a/src/app/src/components/AnimatedMap.tsx b/src/app/src/components/AnimatedMap.tsx index 67f4412..652355f 100644 --- a/src/app/src/components/AnimatedMap.tsx +++ b/src/app/src/components/AnimatedMap.tsx @@ -3,7 +3,6 @@ import { useMap } from 'react-leaflet'; import { Heading, Spacer, - HStack, Box, IconButton, Progress, @@ -23,6 +22,7 @@ import { SpendingByGeographyAtMonth, } from '../types/api'; import { spendingDataByMonth } from './dummySpendingDataByMonth'; +import AnimatedMapLegend from './AnimatedMapLegend'; export default function AnimatedMap() { return ( @@ -31,33 +31,7 @@ export default function AnimatedMap() { Allocation of announced award funding over time - - - - - ≥1% BIL - - - ≥2% BIL - - - + diff --git a/src/app/src/components/AnimatedMapLegend.tsx b/src/app/src/components/AnimatedMapLegend.tsx new file mode 100644 index 0000000..10f57fc --- /dev/null +++ b/src/app/src/components/AnimatedMapLegend.tsx @@ -0,0 +1,29 @@ +import { HStack, Box } from '@chakra-ui/react'; + +export function ColorRangeBox({ bg, text }: { bg: string, text?: String }) { + return ( + + {text} + + ); +} + +export default function AnimatedMapLegend() { + return ( + + + + + + + + ); +}