diff --git a/src/css/app.scss b/src/css/app.scss
index 5f6cdb12..32db6ef4 100644
--- a/src/css/app.scss
+++ b/src/css/app.scss
@@ -14,4 +14,5 @@
@use 'layer-catalogue.css';
@use 'layer-switcher.css';
@use 'my-account.css';
+@use 'poi.css';
@use 'media-queries.css';
diff --git a/src/css/assets/filtrer.svg b/src/css/assets/filtrer.svg
new file mode 100644
index 00000000..68304472
--- /dev/null
+++ b/src/css/assets/filtrer.svg
@@ -0,0 +1,5 @@
+
+
diff --git a/src/css/map-buttons.css b/src/css/map-buttons.css
index 0756d435..2d0ebcb2 100644
--- a/src/css/map-buttons.css
+++ b/src/css/map-buttons.css
@@ -21,7 +21,8 @@
#sideBySideBtn,
#layerManagerBtn,
#geolocateBtn,
-#compassBtn {
+#compassBtn,
+#filterPoiBtn {
width: 40px;
height: 40px;
border-radius: 60px;
@@ -59,6 +60,12 @@
bottom: calc(225px + env(safe-area-inset-bottom));
}
+#filterPoiBtn {
+ background-image: url("assets/filtrer.svg");
+ position: absolute;
+ top: calc(80px + env(safe-area-inset-top));
+}
+
@media (min-width: 615px), screen and (min-aspect-ratio: 1/1) and (min-width:400px) {
#layerManagerBtn {
bottom: calc(65px + env(safe-area-inset-bottom));
diff --git a/src/css/poi.css b/src/css/poi.css
new file mode 100644
index 00000000..46530613
--- /dev/null
+++ b/src/css/poi.css
@@ -0,0 +1,42 @@
+.divPOIContainer {}
+
+.spanPOITitle {
+ text-align: left;
+ width: 100%;
+ font-family: "Open Sans";
+ font-weight: bold;
+ font-size: 1.1em;
+}
+
+.divPOIDisplayGoBackTime,
+.divPOIDisplay {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ font-family: "Open Sans";
+ padding-top: 15px;
+ align-items: center;
+}
+
+.divPOIDisplay > span,
+.divPOIDisplayGoBackTime > span {
+ max-width: 50%;
+ white-space: wrap;
+ text-align: left;
+ }
+
+
+.divPOIFilterItems {
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+ font-family: "Open Sans";
+}
+.lblPOIFilterItem {
+ margin-bottom: 8px;
+ width: fit-content;
+}
+.inputPOIFilterItem {}
+
+#displayPOI {}
+#displayPOIGoBackTime {}
diff --git a/src/css/tabs.css b/src/css/tabs.css
index 8a040fbc..6c13af8a 100644
--- a/src/css/tabs.css
+++ b/src/css/tabs.css
@@ -9,7 +9,8 @@
#directionsWindow,
#directionsResultsWindow,
#mypositionWindow,
-#layerManagerWindow {
+#layerManagerWindow,
+#poiWindow {
margin-top: 10px;
position: relative;
border-top-left-radius: 5px;
diff --git a/src/html/index.html b/src/html/index.html
index b9bf935e..c7372590 100644
--- a/src/html/index.html
+++ b/src/html/index.html
@@ -44,6 +44,7 @@
<%= require('html-loader!./tabs/mypositionWindow.html').default %>
<%= require('html-loader!./tabs/myaccountWindow.html').default %>
<%= require('html-loader!./tabs/informationsWindow.html').default %>
+ <%= require('html-loader!./tabs/poiWindow.html').default %>
diff --git a/src/html/mapButtons.html b/src/html/mapButtons.html
index db93a3dc..be081c45 100644
--- a/src/html/mapButtons.html
+++ b/src/html/mapButtons.html
@@ -8,3 +8,5 @@
+
+
diff --git a/src/html/tabs/layermanagerWindow.html b/src/html/tabs/layermanagerWindow.html
index 3802c82b..64726af4 100644
--- a/src/html/tabs/layermanagerWindow.html
+++ b/src/html/tabs/layermanagerWindow.html
@@ -8,7 +8,7 @@
-
+
diff --git a/src/html/tabs/poiWindow.html b/src/html/tabs/poiWindow.html
new file mode 100644
index 00000000..4a75ca02
--- /dev/null
+++ b/src/html/tabs/poiWindow.html
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/src/js/controls.js b/src/js/controls.js
index cb0fbe66..95410464 100644
--- a/src/js/controls.js
+++ b/src/js/controls.js
@@ -6,6 +6,7 @@ import Isochrone from "./isochrone/isochrone";
import Position from "./my-position";
import Search from "./search";
import Compare from './compare';
+import POI from './poi';
/**
* Ajout des contrôle à la fin du chargement de la carte
@@ -15,6 +16,7 @@ import Compare from './compare';
* @see Position
* @see Compare
* @see Search
+ * @see POI
*/
const addControls = () => {
const map = Globals.map;
@@ -60,6 +62,18 @@ const addControls = () => {
maxWidth: 150,
unit: 'metric'
}), "bottom-left");
+
+ // contrôle filtres POI
+ Globals.poi = new POI(map, {});
+ Globals.poi.load() // promise !
+ .then(() => {
+ // opérations possibles aprés le chargement des POI
+ console.debug("layer POI loaded !");
+ })
+ .catch((e) => {
+ // on ne capture pas les exceptions
+ console.error(e);
+ });
});
}
diff --git a/src/js/data-layer/layers-config.json b/src/js/data-layer/layers-config.json
index 77808a61..b8e8b77d 100644
--- a/src/js/data-layer/layers-config.json
+++ b/src/js/data-layer/layers-config.json
@@ -4283,6 +4283,48 @@
"quicklookUrl": "",
"layerId": "PLAN.IGN.INTERACTIF$GEOPORTAIL:GPP:TMS",
"defaultProjection": "EPSG:3857"
+ },
+ "OSM.POI$GEOPORTAIL:GPP:TMS": {
+ "hidden": true,
+ "queryable": true,
+ "serviceParams": {
+ "id": "GPP:TMS",
+ "version": "1.0.0",
+ "serverUrl": {
+ "appign": "https://data.geopf.fr/tms/1.0.0/"
+ }
+ },
+ "name": "OSM.POI",
+ "title": "POI OSM interactif",
+ "description": "",
+ "formats": [
+ {
+ "current": true,
+ "name": "application/x-protobuf"
+ }
+ ],
+ "styles": [
+ {
+ "name": "standard",
+ "title": "Style standard",
+ "current": true,
+ "url": "data/poi-osm-style.json"
+ }
+ ],
+ "globalConstraint": {
+ "crs": null,
+ "bbox": {
+ "left": -724011.531917197,
+ "right": 1095801.237496279,
+ "top": 6672646.821182753,
+ "bottom": 5009377.0856973175
+ },
+ "minScaleDenominator": null,
+ "maxScaleDenominator": null
+ },
+ "quicklookUrl": "",
+ "layerId": "OSM.POI$GEOPORTAIL:GPP:TMS",
+ "defaultProjection": "EPSG:3857"
}
},
diff --git a/src/js/data-layer/poi-osm-layer-config.json b/src/js/data-layer/poi-osm-layer-config.json
new file mode 100644
index 00000000..ca3b1109
--- /dev/null
+++ b/src/js/data-layer/poi-osm-layer-config.json
@@ -0,0 +1,204 @@
+[{
+ "id": "commerce",
+ "name": "Commerce",
+ "visible": true,
+ "filters": [{
+ "field": "symbo",
+ "attributs": [
+ "alcohol",
+ "antiques",
+ "art",
+ "bakery",
+ "beauty",
+ "bicycle",
+ "books",
+ "butcher",
+ "car",
+ "car_parts",
+ "car_repair",
+ "cheese",
+ "chocolate",
+ "clothes",
+ "computer",
+ "confectionery",
+ "convenience",
+ "convenience;gas",
+ "cosmetics",
+ "deli",
+ "doityourself",
+ "dry_cleaning",
+ "e-cigarette",
+ "electronics",
+ "farm",
+ "florist",
+ "frozen_food",
+ "funeral_directors",
+ "furniture",
+ "garden_centre",
+ "gas",
+ "gift",
+ "greengrocer",
+ "hairdresser",
+ "hardware",
+ "hearing_aids",
+ "interior_decoration",
+ "jewelry",
+ "kiosk",
+ "kitchen",
+ "laundry",
+ "mall",
+ "marketplace",
+ "mobile_phone",
+ "motorcycle",
+ "newsagent",
+ "optician",
+ "pastry",
+ "seafood",
+ "shoes",
+ "sports",
+ "supermarket",
+ "tattoo",
+ "ticket",
+ "tobacco",
+ "toys",
+ "travel_agency",
+ "vacant",
+ "variety_store",
+ "wine",
+ "yes"
+ ]
+ }]
+ },
+ {
+ "id": "culture_sports_loisirs",
+ "name": "Culture , Sports et Loisirs",
+ "visible": true,
+ "filters": [{
+ "field": "symbo",
+ "attributs": [
+ "casino",
+ "cinema",
+ "conference_centre",
+ "library",
+ "museum",
+ "sports_centre",
+ "swimming_pool",
+ "theatre",
+ "theme_park",
+ "zoo"
+ ]
+ }]
+ },
+ {
+ "id": "hebergement",
+ "name": "Hébergement",
+ "visible": true,
+ "filters": [{
+ "field": "symbo",
+ "attributs": [
+ "camp_site",
+ "hotel",
+ "hut"
+ ]
+ }]
+ },
+ {
+ "id": "lieux_remarquables",
+ "name": "Lieux remarquables",
+ "visible": true,
+ "filters": [{
+ "field": "symbo",
+ "attributs": [
+ "autrereligion",
+ "castle",
+ "christian",
+ "church_histo",
+ "grave_yard",
+ "lighthouse",
+ "peak",
+ "saddle",
+ "jewish",
+ "muslim",
+ "viewpoint",
+ "waterway"
+ ]
+ }]
+ },
+ {
+ "id": "restauration",
+ "name": "Restauration",
+ "visible": true,
+ "filters": [{
+ "field": "symbo",
+ "attributs": [
+ "bar",
+ "restaurant"
+ ]
+ }]
+ },
+ {
+ "id": "sante",
+ "name": "Santé",
+ "visible": true,
+ "filters": [{
+ "field": "symbo",
+ "attributs": [
+ "hospital",
+ "pharmacy"
+ ]
+ }]
+ },
+ {
+ "id": "services_commodites",
+ "name": "Services et commodités",
+ "visible": true,
+ "filters": [{
+ "field": "symbo",
+ "attributs": [
+ "atm",
+ "information",
+ "picnic_site",
+ "post_office",
+ "toilets"
+ ]
+ }]
+ },
+ {
+ "id": "services_publics",
+ "name": "Services publics",
+ "visible": true,
+ "filters": [{
+ "field": "symbo",
+ "attributs": [
+ "college",
+ "courthouse",
+ "fire_station",
+ "police",
+ "prison",
+ "school",
+ "townhall",
+ "university"
+ ]
+ }]
+ },
+ {
+ "id": "transports",
+ "name": "Transports",
+ "visible": true,
+ "filters": [{
+ "field": "symbo",
+ "attributs": [
+ "aerodrome",
+ "bicycle_parking",
+ "bicycle_rental",
+ "bus_stop",
+ "charging_station",
+ "ferry_terminal",
+ "fuel",
+ "marina",
+ "parking",
+ "station"
+ ]
+ }]
+ }
+]
\ No newline at end of file
diff --git a/src/js/dom.js b/src/js/dom.js
index d42d50b3..1afc0977 100644
--- a/src/js/dom.js
+++ b/src/js/dom.js
@@ -15,6 +15,7 @@ const $backTopLeftBtn = document.getElementById("backTopLeftBtn");
const $compassBtn = document.getElementById("compassBtn");
const $layerManagerBtn = document.getElementById("layerManagerBtn");
const $sideBySideBtn = document.getElementById("sideBySideBtn");
+const $filterPoiBtn = document.getElementById("filterPoiBtn");
const $whiteScreen = document.getElementById("whiteScreen");
const $parameterScreenWindow = document.getElementById("parameterScreenWindow");
@@ -44,6 +45,7 @@ const $directionsResultsWindow = document.getElementById("directionsResultsWindo
const $isochroneWindow = document.getElementById("isochroneWindow");
const $mypositionWindow = document.getElementById("mypositionWindow");
const $myaccountWindow = document.getElementById("myaccountWindow");
+const $poiWindow = document.getElementById("poiWindow");
export default {
$search,
@@ -80,5 +82,7 @@ export default {
$myaccountWindow,
$informationsWindow,
$informationsText,
- $informationsImg
+ $informationsImg,
+ $filterPoiBtn,
+ $poiWindow
};
diff --git a/src/js/globals.js b/src/js/globals.js
index 4ad66fa3..85c4f924 100644
--- a/src/js/globals.js
+++ b/src/js/globals.js
@@ -61,6 +61,9 @@ let menu = null;
// Global Layer Manager
let manager = null;
+// Global POI filters
+let poi = null;
+
// Scroll
let maxScroll = (document.scrollingElement.scrollHeight - document.scrollingElement.clientHeight);
let anchors = [0, maxScroll / 2.5, maxScroll];
@@ -93,5 +96,6 @@ export default {
search,
compare,
menu,
- manager
+ manager,
+ poi
};
diff --git a/src/js/layer-group.js b/src/js/layer-group.js
index 4d62949c..78bbec69 100644
--- a/src/js/layer-group.js
+++ b/src/js/layer-group.js
@@ -139,6 +139,23 @@ const addVisibility = (id, value) => {
}
};
+/**
+ * Modify visibility of a layer
+ *
+ * @param {*} id
+ * @param {*} name
+ * @param {*} value
+ */
+const addVisibilityByID = (id, name, value) => {
+ var layers = Globals.map.getStyle().layers;
+ for (var i = 0; i < layers.length; i++) {
+ if (layers[i].metadata && layers[i].metadata.group === id && layers[i].id === name) {
+ Globals.map.setLayoutProperty(layers[i].id, "visibility", (value) ? "visible" : "none");
+ break;
+ }
+ }
+};
+
/**
* Modify color N/B
*
@@ -308,6 +325,7 @@ export default {
getGroupLayers,
addOpacity,
addVisibility,
+ addVisibilityByID,
addGray,
addColor
};
\ No newline at end of file
diff --git a/src/js/layer-manager.js b/src/js/layer-manager.js
index 7deb9857..bbf1aee9 100644
--- a/src/js/layer-manager.js
+++ b/src/js/layer-manager.js
@@ -84,6 +84,9 @@ class LayerManager {
this.layerSwitcher.event.addEventListener("removelayer", (e) => {
var element = document.getElementById(e.detail.id);
element.classList.remove('selectedLayer');
+ if (e.detail.error) {
+ return;
+ }
this.#updateLayersCounter(e.type);
});
}
diff --git a/src/js/layer-switcher.js b/src/js/layer-switcher.js
index 6c95a827..4efa0921 100644
--- a/src/js/layer-switcher.js
+++ b/src/js/layer-switcher.js
@@ -69,7 +69,8 @@ class LayerSwitcher {
* index : 0,
* position : 0,
* type: "vector",
- * style: "http://.../style.json" ou []
+ * style: "http://.../style.json" ou [],
+ * error : false
* }
* }
*/
@@ -513,6 +514,7 @@ class LayerSwitcher {
style = this.layers[id].style; // url !
} else {
// ex. geojson
+ this.layers[id].error = true;
throw new Error(`Type not yet implemented or unknown : ${type}`);
}
// HACK
@@ -554,7 +556,10 @@ class LayerSwitcher {
// les sprites et les glyphs sont uniques sinon exceptions !
// mais, normalement, on ajoute que des couches IGN, on mutualise sur ces informations.
// FIXME comment gerer les exceptions ?
- this.map.setSprite(data.sprites);
+ if (!data.sprite.startsWith("http")) {
+ data.sprite = document.URL + data.sprite;
+ }
+ this.map.setSprite(data.sprite);
this.map.setGlyphs(data.glyphs);
return data;
})
@@ -563,6 +568,7 @@ class LayerSwitcher {
this.layers[id].style = data.layers; // sauvegarde !
})
.catch((e) => {
+ this.layers[id].error = true;
throw new Error(e);
});
}
@@ -596,7 +602,8 @@ class LayerSwitcher {
gray : false,
visibility : true,
index : this.index,
- position : this.index // cf. #updatePosition()
+ position : this.index, // cf. #updatePosition()
+ error : false
};
this.#addLayerContainer(id);
this.#addLayerMap(id)
@@ -622,6 +629,7 @@ class LayerSwitcher {
);
})
.catch((e) => {
+ this.layers[id].error = true;
throw e;
});
@@ -634,6 +642,8 @@ class LayerSwitcher {
* @public
*/
removeLayer(id) {
+ var berror = this.layers[id].error;
+
this.#removeLayerMap(id);
this.#removeLayerContainer(id);
delete this.layers[id];
@@ -649,7 +659,8 @@ class LayerSwitcher {
new CustomEvent("removelayer", {
bubbles: true,
detail: {
- id : id
+ id : id,
+ error : berror
}
})
);
diff --git a/src/js/map-buttons-listeners.js b/src/js/map-buttons-listeners.js
index 24e4e446..03b3c7df 100644
--- a/src/js/map-buttons-listeners.js
+++ b/src/js/map-buttons-listeners.js
@@ -47,6 +47,9 @@ const addListeners = () => {
// Bouton du gestionnaire de couches
DOM.$layerManagerBtn.addEventListener("click", () => { Globals.menu.open("layerManager"); });
+ // Bouton des filtres POI
+ DOM.$filterPoiBtn.addEventListener("click", () => { Globals.menu.open("poi"); });
+
// Bouton Retour
DOM.$backTopLeftBtn.addEventListener("click", () => { State.onBackKeyDown(); });
}
diff --git a/src/js/nav.js b/src/js/nav.js
index 1b8901b4..f68cb919 100644
--- a/src/js/nav.js
+++ b/src/js/nav.js
@@ -107,6 +107,12 @@ class MenuNavigation {
var isSpecific = false;
var isSpecificSize = false;
switch (id) {
+ case "poi":
+ DOM.$search.style.display = "none";
+ DOM.$backTopLeftBtn.classList.remove('d-none');
+ DOM.$filterPoiBtn.classList.add('d-none');
+ Globals.currentScrollIndex = 1;
+ break;
case "myaccount":
DOM.$search.style.display = "none";
DOM.$backTopLeftBtn.classList.remove('d-none');
@@ -141,6 +147,7 @@ class MenuNavigation {
DOM.$sideBySideBtn.classList.add('d-none');
DOM.$layerManagerBtn.classList.add('d-none');
DOM.$geolocateBtn.classList.add('d-none');
+ DOM.$filterPoiBtn.classList.add('d-none');
DOM.$whiteScreen.classList.remove('d-none');
DOM.$search.style.display = "none";
DOM.$backTopLeftBtn.classList.remove('d-none');
@@ -173,6 +180,7 @@ class MenuNavigation {
DOM.$sideBySideBtn.classList.add('d-none');
DOM.$layerManagerBtn.classList.add('d-none');
DOM.$geolocateBtn.classList.add('d-none');
+ DOM.$filterPoiBtn.classList.add('d-none');
DOM.$whiteScreen.classList.remove('d-none');
DOM.$backTopLeftBtn.classList.remove('d-none');
DOM.$backTopLeftBtn.style.boxShadow = "unset";
@@ -234,6 +242,11 @@ class MenuNavigation {
var isSpecific = false;
var isFinished = false; // hack pour search !
switch (id) {
+ case "poi":
+ DOM.$search.style.display = "flex";
+ DOM.$backTopLeftBtn.classList.add('d-none');
+ DOM.$filterPoiBtn.classList.remove('d-none');
+ break;
case "myaccount":
DOM.$search.style.display = "flex";
DOM.$backTopLeftBtn.classList.add('d-none');
@@ -267,6 +280,7 @@ class MenuNavigation {
document.body.style.overflowY = "auto";
DOM.$sideBySideBtn.classList.remove('d-none');
DOM.$layerManagerBtn.classList.remove('d-none');
+ DOM.$filterPoiBtn.classList.add('d-none');
DOM.$geolocateBtn.classList.remove('d-none');
DOM.$whiteScreen.classList.add('d-none');
DOM.$backTopLeftBtn.classList.add('d-none');
@@ -319,6 +333,7 @@ class MenuNavigation {
document.body.style.overflowY = "auto";
DOM.$sideBySideBtn.classList.remove('d-none');
DOM.$layerManagerBtn.classList.remove('d-none');
+ DOM.$filterPoiBtn.classList.add('d-none');
DOM.$geolocateBtn.classList.remove('d-none');
DOM.$whiteScreen.classList.add('d-none');
DOM.$search.style.display = "flex";
@@ -383,6 +398,7 @@ class MenuNavigation {
DOM.$searchresultsWindow.classList.add('d-none');
DOM.$sideBySideBtn.classList.remove('d-none');
DOM.$layerManagerBtn.classList.remove('d-none');
+ DOM.$filterPoiBtn.classList.remove('d-none');
DOM.$geolocateBtn.classList.remove('d-none');
switch (id) {
case "informations":
diff --git a/src/js/poi.js b/src/js/poi.js
new file mode 100644
index 00000000..c1b0aef5
--- /dev/null
+++ b/src/js/poi.js
@@ -0,0 +1,293 @@
+import maplibregl from "maplibre-gl";
+
+import LayersConfig from './layer-config';
+import LayersGroup from './layer-group';
+
+import PoiConfig from './data-layer/poi-osm-layer-config.json';
+
+/**
+ * Contrôle sur le filtrage attributaire des POI osm
+ * @description
+ * La couche est active par defaut, les filtres de selections sont ajoutés et la visibilité est
+ * désactivée par defaut.
+ * @todo les POI "remonter le temps"
+ * @todo interactions avec les autres composants (ex. isochrone)
+ * @todo classe utilitaire pour le vectorTile !
+ */
+class POI {
+ /**
+ * constructeur
+ * @param {*} map
+ * @param {*} options
+ * @returns
+ */
+ constructor(map, options) {
+ this.options = options || {
+ target: document.getElementById("poiWindow"),
+ id: "OSM.POI$GEOPORTAIL:GPP:TMS"
+ };
+
+ this.opened = false;
+
+ /**
+ * Couche POI active
+ */
+ this.actived = true;
+
+ this.map = map;
+
+ this.target = this.options.target || document.getElementById("poiWindow");
+ this.id = this.options.id || "OSM.POI$GEOPORTAIL:GPP:TMS";
+
+ this.#render();
+ this.#listeners();
+
+ return this;
+ }
+
+ /**
+ * chargement de la couche
+ * @public
+ */
+ async load() {
+ var props = LayersConfig.getLayerProps(this.id);
+ var style = props.style; // url !
+
+ return fetch(style)
+ .then((response) => {
+ return response.json();
+ })
+ .then((data) => {
+ // INFO
+ // on ajoute les sources !
+ // les sources des couches tuiles vectorielles ne sont pas pré chargées
+ // car on les connait que maintenant en lisant le fichier de style.
+ // l'id des source est different du nom de la couche pour le vecteur !
+ for (const key in data.sources) {
+ if (Object.hasOwnProperty.call(data.sources, key)) {
+ const source = data.sources[key];
+ // on ne peut pas ajouter la même source !
+ if (! this.map.getStyle().sources[key]) {
+ this.map.addSource(key, source);
+ }
+ }
+ }
+ return data;
+ })
+ .then((data) => {
+ // les sprites et les glyphs sont uniques sinon exceptions !
+ // mais, normalement, on ajoute que des couches IGN, on mutualise sur ces informations.
+ if (!data.sprite.startsWith("http")) {
+ data.sprite = document.URL + data.sprite;
+ }
+ this.map.setSprite(data.sprite);
+ this.map.setGlyphs(data.glyphs);
+ return data;
+ })
+ .then((data) => {
+ var layers = this.#createFilters(data.layers);
+ LayersGroup.addGroup(this.id, layers);
+ })
+ .catch((e) => {
+ throw new Error(e);
+ });
+ }
+
+ /**
+ * creation des filtres de sélections dans les styles
+ * @param {*} layers
+ * @returns
+ */
+ #createFilters(layers) {
+ var layersDisplay = layers;
+ var layersSelection = [];
+ for (let i = 0; i < layersDisplay.length; i++) {
+ const l = layersDisplay[i];
+ for (let j = 0; j < PoiConfig.length; j++) {
+ const poi = PoiConfig[j];
+ var layer = Object.assign({}, l); // clone
+ layer.id = poi.id + " - " + layer.id;
+ layer.filter = [
+ "in",
+ poi.filters[0].field,
+ poi.filters[0].attributs
+ ].flat();
+ layer.layout.visibility = (poi.visible) ? "visible" : "none";
+ layer.metadata = {
+ thematic: poi.id
+ };
+ layersSelection.push(layer);
+ }
+ }
+ return layersSelection;
+ }
+
+ /**
+ * creation de l'interface
+ */
+ #render() {
+ if (! this.target) {
+ console.warn();
+ return;
+ }
+
+ // on évite les ID sur le DOM afin de pouvoir multiplier ce code dans d'autres composants
+ const tplPOIThematics = (values) => {
+ var checked = null;
+ if (values.visible) {
+ checked = "checked";
+ }
+ return `
+
+ `;
+ };
+
+ var strPOIThematics = "";
+ for(let i = 0; i < PoiConfig.length; i++) {
+ var item = PoiConfig[i];
+ strPOIThematics += tplPOIThematics({
+ id : item.id,
+ name : item.name,
+ visible : item.visible // TODO
+ });
+ }
+
+ var tpltContainer = `
+
+
Point d'interêt
+
+ Afficher les POI
+
+
+
+
+ ${strPOIThematics}
+
+
+
+ POI remonter le temps
+
+
+
+ `;
+
+ const stringToHTML = (str) => {
+
+ var support = function () {
+ if (!window.DOMParser) return false;
+ var parser = new DOMParser();
+ try {
+ parser.parseFromString('x', 'text/html');
+ } catch (err) {
+ return false;
+ }
+ return true;
+ };
+
+ // If DOMParser is supported, use it
+ if (support()) {
+ var parser = new DOMParser();
+ var doc = parser.parseFromString(str, 'text/html');
+ return doc.body.firstChild;
+ }
+
+ // Otherwise, fallback to old-school method
+ var dom = document.createElement('div');
+ dom.innerHTML = str;
+ return dom;
+
+ };
+
+ // transformation du container : String -> DOM
+ var container = stringToHTML(tpltContainer.trim());
+
+ if (! container) {
+ console.warn();
+ return;
+ }
+
+ // ajout du shadow DOM
+ const shadowContainer = container.attachShadow({ mode: "open" });
+ shadowContainer.innerHTML = tpltContainer.trim();
+
+ if (! shadowContainer) {
+ console.warn();
+ return;
+ }
+
+ // ajout du container shadow
+ this.target.appendChild(shadowContainer);
+ }
+
+ /**
+ * ajout d'ecouteurs
+ */
+ #listeners() {
+ // rendre la couche POI active en affichant ou non tous les filtres sélectionnés
+ document.getElementById("displayPOI").addEventListener("change", (e) => {
+ this.actived = e.target.checked;
+ document.querySelectorAll(".inputPOIFilterItem").forEach((el) => {
+ if (el.checked) {
+ var layers = LayersGroup.getGroupLayers(this.id).filter((layer) => { return layer.metadata.thematic === el.name });
+ for (let i = 0; i < layers.length; i++) {
+ const element = layers[i];
+ LayersGroup.addVisibilityByID(this.id, element.id, this.actived);
+ }
+ }
+ });
+ });
+ // TODO rendre visible ou non tous les filtres
+ document.getElementById("displayPOIGoBackTime").addEventListener("change", (e) => {
+ console.debug(e);
+ });
+ // rendre visible ou non le filtre si la couche POI est active sinon rien à faire
+ document.querySelectorAll(".inputPOIFilterItem").forEach((el) => {
+ el.addEventListener("change", (e) => {
+ if (!this.actived) {
+ return;
+ }
+ var layers = LayersGroup.getGroupLayers(this.id).filter((layer) => { return layer.metadata.thematic === e.target.name });
+ for (let i = 0; i < layers.length; i++) {
+ const element = layers[i];
+ LayersGroup.addVisibilityByID(this.id, element.id, e.target.checked);
+ }
+ });
+ });
+ }
+
+ /**
+ * ouvre l'interface
+ * @public
+ */
+ show() {
+ this.opened = true;
+ console.debug("show")
+ }
+
+ /**
+ * ferme l'interface
+ * @public
+ */
+ hide() {
+ this.opened = false;
+ console.debug("hide");
+ }
+}
+
+export default POI;
\ No newline at end of file
diff --git a/src/js/state.js b/src/js/state.js
index bbe33e78..e7a6c4ce 100644
--- a/src/js/state.js
+++ b/src/js/state.js
@@ -59,6 +59,9 @@ const onBackKeyDown = () => {
if (Globals.backButtonState === 'myposition') {
Globals.menu.close('myposition');
}
+ if (Globals.backButtonState === 'poi') {
+ Globals.menu.close('poi');
+ }
}
export default {
diff --git a/webpack.dev.js b/webpack.dev.js
index 9b66607f..4cf9ae11 100644
--- a/webpack.dev.js
+++ b/webpack.dev.js
@@ -13,7 +13,7 @@ module.exports = {
},
devServer: {
static: {
- directory: path.resolve(__dirname, './data'),
+ directory: path.resolve(__dirname, './www/data'),
publicPath: '/data'
}
},
diff --git a/data/plan-ign-interactif-style.json b/www/data/plan-ign-interactif-style.json
similarity index 100%
rename from data/plan-ign-interactif-style.json
rename to www/data/plan-ign-interactif-style.json
diff --git a/www/data/poi-osm-sprite.json b/www/data/poi-osm-sprite.json
new file mode 100644
index 00000000..857e8923
--- /dev/null
+++ b/www/data/poi-osm-sprite.json
@@ -0,0 +1,120 @@
+{
+"atm_17" :{"x":18,"y":182,"width":17,"height":17,"pixelRatio":1},
+"atm_21" :{"x":128,"y":44,"width":21,"height":21,"pixelRatio":1},
+"autrereligion_17" :{"x":106,"y":44,"width":17,"height":17,"pixelRatio":1},
+"autrereligion_21" :{"x":194,"y":132,"width":21,"height":21,"pixelRatio":1},
+"bakery_17" :{"x":36,"y":200,"width":17,"height":17,"pixelRatio":1},
+"bakery_21" :{"x":194,"y":176,"width":21,"height":21,"pixelRatio":1},
+"bar_17" :{"x":120,"y":142,"width":17,"height":17,"pixelRatio":1},
+"bar_21" :{"x":22,"y":142,"width":21,"height":21,"pixelRatio":1},
+"bicycle_parking_17" :{"x":18,"y":164,"width":17,"height":17,"pixelRatio":1},
+"bicycle_parking_21" :{"x":62,"y":0,"width":21,"height":21,"pixelRatio":1},
+"bicycle_rental_17" :{"x":102,"y":142,"width":17,"height":17,"pixelRatio":1},
+"bicycle_rental_21" :{"x":194,"y":22,"width":21,"height":21,"pixelRatio":1},
+"bus_stop_17" :{"x":0,"y":80,"width":17,"height":17,"pixelRatio":1},
+"bus_stop_21" :{"x":194,"y":44,"width":21,"height":21,"pixelRatio":1},
+"camp_site_17" :{"x":150,"y":142,"width":17,"height":17,"pixelRatio":1},
+"camp_site_21" :{"x":128,"y":22,"width":21,"height":21,"pixelRatio":1},
+"casino_17" :{"x":198,"y":200,"width":17,"height":17,"pixelRatio":1},
+"casino_21" :{"x":106,"y":84,"width":21,"height":21,"pixelRatio":1},
+"castle_17" :{"x":44,"y":58,"width":17,"height":17,"pixelRatio":1},
+"castle_21" :{"x":172,"y":132,"width":21,"height":21,"pixelRatio":1},
+"charging_station_17" :{"x":76,"y":120,"width":17,"height":17,"pixelRatio":1},
+"charging_station_21" :{"x":216,"y":154,"width":21,"height":21,"pixelRatio":1},
+"christian_17" :{"x":22,"y":18,"width":17,"height":17,"pixelRatio":1},
+"christian_21" :{"x":194,"y":110,"width":21,"height":21,"pixelRatio":1},
+"church_histo_17" :{"x":108,"y":164,"width":17,"height":17,"pixelRatio":1},
+"church_histo_21" :{"x":0,"y":98,"width":21,"height":21,"pixelRatio":1},
+"cinema_17" :{"x":150,"y":124,"width":17,"height":17,"pixelRatio":1},
+"cinema_21" :{"x":66,"y":98,"width":21,"height":21,"pixelRatio":1},
+"college_17" :{"x":40,"y":120,"width":17,"height":17,"pixelRatio":1},
+"college_21" :{"x":216,"y":88,"width":21,"height":21,"pixelRatio":1},
+"conference_centre_17" :{"x":22,"y":120,"width":17,"height":17,"pixelRatio":1},
+"conference_centre_21" :{"x":106,"y":22,"width":21,"height":21,"pixelRatio":1},
+"courthouse_17" :{"x":36,"y":80,"width":17,"height":17,"pixelRatio":1},
+"courthouse_21" :{"x":172,"y":66,"width":21,"height":21,"pixelRatio":1},
+"divers_17" :{"x":94,"y":120,"width":17,"height":17,"pixelRatio":1},
+"divers_21" :{"x":106,"y":62,"width":21,"height":21,"pixelRatio":1},
+"ferry_terminal_17" :{"x":90,"y":200,"width":17,"height":17,"pixelRatio":1},
+"ferry_terminal_21" :{"x":128,"y":66,"width":21,"height":21,"pixelRatio":1},
+"fire_station_17" :{"x":126,"y":164,"width":17,"height":17,"pixelRatio":1},
+"fire_station_21" :{"x":150,"y":80,"width":21,"height":21,"pixelRatio":1},
+"fuel_17" :{"x":66,"y":142,"width":17,"height":17,"pixelRatio":1},
+"fuel_21" :{"x":128,"y":110,"width":21,"height":21,"pixelRatio":1},
+"grave_yard_17" :{"x":0,"y":200,"width":17,"height":17,"pixelRatio":1},
+"grave_yard_21" :{"x":216,"y":176,"width":21,"height":21,"pixelRatio":1},
+"greengrocer_17" :{"x":162,"y":200,"width":17,"height":17,"pixelRatio":1},
+"greengrocer_21" :{"x":216,"y":44,"width":21,"height":21,"pixelRatio":1},
+"hospital_17" :{"x":72,"y":200,"width":17,"height":17,"pixelRatio":1},
+"hospital_21" :{"x":106,"y":0,"width":21,"height":21,"pixelRatio":1},
+"hotel_17" :{"x":150,"y":44,"width":17,"height":17,"pixelRatio":1},
+"hotel_21" :{"x":216,"y":110,"width":21,"height":21,"pixelRatio":1},
+"hut_17" :{"x":0,"y":40,"width":17,"height":17,"pixelRatio":1},
+"hut_21" :{"x":216,"y":132,"width":21,"height":21,"pixelRatio":1},
+"information_17" :{"x":216,"y":198,"width":17,"height":17,"pixelRatio":1},
+"information_21" :{"x":216,"y":66,"width":21,"height":21,"pixelRatio":1},
+"jardin_17" :{"x":108,"y":200,"width":17,"height":17,"pixelRatio":1},
+"jardin_21" :{"x":172,"y":22,"width":21,"height":21,"pixelRatio":1},
+"jewish_17" :{"x":22,"y":0,"width":17,"height":17,"pixelRatio":1},
+"jewish_21" :{"x":128,"y":0,"width":21,"height":21,"pixelRatio":1},
+"library_17" :{"x":54,"y":182,"width":17,"height":17,"pixelRatio":1},
+"library_21" :{"x":128,"y":88,"width":21,"height":21,"pixelRatio":1},
+"lighthouse_17" :{"x":54,"y":200,"width":17,"height":17,"pixelRatio":1},
+"lighthouse_21" :{"x":194,"y":66,"width":21,"height":21,"pixelRatio":1},
+"mall_17" :{"x":126,"y":200,"width":17,"height":17,"pixelRatio":1},
+"mall_21" :{"x":84,"y":66,"width":21,"height":21,"pixelRatio":1},
+"marina_17" :{"x":84,"y":142,"width":17,"height":17,"pixelRatio":1},
+"marina_21" :{"x":44,"y":142,"width":21,"height":21,"pixelRatio":1},
+"marketplace_17" :{"x":36,"y":164,"width":17,"height":17,"pixelRatio":1},
+"marketplace_21" :{"x":40,"y":0,"width":21,"height":21,"pixelRatio":1},
+"museum_17" :{"x":72,"y":182,"width":17,"height":17,"pixelRatio":1},
+"museum_21" :{"x":0,"y":120,"width":21,"height":21,"pixelRatio":1},
+"muslim_17" :{"x":180,"y":200,"width":17,"height":17,"pixelRatio":1},
+"muslim_21" :{"x":62,"y":58,"width":21,"height":21,"pixelRatio":1},
+"parking_17" :{"x":108,"y":182,"width":17,"height":17,"pixelRatio":1},
+"parking_21" :{"x":150,"y":102,"width":21,"height":21,"pixelRatio":1},
+"peak_17" :{"x":18,"y":200,"width":17,"height":17,"pixelRatio":1},
+"peak_21" :{"x":0,"y":142,"width":21,"height":21,"pixelRatio":1},
+"pharmacy_17" :{"x":18,"y":40,"width":17,"height":17,"pixelRatio":1},
+"pharmacy_21" :{"x":84,"y":0,"width":21,"height":21,"pixelRatio":1},
+"picnic_site_17" :{"x":144,"y":200,"width":17,"height":17,"pixelRatio":1},
+"picnic_site_21" :{"x":172,"y":44,"width":21,"height":21,"pixelRatio":1},
+"police_17" :{"x":144,"y":182,"width":17,"height":17,"pixelRatio":1},
+"police_21" :{"x":0,"y":58,"width":21,"height":21,"pixelRatio":1},
+"post_office_17" :{"x":90,"y":164,"width":17,"height":17,"pixelRatio":1},
+"post_office_21" :{"x":84,"y":22,"width":21,"height":21,"pixelRatio":1},
+"prison_17" :{"x":54,"y":164,"width":17,"height":17,"pixelRatio":1},
+"prison_21" :{"x":40,"y":22,"width":21,"height":21,"pixelRatio":1},
+"restaurant_17" :{"x":72,"y":164,"width":17,"height":17,"pixelRatio":1},
+"restaurant_21" :{"x":44,"y":98,"width":21,"height":21,"pixelRatio":1},
+"saddle_17" :{"x":0,"y":182,"width":17,"height":17,"pixelRatio":1},
+"saddle_21" :{"x":216,"y":22,"width":21,"height":21,"pixelRatio":1},
+"school_17" :{"x":36,"y":182,"width":17,"height":17,"pixelRatio":1},
+"school_21" :{"x":194,"y":88,"width":21,"height":21,"pixelRatio":1},
+"sports_centre_17" :{"x":58,"y":120,"width":17,"height":17,"pixelRatio":1},
+"sports_centre_21" :{"x":172,"y":0,"width":21,"height":21,"pixelRatio":1},
+"station_17" :{"x":126,"y":182,"width":17,"height":17,"pixelRatio":1},
+"station_21" :{"x":194,"y":154,"width":21,"height":21,"pixelRatio":1},
+"supermarket_17" :{"x":88,"y":98,"width":17,"height":17,"pixelRatio":1},
+"supermarket_21" :{"x":22,"y":98,"width":21,"height":21,"pixelRatio":1},
+"swimming_pool_17" :{"x":62,"y":22,"width":17,"height":17,"pixelRatio":1},
+"swimming_pool_21" :{"x":22,"y":58,"width":21,"height":21,"pixelRatio":1},
+"theatre_17" :{"x":62,"y":40,"width":17,"height":17,"pixelRatio":1},
+"theatre_21" :{"x":84,"y":44,"width":21,"height":21,"pixelRatio":1},
+"theme_park_17" :{"x":18,"y":80,"width":17,"height":17,"pixelRatio":1},
+"theme_park_21" :{"x":150,"y":0,"width":21,"height":21,"pixelRatio":1},
+"toilets_17" :{"x":144,"y":164,"width":17,"height":17,"pixelRatio":1},
+"toilets_21" :{"x":172,"y":154,"width":21,"height":21,"pixelRatio":1},
+"townhall_17" :{"x":54,"y":80,"width":17,"height":17,"pixelRatio":1},
+"townhall_21" :{"x":194,"y":0,"width":21,"height":21,"pixelRatio":1},
+"university_17" :{"x":162,"y":182,"width":17,"height":17,"pixelRatio":1},
+"university_21" :{"x":150,"y":22,"width":21,"height":21,"pixelRatio":1},
+"viewpoint_17" :{"x":150,"y":62,"width":17,"height":17,"pixelRatio":1},
+"viewpoint_21" :{"x":0,"y":0,"width":21,"height":21,"pixelRatio":1},
+"waterway_17" :{"x":0,"y":164,"width":17,"height":17,"pixelRatio":1},
+"waterway_21" :{"x":172,"y":110,"width":21,"height":21,"pixelRatio":1},
+"zoo_17" :{"x":0,"y":22,"width":17,"height":17,"pixelRatio":1},
+"zoo_21" :{"x":216,"y":0,"width":21,"height":21,"pixelRatio":1},
+"aerodrome_17" :{"x":90,"y":182,"width":17,"height":17,"pixelRatio":1},
+"aerodrome_21" :{"x":172,"y":88,"width":21,"height":21,"pixelRatio":1}
+}
\ No newline at end of file
diff --git a/www/data/poi-osm-sprite.png b/www/data/poi-osm-sprite.png
new file mode 100644
index 00000000..dd6254ef
Binary files /dev/null and b/www/data/poi-osm-sprite.png differ
diff --git a/www/data/poi-osm-sprite@2x.json b/www/data/poi-osm-sprite@2x.json
new file mode 100644
index 00000000..857e8923
--- /dev/null
+++ b/www/data/poi-osm-sprite@2x.json
@@ -0,0 +1,120 @@
+{
+"atm_17" :{"x":18,"y":182,"width":17,"height":17,"pixelRatio":1},
+"atm_21" :{"x":128,"y":44,"width":21,"height":21,"pixelRatio":1},
+"autrereligion_17" :{"x":106,"y":44,"width":17,"height":17,"pixelRatio":1},
+"autrereligion_21" :{"x":194,"y":132,"width":21,"height":21,"pixelRatio":1},
+"bakery_17" :{"x":36,"y":200,"width":17,"height":17,"pixelRatio":1},
+"bakery_21" :{"x":194,"y":176,"width":21,"height":21,"pixelRatio":1},
+"bar_17" :{"x":120,"y":142,"width":17,"height":17,"pixelRatio":1},
+"bar_21" :{"x":22,"y":142,"width":21,"height":21,"pixelRatio":1},
+"bicycle_parking_17" :{"x":18,"y":164,"width":17,"height":17,"pixelRatio":1},
+"bicycle_parking_21" :{"x":62,"y":0,"width":21,"height":21,"pixelRatio":1},
+"bicycle_rental_17" :{"x":102,"y":142,"width":17,"height":17,"pixelRatio":1},
+"bicycle_rental_21" :{"x":194,"y":22,"width":21,"height":21,"pixelRatio":1},
+"bus_stop_17" :{"x":0,"y":80,"width":17,"height":17,"pixelRatio":1},
+"bus_stop_21" :{"x":194,"y":44,"width":21,"height":21,"pixelRatio":1},
+"camp_site_17" :{"x":150,"y":142,"width":17,"height":17,"pixelRatio":1},
+"camp_site_21" :{"x":128,"y":22,"width":21,"height":21,"pixelRatio":1},
+"casino_17" :{"x":198,"y":200,"width":17,"height":17,"pixelRatio":1},
+"casino_21" :{"x":106,"y":84,"width":21,"height":21,"pixelRatio":1},
+"castle_17" :{"x":44,"y":58,"width":17,"height":17,"pixelRatio":1},
+"castle_21" :{"x":172,"y":132,"width":21,"height":21,"pixelRatio":1},
+"charging_station_17" :{"x":76,"y":120,"width":17,"height":17,"pixelRatio":1},
+"charging_station_21" :{"x":216,"y":154,"width":21,"height":21,"pixelRatio":1},
+"christian_17" :{"x":22,"y":18,"width":17,"height":17,"pixelRatio":1},
+"christian_21" :{"x":194,"y":110,"width":21,"height":21,"pixelRatio":1},
+"church_histo_17" :{"x":108,"y":164,"width":17,"height":17,"pixelRatio":1},
+"church_histo_21" :{"x":0,"y":98,"width":21,"height":21,"pixelRatio":1},
+"cinema_17" :{"x":150,"y":124,"width":17,"height":17,"pixelRatio":1},
+"cinema_21" :{"x":66,"y":98,"width":21,"height":21,"pixelRatio":1},
+"college_17" :{"x":40,"y":120,"width":17,"height":17,"pixelRatio":1},
+"college_21" :{"x":216,"y":88,"width":21,"height":21,"pixelRatio":1},
+"conference_centre_17" :{"x":22,"y":120,"width":17,"height":17,"pixelRatio":1},
+"conference_centre_21" :{"x":106,"y":22,"width":21,"height":21,"pixelRatio":1},
+"courthouse_17" :{"x":36,"y":80,"width":17,"height":17,"pixelRatio":1},
+"courthouse_21" :{"x":172,"y":66,"width":21,"height":21,"pixelRatio":1},
+"divers_17" :{"x":94,"y":120,"width":17,"height":17,"pixelRatio":1},
+"divers_21" :{"x":106,"y":62,"width":21,"height":21,"pixelRatio":1},
+"ferry_terminal_17" :{"x":90,"y":200,"width":17,"height":17,"pixelRatio":1},
+"ferry_terminal_21" :{"x":128,"y":66,"width":21,"height":21,"pixelRatio":1},
+"fire_station_17" :{"x":126,"y":164,"width":17,"height":17,"pixelRatio":1},
+"fire_station_21" :{"x":150,"y":80,"width":21,"height":21,"pixelRatio":1},
+"fuel_17" :{"x":66,"y":142,"width":17,"height":17,"pixelRatio":1},
+"fuel_21" :{"x":128,"y":110,"width":21,"height":21,"pixelRatio":1},
+"grave_yard_17" :{"x":0,"y":200,"width":17,"height":17,"pixelRatio":1},
+"grave_yard_21" :{"x":216,"y":176,"width":21,"height":21,"pixelRatio":1},
+"greengrocer_17" :{"x":162,"y":200,"width":17,"height":17,"pixelRatio":1},
+"greengrocer_21" :{"x":216,"y":44,"width":21,"height":21,"pixelRatio":1},
+"hospital_17" :{"x":72,"y":200,"width":17,"height":17,"pixelRatio":1},
+"hospital_21" :{"x":106,"y":0,"width":21,"height":21,"pixelRatio":1},
+"hotel_17" :{"x":150,"y":44,"width":17,"height":17,"pixelRatio":1},
+"hotel_21" :{"x":216,"y":110,"width":21,"height":21,"pixelRatio":1},
+"hut_17" :{"x":0,"y":40,"width":17,"height":17,"pixelRatio":1},
+"hut_21" :{"x":216,"y":132,"width":21,"height":21,"pixelRatio":1},
+"information_17" :{"x":216,"y":198,"width":17,"height":17,"pixelRatio":1},
+"information_21" :{"x":216,"y":66,"width":21,"height":21,"pixelRatio":1},
+"jardin_17" :{"x":108,"y":200,"width":17,"height":17,"pixelRatio":1},
+"jardin_21" :{"x":172,"y":22,"width":21,"height":21,"pixelRatio":1},
+"jewish_17" :{"x":22,"y":0,"width":17,"height":17,"pixelRatio":1},
+"jewish_21" :{"x":128,"y":0,"width":21,"height":21,"pixelRatio":1},
+"library_17" :{"x":54,"y":182,"width":17,"height":17,"pixelRatio":1},
+"library_21" :{"x":128,"y":88,"width":21,"height":21,"pixelRatio":1},
+"lighthouse_17" :{"x":54,"y":200,"width":17,"height":17,"pixelRatio":1},
+"lighthouse_21" :{"x":194,"y":66,"width":21,"height":21,"pixelRatio":1},
+"mall_17" :{"x":126,"y":200,"width":17,"height":17,"pixelRatio":1},
+"mall_21" :{"x":84,"y":66,"width":21,"height":21,"pixelRatio":1},
+"marina_17" :{"x":84,"y":142,"width":17,"height":17,"pixelRatio":1},
+"marina_21" :{"x":44,"y":142,"width":21,"height":21,"pixelRatio":1},
+"marketplace_17" :{"x":36,"y":164,"width":17,"height":17,"pixelRatio":1},
+"marketplace_21" :{"x":40,"y":0,"width":21,"height":21,"pixelRatio":1},
+"museum_17" :{"x":72,"y":182,"width":17,"height":17,"pixelRatio":1},
+"museum_21" :{"x":0,"y":120,"width":21,"height":21,"pixelRatio":1},
+"muslim_17" :{"x":180,"y":200,"width":17,"height":17,"pixelRatio":1},
+"muslim_21" :{"x":62,"y":58,"width":21,"height":21,"pixelRatio":1},
+"parking_17" :{"x":108,"y":182,"width":17,"height":17,"pixelRatio":1},
+"parking_21" :{"x":150,"y":102,"width":21,"height":21,"pixelRatio":1},
+"peak_17" :{"x":18,"y":200,"width":17,"height":17,"pixelRatio":1},
+"peak_21" :{"x":0,"y":142,"width":21,"height":21,"pixelRatio":1},
+"pharmacy_17" :{"x":18,"y":40,"width":17,"height":17,"pixelRatio":1},
+"pharmacy_21" :{"x":84,"y":0,"width":21,"height":21,"pixelRatio":1},
+"picnic_site_17" :{"x":144,"y":200,"width":17,"height":17,"pixelRatio":1},
+"picnic_site_21" :{"x":172,"y":44,"width":21,"height":21,"pixelRatio":1},
+"police_17" :{"x":144,"y":182,"width":17,"height":17,"pixelRatio":1},
+"police_21" :{"x":0,"y":58,"width":21,"height":21,"pixelRatio":1},
+"post_office_17" :{"x":90,"y":164,"width":17,"height":17,"pixelRatio":1},
+"post_office_21" :{"x":84,"y":22,"width":21,"height":21,"pixelRatio":1},
+"prison_17" :{"x":54,"y":164,"width":17,"height":17,"pixelRatio":1},
+"prison_21" :{"x":40,"y":22,"width":21,"height":21,"pixelRatio":1},
+"restaurant_17" :{"x":72,"y":164,"width":17,"height":17,"pixelRatio":1},
+"restaurant_21" :{"x":44,"y":98,"width":21,"height":21,"pixelRatio":1},
+"saddle_17" :{"x":0,"y":182,"width":17,"height":17,"pixelRatio":1},
+"saddle_21" :{"x":216,"y":22,"width":21,"height":21,"pixelRatio":1},
+"school_17" :{"x":36,"y":182,"width":17,"height":17,"pixelRatio":1},
+"school_21" :{"x":194,"y":88,"width":21,"height":21,"pixelRatio":1},
+"sports_centre_17" :{"x":58,"y":120,"width":17,"height":17,"pixelRatio":1},
+"sports_centre_21" :{"x":172,"y":0,"width":21,"height":21,"pixelRatio":1},
+"station_17" :{"x":126,"y":182,"width":17,"height":17,"pixelRatio":1},
+"station_21" :{"x":194,"y":154,"width":21,"height":21,"pixelRatio":1},
+"supermarket_17" :{"x":88,"y":98,"width":17,"height":17,"pixelRatio":1},
+"supermarket_21" :{"x":22,"y":98,"width":21,"height":21,"pixelRatio":1},
+"swimming_pool_17" :{"x":62,"y":22,"width":17,"height":17,"pixelRatio":1},
+"swimming_pool_21" :{"x":22,"y":58,"width":21,"height":21,"pixelRatio":1},
+"theatre_17" :{"x":62,"y":40,"width":17,"height":17,"pixelRatio":1},
+"theatre_21" :{"x":84,"y":44,"width":21,"height":21,"pixelRatio":1},
+"theme_park_17" :{"x":18,"y":80,"width":17,"height":17,"pixelRatio":1},
+"theme_park_21" :{"x":150,"y":0,"width":21,"height":21,"pixelRatio":1},
+"toilets_17" :{"x":144,"y":164,"width":17,"height":17,"pixelRatio":1},
+"toilets_21" :{"x":172,"y":154,"width":21,"height":21,"pixelRatio":1},
+"townhall_17" :{"x":54,"y":80,"width":17,"height":17,"pixelRatio":1},
+"townhall_21" :{"x":194,"y":0,"width":21,"height":21,"pixelRatio":1},
+"university_17" :{"x":162,"y":182,"width":17,"height":17,"pixelRatio":1},
+"university_21" :{"x":150,"y":22,"width":21,"height":21,"pixelRatio":1},
+"viewpoint_17" :{"x":150,"y":62,"width":17,"height":17,"pixelRatio":1},
+"viewpoint_21" :{"x":0,"y":0,"width":21,"height":21,"pixelRatio":1},
+"waterway_17" :{"x":0,"y":164,"width":17,"height":17,"pixelRatio":1},
+"waterway_21" :{"x":172,"y":110,"width":21,"height":21,"pixelRatio":1},
+"zoo_17" :{"x":0,"y":22,"width":17,"height":17,"pixelRatio":1},
+"zoo_21" :{"x":216,"y":0,"width":21,"height":21,"pixelRatio":1},
+"aerodrome_17" :{"x":90,"y":182,"width":17,"height":17,"pixelRatio":1},
+"aerodrome_21" :{"x":172,"y":88,"width":21,"height":21,"pixelRatio":1}
+}
\ No newline at end of file
diff --git a/www/data/poi-osm-sprite@2x.png b/www/data/poi-osm-sprite@2x.png
new file mode 100644
index 00000000..dd6254ef
Binary files /dev/null and b/www/data/poi-osm-sprite@2x.png differ
diff --git a/www/data/poi-osm-style.json b/www/data/poi-osm-style.json
new file mode 100644
index 00000000..89f1a7f1
--- /dev/null
+++ b/www/data/poi-osm-style.json
@@ -0,0 +1,55 @@
+{
+ "version": 8,
+ "name": "POI OSM",
+ "glyphs": "https://wxs.ign.fr/static/vectorTiles/fonts/{fontstack}/{range}.pbf",
+ "sprite": "data/poi-osm-sprite",
+ "sources": {
+ "poi_osm": {
+ "type": "vector",
+ "tiles": [
+ "https://data.geopf.fr/tms/1.0.0/OSM.POI/{z}/{x}/{y}.pbf"
+ ]
+ }
+ },
+ "transition": {
+ "duration": 300,
+ "delay": 0
+ },
+ "layers": [
+ {
+ "id": "POI OSM 16et17",
+ "type": "symbol",
+ "source": "poi_osm",
+ "source-layer": "point_interet",
+ "minzoom": 15,
+ "maxzoom": 17,
+ "layout": {
+ "visibility": "visible",
+ "icon-image": "{symbo}_17"
+ }
+ },
+ {
+ "id": "POI OSM 18et19",
+ "type": "symbol",
+ "source": "poi_osm",
+ "source-layer": "point_interet",
+ "minzoom": 17,
+ "layout": {
+ "visibility": "visible",
+ "symbol-placement": "point",
+ "text-field": "{texte}",
+ "text-size": 9,
+ "text-max-width": 9,
+ "text-allow-overlap": false,
+ "text-offset": [0, -0.9],
+ "text-padding": 3,
+ "text-anchor": "bottom",
+ "text-font": ["Source Sans Pro Bold Italic"],
+ "icon-image": "{symbo}_21"
+ },
+ "paint": {
+ "text-color": "#0000CC"
+ }
+ }
+ ]
+}