Клуб API Карт

Геокодирование с кастомным результатом

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

На вход подаётся список городов, при чем каждому городу соотвествует количество людей.

Например, Москва - 3, Севастополь - 5, Ялта - 7

 

По идее, чтобы не загружать трафик, нужно воспользоваться множественным геокодированием и сделать как-то так:

 

 

var objects = ymaps.geoQuery(ymaps.geocode('Москва'))

for (var key in cities) {

    city = cities[key].title;

    objects.add(ymaps.geocode(city));

objects.addToMap(myMap);

 

 

Но. Нужно, чтобы каждый геообъект менял iconContent на соотвествующее количество, и другие мелочи (текст балуна, вид метки в зависимости от количества).

Более того, нужно еще, чтобы кластеризатор учитывал это количество.

 

 

Поэтому я сделал так:

 

 

for (var ck in cts) //cts - города, ck - идентификатор-название города

 

{

   var current = {

   city: ck

    };

 

 ymaps.geocode(ck,{kind:"locality",results:1}).then(ymaps.util.bind(function (res) { 

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

    object.properties.set('iconContent', cts[this.city]["count"]);

    object.properties.set('balloonContentHeader', this.city+" ("+cts[this.city]["count"]+")");

 

    clusterer.add(object);

 

    clusterer.createCluster = function (center, geoObjects) {

         // Создаем метку-кластер с помощью стандартной реализации метода.

        var clusterPlacemark = ymaps.Clusterer.prototype.createCluster.call(this, center, geoObjects),

        geoObjectsLength = clusterPlacemark.getGeoObjects().length,

        realGeoObjectsLength = 0;

        var objs = clusterPlacemark.getGeoObjects();

 

        for (var j=0; j<geoObjectsLength; j++) {

            realGeoObjectsLength = realGeoObjectsLength + objs[j].properties.get('iconContent');

        }

 

        clusterPlacemark.options.set('clusterIconContentLayout', ymaps.templateLayoutFactory.createClass('<div style="color: #FFFFFF; font-weight: bold;">'+realGeoObjectsLength+'</div>'));

        return clusterPlacemark;

    };

 

}, current));

}

myMap.geoObjects.add(clusterer);

 

 

Так метки с городами и кластерами отображаются с нужными числами.

Но, во-первых, такое решение далеко от принципа множественного геокодирования.

При этом, города могут быть абсолютно любые, самые популярные города можно сохранить в БД, и оттуда вытягивать, но все равно - будут и непопулярные города.

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

 

Как быть? Как сделать кастомный вывод метки в зависимости от города(от его параметров) и при этом не превысить лимит запросов?

 

П.С.: текст кода упрощен в процессе задавания вопроса, поэтому может содержать формальные ошибки. Важен же ответ по существу.

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

 1.

  
По идее, чтобы не загружать трафик, нужно воспользоваться множественным геокодированием и сделать как-то так:

Так вы все равно будете геокодировать одно и то же на каждом клиенте что через geoQuery что через цикл

 

 

2. Метод then принимает контекст последним параметром

Не надо использовать util.bind и тем более советовать другим его использовать.

 

По существу:

решение таких задач на клиенте - плохая идея и дело не только в кол-ве запросов, трафике и превышении лимитов. 

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

 

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

непопулярные можно также геокодировать и сохранять на сервере, если не в БД, то хотя бы в memcached

ну и конечно загрузка сайта ускорится в разы. 

На каждом клиенте не одно и то же. Дело в том, что список городов зависит от клиента, и я не знаю заранее, какие они будут. В общем-то, абсолютно любые из миллионов городов в мире.

 Поэтому я не нашел решения лучше чем представленное выше - через util.bind. У меня нет желания научить или насоветовать чего-то плохого кому-то (тем более злоумышленно) - просто поделился своим решением; тем более я паралельно задал связанный вопрос. В конце концов, может у человека аналогичная задача.

Я в любом случае буду хранить данные городов в БД. Но это ж не отменяет, что после того, как я откину из пришедшего списка сохраненные в БД города, мне не придется остальные прогеокодировать - и их будет больше одной штуки. 

 

Чтобы не превышать лимиты геокодируйте через собственный кешируюший прокси

Если я правильно понимаю, в общем-то результат будет тот же, что и с БД - новые запросы все равно будут идти. Разве что в бан попадет прокси-сервер, а не сам сайт)
Думаю, как вариант, можно подсчитывать количество запросов в сутки, записывать в ту же БД, и самому ограничивать запросы.

По-прежнему интересует - можно ли модифицировать полученные в результате геокодирования объекты, например IconContent, как-то иначе, чем в цикле с передачей через контекст итерации, как я это делаю?



 

 

Прокси очевидно часть запросов будет брать из кеша, для этого он и нужен собственно.

 

Я не знаю как вы планируете получать эти данные для списка городов. Отдельным запросом?

Обычно есть 2 списка:

Список городов для геокодирования и список данных для найденных городов, тогда можно делать как то так:

http://jsbin.com/xovuvosiqi/1/edit?html,console,output

 

Спасибо большое! Кажется, то, что нужно.

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