Estados y estilos de secciones
El booking renderer rastrea cuatro estados para cada contorno de sección: highlighted, selected, unavailable y filtered. Cada estado puede estilizarse de forma independiente mediante el tema svgSectionStyles y alternarse de forma programática a través de la API del renderer. Los estados funcionan de manera uniforme en todos los tipos de contorno: fondos SVG, formas creadas en el Editor, contornos generados automáticamente y contornos de respaldo.
Estados de secciones
Cada contorno de sección puede tener cero o más de estos estados activos simultáneamente:
| State | Trigger | Typical use |
|---|---|---|
highlighted |
Paso del ratón o programático | Retroalimentación visual al pasar el ratón |
selected |
Clic del usuario en una sección de Admisión General (GA) | Sección añadida al carrito |
unavailable |
disableSections() |
Secciones agotadas, restringidas o cerradas |
filtered |
filterSections() |
Mostrar solo un subconjunto de secciones (p. ej., nivel de precio) |
Los estados se almacenan como atributos data-* en los elementos de contorno SVG (data-highlighted, data-selected, data-unavailable, data-filtered) y se estilizan mediante CSS generado a partir de la configuración de tu tema.
Estilos con svgSectionStyles
Pasa un objeto svgSectionStyles dentro de theme al crear el renderer. Cada clave corresponde a un estado, y cada valor controla las propiedades visuales de ese estado.
import { SeatmapBookingRenderer } from '@seatmap.pro/renderer';
const renderer = new SeatmapBookingRenderer(document.getElementById('seatmap'), {
publicKey: 'your-public-key',
theme: {
svgSectionStyles: {
default: {
bgColor: 'rgba(200, 200, 200, 0.2)',
stroke: { color: '#888', width: '2', opacity: 1 },
cursor: 'pointer',
},
hovered: {
bgColor: 'rgba(33, 150, 243, 0.5)',
stroke: { color: '#1565C0', width: '3', opacity: 1 },
cursor: 'pointer',
},
selected: {
bgColor: 'rgba(76, 175, 80, 0.6)',
stroke: { color: '#2E7D32', width: '3', opacity: 1 },
cursor: 'pointer',
},
unavailable: {
bgColor: 'rgba(244, 67, 54, 0.4)',
stroke: { color: '#C62828', width: '3', opacity: 1 },
cursor: 'not-allowed',
opacity: 0.5,
},
filtered: {
bgColor: 'rgba(0, 0, 0, 0.15)',
stroke: { color: '#999', width: '1', opacity: 0.5 },
cursor: 'default',
opacity: 0.3,
},
},
},
});
renderer.loadEvent('your-event-id');
Referencia de propiedades de estilo
Cada estado acepta estas propiedades:
| Property | Type | Description |
|---|---|---|
bgColor |
string |
Color de relleno del contorno. Usa rgba() para superposiciones semitransparentes sobre el fondo del recinto. |
stroke.color |
string |
Color del borde del contorno. |
stroke.width |
string |
Grosor del borde del contorno (p. ej., '2'). |
stroke.opacity |
number |
Opacidad del borde del contorno (de 0 a 1). |
sectionName.color |
string |
Color del texto de la etiqueta de la sección dentro del contorno. |
cursor |
string |
Cursor CSS al pasar el ratón sobre la sección (p. ej., 'pointer', 'not-allowed'). |
opacity |
number |
Opacidad general del elemento de contorno (de 0 a 1). Predeterminados: 0.5 para unavailable, 0.3 para filtered. Los valores del tema anulan los predeterminados. |
El estado default acepta todas las propiedades listadas arriba. Los demás estados (hovered, selected, unavailable, filtered) admiten además bgColor para el relleno de la superposición.
Interfaz OutlineStates
El renderer rastrea el estado de la sección mediante la interfaz OutlineStates. Cada campo es un booleano opcional: establece solo los campos que quieras cambiar.
interface OutlineStates {
highlighted?: boolean; // Mouse hover or programmatic highlight
selected?: boolean; // Section added to cart (GA sections)
unavailable?: boolean; // Disabled -- cannot interact
filtered?: boolean; // Dimmed by active filter
}
Al leer el estado de vuelta, los cuatro campos siempre están presentes:
interface IEntityStates {
highlighted: boolean;
selected: boolean;
unavailable: boolean;
filtered: boolean;
}
Referencia de la API
Desactivar secciones
Marca secciones como no disponibles para impedir la interacción. Las secciones desactivadas muestran el estilo unavailable e ignoran los clics.
// Disable specific sections by ID
renderer.disableSections([101, 102, 103]);
// Disable with reset -- re-enable all previously disabled, then disable these
// Useful for category buttons: each click disables a new set without accumulating
renderer.disableSections([201, 202], { resetAll: true });
// Re-enable specific sections
renderer.enableSections([101, 102, 103]);
También puedes desactivar por nombre de sección:
renderer.disableSectionsByNames(['Floor A', 'Floor B']);
renderer.enableSectionsByNames(['Floor A']);
Filtrar secciones
El filtrado muestra solo las secciones que especifiques, atenuando todas las demás. Es útil para la selección de niveles de precio, el filtrado por accesibilidad o las vistas por categoría.
// Show only these sections -- all others get the "filtered" style
const premiumIds = [101, 102, 103];
renderer.filterSections(premiumIds);
// Remove all filters -- restore all sections to normal
renderer.removeFilterSections();
La lógica del filtro invierte los IDs que pasas: las secciones incluidas en el array permanecen normales, y las secciones no incluidas en el array obtienen el estado filtered.
Consultar secciones
// Get all sections with their current state
const sections = renderer.getSections();
sections.forEach((section) => {
console.log(section.id, section.name, section.isGa, section.disabled, section.filtered);
});
Lista completa de métodos
| Method | Description |
|---|---|
disableSections(ids, options?) |
Desactivar secciones por IDs numéricos. Pasa { resetAll: true } para reactivar todas antes de desactivar. |
enableSections(ids) |
Reactivar secciones previamente desactivadas. |
disableSectionsByNames(names, options?) |
Desactivar secciones por cadena de nombre. |
enableSectionsByNames(names) |
Reactivar secciones por cadena de nombre. |
filterSections(ids, options?) |
Mostrar solo las secciones especificadas; atenuar todas las demás. |
removeFilterSections(ids?) |
Quitar el filtro de secciones concretas, o de todas si no se pasan IDs. |
getSections() |
Devuelve todas las secciones con su estado actual (id, name, isGa, disabled, filtered). |
setOutlineStates(id, states) |
Bajo nivel: establecer estados concretos en una sección. Pasa null para limpiar. Pasa undefined como id para aplicar a todas. |
getOutlineStates(id) |
Bajo nivel: leer el estado actual de una sección. Devuelve los cuatro campos booleanos. |
onSectionStateChange(callback) |
Registrar un callback que se dispara cuando cambia el estado de cualquier sección. Recibe el ID de la sección. |
Migración desde los nombres de métodos heredados
Los nombres de método anteriores *SvgSections* están obsoletos pero siguen funcionando. Actualízalos cuando te resulte conveniente:
| Deprecated | Replacement |
|---|---|
disableSvgSectionsByIds() |
disableSections() |
enableSvgSectionsByIds() |
enableSections() |
disableSvgSectionsByNames() |
disableSectionsByNames() |
enableSvgSectionsByNames() |
enableSectionsByNames() |
filterSvgSectionsByIds() |
filterSections() |
removeFilterSvgSectionsByIds() |
removeFilterSections() |
Los nuevos nombres reflejan que estos métodos funcionan de forma idéntica en todos los tipos de sección, no solo en las secciones vinculadas a SVG.
Al llamar a métodos obsoletos, el renderer registra una sola vez una advertencia en la consola con el reemplazo recomendado. Para suprimir estas advertencias durante la migración:
const renderer = new SeatmapBookingRenderer(element, {
publicKey: 'your-public-key',
suppressDeprecationWarnings: true,
});
API de estado de bajo nivel
Para casos de uso avanzados – frameworks de UI personalizados, sincronización de estado externa o aplicación de varios estados simultáneamente – usa directamente la API de estado de bajo nivel.
// Set multiple states on a single section
renderer.setOutlineStates(101, {
highlighted: true,
unavailable: true,
});
// Read current state
const state = renderer.getOutlineStates(101);
// Returns: { highlighted: true, selected: false, unavailable: true, filtered: false }
// Clear all states on a section
renderer.setOutlineStates(101, null);
// Clear all states on all sections (pass undefined as id)
renderer.setOutlineStates(undefined, null);
La API de bajo nivel establece estados directamente sin efectos secundarios (sin recálculo de precios, sin actualizaciones del modelo de datos). Usa los métodos de alto nivel (disableSections, filterSections) para los flujos estándar que también actualizan el modelo de datos.
Callback de cambio de estado
Registra un callback para recibir notificaciones cuando cambie el estado de cualquier sección. Es útil para mantener una UI externa (barra lateral, leyenda, tooltip) sincronizada con el estado del renderer.
renderer.onSectionStateChange((sectionId) => {
const state = renderer.getOutlineStates(sectionId);
updateSidebar(sectionId, state);
});
El callback se dispara con todos los cambios de estado: paso del ratón, selección, desactivación, filtrado y actualizaciones programáticas.
La opción resetAll
Tanto disableSections como filterSections aceptan un parámetro opcional { resetAll: true }. Cuando se establece, el renderer primero limpia todos los estados de ese tipo aplicados previamente antes de aplicar los nuevos.
Esto es útil para patrones de selección exclusiva, como los botones de filtro por categoría:
// Category filter buttons -- each click shows only that category
document.getElementById('btn-vip').addEventListener('click', () => {
renderer.filterSections(vipSectionIds, { resetAll: true });
});
document.getElementById('btn-standard').addEventListener('click', () => {
renderer.filterSections(standardSectionIds, { resetAll: true });
});
document.getElementById('btn-all').addEventListener('click', () => {
renderer.removeFilterSections();
});
Sin resetAll, tendrías que llamar a removeFilterSections() antes de cada llamada a filterSections(), lo que puede provocar un parpadeo visible.
Paso del ratón y selección de secciones
El resaltado al pasar el ratón y la selección de secciones se habilitan mediante los ajustes del renderer:
const renderer = new SeatmapBookingRenderer(document.getElementById('seatmap'), {
publicKey: 'your-public-key',
highlightSectionOnHover: true,
enableSectionSelection: true,
onSectionSelect: (section) => {
console.log('Selected:', section.id, section.name);
return true; // return true to confirm selection
},
onSectionDeselect: (section) => {
console.log('Deselected:', section.id, section.name);
return true;
},
onSectionMouseEnter: (section) => {
// Update external UI (tooltip, sidebar, etc.)
},
onSectionMouseLeave: () => {
// Clear external UI
},
});
Cuando highlightSectionOnHover es true, pasar el ratón sobre una sección aplica el estilo hovered. Cuando enableSectionSelection es true, hacer clic en una sección de Admisión General (GA) alterna el estilo selected y dispara los callbacks de selección/deselección.
Combinaciones de estados
Varios estados pueden estar activos en la misma sección. El renderer aplica CSS con reglas de especificidad:
| Combination | Visual result |
|---|---|
selected + paso del ratón |
Borde más grueso, opacidad completa |
unavailable + paso del ratón |
Opacidad ligeramente mayor (sigue mostrando no disponible) |
selected + unavailable |
Se muestra con opacidad reducida (unavailable tiene prioridad visual) |
Tipos de contorno
El renderer crea contornos de sección a partir de varias fuentes. Los cuatro tipos responden a los estados y estilos de forma idéntica:
| Source | Origin | Attribute |
|---|---|---|
| Fondo SVG | SVG del plano con vínculos de sección | data-outline-source="svg" |
| Forma | Rectángulos, polígonos y trazados creados en el Editor | data-outline-source="shape" |
| Auto | Contornos generados por el Editor a partir de grupos de asientos | data-outline-source="auto" |
| Respaldo | Generados en tiempo de ejecución a partir de posiciones de asientos | data-outline-source="fallback" |
No necesitas tratar estos tipos de forma diferente. Todos los métodos públicos de la API funcionan de manera uniforme en todos los tipos. El atributo data-outline-source es un detalle interno expuesto solo para depuración.
Visibilidad de contornos durante la animación
Durante las animaciones de paneo y zoom, la capa SVG de contornos se oculta por defecto por rendimiento. Los contornos reaparecen al completarse la animación. Para mantener los contornos visibles durante las animaciones (a costa de rendimiento), establece:
const renderer = new SeatmapBookingRenderer(element, {
publicKey: 'your-public-key',
showOutlineLayerOnAnimation: true,
});
Ejemplo completo
Este ejemplo crea un renderer con estados estilizados, desactiva las secciones agotadas y filtra a un nivel de precio específico al actuar el usuario:
import { SeatmapBookingRenderer } from '@seatmap.pro/renderer';
const renderer = new SeatmapBookingRenderer(document.getElementById('seatmap'), {
publicKey: 'your-public-key',
highlightSectionOnHover: true,
enableSectionSelection: true,
theme: {
svgSectionStyles: {
default: {
bgColor: 'rgba(100, 100, 100, 0.1)',
stroke: { color: '#666', width: '1', opacity: 0.8 },
cursor: 'pointer',
},
hovered: {
bgColor: 'rgba(33, 150, 243, 0.4)',
stroke: { color: '#1976D2', width: '2', opacity: 1 },
},
selected: {
bgColor: 'rgba(76, 175, 80, 0.5)',
stroke: { color: '#388E3C', width: '2', opacity: 1 },
},
unavailable: {
bgColor: 'rgba(158, 158, 158, 0.3)',
stroke: { color: '#9E9E9E', width: '1', opacity: 0.5 },
cursor: 'not-allowed',
opacity: 0.4,
},
filtered: {
bgColor: 'rgba(0, 0, 0, 0.08)',
stroke: { color: '#ccc', width: '1', opacity: 0.3 },
cursor: 'default',
opacity: 0.2,
},
},
},
onSectionSelect: (section) => {
console.log('Added to cart:', section.name);
return true;
},
onSectionDeselect: (section) => {
console.log('Removed from cart:', section.name);
return true;
},
});
renderer.loadEvent('your-event-id').then(() => {
// Disable sold-out sections after event loads
const soldOutIds = [301, 302];
renderer.disableSections(soldOutIds);
});
// Filter to a price tier when user clicks a button
document.getElementById('filter-premium').addEventListener('click', () => {
const premiumIds = [101, 102, 103];
renderer.filterSections(premiumIds);
});
document.getElementById('clear-filter').addEventListener('click', () => {
renderer.removeFilterSections();
});
Playground
Usa el playground interactivo para probar todos los estados de sección en tiempo real. Carga el preset unifiedSectionStates en /playground/?preset=unifiedSectionStates para ver:
- Contornos estilizados en todos los tipos de contorno (SVG, forma, respaldo)
- Botones para desactivar, activar, filtrar, quitar filtro, seleccionar y restablecer
- Inspector DOM que muestra en vivo los atributos
data-*, los estilos calculados y los valores de cursor - Registro en consola de todos los eventos de sección