From 2ef752dc75fa642de76a23071a150bcbd3d3a31b Mon Sep 17 00:00:00 2001 From: Tanner Collin Date: Sun, 17 Aug 2025 18:46:03 +0000 Subject: [PATCH] feat: Add include area button to narrow time range by selection Co-authored-by: aider (gemini/gemini-2.5-pro) --- mapper/src/App.js | 58 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/mapper/src/App.js b/mapper/src/App.js index d1c32c8..251a364 100644 --- a/mapper/src/App.js +++ b/mapper/src/App.js @@ -510,6 +510,63 @@ function Menu({data, duration, setDuration, end, setEnd, slider, setSlider, subm setSubmenu(false); }; + const includeArea = () => { + const drawnRectangles = drawnItems.map(item => item.bounds); + if (!drawnRectangles.length || !data || !Array.isArray(data)) { + if (!drawnRectangles.length) alert("Please draw one or more rectangles on the map first."); + setSubmenu(false); + return; + } + + const isInsideInclusionZone = (lat, lon) => { + for (const rect of drawnRectangles) { + if (rect.contains([lat, lon])) { + return true; + } + } + return false; + }; + + let minTime = null; + let maxTime = null; + + for (const point of data) { + if (!point || typeof point.lat !== 'number' || typeof point.lon !== 'number' || !point.time) { + continue; + } + + const isInside = isInsideInclusionZone(point.lat, point.lon); + + if (isInside) { + if (minTime === null || point.time < minTime) { + minTime = point.time; + } + if (maxTime === null || point.time > maxTime) { + maxTime = point.time; + } + } + } + + if (minTime === null) { + alert("No data points found inside the selected area(s)."); + setSubmenu(false); + return; + } + + const startUnix = moment(minTime).unix(); + const endUnix = moment(maxTime).unix(); + const endOfWindowUnix = end.unix(); + + const newSliderStart = Math.floor((startUnix - endOfWindowUnix) / duration.secs + duration.num); + const newSliderEnd = Math.ceil((endUnix - endOfWindowUnix) / duration.secs + duration.num); + + const clampedStart = Math.max(0, newSliderStart); + const clampedEnd = Math.min(duration.num, newSliderEnd); + + setSlider([clampedStart, clampedEnd]); + setSubmenu(false); + }; + const searchArea = async () => { const drawnRectangles = drawnItems.map(item => item.bounds); if (!drawnRectangles.length) { @@ -837,6 +894,7 @@ function Menu({data, duration, setDuration, end, setEnd, slider, setSlider, subm +