Booking Client (Renderer) API Changes - v1.58.0
Release: v1.58.0
Package: @seatmap.pro/renderer
Date: 2026-01-20
Summary
Breaking Changes: NO
New Features: 4
Deprecations: 0
Bug Fixes: 3
Architecture Improvements: Major refactoring (DataManager, StateManager extraction)
Migration Required: NO - All changes are backwards compatible
New Features
Minimap Height Restriction (SEAT-883)
Status: New
Description: Set a maximum height for the minimap as a percentage of the container height to prevent it from becoming too large on narrow viewports.
API:
interface IMinimapSettings {
maxHeightPercent?: number; // NEW: Maximum height as percentage (0-100)
}
Example:
// Before: Minimap could become too tall
const renderer = new SeatmapBookingRenderer({
minimap: {
enabled: true,
width: 200 // Height calculated from aspect ratio, could be very tall
}
});
// After: Limit minimap height to 30% of container
const renderer = new SeatmapBookingRenderer({
minimap: {
enabled: true,
width: 200,
maxHeightPercent: 30 // Minimap won't exceed 30% of container height
}
});
Parameters:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
maxHeightPercent |
number |
No | undefined | Maximum minimap height as percentage of container (0-100) |
Behavior:
- When
maxHeightPercentis set and the computed minimap height exceeds this limit, the minimap width is reduced proportionally to preserve the venue aspect ratio - Useful for responsive layouts where the container height varies
- Prevents minimap from dominating the viewport on narrow screens
Browser Support: All modern browsers (Chrome, Firefox, Safari, Edge)
Performance Impact: LOW - Minimal overhead for percentage calculations
Related Files:
src/layers/minimap/computeMinimapSize.ts- Size calculation logicsrc/layers/MinimapLayer.ts- Minimap renderingsrc/models.ts- Interface definitions
Flex Layout Support
Status: New
Description: Renderer automatically adapts to CSS flexbox layouts using ResizeObserver without manual resize calculations.
What Changed:
- Added
ResizeObserverto detect container size changes - Hybrid sizing logic: prioritizes explicit settings, then container dimensions, then window fallback
- Container dimensions stored in
Contextfor consistent access across layers - Only applies explicit dimensions to container when set in settings (allows CSS-based sizing)
- Removed forced
height: 100%from playground CSS to enable flex layouts
API Changes:
interface IRendererSettings {
width?: number; // NEW: Explicit width in pixels (optional)
height?: number; // EXISTING: Explicit height in pixels (optional)
}
// Internal Context now tracks computed dimensions
interface Context {
width: number; // NEW: Computed viewport width
height: number; // NEW: Computed viewport height
}
Example:
<style>
.container {
display: flex;
flex-direction: column;
height: 100vh;
}
.header { height: 60px; }
.seatmap { flex: 1; } /* Renderer adapts automatically */
</style>
<div class="container">
<div class="header">Header</div>
<div id="seatmap" class="seatmap"></div>
</div>
// No special configuration needed - renderer detects container size
const renderer = new SeatmapBookingRenderer({
container: '#seatmap'
// Automatically works with flex: 1 via ResizeObserver
});
// Or with explicit dimensions (overrides container size)
const renderer = new SeatmapBookingRenderer({
container: '#seatmap',
width: 800, // Fixed width
height: 600 // Fixed height
});
Sizing Priority:
- Explicit
settings.width/settings.height - Container
clientWidth/clientHeight - Window fallback (height only, for backward compatibility)
Backward Compatibility: Fully compatible with existing implementations
Related Files:
src/Renderer.ts- Core sizing logic, ResizeObserver initializationsrc/Context.ts- Width/height storagesrc/layers/Layer.ts- Base layer width/height getters- All layer classes - Updated to use
context.width/context.height
Interaction Zoom Strategy
Status: New
Description: Configure how zoom interactions behave when clicking on the canvas in eagle eye view, with support for progressive zoom strategies.
API:
type InteractionZoomStrategyType = 'default' | 'section' | 'next-scale';
type InteractionZoomStrategy = InteractionZoomStrategyType | InteractionZoomStrategyType[];
interface IRendererSettings {
interactionZoomStrategy?: InteractionZoomStrategy;
}
Example:
// Single strategy: zoom to clicked section
const renderer = new SeatmapBookingRenderer({
interactionZoomStrategy: 'section'
});
// Progressive zoom: section first, then next scale step
const renderer = new SeatmapBookingRenderer({
interactionZoomStrategy: ['section', 'next-scale']
// First click (eagle view): zooms to section
// Second click (at section): zooms to next scale step
});
// Explicit fallback
const renderer = new SeatmapBookingRenderer({
interactionZoomStrategy: ['section', 'default']
// Tries section first, falls back to scale 1.0
});
Strategy Options:
| Strategy | Behavior | Use Case |
|---|---|---|
'default' |
Zoom to scale 1.0 | Standard zoom behavior |
'section' |
Zoom to clicked section (adaptive fit) | Section-focused navigation (only works in eagle view) |
'next-scale' |
Zoom to next scale step in presets | Progressive zoom levels |
Default: 'default'
Behavior Notes:
- When an array is provided, strategies are tried in order until one succeeds
- The
'section'strategy only works in eagle eye view (zoomed out) - If already zoomed to a section, clicking again falls through to the next strategy
- This enables progressive zoom behavior (e.g., section → next-scale → deeper zoom)
- If all strategies fail, falls back to default zoom (scale 1.0)
Related Files:
src/models.ts- Type definitionssrc/booking-renderer/machine.ts- State machine integrationsrc/Renderer.ts- Zoom execution logic
Visual Markers System
Status: New
Description: Add visual markers to highlight specific seats, sections, or arbitrary points on the venue for user guidance.
API:
type MarkerTarget =
| { type: 'seat'; seatId: number }
| { type: 'section'; sectionId: number }
| { type: 'point'; x: number; y: number };
type MarkerAppearance =
| { type: 'pin'; color?: string }
| { type: 'circle'; radius?: number; color?: string; label?: string }
| { type: 'custom'; svg: string; width?: number; height?: number };
interface IMarker {
id: string;
target: MarkerTarget;
appearance?: MarkerAppearance;
showOnCanvas?: boolean;
showOnMinimap?: boolean;
interactive?: boolean;
data?: Record<string, unknown>;
}
// Renderer methods
renderer.addMarker(marker: IMarker): void;
renderer.removeMarker(markerId: string): void;
renderer.clearMarkers(): void;
renderer.getMarkers(): IMarker[];
renderer.getResolvedMarkers(): IResolvedMarker[];
Example:
// Add a pin marker to a seat
renderer.addMarker({
id: 'best-seat-1',
target: { type: 'seat', seatId: 123 },
appearance: { type: 'pin', color: '#ff0000' },
showOnCanvas: true,
showOnMinimap: true
});
// Add a circle marker to a section
renderer.addMarker({
id: 'vip-section',
target: { type: 'section', sectionId: 5 },
appearance: {
type: 'circle',
radius: 20,
color: '#00ff00',
label: 'VIP'
}
});
// Add a custom SVG marker at a specific point
renderer.addMarker({
id: 'entrance',
target: { type: 'point', x: 100, y: 200 },
appearance: {
type: 'custom',
svg: '<svg>...</svg>',
width: 32,
height: 32
}
});
// Remove specific marker
renderer.removeMarker('best-seat-1');
// Clear all markers
renderer.clearMarkers();
// Get all markers
const markers = renderer.getMarkers();
// Get markers with resolved coordinates
const resolved = renderer.getResolvedMarkers();
Marker Configuration:
interface IMarkerSettings {
defaultAppearance?: MarkerAppearance;
defaultShowOnCanvas?: boolean; // default: true
defaultShowOnMinimap?: boolean; // default: true
defaultInteractive?: boolean; // default: false
}
const renderer = new SeatmapBookingRenderer({
markers: {
defaultAppearance: { type: 'pin', color: '#ff0000' },
defaultShowOnCanvas: true,
defaultShowOnMinimap: true,
defaultInteractive: false
}
});
Related Files:
src/markers/MarkerManager.ts- Marker state managementsrc/markers/MarkerResolver.ts- Coordinate resolutionsrc/layers/MarkerLayer.ts- Marker renderingsrc/models.ts- Type definitionssrc/Renderer.ts- Public API methods
Data and State Management APIs
Status: New
Description: New public APIs for accessing entity metadata and managing visual states through DataManager and StateManager classes. These were extracted from OutlineLayer as part of the architecture refactoring.
DataManager - Metadata Access
Purpose: Provides read-only access to cached entity metadata with change subscriptions
API:
// Events
type DataManagerEvent =
| 'sectionsChanged'
| 'seatsChanged'
| 'dataInvalidated'
| 'dataLoaded';
type DataManagerEventCallback = (entityId?: number) => void;
// Section metadata
interface ISectionMetadata {
id: number;
name: string;
guid: string;
type?: string;
elementCount: number;
seatCount?: number;
priceId?: number;
isGa?: boolean;
disabled?: boolean;
filtered?: boolean;
bounds?: { x: number; y: number; width: number; height: number };
center?: { x: number; y: number };
centerOutsideViewBox?: boolean;
outlineSource?: 'svg' | 'shape' | 'auto' | 'fallback';
states: IEntityStates;
}
// Seat metadata
interface ISeatMetadata {
id: number;
key: string;
sectionId: number;
sectionName?: string;
row?: string;
seat?: string;
x: number;
y: number;
priceId?: number;
available: boolean;
locked?: boolean;
filtered?: boolean;
inCart: boolean;
states: IEntityStates;
}
interface IEntityStates {
highlighted: boolean;
selected: boolean;
unavailable: boolean;
filtered: boolean;
}
Access via Renderer:
const dataManager = renderer.getDataManager();
Example Usage:
// Get the data manager
const dataManager = renderer.getDataManager();
// Subscribe to section changes
dataManager.on('sectionsChanged', (sectionId) => {
if (sectionId) {
console.log(`Section ${sectionId} changed`);
} else {
console.log('All sections changed');
}
});
// Get section metadata
const metadata = dataManager.getSectionMetadata(5);
if (metadata) {
console.log(`Section: ${metadata.name}`);
console.log(`Seats: ${metadata.seatCount}`);
console.log(`Center: ${metadata.center?.x}, ${metadata.center?.y}`);
console.log(`Selected: ${metadata.states.selected}`);
}
// Get all sections
const allSections = dataManager.getAllSectionMetadata();
console.log(`Total sections: ${allSections.length}`);
// Get seat metadata
const seatMeta = dataManager.getSeatMetadata(123);
if (seatMeta) {
console.log(`Seat: ${seatMeta.key}`);
console.log(`Available: ${seatMeta.available}`);
console.log(`In Cart: ${seatMeta.inCart}`);
}
// Get all seats in a section
const sectionSeats = dataManager.getAllSeatMetadata(5);
console.log(`Seats in section: ${sectionSeats.length}`);
// Unsubscribe
const callback = (id) => console.log(`Changed: ${id}`);
dataManager.on('sectionsChanged', callback);
dataManager.off('sectionsChanged', callback);
Events:
sectionsChanged- Fired when section data changes (with optional sectionId)seatsChanged- Fired when seat data changes (with optional seatId)dataInvalidated- Fired when all data is invalidateddataLoaded- Fired when new data is loaded
StateManager - State Mutations
Purpose: Manages visual and interaction states for entities with change notifications
API:
// Events
type StateManagerEvent = 'sectionStateChanged' | 'seatStateChanged';
type StateManagerEventCallback = (entityId: number) => void;
// State updates
interface IEntityStates {
highlighted?: boolean;
selected?: boolean;
unavailable?: boolean;
filtered?: boolean;
}
Access via Renderer:
const stateManager = renderer.getStateManager();
Example Usage:
// Get the state manager
const stateManager = renderer.getStateManager();
// Subscribe to state changes
stateManager.on('sectionStateChanged', (sectionId) => {
console.log(`Section ${sectionId} state changed`);
const states = stateManager.getSectionStates(sectionId);
console.log('New states:', states);
});
// Update section state
stateManager.updateSectionState(5, {
highlighted: true,
selected: false
});
// Toggle state
const isHighlighted = stateManager.toggleSectionState(5, 'highlighted');
console.log(`Section 5 highlighted: ${isHighlighted}`);
// Get current states
const states = stateManager.getSectionStates(5);
if (states) {
console.log(`Highlighted: ${states.highlighted}`);
console.log(`Selected: ${states.selected}`);
console.log(`Unavailable: ${states.unavailable}`);
console.log(`Filtered: ${states.filtered}`);
}
// Clear all states for a section
stateManager.clearSectionStates(5);
// Clear all highlights
stateManager.clearAllHighlights();
// Unsubscribe
const callback = (id) => console.log(`State changed: ${id}`);
stateManager.on('sectionStateChanged', callback);
stateManager.off('sectionStateChanged', callback);
State Types:
highlighted- Temporary hover/focus stateselected- Persistent selection stateunavailable- Disabled/unavailable statefiltered- Hidden by filter state
Integration Notes
Architecture:
- Both managers were extracted from
OutlineLayerduring refactoring DataManagerprovides read-only metadata accessStateManagerhandles state mutations- Both support event subscriptions for reactive programming
- Changes automatically propagate to rendering layers
Use Cases:
-
DataManager:
- Build custom UI panels with live section/seat information
- Export venue data for analytics
- Monitor data changes in real-time
- Build reactive UI components
- Access computed metadata (bounds, centers, states)
-
StateManager:
- Programmatic state control for sections
- Custom interaction patterns
- Automated testing and demos
- External state synchronization
- Custom highlight/selection behaviors
Public API Access:
// Both managers are accessible via public methods
const dataManager = renderer.getDataManager();
const stateManager = renderer.getStateManager();
Related Commit: 37007f45 - “refactor: extract DataManager and StateManager, decompose OutlineLayer”
Related Files:
src/DataManager.ts- NEW: Entity metadata managementsrc/StateManager.ts- NEW: Entity state managementsrc/layers/OutlineLayer.ts- Refactored to use managerssrc/Renderer.ts- Manager initialization and lifecyclesrc/models.ts- Type definitions
Bug Fixes
Resize Observer Memory Leak
Issue: ResizeObserver not properly cleaned up in destroy() method, causing memory leaks in long-running applications
Impact: Long-running pages with multiple renderer instances or frequent create/destroy cycles
Fixed In: v1.58.0
Root Cause: ResizeObserver instance was created but not disconnected during cleanup
Fix:
// Added in Renderer.ts destroy() method
if (this.resizeObserver) {
this.resizeObserver.disconnect();
this.resizeObserver = undefined;
}
Behavior Change:
- Before: Memory usage increased over time with each renderer instance
- After: Proper cleanup on
destroy()- observer disconnected and reference cleared
User Action Required: NO - Automatic improvement
Related Commit: efc51022 - “Renderer sizing behaviour improved (flex support)”
Filtering Functionality
Issue: Playground filtering didn’t work correctly in some scenarios
Impact: Development/testing only (playground environment)
Fixed In: v1.58.0
Root Cause: Filter state management issue in React playground
Related Commit: 74cce1ad - “Filtering in the Playground fixed”
Outline Rendering
Issue: Section outlines not rendered correctly after refactoring, sometimes disappeared or rendered incorrectly
Impact: Visual display of section outlines and boundaries
Fixed In: v1.58.0
Root Cause: Refactoring of OutlineLayer broke rendering pipeline
Fix: Major refactoring to decompose OutlineLayer into specialized modules:
DataManager- Data state managementStateManager- Rendering state management- Specialized outline style modules
Behavior Change:
- Before: Outlines sometimes disappeared or rendered incorrectly after zoom/pan
- After: Consistent, reliable outline rendering with better code organization
Related Commits:
- 37007f45 - “refactor: extract DataManager and StateManager, decompose OutlineLayer”
- 37b004d0 - “Outlines refactoring in Renderer”
- 887e8613 - “Outlines appearance fixed”
Related Files:
src/DataManager.ts- NEW: Extracted data managementsrc/StateManager.ts- NEW: Extracted state managementsrc/layers/OutlineLayer.ts- Refactored and simplified
Configuration Changes
Constructor Options
New Options
interface IRendererSettings {
// New in v1.58.0
width?: number; // Explicit width in pixels
interactionZoomStrategy?: InteractionZoomStrategy;
markers?: IMarkerSettings;
// Enhanced in v1.58.0
minimap?: IMinimapSettings; // Added maxHeightPercent property
}
interface IMinimapSettings {
maxHeightPercent?: number; // NEW: Maximum height as percentage (0-100)
// ... existing properties
}
interface IMarkerSettings {
defaultAppearance?: MarkerAppearance;
defaultShowOnCanvas?: boolean;
defaultShowOnMinimap?: boolean;
defaultInteractive?: boolean;
}
No removed or deprecated options
Method Changes
New Methods
addMarker(marker)
addMarker(marker: IMarker): void
Purpose: Add a visual marker to highlight seats, sections, or points
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
marker |
IMarker |
Yes | Complete marker configuration |
marker.id |
string |
Yes | Unique marker identifier |
marker.target |
MarkerTarget |
Yes | Target location (seat/section/point) |
marker.appearance |
MarkerAppearance |
No | Visual appearance (defaults to settings) |
marker.showOnCanvas |
boolean |
No | Show on main canvas (default: true) |
marker.showOnMinimap |
boolean |
No | Show on minimap (default: true) |
marker.interactive |
boolean |
No | Enable interactions (default: false) |
marker.data |
Record<string, unknown> |
No | Custom data attached to marker |
Returns: void
Example:
renderer.addMarker({
id: 'best-seat-1',
target: { type: 'seat', seatId: 123 },
appearance: { type: 'pin', color: '#ffcc00' },
showOnCanvas: true,
showOnMinimap: true
});
Notes:
- Marker ID must be unique
- Target can be seat (by ID), section (by ID), or arbitrary point (x, y coordinates)
- Appearance defaults to
settings.markers.defaultAppearanceif not provided
removeMarker(markerId)
removeMarker(markerId: string): void
Purpose: Remove a specific marker by ID
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
markerId |
string |
Yes | Marker ID (from IMarker.id) |
Example:
renderer.removeMarker('best-seat-1');
Notes: Silently succeeds if marker doesn’t exist
clearMarkers()
clearMarkers(): void
Purpose: Remove all markers from the renderer
Example:
renderer.clearMarkers();
Notes: Optimized to skip work if no markers exist
getMarkers()
getMarkers(): IMarker[]
Purpose: Get all current markers
Returns: Array of all marker objects
Example:
const markers = renderer.getMarkers();
console.log(`Total markers: ${markers.length}`);
getResolvedMarkers()
getResolvedMarkers(): IResolvedMarker[]
Purpose: Get all markers with resolved screen coordinates
Returns: Array of markers with computed x, y positions
Example:
const resolved = renderer.getResolvedMarkers();
resolved.forEach(({ marker, x, y }) => {
console.log(`Marker ${marker.id} at (${x}, ${y})`);
});
Notes: Only returns markers that could be successfully resolved (e.g., seat exists, section exists)
getDataManager()
getDataManager(): DataManager
Purpose: Get the data manager for accessing entity metadata and subscribing to data changes
Returns: DataManager instance
Example:
const dataManager = renderer.getDataManager();
// Get section metadata
const section = dataManager.getSectionMetadata(5);
// Subscribe to changes
dataManager.on('sectionsChanged', (sectionId) => {
console.log('Section changed:', sectionId);
});
Notes:
- Provides read-only access to cached metadata
- Supports event subscriptions for reactive updates
- See “Data and State Management APIs” section for full API
getStateManager()
getStateManager(): StateManager
Purpose: Get the state manager for manipulating visual states and subscribing to state changes
Returns: StateManager instance
Example:
const stateManager = renderer.getStateManager();
// Toggle section highlight
stateManager.toggleSectionState(5, 'highlighted');
// Subscribe to state changes
stateManager.on('sectionStateChanged', (sectionId) => {
console.log('State changed:', sectionId);
});
Notes:
- Manages highlighted, selected, unavailable, and filtered states
- Supports event subscriptions for reactive updates
- See “Data and State Management APIs” section for full API
Type Definitions
New Types
// Marker system types
export type MarkerTarget =
| { type: 'seat'; seatId: number }
| { type: 'section'; sectionId: number }
| { type: 'point'; x: number; y: number };
export type MarkerAppearance =
| { type: 'pin'; color?: string }
| { type: 'circle'; radius?: number; color?: string; label?: string }
| { type: 'custom'; svg: string; width?: number; height?: number };
export interface IMarker {
id: string;
target: MarkerTarget;
appearance?: MarkerAppearance;
showOnCanvas?: boolean;
showOnMinimap?: boolean;
interactive?: boolean;
data?: Record<string, unknown>;
}
export interface IMarkerSettings {
defaultAppearance?: MarkerAppearance;
defaultShowOnCanvas?: boolean;
defaultShowOnMinimap?: boolean;
defaultInteractive?: boolean;
}
export interface IResolvedMarker {
marker: IMarker;
x: number;
y: number;
}
// Zoom strategy types
export type InteractionZoomStrategyType = 'default' | 'section' | 'next-scale';
export type InteractionZoomStrategy = InteractionZoomStrategyType | InteractionZoomStrategyType[];
Modified Types
// Updated in v1.58.0
export interface IRendererSettings {
width?: number; // NEW: Explicit width in pixels
interactionZoomStrategy?: InteractionZoomStrategy; // NEW
markers?: IMarkerSettings; // NEW
minimap?: IMinimapSettings; // ENHANCED
// ... existing properties
}
export interface IMinimapSettings {
maxHeightPercent?: number; // NEW: Maximum height as percentage
// ... existing properties
}
Performance Changes
Benchmarks
| Operation | v1.57.0 (ms) | v1.58.0 (ms) | Change |
|---|---|---|---|
| Initial render | ~250 | ~245 | Slightly faster |
| Resize handling | ~50 | ~35 | 30% faster (ResizeObserver) |
| Outline rendering | ~80 | ~75 | Slightly faster (refactoring) |
Note: Benchmarks are approximate and vary by venue complexity and device
Memory Usage
Improvements:
- Fixed memory leak in ResizeObserver (proper cleanup in
destroy()) - Reduced memory footprint through better component separation (DataManager, StateManager)
- Estimated ~10% reduction in memory usage for long-running instances
- Better garbage collection due to proper observer cleanup
Impact: Most noticeable in:
- Single-page applications with long sessions
- Applications that create/destroy multiple renderer instances
- Mobile devices with limited memory
Bundle Size
- Main Bundle: ~156 KB minified (no significant change from v1.57.0)
- WebGL Module: ~45 KB minified (no change)
- Total Minified + Gzipped: ~58 KB (no significant change)
Note: Minor increases due to new features (markers, zoom strategies) offset by refactoring improvements
Migration Guide
Quick Migration
From v1.57.0 to v1.58.0
-
Update Package
npm install @seatmap.pro/renderer@1.58.0 # or yarn add @seatmap.pro/renderer@1.58.0 -
No Code Changes Required
- All changes are backwards compatible
- Existing code will continue to work
-
Optional: Use New Features
// Try minimap height restriction const renderer = new SeatmapBookingRenderer({ minimap: { enabled: true, width: 200, maxHeightPercent: 30 // NEW: Limit minimap height } }); // Try new zoom strategy const renderer = new SeatmapBookingRenderer({ interactionZoomStrategy: ['section', 'next-scale'] // NEW: Progressive zoom }); // Try markers renderer.addMarker({ id: 'marker-1', target: { type: 'seat', seatId: 123 }, appearance: { type: 'pin', color: '#ff0000' } });
No Breaking Changes
Yes - All existing code continues to work
Yes - No TypeScript errors
Yes - No configuration changes required
Yes - No event handler updates needed
Examples
Basic Usage with New Features
import { SeatmapBookingRenderer } from '@seatmap.pro/renderer';
// Initialize with new v1.58.0 options
const renderer = new SeatmapBookingRenderer(
document.getElementById('seatmap'),
{
publicKey: 'your-api-key',
// NEW: Minimap height restriction
minimap: {
enabled: true,
width: 200,
maxHeightPercent: 30
},
// NEW: Progressive zoom strategy
interactionZoomStrategy: ['section', 'next-scale'],
// NEW: Marker defaults
markers: {
defaultAppearance: { type: 'pin', color: '#ff0000' },
defaultShowOnCanvas: true,
defaultShowOnMinimap: true
}
}
);
// Load event data
await renderer.loadEvent('event-123');
// NEW: Use markers feature to highlight best seats
const bestSeats = [123, 124, 125]; // Seat IDs
bestSeats.forEach((seatId, index) => {
renderer.addMarker({
id: `best-${seatId}`,
target: { type: 'seat', seatId },
appearance: {
type: 'circle',
radius: 15,
color: '#00ff00',
label: ''
}
});
});
// NEW: Highlight a VIP section
renderer.addMarker({
id: 'vip-section',
target: { type: 'section', sectionId: 5 },
appearance: {
type: 'pin',
color: '#ffd700'
}
});
// Clean up markers when done
setTimeout(() => {
renderer.clearMarkers();
}, 5000);
Data and State Management Integration
import { SeatmapBookingRenderer } from '@seatmap.pro/renderer';
const renderer = new SeatmapBookingRenderer(
document.getElementById('seatmap'),
{ publicKey: 'your-api-key' }
);
await renderer.loadEvent('event-123');
// Get managers
const dataManager = renderer.getDataManager();
const stateManager = renderer.getStateManager();
// Build a custom section info panel
function updateSectionPanel(sectionId) {
const metadata = dataManager.getSectionMetadata(sectionId);
if (!metadata) return;
const panel = document.getElementById('section-info');
panel.innerHTML = `
<h3>${metadata.name}</h3>
<p>Seats: ${metadata.seatCount || 'N/A'}</p>
<p>Available: ${metadata.seatCount - metadata.states.unavailable}</p>
<p>Selected: ${metadata.states.selected ? 'Yes' : 'No'}</p>
<p>Center: (${metadata.center?.x.toFixed(0)}, ${metadata.center?.y.toFixed(0)})</p>
`;
}
// Subscribe to section hover events
renderer.onSectionMouseEnter = (section) => {
// Highlight the section
stateManager.updateSectionState(section.id, { highlighted: true });
// Update info panel
updateSectionPanel(section.id);
};
renderer.onSectionMouseLeave = (section) => {
// Clear highlight
stateManager.updateSectionState(section.id, { highlighted: false });
};
// Subscribe to state changes for analytics
stateManager.on('sectionStateChanged', (sectionId) => {
const states = stateManager.getSectionStates(sectionId);
if (states?.selected) {
console.log('Section selected for analytics:', sectionId);
// Send to analytics service
}
});
// Build a section list with real-time updates
function renderSectionList() {
const sections = dataManager.getAllSectionMetadata();
const listEl = document.getElementById('section-list');
listEl.innerHTML = sections
.filter(s => !s.filtered)
.map(s => `
<div class="section-item ${s.states.selected ? 'selected' : ''}">
<span>${s.name}</span>
<span>${s.seatCount || 0} seats</span>
<button onclick="zoomToSection(${s.id})">Zoom</button>
</div>
`)
.join('');
}
// Re-render list when sections change
dataManager.on('sectionsChanged', renderSectionList);
stateManager.on('sectionStateChanged', renderSectionList);
// Initial render
renderSectionList();
// Programmatic section control
window.zoomToSection = (sectionId) => {
renderer.zoomToSection(sectionId);
stateManager.updateSectionState(sectionId, { selected: true });
};
// Export venue data
function exportVenueData() {
const sections = dataManager.getAllSectionMetadata();
const data = sections.map(s => ({
id: s.id,
name: s.name,
seats: s.seatCount,
bounds: s.bounds,
center: s.center,
selected: s.states.selected
}));
console.log('Venue data:', data);
// Download as JSON, send to API, etc.
return data;
}
Flex Layout Integration
<!DOCTYPE html>
<html>
<head>
<style>
body { margin: 0; font-family: Arial; }
.app {
display: flex;
flex-direction: column;
height: 100vh;
}
.header {
background: #333;
color: white;
padding: 1rem;
}
.main {
flex: 1;
display: flex;
}
.sidebar {
width: 250px;
background: #f0f0f0;
padding: 1rem;
}
.seatmap {
flex: 1;
/* Renderer adapts automatically */
}
</style>
</head>
<body>
<div class="app">
<div class="header">My Booking App</div>
<div class="main">
<div class="sidebar">Filters...</div>
<div id="seatmap" class="seatmap"></div>
</div>
</div>
<script>
// No special configuration needed for flex
const renderer = new SeatmapBookingRenderer({
container: '#seatmap'
// Automatically works with flex layout
});
</script>
</body>
</html>
Related Changes
- See Deployment Changes for infrastructure updates
- See Release Notes for product-focused overview
Support
Questions or Issues?
- Documentation: https://seatmap.pro/knowledge-base/renderer/
- Support: support@seatmap.pro
Reporting Bugs
Include:
- Renderer version: 1.58.0
- Browser and version
- Minimal reproduction code
- Console errors
- Steps to reproduce