Search code examples
javascriptcssleaflet

How to place Leaflet (timeline) control across the bottom below attribution control (like MerrySky)


MerrySky has a timeline control at the very bottom of its Leaflet map. When the map is expanded to full-screen, the timeline is included. How do I make a similar Leaflet control? (Similar size/location/layout)

The Leaflet L.Control class only has 4 possible values for position: 'topleft', 'topright', 'bottomleft' or 'bottomright'. Most other Leaflet plugins seem to place custom controls more "inside" the map or completely outside the map.

Inspecting the DOM makes me think MerrySky injected custom controls manually, outside of the Leaflet API:

  • All three custom controls are outside the leaflet-control-container div.
  • MerrrySky custom replayer-control has both leaflet-left and leaflet-right classes.

So I think MerrySky injected these custom controls after Leaflet rendered the .map div. However, is there another way? Either using the Leaflet API and/or a Leaflet wrapper like React Leaflet?


Solution

  • There is an open Leaflet issue that might make this easier in the future: Refactor/extend positioning of controls

    In the meantime, I was able to accomplish everything using the Leaflet API (plus some internal props):

    Repo with full (SvelteKit) source:

    Demo: https://zeus-leftium.vercel.app/

    // Insert div.leaflet-footer element into leaflet map.
    // Add to list of Leaflet control corners as 'footer'.
    map._controlCorners.footer = DomUtil.create('div', 'leaflet-footer', map._container);
    
    // Define a simple control class that positions itself into newly created footer control corner:
    const RadarControl = Control.extend({
        options: {
            position: 'footer'
        },
        onAdd: function () {
            const container = DomUtil.create('div', 'description');
            DomEvent.disableClickPropagation(container);
            container.insertAdjacentHTML('beforeend', 'FOOTER');
    
            return container;
        }
    });
    
    // Add simple control defined above to map:
    new RadarControl().addTo(map);
    

    Some CSS is needed to properly size/position the new/existing controls:

    .leaflet-footer {
        /* Stick to bottom of map: */
        position: absolute;
        left: 0;
        right: 0;
        bottom: 0;
    
        /* Display above map layers: */
        z-index: 1000;
    
        pointer-events: none;
    
        background-color: whitesmoke;
        height: 41px;
    
        padding: 3px 10px;
    }
    
    /* Raise bottom control corners above footer: */
    .leaflet-bottom {
        bottom: 42px;
    }