Refresh nearby stations after map idle
This commit is contained in:
@@ -31,6 +31,8 @@ interface UseLeafletMapArgs {
|
|||||||
|
|
||||||
const AUTO_NEARBY_MIN_ZOOM = 8;
|
const AUTO_NEARBY_MIN_ZOOM = 8;
|
||||||
const AUTO_NEARBY_MAX_DISTANCE_M = 120000;
|
const AUTO_NEARBY_MAX_DISTANCE_M = 120000;
|
||||||
|
const AUTO_NEARBY_IDLE_REFRESH_DELAY_MS = 20_000;
|
||||||
|
const AUTO_NEARBY_MIN_REFRESH_INTERVAL_MS = 90_000;
|
||||||
const MAP_MAX_ZOOM = 19;
|
const MAP_MAX_ZOOM = 19;
|
||||||
const CITY_MARKER_DISPLAY_OFFSETS: Record<
|
const CITY_MARKER_DISPLAY_OFFSETS: Record<
|
||||||
string,
|
string,
|
||||||
@@ -225,6 +227,10 @@ export function useLeafletMap({
|
|||||||
const interactionIdleTimerRef = useRef<ReturnType<typeof setTimeout> | null>(
|
const interactionIdleTimerRef = useRef<ReturnType<typeof setTimeout> | null>(
|
||||||
null,
|
null,
|
||||||
);
|
);
|
||||||
|
const nearbyRefreshTimerRef = useRef<ReturnType<typeof setTimeout> | null>(
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
const lastNearbyRefreshAtRef = useRef<Record<string, number>>({});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
onClosePanelRef.current = onClosePanel;
|
onClosePanelRef.current = onClosePanel;
|
||||||
@@ -294,6 +300,10 @@ export function useLeafletMap({
|
|||||||
clearTimeout(interactionIdleTimerRef.current);
|
clearTimeout(interactionIdleTimerRef.current);
|
||||||
interactionIdleTimerRef.current = null;
|
interactionIdleTimerRef.current = null;
|
||||||
}
|
}
|
||||||
|
if (nearbyRefreshTimerRef.current) {
|
||||||
|
clearTimeout(nearbyRefreshTimerRef.current);
|
||||||
|
nearbyRefreshTimerRef.current = null;
|
||||||
|
}
|
||||||
onMapInteractionChangeRef.current(true);
|
onMapInteractionChangeRef.current(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -319,6 +329,10 @@ export function useLeafletMap({
|
|||||||
clearTimeout(interactionIdleTimerRef.current);
|
clearTimeout(interactionIdleTimerRef.current);
|
||||||
interactionIdleTimerRef.current = null;
|
interactionIdleTimerRef.current = null;
|
||||||
}
|
}
|
||||||
|
if (nearbyRefreshTimerRef.current) {
|
||||||
|
clearTimeout(nearbyRefreshTimerRef.current);
|
||||||
|
nearbyRefreshTimerRef.current = null;
|
||||||
|
}
|
||||||
onMapInteractionChangeRef.current(false);
|
onMapInteractionChangeRef.current(false);
|
||||||
map.off("movestart", markInteracting);
|
map.off("movestart", markInteracting);
|
||||||
map.off("zoomstart", markInteracting);
|
map.off("zoomstart", markInteracting);
|
||||||
@@ -446,6 +460,12 @@ export function useLeafletMap({
|
|||||||
if (!mapRef.current || !nearbyLayerRef.current) return;
|
if (!mapRef.current || !nearbyLayerRef.current) return;
|
||||||
const map = mapRef.current;
|
const map = mapRef.current;
|
||||||
const layer = nearbyLayerRef.current;
|
const layer = nearbyLayerRef.current;
|
||||||
|
const clearNearbyRefreshTimer = () => {
|
||||||
|
if (nearbyRefreshTimerRef.current) {
|
||||||
|
clearTimeout(nearbyRefreshTimerRef.current);
|
||||||
|
nearbyRefreshTimerRef.current = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
function renderNearbyStations(detail: CityDetail, preserveView = false) {
|
function renderNearbyStations(detail: CityDetail, preserveView = false) {
|
||||||
layer.clearLayers();
|
layer.clearLayers();
|
||||||
@@ -506,6 +526,39 @@ export function useLeafletMap({
|
|||||||
// This section is primarily for auto-discovery movement if needed.
|
// This section is primarily for auto-discovery movement if needed.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function scheduleIdleNearbyRefresh(targetCity: string | null) {
|
||||||
|
clearNearbyRefreshTimer();
|
||||||
|
if (!targetCity || suspendMotion) return;
|
||||||
|
if (map.getZoom() < AUTO_NEARBY_MIN_ZOOM) return;
|
||||||
|
|
||||||
|
nearbyRefreshTimerRef.current = setTimeout(async () => {
|
||||||
|
nearbyRefreshTimerRef.current = null;
|
||||||
|
if (loadingAutoNearbyRef.current || handlingAutoNearbyRef.current) return;
|
||||||
|
if (!mapRef.current || mapRef.current.getZoom() < AUTO_NEARBY_MIN_ZOOM) return;
|
||||||
|
if (autoNearbyCityRef.current !== targetCity) return;
|
||||||
|
|
||||||
|
const lastRefreshAt = lastNearbyRefreshAtRef.current[targetCity] || 0;
|
||||||
|
if (Date.now() - lastRefreshAt < AUTO_NEARBY_MIN_REFRESH_INTERVAL_MS) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
loadingAutoNearbyRef.current = true;
|
||||||
|
lastNearbyRefreshAtRef.current[targetCity] = Date.now();
|
||||||
|
try {
|
||||||
|
const detail = await onEnsureCityDetailRef.current(
|
||||||
|
targetCity,
|
||||||
|
true,
|
||||||
|
"nearby",
|
||||||
|
);
|
||||||
|
if (autoNearbyCityRef.current !== targetCity) return;
|
||||||
|
renderNearbyStations(detail, true);
|
||||||
|
} catch {
|
||||||
|
} finally {
|
||||||
|
loadingAutoNearbyRef.current = false;
|
||||||
|
}
|
||||||
|
}, AUTO_NEARBY_IDLE_REFRESH_DELAY_MS);
|
||||||
|
}
|
||||||
|
|
||||||
async function maybeAutoShowNearbyStations() {
|
async function maybeAutoShowNearbyStations() {
|
||||||
if (handlingAutoNearbyRef.current) {
|
if (handlingAutoNearbyRef.current) {
|
||||||
return;
|
return;
|
||||||
@@ -517,11 +570,14 @@ export function useLeafletMap({
|
|||||||
if (selectedNearbyStations.length) {
|
if (selectedNearbyStations.length) {
|
||||||
// Just render stations, no camera move from here
|
// Just render stations, no camera move from here
|
||||||
renderNearbyStations(selectedDetail, true);
|
renderNearbyStations(selectedDetail, true);
|
||||||
|
autoNearbyCityRef.current = selectedCity || selectedDetail.name || null;
|
||||||
|
scheduleIdleNearbyRefresh(autoNearbyCityRef.current);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (suspendMotion) {
|
if (suspendMotion) {
|
||||||
|
clearNearbyRefreshTimer();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -530,6 +586,7 @@ export function useLeafletMap({
|
|||||||
|
|
||||||
if (map.getZoom() < AUTO_NEARBY_MIN_ZOOM) {
|
if (map.getZoom() < AUTO_NEARBY_MIN_ZOOM) {
|
||||||
autoNearbyCityRef.current = null;
|
autoNearbyCityRef.current = null;
|
||||||
|
clearNearbyRefreshTimer();
|
||||||
layer.clearLayers();
|
layer.clearLayers();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -550,6 +607,7 @@ export function useLeafletMap({
|
|||||||
const targetCity = selectedCity || best?.cityName || null;
|
const targetCity = selectedCity || best?.cityName || null;
|
||||||
if (!targetCity) {
|
if (!targetCity) {
|
||||||
autoNearbyCityRef.current = null;
|
autoNearbyCityRef.current = null;
|
||||||
|
clearNearbyRefreshTimer();
|
||||||
layer.clearLayers();
|
layer.clearLayers();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -558,6 +616,7 @@ export function useLeafletMap({
|
|||||||
autoNearbyCityRef.current === targetCity &&
|
autoNearbyCityRef.current === targetCity &&
|
||||||
layer.getLayers().length > 0
|
layer.getLayers().length > 0
|
||||||
) {
|
) {
|
||||||
|
scheduleIdleNearbyRefresh(targetCity);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -565,6 +624,7 @@ export function useLeafletMap({
|
|||||||
const cachedDetail = cityDetailsByName[targetCity];
|
const cachedDetail = cityDetailsByName[targetCity];
|
||||||
if (cachedDetail && pickMapNearbyStations(cachedDetail).length) {
|
if (cachedDetail && pickMapNearbyStations(cachedDetail).length) {
|
||||||
renderNearbyStations(cachedDetail, true);
|
renderNearbyStations(cachedDetail, true);
|
||||||
|
scheduleIdleNearbyRefresh(targetCity);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -577,6 +637,7 @@ export function useLeafletMap({
|
|||||||
"nearby",
|
"nearby",
|
||||||
);
|
);
|
||||||
renderNearbyStations(detail, true);
|
renderNearbyStations(detail, true);
|
||||||
|
scheduleIdleNearbyRefresh(targetCity);
|
||||||
} catch {
|
} catch {
|
||||||
} finally {
|
} finally {
|
||||||
loadingAutoNearbyRef.current = false;
|
loadingAutoNearbyRef.current = false;
|
||||||
@@ -602,6 +663,7 @@ export function useLeafletMap({
|
|||||||
map.on("moveend", maybeAutoShowNearbyStations);
|
map.on("moveend", maybeAutoShowNearbyStations);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
|
clearNearbyRefreshTimer();
|
||||||
map.off("zoomend", syncVisibility);
|
map.off("zoomend", syncVisibility);
|
||||||
map.off("moveend", maybeAutoShowNearbyStations);
|
map.off("moveend", maybeAutoShowNearbyStations);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user