Non puoi selezionare più di 25 argomenti
Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.
349 righe
9.0 KiB
349 righe
9.0 KiB
/* |
|
* L.Control.Coordinates is used for displaying current mouse coordinates on the map. |
|
*/ |
|
|
|
L.Control.Coordinates = L.Control.extend({ |
|
options: { |
|
position: 'bottomright', |
|
//decimals used if not using DMS or labelFormatter functions |
|
decimals: 4, |
|
//decimalseperator used if not using DMS or labelFormatter functions |
|
decimalSeperator: ".", |
|
//label templates for usage if no labelFormatter function is defined |
|
labelTemplateLat: "Lat: {y}", |
|
labelTemplateLng: "Lng: {x}", |
|
//label formatter functions |
|
labelFormatterLat: undefined, |
|
labelFormatterLng: undefined, |
|
//switch on/off input fields on click |
|
enableUserInput: true, |
|
//use Degree-Minute-Second |
|
useDMS: false, |
|
//if true lat-lng instead of lng-lat label ordering is used |
|
useLatLngOrder: false, |
|
//if true user given coordinates are centered directly |
|
centerUserCoordinates: true, |
|
//leaflet marker type |
|
markerType: L.marker, |
|
//leaflet marker properties |
|
markerProps: {}//, |
|
//customLabelFcn: function(latLonObj, opts) { "Geohash: " + encodeGeoHash(latLonObj.lat, latLonObj.lng)} //optional default none |
|
}, |
|
|
|
onAdd: function(map) { |
|
this._map = map; |
|
|
|
var className = 'leaflet-control-coordinates', |
|
container = this._container = L.DomUtil.create('div', className), |
|
options = this.options; |
|
|
|
//label containers |
|
this._labelcontainer = L.DomUtil.create("div", "uiElement label", container); |
|
this._label = L.DomUtil.create("span", "labelFirst", this._labelcontainer); |
|
|
|
|
|
//input containers |
|
this._inputcontainer = L.DomUtil.create("div", "uiElement input uiHidden", container); |
|
var xSpan, ySpan; |
|
if (options.useLatLngOrder) { |
|
ySpan = L.DomUtil.create("span", "", this._inputcontainer); |
|
this._inputY = this._createInput("inputY", this._inputcontainer); |
|
xSpan = L.DomUtil.create("span", "", this._inputcontainer); |
|
this._inputX = this._createInput("inputX", this._inputcontainer); |
|
} else { |
|
xSpan = L.DomUtil.create("span", "", this._inputcontainer); |
|
this._inputX = this._createInput("inputX", this._inputcontainer); |
|
ySpan = L.DomUtil.create("span", "", this._inputcontainer); |
|
this._inputY = this._createInput("inputY", this._inputcontainer); |
|
} |
|
xSpan.innerHTML = options.labelTemplateLng.replace("{x}", ""); |
|
ySpan.innerHTML = options.labelTemplateLat.replace("{y}", ""); |
|
|
|
L.DomEvent.on(this._inputX, 'keyup', this._handleKeypress, this); |
|
L.DomEvent.on(this._inputY, 'keyup', this._handleKeypress, this); |
|
|
|
//connect to mouseevents |
|
map.on("mousemove", this._update, this); |
|
map.on('dragstart', this.collapse, this); |
|
|
|
map.whenReady(this._update, this); |
|
|
|
this._showsCoordinates = true; |
|
//wether or not to show inputs on click |
|
if (options.enableUserInput) { |
|
L.DomEvent.addListener(this._container, "click", this._switchUI, this); |
|
} |
|
|
|
return container; |
|
}, |
|
|
|
/** |
|
* Creates an input HTML element in given container with given classname |
|
*/ |
|
_createInput: function(classname, container) { |
|
var input = L.DomUtil.create("input", classname, container); |
|
input.type = "text"; |
|
L.DomEvent.disableClickPropagation(input); |
|
return input; |
|
}, |
|
|
|
_clearMarker: function() { |
|
this._map.removeLayer(this._marker); |
|
}, |
|
|
|
/** |
|
* Called onkeyup of input fields |
|
*/ |
|
_handleKeypress: function(e) { |
|
switch (e.keyCode) { |
|
case 27: //Esc |
|
this.collapse(); |
|
break; |
|
case 13: //Enter |
|
this._handleSubmit(); |
|
this.collapse(); |
|
break; |
|
default: //All keys |
|
this._handleSubmit(); |
|
break; |
|
} |
|
}, |
|
|
|
/** |
|
* Called on each keyup except ESC |
|
*/ |
|
_handleSubmit: function() { |
|
var x = L.NumberFormatter.createValidNumber(this._inputX.value, this.options.decimalSeperator); |
|
var y = L.NumberFormatter.createValidNumber(this._inputY.value, this.options.decimalSeperator); |
|
if (x !== undefined && y !== undefined) { |
|
var marker = this._marker; |
|
if (!marker) { |
|
marker = this._marker = this._createNewMarker(); |
|
marker.on("click", this._clearMarker, this); |
|
} |
|
var ll = new L.LatLng(y, x); |
|
marker.setLatLng(ll); |
|
marker.addTo(this._map); |
|
if (this.options.centerUserCoordinates) { |
|
this._map.setView(ll, this._map.getZoom()); |
|
} |
|
} |
|
}, |
|
|
|
/** |
|
* Shows inputs fields |
|
*/ |
|
expand: function() { |
|
this._showsCoordinates = false; |
|
|
|
this._map.off("mousemove", this._update, this); |
|
|
|
L.DomEvent.addListener(this._container, "mousemove", L.DomEvent.stop); |
|
L.DomEvent.removeListener(this._container, "click", this._switchUI, this); |
|
|
|
L.DomUtil.addClass(this._labelcontainer, "uiHidden"); |
|
L.DomUtil.removeClass(this._inputcontainer, "uiHidden"); |
|
}, |
|
|
|
/** |
|
* Creates the label according to given options and formatters |
|
*/ |
|
_createCoordinateLabel: function(ll) { |
|
var opts = this.options, |
|
x, y; |
|
if (opts.customLabelFcn) { |
|
return opts.customLabelFcn(ll, opts); |
|
} |
|
if (opts.labelLng) { |
|
x = opts.labelFormatterLng(ll.lng); |
|
} else { |
|
x = L.Util.template(opts.labelTemplateLng, { |
|
x: this._getNumber(ll.lng, opts) |
|
}); |
|
} |
|
if (opts.labelFormatterLat) { |
|
y = opts.labelFormatterLat(ll.lat); |
|
} else { |
|
y = L.Util.template(opts.labelTemplateLat, { |
|
y: this._getNumber(ll.lat, opts) |
|
}); |
|
} |
|
if (opts.useLatLngOrder) { |
|
return y + " " + x; |
|
} |
|
return x + " " + y; |
|
}, |
|
|
|
/** |
|
* Returns a Number according to options (DMS or decimal) |
|
*/ |
|
_getNumber: function(n, opts) { |
|
var res; |
|
if (opts.useDMS) { |
|
res = L.NumberFormatter.toDMS(n); |
|
} else { |
|
res = L.NumberFormatter.round(n, opts.decimals, opts.decimalSeperator); |
|
} |
|
return res; |
|
}, |
|
|
|
/** |
|
* Shows coordinate labels after user input has ended. Also |
|
* displays a marker with popup at the last input position. |
|
*/ |
|
collapse: function() { |
|
if (!this._showsCoordinates) { |
|
this._map.on("mousemove", this._update, this); |
|
this._showsCoordinates = true; |
|
var opts = this.options; |
|
L.DomEvent.addListener(this._container, "click", this._switchUI, this); |
|
L.DomEvent.removeListener(this._container, "mousemove", L.DomEvent.stop); |
|
|
|
L.DomUtil.addClass(this._inputcontainer, "uiHidden"); |
|
L.DomUtil.removeClass(this._labelcontainer, "uiHidden"); |
|
|
|
if (this._marker) { |
|
var m = this._createNewMarker(), |
|
ll = this._marker.getLatLng(); |
|
m.setLatLng(ll); |
|
|
|
var container = L.DomUtil.create("div", ""); |
|
var label = L.DomUtil.create("div", "", container); |
|
label.innerHTML = this._ordinateLabel(ll); |
|
|
|
var close = L.DomUtil.create("a", "", container); |
|
close.innerHTML = "Remove"; |
|
close.href = "#"; |
|
var stop = L.DomEvent.stopPropagation; |
|
|
|
L.DomEvent |
|
.on(close, 'click', stop) |
|
.on(close, 'mousedown', stop) |
|
.on(close, 'dblclick', stop) |
|
.on(close, 'click', L.DomEvent.preventDefault) |
|
.on(close, 'click', function() { |
|
this._map.removeLayer(m); |
|
}, this); |
|
|
|
m.bindPopup(container); |
|
m.addTo(this._map); |
|
this._map.removeLayer(this._marker); |
|
this._marker = null; |
|
} |
|
} |
|
}, |
|
|
|
/** |
|
* Click callback for UI |
|
*/ |
|
_switchUI: function(evt) { |
|
L.DomEvent.stop(evt); |
|
L.DomEvent.stopPropagation(evt); |
|
L.DomEvent.preventDefault(evt); |
|
if (this._showsCoordinates) { |
|
//show textfields |
|
this.expand(); |
|
} else { |
|
//show coordinates |
|
this.collapse(); |
|
} |
|
}, |
|
|
|
onRemove: function(map) { |
|
map.off("mousemove", this._update, this); |
|
}, |
|
|
|
/** |
|
* Mousemove callback function updating labels and input elements |
|
*/ |
|
_update: function(evt) { |
|
var pos = evt.latlng, |
|
opts = this.options; |
|
if (pos) { |
|
pos = pos.wrap(); |
|
this._currentPos = pos; |
|
this._inputY.value = L.NumberFormatter.round(pos.lat, opts.decimals, opts.decimalSeperator); |
|
this._inputX.value = L.NumberFormatter.round(pos.lng, opts.decimals, opts.decimalSeperator); |
|
this._label.innerHTML = this._createCoordinateLabel(pos); |
|
} |
|
}, |
|
|
|
_createNewMarker: function() { |
|
return this.options.markerType(null, this.options.markerProps); |
|
} |
|
|
|
}); |
|
|
|
//constructor registration |
|
L.control.coordinates = function(options) { |
|
return new L.Control.Coordinates(options); |
|
}; |
|
|
|
//map init hook |
|
L.Map.mergeOptions({ |
|
coordinateControl: false |
|
}); |
|
|
|
L.Map.addInitHook(function() { |
|
if (this.options.coordinateControl) { |
|
this.coordinateControl = new L.Control.Coordinates(); |
|
this.addControl(this.coordinateControl); |
|
} |
|
}); |
|
L.NumberFormatter = { |
|
round: function(num, dec, sep) { |
|
var res = L.Util.formatNum(num, dec) + "", |
|
numbers = res.split("."); |
|
if (numbers[1]) { |
|
var d = dec - numbers[1].length; |
|
for (; d > 0; d--) { |
|
numbers[1] += "0"; |
|
} |
|
res = numbers.join(sep || "."); |
|
} |
|
return res; |
|
}, |
|
|
|
toDMS: function(deg) { |
|
var d = Math.floor(Math.abs(deg)); |
|
var minfloat = (Math.abs(deg) - d) * 60; |
|
var m = Math.floor(minfloat); |
|
var secfloat = (minfloat - m) * 60; |
|
var s = Math.round(secfloat); |
|
if (s == 60) { |
|
m++; |
|
s = "00"; |
|
} |
|
if (m == 60) { |
|
d++; |
|
m = "00"; |
|
} |
|
if (s < 10) { |
|
s = "0" + s; |
|
} |
|
if (m < 10) { |
|
m = "0" + m; |
|
} |
|
var dir = ""; |
|
if (deg < 0) { |
|
dir = "-"; |
|
} |
|
return ("" + dir + d + "° " + m + "' " + s + "''"); |
|
}, |
|
|
|
createValidNumber: function(num, sep) { |
|
if (num && num.length > 0) { |
|
var numbers = num.split(sep || "."); |
|
try { |
|
var numRes = Number(numbers.join(".")); |
|
if (isNaN(numRes)) { |
|
return undefined; |
|
} |
|
return numRes; |
|
} catch (e) { |
|
return undefined; |
|
} |
|
} |
|
return undefined; |
|
} |
|
}; |