Google Maps API: Mutiple Marker/Closures - javascript

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.

Related

Displaying google map with markers using data from mysql (laravel)

I'm working on a web app that includes google map and a bunch of markers.
This morning I had working map+markers from db (but I used only one table with data).
ss this morning:
Now I'm trying to put marker custom icons and info windows to get something like this (this was made without laravel, only php).
This is my code:
#extends('layouts.app')
#section('content')
<script src="http://maps.google.com/maps/api/js?sensor=false"
type="text/javascript"></script>
<script type="text/javascript">
//<![CDATA[
function load() {
var map = new google.maps.Map(document.getElementById('map'), {
center: {lat: 45.327168, lng: 14.442902},
zoom: 13
});
var infoWindow = new google.maps.InfoWindow;
#foreach($markers as $marker)
var sadrzaj = {{$marker->nazivMarkera}};
var adresa = {{$marker->adresa}};
var grad = {{$marker->nazivGrada}};
var postanskibroj = {{$marker->postanski_broj}};
var zupanija = {{$marker->nazivZupanije}};
var html = "<b>" + sadrzaj + "</b> <br/>" + adresa +",<br/>"+postanskibroj+" "+grad+",<br/>"+zupanija;
var lat = {{$marker->lat}};
var lng = {{$marker->lng}};
var image = {{$marker->slika}};
var markerLatlng = new google.maps.LatLng(parseFloat(lat),parseFloat(lng));
var mark = new google.maps.Marker({
map: map,
position: markerLatlng,
icon: image
});
bindInfoWindow(mark, map, infoWindow, html);
#endforeach
}
function bindInfoWindow(mark, map, infoWindow, html){
google.maps.event.addListener(marker, 'click', function(){
infoWindow.setContent(html);
infowWindow.open(map, mark);
});
}
function doNothing(){}
//]]>
</script>
<div class="container">
<div class="row">
<div class="col-md-10 col-md-offset-1">
<div class="panel panel-default">
<div class="panel-heading">Dobro došli!</div>
<div class="panel-body">
<!-- Moj kod -->
<div id="map"></div>
<!-- DO TU -->
</div>
</div>
</div>
</div>
</div>
#endsection
When I inspect the page I can see that my array with data is filled and I have all the data from db.
Can someone help me and explain to me where is the problem? Why when I remove functions for markers, and set only map init, I get map view with no problem, and now I don't even get the map.
Now:
It looks like load() is not getting called anywhere.
Also I noticed in your screen shots, the variables which have been echoed in by laravel don't have quotes around them.
I would leave laravel(blade) out of the javascript. Currently, your foreach loop will dump heaps of javascript code which will be overriding and re-declaring variables. This is generally messy, and considered bad practice.
I would also make map a global variable, incase you want to manipulate it later.
Try this:
var map;
var markers = {!! json_encode($markers) !!}; //this should dump a javascript array object which does not need any extra interperting.
var marks = []; //just incase you want to be able to manipulate this later
function load() {
map = new google.maps.Map(document.getElementById('map'), {
center: {lat: 45.327168, lng: 14.442902},
zoom: 13
});
for(var i = 0; i < markers.length; i++){
marks[i] = addMarker(markers[i]);
}
}
function addMarker(marker){
var sadrzaj = marker.nazivMarkera};
var adresa = marker.adresa;
var grad = marker.nazivGrada;
var postanskibroj = marker.postanski_broj;
var zupanija = marker.nazivZupanije;
var html = "<b>" + sadrzaj + "</b> <br/>" + adresa +",<br/>"+postanskibroj+" "+grad+",<br/>"+zupanija;
var markerLatlng = new google.maps.LatLng(parseFloat(marker.lat),parseFloat(marker.lng));
var mark = new google.maps.Marker({
map: map,
position: markerLatlng,
icon: marker.slika
});
var infoWindow = new google.maps.InfoWindow;
google.maps.event.addListener(mark, 'click', function(){
infoWindow.setContent(html);
infoWindow.open(map, mark);
});
return mark;
}
function doNothing(){} //very appropriately named function. whats it for?
I also fixed up several small errors in the code, such as
info window was spelt wrong inside your bind function "infowWindow"
your infoWindow listener need to bind to mark not marker
you don't really need to individually extract out each variable from marker
Also, you need to call the load() function from somewhere. Maybe put onLoad="load()" on your body object or top level div. Or use the google DOM listener:
google.maps.event.addDomListener(window, 'load', load);
This will execute your load() function when the window is ready.
You have lo leave
var map = new google.maps.Map(document.getElementById('map'), {
center: {lat: 45.327168, lng: 14.442902},
zoom: 13
});
out of the commented area, otherwise you're not initializing it.

Doing a Google Maps reverse geocode and displaying the result as part as HTML content inside an infowindow

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!
});

Google map markers are not displaying with ajax json data

I am getting latitude & longitude from database table and trying to display markers on ajax success. I am getting latitude & longitude on json format but when tried with loop, markers are not displaying.
My JSON Data:
[
{"latitude":"23.046100780353495","longitude":"72.56860542227514"},
{"latitude":"23.088427701737665","longitude":"72.49273109366186"},
{"latitude":"23.061264193197644","longitude":"72.68224525381811"},
{"latitude":"22.977212139977677","longitude":"72.52191352774389"},
{"latitude":"23.002180435752084","longitude":"72.47590827872045"},
{"latitude":"23.108638843843046","longitude":"72.49444770743139"}
]
Google map with Ajax Code:
<script type="text/javascript">
// Check DOM Ready
$(document).ready(function() {
// Execute
(function() {
// Map options
var options = {
zoom: 6,
center: new google.maps.LatLng(23.039567700000000000, 72.566004499999960000), // Centered
mapTypeId: google.maps.MapTypeId.TERRAIN,
mapTypeControl: false
};
// Init map
var map = new google.maps.Map(document.getElementById('map_canvas'), options);
$.ajax({
url: 'get-locations.php',
success:function(data){
var obj = JSON.parse(data);
var totalLocations = obj.length;
for (var i = 0; i < totalLocations; i++) {
// Init markers
var marker = new google.maps.Marker({
position: new google.maps.LatLng(obj[i].latitude + ',' + obj[i].longitude),
map: map,
title: 'Click Me ' + i
});
// Process multiple info windows
(function(marker, i) {
// add click event
google.maps.event.addListener(marker, 'click', function() {
infowindow = new google.maps.InfoWindow({
content: 'Hello, World!!'
});
infowindow.open(map, marker);
});
})(marker, i);
}
}
});
})();
});
</script>
When I tried to pass static latitude & longitude inside the loop marker is displayed:
position: new google.maps.LatLng(23.046100780353495,72.56860542227514),
but not working with dynamic with loop.
Any idea why markers are not displaying?
Thanks.
You're passing the coordinates incorrectly to the google.maps.LatLng constructor. There should be two parameters separated by a comma but you're concatenating them as a string.
The code should look like this:
position: new google.maps.LatLng(obj[i].latitude, obj[i].longitude)

passing variable from apex report to javascript function

I was looking over S.O. and found two questions that combined would solve a problem I am having.
I would like to post pct markers onto google map from Apex report.
passing variable from report works.. javascript:LOCATION(#LOCATION#);
but I can't seem to get the javascript to run.
thanks
<script type="text/javascript">
function LOCATION(pLoc){
var Loc = (pLoc);
var locations = ['+Loc+'];
var map = new google.maps.Map(document.getElementById('map'), {
zoom: 10,
center: new google.maps.LatLng(-33.92, 151.25),
mapTypeId: google.maps.MapTypeId.ROADMAP
});
var infowindow = new google.maps.InfoWindow();
var marker, i;
for (i = 0; i < locations.length; i++) {
marker = new google.maps.Marker({
position: new google.maps.LatLng(locations[i][1], locations[i][2]),
map: map
});
google.maps.event.addListener(marker, 'click', (function(marker, i) {
return function() {
infowindow.setContent(locations[i][0]);
infowindow.open(map, marker);
}}
})(marker, i));
}
}
</script>
thanks for your time.
Your Query:
SELECT stragg(a.location) as location, a.region
FROM
(SELECT DISTINCT rownum
, '['||''''||'test'||''''|| c.lon ||','|| c.lat ||', '||rownum|| ']' as location
, a.pct_name
, b.election_code_id
, c.region
FROM ecms.prv_pcts a
, ecms.sites_assign b
, ecms.sites_details c
WHERE b.site_id = c.site_id
AND b.pct_id = a.prv_pct_id
AND a.pct_name NOT LIKE 'ALL PR%'
AND b.election_code_id IS NOT NULL
AND b.election_code_id = '117'
ORDER by 1, 2
) a
GROUP BY a.region
Would give an output of:
['testLON',LAT,1],['testLON2',LAT2,2]
Calling function LOCATION with these values would provide the function with multiple parameters.
Thus, locations[][] wouldn't exactly work as pLoc is not an array holding arrays. You could fix this by using
SELECT '['||stragg(a.location)||']' as location, a.region
Also,
var locations = ['+Loc+']; kind of defeats the purpose, no?
DISTINCT ROWNUM?

Google Maps API (v3) adding/updating markers

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);

Categories

Resources