Framework-agnostic seat map renderer with pixel-perfect positioning
npm install @metrixlabs/seatmap-rendererA 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.
- 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
``bash`
npm install @metrixlabs/seatmap-renderer
`javascript`
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
`
`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()
`
`javascriptseat seat-${seat.status}
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.rowTitle} ${seat.localIndex + 1}, ${sector?.price || 'Free'}
},
a11yLabel: (seat, sector) => {
// Custom accessibility labels
return `
}
})
`tsx
import React, { useEffect, useRef } from 'react'
import { mountVanillaSeatMap, type SeatMapData } from '@metrixlabs/seatmap-renderer'
const SeatMapComponent: React.FC = () => {
const containerRef = useRef
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 (
$3
`tsx
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 (
{/ Render seat map /}
)
}
`📖 For complete React examples, see REACT_USAGE_EXAMPLES.md
API Reference
$3
Generates an SVG string representation of the seat map.
Options:
-
data: SeatMapData - The seat map data
- seatRadius?: 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 function
- getSeatFill?: (seat: SeatGlyph, sector?: Sector) => string - Custom fill color function
- a11yLabel?: (seat: SeatGlyph, sector?: Sector) => string - Custom accessibility label function$3
Mounts an interactive seat map in a DOM element.
Options:
-
target: HTMLElement - Target DOM element
- data: SeatMapData - The seat map data
- seatRadius?: number - Seat circle radius
- padding?: number - ViewBox padding
- onSeatClick?: (seatId: string, meta: DOMStringMap, event: MouseEvent) => void - Click handler
- onSeatHover?: (seatId: string | null, meta: DOMStringMap | null, event: PointerEvent) => void - Hover handler
- a11y?: { enableKeyboard?: boolean } - Accessibility options (default: true)
- classNameForSeat?: (seat: SeatGlyph) => string - Custom CSS class function
- getSeatFill?: (seat: SeatGlyph, sector?: Sector) => string - Custom fill color functionReturns:
{ el: SVGSVGElement, destroy(): void }$3
Converts editor JSON data to the renderable format.
Parameters:
-
editorJson: any - The editor state JSON
- options?: { seatRadius?: number } - Conversion optionsReturns:
SeatGlyph[]$3
Computes the optimal SVG viewBox for the given seats.
Parameters:
-
seats: SeatGlyph[] - Array of seat glyphs
- padding?: number - Padding around the seats (default: 24)Returns:
{ minX: number, minY: number, width: number, height: number }Types
$3
`typescript
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
}
`$3
`typescript
type Sector = {
id: string; // Sector identifier
color?: string; // CSS color
price?: number; // Default price
currency?: string; // Price currency
}
`$3
`typescript
type SeatMapData = {
seats: SeatGlyph[]; // Array of seats
sectors?: Sector[]; // Array of sectors
meta?: Record; // Additional metadata
}
``- Chrome 90+
- Firefox 88+
- Safari 14+
- Edge 90+
MIT License - see LICENSE file for details.
1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Add tests if applicable
5. Submit a pull request