Google Maps API (v3) adding/updating markers - javascript

EDIT: It now works, but does not load if the user does not allow or have location-based services. See accepted answer comment for jsfiddle example.
I've looked through a few tutorials and questions but I can't quiet understand what's happening (or in this case, not happening). I'm loading my map when the user clicks a link. This loads the map with the users current location in the center, and a marker at the users location. However, any markers outside of the if (navigation.location) don't seem to load. Below is my current code:
function initialize() {
// Check if user support geo-location
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(position) {
var point = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
var userLat = position.coords.latitude;
var userLong = position.coords.longitude;
var mapOptions = {
zoom: 8,
center: point,
mapTypeId: google.maps.MapTypeId.HYBRID
}
// Initialize the Google Maps API v3
var map = new google.maps.Map(document.getElementById("map"), mapOptions);
// Place a marker
new google.maps.Marker({
position: point,
map: map,
title: 'Your GPS Location'
});
});
} else {
var userLat = 53;
var userLong = 0;
var mapOptions = {
zoom: 8,
center: new google.maps.LatLng(userLat, userLong),
mapTypeId: google.maps.MapTypeId.HYBRID
}
// Place a marker
new google.maps.Marker({
position: point,
map: map,
title: 'Default Location'
});
// Initialize the Google Maps API v3
var map = new google.maps.Map(document.getElementById("map"), mapOptions);
}
<?
for ($i = 0; $i < sizeof($userLocations); $i++) {
?>
var userLatLong = new google.maps.LatLng(<? echo $userLocations[$i]['lat']; ?>, <? echo $userLocations[$i]['long']; ?>);
new google.maps.Marker({
position: userLatLong,
map: map,
title:"<? echo $userLocations[$i]['displayName'] . ', ' . $userLocations[$i]['usertype']; ?>"
});
<?
}
?>
}
function loadMapScript() {
if (typeof(loaded) == "undefined") {
$("#showMap").css("display", "none");
$("#showMapLink").removeAttr("href");
$("#map").css("height", "600px");
$("#map").css("width", "600px");
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "http://maps.googleapis.com/maps/api/js?key=MY_API_KEY&sensor=true&callback=initialize";
document.body.appendChild(script);
loaded = true;
} else {
alert("Map already loaded!");
}
}
loadMapScript() is called when the user clicks a link. The php for loop loops through a pre-created array with all the information.
I'm guessing I don't fully understand it, as when if I put:
var userLatLong = new google.maps.LatLng(53, 0);
new google.maps.Marker({
position: userLatLong,
map: map,
title:"Title"
});
into the console (Google Chrome), I get the error:
Error: Invalid value for property <map>: [object HTMLDivElement]
I don't, however, get any errors otherwise. Any help would be much appreciated! :)

navigator.geolocation.getCurrentPosition() is asynchronous.
Reorganize your code like this:
var mapOptions = {
zoom: 8,
mapTypeId: google.maps.MapTypeId.HYBRID
}
function initialize() {
// Check if user support geo-location
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(function(position) {
makeMap(position.coords.latitude, position.coords.longitude, 'Your GPS Location');
});
} else {
makeMap(53, 0, 'DefaultLocation');
}
}
function makeMap(lat, lng, text) {
var point = new google.maps.LatLng(lat, lng);
mapOptions.center = point;
map = new google.maps.Map(document.getElementById("map"), mapOptions);
new google.maps.Marker({
position: point,
map: map,
title: text
});
<?php for ($i = 0; $i < sizeof($userLocations); $i++): ?>
var userLatLong = new google.maps.LatLng(<? echo $userLocations[$i]['lat']; ?>, <? echo $userLocations[$i]['long']; ?>);
new google.maps.Marker({
position: userLatLong,
map: map,
title:"<? echo $userLocations[$i]['displayName'] . ', ' . $userLocations[$i]['usertype']; ?>"
});
<?php endforeach ?>
}
Also, consider bootstraping the $userLocations into a JavaScript variable like this:
var userLocations = <?php print json_encode($userLocations) ?>;
Then execute your for loop in JavaScript, instead of mixing languages.

Have you tried:
var map = null;
function initialize() { ... }
and then changing the code inside:
map = new google.maps.Map( ... ); //make this the first line
if (navigator.geolocation) {
// Change the code from:
var map ...
// to:
map ...
You just reference the map directly (without the var) everywhere else, so that should work.

Change:
var map = new google.maps.Map(document.getElementById("map"), mapOptions);
To:
map = new google.maps.Map(document.getElementById("map"), mapOptions);
Because of var, your map variable is tied the the scope of initialize(). Removing it will set it as the global map variable (or window.map), making it available outside of the initialize() function.
What's happening is you have an HTML element <div id="map">. In many browsers, global variables are created from html element ids, so map equals document.getElementById('map').
Edit: Actually, this only explains your problem in the Chrome console. You need to set map before trying to attach markers to it, as you do within if (navigator.geolocation) {}. This also explains why none of the user location markers are being placed. The code to place them runs before initialize(). Put this code either within initialize or within its own function, and call that function from initialize.

It looks like you're creating the marker, but not doing anything with it. Try changing your new Marker to look like this:
var marker = new google.maps.Marker({
position: point, // this won't actually work - point is out of scope
title: 'Your GPS Location'
});
marker.setMap(map);
Edit: Make sure the point is inside the map!
var bounds = new google.maps.LatLngBounds();
bounds.extend(point);
map.fitBounds(bounds);

Related

Google Maps API: Mutiple Marker/Closures

Hey first time posting here. Trying to post multiple markers that I am pulling in from an API. I am a novice programmer, but I believe closures in the issue. I have tried many variations but I still can't get it to work. Can someone take a look?
$data = json_decode($json);
//var_dump($data);
foreach($data as $object):?>
<?php endforeach;
?>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.0/jquery.min.js"></script>
<script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCGLTlvxWSV6x4yH5XqqItlgHHIPt8GYp0" type="text/javascript"></script>
<script type="text/javascript">
var lat = '<?php echo $object->{'latitude'}?>';
var long = '<?php echo $object->{'longitude'}?>';
// check DOM Ready
$(document).ready(function() {
// execute
(function() {
// map options
var options = {
zoom: 5,
center: new google.maps.LatLng(39.909736, -98.522109), // centered US
mapTypeId: google.maps.MapTypeId.TERRAIN,
mapTypeControl: false
};
// init map
var map = new google.maps.Map(document.getElementById('map_canvas'), options);
// set multiple marker
for (var i = 0; i < 1000; i++) {
// init markers
var marker = new google.maps.Marker({
position: new google.maps.LatLng(lat,long),
map: map,
title: 'Check-In ' + i
});
// process multiple info windows
(function(marker, i) {
// add click event
google.maps.event.addListener(marker, 'click', function() {
var infowindow = new google.maps.InfoWindow({
content: '<?php echo $object->{'username'}?>'
});
infowindow.open(map, marker);
});
})(marker, i);
};
})();
});
</script>
</head>
<body>
<div id="map_canvas" style="width: 800px; height:500px;"></div>
</body>
You're in for a world of hurt if you intersperse PHP loops with JavaScript loops like this. What you should do instead is generate a JSON array or JavaScript object for your markers from PHP, and then loop through your array in JavaScript.
For example, you could generate this JavaScript array from PHP:
var places = [
{ lat:10, lng:20, username:"Weez" },
{ lat:30, lng:40, username:"Mike" }
];
You can see where you could use your foreach loop to generate this, or use PHP's json_encode function.
Then your JavaScript code might look something like this:
$(document).ready(function() {
var options = {
zoom: 5,
center: new google.maps.LatLng( 39.909736, -98.522109 ),
mapTypeId: google.maps.MapTypeId.TERRAIN,
mapTypeControl: false
};
var map = new google.maps.Map(
document.getElementById('map_canvas'),
options
);
places.forEach( function( place, index ) {
var marker = new google.maps.Marker({
position: new google.maps.LatLng( place.lat, place.lng ),
map: map,
title: 'Check-In ' + index
});
google.maps.event.addListener( marker, 'click', function() {
var infowindow = new google.maps.InfoWindow({
content: place.username
});
infowindow.open( map, marker );
});
});
});
I took out a couple of nested inline functions that aren't necessary. You are right that you need a closure (or some other mechanism) to capture the username for each of your markers to use in the click event handler, but the the callback function used with the .forEach() loop provides that closure for you. place, index, and marker are unique variables for each iteration of the loop, because they are arguments or local variables in the callback. So when you use place.username inside the click handler it has the value you expect.

Google Map API use LatLng or Address

I'm using Javascript to render an embedded Google Map canvas on my website.
The inputs to the rendering are lat/lng coordinates that are retrieved from a database. However, if lat/lng returns null, the map will render based on the corresponding address string retrieved from the database. The following script always renders correctly for lat/lng coordinates inputs, but doesn't work for address input. Strangely, when I refresh the page multiple times, the address input would work randomly. I'm trying to cut out this randomness. Think I'm pretty close but I can't seem to find the missing link.
Note: if lat/lng is null, a default value is applied to $lat and $lng so it doesn't mess up the JS below.
I would appreciate if anyone could tell me what's wrong with the below code that's causing the random rendering of address strings.
var map;
var marker;
var geocoder;
function initialize() {
var mapCanvas = document.getElementById('map-canvas');
var estLatLng = new google.maps.LatLng( <? php echo $lat; ?> , <? php echo $lng; ?> );
var mapOptions = {
center: estLatLng,
zoom: 17,
mapTypeId: google.maps.MapTypeId.ROADMAP,
disableDefaultUI: false,
streetViewControl: true,
scrollwheel: false
}
map = new google.maps.Map(mapCanvas, mapOptions);
marker = new google.maps.Marker({
position: estLatLng,
map: map,
draggable: false,
animation: google.maps.Animation.DROP,
title: "<?php echo $name;?>"
});
}
function toggleBounce() {
if (marker.getAnimation() != null) {
marker.setAnimation(null);
} else {
marker.setAnimation(google.maps.Animation.BOUNCE);
}
}
google.maps.event.addDomListener(window, 'load', initialize);
<? php
} ?>
$(".navbar").load("navbar.html", function() {
$("#navbarrestaurants").addClass("active");
});
$(document).ready(function() { <? php
if ($calcAddress) { ?> // this chunk of code is not loaded if lat/lng is not null
geocoder = new google.maps.Geocoder();
geocoder.geocode({
'address': "<?php echo $address;?>",
'componentRestrictions': {
country: 'Singapore'
}
}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
map.setCenter(results[0].geometry.location);
marker = new google.maps.Marker({
map: map,
position: results[0].geometry.location
});
} else {
alert('Geocode was not successful for the following reason: ' + status);
}
}); <? php
} ?>
});
I believe your problem is that the code in $(document).ready is being executed before that in your initialize function (listening for window load). The load event is called once the page is completely loaded, including images, etc, while everything in your document ready block is called slightly earlier when the DOM is ready.
Because it is executed sooner, and acting upon variables like map, that haven't been set up yet by the initialize function, the code in your geocoding callback is probably causing errors when it tries to alter the map center and set marker coords.
Try executing your geocoding code after the map is initialized. ie: wrap it in its own function and call it at the end of the initialization function.
function initialize() {
var mapCanvas = document.getElementById('map-canvas');
var estLatLng = new google.maps.LatLng( <? php echo $lat; ?> , <? php echo $lng; ?> );
var mapOptions = {
center: estLatLng,
zoom: 17,
mapTypeId: google.maps.MapTypeId.ROADMAP,
disableDefaultUI: false,
streetViewControl: true,
scrollwheel: false
}
map = new google.maps.Map(mapCanvas, mapOptions);
marker = new google.maps.Marker({
position: estLatLng,
map: map,
draggable: false,
animation: google.maps.Animation.DROP,
title: "<?php echo $name;?>"
});
codeAddress();
}
ex: http://jsfiddle.net/j7pb7w3d/2/
This isn't great however, as the map starts with its default center, then visibly jerks a second later to the new address.
Instead you could determine whether or not geocoding is necessary first, and do this before the map is loaded, then use the result to set the map center and marker when the map is first created. Ex: http://jsfiddle.net/qsefxu5q/2/
Note these examples are hardly perfect and will need to be changed for your purposes. Hopefully they give you some ideas.

Update markers with current position on Google Map API

I am learning to use javascript right now with Rails and I'm having some issues with updating my markers according to my current position using AJAX. I believe the ready page:load is not running the updated coords that have been attached as a data-attribute, coords since the page is not technically reloading. How can I use my current position data and update it with events with longitude/latitude values?
var map;
$(document).on('ready page:load', function() {
if ("geolocation" in navigator) {
myMap.init();
var coords = $('#map-canvas').data('coords');
if (coords){
myMap.addMarkers(coords);
}
}
});
myMap.init = function() {
if(navigator.geolocation){
var mapOptions = {
zoom: 14,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
map = new google.maps.Map(document.getElementById('map-canvas'), mapOptions);
navigator.geolocation.getCurrentPosition(function(position){
var pos = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
var infoWindow = new google.maps.InfoWindow({
map: map,
position: pos
});
var marker = new google.maps.Marker({
position: new google.maps.LatLng(position.coords.latitude, position.coords.longitude),
map: map
});
map.setCenter(pos);
var latitude = position.coords.latitude;
var longitude = position.coords.longitude;
$.ajax({
url:"/all_events",
method: "GET",
data: {
latitude: latitude,
longitude: longitude
},
dataType: 'script'
});
});
} else {
document.getElementById('map-canvas').innerHTML = 'No Geolocation Support.';
}
};
myMap.addMarkers = function(coords){
var image = "http://maps.google.com/mapfiles/ms/icons/yellow-dot.png"
coords.forEach(function(coord){
var myMarker = new google.maps.Marker({
position: new google.maps.LatLng(coord.latitude, coord.longitude),
map: map,
icon: image
});
});
}
In order to make your script work in the way you want please try out the following steps:
Put your foreach loop in a function and call it at the end of your successive AJAX callbacks.
Load the AJAX once the Google Maps have finished loading completely. If Google Maps library has not finished loading than you wont be able to create a Google LatLng object, this is what is probably happening over here.
Hope this would help

How to add Markers on Google maps v3 API asynchronously?

I've been following the official documentation on how to add markers on the map so far
Nevertheless, I can see only one marker at a time max. If I try to add another one, then it doesn't work (I can't even see the first one).
My process is the following:
I initialize gmaps api:
jQuery(window).ready(function(){
//If we click on Find me Lakes
jQuery("#btnInit").click(initiate_geolocation);
});
function initiate_geolocation() {
if (navigator.geolocation)
{
var script = document.createElement("script");
script.type = "text/javascript";
script.src = "https://maps.googleapis.com/maps/api/js?key=AIzaSyBbfJJVh0jL1X9b7XFDcPuV7nHD1HlfsKs&sensor=true&callback=initialize";
document.body.appendChild(script);
navigator.geolocation.getCurrentPosition(handle_geolocation_query, handle_errors);
}
else
{
yqlgeo.get('visitor', normalize_yql_response);
}
}
Then, I display it on the appropriate div. But when it comes to make the AJAX call, in order to get my locations of the different markers I'd like to display, It just doesn't work properly. Here is the code with a simple map displayed (since that's the only thing working for me so far).
function handle_geolocation_query(position){
var mapOptions = {
zoom: 14,
center: new google.maps.LatLng(position.coords.latitude, position.coords.longitude),
mapTypeId: google.maps.MapTypeId.SATELLITE
}
alert('Lat: ' + position.coords.latitude + ' ' +
'Lon: ' + position.coords.longitude);
$('#map-canvas').slideToggle('slow', function(){
var map = new google.maps.Map(document.getElementById("map-canvas"), mapOptions);
});
$.when( getLakes(position.coords.latitude, position.coords.longitude)).done(function(results) {
// InitializeGoogleMaps(results);
if(results)
var data = results.map(function (lake) {
//Check if the lake has any open swims, if not, the button will not be clickable and an alert will pop up
if (lake.available>0)
clickable=true;
else
clickable=false;
return {
name: lake.name,
fishs: lake.fisheryType,
swims: lake.swims,
dist: lake.distance,
lat: lake.latitude,
long: lake.longitude,
id: lake.id,
avail: lake.available,
clickable: clickable,
route: Routing.generate('lake_display', { id: lake.id, lat: position.coords.latitude, lng: position.coords.longitude})
}
});
var template = Handlebars.compile( $('#template').html() );
$('#list').append( template(data) );
} );
};
So I'd like to add markers after the AJAX call. I've set up a function that I should call in the when()
function InitializeGoogleMaps(results) {
};
to display the markers in a foreach loop but nope, can't make it work. It looks like this :
CentralPark = new google.maps.LatLng(37.7699298, -122.4469157);
marker = new google.maps.Marker({
position: location,
map: map
});
Any help would be great !
Thanks
The main issue is that the map variable is declared only in the scope of the anonymous callback on slideToggle. First of all declare at the top-level function scope.
function handle_geolocation_query(position){
var map,
mapOptions = {
zoom: 14,
center: new google.maps.LatLng(position.coords.latitude, position.coords.longitude),
mapTypeId: google.maps.MapTypeId.SATELLITE
}
...
Then change the slideToggle callback to initialise the variable instead of redeclaring:
$('#map-canvas').slideToggle('slow', function(){
map = new google.maps.Map(document.getElementById("map-canvas"), mapOptions);
});
Then you should pass map as a second parameter to your InitializeGoogleMaps function and call it using InitializeGoogleMaps(results, map). See where this gets you and hit me back with any questions.

Google Maps don't fully load

I have a somewhat strange problem. I have two maps on my site, a big one and a small one. I want to use the big one to show a route to a certain address. I'm now trying to implement the two maps but get a weird problem. The small map is working fine, but on the big map only a small area of the div is filled with the map, the rest is empty. (See the image.)
I use the following code to display the two maps:
function initialize() {
var latlng = new google.maps.LatLng(51.92475, 4.38206);
var myOptions = {zoom: 10, center: latlng,mapTypeId: google.maps.MapTypeId.ROADMAP};
var map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
var marker = new google.maps.Marker({position: latlng, map:map, title:"Home"});
var image = '/Core/Images/Icons/citysquare.png';
var myLatLng = new google.maps.LatLng(51.92308, 4.47058);
var cityCentre = new google.maps.Marker({position:myLatLng, map:map, icon:image, title:"Centre"});
marker.setMap(map);
var largeLatlng = new google.maps.LatLng(51.92475, 4.38206);
var largeOptions = {zoom: 10, center: largeLatlng,mapTypeId: google.maps.MapTypeId.ROADMAP};
var largeMap = new google.maps.Map(document.getElementById("largeMap"), largeOptions);
var largeMarker = new google.maps.Marker({position: largeLatlng, map:largeMap, title:"Cherrytrees"});
largeMarker.setMap(largeMap);
}
[..]
jQuery(document).ready(function () {
[..]
initialize();
});
What's going wrong here?
EDIT:
Unfortunately the suggestions below doesn't seem to work. The closes i came is to remove the display:none from the elements and set the elements to hide with jquery
[..]
jQuery(document).ready(function () {
[..]
$("#shadow").add($("#shadowContent"),$("#closebar"),$("#content")).hide();
});
With the following result
Yes, #Argiropoulos-Stavros but, Add it as a listener
google.maps.event.addListenerOnce(map, 'idle', function(){
google.maps.event.trigger(map, 'resize');
map.setCenter(location);
});
It will begin re-sizing after, map rendered.
I think you are using v3.
So google.maps.event.trigger(map, "resize");
Also take a look at here
I fixed it!
I made an own function for the largemap and placed it in the callback when the elements are opened
function largeMap(){
var largeLatlng = new google.maps.LatLng(51.92475, 4.38206);
var largeOptions = {zoom: 10, center: largeLatlng,mapTypeId: google.maps.MapTypeId.ROADMAP};
var largeMap = new google.maps.Map(document.getElementById("largeMap"), largeOptions);
var largeMarker = new google.maps.Marker({position: largeLatlng, map:largeMap, title:"Cherrytrees"});
largeMarker.setMap(largeMap);
}
[..]
$("#showRoute").click(function(e){
e.preventDefault();
$("#shadow").add($("#shadowContent"),$("#closebar"),$("#content")).fadeIn(500);
$("#shadowContent").show().css({'width':'750px','top':'25px','left':'50%','margin-left':'-400px'});
$("#closeBarLink").click(function(l){
l.preventDefault();
$("#shadow").add($("#shadowContent"),$("#closebar"),$("#content")).fadeOut(500);
});
largeMap();
});
Thanks anyway!!
call initialize(); function after you box active.
$(document).ready(function () {
$("#shadow").show(function () {
initialize();
})
});
When you're loading in the large map, try adding this at the end of your map code.
map.checkResize();
When Google Maps first renders on your page, it has the dimensions recorded so that it displays the map images in that size. If you're resizing the map dynamically, you need to tell the API to check the new size.
<script type='text/javascript' >
var geocoder, map;
function codeAddress() {
var address= '<?php echo $this->subject()->address; ?>';
geocoder = new google.maps.Geocoder();
geocoder.geocode({
'address': address
}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
var myOptions = {
zoom: 13,
center: results[0].geometry.location,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
var marker = new google.maps.Marker({
map: map,
position: results[0].geometry.location,
icon:'http://rvillage.com/application/themes/rvillage/images/map-marker.png'
});
var infowindow = new google.maps.InfoWindow({ content: 'coming soon' });
google.maps.event.addListener(marker, 'click', function() {
infowindow.open(map, this);
});
}
});
}
jQuery(document).ready(function () {
codeAddress();
});
</script>
You are using pop up window with jQuery, and I guest you call initialize() function when document is ready ( $(document).ready(function() {initialize(); }) ).
Try call initialize() function after pop up windown showed.
Johnny

Categories

Resources