diff --git a/src/components/periods/Timeline.js b/src/components/periods/Timeline.js index 65138bad4..8bf4f7855 100644 --- a/src/components/periods/Timeline.js +++ b/src/components/periods/Timeline.js @@ -62,98 +62,16 @@ class Timeline extends Component { static contextTypes = { map: PropTypes.object, } - static propTypes = { period: PropTypes.object.isRequired, - periodId: PropTypes.string.isRequired, periods: PropTypes.array.isRequired, onChange: PropTypes.func.isRequired, } - state = { width: null, mode: 'start', } - componentDidMount() { - this.setWidth() - this.context.map.on('resize', this.setWidth) - } - - componentDidUpdate() { - this.setTimeAxis() - } - - componentWillUnmount() { - this.context.map.off('resize', this.setWidth) - } - - render() { - const { mode } = this.state - const uniqueRanks = countUniqueRanks(this.props.periods) - - this.setTimeScale() - const rectTotalHeight = RECT_HEIGHT + (uniqueRanks - 1) * RECT_OFFSET - return ( - - // play/pause button - - - {mode === 'play' ? PAUSE_ICON : PLAY_ICON} - - // rectangles - - {this.getPeriodRects()} - - // x axis - (this.node = node)} - /> - - ) - } - - // Returns array of period rectangles - getPeriodRects = () => { - const { period, periods } = this.props - - const sortedPeriods = sortPeriodsByLevelRank(periods) - - return sortedPeriods.map((item) => { - const isCurrent = period.id === item.id - const { id, startDate, endDate } = item - const x = this.timeScale(startDate) - const width = this.timeScale(endDate) - x - - return ( - this.onPeriodClick(item)} - /> - ) - }) - } - // Set time scale setTimeScale = () => { const { periods } = this.props @@ -163,10 +81,10 @@ class Timeline extends Component { return } - const { minStartDate: startDate, maxEndDate: endDate } = periods.reduce( - (acc, item) => { - const start = new Date(item.startDate) - const end = new Date(item.endDate) + const { minStartDate, maxEndDate } = periods.reduce( + (acc, { startDate, endDate }) => { + const start = new Date(startDate) + const end = new Date(endDate) return { minStartDate: start < acc.minStartDate ? start : acc.minStartDate, @@ -181,7 +99,7 @@ class Timeline extends Component { // Link time domain to timeline width this.timeScale = scaleTime() - .domain([startDate, endDate]) + .domain([minStartDate, maxEndDate]) .range([0, width]) } @@ -196,53 +114,29 @@ class Timeline extends Component { : 1) const { width } = this.state const maxTicks = Math.round(width / LABEL_WIDTH) - const numTicks = maxTicks < numPeriods ? maxTicks : numPeriods - const timeAxis = axisBottom(this.timeScale) - const [startDate, endDate] = this.timeScale.domain() - const ticks = timeTicks(startDate, endDate, numTicks) - - timeAxis.tickValues(ticks) + const numTicks = Math.min(maxTicks, numPeriods) + const ticks = timeTicks(...this.timeScale.domain(), numTicks) + const timeAxis = axisBottom(this.timeScale).tickValues(ticks) select(this.node).call(timeAxis) } - // Set timeline width from DOM el + // Set timeline width from DOM element setWidth = () => { if (this.node) { // clientWith returns 0 for SVG elements in Firefox const box = this.node.parentNode.getBoundingClientRect() const width = box.right - box.left - PADDING_LEFT - PADDING_RIGHT - this.setState({ width }) } } - // Handler for period click - onPeriodClick(period) { - // Switch to period if different - if (period.id !== this.props.period.id) { - this.props.onChange(period) - } - - // Stop animation if running - this.stop() - } - - // Handler for play/pause button - onPlayPause = () => { - if (this.state.mode === 'play') { - this.stop() - } else { - this.play() - } - } - // Play animation play = () => { const { period, periods, onChange } = this.props const sortedPeriods = sortPeriodsByLevelAndStartDate(periods) - const index = sortedPeriods.findIndex((p) => p.id === period.id) - const isLastPeriod = index === sortedPeriods.length - 1 + const currentIndex = sortedPeriods.findIndex((p) => p.id === period.id) + const isLastPeriod = currentIndex === sortedPeriods.length - 1 // If new animation if (!this.timeout) { @@ -260,7 +154,7 @@ class Timeline extends Component { } // Switch to next period - onChange(sortedPeriods[index + 1]) + onChange(sortedPeriods[currentIndex + 1]) } // Call itself after DELAY @@ -273,6 +167,105 @@ class Timeline extends Component { clearTimeout(this.timeout) delete this.timeout } + + // Handler for play/pause button + onPlayPause = () => { + if (this.state.mode === 'play') { + this.stop() + } else { + this.play() + } + } + + // Handler for period click + onPeriodClick(period) { + // Switch to period if different + if (period.id !== this.props.period.id) { + this.props.onChange(period) + } + + // Stop animation if running + this.stop() + } + + componentDidMount() { + this.setWidth() + this.context.map.on('resize', this.setWidth) + } + + componentDidUpdate() { + this.setTimeAxis() + } + + componentWillUnmount() { + this.context.map.off('resize', this.setWidth) + } + + render() { + const { mode } = this.state + const uniqueRanks = countUniqueRanks(this.props.periods) + const rectTotalHeight = RECT_HEIGHT + (uniqueRanks - 1) * RECT_OFFSET + + this.setTimeScale() + return ( + + {/* Play/Pause Button */} + + + {mode === 'play' ? PAUSE_ICON : PLAY_ICON} + + {/* Period Rectangles */} + + {this.getPeriodRects()} + + {/* X-Axis */} + (this.node = node)} + /> + + ) + } + + // Returns array of period rectangles + getPeriodRects = () => { + const { period, periods } = this.props + + const sortedPeriods = sortPeriodsByLevelRank(periods) + + return sortedPeriods.map((item) => { + const isCurrent = period.id === item.id + const { id, startDate, endDate } = item + const x = this.timeScale(startDate) + const width = this.timeScale(endDate) - x + + return ( + this.onPeriodClick(item)} + /> + ) + }) + } } export default Timeline