mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-11-13 07:40:59 +00:00
e28bd2fc99
MapLibre 6 and Mapbox GL 3 both throw out of their Map constructor without WebGL2. Every place that builds a GL map now asks one helper first, components/Map/glSupport.ts, and a browser without WebGL2 gets the Leaflet map with the user's tiles instead of a map that fails to start: - the trip map (MapViewAuto) and the journey maps (JourneyMapAuto) pick their renderer through useGlRenderer, which folds in the Mapbox token rule they each had; - the settings preview, desktop and phone, shows the Leaflet preview through useMapSettingsForm and says why under it; - the tour planner keeps the 2D map when 3D is asked for and says that 3D needs WebGL2; - the PDF route map and the Leaflet vector basemap already fell back and now report a GPU failure too. Behind the probe, buildGlMap wraps each constructor (MapViewGL, JourneyMapGL, the settings preview, the terrain map, the PDF map). A GPU that claims WebGL2 and still refuses the context is reported through utils/webgl, which turns the answer to no and tells every mounted map, so they switch to Leaflet without a reload; any other error is still thrown. Two new strings, map.webgl2.fallback and map.webgl2.terrain, in all 27 locales.
119 lines
4.7 KiB
TypeScript
119 lines
4.7 KiB
TypeScript
import { useEffect, useMemo, useState } from 'react';
|
|
|
|
import { useTranslation } from '../../i18n';
|
|
import { useAuthStore } from '../../store/authStore';
|
|
import { useSettingsStore } from '../../store/settingsStore';
|
|
import type { Place } from '../../types';
|
|
import { normalizeStyleForProvider } from '../Map/glProviders';
|
|
import { useWebGL2 } from '../Map/glSupport';
|
|
import { useToast } from '../shared/Toast';
|
|
import { type MapProvider, normalizeProvider, previewPlace, slotStyle, styleForProvider } from './mapSettingsModel';
|
|
|
|
export interface MapSettingsFormOptions {
|
|
/**
|
|
* The phone shows the normalized style in the field as soon as save is pressed;
|
|
* the desktop only once it is actually persisted.
|
|
*/
|
|
mirrorStyleBeforeSave?: boolean;
|
|
}
|
|
|
|
/**
|
|
* The user's map settings form behind both settings shells (the desktop tab and the
|
|
* phone section render their own markup over this): the provider, the raster tiles
|
|
* and CARTO key, the Mapbox token, the GL style and the 3D and quality toggles,
|
|
* seeded from the settings store and saved back in one patch.
|
|
*/
|
|
export function useMapSettingsForm({ mirrorStyleBeforeSave = false }: MapSettingsFormOptions = {}) {
|
|
const { settings, updateSettings } = useSettingsStore();
|
|
const { t } = useTranslation();
|
|
const toast = useToast();
|
|
const initialProvider = normalizeProvider(settings.map_provider);
|
|
const [saving, setSaving] = useState(false);
|
|
const [provider, setProvider] = useState<MapProvider>(initialProvider);
|
|
const [mapTileUrl, setMapTileUrl] = useState<string>(settings.map_tile_url || '');
|
|
const managed = useAuthStore((s) => s.managed);
|
|
const [mapboxToken, setMapboxToken] = useState<string>(settings.mapbox_access_token || '');
|
|
const [cartoKey, setCartoKey] = useState<string>(settings.carto_api_key || '');
|
|
const [mapboxStyle, setMapboxStyle] = useState<string>(
|
|
styleForProvider(initialProvider, slotStyle(initialProvider, settings))
|
|
);
|
|
const [mapbox3d, setMapbox3d] = useState<boolean>(settings.mapbox_3d_enabled !== false);
|
|
const [mapboxQuality, setMapboxQuality] = useState<boolean>(settings.mapbox_quality_mode === true);
|
|
|
|
useEffect(() => {
|
|
const nextProvider = normalizeProvider(settings.map_provider);
|
|
setProvider(nextProvider);
|
|
setMapTileUrl(settings.map_tile_url || '');
|
|
setMapboxToken(settings.mapbox_access_token || '');
|
|
setCartoKey(settings.carto_api_key || '');
|
|
setMapboxStyle(styleForProvider(nextProvider, slotStyle(nextProvider, settings)));
|
|
setMapbox3d(settings.mapbox_3d_enabled !== false);
|
|
setMapboxQuality(settings.mapbox_quality_mode === true);
|
|
}, [settings]);
|
|
|
|
const previewPlaces = useMemo((): Place[] => [previewPlace()], []);
|
|
// Both GL engines need WebGL2. Without it the preview shows the Leaflet map the
|
|
// trip planner falls back to, and both shells say why.
|
|
const webgl2 = useWebGL2();
|
|
const glPreview = provider !== 'leaflet' && webgl2;
|
|
const webgl2Missing = provider !== 'leaflet' && !webgl2;
|
|
|
|
const save = async (): Promise<void> => {
|
|
setSaving(true);
|
|
try {
|
|
const glStyle = provider === 'leaflet' ? mapboxStyle : normalizeStyleForProvider(provider, mapboxStyle);
|
|
if (mirrorStyleBeforeSave) setMapboxStyle(glStyle);
|
|
// Save into the active provider's own slot so the other provider's style survives.
|
|
const stylePatch = provider === 'maplibre-gl' ? { maplibre_style: glStyle } : { mapbox_style: glStyle };
|
|
await updateSettings({
|
|
map_provider: provider,
|
|
map_tile_url: mapTileUrl,
|
|
mapbox_access_token: mapboxToken,
|
|
carto_api_key: cartoKey,
|
|
...stylePatch,
|
|
mapbox_3d_enabled: mapbox3d,
|
|
mapbox_quality_mode: mapboxQuality,
|
|
});
|
|
// Only mirror the normalized style into the form once it is actually persisted.
|
|
if (!mirrorStyleBeforeSave) setMapboxStyle(glStyle);
|
|
toast.success(t('settings.toast.mapSaved'));
|
|
} catch (err: unknown) {
|
|
toast.error(err instanceof Error ? err.message : t('common.error'));
|
|
} finally {
|
|
setSaving(false);
|
|
}
|
|
};
|
|
|
|
const changeProvider = (nextProvider: MapProvider) => {
|
|
setProvider(nextProvider);
|
|
if (nextProvider !== 'leaflet') setMapboxStyle(styleForProvider(nextProvider, mapboxStyle));
|
|
};
|
|
|
|
// Only CARTO burns a watermark into keyless tiles, so the nudge is scoped to its hosts.
|
|
const cartoNeedsKey = mapTileUrl.includes('basemaps.cartocdn.com') && !cartoKey.trim();
|
|
|
|
return {
|
|
managed,
|
|
saving,
|
|
provider,
|
|
changeProvider,
|
|
mapTileUrl,
|
|
setMapTileUrl,
|
|
mapboxToken,
|
|
setMapboxToken,
|
|
cartoKey,
|
|
setCartoKey,
|
|
cartoNeedsKey,
|
|
mapboxStyle,
|
|
setMapboxStyle,
|
|
mapbox3d,
|
|
setMapbox3d,
|
|
mapboxQuality,
|
|
setMapboxQuality,
|
|
previewPlaces,
|
|
glPreview,
|
|
webgl2Missing,
|
|
save,
|
|
};
|
|
}
|