Package Exports
- @metrixlabs/seatmap-renderer
Readme
@metrixlabs/seatmap-renderer
A framework-agnostic library for rendering pixel-perfect seat maps and venue layouts. This library provides the core rendering capabilities used by the TicketStock Constructor tool.
Features
- Framework-agnostic - Works with React, Vue, Angular, or vanilla JavaScript
- Pixel-perfect positioning - Same layout accuracy as the preview mode
- Interactive seat maps - Click, hover, and keyboard navigation
- Customizable styling - Colors, sizes, accessibility labels
- Data conversion - Convert editor data to renderable format
- TypeScript support - Full type safety
Installation
npm install @metrixlabs/seatmap-rendererQuick Start
Basic SVG Generation
import { toSvgString, flattenSeatMap } from '@metrixlabs/seatmap-renderer'// Convert your editor data to renderable format const seatMapData = flattenSeatMap(editorJson)
// Generate SVG string const svgString = toSvgString({ data: seatMapData, seatRadius: 8, width: '100%', height: '600px', padding: 24 })
// Use the SVG string document.getElementById('seat-map').innerHTML = svgString
### Interactive Seat Map
```javascript
import { mountVanillaSeatMap, flattenSeatMap } from '@metrixlabs/seatmap-renderer'const seatMapData = flattenSeatMap(editorJson)
const { el, destroy } = mountVanillaSeatMap({ target: document.getElementById('seat-map'), data: seatMapData, onSeatClick: (seatId, meta, event) => { console.log('Seat clicked:', seatId) }, onSeatHover: (seatId, meta, event) => { console.log('Seat hovered:', seatId) } })
// Clean up when done destroy()
### Custom Styling
```javascript
const svgString = toSvgString({
data: seatMapData,
getSeatFill: (seat, sector) => {
// Custom color logic
if (seat.status === 'occupied') return '#ff0000'
if (sector?.color) return sector.color
return '#999999'
},
classNameForSeat: (seat) => {
// Custom CSS classes
return `seat seat-${seat.status}`
},
a11yLabel: (seat, sector) => {
// Custom accessibility labels
return `Seat ${seat.rowTitle} ${seat.localIndex + 1}, ${sector?.price || 'Free'}`
}
})React Usage Examples
Simple React Component
import React, { useEffect, useRef } from 'react'
import { mountVanillaSeatMap, type SeatMapData } from '@metrixlabs/seatmap-renderer'
const SeatMapComponent: React.FC = () => {
const containerRef = useRef<HTMLDivElement>(null)
const seatMapData: SeatMapData = {
seats: [
{ id: '1', x: 100, y: 100, r: 8, rowId: 'row1', localIndex: 0, entityId: 'sector1', sectorId: 'vip' },
{ id: '2', x: 120, y: 100, r: 8, rowId: 'row1', localIndex: 1, entityId: 'sector1', sectorId: 'vip' },
],
sectors: [
{ id: 'vip', color: '#ff6b6b', price: 100 }
]
}
useEffect(() => {
if (containerRef.current) {
const cleanup = mountVanillaSeatMap(containerRef.current, seatMapData, {
onSeatClick: (seatId) => console.log('Seat clicked:', seatId),
onSeatHover: (seatId) => console.log('Seat hovered:', seatId)
})
return cleanup
}
}, [])
return (
<div
ref={containerRef}
style={{ width: '600px', height: '400px', border: '1px solid #ccc' }}
/>
)
}Constructor Data Integration
import React, { useState, useEffect } from 'react'
import { flattenSeatMap, toSvgString, mountVanillaSeatMap } from '@metrixlabs/seatmap-renderer'
const ConstructorIntegration: React.FC = () => {
const [seatMapData, setSeatMapData] = useState(null)
// Complex data structure from constructor
const complexData = {
entities: {
'sector1': {
id: 'sector1',
entityKey: 'seatedSector',
name: 'VIP Section',
x: 100, y: 100,
sector: 'vip',
rowPitch: 30, seatPitch: 25,
rowIds: ['row1', 'row2']
}
},
rows: {
'row1': { id: 'row1', title: 'Row A', seatCount: 5, index: 0 },
'row2': { id: 'row2', title: 'Row B', seatCount: 5, index: 1 }
},
sectors: [
{ id: 'vip', name: 'VIP', color: '#ff6b6b', price: 100 }
]
}
useEffect(() => {
const flattened = flattenSeatMap(complexData)
setSeatMapData(flattened)
}, [])
const handleExport = () => {
if (seatMapData) {
const svg = toSvgString(seatMapData)
// Download or display SVG
}
}
return (
<div>
<button onClick={handleExport}>Export SVG</button>
{/* Render seat map */}
</div>
)
}📖 For complete React examples, see REACT_USAGE_EXAMPLES.md
API Reference
toSvgString(options)
Generates an SVG string representation of the seat map.
Options:
data: SeatMapData- The seat map dataseatRadius?: number- Seat circle radius (default: 8)width?: string | number- SVG width (default: '100%')height?: string | number- SVG height (default: '100%')padding?: number- ViewBox padding (default: 24)classNameForSeat?: (seat: SeatGlyph) => string- Custom CSS class functiongetSeatFill?: (seat: SeatGlyph, sector?: Sector) => string- Custom fill color functiona11yLabel?: (seat: SeatGlyph, sector?: Sector) => string- Custom accessibility label function
mountVanillaSeatMap(options)
Mounts an interactive seat map in a DOM element.
Options:
target: HTMLElement- Target DOM elementdata: SeatMapData- The seat map dataseatRadius?: number- Seat circle radiuspadding?: number- ViewBox paddingonSeatClick?: (seatId: string, meta: DOMStringMap, event: MouseEvent) => void- Click handleronSeatHover?: (seatId: string | null, meta: DOMStringMap | null, event: PointerEvent) => void- Hover handlera11y?: { enableKeyboard?: boolean }- Accessibility options (default: true)classNameForSeat?: (seat: SeatGlyph) => string- Custom CSS class functiongetSeatFill?: (seat: SeatGlyph, sector?: Sector) => string- Custom fill color function
Returns: { el: SVGSVGElement, destroy(): void }
flattenSeatMap(editorJson, options?)
Converts editor JSON data to the renderable format.
Parameters:
editorJson: any- The editor state JSONoptions?: { seatRadius?: number }- Conversion options
Returns: SeatGlyph[]
computeViewBox(seats, padding?)
Computes the optimal SVG viewBox for the given seats.
Parameters:
seats: SeatGlyph[]- Array of seat glyphspadding?: number- Padding around the seats (default: 24)
Returns: { minX: number, minY: number, width: number, height: number }
Types
SeatGlyph
type SeatGlyph = {
id: string; // Unique identifier
x: number; // X coordinate
y: number; // Y coordinate
r?: number; // Radius (default: 8)
rowId: string; // Row identifier
rowTitle?: string; // Row display name
localIndex: number; // Seat index within row
entityId: string; // Entity identifier
sectorId?: string; // Sector identifier
price?: number; // Seat price
currency?: string; // Price currency
[k: string]: unknown; // Additional metadata
}Sector
type Sector = {
id: string; // Sector identifier
color?: string; // CSS color
price?: number; // Default price
currency?: string; // Price currency
}SeatMapData
type SeatMapData = {
seats: SeatGlyph[]; // Array of seats
sectors?: Sector[]; // Array of sectors
meta?: Record<string, unknown>; // Additional metadata
}Browser Support
- Chrome 90+
- Firefox 88+
- Safari 14+
- Edge 90+
License
MIT License - see LICENSE file for details.
Contributing
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests if applicable
- Submit a pull request