Vue.js plugin for Seatmap Canvas, an advanced interactive seat selection library.
npm install @alisaitteke/seatmap-canvasRegister the plugin globally in your Vue app:
// main.ts or main.js
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, {
// Optional: Global default options
defaultOptions: {
legend: true,
style: {
seat: {
hover: '#8fe100',
color: '#f0f7fa',
selected: '#8fe100',
}
}
}
});
app.mount('#app');<template>
<div class="seatmap-container">
<SeatmapCanvas
:options="seatmapOptions"
:data="seatmapData"
@ready="onSeatmapReady"
@seat-click="onSeatClick"
container-class="w-full h-full"
:container-style="{ minHeight: '600px' }"
/>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import type { SeatmapOptions, BlockData } from '@alisaitteke/seatmap-canvas/vue';
const seatmapOptions = ref<SeatmapOptions>({
legend: true,
style: {
seat: {
hover: '#8fe100',
color: '#f0f7fa',
selected: '#8fe100',
check_icon_color: '#fff',
not_salable: '#0088d3',
focus: '#8fe100',
},
legend: {
font_color: '#3b3b3b',
show: false
},
block: {
title_color: '#fff'
}
}
});
const seatmapData = ref<BlockData[]>([
{
id: 'block-1',
title: 'Block A',
color: '#01a5ff',
seats: [
{
id: 'seat-1',
x: 50,
y: 50,
salable: true,
title: 'A1',
custom_data: {
price: 50,
row: 1,
seat: 1
}
},
// Add more seats...
]
}
]);
const onSeatmapReady = (instance: any) => {
console.log('Seatmap ready!', instance);
};
const onSeatClick = (seat: any) => {
if (!seat.isSelected() && seat.item.salable === true) {
seat.select();
} else {
seat.unSelect();
}
};
</script>
<style scoped>
.seatmap-container {
width: 100%;
height: 600px;
position: relative;
}
</style>For more control, use the useSeatmap composable:
<template>
<div>
<div ref="containerRef" class="seatmap-container"></div>
<div class="controls">
<button @click="zoomToVenue">Zoom to Venue</button>
<button @click="zoomToBlock('block-1')">Zoom to Block 1</button>
<div>Selected Seats: {{ selectedSeats.length }}</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue';
import { useSeatmap } from '@alisaitteke/seatmap-canvas/vue';
const containerRef = ref<HTMLElement | null>(null);
const {
seatmapInstance,
isReady,
selectedSeats,
init,
loadData,
zoomToBlock,
zoomToVenue,
addEventListener
} = useSeatmap();
onMounted(() => {
if (containerRef.value) {
init(containerRef.value, {
legend: true,
style: {
seat: {
hover: '#8fe100',
color: '#f0f7fa',
selected: '#8fe100',
}
}
});
// Load data
loadData([
{
id: 'block-1',
title: 'Block A',
color: '#01a5ff',
seats: [
{
id: 'seat-1',
x: 50,
y: 50,
salable: true,
title: 'A1'
}
]
}
]);
// Add event listeners
addEventListener('SEAT.CLICK', (seat: any) => {
console.log('Seat clicked:', seat);
if (seat.item.salable) {
if (!seat.isSelected()) {
seat.select();
} else {
seat.unSelect();
}
}
});
}
});
</script>
<style scoped>
.seatmap-container {
width: 100%;
height: 600px;
}
.controls {
margin-top: 1rem;
display: flex;
gap: 1rem;
align-items: center;
}
</style>If you don't want to register globally:
<script setup lang="ts">
import { SeatmapCanvas } from '@alisaitteke/seatmap-canvas/vue';
import '@alisaitteke/seatmap-canvas/dist/seatmap.canvas.css';
</script>
<template>
<SeatmapCanvas :options="options" :data="data" />
</template>| Prop | Type | Default | Description |
|---|---|---|---|
options |
SeatmapOptions |
{} |
Seatmap configuration options |
data |
BlockData[] |
[] |
Array of blocks with seats |
containerClass |
string |
'' |
CSS class for container |
containerStyle |
object |
{} |
Inline styles for container |
autoZoomToVenue |
boolean |
true |
Auto zoom to venue after data load |
| Event | Payload | Description |
|---|---|---|
ready |
SeatMapCanvas |
Fired when seatmap is initialized |
seatClick |
Seat |
Fired when a seat is clicked |
seatSelect |
Seat |
Fired when a seat is selected |
seatUnselect |
Seat |
Fired when a seat is unselected |
blockClick |
Block |
Fired when a block is clicked |
dataChange |
BlockData[] |
Fired when data changes |
| Method | Parameters | Return | Description |
|---|---|---|---|
init |
container, options |
void |
Initialize seatmap |
loadData |
data: BlockData[] |
void |
Load seat data |
getSelectedSeats |
- | Seat[] |
Get all selected seats |
getSeat |
seatId, blockId |
Seat |
Get specific seat |
getBlocks |
- | Block[] |
Get all blocks |
zoomToBlock |
blockId: string |
void |
Zoom to specific block |
zoomToVenue |
- | void |
Zoom out to venue view |
addEventListener |
event, callback |
void |
Add event listener |
destroy |
- | void |
Cleanup instance |
This plugin is written in TypeScript and includes full type definitions.
import type {
SeatmapOptions,
BlockData,
SeatData,
SeatClickEvent
} from '@alisaitteke/seatmap-canvas/vue';Check the /examples/vue directory for complete examples:
- Basic seat selection
- Custom styling
- Dynamic data loading
- Event handling
- Zoom controls
<template>
<SeatmapCanvas :options="options" :data="blocks" />
</template>
<script setup lang="ts">
import { ref } from 'vue';
const options = ref({
style: {
seat: {
shape: "rect", // circle | rect | path | svg
size: 24,
corner_radius: 6,
color: "#6796ff",
hover: "#5671ff",
selected: "#56aa45"
}
}
});
</script>Circle (Default)
options: {
style: { seat: { shape: "circle", radius: 12 } }
}Rectangle
options: {
style: { seat: { shape: "rect", size: 24, corner_radius: 4 } }
}Custom Path
options: {
style: {
seat: {
shape: "path",
path: "M12 0L24 12L12 24L0 12Z", // Diamond
path_box: "0 0 24 24",
size: 24
}
}
}External SVG
options: {
style: {
seat: {
shape: "svg",
svg: "/assets/custom-seat.svg",
radius: 12
}
}
}Option 1: Extract Path from SVG
- Open your SVG in a text editor
- Find the
<path d="...">element - Copy the path data and viewBox:
<script setup lang="ts">
const options = ref({
style: {
seat: {
shape: "path",
path: "M12 21.35l-1.45-1.32C5.4 15.36...", // from d attribute
path_box: "0 0 24 24", // from viewBox attribute
size: 24
}
}
});
</script>Option 2: Use SVG File Directly
Place SVG in your public folder and reference it:
<script setup lang="ts">
const options = ref({
style: {
seat: {
shape: "svg",
svg: "/icons/custom-seat.svg",
radius: 12
}
}
});
</script>Supported SVG Elements:
<path>- Used directly<polygon>,<polyline>- Auto-converted to path<rect>,<circle>- Auto-converted to path- Multiple paths - Automatically combined
Best Practices:
- Use square viewBox (e.g., "0 0 24 24") for consistent sizing
- Keep SVG simple (< 10KB) for better performance
- Use monochrome SVGs (fill color controlled by library)
- Export from design tools with "Outline Stroke" option
// Triangle
{ shape: "path", path: "M12 0L24 24H0Z", path_box: "0 0 24 24" }
// Diamond
{ shape: "path", path: "M12 0L24 12L12 24L0 12Z", path_box: "0 0 24 24" }
// Star
{ shape: "path", path: "M12 0L15 9L24 9L17 15L20 24L12 18L4 24L7 15L0 9L9 9Z", path_box: "0 0 24 24" }<script setup lang="ts">
const options = ref({
style: {
tooltip: {
bg: "#ffffff",
color: "#1f2937",
border_radius: 10,
padding: 14,
font_size: "14px",
font_weight: "600",
line_height: 20,
shadow: "0 8px 24px rgba(0,0,0,0.2)",
text_align: "center",
width: 160
// Height auto-adjusts to content
}
}
});
</script>Features:
- Auto-sizing height based on content
- Centered text alignment
- Modern shadow effects
- Configurable padding and spacing
- Custom fonts and colors
MIT - Copyright (c) 2024 Ali Sait TEKE