2017-10-04 11:05:44 +02:00
|
|
|
/**
|
|
|
|
|
* Geocode backend widget based on Leaflet.
|
|
|
|
|
*
|
|
|
|
|
* @package netzmacht
|
|
|
|
|
* @author David Molineus <david.molineus@netzmacht.de>
|
2018-02-06 16:32:56 +01:00
|
|
|
* @copyright 2016-2018 netzmacht David Molineus. All rights reserved.
|
2017-10-04 11:05:44 +02:00
|
|
|
* @license LGPL-3.0 https://github.com/netzmacht/contao-leaflet-geocode-widget/blob/master/LICENSE
|
|
|
|
|
* @filesource
|
|
|
|
|
*/
|
|
|
|
|
|
2018-02-08 21:53:00 +01:00
|
|
|
var LeafletGeocodeAbstractPicker = L.Class.extend({
|
|
|
|
|
initialize: function (map, options) {
|
|
|
|
|
L.Util.setOptions(this, options);
|
|
|
|
|
this.map = map;
|
|
|
|
|
},
|
2018-02-12 13:36:47 +01:00
|
|
|
show: function (position, radius) {
|
2018-02-08 21:53:00 +01:00
|
|
|
if (!this.marker) {
|
2018-02-12 13:36:47 +01:00
|
|
|
this._createMarker(position, radius);
|
2018-02-08 21:53:00 +01:00
|
|
|
} else {
|
2018-02-12 13:36:47 +01:00
|
|
|
this._updateCoordinates(position, radius);
|
2018-02-08 21:53:00 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this._panTo(position);
|
|
|
|
|
},
|
|
|
|
|
_updateCoordinates: function (position) {
|
|
|
|
|
this.marker.setLatLng(position);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
var LeafletGeocodeMarkerPicker = LeafletGeocodeAbstractPicker.extend({
|
|
|
|
|
apply: function (coordinatesInput) {
|
|
|
|
|
var coordinates = this.marker
|
|
|
|
|
? ( this.marker.getLatLng().lat + ',' + this.marker.getLatLng().lng)
|
|
|
|
|
: '';
|
|
|
|
|
|
|
|
|
|
coordinatesInput.set('value', coordinates);
|
|
|
|
|
},
|
|
|
|
|
_panTo: function (position) {
|
|
|
|
|
this.map.setZoom(this.map.getMaxZoom());
|
|
|
|
|
this.map.panTo(position);
|
|
|
|
|
},
|
|
|
|
|
_createMarker: function (position) {
|
|
|
|
|
this.marker = L.marker(position, {draggable: true}).addTo(this.map);
|
|
|
|
|
this.marker.on('dragend', function () {
|
|
|
|
|
this.map.panTo(this.marker.getLatLng());
|
|
|
|
|
}.bind(this));
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
var LeafletGeocodeCirclePicker = LeafletGeocodeAbstractPicker.extend({
|
|
|
|
|
apply: function (coordinatesInput, radiusInput) {
|
2018-02-23 11:09:40 +01:00
|
|
|
var radius = '';
|
2018-02-08 21:53:00 +01:00
|
|
|
var coordinates = this.marker
|
|
|
|
|
? ( this.marker.getLatLng().lat + ',' + this.marker.getLatLng().lng)
|
|
|
|
|
: '';
|
|
|
|
|
|
|
|
|
|
coordinatesInput.set('value', coordinates);
|
2018-02-23 11:09:40 +01:00
|
|
|
|
|
|
|
|
if (this.marker) {
|
|
|
|
|
radius = Math.round(this.marker.getRadius());
|
|
|
|
|
|
|
|
|
|
if (this.options.radius.steps > 0) {
|
|
|
|
|
radius = (this.options.radius.steps * Math.round(radius / this.options.radius.steps));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
radiusInput.set('value', radius);
|
2018-02-08 21:53:00 +01:00
|
|
|
},
|
|
|
|
|
_panTo: function () {
|
|
|
|
|
this.map.fitBounds(this.marker.getBounds());
|
|
|
|
|
},
|
2018-02-12 13:36:47 +01:00
|
|
|
_createMarker: function (position, radius) {
|
|
|
|
|
this.marker = L.circle(position, { radius: radius || this.options.radius.default });
|
2018-02-08 21:53:00 +01:00
|
|
|
this.marker.addTo(this.map);
|
|
|
|
|
|
|
|
|
|
this.marker.on('pm:markerdragend', function () {
|
|
|
|
|
var radius = this.marker.getRadius();
|
|
|
|
|
|
2018-02-23 11:09:40 +01:00
|
|
|
if (this.options.radius.steps > 0) {
|
|
|
|
|
radius = (this.options.radius.steps * Math.round(radius / this.options.radius.steps));
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-08 21:53:00 +01:00
|
|
|
if (this.options.radius.min > 0 && this.options.radius.min > radius) {
|
|
|
|
|
radius = this.options.radius.min;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (this.options.radius.max > 0 && this.options.radius.max < radius) {
|
|
|
|
|
radius = this.options.radius.max;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (radius != this.marker.getRadius()) {
|
|
|
|
|
this.marker.pm.disable();
|
|
|
|
|
this.marker.setRadius(radius);
|
|
|
|
|
this._enableEditMode();
|
|
|
|
|
} else {
|
|
|
|
|
this.marker.pm._outerMarker.setTooltipContent(this._formatRadius(radius));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.map.fitBounds(this.marker.getBounds());
|
|
|
|
|
}.bind(this));
|
|
|
|
|
|
|
|
|
|
this._enableEditMode();
|
|
|
|
|
},
|
2018-02-12 13:36:47 +01:00
|
|
|
_updateCoordinates: function (position,radius) {
|
2018-02-08 21:53:00 +01:00
|
|
|
this.marker.pm.disable();
|
|
|
|
|
this.marker.setLatLng(position);
|
2018-02-12 15:50:37 +01:00
|
|
|
|
|
|
|
|
if (radius !== undefined) {
|
|
|
|
|
this.marker.setRadius(radius);
|
|
|
|
|
}
|
2018-02-08 21:53:00 +01:00
|
|
|
this.marker.pm.enable();
|
|
|
|
|
},
|
|
|
|
|
_enableEditMode: function () {
|
|
|
|
|
this.marker.pm.enable();
|
|
|
|
|
this.marker.pm._outerMarker.bindTooltip(
|
|
|
|
|
this._formatRadius(this.marker.getRadius()),
|
|
|
|
|
{permanent: true, direction: 'right', offset: [10, 0] }
|
|
|
|
|
);
|
|
|
|
|
},
|
|
|
|
|
_formatRadius: function (radius) {
|
|
|
|
|
var unit = 'm';
|
|
|
|
|
|
|
|
|
|
radius = Math.floor(radius);
|
|
|
|
|
|
|
|
|
|
if (radius > 1000) {
|
|
|
|
|
unit = 'km';
|
|
|
|
|
radius = (radius / 1000).toFixed(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return radius.toString() + ' ' + unit;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2017-01-18 17:16:40 +01:00
|
|
|
var LeafletGeocodeWidget = L.Class.extend({
|
|
|
|
|
options: {
|
2018-02-08 21:53:00 +01:00
|
|
|
mapTemplate: '<div id="leaflet_geocode_widget_map_{id}" class="leaflet-geocode-map"></div>',
|
2017-01-18 17:16:40 +01:00
|
|
|
modalWidth: 800,
|
|
|
|
|
modalTitle: 'Choose coordinates',
|
|
|
|
|
searchPositionLabel: 'Search',
|
2018-02-06 16:32:56 +01:00
|
|
|
applyPositionLabel: 'Apply',
|
2018-02-12 16:51:24 +01:00
|
|
|
confirmPositionLabel: 'Set as new position',
|
|
|
|
|
okLabel: 'Ok',
|
|
|
|
|
cancelLabel: 'Cancel',
|
2018-02-06 16:32:56 +01:00
|
|
|
radius: null,
|
2018-02-08 21:53:00 +01:00
|
|
|
picker: LeafletGeocodeMarkerPicker,
|
|
|
|
|
map: {
|
2018-02-06 16:32:56 +01:00
|
|
|
maxZoom: 15,
|
|
|
|
|
minZoom: 2
|
|
|
|
|
},
|
|
|
|
|
bboxPadding: [0, 70]
|
2017-01-18 17:16:40 +01:00
|
|
|
},
|
|
|
|
|
initialize: function (options) {
|
|
|
|
|
L.Util.setOptions(this, options);
|
|
|
|
|
|
|
|
|
|
this.element = $(this.options.id);
|
|
|
|
|
this.toggle = $(this.options.id + '_toggle');
|
|
|
|
|
this.toggle.addEvent('click', this._showMap.bind(this));
|
2018-02-06 16:32:56 +01:00
|
|
|
|
|
|
|
|
if (this.options.radius) {
|
2018-02-08 21:53:00 +01:00
|
|
|
this.radius = $(this.options.radius.element);
|
|
|
|
|
|
|
|
|
|
if (this.radius.get('value').length > 0) {
|
|
|
|
|
this.options.radius.default = parseInt(this.radius.get('value'));
|
|
|
|
|
}
|
2018-02-12 13:36:47 +01:00
|
|
|
|
|
|
|
|
if (this.options.radius.default === undefined) {
|
|
|
|
|
this.options.radius.default = 0;
|
|
|
|
|
}
|
2018-02-06 16:32:56 +01:00
|
|
|
}
|
2017-01-18 17:16:40 +01:00
|
|
|
},
|
2018-02-12 13:23:18 +01:00
|
|
|
_showMap: function (e) {
|
|
|
|
|
e.stop();
|
|
|
|
|
|
2017-01-18 17:16:40 +01:00
|
|
|
// Create modal window.
|
2018-02-08 21:53:00 +01:00
|
|
|
var content = L.Util.template(this.options.mapTemplate, this.options);
|
|
|
|
|
this.modal = this._createModal();
|
2017-01-18 17:16:40 +01:00
|
|
|
|
2018-02-08 21:53:00 +01:00
|
|
|
this.modal.show({title: this.options.modalTitle, contents: content});
|
2017-01-18 17:16:40 +01:00
|
|
|
|
|
|
|
|
// Initialize map after showing modal so element exists.
|
2018-02-08 21:53:00 +01:00
|
|
|
this._createMap();
|
2017-01-18 17:16:40 +01:00
|
|
|
},
|
|
|
|
|
_createModal: function () {
|
2018-02-08 21:53:00 +01:00
|
|
|
var modal = new SimpleModal({
|
|
|
|
|
width: this.options.modalWidth,
|
|
|
|
|
hideFooter: false,
|
|
|
|
|
draggable: false,
|
|
|
|
|
overlayOpacity: .5,
|
|
|
|
|
btn_ok: Contao.lang.close,
|
|
|
|
|
onShow: function () {
|
2017-10-04 11:05:44 +02:00
|
|
|
document.body.setStyle('overflow', 'hidden');
|
|
|
|
|
},
|
2018-02-08 21:53:00 +01:00
|
|
|
onHide: function () {
|
2017-10-04 11:05:44 +02:00
|
|
|
document.body.setStyle('overflow', 'auto');
|
|
|
|
|
}
|
2017-01-18 17:16:40 +01:00
|
|
|
});
|
2018-02-08 21:53:00 +01:00
|
|
|
|
|
|
|
|
modal.addButton(Contao.lang.apply, 'btn', function () {
|
|
|
|
|
this.picker.apply(this.element, this.radius);
|
|
|
|
|
modal.hide();
|
|
|
|
|
}.bind(this));
|
|
|
|
|
|
|
|
|
|
return modal;
|
2017-01-18 17:16:40 +01:00
|
|
|
},
|
2018-02-08 21:53:00 +01:00
|
|
|
_createMap: function () {
|
|
|
|
|
var map = L.map('leaflet_geocode_widget_map_' + this.options.id, this.options.map).setView([0, 0], 2);
|
2018-02-12 13:36:47 +01:00
|
|
|
var radius = 0;
|
2018-02-08 21:53:00 +01:00
|
|
|
this.picker = new this.options.picker(map, this.options);
|
2017-01-18 17:16:40 +01:00
|
|
|
|
|
|
|
|
L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
|
|
|
|
|
attribution: '© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
|
|
|
|
|
}).addTo(map);
|
|
|
|
|
|
2018-02-12 16:51:24 +01:00
|
|
|
map.on('click', function (event) {
|
|
|
|
|
var marker = new L.marker(event.latlng).addTo(map);
|
|
|
|
|
var container = document.createElement('div');
|
|
|
|
|
var okButton = document.createElement('button');
|
|
|
|
|
var cancelButton = document.createElement('button');
|
|
|
|
|
|
|
|
|
|
okButton.set('class', 'leaflet-geocode-btn').appendHTML(this.options.okLabel);
|
|
|
|
|
okButton.addEvent('click', function (event) {
|
|
|
|
|
event.stop();
|
|
|
|
|
|
|
|
|
|
this.picker.show(marker.getLatLng());
|
|
|
|
|
map.removeLayer(marker);
|
|
|
|
|
}.bind(this));
|
|
|
|
|
|
|
|
|
|
cancelButton.set('class', 'leaflet-geocode-btn').appendHTML(this.options.cancelLabel);
|
|
|
|
|
cancelButton.addEvent('click', function (event) {
|
|
|
|
|
map.removeLayer(marker);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
container.appendHTML('<h2>' + this.options.confirmPositionLabel + '</h2>');
|
|
|
|
|
container.appendChild(okButton);
|
|
|
|
|
container.appendChild(cancelButton);
|
|
|
|
|
|
2018-02-12 17:24:52 +01:00
|
|
|
marker.bindPopup(container, {
|
2018-02-12 16:51:24 +01:00
|
|
|
keepInView: true,
|
|
|
|
|
autoPanPaddingTopLeft: this.options.bboxPadding,
|
|
|
|
|
autoClose: false,
|
|
|
|
|
closeOnClick: false,
|
|
|
|
|
closeButton: false
|
|
|
|
|
}).openPopup();
|
|
|
|
|
}.bind(this));
|
|
|
|
|
|
2017-01-18 17:16:40 +01:00
|
|
|
var geoCoder = L.Control.geocoder({
|
|
|
|
|
defaultMarkGeocode: false,
|
|
|
|
|
collapsed: false,
|
|
|
|
|
placeholder: this.options.searchPositionLabel
|
|
|
|
|
}).addTo(map);
|
|
|
|
|
|
|
|
|
|
geoCoder.on('markgeocode', function (event) {
|
2018-02-08 21:53:00 +01:00
|
|
|
this.picker.show(event.geocode.center);
|
2017-01-18 17:16:40 +01:00
|
|
|
}.bind(this));
|
|
|
|
|
|
|
|
|
|
if (this.element.value) {
|
2018-02-12 13:36:47 +01:00
|
|
|
if (this.radius && this.radius.get('value').length > 0) {
|
|
|
|
|
radius = parseInt(this.radius.get('value'));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.picker.show(L.latLng(this.element.value.split(/,/)), radius);
|
2017-01-18 17:16:40 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|