World SVG Builder (Public Domain)

Data: Natural Earth (Public Domain) · Engine: Leaflet

How this works

  • Loads Natural Earth Admin‑0 (countries) GeoJSON via CDN (Public Domain).
  • Converts it client‑side into an inline world.svg (equirectangular viewBox).
  • Renders the SVG via Leaflet’s L.svgOverlay for interactivity.
  • Click Export to download a fully offline, single‑file HTML with the SVG embedded.
Tip: 10m is most detailed (big), 110m is lightest.
${svgMarkup.replace(/ $(function () { const map = L.map('map', { center: [20, 0], zoom: 2, minZoom: 1, maxZoom: 8, worldCopyJump: true, attributionControl: false }); L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 19, attribution: '© OpenStreetMap contributors' }).addTo(map); const svgEl = document.getElementById('world-svg'); const worldBounds = [[90, -180], [-90, 180]]; const overlay = L.svgOverlay(svgEl, worldBounds).addTo(map); map.fitBounds([[72, -170], [-55, 170]]); function countryName(n){ return n.getAttribute('data-name') || n.id || 'Unknown'; } function svgPathToLatLngBounds(pathEl) { const vb = svgEl.viewBox.baseVal; const bbox = pathEl.getBBox(); if (!vb || vb.width === 0 || vb.height === 0) return null; const xMin = (bbox.x - vb.x) / vb.width; const yMin = (bbox.y - vb.y) / vb.height; const xMax = (bbox.x + bbox.width - vb.x) / vb.width; const yMax = (bbox.y + bbox.height - vb.y) / vb.height; const lonMin = -180 + 360 * xMin; const lonMax = -180 + 360 * xMax; const latMax = 90 - 180 * yMin; const latMin = 90 - 180 * yMax; return L.latLngBounds([latMax, lonMin], [latMin, lonMax]); } svgEl.querySelectorAll('.country').forEach(node => { node.addEventListener('click', () => { svgEl.querySelectorAll('.country.selected').forEach(n => n.classList.remove('selected')); node.classList.add('selected'); const b = svgPathToLatLngBounds(node); if (b) map.fitBounds(b.pad(0.15)); if (b) { const c = b.getCenter(); L.popup({ closeButton: true }) .setLatLng(c) .setContent('' + countryName(node) + ' (' + (node.id||'') + ')') .openOn(map); } }); }); $('#reset').on('click', function () { svgEl.querySelectorAll('.country.selected').forEach(n => n.classList.remove('selected')); map.fitBounds([[72, -170], [-55, 170]]); map.closePopup(); }); }); `; const blob = new Blob([template], { type: 'text/html' }); const a = document.createElement('a'); a.href = URL.createObjectURL(blob); a.download = 'world_inline_public_domain.html'; a.click(); URL.revokeObjectURL(a.href); setStatus('Single-file HTML exported.'); } function rebuild(detail) { setStatus('Building SVG…'); fetchCountries(detail).then(geo => { setStatus('Converting to SVG…'); const svg = buildSVG(geo); renderSVG(svg); attachInteractivity(); setStatus(`Ready. Countries: ${featuresIndex.length}.`); }).catch(err => { console.error(err); setStatus('Failed to load or convert data.'); alert('Could not load Natural Earth data.'); }); } $detail.on('change', function(){ rebuild($(this).val()); }); rebuild($detail.val()); });