Newer
Older
# Filtres sur les couches
Il est possible d'ajouter des formulaires de filtre sur les couches dans le but de visualiser certaines données uniquement.
Alors les utilisateurs du mode cartographique auront accès à un bouton faisant apparaître le formulaire de filtrage, sur la carte "Carte de France" créée par défaut lors de l'installation de l'application un filtre est mis en place à titre d'exemple.
Sur la couche "Commune" un bouton de filtre apparaît

En cliquant dessus le formulaire suivant est affiché dans une fenêtre modale

L'utilisateur peut alors filtrer la couche pour afficher uniquement les communes ayant une population comprise dans la fourchette saisie par l'utilisateur, ainsi si on saisit 50000 à "Population suppérieure à" nous obtenons la carte suivante:
<img src="../../images/filtres_couches_3.jpg" width="45%" /> <img src="../../images/filtres_couches_4.jpg" width="45%" />
Pour ce faire il faudra effectuer plusieurs étapes détaillées ci-dessous.
## 1 - Écrire le filtre sur la couche Mapserver
Après avoir saisit le filtre, vMap va ajouter aux URL permanentant de récupérer les tuiles les paramètres saisis, dans le module Mapserver il est possible de récupérer et d'utiliser ces valeurs. Bien évidemment cette opération est également fonctionnelle si vous utilisez un autre générateur de flux WMS.
Sur le module Mapserver il faudra se rendre dans la définition de la couche pour y renseigner un filtre, nous allons détailler l'exemple des communes, mais si vous voulez plus de détails vous trouverez toute l'information disponible sur la documentation Mapserver http://mapserver.org/fr/cgi/runsub.html#filters
Dans notre exemple voici ce qui est écrit:
```
FILTER ([pop90] > '%pop90_sup%' and [pop90] < '%pop90_inf%')
VALIDATION
'pop90_sup' '^[0-9]*$'
'default_pop90_sup' '0'
'pop90_inf' '^[0-9]*$'
'default_pop90_inf' '100000000'
END
```
**Dans la balise FILTER** on écria la condition à respecter, les noms des colonnes devrons être écrites entre crochets ex: [pop90] et les noms des attributs récupérés à travers le l'URL (c'est à dire le formulaire de filtre) devront être écris entre pourcentages ex: %pop90_sup%
**La balise VALIDATION est obligatoire** et on doit y écrire pour chaque attribut récupéré à travers l'URL (c'est à dire le formulaire de filtre) une expression régulière empéchant les personnes mal intentionnées de faire des injections SQL, dans notre exemple nous avons écrit '^[0-9]\*$' ce qui signifie autant de chiffres entre 0 et 9 que souhaité. **Pour que la carte affiche des valeurs lorsque les filtres sont vides** il faudra définir des valeurs par défaut en écrivant default_[nom de votre attribut], dans notre exemple par défaut la carte filtre les villes entre 0 et 100000000 d'habitants.
On peut également utiliser la balise **FILTERITEM** pour faire un filtre plus générique:
```
FILTERITEM "id_com"
FILTER /%id_com%/
VALIDATION
"id_com" "^[a-zA-Z0-9_|]*$"
"default_id_com" "^[a-zA-Z0-9_|]*$"
END
```
## 2 - Mettre en place un formulaire de filtre
Pour mettre en place le formulaire il faudra aller dans la partie **calques** et mettre Oui à "Calque filtrable (Mapserver)"

Après avoir mis à jour le calque, une nouvelle section "Formulaire de filtre" va apparaître dans lequel vous pourrez mettre en place votre filtre.

# Autres exemples d'utilisation des filtres dans vMap
## 1 - Filtre textuelle non obligatoire et fonctionnement similaire au LIKE en SQL
Dans le studio il faudra définir un champ de type texte ou une liste déroulante avec une source de données adaptée.
Il faudra définir votre filtre pour qu'il utilise une valeur par défaut qui permettra de court-circuiter le filtre. (Dans le cas présent **'empty'**)
Si vous voulez un fonctionnement plus proche d'un LIKE SQL utilisez **~** à la place de **=**. (voir exemple ci-dessous)
```
FILTER (([type] = '%type%' or '%type%' = 'empty') and ([liketext] ~ '%liketext%' or '%liketext%' = 'empty')
VALIDATION
'type' '^empty|value_type_1|value_type_2|value_type_3$'
'liketext' '^empty|.{1,}$'
'default_type' 'empty'
'default_liketext' 'empty'
END
```
## 2 - Filtre sur une colonne de type date/timestamp
Pour filtrer sur un attribut unique de type date/timestamp référez vous à la documentation de MapServer http://mapserver.org/ogc/wms_time.html.
## 3 - Filtre sur plusieurs colonnes de type date/timestamp
Vue que la spécification d'un champ de type date/timestamp se fait dans la partie **METADATA**, il est impossible pour MapServer de traiter deux champs de ce type en théorie.
En réalité par un moyen détourné, il est possible de gérer autant de champs date/timestamp que vous voulez.
Pour l'exemple, je vais prendre trois champs en base creation_date (date de création d'un objet, type postgres timestamp with time zone), date_debut_travaux (une date de début de travaux pour un objet métier par exemple, type timestamp with time zone), duree_travaux_jour (la durée des travaux en jours à partie de la date de début, type integer)
### a - Adapter votre vue
Pour permettre à MapServer de les traiter comme des entiers il va falloir que la vue retourne des entiers.
Exemple de code permettant de faire cela :
```sql
date_part('epoch'::text, table.creation_date)::integer AS mstmstp_creation_date,
date_part('epoch'::text, table.date_debut_travaux)::integer AS mstmstp_date_debut_travaux,
date_part('epoch'::text, table.date_debut_travaux + table.duree_travaux_jour * '1 day'::interval)::integer AS mstmstp_date_fin_travaux
```
### b - Adapter votre formulaire avec le studio
Ajouter les champs dates que vous voulez. Dans le cas présent on va laisser la possibilité de prendre une date au dessus, en dessous, ou d'encadrer la/les date(s).
Pour chaque champ date il faut un champ caché. Le champ date va renvoyer une valeur formatée du type 'DD/MM/YYYY' ou 'YYYY-MM-DD', mais nous voulons un timestamp. Nous allons voir dans la prochaine partie comment utiliser un champ date pour remplir un champ caché avec un timestamp.

### c - Permettre au formulaire de calculer les timestamps
Il va falloir ajouter du code javascript spécifique à ce formulaire. Pour ce faire il va falloir changer de mode d'utilisation du studio, pour pouvoir éditer du javascript.

Vous allez arriver devant un champ vide.
Voici le code permettant de remplir les champs cachés pour l'exemple :
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
```javascript
/* global angular, goog, moment, vitisApp, bootbox */
// goog fonctionne en mode décompilé mais pas en mode compilé
console.info("filtre_mapserver_couche_NOM loaded --> your functions are ready");
/***********************************************************************************
filtre_mapserver_couche_NOM Javascript
***********************************************************************************/
var oFormRequired = {
"sUrl": "",
"scope_": {},
"toDestructor": []
};
/**
* constructor_form
* Fonction appelée à l'initialisation du formulaire
* @param {type} scope
* @param {type} s_url
* @returns {undefined}
*/
var constructor_form = function (scope, s_url) {
oFormRequired.sUrl = s_url;
oFormRequired.scope_ = scope;
var formaterStringFrom = "DD/MM/YYYY";
var formaterStringTo = "X"; // timestamp UNIX
oFormRequired.toDestructor.push(oFormRequired.scope_.$watch("oFormValues." + oFormRequired.scope_.sFormDefinitionName + ".creation_date_min_viz", function (value) {
if (typeof(value) !== "undefined" && value !== "") {
oFormRequired.scope_["oFormValues"][oFormRequired.scope_["sFormDefinitionName"]]["creation_date_min"] = moment(value, formaterStringFrom).format(formaterStringTo);
} else {
oFormRequired.scope_["oFormValues"][oFormRequired.scope_["sFormDefinitionName"]]["creation_date_min"] = null;
}
})
);
oFormRequired.toDestructor.push(oFormRequired.scope_.$watch("oFormValues." + oFormRequired.scope_.sFormDefinitionName + ".creation_date_max_viz", function (value) {
if (typeof(value) !== "undefined" && value !== "") {
oFormRequired.scope_["oFormValues"][oFormRequired.scope_["sFormDefinitionName"]]["creation_date_max"] = moment(value, formaterStringFrom).format(formaterStringTo);
} else {
oFormRequired.scope_["oFormValues"][oFormRequired.scope_["sFormDefinitionName"]]["creation_date_max"] = null;
}
})
);
oFormRequired.toDestructor.push(oFormRequired.scope_.$watch("oFormValues." + oFormRequired.scope_.sFormDefinitionName + ".tavaux_date_min_viz", function (value) {
if (typeof(value) !== "undefined" && value !== "") {
oFormRequired.scope_["oFormValues"][oFormRequired.scope_["sFormDefinitionName"]]["travaux_date_min"] = moment(value, formaterStringFrom).format(formaterStringTo);
} else {
oFormRequired.scope_["oFormValues"][oFormRequired.scope_["sFormDefinitionName"]]["travaux_date_min"] = null;
}
})
);
oFormRequired.toDestructor.push(oFormRequired.scope_.$watch("oFormValues." + oFormRequired.scope_.sFormDefinitionName + ".tavaux_date_max_viz", function (value) {
if (typeof(value) !== "undefined" && value !== "") {
oFormRequired.scope_["oFormValues"][oFormRequired.scope_["sFormDefinitionName"]]["travaux_date_max"] = moment(value, formaterStringFrom).format(formaterStringTo);
} else {
oFormRequired.scope_["oFormValues"][oFormRequired.scope_["sFormDefinitionName"]]["travaux_date_max"] = null;
}
})
);
};
/**
* destructor_form
* Fonction appelée quand on quitte le formulaire (ne pas modifier)
* @returns {undefined}
*/
var destructor_form = function () {
console.log("Destructor");
for (var i = 0; i < oFormRequired.toDestructor.length; i++) {
oFormRequired.toDestructor[i] = undefined;
delete oFormRequired.toDestructor[i];
}
//supprimer la balise script du js pour pouvoir le recharger si on revient sur le formulaire plus tard
angular.element('[src="' + oFormRequired.sUrl + '?version=' + oFormRequired.scope_["oProperties"]["build"] + '"]').remove();
oFormRequired = undefined;
delete oFormRequired;
constructor_form = undefined;
delete constructor_form;
destructor_form = undefined;
delete destructor_form;
};
/**********************************************************************************/
```
Ce code créé une instance pour surveiller les changements des champs dates (**$watch**) et utilise une librairie intégrée à Vitis (**moment.js**) pour parser la date, la transformer en timestamp Unix et stocker le résultat dans le champ caché.
### d - Intégration du filtre dans la couche MapServer
```
FILTER (([mstmstp_date_debut_travaux] < '%travaux_date_max%' or [mstmstp_date_fin_travaux] < '%travaux_date_max%') and ([mstmstp_date_debut_travaux] < '%travaux_date_min%' or [mstmstp_date_fin_travaux] < '%travaux_date_min%') and ([mstmstp_creation_date] < '%travaux_date_max%') and ([mstmstp_creation_date] > '%creation_date_min%'))
VALIDATION
'creation_date_max' '^[0-9]{1,}$'
'creation_date_min' '^[0-9]{1,}$'
'travaux_date_max' '^[0-9]{1,}$'
'travaux_date_min' '^[0-9]{1,}$'
'default_creation_date_max' '10000000000000000000000000'
'default_creation_date_min' '0'
'default_travaux_date_max' '10000000000000000000000000'
'default_travaux_date_min' '0'
END