feat(maps): remembered views for the FT and grid maps, and no wasted first paint
The world map was the only one that remembered anything. Panning and zooming a map is the operator saying which part of the world they work, and on the FT decodes map and the grid-square map that was thrown away on every tab switch. Both now keep centre and zoom, through one shared helper (lib/mapView) that the world map uses too, and the keys are portable so a copied data folder brings the views with it. The world map also waits for the station's square before it paints. It drew the world at 0 degrees and then moved to the operator's longitude — a screenful of Esri tiles fetched and discarded on every first run. It is now built once, knowing where it is looking; a profile with no locator gets the default view after two seconds rather than a blank panel.
This commit is contained in:
@@ -5,6 +5,7 @@ import { gridToLatLon, greatCirclePoints, splitAtAntimeridian } from '@/lib/maid
|
||||
import { BASEMAPS, type BasemapKey } from '@/components/MainMap';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { useI18n } from '@/lib/i18n';
|
||||
import { loadMapView, saveMapView, MAP_VIEW_FT } from '@/lib/mapView';
|
||||
|
||||
// FT Map — the live decode feed as geography: every station decoded in the
|
||||
// last half hour, an arc from the operator's own square to theirs, coloured by
|
||||
@@ -39,6 +40,10 @@ const MAX_ARCS = 300;
|
||||
const MAX_AGE_MS = 30 * 60_000;
|
||||
|
||||
export function FTMapPanel({ decodes, myGrid }: { decodes: FTMapDecode[]; myGrid: string }) {
|
||||
// Where this map was left. Panning and zooming it is the operator saying which
|
||||
// part of the world they are working; throwing that away on every tab switch
|
||||
// made it something to set up again rather than something to glance at.
|
||||
const saved = useRef(loadMapView(MAP_VIEW_FT));
|
||||
const { t } = useI18n();
|
||||
const divRef = useRef<HTMLDivElement>(null);
|
||||
const mapRef = useRef<L.Map | null>(null);
|
||||
@@ -58,7 +63,15 @@ export function FTMapPanel({ decodes, myGrid }: { decodes: FTMapDecode[]; myGrid
|
||||
// No maxBounds: with the world smaller than the window the clamp
|
||||
// dragged every zoom into a corner. noWrap tiles alone keep one world.
|
||||
worldCopyJump: false, preferCanvas: true,
|
||||
center: [25, 0], zoom: 2, minZoom: 2,
|
||||
center: saved.current ? [saved.current.lat, saved.current.lon] : [25, 0],
|
||||
zoom: saved.current ? saved.current.zoom : 2,
|
||||
minZoom: 2,
|
||||
});
|
||||
// Every move, not just the deliberate ones: a zoom is as much a choice as a
|
||||
// pan, and there is no moment afterwards at which to ask.
|
||||
m.on('moveend', () => {
|
||||
const c = m.getCenter();
|
||||
saveMapView(MAP_VIEW_FT, c.lat, c.lng, m.getZoom());
|
||||
});
|
||||
mapRef.current = m;
|
||||
layerRef.current = L.layerGroup().addTo(m);
|
||||
|
||||
Reference in New Issue
Block a user