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.
Related
I have the following code and have been stuck on this issue for a very long time. I'm able to display the multiple markers but cannot get them to display the info details when clicked within a pop up info box. Right now I'm trying to get it to say "Hey!" as a test. Any suggestions is appreciated!
<script src="https://maps.googleapis.com/maps/api/js?signed_in=true&callback=initMap"
async defer>
</script>
<script type="text/javascript">
var map;
var image = 'images/marker_blast.png';
function initialize() {
// Set static latitude, longitude value
var latlng = new google.maps.LatLng(40.4313684, -79.9805005);
// Set map options
var myOptions = {
zoom: 11,
center: latlng,
panControl: true,
zoomControl: true,
scaleControl: true,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
// Create map object with options
map = new google.maps.Map(document.getElementById("map"), myOptions);
//MARK MAP
<?php
$markers = $mysqli->query("SELECT * FROM reports");
while($row_marker = $markers->fetch_assoc()) {
// uncomment the 2 lines below to get real data from the db
// $result = mysql_query("SELECT * FROM parkings");
// while ($row = mysql_fetch_array($result))
echo "addMarker(new google.maps.LatLng(".$row_marker['lat'].", ".$row_marker['lng']."), map);\n";
}
?>
}
function addMarker(latLng, map) {
var marker = new google.maps.Marker({
position: latLng,
map: map,
icon: image,
size:30,
draggable: false, // enables drag & drop
animation: google.maps.Animation.DROP
});
}
var infowindow = new google.maps.InfoWindow();
google.maps.event.addListener(marker, 'mouseover', (function(marker) {
return function() {
var content = "Hey";
infowindow.setContent(content);
infowindow.open(map, marker);
}
})(marker));
</script>
You need to attach the InfoWindow to the marker in the addMarker function where the marker exists:
function addMarker(latLng, name, map) {
var marker = new google.maps.Marker({
position: latLng,
map: map,
icon: image,
size: 30,
draggable: false, // enables drag & drop
animation: google.maps.Animation.DROP
});
google.maps.event.addListener(marker, 'mouseover', (function (marker) {
return function () {
var content = "Hey "+name;
infowindow.setContent(content);
infowindow.open(map, marker);
}
})(marker));
}
proof of concept fiddle
I don't know if echoing the function inside the while loop will make it run like you want it to. Consider a method like this.
<?php while($row_marker = $markers->fetch_assoc()) {
$result = mysql_query("SELECT * FROM parkings");
while ($row = mysql_fetch_array($result)) { ?>
addMarker(new google.maps.LatLng(<?php echo $row_marker['lat']; ?>, <?php echo $row_marker['lng']; ?>), map);
<?php } ?>
<?php } ?>
Also, I'm not sure why you're running the second while loop but it doesn't look like you're using the result $row at all.
I have put together this script (note: I'm using jQuery 1.11.2) that gets lat long coordinates from a PHP operation (used for something else) and displays a map with a customized marker and infowindow that includes HTML for formatting the information that is displayed.
<script src="https://maps.googleapis.com/maps/api/js?v=3.20&sensor=false"></script>
<script type="text/javascript">
var maplat = 41.36058;
var maplong = 2.19234;
function initialize() {
// Create a Google coordinate object for where to center the map
var latlng = new google.maps.LatLng( maplat, maplong ); // Coordinates
var mapOptions = {
center: latlng,
zoom: 3,
mapTypeId: google.maps.MapTypeId.ROADMAP,
scrollwheel: false,
streetViewControl: false,
zoomControl: false,
mapTypeControl: false,
disableDoubleClickZoom: true
};
map = new google.maps.Map(document.getElementById("map-canvas"),mapOptions);
// CREATE AN INFOWINDOW FOR THE MARKER
var content = 'This will show up inside the infowindow and it is here where I would like to show the converted lat/long coordinates into the actual, human-readable City/State/Country'
; // HTML text to display in the InfoWindow
var infowindow = new google.maps.InfoWindow({
content: content,maxWidth: 250
});
var marker = new google.maps.Marker( {
position: latlng,
map: map,
title: "A SHORT BUT BORING TITLE",
});
google.maps.event.addListener(marker, 'click', function() {
infowindow.open(map,marker);
});
infowindow.open(map,marker);
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
What I'm trying to achieve is to do a reverse geocode on the coordinates stored in the latlng variable and get back the results of that in a "City, State, Country" format and insert that into the HTML for the informarker stored in the "content" variable.
Have tried multiple approaches without success. Please note that I've deliberately left out the reverse geocoding script I tried to use for clarity purposes.
Edit: I've adjusted the script presented here to comply with the rules about it being clear, readable and that it actually should work. I also include a link to a CodePen so that you can see it in action: Script on CodePen
Regarding including the script for reverse geocoding, what I did was a disaster, only breaking the page and producing "undefined value" errors. I'd like to learn the correct way of doing this by example, and that's where the wonderful StackOverflow community comes in. Thanks again for your interest in helping me out.
Use a node instead of a string as content , then you may place the geocoding-result inside the content, no matter if the infoWindow is already visible or not or when the result is available(it doesn't even matter if the InfoWindow has already been initialized, a node is always "live").
Simple Demo:
function initialize() {
var geocoder = new google.maps.Geocoder(),
latlng = new google.maps.LatLng(52.5498783, 13.42520);
map = new google.maps.Map(document.getElementById('map-canvas'), {
zoom: 18,
center: latlng
}),
marker = new google.maps.Marker({
map: map,
position: latlng
}),
content = document.createElement('div'),
infoWin = new google.maps.InfoWindow({
content: content
});
content.innerHTML = '<address>the address should appear here</address>';
google.maps.event.addListener(marker, 'click', function() {
infoWin.open(map, this);
});
geocoder.geocode({
location: latlng
}, function(r, s) {
if (s === google.maps.GeocoderStatus.OK) {
content.getElementsByTagName('address')[0].textContent = r[0].formatted_address;
} else {
window.alert('Geocoder failed due to: ' + status);
}
});
}
google.maps.event.addDomListener(window, 'load', initialize);
html,
body,
#map-canvas {
height: 100%;
margin: 0px;
padding: 0px
}
<script src="https://maps.googleapis.com/maps/api/js?v=3"></script>
<div id="map-canvas"></div>
Here's how I would do it:
function reverseGeocoder(lat, lng, callback) {
var geocoder = new google.maps.Geocoder();
var point = new google.maps.LatLng(parseFloat(lat), parseFloat(lng));
geocoder.geocode({"latLng" : point }, function(data, status) {
if (status == google.maps.GeocoderStatus.OK && data[0]) {
callback(null, data[0].formatted_address);
} else {
console.log("Error: " + status);
callback(status, null);
}
});
};
And basically you would call the function like:
reverseGeocoder(lat, lng, function(err, result){
// Do whatever has to be done with result!
// EDIT: For example you can pass the result to your initialize() function like so:
initialize(result); // And then inside your initialize function process the result!
});
I currently enabled user to put the address into text-boxes and display the address on Google map, but I want to do the opposite now and get nearest matching address to the text-boxes (which are on a separate region, same page) from a draggable marker. I heard that I should use JSON with PHP or PL/JSON to get the data from the map to the text-boxes. However, I do not have any knowledge about JSON and I think Google map API provide this sort of geocoding methods inside the JavaScript. I am not sure how to fully apply it, and if it is possible to get both methods in one page (or maybe I should use some procedure with JavaScript and call it on the page, not sure). Here is my code so far in the HTML Header of the page:
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?v=3.exp&sensor=false"></script>
<script type="text/javascript">
var uniLatLng = new google.maps.LatLng (51.887496, -2.088788);
var geocoder = new google.maps.Geocoder();
var map;
function geocodePosition(pos) {
geocoder.geocode({
latLng: pos
},
function(responses) {
if (responses && responses.length > 0) {
updateMarkerAddress(responses[0].formatted_address);
}
else {
updateMarkerAddress('Cannot determine address at this location.');
}
});
}
function updateMarkerStatus(str) {
document.getElementById('P15_ADDRESS').value;
}
function initialize() {
geocoder = new google.maps.Geocoder();
var mapOptions = {
zoom: 16,
center: uniLatLng,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
};
var marker = new google.maps.Marker({
map: map,
animation: google.maps.Animation.DROP,
flat: false,
position: new google.maps.LatLng(59.327383, 18.06747)
})
function map_canvas() {
var address = "&P15_ADDRESS.";
geocoder.geocode( { 'address': address, 'region': "GB"}, function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
map.setCenter(results[0].geometry.location);
var marker = new google.maps.Marker({
map: map,
draggable: true,
animation: google.maps.Animation.DROP,
flat: false,
position: results[0].geometry.location
});
}
else {
alert("Geocode was not successful for the following reason: " + status);
}
});
}
</script>
Page HTML Body Attribute - onload="initialize(), map_canvas()"
Any suggestions how can I achieve this?
I think this example does what you want on the Reverse Geocoding part. https://developers.google.com/maps/documentation/javascript/examples/geocoding-reverse
the only thing you need to add to this is a draggable marker with a listener for on dragged, which would update the position and call the same methods as it is in the Reverse Geocode button.
i am trying to implement google map in chrome, however the geolocation doesn't seems to be working i also changed the setting to 'allow all site to track'
i have taken these code from a tutorial online, and hence i couldn't find a way to make it work
<head>
<title>Map</title>
<!-- Google Maps and Places API -->
<script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?libraries=places&sensor=false"></script>
<!-- jQuery -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript">
function initGeolocation(){
if( navigator.geolocation ){
// Call getCurrentPosition with success and failure callbacks
navigator.geolocation.getCurrentPosition( success, fail );
}else{
alert("Sorry, your browser does not support geolocation services.");
}
}
var map;
function success(position){
// Define the coordinates as a Google Maps LatLng Object
var coords = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
// Prepare the map options
var mapOptions = {
zoom: 14,
center: coords,
mapTypeControl: false,
navigationControlOptions: {style: google.maps.NavigationControlStyle.SMALL},
mapTypeId: google.maps.MapTypeId.ROADMAP
};
// Create the map, and place it in the map_canvas div
map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
//search for schools within 1500 metres of our current location, and as a marker use school.png
//placesRequest('Schools',coords,1500,['school']);
// Place the initial marker
var marker = new google.maps.Marker({
position: coords,
map: map,
title: "Your current location!"
});
}
function fail(){
// Could not obtain location
}
//Request places from Google
function placesRequest(title,latlng,radius,types,icon){
//Parameters for our places request
var request = {
location: latlng,
radius: radius,
types: types
};
//Make the service call to google
var callPlaces = new google.maps.places.PlacesService(map);
callPlaces.search(request, function(results,status){
//trace what Google gives us back
$.each(results, function(i,place){
var placeLoc = place.geometry.location;
var thisplace = new google.maps.Marker({
map: map,
position: place.geometry.location,
icon: icon,
title: place.name
});
})
});
}
</script>
initGeolocation() is not fired anywhere.
The div with id map_canvas is missing and you don't call initGeolocation function anywhere in your code .
Check here , everything works ok
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);