Configurer - Custom control

Un custom control est une interface permettant à l’utilisateur d’interagir avec une couche. Le customcontrol est affiché dans le bloc de légende associée à la couche concernée. Un custom control est associé à une seule couche et est constitué de deux fichiers html + javascript. Ces deux fichiers doivent obligatoirement être nommé comme l” id de la couche associée.

Syntaxe

<layer id="moncustom"
        customcontrol="true"
        customcontrolpath="chemin_vers_fichiers">
</layer>

Paramètres custom control

  • customcontrol: paramètre qui indique si mviewer doit charger un customcontrol. valeurs : true || false. Défaut = false.

  • customcontrolpath: paramètre qui indique où mviewer doit charger le customcontrol. Si ce paramètre n’est pas renseigné, le customcontrol est recherché dans le répertoire racine customcontrols.

Exemple

config.xml
    <layer id="heatmap"
    name="Earthquakes Heatmap"
    visible="true"
    url="demo/heatmap/customlayer.js"
    queryable="true"
    type="customlayer"
    customcontrol="true"
    customcontrolpath="demo/heatmap/control"
    legendurl="demo/heatmap/legend.png"
    opacity="1"
    expanded="true"
    attribution=""
    metadata=""
    metadata-csw="">
</layer>

Cas pratique : customcontrol pour avoir plusieurs filtres sur une couche

Ce customcontrol permet d’avoir la possibilité de filtrer une couche type WMS sur plusieurs attributs comme ceci :

Filtre sur plusieurs attributs

Création du customcontrol

Comme détaillé dans la page Développer un customControl, un customcontrol est composé de 2 fichiers. Dans le cas du filtre sur plusieurs atttributs d’une couche WMS, vous trouverez les fichiers dans le dossier /demo/filtres_multiples/customcontrol. Les 2 fichiers doivent avoir le même nom que l’id de la couche appelée dans mviewer.

Ici le fichier HTML qui s’affichera en dessous de la légende :

lycee.html
<div class="form cql-filter-list">
    <label>Filtre sur 2 champs</label>
    <style>
        .form.cql-filter-list {
            outline: 2px dashed gray;
            display: inline-table;
            padding-bottom: 20px;
            padding-top: 4px;
            outline-offset: 5px;
        }
        #layers-container .form.cql-filter-list .form-group label {
            font-family: "roboto", Arial, Sans-serif;
            font-style: italic;
            padding-left: 17px;
        }
        .form.cql-filter-list>label {
            font-family: "roboto_bold", Arial, Sans-serif;
        }
    </style>
</div>

Et ici le fichier javascript. Pour l’utiliser sur une de ces couches, il faudra modifier l’id de la couche (ici lycee) par l’id de votre donnée.

lycee.js
 1//Modifier lycee par l'id de votre couche
 2mviewer.customControls.lycee = (function () {
 3const _idlayer = "lycee";
 4const _layer = mviewer.getLayer(_idlayer);
 5let noFilterLabel = "All";
 6let logicalOperator = "AND";
 7
 8return {
 9    init: function () {
10    // mandatory - code executed when panel is opened
11    const _html = [];
12    //Check for xml config ccfilters
13    let filters = [];
14    if (_layer.ccfilters && _layer.ccfilters.filter) {
15        //Convert filter to Array if is not Array (Fix one filter bug)
16        if (!Array.isArray(_layer.ccfilters.filter)) {_layer.ccfilters.filter = [_layer.ccfilters.filter]}
17        //Configuration
18        if (_layer.ccfilters.logicaloperator) { logicalOperator = _layer.ccfilters.logicaloperator; }
19        if (_layer.ccfilters.nofilterlabel) { noFilterLabel = _layer.ccfilters.nofilterlabel; }
20        filters = _layer.ccfilters.filter.map(function(f) { return {
21            'label' : f.label,
22            'field' : f.field,
23            'values' : f.values.split(","),
24            'multiple': (f.multiselection && f.multiselection == "true")
25        }
26        });
27    } else {
28        console.log(`Le customcontrol ${_idlayer} n'a pu être initialisé car la conf xml est incomplète (propriété ccfilters)`)
29    }
30    filters.forEach(function(f) {
31        const options = f.values.map(function(v) {return `<option ${f.multiple?'selected':''}>${v}</option>`});
32        if (!f.multiple) {
33        options.unshift(`<option>${noFilterLabel}</option>`);
34        }
35        const select = `<div class="form-group">
36        <label for="${_idlayer}-${f.field}">${f.label} :</label>
37        <div class="col-md-10 col-md-offset-1">
38        <select ${f.multiple?'multiple':''} placeholder="${f.label}" id="${_idlayer}-${f.field}" data-source="${f.field}" class="form-control cql-filter" onchange="mviewer.customControls.${_idlayer}.filter(this);">
39            ${options.join("")}
40        </select>
41        </div>
42    </div>`;
43    _html.push(select);
44    });
45    document.querySelector(".cql-filter-list>style").insertAdjacentHTML("afterend", _html.join("\n"));
46
47    },
48
49    filter: function(element) {
50    const _filter = [];
51    element.closest(".cql-filter-list").querySelectorAll(".cql-filter").forEach(function(q) {
52        const values = Array.from(q.selectedOptions).map(({ value }) => value);
53        if (values.length == 1) {
54        // Filtres avec choix unique
55        const value = values[0];
56        if (value != noFilterLabel) {
57            _filter.push(`${q.dataset.source} = '${value.replace("'", "''")}'`);
58        }
59        } else {
60        // Filtres avec choix multiple
61        const list = []
62        values.forEach(function(value) {
63            list.push(`'${value.replace("'", "''")}'`)
64        })
65        _filter.push(`${q.dataset.source} in (${list.join(',')})`);
66        }
67
68    });
69    console.log(_filter);
70    const layer = _layer.layer;
71    const _source = layer.getSource();
72    const params = _source.getParams();
73    params.t = new Date().getMilliseconds();
74    if (_filter.length > 0) {
75        const cql_filter = _filter.join(` ${logicalOperator} `);
76        params.CQL_FILTER = cql_filter;
77    } else {
78        params.CQL_FILTER = "1=1";
79    }
80    _source.updateParams(params);
81
82    },
83
84    destroy: function () {
85    // mandatory - code executed when panel is closed
86    },
87};
88})();

Paramétrage dans le XML

Une fois le customcontrol créé, il va falloir l’appeler dans votre application. Tout d’abord en ajoutant les options customcontrol et customcontrolpath puis les paramètres du customcontrol, ici contenus dans ccfilters.

lycee.xml
<layer id="lycee" name="Lycées"  visible="true" tiled="false"
    searchable="false" queryable="true" expanded="true"
    infoformat="application/vnd.ogc.gml" featurecount="20"
    customcontrol="true" customcontrolpath="demo/filtres_multiples/customcontrols"
    url="https://ows.region-bretagne.fr/geoserver/rb/wms"
    attribution="Source: Région Bretagne"
    metadata="https://kartenn.region-bretagne.fr/geonetwork/srv/fre/catalog.search#/metadata/99e78163-ce9a-4eee-9ea0-36afc2a53d25"
    metadata-csw="https://kartenn.region-bretagne.fr/geonetwork/srv/eng/csw?SERVICE=CSW&amp;VERSION=2.0.2&amp;REQUEST=GetRecordById&amp;elementSetName=full&amp;ID=99e78163-ce9a-4eee-9ea0-36afc2a53d25" >
    <ccfilters logicaloperator="and" nofilterlabel="Toutes">
        <filter label="Réseau"  field="reseau_lib" values="Agricole,Education nationale,Maritime" multiselection="true"/>
        <filter label="Secteur"  field="secteur_li" values="Privé sous contrat avec l'éducation nationale,Public" multiselection="true"/>
    </ccfilters>
    <template url="https://kartenn.region-bretagne.fr/kartoviz/apps/region/global/templates/global.lycee.mst"></template>
</layer>

Note

Apprendre par l’exemple :