Allow shifting by time range
This commit is contained in:
		@@ -22,6 +22,22 @@ const durations = [
 | 
				
			|||||||
	{id: 3, len: 'Year', win: '2h', full: '2 hour', delta: [1, 'years'], format: 'M/D', num: 4380, secs: 7200},
 | 
						{id: 3, len: 'Year', win: '2h', full: '2 hour', delta: [1, 'years'], format: 'M/D', num: 4380, secs: 7200},
 | 
				
			||||||
];
 | 
					];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const parseSlider = (end, duration, slider) => {
 | 
				
			||||||
 | 
						//console.log(slider);
 | 
				
			||||||
 | 
						// good luck remembering how this works
 | 
				
			||||||
 | 
						const lowOffset = slider[0] * duration.secs - duration.num * duration.secs;
 | 
				
			||||||
 | 
						const highOffset = slider[1] * duration.secs - duration.num * duration.secs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const low = moment.unix(end.unix() + lowOffset);
 | 
				
			||||||
 | 
						const high = moment.unix(end.unix() + highOffset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const lowStr = low.utc().format('YYYY-MM-DDTHH:mm:ss[Z]');
 | 
				
			||||||
 | 
						const highStr = high.utc().format('YYYY-MM-DDTHH:mm:ss[Z]');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						//console.log(lowStr, highStr);
 | 
				
			||||||
 | 
						return [lowStr, highStr];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function useSensor(measurement, name, end, duration) {
 | 
					function useSensor(measurement, name, end, duration) {
 | 
				
			||||||
	const [data, setData] = useState(false);
 | 
						const [data, setData] = useState(false);
 | 
				
			||||||
	const [loading, setLoading] = useState(false);
 | 
						const [loading, setLoading] = useState(false);
 | 
				
			||||||
@@ -51,9 +67,11 @@ function useSensor(measurement, name, end, duration) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function Owntracks({end, duration, range}) {
 | 
					function Owntracks({end, duration, slider}) {
 | 
				
			||||||
	const [data, loading] = useSensor('owntracks', 'OwnTracks', end, duration);
 | 
						const [data, loading] = useSensor('owntracks', 'OwnTracks', end, duration);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const range = parseSlider(end, duration, slider);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const coords = data.length ? data.filter(x => !range || (x.time >= range[0] && x.time <= range[1])).map(({ lat, lon }) => [lat, lon]).filter(([lat, lon]) => lat !== null || lon !== null) : [];
 | 
						const coords = data.length ? data.filter(x => !range || (x.time >= range[0] && x.time <= range[1])).map(({ lat, lon }) => [lat, lon]).filter(([lat, lon]) => lat !== null || lon !== null) : [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const handleSubmit = (e) => {
 | 
						const handleSubmit = (e) => {
 | 
				
			||||||
@@ -90,73 +108,89 @@ function Owntracks({end, duration, range}) {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function Graphs({end, duration, range}) {
 | 
					function Graphs({end, duration, slider}) {
 | 
				
			||||||
	return (
 | 
						return (
 | 
				
			||||||
		<div className='container'>
 | 
							<div className='container'>
 | 
				
			||||||
			<Owntracks end={end} duration={duration} range={range} />
 | 
								<Owntracks end={end} duration={duration} slider={slider} />
 | 
				
			||||||
		</div>
 | 
							</div>
 | 
				
			||||||
	);
 | 
						);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function Menu({duration, setDuration, end, setEnd, range, setRange}) {
 | 
					function Menu({duration, setDuration, end, setEnd, slider, setSlider}) {
 | 
				
			||||||
	const [submenu, setSubmenu] = useState(false);
 | 
						const [submenu, setSubmenu] = useState(false);
 | 
				
			||||||
	const [showRange, setShowRange] = useState(false);
 | 
						const [showRange, setShowRange] = useState(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const chooseDuration = (x) => {
 | 
						const chooseDuration = (x) => {
 | 
				
			||||||
		setSubmenu(false);
 | 
							setSubmenu(false);
 | 
				
			||||||
		setRange(false);
 | 
							setSlider([0, x.num]);
 | 
				
			||||||
		setDuration(x);
 | 
							setDuration(x);
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const chooseEnd = (x) => {
 | 
						const chooseEnd = (x) => {
 | 
				
			||||||
		setSubmenu(false);
 | 
							setSubmenu(false);
 | 
				
			||||||
		const newEnd = x.add(...duration.delta);
 | 
							const newEnd = x.add(...duration.delta);
 | 
				
			||||||
		setRange(false);
 | 
							setSlider([0, duration.num]);
 | 
				
			||||||
		setEnd(newEnd);
 | 
							setEnd(newEnd);
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const chooseNow = (x) => {
 | 
						const chooseNow = (x) => {
 | 
				
			||||||
		setSubmenu(false);
 | 
							setSubmenu(false);
 | 
				
			||||||
		setRange(false);
 | 
							setSlider([0, duration.num]);
 | 
				
			||||||
		setEnd(moment());
 | 
							setEnd(moment());
 | 
				
			||||||
	};
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const rangeStart = (x) => {
 | 
				
			||||||
 | 
							setEnd(moment(range[0]).add(...duration.delta));
 | 
				
			||||||
 | 
							setSlider([0, duration.num]);
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const rangeEnd = (x) => {
 | 
				
			||||||
 | 
							setEnd(moment(range[1]));
 | 
				
			||||||
 | 
							setSlider([0, duration.num]);
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const next = () => {
 | 
						const next = () => {
 | 
				
			||||||
		setSubmenu(false);
 | 
							setSubmenu(false);
 | 
				
			||||||
		setRange(false);
 | 
							setSlider([0, duration.num]);
 | 
				
			||||||
		setEnd(prevEnd => moment(prevEnd).add(...duration.delta));
 | 
							setEnd(prevEnd => moment(prevEnd).add(...duration.delta));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const prev = () => {
 | 
						const prev = () => {
 | 
				
			||||||
		setSubmenu(false);
 | 
							setSubmenu(false);
 | 
				
			||||||
		setRange(false);
 | 
							setSlider([0, duration.num]);
 | 
				
			||||||
		setEnd(prevEnd => moment(prevEnd).subtract(...duration.delta));
 | 
							setEnd(prevEnd => moment(prevEnd).subtract(...duration.delta));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const onSlider = (slider) => {
 | 
						const range = parseSlider(end, duration, slider);
 | 
				
			||||||
		console.log(slider);
 | 
					 | 
				
			||||||
		// good luck remembering how this works
 | 
					 | 
				
			||||||
		const lowOffset = slider[0] * duration.secs - duration.num * duration.secs;
 | 
					 | 
				
			||||||
		const highOffset = slider[1] * duration.secs - duration.num * duration.secs;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		const low = moment.unix(end.unix() + lowOffset);
 | 
					 | 
				
			||||||
		const high = moment.unix(end.unix() + highOffset);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		const lowStr = low.utc().format('YYYY-MM-DDTHH:mm:ss[Z]');
 | 
					 | 
				
			||||||
		const highStr = high.utc().format('YYYY-MM-DDTHH:mm:ss[Z]');
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		console.log(lowStr, highStr);
 | 
					 | 
				
			||||||
		setRange([lowStr, highStr]);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						const rangeTime = (x) => {
 | 
				
			||||||
 | 
							if (new Date().getTimezoneOffset()) {  // non-librewolf browser
 | 
				
			||||||
 | 
								return moment(x).format('lll');  // default to browser's TZ
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								return moment(x).tz('America/Edmonton').format('lll');
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return (
 | 
						return (
 | 
				
			||||||
		<div className='menu'>
 | 
							<div className='menu'>
 | 
				
			||||||
			{showRange && <div className='range'>
 | 
								{(showRange || !!submenu) && <div className='range'>
 | 
				
			||||||
				{moment(range[0]).format('lll')} - {moment(range[1]).format('lll')}
 | 
									{rangeTime(range[0])} - {rangeTime(range[1])}
 | 
				
			||||||
			</div>}
 | 
								</div>}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			{submenu ?
 | 
								<div className='time-slider'>
 | 
				
			||||||
 | 
									<RangeSlider
 | 
				
			||||||
 | 
										min={0}
 | 
				
			||||||
 | 
										max={duration.num}
 | 
				
			||||||
 | 
										value={slider}
 | 
				
			||||||
 | 
										onInput={setSlider}
 | 
				
			||||||
 | 
										onThumbDragStart={() => setShowRange(true)}
 | 
				
			||||||
 | 
										onThumbDragEnd={() => setShowRange(false)}
 | 
				
			||||||
 | 
										onRangeDragStart={() => setShowRange(true)}
 | 
				
			||||||
 | 
										onRangeDragEnd={() => setShowRange(false)}
 | 
				
			||||||
 | 
									/>
 | 
				
			||||||
 | 
								</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								{!!submenu &&
 | 
				
			||||||
				<div className='submenu'>
 | 
									<div className='submenu'>
 | 
				
			||||||
					{submenu === 'end' &&
 | 
										{submenu === 'end' &&
 | 
				
			||||||
						<>
 | 
											<>
 | 
				
			||||||
@@ -174,6 +208,8 @@ function Menu({duration, setDuration, end, setEnd, range, setRange}) {
 | 
				
			|||||||
							</div>
 | 
												</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							<button onClick={chooseNow}>Jump to Now</button>
 | 
												<button onClick={chooseNow}>Jump to Now</button>
 | 
				
			||||||
 | 
												<button onClick={rangeStart}>Shift to Range Start</button>
 | 
				
			||||||
 | 
												<button onClick={rangeEnd}>Shift to Range End</button>
 | 
				
			||||||
						</>
 | 
											</>
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -190,20 +226,6 @@ function Menu({duration, setDuration, end, setEnd, range, setRange}) {
 | 
				
			|||||||
						</>
 | 
											</>
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				</div>
 | 
									</div>
 | 
				
			||||||
			:
 | 
					 | 
				
			||||||
				<div className='time-slider'>
 | 
					 | 
				
			||||||
					<RangeSlider
 | 
					 | 
				
			||||||
						min={0}
 | 
					 | 
				
			||||||
						max={duration.num}
 | 
					 | 
				
			||||||
						defaultValue={[0, duration.num]}
 | 
					 | 
				
			||||||
						onInput={onSlider}
 | 
					 | 
				
			||||||
						onThumbDragStart={() => setShowRange(true)}
 | 
					 | 
				
			||||||
						onThumbDragEnd={() => setShowRange(false)}
 | 
					 | 
				
			||||||
						onRangeDragStart={() => setShowRange(true)}
 | 
					 | 
				
			||||||
						onRangeDragEnd={() => setShowRange(false)}
 | 
					 | 
				
			||||||
					/>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
				</div>
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			<div className='menu-container'>
 | 
								<div className='menu-container'>
 | 
				
			||||||
@@ -232,7 +254,7 @@ function Menu({duration, setDuration, end, setEnd, range, setRange}) {
 | 
				
			|||||||
function App() {
 | 
					function App() {
 | 
				
			||||||
	const [duration, setDuration] = useState(durations[0]);
 | 
						const [duration, setDuration] = useState(durations[0]);
 | 
				
			||||||
	const [end, setEnd] = useState(moment());
 | 
						const [end, setEnd] = useState(moment());
 | 
				
			||||||
	const [range, setRange] = useState(false);
 | 
						const [slider, setSlider] = useState([0, duration.num]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return (
 | 
						return (
 | 
				
			||||||
		<div>
 | 
							<div>
 | 
				
			||||||
@@ -241,14 +263,14 @@ function App() {
 | 
				
			|||||||
				setDuration={setDuration}
 | 
									setDuration={setDuration}
 | 
				
			||||||
				end={end}
 | 
									end={end}
 | 
				
			||||||
				setEnd={setEnd}
 | 
									setEnd={setEnd}
 | 
				
			||||||
				range={range}
 | 
									slider={slider}
 | 
				
			||||||
				setRange={setRange}
 | 
									setSlider={setSlider}
 | 
				
			||||||
			/>
 | 
								/>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			<Graphs
 | 
								<Graphs
 | 
				
			||||||
				end={end}
 | 
									end={end}
 | 
				
			||||||
				duration={duration}
 | 
									duration={duration}
 | 
				
			||||||
				range={range}
 | 
									slider={slider}
 | 
				
			||||||
			/>
 | 
								/>
 | 
				
			||||||
		</div>
 | 
							</div>
 | 
				
			||||||
	);
 | 
						);
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user