Action dans une popup

C’est une fonctionnalité dans Lizmap 3.4.

Principe

Ce module permet d’ajouter un ou plusieurs boutons d’action dans la popup Lizmap affichée pour un objet PostgreSQL, qui déclenchera une requête dans la base de données et renverra une **géométrie ** à afficher sur la carte.

Il lit un fichier de configuration JSON qui doit être placé à côté du projet QGIS dans le même répertoire. Ce fichier répertorie les actions PostgreSQL à ajouter dans la popup pour une ou plusieurs couches vectorielles QGIS PostgreSQL.

../../_images/publish-configuration-action-popup.gif

Configurer l’outil

  • Chaque action est caractérisée par un layer_id, un name, un title, une icon, quelques options facultatives, style` ` et ``callbacks. Une nouvelle propriété confirm peut être utilisée depuis Lizmap 3.5
  • Un calque peut avoir une ou plusieurs actions
  • Vous pouvez avoir un ou plusieurs calques avec leurs propres actions

Exemple avec ce fichier de configuration JSON, nom myproject.qgs.action si le fichier de projet QGIS est nommé myproject.qgs. Dans ce projet, il existe une couche vectorielle appelée Points avec l’ID de couche interne points_a7e8943b_7138_4788_a775_f94cbd0ad8b6 (vous pouvez obtenir l’ID interne de la couche QGIS avec l’expression @layer_id)

{
    "points_a7e8943b_7138_4788_a775_f94cbd0ad8b6": [
        {
            "name": "buffer_500",
            "title": "Buffer 500m around this object",
            "confirm": "Do you really want to show the buffer ?",
            "icon": "icon-leaf",
            "options": {
                "buffer_size": 500,
                "other_param": "yes"
            },
            "style": {
                "graphicName": "circle",
                "pointRadius": 6,
                "fill": true,
                "fillColor": "lightblue",
                "fillOpacity": 0.3,
                "stroke": true,
                "strokeWidth": 4,
                "strokeColor": "blue",
                "strokeOpacity": 0.8
            },
            "callbacks": [
                {"method": "zoom"},
                {"method": "select", "layerId": "bati_1a016229_287a_4b5e_a4f7_a2080333f440"},
                {"method": "redraw", "layerId": "bati_1a016229_287a_4b5e_a4f7_a2080333f440"}
            ]
        }
    ]
}

Le fichier configuration JSON répertorie les couches QGIS pour lesquelles vous souhaitez déclarer des actions. Chaque couche est définie par son ID de couche QGIS, par exemple ici points_a7e8943b_7138_4788_a775_f94cbd0ad8b6, et pour chaque ID, une liste d’objets décrivant les actions à autoriser.

Chaque action est un objet défini par :

  • un name qui est l’identifiant de l’action.

  • un title qui est utilisé comme étiquette dans l’interface Lizmap

  • un icon qui sera affiché sur le bouton de l’action (voir https://getbootstrap.com/2.3.2/base-css.html#icons)

  • une propriété facultative confirm, depuis Lizmap 3.5, contenant du texte. Si défini, une boîte de dialogue de confirmation sera affichée à l’utilisateur pour demander si l’action doit vraiment être lancée ou non. Utilisez-le si l’action peut modifier certaines données de votre base de données.

  • un objet options, donnant quelques paramètres supplémentaires pour cette action. Vous pouvez ajouter n’importe quel paramètre nécessaire.

  • un objet style permettant de configurer le style de géométrie renvoyé. Il suit les attributs de style OpenLayers.

  • un objet callbacks permet de déclencher certaines actions après le retour de la géométrie générée. Ils sont définis par un nom de method, qui peut actuellement être :

    • zoom: zoome vers la géométrie retournée
    • select : sélectionnez les entités d’une couche donnée coupant la géométrie renvoyée. La couche cible QGIS internal ID doit être ajoutée dans la propriété layerId. Dans l’exemple, les entités de la couche contenant les bâtiments, l’ID bati_1a016229_287a_4b5e_a4f7_a2080333f440 sera sélectionné
    • redraw : redessine (rafraîchit) une couche donnée dans la carte. L’ID QGIS de la couche cible doit être ajouté dans la propriété layerId.

Lizmap détecte la présence de ce fichier de configuration et ajoute la logique nécessaire lors du chargement de la carte. Lorsque les utilisateurs cliquent sur un objet de l’une de ces couches sur la carte, le panneau contextuel affiche les données de l’entité. En haut de chaque élément contextuel, une barre d’outils affichera un bouton pour chaque action de couche. L’action titre s’affichera en survolant le bouton d’action.

Chaque bouton déclenche l’action correspondante, s’il n’est pas encore actif (sinon il désactive et efface la géométrie) :

  • l’application Lizmap vérifie si l’action est bien configuré,
  • crée la requête PostgreSQL et l’exécute dans la couche de base de données PostgreSQL. (Voir exemple ci-dessous)
  • Cette requête retourne un GeoJSON qui est ensuite affiché sur la carte.
  • Si des callbacks ont été configurés, ils sont lancés
  • Depuis Lizmap 3.5, un événement Lizmap actionResultReceived est émis avec les données et les propriétés de l’action.

La requête PostgreSQL créée est construite par le client Web Lizmap et utilise la fonction PostgreSQL lizmap_get_data(json) qui doit être créée au préalable dans la table de la base de données PostgreSQL. Cette fonction utilise également une fonction plus générique query_to_geojson(text) qui transforme n’importe quelle chaîne de requête PostgreSQL en une sortie GeoJSON.

Voici un exemple ci-dessous de la requête exécutée dans la base de données PostgreSQL par Lizmap Web Client en interne, pour l’exemple de configuration donné ci-dessus, lorsque les utilisateurs cliquent sur le bouton action buffer_500, pour l”entité avec l’id 1 de la couche Points correspondant à la table PostgreSQL test.points :

SELECT public.lizmap_get_data('{
    "layer_name":"points",
    "layer_schema":"test",
    "layer_table":"points",
    "feature_id":1,
    "action_name":"buffer_500",
    "buffer_size":500,
    "other_param": "yes"
}') AS data;

Vous pouvez voir que Lizmap crée des paramètres JSON avec toutes les informations nécessaires et exécute la fonction PostgreSQL lizmap_get_data(text).

Vous devez créer cette fonction PostgreSQL lizmap_get_data(text) qui renvoie un texte GeoJSON valide contenant un seul objet. Le code SQL suivant est un exemple pour vous aider à créer les fonctions nécessaires. Évidemment, vous devez l’adapter à vos besoins.

-- Returns a valid GeoJSON from any query
CREATE OR REPLACE FUNCTION query_to_geojson(datasource text)
RETURNS json AS
$$
DECLARE
    sqltext text;
    ajson json;
BEGIN
    sqltext:= format('
        SELECT jsonb_build_object(
            ''type'',  ''FeatureCollection'',
            ''features'', jsonb_agg(features.feature)
        )::json
        FROM (
          SELECT jsonb_build_object(
            ''type'',       ''Feature'',
            ''id'',         id,
            ''geometry'',   ST_AsGeoJSON(ST_Transform(geom, 4326))::jsonb,
            ''properties'', to_jsonb(inputs) - ''geom''
          ) AS feature
          FROM (
              SELECT * FROM (%s) foo
          ) AS inputs
        ) AS features
    ', datasource);
    RAISE NOTICE 'SQL = %s', sqltext;
    EXECUTE sqltext INTO ajson;
    RETURN ajson;
END;
$$
LANGUAGE 'plpgsql'
IMMUTABLE STRICT;

COMMENT ON FUNCTION query_to_geojson(text) IS 'Generate a valid GEOJSON from a given SQL text query.';

-- Create a query depending on the action, layer and feature and returns a GeoJSON.
CREATE OR REPLACE FUNCTION lizmap_get_data(parameters json)
RETURNS json AS
$$
DECLARE
    feature_id integer;
    layer_name text;
    layer_table text;
    layer_schema text;
    action_name text;
    sqltext text;
    datasource text;
    ajson json;
BEGIN

    action_name:= parameters->>'action_name';
    feature_id:= (parameters->>'feature_id')::integer;
    layer_name:= parameters->>'layer_name';
    layer_schema:= parameters->>'layer_schema';
    layer_table:= parameters->>'layer_table';

    -- Action buffer_500
    -- Written here as an example
    -- Performs a buffer on the geometry
    IF action_name = 'buffer_500' THEN
        datasource:= format('
            SELECT
            %1$s AS id,
            ''The buffer '' || %4$s || ''m has been displayed in the map'' AS message,
            ST_Buffer(geom, %4$s) AS geom
            FROM "%2$s"."%3$s"
            WHERE id = %1$s
        ',
        feature_id,
        layer_schema,
        layer_table,
        parameters->>'buffer_size'
        );
    ELSE
    -- Default : return geometry
        datasource:= format('
            SELECT
            %1$s AS id,
            ''The geometry of the object have been displayed in the map'' AS message
            geom
            FROM "%2$s"."%3$s"
            WHERE id = %1$s
        ',
        feature_id,
        layer_schema,
        layer_table
        );

    END IF;

    SELECT query_to_geojson(datasource)
    INTO ajson
    ;
    RETURN ajson;
END;
$$
LANGUAGE 'plpgsql'
IMMUTABLE STRICT;

COMMENT ON FUNCTION lizmap_get_data(json) IS 'Generate a valid GeoJSON from an action described by a name, PostgreSQL schema and table name of the source data, a QGIS layer name, a feature id and additional options.';
  • La fonction lizmap_get_data(json) est fournie ici à titre d’exemple. Puisqu’il s’agit du point d’entrée clé, vous devez l’adapter à vos besoins. Il vise à créer une requête pour chaque action, créée dynamiquement pour les paramètres donnés, et à renvoyer une représentation GeoJSON des données par rapport à la requête. Vous devriez avoir une seule entité renvoyée : utilisez l’agrégation si nécessaire. Dans l’exemple ci-dessus, nous utilisons la méthode format pour définir le texte de la requête et la fonction query_to_geojson pour renvoyer le GeoJSON pour cette requête.
  • Vous pouvez utiliser tous les paramètres donnés (nom d’action, schéma de données source et nom de table, identifiant d’entité, nom de couche QGIS) pour créer la requête appropriée pour votre/vos action(s), en utilisant les clauses PostgreSQL IF THEN ELSIF ELSE . Voir le contenu de la variable parameters dans l’exemple ci-dessus, contenant certaines des propriétés du fichier de configuration JSON et certaines propriétés de la couche QGIS :
    • le nom de l’action action_name, par exemple buffer_500. Vous devez utiliser un mot simple avec uniquement des lettres, des chiffres et _,
    • QGIS nom de la couche (comme dans la légende QGIS) : layer_name, par exemple Points,
    • le schema PostgreSQL de la table layer_schema et nom de la table layer_table pour cette couche,
    • l’objet feature id feature_id, qui correspond à la valeur du champ clé primaire de l’objet popup,
    • les autres propriétés données dans le fichier de configuration JSON, dans la propriété options, comme buffer_size qui vaut 500 dans l’exemple
  • Le IF ELSE est utilisé pour faire une requête différente, construite dans la variable datasource, en vérifiant le nom de l’action
  • Si les données de retour contiennent un champ message, comme illustré dans l’exemple ci-dessus, le texte contenu dans ce champ sera affiché dans la carte dans une bulle de message.
  • La géométrie renvoyée par la fonction sera affichée sur la carte.
  • Vous pouvez utiliser votre fonction pour éditer certaines données dans votre base de données, avant de renvoyer un GeoJSON. Pour ce faire, vous devez remplacer la propriété IMMUTABLE par VOLATILE. Veuillez l’utiliser avec précaution !

Étant donné que Lizmap Web Client déclenche un événement actionResultReceived à chaque fois que l’utilisateur clique sur un bouton d’action et que les données sont renvoyées (en même temps que la géométrie du résultat est dessinée sur la carte), vous pouvez utiliser votre propre code Javascript pour ajouter une logique après l’affichage du résultat.

Voir aussi

Chapitre Ajouter votre propre JavaScript

Par exemple, ici nous écrivons simplement dans la console du navigateur le contenu reçu :

lizMap.events.on({

    actionResultReceived: function(e) {
        // QGIS Layer id
        var layerId = e.layerId;
        console.log('Layer ID = ' + layerId);
        // Feature ID, which means the value of the primary key field
        var featureId = e.featureId;
        console.log('Feature ID = ' + featureId);
        // Action item with its name and other properties: name, title, options, styles, etc.
        var action = e.action;
        console.log('Action properties = ');
        console.log(action);
        // Features returned by the action
        var features = e.features;
        console.log('Returned object = ');
        console.log(features);
    }
});

Vous pouvez utiliser ces données à votre guise dans votre code JS.