UNPKG

geopf-extensions-openlayers

Version:

French Geoportal Extensions for OpenLayers libraries

440 lines (396 loc) 14.3 kB
// import openlayers import VectorTileLayer from "ol/layer/VectorTile"; import VectorTileSource from "ol/source/VectorTile"; import TileJSONSource from "ol/source/TileJSON"; import MVT from "ol/format/MVT"; import { unByKey as observableUnByKey } from "ol/Observable"; // import olms : module ES6 import { applyStyle } from "ol-mapbox-style"; // import local import Utils from "../Utils/Helper"; import Config from "../Utils/Config"; /** * @classdesc * Geoportal Layer Mapbox creation * * @alias ol.layer.GeoportalMapBox * */ class LayerMapBox extends VectorTileLayer { /** * @module GeoportalMapBox * @constructor * @param {Object} options - options for function call. * @param {String} options.layer - Layer name (e.g. "PLAN.IGN") * @param {Object} [options.configuration] - configuration (cf. example) * @param {String} [options.style] - Style name (e.g. "classique") * @param {String} [options.source] - Source name (e.g. "plan_ign") * @param {Boolean} [options.ssl] - if set true, enforce protocol https (only for nodejs) * @param {Object} [settings] - other options for ol.layer.VectorTile function (see {@link https://openlayers.org/en/latest/apidoc/module-ol_layer_VectorTile-VectorTileLayer.html ol.layer.VectorTile}) * @fires mapbox:style:loaded * @example * var LayerMapBox = new ol.layer.GeoportalMapBox({ * layer : "PLAN.IGN", * [style : "classique",] * [source : "plan_ign",] * [ssl: true] * }, { * opacity * visible * extent * declutter * ... * }); * * // Ex. configuration object for TMS Layer * "PLAN.IGN$GEOPORTAIL:GPP:TMS": { * "hidden": true, * "queryable": false, * "serviceParams": { * "id": "GPP:TMS", * "version": "1.0.0", * "serverUrl": { * "cartes": "https://wxs.ign.fr/cartes/geoportail/tms/1.0.0/" * } * }, * "name": "PLAN.IGN", * "title": "Plan IGN", * "description": "BDUni tuilée", * "formats": [ * { * "current": true, * "name": "application/x-protobuf" * } * ], * "styles": [ * { * "name": "standard", * "title": "Style standard", * "current": true, * "url": "https://wxs.ign.fr/static/vectorTiles/styles/PLAN.IGN/essentiels/standard.json" * }, * { * "name": "classique", * "title": "Style classique", * "current": true, * "url": "https://wxs.ign.fr/static/vectorTiles/styles/PLAN.IGN/essentiels/classique.json" * }, * { * "name": "transparent", * "title": "Style transparent", * "current": true, * "url": "https://wxs.ign.fr/static/vectorTiles/styles/PLAN.IGN/essentiels/transparent.json" * }, * { * "name": "accentue", * "title": "Style accentue", * "current": true, * "url": "https://wxs.ign.fr/static/vectorTiles/styles/PLAN.IGN/essentiels/accentue.json" * }, * { * "name": "attenue", * "title": "Style attenue", * "current": true, * "url": "https://wxs.ign.fr/static/vectorTiles/styles/PLAN.IGN/essentiels/attenue.json" * }, * { * "name": "gris", * "title": "Style en noir et blanc", * "current": false, * "url": "https://wxs.ign.fr/static/vectorTiles/styles/PLAN.IGN/essentiels/gris.json" * }, * { * "name": "epure", * "title": "Style epure", * "current": true, * "url": "https://wxs.ign.fr/static/vectorTiles/styles/PLAN.IGN/essentiels/epure.json" * }, * { * "name": "sans_toponymes", * "title": "Style sans toponymes", * "current": false, * "url": "https://wxs.ign.fr/static/vectorTiles/styles/PLAN.IGN/essentiels/sans_toponymes.json" * } * ], * "globalConstraint": { * "crs": null, * "bbox": { * "left": -724011.531917197, * "right": 1095801.237496279, * "top": 6672646.821182753, * "bottom": 5009377.0856973175 * }, * "minScaleDenominator": null, * "maxScaleDenominator": null * }, * "quicklookUrl": "https://wxs.ign.fr/static/pictures/ign_carte2.jpg", * "layerId": "PLAN.IGN$GEOPORTAIL:GPP:TMS", * "defaultProjection": "EPSG:3857" * } */ constructor (options, settings) { // if (!(this instanceof LayerMapBox)) { // throw new TypeError("ERROR CLASS_CONSTRUCTOR"); // } if (!options.layer) { throw new Error("ERROR PARAM_MISSING : layer"); } if (typeof options.layer !== "string") { throw new Error("ERROR WRONG TYPE : layer"); } // par defaut if (typeof options.ssl === "undefined") { options.ssl = true; } // si ssl = false on fait du http // par défaut, ssl = true, on fait du https var protocol = options.ssl === false ? "http://" : "https://"; // WARNING : // on fait le choix de ne pas utiliser la clef apiKey pour checker // les droits sur la ressource // car le service n'est pas securisé... // configuration de la ressource var layerCfg = options.configuration; // 2 solutions pour la récupération des ressources utiles // * soit depuis la configuration en option // * soit via la variable globale Gp.Config chargée if (!layerCfg) { // Check if configuration is loaded if (!Config.isConfigLoaded()) { throw new Error("ERROR : contract key configuration has to be loaded to load Geoportal layers."); } // id de la ressource var layerId = options.layer + "$GEOPORTAIL:GPP:TMS"; // récupération des ressources utiles depuis la configuration layerCfg = Config.configuration.getLayerConf(layerId); if (!layerCfg) { throw new Error("ERROR : Layer ID not found into the catalogue !?"); } } var styleUrl = null; var styleTitle = ""; var styleName = options.style; for (var i = 0; i < layerCfg.styles.length; i++) { var style = layerCfg.styles[i]; // si le nom du style est en option, on le recherche... // sinon, on recherche le style par defaut ! if (styleName && style.name === styleName) { styleUrl = style.url; styleTitle = style.title; break; } else { if (!styleName && style.current) { styleName = style.name; styleUrl = style.url; styleTitle = style.title; break; } } } if (!styleUrl) { throw new Error("ERROR : Style URL not found !?"); } styleUrl.replace(/(http|https):\/\//, protocol); // création de la source var source = new VectorTileSource({ state : "loading", // statut format : new MVT() }); source._originators = layerCfg.originators; source._legends = layerCfg.legends; source._metadata = layerCfg.metadata; source._description = layerCfg.description; source._title = layerCfg.title + " (" + styleTitle + ")"; source._quicklookUrl = layerCfg.quicklookUrl; // options definies sur ol.layer.VectorTile var layerVectorTileOptions = { source : source }; // récupération des autres paramètres passés par l'utilisateur Utils.mergeParams(layerVectorTileOptions, settings); // on surcharge les originators (non récupérés depuis configuration de la couche) if (options.olParams && !layerCfg.originators) { source._originators = options.olParams.attributions; } // création d'une ol.layer.VectorTile avec les options récupérées ci-dessus. super(layerVectorTileOptions); this.name = options.layer; this.service = "TMS"; this.protocol = protocol; this.sourceId = options.source; this.styleUrl = styleUrl; this.styleName = styleName; this.config = layerCfg; // récuperation du style this.setStyleMapBox(); return this; } /** * Get Style MapBox * @private */ setStyleMapBox () { var self = this; fetch(this.styleUrl, { credentials : "same-origin" }).then(function (response) { if (response.ok) { response.json().then(function (style) { self.onStyleMapBoxLoad(style); }); } }).catch(function (e) { self.onStyleMapBoxError(e); }); }; /** * Add Style * @param {*} style - json style */ onStyleMapBoxLoad (style) { // si on a plusieurs sources, on ne peut en prendre qu'une seule... if (!this.sourceId) { this.sourceId = Object.keys(style.sources)[0]; } var styleSource = style.sources[this.sourceId]; if (!styleSource) { this.onStyleMapBoxError({ message : "ERROR : Source ID not found !? !" }); return; } if (styleSource.type !== "vector") { this.onStyleMapBoxError({ message : "ERROR : Source TYPE not permitted !" }); return; } var source = this.getSource(); // WARNING : // la clef renseignée dans les urls n'est pas forcement la bonne // car la substitution avec la clef utilisateur n'est pas faite par le service... if (styleSource.url) { // protocole : http ou https styleSource.url.replace(/(http|https):\/\//, this.protocol); var vectorTileJson = new TileJSONSource({ url : styleSource.url }); var self = this; var key = vectorTileJson.on("change", function () { if (vectorTileJson.getState() === "ready") { var doc = vectorTileJson.getTileJSON(); if (!doc) { return; } self.set("mapbox-extensions", doc); var tiles = Array.isArray(doc.tiles) ? doc.tiles : [doc.tiles]; // protocole : http ou https for (var i = 0; i < styleSource.tiles.length; i++) { tiles[i].replace(/(http|https):\/\//, this.protocol); } source.setUrls(tiles); observableUnByKey(key); } }); } if (styleSource.tiles) { // protocole : http ou https for (var j = 0; j < styleSource.tiles.length; j++) { styleSource.tiles[j].replace(/(http|https):\/\//, this.protocol); } source.setUrls(styleSource.tiles); } applyStyle(this, style, this.sourceId) .then(() => { source.setState("ready"); this.set("mapbox-styles", style); }) .then(() => { /** * event triggered when a style is apply * * @event mapbox:style:loaded * @property {Object} type - event * @property {String} style - style url * @property {String} name - style name * @property {Object} target - instance LayerMapBox * @example * LayerMapBox.on("mapbox:style:loaded", function (e) { * console.log(e.style); * }) */ this.dispatchEvent({ type : "mapbox:style:loaded", style : this.styleUrl, name : this.styleName }); }) .catch((error) => { this.onStyleMapBoxError(error); }); }; /** * Error * @param {*} error - message */ onStyleMapBoxError (error) { var source = this.getSource(); source.setState("error"); // eslint-disable-next-line no-console console.error(error.message); }; /** * Get configuration * @returns {Object} - configuration */ getConfiguration () { return this.config; } /** * Get legends * @returns {Array} - legends */ getLegends () { return this.getSource()._legends; } /** * Get metadata * @returns {Array} - metadata */ getMetadata () { return this.getSource()._metadata; } /** * Get description * @returns {String} - description */ getDescription () { return this.getSource()._description; } /** * Get title * @returns {String} - title */ getTitle () { return this.getSource()._title; } /** * Get quicklook url * @returns {String} - quicklook */ getQuicklookUrl () { return this.getSource()._quicklookUrl; } /** * Get originators * @returns {Array} - originators */ getOriginators () { return this.getSource()._originators; } }; export default LayerMapBox; // Expose LayerMapBox as ol.layer.GeoportalMapBox. (for a build bundle) if (window.ol && window.ol.layer) { window.ol.layer.GeoportalMapBox = LayerMapBox; }