2019-05-07 01:19:26 +08:00
|
|
|
(function(factory, window){
|
|
|
|
"use strict";
|
|
|
|
if (typeof define === 'function' && define.amd) {
|
|
|
|
define(['leaflet'], factory);
|
|
|
|
} else if (typeof exports === 'object') {
|
|
|
|
module.exports = factory(require('leaflet'));
|
|
|
|
}
|
|
|
|
if (typeof window !== 'undefined' && window.L) {
|
|
|
|
window.L.Ruler = factory(L);
|
|
|
|
}
|
|
|
|
}(function (L) {
|
|
|
|
"use strict";
|
|
|
|
L.Control.Ruler = L.Control.extend({
|
|
|
|
options: {
|
|
|
|
position: 'topright',
|
|
|
|
circleMarker: {
|
|
|
|
color: 'red',
|
|
|
|
radius: 2
|
|
|
|
},
|
|
|
|
lineStyle: {
|
|
|
|
color: 'red',
|
|
|
|
dashArray: '1,6'
|
|
|
|
},
|
|
|
|
lengthUnit: {
|
|
|
|
display: 'km',
|
|
|
|
decimal: 2,
|
|
|
|
factor: null,
|
2024-02-19 17:35:12 +08:00
|
|
|
label: '距离:'
|
2019-05-07 01:19:26 +08:00
|
|
|
},
|
|
|
|
angleUnit: {
|
|
|
|
display: '°',
|
|
|
|
decimal: 2,
|
|
|
|
factor: null,
|
2024-02-19 17:35:12 +08:00
|
|
|
label: '方位:'
|
2019-05-07 01:19:26 +08:00
|
|
|
}
|
|
|
|
},
|
|
|
|
onAdd: function(map) {
|
|
|
|
this._map = map;
|
|
|
|
this._container = L.DomUtil.create('div', 'leaflet-bar');
|
|
|
|
this._container.classList.add('leaflet-ruler');
|
|
|
|
L.DomEvent.disableClickPropagation(this._container);
|
|
|
|
L.DomEvent.on(this._container, 'click', this._toggleMeasure, this);
|
|
|
|
this._choice = false;
|
|
|
|
this._defaultCursor = this._map._container.style.cursor;
|
|
|
|
this._allLayers = L.layerGroup();
|
|
|
|
return this._container;
|
|
|
|
},
|
|
|
|
onRemove: function() {
|
|
|
|
L.DomEvent.off(this._container, 'click', this._toggleMeasure, this);
|
|
|
|
},
|
|
|
|
_toggleMeasure: function() {
|
|
|
|
this._choice = !this._choice;
|
|
|
|
this._clickedLatLong = null;
|
|
|
|
this._clickedPoints = [];
|
|
|
|
this._totalLength = 0;
|
|
|
|
if (this._choice){
|
|
|
|
this._map.doubleClickZoom.disable();
|
|
|
|
L.DomEvent.on(this._map._container, 'keydown', this._escape, this);
|
|
|
|
L.DomEvent.on(this._map._container, 'dblclick', this._closePath, this);
|
|
|
|
this._container.classList.add("leaflet-ruler-clicked");
|
|
|
|
this._clickCount = 0;
|
|
|
|
this._tempLine = L.featureGroup().addTo(this._allLayers);
|
|
|
|
this._tempPoint = L.featureGroup().addTo(this._allLayers);
|
|
|
|
this._pointLayer = L.featureGroup().addTo(this._allLayers);
|
|
|
|
this._polylineLayer = L.featureGroup().addTo(this._allLayers);
|
|
|
|
this._allLayers.addTo(this._map);
|
|
|
|
this._map._container.style.cursor = 'crosshair';
|
|
|
|
this._map.on('click', this._clicked, this);
|
|
|
|
this._map.on('mousemove', this._moving, this);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
this._map.doubleClickZoom.enable();
|
|
|
|
L.DomEvent.off(this._map._container, 'keydown', this._escape, this);
|
|
|
|
L.DomEvent.off(this._map._container, 'dblclick', this._closePath, this);
|
|
|
|
this._container.classList.remove("leaflet-ruler-clicked");
|
|
|
|
this._map.removeLayer(this._allLayers);
|
|
|
|
this._allLayers = L.layerGroup();
|
|
|
|
this._map._container.style.cursor = this._defaultCursor;
|
|
|
|
this._map.off('click', this._clicked, this);
|
|
|
|
this._map.off('mousemove', this._moving, this);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
_clicked: function(e) {
|
|
|
|
this._clickedLatLong = e.latlng;
|
|
|
|
this._clickedPoints.push(this._clickedLatLong);
|
|
|
|
L.circleMarker(this._clickedLatLong, this.options.circleMarker).addTo(this._pointLayer);
|
|
|
|
if(this._clickCount > 0 && !e.latlng.equals(this._clickedPoints[this._clickedPoints.length - 2])){
|
|
|
|
if (this._movingLatLong){
|
|
|
|
L.polyline([this._clickedPoints[this._clickCount-1], this._movingLatLong], this.options.lineStyle).addTo(this._polylineLayer);
|
|
|
|
}
|
|
|
|
var text;
|
|
|
|
this._totalLength += this._result.Distance;
|
|
|
|
if (this._clickCount > 1){
|
|
|
|
text = '<b>' + this.options.angleUnit.label + '</b> ' + this._result.Bearing.toFixed(this.options.angleUnit.decimal) + ' ' + this.options.angleUnit.display + '<br><b>' + this.options.lengthUnit.label + '</b> ' + this._totalLength.toFixed(this.options.lengthUnit.decimal) + ' ' + this.options.lengthUnit.display;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
text = '<b>' + this.options.angleUnit.label + '</b> ' + this._result.Bearing.toFixed(this.options.angleUnit.decimal) + ' ' + this.options.angleUnit.display + '<br><b>' + this.options.lengthUnit.label + '</b> ' + this._result.Distance.toFixed(this.options.lengthUnit.decimal) + ' ' + this.options.lengthUnit.display;
|
|
|
|
}
|
|
|
|
L.circleMarker(this._clickedLatLong, this.options.circleMarker).bindTooltip(text, {permanent: true, className: 'result-tooltip'}).addTo(this._pointLayer).openTooltip();
|
|
|
|
}
|
|
|
|
this._clickCount++;
|
|
|
|
},
|
|
|
|
_moving: function(e) {
|
|
|
|
if (this._clickedLatLong){
|
|
|
|
L.DomEvent.off(this._container, 'click', this._toggleMeasure, this);
|
|
|
|
this._movingLatLong = e.latlng;
|
|
|
|
if (this._tempLine){
|
|
|
|
this._map.removeLayer(this._tempLine);
|
|
|
|
this._map.removeLayer(this._tempPoint);
|
|
|
|
}
|
|
|
|
var text;
|
|
|
|
this._addedLength = 0;
|
|
|
|
this._tempLine = L.featureGroup();
|
|
|
|
this._tempPoint = L.featureGroup();
|
|
|
|
this._tempLine.addTo(this._map);
|
|
|
|
this._tempPoint.addTo(this._map);
|
|
|
|
this._calculateBearingAndDistance();
|
|
|
|
this._addedLength = this._result.Distance + this._totalLength;
|
|
|
|
L.polyline([this._clickedLatLong, this._movingLatLong], this.options.lineStyle).addTo(this._tempLine);
|
|
|
|
if (this._clickCount > 1){
|
|
|
|
text = '<b>' + this.options.angleUnit.label + '</b> ' + this._result.Bearing.toFixed(this.options.angleUnit.decimal) + ' ' + this.options.angleUnit.display + '<br><b>' + this.options.lengthUnit.label + '</b> ' + this._addedLength.toFixed(this.options.lengthUnit.decimal) + ' ' + this.options.lengthUnit.display + '<br><div class="plus-length">(+' + this._result.Distance.toFixed(this.options.lengthUnit.decimal) + ')</div>';
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
text = '<b>' + this.options.angleUnit.label + '</b> ' + this._result.Bearing.toFixed(this.options.angleUnit.decimal) + ' ' + this.options.angleUnit.display + '<br><b>' + this.options.lengthUnit.label + '</b> ' + this._result.Distance.toFixed(this.options.lengthUnit.decimal) + ' ' + this.options.lengthUnit.display;
|
|
|
|
}
|
|
|
|
L.circleMarker(this._movingLatLong, this.options.circleMarker).bindTooltip(text, {sticky: true, offset: L.point(0, -40) ,className: 'moving-tooltip'}).addTo(this._tempPoint).openTooltip();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
_escape: function(e) {
|
|
|
|
if (e.keyCode === 27){
|
|
|
|
if (this._clickCount > 0){
|
|
|
|
this._closePath();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
this._choice = true;
|
|
|
|
this._toggleMeasure();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
_calculateBearingAndDistance: function() {
|
|
|
|
var f1 = this._clickedLatLong.lat, l1 = this._clickedLatLong.lng, f2 = this._movingLatLong.lat, l2 = this._movingLatLong.lng;
|
|
|
|
var toRadian = Math.PI / 180;
|
|
|
|
// haversine formula
|
|
|
|
// bearing
|
|
|
|
var y = Math.sin((l2-l1)*toRadian) * Math.cos(f2*toRadian);
|
|
|
|
var x = Math.cos(f1*toRadian)*Math.sin(f2*toRadian) - Math.sin(f1*toRadian)*Math.cos(f2*toRadian)*Math.cos((l2-l1)*toRadian);
|
|
|
|
var brng = Math.atan2(y, x)*((this.options.angleUnit.factor ? this.options.angleUnit.factor/2 : 180)/Math.PI);
|
|
|
|
brng += brng < 0 ? (this.options.angleUnit.factor ? this.options.angleUnit.factor : 360) : 0;
|
|
|
|
// distance
|
|
|
|
var R = this.options.lengthUnit.factor ? 6371 * this.options.lengthUnit.factor : 6371; // kilometres
|
|
|
|
var deltaF = (f2 - f1)*toRadian;
|
|
|
|
var deltaL = (l2 - l1)*toRadian;
|
|
|
|
var a = Math.sin(deltaF/2) * Math.sin(deltaF/2) + Math.cos(f1*toRadian) * Math.cos(f2*toRadian) * Math.sin(deltaL/2) * Math.sin(deltaL/2);
|
|
|
|
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
|
|
|
|
var distance = R * c;
|
|
|
|
this._result = {
|
|
|
|
Bearing: brng,
|
|
|
|
Distance: distance
|
|
|
|
};
|
|
|
|
},
|
|
|
|
_closePath: function() {
|
|
|
|
this._map.removeLayer(this._tempLine);
|
|
|
|
this._map.removeLayer(this._tempPoint);
|
|
|
|
this._choice = false;
|
|
|
|
L.DomEvent.on(this._container, 'click', this._toggleMeasure, this);
|
|
|
|
this._toggleMeasure();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
L.control.ruler = function(options) {
|
|
|
|
return new L.Control.Ruler(options);
|
|
|
|
};
|
|
|
|
}, window));
|