# GeoLeaf Profiles Guide
Product Version: GeoLeaf Platform V2 Version: 2.0.0 Last Updated: mars 2026 Audience: Developers creating custom business profiles
Version courante : GeoLeaf v2.0.0 — structure de profil modulaire (10 fichiers).
Table of Contents
- What are Profiles?
- Profile Structure
- Built-in Profiles
- Creating Custom Profiles
- Profile Best Practices
- Profile Migration
- Troubleshooting
What are Profiles?
Definition
A GeoLeaf Profile is a self-contained configuration package that defines the complete behavior and appearance of a GeoLeaf map application for a specific business domain or use case.
Think of profiles as themes on steroids — they control not just visual styling, but also:
- Available POI categories and icons
- Map layers and data sources
- UI components and controls
- Search and filter capabilities
- Basemap options
- Default settings
Use Cases
| Profile Type | Best For | Example Applications |
|---|---|---|
| Tourism | Public-facing discovery | Tourist attractions, hiking trails, accommodations |
| Real Estate | Property management | Properties, buildings, land parcels |
| Emergency | Crisis response | Shelters, hospitals, emergency routes |
| Retail | Store management | Store locations, inventory, service areas |
When to Create Custom vs Use Built-in
Use Built-in Profile if:
- ✅ Your use case closely matches Tourism
- ✅ You only need minor customization (colors, labels)
- ✅ You want to start quickly
Create Custom Profile if:
- ✅ You have unique business domain requirements
- ✅ You need custom POI categories (e.g., medical facilities, schools)
- ✅ You require specific data sources or layers
- ✅ You need specialized UI components
- ✅ You want complete control over behavior
Profile Structure
Directory Layout
profiles/
├── geoleaf.config.json # Config racine (sélection du profil)
└── {profile-name}/ # Répertoire du profil
├── 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 externes
└── layers/ # ⚪ Optionnel — configs & données GeoJSON
└── {layer-id}/
├── {layer-id}_config.json # Config de la couche
└── styles/
├── defaut.json # Style par défaut
└── *.json # Styles alternatifsRequired Files
1. profile.json
Purpose: Main configuration file defining UI, basemaps, and behavior.
Key Sections:
{
"id": "my-profile",
"label": "My Custom Profile",
"description": "Brief description",
"version": "1.0.0",
"map": {
"bounds": [
[-56, -74],
[-21, -53]
],
"center": [-15, -62],
"zoom": 6,
"positionFixed": true
},
"Files": {
"taxonomyFile": "taxonomy.json",
"themesFile": "themes.json",
"layersFile": "layers.json",
"basemapsFile": "basemaps.json",
"uiFile": "ui.json"
},
"performance": {
"maxConcurrentLayers": 8,
"layerLoadDelay": 200,
"fitBoundsOnThemeChange": false
}
}See: Configuration Guide - profile.json
2. basemaps.json
Purpose: Defines tile sources (raster and vector). Extracted from profile.json since v2.0.0.
Key Structure:
{
"basemaps": {
"street": {
"id": "street",
"label": "Street Map",
"type": "tile",
"url": "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
"attribution": "© OpenStreetMap contributors",
"subdomains": "abc",
"minZoom": 3,
"maxZoom": 19,
"defaultBasemap": true,
"offline": true
},
"satellite": {
"id": "satellite",
"label": "Satellite",
"type": "maplibre",
"style": "https://cdn.example.com/styles/satellite.json",
"fallbackUrl": "https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}",
"defaultBasemap": false
}
}
}See: Configuration Guide - basemaps.json
3. ui.json
Purpose: UI controls visibility and configuration. Extracted from profile.json since v2.0.0.
Key Structure:
{
"showLayerManager": true,
"showFilterPanel": true,
"showThemeSelector": true,
"showLegend": true,
"showCacheButton": false,
"showAddPoi": false,
"enableGeolocation": true,
"language": "fr",
"permalink": {
"enabled": false,
"mode": "hash"
}
}See: Configuration Guide - ui.json
4. layers.json
Purpose: Lists all layers available in the profile.
Key Structure:
[
{
"id": "villes_principales",
"label": "Villes principales",
"configFile": "layers/villes_principales/villes_principales_config.json",
"visible": true,
"layerManagerId": "group-geo"
}
]5. taxonomy.json
Purpose: Defines POI categories, subcategories, and icon configuration.
Key Sections:
{
"icons": {
"spriteUrl": "path/to/sprite.svg",
"symbolPrefix": "my-prefix-",
"defaultIcon": "default-icon"
},
"categories": {
"category-1": {
"label": "Category 1",
"icon": "icon-name",
"subcategories": {
"subcat-1": {
"label": "Subcategory 1",
"icon": "icon-name"
}
}
}
}
}See: Configuration Guide - taxonomy.json
6. themes.json
Purpose: Defines layer visibility presets (themes).
Key Sections:
{
"config": {
"defautTheme": "default",
"primaryThemes": { "enabled": false },
"secondaryThemes": { "enabled": true, "placeholder": "Choisir un thème" }
},
"themes": [
{
"id": "default",
"label": "Vue complète",
"type": "primary",
"icon": "🗺️",
"layers": [
{ "id": "villes_principales", "visible": true },
{ "id": "routes_principales", "visible": false }
]
}
]
}See: Configuration Guide - themes.json
Optional Files
mapping.json
Purpose: Normalizes external data to GeoLeaf's internal format.
Use When:
- Loading data from external APIs
- Converting CSV/Excel to GeoJSON
- Transforming property names
- Applying data transformations (scale, regex, concat)
Example:
{
"poi": {
"mapping": {
"id": "feature_id",
"title": "name",
"latlng": {
"lat": "latitude",
"lng": "longitude"
},
"category": "poi_category",
"properties": {
"description": "desc",
"phone": "contact.phone"
}
}
},
"transforms": [
{
"field": "poi_category",
"type": "map",
"mappings": {
"hotel": "hebergements",
"restaurant": "food"
}
}
]
}See: Configuration Guide - mapping.json
layers/ Directory
Purpose: GeoJSON layer configurations and data.
Structure for each layer:
layers/{layer-id}/
├── config.json # Layer metadata (optional if in layers.json)
├── data.geojson # GeoJSON data
└── styles/
├── default.json # Default style (REQUIRED)
└── *.json # Additional styles (optional)See: Configuration Guide - layers.json
layerTemplates (profile.json)
Purpose: Define reusable layer properties to avoid duplication. Layers can inherit from a template via "template": "templateId".
Example in profile.json:
{
"layerTemplates": {
"geojson-standard": {
"interactiveShape": true,
"tooltipMode": "hover"
},
"geojson-polygon": {
"interactiveShape": true,
"geometry": "polygon",
"tooltipMode": "hover"
}
}
}Layers in layers.json that reference this template inherit all its properties (overridable per-layer).
Built-in Profiles
GeoLeaf includes three production-ready profiles that showcase different use cases.
Tourism Profile
Use Case: Tourist attractions, activities, accommodations, nature sites
Structure:
profiles/tourism/
├── profile.json (214 lines)
├── taxonomy.json (categories: activites, culture, nature, hebergements)
├── themes.json (4+ themes)
├── mapping.json (data normalization)
├── layers.json (35+ layer configs)
└── layers/ (35+ directories)
├── activites-aquatiques/
│ ├── data.geojson
│ └── styles/
│ ├── default.json
│ └── detailed.json
├── culture-musees/
├── hebergements-hotels/
└── ...Key Features:
- 35+ layers organized by category
- 46 migrated styles (introduced with
label.visibleByDefault) - Icon sprite with 50+ tourism symbols
- Sample data for major French cities
- 4 category groups: Activités, Culture, Nature, Hébergements
- Multiple themes: Default, Heritage, Nature Focus
Configuration Highlights:
{
"ui": {
"showLayerManager": true,
"showFilterPanel": true,
"showThemeSelector": true,
"showLegend": true,
"showCacheButton": true
},
"basemaps": {
"street": { "defaultBasemap": true, "offline": true },
"satellite": { "offline": false },
"topo": { "offline": false }
},
"performance": {
"maxConcurrentLayers": 10,
"layerLoadDelay": 200
}
}Best For:
- Tourism boards
- Travel apps
- Hiking/outdoor applications
- Cultural heritage sites
Creating Custom Profiles
Follow these steps to create a new profile from scratch.
Step 1: Create Profile Directory
mkdir -p profiles/my-profile
cd profiles/my-profileStep 2: Create profile.json
Start with a minimal template:
{
"id": "my-profile",
"label": "My Custom Profile",
"description": "Brief description",
"version": "1.0.0",
"map": {
"bounds": [
[-56, -74],
[-21, -53]
],
"center": [-15, -62],
"zoom": 6,
"positionFixed": true
},
"Files": {
"taxonomyFile": "taxonomy.json",
"themesFile": "themes.json",
"layersFile": "layers.json",
"basemapsFile": "basemaps.json",
"uiFile": "ui.json"
},
"performance": {
"maxConcurrentLayers": 8,
"layerLoadDelay": 200,
"fitBoundsOnThemeChange": false
}
}Customization checklist:
- ✅ Set unique
id(lowercase, no spaces) - ✅ Configure
uicomponents needed - ✅ Define at least one basemap
- ✅ Set default map
centerandzoom
Step 3: Create taxonomy.json
Define your POI categories:
{
"icons": {
"spriteUrl": "assets/icons/sprite.svg",
"symbolPrefix": "my-prefix-",
"defaultIcon": "default-icon"
},
"defaults": {
"icon": "default-icon"
},
"categories": {
"category-1": {
"label": "Category 1",
"icon": "icon-1",
"subcategories": {
"subcat-1": {
"label": "Subcategory 1",
"icon": "icon-1a"
},
"subcat-2": {
"label": "Subcategory 2",
"icon": "icon-1b"
}
}
},
"category-2": {
"label": "Category 2",
"icon": "icon-2",
"subcategories": {}
}
}
}Tips:
- Keep category IDs lowercase with hyphens
- Limit depth to 2 levels (category → subcategory)
- Use semantic icon names
- Plan for 5-15 top-level categories max
Step 4: Create themes.json
Define layer visibility presets:
{
"config": {
"defaultTheme": "default",
"allowCustomThemes": true,
"persistSelection": true
},
"themes": [
{
"id": "default",
"label": "Default View",
"icon": "view-all",
"layers": {
"layer-1": true,
"layer-2": true,
"layer-3": true
}
},
{
"id": "minimal",
"label": "Minimal View",
"icon": "view-minimal",
"layers": {
"layer-1": true,
"layer-2": false,
"layer-3": false
}
}
]
}Tips:
- Start with 2-4 themes
- Include an "All Layers" theme
- Name themes by purpose, not technical details
- Keep theme switching fast (avoid >20 layers per theme)
Step 5: Add Layers (Optional)
If you have GeoJSON layers:
A. Create layers directory:
mkdir -p layers/my-layer/stylesB. Add layer data:
layers/my-layer/data.geojson
{
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
"name": "Location 1",
"category": "category-1"
},
"geometry": {
"type": "Point",
"coordinates": [2.5, 46.8]
}
}
]
}C. Add default style:
layers/my-layer/styles/default.json
{
"$schema": "../../../../schema/style.schema.json",
"id": "default",
"name": "Default Style",
"label": {
"enabled": true,
"visibleByDefault": false,
"field": "name"
},
"style": {
"fillColor": "#3b82f6",
"fillOpacity": 0.6,
"color": "#1e40af",
"weight": 2,
"opacity": 1.0
},
"legend": {
"enabled": true,
"title": "My Layer",
"items": [
{
"label": "Feature",
"color": "#3b82f6"
}
]
}
}D. Register layer in layers.json:
layers.json
{
"layers": [
{
"id": "my-layer",
"name": "My Layer",
"type": "point",
"dataSource": "layers/my-layer/data.geojson",
"defaultStyle": "default",
"availableStyles": ["default"],
"minZoom": 8,
"maxZoom": 19
}
]
}Step 6: Prepare Sample Data (Optional)
If you have POI data, create poi.json:
{
"version": "1.0",
"count": 2,
"source": "Sample data",
"pois": [
{
"id": "poi-001",
"latlng": [46.8, 2.5],
"title": "Sample POI 1",
"category": "category-1",
"subcategory": "subcat-1",
"properties": {
"description": "Description here",
"address": "123 Main St"
}
},
{
"id": "poi-002",
"latlng": [46.9, 2.6],
"title": "Sample POI 2",
"category": "category-2",
"properties": {}
}
]
}Step 7: Update Root Config
Add your profile to profiles/geoleaf.config.json:
{
"data": {
"activeProfile": "my-profile",
"profilesBasePath": "/profiles/"
},
"profiles": [
{
"id": "tourism",
"label": "Tourism",
"description": "Tourist attractions and activities"
},
{
"id": "my-profile",
"label": "My Custom Profile",
"description": "Brief description"
}
]
}Step 8: Test Your Profile
A. Start dev server:
npm startB. Load your profile:
http://localhost:8080/demo/?profile=my-profileC. Enable debug mode:
// Activer dans geoleaf.config.json
// { "debug": true }
// Ou en console
GeoLeaf.Config.set("debug", true);D. Check console for errors:
Look for:
- ❌ Profile loading errors
- ❌ Missing files (taxonomy, themes)
- ❌ Invalid JSON syntax
- ❌ Icon sprite not found
Step 9: Validate Configuration
A. Validate JSON with schemas:
# Install AJV CLI
npm install -g ajv-cli
# Valider les fichiers du profil
ajv validate -s profiles/schemas/geoleaf-profile.schema.json -d profiles/my-profile/profile.json
ajv validate -s profiles/schemas/basemaps.schema.json -d profiles/my-profile/basemaps.json
ajv validate -s profiles/schemas/ui.schema.json -d profiles/my-profile/ui.json
ajv validate -s profiles/schemas/taxonomy.schema.json -d profiles/my-profile/taxonomy.json
ajv validate -s profiles/schemas/themes.schema.json -d profiles/my-profile/themes.json
ajv validate -s profiles/schemas/layer-config.schema.json -d "profiles/my-profile/layers/**/*_config.json"
ajv validate -s profiles/schemas/style.schema.json -d "profiles/my-profile/layers/**/styles/*.json"B. Test in VS Code:
Add $schema reference to each file:
{
"$schema": "../../schemas/taxonomy.schema.json",
}Profile Best Practices
Naming Conventions
Profile IDs:
- ✅ Use lowercase with hyphens:
my-profile - ❌ Avoid spaces or special chars:
My Profile! - ✅ Be descriptive:
retail-store-locator - ❌ Don't be generic:
profile1
Category IDs:
- ✅ Use semantic names:
restaurants,hotels - ❌ Avoid abbreviations:
rest,htl - ✅ Pluralize categories:
museums, notmuseum - ❌ Don't use generic names:
type1,category-a
Layer IDs:
- ✅ Use descriptive names:
heritage-sites,bike-routes - ❌ Avoid technical names:
layer1,geojson-data - ✅ Include type if helpful:
zones-nature,routes-bike
Icon Sprite Optimization
SVG Sprite Structure:
<svg xmlns="http://www.w3.org/2000/svg">
<symbol id="my-prefix-icon-1" viewBox="0 0 24 24">
<path d="..." />
</symbol>
<symbol id="my-prefix-icon-2" viewBox="0 0 24 24">
<path d="..." />
</symbol>
</svg>Best Practices:
Consistent prefix: All symbol IDs start with same prefix
json"symbolPrefix": "my-prefix-"Standardize viewBox: Use 24x24 for consistency
xmlviewBox="0 0 24 24"Optimize file size:
- Remove unnecessary groups
- Simplify paths
- Use SVGO:
svgo sprite.svg -o sprite.optimized.svg
Limit icon count: 50-100 icons max per sprite
- Split into multiple sprites if needed
- Load sprites on-demand
Use semantic names:
hotel, noticon-01
Taxonomy Hierarchy
Recommended Depth:
Category (Level 1)
└── Subcategory (Level 2)
└── ❌ DON'T GO DEEPERWhy?
- UI becomes cluttered with >2 levels
- Filter panel complexity increases
- User confusion increases
Good Example:
{
"categories": {
"food": {
"label": "Food & Drink",
"subcategories": {
"restaurant": { "label": "Restaurants" },
"cafe": { "label": "Cafés" },
"bar": { "label": "Bars" }
}
}
}
}Bad Example (too deep):
{
"categories": {
"food": {
"subcategories": {
"restaurant": {
"subcategories": {
"italian": {
"subcategories": {
"pizza": {}, // ❌ Too deep!
},
},
},
},
},
},
},
}Theme Count Recommendations
| Profile Size | Recommended Themes | Why |
|---|---|---|
| Small (5-10 layers) | 2-3 themes | Keep it simple |
| Medium (10-20 layers) | 3-5 themes | Balance flexibility & simplicity |
| Large (20+ layers) | 4-6 themes | Help users navigate complexity |
Theme Strategy:
- Always include "All Layers" - Users want to see everything
- Create purpose-based themes - "Heritage Sites", not "Theme A"
- Group related layers - Don't scatter similar layers across themes
- Test switching performance - Keep <1 second to switch
Performance Considerations
For Large Profiles (100+ layers)
Problem: Slow loading, memory issues, UI lag
Solutions:
Lazy load layers:
json{ "performance": { "maxConcurrentLayers": 5, "layerLoadDelay": 300 } }Use layer visibility themes strategically:
- Don't enable all layers by default
- Create focused themes with 5-10 layers max
Enable clustering for dense POI layers:
json{ "defaultSettings": { "clustering": { "enabled": true, "maxClusterRadius": 80 } } }Optimize GeoJSON:
- Simplify geometries (reduce precision)
- Remove unnecessary properties
- Use
.geojsoninstead of inline JSON
Split large layers:
- Instead of one "Restaurants" layer with 10,000 POIs
- Create regional layers: "Restaurants Paris", "Restaurants Lyon"
For POI-heavy Profiles
If you have 1000+ POIs:
Enable clustering (essential)
Set appropriate zoom levels:
json{ "minZoom": 10, // Don't render at country-level zoom "maxZoom": 19 }Use vector tiles (advanced) if available
Implement search/filter to narrow results
Profile Migration
legacy to 1.0.0
Key Changes:
- Modular structure - Split monolithic config
- New file structure - Separate taxonomy, themes, layers
- Layer manager - New UI component
- Profile object - New top-level structure
Migration Steps:
Before (legacy):
{
"pois": [
/* all POIs inline */
],
"categories": {
/* inline taxonomy */
},
"basemaps": {
/* ... */
},
}After (1.0.0):
profiles/my-profile/
├── profile.json # basemaps, UI config
├── taxonomy.json # categories (extracted)
├── themes.json # NEW
└── poi.json # POIs (extracted)See: Developer Guide for complete migration guidance
1.0.x to 1.1.0
Key Changes:
- Label configuration moved -
visibleByDefaultnow in style files - Breaking change - Layer config
label.visibleByDefaultdeprecated
Migration Steps:
Before (1.0.x) - Layer config:
{
"layers": [
{
"id": "my-layer",
"label": {
"enabled": true,
"visibleByDefault": true, // ❌ DEPRECATED
"field": "name",
},
},
],
}After (1.1.0) - Style file:
{
"id": "default",
"label": {
"enabled": true,
"visibleByDefault": true, // ✅ NOW HERE
"field": "name",
},
"style": {
/* ... */
},
}Automated Migration:
# Run migration script
node scripts/migrate-label-config.cjs
# Or manually use label migrator
node scripts/add-missing-label-config.cjsSee: Labels Documentation for complete details
Structure modulaire (v2.0.0)
Changements principaux :
basemapsextrait — Déplacé deprofile.jsonversbasemaps.jsonuiextrait — Déplacé deprofile.jsonversui.jsonlayersextrait — Déplacé deprofile.jsonverslayers.json- Section
Files—profile.jsoncontient maintenant une sectionFilespointant vers les fichiers séparés
Avant (structure monolithique héritée) :
{
"id": "mon-profil",
"ui": { "showLayerManager": true, "showFilterPanel": true },
"basemaps": { "street": {} },
"layers": [{ "id": "couche1" }]
}Après (structure modulaire — v2.0.0) :
profile.json
{
"id": "mon-profil",
"Files": {
"taxonomyFile": "taxonomy.json",
"themesFile": "themes.json",
"layersFile": "layers.json",
"basemapsFile": "basemaps.json",
"uiFile": "ui.json"
}
}basemaps.json → { "basemaps": { "street": { } } }
ui.json → { "showLayerManager": true, ... }
layers.json → [ { "id": "couche1", ... } ]
Rétrocompat — Les sections
uietbasemapsdirectement dansprofile.jsonrestent supportées (chargement inline).
Troubleshooting
Profile Not Loading
Symptom: Blank map, console error "Profile not found"
Causes & Solutions:
Incorrect profile ID in config
javascript// Check console console.log(GeoLeaf.Config.getActiveProfile()); // Should match profile directory nameWrong profilesBasePath
json{ "data": { "profilesBasePath": "/profiles/" // Check this path } }profile.json syntax error
- Use JSON validator: https://jsonlint.com/
- Check for trailing commas (invalid in JSON)
- Check for missing quotes
CORS issues (if using file:// protocol)
- Use a local web server:
npm start - Or run Chrome with:
--allow-file-access-from-files
- Use a local web server:
Icons Not Showing
Symptom: Generic markers instead of custom icons
Causes & Solutions:
Sprite URL incorrect
json{ "icons": { "spriteUrl": "../path/to/sprite.svg" // Check path relative to profile.json } }Symbol ID mismatch
json// taxonomy.json "icon": "hotel" // Must match symbol ID in sprite // sprite.svg <symbol id="my-prefix-hotel"> // Prefix + icon nameSprite not loading (check Network tab)
- 404: Incorrect spriteUrl path
- CORS: Sprite on different domain
- 200 but still not showing: Check symbol IDs
Missing defaultIcon
json{ "icons": { "defaultIcon": "generic" // Fallback if icon not found } }
Layers Empty
Symptom: Layer loads but shows 0 features
Causes & Solutions:
Invalid GeoJSON
- Validate at: https://geojsonlint.com/
- Check coordinates format:
[lng, lat]NOT[lat, lng]
Data outside map bounds
javascript// Check feature bounds const layer = GeoLeaf.GeoJSON.getLayerById("my-layer"); console.log(layer.getBounds());Incorrect dataSource path
json{ "dataSource": "layers/my-layer/data.geojson" // Relative to profile root }Zoom level out of range
json{ "minZoom": 8, // Layer only visible at zoom 8-19 "maxZoom": 19 }- Zoom to correct level or adjust min/maxZoom
Layer hidden by theme
- Check current theme settings
- Verify layer ID in themes.json
Themes Not Working
Symptom: Theme selector shows themes but switching doesn't change layers
Causes & Solutions:
Layer IDs don't match
json// themes.json "layers": { "my-layer": true // Must match layer ID exactly } // layers.json { "id": "my-layer" // Must match }Theme persistence conflict
json{ "config": { "persistSelection": false // Try disabling persistence } }Cache issue
javascript// Clear theme cache localStorage.removeItem("geoleaf-theme-selection"); location.reload();
Labels Not Showing
Symptom: Labels configured but not appearing
Causes & Solutions:
label.enabled = false in style
json{ "label": { "enabled": true, // ✅ Must be true "visibleByDefault": true, "field": "name" } }Label field missing in data
javascript// Check if field exists const layer = GeoLeaf.GeoJSON.getLayerById("my-layer"); layer.eachLayer((feature) => { console.log(feature.properties.name); // Should exist });Zoom level below labelScale.minZoom
json{ "labelScale": { "minZoom": 14, // Labels only show at zoom 14+ "maxZoom": 19 } }visibleByDefault = false
- Click label button in Layer Manager to enable
1.0.x config still in use
- Migrate to 1.1.0: see Labels Documentation
Performance Issues
Symptom: Map slow, browser hangs, high memory usage
Causes & Solutions:
Too many layers enabled
json{ "performance": { "maxConcurrentLayers": 5 // Limit concurrent layers } }Large GeoJSON files
- Simplify geometries
- Split into regional layers
- Use clustering for POIs
No clustering for dense POI layers
json{ "defaultSettings": { "clustering": { "enabled": true, "maxClusterRadius": 80 } } }Too many label updates
- Check console for "[LabelButtonManager] Bouton créé" spam
- Labels module should debounce updates (300ms)
Memory leak from layers
javascript// Clear layers before switching profiles GeoLeaf.GeoJSON.clearAll();
Related Documentation
- Configuration Guide - Complete JSON reference
- Getting Started - Quick 5-minute tutorial
- User Guide - Using GeoLeaf features
- Tourism Profile - Working profile example
- Schema Documentation - JSON Schema validation
- Labels Documentation - Labels system and migration
Support
For help with profile creation:
- Check Tourism profile:
profiles/tourism/directory has complete working profile - Review built-in profiles: Tourism in
profiles/directory - Validate your JSON: Use JSON Schema validation
- Enable debug mode: See detailed logs in console
- Open an issue: GitHub Issues
Last Updated: January 23, 2026
GeoLeaf Version: 1.2.0
