Клуб API Карт

Подписи к меткам, полученным с помощью множественного геокодирования

SkyCat
3 сентября 2010, 00:36

Здравствуйте.

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

Я брал за основу этот пример.

Вот мой адаптированный вариант вышеуказанного примера.

<script type="text/javascript">
 // Создание обработчика для события window.onLoad
 YMaps.jQuery(function () {

 // Создание экземпляра карты и его привязка к созданному контейнеру
 var map = new YMaps.Map(YMaps.jQuery("#YMapsIDd")[0]);
 map.setCenter(new YMaps.GeoPoint(39.887714, 57.622506), 10);
 var traffic = new YMaps.Traffic.Control();
 var zoom = new YMaps.Zoom({smooth: true});
 map.addControl(new YMaps.Zoom(), new YMaps.ControlPosition(YMaps.ControlPosition.TOP_LEFT), new YMaps.Point(10, 10));
 map.addControl(traffic, new YMaps.ControlPosition(YMaps.ControlPosition.TOP_RIGHT, new YMaps.Point(5, 5)));
 traffic.setState({
 shown: true, // элемент управления развернут, пробки показаны
 infoLayerShown: true
 });

 // Координаты или адреса географических объектов
 var data = ["г. Ярославль, Ленинградский пр-т, 49а", "г. Ярославль, Московский пр-т, д. 108" ];

 var geocoder = new MultiplyGeocoder(data);

 map.addOverlay(geocoder);

 YMaps.Events.observe(geocoder, "Load", function (geocoder) {

 });

 });

 // Реализует наследование прототипа без исполнения конструктора родителя
 // Подробнее о наследовании: http://javascript.ru/tutorial/object/inheritance
 function extend (child, parent) {
 var c = function () {};
 c.prototype = parent.prototype;
 c.prototype.constructor = parent;
 return child.prototype = new c;
 };

 // Множественный геокодер
 // requests - массив адресов
 function MultiplyGeocoder (requests) {

 // Вызов родительского конструктора
 YMaps.GeoObjectCollection.call(this);
 var _this = this,

 // Количество вызовов геокодера
 geocodeCallCount = 0,

 // Обработчики событий
 listeners = [];

 // Последовательно геокодируем все переданные адреса
 for (var i = 0, l = requests.length; i < l; i++) {
 geocode(requests[i]);
 }

 // Функция, отвечающая за геокодировании одного адреса
 function geocode (request) {
	 
 // Геокодируем
 var geocoder = new YMaps.Geocoder(request);

 // Счетчик вызовов геокодирования увеличиваем
 geocodeCallCount++;

 // Сохраняем ссылки на обработчики событий
 listeners = listeners.concat(

 // Обработка событий Load и Fault
 YMaps.Events.observe(geocoder, [geocoder.Events.Load, geocoder.Events.Fault], function (geocoder) {
 if (geocoder.length()) {
 _this.add(geocoder.get(0));
 }

 geocodeCallCount--;
 isFinish();
 })
 );
 }

 // Функция для проверки окончания процесса геокодирования
 function isFinish () {

 // Если все объекты сгеокодированы, то генерируем событие завершения
 if (!geocodeCallCount) {

 // Событие о завершении геокодирования
 YMaps.Events.notify(_this, "Load", _this);

 // Удаление обработчиков событий
 for (var i = 0, l = listeners.length; i < l; i++) {
 listeners[i].cleanup();
 }
 }
 }
 }

 var ptp = extend(MultiplyGeocoder, YMaps.GeoObjectCollection);
</script>

Данные для геокодирования задаются динамически. Адреса берутся из базы данных.

11 комментариев
Подписаться на комментарии к посту
Советую вначале прогеокодировать и закэшировать координаты. Не стоит геокодировать список адресов каждый раз.

Подробнее в этой статье: http://ymapsapi.ya.ru/replies.xml?item_no=81
Да, я понимаю. У нас кэширование реализовано здесь. Но, к сожалению, сам я только учусь программировать, а программист, который делал карту, сейчас недоступен.
Поменяйте стиль у группы-геокодера:

var geocoder = new MultiplyGeocoder(data);
geocoder.setStyle({ balloonContentStyle : { template : new YMaps.Template("$[text]") } });
map.addOverlay(geocoder);
Спасибо большое. Все работает.

Лучше всего составить соответствие поискового запросу тексту и цветовому оформлению и научить MuliplyGeocoder это кушать.

Данные могут быть представлены вот в таком виде:

var data = [{request: "Москва, ул. Льва Толстого, 16", name: "Офис Яндекса", style: "default#greenPoint"}]
А может вам лучше один раз прогеокодировать на серверной стороне и закешировать полученные координаты?

Тестовые данные. В стили можете задать любой html-ый шаблон. html может содержать и в самом name.

var data = [
    {request: "Москва", name: "Столица РФ", style: {
        parentStyle: "default#redPoint",  
        balloonContentStyle: {
            template: new YMaps.Template('

$[name]

')
        }
    }},
    {request: "Санкт-Петербург", name: "Северная столица РФ", style: "default#greenPoint"}
];

Изменненный MultiplyGeocoder:

function MultiplyGeocoder (requests) {
    YMaps.GeoObjectCollection.call(this);

    var _this = this,
        geocodeCallCount = 0,
        listeners = [];

    for (var i = 0, l = requests.length; i < l; i++) {
        geocode(requests[i]);
    }

    function geocode (data) {
        var geocoder = new YMaps.Geocoder(data.request);

        geocodeCallCount++;

        listeners = listeners.concat(
            YMaps.Events.observe(geocoder, [geocoder.Events.Load, geocoder.Events.Fault], function (geocoder) {
                if (geocoder.length()) {
                    var geocodeResult = geocoder.get(0);
                    geocodeResult.name = data.name;
                    geocodeResult.setStyle(data.style);
                    _this.add(geocodeResult);

                }
                geocodeCallCount--;
                isFinish();
            })
        );
    }

    function isFinish () {
        if (!geocodeCallCount) {
            YMaps.Events.notify(_this, "Load", _this);

            for (var i = 0, l = listeners.length; i < l; i++) {
                listeners[i].cleanup();
            }
        }
    }
}

var ptp = YMaps.Utils.extend(MultiplyGeocoder, YMaps.GeoObjectCollection);

Прогресс не стоит на месте и если у вас подключен новый jQuery, то вы можете использовать Deffered-объекты для отслеживания асинхронных событий.

Тогда код будет выглядеть примерно так:

function MultiplyGeocoder (requests) {
    YMaps.GeoObjectCollection.call(this);

    var _this = this,
        listeners = [];

    $.when.apply(this, $.map(requests, geocode)).then(
        function () {
            YMaps.Events.notify(_this, "Load", _this);
        },
        function () {
            YMaps.Events.notify(_this, "Fault", _this);
        }
    )

    function geocode (request) {
        var dfd = new $.Deferred(),
            geocoder = new YMaps.Geocoder(request);

        listeners = listeners.concat(
            YMaps.Events.observe(geocoder, geocoder.Events.Load, function (geocoder) {
                if (geocoder.length()) {
                    var geocodeResult = geocoder.get(0);
                    _this.add(geocodeResult);
                    YMaps.Events.notify(_this, "GeocodeSuccess", request, geocodeResult);
                    dfd.resolve();
                } else {
                    YMaps.Events.notify(_this, "GeocodeError", request, "not found");
                    dfd.reject();
                }
            }),
            YMaps.Events.observe(geocoder, geocoder.Events.Fault, function (geocoder, error) {
                YMaps.Events.notify(_this, "GeocodeError", request, error);
                dfd.reject();
            })
        )

        return dfd.promise()
    }
}
var ptp = YMaps.Utils.extend(MultiplyGeocoder, YMaps.GeoObjectCollection);

В этом варианте я добавли дополнительные события, которые сообщают об удачном/неудачном геокодировании конкретных объектов. Соотвественно, в обработчиках вы сможете делать с этими объектами все, что захотите.

Посмотреть как это примерно работает можно на таком примере:

var data = ["Москва", "Абракадабра"];

var geocoder = new MultiplyGeocoder(data);
map.addOverlay(geocoder);

YMaps.Events.observe(geocoder, "Load", function (geocoder) {
    alert("Геокодирование завершено");
});

YMaps.Events.observe(geocoder, "Fault", function (geocoder) {
    alert("Геокодирование завершено с ошибками");
});

YMaps.Events.observe(geocoder, "GeocodeSuccess", function (request, result) {
    alert(request + " прогеокодирован");
});

YMaps.Events.observe(geocoder, "GeocodeError", function (request, error) {
    alert(request + " прогеокодирован с ошибкой: " + error);
});
Мне больше нравится этот вариант, потому что MultiplyGeocoder делает то, что ему только полагается - геокодирует объекты. Остальную логику к его работе можно добавлять через обработчики соответствующих событий.

var oldPoint = geoResult.getGeoPoint();

geoResult.setGeoPoint(oldPoint.moveBy(new YMaps.GeoPoint(0.1, 0.1))); // Сместить на 0.1 градуса по широте и долготе

Вы хотите отобразить несколько адресов, попавших в одну точку?

Посмотрите схожее обсуждение: http://clubs.ya.ru/mapsapi/replies.xml?item_no=13333

Саша у вас в балуне выводится одна переменная name. Подскажите как сделать вывод в балуне трех переменных: request, name, name2