GeoLeaf Core API - v3.19.0
    Preparing search index...

    The object mounted on GeoLeaf.Layers. Reads promote the per-layer GeoJSONCore store; the base-dataset writes, unit mutations, visible-subset, reactive paint and merge are the seam's own surface.

    interface LayerDataApi {
        getFeatures(layerId: string): Feature<Geometry, GeoJsonProperties>[];
        getFeatureById(
            layerId: string,
            id: string | number,
        ): Feature<Geometry, GeoJsonProperties> | null;
        getFeatureCount(layerId: string): number;
        listLayerIds(): string[];
        hasLayer(layerId: string): boolean;
        search(query: string, opts?: LayerSearchOptions): FeatureMatch[];
        focus(
            layerId: string,
            id: string | number,
            opts?: LayerFocusOptions,
        ): boolean;
        isVisible(layerId: string): boolean;
        isEnabled(layerId: string): boolean;
        isUserOverridden(layerId: string): boolean;
        getVisibilitySource(layerId: string): VisibilitySource | null;
        getStyle(layerId: string): LayerStyleInfo | null;
        setVisibility(
            layerId: string,
            visible: boolean,
            source: VisibilitySource,
        ): boolean;
        create(def: LayerDefinition): Promise<CreatedLayer | null>;
        setData(
            layerId: string,
            features: Feature<Geometry, GeoJsonProperties>[],
        ): void;
        clear(layerId: string): void;
        addFeature(layerId: string, feature: Feature): void;
        removeFeature(layerId: string, id: string | number): boolean;
        updateFeatureId(
            layerId: string,
            oldId: string | number,
            newId: string | number,
        ): void;
        patchFeature(
            layerId: string,
            id: string | number,
            patch: Record<string, unknown>,
            opts?: { rerender?: boolean },
        ): void;
        setVisibleSubset(layerId: string, predicate: (f: Feature) => boolean): void;
        clearVisibleSubset(layerId: string): void;
        hideFeatures(
            layerId: string,
            ids: readonly (string | number)[] | null,
        ): void;
        setFeatureState(
            layerId: string,
            id: string | number,
            state: LayerFeatureState,
        ): void;
        mergeFeatures(
            layerId: string,
            features: readonly Feature<Geometry, GeoJsonProperties>[],
        ): void;
    }
    Index
    • All features of a layer (empty array when the layer is unknown).

      Parameters

      • layerId: string

      Returns Feature<Geometry, GeoJsonProperties>[]

    • A single feature by its stable id (feature.id or properties.id), or null.

      Parameters

      • layerId: string
      • id: string | number

      Returns Feature<Geometry, GeoJsonProperties> | null

    • 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.

      Parameters

      • query: string

        What the user typed. A blank query finds nothing.

      • Optionalopts: LayerSearchOptions

        limit and layerIds.

      Returns FeatureMatch[]

      The matches, best first, at most limit.

      const [hit] = GeoLeaf?.Layers?.search("PT-4472") ?? [];
      if (hit) console.log(hit.label, hit.layerId, hit.featureId);
    • 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.

      Parameters

      • layerId: string

        The feature's layer.

      • id: string | number

        Its id (feature.id or properties.id).

      • Optionalopts: LayerFocusOptions

        zoom for a point.

      Returns boolean

      true once framed; false — and nothing moved — when the layer does not hold that feature, or there is no map.

      const [hit] = GeoLeaf?.Layers?.search("PT-4472") ?? [];
      if (hit?.featureId) GeoLeaf?.Layers?.focus(hit.layerId, hit.featureId);
    • 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.

      Parameters

      • layerId: string

      Returns boolean

    • 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.

      Parameters

      • layerId: string

      Returns boolean

    • 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.

      Parameters

      • layerId: string

      Returns boolean

    • 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.

      Parameters

      • layerId: string

      Returns VisibilitySource | null

    • 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.

      Parameters

      • layerId: string

      Returns LayerStyleInfo | null

    • 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.

      Parameters

      Returns boolean

      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.

      Parameters

      Returns Promise<CreatedLayer | null>

      The created layer, or null when the definition named no resolvable source or was skipped by active: false (the reason is logged).

      When def.id is missing, or already names a layer.

    • Replaces a layer's base features, re-renders the source, and emits.

      Parameters

      • layerId: string
      • features: Feature<Geometry, GeoJsonProperties>[]

      Returns void

    • Re-keys a feature (temp id → server id) on both feature.id and properties.id.

      Parameters

      • layerId: string
      • oldId: string | number
      • newId: string | number

      Returns void

    • 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.

      Parameters

      • layerId: string
      • id: string | number
      • patch: Record<string, unknown>
      • Optionalopts: { rerender?: boolean }

      Returns void

    • 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.

      Parameters

      • layerId: string
      • predicate: (f: Feature) => boolean

      Returns void

    • 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.

      Parameters

      • layerId: string

      Returns void

    • 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.

      Parameters

      • layerId: string

        The layer.

      • ids: readonly (string | number)[] | null

        The features to hide, or null to show them again.

      Returns void

      GeoLeaf?.Layers?.hideFeatures("sites", ["PT-42"]);
      GeoLeaf?.Layers?.hideFeatures("sites", null);
    • Upserts features into the base dataset, de-duplicated by id.

      Parameters

      • layerId: string
      • features: readonly Feature<Geometry, GeoJsonProperties>[]

      Returns void