/**
* Constructor del widget Puntos de interés sobre el mapa
* @class
* @constructor
* @param {cercaliax.widget.PoiProximityOptions} options Opciones del PoiProximity
*/
cercalia.widget.PoiProximity = function (options) {
/**
* Nombre de la classe
* @private
* @type {string}
*/
this.CLASS_NAME_ = "cercalia.widget.PoiProximity";
/**
* DIV id donde se creara el widget
* @private
* @type {string}
*/
this.divId_ = options.div ? options.div : null;
/**
* Height que tendrà el div.
* @private
* @type {string|Function}
*/
this.height_ = options.height ? options.height : "auto";
/**
* Número máximo de elementos para la llamada proximity
* @private
* @type {number}
*/
this.defaultElements_ = options.defaultElements ? options.defaultElements : "25";
/**
* Número máximo de Km para el radio de busqueda de la llamada proximity
* @private
* @type {number}
*/
this.maxRadius_ = options.maxRadius ? options.maxRadius : "50";
/**
* Opciones para el widget listado de categorias
* @private
* @type {cercaliax.widget.PoiListOptions}
*/
this.poiListOptions_ = options.poiListOptions ? options.poiListOptions : {};
/**
* Función que se llama al completar con éxito la llamada a cercalia.
* @private
* @type {Function}
*/
this.completeCallback_ = options.complete ? options.complete : null;
/**
* Función que se llama en caso de error en la llamada a cercalia.
* @private
* @type {Function}
*/
this.errorCallback_ = options.error ? options.error : null;
/**
* Función para mostrar el DIV del widget al modificar la ruta con el mapa.
* @private
* @type {Function}
*/
this.showUICallback_ = options.showUI ? options.showUI : null;
/* VARIABLES PRIVADAS */
/**
* Cercalia map
* @private
* @type {cercalia.Map}
*/
this.map_ = null;
/**
* Categorias seleccionadas del listado.
* @private
* @type {Array.<string>}
*/
this.categoriesSelected_ = null;
/**
* Div donde se aloja el widget de suggest
* @private
* @type {Object}
*/
this.suggestDiv_ = null;
/**
* Widget Slider de jQuery UI
* @private
* @type {Object}
*/
this.slider_ = null;
/**
* Widget Spinner de jQuery UI
* @private
* @type {Object}
*/
this.spinner_ = null;
/**
* Listado de Markers pintados en el mapa
* @private
* @type {Array.<cercalia.Marker>}
*/
this.listMarkers_ = [];
/**
* Circulo que representa el radio
* @private
* @type {cercalia.Feature}
*/
this.featureRadius_ = null;
/**
* Objecto geocoding devuelto por el suggest de cercalia
* @private
* @type {Object}
*/
this.geocoding_ = null;
/* SERVICIOS Y WIDGETS DE CERCALIA */
/**
* Widget listado de categorias
* @private
* @type {cercalia.widget.PoiList}
*/
this.poiListWidget_ = null;
/**
* Objeto proximity para hacer las llamadas a cercalia
* @private
* @type {cercalia.service.Proximity}
*/
this.proximity_ = null;
/**
* Widget de suggest
* @private
* @type {cercalia.widget.GeocodingSuggest}
*/
this.suggest_ = null;
// Inicializamos
this.initialize_();
};
/**
* Inicializa el elemento.
* @private
*/
cercalia.widget.PoiProximity.prototype.initialize_ = function () {
if( ! this.divId_ ) {
cercalia.Exception(cercalia.i18n._('WIDGET_ERR_NO_DIV "%"', this.CLASS_NAME_));
} else {
var height;
if(typeof(this.height_) === "function") {
height = this.height_();
} else {
height = this.height_;
}
var parent = cercalia.jQuery("#" + this.divId_).addClass("cercalia-widget cercalia-widget-poiproximity").css("height", height);
var element = cercalia.jQuery("<div />").addClass("cercalia-widget-poiproximity-search").appendTo(parent).css("height", height);
var result = cercalia.jQuery("<div />").addClass("cercalia-widget-poiproximity-result").appendTo(parent).css("height", height);
var self = this;
this.proximity_ = new cercalia.service.Proximity();
/* DIV DE BUSQUEDA */
// Tipo de proximidad
var tipo = cercalia.jQuery("<div />").addClass("cercalia-widget-poiproximity-type").appendTo(element);
var type1 = cercalia.jQuery("<span />").attr("id", this.divId_ + "-widget-poiproximity-radio1").addClass("cercalia-widget-poiproximity-type-text").attr("data-selected", "true").html(cercalia.i18n._("Direction")).appendTo(tipo);
cercalia.jQuery("<span />").addClass("ui-icon cercalia-icon cercalia-icon-radio-enabled cercalia-widget-poilist-menu-check cercalia-widget-poiproximity-radio").appendTo(type1);
var type2 = cercalia.jQuery("<span />").attr("id", this.divId_ + "-widget-poiproximity-radio2").addClass("cercalia-widget-poiproximity-type-text").attr("data-selected", "false").html(cercalia.i18n._("Map center")).appendTo(tipo);
cercalia.jQuery("<span />").addClass("ui-icon cercalia-icon cercalia-icon-radio-disabled cercalia-widget-poilist-menu-check cercalia-widget-poiproximity-radio").appendTo(type2);
type1.click(function (ev) {
self.radioClick_(this, type1, type2, ev);
});
type2.click(function (ev) {
self.radioClick_(this, type1, type2, ev);
});
this.suggestDiv_ = cercalia.jQuery("<div />").attr("id", this.divId_ + "_suggest").addClass("").appendTo(element);
this.suggest_ = new cercalia.widget.GeocodingSuggest({"div": this.suggestDiv_.attr("id"), complete: function (ge) {
self.geocoding_ = ge;
}});
//this.suggestDiv_.prepend(cercalia.jQuery("<div />").addClass("cercalia-widget-poiproximity-suggest-overlay"));
var divMenu = cercalia.jQuery("<div />").attr("id", this.divId_ + "_menu").appendTo(element);
this.poiListOptions_.div = divMenu.attr("id");
this.poiListOptions_.clickElementList = function () {
var arraySelected = self.poiListWidget_.getSelectedId();
self.categoriesSelected_ = arraySelected;
};
this.poiListWidget_ = new cercalia.widget.PoiList(this.poiListOptions_);
//Opciones
var optionsContainer = cercalia.jQuery("<div />").addClass("cercalia-widget-poiproximity-optionsContainer ui-widget ui-widget-content ui-corner-all").appendTo(element);
// Spinner de numero candidatos
cercalia.jQuery("<i />").html("<a>" + cercalia.i18n._("POIPROXIMITY_SPPINER") + "</a>").appendTo(optionsContainer);
this.spinner_ = cercalia.jQuery("<input />")
.addClass("cercalia-widget-poiproximity-spinner")
.attr("id", this.divId_ + "-widget-poiproximity-spinner")
.appendTo(optionsContainer)
.spinner( { max: 99, min: 0 })
.spinner("value", this.defaultElements_);
cercalia.jQuery("<div />").addClass("cercalia-clean").appendTo(optionsContainer);
// Slider de radio
cercalia.jQuery("<i />").html("<a>" + cercalia.i18n._("POIPROXIMITY_SLIDER") + "</a>").appendTo(optionsContainer);
this.slider_ = cercalia.jQuery("<div />")
.attr("id", this.divId_ + "-widget-poiproximity-slider")
.addClass("cercalia-widget-poiproximity-slider")
.appendTo(optionsContainer)
.slider({
max: 50,
min: 0,
step: 0.1,
value: 50,
start: function ( event, ui ) {
cercalia.jQuery("#" + self.divId_).find(".cercalia-widget-poiproximity-slider-value").tooltip("destroy");
},
stop: function ( event, ui ) {
cercalia.jQuery("#" + self.divId_).find(".cercalia-widget-poiproximity-slider-value").attr("title", ui.value + " km");
cercalia.jQuery("#" + self.divId_).find(".cercalia-widget-poiproximity-slider-value").tooltip();
cercalia.jQuery("#" + self.divId_).find(".cercalia-widget-poiproximity-slider-value").tooltip("open");
}
});
cercalia.jQuery("<span />").addClass("cercalia-widget-poiproximity-slider-min").html("0 km").appendTo(this.slider_);
cercalia.jQuery("<span />").addClass("cercalia-widget-poiproximity-slider-max").html("50 km").appendTo(this.slider_);
// Tooltip con el valor
this.slider_.find("a").attr("title", "0 km").addClass("cercalia-widget-poiproximity-slider-value");
cercalia.jQuery(".cercalia-widget-poiproximity-slider-value").tooltip();
cercalia.jQuery("<button />").addClass("cercalia-widget-poiproximity-find").html(cercalia.i18n._("POIPROXIMITY_FIND")).appendTo(element).button().click(function () {
self.find_(self);
});
cercalia.jQuery("<div />").addClass("cercalia-clean").appendTo(element);
/* DIV DE RESULTADO */
cercalia.jQuery("<button />").addClass("cercalia-widget-poiproximity-newfind").html(cercalia.i18n._("POIPROXIMITY_NEW_FIND")).appendTo(result).button().click(function () {
cercalia.jQuery("#" + self.divId_).find(".cercalia-widget-poiproximity-search").show();
cercalia.jQuery("#" + self.divId_).find(".cercalia-widget-poiproximity-result").hide();
});
cercalia.jQuery("<ul />").addClass("cercalia-widget-poiproximity-result-list").html(cercalia.i18n._("POIPROXIMITY_NEW_FIND")).appendTo(result);
}
};
/**
* Recalcula el tamaño del widget
* @param height {number} : Altura del widget. Si no se define y se ha definido una funcion de height se recalculara utilizando esta.
*/
cercalia.widget.PoiProximity.prototype.resize = function (height) {
var new_height;
if(typeof(height) === "undefined" || height === null) {
if(typeof(this.height_) === "function") {
new_height = this.height_() - 30;
} else {
new_height = this.height_ - 30;
}
} else {
new_height = height - 30;
}
cercalia.jQuery("#" + this.divId_).css("height", new_height);
cercalia.jQuery("#" + this.divId_ + " .cercalia-widget-poiproximity-search").css("height", new_height);
cercalia.jQuery("#" + this.divId_ + " .cercalia-widget-poiproximity-result").css("height", new_height);
};
/**
* Funcion al ejecutar cuando se pulsa un radio button.
* @private
* @param {Object} element Elemento (radio) clickado
* @param {Object} radio1 Radio 1
* @param {Object} radio2 Radio 2
* @param {Object} event Evento de click
*/
cercalia.widget.PoiProximity.prototype.radioClick_ = function (element, radio1, radio2, event) {
var el = cercalia.jQuery(element);
if(el.attr("id") == radio1.attr("id") && radio1.attr("data-selected") == "false") {
radio1.attr("data-selected", "true");
radio2.attr("data-selected", "false");
radio1.find("span.ui-icon").removeClass("cercalia-icon-radio-disabled").addClass("cercalia-icon-radio-enabled");
radio2.find("span.ui-icon").removeClass("cercalia-icon-radio-enabled").addClass("cercalia-icon-radio-disabled");
this.suggestDiv_.find("input, select").removeAttr("disabled", "disabled");//.find(".cercalia-widget-poiproximity-suggest-overlay").removeClass("ui-widget-overlay");
} else if(el.attr("id") == radio2.attr("id") && radio2.attr("data-selected") == "false") {
radio2.attr("data-selected", "true");
radio1.attr("data-selected", "false");
radio2.find("span.ui-icon").removeClass("cercalia-icon-radio-disabled").addClass("cercalia-icon-radio-enabled");
radio1.find("span.ui-icon").removeClass("cercalia-icon-radio-enabled").addClass("cercalia-icon-radio-disabled");
this.suggestDiv_.find("input, select").attr("disabled", "disabled");//.find(".cercalia-widget-poiproximity-suggest-overlay").addClass("ui-widget-overlay");
} else {
// Clickamos sobre un radio y està a true. No hacemos nada!
}
};
/**
* Modifica el mapa con el que interactua el widget.
* @param {cercalia.Map} map Mapa con el que interactuará el Widget.
*/
cercalia.widget.PoiProximity.prototype.setMap = function (map) {
this.map_ = map;
};
/**
* Lanza la busqueda de pois en las coordenadas especificadas
* @param {cercalia.LonLat} lonLat Coordenadas pera hacer la busqueda de proximidad
* @param {Array.<string>} categories Listado de las categorias que se quiere mostrar. Si no pasamos ninguna no hará la busqueda.
*
*/
cercalia.widget.PoiProximity.prototype.findByLonLat = function (lonLat, categories) {
this.map_.setCenter(lonLat);
this.radioClick_(cercalia.jQuery("#" + this.divId_ + "-widget-poiproximity-radio2"), cercalia.jQuery("#" + this.divId_ + "-widget-poiproximity-radio1"), cercalia.jQuery("#" + this.divId_ + "-widget-poiproximity-radio2"), null);
//this.suggest_.setInputText(lonLat.toString());
if(typeof(this.showUICallback_) === "function") this.showUICallback_();
//TODO: fer el find amb categories
if(typeof(categories) !== "undefined" && categories !== null && categories.length > 0) {
this.find_();
}
};
/**
* Lanza la busqueda de pois en el ge seleccionado
* @private
*/
cercalia.widget.PoiProximity.prototype.find_ = function () {
// Limpiamos proximity y resultados anteriores
this.proximity_.clear();
this.cleanMarkers();
var find = false;
if(cercalia.jQuery("#" + this.divId_ + "-widget-poiproximity-radio1").attr("data-selected") == "true") {
// Preparamos nuevo proximity
if(typeof(this.geocoding_) !== "undefined" && this.geocoding_ !== null && typeof(this.proximity_) !== "undefined" && this.proximity_ !== null) {
if(typeof(this.geocoding_.country) !== "undefined" && this.geocoding_.country !== null)
this.proximity_.countryId = this.geocoding_.country.id;
if(typeof(this.geocoding_.municipality) !== "undefined" && this.geocoding_.municipality !== null)
this.proximity_.municipalityId = this.geocoding_.municipality.id;
if(typeof(this.geocoding_.region) !== "undefined" && this.geocoding_.region !== null)
this.proximity_.regionId = this.geocoding_.region.id;
if(typeof(this.geocoding_.subregion) !== "undefined" && this.geocoding_.subregion !== null)
this.proximity_.subregionId = this.geocoding_.subregion.id;
}
find = true;
} else if(cercalia.jQuery("#" + this.divId_ + "-widget-poiproximity-radio2").attr("data-selected") == "true") {
// Cogemos coordenadas del centro del mapa
var centro = this.map_.getCenter();
//context.suggest_.setInputText(centro.toString());
this.proximity_.x = centro.getLon();
this.proximity_.y = centro.getLat();
this.proximity_.srs = "EPSG:4326";
find = true;
} else {
// No hacemos nada.....
find = false;
}
// Hacemos la busqueda
if(find) {
this.proximity_.rqpoicats = this.categoriesSelected_;
this.proximity_.num = this.spinner_.spinner("value");
if(this.slider_.slider("option", "value") == 0) this.proximity_.rad = null;
else this.proximity_.rad = this.slider_.slider("option", "value")*1000; // Pasamos a metros
var self = this;
this.proximity_.proximity(function (result) {
if(typeof(result.cercalia.error) !== "undefined" && result.cercalia.error !== null) {
if(self.errorCallback_ != null) self.errorCallback_(result);
else self.callbackErrorfunction_(result);
} else {
cercalia.jQuery("#" + self.divId_).find(".cercalia-widget-poiproximity-search").hide();
cercalia.jQuery("#" + self.divId_).find(".cercalia-widget-poiproximity-result").show();
//TODO: eliminar
cercalia.jQuery("#" + self.divId_).find(".cercalia-widget-poiproximity-result-list").hide();
if(self.completeCallback_ != null) self.completeCallback_(result, self.proximity_.rad);
else if(self.map_ != null) self.proximityResponse_(result, self.proximity_.rad);
else cercalia.Exception(cercalia.i18n._('WIDGET_ERR_NO_MAP_NO_FUNCTION "%"', self.CLASS_NAME_));
}
});
}
};
/**
* Funcion de callback de error llamada por defecto.
* @private
* @param {Object} result
*/
cercalia.widget.PoiProximity.prototype.callbackErrorfunction_ = function (result) {
cercalia.Exception(cercalia.i18n._('WIDGET_ERR_CERCALIA "%" "%" "%"', this.CLASS_NAME_, result.cercalia.error.id, result.cercalia.error.value));
};
/**
* Funciona que muestra el resultado del proximity
* @param {Object} response Respuesta de cercalia
* @param {number} [radius] Radio de la busqueda.
* @private
*/
cercalia.widget.PoiProximity.prototype.proximityResponse_ = function (response, radius) {
var proximity = response.cercalia.proximity;
// funcion por defecto
if(typeof(proximity) !== "undefined" && proximity !== null) {
if(typeof(proximity.poilist) !== "undefined" && proximity.poilist !== null && proximity.num > 0) {
// Pintamos circulo
this.drawRadius_(proximity, radius);
// Pintamos marcadores de categoria i los ponemos en el listado
var poisList = proximity.poilist.poi;
var resultList = cercalia.jQuery("#" + this.divId_).find(".cercalia-widget-poiproximity-result-list");
for(var index = 0; index < poisList.length; index++) {
var poi = poisList[index];
// Pintamos marcador y popup de informacion
var popup = new cercalia.Popup({
visible: false,
title: poi.name.value,
content: this.popupContent_(poi)
});
var marker = new cercalia.Marker({
position: new cercalia.LonLat(poi.coord.x, poi.coord.y),
icon : new cercalia.Icon({ src: cercaliaGlobals.img + '/pois/' + poi.category_id + '.png', size: [28, 38], anchor: [14, 38] }),
popup: popup
});
this.map_.addMarker(marker);
this.listMarkers_.push(marker);
// Pintamos resultado en el listado
var poiClick = -1;
var self = this;
var itemList = cercalia.jQuery("<li />").addClass("cercalia-widget-poiproximity-result-list-item").appendTo(resultList)
.click({elemNum: index, marker: marker}, function (event) {
if(event.data.elemNum != poiClick) {
if(poiClick == -1) {
// Estamos en zoomout y hacemos zoomin.
self.map_.centerToMarkers([event.data.marker]);
} else {
// Estamos en zoomin y hacemos out e in.
self.map_.centerToMarkers(self.listMarkers_);
setTimeout(function () {self.map_.centerToMarkers([event.data.marker]); }, 1000);
}
poiClick = event.data.elemNum;
} else {
self.map_.centerToMarkers(self.listMarkers_);
poiClick = -1;
}
});
cercalia.jQuery("<span />").addClass("ui-icon cercalia-icon cercalia-icon-category cercalia-icon-category-"+poi.category_id).appendTo(itemList);
itemList.append(poi.info.value);
}
// Siempre habrá como mínimo un elemento
if(this.listMarkers_.length > 1)
this.map_.centerToMarkers(this.listMarkers_);
else
this.map_.setCenter(this.listMarkers_[0].getPosition(), 10);
} else {
cercalia.Exception('WIDGET_WARN_NO_CANDIDATES "%"', this.CLASS_NAME_);
}
} else {
cercalia.Exception('WIDGET_WARN_NO_CANDIDATES "%"', this.CLASS_NAME_);
}
};
/**
* Dibuja un circulo en el centro de la busqueda
* @private
* @param {Object} proximity Proximity devuelto por cercalia.
* @param {number} radius Radio del circulo.
*/
cercalia.widget.PoiProximity.prototype.drawRadius_ = function (proximity, radius) {
// Ponemos un marcador para indicar el centro de la busqueda
var xy = proximity.center.split(",");
var centro = new cercalia.Marker({
position: new cercalia.LonLat(xy[0], xy[1]),
label: new cercalia.Label({text: cercalia.i18n._("POIPROXIMITY_CENTER"), offsetY: 34})
});
this.map_.addMarker(centro);
this.listMarkers_.push(centro);
// Ponemos un circulo si hay radio
if(radius !== null) {
// ol.sphere.WGS84 -> not work
// new ol.Sphere(6378137) === ol.sphere.WGS84
//var circle = ol.geom.Polygon.circular(ol.sphere.WGS84, [parseFloat(xy[0]), parseFloat(xy[1])], radius, 64);
var circle = ol.geom.Polygon.circular(new ol.Sphere(6378137), [parseFloat(xy[0]), parseFloat(xy[1])], radius, 64);
circle.transform('EPSG:4326', this.map_.getProjectionCode());
this.featureRadius_ = new cercalia.Feature({geometry: circle});
this.map_.addFeature(this.featureRadius_);
}
};
/**
* Genera el contenido HTML del Popup.
* @private
* @param {Object} poi Objeto POI de Cercalia.
* @return {string}
*/
cercalia.widget.PoiProximity.prototype.popupContent_ = function (poi) {
var content = cercalia.jQuery("<div />");
var table = cercalia.jQuery("<table />").css("width", "300px").appendTo(content);
var ge = poi.ge;
if(poi.info) {
var tr = cercalia.jQuery("<tr />").appendTo(table);
cercalia.jQuery("<td />").css("font-weight", "bold").html(cercalia.i18n._("Information")).appendTo(tr);
cercalia.jQuery("<td />").css("width", "225px").html(poi.info.value).appendTo(tr);
}
if(ge.city) {
var tr = cercalia.jQuery("<tr />").appendTo(table);
cercalia.jQuery("<td />").css("font-weight", "bold").html(cercalia.i18n._("City")).appendTo(tr);
cercalia.jQuery("<td />").html(ge.city.value).appendTo(tr);
}
if(ge.postalcode) {
var tr = cercalia.jQuery("<tr />").appendTo(table);
cercalia.jQuery("<td />").css("font-weight", "bold").html(cercalia.i18n._("Postal code")).appendTo(tr);
cercalia.jQuery("<td />").html(ge.postalcode.id).appendTo(tr);
}
if(ge.municipality) {
var tr = cercalia.jQuery("<tr />").appendTo(table);
cercalia.jQuery("<td />").css("font-weight", "bold").html(cercalia.i18n._("Municipality")).appendTo(tr);
cercalia.jQuery("<td />").html(ge.municipality.value).appendTo(tr);
}
if(ge.subregion) {
var tr = cercalia.jQuery("<tr />").appendTo(table);
cercalia.jQuery("<td />").css("font-weight", "bold").html(cercalia.i18n._("Subregion")).appendTo(tr);
cercalia.jQuery("<td />").html(ge.subregion.value).appendTo(tr);
}
if(ge.region) {
tr = cercalia.jQuery("<tr />").appendTo(table);
cercalia.jQuery("<td />").css("font-weight", "bold").html(cercalia.i18n._("Region")).appendTo(tr);
cercalia.jQuery("<td />").html(ge.region.value).appendTo(tr);
}
if(ge.country) {
tr = cercalia.jQuery("<tr />").appendTo(table);
cercalia.jQuery("<td />").css("font-weight", "bold").html(cercalia.i18n._("Country")).appendTo(tr);
cercalia.jQuery("<td />").html(ge.country.value).appendTo(tr);
}
if(poi.coord) {
tr = cercalia.jQuery("<tr />").appendTo(table);
cercalia.jQuery("<td />").css("font-weight", "bold").html(cercalia.i18n._("Coords")).appendTo(tr);
cercalia.jQuery("<td />").html(poi.coord.x +", " + poi.coord.y).appendTo(tr);
}
return content.html();
};
/**
* Limpia las busquedas activas de geocoding.
*/
cercalia.widget.PoiProximity.prototype.cleanMarkers = function () {
// Eliminamos marcadores
for(var index = 0; index < this.listMarkers_; index++) {
var marker = this.listMarkers_[index];
marker.destroy();
}
this.listMarkers_ = [];
cercalia.jQuery("#" + this.divId_).find(".cercalia-widget-poiproximity-result-list").empty();
// Eliminamos circulo
if(this.featureRadius_ !== null) this.featureRadius_.destroy();
this.featureRadius_ = null;
};
/**
* Devuelve el tipo del objeto.
* @return {string}
*/
cercalia.widget.PoiProximity.prototype.getClass = function(){
return this.CLASS_NAME_;
};