Modificaciones para mover la imagen

This commit is contained in:
santiago
2025-10-15 22:56:44 +02:00
parent 20fe62de32
commit 9379ae4dc8
3 changed files with 111 additions and 12 deletions
-3
View File
@@ -22,9 +22,6 @@
}
*/
.boton-buscar {
background-color: #c0dff8;
}
body {
background: var(--background);
+110 -9
View File
@@ -1,6 +1,6 @@
'use client'
import React, { useState } from 'react';
import React, { useState, useRef, useCallback } from 'react';
import Image from 'next/image';
import BuscarFuncionario from '@/components/BuscarFuncionario';
import { Funcionario } from '@/types/Funcionarios';
@@ -9,6 +9,68 @@ import organigrama from '@/public/organigrama_FES102025.png'; // Asegúrate de l
export default function Home() {
const [resultados, setResultados] = useState<Funcionario[]>([]);
// Zoom / Pan state
const imgRef = useRef<HTMLDivElement | null>(null);
const [scale, setScale] = useState<number>(1);
const [translate, setTranslate] = useState<{ x: number; y: number }>({ x: 0, y: 0 });
const lastTouch = useRef<{ x: number; y: number } | null>(null);
const isPanning = useRef(false);
const lastMouse = useRef<{ x: number; y: number } | null>(null);
const clamp = (v: number, a = 0.5, b = 5) => Math.min(Math.max(v, a), b);
const handleWheel = useCallback((e: React.WheelEvent) => {
e.preventDefault();
const delta = -e.deltaY; // invert so wheel up = zoom in
const zoomFactor = delta > 0 ? 1.1 : 0.9;
setScale((s) => {
const newScale = clamp(s * zoomFactor);
return newScale;
});
}, []);
const handleMouseDown = (e: React.MouseEvent) => {
isPanning.current = true;
lastMouse.current = { x: e.clientX, y: e.clientY };
};
const handleMouseMove = (e: React.MouseEvent) => {
if (!isPanning.current || !lastMouse.current) return;
const dx = e.clientX - lastMouse.current.x;
const dy = e.clientY - lastMouse.current.y;
lastMouse.current = { x: e.clientX, y: e.clientY };
setTranslate((t) => ({ x: t.x + dx, y: t.y + dy }));
};
const handleMouseUp = () => {
isPanning.current = false;
lastMouse.current = null;
};
const handleTouchStart = (e: React.TouchEvent) => {
if (e.touches.length === 1) {
const t0 = e.touches[0];
lastTouch.current = { x: t0.clientX, y: t0.clientY };
}
};
const handleTouchMove = (e: React.TouchEvent) => {
if (e.touches.length === 1 && lastTouch.current) {
const t0 = e.touches[0];
const dx = t0.clientX - lastTouch.current.x;
const dy = t0.clientY - lastTouch.current.y;
lastTouch.current = { x: t0.clientX, y: t0.clientY };
setTranslate((t) => ({ x: t.x + dx, y: t.y + dy }));
}
// pinch-to-zoom could be added later
};
const zoomIn = () => setScale((s) => clamp(s * 1.2));
const zoomOut = () => setScale((s) => clamp(s / 1.2));
const resetView = () => {
setScale(1);
setTranslate({ x: 0, y: 0 });
};
return (
<main className="container-fluid py-4 bg-light min-h-screen">
@@ -21,16 +83,55 @@ export default function Home() {
<div className="row g-4 m-2">
{resultados.length === 0 ? (
<div className="col-12 text-center">
<Image
src={organigrama}
alt="No hay resultados"
width={organigrama.width} // para usar el tamaño original
height={organigrama.height}
<div
ref={imgRef}
onWheel={handleWheel}
onMouseDown={handleMouseDown}
onMouseMove={handleMouseMove}
onMouseUp={handleMouseUp}
onMouseLeave={handleMouseUp}
onTouchStart={handleTouchStart}
onTouchMove={handleTouchMove}
onTouchEnd={() => (lastTouch.current = null)}
style={{
width: '100%',
height: 'auto',
width: '100%',
height: 'auto',
overflow: 'hidden',
touchAction: 'none',
position: 'relative',
borderRadius: 6,
border: '1px solid #ddd',
background: '#fff',
}}
/>
>
<div style={{ display: 'flex', justifyContent: 'center', padding: 8 }}>
<div style={{ position: 'relative', width: '100%', maxWidth: 1200 }}>
<div
style={{
transform: `translate(${translate.x}px, ${translate.y}px) scale(${scale})`,
transformOrigin: '0 0',
transition: 'transform 0.05s linear',
cursor: isPanning.current ? 'grabbing' : 'grab',
}}
>
<Image
src={organigrama}
alt="Organigrama"
width={organigrama.width}
height={organigrama.height}
style={{ width: '100%', height: 'auto', display: 'block', userSelect: 'none', pointerEvents: 'none' }}
/>
</div>
</div>
</div>
{/* Controls */}
<div style={{ position: 'absolute', right: 12, top: 12, display: 'flex', gap: 8 }}>
<button type="button" className="btn btn-sm btn-outline-secondary" onClick={zoomOut} title="Zoom out"></button>
<button type="button" className="btn btn-sm btn-outline-secondary" onClick={resetView} title="Reset"></button>
<button type="button" className="btn btn-sm btn-outline-secondary" onClick={zoomIn} title="Zoom in">+</button>
</div>
</div>
</div>
) : (
resultados.map((persona, i) => (
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 14 KiB