fix: render choropleth as single image overlay — eliminates all tile seams
All checks were successful
Deploy Internet for Kids / Build & Push (push) Successful in 26s
Deploy Internet for Kids / Deploy (push) Successful in 6s
Deploy Internet for Kids / Health Check (push) Successful in 2s
Deploy Internet for Kids / Smoke Tests (push) Successful in 3s
Deploy Internet for Kids / IndexNow Ping (push) Successful in 7s
Deploy Internet for Kids / Promote to Latest (push) Successful in 2s
Deploy Internet for Kids / Rollback (push) Has been skipped
Deploy Internet for Kids / Audit (push) Successful in 2s
All checks were successful
Deploy Internet for Kids / Build & Push (push) Successful in 26s
Deploy Internet for Kids / Deploy (push) Successful in 6s
Deploy Internet for Kids / Health Check (push) Successful in 2s
Deploy Internet for Kids / Smoke Tests (push) Successful in 3s
Deploy Internet for Kids / IndexNow Ping (push) Successful in 7s
Deploy Internet for Kids / Promote to Latest (push) Successful in 2s
Deploy Internet for Kids / Rollback (push) Has been skipped
Deploy Internet for Kids / Audit (push) Successful in 2s
GeoJSON sources are internally tiled by geojson-vt, causing seams at tile boundaries during panning. Solution: pre-render the choropleth to a canvas, convert to PNG data URL, and add as a MapLibre image source. Single image = zero tiles = zero seams. GeoJSON source kept invisible for hover/click hit testing. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -24,7 +24,8 @@ body { margin: 0; overflow: hidden; }
|
|||||||
var LANG = 'en';
|
var LANG = 'en';
|
||||||
try { var m = parent.location.pathname.match(/^\/(de|fr|en)\//); if (m) LANG = m[1]; } catch(e) {}
|
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 = {
|
var STATUS_LABELS = {
|
||||||
en: { enforced: 'Enforced', passed: 'Passed', progress: 'In Progress', guidelines: 'Guidelines' },
|
en: { enforced: 'Enforced', passed: 'Passed', progress: 'In Progress', guidelines: 'Guidelines' },
|
||||||
de: { enforced: 'In Kraft', passed: 'Verabschiedet', progress: 'In Bearbeitung', guidelines: 'Richtlinien' },
|
de: { enforced: 'In Kraft', passed: 'Verabschiedet', progress: 'In Bearbeitung', guidelines: 'Richtlinien' },
|
||||||
@@ -41,6 +42,7 @@ body { margin: 0; overflow: hidden; }
|
|||||||
center: [20, 20],
|
center: [20, 20],
|
||||||
zoom: 2,
|
zoom: 2,
|
||||||
scrollZoom: false,
|
scrollZoom: false,
|
||||||
|
fadeDuration: 0,
|
||||||
style: 'https://maps.clicksports.de/styles/klokantech-basic/style.json'
|
style: 'https://maps.clicksports.de/styles/klokantech-basic/style.json'
|
||||||
});
|
});
|
||||||
_ifkMap.addControl(new maplibregl.NavigationControl({ showCompass: false }), 'top-right');
|
_ifkMap.addControl(new maplibregl.NavigationControl({ showCompass: false }), 'top-right');
|
||||||
@@ -65,28 +67,57 @@ body { margin: 0; overflow: hidden; }
|
|||||||
geo.features.forEach(function(f) {
|
geo.features.forEach(function(f) {
|
||||||
var id = String(f.id).padStart(3, '0');
|
var id = String(f.id).padStart(3, '0');
|
||||||
var c = byIsoNum[id];
|
var c = byIsoNum[id];
|
||||||
f.properties.fillColor = c ? STATUS_COLORS[c.status] : '#dce4ec';
|
f.properties.fillColor = c ? STATUS_COLORS[c.status] : 'transparent';
|
||||||
f.properties.fillOpacity = c ? 0.65 : 0.1;
|
f.properties.fillOpacity = c ? 1 : 0;
|
||||||
f.properties.isoNum = id;
|
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({
|
// Draw country fills using Equirectangular projection
|
||||||
id: 'choropleth-fill', type: 'fill', source: 'countries',
|
geo.features.forEach(function(f) {
|
||||||
paint: {
|
var id = String(f.id).padStart(3, '0');
|
||||||
'fill-color': ['get', 'fillColor'],
|
var c = byIsoNum[id];
|
||||||
'fill-opacity': ['get', 'fillOpacity'],
|
if (!c) return;
|
||||||
'fill-antialias': false
|
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({
|
_ifkMap.addLayer({
|
||||||
id: 'choropleth-border', type: 'line', source: 'countries',
|
id: 'choropleth-fill',
|
||||||
paint: { 'line-color': '#94a3b8', 'line-width': 0.5 }
|
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({
|
_ifkMap.addLayer({
|
||||||
id: 'choropleth-hover', type: 'fill', source: 'countries',
|
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', '']
|
filter: ['==', 'isoNum', '']
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user