1/* 2GEOLET version 20.12.31 3Copyright (c) 2020 Ruben Holthuijsen; available under the MIT license 4https://github.com/rhlt/leaflet-geolet/ 5*/ 6 7(function () { 8 9 var _consolePrefix = '[GEOLET] '; 10 var L = window.L; 11 12 if (!L || !L.map) { 13 //Was Leaflet loaded correctly? 14 console.error(_consolePrefix + 'Missing Leaflet'); 15 return; 16 } 17 18 var _merge = function (object1, object2) { 19 //Merge all properties from object 2 into object 1, recursively for plain objects 20 21 if (typeof object2 != 'object' || object2 === null) 22 return object1; 23 if (typeof object1 != 'object' || object1 === null) 24 object1 = {}; 25 26 for (key in object2) if (({}).hasOwnProperty.call(object2, key)) { 27 if (typeof object2[key] == 'object' && object2[key] !== null && Object.getPrototypeOf(object2[key]) == Object.getPrototypeOf({})) { 28 //Plain object: merge the next level 29 object1[key] = _merge(object1[key], object2[key]); 30 } else { 31 //Anything else (including typed objects): just assign it 32 object1[key] = object2[key]; 33 } 34 } 35 36 return object1; 37 }; 38 39 var _defaultMarker = function (controlOptions) { 40 //Generate a default marker 41 return L.marker(null, { 42 icon: L.divIcon({ 43 html: '<svg width="20" height="20" viewport="0 0 20 20"><circle cx="10" cy="10" r="10" style="fill:white"/><circle cx="10" cy="10" r="7" style="fill:none;stroke:currentColor;stroke-width:2px"/><circle cx="10" cy="10" r="4" style="fill:currentColor"/></svg>', 44 iconAnchor: [10, 10], 45 className: '' 46 }), 47 attribution: '<a href="https://github.com/rhlt/leaflet-geolet" target="_blank">Geolet</a>', 48 zIndexOffset: 1000 49 }); 50 }; 51 52 53 L.Geolet = L.Control.extend({ 54 55 options: { 56 title: 'Find current location', 57 className: null, 58 activeClassName: null, 59 style: { display: 'flex', color: '' }, 60 activeStyle: { display: 'flex', color: '#E00' }, 61 html: '<svg width="16" height="16" viewport="0 0 16 16" style="margin:auto auto"><circle cx="8" cy="8" r="7" style="fill:none;stroke:currentColor;stroke-width:2px"/><circle cx="8" cy="8" r="4" style="fill:currentColor"/></svg>', 62 geoOptions: { enableHighAccuracy: true, maximumAge: 30000, timeout: 27000 }, 63 marker: null, 64 popup: null, 65 popupContent: null, 66 updatePopupWhenOpen: true, 67 autoPan: true, 68 minZoom: 9 69 }, 70 71 _a: null, 72 _map: null, 73 _watchId: null, 74 _latLng: null, 75 _popupContent: null, 76 _first: false, 77 78 marker: null, 79 popup: null, 80 81 initialize: function (options) { 82 //Set control options 83 if (typeof options == 'object' && options !== null) 84 L.setOptions(this, options); 85 }, 86 87 isActive: function () { 88 //Is the control active (are we displaying the current location, or trying to obtain it)? 89 return this._watchId ? true : false; 90 }, 91 92 getLatLng: function () { 93 //Returns the coordinates of the location currently displayed on the map (if any) -- might still be null if isActive() 94 return this.isActive() ? this._latLng : null; 95 }, 96 97 updatePopup: function () { 98 //Update the popup with new content 99 var popupContent; 100 if (!this._popup) 101 return; 102 if (typeof this.options.popupContent == 'undefined' || this.options.popupContent === null) { 103 popupContent = '<b>' + L.Geolet.formatLatLng(this.getLatLng()) + '</b>'; 104 } else if (typeof this.options.popupContent == 'function') { 105 popupContent = this.options.popupContent.call(this, this.getLatLng()); 106 } else if (this.options.popupContent) { 107 popupContent = this.options.popupContent; 108 } 109 if (popupContent !== null) 110 this._popup.setContent(popupContent); 111 }, 112 113 activate: function () { 114 //Activate the current location display 115 116 if (!L.Geolet.browserSupport) 117 return; 118 119 this.styleAnchor(true); 120 121 var control = this; 122 123 var geoSuccessCallback = function (data) { 124 var first = !!control._first; 125 control._latLng = L.latLng(data.coords.latitude, data.coords.longitude, data.coords.altitude); 126 control._popupContent = control.options.popupContent; 127 if (control._popup) { 128 if (control._popup.isOpen() && control.options.updatePopupWhenOpen) 129 control.updatePopup(); 130 } 131 if (control._marker) { 132 control._marker.setLatLng(control._latLng); 133 control._marker.addTo(control._map); 134 } 135 if (control._first) { 136 control._first = false;
137 if (control.options.autoPan) 138 control._map.setView(control._latLng, control.options.minZoom ? Math.max(control._map.getZoom(), control.options.minZoom) : control._map.getZoom()); 139 } 140 control._map.fire('geolet_success', { 141 control: control, 142 first: first, 143 marker: control._marker, 144 latlng: control._latLng, //"latlng" all-lowercase for consistency with Leaflet's MouseEvent 145 raw: data 146 }); 147 }; 148 149 var geoErrorCallback = function (data) { 150 control.deactivate(); 151 console.warn(_consolePrefix + data.message); 152 control._map.fire('geolet_error', { 153 control: control, 154 raw: data 155 }); 156 }; 157 158 this._first = true; 159 this._watchId = navigator.geolocation.watchPosition(geoSuccessCallback, geoErrorCallback, this.options.geoOptions); 160 }, 161 162 deactivate: function () { 163 //Deactivate current location display 164 165 this.styleAnchor(false); 166 167 if (this.isActive()) { 168 navigator.geolocation.clearWatch(this._watchId); 169 this._watchId = null; 170 } 171 172 this._latLng = null; 173 174 if (this._marker) 175 this._marker.remove(); 176 if (this._popup) 177 this._popup.remove(); 178 }, 179 180 styleAnchor: function (active) { 181 //Apply CSS classes and styles to the button's <a> element 182 183 var className = []; 184 if (!this._a) 185 return; 186 if (this.options.className) 187 className.push(this.options.className); 188 if (active && this.options.activeClassName) 189 className.push(this.options.activeClassName); 190 if (className.length) { 191 this._a.className = className.join(' '); 192 } else { 193 this._a.className = ''; 194 } 195 if (active && this.options.activeStyle) 196 _merge(this._a.style, this.options.activeStyle); 197 if (!active && this.options.style) 198 _merge(this._a.style, this.options.style); 199 }, 200 201 onAdd: function (map) { 202 //Initialize everything when the control is added 203 204 var control = this; 205 var el = L.DomUtil.create('div'); 206 this._map = map; 207 208 if (!L.Geolet.browserSupport) { 209 console.warn(_consolePrefix + 'Browser does not support Geolocation'); 210 el.style.display = 'none'; 211 return el; 212 } 213 214 if (this._marker) 215 this._marker.remove(); 216 if (typeof this.options.marker == 'function') { 217 this._marker = this.options.marker.call(this, map); 218 } else if (this.options.marker) { 219 this._marker = this.options.marker; 220 } else if (typeof this.options.marker == 'undefined' || this.options.marker === null) { 221 this._marker = _defaultMarker(); 222 } else { 223 this._marker = null; 224 } 225 226 if (this._popup) 227 this._popup.remove(); 228 if (typeof this.options.popup == 'function') { 229 this._popup = this.options.popup.call(this, map); 230 } else if (this.options.popup) { 231 this._popup = this.options.popup; 232 } else if (typeof this.options.popup == 'undefined' || this.options.popup === null) { 233 this._popup = L.popup({ autoPan: this.options.autoPan }); 234 } else { 235 this._popup = null; 236 } 237 238 if (this._marker && this._popup) { 239 this._marker.bindPopup(this._popup); 240 this._marker.on('popupopen', function () { control.updatePopup(); }); 241 } 242 243 el.className = 'leaflet-bar leaflet-control'; 244 245 this._a = document.createElement('a'); 246 this._a.setAttribute('href', '#'); 247 if (this.options.title) 248 this._a.setAttribute('title', this.options.title); 249 250 this.styleAnchor(); 251 252 this._a.addEventListener('click', function (event) { 253 if (!control.isActive()) { 254 //Currently inactive 255 control.activate(); 256 } else { 257 //Currently active 258 control.deactivate(); 259 } 260 event.preventDefault(); 261 event.stopPropagation(); 262 }); 263 264 this._a.addEventListener('dblclick', function (event) { 265 //Ignore double clicks 266 event.stopPropagation(); 267 }); 268 269 if (this.options.html) 270 this._a.innerHTML = this.options.html; 271 el.appendChild(this._a); 272 273 return el; 274 }, 275 276 onRemove: function (map) { 277 //Deinitialize everything when the control is removed 278 this.deactivate(); 279 this._a = null; 280 this._map = null; 281 this._popup = null; 282 this._marker = null; 283 } 284 }); 285 286 287 //Browser support test 288 L.Geolet.browserSupport = !!(navigator && navigator.geolocation && navigator.geolocation.watchPosition); 289 290 //Format coordinates (for use in the default pop up) 291 L.Geolet.formatSymbols = {}; 292 L.Geolet.formatLatLng = function (latLng, l, a) { 293 294 latLng = L.latLng(latLng, l, a); 295 if (!latLng) 296 return; 297 298 var result = [];
299 var symbols = _merge({ deg: '°', min: '’', sec: '”', N: 'N', E: 'E', S: 'S', W: 'W', space: ' ', comma: ', ' }, L.Geolet.formatSymbols); 300 301 ['lat', 'lng'].forEach(function (key) { 302 var dir = (key == 'lat' ? (latLng[key] < 0 ? symbols.S : symbols.N) : (latLng[key] < 0 ? symbols.W : symbols.E)); 303 var val = Math.round(Math.abs(latLng[key]) * 3600) / 3600; 304 var deg = Math.floor(val) + symbols.deg; 305 var min = Math.floor(val * 60) % 60 + symbols.min; 306 var sec = Math.floor(val * 3600) % 60 + symbols.sec; 307 result.push([deg, min, sec, dir].join(symbols.space)); 308 }); 309 310 return result.join(symbols.comma); 311 }; 312 313 //Factory function 314 L.geolet = function (options) { 315 return new L.Geolet(options); 316 }; 317 318})()
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.