UNPKG

geopf-extensions-openlayers

Version:

French Geoportal Extensions for OpenLayers libraries

647 lines (585 loc) 23 kB
import EventBus from "eventbusjs"; import EventEditor from "./Event"; import Style from "./Style"; import Legend from "./Legend"; import Filter from "./Filter"; import Utils from "../../Utils/Helper"; import Logger from "../../Utils/LoggerByDefault"; var logger = Logger.getLogger("editor-layer"); /** * @classdesc * * MapBox filter management * * @constructor * @alias ol.style.editor.Layer * @param {Object} options - options for function call. * @example * var layers = new Layer ({ * target : ..., * position : 1, // identifiant de position (unique !) * tools : { * "visibility" : true, // afficher l'icone de visibilité * "icon" : { * "image" : true, // afficher l'icone "oeil" (defaut) ou une checkbox * "anchor" : "start" | "end" // afficher l'icone au debut ou à la fin (defaut) * }, * "type" : true, // afficher l'icone du type de geometrie * "pin" : true, // afficher l'icone de puce * "remove" : false, // TODO afficher l'icone de suppression * "clone" : false // TODO afficher l'icone de duplication * }, * obj : { * "id": "ocs - vegetation", // MANDATORY * "type": "fill", // OPTIONAL * "source": "pyramide_proto", // OPTIONAL * "source-layer": "ocs_vegetation_surf" // OPTIONAL * } * }); * layers.addLegend(oLegend); * layers.slotLegend(); * layers.addStyle(oStyle); * layers.addFilter(oFilter); * layers.add(); * layers.active(false); * layers.visibility(false); * layers.display(false); * layers.collapse(); * EventBus.addEventListener("editor:layer:onclickvisibility", function (e) { * // e.target.data : options ! * // e.target.editorID : id or null * }, this); */ class Layer { constructor (options) { logger.trace("[constructor] Layer", options); // options this.options = options || {}; if (!(this instanceof Layer)) { throw new TypeError("ERROR CLASS_CONSTRUCTOR"); } this._initialize(); this._initContainer(); } // ################################################################### // // ##################### private methods ############################# // // ################################################################### // /** * Initialize component * (called by constructor) * * @private */ _initialize () { // unique editor id (optional!) this.id = this.options.id || null; // null si le layer n'appartient pas à un editeur ! if (!this.options.target) { // cf. add() } if (!this.options.position) { this.options.position = 0; } var _toolsDefault = { visibility : true, icon : { image : true, anchor : "end" }, type : true, pin : true, remove : false, // TODO clone : false // TODO }; if (!this.options.tools) { this.options.tools = _toolsDefault; } Utils.mergeParams(this.options.tools, _toolsDefault, false); var _objDefault = { id : "", type : "", // icone sur le type de geometrie source : "", "source-layer" : "" }; if (!this.options.obj) { this.options.obj = _objDefault; } Utils.mergeParams(this.options.obj, _objDefault, false); // legende intégrée this.bSlotLegend = false; // obj this.oFilter = null; this.oStyle = null; this.oLegend = null; // dom this.container = null; this.DomVisibility = null; this.DomToggle = null; // DOM : className or id this.name = { target : "GPEditorMapBoxLayerTarget", container : "GPEditorMapBoxLayerContainer", containerlegend : "GPEditorMapBoxLayerLegendContainer", containertitle : "GPEditorMapBoxLayerTitleContainer", imagelabelinput : "GPEditorMapBoxLayerImageInput", imagelabel : "GPEditorMapBoxLayerImageLabel", typeimg : "GPEditorMapBoxLayerTypeImage", titleinput : "GPEditorMapBoxLayerTitleInput", titlelabel : "GPEditorMapBoxLayerTitleLabel", containertools : "GPEditorMapBoxToolsContainer", visibilityinput : "GPEditorMapBoxToolsVisibilityInput", visibilitylabel : "GPEditorMapBoxToolsVisibilityLabel", visibilityinputdisable : "GPEditorMapBoxToolsVisibilityInputDisable", visibilitylabeldisable : "GPEditorMapBoxToolsVisibilityLabelDisable" }; } /** * Graphical rendering of the component * (called by constructor) * * @private * @example * // >> Titre 1 |OOO| <- menu tools : visibility, clone, remove * // >> Titre 2 |OXX| <- affichage configurable (cf. options.tools) * // Event : clic sur le titre -> ex. affiche le menu des styles / filtres * // : clic visibility, clone, remove * // DOM : * <div class="GPEditorMapBoxLayerContainer"> * <div id="GPEditorMapBoxLayerTitleContainer-45" class="GPEditorMapBoxLayerTitleContainer"> * <input id="GPEditorMapBoxLayerImageInput-45" class="GPEditorMapBoxLayerImageInput" type="checkbox"> * <label class="GPEditorMapBoxLayerImageLabel" for="GPEditorMapBoxLayerImageInput-45"></label> * <input id="GPEditorMapBoxLayerTitleInput-45" class="GPEditorMapBoxLayerTitleInput" type="checkbox"> * <label class="GPEditorMapBoxLayerTitleLabel" for="GPEditorMapBoxLayerTitleInput-45" title="...">...</label> * </div> * <div id="GPEditorMapBoxToolsContainer-45" class="GPEditorMapBoxToolsContainer"> * <input id="GPEditorMapBoxToolsVisibilityInput-45" type="checkbox" class="GPEditorMapBoxToolsVisibilityInput"> * <label for="GPEditorMapBoxToolsVisibilityInput-45" id="GPEditorMapBoxToolsVisibilityLabel-45" class="GPEditorMapBoxToolsVisibilityLabel" title="Afficher/masquer la couche"></label> * </div> * </div> */ _initContainer () { // contexte var self = this; var obj = this.options.obj; var div = document.createElement("div"); div.className = this.name.container; // title var divTitle = document.createElement("div"); divTitle.id = this.name.containertitle + "-" + this.options.position; divTitle.className = this.name.containertitle; // puce if (this.options.tools.pin) { // Optionnel ! // input var inputImage = document.createElement("input"); inputImage.id = this.name.imagelabelinput + "-" + this.options.position; inputImage.className = this.name.imagelabelinput; inputImage.type = "checkbox"; divTitle.appendChild(inputImage); // puce var labelImage = document.createElement("label"); labelImage.className = this.name.imagelabel; labelImage.htmlFor = inputImage.id; if (labelImage.addEventListener) { labelImage.addEventListener("click", function (e) { self.onClickLayerMapBox(e); }); } else if (labelImage.attachEvent) { labelImage.attachEvent("onclick", function (e) { self.onClickLayerMapBox(e); }); } divTitle.appendChild(labelImage); } // tools : // visibility, (remove, clone) var _addTools = function () { var divTools = document.createElement("div"); divTools.id = this.name.containertools + "-" + this.options.position; divTools.className = this.name.containertools; // visibility if (this.options.tools.visibility) { var inputTools = document.createElement("input"); inputTools.id = this.name.visibilityinput + "-" + this.options.position; inputTools.className = (this.options.tools.icon.image) ? this.name.visibilityinput : this.name.visibilityinputdisable; inputTools.type = "checkbox"; inputTools.checked = "checked"; // par défaut, à modifier via visibility(true|false) ! // event for visibility change if (inputTools.addEventListener) { inputTools.addEventListener("click", function (e) { self.onVisibilityLayerMapBox(e); }); } else if (inputTools.attachEvent) { // internet explorer inputTools.attachEvent("onclick", function (e) { self.onVisibilityLayerMapBox(e); }); } divTools.appendChild(inputTools); // enregistrement utile pour la méthode : visibility() this.DomVisibility = inputTools; var labelTools = document.createElement("label"); labelTools.htmlFor = this.name.visibilityinput + "-" + this.options.position; labelTools.id = this.name.visibilitylabel + "-" + this.options.position; labelTools.className = (this.options.tools.icon.image) ? this.name.visibilitylabel : this.name.visibilitylabeldisable; labelTools.title = "Afficher/masquer la couche"; divTools.appendChild(labelTools); div.appendChild(divTools); } // clone if (this.options.tools.clone) { // TODO... logger.warn("Dom for tools clone, it's not yet implemented !"); } // remove if (this.options.tools.remove) { // TODO... logger.warn("Dom for tools remove, it's not yet implemented !"); } }; // ajout des outils au debut du composant if (this.options.tools.icon.anchor === "start") { _addTools.apply(this); } // type if (this.options.tools.type && obj.type) { // Optionnel ! var imgType = document.createElement("img"); imgType.className = this.name.typeimg; // FIXME il faudrait faire la difference entre : // - icone uniquement : SYMBOL-ICON // - texte uniquement : SYMBOL-TEXT // - les 2 : SYMBOL // Mais il nous faut les styles complets (paint & layout) // pour determiner les 3 types ! switch (obj.type.toUpperCase()) { case "SYMBOL-ICON": // not used ! imgType.style["background-position"] = "0px 0"; break; case "SYMBOL-TEXT": // not used ! imgType.style["background-position"] = "-194px 0"; break; case "SYMBOL": imgType.style["background-position"] = "-84px 0"; break; case "LINE": imgType.style["background-position"] = "-28px 0"; break; case "FILL": imgType.style["background-position"] = "-56px 0"; break; case "BACKGROUND": imgType.style["background-position"] = "-140px 0"; break; case "CIRCLE": imgType.style["background-position"] = "-168px 0"; break; default: // type inconnu ou non pris en charge ou par defaut imgType.style["background-position"] = "-112px 0"; } divTitle.appendChild(imgType); } // container legend (empty) var divLegend = document.createElement("div"); divLegend.id = this.name.containerlegend + "-" + this.options.position; divLegend.className = this.name.containerlegend; divTitle.appendChild(divLegend); // input var inputTitle = document.createElement("input"); inputTitle.id = this.name.titleinput + "-" + this.options.position; inputTitle.className = this.name.titleinput; inputTitle.type = "checkbox"; divTitle.appendChild(inputTitle); // label for var labelTitle = document.createElement("label"); labelTitle.className = this.name.titlelabel; labelTitle.htmlFor = inputTitle.id; labelTitle.innerHTML = obj["id"] || obj["source-layer"] || obj["source"]; labelTitle.title = obj["source-layer"] || obj["source"] || obj["id"]; if (labelTitle.addEventListener) { labelTitle.addEventListener("click", function (e) { self.onClickLayerMapBox(e); }); } else if (labelTitle.attachEvent) { labelTitle.attachEvent("onclick", function (e) { self.onClickLayerMapBox(e); }); } divTitle.appendChild(labelTitle); // enregistrement utile pour la méthode : collapse() this.DomToggle = labelTitle; div.appendChild(divTitle); // ajout des outils au fin du composant if (this.options.tools.icon.anchor === "end") { _addTools.apply(this); } // main container this.container = div; } // ################################################################### // // ##################### public methods ############################## // // ################################################################### // /** * Add element into target DOM * @returns {Object} - Layer instance */ add () { logger.trace("add()"); if (!this.options.target) { if (!document.getElementById(this.name.target)) { var div = document.createElement("div"); div.id = this.name.target; var node = document.documentElement || document.getElementsByTagName("body")[0] || document.getElementsByTagName("head")[0]; node.appendChild(div); } this.options.target = document.getElementById(this.name.target); } if (this.container) { this.options.target.appendChild(this.container); } return this; } /** * Add style in the submenu * * @param {Object} style - style object */ addStyle (style) { logger.trace("addStyle()", style); if (style && typeof style === "object" && style instanceof Style) { this.oStyle = style; this.oStyle.display(false); // par defaut ! } } /** * Add filter in the submenu * * @param {Object} filter - filter object */ addFilter (filter) { logger.trace("addFilter()", filter); if (filter && typeof filter === "object" && filter instanceof Filter) { this.oFilter = filter; this.oFilter.display(false); // par defaut ! } } /** * Add Legend in the submenu * * @param {Object} legend - legend object */ addLegend (legend) { logger.trace("addLegend()", legend); if (legend && typeof legend === "object" && legend instanceof Legend) { this.oLegend = legend; this.oLegend.display(false); // par defaut ! } } /** * Integrate Legend to the layer container */ slotLegend () { // cas particulier : // on souhaite intégrer une partie de la legende dans le container du layer. var legend = this.oLegend; if (legend) { // FIXME c'est pourri... var node = null; var nodesLvl1 = this.container.childNodes; if (nodesLvl1.length) { // selon où se situe l'icone de visibilité : au debut ou à la fin... var idx = (this.options.tools.icon.anchor === "start") ? 1 : 0; var nodesLvl2 = nodesLvl1[idx].childNodes; // on recherche le container de la legende for (var i = 0; i < nodesLvl2.length; i++) { var curnode = nodesLvl2[i]; if (curnode.id.indexOf(this.name.containerlegend) !== -1) { node = curnode; } } } if (node) { var render = legend.getRenderContainer(); if (render) { node.appendChild(render); // legende intégrée this.bSlotLegend = true; } } } } // ################################################################### // // ##################### public methods ############################## // // ################################################################### // /** * Set visibility or get * * @param {Boolean} display - set visibility or undefined to get status * @returns {Boolean} - true/false */ visibility (display) { logger.trace("visibility()", display); if (!this.options.tools.visibility) { return; } if (typeof display !== "undefined") { this.DomVisibility.checked = (display) ? "checked" : ""; } return this.DomVisibility.checked; } /** * Collapse a layer panel (event) */ collapse () { logger.trace("collapse()"); this.DomToggle.click(); } /** * Click on visibility icon (event) */ visible () { logger.trace("visible()"); if (!this.options.tools.visibility) { return; } this.DomVisibility.click(); } /** * Set collapse or get * * @param {Boolean} display - show/hidden container or get status * @returns {Boolean} - true/false */ display (display) { logger.trace("display()", display); var checked = document.getElementById(this.DomToggle.htmlFor).checked; if (typeof display !== "undefined") { this.container.style.display = (display) ? "inline-flex" : "none"; if (this.oStyle) { this.oStyle.display(display && checked); } if (this.oFilter) { this.oFilter.display(display && checked); } if (this.oLegend) { this.oLegend.display(display && checked); } } return checked; } /** * Set disabled/enabled status or get * * @param {Boolean} active - disable/enable layer interaction or get status * @returns {Boolean} - true/false */ active (active) { logger.trace("active()", active); if (typeof active !== "undefined") { this.container.className = (active) ? this.name.container : this.name.container + " disabled"; } return (this.container.className === this.name.container); } /** * Get container (DOM) * * @returns {HTMLElement} DOM element */ getContainer () { return this.container; } // ################################################################### // // ####################### handlers events to dom #################### // // ################################################################### // /** * this method is called by event '' on '' tag form * * @param {Object} e - HTMLElement * @private */ onClickLayerMapBox (e) { logger.trace("onClickLayerMapBox", e); var id = e.target.htmlFor.substring(e.target.htmlFor.indexOf("-")); var checked = document.getElementById(e.target.htmlFor).checked; // gestion des inputs if (e.target.htmlFor === this.name.imagelabelinput + id) { document.getElementById(this.name.titleinput + id).checked = !checked; } if (e.target.htmlFor === this.name.titleinput + id) { // si options.pin:false, ce DOM n'existe pas ! if (document.getElementById(this.name.imagelabelinput + id)) { document.getElementById(this.name.imagelabelinput + id).checked = !checked; } } // ouverture du panneau des styles / filtres if (this.oStyle) { this.oStyle.display(!checked); } if (this.oFilter) { this.oFilter.display(!checked); } // attention, // si la legende est non editable, elle ne se trouve pas dans le sous menu ! if (this.oLegend && this.oLegend.isEditable()) { this.oLegend.display(!checked); } } /** * this method is called by event '' on '' tag form... * * 'e' contains the option object into 'e.target.data' ! * 'e' contains the id editor into 'e.target.editorID' ! * * @param {Object} e - HTMLElement * @private * @fires Layer#editor:layer:onclickvisibility */ onVisibilityLayerMapBox (e) { logger.trace("onVisibilityLayerMapBox", e); e.editorID = this.id; e.data = this.options; EventBus.dispatch(EventEditor.layer.onclickvisibility, e); } /** * this method is called by event '' on '' tag form... * * 'e' contains the option object into 'e.target.data' ! * 'e' contains the id editor into 'e.target.editorID' ! * * @param {Object} e - HTMLElement * @private * @fires Layer#editor:layer:onclickclone */ onCloneLayerMapBox (e) { logger.trace("onCloneLayerMapBox", e); e.editorID = this.id; e.data = this.options; EventBus.dispatch(EventEditor.layer.onclickclone, e); } /** * this method is called by event '' on '' tag form... * * 'e' contains the option object into 'e.target.data' ! * 'e' contains the id editor into 'e.target.editorID' ! * * @param {Object} e - HTMLElement * @private * @fires Layer#editor:layer:onclickremove */ onRemoveLayerMapBox (e) { logger.trace("onRemoveLayerMapBox", e); e.editorID = this.id; e.data = this.options; EventBus.dispatch(EventEditor.layer.onclickremove, e); } }; export default Layer; // Expose Editor as ol.editor.View (for a build bundle) if (window.ol && window.ol.style) { if (!window.ol.style.editor) { window.ol.style.editor = {}; } window.ol.style.editor.Layer = Layer; }