Commit f4fadffb authored by JOE XMG's avatar JOE XMG
Browse files

update

parent abe537c0
Pipeline #6174 passed with stage
in 6 seconds
<!DOCTYPE html>
<html>
<head>
<title>Joe BBOX Finder</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.8.1/font/bootstrap-icons.css">
<link rel="stylesheet" href="libs/leaflet.css" />
<link rel="stylesheet" href="./src/leaflet.draw.css" />
<script src="libs/leaflet-src.js"></script>
<script src="./src/Leaflet.draw.js"></script>
<script src="./src/Leaflet.Draw.Event.js"></script>
<script src="./src/edit/handler/Edit.Poly.js"></script>
<script src="./src/edit/handler/Edit.SimpleShape.js"></script>
<script src="./src/edit/handler/Edit.Rectangle.js"></script>
<script src="./src/edit/handler/Edit.Marker.js"></script>
<script src="./src/edit/handler/Edit.CircleMarker.js"></script>
<script src="./src/edit/handler/Edit.Circle.js"></script>
<script src="./src/draw/handler/Draw.Feature.js"></script>
<script src="./src/draw/handler/Draw.Polyline.js"></script>
<script src="./src/draw/handler/Draw.Polygon.js"></script>
<script src="./src/draw/handler/Draw.SimpleShape.js"></script>
<script src="./src/draw/handler/Draw.Rectangle.js"></script>
<script src="./src/draw/handler/Draw.Circle.js"></script>
<script src="./src/draw/handler/Draw.Marker.js"></script>
<script src="./src/draw/handler/Draw.CircleMarker.js"></script>
<script src="./src/ext/TouchEvents.js"></script>
<script src="./src/ext/LatLngUtil.js"></script>
<script src="./src/ext/GeometryUtil.js"></script>
<script src="./src/ext/LineUtil.Intersect.js"></script>
<script src="./src/ext/Polyline.Intersect.js"></script>
<script src="./src/ext/Polygon.Intersect.js"></script>
<script src="./src/Control.Draw.js"></script>
<script src="./src/Tooltip.js"></script>
<script src="./src/Toolbar.js"></script>
<script src="./src/draw/DrawToolbar.js"></script>
<script src="./src/edit/EditToolbar.js"></script>
<script src="./src/edit/handler/EditToolbar.Edit.js"></script>
<script src="./src/edit/handler/EditToolbar.Delete.js"></script>
</head>
<body>
<style>
.calculation-box {
height: 90px;
width: 600px;
position: absolute;
bottom: 25px;
left: 25px;
background-color: rgba(255, 255, 255, 0.9);
padding: 15px;
text-align: center;
z-index: 1000;
}
p {
/* font-family: 'Open Sans'; */
margin: 0;
font-size: 13px;
font-weight: 600;
}
</style>
<div id="map" style="width: 100%; height: 100vh;"></div>
<div class="calculation-box text-left">
<p class="text-bold text-wrap"> <b>BBOX Finder <i class="bi bi-bounding-box"></i></b>
<br>
<span id="calculated_area">[Hint: Draw a bbox using tool on the right-bottom menu.]</span>
</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"
integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous">
</script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="./libs/proj4js.min.js"></script>
<script>
var Stadia_Outdoors = L.tileLayer('https://tiles.stadiamaps.com/tiles/outdoors/{z}/{x}/{y}{r}.png', {
maxZoom: 20,
attribution: '&copy; <a href="https://stadiamaps.com/">Stadia Maps</a>, &copy; <a href="https://openmaptiles.org/">OpenMapTiles</a> &copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors'
});
var tmp_layer
var osmUrl = 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
osmAttrib = '&copy; <a href="http://openstreetmap.org/copyright">OpenStreetMap</a> contributors',
osm = L.tileLayer(osmUrl, {
maxZoom: 18,
attribution: osmAttrib
}),
map = new L.Map('map', {
layers: [Stadia_Outdoors],
center: new L.LatLng(48.7758, 9.1829),
zoom: 15
});
var drawnItems = new L.FeatureGroup();
map.addLayer(drawnItems);
// Set the title to show on the polygon button
L.drawLocal.draw.toolbar.buttons.polygon = 'Draw a polygon!';
var drawControl = new L.Control.Draw({
position: 'bottomright',
draw: {
polyline: false,
polygon: false,
circle: false,
marker: false,
circlemarker: false
},
edit: {
featureGroup: drawnItems,
remove: true
}
});
map.addControl(drawControl);
map.on(L.Draw.Event.CREATED, function (e) {
if (tmp_layer !== undefined) {
try {
map.removeLayer(tmp_layer)
} catch (error) {}
}
var type = e.layerType,
layer = e.layer;
tmp_layer = layer
if (type === 'marker') {
layer.bindPopup('A popup!');
}
drawnItems.addLayer(layer);
const answer = document.getElementById('calculated_area');
// $("#")
var source = new proj4.Proj('EPSG:4326'); //source coordinates will be in Longitude/Latitude
proj4.defs("EPSG:31463",
"+proj=tmerc +lat_0=0 +lon_0=9 +k=1 +x_0=3500000 +y_0=0 +ellps=bessel +towgs84=598.1,73.7,418.2,0.202,0.045,-2.455,6.7 +units=m +no_defs"
);
var dest = new proj4.Proj('EPSG:31463'); //source coordinates will be in Longitude/Latitude
var p_min = new proj4.toPoint([tmp_layer._bounds._southWest.lng, tmp_layer._bounds._southWest
.lat
]); //any object will do as long as it has 'x' and 'y' properties
var p_max = new proj4.toPoint([tmp_layer._bounds._southWest.lng, tmp_layer._bounds._southWest
.lat
]); //any object will do as long as it has 'x' and 'y' properties
p_dest_min = proj4.transform(source, dest,
p_min); //do the transformation. x and y are modified in place
p_dest_max = proj4.transform(source, dest,
p_max); //do the transformation. x and y are modified in place
answer.innerHTML = `
BBOX (4326):
<input type="text" value="${tmp_layer._bounds._southWest.lng.toFixed(6)},${tmp_layer._bounds._southWest.lat.toFixed(6)},${tmp_layer._bounds._northEast.lng.toFixed(6)},${tmp_layer._bounds._northEast.lat.toFixed(6)}" id="4326" size="60">
<button class="badge bg-secondary" onclick="clickToCopy('4326')">click to copy</button>
<br>
BBOX (31463):
<input type="text" value="${p_dest_min.x.toFixed(4)},${p_dest_min.y.toFixed(4)},${p_dest_max.x.toFixed(4)},${p_dest_max.y.toFixed(4)}" id="31463" size="60">
<button class="badge bg-secondary" onclick="clickToCopy('31463')">click to copy</button>
`;
});
map.on(L.Draw.Event.EDITED, function (e) {
var layers = e.layers;
var countOfEditedLayers = 0;
layers.eachLayer(function (layer) {
countOfEditedLayers++;
});
console.log("Edited " + countOfEditedLayers + " layers");
});
function clickToCopy(id) {
/* Get the text field */
var copyText = document.getElementById(id);
/* Select the text field */
copyText.select();
copyText.setSelectionRange(0, 99999); /* For mobile devices */
/* Copy the text inside the text field */
navigator.clipboard.writeText(copyText.value);
/* Alert the copied text */
alert("BBox Copied:<br>" + copyText.value);
}
</script>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Draw a polygon and calculate its area</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
<link href="https://api.mapbox.com/mapbox-gl-js/v2.7.0/mapbox-gl.css" rel="stylesheet">
<script src="https://api.mapbox.com/mapbox-gl-js/v2.7.0/mapbox-gl.js"></script>
<style>
body {
margin: 0;
padding: 0;
}
#map {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
}
</style>
</head>
<body>
<style>
.calculation-box {
height: 150px;
width: 350px;
position: absolute;
bottom: 40px;
left: 10px;
background-color: rgba(255, 255, 255, 0.9);
padding: 15px;
text-align: center;
}
p {
font-family: 'Open Sans';
margin: 0;
font-size: 13px;
}
</style>
<script src="https://unpkg.com/@turf/turf@6/turf.min.js"></script>
<script src="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-draw/v1.2.2/mapbox-gl-draw.js"></script>
<link rel="stylesheet" href="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-draw/v1.2.2/mapbox-gl-draw.css"
type="text/css">
<div id="map"></div>
<div class="calculation-box">
<p>Click the map to draw a polygon.</p>
<div id="calculated-area"></div>
</div>
<script>
var tmp;
mapboxgl.accessToken =
'pk.eyJ1IjoidGh1bnlhdGhlcCIsImEiOiJjamFpOWV4a2gxd21vMndxdXd2M3VoY3hmIn0.jLlCscei0yH-ZHwcfxF_ug';
const map = new mapboxgl.Map({
container: 'map', // container ID
style: 'mapbox://styles/mapbox/streets-v11', // style URL
center: [9.1829, 48.7758], // starting position [lng, lat] ° N, ° E
zoom: 12 // starting zoom
});
const draw = new MapboxDraw({
displayControlsDefault: false,
// Select which mapbox-gl-draw control buttons to add to the map.
controls: {
polygon: true,
trash: true
},
// Set mapbox-gl-draw to draw by default.
// The user does not have to click the polygon control button first.
defaultMode: 'draw_polygon'
});
map.addControl(draw);
map.on('draw.create', updateArea);
map.on('draw.delete', updateArea);
map.on('draw.update', updateArea);
function updateArea(e) {
const data = draw.getAll();
tmp = data
coord = tmp.features[0].geometry.coordinates[0]
var maxlat = 0
var maxlng = 0
var minlat = 999
var minlng = 999
for (let index = 0; index < coord.length; index++) {
const element = coord[index];
lat = element[1]
lng = element[0]
if (lat> maxlat) {maxlat = lat}
if (lat< minlat) {minlat = lat}
if (lng> maxlng) {maxlng = lng}
if (lng< minlng) {minlng = lng}
}
const answer = document.getElementById('calculated-area');
if (data.features.length > 0) {
const area = turf.area(data);
// Restrict the area to 2 decimal points.
const rounded_area = Math.round(area * 100) / 100;
answer.innerHTML = `
<p><strong>${rounded_area}</strong></p><p>square meters</p>
min: ${minlat},${minlng}
max: ${maxlat},${maxlng}
`;
} else {
answer.innerHTML = '';
if (e.type !== 'draw.delete')
alert('Click the map to draw a polygon.');
}
}
</script>
</body>
</html>
\ No newline at end of file
/**
* Matrix transform path for SVG/VML
* TODO: adapt to Leaflet 0.8 upon release
*/
"use strict";
if (L.Browser.svg) { // SVG transformation
L.Path.include({
/**
* Reset transform matrix
*/
_resetTransform: function() {
this._container.setAttributeNS(null, 'transform', '');
},
/**
* Applies matrix transformation to SVG
* @param {Array.<Number>} matrix
*/
_applyTransform: function(matrix) {
this._container.setAttributeNS(null, "transform",
'matrix(' + matrix.join(' ') + ')');
}
});
} else { // VML transform routines
L.Path.include({
/**
* Reset transform matrix
*/
_resetTransform: function() {
if (this._skew) {
// super important! workaround for a 'jumping' glitch:
// disable transform before removing it
this._skew.on = false;
this._container.removeChild(this._skew);
this._skew = null;
}
},
/**
* Applies matrix transformation to VML
* @param {Array.<Number>} matrix
*/
_applyTransform: function(matrix) {
var skew = this._skew;
if (!skew) {
skew = this._createElement('skew');
this._container.appendChild(skew);
skew.style.behavior = 'url(#default#VML)';
this._skew = skew;
}
// handle skew/translate separately, cause it's broken
var mt = matrix[0].toFixed(8) + " " + matrix[1].toFixed(8) + " " +
matrix[2].toFixed(8) + " " + matrix[3].toFixed(8) + " 0 0";
var offset = Math.floor(matrix[4]).toFixed() + ", " +
Math.floor(matrix[5]).toFixed() + "";
var s = this._container.style;
var l = parseFloat(s.left);
var t = parseFloat(s.top);
var w = parseFloat(s.width);
var h = parseFloat(s.height);
if (isNaN(l)) l = 0;
if (isNaN(t)) t = 0;
if (isNaN(w) || !w) w = 1;
if (isNaN(h) || !h) h = 1;
var origin = (-l / w - 0.5).toFixed(8) + " " + (-t / h - 0.5).toFixed(8);
skew.on = "f";
skew.matrix = mt;
skew.origin = origin;
skew.offset = offset;
skew.on = true;
}
});
}
// Renderer-independent
L.Path.include({
/**
* Check if the feature was dragged, that'll supress the click event
* on mouseup. That fixes popups for example
*
* @param {MouseEvent} e
*/
_onMouseClick: function(e) {
if ((this.dragging && this.dragging.moved()) ||
(this._map.dragging && this._map.dragging.moved())) {
return;
}
this._fireMouseEvent(e);
}
});
/**
* Leaflet vector features drag functionality
* @preserve
*/
"use strict";
/**
* Drag handler
* @class L.Path.Drag
* @extends {L.Handler}
*/
L.Handler.PathDrag = L.Handler.extend( /** @lends L.Path.Drag.prototype */ {
/**
* @param {L.Path} path
* @constructor
*/
initialize: function(path) {
/**
* @type {L.Path}
*/
this._path = path;
/**
* @type {Array.<Number>}
*/
this._matrix = null;
/**
* @type {L.Point}
*/
this._startPoint = null;
/**
* @type {L.Point}
*/
this._dragStartPoint = null;
},
/**
* Enable dragging
*/
addHooks: function() {
this._path.on('mousedown', this._onDragStart, this);
L.DomUtil.addClass(this._path._container, 'leaflet-path-draggable');
},
/**
* Disable dragging
*/
removeHooks: function() {
this._path.off('mousedown', this._onDragStart, this);
L.DomUtil.removeClass(this._path._container, 'leaflet-path-draggable');
},
/**
* @return {Boolean}
*/
moved: function() {
return this._path._dragMoved;
},
/**
* Start drag
* @param {L.MouseEvent} evt
*/
_onDragStart: function(evt) {
this._startPoint = evt.containerPoint.clone();
this._dragStartPoint = evt.containerPoint.clone();
this._matrix = [1, 0, 0, 1, 0, 0];
this._path._map
.on('mousemove', this._onDrag, this)
.on('mouseup', this._onDragEnd, this)
this._path._dragMoved = false;
},
/**
* Dragging
* @param {L.MouseEvent} evt
*/
_onDrag: function(evt) {
var x = evt.containerPoint.x;
var y = evt.containerPoint.y;
var dx = x - this._startPoint.x;
var dy = y - this._startPoint.y;
if (!this._path._dragMoved && (dx || dy)) {
this._path._dragMoved = true;
this._path.fire('dragstart');
}
this._matrix[4] += dx;
this._matrix[5] += dy;
this._startPoint.x = x;
this._startPoint.y = y;
this._path._applyTransform(this._matrix);
this._path.fire('drag');
L.DomEvent.stop(evt.originalEvent);
},
/**
* Dragging stopped, apply
* @param {L.MouseEvent} evt
*/
_onDragEnd: function(evt) {
L.DomEvent.stop(evt);
// undo container transform
this._path._resetTransform();
// apply matrix
this._transformPoints(this._matrix);
this._path._map
.off('mousemove', this._onDrag, this)
.off('mouseup', this._onDragEnd, this);
// consistency
this._path.fire('dragend', {
distance: Math.sqrt(
L.LineUtil._sqDist(this._dragStartPoint, evt.containerPoint)
)
});
this._matrix = null;
this._startPoint = null;
this._dragStartPoint = null;
},
/**
* Applies transformation, does it in one sweep for performance,
* so don't be surprised about the code repetition.
*
* [ x ] [ a b tx ] [ x ] [ a * x + b * y + tx ]
* [ y ] = [ c d ty ] [ y ] = [ c * x + d * y + ty ]
*
* @param {Array.<Number>} matrix
*/
_transformPoints: function(matrix) {
var path = this._path;
var i, len, latlng;
var px = L.point(matrix[4], matrix[5]);
var crs = path._map.options.crs;
var transformation = crs.transformation;
var scale = crs.scale(path._map.getZoom());
var projection = crs.projection;
var diff = transformation.untransform(px, scale)
.subtract(transformation.untransform(L.point(0, 0), scale));
// console.time('transform');
// all shifts are in-place
if (path._point) { // L.Circle
path._latlng = projection.unproject(
projection.project(path._latlng)._add(diff));
path._point._add(px);
} else if (path._originalPoints) { // everything else
for (i = 0, len = path._originalPoints.length; i < len; i++) {
latlng = path._latlngs[i];
path._latlngs[i] = projection
.unproject(projection.project(latlng)._add(diff));
path._originalPoints[i]._add(px);
}
}
// holes operations
if (path._holes) {
for (i = 0, len = path._holes.length; i < len; i++) {
for (var j = 0, len2 = path._holes[i].length; j < len2; j++) {
latlng = path._holes[i][j];
path._holes[i][j] = projection
.unproject(projection.project(latlng)._add(diff));
path._holePoints[i][j]._add(px);
}
}
}
// console.timeEnd('transform');
path._updatePath();
}
});
L.Path.prototype.__initEvents = L.Path.prototype._initEvents;
L.Path.prototype._initEvents = function() {
this.__initEvents();
if (this.options.draggable) {
if (this.dragging) {
this.dragging.enable();
} else {
this.dragging = new L.Handler.PathDrag(this);
this.dragging.enable();
}
} else if (this.dragging) {
this.dragging.disable();
}
};
(function() {
// listen and propagate dragstart on sub-layers
L.FeatureGroup.EVENTS += ' dragstart';
function wrapMethod(klasses, methodName, method) {
for (var i = 0, len = klasses.length; i < len; i++) {
var klass = klasses[i];
klass.prototype['_' + methodName] = klass.prototype[methodName];
klass.prototype[methodName] = method;
}
}
/**
* @param {L.Polygon|L.Polyline} layer
* @return {L.MultiPolygon|L.MultiPolyline}
*/
function addLayer(layer) {
if (this.hasLayer(layer)) {
return this;
}
layer
.on('drag', this._onDrag, this)
.on('dragend', this._onDragEnd, this);
return this._addLayer.call(this, layer);
}
/**
* @param {L.Polygon|L.Polyline} layer
* @return {L.MultiPolygon|L.MultiPolyline}
*/
function removeLayer(layer) {
if (!this.hasLayer(layer)) {
return this;
}
layer
.off('drag', this._onDrag, this)
.off('dragend', this._onDragEnd, this);
return this._removeLayer.call(this, layer);
}
// duck-type methods to listen to the drag events
wrapMethod([L.MultiPolygon, L.MultiPolyline], 'addLayer', addLayer);
wrapMethod([L.MultiPolygon, L.MultiPolyline], 'removeLayer', removeLayer);
var dragMethods = {
_onDrag: function(evt) {
var layer = evt.target;
this.eachLayer(function(otherLayer) {
if (otherLayer !== layer) {
otherLayer._applyTransform(layer.dragging._matrix);
}
});
this._propagateEvent(evt);
},
_onDragEnd: function(evt) {
var layer = evt.target;
this.eachLayer(function(otherLayer) {
if (otherLayer !== layer) {
otherLayer._resetTransform();
otherLayer.dragging._transformPoints(layer.dragging._matrix);
}
});
this._propagateEvent(evt);
}
};
L.MultiPolygon.include(dragMethods);
L.MultiPolyline.include(dragMethods);
})();
// TODO: dismiss that on Leaflet 0.8.x release
L.Polygon.include( /** @lends L.Polygon.prototype */ {
/**
* @return {L.LatLng}
*/
getCenter: function() {
var i, j, len, p1, p2, f, area, x, y,
points = this._parts[0];
// polygon centroid algorithm; only uses the first ring if there are multiple
area = x = y = 0;
for (i = 0, len = points.length, j = len - 1; i < len; j = i++) {
p1 = points[i];
p2 = points[j];
f = p1.y * p2.x - p2.y * p1.x;
x += (p1.x + p2.x) * f;
y += (p1.y + p2.y) * f;
area += f * 3;
}
return this._map.layerPointToLatLng([x / area, y / area]);
}
});
"use strict";
/**
* Static flag for move markers
* @type {Boolean}
*/
L.EditToolbar.Edit.MOVE_MARKERS = false;
L.EditToolbar.Edit.include( /** @lends L.EditToolbar.Edit.prototype */ {
/**
* @override
*/
initialize: function(map, options) {
L.EditToolbar.Edit.MOVE_MARKERS = !!options.selectedPathOptions.moveMarkers;
this._initialize(map, options);
},
/**
* @param {L.Map} map
* @param {Object} options
*/
_initialize: L.EditToolbar.Edit.prototype.initialize
});
/**
* Mainly central marker routines
*/
L.Edit.SimpleShape.include( /** @lends L.Edit.SimpleShape.prototype */ {
/**
* Put move marker into center
*/
_updateMoveMarker: function() {
if (this._moveMarker) {
this._moveMarker.setLatLng(this._getShapeCenter());
}
},
/**
* Shape centroid
* @return {L.LatLng}
*/
_getShapeCenter: function() {
return this._shape.getBounds().getCenter();
},
/**
* @override
*/
_createMoveMarker: function() {
if (L.EditToolbar.Edit.MOVE_MARKERS) {
this._moveMarker = this._createMarker(this._getShapeCenter(),
this.options.moveIcon);
}
}
});
/**
* Override this if you don't want the central marker
* @type {Boolean}
*/
L.Edit.SimpleShape.mergeOptions({
moveMarker: false
});
/**
* Dragging routines for circle
*/
L.Edit.Circle.include( /** @lends L.Edit.Circle.prototype */ {
/**
* @override
*/
addHooks: function() {
if (this._shape._map) {
this._map = this._shape._map;
if (!this._markerGroup) {
this._enableDragging();
this._initMarkers();
}
this._shape._map.addLayer(this._markerGroup);
}
},
/**
* @override
*/
removeHooks: function() {
if (this._shape._map) {
for (var i = 0, l = this._resizeMarkers.length; i < l; i++) {
this._unbindMarker(this._resizeMarkers[i]);
}
this._disableDragging();
this._resizeMarkers = null;
this._map.removeLayer(this._markerGroup);
delete this._markerGroup;
}
this._map = null;
},
/**
* @override
*/
_createMoveMarker: L.Edit.SimpleShape.prototype._createMoveMarker,
/**
* Change
* @param {L.LatLng} latlng
*/
_resize: function(latlng) {
var center = this._shape.getLatLng();
var radius = center.distanceTo(latlng);
this._shape.setRadius(radius);
this._updateMoveMarker();
},
/**
* Adds drag start listeners
*/
_enableDragging: function() {
if (!this._shape.dragging) {
this._shape.dragging = new L.Handler.PathDrag(this._shape);
}
this._shape.dragging.enable();
this._shape
.on('dragstart', this._onStartDragFeature, this)
.on('dragend', this._onStopDragFeature, this);
},
/**
* Removes drag start listeners
*/
_disableDragging: function() {
this._shape.dragging.disable();
this._shape
.off('dragstart', this._onStartDragFeature, this)
.off('dragend', this._onStopDragFeature, this);
},
/**
* Start drag
* @param {L.MouseEvent} evt
*/
_onStartDragFeature: function() {
this._shape._map.removeLayer(this._markerGroup);
this._shape.fire('editstart');
},
/**
* Dragging stopped, apply
* @param {L.MouseEvent} evt
*/
_onStopDragFeature: function() {
var center = this._shape.getLatLng();
//this._moveMarker.setLatLng(center);
this._resizeMarkers[0].setLatLng(this._getResizeMarkerPoint(center));
// show resize marker
this._shape._map.addLayer(this._markerGroup);
this._updateMoveMarker();
this._fireEdit();
}
});
/**
* Dragging routines for poly handler
*/
L.Edit.Rectangle.include( /** @lends L.Edit.Rectangle.prototype */ {
/**
* @override
*/
addHooks: function() {
if (this._shape._map) {
if (!this._markerGroup) {
this._enableDragging();
this._initMarkers();
}
this._shape._map.addLayer(this._markerGroup);
}
},
/**
* @override
*/
removeHooks: function() {
if (this._shape._map) {
this._shape._map.removeLayer(this._markerGroup);
this._disableDragging();
delete this._markerGroup;
delete this._markers;
}
},
/**
* @override
*/
_resize: function(latlng) {
// Update the shape based on the current position of
// this corner and the opposite point
this._shape.setBounds(L.latLngBounds(latlng, this._oppositeCorner));
this._updateMoveMarker();
},
/**
* @override
*/
_onMarkerDragEnd: function(e) {
this._toggleCornerMarkers(1);
this._repositionCornerMarkers();
L.Edit.SimpleShape.prototype._onMarkerDragEnd.call(this, e);
},
/**
* Adds drag start listeners
*/
_enableDragging: function() {
if (!this._shape.dragging) {
this._shape.dragging = new L.Handler.PathDrag(this._shape);
}
this._shape.dragging.enable();
this._shape
.on('dragstart', this._onStartDragFeature, this)
.on('dragend', this._onStopDragFeature, this);
},
/**
* Removes drag start listeners
*/
_disableDragging: function() {
this._shape.dragging.disable();
this._shape
.off('dragstart', this._onStartDragFeature, this)
.off('dragend', this._onStopDragFeature, this);
},
/**
* Start drag
* @param {L.MouseEvent} evt
*/
_onStartDragFeature: function() {
this._shape._map.removeLayer(this._markerGroup);
this._shape.fire('editstart');
},
/**
* Dragging stopped, apply
* @param {L.MouseEvent} evt
*/
_onStopDragFeature: function() {
var polygon = this._shape;
for (var i = 0, len = polygon._latlngs.length; i < len; i++) {
// update marker
var marker = this._resizeMarkers[i];
marker.setLatLng(polygon._latlngs[i]);
// this one's needed to update the path
marker._origLatLng = polygon._latlngs[i];
if (marker._middleLeft) {
marker._middleLeft.setLatLng(this._getMiddleLatLng(marker._prev, marker));
}
if (marker._middleRight) {
marker._middleRight.setLatLng(this._getMiddleLatLng(marker, marker._next));
}
}
// this._moveMarker.setLatLng(polygon.getBounds().getCenter());
// show vertices
this._shape._map.addLayer(this._markerGroup);
this._updateMoveMarker();
this._repositionCornerMarkers();
this._fireEdit();
}
});
/**
* Dragging routines for poly handler
*/
L.Edit.PolyVerticesEdit.include( /** @lends L.Edit.PolyVerticesEdit.prototype */ {
// store methods to call them in overrides
__createMarker: L.Edit.PolyVerticesEdit.prototype._createMarker,
__removeMarker: L.Edit.PolyVerticesEdit.prototype._removeMarker,
/**
* @override
*/
addHooks: function() {
if (this._poly._map) {
if (!this._markerGroup) {
this._enableDragging();
this._initMarkers();
// Create center marker
this._createMoveMarker();
}
this._poly._map.addLayer(this._markerGroup);
}
},
/**
* @override
*/
_createMoveMarker: function() {
if (L.EditToolbar.Edit.MOVE_MARKERS && (this._poly instanceof L.Polygon)) {
this._moveMarker = new L.Marker(this._getShapeCenter(), {
icon: this.options.moveIcon
});
this._moveMarker.on('mousedown', this._delegateToShape, this);
this._markerGroup.addLayer(this._moveMarker);
}
},
/**
* Start dragging through the marker
* @param {L.MouseEvent} evt
*/
_delegateToShape: function(evt) {
var poly = this._shape || this._poly;
var marker = evt.target;
poly.fire('mousedown', L.Util.extend(evt, {
containerPoint: L.DomUtil.getPosition(marker._icon)
.add(poly._map._getMapPanePos())
}));
},
/**
* Polygon centroid
* @return {L.LatLng}
*/
_getShapeCenter: function() {
return this._poly.getCenter();
},
/**
* @override
*/
removeHooks: function() {
if (this._poly._map) {
this._poly._map.removeLayer(this._markerGroup);
this._disableDragging();
delete this._markerGroup;
delete this._markers;
}
},
/**
* Adds drag start listeners
*/
_enableDragging: function() {
if (!this._poly.dragging) {
this._poly.dragging = new L.Handler.PathDrag(this._poly);
}
this._poly.dragging.enable();
this._poly
.on('dragstart', this._onStartDragFeature, this)
.on('dragend', this._onStopDragFeature, this);
},
/**
* Removes drag start listeners
*/
_disableDragging: function() {
this._poly.dragging.disable();
this._poly
.off('dragstart', this._onStartDragFeature, this)
.off('dragend', this._onStopDragFeature, this);
},
/**
* Start drag
* @param {L.MouseEvent} evt
*/
_onStartDragFeature: function(evt) {
this._poly._map.removeLayer(this._markerGroup);
this._poly.fire('editstart');
},
/**
* Dragging stopped, apply
* @param {L.MouseEvent} evt
*/
_onStopDragFeature: function(evt) {
// var polygon = this._poly;
for (var i = 0, len = this._latlngs.length; i < len; i++) {
// update marker
var marker = this._markers[i];
marker.setLatLng(this._latlngs[i]);
// this one's needed to update the path
marker._origLatLng = this._latlngs[i];
if (marker._middleLeft) {
marker._middleLeft.setLatLng(this._getMiddleLatLng(marker._prev, marker));
}
if (marker._middleRight) {
marker._middleRight.setLatLng(this._getMiddleLatLng(marker, marker._next));
}
}
// show vertices
this._poly._map.addLayer(this._markerGroup);
L.Edit.SimpleShape.prototype._updateMoveMarker.call(this);
this._fireEdit();
},
/**
* Copy from simple shape
*/
_updateMoveMarker: L.Edit.SimpleShape.prototype._updateMoveMarker,
/**
* @override
*/
_createMarker: function(latlng, index) {
var marker = this.__createMarker(latlng, index);
marker
.on('dragstart', this._hideMoveMarker, this)
.on('dragend', this._showUpdateMoveMarker, this);
return marker;
},
/**
* @override
*/
_removeMarker: function(marker) {
this.__removeMarker(marker);
marker
.off('dragstart', this._hideMoveMarker, this)
.off('dragend', this._showUpdateMoveMarker, this);
},
/**
* Hide move marker while dragging a vertex
*/
_hideMoveMarker: function() {
if (this._moveMarker) {
this._markerGroup.removeLayer(this._moveMarker);
}
},
/**
* Show and update move marker
*/
_showUpdateMoveMarker: function() {
if (this._moveMarker) {
this._markerGroup.addLayer(this._moveMarker);
this._updateMoveMarker();
}
}
});
/**
* @type {L.DivIcon}
*/
L.Edit.PolyVerticesEdit.prototype.options.moveIcon = new L.DivIcon({
iconSize: new L.Point(8, 8),
className: 'leaflet-div-icon leaflet-editing-icon leaflet-edit-move'
});
/**
* Override this if you don't want the central marker
* @type {Boolean}
*/
L.Edit.PolyVerticesEdit.mergeOptions({
moveMarker: false
});
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
/* required styles */
.leaflet-pane,
.leaflet-tile,
.leaflet-marker-icon,
.leaflet-marker-shadow,
.leaflet-tile-container,
.leaflet-pane > svg,
.leaflet-pane > canvas,
.leaflet-zoom-box,
.leaflet-image-layer,
.leaflet-layer {
position: absolute;
left: 0;
top: 0;
}
.leaflet-container {
overflow: hidden;
}
.leaflet-tile,
.leaflet-marker-icon,
.leaflet-marker-shadow {
-webkit-user-select: none;
-moz-user-select: none;
user-select: none;
-webkit-user-drag: none;
}
/* Safari renders non-retina tile on retina better with this, but Chrome is worse */
.leaflet-safari .leaflet-tile {
image-rendering: -webkit-optimize-contrast;
}
/* hack that prevents hw layers "stretching" when loading new tiles */
.leaflet-safari .leaflet-tile-container {
width: 1600px;
height: 1600px;
-webkit-transform-origin: 0 0;
}
.leaflet-marker-icon,
.leaflet-marker-shadow {
display: block;
}
/* .leaflet-container svg: reset svg max-width decleration shipped in Joomla! (joomla.org) 3.x */
/* .leaflet-container img: map is broken in FF if you have max-width: 100% on tiles */
.leaflet-container .leaflet-overlay-pane svg,
.leaflet-container .leaflet-marker-pane img,
.leaflet-container .leaflet-shadow-pane img,
.leaflet-container .leaflet-tile-pane img,
.leaflet-container img.leaflet-image-layer {
max-width: none !important;
max-height: none !important;
}
.leaflet-container.leaflet-touch-zoom {
-ms-touch-action: pan-x pan-y;
touch-action: pan-x pan-y;
}
.leaflet-container.leaflet-touch-drag {
-ms-touch-action: pinch-zoom;
/* Fallback for FF which doesn't support pinch-zoom */
touch-action: none;
touch-action: pinch-zoom;
}
.leaflet-container.leaflet-touch-drag.leaflet-touch-zoom {
-ms-touch-action: none;
touch-action: none;
}
.leaflet-container {
-webkit-tap-highlight-color: transparent;
}
.leaflet-container a {
-webkit-tap-highlight-color: rgba(51, 181, 229, 0.4);
}
.leaflet-tile {
filter: inherit;
visibility: hidden;
}
.leaflet-tile-loaded {
visibility: inherit;
}
.leaflet-zoom-box {
width: 0;
height: 0;
-moz-box-sizing: border-box;
box-sizing: border-box;
z-index: 800;
}
/* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */
.leaflet-overlay-pane svg {
-moz-user-select: none;
}
.leaflet-pane { z-index: 400; }
.leaflet-tile-pane { z-index: 200; }
.leaflet-overlay-pane { z-index: 400; }
.leaflet-shadow-pane { z-index: 500; }
.leaflet-marker-pane { z-index: 600; }
.leaflet-tooltip-pane { z-index: 650; }
.leaflet-popup-pane { z-index: 700; }
.leaflet-map-pane canvas { z-index: 100; }
.leaflet-map-pane svg { z-index: 200; }
.leaflet-vml-shape {
width: 1px;
height: 1px;
}
.lvml {
behavior: url(#default#VML);
display: inline-block;
position: absolute;
}
/* control positioning */
.leaflet-control {
position: relative;
z-index: 800;
pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
pointer-events: auto;
}
.leaflet-top,
.leaflet-bottom {
position: absolute;
z-index: 1000;
pointer-events: none;
}
.leaflet-top {
top: 0;
}
.leaflet-right {
right: 0;
}
.leaflet-bottom {
bottom: 0;
}
.leaflet-left {
left: 0;
}
.leaflet-control {
float: left;
clear: both;
}
.leaflet-right .leaflet-control {
float: right;
}
.leaflet-top .leaflet-control {
margin-top: 10px;
}
.leaflet-bottom .leaflet-control {
margin-bottom: 10px;
}
.leaflet-left .leaflet-control {
margin-left: 10px;
}
.leaflet-right .leaflet-control {
margin-right: 10px;
}
/* zoom and fade animations */
.leaflet-fade-anim .leaflet-tile {
will-change: opacity;
}
.leaflet-fade-anim .leaflet-popup {
opacity: 0;
-webkit-transition: opacity 0.2s linear;
-moz-transition: opacity 0.2s linear;
-o-transition: opacity 0.2s linear;
transition: opacity 0.2s linear;
}
.leaflet-fade-anim .leaflet-map-pane .leaflet-popup {
opacity: 1;
}
.leaflet-zoom-animated {
-webkit-transform-origin: 0 0;
-ms-transform-origin: 0 0;
transform-origin: 0 0;
}
.leaflet-zoom-anim .leaflet-zoom-animated {
will-change: transform;
}
.leaflet-zoom-anim .leaflet-zoom-animated {
-webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1);
-moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1);
-o-transition: -o-transform 0.25s cubic-bezier(0,0,0.25,1);
transition: transform 0.25s cubic-bezier(0,0,0.25,1);
}
.leaflet-zoom-anim .leaflet-tile,
.leaflet-pan-anim .leaflet-tile {
-webkit-transition: none;
-moz-transition: none;
-o-transition: none;
transition: none;
}
.leaflet-zoom-anim .leaflet-zoom-hide {
visibility: hidden;
}
/* cursors */
.leaflet-interactive {
cursor: pointer;
}
.leaflet-grab {
cursor: -webkit-grab;
cursor: -moz-grab;
}
.leaflet-crosshair,
.leaflet-crosshair .leaflet-interactive {
cursor: crosshair;
}
.leaflet-popup-pane,
.leaflet-control {
cursor: auto;
}
.leaflet-dragging .leaflet-grab,
.leaflet-dragging .leaflet-grab .leaflet-interactive,
.leaflet-dragging .leaflet-marker-draggable {
cursor: move;
cursor: -webkit-grabbing;
cursor: -moz-grabbing;
}
/* marker & overlays interactivity */
.leaflet-marker-icon,
.leaflet-marker-shadow,
.leaflet-image-layer,
.leaflet-pane > svg path,
.leaflet-tile-container {
pointer-events: none;
}
.leaflet-marker-icon.leaflet-interactive,
.leaflet-image-layer.leaflet-interactive,
.leaflet-pane > svg path.leaflet-interactive {
pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
pointer-events: auto;
}
/* visual tweaks */
.leaflet-container {
background: #ddd;
outline: 0;
}
.leaflet-container a {
color: #0078A8;
}
.leaflet-container a.leaflet-active {
outline: 2px solid orange;
}
.leaflet-zoom-box {
border: 2px dotted #38f;
background: rgba(255,255,255,0.5);
}
/* general typography */
.leaflet-container {
font: 12px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif;
}
/* general toolbar styles */
.leaflet-bar {
box-shadow: 0 1px 5px rgba(0,0,0,0.65);
border-radius: 4px;
}
.leaflet-bar a,
.leaflet-bar a:hover {
background-color: #fff;
border-bottom: 1px solid #ccc;
width: 26px;
height: 26px;
line-height: 26px;
display: block;
text-align: center;
text-decoration: none;
color: black;
}
.leaflet-bar a,
.leaflet-control-layers-toggle {
background-position: 50% 50%;
background-repeat: no-repeat;
display: block;
}
.leaflet-bar a:hover {
background-color: #f4f4f4;
}
.leaflet-bar a:first-child {
border-top-left-radius: 4px;
border-top-right-radius: 4px;
}
.leaflet-bar a:last-child {
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
border-bottom: none;
}
.leaflet-bar a.leaflet-disabled {
cursor: default;
background-color: #f4f4f4;
color: #bbb;
}
.leaflet-touch .leaflet-bar a {
width: 30px;
height: 30px;
line-height: 30px;
}
.leaflet-touch .leaflet-bar a:first-child {
border-top-left-radius: 2px;
border-top-right-radius: 2px;
}
.leaflet-touch .leaflet-bar a:last-child {
border-bottom-left-radius: 2px;
border-bottom-right-radius: 2px;
}
/* zoom control */
.leaflet-control-zoom-in,
.leaflet-control-zoom-out {
font: bold 18px 'Lucida Console', Monaco, monospace;
text-indent: 1px;
}
.leaflet-touch .leaflet-control-zoom-in, .leaflet-touch .leaflet-control-zoom-out {
font-size: 22px;
}
/* layers control */
.leaflet-control-layers {
box-shadow: 0 1px 5px rgba(0,0,0,0.4);
background: #fff;
border-radius: 5px;
}
.leaflet-control-layers-toggle {
background-image: url(images/layers.png);
width: 36px;
height: 36px;
}
.leaflet-retina .leaflet-control-layers-toggle {
background-image: url(images/layers-2x.png);
background-size: 26px 26px;
}
.leaflet-touch .leaflet-control-layers-toggle {
width: 44px;
height: 44px;
}
.leaflet-control-layers .leaflet-control-layers-list,
.leaflet-control-layers-expanded .leaflet-control-layers-toggle {
display: none;
}
.leaflet-control-layers-expanded .leaflet-control-layers-list {
display: block;
position: relative;
}
.leaflet-control-layers-expanded {
padding: 6px 10px 6px 6px;
color: #333;
background: #fff;
}
.leaflet-control-layers-scrollbar {
overflow-y: scroll;
overflow-x: hidden;
padding-right: 5px;
}
.leaflet-control-layers-selector {
margin-top: 2px;
position: relative;
top: 1px;
}
.leaflet-control-layers label {
display: block;
}
.leaflet-control-layers-separator {
height: 0;
border-top: 1px solid #ddd;
margin: 5px -10px 5px -6px;
}
/* Default icon URLs */
.leaflet-default-icon-path {
background-image: url(images/marker-icon.png);
}
/* attribution and scale controls */
.leaflet-container .leaflet-control-attribution {
background: #fff;
background: rgba(255, 255, 255, 0.7);
margin: 0;
}
.leaflet-control-attribution,
.leaflet-control-scale-line {
padding: 0 5px;
color: #333;
}
.leaflet-control-attribution a {
text-decoration: none;
}
.leaflet-control-attribution a:hover {
text-decoration: underline;
}
.leaflet-container .leaflet-control-attribution,
.leaflet-container .leaflet-control-scale {
font-size: 11px;
}
.leaflet-left .leaflet-control-scale {
margin-left: 5px;
}
.leaflet-bottom .leaflet-control-scale {
margin-bottom: 5px;
}
.leaflet-control-scale-line {
border: 2px solid #777;
border-top: none;
line-height: 1.1;
padding: 2px 5px 1px;
font-size: 11px;
white-space: nowrap;
overflow: hidden;
-moz-box-sizing: border-box;
box-sizing: border-box;
background: #fff;
background: rgba(255, 255, 255, 0.5);
}
.leaflet-control-scale-line:not(:first-child) {
border-top: 2px solid #777;
border-bottom: none;
margin-top: -2px;
}
.leaflet-control-scale-line:not(:first-child):not(:last-child) {
border-bottom: 2px solid #777;
}
.leaflet-touch .leaflet-control-attribution,
.leaflet-touch .leaflet-control-layers,
.leaflet-touch .leaflet-bar {
box-shadow: none;
}
.leaflet-touch .leaflet-control-layers,
.leaflet-touch .leaflet-bar {
border: 2px solid rgba(0,0,0,0.2);
background-clip: padding-box;
}
/* popup */
.leaflet-popup {
position: absolute;
text-align: center;
margin-bottom: 20px;
}
.leaflet-popup-content-wrapper {
padding: 1px;
text-align: left;
border-radius: 12px;
}
.leaflet-popup-content {
margin: 13px 19px;
line-height: 1.4;
}
.leaflet-popup-content p {
margin: 18px 0;
}
.leaflet-popup-tip-container {
width: 40px;
height: 20px;
position: absolute;
left: 50%;
margin-left: -20px;
overflow: hidden;
pointer-events: none;
}
.leaflet-popup-tip {
width: 17px;
height: 17px;
padding: 1px;
margin: -10px auto 0;
-webkit-transform: rotate(45deg);
-moz-transform: rotate(45deg);
-ms-transform: rotate(45deg);
-o-transform: rotate(45deg);
transform: rotate(45deg);
}
.leaflet-popup-content-wrapper,
.leaflet-popup-tip {
background: white;
color: #333;
box-shadow: 0 3px 14px rgba(0,0,0,0.4);
}
.leaflet-container a.leaflet-popup-close-button {
position: absolute;
top: 0;
right: 0;
padding: 4px 4px 0 0;
border: none;
text-align: center;
width: 18px;
height: 14px;
font: 16px/14px Tahoma, Verdana, sans-serif;
color: #c3c3c3;
text-decoration: none;
font-weight: bold;
background: transparent;
}
.leaflet-container a.leaflet-popup-close-button:hover {
color: #999;
}
.leaflet-popup-scrolled {
overflow: auto;
border-bottom: 1px solid #ddd;
border-top: 1px solid #ddd;
}
.leaflet-oldie .leaflet-popup-content-wrapper {
zoom: 1;
}
.leaflet-oldie .leaflet-popup-tip {
width: 24px;
margin: 0 auto;
-ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)";
filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678);
}
.leaflet-oldie .leaflet-popup-tip-container {
margin-top: -1px;
}
.leaflet-oldie .leaflet-control-zoom,
.leaflet-oldie .leaflet-control-layers,
.leaflet-oldie .leaflet-popup-content-wrapper,
.leaflet-oldie .leaflet-popup-tip {
border: 1px solid #999;
}
/* div icon */
.leaflet-div-icon {
background: #fff;
border: 1px solid #666;
}
/* Tooltip */
/* Base styles for the element that has a tooltip */
.leaflet-tooltip {
position: absolute;
padding: 6px;
background-color: #fff;
border: 1px solid #fff;
border-radius: 3px;
color: #222;
white-space: nowrap;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
pointer-events: none;
box-shadow: 0 1px 3px rgba(0,0,0,0.4);
}
.leaflet-tooltip.leaflet-clickable {
cursor: pointer;
pointer-events: auto;
}
.leaflet-tooltip-top:before,
.leaflet-tooltip-bottom:before,
.leaflet-tooltip-left:before,
.leaflet-tooltip-right:before {
position: absolute;
pointer-events: none;
border: 6px solid transparent;
background: transparent;
content: "";
}
/* Directions */
.leaflet-tooltip-bottom {
margin-top: 6px;
}
.leaflet-tooltip-top {
margin-top: -6px;
}
.leaflet-tooltip-bottom:before,
.leaflet-tooltip-top:before {
left: 50%;
margin-left: -6px;
}
.leaflet-tooltip-top:before {
bottom: 0;
margin-bottom: -12px;
border-top-color: #fff;
}
.leaflet-tooltip-bottom:before {
top: 0;
margin-top: -12px;
margin-left: -6px;
border-bottom-color: #fff;
}
.leaflet-tooltip-left {
margin-left: -6px;
}
.leaflet-tooltip-right {
margin-left: 6px;
}
.leaflet-tooltip-left:before,
.leaflet-tooltip-right:before {
top: 50%;
margin-top: -6px;
}
.leaflet-tooltip-left:before {
right: 0;
margin-right: -12px;
border-left-color: #fff;
}
.leaflet-tooltip-right:before {
left: 0;
margin-left: -12px;
border-right-color: #fff;
}
// Packaging/modules magic dance.
(function (factory) {
var L;
if (typeof define === 'function' && define.amd) {
// AMD
define(['leaflet'], factory);
} else if (typeof module !== 'undefined') {
// Node/CommonJS
L = require('leaflet');
module.exports = factory(L);
} else {
// Browser globals
if (typeof window.L === 'undefined')
throw 'Leaflet must be loaded first';
factory(window.L);
}
}(function (L) {
"use strict";
/**
* @fileOverview Leaflet Geometry utilities for distances and linear referencing.
* @name L.GeometryUtil
*/
L.GeometryUtil = L.extend(L.GeometryUtil || {}, {
/**
Shortcut function for planar distance between two {L.LatLng} at current zoom.
@tutorial distance-length
@param {L.Map} map Leaflet map to be used for this method
@param {L.LatLng} latlngA geographical point A
@param {L.LatLng} latlngB geographical point B
@returns {Number} planar distance
*/
distance: function (map, latlngA, latlngB) {
return map.latLngToLayerPoint(latlngA).distanceTo(map.latLngToLayerPoint(latlngB));
},
/**
Shortcut function for planar distance between a {L.LatLng} and a segment (A-B).
@param {L.Map} map Leaflet map to be used for this method
@param {L.LatLng} latlng - The position to search
@param {L.LatLng} latlngA geographical point A of the segment
@param {L.LatLng} latlngB geographical point B of the segment
@returns {Number} planar distance
*/
distanceSegment: function (map, latlng, latlngA, latlngB) {
var p = map.latLngToLayerPoint(latlng),
p1 = map.latLngToLayerPoint(latlngA),
p2 = map.latLngToLayerPoint(latlngB);
return L.LineUtil.pointToSegmentDistance(p, p1, p2);
},
/**
Shortcut function for converting distance to readable distance.
@param {Number} distance distance to be converted
@param {String} unit 'metric' or 'imperial'
@returns {String} in yard or miles
*/
readableDistance: function (distance, unit) {
var isMetric = (unit !== 'imperial'),
distanceStr;
if (isMetric) {
// show metres when distance is < 1km, then show km
if (distance > 1000) {
distanceStr = (distance / 1000).toFixed(2) + ' km';
}
else {
distanceStr = Math.ceil(distance) + ' m';
}
}
else {
distance *= 1.09361;
if (distance > 1760) {
distanceStr = (distance / 1760).toFixed(2) + ' miles';
}
else {
distanceStr = Math.ceil(distance) + ' yd';
}
}
return distanceStr;
},
/**
Returns true if the latlng belongs to segment A-B
@param {L.LatLng} latlng - The position to search
@param {L.LatLng} latlngA geographical point A of the segment
@param {L.LatLng} latlngB geographical point B of the segment
@param {?Number} [tolerance=0.2] tolerance to accept if latlng belongs really
@returns {boolean}
*/
belongsSegment: function(latlng, latlngA, latlngB, tolerance) {
tolerance = tolerance === undefined ? 0.2 : tolerance;
var hypotenuse = latlngA.distanceTo(latlngB),
delta = latlngA.distanceTo(latlng) + latlng.distanceTo(latlngB) - hypotenuse;
return delta/hypotenuse < tolerance;
},
/**
* Returns total length of line
* @tutorial distance-length
*
* @param {L.Polyline|Array<L.Point>|Array<L.LatLng>} coords Set of coordinates
* @returns {Number} Total length (pixels for Point, meters for LatLng)
*/
length: function (coords) {
var accumulated = L.GeometryUtil.accumulatedLengths(coords);
return accumulated.length > 0 ? accumulated[accumulated.length-1] : 0;
},
/**
* Returns a list of accumulated length along a line.
* @param {L.Polyline|Array<L.Point>|Array<L.LatLng>} coords Set of coordinates
* @returns {Array<Number>} Array of accumulated lengths (pixels for Point, meters for LatLng)
*/
accumulatedLengths: function (coords) {
if (typeof coords.getLatLngs == 'function') {
coords = coords.getLatLngs();
}
if (coords.length === 0)
return [];
var total = 0,
lengths = [0];
for (var i = 0, n = coords.length - 1; i< n; i++) {
total += coords[i].distanceTo(coords[i+1]);
lengths.push(total);
}
return lengths;
},
/**
Returns the closest point of a {L.LatLng} on the segment (A-B)
@tutorial closest
@param {L.Map} map Leaflet map to be used for this method
@param {L.LatLng} latlng - The position to search
@param {L.LatLng} latlngA geographical point A of the segment
@param {L.LatLng} latlngB geographical point B of the segment
@returns {L.LatLng} Closest geographical point
*/
closestOnSegment: function (map, latlng, latlngA, latlngB) {
var maxzoom = map.getMaxZoom();
if (maxzoom === Infinity)
maxzoom = map.getZoom();
var p = map.project(latlng, maxzoom),
p1 = map.project(latlngA, maxzoom),
p2 = map.project(latlngB, maxzoom),
closest = L.LineUtil.closestPointOnSegment(p, p1, p2);
return map.unproject(closest, maxzoom);
},
/**
Returns the closest latlng on layer.
Accept nested arrays
@tutorial closest
@param {L.Map} map Leaflet map to be used for this method
@param {Array<L.LatLng>|Array<Array<L.LatLng>>|L.PolyLine|L.Polygon} layer - Layer that contains the result
@param {L.LatLng} latlng - The position to search
@param {?boolean} [vertices=false] - Whether to restrict to path vertices.
@returns {L.LatLng} Closest geographical point or null if layer param is incorrect
*/
closest: function (map, layer, latlng, vertices) {
var latlngs,
mindist = Infinity,
result = null,
i, n, distance;
if (layer instanceof Array) {
// if layer is Array<Array<T>>
if (layer[0] instanceof Array && typeof layer[0][0] !== 'number') {
// if we have nested arrays, we calc the closest for each array
// recursive
for (var i = 0; i < layer.length; i++) {
var subResult = L.GeometryUtil.closest(map, layer[i], latlng, vertices);
if (subResult.distance < mindist) {
mindist = subResult.distance;
result = subResult;
}
}
return result;
} else if (layer[0] instanceof L.LatLng || typeof layer[0][0] === 'number') { // we could have a latlng as [x,y] with x & y numbers
layer = L.polyline(layer);
} else {
return result;
}
}
// if we don't have here a Polyline, that means layer is incorrect
// see https://github.com/makinacorpus/Leaflet.GeometryUtil/issues/23
if (! ( layer instanceof L.Polyline ) )
return result;
/**
* Flat an array upon a predicate, saying if we have to dig digger or not
* Specific use for Polygon, Polyline, MultiPolyline (0.7.7)
* Leaflet 1.0 change the structure of Polyline (could be MultiPolyline > nested arrays), idem for Polygon
*/
function flattenArray(array, predicate, result) {
var index = -1,
length = array.length;
predicate || ( predicate = function(v) { return true } );
result || ( result = []);
if (predicate(array)) {
while (++index < length) {
var value = array[index];
if (predicate(value)) {
flattenArray(value, predicate, result);
} else {
result.push(value);
}
}
} else {
result.push(array);
}
return result;
}
latlngs = flattenArray(layer.getLatLngs().slice(0), function isFlattenable(value) {
return ( ( value instanceof Array && typeof value[0] !== 'number' ) && ! ( value instanceof L.LatLng ) )
});
// Lookup vertices
if (vertices) {
for(i = 0, n = latlngs.length; i < n; i++) {
var ll = latlngs[i];
distance = L.GeometryUtil.distance(map, latlng, ll);
if (distance < mindist) {
mindist = distance;
result = ll;
result.distance = distance;
}
}
return result;
}
// add the first point to close the polygon
if (layer instanceof L.Polygon) {
latlngs.push(latlngs[0]);
}
// Keep the closest point of all segments
for (i = 0, n = latlngs.length; i < n-1; i++) {
var latlngA = latlngs[i],
latlngB = latlngs[i+1];
distance = L.GeometryUtil.distanceSegment(map, latlng, latlngA, latlngB);
if (distance <= mindist) {
mindist = distance;
result = L.GeometryUtil.closestOnSegment(map, latlng, latlngA, latlngB);
result.distance = distance;
}
}
return result;
},
/**
Returns the closest layer to latlng among a list of layers.
@tutorial closest
@param {L.Map} map Leaflet map to be used for this method
@param {Array<L.ILayer>} layers Set of layers
@param {L.LatLng} latlng - The position to search
@returns {object} ``{layer, latlng, distance}`` or ``null`` if list is empty;
*/
closestLayer: function (map, layers, latlng) {
var mindist = Infinity,
result = null,
ll = null,
distance = Infinity;
for (var i = 0, n = layers.length; i < n; i++) {
var layer = layers[i];
if (layer instanceof L.LayerGroup) {
// recursive
var subResult = L.GeometryUtil.closestLayer(map, layer.getLayers(), latlng);
if (subResult.distance < mindist) {
mindist = subResult.distance;
result = subResult;
}
} else {
// Single dimension, snap on points, else snap on closest
if (typeof layer.getLatLng == 'function') {
ll = layer.getLatLng();
distance = L.GeometryUtil.distance(map, latlng, ll);
}
else {
ll = L.GeometryUtil.closest(map, layer, latlng);
if (ll) distance = ll.distance; // Can return null if layer has no points.
}
if (distance < mindist) {
mindist = distance;
result = {layer: layer, latlng: ll, distance: distance};
}
}
}
return result;
},
/**
* Returns all layers within a radius of the given position, in an ascending order of distance.
@param {L.Map} map Leaflet map to be used for this method
@param {Array<ILayer>} layers - A list of layers.
@param {L.LatLng} latlng - The position to search
@param {?Number} [radius=Infinity] - Search radius in pixels
@return {object[]} an array of objects including layer within the radius, closest latlng, and distance
*/
layersWithin: function(map, layers, latlng, radius) {
radius = typeof radius == 'number' ? radius : Infinity;
var results = [];
var ll = null;
var distance = 0;
for (var i = 0, n = layers.length; i < n; i++) {
var layer = layers[i];
if (typeof layer.getLatLng == 'function') {
ll = layer.getLatLng();
distance = L.GeometryUtil.distance(map, latlng, ll);
}
else {
ll = L.GeometryUtil.closest(map, layer, latlng);
if (ll) distance = ll.distance; // Can return null if layer has no points.
}
if (ll && distance < radius) {
results.push({layer: layer, latlng: ll, distance: distance});
}
}
var sortedResults = results.sort(function(a, b) {
return a.distance - b.distance;
});
return sortedResults;
},
/**
Returns the closest position from specified {LatLng} among specified layers,
with a maximum tolerance in pixels, providing snapping behaviour.
@tutorial closest
@param {L.Map} map Leaflet map to be used for this method
@param {Array<ILayer>} layers - A list of layers to snap on.
@param {L.LatLng} latlng - The position to snap
@param {?Number} [tolerance=Infinity] - Maximum number of pixels.
@param {?boolean} [withVertices=true] - Snap to layers vertices or segment points (not only vertex)
@returns {object} with snapped {LatLng} and snapped {Layer} or null if tolerance exceeded.
*/
closestLayerSnap: function (map, layers, latlng, tolerance, withVertices) {
tolerance = typeof tolerance == 'number' ? tolerance : Infinity;
withVertices = typeof withVertices == 'boolean' ? withVertices : true;
var result = L.GeometryUtil.closestLayer(map, layers, latlng);
if (!result || result.distance > tolerance)
return null;
// If snapped layer is linear, try to snap on vertices (extremities and middle points)
if (withVertices && typeof result.layer.getLatLngs == 'function') {
var closest = L.GeometryUtil.closest(map, result.layer, result.latlng, true);
if (closest.distance < tolerance) {
result.latlng = closest;
result.distance = L.GeometryUtil.distance(map, closest, latlng);
}
}
return result;
},
/**
Returns the Point located on a segment at the specified ratio of the segment length.
@param {L.Point} pA coordinates of point A
@param {L.Point} pB coordinates of point B
@param {Number} the length ratio, expressed as a decimal between 0 and 1, inclusive.
@returns {L.Point} the interpolated point.
*/
interpolateOnPointSegment: function (pA, pB, ratio) {
return L.point(
(pA.x * (1 - ratio)) + (ratio * pB.x),
(pA.y * (1 - ratio)) + (ratio * pB.y)
);
},
/**
Returns the coordinate of the point located on a line at the specified ratio of the line length.
@param {L.Map} map Leaflet map to be used for this method
@param {Array<L.LatLng>|L.PolyLine} latlngs Set of geographical points
@param {Number} ratio the length ratio, expressed as a decimal between 0 and 1, inclusive
@returns {Object} an object with latLng ({LatLng}) and predecessor ({Number}), the index of the preceding vertex in the Polyline
(-1 if the interpolated point is the first vertex)
*/
interpolateOnLine: function (map, latLngs, ratio) {
latLngs = (latLngs instanceof L.Polyline) ? latLngs.getLatLngs() : latLngs;
var n = latLngs.length;
if (n < 2) {
return null;
}
// ensure the ratio is between 0 and 1;
ratio = Math.max(Math.min(ratio, 1), 0);
if (ratio === 0) {
return {
latLng: latLngs[0] instanceof L.LatLng ? latLngs[0] : L.latLng(latLngs[0]),
predecessor: -1
};
}
if (ratio == 1) {
return {
latLng: latLngs[latLngs.length -1] instanceof L.LatLng ? latLngs[latLngs.length -1] : L.latLng(latLngs[latLngs.length -1]),
predecessor: latLngs.length - 2
};
}
// project the LatLngs as Points,
// and compute total planar length of the line at max precision
var maxzoom = map.getMaxZoom();
if (maxzoom === Infinity)
maxzoom = map.getZoom();
var pts = [];
var lineLength = 0;
for(var i = 0; i < n; i++) {
pts[i] = map.project(latLngs[i], maxzoom);
if(i > 0)
lineLength += pts[i-1].distanceTo(pts[i]);
}
var ratioDist = lineLength * ratio;
var a = pts[0],
b = pts[1],
distA = 0,
distB = a.distanceTo(b);
// follow the line segments [ab], adding lengths,
// until we find the segment where the points should lie on
var index = 1;
for (; index < n && distB < ratioDist; index++) {
a = b;
distA = distB;
b = pts[index];
distB += a.distanceTo(b);
}
// compute the ratio relative to the segment [ab]
var segmentRatio = ((distB - distA) !== 0) ? ((ratioDist - distA) / (distB - distA)) : 0;
var interpolatedPoint = L.GeometryUtil.interpolateOnPointSegment(a, b, segmentRatio);
return {
latLng: map.unproject(interpolatedPoint, maxzoom),
predecessor: index-2
};
},
/**
Returns a float between 0 and 1 representing the location of the
closest point on polyline to the given latlng, as a fraction of total line length.
(opposite of L.GeometryUtil.interpolateOnLine())
@param {L.Map} map Leaflet map to be used for this method
@param {L.PolyLine} polyline Polyline on which the latlng will be search
@param {L.LatLng} latlng The position to search
@returns {Number} Float between 0 and 1
*/
locateOnLine: function (map, polyline, latlng) {
var latlngs = polyline.getLatLngs();
if (latlng.equals(latlngs[0]))
return 0.0;
if (latlng.equals(latlngs[latlngs.length-1]))
return 1.0;
var point = L.GeometryUtil.closest(map, polyline, latlng, false),
lengths = L.GeometryUtil.accumulatedLengths(latlngs),
total_length = lengths[lengths.length-1],
portion = 0,
found = false;
for (var i=0, n = latlngs.length-1; i < n; i++) {
var l1 = latlngs[i],
l2 = latlngs[i+1];
portion = lengths[i];
if (L.GeometryUtil.belongsSegment(point, l1, l2)) {
portion += l1.distanceTo(point);
found = true;
break;
}
}
if (!found) {
throw "Could not interpolate " + latlng.toString() + " within " + polyline.toString();
}
return portion / total_length;
},
/**
Returns a clone with reversed coordinates.
@param {L.PolyLine} polyline polyline to reverse
@returns {L.PolyLine} polyline reversed
*/
reverse: function (polyline) {
return L.polyline(polyline.getLatLngs().slice(0).reverse());
},
/**
Returns a sub-part of the polyline, from start to end.
If start is superior to end, returns extraction from inverted line.
@param {L.Map} map Leaflet map to be used for this method
@param {L.PolyLine} polyline Polyline on which will be extracted the sub-part
@param {Number} start ratio, expressed as a decimal between 0 and 1, inclusive
@param {Number} end ratio, expressed as a decimal between 0 and 1, inclusive
@returns {Array<L.LatLng>} new polyline
*/
extract: function (map, polyline, start, end) {
if (start > end) {
return L.GeometryUtil.extract(map, L.GeometryUtil.reverse(polyline), 1.0-start, 1.0-end);
}
// Bound start and end to [0-1]
start = Math.max(Math.min(start, 1), 0);
end = Math.max(Math.min(end, 1), 0);
var latlngs = polyline.getLatLngs(),
startpoint = L.GeometryUtil.interpolateOnLine(map, polyline, start),
endpoint = L.GeometryUtil.interpolateOnLine(map, polyline, end);
// Return single point if start == end
if (start == end) {
var point = L.GeometryUtil.interpolateOnLine(map, polyline, end);
return [point.latLng];
}
// Array.slice() works indexes at 0
if (startpoint.predecessor == -1)
startpoint.predecessor = 0;
if (endpoint.predecessor == -1)
endpoint.predecessor = 0;
var result = latlngs.slice(startpoint.predecessor+1, endpoint.predecessor+1);
result.unshift(startpoint.latLng);
result.push(endpoint.latLng);
return result;
},
/**
Returns true if first polyline ends where other second starts.
@param {L.PolyLine} polyline First polyline
@param {L.PolyLine} other Second polyline
@returns {bool}
*/
isBefore: function (polyline, other) {
if (!other) return false;
var lla = polyline.getLatLngs(),
llb = other.getLatLngs();
return (lla[lla.length-1]).equals(llb[0]);
},
/**
Returns true if first polyline starts where second ends.
@param {L.PolyLine} polyline First polyline
@param {L.PolyLine} other Second polyline
@returns {bool}
*/
isAfter: function (polyline, other) {
if (!other) return false;
var lla = polyline.getLatLngs(),
llb = other.getLatLngs();
return (lla[0]).equals(llb[llb.length-1]);
},
/**
Returns true if first polyline starts where second ends or start.
@param {L.PolyLine} polyline First polyline
@param {L.PolyLine} other Second polyline
@returns {bool}
*/
startsAtExtremity: function (polyline, other) {
if (!other) return false;
var lla = polyline.getLatLngs(),
llb = other.getLatLngs(),
start = lla[0];
return start.equals(llb[0]) || start.equals(llb[llb.length-1]);
},
/**
Returns horizontal angle in degres between two points.
@param {L.Point} a Coordinates of point A
@param {L.Point} b Coordinates of point B
@returns {Number} horizontal angle
*/
computeAngle: function(a, b) {
return (Math.atan2(b.y - a.y, b.x - a.x) * 180 / Math.PI);
},
/**
Returns slope (Ax+B) between two points.
@param {L.Point} a Coordinates of point A
@param {L.Point} b Coordinates of point B
@returns {Object} with ``a`` and ``b`` properties.
*/
computeSlope: function(a, b) {
var s = (b.y - a.y) / (b.x - a.x),
o = a.y - (s * a.x);
return {'a': s, 'b': o};
},
/**
Returns LatLng of rotated point around specified LatLng center.
@param {L.LatLng} latlngPoint: point to rotate
@param {double} angleDeg: angle to rotate in degrees
@param {L.LatLng} latlngCenter: center of rotation
@returns {L.LatLng} rotated point
*/
rotatePoint: function(map, latlngPoint, angleDeg, latlngCenter) {
var maxzoom = map.getMaxZoom();
if (maxzoom === Infinity)
maxzoom = map.getZoom();
var angleRad = angleDeg*Math.PI/180,
pPoint = map.project(latlngPoint, maxzoom),
pCenter = map.project(latlngCenter, maxzoom),
x2 = Math.cos(angleRad)*(pPoint.x-pCenter.x) - Math.sin(angleRad)*(pPoint.y-pCenter.y) + pCenter.x,
y2 = Math.sin(angleRad)*(pPoint.x-pCenter.x) + Math.cos(angleRad)*(pPoint.y-pCenter.y) + pCenter.y;
return map.unproject(new L.Point(x2,y2), maxzoom);
},
/**
Returns the bearing in degrees clockwise from north (0 degrees)
from the first L.LatLng to the second, at the first LatLng
@param {L.LatLng} latlng1: origin point of the bearing
@param {L.LatLng} latlng2: destination point of the bearing
@returns {float} degrees clockwise from north.
*/
bearing: function(latlng1, latlng2) {
var rad = Math.PI / 180,
lat1 = latlng1.lat * rad,
lat2 = latlng2.lat * rad,
lon1 = latlng1.lng * rad,
lon2 = latlng2.lng * rad,
y = Math.sin(lon2 - lon1) * Math.cos(lat2),
x = Math.cos(lat1) * Math.sin(lat2) -
Math.sin(lat1) * Math.cos(lat2) * Math.cos(lon2 - lon1);
var bearing = ((Math.atan2(y, x) * 180 / Math.PI) + 360) % 360;
return bearing >= 180 ? bearing-360 : bearing;
},
/**
Returns the point that is a distance and heading away from
the given origin point.
@param {L.LatLng} latlng: origin point
@param {float}: heading in degrees, clockwise from 0 degrees north.
@param {float}: distance in meters
@returns {L.latLng} the destination point.
Many thanks to Chris Veness at http://www.movable-type.co.uk/scripts/latlong.html
for a great reference and examples.
*/
destination: function(latlng, heading, distance) {
heading = (heading + 360) % 360;
var rad = Math.PI / 180,
radInv = 180 / Math.PI,
R = 6378137, // approximation of Earth's radius
lon1 = latlng.lng * rad,
lat1 = latlng.lat * rad,
rheading = heading * rad,
sinLat1 = Math.sin(lat1),
cosLat1 = Math.cos(lat1),
cosDistR = Math.cos(distance / R),
sinDistR = Math.sin(distance / R),
lat2 = Math.asin(sinLat1 * cosDistR + cosLat1 *
sinDistR * Math.cos(rheading)),
lon2 = lon1 + Math.atan2(Math.sin(rheading) * sinDistR *
cosLat1, cosDistR - sinLat1 * Math.sin(lat2));
lon2 = lon2 * radInv;
lon2 = lon2 > 180 ? lon2 - 360 : lon2 < -180 ? lon2 + 360 : lon2;
return L.latLng([lat2 * radInv, lon2]);
}
});
return L.GeometryUtil;
}));
(function () {
L.Handler.MarkerSnap = L.Handler.extend({
options: {
snapDistance: 15, // in pixels
snapVertices: true
},
initialize: function (map, marker, options) {
L.Handler.prototype.initialize.call(this, map);
this._markers = [];
this._guides = [];
if (arguments.length == 2) {
if (!(marker instanceof L.Class)) {
options = marker;
marker = null;
}
}
L.Util.setOptions(this, options || {});
if (marker) {
// new markers should be draggable !
if (!marker.dragging) marker.dragging = new L.Handler.MarkerDrag(marker);
marker.dragging.enable();
this.watchMarker(marker);
}
// Convert snap distance in pixels into buffer in degres, for searching around mouse
// It changes at each zoom change.
function computeBuffer() {
this._buffer = map.layerPointToLatLng(new L.Point(0,0)).lat -
map.layerPointToLatLng(new L.Point(this.options.snapDistance, 0)).lat;
}
map.on('zoomend', computeBuffer, this);
map.whenReady(computeBuffer, this);
computeBuffer.call(this);
},
enable: function () {
this.disable();
for (var i=0; i<this._markers.length; i++) {
this.watchMarker(this._markers[i]);
}
},
disable: function () {
for (var i=0; i<this._markers.length; i++) {
this.unwatchMarker(this._markers[i]);
}
},
watchMarker: function (marker) {
if (this._markers.indexOf(marker) == -1)
this._markers.push(marker);
marker.on('move', this._snapMarker, this);
},
unwatchMarker: function (marker) {
marker.off('move', this._snapMarker, this);
delete marker['snap'];
},
addGuideLayer: function (layer) {
for (var i=0, n=this._guides.length; i<n; i++)
if (L.stamp(layer) === L.stamp(this._guides[i]))
return;
this._guides.push(layer);
},
_snapMarker: function(e) {
var marker = e.target,
latlng = marker.getLatLng(),
snaplist = [];
function isDifferentLayer(layer) {
if (layer.getLatLng) {
return L.stamp(marker) !== L.stamp(layer);
} else {
if (layer.editing && layer.editing._enabled) {
var points = layer.editing._verticesHandlers[0]._markerGroup.getLayers();
for(var i = 0, n = points.length; i < n; i++) {
if (L.stamp(points[i]) === L.stamp(marker)) { return false; }
}
}
}
return true;
}
function processGuide(guide) {
if ((guide._layers !== undefined) &&
(typeof guide.searchBuffer !== 'function')) {
// Guide is a layer group and has no L.LayerIndexMixin (from Leaflet.LayerIndex)
for (var id in guide._layers) {
processGuide(guide._layers[id]);
}
}
else if (typeof guide.searchBuffer === 'function') {
// Search snaplist around mouse
var nearlayers = guide.searchBuffer(latlng, this._buffer);
snaplist = snaplist.concat(nearlayers.filter(function(layer) {
return isDifferentLayer(layer);
}));
}
// Make sure the marker doesn't snap to itself or the associated polyline layer
else if (isDifferentLayer(guide)) {
snaplist.push(guide);
}
}
for (var i=0, n = this._guides.length; i < n; i++) {
var guide = this._guides[i];
processGuide.call(this, guide);
}
var closest = this._findClosestLayerSnap(this._map,
snaplist,
latlng,
this.options.snapDistance,
this.options.snapVertices);
closest = closest || {layer: null, latlng: null};
this._updateSnap(marker, closest.layer, closest.latlng);
},
_findClosestLayerSnap: function (map, layers, latlng, tolerance, withVertices) {
return L.GeometryUtil.closestLayerSnap(map, layers, latlng, tolerance, withVertices);
},
_updateSnap: function (marker, layer, latlng) {
if (layer && latlng) {
marker._latlng = L.latLng(latlng);
marker.update();
if (marker.snap != layer) {
marker.snap = layer;
if (marker._icon) L.DomUtil.addClass(marker._icon, 'marker-snapped');
marker.fire('snap', {layer:layer, latlng: latlng});
}
}
else {
if (marker.snap) {
if (marker._icon) L.DomUtil.removeClass(marker._icon, 'marker-snapped');
marker.fire('unsnap', {layer:marker.snap});
}
delete marker['snap'];
}
}
});
if (!L.Edit) {
// Leaflet.Draw not available.
return;
}
L.Handler.PolylineSnap = L.Edit.Poly.extend({
initialize: function (map, poly, options) {
var that = this;
L.Edit.Poly.prototype.initialize.call(this, poly, options);
this._snapper = new L.Handler.MarkerSnap(map, options);
poly.on('remove', function() {
that.disable();
});
},
addGuideLayer: function (layer) {
this._snapper.addGuideLayer(layer);
},
_initHandlers: function () {
this._verticesHandlers = [];
for (var i = 0; i < this.latlngs.length; i++) {
this._verticesHandlers.push(new L.Edit.PolyVerticesEditSnap(this._poly, this.latlngs[i], this.options));
}
}
});
L.Edit.PolyVerticesEditSnap = L.Edit.PolyVerticesEdit.extend({
_createMarker: function (latlng, index) {
var marker = L.Edit.PolyVerticesEdit.prototype._createMarker.call(this, latlng, index);
// Treat middle markers differently
var isMiddle = index === undefined;
if (isMiddle) {
// Snap middle markers, only once they were touched
marker.on('dragstart', function () {
this._poly.snapediting._snapper.watchMarker(marker);
}, this);
}
else {
this._poly.snapediting._snapper.watchMarker(marker);
}
return marker;
}
});
L.EditToolbar.SnapEdit = L.EditToolbar.Edit.extend({
snapOptions: {
snapDistance: 15, // in pixels
snapVertices: true
},
initialize: function(map, options) {
L.EditToolbar.Edit.prototype.initialize.call(this, map, options);
if (options.snapOptions) {
L.Util.extend(this.snapOptions, options.snapOptions);
}
if (Array.isArray(this.snapOptions.guideLayers)) {
this._guideLayers = this.snapOptions.guideLayers;
} else if (options.guideLayers instanceof L.LayerGroup) {
this._guideLayers = this.snapOptions.guideLayers.getLayers();
} else {
this._guideLayers = [];
}
},
addGuideLayer: function(layer) {
var index = this._guideLayers.findIndex(function(guideLayer) {
return L.stamp(layer) === L.stamp(guideLayer);
});
if (index === -1) {
this._guideLayers.push(layer);
this._featureGroup.eachLayer(function(layer) {
if (layer.snapediting) { layer.snapediting._guides.push(layer); }
});
}
},
removeGuideLayer: function(layer) {
var index = this._guideLayers.findIndex(function(guideLayer) {
return L.stamp(layer) === L.stamp(guideLayer);
});
if (index !== -1) {
this._guideLayers.splice(index, 1);
this._featureGroup.eachLayer(function(layer) {
if (layer.snapediting) { layer.snapediting._guides.splice(index, 1); }
});
}
},
clearGuideLayers: function() {
this._guideLayers = [];
this._featureGroup.eachLayer(function(layer) {
if (layer.snapediting) { layer.snapediting._guides = []; }
});
},
_enableLayerEdit: function(e) {
L.EditToolbar.Edit.prototype._enableLayerEdit.call(this, e);
var layer = e.layer || e.target || e;
if (!layer.snapediting) {
if (layer.getLatLng) {
layer.snapediting = new L.Handler.MarkerSnap(layer._map, layer, this.snapOptions);
} else {
if (layer.editing) {
layer.editing._verticesHandlers[0]._markerGroup.clearLayers();
delete layer.editing;
}
layer.editing = layer.snapediting = new L.Handler.PolylineSnap(layer._map, layer, this.snapOptions);
}
for (var i = 0, n = this._guideLayers.length; i < n; i++) {
layer.snapediting.addGuideLayer(this._guideLayers[i]);
}
}
layer.snapediting.enable();
}
});
L.Draw.Feature.SnapMixin = {
_snap_initialize: function () {
this.on('enabled', this._snap_on_enabled, this);
this.on('disabled', this._snap_on_disabled, this);
},
_snap_on_enabled: function () {
if (!this.options.guideLayers) {
return;
}
if (!this._mouseMarker) {
this._map.on('layeradd', this._snap_on_enabled, this);
return;
}else{
this._map.off('layeradd', this._snap_on_enabled, this);
}
if (!this._snapper) {
this._snapper = new L.Handler.MarkerSnap(this._map);
if (this.options.snapDistance) {
this._snapper.options.snapDistance = this.options.snapDistance;
}
if (this.options.snapVertices) {
this._snapper.options.snapVertices = this.options.snapVertices;
}
}
for (var i=0, n=this.options.guideLayers.length; i<n; i++)
this._snapper.addGuideLayer(this.options.guideLayers[i]);
var marker = this._mouseMarker;
this._snapper.watchMarker(marker);
// Show marker when (snap for user feedback)
var icon = marker.options.icon;
marker.on('snap', function (e) {
marker.setIcon(this.options.icon);
marker.setOpacity(1);
}, this)
.on('unsnap', function (e) {
marker.setIcon(icon);
marker.setOpacity(0);
}, this);
marker.on('click', this._snap_on_click, this);
},
_snap_on_click: function (e) {
if (this._markers) {
var markerCount = this._markers.length,
marker = this._markers[markerCount - 1];
if (this._mouseMarker.snap) {
if(e){
// update the feature being drawn to reflect the snapped location:
marker.setLatLng(e.target._latlng);
if(this._poly){
var polyPointsCount = this._poly._latlngs.length;
this._poly._latlngs[polyPointsCount - 1] = e.target._latlng;
this._poly.redraw();
}
}
L.DomUtil.addClass(marker._icon, 'marker-snapped');
}
}
},
_snap_on_disabled: function () {
delete this._snapper;
},
};
L.Draw.Feature.include(L.Draw.Feature.SnapMixin);
L.Draw.Feature.addInitHook('_snap_initialize');
})();
!function(t,s){"object"==typeof exports&&"undefined"!=typeof module?module.exports=s():"function"==typeof define&&define.amd?define(s):t.proj4=s()}(this,function(){"use strict";function d(t,s){if(t[s])return t[s];for(var i,a=Object.keys(t),h=s.toLowerCase().replace($,""),e=-1;++e<a.length;)if((i=a[e]).toLowerCase().replace($,"")===h)return t[i]}function a(t){if("string"!=typeof t)throw new Error("not a string");this.text=t.trim(),this.level=0,this.place=0,this.root=null,this.stack=[],this.currentObject=null,this.state=st}function h(t,s,i){Array.isArray(s)&&(i.unshift(s),s=null);var a=s?{}:t,a=i.reduce(function(t,s){return e(s,t),t},a);s&&(t[s]=a)}function e(t,s){if(Array.isArray(t)){var i,a=t.shift();if("PARAMETER"===a&&(a=t.shift()),1===t.length)return Array.isArray(t[0])?(s[a]={},void e(t[0],s[a])):void(s[a]=t[0]);if(t.length)if("TOWGS84"!==a){if("AXIS"===a)return a in s||(s[a]=[]),void s[a].push(t);switch(Array.isArray(a)||(s[a]={}),a){case"UNIT":case"PRIMEM":case"VERT_DATUM":return s[a]={name:t[0].toLowerCase(),convert:t[1]},void(3===t.length&&e(t[2],s[a]));case"SPHEROID":case"ELLIPSOID":return s[a]={name:t[0],a:t[1],rf:t[2]},void(4===t.length&&e(t[3],s[a]));case"PROJECTEDCRS":case"PROJCRS":case"GEOGCS":case"GEOCCS":case"PROJCS":case"LOCAL_CS":case"GEODCRS":case"GEODETICCRS":case"GEODETICDATUM":case"EDATUM":case"ENGINEERINGDATUM":case"VERT_CS":case"VERTCRS":case"VERTICALCRS":case"COMPD_CS":case"COMPOUNDCRS":case"ENGINEERINGCRS":case"ENGCRS":case"FITTED_CS":case"LOCAL_DATUM":case"DATUM":return t[0]=["name",t[0]],void h(s,a,t);default:for(i=-1;++i<t.length;)if(!Array.isArray(t[i]))return e(t,s[a]);return h(s,a,t)}}else s[a]=t;else s[a]=!0}else s[t]=!0}function r(t){return t*rt}function n(h){function t(t){return t*(h.to_meter||1)}if("GEOGCS"===h.type?h.projName="longlat":"LOCAL_CS"===h.type?(h.projName="identity",h.local=!0):"object"==typeof h.PROJECTION?h.projName=Object.keys(h.PROJECTION)[0]:h.projName=h.PROJECTION,h.AXIS){for(var s="",i=0,a=h.AXIS.length;i<a;++i){var e=h.AXIS[i][0].toLowerCase();-1!==e.indexOf("north")?s+="n":-1!==e.indexOf("south")?s+="s":-1!==e.indexOf("east")?s+="e":-1!==e.indexOf("west")&&(s+="w")}2===s.length&&(s+="u"),3===s.length&&(h.axis=s)}h.UNIT&&(h.units=h.UNIT.name.toLowerCase(),"metre"===h.units&&(h.units="meter"),h.UNIT.convert&&("GEOGCS"===h.type?h.DATUM&&h.DATUM.SPHEROID&&(h.to_meter=h.UNIT.convert*h.DATUM.SPHEROID.a):h.to_meter=h.UNIT.convert));var n=h.GEOGCS;"GEOGCS"===h.type&&(n=h),n&&(n.DATUM?h.datumCode=n.DATUM.name.toLowerCase():h.datumCode=n.name.toLowerCase(),"d_"===h.datumCode.slice(0,2)&&(h.datumCode=h.datumCode.slice(2)),"new_zealand_geodetic_datum_1949"!==h.datumCode&&"new_zealand_1949"!==h.datumCode||(h.datumCode="nzgd49"),"wgs_1984"!==h.datumCode&&"world_geodetic_system_1984"!==h.datumCode||("Mercator_Auxiliary_Sphere"===h.PROJECTION&&(h.sphere=!0),h.datumCode="wgs84"),"_ferro"===h.datumCode.slice(-6)&&(h.datumCode=h.datumCode.slice(0,-6)),"_jakarta"===h.datumCode.slice(-8)&&(h.datumCode=h.datumCode.slice(0,-8)),~h.datumCode.indexOf("belge")&&(h.datumCode="rnb72"),n.DATUM&&n.DATUM.SPHEROID&&(h.ellps=n.DATUM.SPHEROID.name.replace("_19","").replace(/[Cc]larke\_18/,"clrk"),"international"===h.ellps.toLowerCase().slice(0,13)&&(h.ellps="intl"),h.a=n.DATUM.SPHEROID.a,h.rf=parseFloat(n.DATUM.SPHEROID.rf,10)),n.DATUM&&n.DATUM.TOWGS84&&(h.datum_params=n.DATUM.TOWGS84),~h.datumCode.indexOf("osgb_1936")&&(h.datumCode="osgb36"),~h.datumCode.indexOf("osni_1952")&&(h.datumCode="osni52"),(~h.datumCode.indexOf("tm65")||~h.datumCode.indexOf("geodetic_datum_of_1965"))&&(h.datumCode="ire65"),"ch1903+"===h.datumCode&&(h.datumCode="ch1903"),~h.datumCode.indexOf("israel")&&(h.datumCode="isr93")),h.b&&!isFinite(h.b)&&(h.b=h.a),[["standard_parallel_1","Standard_Parallel_1"],["standard_parallel_2","Standard_Parallel_2"],["false_easting","False_Easting"],["false_northing","False_Northing"],["central_meridian","Central_Meridian"],["latitude_of_origin","Latitude_Of_Origin"],["latitude_of_origin","Central_Parallel"],["scale_factor","Scale_Factor"],["k0","scale_factor"],["latitude_of_center","Latitude_Of_Center"],["latitude_of_center","Latitude_of_center"],["lat0","latitude_of_center",r],["longitude_of_center","Longitude_Of_Center"],["longitude_of_center","Longitude_of_center"],["longc","longitude_of_center",r],["x0","false_easting",t],["y0","false_northing",t],["long0","central_meridian",r],["lat0","latitude_of_origin",r],["lat0","standard_parallel_1",r],["lat1","standard_parallel_1",r],["lat2","standard_parallel_2",r],["azimuth","Azimuth"],["alpha","azimuth",r],["srsCode","name"]].forEach(function(t){return s=h,a=(i=t)[0],t=i[1],void(!(a in s)&&t in s&&(s[a]=s[t],3===i.length&&(s[a]=i[2](s[a]))));var s,i,a}),h.long0||!h.longc||"Albers_Conic_Equal_Area"!==h.projName&&"Lambert_Azimuthal_Equal_Area"!==h.projName||(h.long0=h.longc),h.lat_ts||!h.lat1||"Stereographic_South_Pole"!==h.projName&&"Polar Stereographic (variant B)"!==h.projName||(h.lat0=r(0<h.lat1?90:-90),h.lat_ts=h.lat1)}function o(t){var s=this;if(2===arguments.length){var i=arguments[1];"string"==typeof i?"+"===i.charAt(0)?o[t]=tt(arguments[1]):o[t]=ot(arguments[1]):o[t]=i}else if(1===arguments.length){if(Array.isArray(t))return t.map(function(t){Array.isArray(t)?o.apply(s,t):o(t)});if("string"==typeof t){if(t in o)return o[t]}else"EPSG"in t?o["EPSG:"+t.EPSG]=t:"ESRI"in t?o["ESRI:"+t.ESRI]=t:"IAU2000"in t?o["IAU2000:"+t.IAU2000]=t:console.log(t)}}function m(t){if("string"!=typeof t)return t;if(t in o)return o[t];var s;if(s=t,ft.some(function(t){return-1<s.indexOf(t)})){var i=ot(t);if(function(t){if(t=d(t,"authority")){t=d(t,"epsg");return t&&-1<dt.indexOf(t)}}(i))return o["EPSG:3857"];var a=function(t){if(t=d(t,"extension"))return d(t,"proj4")}(i);return a?tt(a):i}return"+"===t[0]?tt(t):void 0}function t(t){return t}function s(t,s){var i=xt.length;return t.names?((xt[i]=t).names.forEach(function(t){_t[t.toLowerCase()]=i}),this):(console.log(s),!0)}function p(t){if(0===t.length)return null;var s="@"===t[0];return s&&(t=t.slice(1)),"null"===t?{name:"null",mandatory:!s,grid:null,isNull:!0}:{name:t,mandatory:!s,grid:Nt[t]||null,isNull:!1}}function l(t){return t/3600*Math.PI/180}function c(t,s,i){return String.fromCharCode.apply(null,new Uint8Array(t.buffer.slice(s,i)))}function M(t,s,i){for(var a=[],h=0;h<s.nSubgrids;h++){var e=(o=i,{name:c(n=t,(r=176)+8,r+16).trim(),parent:c(n,r+24,r+24+8).trim(),lowerLatitude:n.getFloat64(r+72,o),upperLatitude:n.getFloat64(r+88,o),lowerLongitude:n.getFloat64(r+104,o),upperLongitude:n.getFloat64(r+120,o),latitudeInterval:n.getFloat64(r+136,o),longitudeInterval:n.getFloat64(r+152,o),gridNodeCount:n.getInt32(r+168,o)}),n=function(t,s,i,a){for(var h=s+176,e=[],n=0;n<i.gridNodeCount;n++){var r={latitudeShift:t.getFloat32(h+16*n,a),longitudeShift:t.getFloat32(h+16*n+4,a),latitudeAccuracy:t.getFloat32(h+16*n+8,a),longitudeAccuracy:t.getFloat32(h+16*n+12,a)};e.push(r)}return e}(t,176,e,i),r=Math.round(1+(e.upperLongitude-e.lowerLongitude)/e.longitudeInterval),o=Math.round(1+(e.upperLatitude-e.lowerLatitude)/e.latitudeInterval);a.push({ll:[l(e.lowerLongitude),l(e.lowerLatitude)],del:[l(e.longitudeInterval),l(e.latitudeInterval)],lim:[r,o],count:e.gridNodeCount,cvs:n.map(function(t){return[l(t.longitudeShift),l(t.latitudeShift)]})})}return a}function y(t,s){if(!(this instanceof y))return new y(t);s=s||function(t){if(t)throw t};var i,a,h,e,n,r,o,l,c,M,u,f=m(t);"object"==typeof f&&(i=y.projections.get(f.projName))?(!f.datumCode||"none"===f.datumCode||(r=d(wt,f.datumCode))&&(f.datum_params=f.datum_params||(r.towgs84?r.towgs84.split(","):null),f.ellps=r.ellipse,f.datumName=r.datumName||f.datumCode),f.k0=f.k0||1,f.axis=f.axis||"enu",f.ellps=f.ellps||"wgs84",f.lat1=f.lat1||f.lat0,o=f.a,l=f.b,c=f.rf,M=f.ellps,u=f.sphere,o||(o=(M=(M=d(bt,M))||vt).a,l=M.b,c=M.rf),c&&!l&&(l=(1-1/c)*o),(0===c||Math.abs(o-l)<W)&&(u=!0,l=o),e=(a={a:o,b:l,rf:c,sphere:u}).a,n=a.b,r=f.R_A,l=((M=e*e)-(o=n*n))/M,n=0,r?(M=(e*=1-l*(F+l*(U+l*Q)))*e,l=0):n=Math.sqrt(l),c={es:l,e:n,ep2:(M-o)/o},r=void 0===(u=f.nadgrids)?null:u.split(",").map(p),h=f.datum||(e=f.datumCode,l=f.datum_params,n=a.a,M=a.b,o=c.es,u=c.ep2,r=r,(h={}).datum_type=void 0===e||"none"===e?B:z,l&&(h.datum_params=l.map(parseFloat),0===h.datum_params[0]&&0===h.datum_params[1]&&0===h.datum_params[2]||(h.datum_type=G),3<h.datum_params.length&&(0===h.datum_params[3]&&0===h.datum_params[4]&&0===h.datum_params[5]&&0===h.datum_params[6]||(h.datum_type=L,h.datum_params[3]*=T,h.datum_params[4]*=T,h.datum_params[5]*=T,h.datum_params[6]=h.datum_params[6]/1e6+1))),r&&(h.datum_type=R,h.grids=r),h.a=n,h.b=M,h.es=o,h.ep2=u,h),mt(this,f),mt(this,i),this.a=a.a,this.b=a.b,this.rf=a.rf,this.sphere=a.sphere,this.es=c.es,this.e=c.e,this.ep2=c.ep2,this.datum=h,this.init(),s(null,this)):s(t)}function u(t,s,i){var a,h=t.x,e=t.y,n=t.z||0;if(e<-D&&-1.001*D<e)e=-D;else if(D<e&&e<1.001*D)e=D;else{if(e<-D)return{x:-1/0,y:-1/0,z:t.z};if(D<e)return{x:1/0,y:1/0,z:t.z}}return h>Math.PI&&(h-=2*Math.PI),a=Math.sin(e),t=Math.cos(e),e=a*a,{x:((e=i/Math.sqrt(1-s*e))+n)*t*Math.cos(h),y:(e+n)*t*Math.sin(h),z:(e*(1-s)+n)*a}}function f(t,s,i,a){var h,e,n,r,o,l,c,M,u,f,d,m=t.x,p=t.y,y=t.z||0,_=Math.sqrt(m*m+p*p),x=Math.sqrt(m*m+p*p+y*y);if(_/i<1e-12){if(f=0,x/i<1e-12)return d=-a,{x:t.x,y:t.y,z:t.z}}else f=Math.atan2(p,m);for(h=y/x,r=(e=_/x)*(1-s)*(n=1/Math.sqrt(1-s*(2-s)*e*e)),o=h*n,u=0;u++,M=s*(M=i/Math.sqrt(1-s*o*o))/(M+(d=_*r+y*o-M*(1-s*o*o))),M=(c=h*(n=1/Math.sqrt(1-M*(2-M)*e*e)))*r-(l=e*(1-M)*n)*o,r=l,o=c,1e-24<M*M&&u<30;);return{x:f,y:Math.atan(c/Math.abs(l)),z:d}}function _(t){return t===G||t===L}function x(t,s,i){if(null===t.grids||0===t.grids.length)return console.log("Grid shift grids not found"),-1;for(var a={x:-i.x,y:i.y},h={x:Number.NaN,y:Number.NaN},e=[],n=0;n<t.grids.length;n++){var r=t.grids[n];if(e.push(r.name),r.isNull){h=a;break}if(null!==r.grid){var o=r.grid.subgrids[0],l=(Math.abs(o.del[1])+Math.abs(o.del[0]))/1e4,c=o.ll[0]-l,M=o.ll[1]-l,u=o.ll[0]+(o.lim[0]-1)*o.del[0]+l,l=o.ll[1]+(o.lim[1]-1)*o.del[1]+l;if(!(a.y<M||a.x<c||l<a.y||u<a.x||(h=function(t,s,i){var a={x:Number.NaN,y:Number.NaN};if(isNaN(t.x))return a;var h={x:t.x,y:t.y};h.x-=i.ll[0],h.y-=i.ll[1],h.x=pt(h.x-Math.PI)+Math.PI;var e=g(h,i);if(s){if(isNaN(e.x))return a;e.x=h.x-e.x,e.y=h.y-e.y;var n,r=9;do{if(n=g(e,i),isNaN(n.x)){console.log("Inverse grid shift iteration failed, presumably at grid edge. Using first approximation.");break}}while(n={x:h.x-(n.x+e.x),y:h.y-(n.y+e.y)},e.x+=n.x,e.y+=n.y,r--&&1e-12<Math.abs(n.x)&&1e-12<Math.abs(n.y));if(r<0)return console.log("Inverse grid shift iterator failed to converge."),a;a.x=pt(e.x+i.ll[0]),a.y=e.y+i.ll[1]}else isNaN(e.x)||(a.x=t.x+e.x,a.y=t.y+e.y);return a}(a,s,o),isNaN(h.x))))break}else if(r.mandatory)return console.log("Unable to find mandatory grid '"+r.name+"'"),-1}return isNaN(h.x)?(console.log("Failed to find a grid shift table for location '"+-a.x*H+" "+a.y*H+" tried: '"+e+"'"),-1):(i.x=-h.x,i.y=h.y,0)}function g(t,s){var i={x:t.x/s.del[0],y:t.y/s.del[1]},a=Math.floor(i.x),h=Math.floor(i.y),e=i.x-+a,n=i.y-+h,r={x:Number.NaN,y:Number.NaN};if(a<0||a>=s.lim[0])return r;if(h<0||h>=s.lim[1])return r;f=h*s.lim[0]+a;var o=s.cvs[f][0],l=s.cvs[f][1];f++;var c=s.cvs[f][0],M=s.cvs[f][1];f+=s.lim[0];var u=s.cvs[f][0],t=s.cvs[f][1];f--;var i=s.cvs[f][0],h=s.cvs[f][1],a=e*n,s=e*(1-n),f=(1-e)*(1-n),n=(1-e)*n;return r.x=f*o+s*c+n*i+a*u,r.y=f*l+s*M+n*h+a*t,r}function i(t){if("function"==typeof Number.isFinite){if(Number.isFinite(t))return;throw new TypeError("coordinates must be finite numbers")}if("number"!=typeof t||t!=t||!isFinite(t))throw new TypeError("coordinates must be finite numbers")}function b(t,s,i){var a,h;if(Array.isArray(i)&&(i=St(i)),kt(i),t.datum&&s.datum&&(h=s,((a=t).datum.datum_type===G||a.datum.datum_type===L)&&"WGS84"!==h.datumCode||(h.datum.datum_type===G||h.datum.datum_type===L)&&"WGS84"!==a.datumCode)&&(i=b(t,a=new y("WGS84"),i),t=a),"enu"!==t.axis&&(i=Pt(t,!1,i)),"longlat"===t.projName)i={x:i.x*X,y:i.y*X,z:i.z||0};else if(t.to_meter&&(i={x:i.x*t.to_meter,y:i.y*t.to_meter,z:i.z||0}),!(i=t.inverse(i)))return;if(t.from_greenwich&&(i.x+=t.from_greenwich),i=Ct(t.datum,s.datum,i))return s.from_greenwich&&(i={x:i.x-s.from_greenwich,y:i.y,z:i.z||0}),"longlat"===s.projName?i={x:i.x*H,y:i.y*H,z:i.z||0}:(i=s.forward(i),s.to_meter&&(i={x:i.x/s.to_meter,y:i.y/s.to_meter,z:i.z||0})),"enu"!==s.axis?Pt(s,!0,i):i}function v(s,i,a){var h,t;return Array.isArray(a)?(t=b(s,i,a)||{x:NaN,y:NaN},2<a.length?void 0!==s.name&&"geocent"===s.name||void 0!==i.name&&"geocent"===i.name?("number"==typeof t.z?[t.x,t.y,t.z]:[t.x,t.y,a[2]]).concat(a.splice(3)):[t.x,t.y].concat(a.splice(2)):[t.x,t.y]):(h=b(s,i,a),2===(t=Object.keys(a)).length||t.forEach(function(t){if(void 0!==s.name&&"geocent"===s.name||void 0!==i.name&&"geocent"===i.name){if("x"===t||"y"===t||"z"===t)return}else if("x"===t||"y"===t)return;h[t]=a[t]}),h)}function w(t){return t instanceof y?t:t.oProj||y(t)}function N(s,i,t){s=w(s);var a=!1;return void 0===i?(i=s,s=Et,a=!0):void 0===i.x&&!Array.isArray(i)||(t=i,i=s,s=Et,a=!0),i=w(i),t?v(s,i,t):(t={forward:function(t){return v(s,i,t)},inverse:function(t){return v(i,s,t)}},a&&(t.oProj=i),t)}function C(t,s){return s=s||5,i=function(t){var s,i,a=t.lat,h=t.lon,e=S(a),n=S(h);i=Math.floor((h+180)/6)+1,180===h&&(i=60),56<=a&&a<64&&3<=h&&h<12&&(i=32),72<=a&&a<84&&(0<=h&&h<9?i=31:9<=h&&h<21?i=33:21<=h&&h<33?i=35:33<=h&&h<42&&(i=37)),r=S(6*(i-1)-180+3),s=6378137/Math.sqrt(1-.00669438*Math.sin(e)*Math.sin(e)),t=Math.tan(e)*Math.tan(e),h=.006739496752268451*Math.cos(e)*Math.cos(e);var r=.9996*s*((n=Math.cos(e)*(n-r))+(1-t+h)*n*n*n/6+(5-18*t+t*t+72*h-.39089081163157013)*n*n*n*n*n/120)+5e5,n=.9996*(6378137*(.9983242984503243*e-.002514607064228144*Math.sin(2*e)+2639046602129982e-21*Math.sin(4*e)-3.418046101696858e-9*Math.sin(6*e))+s*Math.tan(e)*(n*n/2+(5-t+9*h+4*h*h)*n*n*n*n/24+(61-58*t+t*t+600*h-2.2240339282485886)*n*n*n*n*n*n/720));return a<0&&(n+=1e7),{northing:Math.round(n),easting:Math.round(r),zoneNumber:i,zoneLetter:function(t){var s="Z";return t<=84&&72<=t?s="X":t<72&&64<=t?s="W":t<64&&56<=t?s="V":t<56&&48<=t?s="U":t<48&&40<=t?s="T":t<40&&32<=t?s="S":t<32&&24<=t?s="R":t<24&&16<=t?s="Q":t<16&&8<=t?s="P":t<8&&0<=t?s="N":t<0&&-8<=t?s="M":t<-8&&-16<=t?s="L":t<-16&&-24<=t?s="K":t<-24&&-32<=t?s="J":t<-32&&-40<=t?s="H":t<-40&&-48<=t?s="G":t<-48&&-56<=t?s="F":t<-56&&-64<=t?s="E":t<-64&&-72<=t?s="D":t<-72&&-80<=t&&(s="C"),s}(a)}}({lat:t[1],lon:t[0]}),a=s,t="00000"+i.easting,s="00000"+i.northing,i.zoneNumber+i.zoneLetter+function(t,s,i){i=I(i);return function(t,s,i){var a=i-1,h=qt.charCodeAt(a),i=At.charCodeAt(a),a=h+t-1,t=i+s,s=!1;return Rt<a&&(a=a-Rt+Ot-1,s=!0),(a===jt||h<jt&&jt<a||(jt<a||h<jt)&&s)&&a++,(a===Gt||h<Gt&&Gt<a||(Gt<a||h<Gt)&&s)&&++a===jt&&a++,Rt<a&&(a=a-Rt+Ot-1),s=Lt<t&&(t=t-Lt+Ot-1,!0),(t===jt||i<jt&&jt<t||(jt<t||i<jt)&&s)&&t++,(t===Gt||i<Gt&&Gt<t||(Gt<t||i<Gt)&&s)&&++t===jt&&t++,Lt<t&&(t=t-Lt+Ot-1),String.fromCharCode(a)+String.fromCharCode(t)}(Math.floor(t/1e5),Math.floor(s/1e5)%20,i)}(i.easting,i.northing,i.zoneNumber)+t.substr(t.length-5,a)+s.substr(s.length-5,a);var i,a}function P(t){t=E(q(t.toUpperCase()));return t.lat&&t.lon?[t.lon,t.lat]:[(t.left+t.right)/2,(t.top+t.bottom)/2]}function S(t){return t*(Math.PI/180)}function k(t){return t/Math.PI*180}function E(t){var s=t.northing,i=t.easting,a=t.zoneLetter,h=t.zoneNumber;if(h<0||60<h)return null;var e=(1-Math.sqrt(.99330562))/(1+Math.sqrt(.99330562)),n=i-5e5,r=s;a<"N"&&(r-=1e7),i=6*(h-1)-180+3,a=(s=r/.9996/6367449.145945056)+(3*e/2-27*e*e*e/32)*Math.sin(2*s)+(21*e*e/16-55*e*e*e*e/32)*Math.sin(4*s)+151*e*e*e/96*Math.sin(6*s),h=6378137/Math.sqrt(1-.00669438*Math.sin(a)*Math.sin(a)),r=Math.tan(a)*Math.tan(a),e=.006739496752268451*Math.cos(a)*Math.cos(a),s=6335439.32722994/Math.pow(1-.00669438*Math.sin(a)*Math.sin(a),1.5),n=n/(.9996*h);s=k(s=a-h*Math.tan(a)/s*(n*n/2-(5+3*r+10*e-4*e*e-.06065547077041606)*n*n*n*n/24+(61+90*r+298*e+45*r*r-1.6983531815716497-3*e*e)*n*n*n*n*n*n/720)),a=i+k(a=(n-(1+2*r+e)*n*n*n/6+(5-2*e+28*r-3*e*e+.05391597401814761+24*r*r)*n*n*n*n*n/120)/Math.cos(a));return t.accuracy?{top:(t=E({northing:t.northing+t.accuracy,easting:t.easting+t.accuracy,zoneLetter:t.zoneLetter,zoneNumber:t.zoneNumber})).lat,right:t.lon,bottom:s,left:a}:{lat:s,lon:a}}function I(t){t%=It;return 0===t&&(t=It),t}function q(t){if(t&&0===t.length)throw"MGRSPoint coverting from nothing";for(var s,i=t.length,a=null,h="",e=0;!/[A-Z]/.test(s=t.charAt(e));){if(2<=e)throw"MGRSPoint bad conversion from: "+t;h+=s,e++}var n=parseInt(h,10);if(0===e||i<e+3)throw"MGRSPoint bad conversion from: "+t;var r=t.charAt(e++);if(r<="A"||"B"===r||"Y"===r||"Z"<=r||"I"===r||"O"===r)throw"MGRSPoint zone letter "+r+" not handled: "+t;a=t.substring(e,e+=2);for(var o=I(n),l=function(t,s){for(var i=qt.charCodeAt(s-1),a=1e5,h=!1;i!==t.charCodeAt(0);){if(++i===jt&&i++,i===Gt&&i++,Rt<i){if(h)throw"Bad character: "+t;i=Ot,h=!0}a+=1e5}return a}(a.charAt(0),o),c=function(t,s){if("V"<t)throw"MGRSPoint given invalid Northing "+t;for(var i=At.charCodeAt(s-1),a=0,h=!1;i!==t.charCodeAt(0);){if(++i===jt&&i++,i===Gt&&i++,Lt<i){if(h)throw"Bad character: "+t;i=Ot,h=!0}a+=1e5}return a}(a.charAt(1),o);c<function(t){var s;switch(t){case"C":s=11e5;break;case"D":s=2e6;break;case"E":s=28e5;break;case"F":s=37e5;break;case"G":s=46e5;break;case"H":s=55e5;break;case"J":s=64e5;break;case"K":s=73e5;break;case"L":s=82e5;break;case"M":s=91e5;break;case"N":s=0;break;case"P":s=8e5;break;case"Q":s=17e5;break;case"R":s=26e5;break;case"S":s=35e5;break;case"T":s=44e5;break;case"U":s=53e5;break;case"V":s=62e5;break;case"W":s=7e6;break;case"X":s=79e5;break;default:s=-1}if(0<=s)return s;throw"Invalid zone letter: "+t}(r);)c+=2e6;var M=i-e;if(M%2!=0)throw"MGRSPoint has to have an even number \nof digits after the zone letter and two 100km letters - front \nhalf for easting meters, second half for \nnorthing meters"+t;var u,a=M/2,o=0,i=0;return 0<a&&(u=1e5/Math.pow(10,a),M=t.substring(e,e+a),o=parseFloat(M)*u,a=t.substring(e+a),i=parseFloat(a)*u),{easting:o+l,northing:i+c,zoneLetter:r,zoneNumber:n,accuracy:u}}function A(t,s,i){if(!(this instanceof A))return new A(t,s,i);var a;Array.isArray(t)?(this.x=t[0],this.y=t[1],this.z=t[2]||0):"object"==typeof t?(this.x=t.x,this.y=t.y,this.z=t.z||0):"string"==typeof t&&void 0===s?(a=t.split(","),this.x=parseFloat(a[0],10),this.y=parseFloat(a[1],10),this.z=parseFloat(a[2],10)||0):(this.x=t,this.y=s,this.z=i||0),console.warn("proj4.Point will be removed in version 3, use proj4.toPoint")}function O(t,s,i,a){var h;return t<W?(a.value=zs,h=0):(h=Math.atan2(s,i),Math.abs(h)<=J?a.value=zs:J<h&&h<=D+J?(a.value=Bs,h-=D):D+J<h||h<=-(D+J)?(a.value=Ts,h=0<=h?h-V:h+V):(a.value=Ds,h+=D)),h}function j(t,s){s=t+s;return s<-V?s+=K:+V<s&&(s-=K),s}var G=1,L=2,R=3,z=4,B=5,T=484813681109536e-20,D=Math.PI/2,F=.16666666666666666,U=.04722222222222222,Q=.022156084656084655,W=1e-10,X=.017453292519943295,H=57.29577951308232,J=Math.PI/4,K=2*Math.PI,V=3.14159265359,Z={greenwich:0,lisbon:-9.131906111111,paris:2.337229166667,bogota:-74.080916666667,madrid:-3.687938888889,rome:12.452333333333,bern:7.439583333333,jakarta:106.807719444444,ferro:-17.666666666667,brussels:4.367975,stockholm:18.058277777778,athens:23.7163375,oslo:10.722916666667},Y={ft:{to_meter:.3048},"us-ft":{to_meter:1200/3937}},$=/[\s_\-\/\(\)]/g,tt=function(t){var s,i,a,h={},e=t.split("+").map(function(t){return t.trim()}).filter(function(t){return t}).reduce(function(t,s){s=s.split("=");return s.push(!0),t[s[0].toLowerCase()]=s[1],t},{}),n={proj:"projName",datum:"datumCode",rf:function(t){h.rf=parseFloat(t)},lat_0:function(t){h.lat0=t*X},lat_1:function(t){h.lat1=t*X},lat_2:function(t){h.lat2=t*X},lat_ts:function(t){h.lat_ts=t*X},lon_0:function(t){h.long0=t*X},lon_1:function(t){h.long1=t*X},lon_2:function(t){h.long2=t*X},alpha:function(t){h.alpha=parseFloat(t)*X},gamma:function(t){h.rectified_grid_angle=parseFloat(t)},lonc:function(t){h.longc=t*X},x_0:function(t){h.x0=parseFloat(t)},y_0:function(t){h.y0=parseFloat(t)},k_0:function(t){h.k0=parseFloat(t)},k:function(t){h.k0=parseFloat(t)},a:function(t){h.a=parseFloat(t)},b:function(t){h.b=parseFloat(t)},r_a:function(){h.R_A=!0},zone:function(t){h.zone=parseInt(t,10)},south:function(){h.utmSouth=!0},towgs84:function(t){h.datum_params=t.split(",").map(function(t){return parseFloat(t)})},to_meter:function(t){h.to_meter=parseFloat(t)},units:function(t){h.units=t;t=d(Y,t);t&&(h.to_meter=t.to_meter)},from_greenwich:function(t){h.from_greenwich=t*X},pm:function(t){var s=d(Z,t);h.from_greenwich=(s||parseFloat(t))*X},nadgrids:function(t){"@null"===t?h.datumCode="none":h.nadgrids=t},axis:function(t){3===t.length&&-1!=="ewnsud".indexOf(t.substr(0,1))&&-1!=="ewnsud".indexOf(t.substr(1,1))&&-1!=="ewnsud".indexOf(t.substr(2,1))&&(h.axis=t)},approx:function(){h.approx=!0}};for(s in e)i=e[s],s in n?"function"==typeof(a=n[s])?a(i):h[a]=i:h[s]=i;return"string"==typeof h.datumCode&&"WGS84"!==h.datumCode&&(h.datumCode=h.datumCode.toLowerCase()),h},st=1,it=/\s/,at=/[A-Za-z]/,ht=/[A-Za-z84]/,et=/[,\]]/,nt=/[\d\.E\-\+]/;a.prototype.readCharicter=function(){var t=this.text[this.place++];if(4!==this.state)for(;it.test(t);){if(this.place>=this.text.length)return;t=this.text[this.place++]}switch(this.state){case st:return this.neutral(t);case 2:return this.keyword(t);case 4:return this.quoted(t);case 5:return this.afterquote(t);case 3:return this.number(t);case-1:return}},a.prototype.afterquote=function(t){if('"'===t)return this.word+='"',void(this.state=4);if(et.test(t))return this.word=this.word.trim(),void this.afterItem(t);throw new Error("havn't handled \""+t+'" in afterquote yet, index '+this.place)},a.prototype.afterItem=function(t){return","===t?(null!==this.word&&this.currentObject.push(this.word),this.word=null,void(this.state=st)):"]"===t?(this.level--,null!==this.word&&(this.currentObject.push(this.word),this.word=null),this.state=st,this.currentObject=this.stack.pop(),void(this.currentObject||(this.state=-1))):void 0},a.prototype.number=function(t){if(!nt.test(t)){if(et.test(t))return this.word=parseFloat(this.word),void this.afterItem(t);throw new Error("havn't handled \""+t+'" in number yet, index '+this.place)}this.word+=t},a.prototype.quoted=function(t){'"'!==t?this.word+=t:this.state=5},a.prototype.keyword=function(t){if(ht.test(t))this.word+=t;else{if("["===t){var s=[];return s.push(this.word),this.level++,null===this.root?this.root=s:this.currentObject.push(s),this.stack.push(this.currentObject),this.currentObject=s,void(this.state=st)}if(!et.test(t))throw new Error("havn't handled \""+t+'" in keyword yet, index '+this.place);this.afterItem(t)}},a.prototype.neutral=function(t){if(at.test(t))return this.word=t,void(this.state=2);if('"'===t)return this.word="",void(this.state=4);if(nt.test(t))return this.word=t,void(this.state=3);if(!et.test(t))throw new Error("havn't handled \""+t+'" in neutral yet, index '+this.place);this.afterItem(t)},a.prototype.output=function(){for(;this.place<this.text.length;)this.readCharicter();if(-1===this.state)return this.root;throw new Error('unable to parse string "'+this.text+'". State is '+this.state)};var rt=.017453292519943295,ot=function(t){var s=new a(t).output(),i=s.shift(),t=s.shift();s.unshift(["name",t]),s.unshift(["type",i]);i={};return e(s,i),n(i),i};(Js=o)("EPSG:4326","+title=WGS 84 (long/lat) +proj=longlat +ellps=WGS84 +datum=WGS84 +units=degrees"),Js("EPSG:4269","+title=NAD83 (long/lat) +proj=longlat +a=6378137.0 +b=6356752.31414036 +ellps=GRS80 +datum=NAD83 +units=degrees"),Js("EPSG:3857","+title=WGS 84 / Pseudo-Mercator +proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs"),Js.WGS84=Js["EPSG:4326"],Js["EPSG:3785"]=Js["EPSG:3857"],Js.GOOGLE=Js["EPSG:3857"],Js["EPSG:900913"]=Js["EPSG:3857"],Js["EPSG:102113"]=Js["EPSG:3857"];function lt(t,s,i){return s*=t,i/Math.sqrt(1-s*s)}function ct(t){return t<0?-1:1}function Mt(t,s,i){return i*=t,t*=.5,i=Math.pow((1-i)/(1+i),t),Math.tan(.5*(D-s))/i}function ut(t,s){for(var i,a=.5*t,h=D-2*Math.atan(s),e=0;e<=15;e++)if(i=t*Math.sin(h),h+=i=D-2*Math.atan(s*Math.pow((1-i)/(1+i),a))-h,Math.abs(i)<=1e-10)return h;return-9999}var ft=["PROJECTEDCRS","PROJCRS","GEOGCS","GEOCCS","PROJCS","LOCAL_CS","GEODCRS","GEODETICCRS","GEODETICDATUM","ENGCRS","ENGINEERINGCRS"],dt=["3857","900913","3785","102113"],mt=function(t,s){var i,a;if(t=t||{},!s)return t;for(a in s)void 0!==(i=s[a])&&(t[a]=i);return t},pt=function(t){return Math.abs(t)<=V?t:t-ct(t)*K},yt=[{init:function(){var t=this.b/this.a;this.es=1-t*t,"x0"in this||(this.x0=0),"y0"in this||(this.y0=0),this.e=Math.sqrt(this.es),this.lat_ts?this.sphere?this.k0=Math.cos(this.lat_ts):this.k0=lt(this.e,Math.sin(this.lat_ts),Math.cos(this.lat_ts)):this.k0||(this.k?this.k0=this.k:this.k0=1)},forward:function(t){var s,i,a=t.x,h=t.y;return 90<h*H&&h*H<-90&&180<a*H&&a*H<-180||Math.abs(Math.abs(h)-D)<=W?null:(i=this.sphere?(s=this.x0+this.a*this.k0*pt(a-this.long0),this.y0+this.a*this.k0*Math.log(Math.tan(J+.5*h))):(i=Math.sin(h),i=Mt(this.e,h,i),s=this.x0+this.a*this.k0*pt(a-this.long0),this.y0-this.a*this.k0*Math.log(i)),t.x=s,t.y=i,t)},inverse:function(t){var s,i=t.x-this.x0,a=t.y-this.y0;if(this.sphere)s=D-2*Math.atan(Math.exp(-a/(this.a*this.k0)));else{a=Math.exp(-a/(this.a*this.k0));if(-9999===(s=ut(this.e,a)))return null}return i=pt(this.long0+i/(this.a*this.k0)),t.x=i,t.y=s,t},names:["Mercator","Popular Visualisation Pseudo Mercator","Mercator_1SP","Mercator_Auxiliary_Sphere","merc"]},{init:function(){},forward:t,inverse:t,names:["longlat","identity"]}],_t={},xt=[],gt={start:function(){yt.forEach(s)},add:s,get:function(t){if(!t)return!1;t=t.toLowerCase();return void 0!==_t[t]&&xt[_t[t]]?xt[_t[t]]:void 0}},bt={MERIT:{a:6378137,rf:298.257,ellipseName:"MERIT 1983"},SGS85:{a:6378136,rf:298.257,ellipseName:"Soviet Geodetic System 85"},GRS80:{a:6378137,rf:298.257222101,ellipseName:"GRS 1980(IUGG, 1980)"},IAU76:{a:6378140,rf:298.257,ellipseName:"IAU 1976"},airy:{a:6377563.396,b:6356256.91,ellipseName:"Airy 1830"},APL4:{a:6378137,rf:298.25,ellipseName:"Appl. Physics. 1965"},NWL9D:{a:6378145,rf:298.25,ellipseName:"Naval Weapons Lab., 1965"},mod_airy:{a:6377340.189,b:6356034.446,ellipseName:"Modified Airy"},andrae:{a:6377104.43,rf:300,ellipseName:"Andrae 1876 (Den., Iclnd.)"},aust_SA:{a:6378160,rf:298.25,ellipseName:"Australian Natl & S. Amer. 1969"},GRS67:{a:6378160,rf:298.247167427,ellipseName:"GRS 67(IUGG 1967)"},bessel:{a:6377397.155,rf:299.1528128,ellipseName:"Bessel 1841"},bess_nam:{a:6377483.865,rf:299.1528128,ellipseName:"Bessel 1841 (Namibia)"},clrk66:{a:6378206.4,b:6356583.8,ellipseName:"Clarke 1866"},clrk80:{a:6378249.145,rf:293.4663,ellipseName:"Clarke 1880 mod."},clrk58:{a:6378293.645208759,rf:294.2606763692654,ellipseName:"Clarke 1858"},CPM:{a:6375738.7,rf:334.29,ellipseName:"Comm. des Poids et Mesures 1799"},delmbr:{a:6376428,rf:311.5,ellipseName:"Delambre 1810 (Belgium)"},engelis:{a:6378136.05,rf:298.2566,ellipseName:"Engelis 1985"},evrst30:{a:6377276.345,rf:300.8017,ellipseName:"Everest 1830"},evrst48:{a:6377304.063,rf:300.8017,ellipseName:"Everest 1948"},evrst56:{a:6377301.243,rf:300.8017,ellipseName:"Everest 1956"},evrst69:{a:6377295.664,rf:300.8017,ellipseName:"Everest 1969"},evrstSS:{a:6377298.556,rf:300.8017,ellipseName:"Everest (Sabah & Sarawak)"},fschr60:{a:6378166,rf:298.3,ellipseName:"Fischer (Mercury Datum) 1960"},fschr60m:{a:6378155,rf:298.3,ellipseName:"Fischer 1960"},fschr68:{a:6378150,rf:298.3,ellipseName:"Fischer 1968"},helmert:{a:6378200,rf:298.3,ellipseName:"Helmert 1906"},hough:{a:6378270,rf:297,ellipseName:"Hough"},intl:{a:6378388,rf:297,ellipseName:"International 1909 (Hayford)"},kaula:{a:6378163,rf:298.24,ellipseName:"Kaula 1961"},lerch:{a:6378139,rf:298.257,ellipseName:"Lerch 1979"},mprts:{a:6397300,rf:191,ellipseName:"Maupertius 1738"},new_intl:{a:6378157.5,b:6356772.2,ellipseName:"New International 1967"},plessis:{a:6376523,rf:6355863,ellipseName:"Plessis 1817 (France)"},krass:{a:6378245,rf:298.3,ellipseName:"Krassovsky, 1942"},SEasia:{a:6378155,b:6356773.3205,ellipseName:"Southeast Asia"},walbeck:{a:6376896,b:6355834.8467,ellipseName:"Walbeck"},WGS60:{a:6378165,rf:298.3,ellipseName:"WGS 60"},WGS66:{a:6378145,rf:298.25,ellipseName:"WGS 66"},WGS7:{a:6378135,rf:298.26,ellipseName:"WGS 72"}},vt=bt.WGS84={a:6378137,rf:298.257223563,ellipseName:"WGS 84"};bt.sphere={a:6370997,b:6370997,ellipseName:"Normal Sphere (r=6370997)"};var wt={wgs84:{towgs84:"0,0,0",ellipse:"WGS84",datumName:"WGS84"},ch1903:{towgs84:"674.374,15.056,405.346",ellipse:"bessel",datumName:"swiss"},ggrs87:{towgs84:"-199.87,74.79,246.62",ellipse:"GRS80",datumName:"Greek_Geodetic_Reference_System_1987"},nad83:{towgs84:"0,0,0",ellipse:"GRS80",datumName:"North_American_Datum_1983"},nad27:{nadgrids:"@conus,@alaska,@ntv2_0.gsb,@ntv1_can.dat",ellipse:"clrk66",datumName:"North_American_Datum_1927"},potsdam:{towgs84:"606.0,23.0,413.0",ellipse:"bessel",datumName:"Potsdam Rauenberg 1950 DHDN"},carthage:{towgs84:"-263.0,6.0,431.0",ellipse:"clark80",datumName:"Carthage 1934 Tunisia"},hermannskogel:{towgs84:"653.0,-212.0,449.0",ellipse:"bessel",datumName:"Hermannskogel"},osni52:{towgs84:"482.530,-130.596,564.557,-1.042,-0.214,-0.631,8.15",ellipse:"airy",datumName:"Irish National"},ire65:{towgs84:"482.530,-130.596,564.557,-1.042,-0.214,-0.631,8.15",ellipse:"mod_airy",datumName:"Ireland 1965"},rassadiran:{towgs84:"-133.63,-157.5,-158.62",ellipse:"intl",datumName:"Rassadiran"},nzgd49:{towgs84:"59.47,-5.04,187.44,0.47,-0.1,1.024,-4.5993",ellipse:"intl",datumName:"New Zealand Geodetic Datum 1949"},osgb36:{towgs84:"446.448,-125.157,542.060,0.1502,0.2470,0.8421,-20.4894",ellipse:"airy",datumName:"Airy 1830"},s_jtsk:{towgs84:"589,76,480",ellipse:"bessel",datumName:"S-JTSK (Ferro)"},beduaram:{towgs84:"-106,-87,188",ellipse:"clrk80",datumName:"Beduaram"},gunung_segara:{towgs84:"-403,684,41",ellipse:"bessel",datumName:"Gunung Segara Jakarta"},rnb72:{towgs84:"106.869,-52.2978,103.724,-0.33657,0.456955,-1.84218,1",ellipse:"intl",datumName:"Reseau National Belge 1972"}},Nt={};y.projections=gt,y.projections.start();var Ct=function(t,s,i){if(r=s,(n=t).datum_type===r.datum_type&&!(n.a!==r.a||5e-11<Math.abs(n.es-r.es))&&(n.datum_type===G?n.datum_params[0]===r.datum_params[0]&&n.datum_params[1]===r.datum_params[1]&&n.datum_params[2]===r.datum_params[2]:n.datum_type!==L||n.datum_params[0]===r.datum_params[0]&&n.datum_params[1]===r.datum_params[1]&&n.datum_params[2]===r.datum_params[2]&&n.datum_params[3]===r.datum_params[3]&&n.datum_params[4]===r.datum_params[4]&&n.datum_params[5]===r.datum_params[5]&&n.datum_params[6]===r.datum_params[6]))return i;if(t.datum_type===B||s.datum_type===B)return i;var a=t.a,h=t.es;if(t.datum_type===R){if(0!==x(t,!1,i))return;a=6378137,h=.0066943799901413165}var e=s.a,n=s.b,r=s.es;return s.datum_type===R&&(e=6378137,n=6356752.314,r=.0066943799901413165),h!==r||a!==e||_(t.datum_type)||_(s.datum_type)?(i=u(i,h,a),_(t.datum_type)&&(i=function(t,s,i){if(s===G)return{x:t.x+i[0],y:t.y+i[1],z:t.z+i[2]};if(s===L){var a=i[0],h=i[1],e=i[2],n=i[3],r=i[4],s=i[5],i=i[6];return{x:i*(t.x-s*t.y+r*t.z)+a,y:i*(s*t.x+t.y-n*t.z)+h,z:i*(-r*t.x+n*t.y+t.z)+e}}}(i,t.datum_type,t.datum_params)),_(s.datum_type)&&(i=function(t,s,i){if(s===G)return{x:t.x-i[0],y:t.y-i[1],z:t.z-i[2]};if(s===L){var a=i[0],h=i[1],e=i[2],n=i[3],r=i[4],s=i[5],i=i[6],a=(t.x-a)/i,h=(t.y-h)/i,i=(t.z-e)/i;return{x:a+s*h-r*i,y:-s*a+h+n*i,z:r*a-n*h+i}}}(i,s.datum_type,s.datum_params)),i=f(i,r,e,n),s.datum_type!==R||0===x(s,!0,i)?i:void 0):i},Pt=function(t,s,i){for(var a,h,e=i.x,n=i.y,r=i.z||0,o={},l=0;l<3;l++)if(!s||2!==l||void 0!==i.z)switch(h=0===l?(a=e,-1!=="ew".indexOf(t.axis[l])?"x":"y"):1===l?(a=n,-1!=="ns".indexOf(t.axis[l])?"y":"x"):(a=r,"z"),t.axis[l]){case"e":o[h]=a;break;case"w":o[h]=-a;break;case"n":o[h]=a;break;case"s":o[h]=-a;break;case"u":void 0!==i[h]&&(o.z=a);break;case"d":void 0!==i[h]&&(o.z=-a);break;default:return null}return o},St=function(t){var s={x:t[0],y:t[1]};return 2<t.length&&(s.z=t[2]),3<t.length&&(s.m=t[3]),s},kt=function(t){i(t.x),i(t.y)},Et=y("WGS84"),It=6,qt="AJSAJS",At="AFAFAF",Ot=65,jt=73,Gt=79,Lt=86,Rt=90,zt={forward:C,inverse:function(t){t=E(q(t.toUpperCase()));return t.lat&&t.lon?[t.lon,t.lat,t.lon,t.lat]:[t.left,t.bottom,t.right,t.top]},toPoint:P};A.fromMGRS=function(t){return new A(P(t))},A.prototype.toMGRS=function(t){return C([this.x,this.y],t)};function Bt(t){var s=[];s[0]=1-t*(.25+t*(.046875+t*(.01953125+t*es))),s[1]=t*(.75-t*(.046875+t*(.01953125+t*es)));var i=t*t;return s[2]=i*(.46875-t*(.013020833333333334+.007120768229166667*t)),i*=t,s[3]=i*(.3645833333333333-.005696614583333333*t),s[4]=i*t*.3076171875,s}function Tt(t,s,i,a){return i*=s,s*=s,a[0]*t-i*(a[1]+s*(a[2]+s*(a[3]+s*a[4])))}function Dt(t,s,i){for(var a=1/(1-s),h=t,e=20;e;--e){var n=Math.sin(h),r=1-s*n*n;if(h-=r=(Tt(h,n,Math.cos(h),i)-t)*(r*Math.sqrt(r))*a,Math.abs(r)<W)return h}return h}function Ft(t){return((t=Math.exp(t))-1/t)/2}function Ut(t,s){t=Math.abs(t),s=Math.abs(s);var i=Math.max(t,s),s=Math.min(t,s)/(i||1);return i*Math.sqrt(1+Math.pow(s,2))}function Qt(t){var s,i,a,h=Math.abs(t);return s=h*(1+h/(Ut(1,h)+1)),h=0==(a=(i=1+s)-1)?s:s*Math.log(i)/a,t<0?-h:h}function Wt(t,s){for(var i,a=2*Math.cos(2*s),h=t.length-1,e=t[h],n=0;0<=--h;)i=a*e-n+t[h],n=e,e=i;return s+i*Math.sin(2*s)}function Xt(t,s,i){for(var a,h,e=Math.sin(s),n=Math.cos(s),s=Ft(i),i=function(t){t=Math.exp(t);return(t+1/t)/2}(i),r=2*n*i,o=-2*e*s,l=t.length-1,c=t[l],M=0,u=0,f=0;0<=--l;)a=u,h=M,c=r*(u=c)-a-o*(M=f)+t[l],f=o*u-h+r*M;return[(r=e*i)*c-(o=n*s)*f,r*f+o*c]}function Ht(t,s){return Math.pow((1-t)/(1+t),s)}function Jt(t,s,i,a,h){return t*h-s*Math.sin(2*h)+i*Math.sin(4*h)-a*Math.sin(6*h)}function Kt(t){return 1-.25*t*(1+t/16*(3+1.25*t))}function Vt(t){return.375*t*(1+.25*t*(1+.46875*t))}function Zt(t){return.05859375*t*t*(1+.75*t)}function Yt(t){return t*t*t*(35/3072)}function $t(t,s,i){return i*=s,t/Math.sqrt(1-i*i)}function ts(t){return Math.abs(t)<D?t:t-ct(t)*Math.PI}function ss(t,s,i,a,h){for(var e,n=t/s,r=0;r<15;r++)if(n+=e=(t-(s*n-i*Math.sin(2*n)+a*Math.sin(4*n)-h*Math.sin(6*n)))/(s-2*i*Math.cos(2*n)+4*a*Math.cos(4*n)-6*h*Math.cos(6*n)),Math.abs(e)<=1e-10)return n;return NaN}function is(t,s){var i;return 1e-7<t?(1-t*t)*(s/(1-(i=t*s)*i)-.5/t*Math.log((1-i)/(1+i))):2*s}function as(t){return 1<Math.abs(t)&&(t=1<t?1:-1),Math.asin(t)}function hs(t,s){return t[0]+s*(t[1]+s*(t[2]+s*t[3]))}var es=.01068115234375,ns={init:function(){this.x0=void 0!==this.x0?this.x0:0,this.y0=void 0!==this.y0?this.y0:0,this.long0=void 0!==this.long0?this.long0:0,this.lat0=void 0!==this.lat0?this.lat0:0,this.es&&(this.en=Bt(this.es),this.ml0=Tt(this.lat0,Math.sin(this.lat0),Math.cos(this.lat0),this.en))},forward:function(t){var s=t.x,i=t.y,a=pt(s-this.long0),h=Math.sin(i),e=Math.cos(i);if(this.es){var n=e*a,r=Math.pow(n,2),o=this.ep2*Math.pow(e,2),l=Math.pow(o,2),s=Math.abs(e)>W?Math.tan(i):0,c=Math.pow(s,2),M=Math.pow(c,2),u=1-this.es*Math.pow(h,2);n/=Math.sqrt(u);s=Tt(i,h,e,this.en),u=this.a*(this.k0*n*(1+r/6*(1-c+o+r/20*(5-18*c+M+14*o-58*c*o+r/42*(61+179*M-M*c-479*c)))))+this.x0,M=this.a*(this.k0*(s-this.ml0+h*a*n/2*(1+r/12*(5-c+9*o+4*l+r/30*(61+M-58*c+270*o-330*c*o+r/56*(1385+543*M-M*c-3111*c))))))+this.y0}else{c=e*Math.sin(a);if(Math.abs(Math.abs(c)-1)<W)return 93;if(u=.5*this.a*this.k0*Math.log((1+c)/(1-c))+this.x0,M=e*Math.cos(a)/Math.sqrt(1-Math.pow(c,2)),1<=(c=Math.abs(M))){if(W<c-1)return 93;M=0}else M=Math.acos(M);i<0&&(M=-M),M=this.a*this.k0*(M-this.lat0)+this.y0}return t.x=u,t.y=M,t},inverse:function(t){var s,i,a,h,e,n,r,o,l,c,M=(t.x-this.x0)*(1/this.a),u=(t.y-this.y0)*(1/this.a);return c=this.es?(n=this.ml0+u/this.k0,s=Dt(n,this.es,this.en),Math.abs(s)<D?(r=Math.sin(s),i=Math.cos(s),o=Math.abs(i)>W?Math.tan(s):0,a=this.ep2*Math.pow(i,2),l=Math.pow(a,2),h=Math.pow(o,2),e=Math.pow(h,2),n=1-this.es*Math.pow(r,2),r=M*Math.sqrt(n)/this.k0,l=s-(n*=o)*(o=Math.pow(r,2))/(1-this.es)*.5*(1-o/12*(5+3*h-9*a*h+a-4*l-o/30*(61+90*h-252*a*h+45*e+46*a-o/56*(1385+3633*h+4095*e+1574*e*h)))),pt(this.long0+r*(1-o/6*(1+2*h+a-o/20*(5+28*h+24*e+8*a*h+6*a-o/42*(61+662*h+1320*e+720*e*h))))/i)):(l=D*ct(u),0)):(M=.5*((c=Math.exp(M/this.k0))-1/c),c=this.lat0+u/this.k0,c=Math.cos(c),n=Math.sqrt((1-Math.pow(c,2))/(1+Math.pow(M,2))),l=Math.asin(n),u<0&&(l=-l),0==M&&0===c?0:pt(Math.atan2(M,c)+this.long0)),t.x=c,t.y=l,t},names:["Fast_Transverse_Mercator","Fast Transverse Mercator"]},rs={init:function(){if(!this.approx&&(isNaN(this.es)||this.es<=0))throw new Error('Incorrect elliptical usage. Try using the +approx option in the proj string, or PROJECTION["Fast_Transverse_Mercator"] in the WKT.');this.approx&&(ns.init.apply(this),this.forward=ns.forward,this.inverse=ns.inverse),this.x0=void 0!==this.x0?this.x0:0,this.y0=void 0!==this.y0?this.y0:0,this.long0=void 0!==this.long0?this.long0:0,this.lat0=void 0!==this.lat0?this.lat0:0,this.cgb=[],this.cbg=[],this.utg=[],this.gtu=[];var t=this.es/(1+Math.sqrt(1-this.es)),s=t/(2-t),t=s;this.cgb[0]=s*(2+s*(-2/3+s*(s*(116/45+s*(26/45+-2854/675*s))-2))),this.cbg[0]=s*(s*(2/3+s*(4/3+s*(-82/45+s*(32/45+4642/4725*s))))-2),t*=s,this.cgb[1]=t*(7/3+s*(s*(-227/45+s*(2704/315+2323/945*s))-1.6)),this.cbg[1]=t*(5/3+s*(-16/15+s*(-13/9+s*(904/315+-1522/945*s)))),t*=s,this.cgb[2]=t*(56/15+s*(-136/35+s*(-1262/105+73814/2835*s))),this.cbg[2]=t*(-26/15+s*(34/21+s*(1.6+-12686/2835*s))),t*=s,this.cgb[3]=t*(4279/630+s*(-332/35+-399572/14175*s)),this.cbg[3]=t*(1237/630+s*(-24832/14175*s-2.4)),t*=s,this.cgb[4]=t*(4174/315+-144838/6237*s),this.cbg[4]=t*(-734/315+109598/31185*s),t*=s,this.cgb[5]=601676/22275*t,this.cbg[5]=444337/155925*t,t=Math.pow(s,2),this.Qn=this.k0/(1+s)*(1+t*(.25+t*(1/64+t/256))),this.utg[0]=s*(s*(2/3+s*(-37/96+s*(1/360+s*(81/512+-96199/604800*s))))-.5),this.gtu[0]=s*(.5+s*(-2/3+s*(5/16+s*(41/180+s*(-127/288+7891/37800*s))))),this.utg[1]=t*(-1/48+s*(-1/15+s*(437/1440+s*(-46/105+1118711/3870720*s)))),this.gtu[1]=t*(13/48+s*(s*(557/1440+s*(281/630+-1983433/1935360*s))-.6)),t*=s,this.utg[2]=t*(-17/480+s*(37/840+s*(209/4480+-5569/90720*s))),this.gtu[2]=t*(61/240+s*(-103/140+s*(15061/26880+167603/181440*s))),t*=s,this.utg[3]=t*(-4397/161280+s*(11/504+830251/7257600*s)),this.gtu[3]=t*(49561/161280+s*(-179/168+6601661/7257600*s)),t*=s,this.utg[4]=t*(-4583/161280+108847/3991680*s),this.gtu[4]=t*(34729/80640+-3418889/1995840*s),t*=s,this.utg[5]=-.03233083094085698*t,this.gtu[5]=.6650675310896665*t;t=Wt(this.cbg,this.lat0);this.Zb=-this.Qn*(t+function(t,s){for(var i,a=2*Math.cos(s),h=t.length-1,e=t[h],n=0;0<=--h;)i=a*e-n+t[h],n=e,e=i;return Math.sin(s)*i}(this.gtu,2*t))},forward:function(t){var s=pt(t.x-this.long0),i=t.y,i=Wt(this.cbg,i),a=Math.sin(i),h=Math.cos(i),e=Math.sin(s),n=Math.cos(s);i=Math.atan2(a,n*h),s=Math.atan2(e*h,Ut(a,h*n)),s=Qt(Math.tan(s));var r,n=Xt(this.gtu,2*i,2*s);return i+=n[0],s+=n[1],i=Math.abs(s)<=2.623395162778?(r=this.a*(this.Qn*s)+this.x0,this.a*(this.Qn*i+this.Zb)+this.y0):r=1/0,t.x=r,t.y=i,t},inverse:function(t){var s,i,a,h,e=(t.x-this.x0)*(1/this.a),n=(t.y-this.y0)*(1/this.a);return n=(n-this.Zb)/this.Qn,e/=this.Qn,n=Math.abs(e)<=2.623395162778?(n+=(a=Xt(this.utg,2*n,2*e))[0],e+=a[1],e=Math.atan(Ft(e)),s=Math.sin(n),h=Math.cos(n),i=Math.sin(e),a=Math.cos(e),n=Math.atan2(s*a,Ut(i,a*h)),e=Math.atan2(i,a*h),h=pt(e+this.long0),Wt(this.cgb,n)):h=1/0,t.x=h,t.y=n,t},names:["Extended_Transverse_Mercator","Extended Transverse Mercator","etmerc","Transverse_Mercator","Transverse Mercator","tmerc"]},os={init:function(){var t=function(t,s){if(void 0===t){if((t=Math.floor(30*(pt(s)+Math.PI)/Math.PI)+1)<0)return 0;if(60<t)return 60}return t}(this.zone,this.long0);if(void 0===t)throw new Error("unknown utm zone");this.lat0=0,this.long0=(6*Math.abs(t)-183)*X,this.x0=5e5,this.y0=this.utmSouth?1e7:0,this.k0=.9996,rs.init.apply(this),this.forward=rs.forward,this.inverse=rs.inverse},names:["Universal Transverse Mercator System","utm"],dependsOn:"etmerc"},ls={init:function(){var t=Math.sin(this.lat0),s=Math.cos(this.lat0);s*=s,this.rc=Math.sqrt(1-this.es)/(1-this.es*t*t),this.C=Math.sqrt(1+this.es*s*s/(1-this.es)),this.phic0=Math.asin(t/this.C),this.ratexp=.5*this.C*this.e,this.K=Math.tan(.5*this.phic0+J)/(Math.pow(Math.tan(.5*this.lat0+J),this.C)*Ht(this.e*t,this.ratexp))},forward:function(t){var s=t.x,i=t.y;return t.y=2*Math.atan(this.K*Math.pow(Math.tan(.5*i+J),this.C)*Ht(this.e*Math.sin(i),this.ratexp))-D,t.x=this.C*s,t},inverse:function(t){for(var s=t.x/this.C,i=t.y,a=Math.pow(Math.tan(.5*i+J)/this.K,1/this.C),h=20;0<h&&(i=2*Math.atan(a*Ht(this.e*Math.sin(t.y),-.5*this.e))-D,!(Math.abs(i-t.y)<1e-14));--h)t.y=i;return h?(t.x=s,t.y=i,t):null},names:["gauss"]},cs={init:function(){ls.init.apply(this),this.rc&&(this.sinc0=Math.sin(this.phic0),this.cosc0=Math.cos(this.phic0),this.R2=2*this.rc,this.title||(this.title="Oblique Stereographic Alternative"))},forward:function(t){var s,i,a,h;return t.x=pt(t.x-this.long0),ls.forward.apply(this,[t]),s=Math.sin(t.y),i=Math.cos(t.y),a=Math.cos(t.x),h=this.k0*this.R2/(1+this.sinc0*s+this.cosc0*i*a),t.x=h*i*Math.sin(t.x),t.y=h*(this.cosc0*s-this.sinc0*i*a),t.x=this.a*t.x+this.x0,t.y=this.a*t.y+this.y0,t},inverse:function(t){var s,i,a,h;return t.x=(t.x-this.x0)/this.a,t.y=(t.y-this.y0)/this.a,t.x/=this.k0,t.y/=this.k0,h=(s=Math.sqrt(t.x*t.x+t.y*t.y))?(a=2*Math.atan2(s,this.R2),h=Math.sin(a),i=Math.cos(a),a=Math.asin(i*this.sinc0+t.y*h*this.cosc0/s),Math.atan2(t.x*h,s*this.cosc0*i-t.y*this.sinc0*h)):(a=this.phic0,0),t.x=h,t.y=a,ls.inverse.apply(this,[t]),t.x=pt(t.x+this.long0),t},names:["Stereographic_North_Pole","Oblique_Stereographic","Polar_Stereographic","sterea","Oblique Stereographic Alternative","Double_Stereographic"]},Ms={init:function(){this.coslat0=Math.cos(this.lat0),this.sinlat0=Math.sin(this.lat0),this.sphere?1===this.k0&&!isNaN(this.lat_ts)&&Math.abs(this.coslat0)<=W&&(this.k0=.5*(1+ct(this.lat0)*Math.sin(this.lat_ts))):(Math.abs(this.coslat0)<=W&&(0<this.lat0?this.con=1:this.con=-1),this.cons=Math.sqrt(Math.pow(1+this.e,1+this.e)*Math.pow(1-this.e,1-this.e)),1===this.k0&&!isNaN(this.lat_ts)&&Math.abs(this.coslat0)<=W&&(this.k0=.5*this.cons*lt(this.e,Math.sin(this.lat_ts),Math.cos(this.lat_ts))/Mt(this.e,this.con*this.lat_ts,this.con*Math.sin(this.lat_ts))),this.ms1=lt(this.e,this.sinlat0,this.coslat0),this.X0=2*Math.atan(this.ssfn_(this.lat0,this.sinlat0,this.e))-D,this.cosX0=Math.cos(this.X0),this.sinX0=Math.sin(this.X0))},forward:function(t){var s,i,a=t.x,h=t.y,e=Math.sin(h),n=Math.cos(h),r=pt(a-this.long0);return Math.abs(Math.abs(a-this.long0)-Math.PI)<=W&&Math.abs(h+this.lat0)<=W?(t.x=NaN,t.y=NaN):this.sphere?(s=2*this.k0/(1+this.sinlat0*e+this.coslat0*n*Math.cos(r)),t.x=this.a*s*n*Math.sin(r)+this.x0,t.y=this.a*s*(this.coslat0*e-this.sinlat0*n*Math.cos(r))+this.y0):(i=2*Math.atan(this.ssfn_(h,e,this.e))-D,n=Math.cos(i),i=Math.sin(i),Math.abs(this.coslat0)<=W?(e=Mt(this.e,h*this.con,this.con*e),e=2*this.a*this.k0*e/this.cons,t.x=this.x0+e*Math.sin(a-this.long0),t.y=this.y0-this.con*e*Math.cos(a-this.long0)):(Math.abs(this.sinlat0)<W?(s=2*this.a*this.k0/(1+n*Math.cos(r)),t.y=s*i):(s=2*this.a*this.k0*this.ms1/(this.cosX0*(1+this.sinX0*i+this.cosX0*n*Math.cos(r))),t.y=s*(this.cosX0*i-this.sinX0*n*Math.cos(r))+this.y0),t.x=s*n*Math.sin(r)+this.x0)),t},inverse:function(t){t.x-=this.x0,t.y-=this.y0;var s,i,a=Math.sqrt(t.x*t.x+t.y*t.y);if(this.sphere){var h=2*Math.atan(a/(2*this.a*this.k0)),e=this.long0,n=this.lat0;return a<=W||(n=Math.asin(Math.cos(h)*this.sinlat0+t.y*Math.sin(h)*this.coslat0/a),e=pt(Math.abs(this.coslat0)<W?0<this.lat0?this.long0+Math.atan2(t.x,-1*t.y):this.long0+Math.atan2(t.x,t.y):this.long0+Math.atan2(t.x*Math.sin(h),a*this.coslat0*Math.cos(h)-t.y*this.sinlat0*Math.sin(h)))),t.x=e,t.y=n,t}if(Math.abs(this.coslat0)<=W){if(a<=W)return n=this.lat0,e=this.long0,t.x=e,t.y=n,t;t.x*=this.con,t.y*=this.con,s=a*this.cons/(2*this.a*this.k0),n=this.con*ut(this.e,s),e=this.con*pt(this.con*this.long0+Math.atan2(t.x,-1*t.y))}else s=2*Math.atan(a*this.cosX0/(2*this.a*this.k0*this.ms1)),e=this.long0,a<=W?i=this.X0:(i=Math.asin(Math.cos(s)*this.sinX0+t.y*Math.sin(s)*this.cosX0/a),e=pt(this.long0+Math.atan2(t.x*Math.sin(s),a*this.cosX0*Math.cos(s)-t.y*this.sinX0*Math.sin(s)))),n=-1*ut(this.e,Math.tan(.5*(D+i)));return t.x=e,t.y=n,t},names:["stere","Stereographic_South_Pole","Polar Stereographic (variant B)"],ssfn_:function(t,s,i){return s*=i,Math.tan(.5*(D+t))*Math.pow((1-s)/(1+s),.5*i)}},us={init:function(){var t=this.lat0;this.lambda0=this.long0;var s=Math.sin(t),i=this.a,a=1/this.rf,h=2*a-Math.pow(a,2),a=this.e=Math.sqrt(h);this.R=this.k0*i*Math.sqrt(1-h)/(1-h*Math.pow(s,2)),this.alpha=Math.sqrt(1+h/(1-h)*Math.pow(Math.cos(t),4)),this.b0=Math.asin(s/this.alpha);h=Math.log(Math.tan(Math.PI/4+this.b0/2)),t=Math.log(Math.tan(Math.PI/4+t/2)),s=Math.log((1+a*s)/(1-a*s));this.K=h-this.alpha*t+this.alpha*a/2*s},forward:function(t){var s=Math.log(Math.tan(Math.PI/4-t.y/2)),i=this.e/2*Math.log((1+this.e*Math.sin(t.y))/(1-this.e*Math.sin(t.y))),a=-this.alpha*(s+i)+this.K,s=2*(Math.atan(Math.exp(a))-Math.PI/4),i=this.alpha*(t.x-this.lambda0),a=Math.atan(Math.sin(i)/(Math.sin(this.b0)*Math.tan(s)+Math.cos(this.b0)*Math.cos(i))),i=Math.asin(Math.cos(this.b0)*Math.sin(s)-Math.sin(this.b0)*Math.cos(s)*Math.cos(i));return t.y=this.R/2*Math.log((1+Math.sin(i))/(1-Math.sin(i)))+this.y0,t.x=this.R*a+this.x0,t},inverse:function(t){for(var s,i=t.x-this.x0,a=t.y-this.y0,i=i/this.R,a=2*(Math.atan(Math.exp(a/this.R))-Math.PI/4),h=Math.asin(Math.cos(this.b0)*Math.sin(a)+Math.sin(this.b0)*Math.cos(a)*Math.cos(i)),a=Math.atan(Math.sin(i)/(Math.cos(this.b0)*Math.cos(i)-Math.sin(this.b0)*Math.tan(a))),a=this.lambda0+a/this.alpha,e=h,n=-1e3,r=0;1e-7<Math.abs(e-n);){if(20<++r)return;s=1/this.alpha*(Math.log(Math.tan(Math.PI/4+h/2))-this.K)+this.e*Math.log(Math.tan(Math.PI/4+Math.asin(this.e*Math.sin(e))/2)),n=e,e=2*Math.atan(Math.exp(s))-Math.PI/2}return t.x=a,t.y=e,t},names:["somerc"]},fs=1e-7,ds={init:function(){var t,s,i,a,h,e=0,n=0,r=0,o=0,l=0,c=0,M=0;this.no_off=(h="object"==typeof(m=this).PROJECTION?Object.keys(m.PROJECTION)[0]:m.PROJECTION,"no_uoff"in m||"no_off"in m||-1!==["Hotine_Oblique_Mercator","Hotine_Oblique_Mercator_Azimuth_Natural_Origin"].indexOf(h)),this.no_rot="no_rot"in this;var u=!1;"alpha"in this&&(u=!0);var f=!1;if("rectified_grid_angle"in this&&(f=!0),u&&(M=this.alpha),f&&(e=this.rectified_grid_angle*X),u||f)n=this.longc;else if(r=this.long1,l=this.lat1,o=this.long2,c=this.lat2,Math.abs(l-c)<=fs||(t=Math.abs(l))<=fs||Math.abs(t-D)<=fs||Math.abs(Math.abs(this.lat0)-D)<=fs||Math.abs(Math.abs(c)-D)<=fs)throw new Error;var d=1-this.es,m=Math.sqrt(d);Math.abs(this.lat0)>W?(h=Math.sin(this.lat0),i=Math.cos(this.lat0),t=1-this.es*h*h,this.B=i*i,this.B=Math.sqrt(1+this.es*this.B*this.B/d),this.A=this.B*this.k0*m/t,(i=(s=this.B*m/(i*Math.sqrt(t)))*s-1)<=0?i=0:(i=Math.sqrt(i),this.lat0<0&&(i=-i)),this.E=i+=s,this.E*=Math.pow(Mt(this.e,this.lat0,h),this.B)):(this.B=1/m,this.A=this.k0,this.E=s=i=1),u||f?(u?(a=Math.asin(Math.sin(M)/s),f||(e=M)):(a=e,M=Math.asin(s*Math.sin(a))),this.lam0=n-Math.asin(.5*(i-1/i)*Math.tan(a))/this.B):(f=Math.pow(Mt(this.e,l,Math.sin(l)),this.B),n=Math.pow(Mt(this.e,c,Math.sin(c)),this.B),i=this.E/f,l=(n-f)/(n+f),c=((c=this.E*this.E)-n*f)/(c+n*f),(t=r-o)<-Math.pi?o-=K:t>Math.pi&&(o+=K),this.lam0=pt(.5*(r+o)-Math.atan(c*Math.tan(.5*this.B*(r-o))/l)/this.B),a=Math.atan(2*Math.sin(this.B*pt(r-this.lam0))/(i-1/i)),e=M=Math.asin(s*Math.sin(a))),this.singam=Math.sin(a),this.cosgam=Math.cos(a),this.sinrot=Math.sin(e),this.cosrot=Math.cos(e),this.rB=1/this.B,this.ArB=this.A*this.rB,this.BrA=1/this.ArB,this.no_off?this.u_0=0:(this.u_0=Math.abs(this.ArB*Math.atan(Math.sqrt(s*s-1)/Math.cos(M))),this.lat0<0&&(this.u_0=-this.u_0)),i=.5*a,this.v_pole_n=this.ArB*Math.log(Math.tan(J-i)),this.v_pole_s=this.ArB*Math.log(Math.tan(J+i))},forward:function(t){var s,i,a,h,e={};if(t.x=t.x-this.lam0,Math.abs(Math.abs(t.y)-D)>W){if(s=.5*((i=this.E/Math.pow(Mt(this.e,t.y,Math.sin(t.y)),this.B))-(a=1/i)),h=.5*(i+a),i=Math.sin(this.B*t.x),h=(s*this.singam-i*this.cosgam)/h,Math.abs(Math.abs(h)-1)<W)throw new Error;h=.5*this.ArB*Math.log((1-h)/(1+h)),a=Math.cos(this.B*t.x),a=Math.abs(a)<fs?this.A*t.x:this.ArB*Math.atan2(s*this.cosgam+i*this.singam,a)}else h=0<t.y?this.v_pole_n:this.v_pole_s,a=this.ArB*t.y;return this.no_rot?(e.x=a,e.y=h):(a-=this.u_0,e.x=h*this.cosrot+a*this.sinrot,e.y=a*this.cosrot-h*this.sinrot),e.x=this.a*e.x+this.x0,e.y=this.a*e.y+this.y0,e},inverse:function(t){var s,i,a,h={};if(t.x=(t.x-this.x0)*(1/this.a),t.y=(t.y-this.y0)*(1/this.a),s=this.no_rot?(a=t.y,t.x):(a=t.x*this.cosrot-t.y*this.sinrot,t.y*this.cosrot+t.x*this.sinrot+this.u_0),t=.5*((i=Math.exp(-this.BrA*a))-1/i),a=.5*(i+1/i),a=((i=Math.sin(this.BrA*s))*this.cosgam+t*this.singam)/a,Math.abs(Math.abs(a)-1)<W)h.x=0,h.y=a<0?-D:D;else{if(h.y=this.E/Math.sqrt((1+a)/(1-a)),h.y=ut(this.e,Math.pow(h.y,1/this.B)),h.y===1/0)throw new Error;h.x=-this.rB*Math.atan2(t*this.cosgam-i*this.singam,Math.cos(this.BrA*s))}return h.x+=this.lam0,h},names:["Hotine_Oblique_Mercator","Hotine Oblique Mercator","Hotine_Oblique_Mercator_Azimuth_Natural_Origin","Hotine_Oblique_Mercator_Two_Point_Natural_Origin","Hotine_Oblique_Mercator_Azimuth_Center","Oblique_Mercator","omerc"]},ms={init:function(){var t,s,i,a,h,e;this.lat2||(this.lat2=this.lat1),this.k0||(this.k0=1),this.x0=this.x0||0,this.y0=this.y0||0,Math.abs(this.lat1+this.lat2)<W||(h=this.b/this.a,this.e=Math.sqrt(1-h*h),t=Math.sin(this.lat1),a=Math.cos(this.lat1),s=lt(this.e,t,a),i=Mt(this.e,this.lat1,t),e=Math.sin(this.lat2),h=Math.cos(this.lat2),a=lt(this.e,e,h),h=Mt(this.e,this.lat2,e),e=Mt(this.e,this.lat0,Math.sin(this.lat0)),Math.abs(this.lat1-this.lat2)>W?this.ns=Math.log(s/a)/Math.log(i/h):this.ns=t,isNaN(this.ns)&&(this.ns=t),this.f0=s/(this.ns*Math.pow(i,this.ns)),this.rh=this.a*this.f0*Math.pow(e,this.ns),this.title||(this.title="Lambert Conformal Conic"))},forward:function(t){var s=t.x,i=t.y;Math.abs(2*Math.abs(i)-Math.PI)<=W&&(i=ct(i)*(D-2*W));var a,h=Math.abs(Math.abs(i)-D);if(W<h)a=Mt(this.e,i,Math.sin(i)),a=this.a*this.f0*Math.pow(a,this.ns);else{if(i*this.ns<=0)return null;a=0}s=this.ns*pt(s-this.long0);return t.x=this.k0*(a*Math.sin(s))+this.x0,t.y=this.k0*(this.rh-a*Math.cos(s))+this.y0,t},inverse:function(t){var s,i,a=(t.x-this.x0)/this.k0,h=this.rh-(t.y-this.y0)/this.k0,e=0<this.ns?(s=Math.sqrt(a*a+h*h),1):(s=-Math.sqrt(a*a+h*h),-1),n=0;if(0!==s&&(n=Math.atan2(e*a,e*h)),0!==s||0<this.ns){if(e=1/this.ns,i=Math.pow(s/(this.a*this.f0),e),-9999===(i=ut(this.e,i)))return null}else i=-D;return n=pt(n/this.ns+this.long0),t.x=n,t.y=i,t},names:["Lambert Tangential Conformal Conic Projection","Lambert_Conformal_Conic","Lambert_Conformal_Conic_1SP","Lambert_Conformal_Conic_2SP","lcc"]},ps={init:function(){this.a=6377397.155,this.es=.006674372230614,this.e=Math.sqrt(this.es),this.lat0||(this.lat0=.863937979737193),this.long0||(this.long0=.4334234309119251),this.k0||(this.k0=.9999),this.s45=.785398163397448,this.s90=2*this.s45,this.fi0=this.lat0,this.e2=this.es,this.e=Math.sqrt(this.e2),this.alfa=Math.sqrt(1+this.e2*Math.pow(Math.cos(this.fi0),4)/(1-this.e2)),this.uq=1.04216856380474,this.u0=Math.asin(Math.sin(this.fi0)/this.alfa),this.g=Math.pow((1+this.e*Math.sin(this.fi0))/(1-this.e*Math.sin(this.fi0)),this.alfa*this.e/2),this.k=Math.tan(this.u0/2+this.s45)/Math.pow(Math.tan(this.fi0/2+this.s45),this.alfa)*this.g,this.k1=this.k0,this.n0=this.a*Math.sqrt(1-this.e2)/(1-this.e2*Math.pow(Math.sin(this.fi0),2)),this.s0=1.37008346281555,this.n=Math.sin(this.s0),this.ro0=this.k1*this.n0/Math.tan(this.s0),this.ad=this.s90-this.uq},forward:function(t){var s=t.x,i=t.y,a=pt(s-this.long0),s=Math.pow((1+this.e*Math.sin(i))/(1-this.e*Math.sin(i)),this.alfa*this.e/2),i=2*(Math.atan(this.k*Math.pow(Math.tan(i/2+this.s45),this.alfa)/s)-this.s45),s=-a*this.alfa,a=Math.asin(Math.cos(this.ad)*Math.sin(i)+Math.sin(this.ad)*Math.cos(i)*Math.cos(s)),s=Math.asin(Math.cos(i)*Math.sin(s)/Math.cos(a)),s=this.n*s,a=this.ro0*Math.pow(Math.tan(this.s0/2+this.s45),this.n)/Math.pow(Math.tan(a/2+this.s45),this.n);return t.y=a*Math.cos(s),t.x=a*Math.sin(s),this.czech||(t.y*=-1,t.x*=-1),t},inverse:function(t){var s,i,a,h,e=t.x;t.x=t.y,t.y=e,this.czech||(t.y*=-1,t.x*=-1),i=Math.sqrt(t.x*t.x+t.y*t.y),e=Math.atan2(t.y,t.x)/Math.sin(this.s0),i=2*(Math.atan(Math.pow(this.ro0/i,1/this.n)*Math.tan(this.s0/2+this.s45))-this.s45),s=Math.asin(Math.cos(this.ad)*Math.sin(i)-Math.sin(this.ad)*Math.cos(i)*Math.cos(e)),e=Math.asin(Math.cos(i)*Math.sin(e)/Math.cos(s)),t.x=this.long0-e/this.alfa,a=s,h=0;for(var n=0;t.y=2*(Math.atan(Math.pow(this.k,-1/this.alfa)*Math.pow(Math.tan(s/2+this.s45),1/this.alfa)*Math.pow((1+this.e*Math.sin(a))/(1-this.e*Math.sin(a)),this.e/2))-this.s45),Math.abs(a-t.y)<1e-10&&(h=1),a=t.y,n+=1,0===h&&n<15;);return 15<=n?null:t},names:["Krovak","krovak"]},ys={init:function(){this.sphere||(this.e0=Kt(this.es),this.e1=Vt(this.es),this.e2=Zt(this.es),this.e3=Yt(this.es),this.ml0=this.a*Jt(this.e0,this.e1,this.e2,this.e3,this.lat0))},forward:function(t){var s,i,a,h,e,n,r=t.x,o=t.y,r=pt(r-this.long0);return n=this.sphere?(e=this.a*Math.asin(Math.cos(o)*Math.sin(r)),this.a*(Math.atan2(Math.tan(o),Math.cos(r))-this.lat0)):(s=Math.sin(o),i=Math.cos(o),a=$t(this.a,this.e,s),h=Math.tan(o)*Math.tan(o),e=a*(r=r*Math.cos(o))*(1-(n=r*r)*h*(1/6-(8-h+8*(r=this.es*i*i/(1-this.es)))*n/120)),this.a*Jt(this.e0,this.e1,this.e2,this.e3,o)-this.ml0+a*s/i*n*(.5+(5-h+6*r)*n/24)),t.x=e+this.x0,t.y=n+this.y0,t},inverse:function(t){t.x-=this.x0,t.y-=this.y0;var s=t.x/this.a,i=t.y/this.a;if(this.sphere)var a=i+this.lat0,h=Math.asin(Math.sin(a)*Math.cos(s)),e=Math.atan2(Math.tan(s),Math.cos(a));else{var n=this.ml0/this.a+i,r=ss(n,this.e0,this.e1,this.e2,this.e3);if(Math.abs(Math.abs(r)-D)<=W)return t.x=this.long0,t.y=D,i<0&&(t.y*=-1),t;var o=$t(this.a,this.e,Math.sin(r)),a=o*o*o/this.a/this.a*(1-this.es),n=Math.pow(Math.tan(r),2),i=s*this.a/o,s=i*i;h=r-o*Math.tan(r)/a*i*i*(.5-(1+3*n)*i*i/24),e=i*(1-s*(n/3+(1+3*n)*n*s/15))/Math.cos(r)}return t.x=pt(e+this.long0),t.y=ts(h),t},names:["Cassini","Cassini_Soldner","cass"]},_s={init:function(){var t,s,i=Math.abs(this.lat0);if(Math.abs(i-D)<W?this.mode=this.lat0<0?this.S_POLE:this.N_POLE:Math.abs(i)<W?this.mode=this.EQUIT:this.mode=this.OBLIQ,0<this.es)switch(this.qp=is(this.e,1),this.mmf=.5/(1-this.es),this.apa=(t=this.es,(s=[])[0]=.3333333333333333*t,i=t*t,s[0]+=.17222222222222222*i,s[1]=.06388888888888888*i,i*=t,s[0]+=.10257936507936508*i,s[1]+=.0664021164021164*i,s[2]=.016415012942191543*i,s),this.mode){case this.N_POLE:case this.S_POLE:this.dd=1;break;case this.EQUIT:this.rq=Math.sqrt(.5*this.qp),this.dd=1/this.rq,this.xmf=1,this.ymf=.5*this.qp;break;case this.OBLIQ:this.rq=Math.sqrt(.5*this.qp),s=Math.sin(this.lat0),this.sinb1=is(this.e,s)/this.qp,this.cosb1=Math.sqrt(1-this.sinb1*this.sinb1),this.dd=Math.cos(this.lat0)/(Math.sqrt(1-this.es*s*s)*this.rq*this.cosb1),this.ymf=(this.xmf=this.rq)/this.dd,this.xmf*=this.dd}else this.mode===this.OBLIQ&&(this.sinph0=Math.sin(this.lat0),this.cosph0=Math.cos(this.lat0))},forward:function(t){var s,i,a,h,e,n,r,o=t.x,l=t.y,o=pt(o-this.long0);if(this.sphere){if(h=Math.sin(l),r=Math.cos(l),a=Math.cos(o),this.mode===this.OBLIQ||this.mode===this.EQUIT){if((i=this.mode===this.EQUIT?1+r*a:1+this.sinph0*h+this.cosph0*r*a)<=W)return null;s=(i=Math.sqrt(2/i))*r*Math.sin(o),i*=this.mode===this.EQUIT?h:this.cosph0*h-this.sinph0*r*a}else if(this.mode===this.N_POLE||this.mode===this.S_POLE){if(this.mode===this.N_POLE&&(a=-a),Math.abs(l+this.lat0)<W)return null;i=J-.5*l,s=(i=2*(this.mode===this.S_POLE?Math.cos(i):Math.sin(i)))*Math.sin(o),i*=a}}else{switch(r=n=e=0,a=Math.cos(o),o=Math.sin(o),h=Math.sin(l),h=is(this.e,h),this.mode!==this.OBLIQ&&this.mode!==this.EQUIT||(e=h/this.qp,n=Math.sqrt(1-e*e)),this.mode){case this.OBLIQ:r=1+this.sinb1*e+this.cosb1*n*a;break;case this.EQUIT:r=1+n*a;break;case this.N_POLE:r=D+l,h=this.qp-h;break;case this.S_POLE:r=l-D,h=this.qp+h}if(Math.abs(r)<W)return null;switch(this.mode){case this.OBLIQ:case this.EQUIT:r=Math.sqrt(2/r),i=this.mode===this.OBLIQ?this.ymf*r*(this.cosb1*e-this.sinb1*n*a):(r=Math.sqrt(2/(1+n*a)))*e*this.ymf,s=this.xmf*r*n*o;break;case this.N_POLE:case this.S_POLE:0<=h?(s=(r=Math.sqrt(h))*o,i=a*(this.mode===this.S_POLE?r:-r)):s=i=0}}return t.x=this.a*s+this.x0,t.y=this.a*i+this.y0,t},inverse:function(t){t.x-=this.x0,t.y-=this.y0;var s,i,a,h,e=t.x/this.a,n=t.y/this.a;if(this.sphere){var r=0,o=0,l=Math.sqrt(e*e+n*n);if(1<(i=.5*l))return null;switch(i=2*Math.asin(i),this.mode!==this.OBLIQ&&this.mode!==this.EQUIT||(o=Math.sin(i),r=Math.cos(i)),this.mode){case this.EQUIT:i=Math.abs(l)<=W?0:Math.asin(n*o/l),e*=o,n=r*l;break;case this.OBLIQ:i=Math.abs(l)<=W?this.lat0:Math.asin(r*this.sinph0+n*o*this.cosph0/l),e*=o*this.cosph0,n=(r-Math.sin(i)*this.sinph0)*l;break;case this.N_POLE:n=-n,i=D-i;break;case this.S_POLE:i-=D}s=0!==n||this.mode!==this.EQUIT&&this.mode!==this.OBLIQ?Math.atan2(e,n):0}else{if(h=0,this.mode===this.OBLIQ||this.mode===this.EQUIT){if(e/=this.dd,n*=this.dd,(o=Math.sqrt(e*e+n*n))<W)return t.x=this.long0,t.y=this.lat0,t;r=2*Math.asin(.5*o/this.rq),l=Math.cos(r),e*=r=Math.sin(r),n=this.mode===this.OBLIQ?(h=l*this.sinb1+n*r*this.cosb1/o,a=this.qp*h,o*this.cosb1*l-n*this.sinb1*r):(h=n*r/o,a=this.qp*h,o*l)}else if(this.mode===this.N_POLE||this.mode===this.S_POLE){if(this.mode===this.N_POLE&&(n=-n),!(a=e*e+n*n))return t.x=this.long0,t.y=this.lat0,t;h=1-a/this.qp,this.mode===this.S_POLE&&(h=-h)}s=Math.atan2(e,n),e=Math.asin(h),n=this.apa,h=e+e,i=e+n[0]*Math.sin(h)+n[1]*Math.sin(h+h)+n[2]*Math.sin(h+h+h)}return t.x=pt(this.long0+s),t.y=i,t},names:["Lambert Azimuthal Equal Area","Lambert_Azimuthal_Equal_Area","laea"],S_POLE:1,N_POLE:2,EQUIT:3,OBLIQ:4},xs={init:function(){Math.abs(this.lat1+this.lat2)<W||(this.temp=this.b/this.a,this.es=1-Math.pow(this.temp,2),this.e3=Math.sqrt(this.es),this.sin_po=Math.sin(this.lat1),this.cos_po=Math.cos(this.lat1),this.t1=this.sin_po,this.con=this.sin_po,this.ms1=lt(this.e3,this.sin_po,this.cos_po),this.qs1=is(this.e3,this.sin_po,this.cos_po),this.sin_po=Math.sin(this.lat2),this.cos_po=Math.cos(this.lat2),this.t2=this.sin_po,this.ms2=lt(this.e3,this.sin_po,this.cos_po),this.qs2=is(this.e3,this.sin_po,this.cos_po),this.sin_po=Math.sin(this.lat0),this.cos_po=Math.cos(this.lat0),this.t3=this.sin_po,this.qs0=is(this.e3,this.sin_po,this.cos_po),Math.abs(this.lat1-this.lat2)>W?this.ns0=(this.ms1*this.ms1-this.ms2*this.ms2)/(this.qs2-this.qs1):this.ns0=this.con,this.c=this.ms1*this.ms1+this.ns0*this.qs1,this.rh=this.a*Math.sqrt(this.c-this.ns0*this.qs0)/this.ns0)},forward:function(t){var s=t.x,i=t.y;this.sin_phi=Math.sin(i),this.cos_phi=Math.cos(i);var a=is(this.e3,this.sin_phi,this.cos_phi),i=this.a*Math.sqrt(this.c-this.ns0*a)/this.ns0,a=this.ns0*pt(s-this.long0),s=i*Math.sin(a)+this.x0,a=this.rh-i*Math.cos(a)+this.y0;return t.x=s,t.y=a,t},inverse:function(t){var s,i,a,h;return t.x-=this.x0,t.y=this.rh-t.y+this.y0,i=0<=this.ns0?(s=Math.sqrt(t.x*t.x+t.y*t.y),1):(s=-Math.sqrt(t.x*t.x+t.y*t.y),-1),(a=0)!==s&&(a=Math.atan2(i*t.x,i*t.y)),i=s*this.ns0/this.a,h=this.sphere?Math.asin((this.c-i*i)/(2*this.ns0)):(h=(this.c-i*i)/this.ns0,this.phi1z(this.e3,h)),a=pt(a/this.ns0+this.long0),t.x=a,t.y=h,t},names:["Albers_Conic_Equal_Area","Albers","aea"],phi1z:function(t,s){var i,a,h,e=as(.5*s);if(t<W)return e;for(var n=t*t,r=1;r<=25;r++)if(e+=h=.5*(a=1-(h=t*(i=Math.sin(e)))*h)*a/Math.cos(e)*(s/(1-n)-i/a+.5/t*Math.log((1-h)/(1+h))),Math.abs(h)<=1e-7)return e;return null}},gs={init:function(){this.sin_p14=Math.sin(this.lat0),this.cos_p14=Math.cos(this.lat0),this.infinity_dist=1e3*this.a,this.rc=1},forward:function(t){var s,i=t.x,a=t.y,h=pt(i-this.long0),e=Math.sin(a),n=Math.cos(a),i=Math.cos(h),i=0<(a=this.sin_p14*e+this.cos_p14*n*i)||Math.abs(a)<=W?(s=this.x0+ +this.a*n*Math.sin(h)/a,this.y0+ +this.a*(this.cos_p14*e-this.sin_p14*n*i)/a):(s=this.x0+this.infinity_dist*n*Math.sin(h),this.y0+this.infinity_dist*(this.cos_p14*e-this.sin_p14*n*i));return t.x=s,t.y=i,t},inverse:function(t){var s,i,a,h;return t.x=(t.x-this.x0)/this.a,t.y=(t.y-this.y0)/this.a,t.x/=this.k0,t.y/=this.k0,a=(s=Math.sqrt(t.x*t.x+t.y*t.y))?(h=Math.atan2(s,this.rc),a=Math.sin(h),i=Math.cos(h),h=as(i*this.sin_p14+t.y*a*this.cos_p14/s),a=Math.atan2(t.x*a,s*this.cos_p14*i-t.y*this.sin_p14*a),pt(this.long0+a)):(h=this.phic0,0),t.x=a,t.y=h,t},names:["gnom"]},bs={init:function(){this.sphere||(this.k0=lt(this.e,Math.sin(this.lat_ts),Math.cos(this.lat_ts)))},forward:function(t){var s,i,a=t.x,h=t.y,a=pt(a-this.long0);return i=this.sphere?(s=this.x0+this.a*a*Math.cos(this.lat_ts),this.y0+this.a*Math.sin(h)/Math.cos(this.lat_ts)):(i=is(this.e,Math.sin(h)),s=this.x0+this.a*this.k0*a,this.y0+this.a*i*.5/this.k0),t.x=s,t.y=i,t},inverse:function(t){var s,i;return t.x-=this.x0,t.y-=this.y0,this.sphere?(s=pt(this.long0+t.x/this.a/Math.cos(this.lat_ts)),i=Math.asin(t.y/this.a*Math.cos(this.lat_ts))):(i=function(t,s){var i=1-(1-t*t)/(2*t)*Math.log((1-t)/(1+t));if(Math.abs(Math.abs(s)-i)<1e-6)return s<0?-1*D:D;for(var a,h,e,n=Math.asin(.5*s),r=0;r<30;r++)if(a=Math.sin(n),h=Math.cos(n),e=t*a,n+=e=Math.pow(1-e*e,2)/(2*h)*(s/(1-t*t)-a/(1-e*e)+.5/t*Math.log((1-e)/(1+e))),Math.abs(e)<=1e-10)return n;return NaN}(this.e,2*t.y*this.k0/this.a),s=pt(this.long0+t.x/(this.a*this.k0))),t.x=s,t.y=i,t},names:["cea"]},vs={init:function(){this.x0=this.x0||0,this.y0=this.y0||0,this.lat0=this.lat0||0,this.long0=this.long0||0,this.lat_ts=this.lat_ts||0,this.title=this.title||"Equidistant Cylindrical (Plate Carre)",this.rc=Math.cos(this.lat_ts)},forward:function(t){var s=t.x,i=t.y,s=pt(s-this.long0),i=ts(i-this.lat0);return t.x=this.x0+this.a*s*this.rc,t.y=this.y0+this.a*i,t},inverse:function(t){var s=t.x,i=t.y;return t.x=pt(this.long0+(s-this.x0)/(this.a*this.rc)),t.y=ts(this.lat0+(i-this.y0)/this.a),t},names:["Equirectangular","Equidistant_Cylindrical","eqc"]},ws={init:function(){this.temp=this.b/this.a,this.es=1-Math.pow(this.temp,2),this.e=Math.sqrt(this.es),this.e0=Kt(this.es),this.e1=Vt(this.es),this.e2=Zt(this.es),this.e3=Yt(this.es),this.ml0=this.a*Jt(this.e0,this.e1,this.e2,this.e3,this.lat0)},forward:function(t){var s,i=t.x,a=t.y,h=pt(i-this.long0),i=h*Math.sin(a);return i=this.sphere?Math.abs(a)<=W?(s=this.a*h,-1*this.a*this.lat0):(s=this.a*Math.sin(i)/Math.tan(a),this.a*(ts(a-this.lat0)+(1-Math.cos(i))/Math.tan(a))):Math.abs(a)<=W?(s=this.a*h,-1*this.ml0):(s=(h=$t(this.a,this.e,Math.sin(a))/Math.tan(a))*Math.sin(i),this.a*Jt(this.e0,this.e1,this.e2,this.e3,a)-this.ml0+h*(1-Math.cos(i))),t.x=s+this.x0,t.y=i+this.y0,t},inverse:function(t){var s,i,a,h,e,n,r=t.x-this.x0,o=t.y-this.y0;if(this.sphere)if(Math.abs(o+this.a*this.lat0)<=W)s=pt(r/this.a+this.long0),i=0;else{for(var l,c=this.lat0+o/this.a,M=r*r/this.a/this.a+c*c,u=c,f=20;f;--f)if(u+=a=-1*(c*(u*(l=Math.tan(u))+1)-u-.5*(u*u+M)*l)/((u-c)/l-1),Math.abs(a)<=W){i=u;break}s=pt(this.long0+Math.asin(r*Math.tan(u)/this.a)/Math.sin(i))}else if(Math.abs(o+this.ml0)<=W)i=0,s=pt(this.long0+r/this.a);else{for(c=(this.ml0+o)/this.a,M=r*r/this.a/this.a+c*c,u=c,f=20;f;--f)if(n=this.e*Math.sin(u),h=Math.sqrt(1-n*n)*Math.tan(u),e=this.a*Jt(this.e0,this.e1,this.e2,this.e3,u),n=this.e0-2*this.e1*Math.cos(2*u)+4*this.e2*Math.cos(4*u)-6*this.e3*Math.cos(6*u),u-=a=(c*(h*(e=e/this.a)+1)-e-.5*h*(e*e+M))/(this.es*Math.sin(2*u)*(e*e+M-2*c*e)/(4*h)+(c-e)*(h*n-2/Math.sin(2*u))-n),Math.abs(a)<=W){i=u;break}h=Math.sqrt(1-this.es*Math.pow(Math.sin(i),2))*Math.tan(i),s=pt(this.long0+Math.asin(r*h/this.a)/Math.sin(i))}return t.x=s,t.y=i,t},names:["Polyconic","poly"]},Ns={init:function(){this.A=[],this.A[1]=.6399175073,this.A[2]=-.1358797613,this.A[3]=.063294409,this.A[4]=-.02526853,this.A[5]=.0117879,this.A[6]=-.0055161,this.A[7]=.0026906,this.A[8]=-.001333,this.A[9]=67e-5,this.A[10]=-34e-5,this.B_re=[],this.B_im=[],this.B_re[1]=.7557853228,this.B_im[1]=0,this.B_re[2]=.249204646,this.B_im[2]=.003371507,this.B_re[3]=-.001541739,this.B_im[3]=.04105856,this.B_re[4]=-.10162907,this.B_im[4]=.01727609,this.B_re[5]=-.26623489,this.B_im[5]=-.36249218,this.B_re[6]=-.6870983,this.B_im[6]=-1.1651967,this.C_re=[],this.C_im=[],this.C_re[1]=1.3231270439,this.C_im[1]=0,this.C_re[2]=-.577245789,this.C_im[2]=-.007809598,this.C_re[3]=.508307513,this.C_im[3]=-.112208952,this.C_re[4]=-.15094762,this.C_im[4]=.18200602,this.C_re[5]=1.01418179,this.C_im[5]=1.64497696,this.C_re[6]=1.9660549,this.C_im[6]=2.5127645,this.D=[],this.D[1]=1.5627014243,this.D[2]=.5185406398,this.D[3]=-.03333098,this.D[4]=-.1052906,this.D[5]=-.0368594,this.D[6]=.007317,this.D[7]=.0122,this.D[8]=.00394,this.D[9]=-.0013},forward:function(t){for(var s=t.x,i=t.y-this.lat0,s=s-this.long0,a=i/T*1e-5,s=s,h=1,e=0,n=1;n<=10;n++)h*=a,e+=this.A[n]*h;var r,o=e,l=s,c=1,M=0,u=0,f=0;for(n=1;n<=6;n++)r=M*o+c*l,c=c*o-M*l,M=r,u=u+this.B_re[n]*c-this.B_im[n]*M,f=f+this.B_im[n]*c+this.B_re[n]*M;return t.x=f*this.a+this.x0,t.y=u*this.a+this.y0,t},inverse:function(t){var s,i=t.x,a=t.y,i=i-this.x0,h=(a-this.y0)/this.a,e=i/this.a,n=1,r=0,o=0,l=0;for(p=1;p<=6;p++)s=r*h+n*e,n=n*h-r*e,r=s,o=o+this.C_re[p]*n-this.C_im[p]*r,l=l+this.C_im[p]*n+this.C_re[p]*r;for(var c=0;c<this.iterations;c++){for(var M,u=o,f=l,d=h,m=e,p=2;p<=6;p++)M=f*o+u*l,u=u*o-f*l,f=M,d+=(p-1)*(this.B_re[p]*u-this.B_im[p]*f),m+=(p-1)*(this.B_im[p]*u+this.B_re[p]*f);u=1,f=0;var y=this.B_re[1],_=this.B_im[1];for(p=2;p<=6;p++)M=f*o+u*l,u=u*o-f*l,f=M,y+=p*(this.B_re[p]*u-this.B_im[p]*f),_+=p*(this.B_im[p]*u+this.B_re[p]*f);var x=y*y+_*_,o=(d*y+m*_)/x,l=(m*y-d*_)/x}var g=o,a=l,b=1,v=0;for(p=1;p<=9;p++)b*=g,v+=this.D[p]*b;i=this.lat0+v*T*1e5,a=this.long0+a;return t.x=a,t.y=i,t},names:["New_Zealand_Map_Grid","nzmg"]},Cs={init:function(){},forward:function(t){var s=t.x,i=t.y,s=pt(s-this.long0),s=this.x0+this.a*s,i=this.y0+this.a*Math.log(Math.tan(Math.PI/4+i/2.5))*1.25;return t.x=s,t.y=i,t},inverse:function(t){t.x-=this.x0,t.y-=this.y0;var s=pt(this.long0+t.x/this.a),i=2.5*(Math.atan(Math.exp(.8*t.y/this.a))-Math.PI/4);return t.x=s,t.y=i,t},names:["Miller_Cylindrical","mill"]},Ps={init:function(){this.sphere?(this.n=1,this.m=0,this.es=0,this.C_y=Math.sqrt((this.m+1)/this.n),this.C_x=this.C_y/(this.m+1)):this.en=Bt(this.es)},forward:function(t){var s=t.x,i=t.y,s=pt(s-this.long0);if(this.sphere){if(this.m)for(var a=this.n*Math.sin(i),h=20;h;--h){var e=(this.m*i+Math.sin(i)-a)/(this.m+Math.cos(i));if(i-=e,Math.abs(e)<W)break}else i=1!==this.n?Math.asin(this.n*Math.sin(i)):i;l=this.a*this.C_x*s*(this.m+Math.cos(i)),o=this.a*this.C_y*i}else var n=Math.sin(i),r=Math.cos(i),o=this.a*Tt(i,n,r,this.en),l=this.a*s*r/Math.sqrt(1-this.es*n*n);return t.x=l,t.y=o,t},inverse:function(t){var s,i,a,h;return t.x-=this.x0,a=t.x/this.a,t.y-=this.y0,s=t.y/this.a,this.sphere?(s/=this.C_y,a/=this.C_x*(this.m+Math.cos(s)),this.m?s=as((this.m*s+Math.sin(s))/this.n):1!==this.n&&(s=as(Math.sin(s)/this.n)),a=pt(a+this.long0),s=ts(s)):(s=Dt(t.y/this.a,this.es,this.en),(h=Math.abs(s))<D?(h=Math.sin(s),i=this.long0+t.x*Math.sqrt(1-this.es*h*h)/(this.a*Math.cos(s)),a=pt(i)):h-W<D&&(a=this.long0)),t.x=a,t.y=s,t},names:["Sinusoidal","sinu"]},Ss={init:function(){},forward:function(t){for(var s=t.x,i=t.y,s=pt(s-this.long0),a=i,h=Math.PI*Math.sin(i);;){var e=-(a+Math.sin(a)-h)/(1+Math.cos(a));if(a+=e,Math.abs(e)<W)break}a/=2,Math.PI/2-Math.abs(i)<W&&(s=0);i=.900316316158*this.a*s*Math.cos(a)+this.x0,s=1.4142135623731*this.a*Math.sin(a)+this.y0;return t.x=i,t.y=s,t},inverse:function(t){var s;t.x-=this.x0,t.y-=this.y0,a=t.y/(1.4142135623731*this.a),.999999999999<Math.abs(a)&&(a=.999999999999),s=Math.asin(a);var i=pt(this.long0+t.x/(.900316316158*this.a*Math.cos(s)));i<-Math.PI&&(i=-Math.PI),i>Math.PI&&(i=Math.PI),a=(2*s+Math.sin(2*s))/Math.PI,1<Math.abs(a)&&(a=1);var a=Math.asin(a);return t.x=i,t.y=a,t},names:["Mollweide","moll"]},ks={init:function(){Math.abs(this.lat1+this.lat2)<W||(this.lat2=this.lat2||this.lat1,this.temp=this.b/this.a,this.es=1-Math.pow(this.temp,2),this.e=Math.sqrt(this.es),this.e0=Kt(this.es),this.e1=Vt(this.es),this.e2=Zt(this.es),this.e3=Yt(this.es),this.sinphi=Math.sin(this.lat1),this.cosphi=Math.cos(this.lat1),this.ms1=lt(this.e,this.sinphi,this.cosphi),this.ml1=Jt(this.e0,this.e1,this.e2,this.e3,this.lat1),Math.abs(this.lat1-this.lat2)<W?this.ns=this.sinphi:(this.sinphi=Math.sin(this.lat2),this.cosphi=Math.cos(this.lat2),this.ms2=lt(this.e,this.sinphi,this.cosphi),this.ml2=Jt(this.e0,this.e1,this.e2,this.e3,this.lat2),this.ns=(this.ms1-this.ms2)/(this.ml2-this.ml1)),this.g=this.ml1+this.ms1/this.ns,this.ml0=Jt(this.e0,this.e1,this.e2,this.e3,this.lat0),this.rh=this.a*(this.g-this.ml0))},forward:function(t){var s=t.x,i=t.y;i=this.sphere?this.a*(this.g-i):(a=Jt(this.e0,this.e1,this.e2,this.e3,i),this.a*(this.g-a));var a=this.ns*pt(s-this.long0),s=this.x0+i*Math.sin(a),a=this.y0+this.rh-i*Math.cos(a);return t.x=s,t.y=a,t},inverse:function(t){var s;t.x-=this.x0,t.y=this.rh-t.y+this.y0,s=0<=this.ns?(a=Math.sqrt(t.x*t.x+t.y*t.y),1):(a=-Math.sqrt(t.x*t.x+t.y*t.y),-1);var i=0;if(0!==a&&(i=Math.atan2(s*t.x,s*t.y)),this.sphere)return e=pt(this.long0+i/this.ns),h=ts(this.g-a/this.a),t.x=e,t.y=h,t;var a=this.g-a/this.a,h=ss(a,this.e0,this.e1,this.e2,this.e3),e=pt(this.long0+i/this.ns);return t.x=e,t.y=h,t},names:["Equidistant_Conic","eqdc"]},Es={init:function(){this.R=this.a},forward:function(t){var s,i=t.x,a=t.y,h=pt(i-this.long0);Math.abs(a)<=W&&(s=this.x0+this.R*h,c=this.y0);var e=as(2*Math.abs(a/Math.PI));(Math.abs(h)<=W||Math.abs(Math.abs(a)-D)<=W)&&(s=this.x0,c=0<=a?this.y0+Math.PI*this.R*Math.tan(.5*e):this.y0+Math.PI*this.R*-Math.tan(.5*e));var n=.5*Math.abs(Math.PI/h-h/Math.PI),r=n*n,o=Math.sin(e),l=Math.cos(e),i=l/(o+l-1),e=i*i,l=i*(2/o-1),o=l*l,e=Math.PI*this.R*(n*(i-o)+Math.sqrt(r*(i-o)*(i-o)-(o+r)*(e-o)))/(o+r);h<0&&(e=-e),s=this.x0+e;var i=r+i,e=Math.PI*this.R*(l*i-n*Math.sqrt((o+r)*(1+r)-i*i))/(o+r),c=0<=a?this.y0+e:this.y0-e;return t.x=s,t.y=c,t},inverse:function(t){var s,i,a,h,e,n,r;return t.x-=this.x0,t.y-=this.y0,r=Math.PI*this.R,a=(s=t.x/r)*s+(i=t.y/r)*i,r=3*(i*i/(e=-2*(n=-Math.abs(i)*(1+a))+1+2*i*i+a*a)+(2*(h=n-2*i*i+s*s)*h*h/e/e/e-9*n*h/e/e)/27)/(n=(n-h*h/3/e)/e)/(n=2*Math.sqrt(-n/3)),1<Math.abs(r)&&(r=0<=r?1:-1),r=Math.acos(r)/3,e=0<=t.y?(-n*Math.cos(r+Math.PI/3)-h/3/e)*Math.PI:-(-n*Math.cos(r+Math.PI/3)-h/3/e)*Math.PI,s=Math.abs(s)<W?this.long0:pt(this.long0+Math.PI*(a-1+Math.sqrt(1+2*(s*s-i*i)+a*a))/2/s),t.x=s,t.y=e,t},names:["Van_der_Grinten_I","VanDerGrinten","vandg"]},Is={init:function(){this.sin_p12=Math.sin(this.lat0),this.cos_p12=Math.cos(this.lat0)},forward:function(t){var s,i,a,h,e,n,r=t.x,o=t.y,l=Math.sin(t.y),c=Math.cos(t.y),M=pt(r-this.long0);return this.sphere?Math.abs(this.sin_p12-1)<=W?(t.x=this.x0+this.a*(D-o)*Math.sin(M),t.y=this.y0-this.a*(D-o)*Math.cos(M)):Math.abs(this.sin_p12+1)<=W?(t.x=this.x0+this.a*(D+o)*Math.sin(M),t.y=this.y0+this.a*(D+o)*Math.cos(M)):(e=this.sin_p12*l+this.cos_p12*c*Math.cos(M),h=(a=Math.acos(e))?a/Math.sin(a):1,t.x=this.x0+this.a*h*c*Math.sin(M),t.y=this.y0+this.a*h*(this.cos_p12*l-this.sin_p12*c*Math.cos(M))):(s=Kt(this.es),r=Vt(this.es),e=Zt(this.es),h=Yt(this.es),Math.abs(this.sin_p12-1)<=W?(i=this.a*Jt(s,r,e,h,D),n=this.a*Jt(s,r,e,h,o),t.x=this.x0+(i-n)*Math.sin(M),t.y=this.y0-(i-n)*Math.cos(M)):Math.abs(this.sin_p12+1)<=W?(i=this.a*Jt(s,r,e,h,D),n=this.a*Jt(s,r,e,h,o),t.x=this.x0+(i+n)*Math.sin(M),t.y=this.y0+(i+n)*Math.cos(M)):(o=l/c,i=$t(this.a,this.e,this.sin_p12),n=$t(this.a,this.e,l),l=Math.atan((1-this.es)*o+this.es*i*this.sin_p12/(n*c)),n=0===(o=Math.atan2(Math.sin(M),this.cos_p12*Math.tan(l)-this.sin_p12*Math.cos(M)))?Math.asin(this.cos_p12*Math.sin(l)-this.sin_p12*Math.cos(l)):Math.abs(Math.abs(o)-Math.PI)<=W?-Math.asin(this.cos_p12*Math.sin(l)-this.sin_p12*Math.cos(l)):Math.asin(Math.sin(M)*Math.cos(l)/Math.sin(o)),c=this.e*this.sin_p12/Math.sqrt(1-this.es),a=i*n*(1-(M=n*n)*(i=(l=this.e*this.cos_p12*Math.cos(o)/Math.sqrt(1-this.es))*l)*(1-i)/6+(M=M*n)/8*(l=c*l)*(1-2*i)+(M=M*n)/120*(i*(4-7*i)-3*c*c*(1-7*i))-M*n/48*l),t.x=this.x0+a*Math.sin(o),t.y=this.y0+a*Math.cos(o))),t},inverse:function(t){var s,i,a,h,e,n,r,o;return t.x-=this.x0,t.y-=this.y0,this.sphere?(s=Math.sqrt(t.x*t.x+t.y*t.y))>2*D*this.a?void 0:(r=s/this.a,o=Math.sin(r),n=Math.cos(r),i=this.long0,Math.abs(s)<=W?a=this.lat0:(a=as(n*this.sin_p12+t.y*o*this.cos_p12/s),e=Math.abs(this.lat0)-D,i=pt(Math.abs(e)<=W?0<=this.lat0?this.long0+Math.atan2(t.x,-t.y):this.long0-Math.atan2(-t.x,t.y):this.long0+Math.atan2(t.x*o,s*this.cos_p12*n-t.y*this.sin_p12*o))),t.x=i,t.y=a,t):(r=Kt(this.es),e=Vt(this.es),n=Zt(this.es),o=Yt(this.es),Math.abs(this.sin_p12-1)<=W?(h=this.a*Jt(r,e,n,o,D),s=Math.sqrt(t.x*t.x+t.y*t.y),a=ss((h-s)/this.a,r,e,n,o),i=pt(this.long0+Math.atan2(t.x,-1*t.y))):Math.abs(this.sin_p12+1)<=W?(h=this.a*Jt(r,e,n,o,D),s=Math.sqrt(t.x*t.x+t.y*t.y),a=ss((s-h)/this.a,r,e,n,o),i=pt(this.long0+Math.atan2(t.x,t.y))):(s=Math.sqrt(t.x*t.x+t.y*t.y),h=Math.atan2(t.x,t.y),r=$t(this.a,this.e,this.sin_p12),e=Math.cos(h),o=-(n=this.e*this.cos_p12*e)*n/(1-this.es),n=3*this.es*(1-o)*this.sin_p12*this.cos_p12*e/(1-this.es),r=1-o*(o=(r=s/r)-o*(1+o)*Math.pow(r,3)/6-n*(1+3*o)*Math.pow(r,4)/24)*o/2-r*o*o*o/6,e=Math.asin(this.sin_p12*Math.cos(o)+this.cos_p12*Math.sin(o)*e),i=pt(this.long0+Math.asin(Math.sin(h)*Math.sin(o)/Math.cos(e))),o=Math.sin(e),a=Math.atan2((o-this.es*r*this.sin_p12)*Math.tan(e),o*(1-this.es))),t.x=i,t.y=a,t)},names:["Azimuthal_Equidistant","aeqd"]},qs={init:function(){this.sin_p14=Math.sin(this.lat0),this.cos_p14=Math.cos(this.lat0)},forward:function(t){var s,i,a=t.x,h=t.y,e=pt(a-this.long0),n=Math.sin(h),r=Math.cos(h),a=Math.cos(e);return(0<(h=this.sin_p14*n+this.cos_p14*r*a)||Math.abs(h)<=W)&&(s=+this.a*r*Math.sin(e),i=this.y0+ +this.a*(this.cos_p14*n-this.sin_p14*r*a)),t.x=s,t.y=i,t},inverse:function(t){var s,i,a,h,e,n;return t.x-=this.x0,t.y-=this.y0,s=Math.sqrt(t.x*t.x+t.y*t.y),h=as(s/this.a),i=Math.sin(h),a=Math.cos(h),e=this.long0,Math.abs(s)<=W?n=this.lat0:(n=as(a*this.sin_p14+t.y*i*this.cos_p14/s),h=Math.abs(this.lat0)-D,e=Math.abs(h)<=W?pt(0<=this.lat0?this.long0+Math.atan2(t.x,-t.y):this.long0-Math.atan2(-t.x,t.y)):pt(this.long0+Math.atan2(t.x*i,s*this.cos_p14*a-t.y*this.sin_p14*i))),t.x=e,t.y=n,t},names:["ortho"]},As=1,Os=2,js=3,Gs=4,Ls=5,Rs=6,zs=1,Bs=2,Ts=3,Ds=4,Fs={init:function(){this.x0=this.x0||0,this.y0=this.y0||0,this.lat0=this.lat0||0,this.long0=this.long0||0,this.lat_ts=this.lat_ts||0,this.title=this.title||"Quadrilateralized Spherical Cube",this.lat0>=D-J/2?this.face=Ls:this.lat0<=-(D-J/2)?this.face=Rs:Math.abs(this.long0)<=J?this.face=As:Math.abs(this.long0)<=D+J?this.face=0<this.long0?Os:Gs:this.face=js,0!==this.es&&(this.one_minus_f=1-(this.a-this.b)/this.a,this.one_minus_f_squared=this.one_minus_f*this.one_minus_f)},forward:function(t){var s,i,a,h,e,n,r,o={x:0,y:0},l={value:0};return t.x-=this.long0,r=0!==this.es?Math.atan(this.one_minus_f_squared*Math.tan(t.y)):t.y,s=t.x,this.face===Ls?(i=D-r,a=J<=s&&s<=D+J?(l.value=zs,s-D):D+J<s||s<=-(D+J)?(l.value=Bs,0<s?s-V:s+V):-(D+J)<s&&s<=-J?(l.value=Ts,s+D):(l.value=Ds,s)):this.face===Rs?(i=D+r,a=J<=s&&s<=D+J?(l.value=zs,D-s):s<J&&-J<=s?(l.value=Bs,-s):s<-J&&-(D+J)<=s?(l.value=Ts,-s-D):(l.value=Ds,0<s?V-s:-s-V)):(this.face===Os?s=j(s,+D):this.face===js?s=j(s,+V):this.face===Gs&&(s=j(s,-D)),e=Math.sin(r),n=Math.cos(r),r=Math.sin(s),h=n*Math.cos(s),r=n*r,e=e,this.face===As?a=O(i=Math.acos(h),e,r,l):this.face===Os?a=O(i=Math.acos(r),e,-h,l):this.face===js?a=O(i=Math.acos(-h),e,-r,l):this.face===Gs?a=O(i=Math.acos(-r),e,h,l):(i=a=0,l.value=zs)),h=Math.atan(12/V*(a+Math.acos(Math.sin(a)*Math.cos(J))-D)),a=Math.sqrt((1-Math.cos(i))/(Math.cos(h)*Math.cos(h))/(1-Math.cos(Math.atan(1/Math.cos(a))))),l.value===Bs?h+=D:l.value===Ts?h+=V:l.value===Ds&&(h+=1.5*V),o.x=a*Math.cos(h),o.y=a*Math.sin(h),o.x=o.x*this.a+this.x0,o.y=o.y*this.a+this.y0,t.x=o.x,t.y=o.y,t},inverse:function(t){var s,i,a,h,e,n,r,o={lam:0,phi:0},l={value:0};return t.x=(t.x-this.x0)/this.a,t.y=(t.y-this.y0)/this.a,i=Math.atan(Math.sqrt(t.x*t.x+t.y*t.y)),s=Math.atan2(t.y,t.x),0<=t.x&&t.x>=Math.abs(t.y)?l.value=zs:0<=t.y&&t.y>=Math.abs(t.x)?(l.value=Bs,s-=D):t.x<0&&-t.x>=Math.abs(t.y)?(l.value=Ts,s=s<0?s+V:s-V):(l.value=Ds,s+=D),e=V/12*Math.tan(s),h=Math.sin(e)/(Math.cos(e)-1/Math.sqrt(2)),h=Math.atan(h),(i=1-(s=Math.cos(s))*s*(i=Math.tan(i))*i*(1-Math.cos(Math.atan(1/Math.cos(h)))))<-1?i=-1:1<i&&(i=1),this.face===Ls?(a=Math.acos(i),o.phi=D-a,l.value===zs?o.lam=h+D:l.value===Bs?o.lam=h<0?h+V:h-V:l.value===Ts?o.lam=h-D:o.lam=h):this.face===Rs?(a=Math.acos(i),o.phi=a-D,l.value===zs?o.lam=D-h:l.value===Bs?o.lam=-h:l.value===Ts?o.lam=-h-D:o.lam=h<0?-h-V:V-h):(e=(r=i)*r,n=1<=(e+=(h=1<=e?0:Math.sqrt(1-e)*Math.sin(h))*h)?0:Math.sqrt(1-e),l.value===Bs?(e=n,n=-h,h=e):l.value===Ts?(n=-n,h=-h):l.value===Ds&&(e=n,n=h,h=-e),this.face===Os?(e=r,r=-n,n=e):this.face===js?(r=-r,n=-n):this.face===Gs&&(e=r,r=n,n=-e),o.phi=Math.acos(-h)-D,o.lam=Math.atan2(n,r),this.face===Os?o.lam=j(o.lam,-D):this.face===js?o.lam=j(o.lam,-V):this.face===Gs&&(o.lam=j(o.lam,+D))),0!==this.es&&(n=o.phi<0?1:0,r=Math.tan(o.phi),r=this.b/Math.sqrt(r*r+this.one_minus_f_squared),o.phi=Math.atan(Math.sqrt(this.a*this.a-r*r)/(this.one_minus_f*r)),n&&(o.phi=-o.phi)),o.lam+=this.long0,t.x=o.lam,t.y=o.phi,t},names:["Quadrilateralized Spherical Cube","Quadrilateralized_Spherical_Cube","qsc"]},Us=[[1,22199e-21,-715515e-10,31103e-10],[.9986,-482243e-9,-24897e-9,-13309e-10],[.9954,-83103e-8,-448605e-10,-9.86701e-7],[.99,-.00135364,-59661e-9,36777e-10],[.9822,-.00167442,-449547e-11,-572411e-11],[.973,-.00214868,-903571e-10,1.8736e-8],[.96,-.00305085,-900761e-10,164917e-11],[.9427,-.00382792,-653386e-10,-26154e-10],[.9216,-.00467746,-10457e-8,481243e-11],[.8962,-.00536223,-323831e-10,-543432e-11],[.8679,-.00609363,-113898e-9,332484e-11],[.835,-.00698325,-640253e-10,9.34959e-7],[.7986,-.00755338,-500009e-10,9.35324e-7],[.7597,-.00798324,-35971e-9,-227626e-11],[.7186,-.00851367,-701149e-10,-86303e-10],[.6732,-.00986209,-199569e-9,191974e-10],[.6213,-.010418,883923e-10,624051e-11],[.5722,-.00906601,182e-6,624051e-11],[.5322,-.00677797,275608e-9,624051e-11]],Qs=[[-520417e-23,.0124,121431e-23,-845284e-16],[.062,.0124,-1.26793e-9,4.22642e-10],[.124,.0124,5.07171e-9,-1.60604e-9],[.186,.0123999,-1.90189e-8,6.00152e-9],[.248,.0124002,7.10039e-8,-2.24e-8],[.31,.0123992,-2.64997e-7,8.35986e-8],[.372,.0124029,9.88983e-7,-3.11994e-7],[.434,.0123893,-369093e-11,-4.35621e-7],[.4958,.0123198,-102252e-10,-3.45523e-7],[.5571,.0121916,-154081e-10,-5.82288e-7],[.6176,.0119938,-241424e-10,-5.25327e-7],[.6769,.011713,-320223e-10,-5.16405e-7],[.7346,.0113541,-397684e-10,-6.09052e-7],[.7903,.0109107,-489042e-10,-104739e-11],[.8435,.0103431,-64615e-9,-1.40374e-9],[.8936,.00969686,-64636e-9,-8547e-9],[.9394,.00840947,-192841e-9,-42106e-10],[.9761,.00616527,-256e-6,-42106e-10],[1,.00328947,-319159e-9,-42106e-10]],Ws=H/5,Xs=1/Ws,Hs={init:function(){this.x0=this.x0||0,this.y0=this.y0||0,this.long0=this.long0||0,this.es=0,this.title=this.title||"Robinson"},forward:function(t){var s=pt(t.x-this.long0),i=Math.abs(t.y),a=Math.floor(i*Ws);a<0?a=0:18<=a&&(a=17);i={x:hs(Us[a],i=H*(i-Xs*a))*s,y:hs(Qs[a],i)};return t.y<0&&(i.y=-i.y),i.x=i.x*this.a*.8487+this.x0,i.y=i.y*this.a*1.3523+this.y0,i},inverse:function(t){var i={x:(t.x-this.x0)/(.8487*this.a),y:Math.abs(t.y-this.y0)/(1.3523*this.a)};if(1<=i.y)i.x/=Us[18][0],i.y=t.y<0?-D:D;else{var s=Math.floor(18*i.y);for(s<0?s=0:18<=s&&(s=17);;)if(Qs[s][0]>i.y)--s;else{if(!(Qs[s+1][0]<=i.y))break;++s}var a=Qs[s],h=function(t,s,i,a){for(var h=s;a;--a){var e=t(h);if(h-=e,Math.abs(e)<i)break}return h}(function(t){return(hs(a,t)-i.y)/(s=t,(t=a)[1]+s*(2*t[2]+3*s*t[3]));var s},h=5*(i.y-a[0])/(Qs[s+1][0]-a[0]),W,100);i.x/=hs(Us[s],h),i.y=(5*s+h)*X,t.y<0&&(i.y=-i.y)}return i.x=pt(i.x+this.long0),i},names:["Robinson","robin"]},Js={init:function(){this.name="geocent"},forward:function(t){return u(t,this.es,this.a)},inverse:function(t){return f(t,this.es,this.a,this.b)},names:["Geocentric","geocentric","geocent","Geocent"]},Ks=0,Vs=1,Zs=2,Ys=3,$s={h:{def:1e5,num:!0},azi:{def:0,num:!0,degrees:!0},tilt:{def:0,num:!0,degrees:!0},long0:{def:0,num:!0},lat0:{def:0,num:!0}},gt={init:function(){if(Object.keys($s).forEach(function(t){if(void 0===this[t])this[t]=$s[t].def;else{if($s[t].num&&isNaN(this[t]))throw new Error("Invalid parameter value, must be numeric "+t+" = "+this[t]);$s[t].num&&(this[t]=parseFloat(this[t]))}$s[t].degrees&&(this[t]=this[t]*X)}.bind(this)),Math.abs(Math.abs(this.lat0)-D)<W?this.mode=this.lat0<0?Vs:Ks:Math.abs(this.lat0)<W?this.mode=Zs:(this.mode=Ys,this.sinph0=Math.sin(this.lat0),this.cosph0=Math.cos(this.lat0)),this.pn1=this.h/this.a,this.pn1<=0||1e10<this.pn1)throw new Error("Invalid height");this.p=1+this.pn1,this.rp=1/this.p,this.h1=1/this.pn1,this.pfact=(this.p+1)*this.h1,this.es=0;var t=this.tilt,s=this.azi;this.cg=Math.cos(s),this.sg=Math.sin(s),this.cw=Math.cos(t),this.sw=Math.sin(t)},forward:function(t){t.x-=this.long0;var s,i,a=Math.sin(t.y),h=Math.cos(t.y),e=Math.cos(t.x);switch(this.mode){case Ys:i=this.sinph0*a+this.cosph0*h*e;break;case Zs:i=h*e;break;case Vs:i=-a;break;case Ks:i=a}switch(s=(i=this.pn1/(this.p-i))*h*Math.sin(t.x),this.mode){case Ys:i*=this.cosph0*a-this.sinph0*h*e;break;case Zs:i*=a;break;case Ks:i*=-h*e;break;case Vs:i*=h*e}return e=1/((h=i*this.cg+s*this.sg)*this.sw*this.h1+this.cw),s=(s*this.cg-i*this.sg)*this.cw*e,i=h*e,t.x=s*this.a,t.y=i*this.a,t},inverse:function(t){t.x/=this.a,t.y/=this.a;var s={x:t.x,y:t.y},i=1/(this.pn1-t.y*this.sw),a=this.pn1*t.x*i,h=this.pn1*t.y*this.cw*i;t.x=a*this.cg+h*this.sg,t.y=h*this.cg-a*this.sg;i=Ut(t.x,t.y);if(Math.abs(i)<W)s.x=0,s.y=t.y;else{h=1-i*i*this.pfact;switch(h=(this.p-Math.sqrt(h))/(this.pn1/i+i/this.pn1),a=Math.sqrt(1-h*h),this.mode){case Ys:s.y=Math.asin(a*this.sinph0+t.y*h*this.cosph0/i),t.y=(a-this.sinph0*Math.sin(s.y))*i,t.x*=h*this.cosph0;break;case Zs:s.y=Math.asin(t.y*h/i),t.y=a*i,t.x*=h;break;case Ks:s.y=Math.asin(a),t.y=-t.y;break;case Vs:s.y=-Math.asin(a)}s.x=Math.atan2(t.x,t.y)}return t.x=s.x+this.long0,t.y=s.y,t},names:["Tilted_Perspective","tpers"]};return N.defaultDatum="WGS84",N.Proj=y,N.WGS84=new N.Proj("WGS84"),N.Point=A,N.toPoint=St,N.defs=o,N.nadgrid=function(t,s){var i,a=new DataView(s),h=11!==(i=a).getInt32(8,!1)&&(11!==i.getInt32(8,!0)&&console.warn("Failed to detect nadgrid endian-ness, defaulting to little-endian"),!0),s=(s=h,{nFields:(i=a).getInt32(8,s),nSubgridFields:i.getInt32(24,s),nSubgrids:i.getInt32(40,s),shiftType:c(i,56,64).trim(),fromSemiMajorAxis:i.getFloat64(120,s),fromSemiMinorAxis:i.getFloat64(136,s),toSemiMajorAxis:i.getFloat64(152,s),toSemiMinorAxis:i.getFloat64(168,s)});1<s.nSubgrids&&console.log("Only single NTv2 subgrids are currently supported, subsequent sub grids are ignored");h={header:s,subgrids:M(a,s,h)};return Nt[t]=h},N.transform=b,N.mgrs=zt,N.version="2.7.2",(zt=N).Proj.projections.add(ns),zt.Proj.projections.add(rs),zt.Proj.projections.add(os),zt.Proj.projections.add(cs),zt.Proj.projections.add(Ms),zt.Proj.projections.add(us),zt.Proj.projections.add(ds),zt.Proj.projections.add(ms),zt.Proj.projections.add(ps),zt.Proj.projections.add(ys),zt.Proj.projections.add(_s),zt.Proj.projections.add(xs),zt.Proj.projections.add(gs),zt.Proj.projections.add(bs),zt.Proj.projections.add(vs),zt.Proj.projections.add(ws),zt.Proj.projections.add(Ns),zt.Proj.projections.add(Cs),zt.Proj.projections.add(Ps),zt.Proj.projections.add(Ss),zt.Proj.projections.add(ks),zt.Proj.projections.add(Es),zt.Proj.projections.add(Is),zt.Proj.projections.add(qs),zt.Proj.projections.add(Fs),zt.Proj.projections.add(Hs),zt.Proj.projections.add(Js),zt.Proj.projections.add(gt),N});
\ No newline at end of file
/***
Spectrum Colorpicker v1.3.4
https://github.com/bgrins/spectrum
Author: Brian Grinstead
License: MIT
***/
.sp-container {
position:absolute;
top:0;
left:0;
display:inline-block;
*display: inline;
*zoom: 1;
/* https://github.com/bgrins/spectrum/issues/40 */
z-index: 9999994;
overflow: hidden;
}
.sp-container.sp-flat {
position: relative;
}
/* Fix for * { box-sizing: border-box; } */
.sp-container,
.sp-container * {
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box;
}
/* http://ansciath.tumblr.com/post/7347495869/css-aspect-ratio */
.sp-top {
position:relative;
width: 100%;
display:inline-block;
}
.sp-top-inner {
position:absolute;
top:0;
left:0;
bottom:0;
right:0;
}
.sp-color {
position: absolute;
top:0;
left:0;
bottom:0;
right:20%;
}
.sp-hue {
position: absolute;
top:0;
right:0;
bottom:0;
left:84%;
height: 100%;
}
.sp-clear-enabled .sp-hue {
top:33px;
height: 77.5%;
}
.sp-fill {
padding-top: 80%;
}
.sp-sat, .sp-val {
position: absolute;
top:0;
left:0;
right:0;
bottom:0;
}
.sp-alpha-enabled .sp-top {
margin-bottom: 18px;
}
.sp-alpha-enabled .sp-alpha {
display: block;
}
.sp-alpha-handle {
position:absolute;
top:-4px;
bottom: -4px;
width: 6px;
left: 50%;
cursor: pointer;
border: 1px solid black;
background: white;
opacity: .8;
}
.sp-alpha {
display: none;
position: absolute;
bottom: -14px;
right: 0;
left: 0;
height: 8px;
}
.sp-alpha-inner {
border: solid 1px #333;
}
.sp-clear {
display: none;
}
.sp-clear.sp-clear-display {
background-position: center;
}
.sp-clear-enabled .sp-clear {
display: block;
position:absolute;
top:0px;
right:0;
bottom:0;
left:84%;
height: 28px;
}
/* Don't allow text selection */
.sp-container, .sp-replacer, .sp-preview, .sp-dragger, .sp-slider, .sp-alpha, .sp-clear, .sp-alpha-handle, .sp-container.sp-dragging .sp-input, .sp-container button {
-webkit-user-select:none;
-moz-user-select: -moz-none;
-o-user-select:none;
user-select: none;
}
.sp-container.sp-input-disabled .sp-input-container {
display: none;
}
.sp-container.sp-buttons-disabled .sp-button-container {
display: none;
}
.sp-palette-only .sp-picker-container {
display: none;
}
.sp-palette-disabled .sp-palette-container {
display: none;
}
.sp-initial-disabled .sp-initial {
display: none;
}
/* Gradients for hue, saturation and value instead of images. Not pretty... but it works */
.sp-sat {
background-image: -webkit-gradient(linear, 0 0, 100% 0, from(#FFF), to(rgba(204, 154, 129, 0)));
background-image: -webkit-linear-gradient(left, #FFF, rgba(204, 154, 129, 0));
background-image: -moz-linear-gradient(left, #fff, rgba(204, 154, 129, 0));
background-image: -o-linear-gradient(left, #fff, rgba(204, 154, 129, 0));
background-image: -ms-linear-gradient(left, #fff, rgba(204, 154, 129, 0));
background-image: linear-gradient(to right, #fff, rgba(204, 154, 129, 0));
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(GradientType = 1, startColorstr=#FFFFFFFF, endColorstr=#00CC9A81)";
filter : progid:DXImageTransform.Microsoft.gradient(GradientType = 1, startColorstr='#FFFFFFFF', endColorstr='#00CC9A81');
}
.sp-val {
background-image: -webkit-gradient(linear, 0 100%, 0 0, from(#000000), to(rgba(204, 154, 129, 0)));
background-image: -webkit-linear-gradient(bottom, #000000, rgba(204, 154, 129, 0));
background-image: -moz-linear-gradient(bottom, #000, rgba(204, 154, 129, 0));
background-image: -o-linear-gradient(bottom, #000, rgba(204, 154, 129, 0));
background-image: -ms-linear-gradient(bottom, #000, rgba(204, 154, 129, 0));
background-image: linear-gradient(to top, #000, rgba(204, 154, 129, 0));
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#00CC9A81, endColorstr=#FF000000)";
filter : progid:DXImageTransform.Microsoft.gradient(startColorstr='#00CC9A81', endColorstr='#FF000000');
}
.sp-hue {
background: -moz-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%);
background: -ms-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%);
background: -o-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%);
background: -webkit-gradient(linear, left top, left bottom, from(#ff0000), color-stop(0.17, #ffff00), color-stop(0.33, #00ff00), color-stop(0.5, #00ffff), color-stop(0.67, #0000ff), color-stop(0.83, #ff00ff), to(#ff0000));
background: -webkit-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%);
}
/* IE filters do not support multiple color stops.
Generate 6 divs, line them up, and do two color gradients for each.
Yes, really.
*/
.sp-1 {
height:17%;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0000', endColorstr='#ffff00');
}
.sp-2 {
height:16%;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffff00', endColorstr='#00ff00');
}
.sp-3 {
height:17%;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00ff00', endColorstr='#00ffff');
}
.sp-4 {
height:17%;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00ffff', endColorstr='#0000ff');
}
.sp-5 {
height:16%;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0000ff', endColorstr='#ff00ff');
}
.sp-6 {
height:17%;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff00ff', endColorstr='#ff0000');
}
.sp-hidden {
display: none !important;
}
/* Clearfix hack */
.sp-cf:before, .sp-cf:after { content: ""; display: table; }
.sp-cf:after { clear: both; }
.sp-cf { *zoom: 1; }
/* Mobile devices, make hue slider bigger so it is easier to slide */
@media (max-device-width: 480px) {
.sp-color { right: 40%; }
.sp-hue { left: 63%; }
.sp-fill { padding-top: 60%; }
}
.sp-dragger {
border-radius: 5px;
height: 5px;
width: 5px;
border: 1px solid #fff;
background: #000;
cursor: pointer;
position:absolute;
top:0;
left: 0;
}
.sp-slider {
position: absolute;
top:0;
cursor:pointer;
height: 3px;
left: -1px;
right: -1px;
border: 1px solid #000;
background: white;
opacity: .8;
}
/*
Theme authors:
Here are the basic themeable display options (colors, fonts, global widths).
See http://bgrins.github.io/spectrum/themes/ for instructions.
*/
.sp-container {
border-radius: 0;
background-color: #ECECEC;
border: solid 1px #f0c49B;
padding: 0;
}
.sp-container, .sp-container button, .sp-container input, .sp-color, .sp-hue, .sp-clear
{
font: normal 12px "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
-ms-box-sizing: border-box;
box-sizing: border-box;
}
.sp-top
{
margin-bottom: 3px;
}
.sp-color, .sp-hue, .sp-clear
{
border: solid 1px #666;
}
/* Input */
.sp-input-container {
float:right;
width: 100px;
margin-bottom: 4px;
}
.sp-initial-disabled .sp-input-container {
width: 100%;
}
.sp-input {
font-size: 12px !important;
border: 1px inset;
padding: 4px 5px;
margin: 0;
width: 100%;
background:transparent;
border-radius: 3px;
color: #222;
}
.sp-input:focus {
border: 1px solid orange;
}
.sp-input.sp-validation-error
{
border: 1px solid red;
background: #fdd;
}
.sp-picker-container , .sp-palette-container
{
float:left;
position: relative;
padding: 10px;
padding-bottom: 300px;
margin-bottom: -290px;
}
.sp-picker-container
{
width: 172px;
border-left: solid 1px #fff;
}
/* Palettes */
.sp-palette-container
{
border-right: solid 1px #ccc;
}
.sp-palette .sp-thumb-el {
display: block;
position:relative;
float:left;
width: 24px;
height: 15px;
margin: 3px;
cursor: pointer;
border:solid 2px transparent;
}
.sp-palette .sp-thumb-el:hover, .sp-palette .sp-thumb-el.sp-thumb-active {
border-color: orange;
}
.sp-thumb-el
{
position:relative;
}
/* Initial */
.sp-initial
{
float: left;
border: solid 1px #333;
}
.sp-initial span {
width: 30px;
height: 25px;
border:none;
display:block;
float:left;
margin:0;
}
.sp-initial .sp-clear-display {
background-position: center;
}
/* Buttons */
.sp-button-container {
float: right;
}
/* Replacer (the little preview div that shows up instead of the <input>) */
.sp-replacer {
margin:0;
overflow:hidden;
cursor:pointer;
padding: 4px;
display:inline-block;
*zoom: 1;
*display: inline;
border: solid 1px #91765d;
background: #eee;
color: #333;
vertical-align: middle;
}
.sp-replacer:hover, .sp-replacer.sp-active {
border-color: #F0C49B;
color: #111;
}
.sp-replacer.sp-disabled {
cursor:default;
border-color: silver;
color: silver;
}
.sp-dd {
padding: 2px 0;
height: 16px;
line-height: 16px;
float:left;
font-size:10px;
}
.sp-preview
{
position:relative;
width:25px;
height: 20px;
border: solid 1px #222;
margin-right: 5px;
float:left;
z-index: 0;
}
.sp-palette
{
*width: 220px;
max-width: 220px;
}
.sp-palette .sp-thumb-el
{
width:16px;
height: 16px;
margin:2px 1px;
border: solid 1px #d0d0d0;
}
.sp-container
{
padding-bottom:0;
}
/* Buttons: http://hellohappy.org/css3-buttons/ */
.sp-container button {
background-color: #eeeeee;
background-image: -webkit-linear-gradient(top, #eeeeee, #cccccc);
background-image: -moz-linear-gradient(top, #eeeeee, #cccccc);
background-image: -ms-linear-gradient(top, #eeeeee, #cccccc);
background-image: -o-linear-gradient(top, #eeeeee, #cccccc);
background-image: linear-gradient(to bottom, #eeeeee, #cccccc);
border: 1px solid #ccc;
border-bottom: 1px solid #bbb;
border-radius: 3px;
color: #333;
font-size: 14px;
line-height: 1;
padding: 5px 4px;
text-align: center;
text-shadow: 0 1px 0 #eee;
vertical-align: middle;
}
.sp-container button:hover {
background-color: #dddddd;
background-image: -webkit-linear-gradient(top, #dddddd, #bbbbbb);
background-image: -moz-linear-gradient(top, #dddddd, #bbbbbb);
background-image: -ms-linear-gradient(top, #dddddd, #bbbbbb);
background-image: -o-linear-gradient(top, #dddddd, #bbbbbb);
background-image: linear-gradient(to bottom, #dddddd, #bbbbbb);
border: 1px solid #bbb;
border-bottom: 1px solid #999;
cursor: pointer;
text-shadow: 0 1px 0 #ddd;
}
.sp-container button:active {
border: 1px solid #aaa;
border-bottom: 1px solid #888;
-webkit-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee;
-moz-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee;
-ms-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee;
-o-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee;
box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee;
}
.sp-cancel
{
font-size: 11px;
color: #d93f3f !important;
margin:0;
padding:2px;
margin-right: 5px;
vertical-align: middle;
text-decoration:none;
}
.sp-cancel:hover
{
color: #d93f3f !important;
text-decoration: underline;
}
.sp-palette span:hover, .sp-palette span.sp-thumb-active
{
border-color: #000;
}
.sp-preview, .sp-alpha, .sp-thumb-el
{
position:relative;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==);
}
.sp-preview-inner, .sp-alpha-inner, .sp-thumb-inner
{
display:block;
position:absolute;
top:0;left:0;bottom:0;right:0;
}
.sp-palette .sp-thumb-inner
{
background-position: 50% 50%;
background-repeat: no-repeat;
}
.sp-palette .sp-thumb-light.sp-thumb-active .sp-thumb-inner
{
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAIVJREFUeNpiYBhsgJFMffxAXABlN5JruT4Q3wfi/0DsT64h8UD8HmpIPCWG/KemIfOJCUB+Aoacx6EGBZyHBqI+WsDCwuQ9mhxeg2A210Ntfo8klk9sOMijaURm7yc1UP2RNCMbKE9ODK1HM6iegYLkfx8pligC9lCD7KmRof0ZhjQACDAAceovrtpVBRkAAAAASUVORK5CYII=);
}
.sp-palette .sp-thumb-dark.sp-thumb-active .sp-thumb-inner
{
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAMdJREFUOE+tkgsNwzAMRMugEAahEAahEAZhEAqlEAZhEAohEAYh81X2dIm8fKpEspLGvudPOsUYpxE2BIJCroJmEW9qJ+MKaBFhEMNabSy9oIcIPwrB+afvAUFoK4H0tMaQ3XtlrggDhOVVMuT4E5MMG0FBbCEYzjYT7OxLEvIHQLY2zWwQ3D+9luyOQTfKDiFD3iUIfPk8VqrKjgAiSfGFPecrg6HN6m/iBcwiDAo7WiBeawa+Kwh7tZoSCGLMqwlSAzVDhoK+6vH4G0P5wdkAAAAASUVORK5CYII=);
}
.sp-clear-display {
background-repeat:no-repeat;
background-position: center;
background-image: url(data:image/gif;base64,R0lGODlhFAAUAPcAAAAAAJmZmZ2dnZ6enqKioqOjo6SkpKWlpaampqenp6ioqKmpqaqqqqurq/Hx8fLy8vT09PX19ff39/j4+Pn5+fr6+vv7+wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAP8ALAAAAAAUABQAAAihAP9FoPCvoMGDBy08+EdhQAIJCCMybCDAAYUEARBAlFiQQoMABQhKUJBxY0SPICEYHBnggEmDKAuoPMjS5cGYMxHW3IiT478JJA8M/CjTZ0GgLRekNGpwAsYABHIypcAgQMsITDtWJYBR6NSqMico9cqR6tKfY7GeBCuVwlipDNmefAtTrkSzB1RaIAoXodsABiZAEFB06gIBWC1mLVgBa0AAOw==);
}
// Spectrum Colorpicker v1.3.4
// https://github.com/bgrins/spectrum
// Author: Brian Grinstead
// License: MIT
(function (window, $, undefined) {
var defaultOpts = {
// Callbacks
beforeShow: noop,
move: noop,
change: noop,
show: noop,
hide: noop,
// Options
color: false,
flat: false,
showInput: false,
allowEmpty: false,
showButtons: true,
clickoutFiresChange: false,
showInitial: false,
showPalette: false,
showPaletteOnly: false,
showSelectionPalette: true,
localStorageKey: false,
appendTo: "body",
maxSelectionSize: 7,
cancelText: "cancel",
chooseText: "choose",
clearText: "Clear Color Selection",
preferredFormat: false,
className: "", // Deprecated - use containerClassName and replacerClassName instead.
containerClassName: "",
replacerClassName: "",
showAlpha: false,
theme: "sp-light",
palette: [["#ffffff", "#000000", "#ff0000", "#ff8000", "#ffff00", "#008000", "#0000ff", "#4b0082", "#9400d3"]],
selectionPalette: [],
disabled: false
},
spectrums = [],
IE = !!/msie/i.exec( window.navigator.userAgent ),
rgbaSupport = (function() {
function contains( str, substr ) {
return !!~('' + str).indexOf(substr);
}
var elem = document.createElement('div');
var style = elem.style;
style.cssText = 'background-color:rgba(0,0,0,.5)';
return contains(style.backgroundColor, 'rgba') || contains(style.backgroundColor, 'hsla');
})(),
inputTypeColorSupport = (function() {
var colorInput = $("<input type='color' value='!' />")[0];
return colorInput.type === "color" && colorInput.value !== "!";
})(),
replaceInput = [
"<div class='sp-replacer'>",
"<div class='sp-preview'><div class='sp-preview-inner'></div></div>",
"<div class='sp-dd'>&#9660;</div>",
"</div>"
].join(''),
markup = (function () {
// IE does not support gradients with multiple stops, so we need to simulate
// that for the rainbow slider with 8 divs that each have a single gradient
var gradientFix = "";
if (IE) {
for (var i = 1; i <= 6; i++) {
gradientFix += "<div class='sp-" + i + "'></div>";
}
}
return [
"<div class='sp-container sp-hidden'>",
"<div class='sp-palette-container'>",
"<div class='sp-palette sp-thumb sp-cf'></div>",
"</div>",
"<div class='sp-picker-container'>",
"<div class='sp-top sp-cf'>",
"<div class='sp-fill'></div>",
"<div class='sp-top-inner'>",
"<div class='sp-color'>",
"<div class='sp-sat'>",
"<div class='sp-val'>",
"<div class='sp-dragger'></div>",
"</div>",
"</div>",
"</div>",
"<div class='sp-clear sp-clear-display'>",
"</div>",
"<div class='sp-hue'>",
"<div class='sp-slider'></div>",
gradientFix,
"</div>",
"</div>",
"<div class='sp-alpha'><div class='sp-alpha-inner'><div class='sp-alpha-handle'></div></div></div>",
"</div>",
"<div class='sp-input-container sp-cf'>",
"<input class='sp-input' type='text' spellcheck='false' />",
"</div>",
"<div class='sp-initial sp-thumb sp-cf'></div>",
"<div class='sp-button-container sp-cf'>",
"<a class='sp-cancel' href='#'></a>",
"<button type='button' class='sp-choose'></button>",
"</div>",
"</div>",
"</div>"
].join("");
})();
function paletteTemplate (p, color, className, tooltipFormat) {
var html = [];
for (var i = 0; i < p.length; i++) {
var current = p[i];
if(current) {
var tiny = tinycolor(current);
var c = tiny.toHsl().l < 0.5 ? "sp-thumb-el sp-thumb-dark" : "sp-thumb-el sp-thumb-light";
c += (tinycolor.equals(color, current)) ? " sp-thumb-active" : "";
var formattedString = tiny.toString(tooltipFormat || "rgb");
var swatchStyle = rgbaSupport ? ("background-color:" + tiny.toRgbString()) : "filter:" + tiny.toFilter();
html.push('<span title="' + formattedString + '" data-color="' + tiny.toRgbString() + '" class="' + c + '"><span class="sp-thumb-inner" style="' + swatchStyle + ';" /></span>');
} else {
var cls = 'sp-clear-display';
html.push('<span title="No Color Selected" data-color="" style="background-color:transparent;" class="' + cls + '"></span>');
}
}
return "<div class='sp-cf " + className + "'>" + html.join('') + "</div>";
}
function hideAll() {
for (var i = 0; i < spectrums.length; i++) {
if (spectrums[i]) {
spectrums[i].hide();
}
}
}
function instanceOptions(o, callbackContext) {
var opts = $.extend({}, defaultOpts, o);
opts.callbacks = {
'move': bind(opts.move, callbackContext),
'change': bind(opts.change, callbackContext),
'show': bind(opts.show, callbackContext),
'hide': bind(opts.hide, callbackContext),
'beforeShow': bind(opts.beforeShow, callbackContext)
};
return opts;
}
function spectrum(element, o) {
var opts = instanceOptions(o, element),
flat = opts.flat,
showSelectionPalette = opts.showSelectionPalette,
localStorageKey = opts.localStorageKey,
theme = opts.theme,
callbacks = opts.callbacks,
resize = throttle(reflow, 10),
visible = false,
dragWidth = 0,
dragHeight = 0,
dragHelperHeight = 0,
slideHeight = 0,
slideWidth = 0,
alphaWidth = 0,
alphaSlideHelperWidth = 0,
slideHelperHeight = 0,
currentHue = 0,
currentSaturation = 0,
currentValue = 0,
currentAlpha = 1,
palette = [],
paletteArray = [],
paletteLookup = {},
selectionPalette = opts.selectionPalette.slice(0),
maxSelectionSize = opts.maxSelectionSize,
draggingClass = "sp-dragging",
shiftMovementDirection = null;
var doc = element.ownerDocument,
body = doc.body,
boundElement = $(element),
disabled = false,
container = $(markup, doc).addClass(theme),
dragger = container.find(".sp-color"),
dragHelper = container.find(".sp-dragger"),
slider = container.find(".sp-hue"),
slideHelper = container.find(".sp-slider"),
alphaSliderInner = container.find(".sp-alpha-inner"),
alphaSlider = container.find(".sp-alpha"),
alphaSlideHelper = container.find(".sp-alpha-handle"),
textInput = container.find(".sp-input"),
paletteContainer = container.find(".sp-palette"),
initialColorContainer = container.find(".sp-initial"),
cancelButton = container.find(".sp-cancel"),
clearButton = container.find(".sp-clear"),
chooseButton = container.find(".sp-choose"),
isInput = boundElement.is("input"),
isInputTypeColor = isInput && inputTypeColorSupport && boundElement.attr("type") === "color",
shouldReplace = isInput && !flat,
replacer = (shouldReplace) ? $(replaceInput).addClass(theme).addClass(opts.className).addClass(opts.replacerClassName) : $([]),
offsetElement = (shouldReplace) ? replacer : boundElement,
previewElement = replacer.find(".sp-preview-inner"),
initialColor = opts.color || (isInput && boundElement.val()),
colorOnShow = false,
preferredFormat = opts.preferredFormat,
currentPreferredFormat = preferredFormat,
clickoutFiresChange = !opts.showButtons || opts.clickoutFiresChange,
isEmpty = !initialColor,
allowEmpty = opts.allowEmpty && !isInputTypeColor;
function applyOptions() {
if (opts.showPaletteOnly) {
opts.showPalette = true;
}
if (opts.palette) {
palette = opts.palette.slice(0);
paletteArray = $.isArray(palette[0]) ? palette : [palette];
paletteLookup = {};
for (var i = 0; i < paletteArray.length; i++) {
for (var j = 0; j < paletteArray[i].length; j++) {
var rgb = tinycolor(paletteArray[i][j]).toRgbString();
paletteLookup[rgb] = true;
}
}
}
container.toggleClass("sp-flat", flat);
container.toggleClass("sp-input-disabled", !opts.showInput);
container.toggleClass("sp-alpha-enabled", opts.showAlpha);
container.toggleClass("sp-clear-enabled", allowEmpty);
container.toggleClass("sp-buttons-disabled", !opts.showButtons);
container.toggleClass("sp-palette-disabled", !opts.showPalette);
container.toggleClass("sp-palette-only", opts.showPaletteOnly);
container.toggleClass("sp-initial-disabled", !opts.showInitial);
container.addClass(opts.className).addClass(opts.containerClassName);
reflow();
}
function initialize() {
if (IE) {
container.find("*:not(input)").attr("unselectable", "on");
}
applyOptions();
if (shouldReplace) {
boundElement.after(replacer).hide();
}
if (!allowEmpty) {
clearButton.hide();
}
if (flat) {
boundElement.after(container).hide();
}
else {
var appendTo = opts.appendTo === "parent" ? boundElement.parent() : $(opts.appendTo);
if (appendTo.length !== 1) {
appendTo = $("body");
}
appendTo.append(container);
}
updateSelectionPaletteFromStorage();
offsetElement.bind("click.spectrum touchstart.spectrum", function (e) {
if (!disabled) {
toggle();
}
e.stopPropagation();
if (!$(e.target).is("input")) {
e.preventDefault();
}
});
if(boundElement.is(":disabled") || (opts.disabled === true)) {
disable();
}
// Prevent clicks from bubbling up to document. This would cause it to be hidden.
container.click(stopPropagation);
// Handle user typed input
textInput.change(setFromTextInput);
textInput.bind("paste", function () {
setTimeout(setFromTextInput, 1);
});
textInput.keydown(function (e) { if (e.keyCode == 13) { setFromTextInput(); } });
cancelButton.text(opts.cancelText);
cancelButton.bind("click.spectrum", function (e) {
e.stopPropagation();
e.preventDefault();
hide("cancel");
});
clearButton.attr("title", opts.clearText);
clearButton.bind("click.spectrum", function (e) {
e.stopPropagation();
e.preventDefault();
isEmpty = true;
move();
if(flat) {
//for the flat style, this is a change event
updateOriginalInput(true);
}
});
chooseButton.text(opts.chooseText);
chooseButton.bind("click.spectrum", function (e) {
e.stopPropagation();
e.preventDefault();
if (isValid()) {
updateOriginalInput(true);
hide();
}
});
draggable(alphaSlider, function (dragX, dragY, e) {
currentAlpha = (dragX / alphaWidth);
isEmpty = false;
if (e.shiftKey) {
currentAlpha = Math.round(currentAlpha * 10) / 10;
}
move();
}, dragStart, dragStop);
draggable(slider, function (dragX, dragY) {
currentHue = parseFloat(dragY / slideHeight);
isEmpty = false;
if (!opts.showAlpha) {
currentAlpha = 1;
}
move();
}, dragStart, dragStop);
draggable(dragger, function (dragX, dragY, e) {
// shift+drag should snap the movement to either the x or y axis.
if (!e.shiftKey) {
shiftMovementDirection = null;
}
else if (!shiftMovementDirection) {
var oldDragX = currentSaturation * dragWidth;
var oldDragY = dragHeight - (currentValue * dragHeight);
var furtherFromX = Math.abs(dragX - oldDragX) > Math.abs(dragY - oldDragY);
shiftMovementDirection = furtherFromX ? "x" : "y";
}
var setSaturation = !shiftMovementDirection || shiftMovementDirection === "x";
var setValue = !shiftMovementDirection || shiftMovementDirection === "y";
if (setSaturation) {
currentSaturation = parseFloat(dragX / dragWidth);
}
if (setValue) {
currentValue = parseFloat((dragHeight - dragY) / dragHeight);
}
isEmpty = false;
if (!opts.showAlpha) {
currentAlpha = 1;
}
move();
}, dragStart, dragStop);
if (!!initialColor) {
set(initialColor);
// In case color was black - update the preview UI and set the format
// since the set function will not run (default color is black).
updateUI();
currentPreferredFormat = preferredFormat || tinycolor(initialColor).format;
addColorToSelectionPalette(initialColor);
}
else {
updateUI();
}
if (flat) {
show();
}
function palletElementClick(e) {
if (e.data && e.data.ignore) {
set($(this).data("color"));
move();
}
else {
set($(this).data("color"));
move();
updateOriginalInput(true);
hide();
}
return false;
}
var paletteEvent = IE ? "mousedown.spectrum" : "click.spectrum touchstart.spectrum";
paletteContainer.delegate(".sp-thumb-el", paletteEvent, palletElementClick);
initialColorContainer.delegate(".sp-thumb-el:nth-child(1)", paletteEvent, { ignore: true }, palletElementClick);
}
function updateSelectionPaletteFromStorage() {
if (localStorageKey && window.localStorage) {
// Migrate old palettes over to new format. May want to remove this eventually.
try {
var oldPalette = window.localStorage[localStorageKey].split(",#");
if (oldPalette.length > 1) {
delete window.localStorage[localStorageKey];
$.each(oldPalette, function(i, c) {
addColorToSelectionPalette(c);
});
}
}
catch(e) { }
try {
selectionPalette = window.localStorage[localStorageKey].split(";");
}
catch (e) { }
}
}
function addColorToSelectionPalette(color) {
if (showSelectionPalette) {
var rgb = tinycolor(color).toRgbString();
if (!paletteLookup[rgb] && $.inArray(rgb, selectionPalette) === -1) {
selectionPalette.push(rgb);
while(selectionPalette.length > maxSelectionSize) {
selectionPalette.shift();
}
}
if (localStorageKey && window.localStorage) {
try {
window.localStorage[localStorageKey] = selectionPalette.join(";");
}
catch(e) { }
}
}
}
function getUniqueSelectionPalette() {
var unique = [];
if (opts.showPalette) {
for (i = 0; i < selectionPalette.length; i++) {
var rgb = tinycolor(selectionPalette[i]).toRgbString();
if (!paletteLookup[rgb]) {
unique.push(selectionPalette[i]);
}
}
}
return unique.reverse().slice(0, opts.maxSelectionSize);
}
function drawPalette() {
var currentColor = get();
var html = $.map(paletteArray, function (palette, i) {
return paletteTemplate(palette, currentColor, "sp-palette-row sp-palette-row-" + i, opts.preferredFormat);
});
updateSelectionPaletteFromStorage();
if (selectionPalette) {
html.push(paletteTemplate(getUniqueSelectionPalette(), currentColor, "sp-palette-row sp-palette-row-selection", opts.preferredFormat));
}
paletteContainer.html(html.join(""));
}
function drawInitial() {
if (opts.showInitial) {
var initial = colorOnShow;
var current = get();
initialColorContainer.html(paletteTemplate([initial, current], current, "sp-palette-row-initial", opts.preferredFormat));
}
}
function dragStart() {
if (dragHeight <= 0 || dragWidth <= 0 || slideHeight <= 0) {
reflow();
}
container.addClass(draggingClass);
shiftMovementDirection = null;
boundElement.trigger('dragstart.spectrum', [ get() ]);
}
function dragStop() {
container.removeClass(draggingClass);
boundElement.trigger('dragstop.spectrum', [ get() ]);
}
function setFromTextInput() {
var value = textInput.val();
if ((value === null || value === "") && allowEmpty) {
set(null);
updateOriginalInput(true);
}
else {
var tiny = tinycolor(value);
if (tiny.ok) {
set(tiny);
updateOriginalInput(true);
}
else {
textInput.addClass("sp-validation-error");
}
}
}
function toggle() {
if (visible) {
hide();
}
else {
show();
}
}
function show() {
var event = $.Event('beforeShow.spectrum');
if (visible) {
reflow();
return;
}
boundElement.trigger(event, [ get() ]);
if (callbacks.beforeShow(get()) === false || event.isDefaultPrevented()) {
return;
}
hideAll();
visible = true;
$(doc).bind("click.spectrum", hide);
$(window).bind("resize.spectrum", resize);
replacer.addClass("sp-active");
container.removeClass("sp-hidden");
reflow();
updateUI();
colorOnShow = get();
drawInitial();
callbacks.show(colorOnShow);
boundElement.trigger('show.spectrum', [ colorOnShow ]);
}
function hide(e) {
// Return on right click
if (e && e.type == "click" && e.button == 2) { return; }
// Return if hiding is unnecessary
if (!visible || flat) { return; }
visible = false;
$(doc).unbind("click.spectrum", hide);
$(window).unbind("resize.spectrum", resize);
replacer.removeClass("sp-active");
container.addClass("sp-hidden");
var colorHasChanged = !tinycolor.equals(get(), colorOnShow);
if (colorHasChanged) {
if (clickoutFiresChange && e !== "cancel") {
updateOriginalInput(true);
}
else {
revert();
}
}
callbacks.hide(get());
boundElement.trigger('hide.spectrum', [ get() ]);
}
function revert() {
set(colorOnShow, true);
}
function set(color, ignoreFormatChange) {
if (tinycolor.equals(color, get())) {
// Update UI just in case a validation error needs
// to be cleared.
updateUI();
return;
}
var newColor, newHsv;
if (!color && allowEmpty) {
isEmpty = true;
} else {
isEmpty = false;
newColor = tinycolor(color);
newHsv = newColor.toHsv();
currentHue = (newHsv.h % 360) / 360;
currentSaturation = newHsv.s;
currentValue = newHsv.v;
currentAlpha = newHsv.a;
}
updateUI();
if (newColor && newColor.ok && !ignoreFormatChange) {
currentPreferredFormat = preferredFormat || newColor.format;
}
}
function get(opts) {
opts = opts || { };
if (allowEmpty && isEmpty) {
return null;
}
return tinycolor.fromRatio({
h: currentHue,
s: currentSaturation,
v: currentValue,
a: Math.round(currentAlpha * 100) / 100
}, { format: opts.format || currentPreferredFormat });
}
function isValid() {
return !textInput.hasClass("sp-validation-error");
}
function move() {
updateUI();
callbacks.move(get());
boundElement.trigger('move.spectrum', [ get() ]);
}
function updateUI() {
textInput.removeClass("sp-validation-error");
updateHelperLocations();
// Update dragger background color (gradients take care of saturation and value).
var flatColor = tinycolor.fromRatio({ h: currentHue, s: 1, v: 1 });
dragger.css("background-color", flatColor.toHexString());
// Get a format that alpha will be included in (hex and names ignore alpha)
var format = currentPreferredFormat;
if (currentAlpha < 1 && !(currentAlpha === 0 && format === "name")) {
if (format === "hex" || format === "hex3" || format === "hex6" || format === "name") {
format = "rgb";
}
}
var realColor = get({ format: format }),
displayColor = '';
//reset background info for preview element
previewElement.removeClass("sp-clear-display");
previewElement.css('background-color', 'transparent');
if (!realColor && allowEmpty) {
// Update the replaced elements background with icon indicating no color selection
previewElement.addClass("sp-clear-display");
}
else {
var realHex = realColor.toHexString(),
realRgb = realColor.toRgbString();
// Update the replaced elements background color (with actual selected color)
if (rgbaSupport || realColor.alpha === 1) {
previewElement.css("background-color", realRgb);
}
else {
previewElement.css("background-color", "transparent");
previewElement.css("filter", realColor.toFilter());
}
if (opts.showAlpha) {
var rgb = realColor.toRgb();
rgb.a = 0;
var realAlpha = tinycolor(rgb).toRgbString();
var gradient = "linear-gradient(left, " + realAlpha + ", " + realHex + ")";
if (IE) {
alphaSliderInner.css("filter", tinycolor(realAlpha).toFilter({ gradientType: 1 }, realHex));
}
else {
alphaSliderInner.css("background", "-webkit-" + gradient);
alphaSliderInner.css("background", "-moz-" + gradient);
alphaSliderInner.css("background", "-ms-" + gradient);
// Use current syntax gradient on unprefixed property.
alphaSliderInner.css("background",
"linear-gradient(to right, " + realAlpha + ", " + realHex + ")");
}
}
displayColor = realColor.toString(format);
}
// Update the text entry input as it changes happen
if (opts.showInput) {
textInput.val(displayColor);
}
if (opts.showPalette) {
drawPalette();
}
drawInitial();
}
function updateHelperLocations() {
var s = currentSaturation;
var v = currentValue;
if(allowEmpty && isEmpty) {
//if selected color is empty, hide the helpers
alphaSlideHelper.hide();
slideHelper.hide();
dragHelper.hide();
}
else {
//make sure helpers are visible
alphaSlideHelper.show();
slideHelper.show();
dragHelper.show();
// Where to show the little circle in that displays your current selected color
var dragX = s * dragWidth;
var dragY = dragHeight - (v * dragHeight);
dragX = Math.max(
-dragHelperHeight,
Math.min(dragWidth - dragHelperHeight, dragX - dragHelperHeight)
);
dragY = Math.max(
-dragHelperHeight,
Math.min(dragHeight - dragHelperHeight, dragY - dragHelperHeight)
);
dragHelper.css({
"top": dragY + "px",
"left": dragX + "px"
});
var alphaX = currentAlpha * alphaWidth;
alphaSlideHelper.css({
"left": (alphaX - (alphaSlideHelperWidth / 2)) + "px"
});
// Where to show the bar that displays your current selected hue
var slideY = (currentHue) * slideHeight;
slideHelper.css({
"top": (slideY - slideHelperHeight) + "px"
});
}
}
function updateOriginalInput(fireCallback) {
var color = get(),
displayColor = '',
hasChanged = !tinycolor.equals(color, colorOnShow);
if (color) {
displayColor = color.toString(currentPreferredFormat);
// Update the selection palette with the current color
addColorToSelectionPalette(color);
}
if (isInput) {
boundElement.val(displayColor);
}
colorOnShow = color;
if (fireCallback && hasChanged) {
callbacks.change(color);
boundElement.trigger('change', [ color ]);
}
}
function reflow() {
dragWidth = dragger.width();
dragHeight = dragger.height();
dragHelperHeight = dragHelper.height();
slideWidth = slider.width();
slideHeight = slider.height();
slideHelperHeight = slideHelper.height();
alphaWidth = alphaSlider.width();
alphaSlideHelperWidth = alphaSlideHelper.width();
if (!flat) {
container.css("position", "absolute");
container.offset(getOffset(container, offsetElement));
}
updateHelperLocations();
if (opts.showPalette) {
drawPalette();
}
boundElement.trigger('reflow.spectrum');
}
function destroy() {
boundElement.show();
offsetElement.unbind("click.spectrum touchstart.spectrum");
container.remove();
replacer.remove();
spectrums[spect.id] = null;
}
function option(optionName, optionValue) {
if (optionName === undefined) {
return $.extend({}, opts);
}
if (optionValue === undefined) {
return opts[optionName];
}
opts[optionName] = optionValue;
applyOptions();
}
function enable() {
disabled = false;
boundElement.attr("disabled", false);
offsetElement.removeClass("sp-disabled");
}
function disable() {
hide();
disabled = true;
boundElement.attr("disabled", true);
offsetElement.addClass("sp-disabled");
}
initialize();
var spect = {
show: show,
hide: hide,
toggle: toggle,
reflow: reflow,
option: option,
enable: enable,
disable: disable,
set: function (c) {
set(c);
updateOriginalInput();
},
get: get,
destroy: destroy,
container: container
};
spect.id = spectrums.push(spect) - 1;
return spect;
}
/**
* checkOffset - get the offset below/above and left/right element depending on screen position
* Thanks https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.datepicker.js
*/
function getOffset(picker, input) {
var extraY = 0;
var dpWidth = picker.outerWidth();
var dpHeight = picker.outerHeight();
var inputHeight = input.outerHeight();
var doc = picker[0].ownerDocument;
var docElem = doc.documentElement;
var viewWidth = docElem.clientWidth + $(doc).scrollLeft();
var viewHeight = docElem.clientHeight + $(doc).scrollTop();
var offset = input.offset();
offset.top += inputHeight;
offset.left -=
Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ?
Math.abs(offset.left + dpWidth - viewWidth) : 0);
offset.top -=
Math.min(offset.top, ((offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ?
Math.abs(dpHeight + inputHeight - extraY) : extraY));
return offset;
}
/**
* noop - do nothing
*/
function noop() {
}
/**
* stopPropagation - makes the code only doing this a little easier to read in line
*/
function stopPropagation(e) {
e.stopPropagation();
}
/**
* Create a function bound to a given object
* Thanks to underscore.js
*/
function bind(func, obj) {
var slice = Array.prototype.slice;
var args = slice.call(arguments, 2);
return function () {
return func.apply(obj, args.concat(slice.call(arguments)));
};
}
/**
* Lightweight drag helper. Handles containment within the element, so that
* when dragging, the x is within [0,element.width] and y is within [0,element.height]
*/
function draggable(element, onmove, onstart, onstop) {
onmove = onmove || function () { };
onstart = onstart || function () { };
onstop = onstop || function () { };
var doc = element.ownerDocument || document;
var dragging = false;
var offset = {};
var maxHeight = 0;
var maxWidth = 0;
var hasTouch = ('ontouchstart' in window);
var duringDragEvents = {};
duringDragEvents["selectstart"] = prevent;
duringDragEvents["dragstart"] = prevent;
duringDragEvents["touchmove mousemove"] = move;
duringDragEvents["touchend mouseup"] = stop;
function prevent(e) {
if (e.stopPropagation) {
e.stopPropagation();
}
if (e.preventDefault) {
e.preventDefault();
}
e.returnValue = false;
}
function move(e) {
if (dragging) {
// Mouseup happened outside of window
if (IE && document.documentMode < 9 && !e.button) {
return stop();
}
var touches = e.originalEvent.touches;
var pageX = touches ? touches[0].pageX : e.pageX;
var pageY = touches ? touches[0].pageY : e.pageY;
var dragX = Math.max(0, Math.min(pageX - offset.left, maxWidth));
var dragY = Math.max(0, Math.min(pageY - offset.top, maxHeight));
if (hasTouch) {
// Stop scrolling in iOS
prevent(e);
}
onmove.apply(element, [dragX, dragY, e]);
}
}
function start(e) {
var rightclick = (e.which) ? (e.which == 3) : (e.button == 2);
var touches = e.originalEvent.touches;
if (!rightclick && !dragging) {
if (onstart.apply(element, arguments) !== false) {
dragging = true;
maxHeight = $(element).height();
maxWidth = $(element).width();
offset = $(element).offset();
$(doc).bind(duringDragEvents);
$(doc.body).addClass("sp-dragging");
if (!hasTouch) {
move(e);
}
prevent(e);
}
}
}
function stop() {
if (dragging) {
$(doc).unbind(duringDragEvents);
$(doc.body).removeClass("sp-dragging");
onstop.apply(element, arguments);
}
dragging = false;
}
$(element).bind("touchstart mousedown", start);
}
function throttle(func, wait, debounce) {
var timeout;
return function () {
var context = this, args = arguments;
var throttler = function () {
timeout = null;
func.apply(context, args);
};
if (debounce) clearTimeout(timeout);
if (debounce || !timeout) timeout = setTimeout(throttler, wait);
};
}
function log(){/* jshint -W021 */if(window.console){if(Function.prototype.bind)log=Function.prototype.bind.call(console.log,console);else log=function(){Function.prototype.apply.call(console.log,console,arguments);};log.apply(this,arguments);}}
/**
* Define a jQuery plugin
*/
var dataID = "spectrum.id";
$.fn.spectrum = function (opts, extra) {
if (typeof opts == "string") {
var returnValue = this;
var args = Array.prototype.slice.call( arguments, 1 );
this.each(function () {
var spect = spectrums[$(this).data(dataID)];
if (spect) {
var method = spect[opts];
if (!method) {
throw new Error( "Spectrum: no such method: '" + opts + "'" );
}
if (opts == "get") {
returnValue = spect.get();
}
else if (opts == "container") {
returnValue = spect.container;
}
else if (opts == "option") {
returnValue = spect.option.apply(spect, args);
}
else if (opts == "destroy") {
spect.destroy();
$(this).removeData(dataID);
}
else {
method.apply(spect, args);
}
}
});
return returnValue;
}
// Initializing a new instance of spectrum
return this.spectrum("destroy").each(function () {
var options = $.extend({}, opts, $(this).data());
var spect = spectrum(this, options);
$(this).data(dataID, spect.id);
});
};
$.fn.spectrum.load = true;
$.fn.spectrum.loadOpts = {};
$.fn.spectrum.draggable = draggable;
$.fn.spectrum.defaults = defaultOpts;
$.spectrum = { };
$.spectrum.localization = { };
$.spectrum.palettes = { };
$.fn.spectrum.processNativeColorInputs = function () {
if (!inputTypeColorSupport) {
$("input[type=color]").spectrum({
preferredFormat: "hex6"
});
}
};
// TinyColor v0.9.17
// https://github.com/bgrins/TinyColor
// 2013-08-10, Brian Grinstead, MIT License
(function() {
var trimLeft = /^[\s,#]+/,
trimRight = /\s+$/,
tinyCounter = 0,
math = Math,
mathRound = math.round,
mathMin = math.min,
mathMax = math.max,
mathRandom = math.random;
function tinycolor (color, opts) {
color = (color) ? color : '';
opts = opts || { };
// If input is already a tinycolor, return itself
if (typeof color == "object" && color.hasOwnProperty("_tc_id")) {
return color;
}
var rgb = inputToRGB(color);
var r = rgb.r,
g = rgb.g,
b = rgb.b,
a = rgb.a,
roundA = mathRound(100*a) / 100,
format = opts.format || rgb.format;
// Don't let the range of [0,255] come back in [0,1].
// Potentially lose a little bit of precision here, but will fix issues where
// .5 gets interpreted as half of the total, instead of half of 1
// If it was supposed to be 128, this was already taken care of by `inputToRgb`
if (r < 1) { r = mathRound(r); }
if (g < 1) { g = mathRound(g); }
if (b < 1) { b = mathRound(b); }
return {
ok: rgb.ok,
format: format,
_tc_id: tinyCounter++,
alpha: a,
getAlpha: function() {
return a;
},
setAlpha: function(value) {
a = boundAlpha(value);
roundA = mathRound(100*a) / 100;
},
toHsv: function() {
var hsv = rgbToHsv(r, g, b);
return { h: hsv.h * 360, s: hsv.s, v: hsv.v, a: a };
},
toHsvString: function() {
var hsv = rgbToHsv(r, g, b);
var h = mathRound(hsv.h * 360), s = mathRound(hsv.s * 100), v = mathRound(hsv.v * 100);
return (a == 1) ?
"hsv(" + h + ", " + s + "%, " + v + "%)" :
"hsva(" + h + ", " + s + "%, " + v + "%, "+ roundA + ")";
},
toHsl: function() {
var hsl = rgbToHsl(r, g, b);
return { h: hsl.h * 360, s: hsl.s, l: hsl.l, a: a };
},
toHslString: function() {
var hsl = rgbToHsl(r, g, b);
var h = mathRound(hsl.h * 360), s = mathRound(hsl.s * 100), l = mathRound(hsl.l * 100);
return (a == 1) ?
"hsl(" + h + ", " + s + "%, " + l + "%)" :
"hsla(" + h + ", " + s + "%, " + l + "%, "+ roundA + ")";
},
toHex: function(allow3Char) {
return rgbToHex(r, g, b, allow3Char);
},
toHexString: function(allow3Char) {
return '#' + this.toHex(allow3Char);
},
toHex8: function() {
return rgbaToHex(r, g, b, a);
},
toHex8String: function() {
return '#' + this.toHex8();
},
toRgb: function() {
return { r: mathRound(r), g: mathRound(g), b: mathRound(b), a: a };
},
toRgbString: function() {
return (a == 1) ?
"rgb(" + mathRound(r) + ", " + mathRound(g) + ", " + mathRound(b) + ")" :
"rgba(" + mathRound(r) + ", " + mathRound(g) + ", " + mathRound(b) + ", " + roundA + ")";
},
toPercentageRgb: function() {
return { r: mathRound(bound01(r, 255) * 100) + "%", g: mathRound(bound01(g, 255) * 100) + "%", b: mathRound(bound01(b, 255) * 100) + "%", a: a };
},
toPercentageRgbString: function() {
return (a == 1) ?
"rgb(" + mathRound(bound01(r, 255) * 100) + "%, " + mathRound(bound01(g, 255) * 100) + "%, " + mathRound(bound01(b, 255) * 100) + "%)" :
"rgba(" + mathRound(bound01(r, 255) * 100) + "%, " + mathRound(bound01(g, 255) * 100) + "%, " + mathRound(bound01(b, 255) * 100) + "%, " + roundA + ")";
},
toName: function() {
if (a === 0) {
return "transparent";
}
return hexNames[rgbToHex(r, g, b, true)] || false;
},
toFilter: function(secondColor) {
var hex8String = '#' + rgbaToHex(r, g, b, a);
var secondHex8String = hex8String;
var gradientType = opts && opts.gradientType ? "GradientType = 1, " : "";
if (secondColor) {
var s = tinycolor(secondColor);
secondHex8String = s.toHex8String();
}
return "progid:DXImageTransform.Microsoft.gradient("+gradientType+"startColorstr="+hex8String+",endColorstr="+secondHex8String+")";
},
toString: function(format) {
var formatSet = !!format;
format = format || this.format;
var formattedString = false;
var hasAlphaAndFormatNotSet = !formatSet && a < 1 && a > 0;
var formatWithAlpha = hasAlphaAndFormatNotSet && (format === "hex" || format === "hex6" || format === "hex3" || format === "name");
if (format === "rgb") {
formattedString = this.toRgbString();
}
if (format === "prgb") {
formattedString = this.toPercentageRgbString();
}
if (format === "hex" || format === "hex6") {
formattedString = this.toHexString();
}
if (format === "hex3") {
formattedString = this.toHexString(true);
}
if (format === "hex8") {
formattedString = this.toHex8String();
}
if (format === "name") {
formattedString = this.toName();
}
if (format === "hsl") {
formattedString = this.toHslString();
}
if (format === "hsv") {
formattedString = this.toHsvString();
}
if (formatWithAlpha) {
return this.toRgbString();
}
return formattedString || this.toHexString();
}
};
}
// If input is an object, force 1 into "1.0" to handle ratios properly
// String input requires "1.0" as input, so 1 will be treated as 1
tinycolor.fromRatio = function(color, opts) {
if (typeof color == "object") {
var newColor = {};
for (var i in color) {
if (color.hasOwnProperty(i)) {
if (i === "a") {
newColor[i] = color[i];
}
else {
newColor[i] = convertToPercentage(color[i]);
}
}
}
color = newColor;
}
return tinycolor(color, opts);
};
// Given a string or object, convert that input to RGB
// Possible string inputs:
//
// "red"
// "#f00" or "f00"
// "#ff0000" or "ff0000"
// "#ff000000" or "ff000000"
// "rgb 255 0 0" or "rgb (255, 0, 0)"
// "rgb 1.0 0 0" or "rgb (1, 0, 0)"
// "rgba (255, 0, 0, 1)" or "rgba 255, 0, 0, 1"
// "rgba (1.0, 0, 0, 1)" or "rgba 1.0, 0, 0, 1"
// "hsl(0, 100%, 50%)" or "hsl 0 100% 50%"
// "hsla(0, 100%, 50%, 1)" or "hsla 0 100% 50%, 1"
// "hsv(0, 100%, 100%)" or "hsv 0 100% 100%"
//
function inputToRGB(color) {
var rgb = { r: 0, g: 0, b: 0 };
var a = 1;
var ok = false;
var format = false;
if (typeof color == "string") {
color = stringInputToObject(color);
}
if (typeof color == "object") {
if (color.hasOwnProperty("r") && color.hasOwnProperty("g") && color.hasOwnProperty("b")) {
rgb = rgbToRgb(color.r, color.g, color.b);
ok = true;
format = String(color.r).substr(-1) === "%" ? "prgb" : "rgb";
}
else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("v")) {
color.s = convertToPercentage(color.s);
color.v = convertToPercentage(color.v);
rgb = hsvToRgb(color.h, color.s, color.v);
ok = true;
format = "hsv";
}
else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("l")) {
color.s = convertToPercentage(color.s);
color.l = convertToPercentage(color.l);
rgb = hslToRgb(color.h, color.s, color.l);
ok = true;
format = "hsl";
}
if (color.hasOwnProperty("a")) {
a = color.a;
}
}
a = boundAlpha(a);
return {
ok: ok,
format: color.format || format,
r: mathMin(255, mathMax(rgb.r, 0)),
g: mathMin(255, mathMax(rgb.g, 0)),
b: mathMin(255, mathMax(rgb.b, 0)),
a: a
};
}
// Conversion Functions
// --------------------
// `rgbToHsl`, `rgbToHsv`, `hslToRgb`, `hsvToRgb` modified from:
// <http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript>
// `rgbToRgb`
// Handle bounds / percentage checking to conform to CSS color spec
// <http://www.w3.org/TR/css3-color/>
// *Assumes:* r, g, b in [0, 255] or [0, 1]
// *Returns:* { r, g, b } in [0, 255]
function rgbToRgb(r, g, b){
return {
r: bound01(r, 255) * 255,
g: bound01(g, 255) * 255,
b: bound01(b, 255) * 255
};
}
// `rgbToHsl`
// Converts an RGB color value to HSL.
// *Assumes:* r, g, and b are contained in [0, 255] or [0, 1]
// *Returns:* { h, s, l } in [0,1]
function rgbToHsl(r, g, b) {
r = bound01(r, 255);
g = bound01(g, 255);
b = bound01(b, 255);
var max = mathMax(r, g, b), min = mathMin(r, g, b);
var h, s, l = (max + min) / 2;
if(max == min) {
h = s = 0; // achromatic
}
else {
var d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch(max) {
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
case g: h = (b - r) / d + 2; break;
case b: h = (r - g) / d + 4; break;
}
h /= 6;
}
return { h: h, s: s, l: l };
}
// `hslToRgb`
// Converts an HSL color value to RGB.
// *Assumes:* h is contained in [0, 1] or [0, 360] and s and l are contained [0, 1] or [0, 100]
// *Returns:* { r, g, b } in the set [0, 255]
function hslToRgb(h, s, l) {
var r, g, b;
h = bound01(h, 360);
s = bound01(s, 100);
l = bound01(l, 100);
function hue2rgb(p, q, t) {
if(t < 0) t += 1;
if(t > 1) t -= 1;
if(t < 1/6) return p + (q - p) * 6 * t;
if(t < 1/2) return q;
if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;
return p;
}
if(s === 0) {
r = g = b = l; // achromatic
}
else {
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
var p = 2 * l - q;
r = hue2rgb(p, q, h + 1/3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1/3);
}
return { r: r * 255, g: g * 255, b: b * 255 };
}
// `rgbToHsv`
// Converts an RGB color value to HSV
// *Assumes:* r, g, and b are contained in the set [0, 255] or [0, 1]
// *Returns:* { h, s, v } in [0,1]
function rgbToHsv(r, g, b) {
r = bound01(r, 255);
g = bound01(g, 255);
b = bound01(b, 255);
var max = mathMax(r, g, b), min = mathMin(r, g, b);
var h, s, v = max;
var d = max - min;
s = max === 0 ? 0 : d / max;
if(max == min) {
h = 0; // achromatic
}
else {
switch(max) {
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
case g: h = (b - r) / d + 2; break;
case b: h = (r - g) / d + 4; break;
}
h /= 6;
}
return { h: h, s: s, v: v };
}
// `hsvToRgb`
// Converts an HSV color value to RGB.
// *Assumes:* h is contained in [0, 1] or [0, 360] and s and v are contained in [0, 1] or [0, 100]
// *Returns:* { r, g, b } in the set [0, 255]
function hsvToRgb(h, s, v) {
h = bound01(h, 360) * 6;
s = bound01(s, 100);
v = bound01(v, 100);
var i = math.floor(h),
f = h - i,
p = v * (1 - s),
q = v * (1 - f * s),
t = v * (1 - (1 - f) * s),
mod = i % 6,
r = [v, q, p, p, t, v][mod],
g = [t, v, v, q, p, p][mod],
b = [p, p, t, v, v, q][mod];
return { r: r * 255, g: g * 255, b: b * 255 };
}
// `rgbToHex`
// Converts an RGB color to hex
// Assumes r, g, and b are contained in the set [0, 255]
// Returns a 3 or 6 character hex
function rgbToHex(r, g, b, allow3Char) {
var hex = [
pad2(mathRound(r).toString(16)),
pad2(mathRound(g).toString(16)),
pad2(mathRound(b).toString(16))
];
// Return a 3 character hex if possible
if (allow3Char && hex[0].charAt(0) == hex[0].charAt(1) && hex[1].charAt(0) == hex[1].charAt(1) && hex[2].charAt(0) == hex[2].charAt(1)) {
return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0);
}
return hex.join("");
}
// `rgbaToHex`
// Converts an RGBA color plus alpha transparency to hex
// Assumes r, g, b and a are contained in the set [0, 255]
// Returns an 8 character hex
function rgbaToHex(r, g, b, a) {
var hex = [
pad2(convertDecimalToHex(a)),
pad2(mathRound(r).toString(16)),
pad2(mathRound(g).toString(16)),
pad2(mathRound(b).toString(16))
];
return hex.join("");
}
// `equals`
// Can be called with any tinycolor input
tinycolor.equals = function (color1, color2) {
if (!color1 || !color2) { return false; }
return tinycolor(color1).toRgbString() == tinycolor(color2).toRgbString();
};
tinycolor.random = function() {
return tinycolor.fromRatio({
r: mathRandom(),
g: mathRandom(),
b: mathRandom()
});
};
// Modification Functions
// ----------------------
// Thanks to less.js for some of the basics here
// <https://github.com/cloudhead/less.js/blob/master/lib/less/functions.js>
tinycolor.desaturate = function (color, amount) {
amount = (amount === 0) ? 0 : (amount || 10);
var hsl = tinycolor(color).toHsl();
hsl.s -= amount / 100;
hsl.s = clamp01(hsl.s);
return tinycolor(hsl);
};
tinycolor.saturate = function (color, amount) {
amount = (amount === 0) ? 0 : (amount || 10);
var hsl = tinycolor(color).toHsl();
hsl.s += amount / 100;
hsl.s = clamp01(hsl.s);
return tinycolor(hsl);
};
tinycolor.greyscale = function(color) {
return tinycolor.desaturate(color, 100);
};
tinycolor.lighten = function(color, amount) {
amount = (amount === 0) ? 0 : (amount || 10);
var hsl = tinycolor(color).toHsl();
hsl.l += amount / 100;
hsl.l = clamp01(hsl.l);
return tinycolor(hsl);
};
tinycolor.darken = function (color, amount) {
amount = (amount === 0) ? 0 : (amount || 10);
var hsl = tinycolor(color).toHsl();
hsl.l -= amount / 100;
hsl.l = clamp01(hsl.l);
return tinycolor(hsl);
};
tinycolor.complement = function(color) {
var hsl = tinycolor(color).toHsl();
hsl.h = (hsl.h + 180) % 360;
return tinycolor(hsl);
};
// Combination Functions
// ---------------------
// Thanks to jQuery xColor for some of the ideas behind these
// <https://github.com/infusion/jQuery-xcolor/blob/master/jquery.xcolor.js>
tinycolor.triad = function(color) {
var hsl = tinycolor(color).toHsl();
var h = hsl.h;
return [
tinycolor(color),
tinycolor({ h: (h + 120) % 360, s: hsl.s, l: hsl.l }),
tinycolor({ h: (h + 240) % 360, s: hsl.s, l: hsl.l })
];
};
tinycolor.tetrad = function(color) {
var hsl = tinycolor(color).toHsl();
var h = hsl.h;
return [
tinycolor(color),
tinycolor({ h: (h + 90) % 360, s: hsl.s, l: hsl.l }),
tinycolor({ h: (h + 180) % 360, s: hsl.s, l: hsl.l }),
tinycolor({ h: (h + 270) % 360, s: hsl.s, l: hsl.l })
];
};
tinycolor.splitcomplement = function(color) {
var hsl = tinycolor(color).toHsl();
var h = hsl.h;
return [
tinycolor(color),
tinycolor({ h: (h + 72) % 360, s: hsl.s, l: hsl.l}),
tinycolor({ h: (h + 216) % 360, s: hsl.s, l: hsl.l})
];
};
tinycolor.analogous = function(color, results, slices) {
results = results || 6;
slices = slices || 30;
var hsl = tinycolor(color).toHsl();
var part = 360 / slices;
var ret = [tinycolor(color)];
for (hsl.h = ((hsl.h - (part * results >> 1)) + 720) % 360; --results; ) {
hsl.h = (hsl.h + part) % 360;
ret.push(tinycolor(hsl));
}
return ret;
};
tinycolor.monochromatic = function(color, results) {
results = results || 6;
var hsv = tinycolor(color).toHsv();
var h = hsv.h, s = hsv.s, v = hsv.v;
var ret = [];
var modification = 1 / results;
while (results--) {
ret.push(tinycolor({ h: h, s: s, v: v}));
v = (v + modification) % 1;
}
return ret;
};
// Readability Functions
// ---------------------
// <http://www.w3.org/TR/AERT#color-contrast>
// `readability`
// Analyze the 2 colors and returns an object with the following properties:
// `brightness`: difference in brightness between the two colors
// `color`: difference in color/hue between the two colors
tinycolor.readability = function(color1, color2) {
var a = tinycolor(color1).toRgb();
var b = tinycolor(color2).toRgb();
var brightnessA = (a.r * 299 + a.g * 587 + a.b * 114) / 1000;
var brightnessB = (b.r * 299 + b.g * 587 + b.b * 114) / 1000;
var colorDiff = (
Math.max(a.r, b.r) - Math.min(a.r, b.r) +
Math.max(a.g, b.g) - Math.min(a.g, b.g) +
Math.max(a.b, b.b) - Math.min(a.b, b.b)
);
return {
brightness: Math.abs(brightnessA - brightnessB),
color: colorDiff
};
};
// `readable`
// http://www.w3.org/TR/AERT#color-contrast
// Ensure that foreground and background color combinations provide sufficient contrast.
// *Example*
// tinycolor.readable("#000", "#111") => false
tinycolor.readable = function(color1, color2) {
var readability = tinycolor.readability(color1, color2);
return readability.brightness > 125 && readability.color > 500;
};
// `mostReadable`
// Given a base color and a list of possible foreground or background
// colors for that base, returns the most readable color.
// *Example*
// tinycolor.mostReadable("#123", ["#fff", "#000"]) => "#000"
tinycolor.mostReadable = function(baseColor, colorList) {
var bestColor = null;
var bestScore = 0;
var bestIsReadable = false;
for (var i=0; i < colorList.length; i++) {
// We normalize both around the "acceptable" breaking point,
// but rank brightness constrast higher than hue.
var readability = tinycolor.readability(baseColor, colorList[i]);
var readable = readability.brightness > 125 && readability.color > 500;
var score = 3 * (readability.brightness / 125) + (readability.color / 500);
if ((readable && ! bestIsReadable) ||
(readable && bestIsReadable && score > bestScore) ||
((! readable) && (! bestIsReadable) && score > bestScore)) {
bestIsReadable = readable;
bestScore = score;
bestColor = tinycolor(colorList[i]);
}
}
return bestColor;
};
// Big List of Colors
// ------------------
// <http://www.w3.org/TR/css3-color/#svg-color>
var names = tinycolor.names = {
aliceblue: "f0f8ff",
antiquewhite: "faebd7",
aqua: "0ff",
aquamarine: "7fffd4",
azure: "f0ffff",
beige: "f5f5dc",
bisque: "ffe4c4",
black: "000",
blanchedalmond: "ffebcd",
blue: "00f",
blueviolet: "8a2be2",
brown: "a52a2a",
burlywood: "deb887",
burntsienna: "ea7e5d",
cadetblue: "5f9ea0",
chartreuse: "7fff00",
chocolate: "d2691e",
coral: "ff7f50",
cornflowerblue: "6495ed",
cornsilk: "fff8dc",
crimson: "dc143c",
cyan: "0ff",
darkblue: "00008b",
darkcyan: "008b8b",
darkgoldenrod: "b8860b",
darkgray: "a9a9a9",
darkgreen: "006400",
darkgrey: "a9a9a9",
darkkhaki: "bdb76b",
darkmagenta: "8b008b",
darkolivegreen: "556b2f",
darkorange: "ff8c00",
darkorchid: "9932cc",
darkred: "8b0000",
darksalmon: "e9967a",
darkseagreen: "8fbc8f",
darkslateblue: "483d8b",
darkslategray: "2f4f4f",
darkslategrey: "2f4f4f",
darkturquoise: "00ced1",
darkviolet: "9400d3",
deeppink: "ff1493",
deepskyblue: "00bfff",
dimgray: "696969",
dimgrey: "696969",
dodgerblue: "1e90ff",
firebrick: "b22222",
floralwhite: "fffaf0",
forestgreen: "228b22",
fuchsia: "f0f",
gainsboro: "dcdcdc",
ghostwhite: "f8f8ff",
gold: "ffd700",
goldenrod: "daa520",
gray: "808080",
green: "008000",
greenyellow: "adff2f",
grey: "808080",
honeydew: "f0fff0",
hotpink: "ff69b4",
indianred: "cd5c5c",
indigo: "4b0082",
ivory: "fffff0",
khaki: "f0e68c",
lavender: "e6e6fa",
lavenderblush: "fff0f5",
lawngreen: "7cfc00",
lemonchiffon: "fffacd",
lightblue: "add8e6",
lightcoral: "f08080",
lightcyan: "e0ffff",
lightgoldenrodyellow: "fafad2",
lightgray: "d3d3d3",
lightgreen: "90ee90",
lightgrey: "d3d3d3",
lightpink: "ffb6c1",
lightsalmon: "ffa07a",
lightseagreen: "20b2aa",
lightskyblue: "87cefa",
lightslategray: "789",
lightslategrey: "789",
lightsteelblue: "b0c4de",
lightyellow: "ffffe0",
lime: "0f0",
limegreen: "32cd32",
linen: "faf0e6",
magenta: "f0f",
maroon: "800000",
mediumaquamarine: "66cdaa",
mediumblue: "0000cd",
mediumorchid: "ba55d3",
mediumpurple: "9370db",
mediumseagreen: "3cb371",
mediumslateblue: "7b68ee",
mediumspringgreen: "00fa9a",
mediumturquoise: "48d1cc",
mediumvioletred: "c71585",
midnightblue: "191970",
mintcream: "f5fffa",
mistyrose: "ffe4e1",
moccasin: "ffe4b5",
navajowhite: "ffdead",
navy: "000080",
oldlace: "fdf5e6",
olive: "808000",
olivedrab: "6b8e23",
orange: "ffa500",
orangered: "ff4500",
orchid: "da70d6",
palegoldenrod: "eee8aa",
palegreen: "98fb98",
paleturquoise: "afeeee",
palevioletred: "db7093",
papayawhip: "ffefd5",
peachpuff: "ffdab9",
peru: "cd853f",
pink: "ffc0cb",
plum: "dda0dd",
powderblue: "b0e0e6",
purple: "800080",
red: "f00",
rosybrown: "bc8f8f",
royalblue: "4169e1",
saddlebrown: "8b4513",
salmon: "fa8072",
sandybrown: "f4a460",
seagreen: "2e8b57",
seashell: "fff5ee",
sienna: "a0522d",
silver: "c0c0c0",
skyblue: "87ceeb",
slateblue: "6a5acd",
slategray: "708090",
slategrey: "708090",
snow: "fffafa",
springgreen: "00ff7f",
steelblue: "4682b4",
tan: "d2b48c",
teal: "008080",
thistle: "d8bfd8",
tomato: "ff6347",
turquoise: "40e0d0",
violet: "ee82ee",
wheat: "f5deb3",
white: "fff",
whitesmoke: "f5f5f5",
yellow: "ff0",
yellowgreen: "9acd32"
};
// Make it easy to access colors via `hexNames[hex]`
var hexNames = tinycolor.hexNames = flip(names);
// Utilities
// ---------
// `{ 'name1': 'val1' }` becomes `{ 'val1': 'name1' }`
function flip(o) {
var flipped = { };
for (var i in o) {
if (o.hasOwnProperty(i)) {
flipped[o[i]] = i;
}
}
return flipped;
}
// Return a valid alpha value [0,1] with all invalid values being set to 1
function boundAlpha(a) {
a = parseFloat(a);
if (isNaN(a) || a < 0 || a > 1) {
a = 1;
}
return a;
}
// Take input from [0, n] and return it as [0, 1]
function bound01(n, max) {
if (isOnePointZero(n)) { n = "100%"; }
var processPercent = isPercentage(n);
n = mathMin(max, mathMax(0, parseFloat(n)));
// Automatically convert percentage into number
if (processPercent) {
n = parseInt(n * max, 10) / 100;
}
// Handle floating point rounding errors
if ((math.abs(n - max) < 0.000001)) {
return 1;
}
// Convert into [0, 1] range if it isn't already
return (n % max) / parseFloat(max);
}
// Force a number between 0 and 1
function clamp01(val) {
return mathMin(1, mathMax(0, val));
}
// Parse a base-16 hex value into a base-10 integer
function parseIntFromHex(val) {
return parseInt(val, 16);
}
// Need to handle 1.0 as 100%, since once it is a number, there is no difference between it and 1
// <http://stackoverflow.com/questions/7422072/javascript-how-to-detect-number-as-a-decimal-including-1-0>
function isOnePointZero(n) {
return typeof n == "string" && n.indexOf('.') != -1 && parseFloat(n) === 1;
}
// Check to see if string passed in is a percentage
function isPercentage(n) {
return typeof n === "string" && n.indexOf('%') != -1;
}
// Force a hex value to have 2 characters
function pad2(c) {
return c.length == 1 ? '0' + c : '' + c;
}
// Replace a decimal with it's percentage value
function convertToPercentage(n) {
if (n <= 1) {
n = (n * 100) + "%";
}
return n;
}
// Converts a decimal to a hex value
function convertDecimalToHex(d) {
return Math.round(parseFloat(d) * 255).toString(16);
}
// Converts a hex value to a decimal
function convertHexToDecimal(h) {
return (parseIntFromHex(h) / 255);
}
var matchers = (function() {
// <http://www.w3.org/TR/css3-values/#integers>
var CSS_INTEGER = "[-\\+]?\\d+%?";
// <http://www.w3.org/TR/css3-values/#number-value>
var CSS_NUMBER = "[-\\+]?\\d*\\.\\d+%?";
// Allow positive/negative integer/number. Don't capture the either/or, just the entire outcome.
var CSS_UNIT = "(?:" + CSS_NUMBER + ")|(?:" + CSS_INTEGER + ")";
// Actual matching.
// Parentheses and commas are optional, but not required.
// Whitespace can take the place of commas or opening paren
var PERMISSIVE_MATCH3 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?";
var PERMISSIVE_MATCH4 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?";
return {
rgb: new RegExp("rgb" + PERMISSIVE_MATCH3),
rgba: new RegExp("rgba" + PERMISSIVE_MATCH4),
hsl: new RegExp("hsl" + PERMISSIVE_MATCH3),
hsla: new RegExp("hsla" + PERMISSIVE_MATCH4),
hsv: new RegExp("hsv" + PERMISSIVE_MATCH3),
hex3: /^([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,
hex6: /^([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/,
hex8: /^([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/
};
})();
// `stringInputToObject`
// Permissive string parsing. Take in a number of formats, and output an object
// based on detected format. Returns `{ r, g, b }` or `{ h, s, l }` or `{ h, s, v}`
function stringInputToObject(color) {
color = color.replace(trimLeft,'').replace(trimRight, '').toLowerCase();
var named = false;
if (names[color]) {
color = names[color];
named = true;
}
else if (color == 'transparent') {
return { r: 0, g: 0, b: 0, a: 0, format: "name" };
}
// Try to match string input using regular expressions.
// Keep most of the number bounding out of this function - don't worry about [0,1] or [0,100] or [0,360]
// Just return an object and let the conversion functions handle that.
// This way the result will be the same whether the tinycolor is initialized with string or object.
var match;
if ((match = matchers.rgb.exec(color))) {
return { r: match[1], g: match[2], b: match[3] };
}
if ((match = matchers.rgba.exec(color))) {
return { r: match[1], g: match[2], b: match[3], a: match[4] };
}
if ((match = matchers.hsl.exec(color))) {
return { h: match[1], s: match[2], l: match[3] };
}
if ((match = matchers.hsla.exec(color))) {
return { h: match[1], s: match[2], l: match[3], a: match[4] };
}
if ((match = matchers.hsv.exec(color))) {
return { h: match[1], s: match[2], v: match[3] };
}
if ((match = matchers.hex8.exec(color))) {
return {
a: convertHexToDecimal(match[1]),
r: parseIntFromHex(match[2]),
g: parseIntFromHex(match[3]),
b: parseIntFromHex(match[4]),
format: named ? "name" : "hex8"
};
}
if ((match = matchers.hex6.exec(color))) {
return {
r: parseIntFromHex(match[1]),
g: parseIntFromHex(match[2]),
b: parseIntFromHex(match[3]),
format: named ? "name" : "hex"
};
}
if ((match = matchers.hex3.exec(color))) {
return {
r: parseIntFromHex(match[1] + '' + match[1]),
g: parseIntFromHex(match[2] + '' + match[2]),
b: parseIntFromHex(match[3] + '' + match[3]),
format: named ? "name" : "hex"
};
}
return false;
}
// Expose tinycolor to window, does not need to run in non-browser context.
window.tinycolor = tinycolor;
})();
$(function () {
if ($.fn.spectrum.load) {
$.fn.spectrum.processNativeColorInputs();
}
});
})(window, jQuery);
/**
* @class L.Control.Draw
* @aka L.Draw
*/
L.Control.Draw = L.Control.extend({
// Options
options: {
position: 'topleft',
draw: {},
edit: false
},
// @method initialize(): void
// Initializes draw control, toolbars from the options
initialize: function (options) {
if (L.version < '0.7') {
throw new Error('Leaflet.draw 0.2.3+ requires Leaflet 0.7.0+. Download latest from https://github.com/Leaflet/Leaflet/');
}
L.Control.prototype.initialize.call(this, options);
var toolbar;
this._toolbars = {};
// Initialize toolbars
if (L.DrawToolbar && this.options.draw) {
toolbar = new L.DrawToolbar(this.options.draw);
this._toolbars[L.DrawToolbar.TYPE] = toolbar;
// Listen for when toolbar is enabled
this._toolbars[L.DrawToolbar.TYPE].on('enable', this._toolbarEnabled, this);
}
if (L.EditToolbar && this.options.edit) {
toolbar = new L.EditToolbar(this.options.edit);
this._toolbars[L.EditToolbar.TYPE] = toolbar;
// Listen for when toolbar is enabled
this._toolbars[L.EditToolbar.TYPE].on('enable', this._toolbarEnabled, this);
}
L.toolbar = this; //set global var for editing the toolbar
},
// @method onAdd(): container
// Adds the toolbar container to the map
onAdd: function (map) {
var container = L.DomUtil.create('div', 'leaflet-draw'),
addedTopClass = false,
topClassName = 'leaflet-draw-toolbar-top',
toolbarContainer;
for (var toolbarId in this._toolbars) {
if (this._toolbars.hasOwnProperty(toolbarId)) {
toolbarContainer = this._toolbars[toolbarId].addToolbar(map);
if (toolbarContainer) {
// Add class to the first toolbar to remove the margin
if (!addedTopClass) {
if (!L.DomUtil.hasClass(toolbarContainer, topClassName)) {
L.DomUtil.addClass(toolbarContainer.childNodes[0], topClassName);
}
addedTopClass = true;
}
container.appendChild(toolbarContainer);
}
}
}
return container;
},
// @method onRemove(): void
// Removes the toolbars from the map toolbar container
onRemove: function () {
for (var toolbarId in this._toolbars) {
if (this._toolbars.hasOwnProperty(toolbarId)) {
this._toolbars[toolbarId].removeToolbar();
}
}
},
// @method setDrawingOptions(options): void
// Sets options to all toolbar instances
setDrawingOptions: function (options) {
for (var toolbarId in this._toolbars) {
if (this._toolbars[toolbarId] instanceof L.DrawToolbar) {
this._toolbars[toolbarId].setOptions(options);
}
}
},
_toolbarEnabled: function (e) {
var enabledToolbar = e.target;
for (var toolbarId in this._toolbars) {
if (this._toolbars[toolbarId] !== enabledToolbar) {
this._toolbars[toolbarId].disable();
}
}
}
});
L.Map.mergeOptions({
drawControlTooltips: true,
drawControl: false
});
L.Map.addInitHook(function () {
if (this.options.drawControl) {
this.drawControl = new L.Control.Draw();
this.addControl(this.drawControl);
}
});
/**
* ### Events
* Once you have successfully added the Leaflet.draw plugin to your map you will want to respond to the different
* actions users can initiate. The following events will be triggered on the map:
*
* @class L.Draw.Event
* @aka Draw.Event
*
* Use `L.Draw.Event.EVENTNAME` constants to ensure events are correct.
*
* @example
* ```js
* map.on(L.Draw.Event.CREATED; function (e) {
* var type = e.layerType,
* layer = e.layer;
*
* if (type === 'marker') {
* // Do marker specific actions
* }
*
* // Do whatever else you need to. (save to db; add to map etc)
* map.addLayer(layer);
*});
* ```
*/
L.Draw.Event = {};
/**
* @event draw:created: PolyLine; Polygon; Rectangle; Circle; Marker | String
*
* Layer that was just created.
* The type of layer this is. One of: `polyline`; `polygon`; `rectangle`; `circle`; `marker`
* Triggered when a new vector or marker has been created.
*
*/
L.Draw.Event.CREATED = 'draw:created';
/**
* @event draw:edited: LayerGroup
*
* List of all layers just edited on the map.
*
*
* Triggered when layers in the FeatureGroup; initialised with the plugin; have been edited and saved.
*
* @example
* ```js
* map.on('draw:edited', function (e) {
* var layers = e.layers;
* layers.eachLayer(function (layer) {
* //do whatever you want; most likely save back to db
* });
* });
* ```
*/
L.Draw.Event.EDITED = 'draw:edited';
/**
* @event draw:deleted: LayerGroup
*
* List of all layers just removed from the map.
*
* Triggered when layers have been removed (and saved) from the FeatureGroup.
*/
L.Draw.Event.DELETED = 'draw:deleted';
/**
* @event draw:drawstart: String
*
* The type of layer this is. One of:`polyline`; `polygon`; `rectangle`; `circle`; `marker`
*
* Triggered when the user has chosen to draw a particular vector or marker.
*/
L.Draw.Event.DRAWSTART = 'draw:drawstart';
/**
* @event draw:drawstop: String
*
* The type of layer this is. One of: `polyline`; `polygon`; `rectangle`; `circle`; `marker`
*
* Triggered when the user has finished a particular vector or marker.
*/
L.Draw.Event.DRAWSTOP = 'draw:drawstop';
/**
* @event draw:drawvertex: LayerGroup
*
* List of all layers just being added from the map.
*
* Triggered when a vertex is created on a polyline or polygon.
*/
L.Draw.Event.DRAWVERTEX = 'draw:drawvertex';
/**
* @event draw:editstart: String
*
* The type of edit this is. One of: `edit`
*
* Triggered when the user starts edit mode by clicking the edit tool button.
*/
L.Draw.Event.EDITSTART = 'draw:editstart';
/**
* @event draw:editmove: ILayer
*
* Layer that was just moved.
*
* Triggered as the user moves a rectangle; circle or marker.
*/
L.Draw.Event.EDITMOVE = 'draw:editmove';
/**
* @event draw:editresize: ILayer
*
* Layer that was just moved.
*
* Triggered as the user resizes a rectangle or circle.
*/
L.Draw.Event.EDITRESIZE = 'draw:editresize';
/**
* @event draw:editvertex: LayerGroup
*
* List of all layers just being edited from the map.
*
* Triggered when a vertex is edited on a polyline or polygon.
*/
L.Draw.Event.EDITVERTEX = 'draw:editvertex';
/**
* @event draw:editstop: String
*
* The type of edit this is. One of: `edit`
*
* Triggered when the user has finshed editing (edit mode) and saves edits.
*/
L.Draw.Event.EDITSTOP = 'draw:editstop';
/**
* @event draw:deletestart: String
*
* The type of edit this is. One of: `remove`
*
* Triggered when the user starts remove mode by clicking the remove tool button.
*/
L.Draw.Event.DELETESTART = 'draw:deletestart';
/**
* @event draw:deletestop: String
*
* The type of edit this is. One of: `remove`
*
* Triggered when the user has finished removing shapes (remove mode) and saves.
*/
L.Draw.Event.DELETESTOP = 'draw:deletestop';
/**
* @event draw:toolbaropened: String
*
* Triggered when a toolbar is opened.
*/
L.Draw.Event.TOOLBAROPENED = 'draw:toolbaropened';
/**
* @event draw:toolbarclosed: String
*
* Triggered when a toolbar is closed.
*/
L.Draw.Event.TOOLBARCLOSED = 'draw:toolbarclosed';
/**
* @event draw:markercontext: String
*
* Triggered when a marker is right clicked.
*/
L.Draw.Event.MARKERCONTEXT = 'draw:markercontext';
\ No newline at end of file
/**
* Leaflet.draw assumes that you have already included the Leaflet library.
*/
L.drawVersion = '0.4.2';
/**
* @class L.Draw
* @aka Draw
*
*
* To add the draw toolbar set the option drawControl: true in the map options.
*
* @example
* ```js
* var map = L.map('map', {drawControl: true}).setView([51.505, -0.09], 13);
*
* L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
* attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
* }).addTo(map);
* ```
*
* ### Adding the edit toolbar
* To use the edit toolbar you must initialise the Leaflet.draw control and manually add it to the map.
*
* ```js
* var map = L.map('map').setView([51.505, -0.09], 13);
*
* L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png', {
* attribution: '&copy; <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
* }).addTo(map);
*
* // FeatureGroup is to store editable layers
* var drawnItems = new L.FeatureGroup();
* map.addLayer(drawnItems);
*
* var drawControl = new L.Control.Draw({
* edit: {
* featureGroup: drawnItems
* }
* });
* map.addControl(drawControl);
* ```
*
* The key here is the featureGroup option. This tells the plugin which FeatureGroup contains the layers that
* should be editable. The featureGroup can contain 0 or more features with geometry types Point, LineString, and Polygon.
* Leaflet.draw does not work with multigeometry features such as MultiPoint, MultiLineString, MultiPolygon,
* or GeometryCollection. If you need to add multigeometry features to the draw plugin, convert them to a
* FeatureCollection of non-multigeometries (Points, LineStrings, or Polygons).
*/
L.Draw = {};
/**
* @class L.drawLocal
* @aka L.drawLocal
*
* The core toolbar class of the API — it is used to create the toolbar ui
*
* @example
* ```js
* var modifiedDraw = L.drawLocal.extend({
* draw: {
* toolbar: {
* buttons: {
* polygon: 'Draw an awesome polygon'
* }
* }
* }
* });
* ```
*
* The default state for the control is the draw toolbar just below the zoom control.
* This will allow map users to draw vectors and markers.
* **Please note the edit toolbar is not enabled by default.**
*/
L.drawLocal = {
// format: {
// numeric: {
// delimiters: {
// thousands: ',',
// decimal: '.'
// }
// }
// },
draw: {
toolbar: {
// #TODO: this should be reorganized where actions are nested in actions
// ex: actions.undo or actions.cancel
actions: {
title: 'Cancel drawing',
text: 'Cancel'
},
finish: {
title: 'Finish drawing',
text: 'Finish'
},
undo: {
title: 'Delete last point drawn',
text: 'Delete last point'
},
buttons: {
polyline: 'Draw a polyline',
polygon: 'Draw a polygon',
rectangle: 'Draw a rectangle',
circle: 'Draw a circle',
marker: 'Draw a marker',
circlemarker: 'Draw a circlemarker'
}
},
handlers: {
circle: {
tooltip: {
start: 'Click and drag to draw circle.'
},
radius: 'Radius'
},
circlemarker: {
tooltip: {
start: 'Click map to place circle marker.'
}
},
marker: {
tooltip: {
start: 'Click map to place marker.'
}
},
polygon: {
tooltip: {
start: 'Click to start drawing shape.',
cont: 'Click to continue drawing shape.',
end: 'Click first point to close this shape.'
}
},
polyline: {
error: '<strong>Error:</strong> shape edges cannot cross!',
tooltip: {
start: 'Click to start drawing line.',
cont: 'Click to continue drawing line.',
end: 'Click last point to finish line.'
}
},
rectangle: {
tooltip: {
start: 'Click and drag to draw rectangle.'
}
},
simpleshape: {
tooltip: {
end: 'Release mouse to finish drawing.'
}
}
}
},
edit: {
toolbar: {
actions: {
save: {
title: 'Save changes',
text: 'Save'
},
cancel: {
title: 'Cancel editing, discards all changes',
text: 'Cancel'
},
clearAll: {
title: 'Clear all layers',
text: 'Clear All'
}
},
buttons: {
edit: 'Edit layers',
editDisabled: 'No layers to edit',
remove: 'Delete layers',
removeDisabled: 'No layers to delete'
}
},
handlers: {
edit: {
tooltip: {
text: 'Drag handles or markers to edit features.',
subtext: 'Click cancel to undo changes.'
}
},
remove: {
tooltip: {
text: 'Click on a feature to remove.'
}
}
}
}
};
/**
* @class L.Draw.Toolbar
* @aka Toolbar
*
* The toolbar class of the API — it is used to create the ui
* This will be depreciated
*
* @example
*
* ```js
* var toolbar = L.Toolbar();
* toolbar.addToolbar(map);
* ```
*
* ### Disabling a toolbar
*
* If you do not want a particular toolbar in your app you can turn it off by setting the toolbar to false.
*
* ```js
* var drawControl = new L.Control.Draw({
* draw: false,
* edit: {
* featureGroup: editableLayers
* }
* });
* ```
*
* ### Disabling a toolbar item
*
* If you want to turn off a particular toolbar item, set it to false. The following disables drawing polygons and
* markers. It also turns off the ability to edit layers.
*
* ```js
* var drawControl = new L.Control.Draw({
* draw: {
* polygon: false,
* marker: false
* },
* edit: {
* featureGroup: editableLayers,
* edit: false
* }
* });
* ```
*/
L.Toolbar = L.Class.extend({
// @section Methods for modifying the toolbar
// @method initialize(options): void
// Toolbar constructor
initialize: function (options) {
L.setOptions(this, options);
this._modes = {};
this._actionButtons = [];
this._activeMode = null;
var version = L.version.split('.');
//If Version is >= 1.2.0
if (parseInt(version[0], 10) === 1 && parseInt(version[1], 10) >= 2) {
L.Toolbar.include(L.Evented.prototype);
} else {
L.Toolbar.include(L.Mixin.Events);
}
},
// @method enabled(): boolean
// Gets a true/false of whether the toolbar is enabled
enabled: function () {
return this._activeMode !== null;
},
// @method disable(): void
// Disables the toolbar
disable: function () {
if (!this.enabled()) {
return;
}
this._activeMode.handler.disable();
},
// @method addToolbar(map): L.DomUtil
// Adds the toolbar to the map and returns the toolbar dom element
addToolbar: function (map) {
var container = L.DomUtil.create('div', 'leaflet-draw-section'),
buttonIndex = 0,
buttonClassPrefix = this._toolbarClass || '',
modeHandlers = this.getModeHandlers(map),
i;
this._toolbarContainer = L.DomUtil.create('div', 'leaflet-draw-toolbar leaflet-bar');
this._map = map;
for (i = 0; i < modeHandlers.length; i++) {
if (modeHandlers[i].enabled) {
this._initModeHandler(
modeHandlers[i].handler,
this._toolbarContainer,
buttonIndex++,
buttonClassPrefix,
modeHandlers[i].title
);
}
}
// if no buttons were added, do not add the toolbar
if (!buttonIndex) {
return;
}
// Save button index of the last button, -1 as we would have ++ after the last button
this._lastButtonIndex = --buttonIndex;
// Create empty actions part of the toolbar
this._actionsContainer = L.DomUtil.create('ul', 'leaflet-draw-actions');
// Add draw and cancel containers to the control container
container.appendChild(this._toolbarContainer);
container.appendChild(this._actionsContainer);
return container;
},
// @method removeToolbar(): void
// Removes the toolbar and drops the handler event listeners
removeToolbar: function () {
// Dispose each handler
for (var handlerId in this._modes) {
if (this._modes.hasOwnProperty(handlerId)) {
// Unbind handler button
this._disposeButton(
this._modes[handlerId].button,
this._modes[handlerId].handler.enable,
this._modes[handlerId].handler
);
// Make sure is disabled
this._modes[handlerId].handler.disable();
// Unbind handler
this._modes[handlerId].handler
.off('enabled', this._handlerActivated, this)
.off('disabled', this._handlerDeactivated, this);
}
}
this._modes = {};
// Dispose the actions toolbar
for (var i = 0, l = this._actionButtons.length; i < l; i++) {
this._disposeButton(
this._actionButtons[i].button,
this._actionButtons[i].callback,
this
);
}
this._actionButtons = [];
this._actionsContainer = null;
},
_initModeHandler: function (handler, container, buttonIndex, classNamePredix, buttonTitle) {
var type = handler.type;
this._modes[type] = {};
this._modes[type].handler = handler;
this._modes[type].button = this._createButton({
type: type,
title: buttonTitle,
className: classNamePredix + '-' + type,
container: container,
callback: this._modes[type].handler.enable,
context: this._modes[type].handler
});
this._modes[type].buttonIndex = buttonIndex;
this._modes[type].handler
.on('enabled', this._handlerActivated, this)
.on('disabled', this._handlerDeactivated, this);
},
/* Detect iOS based on browser User Agent, based on:
* http://stackoverflow.com/a/9039885 */
_detectIOS: function () {
var iOS = (/iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream);
return iOS;
},
_createButton: function (options) {
var link = L.DomUtil.create('a', options.className || '', options.container);
// Screen reader tag
var sr = L.DomUtil.create('span', 'sr-only', options.container);
link.href = '#';
link.appendChild(sr);
if (options.title) {
link.title = options.title;
sr.innerHTML = options.title;
}
if (options.text) {
link.innerHTML = options.text;
sr.innerHTML = options.text;
}
/* iOS does not use click events */
var buttonEvent = this._detectIOS() ? 'touchstart' : 'click';
L.DomEvent
.on(link, 'click', L.DomEvent.stopPropagation)
.on(link, 'mousedown', L.DomEvent.stopPropagation)
.on(link, 'dblclick', L.DomEvent.stopPropagation)
.on(link, 'touchstart', L.DomEvent.stopPropagation)
.on(link, 'click', L.DomEvent.preventDefault)
.on(link, buttonEvent, options.callback, options.context);
return link;
},
_disposeButton: function (button, callback) {
/* iOS does not use click events */
var buttonEvent = this._detectIOS() ? 'touchstart' : 'click';
L.DomEvent
.off(button, 'click', L.DomEvent.stopPropagation)
.off(button, 'mousedown', L.DomEvent.stopPropagation)
.off(button, 'dblclick', L.DomEvent.stopPropagation)
.off(button, 'touchstart', L.DomEvent.stopPropagation)
.off(button, 'click', L.DomEvent.preventDefault)
.off(button, buttonEvent, callback);
},
_handlerActivated: function (e) {
// Disable active mode (if present)
this.disable();
// Cache new active feature
this._activeMode = this._modes[e.handler];
L.DomUtil.addClass(this._activeMode.button, 'leaflet-draw-toolbar-button-enabled');
this._showActionsToolbar();
this.fire('enable');
},
_handlerDeactivated: function () {
this._hideActionsToolbar();
L.DomUtil.removeClass(this._activeMode.button, 'leaflet-draw-toolbar-button-enabled');
this._activeMode = null;
this.fire('disable');
},
_createActions: function (handler) {
var container = this._actionsContainer,
buttons = this.getActions(handler),
l = buttons.length,
li, di, dl, button;
// Dispose the actions toolbar (todo: dispose only not used buttons)
for (di = 0, dl = this._actionButtons.length; di < dl; di++) {
this._disposeButton(this._actionButtons[di].button, this._actionButtons[di].callback);
}
this._actionButtons = [];
// Remove all old buttons
while (container.firstChild) {
container.removeChild(container.firstChild);
}
for (var i = 0; i < l; i++) {
if ('enabled' in buttons[i] && !buttons[i].enabled) {
continue;
}
li = L.DomUtil.create('li', '', container);
button = this._createButton({
title: buttons[i].title,
text: buttons[i].text,
container: li,
callback: buttons[i].callback,
context: buttons[i].context
});
this._actionButtons.push({
button: button,
callback: buttons[i].callback
});
}
},
_showActionsToolbar: function () {
var buttonIndex = this._activeMode.buttonIndex,
lastButtonIndex = this._lastButtonIndex,
toolbarPosition = this._activeMode.button.offsetTop - 1;
// Recreate action buttons on every click
this._createActions(this._activeMode.handler);
// Correctly position the cancel button
this._actionsContainer.style.top = toolbarPosition + 'px';
if (buttonIndex === 0) {
L.DomUtil.addClass(this._toolbarContainer, 'leaflet-draw-toolbar-notop');
L.DomUtil.addClass(this._actionsContainer, 'leaflet-draw-actions-top');
}
if (buttonIndex === lastButtonIndex) {
L.DomUtil.addClass(this._toolbarContainer, 'leaflet-draw-toolbar-nobottom');
L.DomUtil.addClass(this._actionsContainer, 'leaflet-draw-actions-bottom');
}
this._actionsContainer.style.display = 'block';
this._map.fire(L.Draw.Event.TOOLBAROPENED);
},
_hideActionsToolbar: function () {
this._actionsContainer.style.display = 'none';
L.DomUtil.removeClass(this._toolbarContainer, 'leaflet-draw-toolbar-notop');
L.DomUtil.removeClass(this._toolbarContainer, 'leaflet-draw-toolbar-nobottom');
L.DomUtil.removeClass(this._actionsContainer, 'leaflet-draw-actions-top');
L.DomUtil.removeClass(this._actionsContainer, 'leaflet-draw-actions-bottom');
this._map.fire(L.Draw.Event.TOOLBARCLOSED);
}
});
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment