¿See pueden encapsular fragmentos de SVG en componentes react y construir un SVG complejo uniendo estos componentes?
¡Definitivamente sí! Esta es una de las mejores prácticas al trabajar con gráficos complejos en React, como tu Odontograma.
El poder de React para manejar componentes se extiende perfectamente al SVG. Puedes encapsular cualquier fragmento de código SVG (desde una forma simple hasta un grupo entero de elementos) dentro de un componente de React.
Aquí te explico por qué es la técnica correcta y cómo se vería la estructura en tu proyecto.
El Principio: SVG como JSX
En React, el código SVG se escribe directamente dentro del método return de tu componente (JSX), lo que significa que el SVG se comporta como cualquier otro elemento HTML/JSX:
1. Componente Atómico: <Superficie />
En lugar de tener 5 polígonos dentro de cada diente, creas un componente para la superficie.
// src/components/Superficie.jsx
const Superficie = ({ id, puntos, estado }) => {
const color = estado === 'Caries' ? 'fill-red-600' : 'fill-gray-300';
return (
<polygon
id={id}
points={puntos}
className={`stroke-gray-800 stroke-1 cursor-pointer transition-colors ${color}`}
// Manejo de eventos encapsulado
onClick={() => console.log(`Clic en ${id}`)}
/>
);
};
2. Componente Molécula: <Diente />
El componente <Diente> utiliza el componente <Superficie /> cinco veces, y se encarga de posicionar y rotar el diente completo.
// src/components/Diente.jsx
const Diente = ({ numero, datosPlan }) => {
// Los datos de posicionamiento y las coordenadas de los polígonos
const { x, y, rotacion, formas } = obtenerGeometria(numero);
return (
<g
id={`tooth-${numero}`}
transform={`translate(${x} ${y}) rotate(${rotacion})`}
>
{/* Cinco instancias de la Superficie */}
<Superficie id="S_O" puntos={formas.oclusal} estado={datosPlan.oclusal.problema} />
<Superficie id="S_D" puntos={formas.distal} estado={datosPlan.distal.problema} />
{/* ... otras superficies ... */}
{/* También puedes agregar el texto del número aquí */}
<text x="0" y="30" textAnchor="middle">{numero}</text>
</g>
);
};
3. Componente Organismo: <Odontograma />
El componente principal simplemente ensambla los 32 dientes.
// src/components/Odontograma.jsx (El componente principal)
const Odontograma = () => {
// Imagina un array de 32 objetos con los datos de cada diente
const planDental = usarPlanDental(); // Hook que trae los datos de Firestore
return (
<svg width="1000" height="500">
{planDental.map((diente) => (
<Diente
key={diente.numero}
numero={diente.numero}
datosPlan={diente.data}
/>
))}
</svg>
);
};
Ventajas de Encapsular SVG en Componentes React
Reutilización: Defines el código de un diente una sola vez y lo utilizas 32 veces, simplemente cambiando sus props (número, coordenadas, rotación, datos clínicos).
Mantenimiento Sencillo: Si necesitas cambiar el color del borde de un diente, lo cambias en un solo lugar: el componente
<Superficie />.Lógica Localizada: La lógica de qué color debe tener una superficie (
isCaries ? 'red' : 'gray') reside solo dentro del componente que la renderiza. Esto hace que el código sea predecible y fácil de depurar.Rendimiento: React se encarga de que solo se re-renderice el componente
<Diente />cuyos datos han cambiado, no todo el SVG.
Esta es la forma más profesional y escalable de construir tu odontograma en React.
¿Se puede componer programáticamente una única imagen SVG a partir de imágenes importadas con SVGR?
¡Absolutamente! Componer un único SVG complejo a partir de múltiples componentes importados con SVGR es precisamente la técnica que necesitas para construir tu Odontograma.
Esto se conoce como Composición de Componentes en React, y funciona perfectamente con SVG.
La Gran Ventaja de Componer SVG en React
Cuando usas SVGR, cada archivo .svg se convierte en un componente React que renderiza las etiquetas SVG (<path>, <circle>, etc.) directamente en tu JSX.
Esto significa que puedes usar estos pequeños componentes SVG (por ejemplo, <SuperficieOclusalIcon /> o <SombraDienteIcon />) como si fueran piezas de LEGO para construir una imagen más grande y funcional.
Técnica: Composición de Componentes SVG
Paso 1: Componentes Atómicos (SVGR)
Asumamos que tienes dos archivos SVG importados con SVGR:
// src/assets/diente-base.svg
import DienteBase from './assets/diente-base.svg';
// src/assets/superficie-caries.svg
import SuperficieCaries from './assets/superficie-caries.svg';
Paso 2: El Componente Compuesto (<Diente />)
Creas un componente superior (la molécula) llamado <Diente> que tiene la etiqueta <svg> principal y anida todas las piezas.
La clave aquí es usar la etiqueta <g> (grupo de SVG) para posicionar y aplicar transformaciones a cada parte individualmente sin afectar al resto.
import React from 'react';import DienteBase from './assets/diente-base.svg';import SuperficieCaries from './assets/superficie-caries.svg';
const Diente = ({ numero, tieneCaries, x, y, rotacion }) => { // 1. Clases y estilos const dienteColor = tieneCaries ? 'fill-red-500' : 'fill-gray-300'; // 2. Transformación para posicionar el diente completo en el arco const transformacionDiente = `translate(${x} ${y}) rotate(${rotacion})`;
return ( // El Diente se dibuja dentro de un grupo SVG. <g id={`diente-${numero}`} transform={transformacionDiente} onClick={() => console.log(`Clic en Diente ${numero}`)} > {/* PIEZA 1: El Componente Base (el cuerpo del diente). Se le pasa la clase de Tailwind para cambiar el color de relleno. */} <DienteBase className={`stroke-gray-800 stroke-1 ${dienteColor}`} />
{/* PIEZA 2 (Condicional): Si hay caries, se superpone la mancha. Se utiliza un <g> adicional si necesitas mover la caries dentro del diente. */} {tieneCaries && ( <g transform="translate(5 5)"> <SuperficieCaries className="fill-red-800 opacity-80" /> </g> )}
{/* Texto de número del diente (no es un componente, sino texto SVG) */} <text x="0" y="30" textAnchor="middle" className="text-sm font-bold"> {numero} </text> </g> );};
export default Diente;
Paso 3: El Lienzo Final (<Odontograma />)
Finalmente, en tu componente principal <Odontograma>, simplemente usas el componente <Diente /> dentro de un <svg> contenedor.
// src/components/Odontograma.jsx
const Odontograma = () => {
// ... lógica de datos ...
return (
<svg viewBox="0 0 1000 400" className="w-full h-full">
{/* Diente 1: Posicionado a la izquierda */}
<Diente
numero={14}
tieneCaries={true}
x={100}
y={100}
rotacion={-10}
/>
{/* Diente 2: Posicionado más a la derecha y rotado diferente */}
<Diente
numero={15}
tieneCaries={false}
x={160}
y={90}
rotacion={-5}
/>
{/* ... 30 dientes más ... */}
</svg>
);
};
## Beneficios de este Enfoque
1. **Modularidad:** Si el diseño del diente cambia, solo editas el archivo `.svg` original.
2. **Control de Estado:** Puedes usar el estado de React (ej. `tieneCaries`) para renderizar condicionalmente partes del SVG (ej. la mancha de caries).
3. **Posicionamiento:** Usas las transformaciones SVG (`translate`, `rotate`) a nivel del componente `<Diente />`, no a nivel del SVG principal, simplificando la lógica.
No hay comentarios:
Publicar un comentario