UNPKG

geoportal-extensions-openlayers

Version:

![GitHub package.json version](https://img.shields.io/github/package-json/v/IGNF/geoportal-extensions?filename=build%2Fscripts%2Frelease%2Fpackage-openlayers.json)

1,340 lines (1,205 loc) 83.5 kB
// import CSS import "../CSS/Controls/Route/GProuteOpenLayers.css"; // import OpenLayers import Control from "ol/control/Control"; import { unByKey as olObservableUnByKey } from "ol/Observable"; import Overlay from "ol/Overlay"; import VectorLayer from "ol/layer/Vector"; import VectorSource from "ol/source/Vector"; // import GeoJSON from "ol/format/GeoJSON"; import { pointerMove as eventPointerMove } from "ol/events/condition"; import { Select as SelectInteraction } from "ol/interaction"; import { Stroke, Style } from "ol/style"; import { transformExtent as olTransformExtentProj } from "ol/proj"; // import geoportal library access import Gp from "geoportal-access-lib"; // import local import Logger from "../../Common/Utils/LoggerByDefault"; import Utils from "../../Common/Utils"; import SelectorID from "../../Common/Utils/SelectorID"; import Markers from "./Utils/Markers"; import Draggable from "../../Common/Utils/Draggable"; import Interactions from "./Utils/Interactions"; // import local with ol dependencies import LocationSelector from "./LocationSelector"; import ButtonExport from "./Export"; import LayerSwitcher from "./LayerSwitcher"; import GeoJSONExtended from "../Formats/GeoJSON"; // DOM import RouteDOM from "../../Common/Controls/RouteDOM"; var logger = Logger.getLogger("route"); /** * @classdesc * * Route Control. * * @constructor * @alias ol.control.Route * @type {ol.control.Route} * @extends {ol.control.Control} * @param {Object} options - route control options * @param {String} [options.apiKey] - API key for services call (route and autocomplete services). The key "calcul" is used by default. * @param {Boolean} [options.ssl = true] - use of ssl or not (default true, service requested using https protocol) * @param {Boolean} [options.collapsed = true] - Specify if widget has to be collapsed (true) or not (false) on map loading. Default is true. * @param {Boolean} [options.draggable = false] - Specify if widget is draggable * @param {Boolean|Object} [options.export = false] - Specify if button "Export" is displayed. For the use of the options of the "Export" control, see {@link ol.control.Export} * @param {Object} [options.exclusions = {"toll" : false, "tunnel" : false, "bridge" : false}] - list of exclusions with status (true = checked). By default : no exclusions checked. * @param {Array} [options.graphs = ["Voiture", "Pieton"]] - list of resources, by default : ["Voiture", "Pieton"]. The first element is selected. * @param {Object} [options.routeOptions = {}] - route service options. see {@link http://ignf.github.io/geoportal-access-lib/latest/jsdoc/module-Services.html#~route Gp.Services.route()} to know all route options. * @param {Object} [options.autocompleteOptions = {}] - autocomplete service options. see {@link http://ignf.github.io/geoportal-access-lib/latest/jsdoc/module-Services.html#~autoComplete Gp.Services.autoComplete()} to know all autocomplete options * @param {Object} [options.markersOpts] - options to use your own markers. Object properties can be "departure", "stages" or "arrival". Corresponding value is an object with following properties : * @param {String} [options.markersOpts.url] - marker base64 encoded url (ex "data:image/png;base64,...""). Mandatory for a custom marker * @param {Array} [options.markersOpts.offset] - Offsets in pixels used when positioning the overlay. The first element in the array is the horizontal offset. A positive value shifts the overlay right. The second element in the array is the vertical offset. A positive value shifts the overlay down. Default is [0, 0]. (see http://openlayers.org/en/latest/apidoc/ol.Overlay.html) * @param {Object} [options.layerDescription = {}] - Layer informations to be displayed in LayerSwitcher widget (only if a LayerSwitcher is also added to the map) * @param {String} [options.layerDescription.title = "Itinéraire"] - Layer title to be displayed in LayerSwitcher * @param {String} [options.layerDescription.description = "Itinéraire basé sur un graphe"] - Layer description to be displayed in LayerSwitcher * @fires route:drawstart * @fires route:drawend * @fires route:compute * @fires export:compute * @example * var route = ol.control.Route({ * "collapsed" : true * "draggable" : true, * "export" : false, * "exclusions" : { * "toll" : true, * "bridge" : false, * "tunnel" : true * }, * "graphs" : ['Pieton', 'Voiture'], * "markersOpts" : { * "departure" : { * "url" : "...", * "offset" : [0,0] * }, * "stages" : { * "url" : "...", * "offset" : [0,0] * }, * "arrival" : { * "url" : "...", * "offset" : [0,0] * } * } * "autocompleteOptions" : {}, * "routeOptions" : {} * }); * * // if you want to pluggued the control Export with options : * var route = new ol.control.Route({ * export : { * name : "export", * format : "geojson", * title : "Exporter", * menu : false * } * }); */ var Route = (function (Control) { /** * See {@link ol.control.Route} * @module Route * @alias module:~Controls/Route * @param {*} options - options * @example * import Route from "src/OpenLayers/Controls/Route" */ function Route (options) { options = options || {}; if (!(this instanceof Route)) { throw new TypeError("ERROR CLASS_CONSTRUCTOR"); } // initialisation du composant this.initialize(options); // Widget main DOM container this._container = this._createMainContainerElement(); this._containerElement = null; // on peut éventuellement encapsuler le composant dans une div passée par l'utilisateur if (options.element && options.element.appendChild) { // dans ce cas on stocke les deux container options.element.appendChild(this._container); this._containerElement = options.element; } // call ol.control.Control constructor Control.call(this, { element : this._containerElement || this._container, target : options.target, render : options.render }); } // Inherits from ol.control.Control if (Control) Route.__proto__ = Control; /** * @lends module:Route */ Route.prototype = Object.create(Control.prototype, {}); // on récupère les méthodes de la classe commune RouteDOM Utils.assign(Route.prototype, RouteDOM); /** * Constructor (alias) * @private */ Route.prototype.constructor = Route; /** * Overwrite OpenLayers setMap method * * @param {ol.Map} map - Map. */ Route.prototype.setMap = function (map) { if (map) { // enrichissement du DOM du container this._container = this._initContainer(map); // ajout d'un bouton d'export if (this.options.export) { var opts = Utils.assign({ control : this }, this.options.export); this.export = new ButtonExport(opts); this.export.render(); var self = this; this.export.on("export:compute", (e) => { self.dispatchEvent({ type : "export:compute", content : e.content }); }); } // mode "draggable" if (this.draggable) { Draggable.dragElement( this._panelRouteContainer, this._panelHeaderRouteContainer, map.getTargetElement() ); } } // on appelle la méthode setMap originale d'OpenLayers Control.prototype.setMap.call(this, map); }; // ################################################################### // // ##################### public methods ############################## // // ################################################################### // /** * Returns true if widget is collapsed (minimized), false otherwise * * @returns {Boolean} collapsed - true if widget is collapsed */ Route.prototype.getCollapsed = function () { return this.collapsed; }; /** * Collapse or display widget main container * * @param {Boolean} collapsed - True to collapse widget, False to display it */ Route.prototype.setCollapsed = function (collapsed) { if (collapsed === undefined) { logger.log("[ERROR] Route:setCollapsed - missing collapsed parameter"); return; } if ((collapsed && this.collapsed) || (!collapsed && !this.collapsed)) { return; } if (collapsed) { document.getElementById("GProutePanelClose-" + this._uid).click(); } else { document.getElementById("GPshowRoute-" + this._uid).click(); } this.collapsed = collapsed; }; /** * Get vector layer where geoJson route is drawn * * @returns {Object} layer - ol.layer.Vector route layer */ Route.prototype.getLayer = function () { return this._geojsonSections; }; /** * Set vector layer where route geometry is drawn * * @param {Object} layer - ol.layer.Vector route layer */ Route.prototype.setLayer = function (layer) { if (!layer) { this._geojsonSections = null; return; } if (!(layer instanceof VectorLayer)) { logger.log("no valid layer given for hosting drawn features."); return; } // application des styles layer.setStyle(this._defaultFeatureStyle); // sauvegarde this._geojsonSections = layer; }; /** * Get vector layer * * @returns {String} geojson - GeoJSON format layer */ Route.prototype.getGeoJSON = function () { return JSON.stringify(this._geojsonObject); }; /** * Set vector layer * * @param {String} geojson - GeoJSON format layer */ Route.prototype.setGeoJSON = function (geojson) { try { this._geojsonObject = JSON.parse(geojson); } catch (e) { logger.log("no valid geojson given :" + e.message); } }; /** * Get route informations * * @returns {Object} data - route informations */ Route.prototype.getData = function () { var points = []; for (let index = 0; index < this._currentPoints.length; index++) { const p = this._currentPoints[index]; points.push(p.getCoordinate()); } var data = { type : "route", points : points, transport : this._currentTransport, exclusions : this._currentExclusions, computation : this._currentComputation, results : {} }; Utils.assign(data.results, this._currentRouteInformations); return data; }; /** * Set route data * * @param {Object} data - control informations * @param {String} data.transport - transport type * @param {String} data.computation - computation type * @param {Array} data.exclusions - list of exclusions * @param {Array} data.points - list of points : [[lon, lat]] * @param {Object} data.results - service response */ Route.prototype.setData = function (data) { // INFO // transmettre toutes les informations necessaires pour reconstruire le panneau de resultats this._currentTransport = data.transport; this._currentComputation = data.computation; this._currentExclusions = data.exclusions; // INFO // nettoyer les points du calcul précedent for (var i = 0; i < this._currentPoints.length; i++) { var point = this._currentPoints[i]; if (point.getCoordinate()) { // clean de l'objet sans declencher les evenements qui suppriment la couche précedente ! // /!\ point.clear() point.clearResults(); // clean du dom var id = (i + 1) + "-" + this._uid; document.getElementById("GPlocationOriginCoords_" + id).value = ""; document.getElementById("GPlocationOrigin_" + id).value = ""; document.getElementById("GPlocationPoint_" + id).style.cssText = ""; if (i > 0 && i < 6) { // on masque les points intermediaires document.getElementById("GPlocationPoint_" + id).className = "GPflexInput GPlocationStageFlexInputHidden"; } document.getElementById("GPlocationOriginPointer_" + id).checked = false; document.getElementById("GPlocationOrigin_" + id).className = "GPlocationOriginVisible"; document.getElementById("GPlocationOriginCoords_" + id).className = "GPlocationOriginHidden"; } } // ajout des nouvelles coordonnnées for (var j = 0; j < data.points.length; j++) { const c = data.points[j]; if (c) { this._currentPoints[j].setCoordinate(c, "EPSG:4326"); } } this._currentRouteInformations = data.results; }; /** * Get container * * @returns {DOMElement} container */ Route.prototype.getContainer = function () { return this._container; }; /** * Get default style * * @returns {ol.style} style */ Route.prototype.getStyle = function () { return this._defaultFeatureStyle; }; /** * This method is public. * It allows to init the control. */ Route.prototype.init = function () { // INFO // reconstruire le panneau de resultats sans lancer de calcul // * construire la liste des points (cf. RouteDOM._createRoutePanelFormElement()) // * construire les resultats // init points for (let index = 0; index < this._currentPoints.length; index++) { const point = this._currentPoints[index]; var id = index + 1; var coordinate = point.getCoordinate(); if (coordinate) { var input = document.getElementById("GPlocationOrigin_" + id + "-" + this._uid); input.value = coordinate[1].toFixed(4) + " / " + coordinate[0].toFixed(4); if (index > 0 && index < 6) { document.getElementById("GPlocationPoint_" + id + "-" + this._uid).className = "GPflexInput GPlocationStageFlexInput"; } } } // add points into panel var points = document.getElementsByClassName("GPlocationPoint-" + this._uid); this._addRouteResultsStagesValuesElement(points); // set transport mode var transportdiv; if (this._currentTransport === "Pieton") { transportdiv = document.getElementById("GProuteTransportPedestrian-" + this._uid); if (transportdiv) { transportdiv.checked = "true"; } } else { transportdiv = document.getElementById("GProuteTransportCar-" + this._uid); if (transportdiv) { transportdiv.checked = "true"; } } // set computation mode var computationdiv = document.getElementById("GProuteComputationSelect-" + this._uid); if (computationdiv) { computationdiv.value = this._currentComputation; } // set exclusions var tollInput = document.getElementById("GProuteExclusionsToll-" + this._uid); if (tollInput) { if (this._currentExclusions.indexOf("toll") !== -1) { tollInput.checked = false; } else { tollInput.checked = true; } } var tunnelInput = document.getElementById("GProuteExclusionsTunnel-" + this._uid); if (tunnelInput) { if (this._currentExclusions.indexOf("tunnel") !== -1) { tunnelInput.checked = false; } else { tunnelInput.checked = true; } } var bridgeInput = document.getElementById("GProuteExclusionsBridge-" + this._uid); if (bridgeInput) { if (this._currentExclusions.indexOf("bridge") !== -1) { bridgeInput.checked = false; } else { bridgeInput.checked = true; } } var distance = this._currentRouteInformations.totalDistance; var duration = this._currentRouteInformations.totalTime; // Détails avec simplifications des troncons var instructions = this._simplifiedInstructions(this._currentRouteInformations.routeInstructions); if (instructions) { this._fillRouteResultsDetailsContainer(distance, duration, instructions); } // affichage du panneau de details du controle ! this._formRouteContainer.className = "GProuteComponentHidden"; this._hideWaitingContainer(); this._resultsRouteContainer.className = ""; }; /** * Clean UI : reinit control */ Route.prototype.clean = function () { this._currentTransport = null; this._currentExclusions = []; this._currentComputation = null; for (var i = 0; i < this._currentPoints.length; i++) { this._currentPoints[i].clear(); } this._removeRouteStepLocations(); this._clearRouteInputOptions(); this._clearRouteResultsDetails(); this.setLayer(); this._formRouteContainer.className = ""; this._resultsRouteContainer.className = "GProuteComponentHidden"; }; // ################################################################### // // ##################### init component ############################## // // ################################################################### // /** * Initialize route control (called by Route constructor) * * @param {Object} options - constructor options * @private */ Route.prototype.initialize = function (options) { this._checkInputOptions(options); // set default options this.options = { collapsed : true, draggable : false, export : false, graphs : ["Voiture", "Pieton"], exclusions : { toll : false, tunnel : false, bridge : false }, routeOptions : {}, autocompleteOptions : {}, layerDescription : { title : "Itinéraire", description : "Itinéraire basé sur un graphe" } }; // merge with user options Utils.assign(this.options, options); // cas particulier des markers par défaut var defaultMarkersOpts = { departure : { url : Markers["red"], offset : Markers.defaultOffset }, stages : { url : Markers["lightOrange"], offset : Markers.defaultOffset }, arrival : { url : Markers["darkOrange"], offset : Markers.defaultOffset } }; // on récupère les options de chaque type de marker si spécifié this.options.markersOpts = Utils.assign(defaultMarkersOpts, options.markersOpts); /** {Boolean} specify if Route control is collapsed (true) or not (false) */ this.collapsed = this.options.collapsed; /** {Boolean} specify if Route control is draggable (true) or not (false) */ this.draggable = this.options.draggable; this._uid = SelectorID.generate(); // containers principaux this._panelRouteContainer = null; this._panelHeaderRouteContainer = null; this._waitingContainer = null; this._formRouteContainer = null; this._resultsRouteContainer = null; this._showRouteExclusionsElement = null; // liste de points selectionnée this._currentPoints = []; // Mode de transport selectionné : 'Voiture' ou 'Pieton' this._currentTransport = null; this._initTransport(); // Mode de calcul selectionné : 'Plus rapide' ou 'plus court' this._currentComputation = null; this._initComputation(); // Exclusions selectionnées : Tunnel, Toll et Bridge this._currentExclusions = []; this._initExclusions(); // si un calcul est en cours ou non this._waiting = false; // timer pour cacher la patience après un certain temps this._timer = null; // la geometrie du parcours this._geojsonRoute = null; // la geometrie des troncons this._geojsonSections = null; // la geometrie des troncons au format GeoJSON this._geojsonObject = null; // bouton export this.export = null; // le container de la popup (pour les troncons selectionnés) this._popupContent = null; this._popupDiv = this._initPopupDiv(); // l'overlay ol.Overlay correspondant à la popup (pour les troncons selectionnés) this._popupOverlay = null; // ol.interaction.Select associées à la couche des résultats (troncons) this._resultsSelectInteraction = null; this._resultsHoverInteraction = null; // styles pour les sélections des features this._defaultFeatureStyle = new Style({ stroke : new Stroke({ color : "rgba(0,183,152,0.9)", width : 12 }) }); this._selectedFeatureStyle = new Style({ stroke : new Stroke({ color : "rgba(255,102,0,0.9)", width : 12 }) }); // reponse du service // Ex. { // totalTime, totalDistance, bbox, routeGeometry, // routeInstructions : [{duration, distance, code, instruction, bbox, geometry}] // } this._currentRouteInformations = null; // liste des ressources avec droits par service // Ex. { // "Route" : { // key : "ger4g456re45er456t4er5ge5", // resources : ["Pieton", "Voiture"] // } // } this._resources = {}; // listener key for event on pointermove or moveend map this.listenerKey = null; }; /** * this method is called by this.initialize() * * @param {Object} options - options * * @private */ Route.prototype._checkInputOptions = function (options) { // vérification des options // mode de transport if (options.graphs) { // on ne permet pas de passer un tableau vide : on spécifie au moins un graph if (Array.isArray(options.graphs) && options.graphs.length) { for (var i = 0; i < options.graphs.length; i++) { if (typeof options.graphs[i] === "string") { if (options.graphs[i].toLowerCase() === "pieton") { options.graphs[i] = "Pieton"; } if (options.graphs[i].toLowerCase() === "voiture") { options.graphs[i] = "Voiture"; } } else { logger.log("[ol.control.Route] ERROR : parameter 'graphs' elements should be of type 'string'"); options.graphs[i] = null; } } } else { logger.warn("'graphs' parameter should be an array"); options.graphs = null; } } // collapsed if (options.collapsed === "true") { options.collapsed = true; } if (options.collapsed === "false") { options.collapsed = false; } }; /** * initialize component container (DOM) * * @param {Object} map - the map * * @returns {DOMElement} DOM element * * @private */ Route.prototype._initContainer = function (map) { // get main container var container = this._container; var inputShow = this._showRouteContainer = this._createShowRouteElement(); container.appendChild(inputShow); // mode "collapsed" if (!this.collapsed) { inputShow.checked = true; } var picto = this._createShowRoutePictoElement(); container.appendChild(picto); var routePanel = this._panelRouteContainer = this._createRoutePanelElement(); // header form var routeHeader = this._panelHeaderRouteContainer = this._createRoutePanelHeaderElement(); routePanel.appendChild(routeHeader); // form var routeForm = this._formRouteContainer = this._createRoutePanelFormElement(); // form: menu des points var points = this._createRoutePanelFormPointsElement(map); for (var i = 0; i < points.length; i++) { routeForm.appendChild(points[i]); } // form: menu des modes var choice = this._createRoutePanelFormModeChoiceElement(); choice.appendChild(this._createRoutePanelFormModeChoiceTransportElement(this.options.graphs)); choice.appendChild(this._createRoutePanelFormModeChoiceComputeElement()); routeForm.appendChild(choice); // form: menu des exclusions routeForm.appendChild(this._createShowRouteExclusionsElement()); this._showRouteExclusionsElement = this._createShowRouteExclusionsPictoElement(); routeForm.appendChild(this._showRouteExclusionsElement); var exclusion = this._createRoutePanelFormExclusionsElement(); exclusion.appendChild(this._createRoutePanelFormExclusionOptionsElement(this.options.exclusions)); routeForm.appendChild(exclusion); var divReset = this._createRouteFormResetElement(); routeForm.appendChild(divReset); // form: bouton du calcul var submit = this._createRouteSubmitFormElement(); routeForm.appendChild(submit); routePanel.appendChild(routeForm); // results var routeResults = this._resultsRouteContainer = this._createRoutePanelResultsElement(); routePanel.appendChild(routeResults); // waiting var waiting = this._waitingContainer = this._createRouteWaitingElement(); routePanel.appendChild(waiting); container.appendChild(routePanel); // hide autocomplete suggested locations on container click if (container.addEventListener) { container.addEventListener("click", (e) => this._hideRouteSuggestedLocations(e)); } return container; }; // ################################################################### // // ####################### init application ########################## // // ################################################################### // /** * this method is called by the constructor and initialize transport mode * ("Voiture" ou "Pieton") * * @private */ Route.prototype._initTransport = function () { // Mode de transport selectionné this._currentTransport = "Voiture"; // par defaut // par defaut var transport = this.options.graphs; if (!transport || transport.length === 0) { this.options.graphs = ["Voiture", "Pieton"]; } // option if (Array.isArray(transport) && transport.length) { // FIXME pb si le 1er graphe n'est pas une ressource connue ! if (transport[0] === "Voiture" || transport[0] === "Pieton") { this._currentTransport = transport[0]; } } // TODO option sur le service var serviceOptions = this.options.routeOptions; if (serviceOptions.graph) { this._currentTransport = serviceOptions.graph; } }; /** * this method is called by the constructor and initialize computation mode * (fastest or shortest) * * @private */ Route.prototype._initComputation = function () { // Mode de calcul selectionné this._currentComputation = "fastest"; // par defaut // TODO option sur le service var serviceOptions = this.options.routeOptions; if (serviceOptions.routePreference) { this._currentComputation = serviceOptions.routePreference; } }; /** * this method is called by the constructor and initialize exclusions * * @private */ Route.prototype._initExclusions = function () { // Exclusions selectionnées : Tunnel, Toll et Bridge this._currentExclusions = []; // par defaut // par defaut var exclusion = this.options.exclusions; if (!exclusion || (typeof exclusion === "object" && Object.keys(exclusion).length === 0)) { this.options.exclusions = { toll : false, tunnel : false, bridge : false }; } // option if (exclusion && typeof exclusion === "object" && Object.keys(exclusion).length) { for (var k in exclusion) { if (exclusion.hasOwnProperty(k)) { if (exclusion[k]) { this._currentExclusions.push(k); } } } } // TODO option sur le service var serviceOptions = this.options.routeOptions; if (Array.isArray(serviceOptions.exclusions)) { this._currentExclusions = serviceOptions.exclusions; } }; /** * this method is called by this.initialize() and initialize popup div * (to display results information on route result click) * * @return {Object} element - DOM element for popup * @private */ Route.prototype._initPopupDiv = function () { var context = this; var element = document.createElement("div"); element.className = "gp-feature-info-div"; var closer = document.createElement("input"); closer.type = "button"; closer.className = "gp-styling-button closer"; // on closer click : remove popup closer.onclick = function () { if (context._popupOverlay != null) { context._popupOverlay.setPosition(undefined); } return false; }; this._popupContent = document.createElement("div"); this._popupContent.className = "gp-features-content-div"; element.appendChild(this._popupContent); element.appendChild(closer); return element; }; // ################################################################### // // ############################## DOM ################################ // // ################################################################### // /** * Create List Points * Overwrite RouteDOM method ! * * @param {Object} map - the map * * @returns {Array} List DOM element * @private */ Route.prototype._createRoutePanelFormPointsElement = function (map) { var points = []; var count = 1; // point de depart var start = new LocationSelector({ apiKey : this.options.apiKey || null, tag : { id : count, groupId : this._uid, markerOpts : this.options.markersOpts["departure"], label : "Départ", display : true }, autocompleteOptions : this.options.autocompleteOptions || null }); start.setMap(map); // on ajoute des écouteurs d'évènements (en plus de ceux de LocationSelector), // pour prendre en compte les CSS spécifiques de GProuteForm this._addFormPointsEventListeners(start); points.push(start._container); this._currentPoints.push(start); // points intermediaires for (count = 2; count < 7; count++) { var step = new LocationSelector({ apiKey : this.options.apiKey || null, tag : { id : count, groupId : this._uid, label : "Etape", markerOpts : this.options.markersOpts["stages"], display : false, removeOption : true }, autocompleteOptions : this.options.autocompleteOptions || null }); step.setMap(map); this._addFormPointsEventListeners(step); points.push(step._container); this._currentPoints.push(step); } // point d'arrivée var end = new LocationSelector({ apiKey : this.options.apiKey || null, tag : { id : count, groupId : this._uid, markerOpts : this.options.markersOpts["arrival"], label : "Arrivée", display : true, addOption : true }, autocompleteOptions : this.options.autocompleteOptions || null }); end.setMap(map); this._addFormPointsEventListeners(end); points.push(end._container); this._currentPoints.push(end); return points; }; /** * Attach events listeners to route form points (locationSelector) * * @param {Object} formPoint - route form point (locationSelector) * @private */ Route.prototype._addFormPointsEventListeners = function (formPoint) { if (!formPoint) { return; } if (formPoint._inputLabelContainer.addEventListener) { // display form on origin label click formPoint._inputLabelContainer.addEventListener( "click", (e) => this.onRouteOriginLabelClick(e) ); // minimize form on input show pointer, and set map event listeners (see this.onRouteOriginPointerClick) formPoint._inputShowPointer.addEventListener( "click", (e) => this.onRouteOriginPointerClick(e, formPoint) ); if (formPoint._removePointElement) { formPoint._removePointElement.addEventListener( "click", (e) => { logger.trace("click on _removePointElement", e); // Moving up exclusions picto // var exclusionsPictoTop = context._showRouteExclusionsElement.style.top; // context._showRouteExclusionsElement.style.top = (parseInt(exclusionsPictoTop, 10) - 33).toString() + "px"; } ); } if (formPoint._addPointElement) { formPoint._addPointElement.addEventListener( "click", (e) => { logger.trace("click on _addPointElement", e); // Moving down exclusions picto // var exclusionsPictoTop = context._showRouteExclusionsElement.style.top; // context._showRouteExclusionsElement.style.top = (parseInt(exclusionsPictoTop, 10) + 33).toString() + "px"; } ); } } else if (formPoint._inputLabelContainer.attachEvent) { // attachEvent: Internet explorer event listeners management formPoint._inputLabelContainer.attachEvent( "onclick", (e) => this.onRouteOriginLabelClick(e) ); formPoint._inputShowPointer.attachEvent( "onclick", (e) => this.onRouteOriginPointerClick(e, formPoint) ); if (formPoint._removePointElement) { formPoint._removePointElement.attachEvent( "onclick", (e) => { // Moving up exclusions picto // var exclusionsPictoTop = context._showRouteExclusionsElement.style.top; // context._showRouteExclusionsElement.style.top = (parseInt(exclusionsPictoTop, 10) - 33).toString() + "px"; } ); } if (formPoint._addPointElement) { formPoint._addPointElement.attachEvent( "onclick", (e) => { // Moving down exclusions picto // var exclusionsPictoTop = context._showRouteExclusionsElement.style.top; // context._showRouteExclusionsElement.style.top = (parseInt(exclusionsPictoTop, 10) + 33).toString() + "px"; } ); } } }; // ################################################################### // // ####################### handlers events to dom #################### // // ################################################################### // /** * this method is called by event 'submit' on 'GProuteForm' tag form * (cf. this._createRoutePanelFormElement), and it displays the results. * * @param {Object} options - options * @private */ Route.prototype.onRouteComputationSubmit = function (options) { logger.log("onRouteComputationSubmit", options); // FIXME on lance une requête en EPSG:4326, les coordonnées // doivent donc être du type cad en lat/lon. // or, BUG du service du calcul d'itineraire car les // coordonnées envoyées doivent être en lon/lat avec une SRS en EPSG:4326 !? // sinon, ça plante... // Liste des points var points = this._currentPoints; // - point de depart (info: points[0].getCoordinate est du type [lon, lat], en EPSG:4326) var start; if (points[0] && points[0].getCoordinate) { var startCoordinate = points[0].getCoordinate(); start = { x : startCoordinate[0], y : startCoordinate[1] }; logger.log("start", start); } // - point d'arrivée var end; var endPoint = points[points.length - 1]; if (endPoint && endPoint.getCoordinate) { var endCoordinate = endPoint.getCoordinate(); end = { x : endCoordinate[0], y : endCoordinate[1] }; logger.log("end", end); } // - les étapes var step = []; for (var i = 1; i < points.length - 1; i++) { if (points[i] && points[i].getCoordinate) { var iCoordinate = points[i].getCoordinate(); if (iCoordinate) { var coordinate = { x : iCoordinate[0], y : iCoordinate[1] }; logger.log("step", coordinate); step.push(coordinate); } } } // valeurs selectionnées this._currentTransport = options.transport; this._currentComputation = options.computation; this._currentExclusions = options.exclusions; // on recupere les éventuelles options du service passées par l'utilisateur var routeOptions = this.options.routeOptions; // OVERLOAD : la resource bd-topo-osrm ne gère pas le calcul piéton en mode fastest // dans ce cas, on utilise valhalla dans le cas d'une utilisation par défaut du widget // sans paramétrage de resource explicitement demandé var routeResource; if (!routeOptions.resource) { if (this._currentComputation === "fastest" && this._currentTransport === "Pieton") { routeResource = "bdtopo-valhalla"; } } else { routeResource = routeOptions.resource; } // gestion du protocole et du timeout // le timeout est indispensable sur le protocole JSONP. var _protocol = routeOptions.protocol || "XHR"; var _timeout = routeOptions.timeOut || 0; if (_protocol === "JSONP" && _timeout === 0) { // FIXME le timeout est obligatoire pour ce type de protocole... _timeout = 15000; } // gestion des callback var bOnFailure = !!(routeOptions.onFailure !== null && typeof routeOptions.onFailure === "function"); // cast variable to boolean var bOnSuccess = !!(routeOptions.onSuccess !== null && typeof routeOptions.onSuccess === "function"); // on met en place l'affichage des resultats dans la fenetre de resultats. var context = this; this._requestRouting({ startPoint : start, endPoint : end, viaPoints : step, graph : routeOptions.graph || this._currentTransport, routePreference : routeOptions.routePreference || this._currentComputation, exclusions : routeOptions.exclusions || this._currentExclusions, geometryInInstructions : true, distanceUnit : "m", timeOut : _timeout, protocol : _protocol, resource : routeResource, // callback onSuccess onSuccess : function (results) { logger.log(results); if (results) { context._fillRouteResultsDetails(results); } if (bOnSuccess) { routeOptions.onSuccess.call(context, results); } }, // callback onFailure onFailure : function (error) { context._hideWaitingContainer(); context._clearRouteResultsDetails(); logger.log(error.message); if (bOnFailure) { routeOptions.onFailure.call(context, error); } } }); }; /** * this method is called by event 'click' on 'GPlocationOriginLabel' label * and set 'GProuteForm' CSS class to "" (normal) * * @param {Object} routeControl - context : route Control (this) * @private */ Route.prototype.onRouteOriginLabelClick = function () { this._formRouteContainer.className = ""; // on désactive l'écouteur d'événements sur la carte (pour ne pas placer un marker au clic) // map.un( // "click", // () => { // // on ne rétablit pas le mode "normal" si on est dans le panel des résultats (où className = "GProuteComponentHidden") // if (this._formRouteContainer.className === "GProuteFormMini") { // this._formRouteContainer.className = ""; // } // } // ); olObservableUnByKey(this.listenerKey); this.dispatchEvent("route:drawend"); }; /** * this method is called by event 'click' on 'GPlocationOriginPointerImg' label * and display or minimize 'GProuteForm', using CSS class ("GProuteFormMini" or "") * * @param {Object} e - context : route Control (equivalent to this) * @param {Object} locationSelector - context : locationSelector input (one of this._currentPoints) * @private */ Route.prototype.onRouteOriginPointerClick = function (e, locationSelector) { var map = this.getMap(); if (locationSelector._inputShowPointerContainer.checked) { // au click sur l'input pour pointer sur la carte: on minimise le formulaire this._formRouteContainer.className = "GProuteFormMini"; // et au clic sur la carte, on réaffichera le formulaire "normal" this.listenerKey = map.on( "click", () => { // on ne rétablit pas le mode "normal" si on est dans le panel des résultats (où className = "GProuteComponentHidden") if (this._formRouteContainer.className === "GProuteFormMini") { this._formRouteContainer.className = ""; } olObservableUnByKey(this.listenerKey); /** * event triggered at the end of drawing input * * @event route:drawend */ this.dispatchEvent("route:drawend"); } ); /** * event triggered at the start of drawing input * * @event route:drawstart */ this.dispatchEvent("route:drawstart"); } else { // si on déselectionne le pointer, on rétablit le formulaire en mode normal this._formRouteContainer.className = ""; // et on enlève l'écouteur d'évènement sur la carte // map.un( // "click", // () => { // // on ne rétablit pas le mode "normal" si on est dans le panel des résultats (où className = "GProuteComponentHidden") // if (this._formRouteContainer.className === "GProuteFormMini") { // this._formRouteContainer.className = ""; // } // } // ); olObservableUnByKey(this.listenerKey); this.dispatchEvent("route:drawend"); } }; /** * this method is called by event 'click' on 'GPshowRoutePicto' * tag label (cf. this._createShowRoutePictoElement), * and it cleans all value of input. * * @param {Object} e - HTMLElement * @private */ Route.prototype.onShowRoutePanelClick = function (e) { var map = this.getMap(); // on supprime toutes les interactions Interactions.unset(map); // clean ! if (!this._geojsonSections && !this._waiting) { this._clear(); } this.collapsed = document.getElementById("GPshowRoute-" + this._uid).checked; // on génère nous même l'evenement OpenLayers de changement de pté // (utiliser ol.control.Route.on("change:collapsed", function ) pour s'abonner à cet évènement) this.dispatchEvent("change:collapsed"); }; /** * this method is called by event 'change' on 'GProuteComputationSelect' tag select * (cf. this._createRoutePanelFormModeChoiceComputeElement). * this value is saved as a parameter for the service route. * * @param {Object} e - HTMLElement * @private */ Route.prototype.onRouteModeComputationChange = function (e) { var idx = e.target.selectedIndex; var value = e.target.options[idx].value; if (!value) { return; } logger.log(value); this._currentComputation = value; }; /** * this method is called by event 'change' on 'GProuteResultsComputationSelect' tag select * (cf. this._createRouteResultsElement). * this value is saved as a parameter for the service route, * and this launches the route request ! * * @param {Object} e - HTMLElement * @private */ Route.prototype.onRouteModeComputationChangeAndRun = function (e) { // event choice computation this.onRouteModeComputationChange(e); // clean avant un nouveau calcul ! this._clearRouteResultsDetails(); this._clearRouteResultsGeometry(); this._clearRouteResultsFeatureGeometry(); // submit request this.onRouteComputationSubmit({ computation : this._currentComputation, transport : this._currentTransport, exclusions : this._currentExclusions }); }; /** * this method is called by event 'change' on 'GProuteTransportCar' or 'GProuteTransportPedestrian' tag input * (cf. this._createRoutePanelFormModeChoiceTransportElement). * this value is saved as a parameter for the service route. * * @param {Object} e - HTMLElement * @private */ Route.prototype.onRouteModeTransportChange = function (e) { var value = e.target.value; if (!value) { return; } this._currentTransport = value; }; /** * TODO this method is called by event 'click' on 'GPshowRouteExclusionsPicto' tag input * (cf. this._createShowRouteExclusionsPictoElement), and it displays the panel options of exclusions. * * @param {Object} e - HTMLElement * @private */ Route.prototype.onShowRouteExclusionsClick = function (e) { logger.log("onShowRouteExclusionsClick", e); // FIXME not use ?! }; /** * this method is called by event 'change' on 'GProuteExclusionsToll' * or 'GProuteExclusionsTunnel' or 'GProuteExclusionsBridge' tag input * (cf. this._createRoutePanelFormExclusionOptionsElement). * this value is saved as a parameter for the service route. * * @param {Object} e - HTMLElement * @private */ Route.prototype.onRouteExclusionsChange = function (e) { var value = e.target.value; var checked = e.target.checked;