mirror of
https://github.com/Dvorinka/MyClubServer.git
synced 2026-06-04 02:32:57 +00:00
upload
This commit is contained in:
@@ -0,0 +1,468 @@
|
||||
# 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
|
||||
Reference in New Issue
Block a user