JSPM

@metrixlabs/seatmap-renderer

1.1.1
  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 6
  • Score
    100M100P100Q45295F
  • License MIT

Framework-agnostic seat map renderer with pixel-perfect positioning

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-renderer

Quick 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 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

mountVanillaSeatMap(options)

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 function

Returns: { el: SVGSVGElement, destroy(): void }

flattenSeatMap(editorJson, options?)

Converts editor JSON data to the renderable format.

Parameters:

  • editorJson: any - The editor state JSON
  • options?: { seatRadius?: number } - Conversion options

Returns: SeatGlyph[]

computeViewBox(seats, padding?)

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

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

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Add tests if applicable
  5. Submit a pull request