Azione in un popup

Questa è una funzionalità di Lizmap 3.4.

Regola

Questo modulo permette di aggiungere uno o più pulsanti d’azione nel popup di Lizmap visualizzato per un oggetto PostgreSQL, il quale avvierà una query nel database e restituirà una geometria da visualizzare sulla mappa.

Legge un file di configurazione JSON che deve essere collocato a lato del progetto QGIS nella stessa directory. Questo file elenca le azioni PostgreSQL da aggiungere nel popup per uno o più livelli vettoriali QGIS PostgreSQL.

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

Configurazione del plugin

  • Ogni azione è caratterizzata da un layer id`, un name`, un title, un icon, alcune options opzionali, style e callbacks. Una nuova proprietà confirm può essere usata da Lizmap 3.5
  • Un livello può avere una o più azioni
  • Si possono avere uno o più livelli con le rispettive azioni

Esempio di questo file di configurazione JSON, nome myproject.qgs.action se il file del progetto QGIS si chiama myproject.qgs. In questo progetto, c’è un livello vettoriale chiamato Points con l’ID interno del livello points_a7e8943b_7138_4788_a775_f94cbd0ad8b6 (puoi ottenere l’ID interno del livello QGIS con l’espressione @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"}
            ]
        }
    ]
}

Il file Configurazione JSON elenca i livelli QGIS per i quali vuoi dichiarare delle azioni. Ogni livello è definito dal suo QGIS layer ID, per esempio qui points_a7e8943b_7138_4788_a775_f94cbd0ad8b6, e per ogni ID, una lista di oggetti che descrivono le azioni da permettere.

Ogni azione è un oggetto definito da:

  • un nome che è l’identificatore dell’azione.

  • un titolo che è usato come etichetta nell’interfaccia Lizmap

  • una icona che viene visualizzata sul pulsante dell’azione ( Vedere https://getbootstrap.com/2.3.2/base-css.html#icons )

  • una proprietà opzionale confirm, da Lizmap 3.5, contenente del testo. Se impostata, un dialogo di conferma verrà mostrato all’utente per chiedere se l’azione deve essere realmente lanciata o no. Usalo se l’azione può modificare alcuni dati nel tuo database.

  • un oggetto options, che fornisce alcuni parametri aggiuntivi per questa azione. Puoi aggiungere qualsiasi parametro necessario.

  • un oggetto style che permette di configurare lo stile della geometria restituita. Segue gli attributi di stile di OpenLayers.

  • un oggetto callbacks permette di innescare alcune azioni dopo la restituzione della geometria generata. Sono definiti da un nome di method, che al momento può essere:

    • zoom: zoom sulla geometria restituita
    • select`: seleziona le caratteristiche di un dato livello che intersecano la geometria restituita. Il livello di destinazione QGIS internal ID deve essere aggiunto nella proprietà layerId. Nell’esempio, saranno selezionate le caratteristiche del livello contenente edifici, ID bati_1a016229_287a_4b5e_a4f7_a2080333f440.
    • redraw: ridisegna (aggiorna) un dato livello nella mappa. L’ID QGIS del livello di destinazione deve essere aggiunto nella proprietà layerId.

Lizmap rileva la presenza di questo file di configurazione, e aggiunge la logica necessaria al caricamento della mappa. Quando l’utente clicca su un oggetto di uno di questi livelli nella mappa, il pannello popup mostra i dati della caratteristica. In cima ad ogni oggetto popup, una barra degli strumenti mostrerà un pulsante per ogni azione del livello. Il titolo dell’azione sarà visualizzato al passaggio del mouse sul pulsante dell’azione.

Ogni pulsante attiva l’azione corrispondente, se non è ancora attiva (altrimenti disattiva e cancella la geometria):

  • Lizmap backend controlla se l’azione è ben configurata,
  • crea la query **PostgreSQL e la esegue nel database PostgreSQL del livello. (Vedi esempio qui sotto)
  • Questa query restituisce un GeoJSON che viene poi visualizzato sulla mappa.
  • Se alcuni callback sono stati configurati, vengono lanciati
  • A partire da Lizmap 3.5, viene emesso un evento Lizmap actionResultReceived con i dati restituiti e le proprietà dell’azione.

La query PostgreSQL creata è costruita dal client web Lizmap e usa la funzione PostgreSQL lizmap_get_data(json) che deve essere creata prima nella tabella database PostgreSQL. Questa funzione usa anche una funzione più generica query_to_geojson(text) che trasforma qualsiasi stringa di interrogazione PostgreSQL in un output GeoJSON.

Ecco un esempio qui sotto della query eseguita nel database PostgreSQL da Lizmap Web Client internamente, per la configurazione di esempio data sopra, quando l’utente clicca sul pulsante azione buffer_500, per la feature con id 1 del layer Points corrispondente alla tabella 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;

Potete notare che Lizmap crea un parametro JSON con tutte le informazioni necessarie ed esegue la funzione PostgreSQL lizmap_get_data(text).

Dovete creare questa funzione PostgreSQL lizmap_get_data(text) che restituisce un testo GeoJSON valido con un singolo oggetto dentro. Il seguente codice SQL è un esempio per aiutarti a creare le funzioni necessarie. Ovviamente, devi adattarlo alle tue esigenze.

-- 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 funzione lizmap_get_data(json) è fornita qui come esempio. Poiché è il punto di ingresso chiave, è necessario adattarlo alle proprie esigenze. Ha lo scopo di creare una query per ogni nome di azione, creata dinamicamente per i parametri forniti, e restituire una rappresentazione GeoJSON dei dati del risultato della query. Dovreste avere solo un elemento restituito: usate l’aggregazione se necessario. Nell’esempio sopra, usiamo il metodo format per impostare il testo della query, e la funzione query_to_geojson per restituire il GeoJSON per questa query.
  • Puoi usare tutti i parametri dati (nome dell’azione, schema dei dati sorgente e nome della tabella, id dell’elemento, nome del livello QGIS) per creare la query appropriata per la tua azione, usando le clausole PostgreSQL IF THEN ELSIF ELSE. Vedi il contenuto della variabile parameters nell’esempio sopra, che contiene alcune delle proprietà del file di configurazione JSON e alcune proprietà del livello QGIS:
    • il nome dell’azione action_name, per esempio buffer_500. Dovresti usare una parola semplice con solo lettere, cifre e _,
    • QGIS nome del livello (come in leggenda QGIS): layer_name, per esempio Punti,
    • la tabella PostgreSQL schema layer_schema e nome della tabella layer_table per questo livello,
    • l’oggetto id elemento feature_id, che corrisponde al valore del campo chiave primaria dell’oggetto popup,
    • le altre proprietà fornite nel file di configurazione JSON, nella proprietà options, come buffer_size che è 500 nell’esempio
  • Il IF ELSE viene usato per fare una query diversa, costruita nella variabile datasource, controllando l” action name
  • Se i dati restituiti contengono un campo message, come mostrato nell’esempio precedente, il testo contenuto in questo campo sarà visualizzato nella mappa in un messaggio a fumetto.
  • La geometria restituita dalla funzione sarà visualizzata sulla mappa.
  • Potresti usare la tua funzione per modificare alcuni dati nel tuo database, prima di restituire un GeoJSON. Per farlo, devi sostituire la proprietà IMMUTABLE con VOLATILE. Per favore utilizzalo con cura !

Dato che Lizmap Web Client innesca un evento actionResultReceived ogni volta che l’utente clicca su un pulsante di azione, e i dati vengono restituiti ( nello stesso momento in cui la geometria del risultato viene disegnata sulla mappa), si potrebbe usare il proprio codice Javascript per aggiungere della logica dopo che il risultato viene mostrato.

Vedi anche

Capitolo Aggiungere il proprio JavaScript

Per esempio, qui ci limitiamo a scrivere nella console del browser il contenuto ricevuto:

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);
    }
});

Potete usare questi dati come preferite nel vostro codice JS.