Клуб API Карт

Найдено на тему «LoadingObjectManager»:
Фильтровать количество точек в видимой области карты
Valentin
13 февраля 2017, 12:14

Добрый день, как фильтровать количество выводимых точек на карте? Точек может быть очень много и хочется на пример показывать только 500, если хочется увидеть больше, то пользователь зумирует карту. 

Использую LoadingObjectManager, сначала фильтер сделали на сервере, но столкнулись с проблемой, на пример работа с картой начинается в г.Москва, макс 500 отрисовалось точек, пользователь зумирует, а новые не видит. 

Думал восп. фильтром для objectmanager, но по какому критерию фильтровать? 

Подскажите пожалуйста, как это осуществить? Отрисовка происходит при помощи смены setUrlTemplate и перезаписью новых данных на карте reloadData.

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

1 комментарий
LoadingObjectManager,filter,ObjectManager,overlays
Переход к метке и её открытие
Valentin
3 февраля 2017, 18:19

Подскажите опжалуйста. Версия 2,1.

Имеется карта, с использованием LoadingObjectManager. 

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

При клике на ссылку:

Перемещаемся к её положению, увеличиваем карту.

myMap.panTo(newLoca).then(function () {
   console.log(idCurrent) // id метки
   myMap.setZoom(17);
   console.log(objectManager.objects)
   console.log(objectManager.objects.get(idCurrent));
},this);

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

Так же имеется ивента на просмотр клика и нажатия на кластер:

var activeObjectMonitor = new ymaps.Monitor(objectManager.clusters.state);
// При клике на некластеризованные объекты получаем содержимое балуна
	objectManager.objects.events.add('click', function(e) {
	var objectId = e.get('objectId');
	setBalloonData(objectId);
});
activeObjectMonitor.add('activeObject', function (e) {
	var objectId = activeObjectMonitor.get('activeObject').id;
	setBalloonData(objectId);
});

Или как еще можно реализовать? 

Спасибо.

LoadingObjectManager,panTo,fire
Как работать с данными карты? LoadingObjectManager + setUrlTemplate + reloadData
Valentin
2 февраля 2017, 17:08

Добрый вечер. Подскажите пожалуйста, как работать с объектами карты, после обновления их через objectManager.setUrlTemplate (получение новых значений) и objectManager.reloadData() , перезаписывания меток?

На пример:

objectManager.objects.getLength();

Могу использовать только до перезаписывания меток, но он отдает "старый" результат, а не новый.

Пробую не что такое: 

myMap.panTo(myMap.geoObjects.getBounds(), {checkZoomRange:true});

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

myMap.setBounds(myMap.geoObjects.getBounds());

Так же не возможно использовать после objectManager.reloadData(). Не понимаю как центровать карту с исп LOM'a?

objectManager — это и есть LOM

objectManager = new ymaps.LoadingObjectManager
1 комментарий
reloadData,ObjectManager,LoadingObjectManager
LoadingObjectManager + загрузка точек в кластере
Valentin
30 января 2017, 13:15
Простите, тупой вопрос был. Ошибка в логике была.

А так же можете обратить внимание на тему: https://yandex.ru/blog/mapsapi/tsentrovka-karty-ot-rezultatov-lop (без ответа) 

claster,LoadingObjectManager
Центровка карты от результатов + LOP
Valentin
19 января 2017, 23:32

Всем привет, подскажите пожалуйста. Имеется собираю точки при помощи: 

objectManager = new ymaps.LoadingObjectManager(mapControl.data.url, {
	splitRequests: false,
	clusterize: true,
	clusterHasBalloon: false,
	geoObjectOpenBalloonOnClick: false
});
objectManager.objects.options.set('preset', 'islands#redIcon');
objectManager.clusters.options.set('preset', 'islands#redClusterIcons');
myMap.geoObjects.add(objectManager);

Так же на карте имеется фильтр, в самом конце он отправляем запрос на получение новых точек, все прекрасно работает (прим.:)

if(serializeFilter.length) {
  objectManager.setUrlTemplate(mapControl.data.url+'&'+serializeFilter);
} else {
  objectManager.setUrlTemplate(mapControl.data.url);
}
objectManager.reloadData();

, но заметил одну проблему. Если в ответе одна точка и она не находится в пределах видимости карты, как можно заставить карту передвинуться и позиционироваться относительно всех точек? И если их очень много, то ближайших (но не более, т.к. точки могут быть разбросаны по всей России). 2 вариант наверное сложный, а про первый, помню было решение, но оно работало не с LoadingObjectManager. Как повторить такое позиционирование с новыми точками?

Большое спасибо.

2 комментария
LoadingObjectManager,map.geoObjects
Возможность реализации серверной части LoadingObjectManager или RemoteObjectManager на PHP
Александр Копосов
10 января 2017, 15:19

Приветствую всех! 

Столкнулся с проблемой реализации серверной части LoadingObjectManager или RemoteObjectManager.

Общая картина: на сайте есть карта; на неё из базы загружаются десятки тысяч меток; используется ObjectManager и PieChartClusterer. Алгоритм такой: Пользователь задаёт фильтр, какие метки ему нужны; из базы загружаются соответствующие данные и формируется JSON; этот JSON скармливается ObjectManager'у; ObjectManager загружается на карту.

И всё бы хорошо, но первоначальная загрузка огромного числа меток занимает 100500 лет (т.е. загрузка довольно долгая).

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

Собственно, сама проблема:

Я читал документацию по "Работе с большим числом объектов", а также статью на Хабре и видел там Проект на гитхабе с примером реализации серверной части для RemoteObjectManager.

Может быть (скорее всего) я чего-то не так понял (ну или вообще не понял), но возможна вообще серверная сторона не на Node.js (как в примере), а на PHP?

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

2 комментария
RemoteObjectManager,LoadingObjectManager,objectManager,множество объектов,PHP
Фильтрация объектов, при исп. LoadingObjectManager
Valentin
21 декабря 2016, 16:49

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

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

objectManager = new ymaps.LoadingObjectManager('/map/coords?bbox=%b', {...});

Если параметры фильтра добавлять к гет параметру, сервер будет возвращать точки, удолетворяющие get параметрам. Но как поведет себя карта при изменении параметров? Ведь она для этой области уже загрузила точки, и может не загрузить новые под эту карту? И не спрячет уже показанные? Или при исп фильтра уничтожать текущий ObjectManager и создавать новый? 

Возможно использовать setFilter(), но не понятно как красиво написать фильтр для мульти селекта, на пример? 

Спасибо.

1 комментарий
LoadingObjectManager,setFilter,filter
Проблема с LoadingObjectManager
SagaranoMail
22 сентября 2016, 18:45

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

для определения, что загрузка закончилась я использую хак с setInterval и прослушкой события "add" для loadingObjectManager.objects

1 комментарий
LoadingObjectManager
Произвольный контент балуна кластера
SagaranoMail
9 сентября 2016, 22:08

Привет!

Использую LoadingObjectManager с включенной кластеризацией. Хочу показывать балун кластеризатора с произвольным макетом и с динамически формируемым контентом. Сейчас при клике на кластеризатор карта зумится к выбранным точкам и это хорошо, когда доходим до макс. зума нужно открыть балун и заполнить его контентом. Вопрос: если отслеживать клик по кластерам

loadingObjectManager.clusters.events.add('click', function (e) {
 var cluster = loadingObjectManager.clusters.getById(e.get('objectId'));
})

как понять что дальше зумить уже нельзя и пора открывать балун? через

myMap.action.getCurrentState().zoom

видимо не то, т.к. значение показывается еще до окончания анимации приближения

Может другое событие отлавливать? Например, через Monitor

var activeObjectMonitor = new ymaps.Monitor(loadingObjectManager.clusters.state);

Но можно ли изменить контент балуна уже после его открытия?

7 комментариев
LoadingObjectManager,cluster
Не очищается слой, задаваемый LoadingObjectManager
as-popov
18 мая 2016, 19:00

Добрый день!

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

Для мелких масштабов отдавать точечные объекты с кластеризацией

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

Регистрирую два загрузчика объектов для точек и полигонов:

var loadingObjectManagerPoints = new ymaps.LoadingObjectManager(ext_ip + '/home/mappoints?bbox=%b&zoom=%z', { clusterize: true });

var loadingObjectManager = new ymaps.RemoteObjectManager(ext_ip + '/home/map?bbox=%b&zoom=%z');
    myMap.geoObjects.add(loadingObjectManagerPoints);
    myMap.geoObjects.add(loadingObjectManager);

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

{ "error": "no data",
  "data": null
}

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

Ссылка на тестовый пример: 

https://gosuslugi.geosys.ru:2003/AspTest

Если же в клиентской части вместо LoadingObjectManager для точечных объектов использовать RemoteObjectManager

var loadingObjectManagerPoints = new ymaps.RemoteObjectManager(ext_ip + '/home/mappoints?bbox=%b&zoom=%z');

Все будет работать правильно, но, естественно, без кластеризации.

2 комментария
LoadingObjectManager,кластеризация
Не открывается балун кластера
Андрей Работинский
12 апреля 2016, 13:21

Добрый день.

Я использую LoadingObjectManager для отрисовки большого количества объектов на карте. На странице с картой есть список видимых на карте объектов. При клике на элементе этого списка хотелось бы, чтобы карта центрировалась на объекте и, если объект входит в состав кластера, то масштабировала карту до тех пор, пока объект будет отображаться отдельно(не в составе кластера) или пока не будет достигнут максимальный для координат объекта зум карты. Если при достижении максимального зума объект все еще будет входить в кластер, то сделать этот объект активным и открыть балун кластера. Все работает при использовании функции приведенной ниже, за исключением открытия балуна на метке кластера. При открытии балуна вне функции setZoom он открывается нормально. Может есть какие-то пути обхода или я где-то что-то упускаю?

function focusOnGeoobject(id) {
        //Находим объект по id, который получаем при клике по элементу списка
        var object = loadingObjectManager.objects.getById(id);
        var coords = object.geometry.coordinates;
        var objectState = loadingObjectManager.getObjectState(id);
         
        myMap.setCenter(coords);

        myMap.zoomRange.get(coords).then(function (zoomRange) {
            //Масштабируем карту до тех пор, пока объект не выйдет из кластера или не будет достигнут максимальный зум
            while (objectState.isClustered && myMap.getZoom() !== zoomRange[1]) {
                myMap.setZoom(myMap.getZoom() + 1);
            }
            if (objectState.isClustered) {
                loadingObjectManager.clusters.state.set('activeObject', object);
                loadingObjectManager.clusters.balloon.open(objectState.cluster.id);
            } else {
                loadingObjectManager.objects.setObjectProperties(id, { preset: 'islands#redStretchyIcon' });
            }
        });
    }

5 комментариев
кластер,балун,LoadingObjectManager,zoom
Изменение опций балуна при использовании LoadingObjectManager
Тим В
30 декабря 2015, 23:47

Добрый день, может у кого есть готовый пример.

Вопрос в следующем, не получается поменять опции balloon и hint (например options.panelMaxMapArea).

Как только не пробовал.

С картами работал мало. Документацию читал. Использую LoadingObjectManager

 

1 комментарий
baloon,LoadingObjectManager
ObjectManager и LoadingObjectManager
Тимофей Соловейчик
20 марта 2015, 22:50

По карте можно перемещаться на запад или восток без ограничений, т.е. можно несколько раз пройти через определённую долготу, к примеру 0-ю, НО метки отображённые через ObjectManager или LoadingObjectManager будут отображены только один раз, и не перемещаются при повторном прохождении 0-й долготы, это так задумано или есть какая-то опция для того, чтобы метки переносились на "новую копию" карты.

5 комментариев
метка,API 2.1,LoadingObjectManager,ObjectManager
LoadingObjectManager событие начала и окончания загрузки
Игорь З.
8 февраля 2015, 23:17

Добрый вечер. Не смог найти ответ в документации.

Нужно показать прелоадер во время выполнения запросов к серверу. Возможно ли это сделать для LoadingObjectManager?

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

Речь не о спиннере на всю карту, нужен просто индикатор все ли точки уже на карте или еще нет.

Спасибо!

 

UPD.

Нашел способ:

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

 

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

1 комментарий
прелоадер,LoadingObjectManager,API 2.1
RemoteObjectManager, LoadingObjectManager - остановить и очистить, события загрузки данных
remitmaster
11 января 2015, 17:23

 

Приветствую.

 

Вопрос 1

Стоит задача при смене зумов на карте показывать разные объекты со своими видами меток и тд. Для увеличения производительности и плавного показа меток при смене рабочей области используется RemoteObjectManager, не получается очищать и останавливать. 

LoadingObjectManager.objects - возвращает коллекцию объектов, но этого тоже не достаточно, при применении метода removeAll() удаляются текущие метки, а нужно удалть все и останавливать загрузку при смене зоны видимости и зума. 


upd:

Нашел только вот такой способ очистить и остановить RemoteObjectManager

// очищаем коллекцию

remoteObjManagerCity.objects.removeAll();

// удаляем саму коллекцию 

map.geoObjects.remove(remoteObjManagerCity); 



 

Вопрос 2

Почему не работает указания preset при создании объекта?

 

ymaps.ready(init);

function init () {

    var myMap = new ymaps.Map('map', {center: [55.76, 37.64], zoom: 10 }),

        objectManager = new ymaps.ObjectManager({ ... },

        {

           // не работает

            preset : 'islands#greenDotIcon'    

        });


    // Работает

    //objectManager.objects.options.set('preset', 'islands#greenDotIcon');

}

 

Вопрос 3

RemoteObjectManager, RemoteObjectManager,  делает запросы при измении зума и видимой области, почему нет событий начала загрузки и окончания загрузки данных,

если медленные запросы то нужно показывать загрузку в виде "ajax loader" 



Спасибо


 

8 комментариев
Preset,LoadingObjectManager,API 2.1,RemoteObjectManager
ObjectManager в API Яндекс.Карт
a.chebotareov
19 ноября 2014, 19:31

Как быстро отрисовать 10000 меток на карте и не затормозить всё вокруг. Как и зачем мы делали ObjectManager — читайте в новой статье на Хабрахабре. Автор статьи — создатель модуля и руководитель группы разработки визуальных компонент API Карт, Марина Степанова.

Перед разработчикам, которые используют API Яндекс.Карт, довольно часто встаёт задача отобразить много объектов на карте. Действительно много — порядка 10 000. Причем эта задача актуальна и для нас самих — попробуйте поискать аптеки на Яндексе. На первый взгляд кажется: «А в чем собственно проблема? Бери да показывай». Но пока не начнешь этим заниматься, не поймешь, что проблем на самом деле целый вагон.

Вопросы по большому количеству меток с завидной регулярностью поступают в наш клуб и техподдержку. Кто все эти люди? Кому может быть интересно показать на карте больше 10 меток? В этом посте я подробно рассмотрю весь вагон проблем и расскажу, как в API появились инструменты, помогающие разработчикам оптимально показать большое количество объектов на карте.

В основном с проблемой сталкиваются информационные сервисы, которые хотят привязать данные к карте. Например сайт bankomator.ru рассказывает пользователям, где найти банкомат нужного банка.

03c40157090c4d039fe324e23a684591.png

Также от большого количества данных страдают ресурсы, посвященные недвижимости. Яркий пример – Cian.ru.

Мы сами внутри Яндекса до недавнего времени советовали смежным командам различные «хаки» и приемы для показа множества точек через API. Яркие примеры – Яндекс.Недвижимость и Яндекс.Такси.

Пункт 1. В чем собственно проблема?

Чтобы прочувствовать на себе всю тяжесть поставленной задачи, нужно попробовать ее решить. Для начала давайте поймем, как показать карту на странице вашего сервиса. Рассмотрим простую схему:

33e83ec6f56341a79c0adb1de12f9b1a.png

Клиент (например, Safari на iPhone) запрашивает с сервера страницу index.html. Страница представляет собой документ вот с таким кодом:

<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <script src="//api-maps.yandex.ru/2.1/?lang=ru_RU" type="text/javascript"></script>
    <script type="text/javascript">
        ymaps.ready(init);

        function init () {
            var myMap = new ymaps.Map('map', {
                center: [55.76, 37.64],
                zoom: 10
            });
        }
    </script>
</head>
<body>
    <div id="map"></div>
</body>

Теперь усложняем задачу. У нас есть база данных, в которой хранятся адреса болельщиков «Зенита». И мы хотим показать на карте адреса этих болельщиков.


Решение задачи «в лоб»:

  • Делаем выборку из базы данных, получаем 1 млрд адресов.
    • Дописываем в файл index.html массив, содержащий весь миллиард адресов.
    • Передаем этот файл на клиент.
  • На киенте перебираем данные массива и рисуем для каждого элемента метку на карте.

Если вы менеджер проекта, и ваш разработчик демонстрирует такое решение, скорее всего, вы поседеете. Вы выскажете ему свое оценочное суждение. Если убрать нецензурную брань, можно будет выделить следующие тезисы:

    • Вес файла index.html увеличится до нескольких Мб и у пользователя страница будет открываться по несколько секунд.
    • Зачем передавать на клиент ВСЮ базу, если нужно показать только метки для Москвы?
    • Зачем рисовать на карте ВСЕ метки, если человек увидит только десятую их часть?
    • Если на карте нарисовать около 100-200 меток обычным способом, карта будет тормозить.
  • Можно загружать метки постепенно, пачками, чтобы канал не забивался и браузер успевал эти метки отрисовывать?

Мысль получает два направления:

      1. Нужно уметь определять, какие данные видит пользователь и запрашивать только нужное.
      2. Когда это нужное пришло, его надо оптимально отрисовать.

В API Яндекс.Карт сто лет назад был сделан инструмент для решения этих задач – технология активных областей. Кому интересно подробно, почитайте руководство разработчика. 

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

С помощью хотспотов, например, рисуются пробки на maps.yandex.ru. На этой же технологии сделан сайт bankomator.ru.

У этой технологии есть несколько существенных минусов

1. Очень сложная серверная часть. Попробуйте на досуге написать модуль, который генерирует вот такие картинки и их геометрические описания, и вы все поймете.

fba4da37164742cdbf44a645228ee962.png

2. Абсолютная негибкость. Невозможно «приподнять» метку при наведении на нее курсора. Невозможно быстро поменять на клиенте внешний вид меток. Короче – на любой чих надо просить сервер перегенерировать картинку.

Поэтому пользователи крутились, как могли, без хотспотов – передавали наборы единичных объектов на клиент пачками, через таймаут. При этом на клиенте их снова ждали проблемы. Если вы передали на клиент 1000 точек, как их отрисовать?

Из каждой точки нужно было сгенерировать объект ymaps.Placemark и добавить его на карту. Можно было добавить метки в кластеризатор (ymaps.Clusterer) и добавить откластеризованные метки на карту. Тут надо обратить внимание, что при кластеризации 10 000 точек нужно сначала эти 10 000 точек инстанцировать, а потом передать в кластеризатор. То есть метка может не показаться на карте, так как войдет в кластер, но мы все равно потратим время на ее инициализацию.

Подытожив все эти дела, мы решили написать модуль, который бы позволил:

    1. Быстро и легко отрисовать на клиенте большое количество точек.
    2. Избежать лишних инициализаций при работе с точками на клиенте.
    3. Загружать данные на клиент строго по требованию.

И мы это сделали. Мы котики.

Пункт 2. Рисуем метки быстро

Чтобы научиться рисовать метки быстро, надо было понять, какие проблемы кроются в текущем, уже существующем решении. Давайте посмотрим, что может делать объект ymaps.Placemark:

    1. Он умеет рисоваться на карте.
    2. У него есть свой менеджер балуна placemark.balloon.
    3. У него есть свой менеджер хинта placemark.hint.
    4. У него есть редактор, который позволяет перетаскивать метку и фиксировать ее координаты placemark.editor.

Кроме того, метка динамически реагирует на любое изменение внешней среды – изменение опций, данных, проекции карты, смена масштаба карты, смена центра карты и многое, многое другое. Такие вот у нас могучие плейсмарки.

А нужна ли вся эта программная мощь для случая, когда разработчику просто нужно показать много однотипных меток на карте? Правильно, не нужна.

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

Второе озарение пришло, когда мы думали над проблемой лишних программных инициализаций. Вспоминаем рассказ выше, где-то в районе вот такой картинки.

Нам захотелось избавиться от лишних программных инициализаций, и мы придумали гениальное. Садитесь поудобнее, сейчас будет откровение: если вам мешают лишние программные инициализации – не делайте их.

 

Мы решили, что будем хранить пользовательские данные об объектах (по факту в JSON), а программные сущности для объектов будут создаваться только тогда, когда какой-либо объект нужно будет отрисовать на карте.

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

На вход этого менеджера скармливается JSON-описание объектов.

Менеджер анализирует, какие метки попадают в видимую область карты и либо рисует метки, либо кластеризует эти метки и показывает результат на карте.

Для отрисовки меток и кластеров на карте мы взяли только часть объектаymaps.Placemark (а именно ymaps.overlay.*), которая отвечала только за отображение метки на карте. Всю инфраструктуру типа балунов и хинтов мы вынесли в единый общий компонент.

Эти приемы позволили нам неплохо продвинуться в вопросе отрисовки большого числа меток на клиенте. Вот какие мы получили приросты по скорости:

1d8d3157f4324a66b46c2381296a6be7.png

График 1. Скорость создания и добавления объектов на карту с последующей асинхронной отрисовкой их видимой части

    1. Создание 1000 меток и добавление их на карту, все метки видны.
    2. Создание 1000 меток и добавление их на карту с кластеризацией, все метки видны.
    3. Создание 10000 меток и добавление их на карту с кластеризацией, все метки видны.
    4. Создание 50 000 меток и добавление их на карту с кластеризацией, все метки видны.
    5. Создание 50 000 меток и добавление их на карту с кластеризацией, видны 500 объектов.
    6. Создание 50 000 меток и добавление их на карту без кластеризации, видны 10 000.

 1b06d3c0650c43949bb45a2ee88dbec0.png

График 2. Скорость создания и добавления объектов на карту с последующей синхронной отрисовкой их видимой части

  1. Создание 1000 меток и добавление их на карту, все метки видны.
  2. Создание 1000 меток и добавление их на карту с кластеризацией, все метки видны.
  3. Создание 10000 меток и добавление их на карту с кластеризацией, все метки видны.
  4. Создание 50 000 меток и добавление их на карту с кластеризацией, все метки видны.
  5. Создание 50 000 меток и добавление их на карту с кластеризацией, видны 500 объектов.
  6. Создание 10 000 меток и добавление их на карту без кластеризации, видны 2000.
  7. Создание 5000 меток и добавление их на карту без кластеризации, видны 1000.

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

У нас получилось ускорить непосредственно создание и отрисовку объектов, вдобавок к этому мы максимально оптимизировали инициализацию программных сущностей. Теперь вы можете, например, откластеризовать на клиенте 50 000 точек, и работать с картой будет комфортно.

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

Итак, мы научились быстро-быстро рисовать и кластеризовать точки на клиенте. Что дальше?

Пункт 3. Оптимально подгружаем данные

Помните пример про болельщиков «Зенита»? Мы решили проблему отрисовки данных на клиенте, но никак не решили проблему, связанную с оптимальной подгрузкой этих данных. Мы начали собирать типовые задачи пользователей API. По итогам исследований мы получили два типовых кейса:

  • У человека на сервере много данных, он хочет показывать их на клиенте, но подгружать данные по мере надобности.
  • Разработчик подготавливает данные на сервере (например, реализует серверную кластеризацию) и хочет показывать на клиенте результаты этой обработки.

Для решения этих кейсов были написаны модули LoadingObjectManager и RemoteObjectManager соответственно.Оба модуля основаны по сути на реализации ObjectManager, но имеют ряд различий в алгоритме загрузки и кеширования загруженных данных.

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

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

Теперь обсудим вариант номер два – отображение на клиенте результатов серверной кластеризации. Допустим, вы написали серверную кластеризацию меток. Также вы написали скрипт, который по запросу от клиента умеет отдавать кластеры и единичные метки, не вошедшие в состав кластера.

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

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

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

Пункт 4. Размышления на тему серверной реализации

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

1. Хранение информации об объектах на сервере в статических файлах

Клиентский код оперирует данными исключительно потайлово. Тайл – это некоторая нумерованная область на карте. Подробнее про нумерацию тайлов можно прочитать в нашей документации.

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

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

zoom=0, tile=[0, 0]
zoom=1, tile=[0, 0]
zoom=1, tile=[0, 1]
zoom=1, tile=[1, 0]
zoom=1, tile=[1, 1]
zoom=2, tile=[0, 0]
…

Поскольку запросы известны заранее, ответы на запросы тоже можно сгенерировать заранее. Организуем на сервере какую-то такую файловую структуру.

В файлах будет храниться примерно такой код:

myCallback_x_1_y_2_z_5({
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "id": 0,
      "geometry": {
        "type": "Point",
        "coordinates": [55.831903, 37.411961]
      },
      "properties": {
        "balloonContent": "Содержимое балуна",
        "clusterCaption": "Метка 1",
        "hintContent": "Текст подсказки"
      }
    },
    ...
  ]
}

При загрузке такого файла на клиенте будет вызван JSONP-callback, прописанный в файле. Данные попадут в недры LoadingObjectManager, закешируются и отрисуются в нужном виде.

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

2. Динамическое формирование ответа из статических файлов

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

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

3. Динамическое формирование ответа с использованием базы данных

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

Вообще хранение геопривязанных данных на сервере и их кластеризация – тема отдельной беседы. Так что обсудим в другой раз.

В этом репозитории живет пример реализации серверной части с серверной grid-кластеризацией, написанный на node.js + mongo.db. может кому-то пригодится (Демо).

Заключение

Сравнительная таблица новых модулей. 

МодульПреимуществаНедостатки
ObjectManagerПозволяет кластеризовать объекты на клиенте.

Отрисовка производится только тех объектов, которые попадают в видимую область карты.

Позволяет фильтровать объекты при их отображении.

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

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

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

Сохраняет загруженные данные. Для каждого объекта данные загружаются только один раз.

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

Кластеризация объектов производится на стороне клиента.

Необходимо реализовать серверную часть.
RemoteObjectManagerИспользует серверную кластеризацию данных.

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

При изменении коэффициента масштабирования данные загружаются заново (даже для тех объектов, для которых данные уже были загружены).

Необходимо реализовывать собственную кластеризацию.

Необходимо реализовать серверную часть.


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

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

Полезные ссылки:

    1. Подробнейшее руководство разработчика с картинками –tech.yandex.ru/maps/doc/jsapi/2.1/dg/concepts/many-objects-docpage/.
    2. Примеры в песочнице – tech.yandex.ru/maps/jsbox/2.1/object_manager
    3. Проект на гитхабе с примером реализации серверной части для RemoteObjectManager – github.com/dimik/geohosting-server.
    4. Клуб разработчиков API Яндекс.Карт, куда нужно приходить с вопросами –clubs.ya.ru/mapsapi.

1 комментарий
API 2.1,новости,LoadingObjectManager,ObjectManager,статьи,RemoteObjectManager
Задержка в отображении точки на карте
Александр Мартынов
10 октября 2014, 13:55

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

В ходе освоения технологии LoadingObjectManager я столкнулся с проблемой задержки в отображении точки на Яндекс.Карте. Вот работающий пример - http://snsd.ru/node/1935. Единственная точка появляется на карте с задержкой аж в 30 секунд, хотя судя по debug-информации jsonp-файл с тайлом успешно загружается практически сразу. Помогите, пожалуйста, разобраться в чем дело.

5 комментариев
LoadingObjectManager,JSON