Javascript promise on google elevation service - javascript

I'm still pretty new with the Promise implementations in javascript. Although I got an easy example working, it didn't work after I popped the Google API elevation callback function in. I would very much appreciate if someone could help me with the function please, because I intend to use this approach a number of times in my application.
this is my current Promise function code (as defined in a javascript class structure):
LinkClass.prototype.getElev = function(coordinate)
{
return new Promise(function(resolve,reject)
{
//get User elevation again, because it is possible that the user elevation did not lock
var locations = []; //locations array
locations.push(coordinate);
// Create a LocationElevationRequest object using the array's one value
var positionalRequest = {'locations': locations}
//get User elevation for antenna elevation calculation
var elevator = new google.maps.ElevationService();
elevator.getElevationForLocations(positionalRequest, function(results, status)
{
if (status == google.maps.ElevationStatus.OK)
{
// Retrieve the first result
if (results[0])
{
resolve(results[0].elevation.toString());
}
else
reject('No valid result was determined from the Google Elevation service. Please try again');
}
else
reject('Google Elevation service was not available. Please try again');
});
}); //end of promise function
}
And then where I implement the function:
LinkClass.prototype.drawLine = function()
{
//do other stuff...
this.getElev(this.UserLocation).then(function(response){
//for now just print the result
alert(response);
},function(Errortxt){
alert(Errortxt);
});
//do other stuff
}
I really need to get this working please!
Thanks

Completely forgot to post the answer for this question. Thanks again for the inputs. For what it's worth, my code posted here is correct for implementing promises, and really cool if you want to synchronize and use answers from callback functions... For all practical purposes, this will work by default in the majority of browsers without including external "Promise javascript" files or whatever, except for Internet Explorer. (They should shortly start to notice that their browser development skills are becoming extinct).
Here is link to standard promise implementation, which I used, with minimum browser version support :) Promise browser impl & support

Related

Is it possible to define a layer which will retry to load, e.g. with exponential back-off?

I am using OpenLayers to connect to a home-grown server, and unlike professional grade servers like Google or Cloudmade that box will actually take a while to calculate the result for a specific tile. And as it is a mathematical function I am plotting, there is no big chance to accelerate the server or even pre-render the tiles.
My initial trials with Leaflet quickly came to the conclusion that Leaflet actually leaves all of the reloading and load-error handling to the browser, while OpenLayers at least has an event that is fired when the tile server does return with an error code.
The idea I am following was to basically start rendering a tile when it was requested and fire an HTTP 503 immediately, relying on the client to try again.
To try again, I implemented a simple layer like this:
var myLayer = new OpenLayers.Layer.OSM.MYLayer("mine", {
'transparent':"true",
'format':"image/png",
'isBaseLayer':false});
myLayer.events.register("tileerror", myLayer, function (param) {
// Try again:
var targetURL = param.tile.layer.getURL(param.tile.bounds);
var tile = param.tile;
tile.timeout = tile.hasOwnProperty("timeout") ? tile.timeout * 2 : 1000;
setTimeout(function (tileToLoad, url) {
if (tileToLoad.url === url) {
tileToLoad.clear();
tileToLoad.url = url;
tileToLoad.initImage();
}
}.bind(undefined, tile, targetURL), tile.timeout);
});
I figured out the code required to reload a tile from the source of OpenLayers, but maybe there is a cleaner way to accomplish this.
My problem is: The tiles themselves are reused, as are the divs in the DOM, so the reload procedure might actually try to reload a tile into a DIV that long as been successfully reused, e.g. because the user scrolled to someplace else where the server was able to provide data quickly.
The question I guess boils down to - is there an official way to use the tileerror event to simply try to reloading, or at least a simpler way in the API to trigger a reload? I spent quite a while in the source of OpenLayers itself but couldn't shed light on why it is still going wrong (the test for tileToLoad.url == url didn't really do it).
Thanks for your help!
Ok, after some more trial and error I found that I could actually add an eventListener to my Layer class, which will do what I want - try to reload the tile again after a certain wait. The trick was the consecutive call of setImgSrc() for cleanup and to draw with the true parameter, which effectively is an (undocumented) force flag. Thanks to the code!
OpenLayers.Layer.OSM.MyLayer= OpenLayers.Class(OpenLayers.Layer.OSM, {
initialize:function (name, options) {
var url = [
"xxxx"
];
options = OpenLayers.Util.extend({
"tileOptions":{
eventListeners:{
'loaderror':function (evt) {
// Later reload
window.setTimeout(function () {
console.log("Drawing ", this);
this.setImgSrc();
this.draw(true);
}.bind(this), 3000); // e.g. after 3 seconds
}
}
}
}, options);
var newArguments = [name, url, options];
OpenLayers.Layer.OSM.prototype.initialize.apply(this, newArguments);
},
CLASS_NAME:"OpenLayers.Layer.OSM.MyLayer"
});
You should have a look at the following resources:
http://dev.openlayers.org/docs/files/OpenLayers/Util-js.html#Util.IMAGE_RELOAD_ATTEMPTS
http://dev.openlayers.org/apidocs/files/OpenLayers/Tile-js.html
http://dev.openlayers.org/docs/files/OpenLayers/Tile/Image-js.html

Get coordinates from Hardware GPS

I've found a lot of questions about GPS Coordinates but not one that confirms using the mobile hardware GPS instead of Web GPS like geoLocation and such like.
My actual method:
I'm using navigator.geolocation.getCurrentPosition(), the Lat/Long comes from the Web, here's the code:
function getGPS(funcCallBack)
{
if (navigator.geolocation)
{
var timeoutVal = getCookie("GPSTimeout");
navigator.geolocation.getCurrentPosition(sucess
,error
,{enableHighAccuracy: true
,timeout: timeoutVal
,maximumAge: 0}
);
}
else{
alert('GPS is turned off, or was not possible to find it. Now, doing the login without localization.');
window.gpsLat = 0;
window.gpsLng = 0;
window.gpsAcc = 0;
funcCallBack();
}
function sucess(position) //sucess
{
window.gpsLat = position.coords.latitude;
window.gpsLng = position.coords.longitude;
window.gpsAcc = position.coords.accuracy;
funcCallBack();
}
function error() //error
{
window.gpsLat = 0;
window.gpsLng = 0;
window.gpsAcc = 0;
funcCallBack();
}
}
My problem:
Sometimes when I do the login I am not getting the GPS Coordinates (they come 0) and sometimes I am getting coordinates with more than 2,000 Accuracy (that is not precise).
By the way, I am testing the GPS on a data internet service, when I do use a Wi-Fi connection it works perfectly with less than 100 Accuracy.
Details:
Maybe you are complaining about:
timeoutVal: it is a cookie with the number 5000 inside it.
funcCallBack: it is a function that continues the login operation.
window.gpsLat: it is a global var containing the Latitude value got from the geoLocation.
window.gpsLng: it is a global var containing the Longitude value got from the geoLocation.
window.gpsAcc: it is a global var containing the Accuracy value got from the geoLocation.
What do I want?
I want a solution in JavaScript or PHP that can get coordinates from the mobile hardware device, the Native GPS, not the geolocation, and when the Native GPS is turned off, ask the user to turn it on.
You should get the location with javascript not PHP. PHP is only capable of doing an IP lookup which is the least accurate method for determining location.
The way navigator.geolocation.getCurrentPosition() works is it uses the most accurate data currently available. In the case of a mobile device it will use GPS first if enabled, then wi-fi.
If native GPS is enabled javascript will access that data instead of the wi-fi data, but there is no way of preventing a check against the wi-fi data if the GPS data isn't available.
Your best solution is to check the accuracy field and if it's not within a range you're happy with ask the user to enable GPS.
Alternatively if you're building a hybrid app, most of the frameworks (PhoneGap .etc.) have APIs to query the device GPS directly. Use PhoneGap to Check if GPS is enabled
Geolocation API does not expose a direct way to check whether GPS is on or off, but you can catch the errors of geolocation and base on error type can draw conclusions from there.
E.g. POSITION_UNAVAILABLE (2) if the network is down or the positioning satellites can’t be contacted.
But its not sure short way you have to handle some conditions!
I will suggest use watchPostion { i agree its meant to watch and continuous to locate position} u can keep it on and if GPS throw the error u can prompt custom alert to make user turn on the GPS device/wifi/internet .. and if its come to success callback u can clear the watch.
var watch =null;
function success(position)
{
var lat = position.coords.latitude;
var lon= position.coords.longitude;
if (watch != null )
/*Need to take care .. as maybe there is no gps and user
want it off so keep attempt 3 times or some kind a way out otherwise it will
infinite loop */
{
navigator.geolocation.clearWatch(watch);
watch = null;
}
}
function getLatLon()
{
var geolocOK = ("geolocation" in navigator);
if ( geolocOK )
{
var option = {enableHighAccuracy:true, maximumAge: 0,timeout:10000 };
watch = navigator.geolocation.watchPosition(success, fails, option);
}
else {
//disable the current location?
}
}
function fails()
{
alert("please turn on the GPS !");
}
getLatLon();

why is javascript-function just executed if an alert() is put at the beginning?

var callback = function(result){
//alert(result);
var json = eval('('+result+')');
if(json.criticalerror==true) dialogCriticalError(json.errormessage);
else{
if(json.error==true) dialogError(json.errormessage);
else{
// Do something else
}
}
};
When this callback-function is executed the "Do something else" part is called without problems. But in the case the json.error is true the dialogError-function is not executed. I've checked the transmitted JSON in Firebug. Everything is ok. The result is a JSON string as it should be.
The interesting thing is, that it actually is executed if i call the JSON-response with an alert() function at the beginning of the callback function. I'm new to JavaScript and probably missing something obvious but i just can't figure it out. Where's the bug?
EDIT:
It seems the problem is the time. If i put a 100ms delay between the JSON-result and the actual callback, everything works perfectly. But this can't be right... I'm kind of clueless.
(Oh and by the way: the communication is done by JBoss Seam Remoting)
The whole function looks like that:
function nextNode() {
var callback = function(result){
var json = JSON.parse(result);
if (json.criticalerror==true) {
dialogCriticalError(json.errormessage);
}else if (json.error==true) {
dialogError(json.errormessage);
}else {
document.getElementById('currentTree').innerHTML = json.state;
document.getElementById('countTrees').innerHTML = json.amountSteps;
document.getElementById('iframe').contentWindow.importGraph(json.tree);
document.getElementById('relevantnode').innerHTML = json.node;
createNodeBar(json);
}
};
manager.nextNode(callback);
}
The manager object is provided by the Seam Framework through the following function:
var manager = Seam.Component.getInstance("solverTreeStructure");
LAST EDIT:
Okay now i got the definite source of the problem. Its not not the Seam Remoting but the dialogError() function and the library it uses to display the dialog.
The dialogError() function looks like that:
function dialogError(error){
TINY.box.show({html:error,width:250,height:100,close:true,mask:true,opacity:20,topsplit:3})
}
It uses a small dialog library called TINYBOX. Now this library offers a variety of parameters to configure the dialog boxes. The 'mask' parameter caused all the trouble. It is resposible for darkening the background of the dialog box. If its turned on, TINYBOX needs a start-delay in order to work with the callback function. (i have NO idea why)
But for those who like riddles:
Thats the library. Its very small and clear. Unfortunately my JavaScript skills are not yet sophisticated enough to understand it.
http://www.scriptiny.com/2011/03/javascript-modal-windows/
Thats the answer. Have a nice day folks! ;)
Just a general advice: do not mix blocks with and without {}. The following form is much more readable and you can pinpoint your problem quicker.
console.log(json);
if (json.criticalerror == true) {
console.log("criticalerror");
dialogCriticalError(json.errormessage);
} else if (json.error == true) {
console.log("error");
dialogError(json.errormessage);
} else {
console.log("something else");
// Do something else
}
It seems the problem is the time. If i
put a 100ms delay between the
JSON-result and the actual callback,
everything works perfectly. But this
can't be right... I'm kind of
clueless.
Sounds like your doing asynchronous (ajax) communication. WHere is the rest of your code that asks the server for some data. Your handling the result before the server gives it to you. This explains the delay.

How to make a "did you mean" link with suggestions, in google maps api?

I'm trying to make a web application with google maps api, that gives directions. Right now, It gives directions fine unless the user types in something wrong, it either doesn't show anything or it tries to figure it out and gives the wrong address. I want to make functionality where if the address is not recognized it has "did you mean" and then make a suggestion that's close to what you were trying to enter. I couldn't find anything in the google code that talked about that, but I'm wondering if anyone knows if it's possible, and how I can do it?
Thanks!
loadFromWayPoints() draws polyline only if the inputs provided to it maps to any definite point on the earth. You can avoid the confusion to function by fixing your from point in form of latitude and longitude, instead of address. Then using following function you may create Did you mean for To point if multiple points returned for toInput.
Code is self explanatory. If you dont understand. Reply in comment.
One of the point you want to plot should return definite point from google geocoder system.
In my I used the from point as definite point. And had it coordinates with me. So there is no chance of getting
geo.getLocations(toInput, function (result){
//map.clearOverlays();
if (result.Status.code == G_GEO_SUCCESS) {
// ===== If there was more than one result, "ask did you mean" on them all =====
if (result.Placemark.length > 1) {
document.getElementById("textualdirectionscontainer").innerHTML = "Did you mean:";
// Loop through the results
for (var i=0; i<result.Placemark.length; i++) {
var p = result.Placemark[i].Point.coordinates;
document.getElementById("textualdirectionscontainer").innerHTML += "<br>"+(i+1)+": <a href='javascript:place(" +p[1]+","+p[0]+")'>"+ result.Placemark[i].address+"<\/a>";
}
}
// ===== If there was a single marker =====
else {
document.getElementById("textualdirectionscontainer").innerHTML = "";
var p = result.Placemark[0].Point.coordinates;
toLatLang = new GLatLng(p[1], p[0]);
// place(p[1],p[0]);
directionsPanel = $('textualdirectionscontainer');
directionsPanel.getElements('div').each(function(item) {
item.dispose();
});
directions.clear();
directions.loadFromWaypoints([hotelLatLng.toString(), toLatLang.toString()], {getPolyline:true});
/*var gp = directions.getPolyline();
map.addOverlay(gp); */
}
}
});

Google Maps - Same text appears in info window when using multiple markers

I'm having an issue with multiple markers on google maps - I currently have a MySQL database storing info (location info). In php I then extract this info and loop through each postcode to dynamically create the required javascript to place a marker for each place in my database.
This works successfully so I know that I'm passing the correct information to the js function - Now what I'm trying to achieve is adding additional information when the marker is clicked but its showing the same on every marker window.
This is the js I'm using (I initiate an icon at the top but excluded this from the code for now):
function usePointFromPostcode(postcode, callbackFunction, text) {
localSearch.setSearchCompleteCallback(null,
function() {
if (localSearch.results[0])
{
var resultLat = localSearch.results[0].lat;
var resultLng = localSearch.results[0].lng;
var point = new GLatLng(resultLat,resultLng);
callbackFunction(point, text);
}else{
alert("Postcode not found!");
}
});
localSearch.execute(postcode + ", UK");
}
function placeMarkerAtPoint(point, html, icon)
{
var marker = new GMarker(point,{icon: icon});
GEvent.addListener(marker,"click",function() {
marker.openInfoWindowHtml(html);
});
map.addOverlay(marker);
}
The php code I have is:
$query = "SELECT * FROM hospitalInfo";
$result = mysql_query($query);
if($result) {
while ($row = mysql_fetch_assoc($result)) {
$code .= "usePointFromPostcode('".$row['Postcode']."', placeMarkerAtPoint,
'".$row['placeName']."');";
}
}
$code is then echo'ed.
Any advice on why this is occuring would be much appreciated! Thanks !
You may be having a scope/closure problem, similar to the issue discussed here.
Try replacing this code:
GEvent.addListener(marker,"click",function() {
marker.openInfoWindowHtml(html);
});
with this:
marker.bindInfoWindowHtml(html);
If that doesn't work, I'd guess that the closure problem is coming from the setSearchCompleteCallback() function. It's difficult to guess without seeing the actual page.
As you mentioned in your comment, the problem is that you're sending several requests before you get any results, and the value of the marker text changes each time you send the request. I think you could greatly simplify your code by using the GClientGeocoder - unless it's absolutely necessary to use GLocalSearch, which isn't really part of the Maps API. Here's Google's tutorial for the geocoder.
First create the geocoder like this:
var geocoder = new GClientGeocoder();
Next, here's your new usePointFromPostcode() function:
function usePointFromPostcode(postcode, text) {
geocoder.getLatLng(postcode, function(point) {
if (!point) {
//alert('address not found');
} else {
var marker = new GMarker(point, {icon: icon});
GEvent.addListener(marker, "click", function() {
marker.openInfoWindowHtml(text);
});
map.addOverlay(marker);
}
});
}
This worked great for me. Try it out and let us know how it goes.
If you need more information about the returned point, like accuracy, use getLocations() instead of getLatLng(). The tutorial explains how it works.
I don't see a problem with your Google Maps Code. I suggest you try logging the html parameters in placeMarkerAtPoint and the text param to the localSearch callback. Google have a very useful logging API you could use:
GLog Reference
I would add at the begining of the placeMarkerAtPoint function:
GLog.write ("placeMarkerAtPoint - " + html);
and in the localSearch callback:
GLog.write ("SearchCompleteCallback - " + text);
I think the logging for these two callbacks (particularly the second one), will make it obvious where the html is getting lost.
Update: Ok, based on your logging your PHP code is fine. You are generating three calls to usePointFromPostcode.
The problem here is with your google.search.SearchControl callback. I am assuming the search is working correctly and the results array you get back is appropriate for each respective postcode?
If so, then the problem is with the text parameter in the setSearchCompleteCallback. I haven't used the Google AJAX Search stuff, but the problem lies in how these callbacks are fired. It looks like you can get multiple callbacks for a single execute.
You're re-using the name marker so the last text you place ends up getting attached to all of them. Create an index and name them marker1, marker2, etc. Its easy to do in a php loop.

Categories

Resources