The target is to embed a Google Apps Script gadget into my Google site. The function of this script is to show a google map, determin the location of the client and center the map to the found location.
The relevant command for getting the position is navigator.geolocation.getCurrentPosition.
The issue is that the security layers block the execution of this command when used with Chrome. (It works in Firefox and Safari. Also when I use "test web for your lates code", it works as intended).
Debugging the browser reveals the following error message:
"Geolocation access has been blocked because of a Feature Policy applied to the current document. See (here comes a link) for more detail."
Following the explanations in the offered link, it results in the suggestion to apply a instruction for geolocation in the iframe command like:
<iframe src="https://example.com" allow="geolocation"></iframe>
Now here comes my problem:
Since I can only use the functions in the Google Site editor to embed a GAS gadget, I have no option to modify an iframe instruction with such a parameter. Therefore, I do not know how I can pass this parameter into the web site.
The question is: Is there a method at all? If yes, what is the correct way to do it?
I have investigated a lot and also tried to add parameters to the doGet function in the sense of:
function doGet() {
return HtmlService.createHtmlOutputFromFile('pmtest')
.setSandboxMode(HtmlService.SandboxMode.IFRAME) .setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL);
}
But this did not make a change.
Here now my code:
code.gs :
function doGet() { return HtmlService.createHtmlOutputFromFile('pmtest') }
html code (pmtest) :
<!DOCTYPE html>
<html>
<script
src="https://maps.googleapis.com/maps/api/js?key=...here is me key ....&libraries=places&callback=initMap">
</script>
<script>
var myCenter=new google.maps.LatLng(51.158742,6.7170850);
function initialize()
{
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(position) {
alert('success');
var myLatlng = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
alert('myLatlng : ' + myLatlng);
myCenter = myLatlng;
CenterMap();
marker.setPosition(myCenter);
}, function(error) {
alert('error');
});
}
var mapProp = {
center: myCenter, zoom:18, gestureHandling: 'greedy', tilt: 0, draggableCursor: 'default',
mapTypeId: google.maps.MapTypeId.SATELLITE
};
var map = new google.maps.Map(document.getElementById("googleMap"),mapProp);
var marker = new google.maps.Marker({ position: myCenter});
marker.setMap(map);
function CenterMap(){ map.panTo(myCenter);}
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
<body>
<div id="googleMap" style="width:1200px;height:700px;"></div>
</body>
</html>
In case you want to open the test page, here is the link:
https://sites.google.com/site/pmtest4711/
When the geolocation command could be executed, a message will appear with "success" and a second with the found position. The google map then shows this location (wherever you are.).
Any good hint would be appreciated.
I'm working on a little weather app project, but now that i've changed the code to make the long and lat change depending on you geo location, the button doesn't work. When i click it nothing happens, i can't even tell if the API is pulling the data. Here is my code as well as a codepen I made to fool around with.
http://codepen.io/lettda/pen/yaGaLx
$(document).ready(function(){
$("#reveal").on("click", function(){
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(position) {
lat = position.coords.latitude;
long = position.coords.longitude;
var long;
var lat;
var api = "http://api.openweathermap.org/data/2.5/weather?lat="+lat+"&lon="+long+"&appid=de61ccfbde0405f57d64dbb53323fccf";
$.getJSON(api, function(data){
$(".message").html(JSON.stringify(data))
});
});
};
});
});
open your developer tools (in chrome press F12) and have a look into the console:
pen.js:4 getCurrentPosition() and watchPosition() no longer work on insecure origins. To use this feature, you should consider switching your application to a secure origin, such as HTTPS. See https://.... for more details.
it's an simple cross origin problem
I really hope someone can help with my problem. I have built a mobile web app http://ufa-ld-qa.azurewebsites.net/ (the QA site) with asp.net mvc4 using Bing Maps API for various functionality in the app. I am having problems with the directions module. When I view the site on my pc (Chrome and IE) it works fine and I see no errors but on mobile devices it is not working (but it did work fine yesterday when we launched to QA). I have used HTML5 geolocation (this may be the issue) to get user's location to allow them to get directions to a location. I will post my code below and if anyone could please help me it would be greatly appreciated. We have tested it on about 7 different mobile devices with different OS's and it doesn't work on any. Does anyone know if this is a Bing issue or my code below? Thanks so much in advance.
<script type="text/javascript">
var map = null;
var directionsManager = null;
var userLat = null;
var userLong = null;
var userPosition = null;
var latlng = new Microsoft.Maps.Location(#Model.latitude, #Model.longitude);
navigator.geolocation.getCurrentPosition(locationHandler);
function locationHandler(position)
{
userPosition = new Microsoft.Maps.Location(position.coords.latitude, position.coords.longitude);
}
function GetMap() {
// Initialize the map
map = new Microsoft.Maps.Map(document.getElementById("map"), { credentials: "Au_7giL-8dUbFkJ8zLjcQKy4dV2ftPfpMxQ0_sVBksoj4Y-1nBT00Z1oqUIU894_",
mapTypeId: Microsoft.Maps.MapTypeId.road});
Microsoft.Maps.loadModule('Microsoft.Maps.Directions', { callback: directionsModuleLoaded });
}
function directionsModuleLoaded() {
// Initialize the DirectionsManager
directionsManager = new Microsoft.Maps.Directions.DirectionsManager(map);
// Create start and end waypoints
var startWaypoint = new Microsoft.Maps.Directions.Waypoint({ location: userPosition });
var endWaypoint = new Microsoft.Maps.Directions.Waypoint({ location: latlng });
directionsManager.addWaypoint(startWaypoint);
directionsManager.addWaypoint(endWaypoint);
// Set request options
directionsManager.setRequestOptions({ routeMode: Microsoft.Maps.Directions.RouteMode.driving });
// Set the render options
directionsManager.setRenderOptions({
itineraryContainer: document.getElementById('directionPanel'),
displayWalkingWarning: false,
walkingPolylineOptions: { strokeColor: new Microsoft.Maps.Color(200, 0, 255, 0) },
});
// Specify a handler for when an error occurs
Microsoft.Maps.Events.addHandler(directionsManager, 'directionsError', displayError);
// Calculate directions, which displays a route on the map
directionsManager.calculateDirections();
}
function displayError(e) {
// Display the error message
alert(e.message);
}
</script>
A couple of things to try. First ensure that your app is allowed to access the users location. Most mobile platforms require you to mark that the app requires access to the GPS in the manifest. Another thing to look into is the possibility that the userLocation isn't populated before your callback for the directions manager is called. It's possible that the GPS takes a little longer on the mobile device to find the users location and as such the directions loaded function is firing before the users location is set, thus passing in a null starting . You might find it useful to have a flag to indicate that the directions manager has loaded and a simple function that runs after setting the flag and also runs after setting the use location that checks that both the directions manager has loaded and the user location has been set and then calls your directions loaded function.
My Windows Phone 8 App is experiencing similar behavior. (Nokia 920)
http://bing.com/maps/default.aspx?cp=47.677797~-122.122013&lvl=12
When the Website preference is set to 'desktop version' the map renders correctly.
When the Website preference is set to 'mobile version' the map renders incorrectly.
Just started happening about a week ago !
Trying to load the Google maps asynchronously so that the start of the HTML page is faster.
Have used the following code as mentioned in the link: https://developers.google.com/maps/documentation/javascript/tutorial#asynch. Section: Asynchronously Loading the API.
function initialize() {
var myOptions = {
zoom: 8,
center: new google.maps.LatLng(-34.397, 150.644),
mapTypeId: google.maps.MapTypeId.ROADMAP
}
var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
}
function loadScript() {
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "http://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&sensor=TRUE_OR_FALSE&callback=initialize";
document.body.appendChild(script);
}
window.onload = loadScript;
Issues:
When the network is disconnected after the loadScript() function is invoked. Currently we do not find anyway to check the network connection is terminated & do appropriate error handling.
Even when the network is available some times the callback function 'initialize()' is never called.
Loading of google maps on mobile device is very slow even on a 3G network.
In both the cases mentioned above, we start a loading icon immediately after loadScript() is invoked. As initialize() is not called back it gets blocked in the loading icon for infinite time.
Kindly provide some pointers to handle the network disconnect & callback function not invoked issues.
The Maps API does not have a native way to handle this. Thankfully HTML5 does. Listening to the document.online / document.offline events is very effective and I have used it to solve this problem.
See https://developer.mozilla.org/en/DOM/document#Event_handlers
This is supported in at least iOS 5 and Android 2.3.
You could also use setTimeout to check that the API callback has occurred and handle it appropriately if not.
I want to use the google geocode via HTTP functionality to translate a city name into longitude and latitude in for my AJAX web application.
However, it appears that no callback function exists for the HTTP geocoder functionality
http://code.google.com/apis/maps/documentation/geocoding/index.html
Is that true, no callback function exists?
Because if that is true, it essentially means that the Google geocode via HTTP api is useless when used with AJAX because JavaScript will throw a crossdomain exception error.
Any ideas on how I can use the geocode via HTTP api in my AJAX web application in JavaScript?
Note: I do not want to use the full blown Google Maps API which is approx 200kb download (i.e. GClientGeocoder). I want to use the HTTP api b/c of it's super quick responsiveness and lack of needing my web users from having to download the huge full blown interactive google maps api.
E.g.
http://maps.google.com/maps/geo?output=json&sensor=false&key={API_KEY}&q={CITY,STATE}&CALLBACK=????
Thanks
Here is an example that uses the Google Maps Geocoder. The geocoder function getLocation takes a callback function as the second argument.
function findAddress(street, city, state, zip) {
var address = [
street,
city.toLowerCase(),
state.toLowerCase(),
zip
].join(', ');
if (!geocoder) {
geocoder = new GClientGeocoder();
}
if (geocoder) {
geocoder.getLocations(
address,
function(result) {
var dialog, len, point;
if (result.Status.code != G_GEO_SUCCESS) {
alert("Error: "+result.Status.code)
} else {
len = result.Placemark.length;
if (len > 1) {
alert("Multiple matches were found. I'll leave it as an exercise to handle this condition");
} else {
point = new GLatLng(
result.Placemark[0].Point.coordinates[1],
result.Placemark[0].Point.coordinates[0]
);
}
}
}
);
}
}
hmm....I think you'd have to have your AJAX call back to your own server, and then call Google's Geocode from your server.
Thats how I do AJAX geocoding, it all goes through my ASP.NET code.
EDIT:
In the ASP.NET webforms environment I might implements this as a lightweight ASHX file, but for the purposes of simplicity, here's an ASPX example:
public partial class GoogleHandler : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e) {
Response.Write(GetGoogleXML("http://pseudo_googlegeocode?parameter=" + parametersFromQuerystring);
}
}
In the example above, the .NET page is only passing the request along.
But in a real environment, I'd rather my .NET code do more than just pass the data over. This way I can do error handling, filtering, validation, business logic, all on the server, before sending that data over to the client.
Also, this allows for greater abstraction. i.e, I might change from google to yahoo geocoding. In this way I'd only have to change my serve logic, and leave the client to just receive a generic set of coordinates/location data.
Also, using that abstraction I could actually aggregate multiple data from various geocoding data sources. Again, the server takes care of aggregating, the client just receives and displays the filtered data.
As others noted, you didn't read the full page. You want what that page calls the JavaScript Client Geocode.
Here's a simplified version of a script I wrote a while back. It also uses a Google Map control, but feel free to ignore that. The delay function hack is because it seemed Google was occasionally returning null when I hit their servers too fast. I don't know if this is still an issue, so don't put it in unless you have to.
<script type="text/javascript">
//<![CDATA[
var freezeLocations;
var coder;
var map;
function load() {
if (GBrowserIsCompatible()) {
map = new GMap2(document.getElementById("map"));
map.setCenter(new GLatLng(38.479395, -98.349609), 4);
map.addControl(new GLargeMapControl());
}
coder = new GClientGeocoder();
missionLocations = new Array();
missionLocationsDelayed = new Array();
addMissionLocation("Atlanta, Georgia", "http://improveverywhere.ning.com/group/atlanta");
//etc.
}
function addMissionLocation(newLocation, url)
{
var successful = false;
var counter = 0;
while(!successful && counter < 3)
{
coder.getLatLng(
newLocation,
function(point) {
if (!point) {
//alert(newLocation + " not found");
successful = false;
} else {
missionLocations.push(new GMarker(point, { title:newLocation}));
//alert(missionLocations.length);
map.addOverlay(missionLocations[missionLocations.length - 1]);
missionLocations[missionLocations.length - 1].bindInfoWindowHtml("<a href='" + url + "'>" + newLocation + "</a>");
successful = true;
}
}
);
if(!successful)
{
delayGeocode();
}
counter++;
}
}
function delayGeocode()
{
for(var i = 0; i < 2000000; i++)
{
}
}
//]]>
</script>
You could use Yahoo Query language as outlined in my blog post http://jawtek.blogspot.com/2009/03/unwritten-guide-to-yahoo-query-langauge.html
You would be able to use a yql statement like: select * from json where
url="http://maps.google.com/maps/geo?output=json&sensor=false&q=Indianapolis,In"
Then you would add a script tag to your html (can be done with document.createElement('script')) with a src http://query.yahooapis.com/v1/public/yql?q={your yql here}&format=json&callback={your function here} where {your yql here} is replace with a URI Encoded version of you yql statment.
If you have looked at the
documentation and not found it and
both Andrew and Mike have not said
"yes", and told you how to do it, I
suspect you have your answer.
lol
and lets all read the service's documentation:
10.13 hide or mask from Google the identity of your service as it uses
the Service, including by failing to
follow the identification conventions
listed in the Maps APIs Documentation;
or
10.14 violate any policies in the Maps APIs Documentation or violate Google's
Software Principles (...)
Also
This service is designed for geocoding static (known) addresses
using a REST interface, for placement
of application content on a map. For
dynamic geocoding of user-defined
addresses (for example, within a user
interface element), consult the
documentation for the JavaScript
Client Geocoder or the Maps API for
Flash Client Geocoder. Geocoding is a
time and resource intensive task.
Whenever possible, pre-geocode known
addresses (using the Geocoding Service
described here or another geocoding
service), and store your results in a
temporary cache of your own design.
But then again you could try Google Maps API V3 Geocoder
Look at the Google Maps API. It has some functions with callback that uses it's geocoding service.
http://code.google.com/apis/maps/documentation/reference.html#GClientGeocoder.getLatLng
I second the suggestion to create a server-side page to access the geocoder. I am doing something similar and it works great. There's a good article about working with the geocoder in PHP here.
Also note that technically you're not permitted to use Google's geocoder unless you'll be displaying the data on a Google Map - but I don't know if they'll actually check on you.
I too encountered the challenges you described above. As you indicated, Google prevents cross-domain HTTP access to the Geocode API URL:
Same origin policy
JSONP and Google Maps API Geocoder - Not a Bug
This does severely diminish its usefulness when using client-side scripting. The only solution I found to this challenge was to create a server-side proxy service that relays the responses from the Google Maps Geocode API to my client-side script.
I wrote an extremely long-winded blog post describing this process.