2025-09-17 11:31:17 -03:00
|
|
|
import axios from 'axios';
|
2025-09-19 17:19:10 -03:00
|
|
|
import { Suspense, useState, useEffect, useCallback, useRef } from 'react';
|
2025-09-17 11:31:17 -03:00
|
|
|
import { useSuspenseQuery } from '@tanstack/react-query';
|
|
|
|
|
import { ComposableMap, Geographies, Geography, ZoomableGroup } from 'react-simple-maps';
|
|
|
|
|
import { Tooltip } from 'react-tooltip';
|
2025-09-19 17:19:10 -03:00
|
|
|
import { geoCentroid } from 'd3-geo';
|
|
|
|
|
import { feature } from 'topojson-client';
|
2025-09-17 11:31:17 -03:00
|
|
|
import { API_BASE_URL, assetBaseUrl } from '../../../../apiService';
|
|
|
|
|
import type { ResultadoMapaDto, AmbitoGeography } from '../../../../types/types';
|
|
|
|
|
import { MapaProvincial } from './MapaProvincial';
|
2025-09-19 17:19:10 -03:00
|
|
|
import { CabaLupa } from './CabaLupa';
|
2025-09-20 22:31:11 -03:00
|
|
|
import { BiZoomIn, BiZoomOut } from "react-icons/bi";
|
2025-10-01 10:03:01 -03:00
|
|
|
import toast from 'react-hot-toast';
|
2025-10-03 13:26:20 -03:00
|
|
|
import { useMediaQuery } from '../hooks/useMediaQuery';
|
2025-09-17 11:31:17 -03:00
|
|
|
|
|
|
|
|
const DEFAULT_MAP_COLOR = '#E0E0E0';
|
|
|
|
|
const FADED_BACKGROUND_COLOR = '#F0F0F0';
|
|
|
|
|
const normalizarTexto = (texto: string = '') => texto.trim().toUpperCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "");
|
|
|
|
|
|
|
|
|
|
type PointTuple = [number, number];
|
|
|
|
|
|
2025-10-03 13:26:20 -03:00
|
|
|
interface ViewConfig {
|
|
|
|
|
center: PointTuple;
|
|
|
|
|
zoom: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const PROVINCE_VIEW_CONFIG: Record<string, { desktop: ViewConfig; mobile?: ViewConfig }> = {
|
|
|
|
|
"BUENOS AIRES": { desktop: { center: [-60.5, -37.3], zoom: 5 }, mobile: { center: [-60, -38], zoom: 5.5 } },
|
|
|
|
|
"SANTA CRUZ": { desktop: { center: [-69.5, -49.3], zoom: 5 }, mobile: { center: [-69.5, -50], zoom: 4 } },
|
|
|
|
|
"CIUDAD AUTONOMA DE BUENOS AIRES": { desktop: { center: [-58.44, -34.65], zoom: 150 } },
|
|
|
|
|
"CHUBUT": { desktop: { center: [-68.5, -44.5], zoom: 5.5 }, mobile: { center: [-68, -44.5], zoom: 4.5 } },
|
|
|
|
|
"SANTA FE": { desktop: { center: [-61, -31.2], zoom: 6 }, mobile: { center: [-61, -31.5], zoom: 7.5 } },
|
|
|
|
|
"CORRIENTES": { desktop: { center: [-58, -29], zoom: 7 }, mobile: { center: [-57.5, -28.8], zoom: 9 } },
|
|
|
|
|
"RIO NEGRO": { desktop: { center: [-67.5, -40], zoom: 5.5 }, mobile: { center: [-67.5, -40], zoom: 4.3 } },
|
|
|
|
|
"SALTA": { desktop: { center: [-64.5, -24], zoom: 7 }, mobile: { center: [-65.5, -24.5], zoom: 6 } },
|
|
|
|
|
"TIERRA DEL FUEGO": { desktop: { center: [-66.5, -54.2], zoom: 7 }, mobile: { center: [-66, -54], zoom: 7.5 } },
|
2025-09-19 17:19:10 -03:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const LUPA_SIZE_RATIO = 0.2;
|
|
|
|
|
const MIN_LUPA_SIZE_PX = 100;
|
|
|
|
|
const MAX_LUPA_SIZE_PX = 180;
|
|
|
|
|
|
2025-09-17 11:31:17 -03:00
|
|
|
interface MapaNacionalProps {
|
|
|
|
|
eleccionId: number;
|
|
|
|
|
categoriaId: number;
|
|
|
|
|
nivel: 'pais' | 'provincia' | 'municipio';
|
|
|
|
|
nombreAmbito: string;
|
2025-09-19 17:19:10 -03:00
|
|
|
nombreProvinciaActiva: string | undefined | null;
|
2025-09-17 11:31:17 -03:00
|
|
|
provinciaDistritoId: string | null;
|
|
|
|
|
onAmbitoSelect: (ambitoId: string, nivel: 'provincia' | 'municipio', nombre: string) => void;
|
|
|
|
|
onVolver: () => void;
|
2025-09-20 22:31:11 -03:00
|
|
|
isMobileView: boolean;
|
2025-09-17 11:31:17 -03:00
|
|
|
}
|
|
|
|
|
|
2025-09-20 22:31:11 -03:00
|
|
|
// --- CONFIGURACIONES DEL MAPA ---
|
|
|
|
|
const desktopProjectionConfig = { scale: 700, center: [-65, -40] as [number, number] };
|
2025-10-03 13:53:11 -03:00
|
|
|
const mobileProjectionConfig = { scale: 1050, center: [-64, -43] as [number, number] };
|
2025-10-03 13:26:20 -03:00
|
|
|
const mobileSmallProjectionConfig = { scale: 900, center: [-64, -43] as [number, number] };
|
|
|
|
|
|
2025-09-20 22:31:11 -03:00
|
|
|
|
|
|
|
|
export const MapaNacional = ({ eleccionId, categoriaId, nivel, nombreAmbito, nombreProvinciaActiva, provinciaDistritoId, onAmbitoSelect, onVolver, isMobileView }: MapaNacionalProps) => {
|
2025-10-03 13:26:20 -03:00
|
|
|
const isMobileSmall = useMediaQuery('(max-width: 380px)');
|
|
|
|
|
|
2025-09-20 22:31:11 -03:00
|
|
|
const [position, setPosition] = useState({
|
2025-10-03 13:26:20 -03:00
|
|
|
zoom: isMobileView ? 1.5 : 1.05,
|
|
|
|
|
center: isMobileView ? mobileProjectionConfig.center : desktopProjectionConfig.center as PointTuple
|
2025-09-20 22:31:11 -03:00
|
|
|
});
|
2025-09-22 09:08:43 -03:00
|
|
|
const [isPanning, setIsPanning] = useState(false);
|
2025-10-03 13:26:20 -03:00
|
|
|
const initialProvincePositionRef = useRef<ViewConfig | null>(null);
|
2025-09-17 11:31:17 -03:00
|
|
|
|
2025-09-19 17:19:10 -03:00
|
|
|
const containerRef = useRef<HTMLDivElement | null>(null);
|
|
|
|
|
const lupaRef = useRef<HTMLDivElement | null>(null);
|
|
|
|
|
const cabaPathRef = useRef<SVGPathElement | null>(null);
|
|
|
|
|
const isAnimatingRef = useRef(false);
|
2025-09-22 09:08:43 -03:00
|
|
|
const initialLoadRef = useRef(true);
|
2025-09-19 17:19:10 -03:00
|
|
|
|
|
|
|
|
const [lupaStyle, setLupaStyle] = useState<React.CSSProperties>({ opacity: 0 });
|
|
|
|
|
|
2025-09-17 11:31:17 -03:00
|
|
|
const { data: mapaDataNacional } = useSuspenseQuery<ResultadoMapaDto[]>({
|
|
|
|
|
queryKey: ['mapaResultados', eleccionId, categoriaId, null],
|
|
|
|
|
queryFn: async () => {
|
|
|
|
|
const url = `${API_BASE_URL}/elecciones/${eleccionId}/mapa-resultados?categoriaId=${categoriaId}`;
|
|
|
|
|
const response = await axios.get(url);
|
|
|
|
|
return response.data;
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const { data: geoDataNacional } = useSuspenseQuery<any>({
|
|
|
|
|
queryKey: ['geoDataNacional'],
|
|
|
|
|
queryFn: () => axios.get(`${assetBaseUrl}/maps/argentina-provincias.topojson`).then(res => res.data),
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (nivel === 'pais') {
|
2025-10-03 13:26:20 -03:00
|
|
|
const currentMobileConfig = isMobileSmall ? mobileSmallProjectionConfig : mobileProjectionConfig;
|
|
|
|
|
const currentMobileZoom = isMobileSmall ? 1.4 : 1.5;
|
|
|
|
|
|
2025-09-20 22:31:11 -03:00
|
|
|
setPosition({
|
2025-10-03 13:26:20 -03:00
|
|
|
zoom: isMobileView ? currentMobileZoom : 1.05,
|
|
|
|
|
center: isMobileView ? currentMobileConfig.center : desktopProjectionConfig.center
|
2025-09-20 22:31:11 -03:00
|
|
|
});
|
|
|
|
|
initialProvincePositionRef.current = null;
|
2025-09-17 11:31:17 -03:00
|
|
|
} else if (nivel === 'provincia') {
|
2025-09-19 17:19:10 -03:00
|
|
|
const nombreNormalizado = normalizarTexto(nombreAmbito);
|
|
|
|
|
const manualConfig = PROVINCE_VIEW_CONFIG[nombreNormalizado];
|
2025-10-03 13:26:20 -03:00
|
|
|
|
|
|
|
|
let provinceConfig: ViewConfig | undefined;
|
2025-09-20 22:31:11 -03:00
|
|
|
|
2025-09-19 17:19:10 -03:00
|
|
|
if (manualConfig) {
|
2025-10-03 13:26:20 -03:00
|
|
|
provinceConfig = (isMobileView && manualConfig.mobile) ? manualConfig.mobile : manualConfig.desktop;
|
2025-09-19 17:19:10 -03:00
|
|
|
} else {
|
|
|
|
|
const provinciaGeo = geoDataNacional.objects.provincias.geometries.find((g: any) => normalizarTexto(g.properties.nombre) === nombreNormalizado);
|
|
|
|
|
if (provinciaGeo) {
|
|
|
|
|
const provinciaFeature = feature(geoDataNacional, provinciaGeo);
|
|
|
|
|
const centroid = geoCentroid(provinciaFeature);
|
2025-10-03 13:26:20 -03:00
|
|
|
provinceConfig = { zoom: isMobileView ? 8 : 7, center: centroid as PointTuple };
|
2025-09-19 17:19:10 -03:00
|
|
|
}
|
|
|
|
|
}
|
2025-09-20 22:31:11 -03:00
|
|
|
|
2025-10-03 13:26:20 -03:00
|
|
|
if (provinceConfig) {
|
|
|
|
|
setPosition(provinceConfig);
|
|
|
|
|
initialProvincePositionRef.current = provinceConfig;
|
|
|
|
|
}
|
2025-09-17 11:31:17 -03:00
|
|
|
}
|
2025-10-03 13:26:20 -03:00
|
|
|
}, [nivel, nombreAmbito, geoDataNacional, isMobileView, isMobileSmall]);
|
|
|
|
|
|
2025-09-19 17:19:10 -03:00
|
|
|
|
|
|
|
|
const resultadosNacionalesPorNombre = new Map<string, ResultadoMapaDto>(mapaDataNacional.map(d => [normalizarTexto(d.ambitoNombre), d]));
|
|
|
|
|
const nombreMunicipioSeleccionado = nivel === 'municipio' ? nombreAmbito : null;
|
|
|
|
|
const handleCalculatedCenter = useCallback((center: PointTuple, zoom: number) => { setPosition({ center, zoom }); }, []);
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
const updateLupaPosition = () => {
|
|
|
|
|
if (nivel === 'pais' && cabaPathRef.current && containerRef.current) {
|
|
|
|
|
const containerRect = containerRef.current.getBoundingClientRect();
|
|
|
|
|
if (containerRect.width === 0) return;
|
|
|
|
|
|
|
|
|
|
const cabaRect = cabaPathRef.current.getBoundingClientRect();
|
|
|
|
|
const cabaCenterX = (cabaRect.left - containerRect.left) + cabaRect.width / 2;
|
|
|
|
|
const cabaCenterY = (cabaRect.top - containerRect.top) + cabaRect.height / 2;
|
2025-09-17 11:31:17 -03:00
|
|
|
|
2025-09-19 17:19:10 -03:00
|
|
|
const calculatedSize = containerRect.width * LUPA_SIZE_RATIO;
|
|
|
|
|
const newLupaSize = Math.max(MIN_LUPA_SIZE_PX, Math.min(calculatedSize, MAX_LUPA_SIZE_PX));
|
2025-09-20 22:31:11 -03:00
|
|
|
|
2025-09-19 17:19:10 -03:00
|
|
|
const horizontalOffset = newLupaSize * 0.5;
|
|
|
|
|
const verticalOffset = newLupaSize * 0.2;
|
|
|
|
|
|
|
|
|
|
setLupaStyle({
|
|
|
|
|
position: 'absolute',
|
|
|
|
|
top: `${cabaCenterY - verticalOffset}px`,
|
|
|
|
|
left: `${cabaCenterX + horizontalOffset}px`,
|
|
|
|
|
width: `${newLupaSize}px`,
|
|
|
|
|
opacity: 1,
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
setLupaStyle({ opacity: 0, pointerEvents: 'none' });
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
isAnimatingRef.current = true;
|
2025-09-22 09:08:43 -03:00
|
|
|
const handleResize = () => { if (!isAnimatingRef.current) updateLupaPosition(); };
|
2025-09-19 17:19:10 -03:00
|
|
|
const resizeObserver = new ResizeObserver(handleResize);
|
2025-09-22 09:08:43 -03:00
|
|
|
if (containerRef.current) resizeObserver.observe(containerRef.current);
|
2025-09-20 22:31:11 -03:00
|
|
|
|
2025-09-19 17:19:10 -03:00
|
|
|
let timerId: NodeJS.Timeout;
|
|
|
|
|
if (initialLoadRef.current && nivel === 'pais') {
|
|
|
|
|
timerId = setTimeout(() => {
|
|
|
|
|
updateLupaPosition();
|
|
|
|
|
isAnimatingRef.current = false;
|
|
|
|
|
}, 0);
|
2025-09-22 09:08:43 -03:00
|
|
|
initialLoadRef.current = false;
|
2025-09-19 17:19:10 -03:00
|
|
|
} else {
|
|
|
|
|
timerId = setTimeout(() => {
|
|
|
|
|
updateLupaPosition();
|
|
|
|
|
isAnimatingRef.current = false;
|
|
|
|
|
}, 800);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return () => {
|
2025-09-22 09:08:43 -03:00
|
|
|
if (containerRef.current) resizeObserver.unobserve(containerRef.current);
|
2025-09-19 17:19:10 -03:00
|
|
|
clearTimeout(timerId);
|
|
|
|
|
isAnimatingRef.current = false;
|
|
|
|
|
};
|
|
|
|
|
}, [position, nivel]);
|
2025-09-17 11:31:17 -03:00
|
|
|
|
2025-10-01 10:03:01 -03:00
|
|
|
const panEnabled =
|
|
|
|
|
nivel === 'provincia' &&
|
|
|
|
|
initialProvincePositionRef.current !== null &&
|
|
|
|
|
position.zoom > initialProvincePositionRef.current.zoom &&
|
|
|
|
|
!nombreMunicipioSeleccionado;
|
|
|
|
|
|
|
|
|
|
const handleZoomIn = () => {
|
|
|
|
|
if (!panEnabled && initialProvincePositionRef.current) {
|
|
|
|
|
const newZoom = position.zoom * 1.8;
|
|
|
|
|
if (newZoom > initialProvincePositionRef.current.zoom) {
|
|
|
|
|
toast.success('Desplazamiento Habilitado', {
|
|
|
|
|
icon: '🖐️',
|
|
|
|
|
style: { background: '#32e5f1ff', color: 'white' },
|
|
|
|
|
duration: 1000,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
setPosition(prev => ({ ...prev, zoom: Math.min(prev.zoom * 1.8, 100) }));
|
|
|
|
|
};
|
2025-09-20 22:31:11 -03:00
|
|
|
|
|
|
|
|
const handleZoomOut = () => {
|
2025-10-01 10:03:01 -03:00
|
|
|
if (panEnabled && initialProvincePositionRef.current) {
|
|
|
|
|
const newZoom = position.zoom / 1.8;
|
|
|
|
|
if (newZoom <= initialProvincePositionRef.current.zoom) {
|
|
|
|
|
toast.error('Desplazamiento Deshabilitado', {
|
|
|
|
|
icon: '🔒',
|
|
|
|
|
style: { background: '#32e5f1ff', color: 'white' },
|
|
|
|
|
duration: 1000,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-09-20 22:31:11 -03:00
|
|
|
setPosition(prev => {
|
|
|
|
|
const newZoom = Math.max(prev.zoom / 1.8, 1);
|
|
|
|
|
const initialPos = initialProvincePositionRef.current;
|
2025-09-22 09:08:43 -03:00
|
|
|
if (initialPos && newZoom <= initialPos.zoom) return initialPos;
|
2025-09-20 22:31:11 -03:00
|
|
|
return { ...prev, zoom: newZoom };
|
|
|
|
|
});
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const handleMoveEnd = (newPosition: { coordinates: PointTuple, zoom: number }) => {
|
|
|
|
|
setPosition(prev => ({ ...prev, center: newPosition.coordinates }));
|
2025-09-22 09:08:43 -03:00
|
|
|
setIsPanning(false);
|
2025-09-20 22:31:11 -03:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const filterInteractionEvents = (event: any) => {
|
2025-09-22 09:08:43 -03:00
|
|
|
if (event.sourceEvent && event.sourceEvent.type === 'wheel') return false;
|
2025-09-20 22:31:11 -03:00
|
|
|
return panEnabled;
|
|
|
|
|
};
|
|
|
|
|
|
2025-09-22 09:08:43 -03:00
|
|
|
const showZoomControls = nivel === 'provincia';
|
2025-09-20 22:31:11 -03:00
|
|
|
const isZoomOutDisabled =
|
|
|
|
|
(nivel === 'provincia' && initialProvincePositionRef.current && position.zoom <= initialProvincePositionRef.current.zoom) ||
|
|
|
|
|
(nivel === 'pais' && position.zoom <= (isMobileView ? 1.4 : 1.05));
|
|
|
|
|
|
2025-09-22 09:08:43 -03:00
|
|
|
const mapContainerClasses = panEnabled ? 'mapa-componente-container map-pannable' : 'mapa-componente-container map-locked';
|
|
|
|
|
|
2025-09-17 11:31:17 -03:00
|
|
|
return (
|
2025-09-22 09:08:43 -03:00
|
|
|
<div className={mapContainerClasses} ref={containerRef}>
|
2025-09-20 22:31:11 -03:00
|
|
|
{showZoomControls && (
|
|
|
|
|
<div className="zoom-controls-container">
|
|
|
|
|
<button onClick={handleZoomIn} className="zoom-btn" title="Acercar">
|
|
|
|
|
<span className="zoom-icon-wrapper"><BiZoomIn /></span>
|
|
|
|
|
</button>
|
|
|
|
|
<button
|
|
|
|
|
onClick={handleZoomOut}
|
|
|
|
|
className={`zoom-btn ${isZoomOutDisabled ? 'disabled' : ''}`}
|
|
|
|
|
title="Alejar"
|
|
|
|
|
disabled={isZoomOutDisabled}
|
|
|
|
|
>
|
|
|
|
|
<span className="zoom-icon-wrapper"><BiZoomOut /></span>
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
|
2025-09-17 11:31:17 -03:00
|
|
|
{nivel !== 'pais' && <button onClick={onVolver} className="mapa-volver-btn">← Volver</button>}
|
2025-09-19 17:19:10 -03:00
|
|
|
|
|
|
|
|
<div className="mapa-render-area">
|
|
|
|
|
<ComposableMap
|
|
|
|
|
projection="geoMercator"
|
2025-10-03 13:26:20 -03:00
|
|
|
projectionConfig={isMobileSmall ? mobileSmallProjectionConfig : (isMobileView ? mobileProjectionConfig : desktopProjectionConfig)}
|
2025-09-19 17:19:10 -03:00
|
|
|
style={{ width: "100%", height: "100%" }}
|
|
|
|
|
>
|
|
|
|
|
<ZoomableGroup
|
|
|
|
|
center={position.center}
|
|
|
|
|
zoom={position.zoom}
|
2025-09-22 09:08:43 -03:00
|
|
|
onMoveStart={() => setIsPanning(true)}
|
2025-09-20 22:31:11 -03:00
|
|
|
onMoveEnd={handleMoveEnd}
|
|
|
|
|
filterZoomEvent={filterInteractionEvents}
|
2025-09-22 09:08:43 -03:00
|
|
|
className={isPanning ? 'panning' : ''}
|
2025-09-19 17:19:10 -03:00
|
|
|
>
|
|
|
|
|
<Geographies geography={geoDataNacional}>
|
|
|
|
|
{({ geographies }: { geographies: AmbitoGeography[] }) => geographies.map((geo) => {
|
|
|
|
|
const nombreNormalizado = normalizarTexto(geo.properties.nombre);
|
|
|
|
|
const esCABA = nombreNormalizado === 'CIUDAD AUTONOMA DE BUENOS AIRES';
|
|
|
|
|
const resultado = resultadosNacionalesPorNombre.get(nombreNormalizado);
|
|
|
|
|
const esProvinciaActiva = provinciaDistritoId && resultado?.ambitoId === provinciaDistritoId;
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<Geography
|
|
|
|
|
key={geo.rsmKey}
|
|
|
|
|
geography={geo}
|
|
|
|
|
ref={esCABA ? cabaPathRef : undefined}
|
|
|
|
|
className={`rsm-geography ${nivel !== 'pais' ? 'rsm-geography-faded' : ''}`}
|
2025-09-22 09:08:43 -03:00
|
|
|
style={{ visibility: esCABA ? 'hidden' : (esProvinciaActiva ? 'hidden' : 'visible') }}
|
2025-09-19 17:19:10 -03:00
|
|
|
fill={nivel === 'pais' ? (resultado?.colorGanador || DEFAULT_MAP_COLOR) : FADED_BACKGROUND_COLOR}
|
|
|
|
|
onClick={() => !esCABA && resultado && onAmbitoSelect(resultado.ambitoId, 'provincia', resultado.ambitoNombre)}
|
|
|
|
|
data-tooltip-id="mapa-tooltip"
|
|
|
|
|
data-tooltip-content={geo.properties.nombre}
|
|
|
|
|
/>
|
|
|
|
|
);
|
|
|
|
|
})}
|
|
|
|
|
</Geographies>
|
|
|
|
|
|
|
|
|
|
{provinciaDistritoId && nombreProvinciaActiva && (
|
|
|
|
|
<Suspense fallback={null}>
|
|
|
|
|
<MapaProvincial
|
|
|
|
|
eleccionId={eleccionId}
|
|
|
|
|
categoriaId={categoriaId}
|
|
|
|
|
distritoId={provinciaDistritoId}
|
|
|
|
|
nombreProvincia={nombreProvinciaActiva}
|
|
|
|
|
nombreMunicipioSeleccionado={nombreMunicipioSeleccionado}
|
|
|
|
|
onMunicipioSelect={(ambitoId, nombre) => onAmbitoSelect(ambitoId, 'municipio', nombre)}
|
|
|
|
|
onCalculatedCenter={handleCalculatedCenter}
|
|
|
|
|
nivel={nivel as 'provincia' | 'municipio'}
|
2025-09-17 11:31:17 -03:00
|
|
|
/>
|
2025-09-19 17:19:10 -03:00
|
|
|
</Suspense>
|
|
|
|
|
)}
|
|
|
|
|
</ZoomableGroup>
|
|
|
|
|
</ComposableMap>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
{nivel === 'pais' && (
|
|
|
|
|
<div id="caba-lupa-anchor" className="caba-magnifier-container" style={lupaStyle} ref={lupaRef}>
|
|
|
|
|
{(() => {
|
|
|
|
|
const resultadoCABA = resultadosNacionalesPorNombre.get("CIUDAD AUTONOMA DE BUENOS AIRES");
|
|
|
|
|
const fillColor = resultadoCABA?.colorGanador || DEFAULT_MAP_COLOR;
|
|
|
|
|
const handleClick = () => {
|
|
|
|
|
if (resultadoCABA) {
|
|
|
|
|
onAmbitoSelect(resultadoCABA.ambitoId, 'provincia', resultadoCABA.ambitoNombre);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
return <CabaLupa fillColor={fillColor} onClick={handleClick} />;
|
|
|
|
|
})()}
|
|
|
|
|
</div>
|
|
|
|
|
)}
|
|
|
|
|
|
2025-09-20 22:31:11 -03:00
|
|
|
<Tooltip id="mapa-tooltip" key={nivel} />
|
2025-09-17 11:31:17 -03:00
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
};
|