/**
* Javascript File class cercalia.Map
* @author Edu Logrono
* @version 0.1des
*/
/**
* `cercalia.MapTypes.CERCALIA`<br/>
* `cercalia.MapTypes.OSM`<br/>
* `cercalia.MapTypes.OPENSTREETMAP`<br/>
* `cercalia.MapTypes.SATELLITE`<br/>
* `cercalia.MapTypes.HYBRID`<br/>
* @enum {string}
*/
cercalia.MapTypes = {
CERCALIA: 'default2',
MAPQUEST: 'mapquest',
OSM: 'osm',
OPENSTREETMAP: 'openstreetmap',
SATELLITE: 'satellite',
HYBRID: 'hybrid'
};
/**
* `cercalia.MapAnimation.ROTATE_LEFT`<br/>
* `cercalia.MapAnimation.ROTATE_RIGHT`<br/>
* `cercalia.MapAnimation.PAN`<br/>
* `cercalia.MapAnimation.ELASTIC`<br/>
* `cercalia.MapAnimation.BOUNCE`<br/>
* `cercalia.MapAnimation.FLY`<br/>
* `cercalia.MapAnimation.SPIRAL`
* @enum {string}
*/
cercalia.MapAnimation = {
ROTATE_LEFT: "rotate_left",
ROTATE_RIGHT: "rotate_right",
PAN: "pan",
ELASTIC: "elastic",
BOUNCE: "bounce",
FLY: "fly",
SPIRAL: "spiral"
};
/**
* @private
* @enum {string}
*/
cercalia.LayerEnumeration = {
MarkerLayer: 'MarkerLayer',
MarkerApiLayer: 'MarkerApiLayer',
RouteLayer: 'RouteLayer',
FeatureLayer: 'FeatureLayer',
DragLayer: 'DragLayer',
DrawLayer: 'DrawLayer',
ClusterLayerMarker: 'ClusterLayerMarker',
ClusterLayerMarkerDraggable: 'ClusterLayerMarkerDraggable',
OpenlrGeojsonLayer: 'OpenlrGeojsonLayer',
CercaliaTrafficReal: 'CercaliaTrafficReal',
CercaliaPredictedTraffic: 'CercaliaPredictedTraffic',
CercaliaAffectationsLines: 'CercaliaAffectationsLines',
CercaliaPKs: 'CercaliaPKs',
CercaliaWMSPois: 'CercaliaWMSPois'
};
/**
* `cercalia.ContextMenuOptions.Location`<br/>
* `cercalia.ContextMenuOptions.Routing`<br/>
* @enum {string}
*/
cercalia.ContextMenuOptions = {
Location: 'Location',
Routing: 'Routing'
};
/**
* @classdesc
*
* The map is the main API component. You can use it for painting markers, features, etc... <br/>
* Uses ol.Map 'core' <a href='http://openlayers.org/en/v3.6.0/apidoc/'>OpenLayers3</a> .<br/>
* For access to OpenLayers object, use the `getMap()` function<br/>
*
* Example for creating the map:
*
* var map = new cercalia.Map({
* target:'divMap',
* controls: []
* });
*
*
* We offer several basemaps: `cercalia.MapTypes.CERCALIA`,
* `cercalia.MapTypes.OSM`, `cercalia.MapTypes.SATELLITE` or `cercalia.MapTypes.HYBRID`.
* It's also possible to add or change a base map using WMS requests.
*
*
* @constructor
* @param {cercaliax.MapOptions} options Map options
*/
cercalia.Map = function(options) {
/**
* @private
* @type {string}
*/
this.id_ = 'CercaliaMapId_' + new Date().getTime() + Math.round((Math.random() * 1000));
/**
* @private
* @type {string}
*/
this.cercaliaKey_ = cercaliaGlobals.key; //Esta variable siempre se pasara al descargar la API
/**
* @private
* @type {string}
*/
this.server_ = servers.servlet;
/**
* @type {string}
* @private
*/
this.containerId_ = options.target;
/**
* @private
* @type {boolean}
*/
this.enabledAPIInterface_ = false;
/**
* @private
* @type {string|undefined}
*/
this.scaleUnits_ = options.scaleUnits && ['metric', 'imperial'].indexOf(options.scaleUnits) !== -1 > 0 ? options.scaleUnits : 'metric';
/**
* @private
* @type {Array.<string>|string|undefined}
*/
this.controls_ = this.initializeControls_(options.controls);
/**
* @private
* @type {Array.<string>|string|undefined}
*/
this.mapLayers_ = options.mapLayers;
/**
* @private
* @type {ol.Collection}
*/
this.controlsMap_ = this.initializeMapControls_(this.controls_);
/**
* @private
* @type {ol.Collection}
*/
this.controlsBar_ = this.initializeBarControls_(this.controls_);
/**
* @private
* @type {boolean}
*/
this.altRotation_ = typeof(options.altRotation) == "boolean" ? options.altRotation : true;
/**
* @private
* @type {number}
*/
this.separateOverlapMarkersOnZoom_ = options.separateOverlapMarkersOnZoom ? options.separateOverlapMarkersOnZoom : null;
/**
* @private
* @type {string}
*/
this.projectionCode_ = options.projectionCode ? options.projectionCode : 'EPSG:3857';
/**
* @private
* @type {ol.proj}
*/
this.mapProjection_ = new ol.proj.Projection({
code: ol.proj.get(this.projectionCode_).getCode(),
extent: ol.proj.get(this.projectionCode_).getExtent(),
units: ol.proj.get(this.projectionCode_).getUnits()
});
/**
* @private
* @type {cercalia.Marker}
*/
this.markerOver_ = null;
/**
* @private
* @type {ol.Feature}
*/
this.clusterFeatureOver_ = null;
/**
* @private
* @type {cercalia.WMS}
*/
this.layerPoiWMS_ = null;
/**
* @private
* @type {cercalia.WMS}
*/
this.layerLiveTraffic_ = null;
/**
* @private
* @type {cercalia.WMS}
*/
this.layerPredictedTraffic_ = null;
/**
* @private
* @type {cercalia.WMS}
*/
this.layerPksTraffic_ = null;
/**
* @private
* @type {Array.<string>}
*/
this.poicatsEnabled_ = [];
/**
* @private
* @type {ol.layer.Vector}
*/
this.markerLayer_ = new ol.layer.Vector({
source: new ol.source.Vector({}),
name: cercalia.LayerEnumeration.MarkerLayer,
opacity: 1,
visible: true
});
/**
* @private
* @type {ol.layer.Vector}
*/
this.markerApiLayer_ = new ol.layer.Vector({
source: new ol.source.Vector({}),
name: cercalia.LayerEnumeration.MarkerApiLayer,
opacity: 1,
visible: true
});
/**
* @private
* @type {ol.layer.Vector}
*/
this.routeLayer_ = new ol.layer.Vector({
source: new ol.source.Vector({}),
name: cercalia.LayerEnumeration.RouteLayer,
opacity: 1,
visible: true
});
/**
* @private
* @type {ol.layer.Vector}
*/
this.featureLayer_ = new ol.layer.Vector({
source: new ol.source.Vector({}),
name: cercalia.LayerEnumeration.FeatureLayer,
visible: true
});
/**
* @private
* @type {ol.layer.Vector}
*/
this.clusterLayer_ = null;
/**
* @private
* @type {ol.layer.Vector}
*/
this.clusterLayerDraggable_ = null;
/**
* @private
* @type {ol.layer.Vector}
*/
this.drawLayer_ = new ol.layer.Vector({
source: new ol.source.Vector(),
name: cercalia.LayerEnumeration.DrawLayer
});
/**
* @private
* @type {ol.Collection}
*/
this.dragLayer_ = new ol.layer.Vector({
source: new ol.source.Vector({}),
name: cercalia.LayerEnumeration.DragLayer,
visible: true
});
/**
* @private
* @type {ol.layer.Tile}
*/
this.baseLayer_ = this.createBaseLayer_(options.mapType ? options.mapType : cercalia.MapTypes.CERCALIA);
/**
* @private
* @type {string}
*/
this.baseLayerName_ = options.mapType ? options.mapType : cercalia.MapTypes.CERCALIA;
var layersToMap = [
this.baseLayer_,
this.routeLayer_,
this.featureLayer_,
this.markerLayer_,
this.markerApiLayer_,
this.drawLayer_,
this.dragLayer_
];
/**
* @private
* @type {ol.Collection}
*/
this.editableFeaturesCollection_ = new ol.Collection();
/**
* @private
* @type {ol.interaction.Modify}
*/
this.modifyControl_ = new ol.interaction.Modify({
features: this.editableFeaturesCollection_
});
var center = options.center ? options.center : new cercalia.LonLat(-2.530985346701069, 40.14298996438731);
/**
* @private
* @type {number}
*/
this.maxZoom_ = options.maxZoom !== undefined ?
(options.maxZoom > 20 ? 20 : options.maxZoom) : 19;
/**
* @private
* @type {Object}
*/
this.viewOptions_ = {
projection: this.mapProjection_,
minZoom: options.minZoom ? options.minZoom : 2,
maxZoom: this.maxZoom_,
center: ol.proj.transform([center.getLon(), center.getLat()], 'EPSG:4326', this.projectionCode_),
zoom: options.zoom ? options.zoom : 6,
rotation: options.rotation ? Math.PI * options.rotation / 180 : 0
};
//Limitación de los límites
if (options.restrictedBounds) {
this.viewOptions_.extent = ol.proj.transformExtent(options.restrictedBounds.toArray(), 'EPSG:4326', this.projectionCode_);
}
var extendInteractions = [];
if (this.altRotation_) {
extendInteractions.push(new ol.interaction.DragRotateAndZoom({
condition: ol.events.condition.altKeyOnly //Drag&Zoom con tecla 'Alt'
}));
}
// l'Interaction dels dragables creats per nosaltes.
this.dragInteraction_ = new cercalia.Interaction.DragFeatures();
extendInteractions.push(this.dragInteraction_);
/**
* @private
* @type {Array<cercalia.WMS|cercalia.KML>}
*/
this.arrayLayersAdded_ = [];
/**
* @private
* @type {ol.Map}
*/
this.map_ = new ol.Map({
controls: this.controlsMap_,
interactions: ol.interaction.defaults({
zoom: false,
rotate: false,
attributionControl: false,
logoControl: false
}).extend(extendInteractions),
target: this.containerId_,
//renderer: ['dom',/*'webgl',*/'canvas'],
renderer: ['canvas', 'dom'],
layers: layersToMap,
view: new ol.View(this.viewOptions_)
});
if (options.bounds) {
var bounds = options.bounds;
var extent = ol.proj.transformExtent(bounds.toArray(), 'EPSG:4326', this.projectionCode_);
this.map_.getView().fitExtent(extent, this.map_.getSize());
}
/**
* @private
* @type {ol.Geolocation}
*/
this.geolocation_ = null;
if (options.centerOnGeolocation) {
this.initialGeolocation_();
}
// Transformamos a button de jQuery el boton de maximizar mapa. Colocado por ol por defecto
cercalia.jQuery("#" + this.containerId_ + " .ol-full-screen button").removeClass("ol-has-tooltip").button({
icons: {
primary: "ui-icon-arrow-4-diag"
},
text: false
});
cercalia.jQuery("#" + this.containerId_ + " .ol-rotate button").removeClass("ol-has-tooltip").button({
icons: {
primary: " ui-icon-arrowrefresh-1-n"
},
text: false
});
//Hacemos que el objeto sea ciclico
this.map_.cercalia = this;
//Cambiamos la clase del viewport
var viewport = this.map_.getViewport();
viewport.className = 'cercaliaMap';
viewport.parentNode.style.position = 'relative';
viewport.style.touchAction = 'none';
viewport.style.msTouchAction = 'none';
var self = this;
cercalia.jQuery(window).resize(function() {
setTimeout(function() {
self.getMap().updateSize();
}, 200);
});
/**
* @private
* @type {cercalia.widget.MainMenu}
*/
this.mainMenuWidget_ = null;
/* WIDGETS */
/**
* @private
* @type {cercalia.widget.PoiProximity}
*/
this.poiProximityWidget_ = null;
if (options.hideRightClickMenuOptions && options.hideRightClickMenuOptions == true) {
this.rightClickMenuOptions_ = [cercalia.ContextMenuOptions.Location];
} else {
this.rightClickMenuOptions_ = [cercalia.ContextMenuOptions.Location, cercalia.ContextMenuOptions.Routing];
}
/**
* @private
* @type {Collection<cercalia.ContextMenuOptions>}
*/
this.rightClickMenuOptions_ = options.rightClickMenuOptions ? options.rightClickMenuOptions : this.rightClickMenuOptions_;
/**
* @private
* @type {ol.Overlay}
*/
this.contextMenuOverlay_ = null;
/**
* @private
* @type {Function}
*/
this.defaultClickMap_ = null;
/**
* @private
* @type {boolean}
*/
this.disableMouseOverEvents_ = options.disableMouseOverEvents !== undefined ? options.disableMouseOverEvents : false;
if (options.defaultClick) {
this.setDefaultClick(options.defaultClick);
}
if (options.rightClickMenu == null || options.rightClickMenu) {
this.contextMenuOverlay_ = this.initializeContextMenu_();
} else if (options.rightClickFunction) {
this.initializeRightClickFunction_(options.rightClickFunction);
}
// Events de zoom end i rotation end
/**
* @private
* @type {Function}
*/
this.onRotationEnd_ = typeof(options.onRotationEnd) == "function" ? options.onRotationEnd : null;
/**
* @private
*/
this.currentRotation_ = this.map_.getView().getRotation();
/**
* @private
* @type {Function}
*/
this.onZoomEnd_ = typeof(options.onZoomEnd) == "function" ? options.onZoomEnd : null;
/**
* @private
* @type {Function}
*/
this.onOverlapMarkersEnd_ = typeof(options.onOverlapMarkersEnd) == "function" ? options.onOverlapMarkersEnd : null;
/**
* @private
*/
this.currentZoom_ = this.map_.getView().getZoom();
//Inicializamos los eventosf
this.initializeMapEvents_();
//this.initializeDragFeatureEvents_();
//Inicializemos la interficie grafica
if (this.enabledAPIInterface_) {
this.initializeTopBarInterface_();
}
/**
* @private
* @type {cercalia.service.Geocoding}
*/
this.geocodingService_ = new cercalia.service.Geocoding();
/**
* @private
* @type {cercalia.service.ReverseGeocoding}
*/
this.reverseGeocodingService_ = new cercalia.service.ReverseGeocoding();
/**
* @private
* @type {cercalia.RouteMap}
*/
this.routing_ = new cercalia.RouteMap({
map: this,
version: 2
});
/**
* @private
* @type {ol.interaction.Draw}
*/
this.measureInteractionActive_ = null;
/**
* "Loading" overlay, blocks the map use
* @type {cercalia.widget.LoadingOverlay}
*/
this.overlayLoading = new cercalia.widget.LoadingOverlay({
div: this.containerId_
});
/**
* @private
* @type {Object}
*/
this.logo_ = cercalia.jQuery('<div class="mapLogo"/>').appendTo(cercalia.jQuery('#' + this.containerId_ + ' .cercaliaMap'));
/**
* @private
* @type {string}
*/
this.logoImg_ = null;
/**
* @private
* @type {boolean}
*/
this.visibleLabels_ = true;
/**
* @private
* @type {ol.interaction.Draw}
*/
this.drawInteraction_ = null;
/**
* @private
* @type {ol.interaction.Modify}
*/
this.modifyDrawFeatures_ = null;
/**
* @private
* @type {boolean}
*/
this.mouseLeftDown_ = false;
/**
* @private
* @type {Element|null}
*/
this.topBarElement_ = null;
/**
* Class name
* @private
* @type {string}
*/
this.CLASS_NAME_ = "cercalia.Map";
};
/**
* @param {Function|undefined} func Function
*/
cercalia.Map.prototype.setDefaultClick = function(func) {
if (this.defaultClickMap_) {
this.map_.un('singleclick', this.defaultClickMap_);
}
var self = this;
this.defaultClickMap_ = function(e) {
e.preventDefault();
if (func && typeof(func) == "function") {
var pixel = self.map_.getEventPixel(e.originalEvent);
var coordinateOL = self.map_.getCoordinateFromPixel(pixel);
var coordinateGeo = ol.proj.transform([coordinateOL[0], coordinateOL[1]], self.projectionCode_, 'EPSG:4326');
func(pixel, new cercalia.LonLat(coordinateGeo[0], coordinateGeo[1]));
}
};
this.map_.on('singleclick', this.defaultClickMap_);
};
/**
* Adds a layer <a href="http://openlayers.org/en/v3.6.0/apidoc/ol.layer.Layer.html">`ol.layer.Layer`</a> specifying
* the position (optional). The layers are declarated in an array and the Z value works from less to more. The Layer
* basemap (map), is fixed in the first position 0.<br/>
* If you need to change the baseLayer, change it to position 1 or remove the baseLayer.
* @param {ol.layer} layer
* @param {number} position
*/
cercalia.Map.prototype.addLayer = function(layer, position) {
if ((layer instanceof cercalia.Heatmap) || (layer instanceof cercalia.WMS)) {
layer.setMap(this, position ? position : 1); //Pregunta Marc: pq position 1?
} else if (layer instanceof cercalia.KML) {
layer.setMap(this, position);
} else {
this.arrayLayersAdded_.push(layer);
if (position || position == 0) {
this.map_.getLayerGroup().getLayers().insertAt(position, layer);
} else {
//Si no se especifica la posición del layer
this.map_.addLayer(layer);
}
}
};
/**
* Clean the layer specified by parameter
* @param {ol.layer} layer
*/
cercalia.Map.prototype.removeLayer = function(layer) {
if (layer instanceof cercalia.KML) {
layer = layer.getLayer();
}
if (layer instanceof ol.layer.Vector) {
this.removeLayerFeatures_(layer);
}
this.map_.removeLayer(layer);
var index = this.arrayLayersAdded_.indexOf(layer);
if (index > -1) {
this.arrayLayersAdded_.splice(index, 1);
}
return this;
};
/**
*
* Clean all features from layer
* @private
* @param {ol.layer} layer
*/
cercalia.Map.prototype.removeLayerFeatures_ = function(layer) {
var source = layer.getSource();
var arrFeatures = layer.getSource().getFeatures();
for (var i = 0; i < arrFeatures.length; i++) {
var feature = arrFeatures[i];
if (feature.feature_) {
feature.feature_.destroy();
}
}
return this;
};
/**
* Add a new option in context menu, adding a function on click to this option.
* @param {string} buttonName Text to show in the neu context menu option
* @param {Function} clickFunction Function to call linked to new button
* @param {string} id Option's identifier.
*/
cercalia.Map.prototype.createContextMenuOption = function(buttonName, clickFunction, id) {
if (this.contextMenuOverlay_) {
this.contextMenuOverlay_.addOption(id, buttonName, clickFunction);
} else {
console.warn("No context menu inicialzed");
}
};
/**
* Open the context menu at the coordinates specified by parameters. If not specified, opens
* the context menu in the map center according to the current position.
* @param {cercalia.LonLat|undefined} lonLat Coordinate
*/
cercalia.Map.prototype.openContextMenu = function(lonLat) {
if (this.contextMenuOverlay_) {
var center = lonLat ? lonLat : this.getCenter();
this.contextMenuOverlay_.open(center, this.getProjectionCode());
if (self.routing_) {
self.routing_.hideContextMenu();
}
} else {
console.warn("No context menu inicialzed");
}
};
cercalia.Map.prototype.getDirectionFunction_ = function(evnt, lonLat) {
if (lonLat) {
var map = this; //map
this.reverseGeocodingService_.getDirection(lonLat, function(data) {
var ge = data.cercalia.proximity.gelist.ge;
var type = data.cercalia.proximity.gelist.type;
var portalBefore = ["ARE", "AUS", "CAN", "EGY", "GBR", "IND", "IRL", "ISR", "KWT", "NZL", "OMN", "QAT", "SAU", "THA", "USA", "ZAF"].indexOf(ge.country.id) != -1;
var content =
"<table style='width:200px;font-size:7pt;font-family:Tahoma'>" +
(type == 'adr' ? "<tr><td>" + cercalia.i18n._('Street') + "</td><td>" + (portalBefore ? ((ge.housenumber ? ge.housenumber.value + " " : "") + ge.name + (ge.km ? ", km: " + ge.km.value : "")) : (ge.name + (ge.housenumber ? ", " + ge.housenumber.value : (ge.km ? ", km: " + ge.km.value : "")))) + "</td></tr>" : "") +
(type == 'st' ? "<tr><td>" + cercalia.i18n._('Street') + "</td><td>" + ge.name + "</td></tr>" : "") +
(ge.city ? "<tr><td>" + cercalia.i18n._('City') + "</td><td>" + ge.city.value + "</td></tr>" : "") +
(ge.postalcode ? "<tr><td>" + cercalia.i18n._('Postal code') + "</td><td>" + ge.postalcode.id + "</td></tr>" : "") +
(ge.municipality ? "<tr><td>" + cercalia.i18n._('Municipality') + "</td><td>" + ge.municipality.value + "</td></tr>" : "") +
(ge.subregion ? "<tr><td>" + cercalia.i18n._('Subregion') + "</td><td>" + ge.subregion.value + "</td></tr>" : "") +
(ge.region ? "<tr><td>" + cercalia.i18n._('Region') + "</td><td>" + ge.region.value + "</td></tr>" : "") +
"<tr><td>" + cercalia.i18n._('Country') + "</td><td>" + ge.country.value + "</td></tr>" +
"<tr><td>" + cercalia.i18n._('Coords') + "</td><td>" + ge.coord.x + "," + ge.coord.y + "</td></tr>" +
"</table>";
var popup = new cercalia.Popup({
title: cercalia.i18n._('Info'),
content: content,
visible: true
});
var marker = new cercalia.Marker({
position: lonLat,
popup: popup
});
map.addMarker(marker);
});
}
};
/**
* Creates and returns the context menu.
* @private
* @return {cercalia.ContextMenu}
*/
cercalia.Map.prototype.initializeContextMenu_ = function() {
var self = this;
var getProximityFunction = function(evnt, lonLat) {
if (lonLat) {
if (self.poiProximityWidget_ != null) {
self.poiProximityWidget_.findByLonLat(lonLat);
}
}
};
// Create the context menu
var idContextMenu = "contextMenu" + this.id_;
var contextMenu = new cercalia.ContextMenu({
id: idContextMenu,
map: this
});
this.addRightClickMenuOptions_(contextMenu);
if (this.poiProximityWidget_ !== null) {
contextMenu.addOption('getProximity', 'Whats close by', getProximityFunction);
}
return contextMenu;
};
/**
* @deprecated
* deprecated function, equivalent: map.getRouteMap().removeRoute();
*/
cercalia.Map.prototype.removeApiRoute = function() {
this.routing_.removeRoute();
};
/**
* @private
* @param {ol.Event} evnt
* @param {cercalia.LonLat} lonLat
*/
cercalia.Map.prototype.setRouteEndFunction_ = function(evnt, lonLat) {
var self = this;
if (lonLat) {
this.routing_.setDestination(lonLat, true)
}
};
/**
* @private
* @param {ol.Event} evnt
* @param {cercalia.LonLat} lonLat
*/
cercalia.Map.prototype.setRouteWaypoint_ = function(evnt, lonLat) {
var self = this;
if (lonLat) {
this.routing_.setStep(lonLat, true);
}
};
/**
* @private
* @param {ol.Event} evnt
* @param {cercalia.LonLat} lonLat
*/
cercalia.Map.prototype.setRouteStartFunction_ = function(evnt, lonLat) {
var self = this;
if (lonLat) {
this.routing_.setOrigin(lonLat, true);
}
};
/**
* @private
* @param {Function} func
*/
cercalia.Map.prototype.initializeRightClickFunction_ = function(func) {
var self = this;
//Boton derecho sobre el mapa
cercalia.jQuery(this.map_.getViewport()).bind('contextmenu', function(e) {
e.preventDefault();
if (func && typeof(func) == "function") {
var pixel = self.map_.getEventPixel(e.originalEvent);
var coordinateOL = self.map_.getCoordinateFromPixel(pixel);
var coordinateGeo = ol.proj.transform([coordinateOL[0], coordinateOL[1]], self.projectionCode_, 'EPSG:4326');
func(pixel, new cercalia.LonLat(coordinateGeo[0], coordinateGeo[1]));
}
});
};
/**
* Centers the map Centra la posición al mapa according to the latest geocode avaliable in 'localStorage'.
* Inf localStorage is not avaliable
* @private
*/
cercalia.Map.prototype.initialGeolocation_ = function() {
this.geolocation_ = new ol.Geolocation();
//Comprobamos primero si guardamos la ultima posicion en el localStorage
if (localStorage && localStorage.getItem('cercaliaLastGeolocation')) {
var coordinate = JSON.parse(localStorage.getItem('cercaliaLastGeolocation'));
var lonLat = new cercalia.LonLat(coordinate[0], coordinate[1]);
var bounds = new cercalia.Bounds();
bounds.extend(lonLat);
this.setCenter(lonLat, 13);
} else {
this.geolocation();
}
this.geolocation_.setTracking(true);
};
/**
* Obtains the geocode at the API access point
* It is possible to declare a callback function, to be executed when obtains the geocode.
* When callback function is not avaliable, the map is centered to API access point.
* @param {Function} callbackFn
*/
cercalia.Map.prototype.geolocation = function(callbackFn) {
var self = this;
this.geolocation_.once('change', function(evt) {
if (callbackFn) {
callbackFn(evt);
} else {
this.setTracking(false);
var lonLatArr = this.getPosition()
if (localStorage) {
localStorage.setItem('cercaliaLastGeolocation', JSON.stringify(lonLatArr));
}
var lonLat = new cercalia.LonLat(lonLatArr[0], lonLatArr[1]);
var bounds = new cercalia.Bounds();
bounds.extend(lonLat);
self.setCenter(lonLat, 13);
}
});
};
/**
* Initializes events map
* Events list: `[click, singleclick, dblclick, mousewheel, moveend, pointerup, pointerdown, pointermove, pointerdrag]`
* @private
*/
cercalia.Map.prototype.initializeMapEvents_ = function() {
var self = this;
var listenLayersOnRightClick = [
cercalia.LayerEnumeration.DragLayer,
cercalia.LayerEnumeration.MarkerLayer,
//cercalia.LayerEnumeration.MarkerApiLayer,
cercalia.LayerEnumeration.FeatureLayer,
cercalia.LayerEnumeration.ClusterLayerMarker,
cercalia.LayerEnumeration.ClusterLayerMarkerDraggable
];
cercalia.jQuery(this.map_.getViewport()).bind('contextmenu', function(e) {
e.preventDefault();
});
//Eventos botón derecho para las features
cercalia.jQuery(this.map_.getViewport()).mousedown(function(e) {
if (e.which == 3) { //boto dret
e.preventDefault();
var pixel = self.map_.getEventPixel(e.originalEvent);
var rightClickFunctionsCalled = 0;
self.map_.forEachFeatureAtPixel(
pixel,
function(feature, layer) {
if (self.clusterLayer_ != null) {
if (feature.get('features') && feature.get('features').length == 1) {
feature = feature.get('features')[0];
} else {
feature.featureType_ = "cercalia.Cluster";
}
}
switch (feature.featureType_) {
case "cercalia.Marker":
if (feature.marker_.onRightClick) {
rightClickFunctionsCalled++;
feature.marker_.onRightClick(feature.marker_, e.originalEvent); //Ejecutar evento 'onRightClick'
}
break;
case "cercalia.Feature":
var cercaliaFeature = feature.feature_;
if (cercaliaFeature.onRightClick) {
rightClickFunctionsCalled++;
cercaliaFeature.onRightClick(cercaliaFeature, e.originalEvent);
}
break;
default:
break;
}
},
undefined,
function(layer) {
return listenLayersOnRightClick.indexOf(layer.get('name')) !== -1; //Filtramos solo para los layers que nos interese
}
);
if (self.contextMenuOverlay_ && rightClickFunctionsCalled <= 0) { // Si no se llaman funcines de marker, llamamos al rightclick del mapa.
var coordinateOL = self.map_.getCoordinateFromPixel(pixel);
self.contextMenuOverlay_.open(coordinateOL, self.projectionCode_);
if (self.routing_) {
self.routing_.hideContextMenu();
}
}
}
});
var listenLayersOnMouseMove = [
cercalia.LayerEnumeration.DragLayer,
cercalia.LayerEnumeration.MarkerLayer,
cercalia.LayerEnumeration.MarkerApiLayer,
cercalia.LayerEnumeration.FeatureLayer,
cercalia.LayerEnumeration.ClusterLayerMarker,
cercalia.LayerEnumeration.ClusterLayerMarkerDraggable,
cercalia.LayerEnumeration.OpenlrGeojsonLayer
];
var onMouseMove = function(e) {
var pixel = self.map_.getEventPixel(e.originalEvent);
var hit = self.map_.forEachFeatureAtPixel(pixel, function(feature, layer) {
if (self.clusterLayer_ != null && self.clusterLayer_ == layer) {
if (feature.get('features').length == 1) {
feature = feature.get('features')[0];
} else {
feature.featureType_ = "cercalia.Cluster";
}
}
if (feature.featureType_) {
switch (feature.featureType_) {
case "cercalia.Marker":
if (self.markerOver_ && feature.marker_ != self.markerOver_) {
if (self.markerOver_.onMouseOut) {
self.markerOver_.onMouseOut(self.markerOver_); //Ejecutar evento 'onMouseOut'
}
}
self.markerOver_ = feature.marker_;
if (feature.marker_.onMouseOver) {
feature.marker_.onMouseOver(self.markerOver_, e.originalEvent); //Ejecutar evento 'onMouseOver'
}
break;
case "cercalia.Feature":
if (self.markerOver_ && feature.feature_ != self.markerOver_) {
if (self.markerOver_.onMouseOut) {
self.markerOver_.onMouseOut(self.markerOver_); //Ejecutar evento 'onMouseOut'
}
}
self.markerOver_ = feature.feature_
if (self.markerOver_.onMouseOver) {
self.markerOver_.onMouseOver(self.markerOver_, e.originalEvent);
}
break;
case "cercalia.Cluster":
if (layer.getProperties().onMouseOverFunction) {
var arrayMarkers = [];
for (var i = 0; i < feature.get('features').length; i++) {
arrayMarkers.push(feature.get('features')[i].marker_);
}
layer.getProperties().onMouseOverFunction(feature, arrayMarkers);
self.clusterFeatureOver_ = feature;
}
break;
default:
break;
}
}
return true;
},
undefined,
function(layer) {
return listenLayersOnMouseMove.indexOf(layer.get('name')) !== -1 || self.arrayLayersAdded_.indexOf(layer) > -1; //Filtramos solo para los layers que nos interese
}
);
if (hit) {
document.getElementById(self.map_.getTarget()).style.cursor = 'pointer';
} else {
if (self.markerOver_) {
if (self.markerOver_.onMouseOut) {
self.markerOver_.onMouseOut(self.markerOver_); //Ejecutar evento 'onMouseOut'
}
self.markerOver_ = null;
}
if (self.clusterFeatureOver_) {
if (self.clusterLayer_ && self.clusterLayer_.getProperties().onMouseOutFunction) {
var arrayMarkers = [];
var featuresClustered = self.clusterFeatureOver_.get('features');
for (var i = 0; i < featuresClustered.length; i++) {
arrayMarkers.push(featuresClustered[i].marker_);
}
self.clusterLayer_.getProperties().onMouseOutFunction(self.clusterFeatureOver_, arrayMarkers);
}
self.clusterFeatureOver_ = null;
}
document.getElementById(self.map_.getTarget()).style.cursor = '';
}
};
var timeoutid = 0;
if (!cercalia.isMobile && !this.disableMouseOverEvents_) {
cercalia.jQuery(self.map_.getViewport()).on('mousemove', function(e) {
if (timeoutid) {
clearTimeout(timeoutid);
timeoutid = 0;
}
timeoutid = setTimeout(function() {
onMouseMove(e);
}, 20);
});
}
//Eventos al clickar una feature. Si se ha especificado el evento lo lanza
//cercalia.jQuery(self.map_.getViewport()).on('click', function(e) {
var listenLayersOnSingleClick = [
cercalia.LayerEnumeration.DragLayer,
cercalia.LayerEnumeration.MarkerLayer,
cercalia.LayerEnumeration.MarkerApiLayer,
cercalia.LayerEnumeration.ClusterLayerMarker,
cercalia.LayerEnumeration.ClusterLayerMarkerDraggable,
cercalia.LayerEnumeration.FeatureLayer,
cercalia.LayerEnumeration.OpenlrGeojsonLayer
];
this.map_.on('singleclick', function(e) {
if (self.contextMenuOverlay_ && self.contextMenuOverlay_.isVisible()) {
self.contextMenuOverlay_.close();
}
if (self.routing_) {
self.routing_.hideContextMenu();
}
var pixel = self.map_.getEventPixel(e.originalEvent);
var coordinate = ol.proj.transform(e.coordinate, self.projectionCode_, 'EPSG:4326');
var lonLat = new cercalia.LonLat(coordinate[0], coordinate[1]);
//Si está activado el Layer de POIs hacemos petición AJAX para obtener información
if (self.layerPoiWMS_ != null) {
var params = {
key: self.cercaliaKey_,
cmd: 'proximity',
x: lonLat.getLon(),
y: lonLat.getLat(),
srs: 'EPSG:4326',
rqpoicats: self.poicatsEnabled_.join(","),
rad: self.pixelsToMeters(12),
rqge: 'adr'
};
cercalia.jQuery.ajax({
url: self.server_,
data: params,
dataType: "json",
crossDomain: true,
timeout: 5000,
success: function(data) {
var poi = data.cercalia.proximity.poilist.poi[0];
var marker = new cercalia.Marker({
position: new cercalia.LonLat(poi.coord.x, poi.coord.y),
popup: new cercalia.Popup({
title: poi.name.value,
content: '<div style="width:180px">' + poi.info.value + '</div>',
visible: true
})
});
marker.setVisible(false);
self.addMarker(marker);
},
error: cercalia.AJAXException
});
}
var eventLaunched = false;
self.map_.forEachFeatureAtPixel(pixel, function(feature, layer) {
if (!layer) {
return;
}
var layerName = layer.get('name');
if (self.clusterLayer_ != null && layerName != cercalia.LayerEnumeration.FeatureLayer) {
// Capa clusterizada
if (layerName == cercalia.LayerEnumeration.ClusterLayerMarker || layerName == cercalia.LayerEnumeration.ClusterLayerMarkerDraggable) {
if (feature.get('features').length == 1) {
feature = feature.get('features')[0];
} else {
feature.featureType_ = "cercalia.Cluster";
}
}
// Else feature = feature;
}
if ([
cercalia.LayerEnumeration.MarkerLayer,
cercalia.LayerEnumeration.ClusterLayerMarker,
cercalia.LayerEnumeration.ClusterLayerMarkerDraggable,
cercalia.LayerEnumeration.FeatureLayer,
cercalia.LayerEnumeration.DragLayer
].indexOf(layerName) !== -1) {
if (!eventLaunched) {
var lonlat = new cercalia.LonLat(e.coordinate[0], e.coordinate[1], self.getProjectionCode());
switch (feature.featureType_) {
case "cercalia.Marker":
var marker = feature.marker_;
var popup = marker.getPopup();
if (popup) {
if (popup.isOpen()) {
popup.hide();
} else {
popup.show();
}
}
if (marker.onClick) {
marker.onClick(feature.marker_, e.originalEvent, lonlat);
eventLaunched = true;
}
break;
case "cercalia.Feature":
var cercaliaFeature = feature.feature_;
if (cercaliaFeature.onClick) {
cercaliaFeature.onClick(cercaliaFeature, e.originalEvent, lonlat);
eventLaunched = true;
}
break;
case "cercalia.Cluster":
var arrayMarkers = [];
for (var i = 0; i < feature.get('features').length; i++) {
arrayMarkers.push(feature.get('features')[i].marker_);
}
eventLaunched = true;
layer.getProperties().onClickFunction(feature, arrayMarkers, lonlat);
break;
default:
break;
}
}
} else if (layerName == cercalia.LayerEnumeration.OpenlrGeojsonLayer) {
if (!this.controlTrafficAffectations_) {
this.controlTrafficAffectations_ = self.getControlsByName(cercalia.MapControls.Traffic);
}
this.controlTrafficAffectations_.showAffectationPopup(feature);
} else if (layerName == cercalia.LayerEnumeration.MarkerApiLayer) {
var marker = feature.marker_;
if (marker.onClick) {
marker.onClick(feature.marker_, e.originalEvent);
eventLaunched = true;
}
}
},
undefined,
function(layer) {
return listenLayersOnSingleClick.indexOf(layer.get('name')) !== -1; //Filtramos solo para los layers que nos interese
}
);
});
//Eventos al clickar una feature. Si se ha especificado el evento lo lanza
//cercalia.jQuery(self.map_.getViewport()).on('click', function(e) {
var listenLayersOnDoubleClick = [
cercalia.LayerEnumeration.DragLayer,
cercalia.LayerEnumeration.MarkerLayer,
cercalia.LayerEnumeration.MarkerApiLayer,
cercalia.LayerEnumeration.ClusterLayerMarker,
cercalia.LayerEnumeration.ClusterLayerMarkerDraggable,
cercalia.LayerEnumeration.FeatureLayer
];
this.map_.on('dblclick', function(e) {
if (self.contextMenuOverlay_ && self.contextMenuOverlay_.isVisible()) {
self.contextMenuOverlay_.close();
}
if (self.routing_) {
self.routing_.hideContextMenu();
}
var pixel = self.map_.getEventPixel(e.originalEvent);
var coordinate = ol.proj.transform(e.coordinate, self.projectionCode_, 'EPSG:4326');
var lonLat = new cercalia.LonLat(coordinate[0], coordinate[1]);
var eventLaunched = false;
self.map_.forEachFeatureAtPixel(pixel, function(feature, layer) {
if (!layer) {
return;
}
var layerName = layer.get('name');
if (self.clusterLayer_ != null && layerName != cercalia.LayerEnumeration.FeatureLayer) {
// Capa clusterizada
if (layerName == cercalia.LayerEnumeration.ClusterLayerMarker || layerName == cercalia.LayerEnumeration.ClusterLayerMarkerDraggable) {
if (feature.get('features').length == 1) {
feature = feature.get('features')[0];
} else {
feature.featureType_ = "cercalia.Cluster";
}
}
// Else feature = feature;
}
if ([
cercalia.LayerEnumeration.MarkerLayer,
cercalia.LayerEnumeration.ClusterLayerMarker,
cercalia.LayerEnumeration.ClusterLayerMarkerDraggable,
cercalia.LayerEnumeration.FeatureLayer,
cercalia.LayerEnumeration.DragLayer
].indexOf(layerName) !== -1) {
if (!eventLaunched) {
switch (feature.featureType_) {
case "cercalia.Marker":
var marker = feature.marker_;
if (marker.onDoubleClick) {
marker.onDoubleClick(feature.marker_, e.originalEvent);
eventLaunched = true;
}
break;
case "cercalia.Feature":
var cercaliaFeature = feature.feature_;
if (cercaliaFeature.onDoubleClick) {
cercaliaFeature.onDoubleClick(cercaliaFeature, e.originalEvent);
eventLaunched = true;
}
break;
case "cercalia.Cluster":
var arrayMarkers = [];
for (var i = 0; i < feature.get('features').length; i++) {
arrayMarkers.push(feature.get('features')[i].marker_);
}
eventLaunched = true;
layer.getProperties().onDoubleClickFunction(feature, arrayMarkers);
break;
default:
break;
}
}
} else if (layerName == cercalia.LayerEnumeration.MarkerApiLayer) {
var marker = feature.marker_;
if (marker && marker.onDoubleClick) {
marker.onDoubleClick(feature.marker_, e.originalEvent);
eventLaunched = true;
}
}
},
undefined,
function(layer) {
return listenLayersOnDoubleClick.indexOf(layer.get('name')) !== -1; //Filtramos solo para los layers que nos interese
});
return !eventLaunched;
});
//Obtener el logo del mapa según los tiles que se muestran
this.map_.on('moveend', function(event) {
self.onMoveEnd_();
if (self.separateOverlapMarkersOnZoom_) { //Anadir condicion segun zoomOverlapChecking //check if overlap
self.overlapMarkers()
}
});
};
/**
* @private
*/
cercalia.Map.prototype.onMoveEnd_ = function() {
// on zoom end i on rotation end
if (this.onRotationEnd_ != null && this.map_.getView().getRotation() != this.currentRotation_) {
var old = this.currentRotation_;
this.currentRotation_ = this.map_.getView().getRotation();
this.onRotationEnd_({
'new': this.map_.getView().getRotation(),
'old': old
});
}
if (this.onZoomEnd_ != null && this.map_.getView().getZoom() != this.currentZoom_) {
var old = this.currentZoom_;
this.currentZoom_ = this.map_.getView().getZoom();
this.onZoomEnd_({
'new': this.map_.getView().getZoom(),
'old': old
});
}
var params = {
key: this.cercaliaKey_,
cmd: 'logo',
center: ol.proj.transform(this.map_.getView().getCenter(), this.getProjectionCode(), 'EPSG:54004').join(","),
scale: this.map_.getView().getZoom() - 6 >= 0 ? this.map_.getView().getZoom() - 6 : 0,
style: this.getBaseLayer().getProperties().name
};
var self = this;
cercalia.jQuery.ajax({
url: self.server_,
data: params,
dataType: "json",
crossDomain: true,
timeout: 5000,
success: function(data) {
try {
var serverLogo = self.server_.indexOf('https') == 1 ? 'http://api.cercalia.com' : 'https://api.cercalia.com';
var baseLayerName = self.getBaseLayer().getProperties().name;
if (baseLayerName == cercalia.MapTypes.CERCALIA) {
//Si ess el mismo no lo cambiamos
if (data.cercalia.logo && data.cercalia.logo.href && (self.logoImg_ != data.cercalia.logo.href)) {
self.logoImg_ = data.cercalia.logo.href;
self.logo_.empty().append(cercalia.jQuery('<img src="' + serverLogo + data.cercalia.logo.href + '">'));
}
} else if (baseLayerName == cercalia.MapTypes.OPENSTREETMAP || baseLayerName == cercalia.MapTypes.OSM) {
var imgOSM = serverLogo + '/MapesNG/logo/logo_OSM.gif';
if (self.logoImg_ != imgOSM) {
self.logoImg_ = imgOSM;
self.logo_.empty().append(cercalia.jQuery('<img src="' + self.logoImg_ + '">'));
}
} else if (baseLayerName == cercalia.MapTypes.SATELLITE || baseLayerName == cercalia.MapTypes.MAPQUEST || baseLayerName == cercalia.MapTypes.HYBRID) {
var imgMapbox = serverLogo + '/MapesNG/logo/logo_mapbox.gif';
if (self.logoImg_ != imgMapbox) {
self.logoImg_ = imgMapbox;
self.logo_.empty().append(cercalia.jQuery('<img src="' + self.logoImg_ + '">'));
}
} else {
var logo = self.getBaseLayer().getProperties().logo;
if (!logo) {
self.logoImg_ = null;
self.logo_.empty();
} else {
if (self.logoImg_ != logo) {
self.logoImg_ = logo;
self.logo_.empty().append(cercalia.jQuery('<img src="' + self.logoImg_ + '">'));
}
}
}
} catch (e) {}
}
});
this.onMoveSatelliteLayer_();
};
/**
* Get Overlapped markers
* @param {boolean|undefined} currentExtentView If `true` returns only visible markers at the moment, if not `null` or `false` it returns all markers
* @param {boolean|undefined} tolerance Tolerance in meters.
* @return {Array.<Array.<cercalia.Marker>>}
*/
cercalia.Map.prototype.getOverlappedMarkers = function(currentExtentView, tolerance) {
return this.getOverlapFeaturesByExtentAndDistance_(currentExtentView, tolerance);
};
/**
* @private
* @param {boolean|undefined} currentExtentView
* @param {number|undefined} tolerance
*/
cercalia.Map.prototype.getOverlapFeaturesByExtentAndDistance_ = function(currentExtentView, tolerance) {
var self = this;
var sourceMarkerLayer = this.markerLayer_.getSource();
var sourceDragLayer = this.dragLayer_.getSource();
var features = [];
var overlapGroupMarkers = [];
if (currentExtentView) { //get only features in current extent view
var extentAct = this.map_.getView().calculateExtent(this.map_.getSize());
//Els dos layers poden tenir markers. Els separem entre layer draggable (dragLayer & markerLayer) segons si son draggable o no.
features = sourceMarkerLayer.getFeaturesInExtent(extentAct).concat(sourceDragLayer.getFeaturesInExtent(extentAct));
} else {
//get allfeatures in map
features = sourceMarkerLayer.getFeatures().concat(sourceDragLayer.getFeatures());
}
var clustered = {};
var extent = ol.extent.createEmpty();
for (var i = 0, ii = features.length; i < ii; i++) {
var feature = features[i];
//if (! goog.object.containsKey(clustered, goog.getUid(feature).toString())) {
if (!(feature.getId() in clustered)) {
var geometry = feature.getGeometry();
var coordinates = geometry.getCoordinates();
ol.extent.createOrUpdateFromCoordinate(coordinates, extent);
ol.extent.buffer(extent, tolerance, extent);
var neighbors = sourceMarkerLayer.getFeaturesInExtent(extent).concat(sourceDragLayer.getFeaturesInExtent(extent));
neighbors = neighbors.filter(function(neighbor) {
if (neighbor.getCercaliaObject() instanceof cercalia.Marker) {
var uid = neighbor.getId();
if (!(uid in clustered)) {
clustered[uid] = true;
return true;
} else {
return false;
}
} else {
return false;
}
});
if (neighbors.length > 1) {
overlapGroupMarkers.push(neighbors);
}
}
}
return overlapGroupMarkers;
};
/**
* @private
* @param {Array.<Array.<cercalia.Marker>>} overlapGroupMarkers
* @param {boolean} restorePosition
*/
cercalia.Map.prototype.separateOverlapMarkers_ = function(overlapGroupMarkers, restorePosition) {
for (var i = 0; i < overlapGroupMarkers.length; i++) {
var features = overlapGroupMarkers[i];
var separationAngle = 360 / features.length;
var rotationAct = 0;
for (var j = 0; j < features.length; j++) {
var marker = features[j].getCercaliaObject();
var icon = marker.getIcon();
var size = icon.getIconStyle().getSize()
icon.originalAnchor_ = icon.originalAnchor_ ? icon.originalAnchor_ : icon.getAnchor();
icon.originalRotation_ = icon.originalRotation_ || icon.originalRotation_ == 0 ? icon.originalRotation_ : icon.getRotation();
if (restorePosition) {
icon.setRotation(icon.originalRotation_);
icon.setAnchor(icon.originalAnchor_);
} else {
if (size) {
if (icon.getAnchorUnits() == "fraction") {
icon.setAnchor([0.5, 1.1]);
} else {
icon.setAnchor([icon.originalAnchor_[0], icon.originalAnchor_[1] + (size[1] - icon.originalAnchor_[1])]);
}
}
rotationAct += separationAngle;
icon.setRotation(rotationAct);
}
}
}
};
/**
* Separate overlapped markers when its have same position.
*/
cercalia.Map.prototype.overlapMarkers = function() {
var self = this;
var toleranceToOverlap = 5; //meters
var overlapGroupMarkers = null;
if (this.getZoom() >= this.separateOverlapMarkersOnZoom_) {
overlapGroupMarkers = this.getOverlapFeaturesByExtentAndDistance_(true, toleranceToOverlap);
this.separateOverlapMarkers_(overlapGroupMarkers, false);
this.overlapMarkersSeparated_ = true;
} else {
if (this.overlapMarkersSeparated_) {
overlapGroupMarkers = this.getOverlapFeaturesByExtentAndDistance_(true, toleranceToOverlap);
this.separateOverlapMarkers_(overlapGroupMarkers, true);
this.overlapMarkersSeparated_ = false;
}
}
if (this.onOverlapMarkersEnd_ && overlapGroupMarkers) {
this.onOverlapMarkersEnd_.call(this, overlapGroupMarkers, this.overlapMarkersSeparated_);
}
};
/**
* Returns an array with control objects already created. Send by parameter
* an array with the Strings constants of controls declared in the file
* "cercalia.control.js"
* @private
* @param {Array.<string>|string|undefined} opt_controls
* @return {Array.<string>} controls
*/
cercalia.Map.prototype.initializeControls_ = function(opt_controls) {
var listControlsToAdd = null;
if (opt_controls) {
if (opt_controls instanceof Array) {
listControlsToAdd = opt_controls;
// No hay zoom definido
if (listControlsToAdd.indexOf(cercalia.MapControls.ZoomSlider) <= -1 && listControlsToAdd.indexOf(cercalia.MapControls.Zoom) <= -1) {
listControlsToAdd.push(cercalia.MapControls.Zoom);
}
} else if (typeof(opt_controls) == "string" && opt_controls == "none") {
listControlsToAdd = []; // opt_control == none
} else {
listControlsToAdd = [cercalia.MapControls.Zoom, cercalia.MapControls.FullScreen, cercalia.MapControls.ScaleLine]; // Controles que aparecerán al mapa por defecto
}
} else {
listControlsToAdd = [cercalia.MapControls.Zoom, cercalia.MapControls.FullScreen, cercalia.MapControls.ScaleLine]; // Controles que aparecerán al mapa por defecto
}
return listControlsToAdd;
};
/**
* Returns true if controls contains some included in toolsbar.
* @private
* @param {Array.<string>} allControls
* @return {boolean}
*/
cercalia.Map.prototype.findBarControls_ = function(allControls) {
return allControls.indexOf(cercalia.MapControls.CleanControl) >= 0 ||
allControls.indexOf(cercalia.MapControls.DragControl) >= 0 ||
allControls.indexOf(cercalia.MapControls.DrawControl) >= 0 ||
allControls.indexOf(cercalia.MapControls.GasStations) >= 0 ||
allControls.indexOf(cercalia.MapControls.Isochrones) >= 0 ||
allControls.indexOf(cercalia.MapControls.LayerSwitcher) >= 0 ||
allControls.indexOf(cercalia.MapControls.Logistics) >= 0 ||
allControls.indexOf(cercalia.MapControls.MeasureControl) >= 0 ||
allControls.indexOf(cercalia.MapControls.MeteoControl) >= 0 ||
allControls.indexOf(cercalia.MapControls.Traffic) >= 0 ||
allControls.indexOf(cercalia.MapControls.CustomSwitcherControl) >= 0;
};
/**
* Returns an array with the map controls objects.
* @private
* @param {Array.<string>} allControls
* @return {Array.<cercalia.Control>} controls
*/
cercalia.Map.prototype.initializeMapControls_ = function(allControls) {
// Posicion top donde empezamos a colocar botones en el mapa
var initTop = 5; // Posicion sin barra de controles
if (this.findBarControls_(allControls)) {
initTop = 65; // Posición con barra de controles.
}
var northTop = initTop,
zoomTop = initTop,
fullTop = initTop,
controlZoomType = null;
var controls = new ol.Collection();
if (allControls.indexOf(cercalia.MapControls.RotateNorth) >= 0) {
zoomTop += 45;
}
if (allControls.indexOf(cercalia.MapControls.ZoomSlider) != -1 && !cercalia.isMobile) {
controlZoomType = cercalia.MapControls.ZoomSlider;
} else {
controlZoomType = cercalia.MapControls.Zoom;
}
for (var i = 0; i < allControls.length; i++) {
switch (allControls[i]) {
case cercalia.MapControls.RotateNorth:
controls.push(new cercalia.Control.RotateNorth({
controlZoomType: controlZoomType, //Le pasamos que tipo de zoom hay ya que variará su estilo
top: northTop
}));
break;
case cercalia.MapControls.FullScreen:
//if (!cercalia.isMobile) {
controls.push(new cercalia.Control.FullScreen({
top: fullTop
}));
//}
break;
case cercalia.MapControls.ScaleLine:
controls.push(new cercalia.Control.ScaleLine({
units: this.scaleUnits_
}));
break;
case cercalia.MapControls.ZoomSlider:
controls.push(new cercalia.Control.ZoomSlider({
top: zoomTop + 35
}));
break;
case cercalia.MapControls.Zoom:
controls.push(new cercalia.Control.Zoom({
top: zoomTop
}));
break;
case cercalia.MapControls.StreetView:
if (!cercalia.isMobile) {
controls.push(new cercalia.Control.StreetView({}));
}
break;
}
}
return controls;
};
/**
* Returns an array with the map controls objects.
* @private
* @param {Array.<string>} allControls
* @return {Array.<string>} controls
*/
cercalia.Map.prototype.initializeBarControls_ = function(allControls) {
var controls = [];
if (this.findBarControls_(allControls)) {
this.enabledAPIInterface_ = true;
for (var i = 0; i < allControls.length; i++) {
switch (allControls[i]) {
case cercalia.MapControls.CleanControl:
controls.push(allControls[i]);
break;
case cercalia.MapControls.DragControl:
controls.push(allControls[i]);
break;
case cercalia.MapControls.DrawControl:
controls.push(allControls[i]);
break;
case cercalia.MapControls.GasStations:
controls.push(allControls[i]);
break;
case cercalia.MapControls.Isochrones:
controls.push(allControls[i]);
break;
case cercalia.MapControls.LayerSwitcher:
controls.push(allControls[i]);
break;
case cercalia.MapControls.Logistics:
controls.push(allControls[i]);
break;
case cercalia.MapControls.MeteoControl:
controls.push(allControls[i]);
break;
case cercalia.MapControls.MeasureControl:
controls.push(allControls[i]);
break;
case cercalia.MapControls.Traffic:
controls.push(allControls[i]);
break;
}
}
}
return controls;
};
/**
* Returns the map internal ID.
* @return {string} map internal ID.
*/
cercalia.Map.prototype.getId = function() {
return this.id_;
};
/**
* Returns the container ID
* @private
* @return {string} id Map container Id
*/
cercalia.Map.prototype.getContainerId = function() {
return this.containerId_;
};
/**
* Returns the OpenLayers3 object <a href='http://openlayers.org/en/v3.6.0/apidoc/ol.Map.html'>`ol.Map`</a>
* @return {ol.Map} Map
*/
cercalia.Map.prototype.getMap = function() {
return this.map_;
};
/**
* Returns the layer (<a href='http://openlayers.org/en/v3.6.0/apidoc/ol.layer.Tile.html'>ol.layer.Tile</a>) used as basemap
* @return {ol.layer.Tile}
*/
cercalia.Map.prototype.getBaseLayer = function() {
return this.getMap().getLayers().getArray()[0];
};
/**
* Returns the drag interaction.
* @return {ol.interaction.DragInteraction}
*/
cercalia.Map.prototype.getDragInteraction = function() {
return this.dragInteraction_;
};
/**
* Returns the draw interaction.
* @return {ol.interaction.DrawInteraction}
*/
cercalia.Map.prototype.getDrawInteraction = function() {
return this.drawInteraction_;
};
/**
* Returns the map center.
* @return {cercalia.LonLat} Coordinates.
*/
cercalia.Map.prototype.getCenter = function() {
var coordsGeo = ol.proj.transform(this.map_.getView().getCenter(), this.projectionCode_, 'EPSG:4326');
return new cercalia.LonLat(coordsGeo[0], coordsGeo[1]);
};
/**
* Set the map center
* @param {cercalia.LonLat} lonLat Coordinates
* @param {number} zoom Zoom
* @param {boolean|undefined} animation Animation, activated by default
*/
cercalia.Map.prototype.setCenter = function(lonLat, zoom, animation) {
var currentResolution = this.map_.getView().getResolution();
if (typeof(animation) == "undefined" || animation) {
this.getMap().beforeRender(
ol.animation.zoom({
resolution: currentResolution,
duration: 1000,
easing: ol.easing.easeOut
}),
ol.animation.pan({
duration: 1000,
source: this.map_.getView().getCenter(),
start: +new Date()
})
);
}
this.map_.getView().setCenter(ol.proj.transform([lonLat.getLon(), lonLat.getLat()], 'EPSG:4326', this.projectionCode_));
if (zoom) {
this.map_.getView().setZoom(zoom);
}
};
/**
* @return {number} Current zoom level of map.
*/
cercalia.Map.prototype.getZoom = function() {
return this.map_.getView().getZoom();
};
/**
* Set the zoom level of map. If second parameter is specified (boolean, optional), can apply animation effect
* @param {number} zoom Zoom level to adjust
* @param {boolean} animation True/False if want to apply animation effect. Defaulf: true
*/
cercalia.Map.prototype.setZoom = function(zoom, animation) {
if (typeof(animation) == "undefined" || animation) {
var zoomAnimation = ol.animation.zoom({
resolution: this.map_.getView().getResolution()
});
this.map_.beforeRender(zoomAnimation);
}
this.map_.getView().setZoom(zoom);
};
/**
* Returns the pixel value from a coordinate
* @param {cercalia.LonLat} lonLat
* @return {ol.Pixel}
*/
cercalia.Map.prototype.coordToPixel = function(lonLat) {
var coordinate = ol.proj.transform([lonLat.getLon(), lonLat.getLat()], 'EPSG:4326', this.projectionCode_);
return this.map_.getPixelFromCoordinate(coordinate);
};
/**
* Returns the coordinate from a pixel value
* @param {ol.Pixel} pixel
* @return {cercalia.LonLat} Coordinate
*/
cercalia.Map.prototype.pixelToCoord = function(pixel) {
var coordinate = this.map_.getCoordinateFromPixel(pixel);
var coordGeo = ol.proj.transform(coordinate, this.projectionCode_, 'EPSG:4326');
return new cercalia.LonLat(coordGeo[0], coordGeo[1]);
};
/**
* Obtains pixel
* @param {event} evt
* @return {Pixel}
*/
cercalia.Map.prototype.getEventPixel = function(evt) {
return this.map_.getEventPixel(evt.originalEvent);
};
/**
* @param {event} evt
* @return {cercalia.LonLat}
*/
cercalia.Map.prototype.getEventCoordinate = function(evt) {
var coord = this.map_.getEventCoordinate(evt.originalEvent);
var coordGeo = ol.proj.transform(coord, this.projectionCode_, 'EPSG:4326');
return new cercalia.LonLat(coordGeo[0], coordGeo[1]);
};
/**
* Calculate the real distance in meters, from pixels values.
* @param {number} pixels
* @return {number} meters
*/
cercalia.Map.prototype.pixelsToMeters = function(pixels) {
var size = this.map_.getSize();
var view = this.map_.getView();
var extent = view.calculateExtent(size);
var widthPixels = size[0];
var widthMeters = extent[2] - extent[0];
return (widthMeters / widthPixels) * pixels;
};
/**
*
* @param {string} layerName
* @return {ol.layer} Layer objeto ol3
*/
cercalia.Map.prototype.getLayerByName = function(layerName) {
var layers = this.map_.getLayers();
var numLayers = layers.getLength();
for (var i = 0; i < numLayers; i++) {
if (layers.item(i).get('name') == layerName) {
return layers.item(i);
}
}
return null;
};
/**
* Obtains the map control from its name. Complete controls list (if are created): <br/>
* - `cercalia.MapControls.CleanControl`<br/>
* - `cercalia.MapControls.DragControl`<br/>
* - `cercalia.MapControls.DrawControl`<br/>
* - `cercalia.MapControls.FullScreen`<br/>
* - `cercalia.MapControls.LayerSwitcher`<br/>
* - `cercalia.MapControls.Logistics`<br/>
* - `cercalia.MapControls.MeasureControl`<br/>
* - `cercalia.MapControls.MeteoControl`<br/>
* - `cercalia.MapControls.RotateNorth`<br/>
* - `cercalia.MapControls.ScaleLine`<br/>
* - `cercalia.MapControls.StreetView`<br/>
* - `cercalia.MapControls.Traffic`<br/>
* - `cercalia.MapControls.Zoom`<br/>
* - `cercalia.MapControls.ZoomSlider`
*
* @param {string} controlName
* @return {ol.Control}
*/
cercalia.Map.prototype.getControlsByName = function(controlName) {
var arrayControls = this.map_.getControls().getArray();
for (var i = 0; i < arrayControls.length; i++) {
if (arrayControls[i].getName && arrayControls[i].getName() == controlName) {
return arrayControls[i];
}
}
return null;
};
/**
* Centers the map with animation (or not) to the markers list. Optionally it's possible to change the zoom for including all the markers.
* If markers array is not specified, by default centers to all markers
* @param {Array.<cercalia.Marker>|undefined} markers
* @param {boolean} changeZoom Default: true
* @param {boolean} animation Default: true
*/
cercalia.Map.prototype.centerToMarkers = function(markers, changeZoom, animation) {
var bounds = new cercalia.Bounds();
if (markers) {
if (!(markers instanceof Array)) {
markers = [markers];
}
for (var i = 0; i < markers.length; i++) {
bounds.extend(markers[i].getPosition());
}
} else {
//todos los markers (si no se pasa por parametro)
var featuresOL = this.markerLayer_.getSource().getFeatures();
var draggableFeaturesOl = this.dragLayer_.getSource().getFeatures();
//Evitamos el marker draggable..
for (var i = 0; i < draggableFeaturesOl.length; i++) {
if (draggableFeaturesOl[i].getId().indexOf("MarkerRouteDrag") === -1) {
featuresOL.push(draggableFeaturesOl[i]);
}
}
for (var i = 0; i < featuresOL.length; i++) {
if (featuresOL[i].marker_) {
bounds.extend(featuresOL[i].marker_.getPosition());
}
}
}
if (bounds.getTop()) {
if (typeof(changeZoom) == "undefined" || changeZoom) {
if (bounds.getWidthInMeters() > 200 || bounds.getHeightInMeters() > 120) {
this.fitBounds(bounds, typeof(animation) == "undefined" || animation);
} else {
this.setCenter(bounds.getCenterLonLat(), 19, false);
}
} else {
this.panTo(bounds.getCenterLonLat(), typeof(animation) == "undefined" || animation);
}
}
};
/**
* Center the map
* @param {Array.<cercalia.Feature>|cercalia.Feature} features Features list or object.
* @param {number} changeZoom Change zoom on features center. Default: true
* @param {boolean} animation Animation. Default: true
*/
cercalia.Map.prototype.centerToFeatures = function(features, changeZoom, animation) {
var bounds = new cercalia.Bounds();
if (features) {
if (!(features instanceof Array)) {
features = [features];
}
for (var i = 0; i < features.length; i++) {
bounds.extend(features[i].getBounds());
}
} else {
//todos los markers (si no se pasa por parametro)
var featuresOL = this.featureLayer_.getSource().getFeatures();
for (var i = 0; i < featuresOL.length; i++) {
if (featuresOL[i].feature_) {
bounds.extend(featuresOL[i].feature_.getBounds());
}
}
}
if (bounds.getTop()) {
if (typeof(changeZoom) == "undefined" || changeZoom) {
this.fitBounds(bounds, typeof(animation) == "undefined" || animation);
} else {
this.panTo(bounds.getCenterLonLat(), animation);
}
}
};
/**
* Returns the current bounds
* @return {cercalia.Bounds} Current bounds, according to the zoom level, position and widht-height
*/
cercalia.Map.prototype.getBounds = function() {
var extent = this.map_.getView().calculateExtent(this.map_.getSize());
var extentGdd = ol.proj.transformExtent(extent, this.projectionCode_, 'EPSG:4326');
return new cercalia.Bounds(extentGdd);
};
/**
* Fit the bounds: change the current map bounds to new bounds.
* By default applies animation effect
* @param {cercalia.Bounds} bounds New bounds
* @param {boolean} animation True/False, if want to apply animation or not. Default: true
*/
cercalia.Map.prototype.fitBounds = function(bounds, animation) {
if (bounds instanceof cercalia.Bounds) {
var currentResolution = this.map_.getView().getResolution();
if (typeof(animation) == "undefined" || animation) {
this.getMap().beforeRender(
ol.animation.zoom({
resolution: currentResolution,
duration: 1000,
easing: ol.easing.easeOut
}),
ol.animation.pan({
duration: 1000,
source: this.map_.getView().getCenter(),
start: +new Date()
})
);
}
this.map_.getView().fitExtent(ol.proj.transformExtent(bounds.cloneIncreasingPercentage("15").toArray(), 'EPSG:4326', this.projectionCode_), this.map_.getSize());
} else {
cercalia.Exception(cercalia.i18n._('Type of parameter is not "%"', ['cercalia.Bounds']));
}
};
/**
* Map center maintaining the zoom level
* @param {cercalia.Bounds} bounds Mapbounds.
* @param {boolean} animation Boolean for apply or not animation effect. Values: `true` or `false`.
* @param {number} duration Animation duration (in miliseconds). Default `2000`.
*/
cercalia.Map.prototype.panToBounds = function(bounds, animation, duration) {
this.panTo(bounds.getCenterLonLat(), animation, duration);
};
/**
* Moves the map to the new center. Optional: animation effect-
* @param {cercalia.LonLat} lonLat Coordinate
* @param {string} animation Boolean animation effect. Values `true` or `false`, specifying the type of animation:
* `cercalia.MapAnimation.ROTATE_LEFT`,
* `cercalia.MapAnimation.ROTATE_RIGHT`,
* `cercalia.MapAnimation.PAN`,
* `cercalia.MapAnimation.ELASTIC`,
* `cercalia.MapAnimation.BOUNCE`,
* `cercalia.MapAnimation.FLY`,
* `cercalia.MapAnimation.SPIRAL`
* @param {number} duration Animation duration (in miliseconds). Defaulf `2000`.
*/
cercalia.Map.prototype.panTo = function(lonLat, animation, duration) {
var olAnimation = null;
var durationAnim = duration ? duration : 2000;
if (animation || typeof(animation) == "undefined") {
switch (animation) {
case cercalia.MapAnimation.ROTATE_LEFT:
var start = +new Date();
var olAnimation = ol.animation.pan({
duration: durationAnim,
source: this.map_.getView().getCenter(),
start: start
});
var olAnimation2 = ol.animation.rotate({
duration: durationAnim,
rotation: -2 * Math.PI,
start: start
});
this.map_.beforeRender(olAnimation, olAnimation2);
break;
case cercalia.MapAnimation.ROTATE_RIGHT:
var start = +new Date();
var olAnimation = ol.animation.pan({
duration: durationAnim,
source: this.map_.getView().getCenter(),
start: start
});
var olAnimation2 = ol.animation.rotate({
duration: durationAnim,
rotation: 2 * Math.PI,
start: start
});
this.map_.beforeRender(olAnimation, olAnimation2);
break;
case cercalia.MapAnimation.PAN:
olAnimation = ol.animation.pan({
duration: durationAnim,
source: this.map_.getView().getCenter()
});
this.map_.beforeRender(olAnimation);
break;
case cercalia.MapAnimation.ELASTIC:
olAnimation = ol.animation.rotate({
duration: durationAnim,
easing: ol.easing.elastic,
source: this.map_.getView().getCenter()
});
this.map_.beforeRender(olAnimation);
break;
case cercalia.MapAnimation.BOUNCE:
olAnimation = ol.animation.rotate({
duration: durationAnim,
easing: ol.easing.bounce,
rotation: -4 * Math.PI
});
this.map_.beforeRender(olAnimation);
break;
case cercalia.MapAnimation.FLY:
var start = +new Date();
olAnimation = ol.animation.pan({
duration: durationAnim,
source: this.map_.getView().getCenter(),
start: start
});
var olAnimation2 = ol.animation.bounce({
duration: durationAnim,
resolution: 4 * this.map_.getView().getResolution(),
start: start
});
this.map_.beforeRender(olAnimation, olAnimation2);
break;
case cercalia.MapAnimation.SPIRAL:
var start = +new Date();
olAnimation = ol.animation.pan({
duration: durationAnim,
source: this.map_.getView().getCenter(),
start: start
});
var olAnimation2 = ol.animation.bounce({
duration: durationAnim,
resolution: 2 * this.map_.getView().getResolution(),
start: start
});
var olAnimation3 = ol.animation.rotate({
duration: durationAnim,
rotation: -4 * Math.PI,
start: start
});
this.map_.beforeRender(olAnimation, olAnimation2, olAnimation3);
break;
default:
olAnimation = ol.animation.pan({
duration: durationAnim,
source: this.map_.getView().getCenter()
});
this.map_.beforeRender(olAnimation);
break;
}
}
this.map_.getView().setCenter(ol.proj.transform([lonLat.getLon(), lonLat.getLat()], 'EPSG:4326', this.projectionCode_));
};
/**
* Sets the map rotation
* @param {number} angle
*/
cercalia.Map.prototype.setRotation = function(angle) {
this.map_.getView().setRotation(Math.PI * angle / 180);
};
/**
* Rotates the map <angle> degrees, by parameter
* @param {number} angle Angle (degrees).
*/
cercalia.Map.prototype.rotate = function(angle) {
var rotAct = this.map_.getView().getRotation();
this.map_.getView().setRotation(rotAct + (Math.PI * angle / 180));
};
/**
* Obtains the map projection code
* @return {string} EPSG code. For example: `EPSG:3857`.
*/
cercalia.Map.prototype.getProjectionCode = function() {
return this.map_.getView().getProjection().getCode();
};
/**
* Fixes the minimum and maximum zoom level
* @param {number|boolean} minZoom Min zoom, false if don't want this limit
* @param {number|boolean} maxZoom Max zoom, false if don't want this limit
* @param {cercalia.Bounds} bounds Map bounds limits
*/
cercalia.Map.prototype.setRestrictedView = function(minZoom, maxZoom, bounds) {
if (minZoom) this.viewOptions_.minZoom = minZoom;
if (maxZoom) this.viewOptions_.maxZoom = maxZoom;
if (bounds) this.viewOptions_.extent = ol.proj.transformExtent(bounds.toArray(), 'EPSG:4326', this.projectionCode_);
this.viewOptions_.resolution = this.map_.getView().getResolution();
this.viewOptions_.center = this.map_.getView().getCenter();
var view = new ol.View(this.viewOptions_);
this.map_.setView(view);
};
/**
* Changes the projection to basemap and all the layers painted over it (markers, features, WMS, etc).
* @param {ol.Projection} projection Projection.
*/
cercalia.Map.prototype.setProjection = function(projection) {
if (projection != this.mapProjection_) {
var self = this;
var center = this.getCenter();
this.viewOptions_.projection = projection;
this.viewOptions_.resolution = this.map_.getView().getResolution();
this.viewOptions_.center = this.map_.getView().getCenter();
var view = new ol.View(this.viewOptions_);
var projectionAnt = this.getProjectionCode();
this.mapProjection_ = projection;
this.projectionCode_ = projection.getCode();
this.map_.setView(view);
//this.map_.getView().setResolution(map.getMap().getView().constrainResolution(map.getMap().getView().getResolution()));
//this.map_.getView().setResolution(view.constrainResolution(view.getResolution()));
//this.setCenter(center,false,false);
var newExtent = ol.proj.transformExtent(this.getBounds().toArray(), 'EPSG:4326', this.projectionCode_);
this.map_.getView().fitExtent(newExtent, this.map_.getSize());
//Cambiar la proyeccion de todos los features de todos los layers
var allLayers = this.map_.getLayers();
//Desactivamos durante la reproyeccion si el clusternig está activado
var clusteringEnabled = this.clusterLayer_ != null;
if (clusteringEnabled) {
this.disableClustering();
}
allLayers.forEach(function(layerAct, index) {
if (layerAct instanceof ol.layer.Vector) {
var source = layerAct.getSource();
//Solució indefinida pels markers (si no borrem i treiem els markers, després falla tot el tema del dragging)
if (layerAct == self.markerLayer_ || layerAct == self.dragLayer_) {
var arrMarkers = [];
source.getFeatures().forEach(function(featureAct, index) {
featureAct.getGeometry().transform(projectionAnt, projection.getCode());
if (featureAct.getCercaliaObject) {
var markerAct = featureAct.getCercaliaObject();
markerAct.refreshPositionFromGeometry(); //pels labels&simple labels
arrMarkers.push(markerAct);
}
});
if (arrMarkers.length > 0) {
self.removeMarkers(arrMarkers);
self.addMarkers(arrMarkers);
}
} else {
source.getFeatures().forEach(function(featureAct, index) {
featureAct.getGeometry().transform(projectionAnt, projection.getCode());
});
}
}
});
//Activamos después de la reproyeccion si el clusternig está activado
if (clusteringEnabled) {
this.enableClustering();
}
var allOverlays = this.map_.getOverlays().getArray();
//allOverlays.forEach(function(overlay, index) {
// if (overlay.getPosition()) {
// overlay.setPosition(ol.proj.transform(overlay.getPosition(),projectionAnt, projection.getCode()));
// }
//});
}
};
/**
* Adds a WMS layer {@link cercalia.WMS} to the map
* @param {cercalia.WMS} wmsLayer
* @param {number} position WMSLayer position. If not declared, it's included just one level over the basemap.
*/
cercalia.Map.prototype.addWMSLayer = function(wmsLayer, position) {
wmsLayer.setMap(this, position ? position : 1);
};
/**
* Remove a WMS layer {@link cercalia.WMS} from the map
* @param {cercalia.WMS} wmsLayer
*/
cercalia.Map.prototype.removeWMSLayer = function(wmsLayer) {
wmsLayer.setMap(null);
};
/**
* Returns the layer (<a href='http://openlayers.org/en/v3.6.0/apidoc/ol.layer.Vector.html'>`ol.layer.Vector`</a>) used
* for painting on the map.
* @return {ol.layer.Vector} layer
*/
cercalia.Map.prototype.getDrawLayer = function() {
return this.drawLayer_;
};
/**
* Obtains the layer position (Z value). The layers are painted respecting Z position: 0 is the base map.
* @param {string} layerName
* @return {number} Layer position
*/
cercalia.Map.prototype.getLayerIndexByName = function(layerName) {
var layers = this.map_.getLayers();
var numLayers = layers.getLength();
for (var i = 0; i < numLayers; i++) {
if (layers.item(i).get('name') == layerName) {
return i;
}
}
return null;
};
/**
* @private
* @param {Array.<cercalia.Marker>|Array.<cercalia.Linestring>|Array.<cercalia.Feature>} arrayElements
* @param {boolean} checkIfMouseOver
* @return {Array.<ol.Feature>}
*/
cercalia.Map.prototype.arrayElementsToFeatures_ = function(arrayElements, layerToAdd) {
var arrayFeatures = [];
var arrayFeaturesDraggables = [];
var numElements = arrayElements.length;
for (var i = 0; i < numElements; i++) {
var featureOL = arrayElements[i].getFeature();
arrayFeatures.push(featureOL);
arrayElements[i].setMap(this);
if (arrayElements[i].isDraggable()) {
arrayFeaturesDraggables.push(featureOL);
}
}
this.putMarkerToLayerNoDrag_(layerToAdd, arrayFeatures, this.dragLayer_);
if (arrayFeaturesDraggables.length > 0) {
this.addMarkerToDragLayer_(arrayFeaturesDraggables, layerToAdd);
}
return arrayFeatures;
};
/**
* Paint {@link cercalia.Marker} list on the map.
* @param {cercalia.Marker} marker
*/
cercalia.Map.prototype.addMarker = function(marker) {
this.putMarkerToLayerNoDrag_(this.markerLayer_, marker.getFeature(), this.dragLayer_);
if (marker.isDraggable()) {
this.addMarkerToDragLayer_(marker, this.markerLayer_);
} else {
this.removeMarkerFromDragLayer_(marker);
}
marker.setMap(this);
};
/**
* Paint on the map the {@link cercalia.Marker} list. In this function must send an `Array`.
* @param {Array.<cercalia.Marker>} markers
*/
cercalia.Map.prototype.addMarkers = function(markers) {
var arrayFeatures = this.arrayElementsToFeatures_(markers, this.markerLayer_);
};
/**
* @private
* @param {Array.<cercalia.Marker>} markers
*/
cercalia.Map.prototype.addApiMarkers = function(markers) {
var arrayFeatures = this.arrayElementsToFeatures_(markers, this.markerApiLayer_);
};
/**
* Paint {@link cercalia.Linestring} on the map
* @param {cercalia.Linestring} linestring
*/
cercalia.Map.prototype.addLinestring = function(linestring) {
this.putMarkerToLayerNoDrag_(this.routeLayer_, linestring.getFeature(), this.dragLayer_);
if (linestring.isDraggable()) {
this.addMarkerToDragLayer_(linestring, this.routeLayer_);
}
linestring.setMap(this);
};
/**
* Paint on the map the {@link cercalia.Linestring} list. In this function must send an `Array`.
* @param {Array.<cercalia.Linestring>} linestrings
*/
cercalia.Map.prototype.addLinestrings = function(linestrings) {
var arrayFeatures = this.arrayElementsToFeatures_(linestrings, this.routeLayer_);
};
/**
* Paint {@link cercalia.Feature} on the map.
* @param {cercalia.Feature} feature
* @param {ol.Layer|undefined} layer
*/
cercalia.Map.prototype.addFeature = function(feature, layer) {
layer = layer ? layer : this.featureLayer_;
//this.featureLayer_.getSource().addFeature(feature.getFeature());
this.putMarkerToLayerNoDrag_(layer, feature, this.dragLayer_);
if (feature.isDraggable()) {
// try {
this.addMarkerToDragLayer_(feature, layer);
// }catch(e) {
// //Si no da tiempo a inicializarse del todo da un error aunque el push ha finalizado correctamente. Parece que no afecta a nada.
// }
} else {
this.removeMarkerFromDragLayer_(feature);
}
feature.setMap(this);
if (feature.isEditable()) {
//this.editableFeaturesCollection_.push(feature.getFeature());
}
};
/**
* Set feature editable.
* @param {cercalia.Feature} feature Feature to be edited.
* @param {boolean} edit Set the feature as editable or not.
*/
cercalia.Map.prototype.setFeatureEditable = function(feature, edit) {
// mirem si la interaction està activa i la desactivem
var isActive = this.isModifyControlActive_();
this.enableFeatureEditable(false);
// afegim o treiem feature
if (edit) {
this.editableFeaturesCollection_.push(feature.getFeature());
} else {
this.editableFeaturesCollection_.remove(feature.getFeature());
}
// activem la interacció si ho estava
this.enableFeatureEditable(true);
};
/**
* Set the features as editables if it isn't, or change to not editable if it's editable.
* @param {boolean} enable Set on/off the editable mode.
*/
cercalia.Map.prototype.enableFeatureEditable = function(enable) {
if (enable && !this.isModifyControlActive_()) {
this.map_.addInteraction(this.modifyControl_);
} else if (!enable && this.isModifyControlActive_()) {
this.map_.removeInteraction(this.modifyControl_);
}
};
/**
* Returns interaction status
* @private
* @returns {boolean}
*/
cercalia.Map.prototype.isModifyControlActive_ = function() {
return this.map_.getInteractions().getArray().indexOf(this.modifyControl_) != -1;
};
/**
* Paint several {@link cercalia.Feature} on the map. Must send an `Array`.
* @param {Array.<cercalia.Feature>} features Array de {@link cercalia.Feature}
* @param {ol.layer} layer
*/
cercalia.Map.prototype.addFeatures = function(features, layer) {
var arrayFeatures = this.arrayElementsToFeatures_(features, layer ? layer : this.featureLayer_);
};
/**
* Obtain all the {@link cercalia.Marker} painted on the map
* @return {Array.<cercalia.Marker>|null} Marker list painted on the map
*/
cercalia.Map.prototype.getMarkers = function() {
var arrayMarkers = this.getFeaturesByLayer_(this.markerLayer_);
var featuresDraggables = this.getFeaturesByLayer_(this.dragLayer_); //quan son draggables estan en un altre layer.
for (var i = featuresDraggables.length - 1; i >= 0; i--) { //Evitem retornar el marker draggable de ruta que tambe esta al layer.
if (!(featuresDraggables[i] instanceof cercalia.Marker) || (featuresDraggables[i].getId().indexOf("MarkerRouteDrag") !== -1)) {
featuresDraggables.splice(i, 1);
}
}
return arrayMarkers.concat(featuresDraggables);
};
/**
* @return {cercalia.Marker} marker
*/
cercalia.Map.prototype.getMarkerById = function(id) {
var feature = this.markerLayer_.getSource().getFeatureById(id);
if (!feature) {
feature = this.dragLayer_.getSource().getFeatureById(id);
}
var marker = feature ? feature.getCercaliaObject() : null;
return marker;
};
/**
* Obtain all the {@link cercalia.Linestring} painted on the map
* @return {Array.<cercalia.Linestring>|null} Linestrings list painted on the map
*/
cercalia.Map.prototype.getLinestrings = function() {
return this.getFeaturesByLayer_(this.routeLayer_);
};
/**
* Obtain all the {@link cercalia.Feature} painted on the map
* @return {Array.<cercalia.Linestring>|null} Linestring list painted on the map
*/
cercalia.Map.prototype.getFeatures = function() {
var features = this.getFeaturesByLayer_(this.featureLayer_);
var dragFeatures = this.getFeaturesByLayer_(this.dragLayer_, 'cercalia.Feature'); //dragLayer contiene cercalia.Feature, cercalia.Marker..
return features.concat(dragFeatures);
};
/**
* @private
* @param {ol.layer} layer Layer
* @param {opt_className} opt_type Optional filter by className. For example `cercalia.Marker` or `cercalia.Feature`
* @return {Array.<cercalia.Marker>|Array.<cercalia.Linestring>|Array.<cercalia.Feature>}
*/
cercalia.Map.prototype.getFeaturesByLayer_ = function(layer, opt_type) {
var arrayFeatures = layer.getSource().getFeatures();
var features = [];
for (var i = 0; i < arrayFeatures.length; i++) {
var featureAct = arrayFeatures[i].getCercaliaObject();
if (opt_type) {
if (featureAct.getClass() === opt_type) {
features.push(featureAct);
}
} else {
//All. No filtering
features.push(featureAct);
}
}
return features;
};
/**
* Show the markers painted on the map. This function is usefull when some or all markers are hidden.
* @param {cercalia.Marker|Array.<cercalia.Marker>} markers
* @param {boolean} show
*/
cercalia.Map.prototype.showMarkers = function(markers, show) {
if (markers instanceof Array) {
for (var i = 0; i < markers.length; i++) {
markers[i].setVisible(show);
}
} else {
markers.setVisible(show);
}
//this.refreshClustering_();
};
/**
* Remove markers list from map
* @param {cercalia.Marker|Array.cercalia.Marker} markers
*/
cercalia.Map.prototype.removeMarkers = function(markers) {
if (markers != null) {
this.removeFeaturesByLayer_(markers, this.markerLayer_);
}
};
/**
* Remove API markers list from map
* @param {cercalia.Marker|Array.<cercalia.Marker>} markers
*/
cercalia.Map.prototype.removeApiMarkers = function(markers) {
if (markers != null) {
this.removeFeaturesByLayer_(markers, this.markerApiLayer_);
}
};
/**
* Remove linestring list from map
* @param {cercalia.Linestring|Array.<cercalia.Linestring>} linestrings
*/
cercalia.Map.prototype.removeLinestrings = function(linestrings) {
this.removeFeaturesByLayer_(linestrings, this.routeLayer_);
};
/**
* Remove features list from map
* @param {cercalia.Feature|Array.<cercalia.Feature>} features
* @param {ol.Layer|undefined} layer If not defined it will remove features in internal Cercalia layer.
*/
cercalia.Map.prototype.removeFeatures = function(features, layer) {
this.removeFeaturesByLayer_(features, layer ? layer : this.featureLayer_);
};
/**
* @private
* @param {cercalia.Marker|Array.<cercalia.Marker>|cercalia.Linestring|Array.<cercalia.Linestring>|cercalia.Feature|Array.<cercalia.Feature>} features
* @param {ol.layer} layer
*/
cercalia.Map.prototype.removeFeaturesByLayer_ = function(features, layer) {
if (features instanceof Array) {
for (var i = features.length - 1; i >= 0; i--) {
this.removeFeatureByLayer_(features[i], layer);
}
} else {
this.removeFeatureByLayer_(features, layer);
}
};
/**
*
* @private
* @param {cercalia.Marker|cercalia.Linestring|cercalia.Feature} feature
* @param {ol.layer} layer
*/
cercalia.Map.prototype.removeFeatureByLayer_ = function(feature, layer) {
var featureOL, featureCercalia;
if (feature instanceof ol.Feature) {
featureOL = feature;
featureCercalia = feature.getCercaliaObject();
} else {
featureOL = feature.getFeature();
featureCercalia = feature;
}
if (featureOL) {
this.removeMarkerToLayerNoDrag_(layer, featureOL);
}
if (featureCercalia) {
featureCercalia.setMap(null);
if (featureCercalia.isDraggable()) {
this.removeMarkerFromDragLayer_(featureOL);
//this.dragFeatures_.remove(featureOL);
}
}
};
/**
* Clean all markers and popups
*/
cercalia.Map.prototype.removeAllMarkers = function() {
var arrayFeatures = this.markerLayer_.getSource().getFeatures();
this.removeFeaturesByLayer_(arrayFeatures, this.markerLayer_);
};
/**
* Clean all linestrings
*/
cercalia.Map.prototype.removeAllLinestrings = function() {
var arrayFeatures = this.routeLayer_.getSource().getFeatures();
this.removeFeaturesByLayer_(arrayFeatures, this.routeLayer_);
};
/**
* Clean all features
*/
cercalia.Map.prototype.removeAllFeatures = function() {
var arrayFeatures = this.featureLayer_.getSource().getFeatures();
this.removeFeaturesByLayer_(arrayFeatures, this.featureLayer_);
};
/**
* Clean all the features painted on the map with draw tool.
* Layer 'DrawLayer'
*/
cercalia.Map.prototype.removeDrawFeatures = function() {
var source = this.getDrawLayer().getSource();
var arrayFeatures = source.getFeatures();
for (var i = arrayFeatures.length - 1; i >= 0; i--) {
source.removeFeature(arrayFeatures[i]);
arrayFeatures[i] = null;
}
arrayFeatures = null;
};
/**
* Clean all overlays painted on the map
*/
cercalia.Map.prototype.removeAllOverlays = function() {
this.removeAllMarkers();
this.removeAllLinestrings();
this.removeAllFeatures();
this.removeDrawFeatures();
if (this.routing_) {
this.routing_.removeRoute();
}
};
/**
* Hide all labels {@link cercalia.Label} from markers painted on the map
*/
cercalia.Map.prototype.hideLabels = function() {
var markers = this.getMarkers();
for (var i = 0; i < markers.length; i++) {
markers[i].hideLabel();
}
this.visibleLabels_ = false;
};
/**
* Show all labels {@link cercalia.Label} from markers painted on the map
*/
cercalia.Map.prototype.showLabels = function() {
// var arrayFeatures = this.markerLayer_.getSource().getFeatures();
// for (var i = 0; i < arrayFeatures.length; i++) {
// arrayFeatures[i].marker_.showLabel();
// }
var markers = this.getMarkers();
for (var i = 0; i < markers.length; i++) {
markers[i].showLabel();
}
this.visibleLabels_ = true;
};
/**
* Returns boolean showing if all labels are showing or hidden.
* @returns {Boolean}
*/
cercalia.Map.prototype.showingLabels = function() {
return this.visibleLabels_;
};
/**
* Close all popups opened
*/
cercalia.Map.prototype.closePopups = function() {
var arrayFeatures = this.markerLayer_.getSource().getFeatures();
for (var i = 0; i < arrayFeatures.length; i++) {
var popup = arrayFeatures[i].marker_.getPopup();
if (popup) {
popup.hide();
}
}
};
/**
* Show all markers popups. Only for markers with popup created
*/
cercalia.Map.prototype.openPopups = function() {
var arrayFeatures = this.markerLayer_.getSource().getFeatures();
for (var i = 0; i < arrayFeatures.length; i++) {
arrayFeatures[i].marker_.getPopup().show();
}
};
/**
* @param {string|cercalia.WMS|ol.layer.Layer|ol.layer.Group} mapType Change base map. <br/>
* Maps avaliable by default. String: <br/>
* - `cercalia.MapTypes.CERCALIA` Cercalia<br/>
* - `cercalia.MapTypes.OSM` Cercalia<br/>
* - `cercalia.MapTypes.SATELLITE` <br/>
* - `cercalia.MapTypes.HYBRID` <br/>
* <br/>
* Also can use a WMS layer (object cercalia.WMS), that will be set as base Layer.
* Also can add layers using OpenLayers classes
* <a href="http://openlayers.org/en/v3.6.0/apidoc/ol.layer.Layer.html">`ol.layer.Layer`</a> y
* <a href="http://openlayers.org/en/v3.6.0/apidoc/ol.layer.Group.html">`ol.layer.Group`</a>.
*/
cercalia.Map.prototype.setBaseLayer = function(mapType) {
//Borrem el base Layer
this.removeLayer(this.getBaseLayer());
if (typeof(mapType) == "string") {
var layer = this.createBaseLayer_(mapType);
this.addLayer(layer, 0);
} else if (mapType instanceof cercalia.WMS) {
this.addLayer(mapType.getLayer(), 0);
} else if (mapType instanceof ol.layer.Layer) {
this.addLayer(mapType, 0);
} else if (mapType instanceof ol.layer.Group) {
this.addLayer(mapType, 0);
} else {
alert('Unknown setBaseLayer: ' + mapType);
}
this.onMoveEnd_();
};
cercalia.Map.prototype.getMapboxSatelliteUrls_ = function() {
var mapboxToken = 'pk.eyJ1IjoibmV4dXNnZW9ncmFmaWNzIiwiYSI6InZDVTlYYXcifQ.lEWyf37JNHHw_5s--HjJHA';
return [
'https://a.tiles.mapbox.com/v4/mapbox.satellite/{z}/{x}/{y}.jpg90?access_token=' + mapboxToken,
'https://b.tiles.mapbox.com/v4/mapbox.satellite/{z}/{x}/{y}.jpg90?access_token=' + mapboxToken,
'https://c.tiles.mapbox.com/v4/mapbox.satellite/{z}/{x}/{y}.jpg90?access_token=' + mapboxToken,
'https://d.tiles.mapbox.com/v4/mapbox.satellite/{z}/{x}/{y}.jpg90?access_token=' + mapboxToken
];
}
/**
* @private
* @param {string} baseLayer
* @return {ol.layer.Tile}
*/
cercalia.Map.prototype.createBaseLayer_ = function(baseLayer) {
this.baseLayerName_ = baseLayer ? baseLayer : cercalia.MapTypes.CERCALIA
if (this.baseLayerName_ == cercalia.MapTypes.CERCALIA) {
var baseLayerSource = new ol.source.XYZ({
urls: servers.backgroundXYZ,
crossOrigin: 'anonymous'
});
return new ol.layer.Tile({
source: baseLayerSource,
name: cercalia.MapTypes.CERCALIA,
baseLayer: true
});
} else if (this.baseLayerName_ == cercalia.MapTypes.MAPQUEST || this.baseLayerName_ == cercalia.MapTypes.OSM) {
var baseLayerSource = new ol.source.OSM();
return new ol.layer.Tile({
source: baseLayerSource,
name: this.baseLayerName_,
baseLayer: true
});
} else if (baseLayer == cercalia.MapTypes.HYBRID) {
var baseLayerSource = new ol.source.XYZ({
attributions: [new ol.Attribution({
html: "Tiles © <a href='http://mapbox.com/'>MapBox</a>"
})],
urls: this.getMapboxSatelliteUrls_(),
crossOrigin: 'anonymous'
});
var satelliteLayer = new ol.layer.Tile({
source: baseLayerSource,
name: this.baseLayerName_,
baseLayer: true
});
var labelLayer = new ol.layer.Tile({
source: new ol.source.TileWMS({
urls: [
'https://cdn1.cercalia.com/cgi-bin/mapserv7?map=/usr/nexus/cercalia2/WMS_hibrid.map',
'https://cdn2.cercalia.com/cgi-bin/mapserv7?map=/usr/nexus/cercalia2/WMS_hibrid.map'
],
params: {
'LAYERS': 'default'
}
})
});
return new ol.layer.Group({
layers: [satelliteLayer, labelLayer]
});
} else if (baseLayer == cercalia.MapTypes.OPENSTREETMAP) {
return new ol.layer.Tile({
source: new ol.source.OSM(),
name: this.baseLayerName_,
baseLayer: true
});
} else if (baseLayer == cercalia.MapTypes.SATELLITE) {
var baseLayerSource = new ol.source.XYZ({
attributions: [new ol.Attribution({
html: "Tiles © <a href='http://mapbox.com/'>MapBox</a>"
})],
crossOrigin: 'anonymous',
urls: this.getMapboxSatelliteUrls_()
});
return new ol.layer.Tile({
source: baseLayerSource,
name: cercalia.MapTypes.SATELLITE,
baseLayer: true
});
}
};
/**
* Create topbar
* @return {Element}
*/
cercalia.Map.prototype.createTopBar = function() {
if (!this.topBarElement_) {
var topBarId = "topBar_" + this.id_;
this.topBarElement_ = document.createElement('div');
this.topBarElement_.setAttribute('id', topBarId);
this.topBarElement_.className = 'cercalia-bar-top';
var container = document.getElementById(this.containerId_);
container.insertBefore(this.topBarElement_, container.firstChild);
return container;
}
};
/**
* Function Function for API interface initialization.
* @private
*/
cercalia.Map.prototype.initializeTopBarInterface_ = function() {
this.createTopBar();
//document.getElementById(this.containerId_).appendChild(topBarElement);
//Controles
for (var index in this.controlsBar_) {
switch (this.controlsBar_[index]) {
case cercalia.MapControls.LayerSwitcher:
this.addControl(new cercalia.Control.LayerSwitcher({
listMapTypes: this.mapLayers_
}));
break;
case cercalia.MapControls.Logisitics:
this.addControl(new cercalia.Control.Logistics({}));
break;
case cercalia.MapControls.MeteoControl:
this.addControl(new cercalia.Control.Meteo({}));
break;
case cercalia.MapControls.MeasureControl:
this.addControl(new cercalia.Control.Measure({
scaleUnits: this.scaleUnits_
}));
break;
case cercalia.MapControls.CleanControl:
this.addControl(new cercalia.Control.Clean({}));
break;
case cercalia.MapControls.DrawControl:
this.addControl(new cercalia.Control.Draw({}));
break;
case cercalia.MapControls.DragControl:
this.addControl(new cercalia.Control.Drag({}));
break;
case cercalia.MapControls.Traffic:
this.addControl(new cercalia.Control.Traffic({}));
break;
case cercalia.MapControls.GasStations:
this.addControl(new cercalia.Control.GasStations());
break;
case cercalia.MapControls.Isochrones:
this.addControl(new cercalia.Control.Isochrones());
break;
}
}
};
/**
* Show all controls
*/
cercalia.Map.prototype.showAllControls = function() {
var topBarId = "topBar_" + this.id_;
this.map_.getControls().forEach(function(control) {
control.show();
});
cercalia.jQuery('#' + topBarId).show();
};
/**
* Hide all controls
*/
cercalia.Map.prototype.hideAllControls = function() {
var topBarId = "topBar_" + this.id_;
this.map_.getControls().forEach(function(control) {
control.hide();
});
cercalia.jQuery('#' + topBarId).hide();
};
/**
* Add a control in the map, by parameter
* @param {cercalia.Control} control
*/
cercalia.Map.prototype.addControl = function(control) {
var topBarId = "topBar_" + this.id_;
switch (control.getClass()) {
case "cercalia.Control.Clean":
case "cercalia.Control.CustomControl":
case "cercalia.Control.CustomSwitcherControl":
case "cercalia.Control.Drag":
case "cercalia.Control.Draw":
case "cercalia.Control.GasStations":
case "cercalia.Control.Isochrones":
case "cercalia.Control.LayerSwitcher":
case "cercalia.Control.Logistics":
case "cercalia.Control.Measure":
case "cercalia.Control.Meteo":
case "cercalia.Control.Traffic":
control.setTopBar(topBarId);
break;
}
this.map_.addControl(control);
};
/**
* Disable the active controls
*/
cercalia.Map.prototype.deactivateControls = function() {
var controls = this.map_.getControls().getArray();
for (var i = 0; i < controls.length; i++) {
if (controls[i].getName) {
switch (controls[i].getName()) {
case "DrawControl":
if (controls[i].getDialog()) {
controls[i].getDialog().dialog('close');
}
controls[i].disableDrawInteraction();
break;
case "MeasureControl":
if (controls[i].getDialog()) {
controls[i].getDialog().dialog('close');
}
controls[i].disableMeasureInteraction();
break;
}
}
}
};
/**
* Clean POIs layers, if painted
*/
cercalia.Map.prototype.removeWMSPOIs = function() {
if (this.layerPoiWMS_) {
this.removeWMSLayer(this.layerPoiWMS_);
this.layerPoiWMS_.destroy();
this.layerPoiWMS_ = null;
}
};
/**
* Create a WMS POIs layer, specifying the categories to be painted.<br/>
* Contact with Nexus Geografics for additional information and use.
* @param {Array.<string>|string} categories
*/
cercalia.Map.prototype.createWMSPOIs = function(categories) {
var self = this;
var poicats = null;
if (categories != null) {
poicats = (categories instanceof Array) ? categories.join(",").replace(/ +(?= )/g, '') : categories.trim();
this.poicatsEnabled_ = (poicats == "") ? [] : poicats.split(",");
}
//Si no se ha pasado ninguna categoria (si categories==null || categories==[])
if (categories == null || this.poicatsEnabled_.length == 0) {
this.removeWMSPOIs();
this.poicatsEnabled_ = [];
}
//Si tenemos que hacer alguna petición..
if (this.poicatsEnabled_.length > 0) {
var params = {
key: this.cercaliaKey_,
cmd: 'authcategory',
categories: poicats
};
cercalia.jQuery.ajax({
url: this.server_,
data: params,
dataType: "json",
crossDomain: true,
timeout: 5000,
beforeSend: function() {
self.removeWMSPOIs();
},
success: function(data) {
var authkey = data.cercalia.auth.key;
var params = {
LAYERS: "pois",
FORMAT: "image/png",
TRANSPARENT: "TRUE",
VERSION: '1.1.1',
SERVICE: 'WMS',
authkey: authkey
};
var options = {
gutter: 10
};
self.layerPoiWMS_ = new cercalia.WMS(cercalia.LayerEnumeration.CercaliaWMSPois, servers.pois, params, options);
self.addWMSLayer(self.layerPoiWMS_);
},
error: cercalia.AJAXException
});
}
};
/**
* Resets services
*/
cercalia.Map.prototype.clearCercaliaServices = function() {
this.geocodingService_ = new cercalia.service.Geocoding();
this.reverseGeocodingService_ = new cercalia.service.ReverseGeocoding();
this.routing_.removeRoute();
//this.routing_ = new cercalia.RouteMap({map: this, version: 2});
};
/**
* Widget reference to map.
* @private
* @param {cercalia.widget} widget Widget to register.
*/
cercalia.Map.prototype.addWidget = function(widget) {
switch (widget.getClass()) {
case "cercalia.widget.Routing":
widget.setMap(this);
this.routing_.setWidget(widget);
break;
case "cercalia.widget.PoiProximity":
this.poiProximityWidget_ = widget;
widget.setMap(this);
break;
case "cercalia.widget.PoiMap":
case "cercalia.widget.PoiSuggest":
case "cercalia.widget.Geocoding":
case "cercalia.widget.GeocodingSuggest":
case "cercalia.widget.ReverseGeocoding":
widget.setMap(this);
break;
default:
cercalia.Exception("Widget no soportado: " + widget.getClass());
}
};
/**
*
* @param {cercalia.RouteMap} routeMap
*/
cercalia.Map.prototype.setRouteMap = function(routeMap) {
this.routing_ = routeMap;
};
/**
*
* @return routeMap {cercalia.RouteMap}
*/
cercalia.Map.prototype.getRouteMap = function() {
return this.routing_;
};
/**
* Enable the painting status. The features can be draggables, changing the features styles.
* @param {string} type Type `[Point|LineString|Polygon|Circle]`
* @param {boolean|undefined} dragFeatures Boolean. `true` or `false`.
* @param {Object|undefined} styles JS object with the style values: `[strokeColor, strokeWidth, strokeOpacity, fillColor, fillOpacity, radius]`. For example:
* `{strokeColor:'#ff0000',fillColor:'#00ff00',radius:5,fillOpacity:0.5}`
* @param {Function|undefined} drawEndFunction Call function when user finish drawing the feature. Send the same feature painted
*/
cercalia.Map.prototype.enableDrawInteraction = function(type, dragFeatures, styles, drawEndFunction) {
this.disableDrawInteraction();
styles = styles || {};
if (type) {
this.drawInteraction_ = new ol.interaction.Draw({
//source: this.drawLayer_.getSource(), // No fa falta perque volem afegir els features resultants nosaltres. Si posem aquest layer ell dibuixa automaticament el resultat aqui.
type: type
});
this.map_.addInteraction(this.drawInteraction_);
var self = this;
this.drawInteraction_.on('drawstart', function(evt) {
self.dragInteraction_.setActive(false);
});
this.drawInteraction_.on('drawend', function(evt) {
var cercaliaFeature = new cercalia.Feature({
geometry: evt.feature.getGeometry(),
strokeColor: styles.strokeColor ? styles.strokeColor : '#B5E2FF',
strokeOpacity: styles.strokeOpacity ? styles.strokeOpacity : 0.75,
fillColor: styles.fillColor ? styles.fillColor : '#B5E2FF',
fillOpacity: styles.fillOpacity ? styles.fillOpacity : 0.75,
radius: styles.radius ? styles.radius : 5,
zIndex: styles.zIndex ? styles.zIndex : null
});
self.addFeature(cercaliaFeature); //Para añadir nuestra feature 'cercalia.Feature'
if (drawEndFunction) {
drawEndFunction(cercaliaFeature);
}
self.dragInteraction_.setActive(true);
});
}
};
/**
* Disable the painting status
*/
cercalia.Map.prototype.disableDrawInteraction = function() {
if (this.drawInteraction_ != null) {
this.map_.removeInteraction(this.drawInteraction_);
this.drawInteraction_ = null;
}
};
/**
* Enable markers clustering. Note: When clustering is enabled drag markers won't work.
* @param {number|undefined} [distance=40] Distance, in pixels, to group markers with clusters. Default value: 40.
* @param {Function|undefined} clickFunction Call function on cluster click. <br/>Parameters avaliable (clusterFeature, features). <br/>
* First parameter it's an object <a href="http://openlayers.org/en/v3.6.0/apidoc/ol.Feature.html">`ol.Feature`</a>
* visible on map as a cluster, <br/>
* Second parameter it's a {@link cercalia.Marker} array objects with the features contained in a cluster.
* @param {Function|undefined} mouseOverFunction Call function on cluster mouseover. Same parameters used in 'clickFunction' event
* @param {Function|undefined} doubleClickFunction Call function on double click on cluster. <br/>Parameters avaliable (clusterFeature, features). <br/>
* @param {Function|undefined} mouseOutFunction Call function on cluster mouseout. Same parameters used in 'clickFunction' event
*/
cercalia.Map.prototype.enableClustering = function(distance, clickFunction, mouseOverFunction, doubleClickFunction, mouseOutFunction) {
if (this.clusterLayer_ == null && this.clusterLayerDraggable_ == null) {
this.closePopups();
this.removeLayer(this.markerLayer_);
this.removeLayer(this.dragLayer_);
var self = this;
var clusterSource = new ol.source.Cluster({
distance: distance ? distance : 40,
source: this.markerLayer_.getSource()
});
var clusterSourceDraggable = new ol.source.Cluster({
distance: distance ? distance : 40,
source: this.dragLayer_.getSource()
});
var styleCache = {};
//Funcion por defecto si no se especifica
if (!clickFunction) {
clickFunction = function(clusterFeature, markers) {
// Funcion por defecto: Hacer fitBounds a los markers
var bounds = new cercalia.Bounds();
for (var i = 0; i < markers.length; i++) {
bounds.extend(markers[i].getPosition());
}
self.fitBounds(bounds);
};
}
var optionsClusterLayerMarkerBase = {
onClickFunction: clickFunction,
onDoubleClickFunction: doubleClickFunction,
onMouseOverFunction: mouseOverFunction,
onMouseOutFunction: mouseOutFunction,
style: function(feature, resolution) {
var size = feature.get('features').length;
var style = styleCache[size];
if (!style) {
if (size > 1) {
var color, radius, strokeColor;
if (size < 10) {
color = '#008CFF';
strokeColor = cercalia.Util.transformColor2rgba('#008CFF', 0.5);
radius = 10;
} else if (size < 20) {
color = '#FFBF00';
strokeColor = cercalia.Util.transformColor2rgba('#FFBF00', 0.5);
radius = 12;
} else {
strokeColor = cercalia.Util.transformColor2rgba('#FF0001', 0.5);
color = '#FF0001';
radius = 14;
}
style = [new ol.style.Style({
image: new ol.style.Circle({
radius: radius,
stroke: new ol.style.Stroke({
color: strokeColor,
width: 10
}),
fill: new ol.style.Fill({
color: color
})
}),
text: new ol.style.Text({
text: size.toString(),
fill: new ol.style.Fill({
color: '#fff' //Color del texto
})
})
})];
styleCache[size] = style;
} else {
var featureStyle = feature.get('features')[0].getStyle();
style = Array.isArray(featureStyle) ? featureStyle : [featureStyle];
//style = [feature.get('features')[0].getStyle()]; //Estilo de la única feature que hay
}
}
//Si se mostraban anteriormente los labels hacemos el tratamiento
if (self.visibleLabels_) {
//Comprobamos si tienen que mostrar o no el label. Solo lo mostrara cuando haya solo un marker, es decir, que no esté en cluster
if (size > 1) {
for (var i = 0; i < size; i++) {
var marker = feature.get('features')[i].marker_;
if (marker) marker.hideLabel();
}
} else {
var marker = feature.get('features')[0].marker_;
if (marker) marker.showLabel();
}
}
return style;
}
};
var optionsClusterLayerMarker = cercalia.jQuery.extend({
name: cercalia.LayerEnumeration.ClusterLayerMarker,
source: clusterSource
}, optionsClusterLayerMarkerBase);
var optionsClusterLayerMarkerDraggable = cercalia.jQuery.extend({
name: cercalia.LayerEnumeration.ClusterLayerMarkerDraggable,
source: clusterSourceDraggable
}, optionsClusterLayerMarkerBase);
this.clusterLayer_ = new ol.layer.Vector(optionsClusterLayerMarker);
this.clusterLayerDraggable_ = new ol.layer.Vector(optionsClusterLayerMarkerDraggable);
this.addLayer(this.clusterLayerDraggable_);
this.addLayer(this.clusterLayer_);
}
};
/**
* Disable markers clustering. Every marker will be painted singly, with its icon.
*/
cercalia.Map.prototype.disableClustering = function() {
if (this.clusterLayer_ != null && this.clusterLayerDraggable_ != null) {
this.closePopups();
//Layer markers no draggables
this.removeLayer(this.clusterLayer_);
if (this.clusterLayer_.getSource().unlistenSource) { //Cuidado! funcio afegida per nosaltres a OL
this.clusterLayer_.getSource().unlistenSource();
}
this.clusterLayer_ = null;
this.addLayer(this.markerLayer_);
//Layer markers draggables
this.removeLayer(this.clusterLayerDraggable_);
if (this.clusterLayerDraggable_.getSource().unlistenSource) { //Cuidado! funcio afegida per nosaltres a OL!
this.clusterLayerDraggable_.getSource().unlistenSource();
}
this.clusterLayerDraggable_ = null;
this.addLayer(this.dragLayer_);
if (this.visibleLabels_) {
this.showLabels();
}
}
};
/**
* @private
* @param {cercalia.widget.MainMenu} mainMenu
*/
cercalia.Map.prototype.setMainMenu = function(mainMenuWidget) {
this.mainMenuWidget_ = mainMenuWidget;
};
/**
* @return {cercalia.widget.MainMenu} Returns the reference to {@link cercalia.widget.MainMenu}
*/
cercalia.Map.prototype.getMainMenu = function() {
return this.mainMenuWidget_;
};
/**
* @return {string} Object ClassName. Value: `cercaila.Map`.
*/
cercalia.Map.prototype.getClass = function() {
return this.CLASS_NAME_;
};
/**
* @return {Object} View options from cercalia map.
*/
cercalia.Map.prototype.getViewOptions = function() {
return this.viewOptions_;
};
/**
* @param {cercalia.LonLat} position
* @return {cercalia.Feature} Nearest feature to coordinate
*/
cercalia.Map.prototype.getClosestFeature = function(position) {
return this.getClosestFeatureByLayer_(position, this.featureLayer_);
};
/**
* @param {cercalia.LonLat} position
* @return {cercalia.Marker} Nearest marker to coordinate
*/
cercalia.Map.prototype.getClosestMarker = function(position) {
return this.getClosestFeatureByLayer_(position, this.markerLayer_);
};
/**
* @private
* @param {cercalia.LonLat} position
* @return {cercalia.Marker|cercalia.Feature} Nearest marker to coordinate
*/
cercalia.Map.prototype.getClosestFeatureByLayer_ = function(position, layer) {
var source = layer.getSource();
var featureOL = source.getClosestFeatureToCoordinate(position.transform('EPSG:3857'));
if (featureOL != null && featureOL.getCercaliaObject() != null) {
return featureOL.getCercaliaObject();
} else {
return null;
}
};
/**
* @return {array<string>} return rightClick menu options.
*/
cercalia.Map.prototype.getRightClickMenuOptions = function() {
return this.rightClickMenuOptions_
};
/**
* @param {array<string>} Set rightClick menu options.
*/
cercalia.Map.prototype.setRightClickMenuOptions = function(array) {
if (this.contextMenuOverlay_ != null) {
for (var i = 0; i < this.rightClickMenuOptions_.length; i++) {
//this.contextMenuOverlay_.removeOption(this.rightClickMenuOptions_[i]);
var o = this.rightClickMenuOptions_[i];
if (o === cercalia.ContextMenuOptions.Location) {
// remove get direction option
this.contextMenuOverlay_.removeOption('getDirection');
} else if (o === cercalia.ContextMenuOptions.Routing) {
// remove route options
this.contextMenuOverlay_.removeOption('setRouteStart');
this.contextMenuOverlay_.removeOption('setRouteWaypoint');
this.contextMenuOverlay_.removeOption('setRouteEnd');
}
}
}
this.rightClickMenuOptions_ = array;
this.addRightClickMenuOptions_(this.contextMenuOverlay_);
};
/**
* @private
* @param {ol.Overlay} contextMenu add rightClickMenuOption in contextMenu
*/
cercalia.Map.prototype.addRightClickMenuOptions_ = function(contextMenu) {
var self = this;
if (this.rightClickMenuOptions_ != null) {
for (var i = 0; i < this.rightClickMenuOptions_.length; i++) {
var o = this.rightClickMenuOptions_[i];
if (o === cercalia.ContextMenuOptions.Location) {
// Adding get direction option
contextMenu.addOption('getDirection', 'Get address', function(evnt, lonLat) {
self.getDirectionFunction_(evnt, lonLat);
});
} else if (o === cercalia.ContextMenuOptions.Routing) {
// Adding route options
contextMenu.addOption('setRouteStart', 'Route origin', function(evnt, lonLat) {
self.setRouteStartFunction_(evnt, lonLat);
});
contextMenu.addOption('setRouteWaypoint', 'Route waypoint', function(evnt, lonLat) {
self.setRouteWaypoint_(evnt, lonLat);
});
contextMenu.addOption('setRouteEnd', 'Route destination', function(evnt, lonLat) {
self.setRouteEndFunction_(evnt, lonLat);
});
}
}
}
};
/**
* Set the marker in the 'layer', and clean it from 'dragLayerToRemove'.
* @private
* @param {ol.layer} layer where set the marker
* @param {cercalia.Marker|cercalia.Feature|ol.Feature|Array.<cercalia.Marker>|Array.<cercalia.Feature>|Array.<ol.Feature>} feature
* @param {ol.layer} dragLayerToRemove layer where the marker is removed
*/
cercalia.Map.prototype.putMarkerToLayerNoDrag_ = function(layer, feature, dragLayerToRemove) {
//var feature = marker instanceof cercalia.Feature || marker instanceof cercalia.Marker ? marker.getFeature() : marker;
if (feature.constructor !== Array) {
feature = [feature];
}
var arrFeatureOL = [];
for (var i = 0; i < feature.length; i++) {
var featureOL = feature[i].getFeature ? feature[i].getFeature() : feature[i];
arrFeatureOL.push(featureOL);
if (dragLayerToRemove.getSource().getFeatureById(featureOL.getId()) != null) {
dragLayerToRemove.getSource().removeFeature(featureOL);
}
}
layer.getSource().addFeatures(arrFeatureOL);
};
/**
* Remove the marker from specified layer.
* @private
* @param {ol.layer.Vector} layer that contains the marker.
* @param {cercalia.Marker|cercalia.Feature} feature
*/
cercalia.Map.prototype.removeMarkerToLayerNoDrag_ = function(layer, feature) {
try {
var source = layer.getSource();
var featureOL = feature.getFeature ? feature.getFeature() : feature;
if (layer && source.getFeatureById(featureOL.getId()) != null) {
layer.getSource().removeFeature(featureOL);
}
} catch (err) {
console.error(err);
}
};
/**
* Set the marker in the drag layer, and remove it from the specified layer.
* @private
* @param {cercalia.Marker|cercalia.Feature|ol.Feature|Array.<cercalia.Marker>|Array.<cercalia.Feature>|Array.<ol.Feature>} feature
* @param {ol.layer} layerToRemove layer where the marker is removed.
*/
cercalia.Map.prototype.addMarkerToDragLayer_ = function(feature, layerToRemove) {
if (feature.constructor !== Array) {
feature = [feature];
}
var arrFeatureOL = [];
for (var i = 0; i < feature.length; i++) {
var featureOL = feature[i].getFeature ? feature[i].getFeature() : feature[i];
arrFeatureOL.push(featureOL);
if (layerToRemove.getSource().getFeatureById(featureOL.getId()) != null) {
layerToRemove.getSource().removeFeature(featureOL);
}
}
this.dragLayer_.getSource().addFeatures(arrFeatureOL);
};
/**
* Remove the marker from drag layer.
* @private
* @param {cercalia.Marker|cercalia.Feature|ol.Feature} marker
*/
cercalia.Map.prototype.removeMarkerFromDragLayer_ = function(feature) {
var featureOL = feature.getFeature ? feature.getFeature() : feature;
if (this.dragLayer_ && this.dragLayer_.getSource().getFeatureById(featureOL.getId()) != null) {
this.dragLayer_.getSource().removeFeature(featureOL);
}
};
/**
*
* @return {cercalia.Interaction.DragFeatures} dragInteraction
*/
cercalia.Map.prototype.getInteractionDrag = function() {
return this.dragInteraction_;
}
/**
* Destroy function
*/
cercalia.Map.prototype.destroy = function() {
this.map_.setTarget(null);
for (var key in this) {
delete this[key];
}
};
/**
*
* @returns {ol.Overlay}
*/
cercalia.Map.prototype.getContextMenuOverlay = function() {
return this.contextMenuOverlay_;
}
/**
* Shows "Loading..."
*/
cercalia.Map.prototype.showLoading = function() {
this.overlayLoading.show();
};
/**
* Hide "Loading..."
*/
cercalia.Map.prototype.hideLoading = function() {
this.overlayLoading.hide();
};
/**
* @private
*/
cercalia.Map.prototype.onMoveSatelliteLayer_ = function() {
if ([cercalia.MapTypes.SATELLITE, cercalia.MapTypes.HYBRID].indexOf(this.baseLayerName_) !== -1) {
var bounds = this.getBounds();
var zoom = this.getZoom();
var boundsInsidePolygon = this.boundsInsidePolygon_(
bounds,
"POLYGON ((3.05038909973088 42.4721482396786,5.77051820595404 42.4965330815095," +
"5.86561908909407 37.6524842518256,-0.571979154231091 36.7063523887915,-2.24965627218856 36.0235768175297," +
"-5.33677724796494 35.9650531971358,-5.51722507751269 35.9455453236712,-7.42899667704562 36.001630459882," +
"-7.42533895077099 37.1751509729882,-7.51800134972794 37.5750623790129,-7.41070804567252 37.736002335096," +
"-7.3034147416171 37.8384186707853,-7.25220657377247 37.987166205953,-7.10589752278781 38.0310589212484," +
"-6.99616573454931 38.0456898263469,-6.94008059833853 38.2139452349793,-7.08638964932319 38.1676140355008," +
"-7.31560716253249 38.4309703272732,-7.25952202632171 38.7162729766933,-7.04493541821087 38.8820899011426," +
"-6.954711503437 39.0137680470287,-7.01811209219702 39.1186228669011,-7.09614358605551 39.1039919618026," +
"-7.14247478553399 39.1137458985349,-7.12784388043552 39.1649540663796,-7.23026021612479 39.2015313291257," +
"-7.22782173194171 39.2673704020688,-7.30341474161712 39.3283325066458,-7.3058532258002 39.4136794530535," +
"-7.36193836201099 39.4941494310951,-7.45947772933409 39.5575500198551,-7.54482467574181 39.6624048397274," +
"-7.33267655181405 39.6428969662628,-7.18880598501247 39.6599663555443,-6.99616573454933 39.6916666499244," +
"-6.85961062029698 40.0428083722875,-6.98641179781702 40.1110859294137,-7.00591967128164 40.2086252967368," +
"-6.86936455702929 40.2573949803984,-6.81084093663542 40.3549343477215,-6.80596396826926 40.7402148486478," +
"-6.92788817742315 41.0230790138848,-6.7913330631708 41.0425868873494,-6.76694822134002 41.1303723179402," +
"-6.50359192956763 41.281558337291,-6.19146595413368 41.593684312725,-6.54748464486303 41.6912236800481," +
"-6.51822283466609 41.876548477962,-6.75231731624156 41.9497030034543,-7.17661356409708 41.9935957187497," +
"-7.17661356409708 41.8911793830604,-7.34730745691252 41.8326557626666,-7.49849347626333 41.8521636361312," +
"-7.70332614764186 41.8960563514266,-7.94717456594963 41.8716715095958,-8.20077692098972 41.8863024146943," +
"-8.08860664856814 42.0179805605805,-8.16419965824355 42.1106429595374,-8.43487140256518 42.0618732758759," +
"-8.91525278663149 41.8277787943004,-9.14726476108778 42.4956854714353,-9.70638742542847 42.0554356245464," +
"-10.8367783228967 41.5351606923311,-10.7977625759675 44.2272472304489,-10.7392389555736 45.3977196383262," +
"-6.42799891989222 45.4757511321847,-2.05823526381696 45.4757511321847,-1.77537109857994 43.3713392821886," +
"-1.7241629307353 43.3030617250625,-1.67539324707375 43.3128156617948,-1.62174659504604 43.3006232408794," +
"-1.59492326903218 43.2469765888517,-1.55834600628602 43.288430819964,-1.51445329099062 43.2933077883302," +
"-1.41203695530135 43.2689229464994,-1.38277514510442 43.2469765888517,-1.38216552405865 43.2039983051249," +
"-1.39496756601981 43.1811375159086,-1.41691392366751 43.1265764323122,-1.46324512314598 43.0860366327686," +
"-1.44861421804752 43.0518978542055,-1.35595181909056 43.037266949107,-1.34223534556075 43.0619566014607," +
"-1.34345458765229 43.0960953800238,-1.32821406150806 43.1101166640765,-1.3114494827494 43.1134695798282," +
"-1.27090968320573 43.1186513587172,-1.28035880941516 43.1104214745993,-1.28035880941516 43.0592133067547," +
"-0.975548286530442 42.9982512021778,-0.843870140644245 42.942166065967,-0.758523194236525 42.9616739394316," +
"-0.729261384039593 42.9153427399531,-0.673176247828805 42.8836424455731,-0.578075364688774 42.7982954991654," +
"-0.504920839196443 42.81780337263,-0.387873598408713 42.7958570149823,-0.314719072916382 42.8421882144608," +
"-0.161094569382486 42.7885415624331,-0.100132464805543 42.7202640053069,0.026668712714498 42.6958791634761," +
"0.120465397621847 42.7636047071219,0.227843657818432 42.7867126992956,0.374152708803095 42.7793972467464," +
"0.600931737829322 42.735504531451,0.593616285280089 42.8208514778587,0.689936410511658 42.8952252454426," +
"0.866726513784792 42.8403593513233,1.0240087435933 42.830605414591,1.18129097340182 42.7733010362887," +
"1.35076562412572 42.7464777102748,1.44342802308267 42.6123610802056,1.41172772870266 42.5392065547132," +
"1.44586650726575 42.5257948917063,1.41538545497728 42.4733674817701,1.47025134909653 42.423378556017," +
"1.55315981132117 42.4270362822917,1.72385370413661 42.4965330815094,1.83358549237511 42.4831214185025," +
"1.94697500688822 42.4441056715732,1.98233302754285 42.3624164514401,2.07865315277442 42.3624164514401," +
"2.15546540454136 42.4197208297424,2.27251264532909 42.4380094611155,2.42979487513761 42.3868012932709," +
"2.48466076925686 42.3368123675178,2.55659605265765 42.3490047884332,2.58585786285458 42.3575394830739," +
"2.65901238834691 42.3587587251655,2.6712048092623 42.4038706825524,2.75777099776156 42.4270362822917," +
"2.87116051227467 42.4697097554955,2.96138442704855 42.4794636922278,3.05038909973088 42.4721482396786))"
);
boundsInsidePolygon = boundsInsidePolygon || this.boundsInsidePolygon_(bounds, 'POLYGON ((-20.9041600806812 31.2533745764583,-11.7908072326128 31.1445119997749,-11.7908072326128 31.1445119997749,-11.6974964525984 29.2938481961569,-12.2884647260226 29.0294676527829,-13.7347818162451 27.3654254091936,-14.9478219564317 26.2456960490214,-20.8730564873431 26.1679370656761,-20.9041600806812 31.2533745764583))');
var urls = zoom > 6 && boundsInsidePolygon ? ['https://tms-pnoa-ma.idee.es/1.0.0/pnoa-ma/{z}/{x}/{-y}.jpeg'] : this.getMapboxSatelliteUrls_();
var newSource = new ol.source.XYZ({
urls: urls,
crossOrigin: 'anonymous'
});
//this.map_.getLayers().getArray()[0].getLayers().getArray()[0].setSource(newSource);
if (this.baseLayerName_ === cercalia.MapTypes.SATELLITE) {
this.map_.getLayers().getArray()[0].setSource(newSource);
} else {
this.map_.getLayers().getArray()[0].getLayers().getArray()[0].setSource(newSource);
}
}
};
/**
* Check if bounds are inside a WKT polygon
* @param {cercalia.Bounds} bounds Map bounds
* @param {string} polygon WKT Polygon
* @returns {boolean} True if inside
*/
cercalia.Map.prototype.boundsInsidePolygon_ = function(bounds, polygon) {
var insidePolygon = true;
var idx = 0;
var boundsCorners = [
bounds.getNorthWest(),
bounds.getNorthEast(),
bounds.getSouthEast(),
bounds.getSouthWest()
];
do {
insidePolygon = cercalia.Util.geofencing(polygon, boundsCorners[idx]);
idx += 1;
} while (insidePolygon && idx < boundsCorners.length);
return insidePolygon;
};
/**
* Export PNG image
* @param {string|undefined} filename
*/
cercalia.Map.prototype.exportPNG = function(filename) {
var self = this;
var exportPNGElement = document.createElement('a');
exportPNGElement.addEventListener('click', function() {
self.map_.once('postcompose', function(event) {
var canvas = event.context.canvas;
exportPNGElement.download = filename ? filename : 'ExportCercaliaMap.png';
exportPNGElement.href = canvas.toDataURL('image/png');
});
self.map_.renderSync();
}, false);
document.body.appendChild(exportPNGElement);
exportPNGElement.click();
document.body.removeChild(exportPNGElement);
};
/**
* @return scale units. Values `metric` or `imperial`
*/
cercalia.Map.prototype.getScaleUnits = function() {
return this.scaleUnits_;
};