Try Catch for error message in google maps api - javascript

I an using javascript and am getting an message that I have exceeded my daily request quota for this API. Is there a way to capture this error message in a try catch block so when I go over my quota I can execute another piece of code. I have seen several similar posts, but nothing that has been helpful. Here is my code.
(function (window, google, lat, lng) {
var options = {
center: {
lat: Number(lat),
lng: Number(lng)
},
zoom: 5,
disableDefaultUI: true,
scrollwheel: true,
draggable: false
},
element = document.getElementById('map-canvas')
var map = new google.maps.Map(element, options)
}(window, window.google, result[i]['latitude'], result[i]['longitude']));

Update
As per the documentation:
if you want to programmatically detect an authentication failure (for example to automatically send an beacon) you can prepare a callback function. If the following global function is defined it will be called when the authentication fails. function gm_authFailure() {//code}
Here is a list of errors that the gm_authFaliure function should be able to catch. It also mentions a OverQuotaMapError error.
As per the documentation:
if too many requests are made within a certain time period, the API returns an OVER_QUERY_LIMIT response code.
So you should check the response code. If the Google maps javascript library does not allow to access to the response code then I recommend making a HTTP request to the API to get the response code.
function initMap(window, google, lat, lng) {
var options = {
center: {
lat: Number(lat),
lng: Number(lng)
},
zoom: 5,
disableDefaultUI: true,
scrollwheel: true,
draggable: false
},
element = document.getElementById('map-canvas'),
map = new google.maps.Map(element, options);
};
function googleMapsCustomError(){
alert('Google Maps custom error triggered');
}
// if you want to respond to a specific error, you may hack the
// console to intercept messages.
// check if a message is a Google Map's error message and respond
// accordingly
(function takeOverConsole() { // taken from http://tobyho.com/2012/07/27/taking-over-console-log/
var console = window.console
if (!console) return
function intercept(method) {
var original = console[method]
console[method] = function() {
// check message
if(arguments[0] && arguments[0].indexOf('OverQuotaMapError') !== -1) {
googleMapsCustomError();
}
if (original.apply) {
// Do this for normal browsers
original.apply(console, arguments)
} else {
// Do this for IE
var message = Array.prototype.slice.apply(arguments).join(' ')
original(message)
}
}
}
var methods = ['error']; // only interested in the console.error method
for (var i = 0; i < methods.length; i++)
intercept(methods[i])
}())
<!DOCTYPE html>
<div id="map-canvas"></div>
<script>
// Notice i am defining this within my html file, just to be sure that this function exists before the Google Maps API is loaded.
window.gm_authFailure = function() {
// remove the map div or maybe call another API to load map
// maybe display a useful message to the user
alert('Google maps failed to load!');
}
window.showMap = function() {
var lat = -34.397,
lng = 150.644;
initMap(window, window.google, lat, lng);
};
</script>
<!-- We are passing an invalid API key. Also notice that we have defined 'callback' as 'showMap' which means that when the Google API JavaScript library is finished loading it will call the 'showMap' function. -->
<script src="https://maps.googleapis.com/maps/api/js?key=INVALID_API_KEY&callback=showMap"
async defer></script>

Yes, JavaScript supports try-catch blocks. Here is a sample implementation for your code:
(function (window, google, lat, lng) {
var options = {
center: {
lat: Number(lat),
lng: Number(lng)
},
zoom: 5,
disableDefaultUI: true,
scrollwheel: true,
draggable: false
},
element = document.getElementById('map-canvas')
try {
var map = new google.maps.Map(element, options)
} catch (error) {
// handle error
console.log(error.message);
} finally {
// optional cleanup code
}
}(window, window.google, result[i]['latitude'], result[i]['longitude']));

As per google documentation.
If you exceed the usage limits you will get an OVER_QUERY_LIMIT status
code as a response.
This means that the web service will stop providing normal responses
and switch to returning only status code OVER_QUERY_LIMIT until more
usage is allowed again. This can happen:
Within a few seconds, if the error was received because your application sent too many requests per second.
Within the next 24 hours, if the error was received because your application sent too many requests per day. The daily quotas are
reset at midnight, Pacific Time.
Please refer this link. It would be helpful.

Related

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.

Return value from nested function in another function if uses .then() or other method (JavaScript, Maps APIs)

I wrote AngularJS application which shows Google, Yandex and Gis maps for specific coordinates, obtained from JSON object. JSON may contains [0...n] objects.
And it is well works with Google Maps API, but not with Yandex/Gis Maps API.
Yandex Maps:
// DOESN'T WORK
$scope.yandexMaps = function (city) {
ymaps.ready(init);
function init() {
$scope.mapContainer = document.createElement('div');
$scope.mapContainer.className = 'mapCon';
$scope.yandexMap = new ymaps.Map($scope.mapContainer, {
center: [city.lat, city.lng],
zoom: 12
});
$scope.placemark = new ymaps.Placemark([city.lat, city.lng]);
$scope.yandexMap.geoObjects.add($scope.placemark);
return $scope.mapContainer; //I NEED TO GET IT !
}
//BUT I NEED TO GET IT THERE !
};
Gis Maps:
// DOESN'T WORK
$scope.gisMaps = function (city) {
DG.then(init);
function init() {
$scope.mapContainer = document.createElement('div');
$scope.mapContainer.className = 'mapCon';
$scope.gisMap = DG.map($scope.mapContainer, {
center: [city.lat, city.lng],
zoom: 13
});
DG.marker([city.lat, city.lng]).addTo($scope.gisMap);
return $scope.mapContainer; //I NEED TO GET IT !
}
//BUT I NEED TO GET IT THERE !
};
The problem is that ymaps.ready(init); and DG.then(init); call init() functions only after they will be checked for ready map state. And I can't return $scope.mapContainer in both cases because they are in nested functions.
I tried to create global variable above init() functions and assign to this $scope.mapContainer, but when I return this global value in parent below init() function it is not visible. It is visible only in nested function.
YOU CAN SEE working JSFiddle here: https://jsfiddle.net/oxpgkLhj/2/
Please, open console to see errors
If you are commenting this part at the end of code:
//adding yandex map to common container
$scope.yandexMap = $scope.yandexMap(value);
$scope.yandexMap.id = "yandexMapContainer" + i;
angular.element($scope.container).append($scope.yandexMap);
and this:
//adding gis map to common container
$scope.gisMap = $scope.gisMaps(value);
$scope.gisMap.id = "gisMapContainer" + i;
angular.element($scope.container).append($scope.gisMap);
you will see perfectly worked Google Maps. I want to see Yandex and Gis Maps exactly the same. Please help...

Bing Maps Geocode Callbacks Don't Get Called

Overall Picture:
I want to add geocoding to my application. I was able to get it working in straight up JavaScript, but the callbacks are not getting triggered after converting to Angular/TypeScript.
Example: if a user enters 1 Microsoft Way, Redmond, WA. The longitude and latitude should be returned: latitude: 47.64006815850735, longitude: -122.12985791265965
Code examples are built off the following resources:
Bing Maps Ajax API - get location from address
https://msdn.microsoft.com/en-us/library/hh868062.aspx
Error Details:
The errors are occurring specifically within the variable name: geocodeRequest. searchModuleLoaded() gets loaded, but my geocodeRequest never triggers geocodeCallback or errCallback. I'm thinking it has something to do with the scope of my methods, but can't seem to isolate what is causing the error. Any ideas on how to get my callbacks to trigger?
Angular/TypeScript (Not Working)
$onInit() {
this.getMap();
}
getMap() {
this.map = new Microsoft.Maps.Map(document.getElementById('myMap'), {credentials: "your key here"});
Microsoft.Maps.loadModule('Microsoft.Maps.Search', { callback: this.searchModuleLoaded });
};
searchModuleLoaded() {
var searchManager = new Microsoft.Maps.Search.SearchManager(this.map);
var geocodeRequest = {
where: "1 Microsoft Way, Redmond, WA",
count: 10,
callback: this.geocodeCallback,
errorCallback: this.errCallback
};
searchManager.geocode(geocodeRequest);
}
geocodeCallback(geocodeResult, userData) {
// this callback never gets triggered
alert("The first geocode result is " + geocodeResult.results[0].location + ".");
}
errCallback(geocodeRequest) {
// this callback never gets triggered
alert("An error occurred.");
}
Working Version (Works, but no Angular/TypeScript)
function GetMap(){
map = new Microsoft.Maps.Map(document.getElementById("mapDiv"), {credentials: "key goes here", center: new Microsoft.Maps.Location(47.5, -122.3), zoom: 9 });
Microsoft.Maps.loadModule('Microsoft.Maps.Search', { callback: searchModuleLoaded });
}
function searchModuleLoaded(){
var searchManager = new Microsoft.Maps.Search.SearchManager(map);
var geocodeRequest = {where:"1 Microsoft Way, Redmond, WA", count:10, callback:geocodeCallback, errorCallback:errCallback};
searchManager.geocode(geocodeRequest);
debugger;
}
function geocodeCallback(geocodeResult, userData){
alert("The first geocode result is " + geocodeResult.results[0].location + ".");
}
function errCallback(geocodeRequest){
alert("An error occurred.");
}
After furthing investigation, I was able to resolve my issue.
What was the problem?
The issue was occurring within the searchModuleLoaded. Both callbacks were undefined. One issue is that it was trying to execute searchModuleLoaded before the module had loaded and another issue was caused because it didn't know the context of this.
To fix the issue, I had to modify the callback while loading Microsoft.Maps.Search. The module's callback is now converted to a lambda function, which calls this.searchModuleLoaded(). Once this gets compiled into JavaScript, it sets the this context appropriatly i.e _this = this. My code looks like this now:
getMap() {
this.map = new Microsoft.Maps.Map(document.getElementById('myMap'), {credentials: "put your key here"});
Microsoft.Maps.loadModule('Microsoft.Maps.Search', {
callback: () => {
this.searchModuleLoaded();
}
});
};
searchModuleLoaded() {
var searchManager = new Microsoft.Maps.Search.SearchManager(this.map);
var geocodeRequest = {
where: "1 Microsoft Way, Redmond, WA",
count: 10,
callback: this.geocodeCallback,
errorCallback: this.errCallback
};
searchManager.geocode(geocodeRequest);
};
geocodeCallback(geocodeResult, userData) {
alert("The first geocode result is " + geocodeResult.results[0].location + ".");
};
errCallback(geocodeRequest) {
alert("An error occurred.");
};

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