UNPKG

geopf-extensions-openlayers

Version:

French Geoportal Extensions for OpenLayers libraries

626 lines (564 loc) 20.4 kB
// import CSS import "../../CSS/Controls/Territories/GPFterritories.css"; // import OpenLayers import Control from "../Control"; import Widget from "../Widget"; import Map from "ol/Map"; import { transformExtent as olTransformExtentProj, transform as olTransformProj } from "ol/proj"; // import local import Utils from "../../Utils/Helper"; import SelectorID from "../../Utils/SelectorID"; import Logger from "../../Utils/LoggerByDefault"; import Draggable from "../../Utils/Draggable"; import TerritoriesJson from "./Territories.json"; // DOM import TerritoriesDOM from "./TerritoriesDOM"; var logger = Logger.getLogger("territories"); /** * @typedef {Object} TerritoriesOptions * @property {boolean} [collapsed=true] - Définit si le widget est replié au chargement. * @property {boolean} [draggable=false] - Permet de déplacer le panneau du widget. * @property {boolean} [panel=true] - Affiche un en-tête (header) dans le panneau. * @property {boolean} [auto=false] - Charge automatiquement la liste par défaut des territoires. * @property {boolean} [thumbnail=false] - Affiche une imagette pour chaque territoire. * @property {boolean} [reduce=false] - Affiche les tuiles en mode réduit (nom uniquement). * @property {number} [tiles=3] - Nombre de tuiles affichées (0 = toutes). * @property {Array<Territory>} [territories=[]] - Liste personnalisée des territoires à afficher. * @property {Object} [upload] - Options pour l’import de configuration. * @property {boolean} [upload.active=false] - Active le menu d’import de fichier. * @property {string} [upload.title="Ajouter un fichier de configuration"] - Titre du menu d’import. * @property {string} [upload.description=""] - Description du menu d’import. * @property {string} [title="Sélectionner un territoire"] - Titre affiché dans le panneau. * @property {string} [position] - Position CSS du widget sur la carte. * @property {boolean} [gutter] - Ajoute ou retire l’espace autour du panneau. * @property {string|number} [id] - Identifiant unique du widget. */ /** * @typedef {Object} Territory * @property {string} id - IdenObjecttifiant unique du territoire (ex: FRA, MTQ, GLP, ...). * @property {string} title - Titre du territoire. * @property {string} description - Description du territoire. * @property {Array<number>} bbox - Bbox du territoire au format [minx, miny, maxx, maxy] en EPSG:4326. * @property {Array<number>} [point] - Point central du territoire au format [lon, lat] en EPSG:4326. * @property {number} [zoom] - Niveau de zoom à appliquer lors de la sélection du territoire. * @property {string} [thumbnail] - URL ou data URI de l’imagette du territoire. */ /**Object * @classdesc * * Territories map widget * * @alias ol.control.Territories * @module Territories */ class Territories extends Control { /** * @constructor * @param {TerritoriesOptions} options - options for function call. * * @fires territories:change * @example * var territories = new ol.control.Territories({ * collapsed: true, * panel: true, * auto: true * }); * map.addControl(territories); * * or/and * * var territories = new ol.control.Territories({}); * territories.setTerritory({id: "MTQ", title: "Martinique", description: "", bbox: [], thumbnail: "data:image/png;base64,..."}); * territories.setTerritory({id: "GLP", title: "Guadeloupe", description: "", bbox: [], thumbnail: "http://..."}); * map.addControl(territories); */ constructor (options) { options = options || {}; // call ol.control.Control constructor super(options); if (!(this instanceof Territories)) { throw new TypeError("ERROR CLASS_CONSTRUCTOR"); } /** * Nom de la classe (heritage) * @private */ this.CLASSNAME = "Territories"; // initialisation du composant this.initialize(options); // Territories main DOM container this.container = this.initContainer(); // ajout du container (this.element) ? this.element.appendChild(this.container) : this.element = this.container; return this; } // ################################################################### // // ##################### public methods ############################## // // ################################################################### // /** * Overwrite OpenLayers setMap method * * @param {Map} map - Map. */ setMap (map) { if (map) { // mode "draggable" if (this.draggable) { Draggable.dragElement( this.panelTerritoriesContainer, this.panelTerritoriesHeaderContainer, map.getTargetElement() ); } // mode "collapsed" if (!this.collapsed) { this.buttonTerritoriesShow.setAttribute("aria-pressed", true); } // Ajout des territoires par defaut ou customisés var territories = (this.auto) ? TerritoriesJson : this.options.territories; for (let index = 0; index < territories.length; index++) { const territory = territories[index]; this.setTerritory(territory); } } else { // some stuff when remove widget } // on appelle la méthode setMap originale d'OpenLayers super.setMap(map); // position if (this.options.position) { this.setPosition(this.options.position); } // reunion du bouton avec le précédent if (this.options.gutter === false) { this.getContainer().classList.add("gpf-button-no-gutter"); } } // ################################################################### // // ################### getters / setters ############################# // // ################################################################### // /** * Add a territory * * @param {Territory} territory - territory * @returns {Boolean} - true|false * @public * @example * territories.setTerritory ({ * id: "MTQ", * title: "Martinique", * description: "", * bbox: [minx, miny, maxx, maxy], * thumbnail: "data:image/png;base64,..." * }); */ setTerritory (territory) { // Test if a territory already exist var founded = this.territories.some(e => e.data.id === territory.id); if (territory && !founded) { var entry = this._createTerritoryEntry(territory); if (entry) { this.panelTerritoriesEntriesContainer.appendChild(entry); this.territories.push({ data : territory, dom : entry }); return true; } } return false; } /** * Load a new configuration * * @param {Array<Territory>} territories - file config */ setTerritories (territories) { for (let j = 0; j < territories.length; j++) { const territory = territories[j]; this.setTerritory(territory); } } /** * Remove a territory * * @param {String} territory - territory id (FRA, MTQ, ...) * @returns {Boolean} - true|false * @public * @example * territories.removeTerritory("MTQ"); // id du territoire */ removeTerritory (territory) { var found = false; if (territory) { for (let i = 0; i < this.territories.length; i++) { const o = this.territories[i]; if (o.data.id === territory.data.id) { this.territories[i].dom.remove(); this.territories.splice(i, 1); found = true; break; } } } return found; } /** * Remove all territories */ removeTerritories () { for (let i = 0; i < this.territories.length; i++) { const territory = this.territories[i]; territory.dom.remove(); } this.territories = []; } /** * Set collapse * * @param {Boolean} collapsed - true|false * @todo ... * @public */ setCollapse (collapsed) { if (collapsed === undefined) { logger.log("[ERROR] Territory:setCollapsed - missing collapsed parameter"); return; } if ((collapsed && this.collapsed) || (!collapsed && !this.collapsed)) { return; } if (collapsed) { document.getElementById("GPterritoriesPanelClose").click(); } else { this.buttonTerritoriesShow.click(); } this.collapsed = collapsed; } /** * Mode reduit des tuiles (uniquement le nom du territoire) * * @param {*} reduce - true|false * @public */ setReduce (reduce) { if (reduce) { this.panelTerritoriesEntriesContainer.classList.add("tiles-reduce"); } else { this.panelTerritoriesEntriesContainer.classList.remove("tiles-reduce"); } } /** * Get container * * @returns {HTMLElement} container */ getContainer () { return this.container; } // ################################################################### // // #################### privates methods ############################# // // ################################################################### // /** * Initialize Territories control (called by Territories constructor) * * @param {Object} options - constructor options * @private */ initialize (options) { this.uid = options.id || SelectorID.generate(); // set default options this.options = { collapsed : true, draggable : false, panel : true, // titre upload : { active : false, title : "Ajouter un fichier de configuration", description : "" }, // menu du upload title : "Sélectionner un territoire", auto : false, // chargement auto des territoires par defaut thumbnail : false, // imagette des territoires reduce : false, // tuiles reduites par defaut tiles : 3, // nombre de tuiles affichables, 0 = toutes ! territories : [] }; // merge with user options var uploadOpts = Utils.assign(this.options.upload, options.upload); Utils.assign(this.options, options); Utils.assign(this.options.upload, uploadOpts); /** * @type {Boolean} * specify if control is collapsed (true) or not (false) */ this.collapsed = this.options.collapsed; /** * @type {Boolean} * specify if control is draggable (true) or not (false) * */ this.draggable = this.options.draggable; /** * specify if we load the list of territories by default * @type {Boolean} */ this.auto = this.options.auto; /** * list of object territories * @type {Array} * @example * { * dom : { HTMLelment }, * data : { * id: "MTQ", * title: "Martinique", * description: "", * bbox: [minx, miny, maxx, maxy], * thumbnail: "data:image/png;base64,..." * } * } */ this.territories = []; /** * @type {Boolean} * specify if a list of object territories must be appended or replaced */ this.append = false; /** @private */ this.buttonTerritoriesShow = null; /** @private */ this.panelTerritoriesContainer = null; /** @private */ this.panelTerritoriesHeaderContainer = null; // usefull for the dragNdrop /** @private */ this.buttonTerritoriesClose = null; /** @private */ this.containerTerritoriesOptions = null; /** @private */ this.panelTerritoriesEntriesContainer = null; } /** * Create control main container (DOM initialize) * * @returns {HTMLElement} DOM element * @private */ initContainer () { // create main container var container = this._createMainContainerElement(); var picto = this.buttonTerritoriesShow = this._createShowTerritoriesPictoElement(); container.appendChild(picto); // panel var territoriesPanel = this.panelTerritoriesContainer = this._createTerritoriesPanelElement(); territoriesPanel.classList.add("tiles-direction"); territoriesPanel.classList.add("tiles-" + this.options.tiles); var territoriesPanelDiv = this._createTerritoriesPanelDivElement(); territoriesPanel.appendChild(territoriesPanelDiv); // container for the custom code var territoriesEntriesDiv = this.panelTerritoriesEntriesContainer = this._createTerritoriesElement(); territoriesEntriesDiv.classList.add("tiles-direction"); territoriesEntriesDiv.classList.add("tiles-" + this.options.tiles); if (this.options.reduce) { territoriesEntriesDiv.classList.add("tiles-reduce"); } if (this.options.thumbnail) { territoriesEntriesDiv.classList.add("tiles-thumbnail"); } else { territoriesEntriesDiv.classList.add("tiles-icon"); } territoriesPanel.appendChild(territoriesEntriesDiv); // header ? if (this.options.panel) { var territoriesPanelHeader = this.panelTerritoriesHeaderContainer = this._createTerritoriesPanelHeaderElement(); // icone var territoriesPanelIcon = this._createTerritoriesPanelIconElement(); territoriesPanelHeader.appendChild(territoriesPanelIcon); // title var territoriesPanelTitle = this._createTerritoriesPanelTitleElement(this.options.title); territoriesPanelHeader.appendChild(territoriesPanelTitle); // options if (this.options.upload && this.options.upload.active) { var territoriesPanelOptions = this.containerTerritoriesOptions = this._createTerritoriesPanelOptionsElement(this.options.upload.title, this.options.upload.description); territoriesPanelHeader.appendChild(territoriesPanelOptions); } // close picto var territoriesCloseBtn = this.buttonTerritoriesClose = this._createTerritoriesPanelCloseElement(); territoriesPanelHeader.appendChild(territoriesCloseBtn); territoriesPanelDiv.appendChild(territoriesPanelHeader); } container.appendChild(territoriesPanel); logger.log(container); return container; } /** * Close panel option * @private */ closePanelUpLoad () { this.containerTerritoriesOptions.children[0].click(); } // ################################################################### // // ######################## event dom ################################ // // ################################################################### // /** * ... * @param {Event} e - ... * @private */ onShowTerritoriesClick (e) { if (e.target.ariaPressed === "true") { this.onPanelOpen(); } logger.trace(e); this.collapsed = !this.collapsed; } /** * ... * @param {Event} e - ... * @private */ onCloseTerritoriesClick (e) { logger.trace(e); } /** * ... * @param {Event} e - ... * @param {*} id - ... * @private */ onImageTerritoriesClick (e, id) { logger.trace(e, id); var territory = this.territories.find(e => e.data.id === id); if (territory) { var zoom = territory.data.zoom; var bbox = territory.data.bbox; // [left, bottom, right, top] var point = territory.data.point; if (bbox && !bbox.length) { return; } if (!point && !bbox) { return; } var map = this.getMap(); var proj = map.getView().getProjection().getCode(); if (bbox) { var extent = olTransformExtentProj(bbox, "EPSG:4326", proj); map.getView().fit(extent, map.getSize()); } if (point) { var coord = olTransformProj(point, "EPSG:4326", proj); map.getView().setCenter(coord); } if (zoom) { map.getView().setZoom(zoom); } this.setCollapse(true); /** * event triggered when a territory is clicked * * @event territories:change * @property {Object} type - event * @property {Object} target - instance Territories * @property {Object} territory - territory * @example * Route.on("territories:change", function (e) { * console.log(e.target.getData()); * }) */ this.dispatchEvent({ type : "territories:change", territory : territory }); } } /** * ... * @param {Event} e - ... * @private */ onUploadFileClick (e) { var file = e.target.files[0]; var target = e.target; if (!file) { logger.warn("Missing file to upload !"); return; } var fReader = new FileReader(); // Définition des fonctions de callbacks associées au reader var self = this; /** * on readAsText error * @param {*} e - ... * @private */ fReader.onerror = (e) => { logger.log("onerror"); }; /** on readAsText progress * @param {*} e - ... * @private */ fReader.onprogress = (e) => { logger.log("onprogress"); }; /** on load start * @param {*} e - ... * @private */ fReader.onloadstart = (e) => { logger.log("onloadstart"); }; /** on readAsText abort * @param {*} e - ... * @private */ fReader.onabort = (e) => { logger.log("onabort"); }; /** on readAsText loadend * @param {*} e - ... * @private */ fReader.onloadend = (e) => { logger.log("onloadend : ", e); }; /** on readAsText load * @param {*} e - ... * @private */ fReader.onload = (e) => { logger.log("file content : ", e.target.result); // on ferme le panneau self.closePanelUpLoad(target); // on convertie string -> json var config = JSON.parse(e.target.result); if (!self.append) { // on nettoie l'ancienne configuration self.removeTerritories(); } // et, on en ajoute une autre self.setTerritories(config); }; // Lecture du fichier chargé à l'aide de fileReader fReader.readAsText(file); } /** * ... * @param {Event} e - ... * @private */ onUploadToggleClick (e) { // INFO // la configuration des territoires doit elle être ajoutée // à la liste courrante ou remplacée ? this.append = e.target.checked; } }; // on récupère les méthodes de la classe DOM Object.assign(Territories.prototype, TerritoriesDOM); Object.assign(Territories.prototype, Widget); export default Territories; // Expose Export as ol.control.Territories (for a build bundle) if (window.ol && window.ol.control) { window.ol.control.Territories = Territories; }