import { useMemo } from 'react' import type { Categoria } from '../../../types' interface RuletaSVGProps { categorias: Categoria[] rotacion: number isSpinning: boolean onClick: () => void } /* ─── Constantes geométricas ──────────────────── */ const CX = 250 const CY = 265 const SEGMENT_R = 195 const RING_R = 207 const RING_STROKE = 26 const CENTER_R = 28 const VIEWBOX_W = 500 const VIEWBOX_H = 550 const TOTAL_SEGMENTS = 4 /* ─── Estilos visuales por segmento ───────────── */ interface SegmentStyle { bg: string textColor: string iconColor: string } const SEGMENT_STYLES: SegmentStyle[] = [ { bg: '#DC2626', textColor: '#FFFFFF', iconColor: '#FFFFFF' }, // Agua — rojo { bg: '#D1D5DB', textColor: '#1F2937', iconColor: '#374151' }, // Residuos — gris claro { bg: '#374151', textColor: '#FFFFFF', iconColor: '#FBBF24' }, // Energía — gris oscuro { bg: '#F9FAFB', textColor: '#1F2937', iconColor: '#2563EB' }, // Electromovilidad — blanco ] /* ─── Utilidad: polar → cartesiano ────────────── */ function polarToCartesian(cx: number, cy: number, angle: number, radius: number) { const rad = (angle - 90) * (Math.PI / 180) return { x: cx + radius * Math.cos(rad), y: cy + radius * Math.sin(rad), } } /* ─── Path de sector circular ─────────────────── */ function sectorPath(cx: number, cy: number, r: number, startAngle: number, endAngle: number) { const start = polarToCartesian(cx, cy, startAngle, r) const end = polarToCartesian(cx, cy, endAngle, r) const largeArc = endAngle - startAngle > 180 ? 1 : 0 return `M ${cx} ${cy} L ${start.x} ${start.y} A ${r} ${r} 0 ${largeArc} 1 ${end.x} ${end.y} Z` } /* ═══════════════════════════════════════════════ COMPONENTE PRINCIPAL ═══════════════════════════════════════════════ */ export default function RuletaSVG({ categorias, rotacion, isSpinning, onClick }: RuletaSVGProps) { const angleStep = 360 / TOTAL_SEGMENTS /* Puntos decorativos del anillo exterior */ const decorElements = useMemo(() => { const dots: { x: number; y: number; isStar: boolean }[] = [] for (let i = 0; i < 24; i++) { const angle = (i * 15) const pos = polarToCartesian(CX, CY, angle, RING_R) dots.push({ x: pos.x, y: pos.y, isStar: i % 3 === 0 }) } return dots }, []) return (
{/* ─── Puntero ─── */}
Indicador
{/* ─── SVG principal ─── */} {/* Sombra del anillo */} {/* Sombra del botón central */} {/* ══════ GRUPO GIRATORIO: Segmentos + centro ══════ */} {categorias.slice(0, TOTAL_SEGMENTS).map((cat, i) => { const startAngle = i * angleStep const endAngle = startAngle + angleStep const midAngle = startAngle + angleStep / 2 const style = SEGMENT_STYLES[i] ?? SEGMENT_STYLES[0] // Posición de la imagen (~58% del radio) const imgCenter = polarToCartesian(CX, CY, midAngle, SEGMENT_R * 0.58) // Posición del texto: radio y offset por categoría const textRadius = i === 0 ? SEGMENT_R * 0.58 : SEGMENT_R * 0.84 const textPosRaw = polarToCartesian(CX, CY, midAngle, textRadius) const textOffsetX = i === 0 ? 0 : i === 1 ? -40 : i === 2 ? 30 : i === 3 ? 38 : 0 const textOffsetY = i === 0 ? -45 : i === 1 ? 10 : i === 3 ? -12 : 0 const textPos = { x: textPosRaw.x + textOffsetX, y: textPosRaw.y + textOffsetY } const imgSize = i === 1 ? 58 : i === 2 ? 95 : i === 3 ? 88 : 70 const imgOffsetY = i === 0 ? 12 : i === 3 ? 15 : 0 /* Imágenes por segmento */ const imgs = ['agua.png', 'residuos.png', 'energia.png', 'movilidad.png'] /* Determinar si el texto es multilínea */ const esMultilinea = cat.nombre.length > 20 const lineas = esMultilinea ? cat.nombre.split(' y ') : [cat.nombre] return ( {/* Sector de color base */} {/* Imagen PNG (arriba, más cerca del centro) */} {/* Texto del nombre (debajo de la imagen) */} {lineas.map((linea, j) => ( {linea}{j < lineas.length - 1 ? ' y' : ''} ))} ) })} {/* ─── Botón central ─── */} {/* Círculo exterior (borde rojo) */} {/* Círculo blanco */} {/* Logo TIP */} {/* ══════ ANILLO EXTERIOR (estático) ══════ */} {/* Borde interior del anillo */} {/* Borde exterior del anillo */} {/* ══════ ELEMENTOS DECORATIVOS DEL ANILLO ══════ */} {decorElements.map((d, i) => ( {d.isStar ? ( /* Estrella de 4 puntas */ ) : ( /* Círculo decorativo */ )} ))}
) }