Клуб API Карт

ObjectManager cluster balloon - кастомный контент балуна

Пост в архиве.

Не могу найти в документации , каким образом я могу:

1. сделать layout балуна кластера - только свой контент без разметки на колонки.

2. вставить свой контент в этот балун.

3. где найти весь список layout

 

Я не использую clusterer, на который много примеров, у меня работа идет через ObjectManager с кластеризацией на клиенте.

 

 

            objectManager = new ymaps.ObjectManager({

                 clusterize: true,

                clusterHasBalloon: true,

                clusterOpenBalloonOnClick: false,

                clusterDisableClickZoom: true,

                hasBalloon:false,

                geoObjectOpenBalloonOnClick: true

            });

            objectManager.add([JSON_COLLECTION]);
            map.geoObjects.add(objectManager);

            objectManager.clusters.events.add('click', function (e) {

                    var cluster = objectManager.clusters.getById(e.get('objectId'));

 

                    jQuery.get(href, function(data) {

                        // пробовал так

                        objectManager.clusters.setClusterOptions(e.get('objectId'), {

                           balloonContentLayout:  'cluster#EMPTY',  // какой лейаут должен быть?

                           clusterBalloonContentLayout: 'cluster#EMPTY', // или так?

                            balloonContent:  data,

                            clusterBalloonContent: data,

                        });

                       // бесполезно <<<<<

                        objectManager.clusters.balloon.open(e.get('objectId'));

                    });

                    return false;

                }

            });

 

  

В итоге открывается балун с дефолтовым layout в 2 колонки и пустой.

 

30 комментариев

Работа с ObjectManager похожа во многом на работу с обычным кластеризатором. Переделала пример по созданию кастомного балуна кластера под ObjectManager -  http://jsfiddle.net/1z6puLxk/

1. мне нужно кастомный балун кластера именно. а не плейсмарка. (не по темплейту в цикле выводить объекты, а просто ХТМЛ отобразить.)

2. непонятно как добраться до кластера и его балуна с параметром контента

3. в вашем примере, если карту мышкой увести от всех плейсмарков с кластерами в сторону далеко , сделать более ничего нельзя, перемещение карты вызывает ошибки js

1. В примере открыт кастомный балун именно кластера

2. откуда именно добраться?

3. Забыла у объектов прописать айдишник, вот исправленный вариант http://jsfiddle.net/1z6puLxk/1/

http://jsfiddle.net/u1yeehs0/2/

 

вот что я имел в виду.

 

1. я вешаю колбек на клик через 

objectManager.clusters.events.add('click'

 

1.5. при клике происходит запрос ajax и получаю html. его надо вставить в балун.

 

2. в колбеке получаю кликнутый кластер через

var cluster = objectManager.clusters.getById(e.get('objectId'));

 

3. Не могу никак добраться до опции (или проперти) этого кластера, который означает "контент балуна" и изменить его соответственно.

Тоже голосую за ответ на вопрос номер 3.


Только добавлю ещё пару "спецэффектов".

 

1) В пункте 1) наверное надо вешать колбек на событие balloonopen. Так как сначала кластер при клике раскрывается на отдельные части и только если есть несколько объектов с одинаковой координатой кластер уже не раскрывается, а при клике открывает балун.

 

2) У меня не получается найти событие, которое происходит при клике на выбор конкретного объекта внутри кластера. В вашем примере вы подписываетесь на событие click. Но в случае если формат кластера карусель (balloonCarousel), то тайтлы объектов не показываются, а клик по цифрам в подвале карусели не генерит событие click для объектов.

 

1) тут могут быть вариации в зависимости от того, какое поведение вы хотите получить

(запретить кластерам зум при клике, хотите показывать индикатор загрузки данных при открытии пустого балуна и тд и тп)

У вас есть кейс, когда вы хотите детектить кластер на максимальном зуме и открывать на нем балун, верно?

 

2) Для стандартных макетов балуна следить за активным объектом кластера можно через поле

var currentObject = objectManager.clusters.state.get('activeObject');

objectManager.clusters.state.events.add('change', function () {

    var newActiveObjects = objectManager.clusters.state.get('activeObject');

if (newActiveObject != currentObject) {

   // нужные действия при смене активного объекта

}

});

2) Помогите, пожалуйста, получить id активного объекта кластера. Если в консоли делаю currentObject.id то всё ок. Если в коде пытаюсь так получить значение (нужно чтобы загрузить содержимое балуна), то картам сносит мозг от этого окончательно.

А ещё получить id самого кластера через ActiveObject вообще было бы отлично.


И ещё есть странный момент - вероятно баг.

 

Когда подписываюсь на событие change в clusters.state.events, то при первом клике на кластер это событие срабатывает 3 раза - в первый раз ActiveObject undefined, а потом ещё 2 раза это событие срабатывает для первого элемента кластера. При последующих открытиях балуна кластера всё ок - событие правильно срабатывает только один раз.

Поясню зачем мне надо получить id активного элемента в кластере и зачем нужен id самого кластера.

 

В вашем примере в этой ветке вы подписываетесь на событие click кластера и через него получаете id кластера, чтобы затем управлять составом и поведением балуна.

 

cluster.properties.balloonContent = data;    objectManager.clusters.balloon.open(clusterId);


А подписываюсь на событие в clusters.state.events.add которое не передаёт никаких параметров в себе и поэтому не получается через это событие ничего получить ни о кластере ни об активном элементе.


А id элемента нужен, так как при создании объектов я в это поле прописываю id объектов у себя в базе и содержимое балуна получаю ajax запросом.

Я ничего не поняла(

можете прям дать кусок кода и в комментариях написать, в каком месте непонятно?

Задача очень простая, классический пример применения карт - на карте есть объекты, а в балунах надо показать информацию об этих объектах.

 

Объекты загружаю в ObjectManager при создании карты и всем точкам прописываю нужные мне Id, чтобы по этим номерам потом получать содержимое балуна для этого объекта.

 

Объекты кластеризируются, формат кластера карусель (balloonCarousel).

 

Для некластеризированных объектов всё решается без проблем, по примеру из песочницы:

objectManager.objects.events.add('click', function (e) {

    var objectId = e.get('objectId');

    if (hasBalloonData(objectId)) {

        objectManager.objects.balloon.open(objectId);

    } else {

        getBalloonData(objectId).done(function(data) {

            var obj = objectManager.objects.getById(objectId);

            obj.properties.balloonContent = data;

            objectManager.objects.balloon.open(objectId);

        });

    }

});

 

Я хочу получить вот такое поведение:

при клике на кластер, открывается балун и подгружается в балун содержимое активного элемента. При смене активного элемента мы загружаем информацию по новому активному элементу и подставляем эти данные в ballonContent кластера.

 

Для управления активным элементом кластера вы посоветовали использовать вот этот код:

 

var currentObject = objectManager.clusters.state.get('activeObject');

objectManager.clusters.state.events.add('change', function () {

var newActiveObjects = objectManager.clusters.state.get('activeObject');

if (newActiveObject != currentObject) {

  // нужные действия при смене активного объекта

}

});

 

и он работает отлично - событие change в clusters.state.events даёт возможность управлять сменой активного элемента. Но есть 2 проблемы как раз в том, что должно быть на месте комментария "нужные действия при смене активного объекта".

 

1) Мне нужно узнать Id активного элемента, чтобы загрузить для него данные.

2) Мне нужно узнать Id кластера, чтобы именно для этого кластера выставить ballonContent.

 

А событие change в clusters.state.events не передаёт на вход никакой информации, чтобы узнать информацию о кластере в котором происходит активность.

activeObject тоже какая-то урезанная сущность, так и не понял как получить из неё её собственный Id.

 

Вот с этими двумя проблемами и прошу помочь!

1) В переменной newActiveObject как раз будет хэш с описанием объекта, его айдишник соответственно доступен по newActiveObject.id

2) Чтобы узнать, к какому кластеру относится объект, нужно выполнить

objectManager.getObjectState(newActiveObject.id).cluster.id

Объясните бестолковому как в коде получать эти id.

 

Если пробую так:

var currentObject = objectManager.clusters.state.get('activeObject');

var currentObjectId = currentObject.id;

 

то никаких ошибок в консоли нет, а карте от этого сносит голову напрочь. Балун отползает от маркера и в подвале балуна на месте ссылок на элементы класетра нули.

 

Жаль не могу приложить скриншот тут.

 

Аналогично с 

var clusterId = objectManager.getObjectState(currentObject.id).cluster.id

Вот сделал пример, того что пытаюсь сделать. И id активного элемента и id кластера пытаюсь получить, как советуете.

http://jsfiddle.net/boobooking/89cp39kL/8/

Но с балуном происходит явно, что-то неадекватное. Подскажите, пожалуйста, в чём ошибка.

 

Я конечно корявенько там поправила, дуюблируется код и тд. Но работает %) http://jsfiddle.net/89cp39kL/9/

Спасибо за идею, ваш вариант действительно работает. Но согласитесь, что это очень похоже на костыль. Такие сложные пути, чтобы сделать простую задачу.

Если бы не 2 бага в существующей реализации API (на мой взгляд бага), то всё можно было бы сделать очень изящно.

По той же ссылке обновил код - http://jsfiddle.net/boobooking/89cp39kL/17/

 

Посмотрите, пожалуйста, на идею.

Код "почти" работает, есть 2 тонких момента.

 

1) При первом клике на Placemark клаcтера событие change отрабатывает 3 раза вместо одного. Первый раз ActiveObject undefined и потом два раза активным принимается первый элемент кластера.  Посмотрите в консоль - оставил в коде логирование активного объекта. Только при первом клике такой эффект - дальше всё работает корректно.

Если бы событие отрабатывало корректно 1 раз, то можно было бы избавиться от ненужной проверки if (currentObject) {}

 

2) Когда сейчас открывается балун кластера при клике он пустой, но на самом деле в нём есть правильные загруженные данные и надо только подвинуть карту мышкой и балун отрисуется заново и данные появятся.

 

Подскажите, можно ли программно вызвать перерисовку балуна?

Если да, то такое решение полностью бы устроило.

1) Это не баг. activeObject это всего лишь одно из полей в state кластера.

Если вас напрягают проверки, можно создать монитор на изменение конкретного поля state

var monitor = new ymaps.Monitor(objectManager.clusters.state).add('activeObject', function () {

  // Этот код будет вызываться строго при изменении поля activeObject

});

 

2) Можно повторно вызвать метод open балуна, балун не закроется, а данные обновятся

Спасибо огромное!

Открыл для себя новую возможность карт - Monitor.

Всё что хотел сделать в итоге реализовал, без вашей помощи не справился бы.

 

http://jsfiddle.net/boobooking/89cp39kL/23/

Ура)))

Огромное спасибо за реализацию!

Как раз то, что требовалось, только немного подправил под свои нужды.

mari-na-bzzz, Вам отдельное спасибо. Съэкономил много времени благодаря этой ветке.

 

Итак, вам нужен пример, в котором

1. Переопределяется стиль балуна кластера (вам не подходит ни один из стандартных)

2. Данные для этого кластера подгружаются отложенно по клику на кластер

 

Все верно?

Верно все.

 

данные грузятся по клику на кластер. 

ПереОпределить контент балуна из стандартного колбе ка на клик по кластеру

 

objectManager.clusters.events.add('click', function (e) {


Это вроде документованный код - стандартный

Набросала пример http://jsfiddle.net/1z6puLxk/2/

Теперь получилось. Спасибо!

мой правленный вариант http://jsfiddle.net/u1yeehs0/4/

ура)

mari-na-bzzz,
Ветка старая, но большое спасибо. Сильно помогло, уже весь день разбираюсь с балунами в objectsManager
mari-na-bzzz,
Вы мне очень помогли, и сэкономили кучу времени спасибо большущие!!!!
mari-na-bzzz,
Марина, спасибо! Очень полезный пример!
А можно ли вместо события 'click' в objectManager использовать 'balloonopen' ?
т.е. менять содержимое(при необходимости) балуна после его открытия ? Ведь если перерисовать балун можно только его снова как-бы открыв objectManager.objects.balloon.open, то будет рекурсивное зацикливание. Есть выход ? Или только по click ?
Павел _,
почему нет. благодаря  вам и сделал, думал событие просто open.
на balloonopen:
e.preventDefault();
var clusterId = e.get('objectId');
var cluster = objectManager.clusters.getById(clusterId);
var clusterBalloonContent = cluster.properties.balloonContent;
var clusterFeatures = cluster.features;

if (clusterBalloonContent) {
objectManager.clusters.balloon.open(clusterId);
} else {
$.each(clusterFeatures, function (index, item) {
setBalloonData(item.properties.placemarkId);
});
}
objectManager.clusters.balloon.open(clusterId);
setClusterData(objectId);
подскажите, как задать ширину балуна около такой строчки
objectManager.clusters.balloon.open(e.get('objectId'));



, возможно раньше, изрыл доку вдоль и поперек, не понимаю, максимальная ширина 400px и все