@wedeho/vue-table-map
v1.1.1
Published
A Vue 3 plugin for creating and displaying interactive table seating plans with drag-drop, zoom, pan, and multi-floor support
Maintainers
Readme
Vue Table Map
🪑 A Vue 3 plugin to create and display interactive table maps with drag-drop, zoom, pan and multi-floor support
✨ Features
- 🎯 Interactive table map creation - Add, move and resize tables
- 🔄 Multiple shapes - Rectangle, square and round
- 🪑 Chair configuration - Define the number and position of chairs per side
- 🔄 Table rotation - Free rotation from -180° to +180°
- 🏢 Multi-floor support - Manage multiple floors/levels (Ground floor, Floor 1, Basement, etc.)
- 🔍 Zoom and Pan - Smooth navigation with mouse wheel and drag to move the view
- 🎨 Customizable - Complete API with props, events, slots and exposed methods
- 📱 Responsive - Infinite canvas with horizontal and vertical scrolling
- 👀 Read-only mode - Display without editing capabilities
- 💾 Import/Export - JSON configuration to save and load your plans
📦 Installation
npm install @julienp/vue-table-map🚀 Basic Usage
Global Installation
import { createApp } from 'vue'
import VueTableMap from '@wedeho/vue-table-map'
import '@wedeho/vue-table-map/dist/style.css'
const app = createApp(App)
app.use(VueTableMap)
app.mount('#app')Direct Component Import
<script setup>
import { ref } from 'vue'
import { TableMapCanvas } from '@julienp/vue-table-map'
import '@wedeho/vue-table-map/dist/style.css'
const tables = ref([])
</script>
<template>
<TableMapCanvas
v-model="tables"
:readonly="false"
/>
</template>📖 Documentation
Props
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| modelValue | Array | [] | Tables to display (v-model) |
| initialTables | Array | [] | Initial tables (alternative to v-model) |
| readonly | Boolean | false | Read-only mode |
| width | Number | 1200 | Canvas width |
| height | Number | 800 | Canvas height |
| gridSize | Number | 20 | Grid size (snap) |
| showToolbar | Boolean | false | Show default toolbar |
| showZoomControls | Boolean | true | Show zoom controls |
| showFloorSelector | Boolean | true | Show floor selector |
| showInfoPanel | Boolean | false | Show information panel |
| showEditPanel | Boolean | true | Show edit panel |
| controlsPosition | String | 'top' | Controls position ('top' or 'bottom') |
| maxZoom | Number | 5 | Maximum zoom level |
| minZoom | Number | 0.1 | Minimum zoom level |
Note on responsiveness: The width and height props are used as default values, but the canvas automatically adapts to its container size (100% width and height). Use CSS to define the parent container dimensions.
Note on controls: Zoom and floor selection controls are positioned inside the canvas as floating elements, horizontally centered. Use the controlsPosition prop to place them at the top or bottom.
Events
| Event | Payload | Description |
|-------|---------|-------------|
| @update:modelValue | tables: Array | Emitted when tables change (v-model) |
| @table-added | table: Object | Emitted when a table is added |
| @table-updated | table: Object | Emitted when a table is modified |
| @table-removed | tableId: String | Emitted when a table is removed |
| @table-selected | table: Object | Emitted when a table is selected |
| @table-click | { table, event } | Emitted when a table is clicked (readonly) |
| @floor-changed | floor: Number | Emitted when the floor changes |
Exposed Methods (via ref)
<script setup>
import { ref } from 'vue'
const canvasRef = ref(null)
// Add a table
const addTable = () => {
canvasRef.value?.addTable('rectangle')
}
// Remove the selected table
const removeTable = () => {
canvasRef.value?.removeTable()
}
// Get all tables
const getTables = () => {
return canvasRef.value?.getTables()
}
</script>
<template>
<TableMapCanvas ref="canvasRef" />
</template>List of Methods
addTable(shape)- Add a table ('rectangle', 'square', 'round')removeTable()- Remove the selected tableupdateTable(updates)- Update the selected tableselectTable(tableId)- Select a tabledeselectTable()- Deselect the current tablesetFloor(floor)- Change floorclearTables()- Remove all tablesclearCurrentFloor()- Remove tables from the current floorexportTables()- Export configurationimportTables(data)- Import a configurationgetTables()- Get all tablesgetSelectedTable()- Get the selected tablegetCurrentFloor()- Get the current floorzoomIn()- Zoom inzoomOut()- Zoom outresetZoom()- Reset zoom
Slots
Customize the interface with available slots:
table-content
Customize the content displayed in each table:
<TableMapCanvas v-model="tables">
<template #table-content="{ table, index }">
<div style="text-align: center;">
<strong>{{ table.name }}</strong>
<div>{{ table.seats }} seats</div>
</div>
</template>
</TableMapCanvas>toolbar
Replace the default toolbar:
<TableMapCanvas :show-toolbar="true">
<template #toolbar="{ addTable, deleteSelected }">
<button @click="addTable('rectangle')">Add Table</button>
<button @click="deleteSelected">Delete</button>
</template>
</TableMapCanvas>Other Available Slots
zoom-controls- Custom zoom controlsfloor-selector- Custom floor selectorinfo-panel- Custom information panel
Table Structure
{
id: 'unique-id',
name: 'Table 1',
shape: 'rectangle', // 'rectangle' | 'square' | 'round'
x: 100,
y: 100,
width: 140,
height: 80,
seats: 6,
rotation: 0, // -180 to 180
floor: 0, // 0 = Ground floor, 1+ = Floors, -1- = Basements
chairLayoutTop: 2, // For rectangle/square
chairLayoutRight: 1,
chairLayoutBottom: 2,
chairLayoutLeft: 1
}💡 Examples
Example 1: Custom Interface
<script setup>
import { ref } from 'vue'
import { TableMapCanvas } from '@julienp/vue-table-map'
const canvasRef = ref(null)
const tables = ref([])
const addRectangle = () => canvasRef.value?.addTable('rectangle')
const addRound = () => canvasRef.value?.addTable('round')
const deleteTable = () => canvasRef.value?.removeTable()
const exportPlan = () => {
const data = canvasRef.value?.exportTables()
console.log('Export:', data)
}
</script>
<template>
<div>
<div class="toolbar">
<button @click="addRectangle">➕ Rectangle</button>
<button @click="addRound">➕ Round</button>
<button @click="deleteTable">🗑️ Delete</button>
<button @click="exportPlan">💾 Export</button>
</div>
<TableMapCanvas
ref="canvasRef"
v-model="tables"
:show-toolbar="false"
:show-edit-panel="false"
@table-selected="table => console.log('Selected:', table)"
/>
</div>
</template>Example 2: Read-only Mode with Custom Content
<script setup>
import { ref } from 'vue'
import { TableMapCanvas } from '@julienp/vue-table-map'
const tables = ref([
{
id: '1',
name: 'VIP Table',
shape: 'round',
x: 200,
y: 200,
width: 120,
height: 120,
seats: 8,
floor: 0,
isVip: true
}
])
const handleTableClick = ({ table }) => {
alert(`Table: ${table.name}\nSeats: ${table.seats}`)
}
</script>
<template>
<TableMapCanvas
v-model="tables"
:readonly="true"
@table-click="handleTableClick"
>
<template #table-content="{ table }">
<div style="text-align: center; color: #1e293b;">
<div style="font-weight: bold; font-size: 14px;">
{{ table.name }}
</div>
<div style="font-size: 12px; color: #64748b;">
{{ table.seats }} seats
</div>
<div v-if="table.isVip" style="color: gold; font-size: 16px;">
⭐
</div>
</div>
</template>
</TableMapCanvas>
</template>Example 3: Multi-floor with Initial Data
<script setup>
import { ref } from 'vue'
import { TableMapCanvas } from '@julienp/vue-table-map'
const tables = ref([
// Ground floor
{
id: '1',
name: 'Table 1',
shape: 'rectangle',
x: 150,
y: 150,
width: 140,
height: 80,
seats: 6,
floor: 0,
chairLayoutTop: 2,
chairLayoutRight: 1,
chairLayoutBottom: 2,
chairLayoutLeft: 1
},
// Floor 1
{
id: '2',
name: 'Table 2',
shape: 'round',
x: 200,
y: 200,
width: 100,
height: 100,
seats: 6,
floor: 1
}
])
const handleFloorChange = (floor) => {
console.log('Active floor:', floor)
}
</script>
<template>
<TableMapCanvas
v-model="tables"
@floor-changed="handleFloorChange"
/>
</template>🎮 Controls
Edit Mode
- Move a table: Click and drag
- Resize: Use the handles on corners and edges
- Select: Click on a table
- Zoom: Mouse wheel or +/- buttons
- Pan: Drag the background (when no table selected) or Shift+Drag
- Edit: Double-click or "Edit" button when selected
Read-only Mode
- Zoom: Mouse wheel
- Pan: Click and drag
- Table click:
@table-clickevent
🎨 Style Customization
The plugin uses scoped CSS. You can override styles if needed:
/* Customize tables */
.table-element {
/* your styles */
}
/* Customize chairs */
.chair-element {
/* your styles */
}🛠️ Development
# Install dependencies
npm install
# Development with Hot Module Replacement
npm run dev
# Build library
npm run build:lib
# Build demo
npm run build
npm publish --access public📝 License
MIT © Julien PARDONS / Wedeho
🤝 Contributing
Contributions are welcome! Feel free to open an issue or pull request.
🐛 Support
To report a bug or request a feature, please create an issue.
