forked from MapComplete/MapComplete
		
	Add geolocation button which uses device GPS
This commit is contained in:
		
							parent
							
								
									57c9fcc5aa
								
							
						
					
					
						commit
						a566ab6725
					
				
					 6 changed files with 299 additions and 32 deletions
				
			
		
							
								
								
									
										107
									
								
								Logic/GeoLocationHandler.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								Logic/GeoLocationHandler.ts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,107 @@
 | 
				
			||||||
 | 
					import {Basemap} from "./Basemap";
 | 
				
			||||||
 | 
					import {UIEventSource} from "../UI/UIEventSource";
 | 
				
			||||||
 | 
					import {UIElement} from "../UI/UIElement";
 | 
				
			||||||
 | 
					import L from "leaflet";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export class GeoLocationHandler extends UIElement {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    currentLocation: UIEventSource<{
 | 
				
			||||||
 | 
					        latlng: number,
 | 
				
			||||||
 | 
					        accuracy: number
 | 
				
			||||||
 | 
					    }> = new UIEventSource<{ latlng: number, accuracy: number }>(undefined);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private _isActive: UIEventSource<boolean> = new UIEventSource<boolean>(false);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private _map: Basemap;
 | 
				
			||||||
 | 
					    private _marker: any;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constructor(map: Basemap) {
 | 
				
			||||||
 | 
					        super(undefined);
 | 
				
			||||||
 | 
					        this._map = map;
 | 
				
			||||||
 | 
					        this.ListenTo(this.currentLocation);
 | 
				
			||||||
 | 
					        this.ListenTo(this._isActive);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const self = this;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        function onAccuratePositionProgress(e) {
 | 
				
			||||||
 | 
					            console.log(e.accuracy);
 | 
				
			||||||
 | 
					            console.log(e.latlng);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        function onAccuratePositionFound(e) {
 | 
				
			||||||
 | 
					            console.log(e.accuracy);
 | 
				
			||||||
 | 
					            console.log(e.latlng);
 | 
				
			||||||
 | 
					            self.currentLocation.setData({latlng: e.latlng, accuracy: e.accuracy});
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        function onAccuratePositionError(e) {
 | 
				
			||||||
 | 
					            console.log("onerror", e.message);
 | 
				
			||||||
 | 
					           
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        map.map.on('accuratepositionprogress', onAccuratePositionProgress);
 | 
				
			||||||
 | 
					        map.map.on('accuratepositionfound', onAccuratePositionFound);
 | 
				
			||||||
 | 
					        map.map.on('accuratepositionerror', onAccuratePositionError);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const icon = L.icon(
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                iconUrl: './assets/crosshair-blue.svg',
 | 
				
			||||||
 | 
					                iconSize: [40, 40], // size of the icon
 | 
				
			||||||
 | 
					                iconAnchor: [20, 20], // point of the icon which will correspond to marker's location
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.currentLocation.addCallback((location) => {
 | 
				
			||||||
 | 
					            const newMarker = L.marker(location.latlng, {icon: icon});
 | 
				
			||||||
 | 
					            newMarker.addTo(map.map);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (self._marker !== undefined) {
 | 
				
			||||||
 | 
					                map.map.removeLayer(self._marker);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            self._marker = newMarker;
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        navigator.permissions.query({ name: 'geolocation' })
 | 
				
			||||||
 | 
					            .then(function(){self.StartGeolocating()});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected InnerRender(): string {
 | 
				
			||||||
 | 
					        if (this.currentLocation.data) {
 | 
				
			||||||
 | 
					            return "<img src='./assets/crosshair-blue.svg' alt='locate me'>";
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (this._isActive.data) {
 | 
				
			||||||
 | 
					            return "<img src='./assets/crosshair-blue-center.svg' alt='locate me'>";
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return "<img src='./assets/crosshair.svg' alt='locate me'>";
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    private StartGeolocating(){
 | 
				
			||||||
 | 
					        const self = this;
 | 
				
			||||||
 | 
					        if (self.currentLocation.data !== undefined) {
 | 
				
			||||||
 | 
					            self._map.map.flyTo(self.currentLocation.data.latlng, 18);
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self._isActive.setData(true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        console.log("Searching location using GPS")
 | 
				
			||||||
 | 
					        self._map.map.findAccuratePosition({
 | 
				
			||||||
 | 
					            maxWait: 15000, // defaults to 10000
 | 
				
			||||||
 | 
					            desiredAccuracy: 30 // defaults to 20
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    InnerUpdate(htmlElement: HTMLElement) {
 | 
				
			||||||
 | 
					        super.InnerUpdate(htmlElement);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        const self = this;
 | 
				
			||||||
 | 
					        htmlElement.onclick = function () {
 | 
				
			||||||
 | 
					            self.StartGeolocating();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -95,13 +95,12 @@ export class LayerUpdater {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private buildBboxFor(): string {
 | 
					    private buildBboxFor(): string {
 | 
				
			||||||
        const b = this._map.map.getBounds();
 | 
					        const b = this._map.map.getBounds();
 | 
				
			||||||
        const latDiff = Math.abs(b.getNorth() - b.getSouth());
 | 
					        const diff =0.07;
 | 
				
			||||||
        const lonDiff = Math.abs(b.getEast() - b.getWest());
 | 
					        
 | 
				
			||||||
        const extra = 0.5;
 | 
					        const n = b.getNorth() + diff;
 | 
				
			||||||
        const n = b.getNorth() + latDiff * extra;
 | 
					        const e = b.getEast() +  diff;
 | 
				
			||||||
        const e = b.getEast() + lonDiff * extra;
 | 
					        const s = b.getSouth() - diff;
 | 
				
			||||||
        const s = b.getSouth() - latDiff * extra;
 | 
					        const w = b.getWest() -  diff;
 | 
				
			||||||
        const w = b.getWest() - lonDiff * extra;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
        this.previousBounds = {north: n, east: e, south: s, west: w};
 | 
					        this.previousBounds = {north: n, east: e, south: s, west: w};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										67
									
								
								index.css
									
										
									
									
									
								
							
							
						
						
									
										67
									
								
								index.css
									
										
									
									
									
								
							| 
						 | 
					@ -16,6 +16,26 @@ img {
 | 
				
			||||||
    border-radius: 1em;
 | 
					    border-radius: 1em;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#geolocate-button {
 | 
				
			||||||
 | 
					    position: absolute;
 | 
				
			||||||
 | 
					    bottom: 27px;
 | 
				
			||||||
 | 
					    right: 65px;
 | 
				
			||||||
 | 
					    z-index: 999; /*Just below leaflets zoom*/
 | 
				
			||||||
 | 
					    background-color: white;
 | 
				
			||||||
 | 
					    border-radius: 5px;
 | 
				
			||||||
 | 
					    border: solid 2px rgba(0,0,0,0.2);
 | 
				
			||||||
 | 
					    cursor: pointer;
 | 
				
			||||||
 | 
					    width: 43px;
 | 
				
			||||||
 | 
					    height:43px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#geolocate-button img{
 | 
				
			||||||
 | 
					    width: 31px;
 | 
				
			||||||
 | 
					    height:31px;
 | 
				
			||||||
 | 
					    margin: 6px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**************** GENERIC ****************/
 | 
					/**************** GENERIC ****************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.uielement {
 | 
					.uielement {
 | 
				
			||||||
| 
						 | 
					@ -145,9 +165,9 @@ img {
 | 
				
			||||||
#welcomeMessage {
 | 
					#welcomeMessage {
 | 
				
			||||||
    display: inline-block;
 | 
					    display: inline-block;
 | 
				
			||||||
    max-width: 30em;
 | 
					    max-width: 30em;
 | 
				
			||||||
 | 
					    padding: 1em;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
#messagesboxmobilewrapper {
 | 
					#messagesboxmobilewrapper {
 | 
				
			||||||
    display: none; /*Only shown on small screens*/
 | 
					    display: none; /*Only shown on small screens*/
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -190,30 +210,33 @@ img {
 | 
				
			||||||
    #messagesboxmobile-scroll {
 | 
					    #messagesboxmobile-scroll {
 | 
				
			||||||
        display: block;
 | 
					        display: block;
 | 
				
			||||||
        overflow-y: auto;
 | 
					        overflow-y: auto;
 | 
				
			||||||
        height: calc(100vh - 9em);
 | 
					        width: 100vw;
 | 
				
			||||||
        padding-top: 1em;
 | 
					        padding: 0;
 | 
				
			||||||
        padding-bottom: 2em;
 | 
					        margin:0;
 | 
				
			||||||
        margin-bottom: 0;
 | 
					        height: calc(100% - 5em); /*Height of to-the-map is 2em, padding is 2 * 0.5em*/
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    #messagesboxmobile {
 | 
					    #messagesboxmobile {
 | 
				
			||||||
        margin: 1em;
 | 
					        margin: 1em;
 | 
				
			||||||
        margin-bottom: 2em;
 | 
					        padding-bottom: 2em;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#to-the-map {
 | 
					#to-the-map {
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    height: 4em;
 | 
				
			||||||
 | 
					    padding: 0.5em;
 | 
				
			||||||
    margin: 0;
 | 
					    margin: 0;
 | 
				
			||||||
    padding: 1em;
 | 
					    
 | 
				
			||||||
    padding-right: 2em;
 | 
					 | 
				
			||||||
    color: white;
 | 
					 | 
				
			||||||
    background-color: #7ebc6f;
 | 
					 | 
				
			||||||
    position: absolute;
 | 
					    position: absolute;
 | 
				
			||||||
    bottom: 0;
 | 
					    bottom: 0;
 | 
				
			||||||
    right: 0;
 | 
					    right: 0;
 | 
				
			||||||
    text-align: right;
 | 
					    
 | 
				
			||||||
 | 
					    padding-right: 2em;
 | 
				
			||||||
    width: 100%;
 | 
					    width: 100%;
 | 
				
			||||||
    height: 4em;
 | 
					    text-align: right;
 | 
				
			||||||
 | 
					    color: white;
 | 
				
			||||||
 | 
					    background-color: #7ebc6f;
 | 
				
			||||||
    cursor: pointer;
 | 
					    cursor: pointer;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -228,6 +251,7 @@ img {
 | 
				
			||||||
    padding: 0;
 | 
					    padding: 0;
 | 
				
			||||||
    right: 1em;
 | 
					    right: 1em;
 | 
				
			||||||
    top: 1em;
 | 
					    top: 1em;
 | 
				
			||||||
 | 
					    border-radius: 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#centermessage {
 | 
					#centermessage {
 | 
				
			||||||
| 
						 | 
					@ -319,8 +343,7 @@ img {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    content:url(assets/arrow-left-smooth.svg);
 | 
					    content:url(assets/arrow-left-smooth.svg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    border-bottom-left-radius: 1em;
 | 
					    border-radius: 1em;
 | 
				
			||||||
    border-top-left-radius: 1em;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -335,8 +358,7 @@ img {
 | 
				
			||||||
    top: 50%;
 | 
					    top: 50%;
 | 
				
			||||||
    right: 0;
 | 
					    right: 0;
 | 
				
			||||||
    transform: translate(0, -50%);
 | 
					    transform: translate(0, -50%);
 | 
				
			||||||
    border-bottom-right-radius: 1em;
 | 
					    border-radius: 1em;
 | 
				
			||||||
    border-top-right-radius: 1em;
 | 
					 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    z-index: 5060;
 | 
					    z-index: 5060;
 | 
				
			||||||
| 
						 | 
					@ -345,11 +367,12 @@ img {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.slide > span > img {
 | 
					.slide > span img {
 | 
				
			||||||
    width: 500px;
 | 
					 | 
				
			||||||
    max-width: 100%;
 | 
					 | 
				
			||||||
    height: auto;
 | 
					    height: auto;
 | 
				
			||||||
    
 | 
					    width: auto;
 | 
				
			||||||
 | 
					    max-width: 100%;
 | 
				
			||||||
 | 
					    max-height: 20vh;
 | 
				
			||||||
 | 
					    border-radius: 1em;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -369,8 +392,8 @@ img {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.wikimedia-link {
 | 
					.wikimedia-link {
 | 
				
			||||||
    width: 1.5em;
 | 
					    /*The actual wikimedia logo*/
 | 
				
			||||||
    height: auto;
 | 
					    width: 1.5em !important;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.attribution {
 | 
					.attribution {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -33,10 +33,11 @@
 | 
				
			||||||
<div id="centermessage"></div>
 | 
					<div id="centermessage"></div>
 | 
				
			||||||
<div id="bottomRight" style="display: none">ADD</div>
 | 
					<div id="bottomRight" style="display: none">ADD</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<div id="geolocate-button"></div>
 | 
				
			||||||
<div id="leafletDiv"></div>
 | 
					<div id="leafletDiv"></div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<script src="./index.ts"></script>
 | 
					<script src="./index.ts"></script>
 | 
				
			||||||
 | 
					<script src="vendor/Leaflet.AccuratePosition.js"></script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<!-- 3 dagen eerste protoype -->
 | 
					<!-- 3 dagen eerste protoype -->
 | 
				
			||||||
<!-- 19 juni: eerste feedbackronde, foto's -->
 | 
					<!-- 19 juni: eerste feedbackronde, foto's -->
 | 
				
			||||||
| 
						 | 
					@ -44,7 +45,7 @@
 | 
				
			||||||
<!-- 24 juni: foto's via imgur -->
 | 
					<!-- 24 juni: foto's via imgur -->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<!-- 26 restylen infobox -->
 | 
					<!-- 26 restylen infobox -->
 | 
				
			||||||
 | 
					<!-- 27 restylen infobox, flow UI verbeteren, mobile, locate-me -->
 | 
				
			||||||
<script data-goatcounter="https://pietervdvn.goatcounter.com/count"
 | 
					<script data-goatcounter="https://pietervdvn.goatcounter.com/count"
 | 
				
			||||||
        async src="//gc.zgo.at/count.js"></script>
 | 
					        async src="//gc.zgo.at/count.js"></script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										4
									
								
								index.ts
									
										
									
									
									
								
							
							
						
						
									
										4
									
								
								index.ts
									
										
									
									
									
								
							| 
						 | 
					@ -17,6 +17,7 @@ import {MessageBoxHandler} from "./UI/MessageBoxHandler";
 | 
				
			||||||
import {Overpass} from "./Logic/Overpass";
 | 
					import {Overpass} from "./Logic/Overpass";
 | 
				
			||||||
import {FixedUiElement} from "./UI/FixedUiElement";
 | 
					import {FixedUiElement} from "./UI/FixedUiElement";
 | 
				
			||||||
import {FeatureInfoBox} from "./UI/FeatureInfoBox";
 | 
					import {FeatureInfoBox} from "./UI/FeatureInfoBox";
 | 
				
			||||||
 | 
					import {GeoLocationHandler} from "./Logic/GeoLocationHandler";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
let dryRun = false;
 | 
					let dryRun = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -188,6 +189,9 @@ Helpers.LastEffortSave(changes);
 | 
				
			||||||
osmConnection.registerActivateOsmAUthenticationClass();
 | 
					osmConnection.registerActivateOsmAUthenticationClass();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					new GeoLocationHandler(bm).AttachTo("geolocate-button");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// --------------- Send a ping to start various action --------
 | 
					// --------------- Send a ping to start various action --------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
locationControl.ping();
 | 
					locationControl.ping();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										133
									
								
								vendor/Leaflet.AccuratePosition.js
									
										
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								vendor/Leaflet.AccuratePosition.js
									
										
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,133 @@
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Leaflet.AccuratePosition aims to provide an accurate device location when simply calling map.locate() doesn’t.
 | 
				
			||||||
 | 
					 * https://github.com/m165437/Leaflet.AccuratePosition
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Greg Wilson's getAccurateCurrentPosition() forked to be a Leaflet plugin
 | 
				
			||||||
 | 
					 * https://github.com/gwilson/getAccurateCurrentPosition
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright (C) 2013 Greg Wilson, 2014 Michael Schmidt-Voigt
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					L.Map.include({
 | 
				
			||||||
 | 
					    _defaultAccuratePositionOptions: {
 | 
				
			||||||
 | 
					        maxWait: 10000,
 | 
				
			||||||
 | 
					        desiredAccuracy: 20
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    findAccuratePosition: function (options) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!navigator.geolocation) {
 | 
				
			||||||
 | 
					            this._handleAccuratePositionError({
 | 
				
			||||||
 | 
					                code: 0,
 | 
				
			||||||
 | 
					                message: 'Geolocation not supported.'
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            return this;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this._accuratePositionEventCount = 0;
 | 
				
			||||||
 | 
					        this._accuratePositionOptions = L.extend(this._defaultAccuratePositionOptions, options);
 | 
				
			||||||
 | 
					        this._accuratePositionOptions.enableHighAccuracy = true;
 | 
				
			||||||
 | 
					        this._accuratePositionOptions.maximumAge = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!this._accuratePositionOptions.timeout)
 | 
				
			||||||
 | 
					            this._accuratePositionOptions.timeout = this._accuratePositionOptions.maxWait;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        var onResponse = L.bind(this._checkAccuratePosition, this),
 | 
				
			||||||
 | 
					            onError = L.bind(this._handleAccuratePositionError, this),
 | 
				
			||||||
 | 
					            onTimeout = L.bind(this._handleAccuratePositionTimeout, this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this._accuratePositionWatchId = navigator.geolocation.watchPosition(
 | 
				
			||||||
 | 
					            onResponse,
 | 
				
			||||||
 | 
					            onError,
 | 
				
			||||||
 | 
					            this._accuratePositionOptions);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this._accuratePositionTimerId = setTimeout(
 | 
				
			||||||
 | 
					            onTimeout,
 | 
				
			||||||
 | 
					            this._accuratePositionOptions.maxWait);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _handleAccuratePositionTimeout: function() {
 | 
				
			||||||
 | 
					        navigator.geolocation.clearWatch(this._accuratePositionWatchId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (typeof this._lastCheckedAccuratePosition !== 'undefined') {
 | 
				
			||||||
 | 
					            this._handleAccuratePositionResponse(this._lastCheckedAccuratePosition);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            this._handleAccuratePositionError({
 | 
				
			||||||
 | 
					                code: 3,
 | 
				
			||||||
 | 
					                message: 'Timeout expired'
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return this;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _cleanUpAccuratePositioning: function () {
 | 
				
			||||||
 | 
					        clearTimeout(this._accuratePositionTimerId);
 | 
				
			||||||
 | 
					        navigator.geolocation.clearWatch(this._accuratePositionWatchId);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _checkAccuratePosition: function (pos) {
 | 
				
			||||||
 | 
					        var accuracyReached = pos.coords.accuracy <= this._accuratePositionOptions.desiredAccuracy;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this._lastCheckedAccuratePosition = pos;
 | 
				
			||||||
 | 
					        this._accuratePositionEventCount = this._accuratePositionEventCount + 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (accuracyReached && (this._accuratePositionEventCount > 1)) {
 | 
				
			||||||
 | 
					            this._cleanUpAccuratePositioning();
 | 
				
			||||||
 | 
					            this._handleAccuratePositionResponse(pos);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            this._handleAccuratePositionProgress(pos);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _prepareAccuratePositionData: function (pos) {
 | 
				
			||||||
 | 
					        var lat = pos.coords.latitude,
 | 
				
			||||||
 | 
					            lng = pos.coords.longitude,
 | 
				
			||||||
 | 
					            latlng = new L.LatLng(lat, lng),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            latAccuracy = 180 * pos.coords.accuracy / 40075017,
 | 
				
			||||||
 | 
					            lngAccuracy = latAccuracy / Math.cos(Math.PI / 180 * lat),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            bounds = L.latLngBounds(
 | 
				
			||||||
 | 
					                [lat - latAccuracy, lng - lngAccuracy],
 | 
				
			||||||
 | 
					                [lat + latAccuracy, lng + lngAccuracy]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        var data = {
 | 
				
			||||||
 | 
					            latlng: latlng,
 | 
				
			||||||
 | 
					            bounds: bounds,
 | 
				
			||||||
 | 
					            timestamp: pos.timestamp
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for (var i in pos.coords) {
 | 
				
			||||||
 | 
					            if (typeof pos.coords[i] === 'number') {
 | 
				
			||||||
 | 
					                data[i] = pos.coords[i];
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return data;
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _handleAccuratePositionProgress: function (pos) {
 | 
				
			||||||
 | 
					        var data = this._prepareAccuratePositionData(pos);
 | 
				
			||||||
 | 
					        this.fire('accuratepositionprogress', data);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _handleAccuratePositionResponse: function (pos) {
 | 
				
			||||||
 | 
					        var data = this._prepareAccuratePositionData(pos);
 | 
				
			||||||
 | 
					        this.fire('accuratepositionfound', data);
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _handleAccuratePositionError: function (error) {
 | 
				
			||||||
 | 
					        var c = error.code,
 | 
				
			||||||
 | 
					            message = error.message ||
 | 
				
			||||||
 | 
					                (c === 1 ? 'permission denied' :
 | 
				
			||||||
 | 
					                    (c === 2 ? 'position unavailable' : 'timeout'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this._cleanUpAccuratePositioning();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        this.fire('accuratepositionerror', {
 | 
				
			||||||
 | 
					            code: c,
 | 
				
			||||||
 | 
					            message: 'Geolocation error: ' + message + '.'
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue