Skip to content

GeoLeaf Configuration Guide

Product Version: GeoLeaf Platform V2 Version: 2.0.0 Last Updated: avril 2026 Level: Intermediate to Advanced

Version courante : GeoLeaf v2.0.0. Structure de profil modulaire avec fichiers séparés basemaps.json et ui.json.

This comprehensive guide documents all JSON configuration files used by GeoLeaf JS to customize behavior, appearance, and data sources for different business profiles (Tourism, Custom…).


Table of Contents

  1. Overview
  2. geoleaf.config.json - Main Configuration
  3. profile.json - Profile Configuration
  4. taxonomy.json - Categories and Icons
  5. themes.json - Layer Visibility Presets
  6. layers.json - Layer Definitions
  7. mapping.json - Data Normalization
  8. Style Files - Layer Styling
  9. POI Configuration
  10. Route Configuration
  11. POI Add Feature — showAddPoi vs poiAddConfig.enabled
  12. geocodingConfig — Address Search

1. Overview

Configuration File Hierarchy

geoleaf.config.json              (Racine — optionnel, sélection du profil)
  └── profiles/
      └── {profile-name}/
          ├── profile.json       (REQUIS — métadonnées, section Files)
          ├── basemaps.json      (REQUIS — sources de tuiles)
          ├── ui.json            (REQUIS — contrôles UI)
          ├── layers.json        (REQUIS — liste des couches)
          ├── taxonomy.json      (REQUIS — catégories & icônes POI)
          ├── themes.json        (REQUIS — préréglages de visibilité)
          ├── mapping.json       (Optionnel — normalisation données POI)
          └── layers/            (Optionnel — configs & données GeoJSON)
              └── {layer-id}/
                  ├── {layer-id}_config.json
                  └── styles/
                      ├── defaut.json
                      └── *.json

Load Order

  1. geoleaf.config.json is loaded first (or defaults are used)
  2. profile.json is loaded based on activeProfile
  3. taxonomy.json, themes.json, mapping.json are loaded in parallel
  4. Layer configs and styles are loaded on-demand when layers are activated
  5. POI/route data loaded as configured in profile.json

Configuration Principles

  • JSON Schema validation - All files validated against schemas (see schema/)
  • Graceful fallbacks - Missing optional files use sensible defaults
  • Profile isolation - Each profile is self-contained
  • Hot-reloading - Most configs can be updated without page reload
  • Type safety - TypeScript definitions available in index.d.ts

2. geoleaf.config.json - Main Configuration

Location: Project root or custom path
Required: No (uses defaults if missing)
Purpose: Define which profile to load and debug settings

Complete Structure

json
{
    "debug": false,
    "data": {
        "activeProfile": "tourism",
        "profilesBasePath": "/profiles/"
    },
    "logging": {
        "level": "info"
    },
    "branding": {
        "enabled": false,
        "text": "Mon Application",
        "position": "bottom-left"
    },
    "security": {
        "httpsOnly": false
    }
}

Field Reference

debug (boolean, optional)

Active le logging verbeux dans la console. Valeur par défaut : false.

json
{ "debug": true }

Pour contrôler le niveau de log, utilisez la section logging :

json
{
    "logging": {
        "level": "debug"
    }
}

Niveaux disponibles : "debug", "info", "warn", "error", "production".

branding (object, optional)

Overlay de branding affiché sur la carte.

ChampTypeDescription
enabledbooleanActiver l'overlay. Défaut false.
textstringTexte affiché.
positionstringPosition sur la carte (ex. "bottom-left").

security (object, optional)

ChampTypeDescription
httpsOnlybooleanRejette les URLs http: (sauf images data:). Défaut false.

data (object, required)

Data loading configuration.

FieldTypeDefaultDescription
activeProfilestring"default"Profile name to load. Must match a directory in profilesBasePath
profilesBasePathstring"/profiles/"Base path to profiles directory (relative to HTML page or absolute URL)

Example:

json
{
    "data": {
        "activeProfile": "tourism",
        "profilesBasePath": "https://cdn.example.com/geoleaf-profiles/"
    }
}

performance (object, optional)

Performance optimization settings.

ChampTypeDéfautDescription
maxConcurrentLayersnumber10Nombre maximum de couches chargées en parallèle
layerLoadDelaynumber200Délai en ms entre chaque chargement de couche
fitBoundsOnThemeChangebooleanfalseRecadrer la carte lors du changement de thème

3. profile.json - Profile Configuration

Location: profiles/{profile-name}/profile.json
Required: Yes (each profile must have this file)
Purpose: Define UI, basemaps, file paths, and default settings

Complete Structure

json
{
    "id": "my-profile",
    "label": "Mon Profil",
    "description": "Description du profil",
    "version": "1.3.0",
    "map": {
        "bounds": [
            [-56, -74],
            [-21, -53]
        ],
        "center": [-15, -62],
        "zoom": 6,
        "maxZoom": 18,
        "positionFixed": true
    },
    "Files": {
        "taxonomyFile": "taxonomy.json",
        "themesFile": "themes.json",
        "layersFile": "layers.json",
        "basemapsFile": "basemaps.json",
        "uiFile": "ui.json"
    },
    "performance": {
        "maxConcurrentLayers": 10,
        "layerLoadDelay": 200,
        "fitBoundsOnThemeChange": false
    },
    "clusteringConfig": {
        "enabled": true,
        "strategy": "by-layer",
        "maxClusterRadius": 80,
        "disableClusteringAtZoom": 12
    },
    "poiConfig": {
        "enabled": false
    }
}

Field Reference

ui (object, optional)

UI component configuration. Each component has the same structure:

FieldTypeDefaultDescription
enabledbooleanfalseWhether component is visible
positionstringvariesMapLibre GL JS control position: "topleft", "topright", "bottomleft", "bottomright"
collapsedbooleanfalseInitial collapsed state (if applicable)
titlestringvariesComponent title/label

Available components:

  • layerManager - Layer visibility controls
  • filterPanel - POI filtering UI
  • searchBar - Search input with autocomplete
  • cacheControls - Offline cache management buttons
  • themeSelector - Theme dropdown selector

basemaps (array, required)

Background map definitions.

FieldTypeRequiredDescription
idstringUnique basemap identifier
namestringDisplay name in UI
urlstringTile URL template with {z}, {x}, {y} placeholders
attributionstringCopyright/attribution HTML
maxZoomnumberMaximum zoom level (1-20)
minZoomnumberMinimum zoom level (1-20)
defaultbooleanWhether this is the default basemap
tileSizenumberTile size in pixels (default: 256)
subdomainsarray<string>Subdomains for load balancing (default: ["a","b","c"])

Common tile providers:

json
{
    "basemaps": [
        {
            "id": "osm",
            "name": "OpenStreetMap",
            "url": "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
            "attribution": "&copy; OpenStreetMap",
            "default": true
        },
        {
            "id": "topo",
            "name": "OpenTopoMap",
            "url": "https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png",
            "attribution": "&copy; OpenTopoMap",
            "maxZoom": 17
        },
        {
            "id": "cartodb-light",
            "name": "CartoDB Light",
            "url": "https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}.png",
            "attribution": "&copy; CartoDB"
        }
    ]
}

Files (object, required)

Paths to configuration and data files (relative to profile directory).

ChampTypeRequisDescription
taxonomyFilestringChemin vers taxonomy.json
themesFilestringChemin vers themes.json
layersFilestringChemin vers layers.json (index des couches)
basemapsFilestringChemin vers basemaps.json (fonds de carte)
uiFilestringChemin vers ui.json (composants UI)
mappingFilestringChemin vers mapping.json (normalisation POI)

Directory (object, optional)

Path templates for layer-specific files. Use {layerId} placeholder.

FieldTypeDescription
stylesstringPath template to styles directory
datastringPath template to GeoJSON data file

Example:

json
{
    "Directory": {
        "styles": "layers/{layerId}/styles/",
        "data": "layers/{layerId}/data.geojson"
    }
}

Resolved for layer "cities":

  • Styles: profiles/tourism/layers/cities/styles/
  • Data: profiles/tourism/layers/cities/data.geojson

poiAddConfig (object, optional)

Configuration for POI creation form.

FieldTypeDefaultDescription
enabledbooleantrueAllow users to add POIs
categoriesarray<string>[]Available categories in form
defaultCategorystringfirst in arrayPre-selected category
requiredFieldsarray<string>["title","latlng"]Required form fields
optionalFieldsarray<string>[]Optional form fields
allowCustomCategoriesbooleanfalseAllow users to create new categories
validationobject{}Field validation rules

Validation rules:

json
{
    "validation": {
        "title": {
            "minLength": 3,
            "maxLength": 100,
            "pattern": "^[a-zA-Z0-9\\s-]+$"
        },
        "phone": {
            "pattern": "^\\+?[0-9\\s-]+$"
        },
        "website": {
            "pattern": "^https?://.*$"
        }
    }
}

search (object, optional)

Search configuration.

FieldTypeDefaultDescription
enabledbooleantrueEnable search functionality
sourcesarray<string>["poi"]Data sources to search: "poi", "layers"
fieldsarray<string>["title"]Fields to search in
fuzzyMatchbooleanfalseEnable fuzzy string matching
fuzzyThresholdnumber0.6Fuzzy match threshold (0-1, lower = more strict)

defaultSettings (object, optional)

Initial map state.

json
{
    "defaultSettings": {
        "map": {
            "center": [48.8566, 2.3522],
            "zoom": 12,
            "minZoom": 5,
            "maxZoom": 18
        },
        "theme": "light",
        "basemap": "osm",
        "language": "fr"
    }
}

basemaps.json

Localisation : profiles/{profile-name}/basemaps.jsonRequis : Oui (depuis v2.0.0) Référencé par : profile.json → Files.basemapsFile

Définit les sources de tuiles disponibles. Chaque entrée est indexée par son ID.

json
{
    "basemaps": {
        "street": {
            "id": "street",
            "label": "OpenStreetMap",
            "type": "tile",
            "url": "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
            "subdomains": "abc",
            "attribution": "&copy; OpenStreetMap contributors",
            "minZoom": 3,
            "maxZoom": 19,
            "tileSize": 256,
            "defaultBasemap": true,
            "offline": true
        },
        "maplibre_vector": {
            "id": "maplibre_vector",
            "label": "Carte vectorielle",
            "type": "maplibre",
            "style": "https://cdn.example.com/styles/vector.json",
            "fallbackUrl": "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
            "defaultBasemap": false
        }
    }
}
ChampTypeDescription
idstringIdentifiant (miroir de la clé)
labelstringLibellé dans le sélecteur
type"tile" | "maplibre""tile" = raster, "maplibre" = vectoriel GL
urlstringTemplate URL raster avec {s}, {z}, {x}, {y}
stylestringURL du style MapLibre GL (type "maplibre" uniquement)
fallbackUrlstringURL raster de secours si MapLibre GL indisponible
tilesstring[]Tableau d'URLs explicites (remplace expansion {s})
subdomainsstring | string[]Sous-domaines de rotation
attributionstringAttribution HTML
tileSizenumberTaille des tuiles en pixels. Défaut 256.
defaultBasemapbooleanBasemap active au démarrage
offlinebooleanSupport du cache offline

ui.json

Localisation : profiles/{profile-name}/ui.jsonRequis : Oui (depuis v2.0.0) Référencé par : profile.json → Files.uiFile

Configure la visibilité et le comportement des composants UI. Ces paramètres étaient dans la section ui de profile.json avant v2.0.0 (toujours supporté en rétrocompat inline).

json
{
    "ui": {
        "theme": "light",
        "language": "fr",
        "showBaseLayerControls": false,
        "showLayerManager": true,
        "showFilterPanel": true,
        "showThemeSelector": true,
        "showLegend": false,
        "showTable": true,
        "showGeolocation": true,
        "showCoordinates": true,
        "showScale": true,
        "showCacheButton": false,
        "showAddPoi": false,
        "permalink": {
            "enabled": false,
            "mode": "hash",
            "fields": ["lat", "lng", "zoom", "layers"]
        }
    }
}
ChampTypeDéfautDescription
theme"light" | "dark" | "auto""auto"Thème UI
languagestring"fr"Code langue
showBaseLayerControlsbooleantrueBouton sélecteur de fond de carte
showLayerManagerbooleantruePanneau de gestion des couches
showFilterPanelbooleantruePanneau de filtres/recherche
showThemeSelectorbooleantrueBouton sélection de thème
showLegendbooleantruePanneau légende
showTablebooleantruePanneau tableau de données
showGeolocationbooleantrueBouton géolocalisation GPS
showCoordinatesbooleantrueAffichage des coordonnées
showScalebooleantrueAffichage de la barre d'échelle
showCacheButtonbooleanfalseBouton cache offline (@geoleaf-plugins/storage requis)
showAddPoibooleanfalseBouton ajout POI (@geoleaf-plugins/addpoi requis)
permalink.enabledbooleanfalseSynchronisation état dans l'URL
permalink.mode"hash" | "query" | "compact""hash"Stratégie d'encodage URL
permalink.fieldsstring[]all fieldsChamps d'état à sérialiser dans l'URL (ex: ["lat","lng","zoom","layers"])

Note : cache offlineshowCacheButton: true pré-suppose l’installation du plugin commercial @geoleaf-plugins/storage (IndexedDB). Le core @geoleaf/core ne fournit qu’un détecteur de connectivité (offline-detector). Sans le plugin, le bouton ne s’affiche pas même si l’option est activée.

searchConfig (objet, optionnel)

Configure le panneau de filtres/recherche (affiché si ui.showFilterPanel: true). Dans ui.json depuis v2.0.0, cette clé remplace search de l'ancien profile.json inline.

json
{
    "searchConfig": {
        "title": "Filtrer",
        "radiusMin": 1,
        "radiusMax": 200,
        "radiusStep": 1,
        "radiusDefault": 10,
        "searchPlaceholder": "Rechercher un POI\u2026",
        "filters": [
            {
                "id": "searchText",
                "type": "search",
                "label": "Recherche textuelle",
                "placeholder": "Rechercher...",
                "searchFields": ["title", "properties.name", "description"]
            },
            {
                "id": "proximity",
                "type": "proximity",
                "label": "Recherche par proximit\u00e9",
                "buttonLabel": "Activer",
                "instructionText": "Cliquez sur la carte pour d\u00e9finir le point central"
            },
            {
                "id": "categories",
                "type": "tree",
                "label": "Cat\u00e9gories"
            },
            {
                "id": "tags",
                "type": "multiselect-tags",
                "label": "Tags",
                "field": "attributes.tags"
            }
        ],
        "actions": {
            "applyLabel": "Appliquer",
            "resetLabel": "R\u00e9initialiser"
        }
    }
}
ChampTypeDescription
titlestringTitre du panneau de filtres
radiusMinnumberRayon minimum de la recherche par proximité (km)
radiusMaxnumberRayon maximum (km)
radiusStepnumberPas du curseur de rayon (km)
radiusDefaultnumberRayon par défaut (km)
searchPlaceholderstringPlaceholder du champ de recherche textuelle
filtersarrayListe des filtres (voir types ci-dessous)
actions.applyLabelstringLibellé du bouton "Appliquer"
actions.resetLabelstringLibellé du bouton "Réinitialiser"

Types de filtre disponibles (filters[].type) :

TypeDescription
"search"Champ de recherche textuelle libre
"proximity"Filtre géographique par rayon autour d'un point
"tree"Arbre de sélection hiérarchique (catégories)
"multiselect-tags"Sélection multiple par tags
"select"Liste déroulante (valeur unique)
"range"Curseur de plage numérique

tableConfig (objet, optionnel)

Configure le panneau tableau de données (module Table, lazy-loadé).

json
{
    "tableConfig": {
        "title": "Tableau",
        "enabled": true,
        "defaultVisible": false,
        "pageSize": 50,
        "maxRowsPerLayer": 10000,
        "enableExportButton": true,
        "virtualScrolling": true,
        "defaultHeight": "40%",
        "minHeight": "20%",
        "maxHeight": "60%",
        "resizable": true
    }
}
ChampTypeDéfautDescription
titlestringTitre affiché dans l'en-tête du panneau
enabledbooleantrueActive ou désactive le module Table
defaultVisiblebooleanfalsePanneau visible au démarrage
pageSizenumber50Nombre de lignes par page
maxRowsPerLayernumber10000Limite de lignes affichées par couche
enableExportButtonbooleantrueAffiche le bouton d'export CSV
virtualScrollingbooleantrueActive le défilement virtuel (performances sur grands jeux)
defaultHeightstring"40%"Hauteur initiale du panneau (CSS)
minHeightstring"20%"Hauteur minimale lors du redimensionnement
maxHeightstring"60%"Hauteur maximale lors du redimensionnement
resizablebooleantruePermet à l'utilisateur de redimensionner le panneau

scaleConfig (objet, optionnel)

Configure l'affichage de l'échelle (activé si ui.showScale: true).

json
{
    "scaleConfig": {
        "scaleGraphic": true,
        "scaleNumeric": true,
        "scaleNumericEditable": true,
        "scaleNivel": true,
        "position": "bottomleft"
    }
}
ChampTypeDéfautDescription
scaleGraphicbooleantrueAffiche la barre d'échelle graphique
scaleNumericbooleantrueAffiche la valeur numérique de l'échelle
scaleNumericEditablebooleantruePermet la saisie manuelle d'une valeur d'échelle
scaleNivelbooleantrueAffiche le niveau de zoom numérique
positionstring"bottomleft"Position : bottomleft, bottomright, topleft, topright

4. taxonomy.json - Categories and Icons

Location: profiles/{profile-name}/taxonomy.json
Required: Yes
Purpose: Define hierarchical categories, subcategories, and icon mappings

Complete Structure

json
{
    "icons": {
        "spriteUrl": "icons/sprite_tourism.svg",
        "symbolPrefix": "tourism-poi-cat-",
        "defaultIcon": "activity-generic"
    },
    "defaults": {
        "icon": "activity-generic"
    },
    "categories": {
        "activites": {
            "label": "Activités",
            "icon": "activity-generic",
            "subcategories": {
                "randonnee": {
                    "label": "Randonnée",
                    "icon": "activity-mountain"
                },
                "velo": {
                    "label": "Vélo",
                    "icon": "activity-vehicle"
                }
            }
        },
        "hebergement": {
            "label": "Hébergements",
            "icon": "lodging-hotel",
            "subcategories": {
                "hotel": {
                    "label": "Hôtel",
                    "icon": "lodging-hotel"
                },
                "camping": {
                    "label": "Camping",
                    "icon": "lodging-camping"
                }
            }
        },
        "culture": {
            "label": "Culture",
            "icon": "culture-building",
            "subcategories": {
                "musee": {
                    "label": "Musée",
                    "icon": "culture-building"
                },
                "monument": {
                    "label": "Monument",
                    "icon": "culture-building"
                }
            }
        }
    }
}

Field Reference

icons (object, required)

Configuration du sprite SVG pour les icônes POI (format MapLibre GL JS).

FieldTypeRequiredDescription
spriteUrlstringChemin vers le fichier sprite SVG (relatif au profil)
symbolPrefixstringPréfixe des noms de symboles dans le sprite (ex: "tourism-poi-cat-")
defaultIconstringIdentifiant du symbole utilisé en fallback

defaults (object, optional)

FieldTypeRequiredDescription
iconstringIcône par défaut pour les POI sans catégorie

categories (object, required)

Définitions des catégories de premier niveau, sous forme d'objet clé→valeur. Les clés sont les identifiants de catégorie.

FieldTypeRequiredDescription
labelstringNom d'affichage de la catégorie
iconstringIdentifiant du symbole dans le sprite
subcategoriesobjectSous-catégories (objet clé→valeur)

subcategories (object, optional)

Sous-catégories d'une catégorie parente, sous forme d'objet clé→valeur. Les clés sont les identifiants de sous-catégorie.

FieldTypeRequiredDescription
labelstringNom d'affichage de la sous-catégorie
iconstringIdentifiant du symbole (peut différer du parent)

5. themes.json - Layer Visibility Presets

Location: profiles/{profile-name}/themes.json
Required: Yes
Purpose: Define named presets that control which layers are visible

Complete Structure

json
{
    "config": {
        "defautTheme": "defaut",
        "primaryThemes": {
            "enabled": true,
            "position": "top-map"
        },
        "secondaryThemes": {
            "enabled": true,
            "showNavigationButtons": true,
            "position": "top-layermanager"
        }
    },

    "themes": [
        {
            "id": "defaut",
            "label": "Vue par défaut",
            "description": "Vue standard avec les couches principales",
            "type": "primary",
            "icon": "🗺️",
            "layers": [
                { "id": "cities", "visible": true, "style": "defaut" },
                { "id": "climate", "visible": true, "style": "defaut" },
                { "id": "poi", "visible": true, "style": "defaut" }
            ]
        },
        {
            "id": "nature",
            "label": "Nature",
            "description": "Zones naturelles et protégées",
            "type": "primary",
            "icon": "🌿",
            "layers": [
                { "id": "cities", "visible": false, "style": "defaut" },
                { "id": "climate", "visible": false, "style": "defaut" },
                { "id": "poi", "visible": true, "style": "defaut" },
                { "id": "conservation-zones", "visible": true, "style": "defaut" }
            ]
        }
    ]
}

Field Reference

config (object, optional)

Theme system configuration.

FieldTypeDefaultDescription
defautThemestringfirst theme IDIdentifiant du thème actif au démarrage
primaryThemes.enabledbooleantrueAfficher le sélecteur de thèmes primaires
primaryThemes.positionstring"top-map"Position du contrôle dans l'UI
secondaryThemes.enabledbooleanfalseActiver les thèmes secondaires
secondaryThemes.showNavigationButtonsbooleanfalseAfficher les boutons de navigation
secondaryThemes.positionstring"top-layermanager"Position du contrôle secondaire

themes (array, required)

Theme definitions.

FieldTypeRequiredDescription
idstringIdentifiant unique du thème
labelstringNom d'affichage du thème
descriptionstringDescription affichée dans l'UI
typestring"primary" (visible dans le sélecteur) ou "secondary" (programmatique)
iconstringIcône (emoji ou identifiant) pour le bouton thème
layersarrayTableau d'entrées {id, visible, style} définissant la visibilité de chaque couche

Format d'entrée dans layers :

FieldTypeRequiredDescription
idstringIdentifiant de la couche (doit correspondre à l'id dans layers.json)
visiblebooleanVisibilité initiale de la couche pour ce thème
stylestringVariante de style à appliquer (défaut : "defaut")

Theme types:

  • primary — Affiché dans le sélecteur de thèmes, accessible par l'utilisateur
  • secondary — Masqué dans l'UI, déclenché programmatiquement ou utilisé comme preset

Layer References

The layers object keys must match layer IDs defined in:

  • Layer directories: layers/{layerId}/
  • Layer config files: layers/{layerId}/config.json
  • GeoJSON layer IDs added via /* GeoLeaf.GeoJSON est interne - configurer via geojsonLayers dans geoleaf.config.json */

Example matching:

profiles/tourism/
  layers/
    climate/          ← ID: "climate"
    cities/           ← ID: "cities"
    monuments/        ← ID: "monuments"
  themes.json         ← References "climate", "cities", "monuments"

Dynamic Theme Creation

javascript
// Create custom theme programmatically
await GeoLeaf.Theme.create({
    id: "my-custom",
    name: "My Custom Theme",
    type: "secondary",
    layers: {
        poi: true,
        cities: true,
        climate: false,
    },
});

// Activate it
await GeoLeaf.Theme.setActive("my-custom");

6. layers.json - Layer Definitions

Location: profiles/{profile-name}/layers.json OR profiles/{profile-name}/layers/{layerId}/config.json
Required: No (layers can be defined inline or in separate files)
Purpose: Define GeoJSON layer properties, data sources, and default styles

Complete Structure

layers.json (fichier d'index) :

json
{
    "layers": [
        {
            "id": "cities",
            "configFile": "layers/cities/cities_config.json",
            "layerManagerId": "data-administration"
        },
        {
            "id": "climate",
            "configFile": "layers/climate/climate_config.json",
            "layerManagerId": "data-environment"
        }
    ]
}

Config individuelle (layers/{layerId}/{layerId}_config.json) :

json
{
    "id": "cities",
    "label": "Villes principales",
    "zIndex": 40,
    "geometry": "point",
    "data": {
        "directory": "data",
        "file": "cities.geojson"
    },
    "styles": {
        "directory": "styles",
        "default": "defaut.json",
        "available": [{ "id": "defaut", "label": "Défaut", "file": "defaut.json" }]
    },
    "table": { "enabled": false },
    "clustering": { "enabled": false }
}

Field Reference

layers.json — Fichier d'index

FieldTypeRequiredDescription
idstringIdentifiant unique de la couche
configFilestringChemin relatif vers la config individuelle de la couche
layerManagerIdstringIdentifiant du groupe dans le gestionnaire de couches

Config individuelle {layerId}_config.json

FieldTypeRequiredDescription
idstringIdentifiant unique (doit correspondre au nom de répertoire)
labelstringNom d'affichage de la couche
zIndexnumberOrdre de rendu (plus élevé = dessiné au-dessus)
geometrystringType géométrique : "point", "polyline", "polygon"
data.directorystringSous-répertoire des données (défaut : "data")
data.filestringFichier GeoJSON (relatif au répertoire de la couche)
styles.directorystringSous-répertoire des styles (défaut : "styles")
styles.defaultstringNom du fichier de style par défaut
styles.availablearrayVariantes de style disponibles {id, label, file}
table.enabledbooleanActiver le panneau table de données
clustering.enabledbooleanActiver le clustering (couches de type point)

Multi-Layer Configuration File

To define all layers in one file (layers.json):

json
{
    "layers": [
        {
            "id": "climate",
            "name": "Climate Zones",
            "type": "polygon",
            "dataSource": "layers/climate/data.geojson",
            "defaultStyle": "default"
        },
        {
            "id": "cities",
            "name": "Cities",
            "type": "point",
            "dataSource": "layers/cities/data.geojson",
            "defaultStyle": "default"
        }
    ]
}

7. mapping.json - Data Normalization

Location: profiles/{profile-name}/mapping.json
Required: No
Purpose: Mapper les noms de champs externes vers la structure interne de GeoLeaf

Complete Structure

json
{
    "source": "description ou endpoint source (informatif)",
    "mapping": {
        "id": "external_id",
        "title": "name",
        "lat": "latitude",
        "lng": "longitude",
        "categoryId": "poi_type"
    }
}

Field Reference

FieldTypeRequiredDescription
sourcestringDescription ou URL de la source de données (informatif)
mappingobjectTable de correspondance : {champGeoLeaf: "champExterne"}

Champs mappables dans mapping :

Clé GeoLeafDescription
idIdentifiant unique du POI
titleNom du POI
latLatitude
lngLongitude
categoryIdIdentifiant de catégorie (correspond à taxonomy)

Pour le format complet du normaliseur et les options de transformation avancées, voir data-normalizer.md.


8. Style Files - Layer Styling

Location: profiles/{profile-name}/layers/{layerId}/styles/{styleId}.json
Required: At least one style (usually default.json) per layer
Purpose: Define visual appearance, labels, and legend for layer

Complete Structure

json
{
    "id": "default",
    "name": "Default Style",
    "name_fr": "Style par défaut",
    "description": "Standard visualization for climate zones",

    "label": {
        "enabled": true,
        "visibleByDefault": false,
        "field": "name",
        "format": "{name}",
        "minZoom": 10,
        "maxZoom": 18
    },

    "layerScale": {
        "minZoom": 5,
        "maxZoom": 18
    },

    "labelScale": {
        "minZoom": 10,
        "maxZoom": 18
    },

    "style": {
        "fillColor": "#3388ff",
        "fillOpacity": 0.2,
        "color": "#3388ff",
        "weight": 2,
        "opacity": 1,
        "dashArray": null
    },

    "styleRules": [
        {
            "condition": { "property": "climate_type", "equals": "Temperate" },
            "style": {
                "fillColor": "#66cc66",
                "color": "#44aa44"
            }
        },
        {
            "condition": { "property": "climate_type", "equals": "Mediterranean" },
            "style": {
                "fillColor": "#ff8833",
                "color": "#dd6611"
            }
        }
    ],

    "legend": {
        "enabled": true,
        "title": "Climate Types",
        "items": [
            {
                "label": "Temperate",
                "label_fr": "Tempéré",
                "color": "#66cc66",
                "icon": null
            },
            {
                "label": "Mediterranean",
                "label_fr": "Méditerranéen",
                "color": "#ff8833",
                "icon": null
            },
            {
                "label": "Continental",
                "label_fr": "Continental",
                "color": "#3388ff",
                "icon": null
            }
        ]
    }
}

Field Reference

label (object, required)

Label configuration for this style.

FieldTypeRequiredDescription
enabledbooleanWhether labels are supported for this style
visibleByDefaultbooleanInitial label visibility when layer activated (depuis v2.0.0 — voir Labels documentation)
fieldstringGeoJSON property field to use for label text
formatstringLabel template with {fieldName} placeholders
minZoomnumberMinimum zoom for label visibility (overrides labelScale.minZoom)
maxZoomnumberMaximum zoom for label visibility

Note : visibleByDefault doit se trouver dans le fichier de style, pas dans la config de couche. Voir la documentation Labels.

Label format examples:

jsonc
{
  "format": "{name}"                           // Simple field
}
{
  "format": "{name} ({population})"            // Multiple fields
}
{
  "format": "{name} - {climate_type}"          // With separator
}

layerScale (object, optional)

Zoom range for layer visibility (features are rendered).

FieldTypeDefaultDescription
minZoomnumber1Minimum zoom level
maxZoomnumber18Maximum zoom level

labelScale (object, optional)

Zoom range for label visibility (typically narrower than layerScale to avoid clutter).

FieldTypeDefaultDescription
minZoomnumber10Minimum zoom level for labels
maxZoomnumber18Maximum zoom level for labels

Best practice: Set labelScale.minZoom higher than layerScale.minZoom:

jsonc
{
    "layerScale": { "minZoom": 5, "maxZoom": 18 }, // Layer visible from zoom 5
    "labelScale": { "minZoom": 10, "maxZoom": 18 }, // Labels visible from zoom 10
}

style (object, required)

MapLibre GL JS paint/layout options for styling features.

For polygons/multipolygons:

FieldTypeDescription
fillColorstringFill color (hex, rgb, or named color)
fillOpacitynumberFill opacity (0-1)
colorstringBorder color
weightnumberBorder width in pixels
opacitynumberBorder opacity (0-1)
dashArraystringDash pattern (e.g., "5, 10") or null for solid

For lines:

FieldTypeDescription
colorstringLine color
weightnumberLine width in pixels
opacitynumberLine opacity (0-1)
dashArraystringDash pattern or null
lineCapstringLine cap style: "butt", "round", "square"
lineJoinstringLine join style: "miter", "round", "bevel"

For points (markers):

Markers use taxonomy icon configuration, not style settings.

styleRules (array, optional)

Conditional styling based on feature properties.

Rule structure:

jsonc
{
    "condition": {
        "property": "field_name",
        "operator": "equals", // equals, contains, gt, gte, lt, lte, in
        "value": "comparison_value",
    },
    "style": {
        // Override style properties
    },
}

Operators:

  • equals - Exact match
  • contains - String contains substring
  • gt / gte - Greater than / greater than or equal
  • lt / lte - Less than / less than or equal
  • in - Value in array

Examples:

json
{
    "styleRules": [
        {
            "condition": { "property": "population", "operator": "gt", "value": 1000000 },
            "style": { "fillColor": "#ff0000", "weight": 3 }
        },
        {
            "condition": { "property": "type", "operator": "in", "value": ["city", "town"] },
            "style": { "fillColor": "#ffff00" }
        }
    ]
}

legend (object, optional)

Legend configuration for this style.

FieldTypeRequiredDescription
enabledbooleanWhether to display legend
titlestringLegend title
title_frstringLocalized title
itemsarrayLegend item definitions

Legend item:

jsonc
{
    "label": "Item Label",
    "label_fr": "Libellé",
    "color": "#ff0000",
    "icon": null, // Or icon identifier
    "description": "Optional description",
}

9. POI Configuration

Location: profiles/{profile-name}/data/poi.json
Required: No (POIs can be added programmatically)
Purpose: Initial POI data loaded on map initialization

Structure

json
{
    "version": "1.0",
    "lastUpdated": "2026-01-20",
    "count": 3,

    "pois": [
        {
            "id": "eiffel-tower",
            "latlng": [48.8584, 2.2945],
            "title": "Eiffel Tower",
            "description": "Iconic iron lattice tower",
            "category": "monument",
            "subcategory": "landmark",
            "properties": {
                "address": "Champ de Mars, 5 Avenue Anatole France, 75007 Paris",
                "phone": "+33 892 70 12 39",
                "website": "https://www.toureiffel.paris",
                "openingHours": "9:00-23:45",
                "ticketPrice": "26.80 EUR",
                "accessibility": "partial",
                "rating": 4.6
            }
        },
        {
            "id": "louvre",
            "latlng": [48.8606, 2.3376],
            "title": "Louvre Museum",
            "description": "World's largest art museum",
            "category": "museum",
            "subcategory": "art",
            "properties": {
                "address": "Rue de Rivoli, 75001 Paris",
                "phone": "+33 1 40 20 50 50",
                "website": "https://www.louvre.fr",
                "openingHours": "9:00-18:00",
                "closedDays": ["Tuesday"],
                "ticketPrice": "17 EUR",
                "accessibility": "full"
            }
        },
        {
            "id": "notre-dame",
            "latlng": [48.853, 2.3499],
            "title": "Notre-Dame Cathedral",
            "description": "Medieval Catholic cathedral (under restoration)",
            "category": "monument",
            "subcategory": "religious",
            "properties": {
                "address": "6 Parvis Notre-Dame, 75004 Paris",
                "website": "https://www.notredamedeparis.fr",
                "status": "restoration",
                "reopening": "2024-12-08"
            }
        }
    ]
}

Field Reference

Root fields:

FieldTypeDescription
versionstringData version
lastUpdatedstringISO date of last update
countnumberTotal POI count
poisarrayArray of POI objects

POI object (required fields):

FieldTypeDescription
idstringUnique POI identifier
latlng[number, number]Coordinates [latitude, longitude]
titlestringPOI name/title
categorystringCategory ID (must match taxonomy)

POI object (optional fields):

FieldTypeDescription
descriptionstringPOI description
subcategorystringSubcategory ID (must match taxonomy)
propertiesobjectCustom properties (address, phone, etc.)

10. Route Configuration

Location: profiles/{profile-name}/data/routes.json
Required: No
Purpose: Define routes (paths, itineraries) with waypoints

Structure

json
{
    "version": "1.0",
    "routes": [
        {
            "id": "paris-tour",
            "name": "Paris Highlights Tour",
            "name_fr": "Tour des points forts de Paris",
            "description": "2-hour walking tour of major attractions",
            "type": "walking",
            "distance": 5200,
            "duration": 7200,
            "difficulty": "easy",

            "waypoints": [
                {
                    "id": "eiffel-tower",
                    "order": 1,
                    "latlng": [48.8584, 2.2945],
                    "title": "Eiffel Tower",
                    "stopDuration": 1800
                },
                {
                    "id": "trocadero",
                    "order": 2,
                    "latlng": [48.862, 2.2876],
                    "title": "Trocadéro",
                    "stopDuration": 600
                },
                {
                    "id": "arc-triomphe",
                    "order": 3,
                    "latlng": [48.8738, 2.295],
                    "title": "Arc de Triomphe",
                    "stopDuration": 900
                }
            ],

            "path": [
                [48.8584, 2.2945],
                [48.86, 2.29],
                [48.862, 2.2876],
                [48.865, 2.29],
                [48.8738, 2.295]
            ],

            "style": {
                "color": "#e74c3c",
                "weight": 4,
                "opacity": 0.7,
                "dashArray": null
            },

            "properties": {
                "accessibility": "wheelchair-friendly",
                "highlights": ["Eiffel Tower", "Arc de Triomphe"],
                "bestTime": "morning"
            }
        }
    ]
}

Field Reference

Route object:

FieldTypeRequiredDescription
idstringUnique route identifier
namestringRoute name
typestringRoute type: "walking", "cycling", "driving", "transit"
distancenumberTotal distance in meters
durationnumberEstimated duration in seconds
difficultystringDifficulty: "easy", "moderate", "hard"
waypointsarrayArray of waypoint objects
patharrayArray of [lat, lng] coordinates defining the route path
styleobjectMapLibre GL JS paint options for line/polyline styling
propertiesobjectCustom properties

Waypoint object:

FieldTypeRequiredDescription
idstringWaypoint identifier (can reference POI ID)
ordernumberStop order (1, 2, 3, ...)
latlng[number, number]Coordinates
titlestringWaypoint name
stopDurationnumberRecommended stop duration in seconds

11. POI Add Feature — showAddPoi vs poiAddConfig.enabled

The POI-add feature is governed by two complementary parameters that operate at different levels.

Difference in Usage

ParameterLocation in profile.jsonRole
ui.showAddPoiui sectionControls button visibility in the toolbar
poiAddConfig.enabledpoiAddConfig sectionEnables/disables the AddPOI plugin behavior

Priority Order

ui.showAddPoi is evaluated first. If false, the AddPOI control is not created and poiAddConfig is never read.

javascript
// control-poi-add.ts
if (!config?.ui?.showAddPoi) return; // primary gate — control not created

// poiAddConfig is only read after the gate passes
const defaultPosition = config?.poiAddConfig?.defaultPosition || "placement-mode";

JSON Examples

Show the add-POI button (minimum config):

json
{
    "ui": {
        "showAddPoi": true
    }
}

Full configuration with plugin behavior:

json
{
    "ui": {
        "showAddPoi": true
    },
    "poiAddConfig": {
        "enabled": true,
        "defaultPosition": "placement-mode"
    }
}

Disable the button without changing plugin config:

json
{
    "ui": {
        "showAddPoi": false
    }
}

Recommendation

  • To show or hide the button: use ui.showAddPoi only.
  • To configure behavior: use poiAddConfig (defaultPosition, enabled).
  • If ui.showAddPoi is false, poiAddConfig.enabled has no effect — the control is never built.
  • The AddPOI plugin must be loaded for the feature to be operational. If showAddPoi: true but the plugin is not loaded, a warning is emitted: ⚠️ Config has showAddPoi=true but AddPOI plugin is not loaded.

See also: Identifiant utilisateur pour l'édition POI


Localisation : Clé geocodingConfig dans geoleaf.config.json ou dans profile.json
Requis : Non (désactivé par défaut) **Façade publique :**GeoLeaf.Geocoding`

Configure le contrôle de recherche d’adresse intégré à la carte. Basé sur un widget de saisie avec suggestions en temps réel. 4 providers supportés — aucune clé API requise pour les providers open-data.

Référence des champs

ChampTypeDéfautDescription
enabledbooleanfalseActive le contrôle de recherche sur la carte
providerstring"addok"Provider de géocodage (voir tableau ci-dessous)
positionstring"top-right"Position du contrôle : "top-left", "top-right", "bottom-left", "bottom-right"
placeholderstring"Rechercher une adresse…"Texte du champ de saisie
minCharsnumber3Nombre min. de caractères avant déclenchement de la recherche
resultLimitnumber5Nombre max. de résultats affichés
debounceMsnumber300Délai en ms entre la saisie et le déclenchement de la requête
flyToZoomnumber15Niveau de zoom lors du survol vers un résultat ponctuel

Providers disponibles

Clé providerServiceZoneClé API
"addok"BAN — Base Adresse NationaleFranceAucune
"nominatim"OpenStreetMap NominatimMondialAucune
"photon"Photon par KomootMondialAucune
URL HTTPS customEndpoint retournant GeoJSON FCAu choixSelon l’API

Provider custom : passez une URL HTTPS complète comme valeur de provider. L’URL doit accepter un paramètre q={query} et retourner un GeoJSON FeatureCollection.

Exemples de configuration

Activer avec le provider par défaut (France) :

json
{
    "geocodingConfig": {
        "enabled": true
    }
}

Recherche mondiale via Nominatim :

json
{
    "geocodingConfig": {
        "enabled": true,
        "provider": "nominatim",
        "position": "top-left",
        "placeholder": "Search an address…",
        "resultLimit": 8,
        "flyToZoom": 14
    }
}

Provider custom :

json
{
    "geocodingConfig": {
        "enabled": true,
        "provider": "https://api.my-service.com/geocode",
        "minChars": 2,
        "resultLimit": 10
    }
}

Événement émis

Lors de la sélection d’un résultat par l’utilisateur :

ts
document.addEventListener("geoleaf:geocoding:result", (e) => {
    const { label, lat, lng, bounds } = e.detail;
    console.log(`Adresse sélectionnée : ${label} (${lat}, ${lng})`);
});
// ou via GeoLeaf.Events:
GeoLeaf.Events.on("geoleaf:geocoding:result", (e) => {
    console.log(e.detail.label);
});

Note : La recherche Nominatim est soumise aux conditions d’utilisation d’OSM. Pour un usage intensif, hébergez votre propre instance ou utilisez un provider commercial.


Configuration Best Practices

1. File Organization

profiles/
  tourism/
    profile.json              ← Main config (single source of truth)
    taxonomy.json             ← Categories
    themes.json               ← Themes
    mapping.json              ← Data mapping (optional)
    layers/
      climate/
        config.json           ← Layer config
        data.geojson          ← GeoJSON data
        styles/
          default.json        ← Default style
          detailed.json       ← Alternative style
      cities/
        ... (same structure)
    data/
      poi.json                ← Initial POIs
      routes.json             ← Routes

2. Validation

  • Always validate JSON before deploying (use JSONLint, VS Code, or npm run validate)
  • Use JSON Schema validation for strict type checking
  • Test with debug mode enabled: { "debug": { "enabled": true } }

3. Performance

  • Minimize file sizes - Use minified GeoJSON, compress with gzip
  • Lazy load layers - Don't load all layers on init, load on-demand
  • Use CDN for static files when possible
  • Enable clustering for 100+ POIs

4. Maintainability

  • Use descriptive IDs - "hotel-eiffel" not "h1"
  • Add descriptions - Future maintainers will thank you
  • Version your configs - Include version field in all files
  • Document custom properties - Add comments in separate README

5. Internationalization

  • Use name_{lang} pattern for translations
  • Support fallback - If name_fr missing, use name
  • Separate UI strings from config when possible

Migration Notes

Structure historique des labels (v2.0.0)

⚠️ BREAKING CHANGE: Label visibleByDefault moved from layer config to style files.

Ancienne structure (label dans la config couche) :

jsonc
// layers/cities/config.json
{
    "id": "cities",
    "labels": {
        "enabled": true,
        "visibleByDefault": false,
    },
}

Structure actuelle (label dans le fichier de style) :

jsonc
// layers/cities/styles/default.json
{
  "id": "default",
  "label": {
    "enabled": true,
    "visibleByDefault": false Moved here
  }
}

See Labels documentation for full migration instructions.


Identifiant utilisateur pour l'édition POI

GeoLeaf.AddPOI attribue les créations/modifications au champ modifiedBy, résolu dans cet ordre de priorité :

  1. Champ de config user.id dans le profil JSON actif
  2. sessionStorage clé gl-user-id (positionné par votre application hôte)
  3. Fallback anonyme anonymous-<timestamp> (cohérent sur la session)

Exemple d'intégration :

html
<script>
    sessionStorage.setItem("gl-user-id", currentUser.email);
</script>
<script type="module" src="dist/geoleaf.esm.js"></script>

Ou via le profil JSON :

json
{
    "user": {
        "id": "admin@example.com"
    }
}

Next Steps


Questions? Check FAQ or open an issue

Released under the MIT License.