geoportal-extensions-openlayers
Version:

1,316 lines (1,180 loc) • 61.7 kB
JavaScript
// import CSS
import "../CSS/Controls/Isochrone/GPisochronOpenLayers.css";
// import OpenLayers
import Control from "ol/control/Control";
import { unByKey as olObservableUnByKey } from "ol/Observable";
import VectorLayer from "ol/layer/Vector";
import VectorSource from "ol/source/Vector";
// import GeoJSON from "ol/format/GeoJSON";
import {
Fill,
Stroke,
Style
} from "ol/style";
// import geoportal library access
import Gp from "geoportal-access-lib";
// import local
import Utils from "../../Common/Utils";
import Logger from "../../Common/Utils/LoggerByDefault";
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 LayerSwitcher from "./LayerSwitcher";
import LocationSelector from "./LocationSelector";
import ButtonExport from "./Export";
import GeoJSONExtended from "../Formats/GeoJSON";
// DOM
import IsoDOM from "../../Common/Controls/IsoDOM";
var logger = Logger.getLogger("isocurve");
/**
* @classdesc
*
* Isocurve Control.
*
* @constructor
* @alias ol.control.Isocurve
* @type {ol.control.Isocurve}
* @extends {ol.control.Control}
* @param {Object} options - Isocurve control options
* @param {String} [options.apiKey] - API key for services call (isocurve 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 graph resources to be used for isocurve calculation, by default : ["Voiture", "Pieton"]. Possible values are "Voiture" and "Pieton". The first element is selected.
* @param {Array} [options.methods = ["time", "distance"]] - list of methods, by default : ["time", "distance"]. Possible values are "time" and "distance". The first element is selected by default.
* @param {Array} [options.directions = ["departure", "arrival"]] - list of directions to be displayed, by default : ["departure", "arrival"]. The first element is selected by default. Possible values are "departure" and "arrival".
* Directions enable to specify if input location point will be used as a departure point ("departure") or as an arrival point ("arrival")
* @param {Object} [options.isocurveOptions = {}] - isocurve service options. see {@link http://ignf.github.io/geoportal-access-lib/latest/jsdoc/module-Services.html#~isoCurve Gp.Services.isoCurve()} to know all isocurve 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.markerOpts] - options to use your own marker. Default is a lightOrange marker.
* @param {String} [options.markerOpts.url] - marker base64 encoded url (ex "data:image/png;base64,...""). Mandatory for a custom marker
* @param {Array} [options.markerOpts.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 = "Isochrone/Isodistance"] - Layer title to be displayed in LayerSwitcher
* @param {String} [options.layerDescription.description = "isochrone/isodistance basé sur un graphe"] - Layer description to be displayed in LayerSwitcher
* @fires isocurve:drawstart
* @fires isocurve:drawend
* @fires isocurve:compute
* @fires export:compute
* @example
* var iso = ol.control.Isocurve({
* "collapsed" : false,
* "draggable" : true,
* "export" : false,
* "methods" : ["time", "distance"],
* "exclusions" : {
* "toll" : true,
* "bridge" : false,
* "tunnel" : true
* },
* "graphs" : ["Pieton", "Voiture"],
* "markerOpts" : {
* "url" : "...",
* "offset" : [0,0]
* }
* "isocurveOptions" : {},
* "autocompleteOptions" : {}
* });
*
* // if you want to pluggued the control Export with options :
* var iso = new ol.control.Isocurve({
* export : {
* name : "export",
* format : "geojson",
* title : "Exporter",
* menu : false
* }
* });
*/
var Isocurve = (function (Control) {
/**
* See {@link ol.control.Isocurve}
* @module Isocurve
* @alias module:~Controls/Isocurve
* @param {*} options - options
* @example
* import Isocurve from "src/OpenLayers/Controls/Isocurve"
*/
function Isocurve (options) {
options = options || {};
if (!(this instanceof Isocurve)) {
throw new TypeError("ERROR CLASS_CONSTRUCTOR");
}
// initialisation du composant
this.initialize(options);
// // Widget main DOM container
this._container = this._createMainContainerElement();
// info: le container sera complété lors de l'ajout à la carte (setMap), car certains composants nécessitent d'être liés à la map.
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) Isocurve.__proto__ = Control;
/**
* @lends module:Isocurve
*/
Isocurve.prototype = Object.create(Control.prototype, {});
// on récupère les méthodes de la classe commune IsoDOM
Utils.assign(Isocurve.prototype, IsoDOM);
/**
* Constructor (alias)
*
* @private
*/
Isocurve.prototype.constructor = Isocurve;
/**
* Overwrite OpenLayers setMap method
*
* @param {ol.Map} map - Map.
*/
Isocurve.prototype.setMap = function (map) {
if (map) {
// enrichissement du DOM du container lors de l'ajout à la carte
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._IsoPanelContainer,
this._IsoPanelHeaderContainer,
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
*/
Isocurve.prototype.getCollapsed = function () {
return this.collapsed;
};
/**
* Collapse or display widget main container
*
* @param {Boolean} collapsed - True to collapse widget, False to display it
*/
Isocurve.prototype.setCollapsed = function (collapsed) {
if (collapsed === undefined) {
logger.log("[ERROR] Isocurve:setCollapsed - missing collapsed parameter");
return;
}
if ((collapsed && this.collapsed) || (!collapsed && !this.collapsed)) {
return;
}
if (collapsed) {
document.getElementById("GPisochronPanelClose-" + this._uid).click();
} else {
document.getElementById("GPshowIsochronPicto-" + this._uid).click();
}
this.collapsed = collapsed;
};
/**
* Get vector layer where Isocurve geometry is drawn
*
* @returns {Object} layer - ol.layer.Vector isocurve layer
*/
Isocurve.prototype.getLayer = function () {
return this._geojsonLayer;
};
/**
* Set vector layer where Isocurve geometry is drawn
*
* @param {Object} layer - ol.layer.Vector isocurve layer
*/
Isocurve.prototype.setLayer = function (layer) {
if (!layer) {
this._geojsonLayer = 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._geojsonLayer = layer;
};
/**
* Get vector layer
*
* @returns {String} geojson - GeoJSON format layer
*/
Isocurve.prototype.getGeoJSON = function () {
return JSON.stringify(this._geojsonObject);
};
/**
* Set vector layer
*
* @param {String} geojson - GeoJSON format layer
*/
Isocurve.prototype.setGeoJSON = function (geojson) {
try {
this._geojsonObject = JSON.parse(geojson);
} catch (e) {
logger.log("no valid geojson given :" + e.message);
}
};
/**
* Get isocurve data
*
* @returns {Object} data - process results
*/
Isocurve.prototype.getData = function () {
var data = {
type : "isocurve",
transport : this._currentTransport,
computation : this._currentComputation,
exclusions : this._currentExclusions,
direction : this._currentDirection,
point : this._originPoint.getCoordinate(), // lon/lat wgs84
results : {}
};
Utils.assign(data.results, this._currentIsoResults);
return data;
};
/**
* Set isocurve 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 {String} data.direction - direction type
* @param {Array} data.point - [lon, lat]
* @param {Object} data.results - service response
*/
Isocurve.prototype.setData = function (data) {
this._currentTransport = data.transport;
this._currentComputation = data.computation;
this._currentExclusions = data.exclusions;
this._currentDirection = data.direction;
// INFO
// > this._originPoint.clear();
// l'utilisation de cette méthode declenche des evenements qui retirent la couche en cours !
// (cf. _createIsoPanelFormPointElement),
var inputPointer = document.getElementById("GPlocationOriginPointer_" + 1 + "-" + this._uid);
inputPointer.checked = true;
var inputCoords = document.getElementById("GPlocationOriginCoords_" + 1 + "-" + this._uid);
inputCoords.value = "";
this._originPoint.setCoordinate(data.point, "EPSG:4326");
this._currentIsoResults = data.results;
};
/**
* Get container
*
* @returns {DOMElement} container
*/
Isocurve.prototype.getContainer = function () {
return this._container;
};
/**
* Get default style
*
* @returns {ol.style} style
*/
Isocurve.prototype.getStyle = function () {
return this._defaultFeatureStyle;
};
/**
* This method is public.
* It allows to control the execution of a traitment.
*
* @param {Array} position - position in the projection map [ x, y ]
* @param {Object} value - distance in km or hours-minutes
* @param {Object} options - options = {...}
*/
Isocurve.prototype.compute = function (position, value, options) {
this._clear();
if (!this._showIsoContainer.checked) {
this._pictoIsoContainer.click();
}
var map = this.getMap();
if (!map) {
return;
}
// Les options par defauts
var settings = {
direction : "departure",
method : "time",
transport : "Voiture",
exclusions : []
};
// On recupere les options
Utils.assign(settings, options);
this._originPoint.setCoordinate(position);
var coordinate = this._originPoint.getCoordinate();
var input = document.getElementById("GPlocationOrigin_" + 1 + "-" + this._uid);
input.value = coordinate[0].toFixed(4) + " / " + coordinate[1].toFixed(4);
this._currentTransport = settings.transport;
if (settings.transport === "Voiture") {
document.getElementById("GPisochronTransportCar-" + this._uid).checked = true;
} else {
document.getElementById("GPisochronTransportPedestrian-" + this._uid).checked = true;
}
this._currentExclusions = settings.exclusions;
this._currentComputation = settings.method;
if (settings.method === "time") {
var time = value.split(".");
this._currentTimeHour = time[0] || 0;
document.getElementById("GPisochronValueChronInput1-" + this._uid).value = this._currentTimeHour;
this._currentTimeMinute = time[1] || 0;
document.getElementById("GPisochronValueChronInput2-" + this._uid).value = this._currentTimeMinute;
document.getElementById("GPisochronChoiceAltChron-" + this._uid).click();
} else {
this._currentDistance = value;
document.getElementById("GPisochronValueDistInput-" + this._uid).value = this._currentDistance;
document.getElementById("GPisochronChoiceAltDist-" + this._uid).click();
}
this._currentDirection = settings.direction;
(settings.direction === "departure")
? document.getElementById("GPisochronDirectionSelect-" + this._uid).selectedIndex = 0 : document.getElementById("GPisochronDirectionSelect-" + this._uid).selectedIndex = 1;
this.onIsoComputationSubmit();
};
/**
* This method is public.
* It allows to init the control.
*/
Isocurve.prototype.init = function () {
// point
var coordinate = this._originPoint.getCoordinate();
var input = document.getElementById("GPlocationOrigin_" + 1 + "-" + this._uid);
input.value = coordinate[1].toFixed(4) + " / " + coordinate[0].toFixed(4);
// transport
if (this._currentTransport === "Voiture") {
document.getElementById("GPisochronTransportCar-" + this._uid).checked = true;
} else {
document.getElementById("GPisochronTransportPedestrian-" + this._uid).checked = true;
}
// method
if (this._currentComputation === "time") {
var minutes = this._currentIsoResults.time / 60;
this._currentTimeHour = Math.floor(minutes / 60);
document.getElementById("GPisochronValueChronInput1-" + this._uid).value = this._currentTimeHour;
this._currentTimeMinute = Math.round(((minutes / 60) - this._currentTimeHour) * 60);
document.getElementById("GPisochronValueChronInput2-" + this._uid).value = this._currentTimeMinute;
document.getElementById("GPisochronChoiceAltChron-" + this._uid).click();
} else {
this._currentDistance = this._currentIsoResults.distance / 1000;
document.getElementById("GPisochronValueDistInput-" + this._uid).value = this._currentDistance;
document.getElementById("GPisochronChoiceAltDist-" + this._uid).click();
}
// direction
(this._currentDirection === "departure")
? document.getElementById("GPisochronDirectionSelect-" + this._uid).selectedIndex = 0 : document.getElementById("GPisochronDirectionSelect-" + this._uid).selectedIndex = 1;
};
/**
* Clean UI : reinit control
*/
Isocurve.prototype.clean = function () {
this._clearIsoInputs();
// INFO
// le comportement est surchargé, ceci supprime la couche !?
// cf. _createIsoPanelFormPointElement()
this._originPoint.clearResults();
document.getElementById("GPlocationPoint_1-" + this._uid).style.cssText = "";
document.getElementById("GPlocationOriginCoords_1-" + this._uid).value = "";
document.getElementById("GPlocationOrigin_1-" + this._uid).value = "";
document.getElementById("GPlocationPoint_1-" + this._uid).style.cssText = "";
document.getElementById("GPlocationOriginPointer_1-" + this._uid).checked = false;
document.getElementById("GPlocationOrigin_1-" + this._uid).className = "GPlocationOriginVisible";
document.getElementById("GPlocationOriginCoords_1-" + this._uid).className = "GPlocationOriginHidden";
this._currentIsoResults = null;
this.setLayer();
};
// ################################################################### //
// ##################### init component ############################## //
// ################################################################### //
/**
* Initialize Isocurve control (called by Isocurve constructor)
*
* @param {Object} options - constructor options
* @private
*/
Isocurve.prototype.initialize = function (options) {
this._checkInputOptions(options);
// set default options
this.options = {
collapsed : true,
draggable : false,
export : false,
methods : ["time", "distance"],
graphs : ["Voiture", "Pieton"],
exclusions : {
toll : false,
tunnel : false,
bridge : false
},
directions : ["departure", "arrival"],
markerOpts : {
url : Markers["lightOrange"],
offset : Markers.defaultOffset
},
isocurveOptions : {},
autocompleteOptions : {},
layerDescription : {
title : "Isochrone/Isodistance",
description : "isochrone/isodistance basé sur un graphe"
}
};
// merge with user options
Utils.assign(this.options, options);
/** {Boolean} specify if isocurve control is collapsed (true) or not (false) */
this.collapsed = this.options.collapsed;
/** {Boolean} specify if isocurve control is draggable (true) or not (false) */
this.draggable = this.options.draggable;
// identifiant du contrôle : utile pour suffixer les identifiants CSS (pour gérer le cas où il y en a plusieurs dans la même page)
this._uid = SelectorID.generate();
// Options du service paramétrables via l'interface (graph, method, exclusions)
// Mode de transport selectionné : 'Voiture' ou 'Pieton'
this._currentTransport = null;
this._initTransport();
// Mode de calcul selectionné : 'time' (isochron) ou 'distance' (isodistance)
this._currentComputation = null;
this._initComputation();
// Exclusions selectionnées : Tunnel, Toll et Bridge
this._currentExclusions = [];
this._initExclusions();
// sens de parcours : "departure" ou "arrival"
this._currentDirection = null;
this._initDirection();
// point de saisie
this._originPoint = null;
// // containers principaux
this._showIsoContainer = null;
this._pictoIsoContainer = null;
this._waitingContainer = null;
this._formContainer = null;
this._IsoPanelContainer = null;
this._IsoPanelHeaderContainer = null;
// les résultats du calcul
this._currentIsoResults = null;
// la géométrie
this._geojsonLayer = null;
this._geojsonObject = null;
// bouton export
this.export = null;
// si un calcul est en cours ou non
this._waiting = false;
// timer pour cacher la patience après un certain temps
this._timer = null;
// styles pour les sélections des features
this._defaultFeatureStyle = new Style({
fill : new Fill({
color : "rgba(0, 183, 152, 0.7)"
}),
stroke : new Stroke({
color : "rgba(0, 183, 152, 0)",
width : 1
})
});
// liste des ressources avec droits par service
// Ex. {
// "Isocurve" : {
// key : "ger4g456re45er456t4er5ge5",
// resources : ["Pieton", "Voiture"]
// }
// }
this._resources = {};
// listener key for event click on map
this.listenerKey = null;
};
/**
* this method is called by this.initialize()
*
* @param {Object} options - options
*
* @private
*/
Isocurve.prototype._checkInputOptions = function (options) {
// vérification des options
// on ne permet pas de n'afficher aucun mode de calcul ou aucun mode de transport ?
var i;
// modes de calcul
if (options.methods) {
if (Array.isArray(options.methods)) {
// on ne permet pas de passer un tableau vide : on spécifie au moins une méthode
if (options.methods.length === 0) {
options.methods = null;
} else {
for (i = 0; i < options.methods.length; i++) {
if (typeof options.methods[i] !== "string") {
logger.log("[ol.control.Isocurve] ERROR : parameter 'methods' elements should be of type 'string'");
}
}
}
} else {
logger.warn("'methods' parameter should be an array");
options.methods = null;
}
}
// mode de transport
if (options.graphs) {
if (Array.isArray(options.graphs)) {
// on ne permet pas de passer un tableau vide : on spécifie au moins un graph
if (options.graphs.length === 0) {
options.graphs = null;
} else {
for (i = 0; i < options.graphs.length; i++) {
if (typeof options.graphs[i] !== "string") {
logger.log("[ol.control.Isocurve] ERROR : parameter 'graphs' elements should be of type 'string'");
} else {
if (options.graphs[i].toLowerCase() === "pieton") {
options.graphs[i] = "Pieton";
}
if (options.graphs[i].toLowerCase() === "voiture") {
options.graphs[i] = "Voiture";
}
}
}
}
} else {
logger.warn("'graphs' parameter should be an array");
options.graphs = null;
}
}
// sens du parcours
if (options.directions) {
if (Array.isArray(options.directions)) {
// on ne permet pas de passer un tableau vide : on spécifie au moins une direction
if (options.directions.length === 0) {
options.directions = null;
} else {
for (i = 0; i < options.directions.length; i++) {
if (typeof options.directions[i] !== "string") {
logger.log("[ol.control.Isocurve] ERROR : parameter 'directions' elements should be of type 'string'");
}
}
}
} else {
logger.warn("'directions' parameter should be an array");
options.directions = null;
}
}
// collapsed
if (options.collapsed === "true") {
options.collapsed = true;
}
if (options.collapsed === "false") {
options.collapsed = false;
}
};
/**
* this method is called by this.initialize() and initialize transport mode
* ("Voiture" ou "Pieton")
*
* @private
*/
Isocurve.prototype._initTransport = function () {
// Mode de transport selectionné
this._currentTransport = "Voiture"; // par defaut
// par defaut
var transports = this.options.graphs;
if (!transports || transports.length === 0) {
this.options.graphs = ["Voiture", "Pieton"];
}
// option
if (Array.isArray(transports) && transports.length) {
// FIXME pb si le 1er graphe n'est pas une ressource connue !
if (transports[0] === "Voiture" || transports[0] === "Pieton") {
this._currentTransport = transports[0];
}
}
// si l'utilisateur a spécifié un graph dans le service, on surcharge les options du widget
var serviceOptions = this.options.isocurveOptions;
if (serviceOptions.graph) {
this._currentTransport = serviceOptions.graph;
}
};
/**
* this method is called by this.initialize() and initialize computation mode
* (time or distance)
*
* @private
*/
Isocurve.prototype._initComputation = function () {
// Mode de calcul selectionné
this._currentComputation = "time"; // par defaut
// par defaut
var methods = this.options.methods;
if (!methods || methods.length === 0) {
this.options.methods = ["time", "distance"];
}
// option
if (Array.isArray(methods) && methods.length) {
// FIXME pb si le 1er graphe n'est pas une ressource connue !
if (methods[0] === "time" || methods[0] === "distance") {
this._currentComputation = methods[0];
}
}
// si l'utilisateur a spécifié une méthode dans le service, on surcharge les options du widget
var serviceOptions = this.options.isocurveOptions;
if (serviceOptions.method) {
this._currentComputation = serviceOptions.method;
}
if (serviceOptions.time) {
this._currentComputation = "time";
}
if (serviceOptions.distance) {
this._currentComputation = "distance";
}
};
/**
* this method is called by this.initialize() and initialize direction mode
* (departure or arrival)
*
* @private
*/
Isocurve.prototype._initDirection = function () {
// Mode de calcul selectionné
this._currentDirection = "departure"; // par defaut
// par defaut
var directions = this.options.directions;
if (!directions || directions.length === 0) {
this.options.directions = ["departure", "arrival"];
}
// option
if (Array.isArray(directions) && directions.length) {
// FIXME pb si le 1er graphe n'est pas une ressource connue !
if (directions[0] === "departure" || directions[0] === "arrival") {
this._currentDirection = directions[0];
}
}
// si l'utilisateur a spécifié une méthode dans le service, on surcharge les options du widget
var serviceOptions = this.options.isocurveOptions;
if (!serviceOptions.reverse) {
this._currentDirection = "departure";
}
if (serviceOptions.reverse === true) {
this._currentDirection = "arrival";
this.options.directions = ["arrival", "departure"];
}
};
/**
* this method is called by this.initialize() and initialize exclusions
*
* @private
*/
Isocurve.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);
}
}
}
}
// si l'utilisateur a spécifié des exclusions dans le service, on surcharge les options du widget
var serviceOptions = this.options.isocurveOptions;
if (Array.isArray(serviceOptions.exclusions)) {
this._currentExclusions = serviceOptions.exclusions;
}
};
// ################################################################### //
// ######################## DOM initialize ########################### //
// ################################################################### //
/**
* initialize component container (DOM)
*
* @param {Object} map - the map
*
* @returns {DOMElement} DOM element
*
* @private
*/
Isocurve.prototype._initContainer = function (map) {
// get main container
var container = this._container;
var inputShow = this._showIsoContainer = this._createShowIsoElement();
container.appendChild(inputShow);
// mode "collapsed"
if (!this.collapsed) {
inputShow.checked = true;
}
var picto = this._pictoIsoContainer = this._createShowIsoPictoElement();
container.appendChild(picto);
// panneau
var panel = this._IsoPanelContainer = this._createIsoPanelElement();
// header
var header = this._IsoPanelHeaderContainer = this._createIsoPanelHeaderElement();
panel.appendChild(header);
// form
var form = this._formContainer = this._createIsoPanelFormElement();
// form: input de saisie de la localisation (fonction de Isocurve, voir ci-dessous)
var point = this._createIsoPanelFormPointElement(map);
form.appendChild(point);
var isoChronChecked = false;
var isoDistChecked = false;
var typeChoice = this._createIsoPanelFormTypeChoiceElement();
for (var i = 0; i < this.options.methods.length; i++) {
if (this.options.methods[i] === "time") {
isoChronChecked = (i === 0);
typeChoice.appendChild(this._createIsoPanelFormTypeChoiceChronElement(isoChronChecked));
}
if (this.options.methods[i] === "distance") {
isoDistChecked = (i === 0);
typeChoice.appendChild(this._createIsoPanelFormTypeChoiceDistElement(isoDistChecked));
}
}
form.appendChild(typeChoice);
// form: menu du choix des valeurs
form.appendChild(this._createIsoPanelFormValueIsochronElement(isoChronChecked));
form.appendChild(this._createIsoPanelFormValueIsodistanceElement(isoDistChecked));
// form: menu du choix du transport et du sens du parcours
var modeChoice = this._createIsoPanelFormModeChoiceElement();
modeChoice.appendChild(this._createIsoPanelFormModeChoiceTransportElement(this.options.graphs));
// FIXME : doit on passer le paramètre defaultDirection ?
modeChoice.appendChild(this._createIsoPanelFormModeChoiceDirectionElement(this.options.directions));
form.appendChild(modeChoice);
// form: menu des exclusions
if (this.options.exclusions && (typeof this.options.exclusions === "object") && (Object.keys(this.options.exclusions).length !== 0)) {
form.appendChild(this._createShowIsoExclusionsElement());
form.appendChild(this._createShowIsoExclusionsPictoElement());
var exclusion = this._createIsoPanelFormExclusionsElement();
exclusion.appendChild(this._createIsoPanelFormExclusionOptionsElement(this.options.exclusions));
form.appendChild(exclusion);
}
var divReset = this._createIsoFormResetElement();
form.appendChild(divReset);
// form: bouton du calcul
var submit = this._submitContainer = this._createIsoSubmitFormElement();
form.appendChild(submit);
panel.appendChild(form);
// waiting
var waiting = this._waitingContainer = this._createIsoWaitingElement();
panel.appendChild(waiting);
container.appendChild(panel);
// hide autocomplete suggested locations on container click
if (container.addEventListener) {
container.addEventListener("click", (e) => this._hideIsoSuggestedLocations(e));
}
return container;
};
/**
* Create start point
*
* @param {Object} map - the map
*
* @returns {Object} DOM element
* @private
*/
Isocurve.prototype._createIsoPanelFormPointElement = function (map) {
this._originPoint = new LocationSelector({
apiKey : this.options.apiKey || null,
tag : {
id : 1,
groupId : this._uid,
markerOpts : this.options.markerOpts,
label : "Départ",
display : true
},
autocompleteOptions : this.options.autocompleteOptions || null
});
this._originPoint.setMap(map);
// a la sélection d'un nouveau point, on réinitialise aussi le tracé
var self = this;
// click sur le pointer
document.getElementById("GPlocationOriginPointerImg_1-" + this._uid).onclick = function () {
self._clearGeojsonLayer();
var map = self.getMap();
if (self._originPoint._inputShowPointerContainer.checked) {
// au click sur l'input pour pointer sur la carte: on minimise le formulaire
self._formContainer.className = "GPisochronFormMini";
// et au clic sur la carte, on réaffichera le formulaire "normal"
this.listenerKey = map.on(
"click",
() => {
self._formContainer.className = "";
self.dispatchEvent("isocurve:drawend");
}
);
} else {
// si on déselectionne le pointer, on rétablit le formulaire en mode normal
self._formContainer.className = "";
// et on enlève l'écouteur d'évènement sur la carte
// map.un("click", () => { self._formContainer.className = ""; });
olObservableUnByKey(this.listenerKey);
}
/**
* event triggered at the start of drawing input
*
* @event isocurve:drawstart
*/
self.dispatchEvent("isocurve:drawstart");
};
// click sur le label
document.getElementById("GPlocationOriginLabel_1-" + this._uid).onclick = function () {
self._clearGeojsonLayer();
self._formContainer.className = "";
// on désactive l'écouteur d'événements sur la carte (pour ne pas placer un marker au clic)
map.un(
"click",
() => {
self._formContainer.className = "";
}
);
self.dispatchEvent("isocurve:drawend");
};
// click sur la zone de saisie
document.getElementById("GPlocationOrigin_1-" + this._uid).onclick = function () {
self._clearGeojsonLayer();
/**
* event triggered at the end of drawing input
*
* @event isocurve:drawend
*/
self.dispatchEvent("isocurve:drawend");
};
return this._originPoint._container;
};
// ################################################################### //
// ####################### handlers events to dom #################### //
// ################################################################### //
/**
* this method is called by event 'submit' on 'GPisochronForm' tag form
* (cf. this._createIsoPanelFormElement),
* and call isocurve service to display results
*
* @private
*/
Isocurve.prototype.onIsoComputationSubmit = function () {
// si on n'a pas de valeur récupérée pour notre point origine, on ne fait rien
if (!this._originPoint || !this._originPoint.getCoordinate || !this._originPoint.getCoordinate()) {
logger.log("[Isocurve] Missing position parameter to submit isocurve request");
return;
}
// récupération de l'origine
var positionCoordinates = this._originPoint.getCoordinate();
var position = {
x : positionCoordinates[0],
y : positionCoordinates[1]
};
logger.log("origin : ", position);
// récupération du temps ou de la distance
var time;
var distance;
if (this._currentComputation.toLowerCase() === "time") {
var timeHourInput = document.getElementById("GPisochronValueChronInput1-" + this._uid);
var hours = parseInt(timeHourInput.value, 10);
if (isNaN && isNaN(hours)) {
hours = 0;
}
var timeMinutesInput = document.getElementById("GPisochronValueChronInput2-" + this._uid);
var minutes = parseInt(timeMinutesInput.value, 10);
if (isNaN && isNaN(minutes)) {
minutes = 0;
}
// durée exprimée en secondes
time = hours * 3600 + minutes * 60;
logger.log("time : " + time);
}
if (this._currentComputation.toLowerCase() === "distance") {
var distInput = document.getElementById("GPisochronValueDistInput-" + this._uid);
// distance exprimée en mètres
distance = parseFloat(distInput.value) * 1000;
logger.log("distance : " + distance);
}
// si on n'a pas de valeur de calcul renseignée, on ne lance pas la requête.
if (!time && !distance) {
logger.log("[Isocurve] Missing time or distance parameter to submit isocurve request");
return;
}
// on recupere les éventuelles options du service passées par l'utilisateur
var options = this.options.isocurveOptions || {};
// gestion du protocole et du timeout
// le timeout est indispensable sur le protocole JSONP.
var _protocol = options.protocol || "XHR";
var _timeout = options.timeOut || 0;
if (_protocol === "JSONP" && _timeout === 0) {
// FIXME le timeout est obligatoire pour ce type de protocole...
_timeout = 15000;
}
// gestion des callback
var bOnFailure = !!(options.onFailure !== null && typeof options.onFailure === "function"); // cast variable to boolean
var bOnSuccess = !!(options.onSuccess !== null && typeof options.onSuccess === "function");
// on met en place l'affichage des resultats dans la fenetre de resultats.
var context = this;
var isoRequestOptions = {
position : position,
graph : options.graph || this._currentTransport,
exclusions : options.exclusions || this._currentExclusions,
method : options.method || this._currentComputation,
smoothing : options.smoothing || true,
timeOut : _timeout,
protocol : _protocol,
resource : options.resource,
// callback onSuccess
onSuccess : function (results) {
logger.log(results);
if (results) {
context._drawIsoResults(results);
}
if (bOnSuccess) {
options.onSuccess.call(context, results);
}
},
// callback onFailure
onFailure : function (error) {
// FIXME mise à jour du controle mais le service ne repond pas en 200 !?
context._hideWaitingContainer();
logger.log(error.message);
if (bOnFailure) {
options.onFailure.call(context, error);
}
}
};
if ((this._currentDirection.toLowerCase() === "arrival") || (options.reverse)) {
isoRequestOptions.reverse = true;
}
if (time) {
isoRequestOptions.time = time;
}
if (distance) {
isoRequestOptions.distance = distance;
}
this._requestIsoCurve(isoRequestOptions);
};
/**
* this method is called by event 'click' on 'GPshowIsochronPicto' picto
* (cf. this._createShowIsoPictoElement),
* and clear inputs and previous isocurve drawings
*
* @private
*/
Isocurve.prototype.onShowIsoPanelClick = function () {
var map = this.getMap();
// on supprime toutes les interactions
Interactions.unset(map);
this.collapsed = this._showIsoContainer.checked;
// on génère nous même l'evenement OpenLayers de changement de propriété
// (utiliser ol.control.Isocurve.on("change:collapsed", function ) pour s'abonner à cet évènement)
this.dispatchEvent("change:collapsed");
};
/**
* this method is called by event 'change' on 'GPisochronChoiceAltDist' or 'GPisochronChoiceAltChron'
* input (cf. this._createIsoPanelFormTypeChoiceElement),
* and updates current computation mode
*
* @param {Object} e - HTMLElement
* @private
*/
Isocurve.prototype.onIsoTypeChoiceChange = function (e) {
var value = e.target.value;
if (!value) {
return;
}
if (value === "isodistance") {
this._currentComputation = "distance";
}
if (value === "isochron") {
this._currentComputation = "time";
}
};
/**
* this method is called by event 'click' on 'GPisochronTransportPedestrian' or 'GPisochronTransportCar'
* input (cf. this._createIsoPanelFormModeChoiceTransportElement),
* and updates current transport mode
*
* @param {Object} e - HTMLElement
* @private
*/
Isocurve.prototype.onIsoModeTransportChange = function (e) {
var value = e.target.value;
if (!value) {
return;
}
this._currentTransport = value;
};
/**
* this method is called by event 'change' on 'GPisochronDirectionSelect' select
* (cf. this._createIsoPanelFormModeChoiceDirectionElement),
* and updates current direction mode
*
* @param {Object} e - HTMLElement
* @private
*/
Isocurve.prototype.onIsoModeDirectionChange = function (e) {
var value = e.target.value;
if (!value) {
return;
}
if (value.toLowerCase() === "arrival") {
this._originPoint._inputLabelContainer.innerHTML = "Arrivée";
} else {
this._originPoint._inputLabelContainer.innerHTML = "Départ";
}
this._currentDirection = value;
};
/**
* this method is called by event 'change' on 'GPIsoExclusionsToll'
* or 'GPIsoeExclusionsTunnel' or 'GPIsoExclusionsBridge' tag input
* (cf. this._createIsoPanelFormExclusionOptionsElement).
* this value is saved as a parameter for the service isocurve.
*
* @param {Object} e - HTMLElement
* @private
*/
Isocurve.prototype.onIsoExclusionsChange = function (e) {
var value = e.target.value;
var checked = e.target.checked;
if (!value) {
return;
}
var bFound = false;
var iFound = null;
for (var i = 0; i < this._currentExclusions.length; i++) {
if (deepEqual(this._currentExclusions[i], value.toLowerCase())) {
iFound = i;
bFound = true;
}
}
// on l'ajoute si la valeur n'existe pas et est selectionnée
if (!bFound && !checked) {
this._currentExclusions.push(value.toLowerCase());
}
// on la retire si la valeur existe et est deselectionnée
if (bFound && checked) {
this._currentExclusions[iFound] = null;
}
};
/**
* this method is called by event 'click' on 'GPisoReset'
* tag label (cf. this._createIsoFormResetElement),
* and it cleans all isochron input options and results.
*
* @private
*/
Isocurve.prototype.onIsoResetClick = function () {
// clear
this._clear();
};
// ################################################################### //
// ######################## isocurve calculation ##################### //
// ################################################################### //
/**
* this method is called by this.onIsoComputationSubmit
* and executes a request to the service.
*
* @param {Object} options - isocurve service request options
* @private
*/
Isocurve.prototype._requestIsoCurve = function (options) {
// on ne fait pas de requête si on n'a pas renseigné de parametres !
if (!options || ((typeof options === "object") && (Object.keys(options).length === 0))) {
return;
}
// on ne fait pas de requête si on n'a pas de point d'origine
if (!options.position) {
return;
}
// si l'utilisateur a spécifié le paramètre ssl au niveau du control, on s'en sert
// true par défaut (https)
if (typeof options.ssl !== "boolean") {
if (typeof this.options.ssl === "boolean") {
options.ssl = this.options.ssl;
} else {
options.ssl = true;
}
}
logger.log(options);
// on efface une éventuelle précédente couche
this._clearGeojsonLayer();
// mise en place de la patience
this._displayWaitingContainer();
// appel du service de calcul d'isochrones
Gp.Services.isoCurve(options);
};
/**
* this method is called by this.onIsoComputationSubmit (in case of success)
* and draw isocurve results geometry on map
*
* @param {Object} results - isocurve response results
* @private
*/
Isocurve.prototype._drawIsoResults = function (results) {
// sauvegarde de l'etat des resultats
this._currentIsoResults = results;
// cache la patience
this._hideWaitingContainer();
if (!results.geometry) {
return;
}
var map = this.getMap();
// 1. création de l'objet geoJSON
this._geojsonObject = {
type : "FeatureCollection",
crs : {
type : "name",
properties : {
name : "EPSG:4326"
}
},
features : [
{
type : "Feature",
crs : {
type : "name",
properties : {
name : "EPSG:4326"
}
},
geometry : results.geometry
}
]
};
this._geojsonObject.features.push({
type : "Feature",
geometry : {
type : "Point",
coordinates : this._originPoint.getCoordinate()
},
properties : {
description : "Point d'origine",
"marker-symbol" : this.options.markerOp