问题
I want to introduce a functionality which allows a marker's infoname to appear or disappear upon mouseover or mouseout of a corresponding DIV element generated from jQuery. However, I am getting a "a is undefined" error on line 19 of main.js. After extensive testing on my script, I realise that this has something to do with the marker in the newly added lines as commented below:
function addMarker(A) {
var point = new google.maps.LatLng(A.lat, A.lng);
var image = new google.maps.MarkerImage('images/r.png',
new google.maps.Size(30, 30),
new google.maps.Point(0, 0),
new google.maps.Point(0, 30));
marker = new google.maps.Marker({
map: map,
position: point,
icon: image,
});
}
function addInfoName(A) {
var infoname = new infoName; // custom object
google.maps.event.addListener(marker, 'mouseover', function(event) {infoname.show();});
google.maps.event.addListener(marker, 'mouseout', function(event) {infoname.hide();});
infoname.open(map, marker);
}
function showResult(A) {
$('#results').append('<DIV id=' + A.pid + '>{Blah Blah Blah}</DIV>');
return document.getElementById(A.pid);
}
function process(json) {
$('#results').empty();
total = json.details.length;
for(i=0; i<total; i++) {
var detail = json.details[i];
var marker;
addMarker(detail);
addInfoName(detail);
// these new lines are added
var listDisplay = showResult(detail);
listDisplay.onmouseover = function(){google.maps.event.trigger(marker, 'mouseover');};
listDisplay.onmouseout = function(){google.maps.event.trigger(marker, 'mouseout');};
}
}
google.maps.event.addListener(map, 'idle', function () {$.getJSON(query, process);});
The error disappears if I merge the function addInfoName into process. However, all the DIVs will point to the last marker if I do so. My question is, how do I modify my script to achieve the functionality mentioned above?
回答1:
Currently you've got a variable marker declared local to the process function, but you're trying to read and write to it from other functions. In particular, addMarker writes to marker without var, which causes an accidental global variable to be created. Meanwhile process is not actually writing to the marker local it has declared, so it contains undefined, which will trip the Google Maps code up when you pass that in.
(Tools like jslint, or ECMAScript 5 Strict Mode can catch accidental globals for you. Note total and i are also accidental globals.)
It looks like addMarker and addInfoname have been hacked out of the body of process without tying up the variables from process that both of them used. If they were included in the body of process it would work, but you'd get the described behaviour where the same marker value was used for every div because of the Closure Loop Problem.
This problem occurs in languages with closures and function-level scope, which includes JavaScript, Python and others. In these languages any variables defined by or inside a for loop are local to the containing function, not reallocated every time you go around the loop. So if you make a closure referring to i in the first iteration of the loop, it's the same variable i as you refer to in the second iteration of the loop; every instance of the function has a closure over the same variable i so every function will see the same value. The same would be true of marker.
The Closure Loop Problem can be avoided through use of a second closure that keeps the loop variable in an argument, or, more cleanly, using a closure-based loop mechanism instead of the C-like for loop. ECMAScript 5 offers array.forEach() for this purpose and jQuery offers $.each():
function process(json) {
$('#results').empty();
var gev= google.maps.event;
$.each(json.details, function(detaili, detail) {
var marker= addMarker(detail.lat, detail.lng);
$('#results').append($('<div>', {
text: detail.name,
mouseover: function() { gev.trigger(marker, 'mouseover'); },
mouseout: function() { gev.trigger(marker, 'mouseout'); }
}));
var infoname= new InfoName();
gev.addListener(marker, 'mouseover', function() { infoname.show(); });
gev.addListener(marker, 'mouseout', function() { infoname.hide(); });
infoname.open(map, marker);
});
}
function addMarker(lat, lng) {
return new google.maps.Marker({
map: map,
position: new google.maps.LatLng(lat, lng),
icon: new google.maps.MarkerImage(
'images/r.png',
new google.maps.Size(30, 30),
new google.maps.Point(0, 0),
new google.maps.Point(0, 30)
)
});
}
回答2:
The "a is undefined" error is probably because you are trying to create the map before the dom is ready. At least, that's the only time I have seen it. I can't tell from your code where you're creating it, but make sure that the map div is ready. You either have to place the call to your initialize function at the bottom of the page or in an page load listener. Here's one way you can do that (this can go anywhere in the page):
function initialize() {
var map = new google.maps.Map(document.getElementById("map_canvas"), {
zoom: 6,
mapTypeId: google.maps.MapTypeId.ROADMAP
});
google.maps.event.addListener(map, 'idle', function () {
$.getJSON(query, process);
});
}
google.maps.event.addDomListener(window, 'load', initialize);
Also notice that your idle listener goes in that init function, too, since it won't be able to run until the map has been created.
If that's not causing the "a is undefined" error, then I can't see it in the code you've posted. I do, however, see some other problems with your code. So maybe that is actually what's causing it. First, the var marker; definition in process doesn't do anything. Here you are creating a local variable, but that local variable never gets defined. Then addMarker you are creating a global variable by defining marker without the var. So the marker in addInfoname always refers to the global marker, which will always be the last marker defined. So that's why the divs are always showing up with the last marker. I would put a return before marker = ... in addMarker, and use it to set the marker variable like this:
var marker = addMarker(detail);
In process, of course. Then you also have to send this to addInfoname as a parameter so it gets the correct one.
来源:https://stackoverflow.com/questions/7621016/showing-google-maps-marker-infoname-on-mouseover-of-a-dynamically-generated-div