fix: CSP allow ArcGIS/Swisstopo tiles, add 4 base maps (OSM, Satellit, Swisstopo, Luftbild CH)

This commit is contained in:
Pepe Ziberi
2026-02-22 00:06:56 +01:00
parent 2432e9a17f
commit 5bf4106db2
2 changed files with 55 additions and 15 deletions

View File

@@ -49,9 +49,9 @@ const nextConfig = {
"default-src 'self'", "default-src 'self'",
"script-src 'self' 'unsafe-inline' 'unsafe-eval' blob:", "script-src 'self' 'unsafe-inline' 'unsafe-eval' blob:",
"style-src 'self' 'unsafe-inline'", "style-src 'self' 'unsafe-inline'",
"img-src 'self' data: blob: https://*.tile.openstreetmap.org https://api.maptiler.com http://localhost:9000 http://minio:9000", "img-src 'self' data: blob: https://*.tile.openstreetmap.org https://api.maptiler.com https://server.arcgisonline.com https://wmts.geo.admin.ch https://wmts0.geo.admin.ch https://wmts1.geo.admin.ch https://wmts2.geo.admin.ch https://wmts3.geo.admin.ch https://wmts4.geo.admin.ch http://localhost:9000 http://minio:9000",
"font-src 'self' data:", "font-src 'self' data:",
"connect-src 'self' ws: wss: https://api.maptiler.com https://*.tile.openstreetmap.org https://api.open-meteo.com", "connect-src 'self' ws: wss: https://api.maptiler.com https://*.tile.openstreetmap.org https://api.open-meteo.com https://server.arcgisonline.com https://wmts.geo.admin.ch https://wmts0.geo.admin.ch https://wmts1.geo.admin.ch https://wmts2.geo.admin.ch https://wmts3.geo.admin.ch https://wmts4.geo.admin.ch",
"frame-ancestors 'self'", "frame-ancestors 'self'",
"base-uri 'self'", "base-uri 'self'",
"form-action 'self'", "form-action 'self'",

View File

@@ -106,7 +106,7 @@ export function MapView({
const measureMarkersRef = useRef<maplibregl.Marker[]>([]) const measureMarkersRef = useRef<maplibregl.Marker[]>([])
const measureCoordsRef = useRef<number[][]>([]) const measureCoordsRef = useRef<number[][]>([])
const [isMapLoaded, setIsMapLoaded] = useState(false) const [isMapLoaded, setIsMapLoaded] = useState(false)
const [isSatellite, setIsSatellite] = useState(false) const [activeBaseLayer, setActiveBaseLayer] = useState<'osm' | 'satellite' | 'swisstopo' | 'swissimage'>('osm')
const [measurePointCount, setMeasurePointCount] = useState(0) const [measurePointCount, setMeasurePointCount] = useState(0)
const [measureFinished, setMeasureFinished] = useState(false) const [measureFinished, setMeasureFinished] = useState(false)
const [drawingPointCount, setDrawingPointCount] = useState(0) const [drawingPointCount, setDrawingPointCount] = useState(0)
@@ -689,6 +689,24 @@ export function MapView({
attribution: '© Esri, Maxar, Earthstar Geographics', attribution: '© Esri, Maxar, Earthstar Geographics',
maxzoom: 19, maxzoom: 19,
}, },
'swisstopo': {
type: 'raster',
tiles: [
'https://wmts.geo.admin.ch/1.0.0/ch.swisstopo.pixelkarte-farbe/default/current/3857/{z}/{x}/{y}.jpeg',
],
tileSize: 256,
attribution: '© swisstopo',
maxzoom: 18,
},
'swissimage': {
type: 'raster',
tiles: [
'https://wmts.geo.admin.ch/1.0.0/ch.swisstopo.swissimage/default/current/3857/{z}/{x}/{y}.jpeg',
],
tileSize: 256,
attribution: '© swisstopo SWISSIMAGE',
maxzoom: 20,
},
}, },
layers: [ layers: [
{ {
@@ -702,6 +720,18 @@ export function MapView({
source: 'satellite', source: 'satellite',
layout: { visibility: 'none' }, layout: { visibility: 'none' },
}, },
{
id: 'swisstopo',
type: 'raster',
source: 'swisstopo',
layout: { visibility: 'none' },
},
{
id: 'swissimage',
type: 'raster',
source: 'swissimage',
layout: { visibility: 'none' },
},
], ],
}, },
center: [initialCenter.lng, initialCenter.lat], center: [initialCenter.lng, initialCenter.lat],
@@ -2109,28 +2139,38 @@ export function MapView({
</> </>
)} )}
{/* Layer toggle: OSM / Satellite */} {/* Layer toggle: cycle through base maps */}
<button <button
onClick={() => { onClick={() => {
if (!map.current) return if (!map.current) return
const newSat = !isSatellite const layers: Array<'osm' | 'satellite' | 'swisstopo' | 'swissimage'> = ['osm', 'satellite', 'swisstopo', 'swissimage']
setIsSatellite(newSat) const currentIdx = layers.indexOf(activeBaseLayer)
map.current.setLayoutProperty('osm', 'visibility', newSat ? 'none' : 'visible') const nextLayer = layers[(currentIdx + 1) % layers.length]
map.current.setLayoutProperty('satellite', 'visibility', newSat ? 'visible' : 'none') for (const l of layers) {
map.current.setLayoutProperty(l, 'visibility', l === nextLayer ? 'visible' : 'none')
}
setActiveBaseLayer(nextLayer)
}} }}
className="absolute top-3 right-3 z-10 flex items-center gap-1.5 px-2.5 py-1.5 rounded-lg text-xs font-semibold shadow-lg border transition-colors" className="absolute top-3 right-3 z-10 flex items-center gap-1.5 px-2.5 py-1.5 rounded-lg text-xs font-semibold shadow-lg border transition-colors"
style={{ style={{
background: isSatellite ? 'rgba(0,0,0,0.7)' : 'rgba(255,255,255,0.95)', background: activeBaseLayer !== 'osm' ? 'rgba(0,0,0,0.7)' : 'rgba(255,255,255,0.95)',
color: isSatellite ? '#fff' : '#333', color: activeBaseLayer !== 'osm' ? '#fff' : '#333',
borderColor: isSatellite ? 'rgba(255,255,255,0.3)' : 'rgba(0,0,0,0.15)', borderColor: activeBaseLayer !== 'osm' ? 'rgba(255,255,255,0.3)' : 'rgba(0,0,0,0.15)',
}} }}
title={isSatellite ? 'Zur Kartenansicht wechseln' : 'Zur Satellitenansicht wechseln'} title="Kartenstil wechseln"
> >
{isSatellite ? ( {activeBaseLayer === 'osm' && (
<><svg className="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M3 7l6-3 6 3 6-3v13l-6 3-6-3-6 3z"/><path d="M9 4v13"/><path d="M15 7v13"/></svg>Karte</>
) : (
<><svg className="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><circle cx="12" cy="12" r="10"/><path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20"/><path d="M2 12h20"/></svg>Satellit</> <><svg className="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><circle cx="12" cy="12" r="10"/><path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20"/><path d="M2 12h20"/></svg>Satellit</>
)} )}
{activeBaseLayer === 'satellite' && (
<><svg className="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M3 7l6-3 6 3 6-3v13l-6 3-6-3-6 3z"/><path d="M9 4v13"/><path d="M15 7v13"/></svg>Swisstopo</>
)}
{activeBaseLayer === 'swisstopo' && (
<><svg className="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><circle cx="12" cy="12" r="10"/><path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20"/><path d="M2 12h20"/></svg>Luftbild CH</>
)}
{activeBaseLayer === 'swissimage' && (
<><svg className="w-4 h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M3 7l6-3 6 3 6-3v13l-6 3-6-3-6 3z"/><path d="M9 4v13"/><path d="M15 7v13"/></svg>OSM</>
)}
</button> </button>
{/* Zeichnung abschliessen Button (Linie/Polygon/Pfeil) */} {/* Zeichnung abschliessen Button (Linie/Polygon/Pfeil) */}