diff --git a/static/map-embed.html b/static/map-embed.html index ef68c3e..60753f9 100644 --- a/static/map-embed.html +++ b/static/map-embed.html @@ -24,7 +24,8 @@ body { margin: 0; overflow: hidden; } var LANG = 'en'; try { var m = parent.location.pathname.match(/^\/(de|fr|en)\//); if (m) LANG = m[1]; } catch(e) {} - var STATUS_COLORS = { enforced: '#667eea', passed: '#764ba2', progress: '#a5b4fc', guidelines: '#e0e7ff' }; + // Pre-blended with base map — fully opaque to prevent tile seam artifacts from transparency + var STATUS_COLORS = { enforced: '#9cabf1', passed: '#a68ac3', progress: '#c5cefd', guidelines: '#ebefff' }; var STATUS_LABELS = { en: { enforced: 'Enforced', passed: 'Passed', progress: 'In Progress', guidelines: 'Guidelines' }, de: { enforced: 'In Kraft', passed: 'Verabschiedet', progress: 'In Bearbeitung', guidelines: 'Richtlinien' }, @@ -41,6 +42,7 @@ body { margin: 0; overflow: hidden; } center: [20, 20], zoom: 2, scrollZoom: false, + fadeDuration: 0, style: 'https://maps.clicksports.de/styles/klokantech-basic/style.json' }); _ifkMap.addControl(new maplibregl.NavigationControl({ showCompass: false }), 'top-right'); @@ -65,28 +67,57 @@ body { margin: 0; overflow: hidden; } geo.features.forEach(function(f) { var id = String(f.id).padStart(3, '0'); var c = byIsoNum[id]; - f.properties.fillColor = c ? STATUS_COLORS[c.status] : '#dce4ec'; - f.properties.fillOpacity = c ? 0.65 : 0.1; + f.properties.fillColor = c ? STATUS_COLORS[c.status] : 'transparent'; + f.properties.fillOpacity = c ? 1 : 0; f.properties.isoNum = id; }); - _ifkMap.addSource('countries', { type: 'geojson', data: geo }); + // Render choropleth to a canvas, then add as single image source (NOT tiled) + var W = 2048, H = 1024; + var offscreen = document.createElement('canvas'); + offscreen.width = W; offscreen.height = H; + var ctx = offscreen.getContext('2d'); - _ifkMap.addLayer({ - id: 'choropleth-fill', type: 'fill', source: 'countries', - paint: { - 'fill-color': ['get', 'fillColor'], - 'fill-opacity': ['get', 'fillOpacity'], - 'fill-antialias': false - } + // Draw country fills using Equirectangular projection + geo.features.forEach(function(f) { + var id = String(f.id).padStart(3, '0'); + var c = byIsoNum[id]; + if (!c) return; + ctx.fillStyle = STATUS_COLORS[c.status]; + ctx.beginPath(); + var coords = f.geometry.type === 'Polygon' ? [f.geometry.coordinates] : f.geometry.coordinates; + coords.forEach(function(poly) { + poly.forEach(function(ring) { + for (var i = 0; i < ring.length; i++) { + var x = (ring[i][0] + 180) / 360 * W; + var y = (90 - ring[i][1]) / 180 * H; + if (i === 0) ctx.moveTo(x, y); + else ctx.lineTo(x, y); + } + ctx.closePath(); + }); + }); + ctx.fill(); + }); + + // Add as image source — single image, NO tiling + _ifkMap.addSource('choropleth-img', { + type: 'image', + url: offscreen.toDataURL('image/png'), + coordinates: [[-180, 85.05], [180, 85.05], [180, -85.05], [-180, -85.05]] }); _ifkMap.addLayer({ - id: 'choropleth-border', type: 'line', source: 'countries', - paint: { 'line-color': '#94a3b8', 'line-width': 0.5 } + id: 'choropleth-fill', + type: 'raster', + source: 'choropleth-img', + paint: { 'raster-opacity': 0.85, 'raster-fade-duration': 0 } }); + + // Keep GeoJSON source for hover/click interaction (invisible) + _ifkMap.addSource('countries', { type: 'geojson', data: geo }); _ifkMap.addLayer({ id: 'choropleth-hover', type: 'fill', source: 'countries', - paint: { 'fill-color': '#667eea', 'fill-opacity': 0.2 }, + paint: { 'fill-color': '#667eea', 'fill-opacity': 0.2, 'fill-antialias': false }, filter: ['==', 'isoNum', ''] });