galadrielmap_sk
Version:
a server-based chartplotter navigation software for pleasure crafts, motorhomes, and off-road cars. It's can be used on tablets and smartphones without install any app. Only browser need.
421 lines (341 loc) • 13.9 kB
JavaScript
!(function() {
'use strict';
L.Marker.Measurement = L[L.Layer ? 'Layer' : 'Class'].extend({
options: {
pane: 'markerPane'
},
initialize: function(latlng, measurement, title, rotation, options) {
L.setOptions(this, options);
this._latlng = latlng;
this._measurement = measurement;
this._title = title;
this._rotation = rotation;
},
addTo: function(map) {
map.addLayer(this);
return this;
},
onAdd: function(map) {
this._map = map;
var pane = this.getPane ? this.getPane() : map.getPanes().markerPane;
var el = this._element = L.DomUtil.create('div', 'leaflet-zoom-animated leaflet-measure-path-measurement', pane);
var inner = L.DomUtil.create('div', '', el);
inner.title = this._title;
inner.innerHTML = this._measurement;
map.on('zoomanim', this._animateZoom, this);
this._setPosition();
},
onRemove: function(map) {
map.off('zoomanim', this._animateZoom, this);
var pane = this.getPane ? this.getPane() : map.getPanes().markerPane;
pane.removeChild(this._element);
this._map = null;
},
_setPosition: function() {
L.DomUtil.setPosition(this._element, this._map.latLngToLayerPoint(this._latlng));
this._element.style.transform += ' rotate(' + this._rotation + 'rad)';
},
_animateZoom: function(opt) {
var pos = this._map._latLngToNewLayerPoint(this._latlng, opt.zoom, opt.center).round();
L.DomUtil.setPosition(this._element, pos);
this._element.style.transform += ' rotate(' + this._rotation + 'rad)';
}
});
L.marker.measurement = function(latLng, measurement, title, rotation, options) {
return new L.Marker.Measurement(latLng, measurement, title, rotation, options);
};
var formatDistance = function(d) {
var unit,
feet;
if (this._measurementOptions.imperial) {
feet = d / 0.3048;
if (feet > 3000) {
d = d / 1609.344;
unit = 'mi';
} else {
d = feet;
unit = 'ft';
}
} else {
if (d > 1000) {
d = d / 1000;
unit = 'km';
} else {
unit = 'm';
}
}
if (d < 100) {
return d.toFixed(1) + ' ' + unit;
} else {
return Math.round(d) + ' ' + unit;
}
}
var formatArea = function(a) {
var unit,
sqfeet;
if (this._measurementOptions.imperial) {
if (a > 404.685642) {
a = a / 4046.85642;
unit = 'ac';
} else {
a = a / 0.09290304;
unit = 'ft²';
}
} else {
if (a > 1000000) {
a = a / 1000000;
unit = 'km²';
} else {
unit = 'm²';
}
}
if (a < 100) {
return a.toFixed(1) + ' ' + unit;
} else {
return Math.round(a) + ' ' + unit;
}
}
var RADIUS = 6378137;
// ringArea function copied from geojson-area
// (https://github.com/mapbox/geojson-area)
// This function is distributed under a separate license,
// see LICENSE.md.
var ringArea = function ringArea(coords) {
var rad = function rad(_) {
return _ * Math.PI / 180;
};
var p1, p2, p3, lowerIndex, middleIndex, upperIndex,
area = 0,
coordsLength = coords.length;
if (coordsLength > 2) {
for (var i = 0; i < coordsLength; i++) {
if (i === coordsLength - 2) {// i = N-2
lowerIndex = coordsLength - 2;
middleIndex = coordsLength -1;
upperIndex = 0;
} else if (i === coordsLength - 1) {// i = N-1
lowerIndex = coordsLength - 1;
middleIndex = 0;
upperIndex = 1;
} else { // i = 0 to N-3
lowerIndex = i;
middleIndex = i+1;
upperIndex = i+2;
}
p1 = coords[lowerIndex];
p2 = coords[middleIndex];
p3 = coords[upperIndex];
area += ( rad(p3.lng) - rad(p1.lng) ) * Math.sin( rad(p2.lat));
}
area = area * RADIUS * RADIUS / 2;
}
return Math.abs(area);
};
/**
* Handles the init hook for polylines and circles.
* Implements the showOnHover functionality if called for.
*/
var addInitHook = function() {
var showOnHover = this.options.measurementOptions && this.options.measurementOptions.showOnHover;
if (this.options.showMeasurements && !showOnHover) {
this.showMeasurements();
}
if (this.options.showMeasurements && showOnHover) {
this.on('mouseover', function() {
this.showMeasurements();
});
this.on('mouseout', function() {
this.hideMeasurements();
});
}
};
var circleArea = function circleArea(d) {
var rho = d / RADIUS;
return 2 * Math.PI * RADIUS * RADIUS * (1 - Math.cos(rho));
};
var override = function(method, fn, hookAfter) {
if (!hookAfter) {
return function() {
var originalReturnValue = method.apply(this, arguments);
var args = Array.prototype.slice.call(arguments)
args.push(originalReturnValue);
return fn.apply(this, args);
}
} else {
return function() {
fn.apply(this, arguments);
return method.apply(this, arguments);
}
}
};
L.Polyline.include({
showMeasurements: function(options) {
if (!this._map || this._measurementLayer) return this;
this._measurementOptions = L.extend({
showOnHover: (options && options.showOnHover) || false,
minPixelDistance: 30,
showDistances: true,
showArea: true,
showTotalDistance: true,
lang: {
totalLength: 'Total length',
totalArea: 'Total area',
segmentLength: 'Segment length'
}
}, options || {});
this._measurementLayer = L.layerGroup().addTo(this._map);
this.updateMeasurements();
this._map.on('zoomend', this.updateMeasurements, this);
return this;
},
hideMeasurements: function() {
if (!this._map) return this;
this._map.off('zoomend', this.updateMeasurements, this);
if (!this._measurementLayer) return this;
this._map.removeLayer(this._measurementLayer);
this._measurementLayer = null;
return this;
},
onAdd: override(L.Polyline.prototype.onAdd, function(originalReturnValue) {
var showOnHover = this.options.measurementOptions && this.options.measurementOptions.showOnHover;
if (this.options.showMeasurements && !showOnHover) {
this.showMeasurements(this.options.measurementOptions);
}
return originalReturnValue;
}),
onRemove: override(L.Polyline.prototype.onRemove, function(originalReturnValue) {
this.hideMeasurements();
return originalReturnValue;
}, true),
setLatLngs: override(L.Polyline.prototype.setLatLngs, function(originalReturnValue) {
this.updateMeasurements();
return originalReturnValue;
}),
spliceLatLngs: override(L.Polyline.prototype.spliceLatLngs, function(originalReturnValue) {
this.updateMeasurements();
return originalReturnValue;
}),
formatDistance: formatDistance,
formatArea: formatArea,
updateMeasurements: function() {
if (!this._measurementLayer) return this;
var latLngs = this.getLatLngs(),
isPolygon = this instanceof L.Polygon,
options = this._measurementOptions,
totalDist = 0,
formatter,
ll1,
ll2,
p1,
p2,
pixelDist,
dist;
if (latLngs && latLngs.length && L.Util.isArray(latLngs[0])) {
// Outer ring is stored as an array in the first element,
// use that instead.
latLngs = latLngs[0];
}
this._measurementLayer.clearLayers();
if (this._measurementOptions.showDistances && latLngs.length > 1) {
formatter = this._measurementOptions.formatDistance || L.bind(this.formatDistance, this);
for (var i = 1, len = latLngs.length; (isPolygon && i <= len) || i < len; i++) {
ll1 = latLngs[i - 1];
ll2 = latLngs[i % len];
dist = ll1.distanceTo(ll2);
totalDist += dist;
p1 = this._map.latLngToLayerPoint(ll1);
p2 = this._map.latLngToLayerPoint(ll2);
pixelDist = p1.distanceTo(p2);
if (pixelDist >= options.minPixelDistance) {
L.marker.measurement(
this._map.layerPointToLatLng([(p1.x + p2.x) / 2, (p1.y + p2.y) / 2]),
formatter(dist), options.lang.segmentLength, this._getRotation(ll1, ll2), options)
.addTo(this._measurementLayer);
}
}
// Show total length for polylines
if (!isPolygon && this._measurementOptions.showTotalDistance) {
L.marker.measurement(ll2, formatter(totalDist), options.lang.totalLength, 0, options)
.addTo(this._measurementLayer);
}
}
if (isPolygon && options.showArea && latLngs.length > 2) {
formatter = options.formatArea || L.bind(this.formatArea, this);
var area = ringArea(latLngs);
L.marker.measurement(this.getBounds().getCenter(),
formatter(area), options.lang.totalArea, 0, options)
.addTo(this._measurementLayer);
}
return this;
},
_getRotation: function(ll1, ll2) {
var p1 = this._map.project(ll1),
p2 = this._map.project(ll2);
return Math.atan((p2.y - p1.y) / (p2.x - p1.x));
}
});
L.Polyline.addInitHook(function() {
addInitHook.call(this);
});
L.Circle.include({
showMeasurements: function(options) {
if (!this._map || this._measurementLayer) return this;
this._measurementOptions = L.extend({
showOnHover: false,
showArea: true,
lang: {
totalArea: 'Total area',
}
}, options || {});
this._measurementLayer = L.layerGroup().addTo(this._map);
this.updateMeasurements();
this._map.on('zoomend', this.updateMeasurements, this);
return this;
},
hideMeasurements: function() {
if (!this._map) return this;
this._map.on('zoomend', this.updateMeasurements, this);
if (!this._measurementLayer) return this;
this._map.removeLayer(this._measurementLayer);
this._measurementLayer = null;
return this;
},
onAdd: override(L.Circle.prototype.onAdd, function(originalReturnValue) {
var showOnHover = this.options.measurementOptions && this.options.measurementOptions.showOnHover;
if (this.options.showMeasurements && !showOnHover) {
this.showMeasurements(this.options.measurementOptions);
}
return originalReturnValue;
}),
onRemove: override(L.Circle.prototype.onRemove, function(originalReturnValue) {
this.hideMeasurements();
return originalReturnValue;
}, true),
setLatLng: override(L.Circle.prototype.setLatLng, function(originalReturnValue) {
this.updateMeasurements();
return originalReturnValue;
}),
setRadius: override(L.Circle.prototype.setRadius, function(originalReturnValue) {
this.updateMeasurements();
return originalReturnValue;
}),
formatArea: formatArea,
updateMeasurements: function() {
if (!this._measurementLayer) return;
var latLng = this.getLatLng(),
options = this._measurementOptions,
formatter = options.formatArea || L.bind(this.formatArea, this);
this._measurementLayer.clearLayers();
if (options.showArea) {
formatter = options.formatArea || L.bind(this.formatArea, this);
var area = circleArea(this.getRadius());
L.marker.measurement(latLng,
formatter(area), options.lang.totalArea, 0, options)
.addTo(this._measurementLayer);
}
}
})
L.Circle.addInitHook(function() {
addInitHook.call(this);
});
})();