Skip to content

Layer Groups and Feature Groups

Purpose and Scope

This document covers the LayerGroup and FeatureGroup classes, which enable managing collections of layers as single units. These classes provide mechanisms for adding, removing, and iterating over multiple layers collectively, and integrating them with the map's lifecycle.

For information about the base Layer class that these extend, see Layer Base Class. For details on specific layer types (markers, vectors, etc.) that can be grouped, see their respective sections (Markers, Vector Layers). For GeoJSON integration with FeatureGroup, see GeoJSON Support.

Overview

LayerGroup and FeatureGroup provide hierarchical layer management in Leaflet. Both classes extend the base Layer class and manage collections of child layers, but differ in their event handling and collective operations capabilities.

SVG
100%

LayerGroup Class

Architecture and Layer Storage

LayerGroup stores child layers in an internal _layers object, indexed by unique numeric IDs generated using Util.stamp(). This approach enables efficient layer lookup by ID and supports both layer objects and IDs in method calls.

SVG
100%

The initialize method sets up the layer storage and adds any initial layers provided in the constructor:

Constructor ParameterTypeDescription
layersLayer[] (optional)Initial set of layers to add to the group
optionsObject (optional)Options object merged via Util.setOptions

Core Methods

Layer Management

The LayerGroup provides methods for adding, removing, and querying layers:

SVG
100%
MethodParametersReturnDescription
addLayerlayer: LayerthisAdds layer to group; adds to map if group is on map
removeLayerlayer: Layer or id: NumberthisRemoves layer from group and map
hasLayerlayer: Layer or id: NumberBooleanChecks if layer is in group
clearLayersnonethisRemoves all layers from group
getLayerid: NumberLayerReturns layer with given ID
getLayersnoneLayer[]Returns array of all layers
getLayerIdlayer: LayerNumberReturns internal ID for a layer

Iteration

The eachLayer method provides a functional approach to layer iteration:

// Signature from src/layer/LayerGroup.js:94-98
eachLayer(method, context)

This method iterates over all layers in the group, calling the provided function for each layer. The context parameter sets the this value in the callback.

Map Lifecycle Integration

LayerGroup integrates with the map's layer lifecycle through the onAdd and onRemove methods inherited from the base Layer class:

SVG
100%

When a LayerGroup is added to or removed from a map, it automatically adds or removes all its child layers by iterating through them with eachLayer.

Collective Operations

LayerGroup provides a setZIndex method that applies to all child layers:

// From src/layer/LayerGroup.js:117-119
setZIndex(zIndex) {
    return this.eachLayer(l => l.setZIndex?.(zIndex));
}

This method uses optional chaining (?.) to safely call setZIndex only on layers that support it.

FeatureGroup Class

Extension of LayerGroup

FeatureGroup extends LayerGroup with event propagation and additional collective operations. The class is designed for interactive feature collections where events from individual layers should bubble up to the group level.

SVG
100%

Event Propagation

FeatureGroup establishes itself as an event parent for all child layers, enabling event bubbling from children to the group:

SVG
100%

The event parent relationship is managed in the overridden addLayer and removeLayer methods:

MethodEvent Parent ActionLayer Event Fired
addLayerlayer.addEventParent(this)layeradd
removeLayerlayer.removeEventParent(this)layerremove

Layer Events

FeatureGroup fires layeradd and layerremove events when layers are added or removed:

// From addLayer method, src/layer/FeatureGroup.js:38-40
// @event layeradd: LayerEvent
// Fired when a layer is added to this \`FeatureGroup\`
return this.fire('layeradd', {layer});

// From removeLayer method, src/layer/FeatureGroup.js:55-57
// @event layerremove: LayerEvent
// Fired when a layer is removed from this \`FeatureGroup\`
return this.fire('layerremove', {layer});

Collective Operations

FeatureGroup provides methods to apply operations to all child layers that support them:

MethodDescriptionImplementation Strategy
setStyle(style)Applies path styling to all vector layersCalls setStyle on layers that have the method
bringToFront()Moves all layers to the top of the rendering orderCalls bringToFront on supporting layers
bringToBack()Moves all layers to the bottom of the rendering orderCalls bringToBack on supporting layers

Each method uses optional chaining to safely handle layers that may not support the operation:

// From src/layer/FeatureGroup.js:62-76
setStyle(style) {
    return this.eachLayer(l => l.setStyle?.(style));
}

bringToFront() {
    return this.eachLayer(l => l.bringToFront?.());
}

bringToBack() {
    return this.eachLayer(l => l.bringToBack?.());
}

Bounds Calculation

The getBounds() method computes the geographic bounding box encompassing all child layers:

SVG
100%

The implementation handles both layers with bounds (polygons, polylines) and point layers (markers):

// From src/layer/FeatureGroup.js:80-87
getBounds() {
    const bounds = new LatLngBounds();
    
    for (const layer of Object.values(this._layers)) {
        bounds.extend(layer.getBounds ? layer.getBounds() : layer.getLatLng());
    }
    return bounds;
}

Comparison: LayerGroup vs FeatureGroup

FeatureLayerGroupFeatureGroup
Base ClassLayerLayerGroup
Layer Management✓ (add, remove, iterate)✓ (inherited)
Event Propagation✓ (addEventParent)
Layer Events✓ (layeradd, layerremove)
Collective Styling✓ (setStyle)
Z-Order ManagementsetZIndex onlysetZIndex, bringToFront, bringToBack
Bounds Calculation✓ (getBounds)
Typical Use CaseSimple groupingInteractive feature collections

Usage Patterns

Basic LayerGroup Usage

// Example from src/layer/LayerGroup.js:14-19
const group = new LayerGroup([marker1, marker2])
    .addLayer(polyline)
    .addTo(map);

// Remove all layers
group.clearLayers();

// Iterate over layers
group.eachLayer(layer => {
    console.log(layer);
});

FeatureGroup with Event Handling

// Example from src/layer/FeatureGroup.js:17-22
new FeatureGroup([marker1, marker2, polyline])
    .bindPopup('Hello world!')
    .on('click', function() { 
        alert('Clicked on a member of the group!'); 
    })
    .addTo(map);

The event handler receives events from any child layer due to event propagation.

Collective Styling

// Apply styling to all vector layers in the group
featureGroup.setStyle({
    color: 'red',
    weight: 5
});

// Reorder all layers
featureGroup.bringToFront();

Implementation Details

Layer ID Generation

Both classes use Util.stamp(layer) to generate unique numeric IDs for layers. This function assigns and returns a unique identifier that remains consistent for the layer's lifetime:

// From src/layer/LayerGroup.js:123-125
getLayerId(layer) {
    return Util.stamp(layer);
}

Automatic Map Synchronization

When a LayerGroup is added to a map, the _map property is set (by the base Layer class), and onAdd is called. This triggers automatic addition of all child layers:

// From src/layer/LayerGroup.js:81-87
onAdd(map) {
    this.eachLayer(map.addLayer, map);
}

onRemove(map) {
    this.eachLayer(map.removeLayer, map);
}

Similarly, when new layers are added to a group that's already on a map, they're immediately added to the map:

// From src/layer/LayerGroup.js:38-46
addLayer(layer) {
    const id = this.getLayerId(layer);
    this._layers[id] = layer;
    this._map?.addLayer(layer);  // Optional chaining: only if _map exists
    return this;
}

Optional Method Calls

FeatureGroup uses optional chaining (?.) extensively to safely call methods that may not exist on all layer types:

// From src/layer/FeatureGroup.js:62-76
setStyle(style) {
    return this.eachLayer(l => l.setStyle?.(style));  // Only calls if method exists
}

bringToFront() {
    return this.eachLayer(l => l.bringToFront?.());
}

bringToBack() {
    return this.eachLayer(l => l.bringToBack?.());
}

This pattern allows mixed layer types (e.g., markers and polygons) in the same FeatureGroup without errors.

Bounds Extension Strategy

The getBounds() method in FeatureGroup handles two types of layers:

  1. Layers with bounds (polygons, polylines, circles): Uses layer.getBounds() which returns a LatLngBounds object
  2. Point layers (markers): Uses layer.getLatLng() which returns a single LatLng coordinate

The LatLngBounds.extend() method accepts both types, expanding the bounds to include the new geometry:

// From src/layer/FeatureGroup.js:80-87
getBounds() {
    const bounds = new LatLngBounds();
    for (const layer of Object.values(this._layers)) {
        bounds.extend(layer.getBounds ? layer.getBounds() : layer.getLatLng());
    }
    return bounds;
}

Testing Coverage

The LayerGroup test suite validates core functionality:

Test CategoryVerified Behavior
hasLayerThrows on invalid arguments; correctly identifies layer membership
addLayerAdds layers and returns the group instance
removeLayerRemoves layers and returns the group instance
clearLayersRemoves all layers at once
getLayersReturns accurate array of all layers
eachLayerIterates with correct layer and context
toGeoJSONGenerates valid GeoJSON for grouped layers