/* Torre Auro — Mapa de competencia por nicho (decisión por nivel) */ const _nicheCache = {}; // eco → places[] function _hav(aLat, aLng, bLat, bLng) { const R = 6371000, toR = Math.PI / 180; const dLat = (bLat - aLat) * toR, dLng = (bLng - aLng) * toR; const s = Math.sin(dLat/2)**2 + Math.cos(aLat*toR)*Math.cos(bLat*toR)*Math.sin(dLng/2)**2; return 2 * R * Math.asin(Math.sqrt(s)); } function NicheMap({ floor }) { const z = ZONES[floor.zone]; const eco = z.eco; const comp = NICHE_COMPETITION[eco] || NICHE_COMPETITION.corporativo; const acc = z.accHex; const mapRef = useRef(null); const clusterRef = useRef(null); const placesRef = useRef([]); const [ring, setRing] = useState(3000); const [status, setStatus] = useState('cargando'); const [counts, setCounts] = useState({ 1000:0, 3000:0, 5000:0 }); const ringRef = useRef(3000); function applyFilter() { const cl = clusterRef.current; if (!cl) return; cl.clearLayers(); const r = ringRef.current; cl.addLayers(placesRef.current.filter(p => p.dist <= r).map(p => p.marker)); } async function fetchNiche(signal) { if (_nicheCache[eco]) return _nicheCache[eco]; const { lat, lng } = TORRE_COORD; const out = []; const seen = new Set(); try { const url = `https://www.inegi.org.mx/app/api/denue/v1/consulta/Buscar/${encodeURIComponent(comp.term)}/${lat},${lng}/5000/${DENUE_TOKEN}`; const res = await fetch(url, { signal }); if (res.ok) { const data = await res.json(); (data || []).forEach(row => { const la = parseFloat(row.Latitud), ln = parseFloat(row.Longitud); if (!la || !ln) return; const id = row.Id || (row.Nombre + la + ln); if (seen.has(id)) return; seen.add(id); out.push({ lat:la, lng:ln, name: row.Nombre || row.Razon_social || 'Establecimiento', clase: row.Clase_actividad || '', dist: _hav(lat, lng, la, ln) }); }); } } catch (e) { /* ignore */ } _nicheCache[eco] = out; return out; } useEffect(() => { if (!window.L || mapRef.current) return; const el = document.getElementById('nichemap-' + floor.id); if (!el) return; let cancelled = false; const ac = new AbortController(); const { lat, lng } = TORRE_COORD; const map = window.L.map(el, { center:[lat,lng], zoom:14, scrollWheelZoom:false, zoomControl:true, attributionControl:false }); mapRef.current = map; window.L.tileLayer('https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png', { maxZoom:19 }).addTo(map); [5000,3000,1000].forEach(r => window.L.circle([lat,lng], { radius:r, color:acc, weight:1, opacity:.4, fill:false, dashArray:'4 6' }).addTo(map)); const torreIcon = window.L.divIcon({ className:'lmk-torre-wrap', html:'
Torre Auro garantiza exclusividad de giro por categoría. Esto significa cero competencia directa de tu nicho dentro del edificio — mientras el mercado de {comp.label} ya está activo en el entorno inmediato.