UNPKG

test-github-actions-geoportal-sdk-3d

Version:

French Geoportal SDK based on OpenLayers (2D) and iTowns (3D) libraries

437 lines (397 loc) 15.4 kB
/* global true */ import Logger from "../Utils/LoggerByDefault"; import { transform as olTransformProj } from "ol/proj"; import { Services, ProxyUtils } from "geoportal-extensions-openlayers"; import { MapLoader } from "../Utils/MapLoader"; /** * Reloads the map with a new cartographic library. The current view options (camera position, layers, controls) will be conserved. * This function only works with the GpSDK3D bundle (run the "build:3d" npm task to generate it) * * @param {Integer} viewMode - The cartographic view mode. "2d" (for a 2D map) or "3d" (for a 3D map). * * @return {Object} the new map * @static * @private */ var switch2D3D = function (viewMode) { var oldMap = {}; oldMap.projection = this.getProjection(); oldMap.center = this.getCenter(); oldMap.tilt = this.getTilt(); oldMap.azimuth = this.getAzimuth(); oldMap.zoom = this.getZoom(); oldMap.layersOptions = this.getLayersOptions(); oldMap.controlsOptions = this.getControlsOptions(); oldMap.mapDiv = this.div.id; oldMap.apiKey = this.apiKey; oldMap.extent = this.mapOptions.extent; oldMap.enableRotation = this.mapOptions.enableRotation !== undefined ? this.mapOptions.enableRotation : null; oldMap.mapEventsOptions = this.mapOptions.mapEventsOptions !== undefined ? this.mapOptions.mapEventsOptions : null; // remove old controls and associated listeners for (var controlId in oldMap.controlsOptions) { this.removeControls(controlId); } if (viewMode === "3d") { // récupération des couches 3D qui n'étaient pas affichées en 2D if (this._3Dlayers) { for (var l = 0; l < this._3Dlayers.length; l++) { oldMap.layersOptions[this._3Dlayers[l].id] = this._3Dlayers[l].options; } } oldMap.center = [oldMap.center.x, oldMap.center.y]; // transformation des coordonnées de planes en géographiques // FIXME : ne devrait pas se faire avec ol.proj mais avec proj4 car dans IMap, ol n'est pas forcement chargée ! var lonlat = olTransformProj(oldMap.center, oldMap.projection, "EPSG:4326"); oldMap.center = { x : lonlat[0], y : lonlat[1] }; oldMap.azimuth = this.getAzimuth(); } else if (viewMode === "2d") { oldMap.center = [oldMap.center.lon, oldMap.center.lat]; // transformation des coordonnées de géographiques en planes // FIXME : ne devrait pas se faire avec ol.proj mais avec proj4 car dans IMap, ol n'est pas forcement chargée ! var xy = olTransformProj(oldMap.center, "EPSG:4326", "EPSG:3857"); oldMap.center = { x : xy[0], y : xy[1] }; } else { this.logger.info("Unknown viewing mode"); return; } this.destroyMap(); // this.libMap = null; var newMap = MapLoader.load( // FIXME faut-il rajouter un acces aux clés API directement dans Map getApiKeys() // this.libMap.getApiKeys(), // FIXME faut-il rajouter un acces à la div directement dans Map getDiv() // this.libMap.getDiv(), oldMap.mapDiv, // récupére le paramétrage courant de la carte (par les librairies) et pas le paramétrage initial (par this.mapOptions) { apiKey : oldMap.apiKey, enableRotation : oldMap.enableRotation, projection : oldMap.projection, center : oldMap.center, extent : oldMap.extent, azimuth : oldMap.azimuth, tilt : oldMap.tilt, zoom : oldMap.zoom, // maxZoom : this. // minZoom : this. // markerOptions : viewMode : viewMode, // proxyUrl // noProxyDomains // reloadConfig // autoconfUrl layersOptions : oldMap.layersOptions, controlsOptions : oldMap.controlsOptions, mapEventsOptions : oldMap.mapEventsOptions } ); return newMap; }; /** * Map Object. Returned by {@link module:Map Gp.Map.load()} function. Provides methods to interact with map view. * * @param {Object} opts - map options * @constructor * @private */ function IMap (opts) { if (!(this instanceof IMap)) { throw new TypeError("IMap constructor cannot be called as a function."); } // sauvegarde des options du constructeur. this._opts = opts; // logger this.logger = Logger.getLogger("IMap"); this.logger.trace("[Constructeur IMap (options)]"); /** * Couches enregistrées par le SDK * Structure des objets stockés : * { * id : layerId * obj : objet couche géré par l'implémentation. * options : propriétés de la couche (de type layerOptions) * } */ this._layers = []; /** * Couches enregistrées par le SDK et supprimées * Structure des objets stockés : * { * id : layerId * obj : objet couche géré par l'implémentation. * options : propriétés de la couche (de type layerOptions) * } */ this._layersRemoved = []; /** * Controlss enregistrés par le SDK * Structure des objets stockés : * { * id : controlId * obj : objet control géré par l'implémentation. * options : propriétés du controle (de type controlOptions) * } */ this._controls = []; /** * object d'enriegistrements des evenements. * Les propriétés sont les identifiants de l'evenement associées à un tableau : * "eventId" : [{ * action : // function * key : "clef retournée par OL pour l'enregistrement de l'evt" * context : objet d'execution de l'action * }] */ this._events = {}; if (this._opts.mapOptions) { this.apiKey = this._opts.mapOptions.apiKey; } this.div = this._opts.div; // récupère les options par défaut pour les paramètres optionnels // /!\ on duplique l'objet pour ne pas partager les mêmes options entre // differentes cartes. this.mapOptions = Object.create(IMap.DEFAULTOPTIONS); // et on ajoute les options en paramètres aux options par défaut for (var opt in this._opts.mapOptions) { if (this._opts.mapOptions.hasOwnProperty(opt)) { this.mapOptions[opt] = this._opts.mapOptions[opt]; // FIXME : ne marche qu'au premier niveau... this.logger.trace("option " + opt + " récupérée"); } } // intialisation de la carte (à vide) this._initMap(); // Substitute global constants configured at compile time // cf. webpack.config.js if (true) { this.switch2D3D = switch2D3D.bind(this); } }; /** * Options par défaut du service * (pour les options facultatives seulement) * @private */ IMap.DEFAULTOPTIONS = { projection : "EPSG:3857", center : { x : 0, y : 0, projection : "EPSG:4326", geolocate : false, location : null, locationType : ["StreetAddress", "PositionOfInterest"] }, azimuth : 0, enableRotation : true, tilt : 90, zoom : 10, minZoom : 0, maxZoom : 21, reloadConfig : false, controlsOptions : { draggable : true, keyboard : true, selectable : false }, mapEventsOptions : {}, noProxyDomains : ["wxs.ign.fr"] }; IMap.prototype = { /* * Constructeur (alias) */ constructor : IMap, /** * Map initialisation with constructor parameters (after _initMap call) * needed for asynchronous _initMap implementation. * * @private */ _afterInitMap : function () { // abonnement aux evenements demandes var meOptions = this.mapOptions.mapEventsOptions; if (meOptions) { for (var evtId in meOptions) { this.listen(evtId, meOptions[evtId], this); } } // abonnement perso à l'evnement layerChanged pour tenir à jour l'objet this._layers this.listen("layerChanged", this._onLayerChanged, this); // centrage avec les coordonnées x, y (s'il y en a) if (this.getViewMode() === "2d") { this.setXYCenter(this.mapOptions.center); } // centrage par location ou geolocalisation (s'il y en a). Centrage en x,y réalisé au chargement du globe (initMap) if (this.getViewMode() === "3d" && (this.mapOptions.center.location || this.mapOptions.center.geolocate)) { this.setCenter(this.mapOptions.center); } // FIXME Config est créé en runtime dans la variable globale Gp var scope = typeof window !== "undefined" ? window : {}; var Config = scope.Gp ? scope.Gp.Config : undefined; // Gestion du paramètre apiKeys var needsGetConfig = false; if (this.apiKey || this._opts.mapOptions.configUrl || this._opts.mapOptions.autoconfUrl) { // une clef est fournie // on recharge l'autoconf si l'utilisateur l'a demandé // ou si aucun n'appel d'autoconf n'a ete fait pour cette cle // TODO : this.apiKey.length > 1 needsGetConfig = (this._opts.reloadConfig || !Config || !Config.isConfLoaded((Array.isArray(this.apiKey) ? this.apiKey[0] : this.apiKey)) ); } else { // une clef n'est pas fournie // on essaye de trouver une configuration existante if (Config) { this.apiKey = Object.keys(Config.generalOptions.apiKeys); } } // appel du service d'autoconfiguration si nécessaire // Dans tous les cas, le reste s'exécute dans _afterGetConfig if (needsGetConfig) { // autoconf locale ? on met par defaut un callbackSuffix à "" // à moins qu'on ne le surcharge (non documenté). var callbackSuffix = this._opts.mapOptions.callbackSuffix; // deprecated param autoconfUrl if (this._opts.mapOptions.configUrl || this._opts.mapOptions.autoconfUrl) { callbackSuffix = callbackSuffix || ""; } var map = this; Services.getConfig({ apiKey : this.apiKey, serverUrl : this._opts.mapOptions.configUrl || this._opts.mapOptions.autoconfUrl, callbackSuffix : callbackSuffix, // fonction de rappel onSuccess onSuccess : function (configResponse) { map._afterGetConfig(configResponse); }, // fonction de rappel onFailure onFailure : function (error) { this.logger.error(error); map._afterGetConfig(null); } }); } else { this._afterGetConfig(Config); } }, /** * callback d'appel à l'autoconf (ou non). * * @param {Object} configResponse - configuration associée à apiKey. * @private */ _afterGetConfig : function (configResponse) { this.logger.trace("[IMap] : Autoconfiguration chargée ... ou pas"); // TODO : detecter si on a le bon objet (error ou success) // declenchement de l'evenement "configured" var e = IMap.CustomEvent("configured", { detail : { config : configResponse } }); this.div.dispatchEvent(e); // recuperation couche par defaut si aucune specifiee if (configResponse && !this.mapOptions.hasOwnProperty("layersOptions")) { // FIXME : trouver l'info dans l'autoconf ... ou pas ? this.mapOptions.layersOptions = { "ORTHOIMAGERY.ORTHOPHOTOS" : {} }; } // recuperation du centre par défaut si aucun spécifié if (configResponse && (!this.mapOptions.center.hasOwnProperty("x") || this.mapOptions.center.x === 0) && (!this.mapOptions.center.hasOwnProperty("y") || this.mapOptions.center.y === 0)) { var autoconfCenter; var territories = configResponse.getTerritories(); for (var terrCode in territories) { if (territories[terrCode].isDefault) { autoconfCenter = territories[terrCode].geoCenter; // autoconfProj = territories[terrCode].defaultCRS; } } this.logger.trace("[IMap] : _afterGetConfig : setting default map center to (" + autoconfCenter.lon + ", " + autoconfCenter.lat + ")"); this.mapOptions.center.x = autoconfCenter.lon; this.mapOptions.center.y = autoconfCenter.lat; this.mapOptions.center.projection = "EPSG:4326"; } // Centrage de la carte avec les options demandées if (this.getViewMode() === "2d") { this.setCenter(this.mapOptions.center); } // ajout des markers : TODO if (this.mapOptions.hasOwnProperty("markersOptions")) { this._addMarkers(this.mapOptions.markersOptions); } // ajout des couches this.addLayers(this.mapOptions.layersOptions); // ajout des controles // ... par defaut this.addControls(this._getDefaultControls()); // ceux demandés par l'utilisateur this.addControls(this.mapOptions.controlsOptions); // declenchement de l'evenement "mapLoaded" var eMapLoaded = IMap.CustomEvent("mapLoaded", { detail : { map : this } }); this.div.dispatchEvent(eMapLoaded); }, /** * Empty Map initialization : abstract * Implementation has to call _afterInitMap() function. * * @private */ _initMap : function () { this.logger.trace("[IMap] : _initMap"); }, /** * ajoute un proxy aux url des couches vecteurs si besoin. * * @alias Gp.Map.setProxy * @param {String} url - url * * @returns {String} - proxified url */ setProxy : function (url) { return ProxyUtils.proxifyUrl(url, this.mapOptions); }, /** * Returns the current viewing mode (either 2D or 3d). * * @alias Gp.Map.getViewMode * @returns {String} - The current viewing mode */ getViewMode : function () { return this.mapOptions.viewMode; }, /** * Returns wrapped map object implemented by the underlying library. Can be : * - an [ol.Map](https://openlayers.org/en/latest/apidoc/module-ol_Map-Map.html) object with current OpenLayers 3 implementation if the current map is in 2D. * - an [Itowns.GlobeView](http://www.itowns-project.org/itowns/docs/#api/View/GlobeView) object, ie the iTowns GlobeView object overloaded by Geoportal Extension for iTowns, if the current map is in 3D. * * @alias Gp.Map.getLibMap * @returns {Object} - wrapped map object. */ getLibMap : function () { // TO BE OVERRIDDEN return {}; }, /** * Destroy map by canceling all events listening and removing DOM elements */ destroyMap : function () { // TO BE OVERRIDDEN } }; export { IMap };