Delay background preload until map interaction stops

This commit is contained in:
2569718930@qq.com
2026-04-12 10:44:03 +08:00
parent 627bb8aa06
commit a0adf05d1e
3 changed files with 51 additions and 2 deletions
@@ -13,6 +13,7 @@ export function MapCanvas() {
citySummariesByName: store.citySummariesByName, citySummariesByName: store.citySummariesByName,
onClosePanel: store.closePanel, onClosePanel: store.closePanel,
onEnsureCityDetail: store.ensureCityDetail, onEnsureCityDetail: store.ensureCityDetail,
onMapInteractionChange: store.setMapInteractionActive,
onRegisterStopMotion: store.registerMapStopMotion, onRegisterStopMotion: store.registerMapStopMotion,
onSelectCity: (cityName) => { onSelectCity: (cityName) => {
void store.selectCity(cityName); void store.selectCity(cityName);
+6 -2
View File
@@ -47,6 +47,7 @@ interface DashboardStoreValue extends DashboardState {
selectedMarketScan: MarketScan | null; selectedMarketScan: MarketScan | null;
selectedDetail: CityDetail | null; selectedDetail: CityDetail | null;
selectCity: (cityName: string) => Promise<void>; selectCity: (cityName: string) => Promise<void>;
setMapInteractionActive: (active: boolean) => void;
setForecastDate: (dateStr: string | null) => void; setForecastDate: (dateStr: string | null) => void;
marketScanByCityName: Record<string, MarketScan>; marketScanByCityName: Record<string, MarketScan>;
} }
@@ -254,6 +255,7 @@ export function DashboardStoreProvider({
string | null string | null
>(null); >(null);
const [futureModalDate, setFutureModalDate] = useState<string | null>(null); const [futureModalDate, setFutureModalDate] = useState<string | null>(null);
const [isMapInteracting, setIsMapInteracting] = useState(false);
const [loadingState, setLoadingState] = useState<LoadingState>( const [loadingState, setLoadingState] = useState<LoadingState>(
getInitialLoadingState, getInitialLoadingState,
); );
@@ -747,8 +749,9 @@ export function DashboardStoreProvider({
void (async () => { void (async () => {
await runQueue(priorityQueue, EAGER_SUMMARY_PRIORITY_CONCURRENCY); await runQueue(priorityQueue, EAGER_SUMMARY_PRIORITY_CONCURRENCY);
if (!active) return; if (!active) return;
if (isMapInteracting) return;
cancelIdleSchedule = scheduleWhenBrowserIdle(() => { cancelIdleSchedule = scheduleWhenBrowserIdle(() => {
if (!active) return; if (!active || isMapInteracting) return;
void runQueue( void runQueue(
backgroundQueue, backgroundQueue,
EAGER_SUMMARY_BACKGROUND_CONCURRENCY, EAGER_SUMMARY_BACKGROUND_CONCURRENCY,
@@ -760,7 +763,7 @@ export function DashboardStoreProvider({
active = false; active = false;
cancelIdleSchedule(); cancelIdleSchedule();
}; };
}, [cities, loadingState.refresh]); }, [cities, isMapInteracting, loadingState.refresh]);
const selectCity = async (cityName: string) => { const selectCity = async (cityName: string) => {
setSelectedCity(cityName); setSelectedCity(cityName);
@@ -1066,6 +1069,7 @@ export function DashboardStoreProvider({
selectedDetail, selectedDetail,
selectedForecastDate, selectedForecastDate,
selectCity, selectCity,
setMapInteractionActive: setIsMapInteracting,
setForecastDate: (dateStr: string | null) => setForecastDate: (dateStr: string | null) =>
setSelectedForecastDate(dateStr), setSelectedForecastDate(dateStr),
marketScanByCityName, marketScanByCityName,
+44
View File
@@ -19,6 +19,7 @@ interface UseLeafletMapArgs {
cityName: string, cityName: string,
force?: boolean, force?: boolean,
) => Promise<CityDetail>; ) => Promise<CityDetail>;
onMapInteractionChange: (active: boolean) => void;
onRegisterStopMotion: (stopMotion: () => void) => void; onRegisterStopMotion: (stopMotion: () => void) => void;
onSelectCity: (cityName: string) => void; onSelectCity: (cityName: string) => void;
selectedCity: string | null; selectedCity: string | null;
@@ -195,6 +196,7 @@ export function useLeafletMap({
citySummariesByName, citySummariesByName,
onClosePanel, onClosePanel,
onEnsureCityDetail, onEnsureCityDetail,
onMapInteractionChange,
onRegisterStopMotion, onRegisterStopMotion,
onSelectCity, onSelectCity,
selectedCity, selectedCity,
@@ -218,6 +220,10 @@ export function useLeafletMap({
const onRegisterStopMotionRef = useRef(onRegisterStopMotion); const onRegisterStopMotionRef = useRef(onRegisterStopMotion);
const onSelectCityRef = useRef(onSelectCity); const onSelectCityRef = useRef(onSelectCity);
const onEnsureCityDetailRef = useRef(onEnsureCityDetail); const onEnsureCityDetailRef = useRef(onEnsureCityDetail);
const onMapInteractionChangeRef = useRef(onMapInteractionChange);
const interactionIdleTimerRef = useRef<ReturnType<typeof setTimeout> | null>(
null,
);
useEffect(() => { useEffect(() => {
onClosePanelRef.current = onClosePanel; onClosePanelRef.current = onClosePanel;
@@ -235,6 +241,10 @@ export function useLeafletMap({
onEnsureCityDetailRef.current = onEnsureCityDetail; onEnsureCityDetailRef.current = onEnsureCityDetail;
}, [onEnsureCityDetail]); }, [onEnsureCityDetail]);
useEffect(() => {
onMapInteractionChangeRef.current = onMapInteractionChange;
}, [onMapInteractionChange]);
useEffect(() => { useEffect(() => {
suspendMotionRef.current = suspendMotion; suspendMotionRef.current = suspendMotion;
}, [suspendMotion]); }, [suspendMotion]);
@@ -278,8 +288,42 @@ export function useLeafletMap({
}; };
map.on("click", handleMapClick); map.on("click", handleMapClick);
const markInteracting = () => {
if (interactionIdleTimerRef.current) {
clearTimeout(interactionIdleTimerRef.current);
interactionIdleTimerRef.current = null;
}
onMapInteractionChangeRef.current(true);
};
const markIdleSoon = () => {
if (interactionIdleTimerRef.current) {
clearTimeout(interactionIdleTimerRef.current);
}
interactionIdleTimerRef.current = setTimeout(() => {
interactionIdleTimerRef.current = null;
onMapInteractionChangeRef.current(false);
}, 700);
};
map.on("movestart", markInteracting);
map.on("zoomstart", markInteracting);
map.on("dragstart", markInteracting);
map.on("moveend", markIdleSoon);
map.on("zoomend", markIdleSoon);
return () => { return () => {
onRegisterStopMotionRef.current(() => {}); onRegisterStopMotionRef.current(() => {});
if (interactionIdleTimerRef.current) {
clearTimeout(interactionIdleTimerRef.current);
interactionIdleTimerRef.current = null;
}
onMapInteractionChangeRef.current(false);
map.off("movestart", markInteracting);
map.off("zoomstart", markInteracting);
map.off("dragstart", markInteracting);
map.off("moveend", markIdleSoon);
map.off("zoomend", markIdleSoon);
map.off("click", handleMapClick); map.off("click", handleMapClick);
map.remove(); map.remove();
mapRef.current = null; mapRef.current = null;