Отображение инфо-имени маркера Google Maps при наведении курсора на динамически создаваемый DIV - PullRequest
2 голосов
/ 01 октября 2011

Я хочу представить функцию , которая позволяет инфо-имени маркера появляться или исчезать при наведении курсора мыши или наведении мыши на соответствующий элемент DIV , созданный из jQuery. Однако в строке 19 из main.js я получаю сообщение об ошибке " a undefined ". После тщательного тестирования моего сценария я понимаю, что это как-то связано с маркером во вновь добавленных строках, как указано ниже:

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

Ошибка исчезнет, ​​если я объединю функцию addInfoName в process. Однако все DIV будут указывать на последний маркер, если я это сделаю. У меня вопрос, как мне изменить мой скрипт для достижения функциональности, упомянутой выше ?

Ответы [ 2 ]

1 голос
/ 02 октября 2011

В настоящее время у вас есть переменная marker, объявленная локальной для функции process, но вы пытаетесь читать и записывать ее из других функций. В частности, addMarker записывает в marker без var, что приводит к созданию случайной глобальной переменной. Между тем process на самом деле не записывает в объявленный локальный marker локальный код, поэтому он содержит undefined, что приведет к срабатыванию кода Google Maps при его передаче.

(Такие инструменты, как jslint или ECMAScript 5 Strict Mode могут поймать случайные глобалы для вас. Примечание total и i также являются случайными глобалами.)

Похоже, addMarker и addInfoname были взломаны из тела process без привязки переменных из process, которые они оба использовали. Если бы они были включены в тело process, это работало бы, но вы бы получили описанное поведение, в котором одно и то же значение marker использовалось для каждого деления из-за проблемы замкнутого цикла.

Эта проблема возникает в языках с замыканиями и областью действия на уровне функций, включая JavaScript, Python и другие. В этих языках любые переменные, определенные в цикле for или внутри него, являются локальными для содержащей функции, not перераспределяется каждый раз, когда вы обходите цикл. Поэтому, если вы делаете замыкание, ссылаясь на i в первой итерации цикла, это та же самая переменная i, на которую вы ссылаетесь во второй итерации цикла; каждый экземпляр функции имеет замыкание над одной и той же переменной i, поэтому каждая функция будет видеть одно и то же значение. То же самое относится и к marker.

Проблему с замкнутым циклом можно избежать, используя второе замыкание, которое сохраняет переменную цикла в аргументе, или, более чисто, используя механизм цикла на основе замыкания вместо C-подобного цикла for. ECMAScript 5 предлагает array.forEach() для этой цели, а jQuery предлагает $.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)
        )
    });
}
1 голос
/ 01 октября 2011

Ошибка "a is undefined", вероятно, связана с тем, что вы пытаетесь создать карту до того, как dom будет готов. По крайней мере, это единственный раз, когда я видел это. Я не могу сказать из вашего кода, где вы его создаете, но убедитесь, что карта div готова. Вы должны либо разместить вызов функции инициализации внизу страницы, либо в прослушивателе загрузки страницы. Вот один из способов, которым вы можете сделать это (это может быть где угодно на странице):

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

Также обратите внимание, что ваш бездействующий слушатель также выполняет эту функцию инициализации, поскольку он не сможет работать, пока карта не будет создана.

Если это не вызывает ошибку "a is undefined", я не вижу ее в опубликованном вами коде. Я, однако, вижу некоторые другие проблемы с вашим кодом. Так что, возможно, именно это и является причиной этого. Во-первых, определение var marker; в process ничего не делает. Здесь вы создаете локальную переменную, но эта локальная переменная никогда не определяется. Затем addMarker вы создаете глобальную переменную, определяя marker без var. Таким образом, маркер в addInfoname всегда ссылается на глобальный маркер, который всегда будет последним определенным маркером. Вот почему элементы div всегда отображаются с последним маркером. Я бы поставил возврат перед marker = ... в addMarker и использовал его для установки переменной маркера следующим образом:

var marker = addMarker(detail);

В process, конечно. Затем вы также должны отправить это в addInfoname в качестве параметра, чтобы он получил правильный.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...