Fix Arrastre Mapa en Zoom
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
// src/features/legislativas/nacionales/components/MapaNacional.tsx
|
||||
import axios from 'axios';
|
||||
import { Suspense, useState, useEffect, useCallback, useRef } from 'react';
|
||||
import { useSuspenseQuery } from '@tanstack/react-query';
|
||||
@@ -53,13 +54,14 @@ export const MapaNacional = ({ eleccionId, categoriaId, nivel, nombreAmbito, nom
|
||||
zoom: isMobileView ? 1.5 : 1.05, // 1.5 para móvil, 1.05 para desktop
|
||||
center: [-65, -40] as PointTuple
|
||||
});
|
||||
const [isPanning, setIsPanning] = useState(false);
|
||||
const initialProvincePositionRef = useRef<{ zoom: number, center: PointTuple } | null>(null);
|
||||
|
||||
const containerRef = useRef<HTMLDivElement | null>(null);
|
||||
const lupaRef = useRef<HTMLDivElement | null>(null);
|
||||
const cabaPathRef = useRef<SVGPathElement | null>(null);
|
||||
const isAnimatingRef = useRef(false);
|
||||
const initialLoadRef = useRef(true); // Ref para controlar la carga inicial
|
||||
const initialLoadRef = useRef(true);
|
||||
|
||||
const [lupaStyle, setLupaStyle] = useState<React.CSSProperties>({ opacity: 0 });
|
||||
|
||||
@@ -80,10 +82,9 @@ export const MapaNacional = ({ eleccionId, categoriaId, nivel, nombreAmbito, nom
|
||||
useEffect(() => {
|
||||
if (nivel === 'pais') {
|
||||
setPosition({
|
||||
zoom: isMobileView ? 1.4 : 1.05, // 1.5 para móvil, 1.05 para desktop
|
||||
zoom: isMobileView ? 1.4 : 1.05,
|
||||
center: [-65, -40]
|
||||
});
|
||||
// Reseteamos el ref
|
||||
initialProvincePositionRef.current = null;
|
||||
} else if (nivel === 'provincia') {
|
||||
const nombreNormalizado = normalizarTexto(nombreAmbito);
|
||||
@@ -103,11 +104,9 @@ export const MapaNacional = ({ eleccionId, categoriaId, nivel, nombreAmbito, nom
|
||||
}
|
||||
|
||||
setPosition(provinceConfig);
|
||||
|
||||
// --- Guardar el objeto de posición completo en el ref ---
|
||||
initialProvincePositionRef.current = provinceConfig;
|
||||
}
|
||||
}, [nivel, nombreAmbito, geoDataNacional]);
|
||||
}, [nivel, nombreAmbito, geoDataNacional, isMobileView]);
|
||||
|
||||
const resultadosNacionalesPorNombre = new Map<string, ResultadoMapaDto>(mapaDataNacional.map(d => [normalizarTexto(d.ambitoNombre), d]));
|
||||
const nombreMunicipioSeleccionado = nivel === 'municipio' ? nombreAmbito : null;
|
||||
@@ -142,29 +141,18 @@ export const MapaNacional = ({ eleccionId, categoriaId, nivel, nombreAmbito, nom
|
||||
};
|
||||
|
||||
isAnimatingRef.current = true;
|
||||
|
||||
const handleResize = () => {
|
||||
if (!isAnimatingRef.current) {
|
||||
updateLupaPosition();
|
||||
}
|
||||
};
|
||||
|
||||
const handleResize = () => { if (!isAnimatingRef.current) updateLupaPosition(); };
|
||||
const resizeObserver = new ResizeObserver(handleResize);
|
||||
if (containerRef.current) {
|
||||
resizeObserver.observe(containerRef.current);
|
||||
}
|
||||
if (containerRef.current) resizeObserver.observe(containerRef.current);
|
||||
|
||||
let timerId: NodeJS.Timeout;
|
||||
|
||||
if (initialLoadRef.current && nivel === 'pais') {
|
||||
// Carga inicial: posicionar inmediatamente
|
||||
timerId = setTimeout(() => {
|
||||
updateLupaPosition();
|
||||
isAnimatingRef.current = false;
|
||||
}, 0);
|
||||
initialLoadRef.current = false; // Marcar como ya cargado
|
||||
initialLoadRef.current = false;
|
||||
} else {
|
||||
// Transición de vuelta: esperar a que termine la animación
|
||||
timerId = setTimeout(() => {
|
||||
updateLupaPosition();
|
||||
isAnimatingRef.current = false;
|
||||
@@ -172,77 +160,53 @@ export const MapaNacional = ({ eleccionId, categoriaId, nivel, nombreAmbito, nom
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (containerRef.current) {
|
||||
resizeObserver.unobserve(containerRef.current);
|
||||
}
|
||||
if (containerRef.current) resizeObserver.unobserve(containerRef.current);
|
||||
clearTimeout(timerId);
|
||||
isAnimatingRef.current = false;
|
||||
};
|
||||
}, [position, nivel]);
|
||||
|
||||
// --- HANDLERS PARA EL ZOOM ---
|
||||
const handleZoomIn = () => {
|
||||
setPosition(prev => ({
|
||||
...prev,
|
||||
zoom: Math.min(prev.zoom * 1.8, 100) // Multiplica el zoom actual, con un límite
|
||||
}));
|
||||
};
|
||||
const handleZoomIn = () => setPosition(prev => ({ ...prev, zoom: Math.min(prev.zoom * 1.8, 100) }));
|
||||
|
||||
// --- Lógica de reseteo en handleZoomOut ---
|
||||
const handleZoomOut = () => {
|
||||
setPosition(prev => {
|
||||
const newZoom = Math.max(prev.zoom / 1.8, 1);
|
||||
const initialPos = initialProvincePositionRef.current;
|
||||
|
||||
// Si estamos en una provincia Y el nuevo zoom es igual o menor que el inicial...
|
||||
if (initialPos && newZoom <= initialPos.zoom) {
|
||||
// ...reseteamos a la posición inicial guardada (zoom Y centro).
|
||||
return initialPos;
|
||||
}
|
||||
|
||||
// Si no, solo actualizamos el zoom.
|
||||
if (initialPos && newZoom <= initialPos.zoom) return initialPos;
|
||||
return { ...prev, zoom: newZoom };
|
||||
});
|
||||
};
|
||||
|
||||
const handleMoveEnd = (newPosition: { coordinates: PointTuple, zoom: number }) => {
|
||||
// Solo actualizamos el centro (coordenadas), no el zoom, al arrastrar
|
||||
setPosition(prev => ({ ...prev, center: newPosition.coordinates }));
|
||||
setIsPanning(false);
|
||||
};
|
||||
|
||||
const panEnabled =
|
||||
//isMobileView &&
|
||||
nivel === 'provincia' &&
|
||||
initialProvincePositionRef.current !== null &&
|
||||
position.zoom > initialProvincePositionRef.current.zoom &&
|
||||
!nombreMunicipioSeleccionado;
|
||||
|
||||
const showZoomControls = nivel === 'provincia';
|
||||
|
||||
// --- FUNCIÓN DE FILTRO ---
|
||||
const filterInteractionEvents = (event: any) => {
|
||||
// La librería pasa un objeto de evento que contiene el evento original del navegador.
|
||||
// Si el evento original es de la rueda del ratón ('wheel'), siempre lo bloqueamos.
|
||||
if (event.sourceEvent && event.sourceEvent.type === 'wheel') {
|
||||
return false;
|
||||
}
|
||||
// Para cualquier otro evento (arrastre, etc.), la decisión depende de nuestra lógica `panEnabled`.
|
||||
if (event.sourceEvent && event.sourceEvent.type === 'wheel') return false;
|
||||
return panEnabled;
|
||||
};
|
||||
|
||||
// --- LÓGICA PARA DESHABILITAR EL BOTÓN ---
|
||||
const showZoomControls = nivel === 'provincia';
|
||||
const isZoomOutDisabled =
|
||||
(nivel === 'provincia' && initialProvincePositionRef.current && position.zoom <= initialProvincePositionRef.current.zoom) ||
|
||||
(nivel === 'pais' && position.zoom <= (isMobileView ? 1.4 : 1.05));
|
||||
|
||||
const mapContainerClasses = panEnabled ? 'mapa-componente-container map-pannable' : 'mapa-componente-container map-locked';
|
||||
|
||||
return (
|
||||
<div className="mapa-componente-container" ref={containerRef}>
|
||||
<div className={mapContainerClasses} ref={containerRef}>
|
||||
{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' : ''}`}
|
||||
@@ -265,8 +229,10 @@ export const MapaNacional = ({ eleccionId, categoriaId, nivel, nombreAmbito, nom
|
||||
<ZoomableGroup
|
||||
center={position.center}
|
||||
zoom={position.zoom}
|
||||
onMoveStart={() => setIsPanning(true)}
|
||||
onMoveEnd={handleMoveEnd}
|
||||
filterZoomEvent={filterInteractionEvents}
|
||||
className={isPanning ? 'panning' : ''}
|
||||
>
|
||||
<Geographies geography={geoDataNacional}>
|
||||
{({ geographies }: { geographies: AmbitoGeography[] }) => geographies.map((geo) => {
|
||||
@@ -281,9 +247,7 @@ export const MapaNacional = ({ eleccionId, categoriaId, nivel, nombreAmbito, nom
|
||||
geography={geo}
|
||||
ref={esCABA ? cabaPathRef : undefined}
|
||||
className={`rsm-geography ${nivel !== 'pais' ? 'rsm-geography-faded' : ''}`}
|
||||
style={{
|
||||
visibility: esCABA ? 'hidden' : (esProvinciaActiva ? 'hidden' : 'visible'),
|
||||
}}
|
||||
style={{ visibility: esCABA ? 'hidden' : (esProvinciaActiva ? 'hidden' : 'visible') }}
|
||||
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"
|
||||
@@ -321,7 +285,6 @@ export const MapaNacional = ({ eleccionId, categoriaId, nivel, nombreAmbito, nom
|
||||
onAmbitoSelect(resultadoCABA.ambitoId, 'provincia', resultadoCABA.ambitoNombre);
|
||||
}
|
||||
};
|
||||
|
||||
return <CabaLupa fillColor={fillColor} onClick={handleClick} />;
|
||||
})()}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user