Sur cette page

Visionneuse GeoJSON (QML)

L'exemple de visualiseur GeoJson montre comment manipuler des MapItems, gérer les entrées utilisateur et les opérations d'E/S vers et depuis un fichier GeoJson.

Carte de l'Europe sur laquelle sont superposés un polygone et une polyligne

L'exemple affiche une carte comportant divers MapItems. Ces MapItems sont soit importés depuis un fichier GeoJson à l'aide de l'API GeoJsonData de QtLocation, soit dessinés par l'utilisateur à l'aide de TapHandlers.

Vous trouverez des exemples de fichiers GeoJSON dans le répertoire « data » du répertoire d’exemples.

Pour tracer un élément de carte (MapItem), cliquez avec le bouton droit de la souris sur une partie vide de la carte et sélectionnez le type d’élément de votre choix dans le menu qui s’affiche. Les clics suivants permettront de définir l’élément choisi. L’exemple permet de tracer des MapCircles, MapRectangles, MapPolygons et MapPolylines. Les éléments entièrement définis par deux points, c’est-à-dire les cercles et les rectangles, sont tracés en deux clics du bouton gauche de la souris. Les éléments définis par plusieurs points, c'est-à-dire les polygones et les polylignes, sont créés par un nombre arbitraire de clics avec le bouton gauche et finalisés à l’aide du bouton droit de la souris. Les éléments dessinés de cette manière sont enregistrés sous forme de points, de polygones et de polylignes conformément à la spécification GeoJSON, voir https://geojson.org/.

Exécution de l'exemple

Vous pouvez exécuter l’exemple à partir de :

Création d'une MapView

Nous commençons par créer une carte de base sur laquelle tous les éléments peuvent être placés. Nous utilisons un élément MapView qui combine une carte de base Map avec la gestion des entrées (molette de souris, glisser-déposer, etc.). La carte sous-jacente Map est accessible via la propriété map. Si une propriété vous manque dans MapView, vous pourrez très probablement y accéder via MapView.map.

MapView {
    id: view
    anchors.fill: parent
    map.plugin: Plugin { name: "osm" }
    map.zoomLevel: 4
    map.center: QtPositioning.coordinate(3, 8)
}

Configuration du modèle GeoJSON / Affichage des MapItems

Afin d’afficher le contenu du fichier sur la carte, nous utiliserons un modèle de conception appelé « programmation modèle-vue ». Nous devons tout d’abord configurer une vue adaptée, dans cet exemple un élément MapItemView. Son parent doit être défini sur la carte sous-jacente de l’ MapView afin d’afficher correctement tous les éléments qui y sont placés.

MapItemView {
    id: miv
    parent: view.map
}

Ensuite, nous avons besoin d’un modèle adapté, représentant un document GeoJSON. À cette fin, QtLocation propose l’élément GeoJsonData, capable de lire et d’écrire des fichiers GeoJSON. Il peut être facilement instancié

GeoJsonData {
    id: geoDatabase
    sourceUrl: ":/data/11-full.json"
}

et attribué à l’objet ` MapItemView`.

model: geoDatabase.model

Le fichier ` 11-full.json ` est chargé au démarrage à titre d’exemple.

Enfin, nous avons besoin d’un ` delegate`, qui convertit les données du modèle en une représentation d’éléments et remplit le fichier ` MapItemView`.

delegate: GeoJsonDelegate {}

L’élément ` GeoJsonDelegate ` est déclaré dans le fichier ` GeoJsonDelegate.qml`. Il s’agit d’un élément de type ` DelegateChooser `, afin de prendre en compte les propriétés variables des différents types de géométrie.

DelegateChooser {
    id: dc
    role: "type"
}

Le fichier « DelegateChooser » contient un « DelegateChoice » pour chaque type de géométrie pouvant figurer dans un fichier GeoJSON. La propriété « role » sera mise en correspondance avec « DelegateChoice.roleValue » afin de déterminer le délégué approprié.

À titre d’exemple, un point, décrit par "type":"Point" dans GeoJson, est représenté par MapCircle dans la propriété MapItemView:

DelegateChoice {
    roleValue: "Point"
    delegate: MapCircle {
        property string geojsonType: "Point"
        property var props: modelData.properties
        geoShape: modelData.data
        radius: (props && props.radius) || 20*1000
        border.width: 2
        border.color: hh.hovered ? "magenta" : Qt.darker(color)
        opacity: dc.defaultOpacity
        color: (props && props.color) || (parent && parent.props && parent.props.color) || dc.defaultColor
    }
}

Le système tente de lire les propriétés de l’ MapCircle, telles que color ou radius, à partir du fichier GeoJSON disponible sous la forme de la propriété modelData. Cependant, cela ne constitue pas une norme stricte de GeoJSON et des valeurs de secours sont définies pour toutes les propriétés.

Écriture de MapItems dans un fichier GeoJSON

Pour écrire des MapItems dans un fichier GeoJson, il suffit d’appeler la fonction ` GeoJsonData::saveAs ` en lui passant le nom de fichier souhaité. Cela permet d’écrire tous les éléments du modèle actuel dans le fichier spécifié. Tout autre élément devant être écrit dans le fichier doit d’abord être ajouté au modèle à l’aide de la fonction ` GeoJsonData::addItem ` ou ` GeoJsonData::setModelToMapContents`.

geoDatabase.saveAs(fileWriteDialog.selectedFile)

Interaction de l’utilisateur avec les MapItems

Pour gérer les interactions de l'utilisateur, nous utiliserons les ` PointHandlers`. Ces derniers sont particulièrement bien adaptés à cette tâche, car ils épousent exactement la forme de l'élément sous-jacent, contrairement aux ` MouseArea`, qui couvrent toujours une forme carrée. Les `MapItems` importés depuis un fichier GeoJSON disposent de leurs propres ` HoverHandler ` et ` TapHandler ` directement dans le délégué :

TapHandler {
    onTapped: {
        if (props !== undefined)
            console.log(props.name)
        else if (parent.parent.geojsonType == "MultiPoint")
            console.log(parent.parent.props.name)
        else
            console.log("NO NAME!", props)
    }
}
HoverHandler {
    id: hh
}

La propriété TapHandler sert à afficher des informations sur l’élément dans la console lorsque l’utilisateur appuie dessus. La propriété HoverHandler permet de mettre en surbrillance les éléments situés sous le pointeur de la souris. Cette fonctionnalité est mise en œuvre en définissant la propriété border.color en fonction de la propriété / de l’état hovered de l’ HoverHandler.

Ajout de nouveaux éléments

La combinaison des signaux « HoverHandler » et « TapHandler » pour la propriété « MapView » nous permet de réagir aux mouvements de souris et aux clics de l’utilisateur.

Si l’ TapHandler émet un signal singleTapped, nous créerons ou modifierons un nouvel élément MapItem sur LeftButton et finaliserons cet élément sur RightButton. S’il n’y a aucun élément à finaliser, RightButton ouvrira alors un menu.

onSingleTapped: (eventPoint, button) => {
    lastCoordinate = view.map.toCoordinate(tapHandler.point.position)
    if (button === Qt.RightButton) {
        if (view.unfinishedItem !== undefined) {
            view.finishGeoItem()
        } else
            mapPopupMenu.show(lastCoordinate)
    } else if (button === Qt.LeftButton) {
        if (view.unfinishedItem !== undefined) {
            if (view.unfinishedItem.addGeometry(view.map.toCoordinate(tapHandler.point.position), false)) {
                view.finishGeoItem()
            }
        }
    }
}

Le signal pointChanged sert à mettre à jour temporairement un MapItem, offrant ainsi un aperçu à l’utilisateur.

HoverHandler {
    id: hoverHandler
    property variant currentCoordinate
    grabPermissions: PointerHandler.CanTakeOverFromItems | PointerHandler.CanTakeOverFromHandlersOfDifferentType

    onPointChanged: {
        currentCoordinate = view.map.toCoordinate(hoverHandler.point.position)
        if (view.unfinishedItem !== undefined)
            view.unfinishedItem.addGeometry(view.map.toCoordinate(hoverHandler.point.position), true)
    }
}

Les MapItems sont générés à partir de prototypes définis dans des fichiers QML distincts. Ils sont créés à l’aide de la fonction ` createComponent ` et ajoutés à la carte avec ` addMapItem`. Une référence au nouvel élément est stockée pour permettre à l’utilisateur de le manipuler ultérieurement.

function addGeoItem(item)
{
    var co = Qt.createComponent('mapitems/'+item+'.qml')
    if (co.status === Component.Ready) {
        unfinishedItem = co.createObject(map)
        unfinishedItem.setGeometry(tapHandler.lastCoordinate)
        unfinishedItem.addGeometry(hoverHandler.currentCoordinate, false)
        view.map.addMapItem(unfinishedItem)
    } else {
        console.log(item + " is not supported right now, please call us later.")
    }
}

Il suffit d'ajouter l'élément à la ` Map ` pour l'afficher. Cependant, pour pouvoir l'utiliser ultérieurement (par exemple, pour l'enregistrer dans un fichier), il doit être ajouté au modèle. Cette opération s'effectue une fois l'édition terminée :

function finishGeoItem()
{
    unfinishedItem.finishAddGeometry()
    geoDatabase.addItem(unfinishedItem)
    map.removeMapItem(unfinishedItem)
    unfinishedItem = undefined
}

Suppression d’éléments

Pour supprimer tous les éléments de la carte, il suffit d’appeler la fonction reset de l’objet ` GeoJsonData `

function clearAllItems()
{
    geoDatabase.clear();
}

Exemple de projet @ code.qt.io

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.