I've read similar posts, but still didn't find a solution for myself. Basically I have an array with countries+towns in PHP and I need to show them on the map with markers. Here is my code:
function showAddress(markers) {
var address = "<?php echo $Fcity[$j], " , ", $Fcountry[$j]?>";
if (geocoder) {
geocoder.getLatLng(address, function(point) {
if (!point) {
alert(address + " not found");
} else {
var marker = new GMarker(point);
map.addOverlay(marker);
markers[i] = marker;
marker.openInfoWindowHtml(address);
}
}
);
}
}
Everything seems to work if I geocode one location, but I can't put it into a loop to process all of them.
for (var i = 0; i < markers.length; i++) {
showAddress(markers[i]);
}
In your showAddress function, you reference markers[i].
However, you don't pass in i... that variable is not in the scope of the function. So, you aren't iterating and adding, you are adding variables over and over to a non-existent place in the array.
You either need to pass in i or not encapsulate showAddress in a function.
How about making the function showAddresses and putting the loop in the function.
Related
I am trying to write a method that creates Leaflet markers with a function updateRoute which should be called whenever the marker is moved.
My problem is that I can't find the index of the marker that was moved as the wayPointIteration variable is evaluated as the total number of markers. I understand why it doesn't work like that now but I don't know how the method can be executed with knowledge of the iteration of that marker.
function updateWayPointsOnMap() {
let options = {draggable: true};
let wayPointIteration = 1;
getRouteWayPoints().forEach(wayPoint => {
let newMarker = L.marker([wayPoint.lat, wayPoint.lng], options).bindTooltip("Way point " + wayPointIteration).addTo(map)
.on('move', function updateRoute(move) {
getRouteWayPoints()[wayPointIteration - 1] = move.latlng;
updateMap();
});
routeMarkers.push(newMarker);
wayPointIteration ++;
});
}
I want to implement a functionality on Gmap API, that if the zoom is more than 17, show all the markers(otherwise, just hide them). However, when I write code like the following, it just does not work.
PS: the code might not be exactly correct in syntax and arrangement, but it express what I mean
// #latlong is an array of tuple (latitude , longtitude)
// #myMap is the google map object passed to the function
function placeMarker( myMap , latlon)
{
for(var i = 0 ; i < latlon.length ; i ++)
{
myMarker = new google.maps.Marker( {
position: new google.maps.LatLng(latlon[i][0], latlon[i][1])
});
google.maps.event.addListener(myMap, 'zoom_changed', function() {
zoomLevel = myMap.getZoom()
if(zoomLevel >= 17)
{
myMarker.setMap(myMap)
}
else
{
myMarker.setMap(null)
}
});
}
}
And I just change my code to:
function placeMarker( myMap , latlon)
{
for(var i = 0 ; i < latlon.length ; i ++)
{
myMarker = new google.maps.Marker( {
position: new google.maps.LatLng(latlon[i][0], latlon[i][1])
});
(function(myMarker_copy){
google.maps.event.addListener(myMap, 'zoom_changed', function() {
zoomLevel = myMap.getZoom()
if(zoomLevel >= 17)
{
myMarker_copy.setMap(myMap)
}
else
{
myMarker_copy.setMap(null)
}
});
}(myMarker));
}
}
And the second version works.
I know how to make it work, however, I really do not know why it work and why the other does not. Maybe this has something to do with the function closure or parameter passing principle of JS(I have checked a lot references, but some of them just hold different ideas). Could anybody give me a help?
really appreciate it.
The first example which doesn't work: There is one global variable myMarker and many event listeners which at the end all operate on one marker and that is the one created the last in the loop.
The second example which does work: because of closure each event listener receive its own local copy of marker variable. So, when event listener is called it has correct marker value.
I'm stuck with my loop. Everything functions, except markerLayer.markers()[i].showTooltip();
Somehow it shows the wrong marker. Am I passing the wrong arguments? Am I missing the logic here?
for (var i = 0; i < features.length; i++) {
var a = side.appendChild(document.createElement('a'));
a.onclick = (function (feature, i) {
return function () {
markerLayer.interaction.hideTooltips()
map.ease.location({
lat: feature.geometry.coordinates[1],
lon: feature.geometry.coordinates[0]
}).zoom(zoomPlaces).optimal(null, null, function (feature) {
markerLayer.markers()[i].showTooltip();
})
}
})
(features[i], i);
}
The latest version of MapBox and Leaflet's JavaScript APIs use map.markerLayer.getLayers() to return array of layer objects that contains a unique _leaflet_id. Please use that id number to help specify the marker you'd like to togglePopup.
I've been playing around with JavaScript and there's something I don't quite understand. I have this piece of code here:
$.getJSON('data.json', function(obj) {
for( var p in obj.List )
{
datas['id'] = obj.List[p].ListingId;
datas['area'] = area;
//console.log(datas);
var geocoder = new google.maps.Geocoder();
geocoder.geocode( { 'address': datas['area'] }, function(results,status)
{
if(status == google.maps.GeocoderStatus.OK)
{
var latlng = new google.maps.LatLng(results[0].geometry.location.Ya, results[0].geometry.location.Za);
datas['latlng'] = latlng;
//console.log(datas);
}
});
}
});
Ok, now suppose the for loop runs 3 times. If we uncomment the first "console.log(datas)" line and run the page, in the console we see 3 "datas" objects with their own "id" and "area". If I comment that first "console.log(datas)" and uncomment the second "console.log(datas)" in the geocode callback, when I run the code, all 3 "datas" objects are exactly the same in terms of "id", "area", and "latlng". Whereas I expected the 3 "datas" objects would be different with their own latlngs.
Any ideas?
When is the function you pass to the geocoder.geocode function run? If it's not being run immediately then the for loop will run through all three times before the geocode function is run. That means that datas['id'] and datas['area'] will have been set to the last iteration of the loop... in which case you need to capture the datas array inside a closure for the geocode function.
In which case you'd need something like:
$.getJSON('data.json', function(obj) {
for( var p in obj.List )
{
datas['id'] = obj.List[p].ListingId;
datas['area'] = area;
//console.log(datas);
var geocoder = new google.maps.Geocoder();
geocoder.geocode( { 'address': datas['area'] }, function(datas){ return function(results,status)
{
if(status == google.maps.GeocoderStatus.OK)
{
var latlng = new google.maps.LatLng(results[0].geometry.location.Ya, results[0].geometry.location.Za);
datas['latlng'] = latlng;
//console.log(datas);
}
}}(datas));
}
});
This prevents the datas variable as used by the anonymous function being updated by the for loop.
I think this is a scope problem. By the time that last console.log runs the p variable will already refer to the last obj. You need to capture p in a new scope.
for( var p in obj.List ) {
(function(p) {
datas['id'] = obj.List[p].ListingId;
datas['area'] = area;
geocoder.geocode( { 'address': datas['area'] }, function(results,status) {
...
});
}(p));
}
I think datas has to be declared as a global array? Has it?
I have the following code, and having read this, i understand it wont work because the getJSON call is asynchronous. How do i need to change this so that the MarkerClusterer function gets triggered with a full set of markers? I've tried putting the MarkerClusterer function inside the getJSON call but with no luck...
var mcOptions = {gridSize: 50, maxZoom: 9};
var markers = [];
function parse_json(json) {
if (json.length > 0) {
for (i=0; i<json.length; i++) {
var report = json[i];
var latLng = new google.maps.LatLng(report.latitude, report.longitude);
markers[i] = new google.maps.Marker({
position: latLng,
title: report.name + ' ' + report.surf_size_ft_round,
url: "/place/"+report.slug
});
google.maps.event.addListener(markers[i], 'click', function() {
window.location.href = markers[i].url;
});
markers.push(markers[i]);
}
}
};
$.getJSON('<%= request.fullpath + ".json" %>', function(stream) {
if (stream.length > 0) {
parse_json(stream);
alert(markers[1].title); //sanity check - gives result
}
});
alert(markers[5].title); // sanity check - empty
var mc = new MarkerClusterer(map, markers, mcOptions);
Why not put this code snippet:
mc = new MarkerClusterer(map, markers, mcOptions);
inside the anonymous callback function in your $.getJSON? Just declare var mc; somewhere outside the $.getJSON scope to be able to have access to it elsewhere.
Alternatively, you can fire an event at the end of your parse_json function, listen to that event and then fire up another function that creates your MarkerClusterer object when the event has fired. Check this out: How to trigger event in JavaScript?
EDIT:
Upon inspecting your code a bit more, I can see that you set markers[i] to a new Marker instance and then push onto the markers array that same instance. You probably want to either set markers[i] to a new Marker instance or you want to create a var marker, setting it to a new Marker instance and then pushing on the markers array.
Maybe you need to put it inside the success function you give as an input to $.getJSON?
$.getJSON('<%= request.fullpath + ".json" %>', function(stream) {
if (stream.length > 0) {
parse_json(stream);
alert(markers[1].title); //sanity check - gives result
mc = new MarkerClusterer(map, markers, mcOptions);
}
});
alert(markers[5].title); // sanity check - empty