mirror of
https://github.com/Dvorinka/MyClubServer.git
synced 2026-06-04 02:32:57 +00:00
469 lines
11 KiB
Markdown
469 lines
11 KiB
Markdown
# Vector Maps Implementation with MapLibre GL JS & OpenMapTiles
|
|
|
|
## 🚀 Overview
|
|
|
|
This implementation uses **MapLibre GL JS** (open-source) with **OpenMapTiles** vector tiles to provide:
|
|
- **Better performance** - Vector tiles are smaller and faster
|
|
- **Sharp rendering** - Perfect on Retina/HiDPI displays
|
|
- **Dynamic styling** - Change colors and styles at runtime
|
|
- **Club color integration** - Automatic application of club colors to map elements
|
|
- **Custom style support** - Full control via Mapbox GL Style JSON
|
|
|
|
## 📦 What Was Added
|
|
|
|
### New Files
|
|
- `frontend/src/components/home/VectorMap.tsx` - Main vector map component
|
|
- `frontend/src/components/admin/VectorMapStyleSelector.tsx` - Admin UI for vector maps
|
|
- `VECTOR_MAPS_IMPLEMENTATION.md` - This documentation
|
|
|
|
### Dependencies Added
|
|
```json
|
|
{
|
|
"maplibre-gl": "^4.x.x",
|
|
"@types/maplibre-gl": "^4.x.x"
|
|
}
|
|
```
|
|
|
|
## 🎨 Features
|
|
|
|
### 1. Vector Map Styles
|
|
|
|
Four professional styles from MapTiler (based on OpenMapTiles):
|
|
|
|
| Style | Description | Best For |
|
|
|-------|-------------|----------|
|
|
| **Positron** | Clean light style | Data visualization, colored overlays |
|
|
| **Dark Matter** | Sleek dark theme | Modern interfaces, night mode |
|
|
| **OSM Bright** | Colorful OSM style | General purpose, vibrant look |
|
|
| **Basic** | Simple clean base | Minimal, professional |
|
|
|
|
### 2. Dynamic Club Color Integration
|
|
|
|
The vector map automatically applies your club colors to:
|
|
- **Marker pins** - Colored with primary club color
|
|
- **Water features** - Tinted with club color (subtle)
|
|
- **Custom elements** - Can be extended via style JSON
|
|
|
|
### 3. Custom Style Support
|
|
|
|
Advanced users can provide custom Mapbox GL Style JSON:
|
|
|
|
```typescript
|
|
<VectorMap
|
|
customStyleUrl="https://your-server.com/custom-style.json"
|
|
clubPrimaryColor="#e11d48"
|
|
// ... other props
|
|
/>
|
|
```
|
|
|
|
## 🛠️ Technical Details
|
|
|
|
### MapLibre GL JS
|
|
|
|
**Why MapLibre?**
|
|
- ✅ Open-source fork of Mapbox GL JS
|
|
- ✅ No vendor lock-in
|
|
- ✅ Free for all uses
|
|
- ✅ Active community development
|
|
- ✅ Compatible with Mapbox styles
|
|
|
|
### OpenMapTiles
|
|
|
|
**Data Source:**
|
|
- Vector tiles from MapTiler API (free tier available)
|
|
- Based on OpenStreetMap data
|
|
- Updated regularly
|
|
- Global coverage
|
|
|
|
**Performance:**
|
|
- Vector tiles are ~75% smaller than raster tiles
|
|
- Smooth zooming and rotation
|
|
- Client-side rendering
|
|
- GPU acceleration
|
|
|
|
## 📋 Usage
|
|
|
|
### Basic Usage
|
|
|
|
```typescript
|
|
import VectorMap from '../components/home/VectorMap';
|
|
|
|
<VectorMap
|
|
latitude={50.0755}
|
|
longitude={14.4378}
|
|
zoom={15}
|
|
clubName="FK Example"
|
|
address="Example Street 123, Prague"
|
|
mapStyle="positron"
|
|
clubPrimaryColor="#e11d48"
|
|
clubSecondaryColor="#3b82f6"
|
|
/>
|
|
```
|
|
|
|
### Props
|
|
|
|
```typescript
|
|
interface VectorMapProps {
|
|
latitude: number; // Required
|
|
longitude: number; // Required
|
|
zoom?: number; // Default: 15
|
|
address?: string; // Optional popup content
|
|
clubName?: string; // Optional popup content
|
|
mapStyle?: 'positron' | 'dark-matter' | 'osm-bright' | 'klokantech-basic';
|
|
height?: number; // Default: 400
|
|
clubPrimaryColor?: string; // Hex color for marker
|
|
clubSecondaryColor?: string; // Secondary color
|
|
customStyleUrl?: string; // Custom Mapbox GL Style JSON URL
|
|
}
|
|
```
|
|
|
|
## 🔑 API Key Setup
|
|
|
|
### For Development
|
|
The component includes a demo API key for testing.
|
|
|
|
### For Production
|
|
|
|
1. **Get a free API key** from [MapTiler](https://www.maptiler.com/)
|
|
- Sign up (free tier: 100,000 tile requests/month)
|
|
- Copy your API key
|
|
|
|
2. **Add to environment:**
|
|
|
|
Create/edit `.env` file:
|
|
```bash
|
|
REACT_APP_MAPTILER_KEY=your_api_key_here
|
|
```
|
|
|
|
3. **Rebuild the app:**
|
|
```bash
|
|
npm run build
|
|
```
|
|
|
|
## 🎨 Custom Styling
|
|
|
|
### Method 1: Modify Built-in Styles
|
|
|
|
Edit `VectorMap.tsx` and customize the `createCustomPositronStyle` function:
|
|
|
|
```typescript
|
|
const createCustomPositronStyle = (primaryColor?: string, secondaryColor?: string): any => {
|
|
return {
|
|
version: 8,
|
|
name: 'Custom Style',
|
|
sources: { /* ... */ },
|
|
layers: [
|
|
// Add/modify layers here
|
|
{
|
|
id: 'water',
|
|
type: 'fill',
|
|
paint: {
|
|
'fill-color': yourCustomColor
|
|
}
|
|
}
|
|
]
|
|
};
|
|
};
|
|
```
|
|
|
|
### Method 2: External Style JSON
|
|
|
|
Host your custom style JSON and reference it:
|
|
|
|
```typescript
|
|
<VectorMap
|
|
customStyleUrl="https://your-cdn.com/custom-positron.json"
|
|
/>
|
|
```
|
|
|
|
**Style JSON structure** (based on [Mapbox GL Style Spec](https://docs.mapbox.com/mapbox-gl-js/style-spec/)):
|
|
|
|
```json
|
|
{
|
|
"version": 8,
|
|
"name": "Custom Style",
|
|
"sources": {
|
|
"openmaptiles": {
|
|
"type": "vector",
|
|
"url": "https://api.maptiler.com/tiles/v3/tiles.json?key=YOUR_KEY"
|
|
}
|
|
},
|
|
"layers": [
|
|
{
|
|
"id": "background",
|
|
"type": "background",
|
|
"paint": { "background-color": "#f8f8f8" }
|
|
},
|
|
{
|
|
"id": "water",
|
|
"type": "fill",
|
|
"source": "openmaptiles",
|
|
"source-layer": "water",
|
|
"paint": { "fill-color": "#your-color" }
|
|
}
|
|
// ... more layers
|
|
]
|
|
}
|
|
```
|
|
|
|
### Method 3: Fork Positron GL Style
|
|
|
|
1. Clone the repository:
|
|
```bash
|
|
git clone https://github.com/openmaptiles/positron-gl-style.git
|
|
```
|
|
|
|
2. Customize `style.json`
|
|
|
|
3. Host on your server or CDN
|
|
|
|
4. Reference in your app
|
|
|
|
## 🎯 Integration with Existing System
|
|
|
|
### Option 1: Replace Existing Maps
|
|
|
|
Update imports in your components:
|
|
|
|
```typescript
|
|
// Old
|
|
import ContactMap from '../components/home/ContactMap';
|
|
|
|
// New
|
|
import VectorMap from '../components/home/VectorMap';
|
|
|
|
// Usage stays similar
|
|
<VectorMap
|
|
latitude={lat}
|
|
longitude={lng}
|
|
clubPrimaryColor={settings.primary_color}
|
|
// ... same props
|
|
/>
|
|
```
|
|
|
|
### Option 2: Toggle Between Raster/Vector
|
|
|
|
Create a wrapper component:
|
|
|
|
```typescript
|
|
const AdaptiveMap: React.FC<MapProps> = (props) => {
|
|
const useVector = settings.use_vector_maps; // from settings
|
|
|
|
return useVector
|
|
? <VectorMap {...props} />
|
|
: <ContactMap {...props} />;
|
|
};
|
|
```
|
|
|
|
## 📊 Performance Comparison
|
|
|
|
### Vector Maps (MapLibre GL)
|
|
- **Initial Load:** 150-200 KB (tiles + library)
|
|
- **Per Zoom:** 20-50 KB (vector tiles)
|
|
- **Rendering:** GPU-accelerated
|
|
- **Zoom Quality:** Always sharp
|
|
- **Customization:** Full runtime control
|
|
|
|
### Raster Maps (Leaflet)
|
|
- **Initial Load:** 100 KB (library only)
|
|
- **Per Zoom:** 100-200 KB (PNG tiles)
|
|
- **Rendering:** Image-based
|
|
- **Zoom Quality:** Pixelated between levels
|
|
- **Customization:** Limited to tile source
|
|
|
|
**Verdict:** Vector maps are faster after initial load and provide better visual quality.
|
|
|
|
## 🌍 Self-Hosting Tiles (Advanced)
|
|
|
|
For complete independence from third-party services:
|
|
|
|
### 1. Set Up OpenMapTiles Server
|
|
|
|
```bash
|
|
# Clone OpenMapTiles
|
|
git clone https://github.com/openmaptiles/openmaptiles.git
|
|
cd openmaptiles
|
|
|
|
# Generate tiles for your region
|
|
./quickstart.sh czech-republic
|
|
|
|
# Start tile server
|
|
docker-compose up -d
|
|
```
|
|
|
|
### 2. Update VectorMap Component
|
|
|
|
```typescript
|
|
const TILE_SERVER = 'http://your-server.com';
|
|
|
|
sources: {
|
|
'openmaptiles': {
|
|
type: 'vector',
|
|
url: `${TILE_SERVER}/tiles.json`
|
|
}
|
|
}
|
|
```
|
|
|
|
### Benefits of Self-Hosting:
|
|
- ✅ No API key required
|
|
- ✅ No request limits
|
|
- ✅ Full data control
|
|
- ✅ Offline capability
|
|
- ❌ Requires server maintenance
|
|
|
|
## 🎨 Club Color Examples
|
|
|
|
### Red Club (e.g., Slavia Prague)
|
|
```typescript
|
|
<VectorMap
|
|
mapStyle="positron"
|
|
clubPrimaryColor="#e11d48"
|
|
clubSecondaryColor="#ffffff"
|
|
/>
|
|
```
|
|
Result: Red markers on light map, subtle red tint on water
|
|
|
|
### Blue Club (e.g., Slovan Liberec)
|
|
```typescript
|
|
<VectorMap
|
|
mapStyle="dark-matter"
|
|
clubPrimaryColor="#3b82f6"
|
|
clubSecondaryColor="#60a5fa"
|
|
/>
|
|
```
|
|
Result: Blue markers on dark map, modern look
|
|
|
|
### Green Club
|
|
```typescript
|
|
<VectorMap
|
|
mapStyle="osm-bright"
|
|
clubPrimaryColor="#16a34a"
|
|
clubSecondaryColor="#fbbf24"
|
|
/>
|
|
```
|
|
Result: Green markers on colorful map
|
|
|
|
## 🐛 Troubleshooting
|
|
|
|
### Map Not Loading
|
|
|
|
**Check browser console for errors:**
|
|
|
|
1. **API Key Issue:**
|
|
```
|
|
Error: HTTP 403 - Unauthorized
|
|
```
|
|
Solution: Add valid `REACT_APP_MAPTILER_KEY` to `.env`
|
|
|
|
2. **Network Error:**
|
|
```
|
|
Error: Failed to fetch tiles
|
|
```
|
|
Solution: Check internet connection, firewall settings
|
|
|
|
3. **Style Loading Error:**
|
|
```
|
|
Error: Failed to parse style
|
|
```
|
|
Solution: Validate your custom style JSON
|
|
|
|
### Blank Map
|
|
|
|
- Verify coordinates are valid (lat: -90 to 90, lng: -180 to 180)
|
|
- Check zoom level (1-20)
|
|
- Ensure API key has not exceeded quota
|
|
|
|
### Marker Not Visible
|
|
|
|
- Check `clubPrimaryColor` is a valid color
|
|
- Ensure marker color contrasts with map style
|
|
- Verify marker is within viewport
|
|
|
|
### Performance Issues
|
|
|
|
- Reduce zoom level for overview maps
|
|
- Use simpler map style (e.g., 'klokantech-basic')
|
|
- Limit number of map instances per page
|
|
|
|
## 📱 Mobile Optimization
|
|
|
|
Vector maps are automatically mobile-optimized:
|
|
|
|
- ✅ Touch gestures (pinch, pan, rotate)
|
|
- ✅ Responsive sizing
|
|
- ✅ Efficient data loading
|
|
- ✅ GPU acceleration on mobile
|
|
|
|
**Tips:**
|
|
- Use lower zoom levels on mobile (12-14 instead of 15-17)
|
|
- Consider disabling rotation on mobile
|
|
- Test on actual devices, not just desktop browser
|
|
|
|
## 🔮 Future Enhancements
|
|
|
|
Potential additions:
|
|
|
|
1. **Multiple Markers** - Show multiple club locations
|
|
2. **Custom Marker Icons** - Use club logo as marker
|
|
3. **Heatmaps** - Show fan distribution
|
|
4. **3D Buildings** - Add depth to maps
|
|
5. **Route Planning** - Show directions to stadium
|
|
6. **Catchment Areas** - Draw radius around stadium
|
|
7. **Animation** - Animate markers and transitions
|
|
8. **Clustering** - Group nearby markers
|
|
|
|
## 📚 Resources
|
|
|
|
### Documentation
|
|
- [MapLibre GL JS Docs](https://maplibre.org/maplibre-gl-js-docs/)
|
|
- [Mapbox GL Style Spec](https://docs.mapbox.com/mapbox-gl-js/style-spec/)
|
|
- [OpenMapTiles Schema](https://openmaptiles.org/schema/)
|
|
- [Positron GL Style](https://github.com/openmaptiles/positron-gl-style)
|
|
|
|
### Tools
|
|
- [Maputnik Style Editor](https://maputnik.github.io/) - Visual style editor
|
|
- [MapTiler Cloud](https://www.maptiler.com/) - Hosted tiles
|
|
- [OpenMapTiles](https://openmaptiles.org/) - Self-hosted solution
|
|
|
|
### Examples
|
|
- [MapLibre Examples](https://maplibre.org/maplibre-gl-js-docs/example/)
|
|
- [Vector Tile Style Gallery](https://openmaptiles.org/styles/)
|
|
|
|
## ✅ Checklist for Production
|
|
|
|
- [ ] Obtain MapTiler API key
|
|
- [ ] Add `REACT_APP_MAPTILER_KEY` to `.env`
|
|
- [ ] Test all map styles
|
|
- [ ] Verify club colors are applied correctly
|
|
- [ ] Test on mobile devices
|
|
- [ ] Check performance with browser DevTools
|
|
- [ ] Monitor API usage in MapTiler dashboard
|
|
- [ ] Consider self-hosting for high-traffic sites
|
|
- [ ] Add error boundaries for graceful failures
|
|
- [ ] Document custom styles if used
|
|
|
|
## 🎯 Migration Path
|
|
|
|
### Phase 1: Parallel Run (Recommended)
|
|
- Keep existing Leaflet maps
|
|
- Add vector maps as opt-in feature
|
|
- A/B test with users
|
|
- Monitor performance and feedback
|
|
|
|
### Phase 2: Gradual Rollout
|
|
- Enable vector maps for new features
|
|
- Offer toggle in admin settings
|
|
- Migrate high-traffic pages first
|
|
|
|
### Phase 3: Full Migration
|
|
- Default to vector maps
|
|
- Keep raster maps as fallback
|
|
- Remove Leaflet dependency
|
|
|
|
---
|
|
|
|
**Implementation Date:** 2025-10-10
|
|
**Technology:** MapLibre GL JS 4.x + OpenMapTiles
|
|
**License:** Open Source (BSD-3-Clause)
|
|
**Status:** ✅ Ready for Integration
|