getLocation and setInterval - javascript

I'd like to create an application, what is showing my current position on a google map in "real time".
Here is the relevant code:
function updatePosition() {
navigator.geolocation.getCurrentPosition(function (position) {
var myLatLng = {lat: position.coords.latitude, lng: position.coords.longitude};
marker.setPosition(myLatLng);
$('#log').append('<p>new position - lat: ' + position.coords.latitude + ', lng: ' + position.coords.longitude + ' </p>');
});
}
setInterval(updatePosition, 2000);
How can I say it... It works. But not as I expected. Instead 2secs, it refreshes my position and write into the log about 5 - 30 secs.
Is it possible to do this position refreshing with google maps, or if not, should I use another map like Leaflet or OpenLayers?

If you run code like this
function updatePosition() {
navigator.geolocation.getCurrentPosition(function (position) {
var myLatLng = {lat: position.coords.latitude, lng: position.coords.longitude};
console.log(myLatLng);
setTimeout(updatePosition, 0);
});
}
updatePosition();
You'll see that the getCurrentPosition takes a finite amount of time - in my case, 5 seconds, that's with a ZERO timeout ... so, running it every two seconds like you are is not going to make it update any faster

The delay you are encountering is probably due to the delay to acquire the position from the device.
Moreover, try checking for errors as a second handler to the getCurrentPosition function.

Related

Google Maps API use zoom level and center position from local storage values to adjust map on page load

I am working with a WordPress/jQuery/Google Maps setup to display a map of listings to users.
The jQuery.goMap.map code is used to load in the Google Maps instance used on the WordPress plugin.
I have wrote the following functions to store and load the latitude, longitude, and zoom level with local storage. The storing of the lat/lng and zoom levels is working, and the loading of the zoom level is working, but I cannot get the map to center on the loaded latitude and longitude position.
I have tried using bounds.extend(latLng); and jQuery.goMap.map.fitBounds(bounds); in the loadUserZoom function, but the result is a fully zoomed in map. This means the stored zoom level value is being ignored.
The current functioning code can be tested here.
The Clear text link in the header navigation can be used to clear the local storage values from the browser. This is implemented for testing purposes.
Any assistance is greatly appreciated.
Function: storeUserZoom
function storeUserZoom() {
let zoom = jQuery.goMap.map.getZoom();
localStorage.setItem( 'zoom', zoom);
let center = jQuery.goMap.map.getCenter();
let lat = center.lat();
let lng = center.lng();
let latLng = {
lat: lat,
lng: lng
}
localStorage.setItem( 'latLng', JSON.stringify(latLng));
}
Function: loadUserZoom
function loadUserZoom() {
if (localStorage.getItem( 'zoom' )) {
let zoom = parseInt(localStorage.getItem( 'zoom' ));
console.log(zoom);
// Logs correct zoom level
let latLng = JSON.parse(localStorage.getItem( 'latLng' ));
console.log(latLng);
// Logs Object { lat: 51.69124213478852, lng: -113.2478200914128 }
jQuery.goMap.map.setZoom(zoom);
jQuery.goMap.map.setCenter(latLng);
// latLng used is incorrect
}
}
I believe I have zeroed in on the problem by adjusting how the loadUserZoom function was executed in the initMap function.
The loadUserZoom function was wrapped in a Google Maps listen once event listener when the map was idle. The code is included below.
google.maps.event.addListenerOnce(jQuery.goMap.map, 'idle', function() {
loadUserZoom();
});
I had it set initially to addListener, which seemed to conflict with the required functionality. I assume this meant it was execute regularly whenever the map was in an idle state.
My updated loadUserZoom function is included below.
function loadUserZoom() {
if (localStorage.getItem( 'zoom' )) {
let zoom = parseInt(localStorage.getItem( 'zoom' ));
let latLng = JSON.parse(localStorage.getItem( 'latLng' ));
jQuery.goMap.map.setZoom(zoom);
jQuery.goMap.map.setCenter(latLng);
}
}

Track a user draw polyline snap to roads bing maps

Was wondering if anyone has any experience or could help with the logic, to track a user (car) with Bing maps
As the user travels a line should be drawn of their journey, but snap to roads, the way I have things set at the moment, lines will be drawn through buildings.
Because whenever there is an update to the position, 2 points are calculated and a line is added to the map
(At the moment am using watchPosition but in future will get position every 30 seconds)
watchPos() {
let options = { timeout: 60000 }
this.watchId = navigator.geolocation.watchPosition((position) => {
this.lat = position.coords.latitude;
this.lng = position.coords.longitude;
this.setMap()
console.log(this.lat, this.lng)
}, this.errorHandler, options);
}
setMap() {
this.loc = new Microsoft.Maps.Location(this.lat, this.lng);
if (!this.initialised) {
this.oldLoc = this.loc;
this.initialised = true
this.map = new Microsoft.Maps.Map(this.driveMap.nativeElement, {
credentials: CONFIG.BING_API_KEY,
center: this.loc,
mapTypeId: Microsoft.Maps.MapTypeId.road,
navigationBarMode: 2,
zoom: this.zoom
});
this.user = new Microsoft.Maps.Pushpin(this.loc, { icon: '../images/icon.svg' });
this.map.entities.push(this.user);
// console.log(loc)
} else {
// Draw line
// from this.oldLoc to this.loc
let lineVertices = new Array(this.oldLoc, this.loc);
let line = new Microsoft.Maps.Polyline(lineVertices);
// Then set oldLoc to new loc
this.oldLoc = this.loc
this.map.entities.push(line);
this.map.setView({
center: this.loc
});
this.user.setLocation(this.loc);
}
}
Bing Maps has a snap to road API coming out near the end of next week which is specifically designed for this. You pass in your GPS coordinates and it will snap it to the roads, additionally, if you pass in an array of points you can also have it return a logical path that passes through the snapped points. Watch the Bing Maps blog for the announcement: https://blogs.bing.com/maps

How to convert custom library events (ie. Google Maps events) into Observable stream in RxJS?

I want to create an RxJS observable stream from Google Map events. I know how to do this from native browser events, like so:
var result = document.getElementById('result');
var source = Rx.Observable.fromEvent(document, 'mousemove');
var subscription = source.subscribe(function (e) {
result.innerHTML = e.clientX + ', ' + e.clientY;
});
The mousemove is a browser event, which leads me to believe that .fromEvent() recognizes mousemove as a hard-coded default. However, if I want to recognize custom events how can I create an observable stream? Take for example Google Maps:
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 4,
center: {lat: -25.363, lng: 131.044}
});
map.addListener('center_changed', function() {
var center = map.getCenter()
console.log(center)
});
The reason why I want to convert these google map events into an observable stream is so that I can use RxJS debounce for performance improvements. That way center_changed is only recognized in batches (instead of firing 10x over 2 seconds, it just recognizes the last 1x in that same 2 seconds). My dilemma is converting that custom Google Maps event into an observable stream. Perhaps there is an easy way to continuously add to an observable, but from my search I have not found out how to do that.
I really appreciate your help in this matter!
You should be able to use fromEventPattern to do what you want:
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 4,
center: { lat: -25.363, lng: 131.044 }
});
var source = Rx.Observable.fromEventPattern(
function (handler) {
return map.addListener('center_changed', handler);
},
function (handler, listener) {
google.maps.event.removeListener(listener);
}
);
source.subscribe(function () {
console.log(map.getCenter());
});
fromEventPattern lets you provide the add and remove implementations, so it's easy to get an observable from most types of 'custom' event mechanisms. Note that the value returned by the add handler is passed to the remove handler as the second parameter. In this case, it's the listener - which is what's needed when removing Google Maps event listeners.

Centering a map with Geolocation

I am teaching myself scripting and have learned a lot. I am, however, stuck at this one point. I am wanting to display a weather map and have it center to the users location. Here is what I have in the body of my html so far..
<div id="map-canvas"></div>
<div id="loading">Loading animation layers... <br>
<span id="progress"></span>% done.
</div>
<script type="text/javascript">
var map, radar, satellite;
var animationSync;
// GeoLocation Services
function showLocation(position) {
var latitude = position.coords.latitude;
var longitude = position.coords.longitude;
}
function errorHandler(err) {
if(err.code == 1) {
alert("Error: Access is denied!");
}
else if( err.code == 2) {
alert("Error: Position is unavailable!");
}
}
function getLocation(){
if(navigator.geolocation){
// timeout at 60000 milliseconds (60 seconds)
var options = {timeout:60000};
navigator.geolocation.getCurrentPosition(showLocation, errorHandler, options);
}
else{
alert("Sorry, browser does not support geolocation!");
}
}
// End GeoLocation Services
map = new aeris.maps.Map('map-canvas', {zoom: 9, center: [36.0462, -96.9942]});
// here is what I am wanting to do instead of the above line..
// map = new aeris.maps.Map('map-canvas', {zoom: 9, center: [latitude +',' + longitude]});
I can display the map perfectly if I hard code the LAT and LON but thats not what I need. I am confident my GeoLocation routine is working as the console in my browser does not show any errors, its only when I try to center the map using LAT and LONG as variables that I have a problem. I am hoping this is just a syntax type issue, but I just don't know enough to figure this out. I have also tried using the map.setCenter command but can't figure where to use it so it works.
Thanks in advance for any help.
Just replace the last line by
map = new aeris.maps.Map('map-canvas', {zoom: 9, center: [latitude, longitude]});
The quotes were not needed and transformed your array with 2 values in an array with a single string value
Current issue
The issue right now is you're performing string concatenation with latitude and longitude. You can just use them as normal inside the array:
map = new aeris.maps.Map('map-canvas', {zoom: 9, center: [latitude, longitude]});
More info that may be of use:
The thing to remember is that both these variables need to be in scope, which they currently aren't. latitude and longitude exist only inside showLocation(), and to further complicate things, it's a callback which means your new aeris.maps.Map() will fail because neither values are set.
If you're just trying to display a map around the position of the current user, this should do it:
var map, radar, satellite;
var animationSync;
// GeoLocation Services
function showLocation(position) {
var latitude = position.coords.latitude;
var longitude = position.coords.longitude;
map = new aeris.maps.Map("map-canvas", {
zoom: 9,
center: [latitude, longitude]
});
}
function errorHandler(err) {
if (err.code == 1) {
alert("Error: Access is denied!");
} else if (err.code == 2) {
alert("Error: Position is unavailable!");
}
}
function getLocation() {
if (navigator.geolocation) {
// timeout at 60000 milliseconds (60 seconds)
var options = {
timeout: 60000
};
navigator.geolocation.getCurrentPosition(showLocation, errorHandler, options);
} else {
alert("Sorry, browser does not support geolocation!");
}
}
getLocation();
It's a bit tricky since the action happens asynchronously, meaning anything you do with map have to happen after showLocation is called.

Passing HTML5 geolocation data to a variable

I'm really new to Javascript, and I'm trying to jump into it.
I want to have a script get geolocation data and pass it to a variable, and then have the information displayed in an alert.
I have a jsFiddle here: http://jsfiddle.net/yJrtR/
When I run it, I get an "undefined" in the alert box. Can someone help me with this?
Here is my code:
function lat() {
navigator.geolocation.getCurrentPosition(function (position) {
var lat = position.coords.latitude;
var lon = position.coords.longitude;
}, function (error) {
console.log("Something went wrong: ", error);
});
}
function alert() {
var lat="";
var lon="";
lat();
alert("lat + lon");
}
There are several weird things in your code. Your fiddle is set to run onLoad, which means the functions you defined in your JavaScript won't be available globally - they'll be defined in the window.onload handler...which doesn't code outside of that to access them (especially inline event handlers). This is a perfect example of why not to use inline event handlers (even though the problem is really because of the jsFiddle settings).
So that means, when you call alert(); in your button's inline click handler, it calls the native window.alert() function, which brings up a dialog window. Since you pass nothing to it, it shows undefined. It's not actually calling your created alert function.
Also, since the getCurrentPosition method seems to be asynchronous, you should pass a callback function to lat, so that you can call it when it gets position.
Try this:
function lat(callback) {
navigator.geolocation.getCurrentPosition(function (position) {
var lat = position.coords.latitude;
var lon = position.coords.longitude;
callback.call(null, lat, lon);
}, function (error) {
console.log("Something went wrong: ", error);
});
}
function getPosition() {
lat(function (latitude, longitude) {
alert("lat: " + latitude + ", lon: " + longitude);
});
}
http://jsfiddle.net/yJrtR/1/
UPDATE:
Per your comment, if you'd like it to be shown "live", you can use something like this:
window.onload = function () {
var latElement = document.getElementById("lat"),
lonElement = document.getElementById("lon"),
lastUpdatedElement = document.getElementById("last_updated"),
getPositionOptions = {
enableHighAccuracy: false,
timeout: 10000,
maximumAge: 0
},
getPos = function () {
console.log("getPos function called");
navigator.geolocation.getCurrentPosition(function (position) {
console.log("Successfully retrieved position: ", position);
var coords = position.coords;
latElement.innerHTML = coords.latitude;
lonElement.innerHTML = coords.longitude;
lastUpdatedElement.innerHTML = new Date(position.timestamp);
setTimeout(getPos, 5000);
}, function (error) {
console.log("Something went wrong retrieving position: ", error);
setTimeout(getPos, 5000);
}, getPositionOptions);
};
getPos();
};
with the following HTML (just to "simulate" the dialog you speak of):
<div id="dialog">
<div>Your latitude is: <span id="lat"></span></div>
<div>Your longitude is: <span id="lon"></span></div>
<div>Last Updated: <small id="last_updated"></small></div>
</div>
DEMO: http://jsfiddle.net/yJrtR/12/
So what this code does is from the time the window has loaded, it continually re-gets the geo position. There are special options you can pass to the getCurrentPosition, that I declared in getPositionOptions.
As I said before, the getCurrentPosition is asynchronous, so the position could be retrieved at any time after calling getCurrentPosition is called...that's what the callbacks are for. In the options object, I set a timeout - 10000 - that says "don't take any longer than 10 seconds to retrieve the position", and if it does, it will call the error callback. The maximumAge option makes sure it always tries to grab the current location (instead of using a cached version, within a certain period of time.
So when either callback is called (could be 1 second later, could be 20 seconds later...although we set a timeout of 10 seconds), it will update the HTML with the details, and then do it all again 5 seconds later - that's what the setTimeout is for. This is because if we continually tried to get the position (without any kind of delay), the page would be very busy getting the position. 5 second delays, or even up to 15, should be fine.
Reference:
https://developer.mozilla.org/en-US/docs/DOM/window.navigator.geolocation.getCurrentPosition
UPDATE:
There is a specific method for the geolocation feature that lets you watch the position, called watchPosition, doing exactly what I was trying to emulate, but more efficiently. You could try this:
window.onload = function () {
var latElement = document.getElementById("lat"),
lonElement = document.getElementById("lon"),
lastUpdatedElement = document.getElementById("last_updated"),
watchPositionOptions = {
enableHighAccuracy: false,
timeout: 10000,
maximumAge: 0
};
navigator.geolocation.watchPosition(function (position) {
console.log("Successfully retrieved position: ", position);
var coords = position.coords;
latElement.innerHTML = coords.latitude;
lonElement.innerHTML = coords.longitude;
lastUpdatedElement.innerHTML = new Date(position.timestamp);
}, function (error) {
console.log("Something went wrong retrieving position: ", error);
}, watchPositionOptions);
};
DEMO: http://jsfiddle.net/yJrtR/14/
Reference:
https://developer.mozilla.org/en-US/docs/DOM/window.navigator.geolocation.watchPosition?redirect=no

Categories

Resources