Modificaciones en los archivos

This commit is contained in:
santiago
2025-10-15 23:52:34 +02:00
parent 98b6668829
commit c82af0cfa8
2 changed files with 127 additions and 127 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
'use client';
'use client';
import React, { useState, useEffect } from 'react';
import axios from 'axios';
+126 -126
View File
@@ -1,46 +1,46 @@
import React from 'react';
interface Props {
onAreaSelect: (areaId: number) => void;
className?: string;
style?: React.CSSProperties;
isPanningRef?: React.RefObject<boolean>;
onAreaSelect: (areaId: number) => void;
className?: string;
style?: React.CSSProperties;
isPanningRef?: React.RefObject<boolean>;
}
// Map display substrings (lowercase) to the area id used in BuscarFuncionario
const areaMap: Record<string, number> = {
'coordinación de actividades deportivas y recreativas': 128,
'coordinación de comunicación social': 122,
'coordinación de cuerpos colegiados': 9,
'coordinación de derecho del sistema de universidad abierta y educación a distancia': 126,
'coordinación de especializaciones': 206,
'coordinación de estudios de posgrado': 120,
'coordinación de la unidad de investigación multidisciplinaria aplicada': 182,
'coordinación de licel sistema de universidad abierta y educación a distancia': 174,
'coordinación de maestrías y doctorados': 221,
'coordinación de relaciones internacionales del sistema de universidad abierta y educación a distancia': 152,
'coordinación de servicios académicos': 121,
'coordinación del centro de difusión cultural': 125,
'coordinación del centro de educación continua': 124,
'coordinación del centro de enseñanza de idiomas': 129,
'coordinación del centro de estudios municipales y metropolitanos': 214,
'coordinación del centro tecnológico para la educación a distancia': 176,
'dirección': 72,
'división de ciencias jurídicas': 80,
'división de ciencias socioeconómicas': 79,
'división de diseño y edificación': 78,
'división de humanidades': 77,
'división de matemáticas e ingeniería': 76,
'secretaría de asuntos académicos estudiantiles': 181,
'secretaría de extensión universitaria y vinculación institucional': 177,
'secretaría de posgrado e investigación': 119,
'secretaría general': 8,
'unidad de administración escolar': 6,
'unidad de servicios editoriales': 2,
'unidad de talleres, laboratorios y audiovisuales': 1,
'unidad del centro de desarrollo tecnológico': 130,
'unidad del centro de información y documentación': 123,
// add more mappings as needed
'coordinación de actividades deportivas y recreativas': 128,
'coordinación de comunicación social': 122,
'coordinación de cuerpos colegiados': 9,
'coordinación de derecho del sistema de universidad abierta y educación a distancia': 126,
'coordinación de especializaciones': 206,
'coordinación de estudios de posgrado': 120,
'coordinación de la unidad de investigación multidisciplinaria aplicada': 182,
'coordinación de licel sistema de universidad abierta y educación a distancia': 174,
'coordinación de maestrías y doctorados': 221,
'coordinación de relaciones internacionales del sistema de universidad abierta y educación a distancia': 152,
'coordinación de servicios académicos': 121,
'coordinación del centro de difusión cultural': 125,
'coordinación del centro de educación continua': 124,
'coordinación del centro de enseñanza de idiomas': 129,
'coordinación del centro de estudios municipales y metropolitanos': 214,
'coordinación del centro tecnológico para la educación a distancia': 176,
'dirección': 72,
'división de ciencias jurídicas': 80,
'división de ciencias socioeconómicas': 79,
'división de diseño y edificación': 78,
'división de humanidades': 77,
'división de matemáticas e ingeniería': 76,
'secretaría de asuntos académicos estudiantiles': 181,
'secretaría de extensión universitaria y vinculación institucional': 177,
'secretaría de posgrado e investigación': 119,
'secretaría general': 8,
'unidad de administración escolar': 6,
'unidad de servicios editoriales': 2,
'unidad de talleres, laboratorios y audiovisuales': 1,
'unidad del centro de desarrollo tecnológico': 130,
'unidad del centro de información y documentación': 123,
// add more mappings as needed
};
const svgContent = `
@@ -53,112 +53,112 @@ const svgContent = `
// But to keep this component self-contained, we'll render an <object> fallback and then query inside it.
export default function OrganigramaInteractivo({ onAreaSelect, className, style, isPanningRef }: Props) {
const containerRef = React.useRef<HTMLDivElement | null>(null);
const containerRef = React.useRef<HTMLDivElement | null>(null);
const normalize = (s: string) =>
s
.normalize('NFD')
.replace(/\p{Diacritic}/gu, '')
.toLowerCase()
.replace(/\s+/g, ' ')
.trim();
const normalize = (s: string) =>
s
.normalize('NFD')
.replace(/\p{Diacritic}/gu, '')
.toLowerCase()
.replace(/\s+/g, ' ')
.trim();
const normalizedAreaEntries = React.useMemo(() => {
return Object.keys(areaMap).map((k) => ({ key: normalize(k), id: areaMap[k] }));
}, []);
const normalizedAreaEntries = React.useMemo(() => {
return Object.keys(areaMap).map((k) => ({ key: normalize(k), id: areaMap[k] }));
}, []);
React.useEffect(() => {
const container = containerRef.current;
if (!container) return;
React.useEffect(() => {
const container = containerRef.current;
if (!container) return;
// Fetch the SVG file from the public path. The SVG is located at /organigrama_FES102025.svg (if placed in public/)
// There's a copy in src/public; to be served statically, ensure the SVG is available at '/organigrama_FES102025.svg'.
let mounted = true;
fetch('/organigrama_FES102025.svg')
.then((r) => r.text())
.then((text) => {
if (!mounted) return;
container.innerHTML = text;
// Fetch the SVG file from the public path. The SVG is located at /organigrama_FES102025.svg (if placed in public/)
// There's a copy in src/public; to be served statically, ensure the SVG is available at '/organigrama_FES102025.svg'.
let mounted = true;
fetch('/organigrama_FES102025.svg')
.then((r) => r.text())
.then((text) => {
if (!mounted) return;
container.innerHTML = text;
const svg = container.querySelector('svg');
if (!svg) return;
const svg = container.querySelector('svg');
if (!svg) return;
const onClick = (e: MouseEvent) => {
// if parent reports it's panning/dragging, ignore clicks
if (isPanningRef && isPanningRef.current) return;
const target = e.target as Element;
const clientX = (e as MouseEvent).clientX;
const clientY = (e as MouseEvent).clientY;
const onClick = (e: MouseEvent) => {
// if parent reports it's panning/dragging, ignore clicks
if (isPanningRef && isPanningRef.current) return;
const target = e.target as Element;
const clientX = (e as MouseEvent).clientX;
const clientY = (e as MouseEvent).clientY;
// Try to find a text element under the click
const texts = Array.from(svg.querySelectorAll('text')) as Element[];
// Try to find a text element under the click
const texts = Array.from(svg.querySelectorAll('text')) as Element[];
// First check which text elements have bounding rect containing the click
const hit = texts.find((t) => {
const r = (t as Element).getBoundingClientRect();
return clientX >= r.left && clientX <= r.right && clientY >= r.top && clientY <= r.bottom;
});
let textContent = '';
if (hit) {
textContent = hit.textContent || '';
} else {
// If no direct hit, find nearest text within 120px
let nearest: { el: Element | null; dist: number } = { el: null, dist: Infinity };
texts.forEach((t) => {
const r = (t as Element).getBoundingClientRect();
const cx = (r.left + r.right) / 2;
const cy = (r.top + r.bottom) / 2;
const d = Math.hypot(clientX - cx, clientY - cy);
if (d < nearest.dist) {
nearest = { el: t, dist: d };
}
// First check which text elements have bounding rect containing the click
const hit = texts.find((t) => {
const r = (t as Element).getBoundingClientRect();
return clientX >= r.left && clientX <= r.right && clientY >= r.top && clientY <= r.bottom;
});
if (nearest.el && nearest.dist < 140) {
textContent = nearest.el.textContent || '';
let textContent = '';
if (hit) {
textContent = hit.textContent || '';
} else {
// If no direct hit, find nearest text within 120px
let nearest: { el: Element | null; dist: number } = { el: null, dist: Infinity };
texts.forEach((t) => {
const r = (t as Element).getBoundingClientRect();
const cx = (r.left + r.right) / 2;
const cy = (r.top + r.bottom) / 2;
const d = Math.hypot(clientX - cx, clientY - cy);
if (d < nearest.dist) {
nearest = { el: t, dist: d };
}
});
if (nearest.el && nearest.dist < 140) {
textContent = nearest.el.textContent || '';
}
}
}
if (!textContent) return;
if (!textContent) return;
const normalized = normalize(textContent);
// Try to match any normalized key in areaMap
for (const entry of normalizedAreaEntries) {
if (normalized.includes(entry.key) || entry.key.includes(normalized)) {
onAreaSelect(entry.id);
return;
}
}
// If target element directly has a title or id
if (target) {
const el = target as HTMLElement;
const title = (el.getAttribute('title') || el.getAttribute('id') || '').toString();
const n = normalize(title);
const normalized = normalize(textContent);
// Try to match any normalized key in areaMap
for (const entry of normalizedAreaEntries) {
if (n.includes(entry.key) || entry.key.includes(n)) {
if (normalized.includes(entry.key) || entry.key.includes(normalized)) {
onAreaSelect(entry.id);
return;
}
}
}
}
// If target element directly has a title or id
if (target) {
const el = target as HTMLElement;
const title = (el.getAttribute('title') || el.getAttribute('id') || '').toString();
const n = normalize(title);
for (const entry of normalizedAreaEntries) {
if (n.includes(entry.key) || entry.key.includes(n)) {
onAreaSelect(entry.id);
return;
}
}
}
};
svg.addEventListener('click', onClick);
// allow pointer events
svg.style.pointerEvents = 'auto';
return () => svg.removeEventListener('click', onClick);
})
.catch((err) => console.error('No se pudo cargar SVG:', err));
return () => {
mounted = false;
};
}, [onAreaSelect]);
svg.addEventListener('click', onClick);
// allow pointer events
svg.style.pointerEvents = 'auto';
return () => svg.removeEventListener('click', onClick);
})
.catch((err) => console.error('No se pudo cargar SVG:', err));
return () => {
mounted = false;
};
}, [onAreaSelect]);
return (
<div ref={containerRef} className={className} style={style} />
);
return (
<div ref={containerRef} className={className} style={style} />
);
}