Клуб API Карт

Единоразовое добавление объектов на карту

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

Есть массив точек (адресов), которые пропускаю через геокодировщик и добавляю в cluster

В завершнии добавляют сам cluster на карту

map.geoObjects.add(cluster);

 

При этом при загрузке страницы каждый объект добавляется независимо а не все сразу. Как вывести на карту только после окончания геокодирования всех элементов

 

Код примерно такой:

 

var promise = new ymaps.util.Promise();
var start = ["Москва","Санкт-Петербург","Воронеж"];
cluster = new ymaps.Clusterer({clusterDisableClickZoom: true});
   start.forEach(function (s, i) {
       ymaps.geocode(s, {results : 1})
           .then(
               function (res) {
                   var obj = res.geoObjects.get(0);
                   obj && cluster.add(obj, i);
               },
               function (err) {
console.log(err);
               }
           );
   });
map.geoObjects.add(cluster);

 

Спасибо

8 комментариев
Алексей Yarrr!
28 января 2016, 03:58

На сколько мне известно, кластер перерисовывается не весь сразу после добавления, а частями. Поэтому, если в данный момент не тормозит - то можете забыть. Если скорость не устраивает - заводите промежуточный буффер, и добавляйте в кластер частями через каждые сколько ms с помощью setTimeout.

Т.е. geocode возвращает вам данные - вы их в буффер. setTimeout говорит, что время выбросить новое - вы их в кластер. А из кластера на карту они попадут так же асинхронно. И у браузера будет время обработать пользовательские телодвижения.

Владимир Батищев
28 января 2016, 03:58

Буду очень признателен, если напишите пару строк как с буфером работать?

 

Спасибо

Алексей Yarrr!
28 января 2016, 03:58

я бы какнибудь так сделал, используя ваш набросок:

var geoBuffer = [], promise = new ymaps.util.Promise();

 

var start = ["Москва","Санкт-Петербург","Воронеж"];

cluster = new ymaps.Clusterer({clusterDisableClickZoom: true});

   start.forEach(function (s, i) { // все ниже делаем для каждого названия

       ymaps.geocode(s, {results : 1}) // дергаем аяксом внешний исхочник - плохой вариант дергать каждый элемент отдельно. никогда не делайте так на живом проекте ;-)

           .then(

               function (res) {

                   var obj = res.geoObjects.get(0);

                   obj && geoBuffer.push({obj: obj, i: i}); // кладем в буффер

               },

               function (err) {

console.error(err);

               }

           );

   });

map.geoObjects.add(cluster); // регистрируем коллекцию на карте - кластер, в нашем случае

 

(function loopsiloop(n){

   setTimeout(function(){

       if (!geoBuffer || n > 100) return; // хватит вертется. задолбив geoBuffer (например delete geoBuffer в любом месте) мы остановим таймер и оно перестанет добавляться. Повторно его запустить можно будет создав geoBuffer = [] и запустив функцию loopsiloop(1). второе условие - если в буффер ничего не кладется в течение долгого времени - тоже перестаем обновлять кластер, потому что скорее всего уже ничего никогда не прилетит.

       if (!geoBuffer.length) {

          n += 10; // увеличим n на 10, если geoBuffer оказался пустым

       }

       var el;

       // добавляем все, что наприлетало в буффер и чистим его

       while (el = geoBuffer.pop()) { // боятся ситуации, когда мы выбираем из буфера и одновременно кладем в него - не стоит ;-) потому что.

         cluster.add(el.obj, el.i);

       }

       loopsiloop(n+1); // recurse

   }, 542+500*n);

})(0); // первый раз запустится через 542+500*0 = 542 ms, второй раз через 1042 ms, и т.д., каждый раз будет ждать на пол секунды больше.

 

Думаю, есть и более элегантные решения, все зависит от контекста.

Вообще, всегда старайтесь сокращать запросы к внешним ресурсам. Аякс хорошо, но он должен быть оправдан. Если есть возможность вообще избавится от лишних запросов, не потеряв в функциональности - всегда делайте это.

 

 

https://developer.mozilla.org/en-US/docs/DOM/window.setTimeout

http://www.erichynds.com/javascript/a-recursive-settimeout-pattern/

Владимир Батищев
28 января 2016, 03:58

Спасибо большое за столь развернутый ответ и предостержения, хотя думаю все равно придется сохранять в базу.

 

Еще раз спасибо! 

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

Алексей Yarrr!
28 января 2016, 03:58
 start.forEach(function (s, i) {       ymaps.geocode(s, {results : 1})           .then(но вот так делать не надо ;-) координаты получайте заранее и храните у себя, незачем от каждого пользователя это делать, если данные всегда одни и те же. у geocode есть простой протокол - надо будет только xml попарсить.
Владимир Батищев
28 января 2016, 03:58

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

Алексей Yarrr!
28 января 2016, 03:58

И вы пролетите с доступом к геокодеру, потому их кол-во ограничено в месяц.