// src/components/MapaBsAs.tsx import { useState, useMemo } from 'react'; import { ComposableMap, Geographies, Geography } from 'react-simple-maps'; import { Tooltip } from 'react-tooltip'; import { useQuery } from '@tanstack/react-query'; import axios from 'axios'; import type { Feature, Geometry } from 'geojson'; import { geoCentroid } from 'd3-geo'; // Para calcular el centro de cada partido import { useSpring, animated } from 'react-spring'; // Para animar el zoom //import geoUrl from '/partidos-bsas.topojson'; import './MapaBsAs.css'; // --- Interfaces y Tipos --- interface ResultadoMapa { partidoId: string; agrupacionGanadoraId: string; porcentajeGanador: number; // Nueva propiedad desde el backend } interface Agrupacion { id: string; nombre: string; } interface PartidoProperties { id: number; departamento: string; cabecera: string; // Asegúrate de que coincida con tu topojson provincia: string; } type PartidoGeography = Feature & { rsmKey: string }; const PALETA_COLORES: { [key: string]: [number, number, number] } = { 'default': [214, 214, 218] // RGB para el color por defecto }; const INITIAL_PROJECTION = { center: [-59.8, -37.0] as [number, number], scale: 5400, }; const MapaBsAs = () => { const [selectedPartido, setSelectedPartido] = useState(null); const [projectionConfig, setProjectionConfig] = useState(INITIAL_PROJECTION); // --- Carga de Datos --- const { data: resultadosData, isLoading: isLoadingResultados } = useQuery({ queryKey: ['mapaResultados'], queryFn: async () => { const { data } = await axios.get('http://localhost:5217/api/Resultados/mapa'); return data; }, }); const { data: geoData, isLoading: isLoadingGeo } = useQuery({ queryKey: ['mapaGeoData'], queryFn: async () => { const { data } = await axios.get('/partidos-bsas.topojson'); return data; }, }); const { data: agrupacionesData, isLoading: isLoadingAgrupaciones } = useQuery({ queryKey: ['catalogoAgrupaciones'], queryFn: async () => { const { data } = await axios.get('http://localhost:5217/api/Catalogos/agrupaciones'); return data; }, }); const { nombresAgrupaciones, coloresPartidos } = useMemo(() => { if (!agrupacionesData) return { nombresAgrupaciones: {}, coloresPartidos: {} }; const nombres = agrupacionesData.reduce((acc, agrupacion) => { acc[agrupacion.id] = agrupacion.nombre; return acc; }, {} as { [key: string]: string }); const colores = agrupacionesData.reduce((acc, agrupacion, index) => { const baseColor = [255, 87, 51, 51, 255, 87, 51, 87, 255, 255, 51, 161, 161, 51, 255, 255, 195, 0, 199, 0, 57, 144, 12, 63, 88, 24, 69]; acc[agrupacion.nombre] = [baseColor[index*3], baseColor[index*3+1], baseColor[index*3+2]]; return acc; }, {} as { [key: string]: [number, number, number] }); colores['default'] = [214, 214, 218]; return { nombresAgrupaciones: nombres, coloresPartidos: colores }; }, [agrupacionesData]); const animatedProps = useSpring({ to: { scale: projectionConfig.scale, cx: projectionConfig.center[0], cy: projectionConfig.center[1] }, config: { tension: 170, friction: 26 }, }); if (isLoadingResultados || isLoadingGeo || isLoadingAgrupaciones) { return
Cargando datos del mapa...
; } const getPartyStyle = (partidoIdGeo: string) => { const resultado = resultadosData?.find(r => r.partidoId === partidoIdGeo); if (!resultado) { return { fill: `rgb(${PALETA_COLORES.default.join(',')})` }; } const nombreAgrupacion = nombresAgrupaciones[resultado.agrupacionGanadoraId] || 'Otro'; const baseColor = coloresPartidos[nombreAgrupacion] || PALETA_COLORES.default; // Calcula la opacidad basada en el porcentaje. 0.4 (débil) a 1.0 (fuerte) const opacity = 0.4 + (resultado.porcentajeGanador / 100) * 0.6; return { fill: `rgba(${baseColor.join(',')}, ${opacity})` }; }; const handleGeographyClick = (geo: PartidoGeography) => { const centroid = geoCentroid(geo); setSelectedPartido(geo); setProjectionConfig({ center: centroid, scale: 18000, // Zoom más cercano }); }; const handleReset = () => { setSelectedPartido(null); setProjectionConfig(INITIAL_PROJECTION); }; return (
`scale(${s / INITIAL_PROJECTION.scale})`), }}> {({ geographies }: { geographies: PartidoGeography[] }) => geographies.map((geo) => { const partidoId = String(geo.properties.id); const partidoNombre = geo.properties.departamento; const resultado = resultadosData?.find(r => r.partidoId === partidoId); const agrupacionNombre = resultado ? (nombresAgrupaciones[resultado.agrupacionGanadoraId] || 'Desconocido') : 'Sin datos'; return ( handleGeographyClick(geo)} /> ); }) }
{selectedPartido ? (

{selectedPartido.properties.departamento}

Cabecera: {selectedPartido.properties.cabecera}

ID: {selectedPartido.properties.id}

{/* Aquí mostrarías más datos del partido seleccionado */}
) : (

Provincia de Buenos Aires

Selecciona un partido para ver más detalles.

)}
); }; // Componente de Leyenda separado const Legend = ({ colores }: { colores: { [key: string]: [number, number, number] } }) => { return (

Leyenda

{Object.entries(colores).map(([nombre, color]) => { if (nombre === 'default') return null; return (
{nombre}
); })}
); }; export default MapaBsAs;