Skip to content

Commit

Permalink
feat(time-slider): add playback functionality (#398)
Browse files Browse the repository at this point in the history
  • Loading branch information
pwambach committed Jul 22, 2020
1 parent 583a99b commit 143fb46
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 40 deletions.
31 changes: 0 additions & 31 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions src/scripts/components/icons/pause-icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import React, {FunctionComponent} from 'react';

export const PauseIcon: FunctionComponent = () => (
<svg
width="24"
height="24"
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg">
<path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z" />
</svg>
);
40 changes: 40 additions & 0 deletions src/scripts/components/time-playback/time-playback.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import {FunctionComponent} from 'react';
import {useSelector, useDispatch} from 'react-redux';

import {timeSelector} from '../../selectors/globe/time';
import setGlobeTime from '../../actions/set-globe-time';
import {useInterval} from '../../hooks/use-interval';

const PLAYBACK_STEP = 1000 * 60 * 60 * 24 * 30; // one month
const PLAYBACK_SPEED = 1000; // increase one step per x milliseconds

interface Props {
minTime: number;
maxTime: number;
speed?: number;
step?: number;
}

const TimePlayback: FunctionComponent<Props> = ({
minTime,
maxTime,
speed = PLAYBACK_SPEED,
step = PLAYBACK_STEP
}) => {
const dispatch = useDispatch();
const time = useSelector(timeSelector);

useInterval(() => {
let newTime = time + step;

if (newTime > maxTime) {
newTime = minTime;
}

dispatch(setGlobeTime(newTime));
}, speed);

return null;
};

export default TimePlayback;
6 changes: 6 additions & 0 deletions src/scripts/components/time-slider/time-slider.styl
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ compareThumb()
font-size: emCalc(16px)

.container
position: relative
min-width: 400px
width: 30%

Expand Down Expand Up @@ -85,3 +86,8 @@ compareThumb()
bottom: 15px
color: $textWhite
transform: translateX(-50%)

.playButton
position: absolute
top: -4px
right: calc(100% + 1em)
27 changes: 19 additions & 8 deletions src/scripts/components/time-slider/time-slider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ import {State} from '../../reducers';
import {selectedLayerIdsSelector} from '../../selectors/layers/selected-ids';
import {getLayerTimeIndex} from '../../libs/get-layer-tile-url';
import TimeSliderRange from '../time-slider-range/time-slider-range';
import TimePlayback from '../time-playback/time-playback';
import Button from '../button/button';
import {PlayIcon} from '../icons/play-icon';
import {PauseIcon} from '../icons/pause-icon';

import styles from './time-slider.styl';

Expand All @@ -32,6 +36,7 @@ const TimeSlider: FunctionComponent = () => {
const language = useSelector(languageSelector);
const globeTime = useSelector(timeSelector);
const [time, setTime] = useState(globeTime);
const [isPlaying, setIsPlaying] = useState(false);
const stepSize = 1000 * 60 * 60 * 24; // one day
const mainLayerDetails = useSelector((state: State) =>
layerDetailsSelector(state, mainId)
Expand Down Expand Up @@ -81,16 +86,12 @@ const TimeSlider: FunctionComponent = () => {
[]
);

// clamp time according to min/max
// sync local time
useEffect(() => {
if (time < combined.min) {
setTime(combined.min);
if (time !== globeTime) {
setTime(globeTime);
}

if (time > combined.max) {
setTime(combined.max);
}
}, [time, combined.min, combined.max]);
}, [time, globeTime]);

// return nothing when no timesteps available
if (combined.timestamps.length === 0) {
Expand All @@ -108,7 +109,16 @@ const TimeSlider: FunctionComponent = () => {

return (
<div className={styles.timeSlider}>
{isPlaying && (
<TimePlayback minTime={combined.min} maxTime={combined.max} />
)}
<div className={styles.container}>
<Button
className={styles.playButton}
icon={isPlaying ? PauseIcon : PlayIcon}
onClick={() => setIsPlaying(!isPlaying)}>
{isPlaying ? 'playing' : 'pausing'}
</Button>
<div className={styles.ranges}>
<input
className={inputStyles}
Expand All @@ -118,6 +128,7 @@ const TimeSlider: FunctionComponent = () => {
const newTime = parseInt(target.value, 10);
setTime(newTime);
debouncedSetGlobeTime(newTime);
setIsPlaying(false);
}}
min={combined.min}
max={combined.max}
Expand Down
2 changes: 1 addition & 1 deletion src/scripts/hooks/use-interval.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {useEffect, useRef} from 'react';

export const useInterval = (callback: () => void, delay: number) => {
export const useInterval = (callback: () => void, delay: number | null) => {
const savedCallback = useRef<() => void | undefined>();

// Remember the latest callback.
Expand Down

0 comments on commit 143fb46

Please sign in to comment.