// world-map.jsx — mapa mundial real (fronteiras verdadeiras via D3 + world-atlas) // Carrega d3 + topojson-client + dados de países (110m) via CDN em tempo real no navegador. // Sem pontos fictícios: os pinos vêm exclusivamente de compromissos reais enviados no formulário. const MAP_W = 900, MAP_H = 460; function loadScriptOnce(src) { return new Promise((resolve, reject) => { const existing = document.querySelector('script[data-src="' + src + '"]'); if (existing) { if (existing.dataset.loaded === '1') return resolve(); existing.addEventListener('load', () => resolve()); existing.addEventListener('error', reject); return; } const s = document.createElement('script'); s.src = src; s.dataset.src = src; s.onload = () => { s.dataset.loaded = '1'; resolve(); }; s.onerror = reject; document.head.appendChild(s); }); } function WorldMap({ pins }) { const canvasRef = React.useRef(null); const [status, setStatus] = React.useState('loading'); // loading | ready | error const projectionRef = React.useRef(null); const [, forceRender] = React.useState(0); React.useEffect(() => { let cancelled = false; async function init() { try { if (!window.d3) await loadScriptOnce('https://cdn.jsdelivr.net/npm/d3@7/dist/d3.min.js'); if (!window.topojson) await loadScriptOnce('https://cdn.jsdelivr.net/npm/topojson-client@3/dist/topojson-client.min.js'); const res = await fetch('https://cdn.jsdelivr.net/npm/world-atlas@2/countries-110m.json'); const topo = await res.json(); if (cancelled) return; const countries = window.topojson.feature(topo, topo.objects.countries); const canvas = canvasRef.current; const dpr = Math.min(window.devicePixelRatio || 1, 2); canvas.width = MAP_W * dpr; canvas.height = MAP_H * dpr; canvas.style.width = '100%'; canvas.style.height = 'auto'; const ctx = canvas.getContext('2d'); ctx.setTransform(dpr, 0, 0, dpr, 0, 0); const projection = window.d3.geoNaturalEarth1().fitSize([MAP_W, MAP_H - 20], countries); projection.translate([projection.translate()[0], projection.translate()[1] + 10]); const path = window.d3.geoPath(projection, ctx); ctx.clearRect(0, 0, MAP_W, MAP_H); ctx.beginPath(); path(countries); ctx.fillStyle = 'rgba(230,197,124,0.30)'; ctx.fill(); ctx.lineWidth = 0.6; ctx.strokeStyle = 'rgba(230,197,124,0.55)'; ctx.stroke(); projectionRef.current = projection; setStatus('ready'); forceRender((n) => n + 1); } catch (e) { if (!cancelled) setStatus('error'); } } init(); return () => { cancelled = true; }; }, []); return (