Utilisation d'une source de données chargée en fonction du zoom

Retour

Cette section à pour but de montrer l'utilisation d'un datalayer avec une source chargée à la volée

  • Les données sont demandée via une fonction appelée après chaque zoom / déplacement de la carte
  • Aucune requête n'est effectuée tant que le calque n'est pas visible (dans l'exemple il faut zoomer en avant pour le rendre visible)
    • le developpeur doit codé une fonction loader afin d'interpréter le retour et créer des features OpenLayer
      • Utiliser un retour geojson est conseillé
      • Les features retournée doivent avoir un id préservé entre deux requête http, sinon il faut gérer dans la fonction loader les features à retourner au layer
        • (l'api vérifi si une feature à déjà été ajoutée grâce a son id)
  • deux modes
    • bbox
      • les données sont demandées à chaque zoom / pan de carte
      • c'est au développeur de vérifier si il faut lancer la requête au serveur
    • tuilé (défaut)
      • la carte est découpée en tuiles et la fonction loader est appelée pour chaque tuile
      • cette stratégie ne requête pas deux fois le serveur pour une même tuile
      • la taille des tuiles est paramétrable (découpage de la carte en "pixel") afin d'avoir la bonne balance entre le nombre de requêtes au serveur et la taille de leur retour
Zoomer en avant pour charger des données
{
  "jsLib": [
    "https://karteis.sct.saas-gfi.eu/dist/mapviewer/latest/karteis-mapviewer-var.js"
  ]
}
<!-- Ne pas utiliser dans votre code -->
<!-- La déclaration du css n'est utile que pour l'affichage sur le site d'exemples -->
<link rel="stylesheet" href="/mapviewer/mapviewer.css">
<!-- Ne pas utiliser dans votre code -->

<!-- Dans nos exemple on utilise font-awesome pour afficher les icones de boutons -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">

<!-- Le div qui sera utilisé pour injecter la carte -->
<div id="kmap" style="height:300px;" />

// Initialisation de la carte avec ses plugins
const kmapvInstance = (new kmapv.Mapviewer({
    mapdiv: document.getElementById('kmap'), // Il est aussi possible d'utiliser directement l'id du div contenant la carte
    projection: 'EPSG:3857',
    defaultCenter: [-444800, 6094400],
    defaultZoom: 15.8,
    minZoom: 5,
    maxZoom: 22,
    interactions: {
        hover: {}
    }
}))
 .use(kmapv.CommonLayer({})) // charge le plugin générique des calques
 .use(kmapv.BackgroundLayer({})) // charge le plugin de prise en charge des fond de plans
 .use(kmapv.DataLayer({})) // chage le plugin de prise en charge des couche de données
 .use(kmapv.Tooltips({stopEvent:false})) // charge le plugin de gestion des tooltips, stopEvents: false le tooltip n'intercepte pas les events souris/tap

// Ajout du fond de plan OSM
kmapvInstance.backgroundLayer.addOSM('background', { title: 'open street map', zIndex: 0 })


const styles = kmapv.Services.createStyle(
{
    // remplissage des polygones
    fill: {
        color: 'rgba(250,200,120,0.5)',
    },
    // style les lignes
    stroke: {
        color: '#333',
        width: 1,
    },
    text: {
        // si on veut que le style dépasse du polygone
        //overflow:true,
        font: '13px Calibri,sans-serif',
        // "boite" autour du texte
        /* backgroundFill: {
            color:"#FFF"
        },*/
        // contour du texte
        stroke: {
            color: '#aaa',
            width: 1,
        },
        // couleur du texte
        fill: {
            color: '#333',
        },

    },
})

// style de point et polygone sélectionnés
const stylesSelected = kmapv.Services.createStyle(
{
    // remplissage des polygones
    fill: {
        color: 'rgba(0,0,255,0.1)',
    },
    // style les lignes
    stroke: {
        color: '#00F',
        width: 3,
    },
    text: {
        font: '13px Calibri,sans-serif',
        // contour du texte
        stroke: {
            color: '#aaa',
            width: 1,
        },
        // couleur du texte
        fill: {
            color: '#333',
        },

    },
})

// le calque va utiliser en entrée une fonction de style
// en entrée la feature Openlayer, la résolution de la carte ("son zoom") et est-ce que la feature est considéré sélectionnée par le viewer
const getStyle = function ({ feature, resolution, selected }) {

    const styleToReturn = selected ? stylesSelected : styles

    // on fait un pseudo thème en changeant la couleur de fond des parcelles dont le numéro termine par 5
    if(!selected) {
        if (feature.get("numero").toString().slice(-1) === "5") {
            styleToReturn.getFill().setColor('rgba(250,120,120,0.5)')
        } else {
            styleToReturn.getFill().setColor('rgba(250,200,120,0.5)')
        }
    }
    // pour chaque feature on set le text a afficher
    styleToReturn.getText().setText(
        [
            `${feature.get('section')} ${feature.get('numero')}`,
            'italic 11px Calibri,sans-serif',
        ]
    )
    return styleToReturn
}

// dans cet exemple on appelle un service wfs

const baseUrl = 'https://data.geopf.fr/wfs/ows?SERVICE=WFS&version=1.1.0&request=GetFeature&srsname=EPSG:3857&typename=CADASTRALPARCELS.PARCELLAIRE_EXPRESS:parcelle&outputFormat=application/json'

// on limite la zone visible
const filtreSpecifique = ` AND section in ('0D','AW') AND code_dep='29' `

// Ajout d'un calque de données
kmapvInstance.dataLayer.addDataLayer({
    title: "Calque de donnée",
    idGroup: 'data',
    zIndex: 1,
    layerId: 'identifiant-du-calque',
    selectable: true,
    minZoom: 16,
    style: getStyle,
    loadingStrategy: {
        //bboxStrategy: true, // utiliser la strategy bbox, defaut false
        //tileStrategy: {tileSize:512}, // taille des tuiles en pixel, default 256
        loader: async (extent, resolution, projection) => {
            try {
                const srid = projection.getCode()
                const url = encodeURI(`${baseUrl}&cql_filter=BBOX(geom,${extent.join(',')},'${srid}') ${filtreSpecifique}`)

                const response = await fetch(url);
                if (!response.ok) {
                    throw new Error(`Response status: ${response.status}`);
                }

                const json = await response.json()
                // le wfs service renvoi du geojson, on a juste à utiliser le service afin de les convertir en features
                const features = kmapv.Services.geoJsonToFeature(json)
                // puis le renvoyer
                return features
            } catch (error) {
                // traitement de l'erreur
                // renvoi de l'erreur a MapViewer
                throw error
            }
        }
    }
})

// on ajoute dans la carte des boutons pour changer de mode sélection (par défaut on est dans le mode "select-single"):
// la barre de sélection est paramétrable, on ajoute les outils qui nous interressent :
// les icones peuvent venir de n'importe quel framework css
const createSelectBarOptions = [
{
    "type": "select",
    "toolId": "select-single",
    //"icon": "fa-solid fa-hand-pointer",
    // est équivalent a :
    "html": "<i class=\"fa-solid fa-hand-pointer\"></i>",
    "title": "Sélection simple",
    "selectMode": "replace"
},
{
    "type": "rectangular",
    "toolId": "select-rectangular",
    "icon": "fa-regular fa-square-full",
    "title": "Sélection rectangle",
    "selectOnce": true
},
{
    "toolId": "select-polygon",
    "title": "Sélection par polygone",
    "icon": "fa-solid fa-draw-polygon",
    "type": "polygon",
    "selectOnce": true
},
{
    "type": "multiselect",
    "toolId": "multiselect",
    "icon": "fa-solid fa-star-half-stroke",
    "title": "Sélection Multiple",
    "selectMode": "toggle"
}]

// ajout de l'outil a la barre du bas
kmapvInstance.horizontalToolbar.addSelectCreateBar({
    className: 'app-edit-bar',
    clearButton: {
      // icon: null,
      // html: '<i class="q-icon map-tool-icon material-icons">not_interested</i>',
      title: 'Effacer la sélection',
    },
    tools:createSelectBarOptions,
  })

// On va écouter les évenements générés par le viewer
kmapvInstance.on('change:selection', (evt) => {

    kmapvInstance.tooltips.deleteTooltip()

    //console.log("Evènement généré chaque changement de sélection:",evt)
    console.log("quel outil à déclenché la sélection?", evt.toolId)
    console.log("ajouté dans la sélection:", evt.selected)
    console.log("retiré de la sélection:", evt.deselected)
    console.log("selection courante: ")

    const consoleInfos = evt.selection.map((selectedFeature) => {
        // on retire les infos qui nous interessent pas pour le console.table
        const {geometry,bbox, ...properties} = selectedFeature.getProperties()
        properties.surfaceCalculee = kmapv.Services.Calc.getArea(geometry)
        return properties
    })

    console.table(consoleInfos)
})

// On va écouter les évenements générés par le viewer
kmapvInstance.on('hover-enter', (evt) => {
    showTooltip(evt.feature)
})

kmapvInstance.on('hover-leave', (evt) => {
    kmapvInstance.tooltips.deleteTooltip()
})


function showTooltip(feature) {

    // affiche un tooltip au centre de la géométrie
    const properties = feature.getProperties()
    const tooltip = `<div class="tooltip">
                    <span>${properties.nom_com}</span>
                    <span><label>${properties.idu}</label></span>
                    </div>`

    kmapvInstance.tooltips.createTooltip(tooltip,kmapv.Services.getCentroid(feature.getGeometry()))

}



.tooltip {
  display:flex;
  flex-direction:column;
  align-items: center;
}

.tooltip label {
    font-weight: bold;
    display:inline-block;
}

/** on rend les tooltips transparents **/
#MapViewerTooltip {
    background-color:rgba(255,255,255,0.5);
}
#MapViewerTooltip:after {
    border-top-color:rgba(255,255,255,0.5);
}

Dernière mise à jour:
Contributors: Jerome Mare