Modificaciones para mover la imagen
This commit is contained in:
@@ -22,9 +22,6 @@
|
||||
}
|
||||
*/
|
||||
|
||||
.boton-buscar {
|
||||
background-color: #c0dff8;
|
||||
}
|
||||
|
||||
body {
|
||||
background: var(--background);
|
||||
|
||||
+110
-9
@@ -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 |
Reference in New Issue
Block a user