Seatmap Canvas is an advanced, open-source library for interactive seat selection in various settings such as stadiums, theaters, and event spaces. Designed with d3.js, this code version is optimized for developers looking for a customizable and efficient solution to handle seat arrangements and user interactions.
π Documentation | π― Live Demo
- Framework Agnostic - Core library works with vanilla JS, plus official React and Vue 3 wrappers
- Dynamic Seat Selection - Interactive selection, categorization, and location of seats
- Custom Background Images - Global and per-block background images with positioning control
- Customizable Styles - Extensive styling options for seats, blocks, and labels
- Interactive Seat Models - Define properties like salability, notes, colors, and custom data
- Block Organization - Organize seats into blocks with titles, colors, and labels
- Event System - Simplified event listeners for seat interactions
| Framework | Status | Package | Documentation | Example |
|---|---|---|---|---|
| Vanilla JS | β Available | @alisaitteke/seatmap-canvas |
π Documentation | π― Example |
| Vue.js 3 | @alisaitteke/seatmap-canvas/vue |
π Documentation | π― Example | |
| React | @alisaitteke/seatmap-canvas/react |
π Documentation | π― Example | |
| Next.js | π Coming Soon | - | - | - |
| Svelte | π Coming Soon | - | - | - |
| Angular | π Coming Soon | - | - | - |
| Nuxt | π Coming Soon | - | - | - |
| Solid.js | π Coming Soon | - | - | - |
| Astro | π Coming Soon | - | - | - |
| Framework | Platform | Status | Package | Documentation | Example |
|---|---|---|---|---|---|
| React Native | iOS β’ Android | π Coming Soon | - | - | - |
| Flutter | iOS β’ Android | π Coming Soon | - | - | - |
| Expo | iOS β’ Android | π Coming Soon | - | - | - |
| Ionic | iOS β’ Android β’ Web | π Coming Soon | - | - | - |
| Capacitor | iOS β’ Android β’ Web | π Coming Soon | - | - | - |
| .NET MAUI | iOS β’ Android β’ Windows β’ macOS | π Coming Soon | - | - | - |
- Seat selection
- Seat categorizing
- Locating
- Turnstile and Gate information
npm install @alisaitteke/seatmap-canvas|
Installation npm install @alisaitteke/seatmap-canvasSetup ( import { createApp } from 'vue';
import App from './App.vue';
import SeatmapCanvasPlugin from '@alisaitteke/seatmap-canvas/vue';
import '@alisaitteke/seatmap-canvas/dist/seatmap.canvas.css';
const app = createApp(App);
app.use(SeatmapCanvasPlugin);
app.mount('#app'); |
Component Usage <template>
<SeatmapCanvas
:options="seatmapOptions"
:data="blocks"
@seat-click="onSeatClick"
/>
</template>
<script setup lang="ts">
const seatmapOptions = {
legend: true,
style: {
seat: {
hover: '#8fe100',
selected: '#8fe100',
}
}
};
const onSeatClick = (seat) => {
seat.isSelected() ? seat.unSelect() : seat.select();
};
</script> |
|
Installation npm install @alisaitteke/seatmap-canvas |
Component Usage import { SeatmapCanvas } from '@alisaitteke/seatmap-canvas/react';
import '@alisaitteke/seatmap-canvas/dist/seatmap.canvas.css';
function App() {
const handleSeatClick = (seat) => {
seat.isSelected() ? seat.unSelect() : seat.select();
};
return (
<SeatmapCanvas
options={{
legend: true,
style: {
seat: { hover: '#8fe100', selected: '#8fe100' }
}
}}
data={blocks}
onSeatClick={handleSeatClick}
/>
);
} |
|
Quick Setup const config = {
resizable: true,
seat_style: {
radius: 12,
color: "#6796ff",
hover: "#5671ff",
selected: "#56aa45"
}
};
const seatmap = new SeatmapCanvas(".container", config);
seatmap.setData(data); |
Event Handling seatmap.addEventListener("seat_click", (seat) => {
if (seat.selected) {
seatmap.seatUnselect(seat);
} else {
seatmap.seatSelect(seat);
}
});
// Get selected seats
const selected = seatmap.getSelectedSeats(); |
π Data Models Reference
{
"id": 1,
"title": "49",
"x": 0,
"y": 0,
"salable": true,
"note": "note test",
"color":"#ffffff",
"custom_data": {
"any": "things"
}
}{
"blocks": [{
"id": 1,
"title": "Test Block 1",
"color": "#2c2828",
"labels": [{ "title": "A", "x": -30, "y": 0 }],
"seats": [
{ "id": 1, "x": 0, "y": 0, "salable": true, "title": "49" },
{ "id": 2, "x": 30, "y": 0, "salable": true, "title": "47" }
]
}]
}{
click_enable_sold_seats: true, // Enable clicking on unavailable seats (default: false)
// Global Background Image
background_image: "assets/stadium.jpg", // Image URL (PNG, JPG, SVG, WebP, GIF)
background_opacity: 0.3, // 0-1 (default: 0.3)
background_fit: "cover", // "cover" | "contain" | "fill" | "none"
background_x: 0, // Manual X position (optional, auto-detect if null)
background_y: 0, // Manual Y position (optional)
background_width: 1500, // Manual width (optional)
background_height: 1000 // Manual height (optional)
}πΌοΈ Custom Background Images
Add a background image to the entire stage:
const seatmap = new SeatmapCanvas(".container", {
background_image: "assets/concert-hall.jpg",
background_opacity: 0.3,
background_fit: "cover"
});With Manual Positioning:
const seatmap = new SeatmapCanvas(".container", {
background_image: "assets/stadium.jpg",
background_x: -500, // Position X
background_y: -500, // Position Y
background_width: 3000, // Width
background_height: 2500, // Height
background_opacity: 0.4,
background_fit: "contain" // Preserve aspect ratio
});Add custom backgrounds to individual blocks:
{
blocks: [{
id: "vip-section",
title: "VIP Area",
background_image: "assets/vip-lounge.jpg",
background_opacity: 0.6,
background_fit: "cover",
seats: [...]
}, {
id: "general",
title: "General Admission",
background_image: "assets/general-area.jpg",
background_opacity: 0.5,
seats: [...]
}]
}With Manual Positioning:
{
blocks: [{
id: "block-a",
background_image: "section-a.jpg",
background_x: 100, // Exact X coordinate
background_y: 200, // Exact Y coordinate
background_width: 500, // Exact width
background_height: 400, // Exact height
background_opacity: 0.7,
background_fit: "cover",
seats: [...]
}]
}cover(default) - Image covers entire area, may cropcontain- Image fits inside area, preserves aspect ratiofill- Image stretches to fill areanone- Image keeps original size, centered
- β Auto-Detection: X, Y, Width, Height auto-calculated from bounds if not specified
- β Clip-Path Masking: Block backgrounds clipped to exact block shape
- β Opacity Control: Adjustable transparency (0-1)
- β Auto-Hide Bounds: Block borders/fills hidden when background exists
- β Zoom Preserved: Bounds calculations still work for zoom levels
- β Format Support: PNG, JPG, SVG, WebP, GIF, all web-compatible formats
- β Performance: Browser-native image loading and caching
Stadium/Arena:
// Stadium overview as background
background_image: "stadium-aerial.jpg"Theater:
// Stage photo per seating section
blocks: [
{ id: "orchestra", background_image: "orchestra-view.jpg" },
{ id: "balcony", background_image: "balcony-view.jpg" }
]Restaurant:
// Floor plan as background
background_image: "floor-plan.png",
background_opacity: 0.5,
background_fit: "contain"Event Space:
// Custom venue layout
background_image: "venue-layout.svg",
background_fit: "contain"- Background images don't affect zoom calculations (bounds preserved)
- Block borders/fills automatically hidden when background assigned
- CORS: Images must be same-origin or CORS-enabled
- Performance: Use optimized images (< 500KB recommended)
- π Full Documentation
- π― Live Demo
- π¦ NPM Package
- π Report Issues
Contributions are welcome! Feel free to submit issues and pull requests.

