dawarich/MAPLIBRE_IMPLEMENTATION.md
2025-10-30 19:17:31 +01:00

9.5 KiB

MapLibre Implementation Guide

Overview

We've successfully implemented MapLibre GL JS as a toggleable alternative to Leaflet in Dawarich. Users can now switch between the two mapping engines using a query parameter or UI toggle button.

What's Been Implemented

1. Package Installation

  • MapLibre GL JS v5.10.0 added to npm dependencies
  • Pinned to Rails importmap for asset management
  • CSS loaded conditionally based on map engine selection

2. MapLibre Controller

Created a new Stimulus controller (app/javascript/controllers/maplibre_controller.js) that provides:

Core Features Implemented

  • Map Initialization - Basic MapLibre map with center/zoom
  • Navigation Controls - Pan, zoom, rotate controls
  • Scale Control - Metric/Imperial units based on user settings
  • Geolocate Control - User location tracking
  • Fullscreen Control - Fullscreen map view
  • Points Display - All GPS points rendered as circle markers
  • Popups - Click markers to view details (timestamp, battery, altitude, speed, country)
  • Hover Effects - Cursor changes on point hover
  • Auto-fit Bounds - Map automatically fits to show all points
  • Theme Support - Dark/light map styles based on user theme

Map Styles Available

  1. OSM (OpenStreetMap) - Raster tiles from OSM
  2. Streets - Stadia Maps Alidade Smooth style
  3. Satellite - Esri World Imagery
  4. Dark - Stadia Maps dark theme
  5. Light - OpenStreetMap light theme

3. Toggle Mechanism

Query Parameter Method

http://localhost:3000/map?maplibre=true   # Use MapLibre
http://localhost:3000/map?maplibre=false  # Use Leaflet

UI Toggle Button

  • Fixed position button in top-right corner (below navbar)
  • Shows "Switch to MapLibre" or "Switch to Leaflet" based on current engine
  • Maintains current date range when switching
  • Uses DaisyUI button styling for consistency

4. Conditional Loading

The implementation conditionally loads CSS and controllers based on the maplibre parameter:

Layout Changes (app/views/layouts/map.html.erb):

  • Loads MapLibre CSS when ?maplibre=true
  • Loads Leaflet CSS + Leaflet.draw CSS otherwise

View Changes (app/views/map/index.html.erb):

  • Uses maplibre controller when enabled
  • Uses maps controller otherwise
  • Hides fog of war element for MapLibre (not yet implemented)

File Changes Summary

New Files

  • app/javascript/controllers/maplibre_controller.js - MapLibre Stimulus controller

Modified Files

  • package.json - Added maplibre-gl dependency
  • config/importmap.rb - Pinned maplibre-gl package
  • app/views/layouts/map.html.erb - Conditional CSS loading
  • app/views/map/index.html.erb - Toggle button and conditional controller

Current Capabilities

Working Features (MapLibre)

  • Map rendering with OpenStreetMap tiles
  • Point markers (all GPS points)
  • Navigation controls (zoom, pan)
  • Scale control
  • Geolocate control
  • Fullscreen control
  • Click popups with point details
  • Auto-fit to bounds
  • Theme-based map styles
  • Toggle between engines

Not Yet Implemented (MapLibre)

These Leaflet features need to be ported to MapLibre:

  1. Routes/Polylines - Speed-colored route rendering
  2. Tracks - GPS track visualization
  3. Heatmap - Density visualization (easier in MapLibre - native support!)
  4. Fog of War - Canvas overlay showing explored areas
  5. Scratch Map - Visited countries overlay
  6. Areas - User-defined geographic areas
  7. Visits - Location visit detection and display
  8. Photos - Geotagged photo markers
  9. Live Mode - Real-time GPS streaming
  10. Family Members - Real-time family location sharing
  11. Location Search - Search and navigate to locations
  12. Drawing Tools - Create custom areas
  13. Layer Control - Show/hide different layers
  14. Settings Panel - Map configuration UI
  15. Calendar Panel - Date range selection

Usage Instructions

For Users

  1. Default Mode (Leaflet):

    • Navigate to /map as usual
    • All existing features work normally
  2. MapLibre Mode:

    • Click "Switch to MapLibre" button in top-right
    • Or add ?maplibre=true to URL
    • See your GPS points on a modern WebGL-powered map
  3. Switching Back:

    • Click "Switch to Leaflet" button
    • Or add ?maplibre=false to URL
    • Return to full-featured Leaflet mode

For Developers

Testing the Implementation

# Start the Rails server
bundle exec rails server

# Visit the map page
open http://localhost:3000/map

# Test MapLibre mode
open http://localhost:3000/map?maplibre=true

Adding New MapLibre Features

  1. Add to maplibre_controller.js:

    // Example: Adding a new feature
    addNewFeature() {
      // Your MapLibre implementation
    }
    
  2. Check data availability:

    • All data attributes from Leaflet controller are available
    • Access via this.element.dataset.xxx
  3. Use MapLibre APIs:

    • Sources: this.map.addSource()
    • Layers: this.map.addLayer()
    • Events: this.map.on()

Next Steps

Phase 1: Core Features (High Priority)

  • Implement polylines/routes with speed colors
  • Add heatmap layer (native MapLibre support)
  • Port track visualization
  • Implement layer control UI

Phase 2: Advanced Features (Medium Priority)

  • Fog of War custom layer
  • Scratch map (visited countries)
  • Areas and visits
  • Photo markers

Phase 3: Real-time Features (Low Priority)

  • Live mode integration
  • Family members layer
  • WebSocket updates

Phase 4: Tools & Interaction (Future)

  • Drawing tools (maplibre-gl-draw)
  • Location search integration
  • Settings panel for MapLibre

Performance Comparison

Expected Benefits of MapLibre

  1. Better Performance:

    • Hardware-accelerated WebGL rendering
    • Smoother with large datasets (10,000+ points)
    • Better mobile performance
  2. Modern Features:

    • Native vector tile support
    • Built-in heatmap layer
    • 3D terrain support (future)
    • Better style expressions
  3. Active Development:

    • Regular updates and improvements
    • Growing community
    • Better documentation

Leaflet Advantages (Why Keep It)

  1. Feature Complete:

    • All existing features work
    • Extensive plugin ecosystem
    • Mature and stable
  2. Simpler API:

    • Easier to understand
    • More examples available
    • Faster development
  3. Lower Resource Usage:

    • Canvas-based rendering
    • Lower GPU requirements
    • Better for older devices

Architecture Notes

Controller Inheritance

Both controllers extend BaseController:

import BaseController from "./base_controller";
export default class extends BaseController {
  // Controller implementation
}

Data Sharing

Both controllers receive identical data attributes:

  • data-api_key - User API key
  • data-coordinates - GPS points array
  • data-tracks - Track data
  • data-user_settings - User preferences
  • data-features - Enabled features
  • data-user_theme - Dark/light theme

Separation of Concerns

  • Leaflet: maps_controller.js + helper files in app/javascript/maps/
  • MapLibre: maplibre_controller.js (self-contained for now)
  • Shared: View templates detect which to load

Technical Decisions

Why Query Parameter?

  • Simple to implement
  • Easy to share URLs
  • No database changes needed
  • Can be enhanced with session storage later

Why Separate Controller?

  • Clean separation of concerns
  • Easier to develop independently
  • No risk of breaking Leaflet functionality
  • Can eventually deprecate Leaflet if MapLibre is preferred

Why Keep Leaflet?

  • Zero-risk migration strategy
  • Users can choose based on needs
  • Fallback for unsupported features
  • Plugin ecosystem still valuable

Known Issues

  1. Family Members Controller: Expects window.mapsController - needs adapter for MapLibre
  2. Points Controller: May expect Leaflet-specific APIs
  3. Add Visit Controller: Drawing tools use Leaflet.draw
  4. No Session Persistence: Toggle preference not saved (yet)

Configuration

User Settings (Respected by MapLibre)

{
  "maps": {
    "distance_unit": "km",  // or "mi"
    "url": "custom-tile-server-url"
  },
  "preferred_map_layer": "OSM"  // or "Streets", "Satellite", etc.
}

Feature Flags (Future)

Could add to features hash:

@features = {
  maplibre_enabled: true,
  maplibre_default: false  # Make MapLibre the default
}

Resources

Testing Checklist

Before deploying to production:

  • Test point rendering with small dataset (< 100 points)
  • Test point rendering with large dataset (> 10,000 points)
  • Test on mobile devices
  • Test theme switching (dark/light)
  • Test with different date ranges
  • Verify toggle button works in all scenarios
  • Check browser console for errors
  • Test with different map styles
  • Verify user settings are respected
  • Test fullscreen mode
  • Test geolocate feature

Support

For issues with the MapLibre implementation:

  1. Check browser console for errors
  2. Verify MapLibre CSS is loaded
  3. Check importmap configuration
  4. Test with ?maplibre=false to confirm Leaflet still works