@boothtrix/viewer
v1.0.0
Published
Lightweight React component for rendering interactive booth maps
Downloads
63
Maintainers
Readme
@boothtrix/viewer
Lightweight React component for rendering interactive booth maps. Built with React and Konva for smooth canvas rendering with touch gesture support.
Installation
npm install @boothtrix/viewerPeer Dependencies
npm install react react-dom konva react-konvaQuick Start
import { BoothMapViewer } from '@boothtrix/viewer';
function App() {
return (
<BoothMapViewer
config={boothMapConfig}
onBoothSelect={(booth) => console.log('Selected:', booth)}
showLegend
/>
);
}Features
- Interactive Selection: Click/tap to select available booths
- Zoom & Pan: Mouse wheel zoom, drag to pan, pinch-to-zoom on touch
- Multi-floor Support: Built-in floor selector for multi-level venues
- State Overrides: Pass booked/blocked booth IDs to override states
- Customizable Colors: Override any booth state color
- Touch Gestures: Full mobile support with pinch-to-zoom
- Responsive: Automatically fills container size
Props
Configuration
| Prop | Type | Description |
|------|------|-------------|
| config | BoothMapConfig | Direct configuration object |
| configUrl | string | URL to fetch configuration from |
State Overrides
| Prop | Type | Description |
|------|------|-------------|
| bookedBooths | string[] | Array of booth IDs/labels to mark as booked |
| blockedBooths | string[] | Array of booth IDs/labels to mark as blocked |
| unavailableBooths | string[] | Array of booth IDs/labels to mark as unavailable |
Selection Callbacks
| Prop | Type | Description |
|------|------|-------------|
| onBoothSelect | (booth: BoothData) => void | Called when a booth is selected |
| onBoothDeselect | (booth: BoothData) => void | Called when a booth is deselected |
| onSelectionChange | (booths: BoothData[]) => void | Called when selection changes |
| onBoothHover | (booth: BoothData \| null) => void | Called on booth hover |
| selectablePredicate | (booth: BoothData) => boolean | Custom logic for booth selectability |
Floor Navigation
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| floorId | string \| null | - | Controlled floor ID |
| onFloorChange | (floorId: string \| null) => void | - | Floor change callback |
| showFloorSelector | boolean | true | Show floor selector UI |
| floorSelectorPosition | 'top-left' \| 'top-right' \| 'bottom-left' \| 'bottom-right' | 'top-right' | Floor selector position |
Zoom Controls
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| showZoomControls | boolean | true | Show zoom buttons |
| zoomControlsPosition | 'top-left' \| 'top-right' \| 'bottom-left' \| 'bottom-right' | 'bottom-right' | Zoom controls position |
| minZoom | number | 0.3 | Minimum zoom level |
| maxZoom | number | 3 | Maximum zoom level |
| zoomStep | number | 0.2 | Zoom increment |
Display Options
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| showLegend | boolean | false | Show color legend |
| showTooltip | boolean | true | Show booth tooltip on hover |
| showDimensions | boolean | true | Show booth dimensions (ft) |
| touchEnabled | boolean | true | Enable touch gestures |
| colorOverrides | Partial<BoothColorSettings> | - | Override default colors |
| className | string | - | Container CSS class |
Lifecycle Callbacks
| Prop | Type | Description |
|------|------|-------------|
| onConfigLoad | (config: BoothMapConfig) => void | Called when config loads |
| onError | (error: Error) => void | Called on error |
Usage Examples
Basic Viewer
import { BoothMapViewer } from '@boothtrix/viewer';
<BoothMapViewer config={boothMapConfig} />Load from API
<BoothMapViewer
configUrl="https://api.example.com/events/123/booth-map"
onConfigLoad={(config) => console.log('Loaded', config)}
onError={(error) => console.error(error)}
/>Booking Integration
import { useState } from 'react';
import { BoothMapViewer } from '@boothtrix/viewer';
import type { BoothData } from '@boothtrix/shared';
function BookingPage() {
const [cart, setCart] = useState<BoothData[]>([]);
// Already booked booth IDs from your backend
const bookedBooths = ['A-101', 'A-102', 'B-201'];
return (
<div style={{ display: 'flex', height: '100vh' }}>
<div style={{ flex: 1 }}>
<BoothMapViewer
config={boothMapConfig}
bookedBooths={bookedBooths}
onSelectionChange={setCart}
selectablePredicate={(booth) =>
booth.state === 'available' && !booth.isBlocked
}
showLegend
/>
</div>
<aside style={{ width: 300, padding: 20 }}>
<h2>Cart ({cart.length} booths)</h2>
{cart.map(booth => (
<div key={booth.id}>
{booth.label} - ${booth.price || 0}
</div>
))}
<div>
Total: ${cart.reduce((sum, b) => sum + (b.price || 0), 0)}
</div>
</aside>
</div>
);
}Custom Colors
<BoothMapViewer
config={boothMapConfig}
colorOverrides={{
boothAvailable: '#10b981',
boothBooked: '#6366f1',
canvasBackground: '#0f172a',
}}
/>Controlled Floor Navigation
function MultiFloorVenue() {
const [currentFloor, setCurrentFloor] = useState<string | null>(null);
return (
<>
<BoothMapViewer
config={boothMapConfig}
floorId={currentFloor}
onFloorChange={setCurrentFloor}
showFloorSelector={false} // Use custom UI
/>
<nav>
<button onClick={() => setCurrentFloor(null)}>All</button>
<button onClick={() => setCurrentFloor('floor-1')}>Level 1</button>
<button onClick={() => setCurrentFloor('floor-2')}>Level 2</button>
</nav>
</>
);
}Mobile-Optimized
<BoothMapViewer
config={boothMapConfig}
touchEnabled
showDimensions={false}
minZoom={0.5}
maxZoom={2}
zoomControlsPosition="bottom-left"
/>Booth States
The viewer displays booths with colors based on their state:
| State | Default Color | Description |
|-------|---------------|-------------|
| available | Green #22c55e | Can be selected |
| reserved | Yellow #eab308 | Temporarily held |
| booked | Blue #3b82f6 | Purchased/assigned |
| blocked | Red #ef4444 | Admin blocked |
| unavailable | Gray #6b7280 | Not available |
| hidden | - | Not rendered |
Styling
The component fills its container. Ensure the parent has explicit dimensions:
<div style={{ width: '100%', height: '600px' }}>
<BoothMapViewer config={config} />
</div>Or use CSS:
.booth-viewer-container {
width: 100%;
height: 100vh;
}<div className="booth-viewer-container">
<BoothMapViewer config={config} className="my-viewer" />
</div>TypeScript
The package includes full TypeScript definitions. Import types from @boothtrix/shared:
import type { BoothData, BoothMapConfig, HallConfig } from '@boothtrix/shared';Related Packages
@boothtrix/shared- Shared types and utilities- Booth Map Studio - Full-featured booth map editor
License
MIT
