воскресенье, 9 сентября 2012 г.

Yandex Map: Открытие балуна метки, объединенной в кластер

Все, кто работает с Yandex картами, знают что открыть балун (ballon) на точке карты (Placemark) с внешней ссылки простое дело.
Но это не так просто сделать для точек, объединенных в кластер (Cluster). Причина этого в том, что точки физически не существует на карте, в целях оптимизации на карте есть только кластер.

Существует несколько способов обхода этого ограничения:
1. Во время клика, вынести точку из кластера, создать на карте, открыть, после этого вернуть в кластер.
2. Подменять каждый раз балун кластера, при попытке открытия метки.
3. Позиционироваться на кластере, увеличивать карту до максимума, чтобы кластер разложился на точки, после этого открывать балун стандартными средствами.

Я расскажу, как реализовать 3ий вариант, как самый простой.

Этот вариант включается в себя пункты:
1. Запоминаем список точек в массив.
2. Позиционируем карту на точке, где будем открывать балун (для этого используем координаты из массива точек)
* Задаем самый близкий масштаб
* При центрировании устанавливаем параметр checkZoomRange = true. Это необходимо на случай, если для данного участка нет подробной карты, то масштаб отредактируется автоматически.
3. По окончанию центрирования вызывается колбэк.
4. Но это еще не конец, т.к. после центрирования карта еще не отрисована.
5. Для отлова окончания загрузки карты используем событие mapchange. mapchange - вызывается 2 раза:
* при начале отрисовки точек
* после окончания загрузки точек. В этом случае event.get('newMap') отлично от null
6. Делаем задержку в 300мс, чтобы дать отрисоваться метке точки (не нашел соответствующего события, так что решено костылем)
7. Открываем балун.

Код:
//клик на ссылку
$(".onmap").click(function() {
  //переходим к карте
  window.scrollTo(0,300);
  //узнаем ID массива точек из ссылки
  var id = parseInt($(this).attr("rel"));

  //позиционируемся на точке, задаем максимальный масштаб = 15
  myMap.setCenter(placemark[id].geometry.getBounds()[0], 15, {
    checkZoomRange: true, //контролируем доступность масштаба
    callback: function() { //спозиционировались
      placemark[id].events.add('mapchange', function(e){ 
       //точка появилась
       if( e.get('newMap') != null) {
        //точка загрузилась
        setTimeout(function() {
           //задержка
           placemark[id].balloon.open();//открытие балуна
        }, 300);        
      } });
    }
  });

  return false;
});


Пример работы с картой.