ngx-venue-map
Version:
Interactive venue seating map component for Angular applications
400 lines (321 loc) • 11.2 kB
Markdown
# 🏟️ ngx-venue-map
<div align="center">
**Interactive venue seating map component for Angular applications**
*Perfect for sports venues, concert halls, theaters, and event booking platforms*
</div>
### If you like this project, ☕ [buy me a coffee](https://buymeacoffee.com/vvtrung)
## ✨ Features
- 🔍 **Zoom & Pan** - Smooth zooming and panning with mini-map navigation
- 🎨 **Customizable Themes** - Built-in themes and full customization support
- 🏷️ **Grade-based Pricing** - Support for different seating categories and pricing
- 🎪 **Multiple Venue Types** - Stadiums, theaters, concert halls, and more
- 🔧 **TypeScript Support** - Fully typed with comprehensive interfaces
- 📦 **Tree-shakable** - Import only what you need
- 🎭 **Event Handling** - Rich event system for seat selection and interaction
## 🚀 Quick Start
### Installation
```bash
npm install ngx-venue-map
```
### Basic Usage
```typescript
// app.component.ts
import { Component } from '@angular/core';
import { VenueMapComponent, Grade, MapConfiguration } from 'ngx-venue-map';
@Component({
selector: 'app-root',
standalone: true,
imports: [VenueMapComponent],
template: `
<app-venue-map
[grades]="grades"
[mapConfiguration]="mapConfig"
(selectGrade)="onGradeSelected($event)"
/>
`
})
export class AppComponent {
grades: Grade[] = [
{
id: '1',
name: 'VIP Section',
abbreviation: 'VIP',
price: 150,
disabled: false,
settings: [
{
color: '#FFD700',
circle: { x: 400, y: 300, textColor: '#000' },
points: [
{ x: 350, y: 250 },
{ x: 450, y: 250 },
{ x: 450, y: 350 },
{ x: 350, y: 350 }
]
}
]
},
{
id: '2',
name: 'Premium Section',
abbreviation: 'PRM',
price: 100,
disabled: false,
settings: [
{
color: '#C0C0C0',
circle: { x: 600, y: 300, textColor: '#000' },
points: [
{ x: 550, y: 250 },
{ x: 650, y: 250 },
{ x: 650, y: 350 },
{ x: 550, y: 350 }
]
}
]
}
];
mapConfig: MapConfiguration = {
path: '/assets/venue-map.png',
width: 1600,
height: 1200,
offsetHeight: 106,
fontSize: 20,
// Configuration will be merged with defaults
};
onGradeSelected(event: { grade: Grade, shapeIndex?: number }) {
console.log('Selected grade:', event.grade);
console.log('Shape index:', event.shapeIndex);
}
}
```
## 🗂️ Multi-Image Support
The venue map component supports both single images and multi-part images for large or high-resolution maps.
### Single Image Configuration
```typescript
const singleImageConfig: MapConfiguration = {
path: '/assets/venue-map.png', // Single image path
width: 1600,
height: 1200
};
```
### Multi-Image Configuration
For large maps that need to be split into multiple parts, use an array of image paths with the naming pattern `col_row.ext`:
```typescript
const multiImageConfig: MapConfiguration = {
path: [
'/assets/map/parts/0_0.png', // Top-left
'/assets/map/parts/0_1.png', // Bottom-left
'/assets/map/parts/1_0.png', // Top-right
'/assets/map/parts/1_1.png' // Bottom-right
],
width: 1600, // Total width of combined image
height: 1200 // Total height of combined image
};
```
### File Naming Convention
Multi-part images must follow the pattern `{col}_{row}.{extension}`:
- `0_0.png` - Column 0, Row 0 (top-left)
- `0_1.png` - Column 0, Row 1 (bottom-left)
- `1_0.png` - Column 1, Row 0 (top-right)
- `1_1.png` - Column 1, Row 1 (bottom-right)
## 📷 Example Venue Map



## 📖 API Reference
### Component Selector
```typescript
<app-venue-map></app-venue-map>
```
### Inputs
| Property | Type | Default | Description |
|----------|------|---------|-------------|
| `grades` | `Grade[]` | `[]` | Array of seating grades/categories with their visual settings |
| `mapConfiguration` | `Partial<MapConfiguration> & Pick<MapConfiguration, 'width' \| 'height' \| 'path'>` | `DEFAULT_MAP_CONFIG` | Map display and behavior configuration |
| `theme` | `Partial<StadiumMapTheme>` | `DEFAULT_STADIUM_MAP_THEME` | Visual theme for the map |
| `reloadMap` | `boolean` | `true` | Whether to reload the map when inputs change |
| `focusedGradePart` | `FocusedGradePart` | `undefined` | Specific grade part to focus on |
### Outputs
| Event | Type | Description |
|-------|------|-------------|
| `selectGrade` | `{ grade: Grade, shapeIndex?: number }` | Emitted when a grade section is selected |
### Core Types
```typescript
interface Grade {
id: string; // Unique identifier for the grade
name: string; // Display name of the grade
abbreviation: string; // Short abbreviation (displayed on map)
price: number; // Price for this grade
disabled: boolean; // Whether this grade is selectable
settings: GradeSetting[]; // Visual settings for grade areas
}
interface GradeSetting {
color: string; // Fill color for the grade area
circle: { // Circle marker configuration
x: number; // X coordinate for circle center
y: number; // Y coordinate for circle center
textColor: string; // Text color for abbreviation
};
points: Point[]; // Polygon points defining the grade area
}
interface Point {
x: number; // X coordinate
y: number; // Y coordinate
}
interface MapConfiguration {
// Required properties
path: string | string[]; // Path to venue map image (single) or array of paths (multi-part)
width: number; // Map width in pixels
height: number; // Map height in pixels
// Optional properties (will use defaults if not provided)
offsetHeight?: number; // Vertical offset (default: 106)
fontSize?: number; // Text size (default: 20)
// Shape configurations
bubble?: SizeShape; // Price bubble configuration
corner?: SizeShape; // Corner marker configuration
arrow?: SizeShape; // Arrow indicator configuration
circle?: SizeShape; // Circle marker configuration
// Interaction configurations
zoom?: ZoomConfiguration; // Zoom behavior settings
minimap?: MiniMapConfiguration; // Mini-map settings
}
interface StadiumMapTheme {
// Canvas colors
canvasBackgroundColor: string;
// Grade visualization
gradeStrokeColor: string;
gradeTextColor: string;
// Price display
priceBackgroundColor: string;
priceTextColor: string;
priceBubbleStrokeColor: string;
// Interactive elements
miniMapViewportColor: string;
// Seat states
availableSeatColor: string;
unavailableSeatColor: string;
selectedSeatColor: string;
selectedSeatBorderColor: string;
availableSeatBorderColor: string;
disabledSeatColor: string;
// Special seat types
premiumSeatColor: string;
premiumSeatHoverColor: string;
goldSeatColor: string;
// UI elements
shadowColor: string;
darkTextColor: string;
}
```
## 🎨 Customization
### Custom Themes
```typescript
const customTheme: Partial<StadiumMapTheme> = {
canvasBackgroundColor: '#1a1a1a',
gradeStrokeColor: '#ffffff',
gradeTextColor: '#ffffff',
priceBackgroundColor: '#333333',
priceTextColor: '#ffffff',
selectedSeatColor: '#ff6b35',
selectedSeatBorderColor: '#ff6b35',
miniMapViewportColor: '#ff6b35'
};
// Apply to component
<app-venue-map [theme]="customTheme" [grades]="grades" [mapConfiguration]="mapConfig" />
```
### Advanced Configuration
```typescript
const advancedConfig: MapConfiguration = {
path: '/assets/my-venue.png',
width: 1920,
height: 1080,
offsetHeight: 120,
fontSize: 16,
zoom: {
min: 1,
max: 3.0,
step: 0.2,
showMiniMapAtLevel: 1.5
},
minimap: {
scale: 0.15,
opacity: 0.7
},
bubble: {
width: 140,
height: 45,
stroke: 2,
cornerRadius: 8,
padding: 8,
offsetLeft: 0,
offsetTop: -50
},
circle: {
width: 60,
height: 60,
stroke: 3,
padding: 12,
offsetLeft: 0,
offsetTop: 0,
cornerRadius: 0
}
};
```
### Integration in Your Project
1. **Import the component**:
```typescript
import { VenueMapComponent } from 'ngx-venue-map';
```
2. **Add to your module or standalone component**:
```typescript
@Component({
// ...
imports: [VenueMapComponent], // For standalone components
// ...
})
```
3. **Prepare your venue map image**:
- Place your venue/venue map image in your `public` or `assets` folder
- Ensure the image has good resolution (recommended: 1600x1200 or higher)
- Supported formats: PNG, JPG, SVG
4. **Define your seating grades**:
- Map out the coordinate points for each seating area
- Choose appropriate colors for each grade
- Set pricing and availability
## 📦 Bundle Information
- **Dependencies**:
- Angular 20+
- fabric.js 5.3.0+
- lodash-es 4.17+
- uuid 9.0+
- **Peer Dependencies**: `@angular/common`, `@angular/core`
- **Tree-shakable**: Yes
- **Side Effects**: None
## 🌐 Browser Support
| Chrome | Firefox | Safari | Edge | IE |
|--------|---------|--------|------|-----|
| ✅ 80+ | ✅ 75+ | ✅ 13+ | ✅ 80+ | ❌ |
**Note**: This library uses modern Canvas APIs and ES6+ features. For older browser support, ensure proper polyfills are included.
## 🤝 Contributing
We welcome contributions! Please follow these steps:
1. Fork the repository
2. Create a feature branch: `git checkout -b feature/amazing-feature`
3. Make your changes and add tests
4. Commit your changes: `git commit -m 'Add amazing feature'`
5. Push to the branch: `git push origin feature/amazing-feature`
6. Open a Pull Request
## 📄 License
This project is licensed under the MIT License - see the [LICENSE](https://raw.githubusercontent.com/vvtrung/angular-venue-map/refs/heads/main/projects/ngx-venue-map/LICENSE) file for details.
## 🙏 Acknowledgments
- Built with [Angular](https://angular.io/) 20+
- Canvas rendering powered by [Fabric.js](http://fabricjs.com/)
- Utility functions from [Lodash](https://lodash.com/)
- TypeScript support throughout
## 📞 Support & Community
- 🐛 **Issues**: [GitHub Issues](https://github.com/vvtrung/angular-venue-map/issues)
- 💬 **Discussions**: [GitHub Discussions](https://github.com/vvtrung/angular-venue-map/discussions)
<div align="center">
**Made with ❤️ for the Angular community**
If you find this library useful, please consider giving it a ⭐ on GitHub!
</div>