I'm working on a site that will use the Google Maps / Places APIs. I have verified that my API key is working fine, so that's not an issue. I just can't even get the map to display - that's my issue.
I've copied the example exactly, and it still won't work.
Here's my code in a gist because it's a few files. It should be runnable, that's all the content.
What I've tried so far:
- Putting it all in a document ready function (jQuery).
- Taking it out of the getCurrentPosition function so it was just out in the main.js file.
- Moving the position of the script link in my HTML file, nothing changed at any position.
- If I console.log() the lat and long variables, they print my location. But they're "undefined" when I type them into Chrome Dev Tools console. However, my "map" variable prints the map div to console.
- Using static coords, rather than coords gathered from the navigator HTML5 element.
- Setting height and width for the map div with pixels, percent, and vh/vw. It's taking the screen - I know because I gave it a background color that is showing.
- Added parameters to the end of my API load: &callback=initialize&libraries=places
This is my first time using Maps, so I'm totally lost here. I followed Google's example to a tee, and still nothing.
WebStorm is underlining all of the google.maps.x classes and saying they're "unresolved variables or types". That may be my problem, but I don't know what causes that or how to fix it. And to be clear, I have looked through every article I could find on Stack Overflow related to this, and haven't found a solution.
UPDATE:
- I just tried copying and pasting this example from Google exactly as it appears (with my API key, of course), and it still didn't work. I put it in script tags in my HTML. The only way it works is if I delete the initMap() function - not the contents of it, just the declaration of it as a function. So why is the scope acting so weird here? It's treating everything inside of the function (which is in a script tag in my HTML) as if it's all undefined just because it's in a function... at the highest scope level.
You are trying to run main.js before the Google Maps SDK has loaded. Move it above main.js' inindex.html`:
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key=MY_KEY&libraries=places"></script>
<script src="js/plugins.js"></script>
<script src="js/main.js"></script>
Then, remove the initialize function:
if ("geolocation" in navigator) {
console.log("Geolocation is enabled.");
navigator.geolocation.getCurrentPosition(function (position) {
var lat = position.coords.latitude;
var long = position.coords.longitude;
var map;
var service;
var infoWindow;
console.log("lat: " + lat);
//Initialize Google Map. Starts at user's location.
var userLocation = new google.maps.LatLng(lat, long);
map = new google.maps.Map(document.getElementById('map'), {
center: userLocation,
zoom: 15
});
var request = {
location: userLocation,
radius: '500',
types: ['store']
};
service = new google.maps.places.PlaceService(map);
service.nearbySearch(request, callback);
//Callback function for nearbySearch
function callback(results, status) {
if (status == google.maps.places.PlacesServiceStatus.OK) {
for (var i = 0; i < results.length; i++) {
var place = results[i];
createMarker(results[i]);
}
}
}
});
} else {
console.log("Geolocation is disabled.");
//Inform user why we use location
//Allow user to enter location manually
}
That works for me.
Related
Code in question:
function setAllMap(map) {
console.debug(3);
for (var i = 0; i < markers.length; i++) {
markers[i].setMap(map);
}
resetZoomOnMapEvents(markers);
}
function resetZoomOnMapEvents(nuLoc) {
console.debug(1);
var marks = typeof nuLoc == 'undefined' ? nuLoc : markers;
var bounds = new google.maps.LatLngBounds();
for (var i in marks) {
bounds.extend(marks[i].position);
}
map.setCenter(bounds.getCenter());
map.fitBounds(bounds);
}
The map works correctly on return of search results. It will sometimes center to the center of the map markers but other times it will center on Spain/Africa. Direct question: why is the behavior not consistent?
Perhaps by sharing my script(s) it will help trigger something?
I have a loop, that for each position, I call a method called "renderMarker". That method assembles the marker.
I then call the "centerMap" method.
var GoogleMaps = {
'map': {},
'marker': {},
'markerArray': [],
'markerlatlngArray': [],
/**
* Renders marker(s) to the map.
* Creates infowindow for the given marker.
*
* #param {object} myobj| data for the given marker.
* #returns {void}
*
*/
renderMarker: function (myobj) {
var markerlatlng = new google.maps.LatLng(myobj.lat, myobj.lng);
GoogleMaps.marker = new google.maps.Marker({
'position': markerlatlng,
'map': GoogleMaps.map,
'title': my_title,
'icon': 'my-icon.png',
'animation': google.maps.Animation.DROP,
'data': '<div class="myobjinfowindow">'
'<p>Whatever you want goes here.</p>'
+ '</div>'
});
GoogleMaps.marker.set('propertyA', myobj.propertyA);
GoogleMaps.marker.set('propertyB', myobj.propertyB);
GoogleMaps.marker.set('propertyC', myobj.propertyC);
GoogleMaps.markerlatlngArray.push(markerlatlng);
GoogleMaps.markerArray.push(GoogleMaps.marker);
GoogleMaps.centerMap();
GoogleMaps.infowindow = new google.maps.InfoWindow();
google.maps.event.addListener(GoogleMaps.marker, 'click', function () {
GoogleMaps.infowindow.close();
GoogleMaps.infowindow.setContent(this.data);
GoogleMaps.infowindow.open(GoogleMaps.map, this);
});
}
/**
* Centers the map around the given markers.
*
* #returns {void}
*
*/
centerMap: function () {
var latlngbounds = new google.maps.LatLngBounds();
$.each(GoogleMaps.markerlatlngArray, function (i, marker) {
latlngbounds.extend(marker);
});
GoogleMaps.map.setCenter(latlngbounds.getCenter());
GoogleMaps.map.fitBounds(latlngbounds);
}
}
As given, the question asks very directly: "Why is it that sometimes the map recenters on an area between Spain and Arica?"
First reasonable analysis would suggest making sure that the code provided actually works.
After extensive testing and tracing, the code does work. Part of the difficulty in this is the fact that this is an inherited project and the methods used are called in multiple locations. The difficulty is increased by virtue of the fact that just loading the page launches a search which fires off these same methods and there is no inherited way to determine if the method is called on page load or user interaction. Therein lies the apparent inconsistency: Why would it load correctly 100% of the time on a manual search but not 100% of the time on initial page load search?
To ensure that this is a reasonable question, extensive testing of all modules and pages using the google maps api needed to be completed and observations noted. Indeed, all pages with this feature worked correctly on manual search and all pages but one worked correctly on initial page load search.
This begs the next logical question: is something happening on that one page to cause inconsistent behavior?
In the pursuit of an answer, javascript was traced, network responses were analyzed. Network times were not responsible (necessary analysis in case data did not exist by the time a call was completed thereby possibly altering results). The remaining conclusion is that, for some reason, sometimes something would recenter the map either before or after the calls noted in the original question.
After more analysis, a method was discovered that reset the map center to 35, 0 lat/long. This is, incidentally, a location between Spain and Africa. Removing the code which forced this recentering solved the issue.
To summarize, there is nothing wrong per se with the code submitted in the original question. The problem with a deeply "hidden" javascript method that was not readily visible and was not documented.
I am working on a somewhat complex google map and have run into an issue with fitbounds.
It works perfectly... most of the time, but occasionally ignores my bounds and loads the map in the middle of the ocean.
My markers still appear and had loaded correctly if i zoom out and search for them.
Any thoughts?
Markers from json string
Code (stripped out for simplicity):
**var mybounds = new google.maps.LatLngBounds();**
$.getJSON(callRoot + JSON.stringify(mapSearchParams), function(data) {
$.each(data.markers, function (i, marker) {
**var position = new google.maps.LatLng(marker.latitude, marker.longitude);**
addMarker(position, findIcon(marker.category, "marker"), marker.category, marker.title, marker.subtitle, marker.destNodeGUID, marker.documentURL, marker.primaryImageURL, marker.isFeatured);
**mybounds.extend(position);**
}); // end .each
**map.fitBounds(mybounds);**
Please also note: I don't get any js errors on the page.
function ZoomCenter(bounds, canvas)
{
var center = bounds.getCenter();
if (canvas.getMapTypeId() == "roadmap") canvas.fitBounds(bounds);
else
{
var maxZoomService = new google.maps.MaxZoomService();
maxZoomService.getMaxZoomAtLatLng(center, function(response)
{
if (response.status != google.maps.MaxZoomStatus.OK) alert("Error in Google MaxZoomService");
else
{
var max_zoom = (response.zoom > SATMAP_MAX_ZOOM) ? SATMAP_MAX_ZOOM : response.zoom;
canvas.setOptions( { maxZoom: max_zoom } );
canvas.fitBounds(bounds);
canvas.setOptions( { maxZoom: SATMAP_MAX_ZOOM} );
}
});
}
}
This first time this is called it zooms to 1 less than what will fit on the map. The second time and and every time after the first it will zoom to the correct level using the exact same bounds data.
Is there a bug in fitBounds? or am I missing something?
Without seeing more code and having never experienced this quirk myself, it's difficult to say. However I am always more suspicious that there is a bug in my own code than in Google's, so I would eliminate the obvious possibilities there first.
Therefore, the first thing I would do is use a JS debugger to confirm that:
bounds is identical both times
it's going through the same execution path hitting the same canvas.fitBounds(bounds) call both times. (You have it in there twice. Which one gets executed depends on your conditional involving MapTypeId. If canvas has a different MapTypeId each time through, that could be causing the quirk.)
If that doesn't turn up the problem, the next place to look might be the Google Maps API issue tracker.
We're trying to build an app that allows users to view places around their current location.
You can see the Google Maps API & the Google Places Library functioning here, but not as one: http://www.blazingsasquatch.com/geo/index4.html
You'll notice the button "show me my loc" pulls your current location and the map is showing an arbitrary location in Boston with places nearby.
We've created variables for both the longitude and latitude and we've attempted to pass those variables directly into the "pyrmont" location variable but we've had no luck.
Initially we tried setting the "pyrmont" location using following, also with no luck:
google.maps.LatLng(position.coords.latitude, position.coords.longitude);
So how can we get the current location populated?
var pyrmont = new google.maps.LatLng("CURRENT LOCATION HERE");
Will it accept a variable or an integer only?
initialize will be called before the callback of navigator.geolocation.getCurrentPosition() , so you cannot use the result in initialize() .(you may view getCurrentPosition as a asynchronous request)
Invoke the action(creation of the marker and places-request) inside the callback of getCurrentPosition()
See a working demo: http://jsfiddle.net/doktormolle/C5ZtK/
The LatLng constructor takes two floating point numbers, like so:
pos = new google.maps.LatLng(-34.397, 150.644);
After reviewing the source code, it seems the problem is another one: the anonymous callback function you are passing to getCurrentPosition() is called when the geographic location is found, which can take some time (especially using GPS and such). initialize() is called when the page is loaded, which is sooner, so place is not set at this time (besides, it's not visible in initialize() since it's not a global variable, but never mind that). So you have to move the stuff you're currently doing in initialize() to the callback function you are passing to getCurrentPosition(). Then, you can use
var pyrmont = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
Nothing I've tried seems to work.
I found these two links and thought they'd be helpful, but that hasn't worked either.
Dynamically load JavaScript with JavaScript
https://developers.google.com/loader/
Here's roughly what my Greasemonkey script looks like currently:
var init_map = function() {
new google.maps.Geocoder().geocode({address:'1125 NW 12th Ave, Portland, OR'},function(result){
alert(result);
});
}
function loadMaps() {
GM_log("loadMaps called");
google.load("maps", "3", {"callback" : init_map, "other_params":"key=foo&sensor=false"});
}
function loadScript(filename,callback){
var fileref=document.createElement('script');
fileref.setAttribute("type","text/javascript");
fileref.onload = callback;
fileref.setAttribute("src", filename);
if (typeof fileref!="undefined"){
document.getElementsByTagName("head")[0].appendChild(fileref);
}
}
$(document).ready(
function() {
GM_log("document ready");
loadScript('http://www.google.com/jsapi?key=ABQIAAAAfoo',function(){
loadMaps();
});
}
);
I've found that if I don't include
// #require http://www.google.com/jsapi?key=ABQIAAAAfoo
in the Greasemonkey script, I get a google is undefined error. If I do include it, init_map() never gets called. Any suggestions?
var init_map defines a local variable in the GreaseMonkey context.
If you want to run JavaScript in the context of a webpage, I recommend to inject two <script> tags in the web page (another method is to prefix all of your global variables with unsafeWindow.):
Google's map API
Your script.
Example:
// ==UserScript==
// #name Name of script
// #namespace YourNameSpaceHere
// #match http://blabla.com/*
// #version 1.0
// #run-at document-end
// ==/UserScript==
var head = document.head || document.documentElement;
var script = document.createElement('script');
script.src = 'http://www.google.com/jsapi?key=ABQIAAAAfoo';
head.appendChild(script);
var script2 = document.createElement('script');
script2.textContent = '... code here ..';
head.appendChild(script2);
// Clean-up:
script.parentNode.removeChild(script);
script2.parentNode.removeChild(script2);
E4X instead of a plain string
The easiest option to embed a string of JavaScript code in your GreaseMonkey script, without escaping quotes and newlines is to use the E4X format:
script2.textContent = <x><![CDATA[
alert("test");
]]></x>.toString();
I flagged this question as duplicate of how to use the google maps api with greasemonkey to read a table of addresses and trace the route? but the mod "found no evidence to support it".
So i will just copy-paste what i did in my question, since its not a duplicate...
Nah, just kidding :)
Lets start with your last statement:
I've found that if I don't include // #require
http://www.google.com/jsapi?key=ABQIAAAAfoo in the Greasemonkey
script, I get a google is undefined error. If I do include it,
init_map() never gets called. Any suggestions?
Yes.
First, the google maps API should not be loaded as a #require. Instead, do it like this
API_js_callback = "http://maps.google.com/maps/api/js?sensor=false®ion=BR&callback=initialize";
var script = document.createElement('script');
script.src = API_js_callback;
var head = document.getElementsByTagName("head")[0];
(head || document.body).appendChild(script);
Second, add google = unsafeWindow.google, otherwise you get the "google is undefined" error.
So, your code should start like this
var init_map = function() {
google = unsafeWindow.google
new google.maps.Geocoder().geocode . . . . . .
About the rest of your code... well, just click on the link above and there you will find how to create a DIV on the fly, add the map to it, append the DIV to the page in a fixed position, etc.
Feel free to copy whatever you want.
Greasemonkey scripts are free anyway :)
I tested the answers here and in many other places and nothing would work. Maybe because the API is now v3 or who knows.
I am going to post the answer that worked for me, which is quite different from the others I found, and I believe can be used for many other cases. It's arguably a bit ugly, but after all this is script injection and nobody likes injections.
I don't copy the whole thing in jsbin / codepen / etc. because they simply cannot replicate the GS (Greasemonkey) environment (at least yet) and inner workings.
LOADING API
I had control over the destination webpage so this was there instead of being added via GS.
<script src="https://maps.googleapis.com/maps/api/js?key=my-personal-key"></script>
On my experience, if you don't add the key, after a few requests it will fail and you will have to wait some time until it works again.
I also have there a div whith a floating window where I would create my map.
<div style="overflow:hidden; height:500px; width:700px; position:fixed; top:20px; right:20px; border:3px solid #73AD21;">
<div id="gmap_canvas" style="height:500px;width:700px;"></div>
<style>#gmap_canvas img{max-width:none!important;background:none!important}</style>
<div id="Content_Title"></div>
</div>
GS SCRIPT
// Pass whatever data you need to the window
unsafeWindow.mapdata=JSON.stringify(mapdata);
// Define content of script
var script2 = document.createElement('script');
script2.textContent = `
// Get data
mapdata=JSON.parse(window.mapdata);
// Create map and use data
function initializeX2() {
// some stuff ...
// Create map
var mapCanvas = document.getElementById('gmap_canvas');
var myLatLng = {lat: parseFloat(mapdata[max].latitude), lng: parseFloat(mapdata[max].longitude)};
var mapOptions = {
center: myLatLng,
zoom: 15,
mapTypeControl: false,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(mapCanvas, mapOptions);
var marker=[];
var contentInfoWindow=[];
var infowindow=[];
// Create markers
for (var i = max ; i > max-iterations ; i--) {
// Create marker
var BLatLng={lat: parseFloat(mapdata[i].latitude), lng: parseFloat(mapdata[i].longitude)};
console.log(BLatLng);
marker[i] = new google.maps.Marker({
position: BLatLng,
map: map
});
// Create infowindow
contentInfoWindow[i]=mapdata[i].number + " - " + mapdata[i].name;
infowindow[i] = new google.maps.InfoWindow({content: contentInfoWindow[i] });
// The function has this strange form to take values of references instead of references (pointers)
google.maps.event.addListener(marker[i], 'click', function(innerKey) {
return function() {
infowindow[innerKey].open(map, marker[innerKey]);
}
}(i));
// Open markers
infowindow[i].open(map, marker[i]);
}; // end of for
}; // end of initializeX2
initializeX2();
`; // End of string to be added to page
// Add script to the page
var head = document.head || document.documentElement;
head.appendChild(script2);
// Clean-up:
script2.parentNode.removeChild(script2);
Some explanations
In my case the markers are opened when created, and multiple may stay open. That is my desired behaviour. If you want something else you have to search around.
This may help you.
Create only ONE window to have only one infowindow open at a time ( http://www.aspsnippets.com/Articles/Google-Maps-API-V3-Open-Show-only-one-InfoWindow-at-a-time-and-close-other-InfoWindow.aspx )
If someone has got the other solutions working with API v3 (via google = unsafeWindow.google ) I would be very interested to know.