# 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 ``` ## 🛠️ 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'; ``` ### 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 ``` **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 ``` ### Option 2: Toggle Between Raster/Vector Create a wrapper component: ```typescript const AdaptiveMap: React.FC = (props) => { const useVector = settings.use_vector_maps; // from settings return useVector ? : ; }; ``` ## 📊 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 ``` Result: Red markers on light map, subtle red tint on water ### Blue Club (e.g., Slovan Liberec) ```typescript ``` Result: Blue markers on dark map, modern look ### Green Club ```typescript ``` 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