Couche de données d'une carte dsfr-data-map : markers, zones géographiques (geoshape), cercles proportionnels ou heatmap. Chaque couche est connectée à sa propre source — le multi-source est naturel.

Enfant de dsfr-data-map : le composant est invisible, il projette les enregistrements de sa source sur la carte hôte. L'affichage au clic passe de préférence par le compagnon dsfr-data-map-popup (les attributs popup-template/popup-fields sont le mode legacy).

Attributs

Source et géolocalisation

AttributTypeDéfautDescription
sourceString""Id de la source (ou du transformateur) dont cette couche consomme les données.
typemarker · geoshape · circle · heatmapmarkerRendu de la couche : marker (epingles), geoshape (polygones/lignes GeoJSON), circle (cercles proportionnels), heatmap (carte de chaleur).
lat-fieldString""Chemin vers le champ latitude (mode coordonnées séparées).
lon-fieldString""Chemin vers le champ longitude (mode coordonnées séparées).
geo-fieldString""Champ geometrie : objet GeoJSON, {lat, lon}, [lat, lon] ou chaîne JSON serialisee (#426). Vide sur une couche geoshape : la première colonne geo_shape, geometry ou geom qui porte du GeoJSON est détectée, et nommée dans l'avertissement des lignes ignorées (#1053).
shape-classString""Classe CSS appliquee aux traces SVG de la couche (geoshape/circle) — permet un style page (motif hachure, pointilles...) via CSS/SVG <pattern>
no-interactiveBooleanfalseCouche decorative : aucune interaction (pas de clic, tooltip ni popup) — contours administratifs, habillage

Sans lat-field/geo-field, la couche auto-détecte les champs geo_point_2d, geopoint, geo_point (points) puis geo_shape, geometry, geom (formes).

Couche geoshape sans geo-field (#1053) : la couche trace la première colonne geo_shape, geometry ou geom qui porte du GeoJSON, objet ou chaîne sérialisée, sur l'une des vingt premières lignes. geo_point_2d n'est jamais retenu pour tracer des formes : un jeu Opendatasoft porte le point et la forme, et c'est la forme qui est dessinée. Les Feature d'une source transform="features" sont lues par leur geometry. La colonne détectée est nommée dans l'avertissement des lignes ignorées. Si aucune ne convient, la couche ne trace rien et le dit en console (« aucune colonne géométrique détectée ») : poser alors geo-field. Le calcul d'emprise (bbox) garde sa propre détection, qui commence par geo_point_2d : voir bbox-field.

Affichage

AttributTypeDéfautDescription
popup-templateString""Template du contenu de la popup, avec substitution de champs. Ex: "{nom} — {val} kW".
popup-fieldsString""Champs a presenter en tableau automatique dans la popup. Ex: "nom,adresse".
tooltip-fieldString""Champ affiché au survol de l'élément.
colorString#000091Couleur de la couche (défaut : blue-france DSFR). Sert aussi de repli quand color-map ne matche pas.
color-fieldString""Champ dont la valeur détermine la couleur (mapping catégoriel via color-map).
color-mapString""Paires valeur:#couleur séparées par des virgules. Ex: "1:#00A95F,2:#FF9940,3:#E1000F". Une virgule ou un deux-points dans une valeur s'écrit %2C ou %3A.
fill-fieldString""Champ numérique utilisé pour le remplissage en choroplèthe, sur une couche geoshape ou circle (#768) — avec classes, method, breaks et selected-palette. Posé avec color-field, il gagne pour le REMPLISSAGE ; color-field / color donnent alors le contour, et la légende décrit les classes. Sans effet sur marker et heatmap.
fill-opacityNumber0.6Opacite du remplissage (0-1).
selected-paletteString""Palette DSFR utilisée pour le dégradé choroplèthe (fill-field) : sequentialAscending (défaut), sequentialDescending, divergentAscending, divergentDescending, neutral, categorical.
methodquantile · equal · manualquantileMéthode de discrétisation de la choroplèthe : quantile (défaut, effectifs égaux par classe), equal (intervalles de même largeur), manual (bornes de breaks).
classesNumber0Nombre de classes de la choroplèthe (fill-field). 0 (défaut) = autant de classes que de couleurs dans l'échelle (9). Plafonné à la taille de l'échelle (#685).
breaksString""Bornes supérieures manuelles des classes, séparées par des virgules : "10,50,100" donne 4 classes (jusqu'à 10, 10 à 50, 50 à 100, plus de 100). Implique method="manual".
radiusNumber8Rayon fixe des cercles (type="circle").
radius-fieldString""Champ numérique pilotant un rayon variable (auto-scaling entre radius-min et radius-max).
radius-unitpx · mpxUnité du rayon : px (constant à l'écran) ou m (mètres, suit le zoom).
radius-minNumber4Rayon minimum de l'auto-scaling, en pixels.
radius-maxNumber30Rayon maximum de l'auto-scaling, en pixels.

Filtrage au clic

AttributTypeDéfautDescription
refine-on-clickString""Champ dont la valeur de l'objet cliqué devient un filtre eq (#681). Premier clic = filtre, second clic sur le même objet = retrait, clic sur un autre objet = remplacement. Avec context="id" (recommandé), la couche s'enregistre comme filtre du dsfr-data-context : diffusion à toutes ses sources cibles au dialecte de chacune, tag dans dsfr-data-context-tags, URL portée par le contexte. Sans context, la clause part directement à source (whereKey map-select-ID) — sans tag ni URL. Attention : si source est aussi une cible du contexte, la carte se filtre elle-même (seul l'objet cliqué reste, jusqu'au second clic) ; pour garder tous les points, ne pas lister cette source dans sources du contexte (ou donner à la carte sa propre source).
contextString""Id du dsfr-data-context auquel s'enregistrer en refine-on-click (#681, ADR-104). Le contexte peut être déclaré après la couche dans la page. Vide = commande directe à source (chemin dégradé).
labelString""Libellé de la couche — sert de libellé au tag du contexte en refine-on-click (#681). Vide = le nom du champ.

Regroupement : un élément par groupe (format long)

Quand les données sont au format long — une ligne par couple ville × aide, coordonnées répétées sur chaque ligne —, group-field="Ville" trace un seul marqueur (ou cercle, ou forme) par valeur distincte du champ, au lieu de N marqueurs empilés. Au clic, la popup, le volet (panel-left / panel-right) ou la modale de dsfr-data-map-popup reçoivent toutes les lignes du groupe : en titre la valeur du groupe (ou le title-field du compagnon, lu sur le premier enregistrement), puis un tableau des popup-fields avec une ligne par enregistrement. Si popup-template (ou le <template> du compagnon) est posé, il s'applique à chaque ligne, en liste. Sans popup-fields ni gabarit, le compagnon montre les colonnes scalaires du jeu, hors géométrie et hors champ de regroupement. Au plus 200 lignes, puis « … et N autres ». Toutes les valeurs sont échappées.

<dsfr-data-map center="46.6,2.3" zoom="6">
  <dsfr-data-map-layer id="aides" source="src-aides" type="marker"
    lat-field="Latitude" lon-field="Longitude"
    group-field="Ville" popup-fields="Action,Domaine"></dsfr-data-map-layer>
  <dsfr-data-map-popup for="aides" mode="panel-right"></dsfr-data-map-popup>
</dsfr-data-map>
AttributTypeDéfautDescription
group-fieldString""Regroupement (#1108) : un seul élément tracé par valeur distincte de ce champ — données au format LONG, une ligne par couple ville × aide avec les coordonnées répétées. Au clic, la popup, le volet ou la modale reçoivent TOUTES les lignes du groupe : titre = valeur du groupe (ou title-field du dsfr-data-map-popup), puis un tableau des popup-fields avec une ligne par enregistrement ; popup-template (ou le <template> du compagnon) s'applique alors à chaque ligne, en liste. Au plus 200 lignes rendues, « … et N autres » au-delà. Position, tooltip-field, color-field, radius-field, fill-field : ceux du PREMIER enregistrement du groupe qui porte des coordonnées exploitables (le premier tout court pour geoshape). Des coordonnées qui diffèrent au sein d'un groupe sont signalées une fois en console. max-items, getRenderedCount() et le bandeau comptent des GROUPES ; refine-on-click (à poser sur le même champ) filtre sur la valeur du groupe ; en cluster, chaque groupe est un point de la grappe. Une ligne sans valeur de regroupement reste un élément à part. Sans effet sur heatmap (chaque ligne reste un point de chaleur, avertissement en console).

Heatmap

AttributTypeDéfautDescription
heat-radiusNumber25Rayon d'influence de chaque point de la heatmap, en pixels.
heat-blurNumber15Flou applique a la heatmap, en pixels.
heat-fieldString""Champ de ponderation des points de la heatmap.

Clustering

AttributTypeDéfautDescription
clusterBooleanfalseRegroupe les marqueurs proches en clusters.
cluster-radiusNumber80Rayon de regroupement des clusters, en pixels.

Zoom et viewport

AttributTypeDéfautDescription
min-zoomNumber0Niveau de zoom en deca duquel la couche est masquee.
max-zoomNumber18Niveau de zoom au-delà duquel la couche est masquee.
bboxBooleanfalseChargement par viewport : re-interroge la source a chaque déplacement de la carte, et une première fois des que la carte est prête (#652). Le tout premier fetch de la source reste NON filtre (elle charge des sa connexion, avant que la carte — différée a la visibilité — ait un viewport) : sur un gros jeu, poser un limit ou un where initial sur la source. La clause de zone visible est écrite par l'adaptateur de la source (adaptateurs déclarant serverGeo, #1149), sur bbox-field ou, à défaut, sur lat-field / lon-field ; sinon, les lignes déjà reçues sont filtrées dans le navigateur.
bbox-debounceNumber300Délai d'anti-rebond avant le re-fetch bbox, en millisecondes.
bbox-fieldString""Champ géographique utilisé pour la requête bbox. Vide : geo-field, sinon détecté sur les premières lignes reçues — la clause serveur attend ces lignes, aucun nom de colonne n'est supposé (#1139).

Animation temporelle

AttributTypeDéfautDescription
time-fieldString""Champ date/heure activant l'animation temporelle (pilotee par <dsfr-data-map-timeline>).
time-bucketnone · hour · day · month · yearnoneGranularite des pas de temps : none, hour, day, month, year.
time-modesnapshot · cumulativesnapshotRendu temporel : snapshot (seulement le pas courant) ou cumulative (tout jusqu'au pas courant).

Performance

AttributTypeDéfautDescription
max-itemsNumber5000Plafond du nombre d'éléments rendus sur la carte (défaut 5000). Il protège les marqueurs DOM (divIcon), le fit et les popups. Un bandeau (role="status") donne les deux chiffres — éléments affichés et total connu — dès que la carte n'en montre qu'une partie : plafond max-items dépassé, OU source qui n'a chargé qu'une partie du jeu (limit, max-records, plafond de pages : le total vient alors de la source, #1020). Il précise que les premiers enregistrements suivent l'ordre du fichier (ou le tri order-by de la source) : leur répartition n'est pas représentative. Aligner le limit de la source sur max-items évite de charger des lignes que la couche ne dessinera pas. Avec cluster, max-items="20000" est sans risque : les marqueurs regroupés ne pèsent pas sur le DOM. En mode bbox, zoomer recharge la zone visible ; hors bbox, seul un plafond plus haut (ou un filtre amont) affiche le reste.

Bandeau « N affichés sur M » (#1020). Dès que la carte ne montre qu'une partie du jeu, la couche pose sous la carte un bandeau role="status", sans aucun contrôle interactif, qui donne les deux chiffres — éléments affichés et total connu — et le biais : ce sont les premiers enregistrements, dans l'ordre du fichier (ou du tri order-by de la source), leur répartition n'est donc pas représentative. Deux cas le déclenchent :

C'est ce second cas qui rend sûr d'aligner le limit de la source sur max-items : la source ne charge plus de lignes que la couche ne dessinerait pas, et le bandeau reste là. Le Builder Carto le fait par défaut, avec un plafond de 1 000 points (la bibliothèque garde 5 000). Pas de bandeau sur une carte verrouillée (encarts) ; plusieurs couches tronquées empilent leurs bandeaux.

<dsfr-data-source id="elus" api-type="tabular" resource="…" limit="1000"></dsfr-data-source>
<dsfr-data-map>
  <dsfr-data-map-layer source="elus" lat-field="lat" lon-field="lon" max-items="1000"></dsfr-data-map-layer>
</dsfr-data-map>
<!-- Bandeau : « 1 000 premiers enregistrements affichés sur 34 826, dans l'ordre du fichier :
     la répartition affichée n'est pas représentative. La source n'a chargé qu'une partie du jeu. » -->

Attribut retiré : filter (retiré en #297, warn console s'il est présent) — filtrer en amont avec dsfr-data-query ou l'attribut where de la source.

Résolution des coordonnées

La couche résout les coordonnées dans cet ordre de priorité :

  1. lat-field + lon-field — coordonnées séparées (CSV, API)
  2. geo-field vers un Point — GeoJSON Point, objet {lat, lon} ou tableau [lat, lon]
  3. geo-field vers Polygon/MultiPolygon — rendu via L.geoJSON()
  4. Auto-détection — geo_point_2d, geopoint, geo_point, puis geo_shape, geometry, geom

À chaque étape, une chaîne JSON sérialisée est acceptée et parsée automatiquement (#426) — le cas des colonnes Text de Grist ou d'un CSV embarquant du GeoJSON.

Événements

ÉvénementdetailDescription
dsfr-data-map-layer-time-ready { steps: string[] } Émis (CustomEvent, bubbles) quand le découpage temporel est prêt : steps = pas de temps triés chronologiquement. Écouté par dsfr-data-map-timeline.

API JavaScript

MéthodeDescription
setTimelineFrame(index)Affiche le pas de temps d'index donné
resetTimeline()Revient à l'affichage complet (hors animation)
getTimeSteps()Retourne la liste des pas de temps découverts

Exemples

1. Markers clusterisés (bornes IRVE)

<dsfr-data-source id="bornes" api-type="opendatasoft"
  base-url="https://odre.opendatasoft.com" dataset-id="bornes-irve"
  select="geo_point_2d,nom_station,puissance_nominale,adresse"
  limit="5000">
</dsfr-data-source>

<dsfr-data-map center="46.6,2.3" zoom="6" tiles="ign-plan" fit-bounds>
  <dsfr-data-map-layer source="bornes" type="marker"
    geo-field="geo_point_2d"
    tooltip-field="nom_station"
    cluster cluster-radius="60">
  </dsfr-data-map-layer>
</dsfr-data-map>

2. Choroplèthe + contours décoratifs + multi-résolution bbox

Régions en choroplèthe au zoom national, communes chargées par viewport (bbox) au zoom local. Le contour de référence est une couche no-interactive : ni clic, ni tooltip, ni influence sur le fit.

<dsfr-data-source id="regions" api-type="opendatasoft"
  base-url="https://public.opendatasoft.com" dataset-id="georef-france-region"
  select="geo_shape,reg_name,population" limit="20">
</dsfr-data-source>

<dsfr-data-source id="communes" api-type="opendatasoft"
  base-url="https://public.opendatasoft.com" dataset-id="georef-france-commune"
  select="geo_shape,com_name,population" limit="500" server-side page-size="500">
</dsfr-data-source>

<dsfr-data-map center="46.6,2.3" zoom="6" tiles="ign-plan" height="600px">

  <!-- Contours de référence, purement décoratifs -->
  <dsfr-data-map-layer source="regions" type="geoshape"
    geo-field="geo_shape" no-interactive
    color="#7b7b7b" fill-opacity="0">
  </dsfr-data-map-layer>

  <!-- Zoom 1-9 : régions -->
  <dsfr-data-map-layer source="regions" type="geoshape"
    geo-field="geo_shape" fill-field="population"
    selected-palette="sequentialAscending"
    tooltip-field="reg_name"
    min-zoom="1" max-zoom="9">
  </dsfr-data-map-layer>

  <!-- Zoom 10+ : communes dans le viewport (in_bbox côté ODS) -->
  <dsfr-data-map-layer source="communes" type="geoshape"
    geo-field="geo_shape" fill-field="population"
    selected-palette="sequentialAscending"
    tooltip-field="com_name"
    min-zoom="10" bbox bbox-debounce="500">
  </dsfr-data-map-layer>

</dsfr-data-map>

3. Cercles proportionnels (px) et zones réelles (m)

<!-- Rayon écran : échelle linéaire radius-min..radius-max en pixels -->
<dsfr-data-map-layer source="villes" type="circle"
  lat-field="latitude" lon-field="longitude"
  radius-field="population" radius-unit="px" radius-min="6" radius-max="35"
  color="#000091" fill-opacity="0.4"
  tooltip-field="nom">
</dsfr-data-map-layer>

<!-- Rayon terrain : la valeur du champ est un rayon en mètres (L.circle) -->
<dsfr-data-map-layer source="antennes" type="circle"
  lat-field="lat" lon-field="lon"
  radius-field="portee_m" radius-unit="m"
  color="#C9191E" fill-opacity="0.15">
</dsfr-data-map-layer>

4. Animation temporelle

<dsfr-data-source id="bornes-trim" data='[
  {"region":"Paris","lat":48.85,"lon":2.35,"bornes":120,"date":"2025-T1"},
  {"region":"Lyon","lat":45.76,"lon":4.83,"bornes":85,"date":"2025-T1"},
  {"region":"Paris","lat":48.85,"lon":2.35,"bornes":250,"date":"2025-T2"},
  {"region":"Lyon","lat":45.76,"lon":4.83,"bornes":160,"date":"2025-T2"}
]'></dsfr-data-source>

<dsfr-data-map center="46.6,2.3" zoom="6" height="550px">
  <dsfr-data-map-layer source="bornes-trim" type="circle"
    lat-field="lat" lon-field="lon"
    radius-field="bornes" radius-min="6" radius-max="35"
    color="#000091" fill-opacity="0.5"
    tooltip-field="region"
    time-field="date" time-mode="snapshot">
  </dsfr-data-map-layer>
  <dsfr-data-map-timeline speed="1" interval="1500"></dsfr-data-map-timeline>
</dsfr-data-map>

Voir aussi