All features of a layer (empty array when the layer is unknown).
A single feature by its stable id (feature.id or properties.id), or null.
Number of features currently held for a layer.
Ids of every layer known to the store.
true when a layer with this id exists in the store.
Finds features by reference in the layers the map holds — with no network.
Searches the layers that declare searchable, on the feature's id and the declared
fields. Accents, case and word order are ignored, with the filter's own rule. Best
first: an exact id, then an exact value, then an id or value starting with the query,
then every word found somewhere.
⚠️ It reads what the map holds, and only that. A layer read from the device store is
held, so this works off-network for what was prepared. A layer never loaded —
active: false, not yet switched on — holds nothing, and a vector-tile layer keeps no
feature: neither is found.
What the user typed. A blank query finds nothing.
Optionalopts: LayerSearchOptions
limit and layerIds.
The matches, best first, at most limit.
Brings one feature into view and selects it — the gesture a search result or a list row ends with.
A point is flown to (opts.zoom, default 17); a line or a polygon is fitted. The
feature's selected feature-state is then set, and the previously focused feature, on
whatever layer, is cleared first: one selection per map.
⚠️ Selection is addressed by properties.id: a feature without one is framed, not
selected. A whole-collection write to its layer (setData, a filter re-feed) clears
the selection.
The feature's layer.
Its id (feature.id or properties.id).
Optionalopts: LayerFocusOptions
zoom for a point.
true once framed; false — and nothing moved — when the layer does not hold
that feature, or there is no map.
true when the layer is painted on the map right now.
This is the PHYSICAL state. A zoom range can force it false while the layer
is still switched on, so use it to answer "what is on screen" — never to
decide what a toggle should show.
true when the layer is switched on, whatever the map is currently painting.
This is the INTENT — what the user or the active theme asked for. It is what a visibility toggle must reflect, since it does not flip on its own when the viewer zooms out of the layer's range.
true when a USER action last set this layer's visibility — as opposed to a
theme, a zoom threshold or the initial load.
⚠️ Distinct from LayerDataApi.isEnabled, and the two are easy to
confuse: isEnabled says WHAT is wanted, this says WHO wanted it. A theme that
switches a layer on leaves isEnabled true and this false. Read it to decide
whether an automatic rule may still override the layer, never to paint a toggle.
WHO last set this layer's visibility — "user", "theme", "zoom" or "system" —
or null for a layer the store does not know.
⚠️ This is the PULL route, and it exists only because the push one cannot answer
for the past. source already leaves the core on every change, typed, through the
geoleaf:layer:toggle event; a consumer subscribed from the start can keep its own
table. What no subscription gives is the source of the state as it stands NOW, to a
caller that mounted afterwards — a panel rebuilt on navigation, a host re-attaching
to a live map. That is the only gap this fills.
🛑 Distinct from LayerDataApi.isUserOverridden, which answers "is the user's
own decision still standing?" — a boolean over one source. This names the source
itself, so "theme" and "zoom" stop being indistinguishable from each other, which
is exactly what a caller reconstructing the value from isUserOverridden loses.
⚠️ The recorded source lags a refused write, and the contract says so rather than pretending otherwise: the manager writes the source only when the physical change goes through, while the intent flags are written unconditionally. A write refused because a higher-ranking source holds the layer leaves the previous source in place — which is the correct answer to "who decided what is displayed", and the wrong one to "who asked last". Read it as the former.
WHICH style is applied to a layer right now — or null for a layer the store does
not know, and for one no style has been applied to yet.
🛑 A projection, and the narrowness is the contract. The runtime entry holds a
currentStyle whose SHAPE depends on which writer spoke last: applying a style
assigns the flattened paint handed to the adapter, which carries no id and no
label, while the style selector restores the full style document over it. A
consumer reading that field directly gets one or the other and cannot tell which —
a defect already shipped once, where the labels toggle greyed out for good. This
returns the two fields that survive both writers, normalised.
⚠️ The paint is deliberately not exposed. style and styleRules are the part
whose shape is unstable, and published subpaths are added, never removed: engraving
them in the contract would make the instability permanent. A caller needing to draw
from the style should say what for — that is a separate decision, not an omission.
Sets a layer's visibility, naming the source of the change.
🛑 source is REQUIRED, and that is what keeps this from being a second door
to an existing room. GeoJSON.showLayer / hideLayer / toggleLayer already
carry the user's own actions and hard-wire "user"; this route exists only for
a caller that must attribute the change to something else — restoring a saved
state as "system", applying its own rule as "theme". Needing no attribution
means needing the existing trio, not this.
The physical state is recomputed against the current zoom before returning, so a layer outside its range stays unpainted while its intent is recorded — the same two-step the existing writes perform.
Id of the layer to switch.
The intent to record.
Who is asking. See VisibilitySource.
true when the state actually changed; false when the layer is
unknown, or when it already held that intent from a source that outranks
this one.
Creates and renders a layer the active profile does not declare, from a definition supplied by the caller.
The definition takes the same shape a profile's layer entry carries and
travels the same loading path, so the result is indistinguishable from a
profile-declared layer once mounted, and a relative dataFile resolves
against the active profile.
⚠️ This is a CREATE, not an upsert: an id that already names a layer is refused rather than silently overwritten. The two operations have different consequences and only one of them is reversible by the caller. To rewrite the features of a layer that exists, use LayerDataApi.setData.
The created layer is registered with the layer manager, so it gets its row like any profile-declared layer — not only a rendering on the map.
The layer definition. id is required.
The created layer, or null when the definition named no resolvable
source or was skipped by active: false (the reason is logged).
Replaces a layer's base features, re-renders the source, and emits.
Empties a layer (equivalent to setData(layerId, [])).
Appends one feature to the base dataset.
Removes one feature by id; returns true when a feature was removed.
Re-keys a feature (temp id → server id) on both feature.id and properties.id.
Merges patch into a feature's properties (baked — persists across
source rebuilds). Silent by default (no source rebuild); pass
{ rerender: true } to re-render immediately.
Optionalopts: { rerender?: boolean }Displays only the features matching predicate, WITHOUT mutating the base
dataset — the subset is re-derived from the full base on each apply (GPU
setFilter id-match, JS predicate fallback).
Every geometry is filtered alike, lines included. A vector-tile layer keeps no feature in memory, so the predicate has nothing to run on and the layer is left as it is.
Shows again what the subset hid — and lifts the panel's filter with it, which writes the
same place. Features hidden by hideFeatures stay hidden.
Hides the listed features from the map, WITHOUT touching the store or the layer's
filter — for a feature being edited, whose copy is drawn elsewhere meanwhile.
null (or an empty list) shows them again.
Composed with the layer's filter, never substituted for it: the layer shows what passes
that filter and is not hidden. (The panel's filter and setVisibleSubset share one place
— the last of the two to write wins; the hidden set alone is kept apart.) On a clustered
layer, a hidden point still counts in its cluster's bubble: clustering is done by the
source, before any filter. Until 3.12.0 the editor hid its original by REPLACING the
layer's filter: selecting a feature under an active filter put every filtered-out feature
back on the map, and releasing it cleared the filter outright. One hidden set per layer:
a second call replaces the first. Features are matched on properties.id, compared as
strings — the key a GeoJSON source promotes to its feature id — and, on a vector-tile
layer, on the tile's own feature id too.
The layer.
The features to hide, or null to show them again.
Sets ephemeral feature-state on a feature (requires promoteId on the source).
Upserts features into the base dataset, de-duplicated by id.
The object mounted on
GeoLeaf.Layers. Reads promote the per-layerGeoJSONCorestore; the base-dataset writes, unit mutations, visible-subset, reactive paint and merge are the seam's own surface.