auspice
Version:
Web app for visualizing pathogen evolution
130 lines (125 loc) • 5.25 kB
JavaScript
import React from "react";
import { connect } from "react-redux";
import Slider from "./slider";
import DateLabel from "./date-label";
import { controlsWidth, minDistanceDateSlider } from "../../util/globals";
import { numericToCalendar } from "../../util/dateHelpers";
import { changeDateFilter } from "../../actions/tree";
import { MAP_ANIMATION_PLAY_PAUSE_BUTTON } from "../../actions/types";
class DateRangeInputs extends React.Component {
constructor(props) {
super(props);
this.state = {
lastSliderUpdateTime: Date.now()
};
this.updateFromSliderNotDebounced = this.updateFromSlider.bind(this, false);
this.updateFromSliderDebounced = this.updateFromSlider.bind(this, true);
this.updateMinFromDatePicker = this.updateMinFromDatePicker.bind(this);
this.updateMaxFromDatePicker = this.updateMaxFromDatePicker.bind(this);
}
maybeClearMapAnimationInterval() {
if (window.NEXTSTRAIN && window.NEXTSTRAIN.animationTickReference) {
clearInterval(window.NEXTSTRAIN.animationTickReference);
window.NEXTSTRAIN.animationTickReference = null;
this.props.dispatch({
type: MAP_ANIMATION_PLAY_PAUSE_BUTTON,
data: "Play"
});
}
}
updateFromSlider(debounce, numDateValues) {
/* debounce: boolean. TRUE: both debounce and quickdraw. */
this.maybeClearMapAnimationInterval();
if (debounce) {
// simple debounce @ 100ms
const currentTime = Date.now();
if (currentTime < this.state.lastSliderUpdateTime + 100) {
return null;
}
// console.log("UPDATING", currentTime, this.state.lastSliderUpdateTime)
this.setState({lastSliderUpdateTime: currentTime});
}
// {numDateValues} is an array of numDates received from Slider
// [numDateStart, numDateEnd]
const newRange = {min: numericToCalendar(numDateValues[0]),
max: numericToCalendar(numDateValues[1])};
if (this.props.dateMin !== newRange.min && this.props.dateMax === newRange.max) { // update min
this.props.dispatch(changeDateFilter({newMin: newRange.min, quickdraw: debounce}));
} else if (this.props.dateMin === newRange.min &&
this.props.dateMax !== newRange.max) { // update max
this.props.dispatch(changeDateFilter({newMax: newRange.max, quickdraw: debounce}));
} else if (this.props.dateMin !== newRange.min &&
this.props.dateMax !== newRange.max) { // update both
this.props.dispatch(changeDateFilter({newMin: newRange.min, newMax: newRange.max, quickdraw: debounce}));
} else if (debounce === false) {
/* this occurs when no dates have actually changed BUT we need to redraw (e.g. quickdraw has come off) */
this.props.dispatch(changeDateFilter({quickdraw: debounce}));
}
return null;
}
updateMinFromDatePicker(value) {
this.props.dispatch(changeDateFilter({newMin: value}));
}
updateMaxFromDatePicker(value) {
this.props.dispatch(changeDateFilter({newMax: value}));
}
render() {
if (this.props.branchLengthsToDisplay === "divOnly") {
return null;
}
return (
<div>
<div style={{width: controlsWidth}}>
<Slider // numDates are handed to Slider
min={this.props.absoluteDateMinNumeric}
max={this.props.absoluteDateMaxNumeric}
defaultValue={[this.props.absoluteDateMinNumeric, this.props.absoluteDateMaxNumeric]}
value={[this.props.dateMinNumeric, this.props.dateMaxNumeric]}
/* debounce the onChange event, but ensure the final one goes through */
onChange={this.updateFromSliderDebounced}
onAfterChange={this.updateFromSliderNotDebounced}
minDistance={minDistanceDateSlider * (this.props.absoluteDateMaxNumeric - this.props.absoluteDateMinNumeric)}
pearling
withBars
/>
</div>
<div style={{height: 5}}/>
<div style={{width: controlsWidth}}>
<DateLabel
value={this.props.dateMin}
minDate={this.props.absoluteDateMin}
maxDate={this.props.dateMax}
onChange={this.updateMinFromDatePicker}
/>
<DateLabel right
value={this.props.dateMax}
minDate={this.props.dateMin}
maxDate={this.props.absoluteDateMax}
onChange={this.updateMaxFromDatePicker}
/>
</div>
</div>
);
}
}
export const DateRangeInfo = (
<>
Use this slider to filter the data based on the sample date.
This may include inferred dates for ancestral nodes in the tree,
and thus the date range here can be wider than the sample collection range.
</>
);
export default DateRangeInputs;