Клуб API Карт

События при кластеризации (раскластеризации)

Денис Артемьев
28 октября 2015, 15:24

Здравствуйте, я заменил иконки на  templateLayoutFactory, то есть там теперь лежит html разметка, по которой проходиться jQuery и считает некоторые данные.

 

Если объекты не кластеризуются, то рассчет работает нормально, если же объекты собраны в кластер, то jQuery их не видит.

 

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

 

Вопрос: как можно поймать событие при раскластеризации объекта, то есть появлении отдельных меток?

 

На данный момент я попробовал добавить следующее событие:

myMap.events.add('boundschange', function (event) {
    if (event.get('newZoom') != event.get('oldZoom')) {
        $('#b_calc').trigger('click');
    }
    if (event.get('newBounds') != event.get('oldBounds')) {
        $('#b_calc').trigger('click');
    }
});

Это событие не удовлетворяют требованиям, хотя события срабатывают.
Получается, что при увеличении карты, сначала срабатывает событие
boundschange потом срабатывает расчет и только потом
объекты раскластеризовываються :)

Буду рад Вашей помощи)

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

Зачем считать по разметке? Считайте по исходным геообъектам

Денис Артемьев
28 октября 2015, 16:11

Спасибо за ответ, то есть нужно удалить все объекты с карты, и заново запустить цикл? (у меня в цикле из json генерируются метки)

Я правильно Вас понимаю?

Удалять ничего не надо. У вас есть ссылка на исходный массив геообъектов, который вы передаете в кластеризатор.

Обходите этот массив с помощью javascript и считайте

Зачем использовать jQuery и ковыряться в DOM, если можно оперировать данными напрямую

Денис Артемьев
29 октября 2015, 08:35

Я идею понял, но с реализацией затрудняюсь(

У меня есть:

geoObjects[coutn] = new ymaps.Placemark(group.items[j].center, {
        balloonHeader: 'Заголовок балуна',
        balloonContent: 'Контент балуна'
},{
        iconLayout: polygonLayout,
        // Описываем фигуру активной области "Полигон".
iconShape: {
            type: 'Polygon',
            // Полигон описывается в виде трехмерного массива. Массив верхнего уровня содержит контуры полигона.
// Первый элемента массива - это внешний контур, а остальные - внутренние.
coordinates: [
                // Описание внешнего контура полигона в виде массива координат.
[[-58,-106],[58,-106],[58,-20],[12,-20],[0,0],[-12,-20],[-58,-20]]
                // , ... Описание внутренних контуров - пустых областей внутри внешнего.
]},
    balloonShadow: false,
    balloonLayout: MyBalloonLayout,
    balloonContentLayout: MyBalloonContentLayout,
    balloonPanelMaxMapArea: 0,
    // Не скрываем иконку при открытом балуне.
hideIconOnBalloonOpen: false,
    // И дополнительно смещаем балун, для открытия над иконкой.
balloonOffset: [3, -40],
        balloonAutoPan: false
}
);
var result = ymaps.geoQuery(geoObjects).applyBoundsToMap(myMap, {checkZoomRange: false});

myMap.geoObjects.add(result.clusterize());


Как обратиться к

iconLayout или balloonLayout

и внутри найти определенный div?

Зачем обращаться в layout-ы?

Выложите их код и код функции, делающей расчет

Денис Артемьев
29 октября 2015, 10:55

Это создание iconLayout

polygonLayout = ymaps.templateLayoutFactory.createClass('' +
    '' +
    '' + group.items[j].p +
    '$' + group.items[j].pr +
    '
' + group.items[j].p +
    'E' + group.items[j].pr +
    '
0
Подробнее ' +
    '');


Это код события при рассчете:

$("#b_calc").click(function () {
//здесь прсваем значение, которое ввел пользователь
    var count = parseFloat($.trim($("#calc").val()));
//здесь присваевается валюта (доллар или евро)
    var val = $.trim($("#val").val());
    if (val == "usd") {
        val = "s_";
    } else {
        val = "e_";
    }
    if (count == "") {
        count = 0;
    }

    $("div.polygon_layout").each(function () {
//здесь берем одно значение с iconLayout, в зависимости от выбранной валюты
        var widthVal = parseFloat($(this).find("."+val+"v1").html());
//здесь выводим на iconLayout результат рассчетов
$(this).find(".rez").html(widthVal*count)
    });

});

 

Дело в том, что макеты (layout) используются для отделения данных геообъекта от представления этих данных в его балуне, хинте ( и иконке для меток )

Вот в таком виде, как вы его используете никакого профита от него нет.

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

 

1. Вам нужно использовать макеты по назначению,

вместо

...

 '' + group.items[j].p + ''

...

 Использовать язык шаблонов в макете:

...

 ''{{ properties.p }}'

...

Сами данные надо положить во второй параметр геообъекта

... 

new ymaps.Placemark(group.items[j].center, {
p: group.items[j].p,
pr: group.items[j].pr
}, 

...

 

Далее для расчетов вы используете свой массив geoObjects

типа того:

var result = geoObjects.reduce(function (total, geoObject) {

  return total + parseFloat(geoObject.properties.get('pr'))

}, 0)

 

Денис Артемьев
30 октября 2015, 12:25

Огромное спасибо за помощь!

 

Сделал так:

geoObjects[coutn] = new ymaps.Placemark(group.items[j].center, {
        balloonHeader: '',
        balloonContent: '',
        p: group.items[j].p,
        pr: group.items[j].pr,
        total: 0,
        name:  group.items[j].name,
        address: group.items[j].address,
        phone: group.items[j].phone,
        mode: group.items[j].mode
}
.....
polygonLayout = ymaps.templateLayoutFactory.createClass('' +
    '' +
    '$[properties.p]
$$[properties.pr]

$[properties.p]E
$[properties.pr]

$[properties.total]
Подробнее' +
    '');

Обработчик:
$("#b_calc").click(function () {
    var count = parseFloat($.trim($("#calc").val()));
    if (!$.isNumeric(count)) {
        count = 0;
    }

    var result = geoObjects.reduce(function (total, geoObject) {
        var widthVal = parseFloat(geoObject.properties.get('p'));
        geoObject.properties.set('total',widthVal*count);
        //return widthVal*count;
}, 0);

});

Хорошо получилось. Можно немного улучшить.

1.


geoObjects[coutn] = new ymaps.Placemark(group.items[j].center, $.extend({ total: 0 }, group.items[j]), {
...
});

 

2. Не надо каждый раз перестраивать макет тут

 

var result = geoObjects.reduce(function (total, geoObject) {
        return parseFloat(geoObject.properties.get('p')) * total;
}, 0);

geoObject.properties.set('total',result);
Денис Артемьев
30 октября 2015, 15:02

Что-то у меня с улучшениями не получилось ничего.

 

1) Я так понимаю extend, должен избавить от изначального обнуления total? Или, вероятно, я что-то недопонимаю)

 

2) geoObject.properties.set('total',result); - эту строку он не понимает, так как она вынесена за пределы функции и у меня же множество объектов, в которых нужно что-то изменить, он же не сможет ничего сделать вне цикла?

 

При внесении этих изменений, иконки становятся дефолтными а баллоны вообще не открываются...