Receiving WatchPosition only once - javascript

I use this code to get the first position ,and i want to keep getting it.
var init = function()
{
navigator.geolocation.getCurrentPosition(function(position)
{
new_position = position;
}, onError, {});
watchID = navigator.geolocation.watchPosition(UserLocationCalculation, onError, {maximumAge: 1000, timeout: 5000, enableHighAccuracy: true});
}
var UserLocationCalculation = function(position)
{
var d;
//alert("Position" + " Latitude " + position.coords.latitude + " Longitude " + position.coords.longitude);
if(new_position == 0)
{
new_position = position;
}
else
{
//Change the positions around
old_position = new_position;
new_position = position;
var conv_old_position = new google.maps.LatLng(old_position.coords.latitude, old_position.coords.longitude);
var conv_new_position = new google.maps.LatLng(new_position.coords.latitude, new_position.coords.longitude);
d = google.maps.geometry.spherical.computeDistanceBetween(conv_old_position, conv_new_position);
run_total = parseInt(run_total);
d = parseInt(d);
run_total += d;
navigator.geolocation.clearWatch( watchID );
}
}
Now i keep an old_position, a new_position and a run_total as global variables. I save the last position as the new, and the one before that as old, and then calculate the distance and add this to a global variable.
But the watchPosition calls the UserLocationCalculation only once, after that, it just doesn't call it anymore.

Your UserLocationCalculation function is only being called once because at the end of the else clause, you are calling navigator.geolocation.clearWatch( watchID );. Since you are calling this, the device stops watching for position changes, so it never fires again.
From the docs: Stop watching for changes to the device's location referenced by the watchID parameter.

Related

Google Sheets Script "Exceeded maximum execution time"

I'm having issues trying to deal with the "Exceeded maximum execution time" error I get when running my script in Google sheets. I've found a few solutions on here that I couldn't get working with my script. Any help would be greatly appreciated, here is the script I am trying to modify:
function getGeocodingRegion() {
return PropertiesService.getDocumentProperties().getProperty('GEOCODING_REGION') || 'au';
}
function addressToPosition() {
// Select a cell with an address and two blank spaces after it
var sheet = SpreadsheetApp.getActiveSheet();
var cells = sheet.getActiveRange();
var addressColumn = 1;
var addressRow;
var latColumn = addressColumn + 1;
var lngColumn = addressColumn + 2;
var API_KEY = "xxx";
var options = {
muteHttpExceptions: true,
contentType: "application/json",
};
for (addressRow = 1; addressRow <= cells.getNumRows(); ++addressRow) {
var address = cells.getCell(addressRow, addressColumn).getValue();
var serviceUrl = "https://maps.googleapis.com/maps/api/geocode/json?address=" + address + "&key=" + API_KEY;
// Logger.log(address);
// Logger.log(serviceUrl);
var response = UrlFetchApp.fetch(serviceUrl, options);
if (response.getResponseCode() == 200) {
var location = JSON.parse(response.getContentText());
// Logger.log(response.getContentText());
if (location["status"] == "OK") {
//return coordinates;
var lat = location["results"][0]["geometry"]["location"]["lat"];
var lng = location["results"][0]["geometry"]["location"]["lng"];
cells.getCell(addressRow, latColumn).setValue(lat);
cells.getCell(addressRow, lngColumn).setValue(lng);
}
}
}
};
function positionToAddress() {
var sheet = SpreadsheetApp.getActiveSheet();
var cells = sheet.getActiveRange();
// Must have selected 3 columns (Address, Lat, Lng).
// Must have selected at least 1 row.
if (cells.getNumColumns() != 3) {
Logger.log("Must select at least 3 columns: Address, Lat, Lng columns.");
return;
}
var addressColumn = 1;
var addressRow;
var latColumn = addressColumn + 1;
var lngColumn = addressColumn + 2;
//Maps.setAuthentication("acqa-test1", "AIzaSyBzNCaW2AQCCfpfJzkYZiQR8NHbHnRGDRg");
var geocoder = Maps.newGeocoder().setRegion(getGeocodingRegion());
var location;
for (addressRow = 1; addressRow <= cells.getNumRows(); ++addressRow) {
var lat = cells.getCell(addressRow, latColumn).getValue();
var lng = cells.getCell(addressRow, lngColumn).getValue();
// Geocode the lat, lng pair to an address.
location = geocoder.reverseGeocode(lat, lng);
// Only change cells if geocoder seems to have gotten a
// valid response.
Logger.log(location.status);
if (location.status == 'OK') {
var address = location["results"][0]["formatted_address"];
cells.getCell(addressRow, addressColumn).setValue(address);
}
}
};
function generateMenu() {
var entries = [{
name: "Geocode Selected Cells (Address to Lat, Long)",
functionName: "addressToPosition"
}, {
name: "Geocode Selected Cells (Address from Lat, Long)",
functionName: "positionToAddress"
}];
return entries;
}
function updateMenu() {
SpreadsheetApp.getActiveSpreadsheet().updateMenu('Geocode', generateMenu())
};
/**
* Adds a custom menu to the active spreadsheet, containing a single menu item
* for invoking the readRows() function specified above.
* The onOpen() function, when defined, is automatically invoked whenever the
* spreadsheet is opened.
*
* For more information on using the Spreadsheet API, see
* https://developers.google.com/apps-script/service_spreadsheet
*/
function onOpen() {
SpreadsheetApp.getActiveSpreadsheet().addMenu('Geocode', generateMenu());
};
Or, any other script you may know of that does geocode in Google sheets and already properly handles max execution time that would be OK too, I'm not tied to this specific script, just getting the outcome I need!
This error's cause is due to script running more than 6 minutes.
A possible solution is to limit the time-consuming part of your script (which is the for loop) to only 5 minutes. Then create a trigger and continue the loop into another instance if it still isn't done.
Script:
function addressToPosition() {
// Select a cell with an address and two blank spaces after it
var sheet = SpreadsheetApp.getActiveSheet();
...
var options = {
muteHttpExceptions: true,
contentType: "application/json",
};
// if lastRow is set, get value, else 0
var continueRow = ScriptProperties.getProperty("lastRow") || 0;
var startTime = Date.now();
var resume = true;
for (addressRow = ++continueRow; addressRow <= cells.getNumRows(); ++addressRow) {
var address = cells.getCell(addressRow, addressColumn).getValue();
...
// if 5 minutes is done
if ((Date.now() - startTime) >= 300000) {
// save what's the last row you processed then exit loop
ScriptProperties.setProperty("lastRow", addressRow)
break;
}
// if you reached last row, assign flag as false to prevent triggering the next run
else if (addressRow == cells.getNumRows())
resume = false;
}
// if addressRow is less than getNumRows()
if (resume) {
// after execution of loop, prepare the trigger for the same function
var next = ScriptApp.newTrigger("addressToPosition").timeBased();
// run script after 1 second to continue where you left off (on another instance)
next.after(1000).create();
}
}
Do the same thing with your other functions.

How to call api again after clearing interval

I am trying to create a stack area graph from the values I get from api's.
My first api gives me a range of dates. Eg: June 1 - June 7.
My second api gives me values need for the graph. The data looks like this
My idea is to call the api and push the count values to function every time to a function. But somehow I could not make that possible so I am calling api once for every 100 ms and grabbing all the data and triggering the graph. Now when I want to call the second api after one iteration is complete the call interrupts the graph. Please help me fix this.
d3.json('/service/dates', function(error, dates) {
var dran = dates;
if (dates != null) {
sDt = new Date(dates.st);
eDt = new Date(dates.et);
var i = 0;
var start = function() {
if (sDt > eDt) {
clearInterval(interval);
$('.wrapper').trigger('newPoint');
return;
}
var sDate = sDt.toISOString();
var eDate = new Date(sDt.setMinutes(sDt.getMinutes() + 30)).toISOString();
//Calling the api for graph values
d3.json("/service/dat?s=" + sDate + "&e=" + eDate, function(error, results) {
if (results != null) {
numbers = numbers.push(results.numbers);
values = values.push(results.values);
}
});
i++;
}
var interval = setInterval(start, 100);
}
});
}
Put the entire API call inside a named function. Then call that from the start() function to restart everything.
function doAPILoop() {
d3.json('/service/dates', function(error, dates) {
var dran = dates;
if (dates != null) {
sDt = new Date(dates.st);
eDt = new Date(dates.et);
var i = 0;
var start = function() {
if (sDt > eDt) {
clearInterval(interval);
$('.wrapper').trigger('newPoint');
doAPILoop();
return;
}
var sDate = sDt.toISOString();
var eDate = new Date(sDt.setMinutes(sDt.getMinutes() + 30)).toISOString();
//Calling the api for graph values
d3.json("/service/dat?s=" + sDate + "&e=" + eDate, function(error, results) {
if (results != null) {
numbers = numbers.concat(results.numbers);
values[values.length] = results.values;
}
});
i++;
}
var interval = setInterval(start, 10);
}
});
}
doAPILoop();

i am getting undefined value in my javascript object property

i have a codepen that basically takes value from openweather and tries to set it according to an app state. I cannot seem to figure out why i am getting an undefined value for this.tempValue and this.tempType. here's the code:
`
var app = {
latitude: '',
longitude: '',
tempType : " C",
tempValue: "",
getGeoLoc: function (id) {
//Removed timeout option due to error
var options = {}; //{ timeout: 3 };
navigator.geolocation.getCurrentPosition(this.foundLoc.bind(this), this.noloc, options);
},
foundLoc : function(position) {
this.latitude = position.coords.latitude;
this.longitude = position.coords.longitude;
console.log('coords ', this.latitude, this.longitude);
// Call your get weather function
// Using call to bind the context of `this`
this.getWather.call(this);
},
// Error method
noloc: function(err) {
console.log(err.message);
},
// Method to get your weather after location is found
getWather: function() {
var url = 'http://api.openweathermap.org/data/2.5/weather?lat=' + this.latitude + '&lon=' + this.longitude +'&APPID=7bda183adf213c8cfa2ef68635588ef3';
console.log('URL is: '+url);
$.getJSON(url, function(data) {
console.log('Your weather data', data);
// Do your dom stuff here
$("#location").text(data.name);
console.log("#5 does this work??? ", data.main.temp.toString().slice(0, 2));
var temp = '';
this.tempValue = data.main.temp.toString().slice(0, 2);
var type = "";
type = this.tempType;
console.log("#6 what's inside tempType. ", this.tempType);
$("#temp").html(this.tempValue + this.tempType);
$("#message").html(data.weather[0].description);
console.log("#3 what is in the description property. ", data.weather[0].description);
//function to convert C to F and vice versa and return a string
function convert (value) {
var celsius = '';
var fahrenheit = '';
var convertedToF = 0;
var convertedToC = 0;
if(value == 'fahrenheit') {
convertedToF = data.main.temp * 9/5 + 32;
this.tempValue = convertedToF;
console.log("#4 fahrenheit value is ", convertedToF);
}
if(value == 'celsius') {
convertedToC = data.main.temp - 32;
convertedToC *= 5/9;
this.tempValue = convertedToC;
}
}
$("#convert").click( function () {
convert('celsius');
}
);
});
},
};
// Make sure to call your initialising function
app.getGeoLoc();
codepen url is: http://codepen.io/rush86999/pen/MKMywE/?editors=1010
Inside the success callBack of getJSON, the this object will point to jqXHR object(as mentioned by #dfsq). That is why you are seeing undefined for that two variables. There a different methods available to fix this. one of them would be,
$.getJSON(url, function(data) {
// ...YOUR CODE...
}.bind(this));

JavaScript Async Loop does not return result

I was having some logic problem when trying to do a function in JavaScript. Basically I have a pointArr to store the coordinates along the route. Then I got a moveNext() which takes in each coordinates along the route and plot onto the map. Then inside the moveNext(), I got another array which is busList. If the coordinates along the route match the coordinates of busList, then I minus the totalBusStopLeft by one. Here is the code where I call the moveNext():
getAllBusLoc(function(busList) {
//At first I set the totalBusLeft by the length of busList which is 13 in this case
var totalBusLoc = busList.length;
document.getElementById("busStopLeft").innerHTML = totalBusLoc;
//Then I set the value to busList for the minus calculation
busLeft = totalBusLoc;
timeout = 1500;
pointArr.forEach(function(coord,index){
setTimeout(function(){
moveNext(coord.x, coord.y, index, busList, busLeft);
}, timeout * index);
});
});
function moveNext(coordx, coordy, k, busList, busLeft){
document.getElementById("busStopLeft").innerHTML = busLeft;
//pointToCompare is the coordinates in the route but not the coordinates of busList
var pointToCompare = coordx + "," + coordy;
//If the coordinates in route matches the coordinate in busList, I minus busLeft by one
if(busList.indexOf(pointToCompare) > -1){
parseFloat(busLeft--);
}
//Code to Add marker
}
However, with this code, my Html component busStopLeft keep showing 13 which is the totalBusLoc but not the busLeft. Any ideas?
Thanks in advance.
EDIT
totalBusLoc = busList.length;
document.getElementById("busStopLeft").innerHTML = totalBusLoc;
timeout = 1500;
pointArr.forEach(function(coord,index){
setTimeout(function(busLeft){
moveNext(coord.x, coord.y, index, busList, totalBusLoc);
}, timeout * index);
});
});
function moveNext(coordx, coordy, k, busList, totalBusLoc, callback){
var pointToCompare = coordx + "," + coordy;
if(busList.indexOf(pointToCompare) > -1){
parseFloat(totalBusLoc--);
document.getElementById("busStopLeft").innerHTML = totalBusLoc;
callback(totalBusLoc);
}
}

Geolocation unit test with JsTestDriver

I'm testing geolocation using JsTestDriver, this is my code:
GeoLocationTest.prototype.testLocation = function(){
expectAsserts(1);
var coordinate = new Coordinate();
var location = coordinate.getLocation();
assertEquals("1,1",location);
};
Te test always fails because it tests immediately, before getting the geolocation coordinates. I tried using a timeout but the test also executes immediately.
setTimeout(function(){assertEquals("1,1",location);},10000);
And this is the javascript I'm trying to test
function Coordinate () {
this.latitude = 0.0;
this.longitude = 0.0;
this.date = new Date();
this.errorMsg = "";
}
Coordinate.prototype.getLocation = function(){
if (this.isBrowserSupported()){ //this test passes
navigator.geolocation.getCurrentPosition(this.setPosition,this.setError);
return "" + this.latitude + "," + this.longitude;
}
return "Browser not supported";
}
Coordinate.prototype.setPosition = function(position){
this.latitude = position.coords.latitude;
this.longitude = position.coords.longitude;
}
AssertError: expected "1,1" but was "0,0"
I was doing it wrong, hate JS
function Coordinate () {
latitude = 0.0;
longitude = 0.0;
date = new Date();
errorMsg = "";
}
Coordinate.prototype.getLocation = function(){
if (this.isBrowserSupported()){ //this test passes
navigator.geolocation.getCurrentPosition(this.setPosition,this.setError);
return 0;
}
return -1;
}
Coordinate.prototype.setPosition = function(position){
Coordinate.prototype.latitude = position.coords.latitude;
Coordinate.prototype.longitude = position.coords.longitude;
}
And then the test
GeoLocationTest.prototype.testLocation = function(){
var timeout = 10000;
expectAsserts(2);
var coordinate = new Coordinate();
coordinate.getLocation();
setTimeout(function(){
assertEquals(1,Coordinate.prototype.latitude);
assertEquals(1,Coordinate.prototype.longitude);
console.log("testLocation finished");
},timeout);
};
JsTestDriver will output "AssertError: Expected '2' asserts but '0' encountered."
So open the browser, open the console and wait for the test to execute. I added the last log because if the test passes nothing happens, if it fails it outputs the failure.

Categories