Skip to content

Multiclass Fill Layers


Overview

A multiclass fill layer packs multiple feature classes (e.g. landcover types) into a single GL layer instead of one layer per class. The paint properties use interpolate + case expressions that branch on the feature's class property at runtime.

This reduces the layer count and lets the JS runtime read classMetadata from the layer metadata to drive per-class visibility and styling.


Usage

MulticlassFillNode goes directly in a style's mapping, just like any other node. It renders through the standard pipeline via the style_layer field on Layer:

from elzar.generator.multiclass_fill import FillClass, MulticlassFillNode

WGS_LANDCOVER = [
    MulticlassFillNode(
        "wgslandcover",
        {
            "wood": FillClass(fill_color=[(0, "#d3f5d1"), (14, "#e8fae7")]),
            "grass": FillClass(fill_color=[(0, "#eeffed"), (14, "#f5fff4")]),
            "ice": FillClass(fill_color=[(0, "#fff"), (14, "#fff")]),
        },
        source="openmaptiles",
        source_layer="wgslandcover",
        feature_type="landscape.natural.landcover",
        fill_opacity=1,
    ),
]

Layer position is controlled by the render_group parameter (defaults to InjectionsNames.LANDCOVER).


FillClass

Each class defines zoom-interpolated color stops as list[tuple[int, str]]:

Field Type Description
fill_color list[tuple[int, str]] Zoom/color stops (required)
fill_outline_color list[tuple[int, str]] \| None Outline zoom/color stops
visible bool Whether the class is rendered (default True)

How it works

MulticlassFillNode.render() builds a FillLayer and sets it as the style_layer on a Layer in the stack. When render_mapbox_style encounters a Layer with style_layer set, it uses it directly instead of resolving through the StyleTree.

The built FillLayer has:

  1. Paint expressions -- fill-color (and optionally fill-outline-color) are interpolate + case expressions that evaluate per zoom level, branching on the feature class property.

  2. Metadata -- classMetadata stores per-class filter, color stops, and visibility so the JS runtime can toggle or restyle individual classes without regenerating the style.

  3. Combined filter -- An ["all", ["has", "class"], ["any", ...]] filter that passes only features matching a visible class.


Landcover example

The WGS landcover layer in streets_classic is defined in the mapping:

from elzar.generator.multiclass_fill import MulticlassFillNode
from .landcover import WGS_LANDCOVER_CLASSES, WGS_LANDCOVER_FEATURE_TYPE, WGS_LANDCOVER_OPACITY

WGS_LANDCOVER = [
    MulticlassFillNode(
        "wgslandcover",
        WGS_LANDCOVER_CLASSES,
        source="openmaptiles",
        source_layer="wgslandcover",
        feature_type=WGS_LANDCOVER_FEATURE_TYPE,
        fill_opacity=WGS_LANDCOVER_OPACITY,
    ),
]

This replaces five separate DataNode + StyleElement pairs with a single layer containing six classes (built-up, wood, grass, cropland, bare vegetation, ice) with zoom-interpolated colors. The LANDCOVER injection point places it right after background.