import $ from 'jquery';
import L from 'leaflet';
import FilterForm from './filterui';
import QuerybuilderAPI from './querybuilderapi';
import registerWidgetClass from './registerwidgetclass';
/** AJAX map widget.
* @constructor
* @param {string} name - widget name used as container ID and
endpoint parameter
* @param {string} formID - optional filter ID
* @param {QuerybuilderAPI} api - the endpoint
* @param {string} params - manually defined string that can be passed
to the endpoint
*/
class Map {
constructor(name, formID, api, params) {
this.arrayMarkers = [];
this.map = null;
this.layerData = null;
this.formID = formID ? '#' + formID : null;
this.mapWidgetId = name;
this.api = api;
this.params = params;
new FilterForm(this.formID);
this._setUpdateMapEventHandling('#' + this.mapWidgetId);
this.init();
}
init() {
this.triggerMap = triggerMapFactory(this.mapWidgetId);
this.map_class = new MapLinker(this.formID,
this.api,
this.params, this.triggerMap,
this.mapWidgetId);
this.layerData = new L.LayerGroup();
this.arrayMarkers = [];
this.map = getLeafletMap(this.mapWidgetId, this.layerData);
this.map_class.retrieveData({containerID: this.mapWidgetId},
this.params, this.triggerMap);
}
addMarker (obj) {
var marker = L.marker({"lat": obj.latitude, "lng": obj.longitude});
var popupText = obj.description;
marker.bindPopup(popupText);
marker.addTo(this.layerData);
this.arrayMarkers.push(marker);
}
_setUpdateMapEventHandling(widgetId) {
$(widgetId).on('update:Map', this._updateMap.bind(this));
}
_updateMap(event, filterData) {
this._removeAllLayers();
this._addMarkers(filterData);
this._zoomLeafletViewport();
}
_zoomLeafletViewport() {
if (this.arrayMarkers.length > 0) {
var group = L.featureGroup(this.arrayMarkers);
this.map.fitBounds(group.getBounds());
}
}
_addMarkers(filterData) {
if (filterData) {
filterData.data.forEach(this._addSingleMarker.bind(this));
}
}
_addSingleMarker(marker) {
this.addMarker(marker);
}
_removeAllLayers() {
this.arrayMarkers.forEach(this._removeLayer.bind(this));
this.arrayMarkers = [];
}
_removeLayer(layer) {
this.map.removeLayer(layer);
this.layerData.removeLayer(layer);
}
static register(element) {
var mapElement = $(element);
var mapData = mapElement.data("django-querybuilder-map");
L.Icon.Default.imagePath = mapData.imageUrl;
var api = new QuerybuilderAPI(mapData.endpoint);
return new Map(mapData.name, mapData.filter, api, mapData.params);
}
}
class MapLinker {
constructor(formID, api, params, triggerMap, mapWidgetId) {
this.mapWidgetId = mapWidgetId;
this.api = api;
this._getData(formID);
this.triggerMap = triggerMap;
this.params = params;
}
retrieveData(queryConfig, params, callback) {
return this.api.retrieveData(this.mapWidgetId,
queryConfig, params, callback);
}
_getData(formID) {
if (formID) {
this.form = $(formID).data('FilterForm');
this.form.onSubmit(this._getFilteredData.bind(this));
} else {
this._getDefaultData();
}
}
_getDefaultData() {
var queryConfig = {containerID: this.mapWidgetId};
this.retrieveData(queryConfig, this.params, this.triggerMap);
}
_getFilteredData(event) {
event.preventDefault();
event.stopPropagation();
var queryConfig = this.form.serialize();
this.retrieveData(queryConfig, this.params, this.triggerMap);
}
}
function triggerMapFactory(containerID) {
var container = containerID ? containerID : 'filter';
return function (filteredData) {
$('#' + container).trigger("update:Map", [filteredData]);
};
}
function getLeafletConfig(osm, layerData) {
return {
center: [0.01, 51.405],
zoom: 13,
fullscreenControl: true,
fullscreenOptions: {
position: 'topleft'
},
layers: [osm, layerData]
};
}
function getOsmTileLayer() {
var osmURL = 'http://{s}.tile.osm.org/{z}/{x}/{y}.png';
var osmAttrib = '© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors';
return new L.TileLayer(osmURL, {attribution: osmAttrib});
}
function getLeafletMap(widgetId, layerData) {
var osm = getOsmTileLayer();
var map = L.map(widgetId, getLeafletConfig(osm, layerData));
var baseLayers = {"OpenStreetMap": osm};
var overlays = {"Data Layer": layerData};
L.control.layers(baseLayers, overlays).addTo(map);
return map;
}
registerWidgetClass("map", Map);
export default Map;