import React from 'react'; import styled from '@emotion/styled'; import { TimeInterval } from 'd3-time'; import { Colors } from '@blueprintjs/core'; interface Props { darkMode: boolean; current: Date; extent: [Date, Date]; interval: TimeInterval; stepDuration: number; speed: number; isPlaying: boolean; onPlay: () => void; onPause: () => void; onAdvance: (date: Date) => void; } const width = 40, height = 40; const OuterSvg = styled.svg<{ darkMode: boolean }>((props) => ({ cursor: 'pointer', '& > circle': { transition: 'fill 0.2s', fill: props.darkMode ? Colors.GRAY4 : Colors.WHITE, }, '&:hover': { '& > circle': { fill: props.darkMode ? Colors.WHITE : Colors.GRAY4, }, }, })); const OuterCircle = styled.circle({ cursor: 'pointer', strokeWidth: 1, stroke: '#000', }); class PlayControl extends React.Component { playTimeout: NodeJS.Timeout | undefined; static defaultProps = { speed: 1, }; componentWillUnmount(): void { this.clearPlayTimeOut(); } start = () => { const { isPlaying, onPlay } = this.props; if (!isPlaying) { const { extent, current, onAdvance } = this.props; onPlay(); this.scheduleNextStep(); if (current >= extent[1]) { // rewind onAdvance(extent[0]); } } }; stop = () => { this.clearPlayTimeOut(); const { isPlaying, onPause } = this.props; if (isPlaying) { onPause(); } }; clearPlayTimeOut = () => { if (this.playTimeout != null) { clearTimeout(this.playTimeout); this.playTimeout = undefined; } }; scheduleNextStep = () => { this.clearPlayTimeOut(); const { stepDuration } = this.props; this.playTimeout = setTimeout(this.nextStep, stepDuration); }; nextStep = () => { const { isPlaying, speed } = this.props; if (isPlaying) { const { interval, extent, current, onAdvance } = this.props; // @ts-ignore const numSteps = interval.count(extent[0], extent[1]); const next = interval.offset(current, speed * Math.max(1, Math.floor(numSteps / 60))); if (next > extent[1]) { this.stop(); } else { onAdvance(next); this.scheduleNextStep(); } } }; render() { const { isPlaying, darkMode } = this.props; const handleTogglePlay = () => { if (isPlaying) { this.stop(); } else { this.start(); } }; let icon; if (!isPlaying) { icon = ( ); } else { icon = ( ); } const r = Math.min(width, height) * 0.48; return ( {icon} ); } } export default PlayControl;