Skip to content

Layer System

Purpose and Scope

The Layer System provides the foundational architecture for displaying geographic and non-geographic data on a Leaflet map. This document covers the base Layer class, the layer lifecycle, map integration, and the pane system that controls rendering order.

For specific layer implementations, see:

Architecture Overview

The layer system follows a hierarchical architecture where all layers extend from a common base class and integrate with the map through a standardized lifecycle.

Layer System Architecture

SVG
100%

Layer Base Class

The Layer class in src/layer/Layer.js29-117 serves as the abstract base for all layer types. It extends Evented to provide event handling capabilities.

Core Layer Structure

SVG
100%

Default Options

Layers have default options set at src/layer/Layer.js31-45:

OptionDefaultDescription
pane'overlayPane'The map pane where the layer will be rendered
attributionnullAttribution text for the layer
bubblingPointerEventstrueWhether pointer events bubble to the map

Key Methods

Layer Lifecycle

Layers follow a strict lifecycle managed through hooks that subclasses implement. The lifecycle ensures proper integration with the map's rendering and event systems.

Layer Lifecycle Flow

SVG
100%

Lifecycle Hooks

Subclasses must or may implement these methods:

  1. beforeAdd(map) - Optional early initialization src/layer/Layer.js136-137

    • Called before the layer is added to _layers
    • No events are initialized yet
    • Use for setup that doesn't require a ready map
  2. getEvents() - Optional event registration src/layer/Layer.js130-131

    • Returns an object like {viewreset: this._reset, zoom: this._update}
    • Events are automatically bound when layer is added
    • Events are automatically removed when layer is removed
  3. onAdd(map) - Required implementation src/layer/Layer.js124-125

    • Create and append DOM elements
    • Add event listeners
    • Initialize layer state
    • Return this for method chaining
  4. onRemove(map) - Optional cleanup src/layer/Layer.js127-128

    • Remove DOM elements
    • Clean up event listeners
    • Release resources

Layer Removal

Layer Removal Flow

SVG
100%

Layer-Map Integration

The map maintains internal registries to track layers and their properties. Understanding this integration is crucial for implementing custom layers.

Layer Registry

The map stores layers in _layers using a unique stamp src/map/Map.js153-162:

// Internal structure (conceptual)
map._layers = {
  [stamp(layer)]: layer,
  // e.g., "42": tileLayer,
  //       "43": marker,
  //       "44": polygon
}

The Util.stamp() function assigns a unique ID to each layer object, ensuring efficient lookups.

Zoom Bounds Tracking

Layers with minZoom or maxZoom options are tracked separately in _zoomBoundLayers src/map/Map.js227-241:

Zoom Bounds Management

SVG
100%

Layer Iteration

The map provides eachLayer() for iterating over all layers src/map/Map.js212-217:

map.eachLayer(function(layer) {
    layer.bindPopup('Hello');
});

This iterates over Object.values(this._layers), providing a clean API without exposing internal structure.

Pane System

The pane system controls the z-ordering and rendering hierarchy of layers. Each pane is a DOM element that contains layers of a specific type.

Default Pane Hierarchy

SVG
100%

Pane Creation

Panes are created during map initialization src/map/Map.js1256-1286:

// Default panes created in _initPanes()
this._panes = {};
this._paneRenderers = {};

this._mapPane = this.createPane('mapPane', this._container);
DomUtil.setPosition(this._mapPane, new Point(0, 0));

this.createPane('tilePane');
this.createPane('overlayPane');
this.createPane('shadowPane');
this.createPane('markerPane');
this.createPane('tooltipPane');
this.createPane('popupPane');

Custom Panes

Layers can use custom panes for specific z-ordering needs src/map/Map.js821-829:

// Create a custom pane
map.createPane('customPane');

// Use it in a layer
const layer = L.marker([0, 0], {
    pane: 'customPane'
});

The createPane() method at src/map/Map.js821-829:

  • Creates a <div> with class leaflet-pane
  • Adds it to _panes registry
  • Appends it to the specified container (or mapPane by default)

Accessing Panes

Layers access their pane through getPane() src/layer/Layer.js77-79:

getPane(name) {
    return this._map.getPane(name ? (this.options[name] || name) : this.options.pane);
}

This allows flexible pane specification:

  • layer.getPane() - Returns the layer's default pane
  • layer.getPane('customPane') - Returns a specific pane by name
  • layer.getPane('tooltipPane') - Returns pane from options property

Attribution System

Layers can provide attribution text that is displayed in the map's attribution control. This is commonly used for tile layer credits and data source acknowledgments.

Attribution Flow

SVG
100%

Setting Attribution

Attribution is set via the attribution option src/layer/Layer.js39-40:

const layer = L.tileLayer('https://tile.example.com/{z}/{x}/{y}.png', {
    attribution: '© OpenStreetMap contributors'
});

Retrieving Attribution

The getAttribution() method src/layer/Layer.js93-95 returns the attribution string:

getAttribution() {
    return this.options.attribution;
}

Subclasses can override this to provide dynamic attribution or aggregate attribution from multiple sources (as LayerGroup does).

Interactive Target Registration

Layers can register DOM elements as interactive targets, allowing the map to route events to the correct layer even when the event originates from a child element.

Registration Methods

addInteractiveTarget(targetEl) src/layer/Layer.js81-84

addInteractiveTarget(targetEl) {
    this._map._targets[Util.stamp(targetEl)] = this;
    return this;
}

removeInteractiveTarget(targetEl) src/layer/Layer.js86-89

removeInteractiveTarget(targetEl) {
    delete this._map._targets[Util.stamp(targetEl)];
    return this;
}

This mechanism allows the map to:

  1. Receive a DOM event on an element
  2. Look up the element's stamp in _targets
  3. Route the event to the owning layer
  4. Fire layer-specific events (e.g., click, pointerover)

Interactive Target Lookup

SVG
100%

Layer Events

Layers fire and listen to various events throughout their lifecycle.

Layer-Specific Events

Defined in src/layer/Layer.js21-26:

  • add - Fired after the layer is added to a map
  • remove - Fired after the layer is removed from a map

Map Layer Events

The map fires events when layers are added or removed src/layer/Layer.js143-148:

  • layeradd - Fired when a new layer is added, includes {layer: Layer}
  • layerremove - Fired when a layer is removed, includes {layer: Layer}

Example Event Usage

// Listen to layer addition
map.on('layeradd', function(e) {
    console.log('Layer added:', e.layer);
});

// Listen to layer's own add event
layer.on('add', function() {
    console.log('I was added to the map');
});

// Layer registers for map events
getEvents() {
    return {
        viewreset: this._reset,
        zoom: this._onZoom,
        moveend: this._update
    };
}

Layer Type Categories

The layer system supports multiple categories of layers, each with specialized behavior:

CategoryBase ClassPurposeSubsection
Raster TilesGridLayer, TileLayerLoad tiled images from URLs3.2
Vector ShapesPath, Polyline, Polygon, CircleDraw geometric shapes3.4
MarkersMarkerDisplay point locations with icons3.3
Layer CollectionsLayerGroup, FeatureGroupGroup multiple layers3.5
HTML OverlaysDivOverlay, Popup, TooltipDisplay HTML content3.6
GeoJSONGeoJSONParse and render GeoJSON data3.7

Each category extends the base Layer class and implements the lifecycle hooks appropriate for its rendering strategy.

Layer Type Hierarchy (Simplified)

SVG
100%

Implementation Guidelines

When implementing a custom layer, follow these guidelines:

Minimum Implementation

  1. Extend Layer

    class CustomLayer extends Layer {
        // Implementation
    }
  2. Implement onAdd(map) src/layer/Layer.js124-125

    • Create DOM elements
    • Append to appropriate pane
    • Initialize state
    • Add event listeners
  3. Implement onRemove(map) src/layer/Layer.js127-128

    • Remove DOM elements
    • Clean up listeners
    • Release resources

Optional Enhancements

  1. Implement getEvents() - Auto-register map event handlers
  2. Implement beforeAdd(map) - Early initialization
  3. Override getAttribution() - Provide attribution
  4. Register interactive targets - Enable event routing
  5. Set default options - Use setDefaultOptions() static method

Example Custom Layer

class CustomLayer extends Layer {
    static {
        this.setDefaultOptions({
            pane: 'overlayPane',
            attribution: '© Custom Layer'
        });
    }
    
    getEvents() {
        return {
            zoom: this._update,
            viewreset: this._reset
        };
    }
    
    onAdd(map) {
        this._container = L.DomUtil.create('div', 'custom-layer');
        this.getPane().appendChild(this._container);
        this._update();
        return this;
    }
    
    onRemove(map) {
        this._container.remove();
        return this;
    }
    
    _update() {
        // Update layer based on map state
        const zoom = this._map.getZoom();
        const center = this._map.getCenter();
        // ... update logic
    }
    
    _reset() {
        // Reset layer state on view reset
    }
}

Testing Considerations

When testing custom layers, verify:

  1. Lifecycle Events - add and remove events fire correctly spec/suites/map/MapSpec.js989-1011
  2. DOM Integration - Elements are added to correct pane spec/suites/map/MapSpec.js734-786
  3. Memory Cleanup - onRemove cleans up properly spec/suites/map/MapSpec.js61-81
  4. Event Registration - Map events are bound/unbound src/layer/Layer.js106-110
  5. Attribution - getAttribution() returns expected value
  6. Layer Registry - Layer appears in _layers when added src/map/Map.js160-162
  7. Zoom Bounds - Layers with min/max zoom update map limits spec/suites/map/MapSpec.js616-674