company_banner

Яндекс.Карты меняют API. Почему нам понадобилось ломать обратную совместимость в кластеризаторе

    Я работаю в Яндексе, у Яндекса есть карты, а у карт есть API. API – вещь, которая позволяет встроить карты Яндекса на свой сайт. С версии 2.0 наш API умеет кластеризовать метки на клиенте. Вот как выглядят метки до и после кластеризации:

    image

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

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

    Содержание статьи:
    1. Отмена асинхронного добавления меток (этот пункт стоит прочитать тем, кто хоть как-то использовал метод objectsaddtomap).
    2. Изменение публичных методов кластеризатора.
    3. Изменение способа разбиения карты на тайлы (может никто и не заметит).
    4. Переименование сущности Cluster в ClusterPlacemark (скорее всего никто не заметит).
    5. Изменения в clusterer.balloon и clusterer.hint (стоит прочесть, если вы использовали балуны кластера или хотели добавить кластерам хинты).
    6. Задание произвольных иконок кластеров – что нового (стоит читать, если… а ну тут и так понятно).
    7. Небольшая доработка опции preset или как изменить цвет кластера при наведении.
    8. Префиксирование опций для кластеров и меток в составе кластера.
    9. Сводная таблица различий в коде.
    10. Сравнение скорости работы версий (для убедительности статьи).

    Отмена асинхронного добавления меток.


    В версии 2.0 геообъекты создавались, добавлялись на карту и отрисовывались сразу, в одном потоке. Чем слабее браузер, чем больше объектов вы добавляли на карту, тем больше была вероятность увидеть сообщение.
    image
    Такую ситуацию наш разработчик Антон называет научным термином «залипон».

    Кластеризатор начинают использовать, когда количество меток на карте много. Когда объектов много, появляется проблема этих самых залипонов. Нужно было что-то решать, и в кластеризаторе было решено по умолчанию сделать асинхронное добавление объектов на карту. Понять, что объекты добавились на карту, можно было по событию objectsaddtomap. Вот так выглядит один из примеров для версии 2.0.

    // Открытие балуна кластера с выбранным объектом.
    
    // Поскольку по умолчанию объекты добавляются асинхронно,
    // обработку данных можно делать только после события, сигнализирующего об
    // окончании добавления объектов на карту.
    cluster.events.add('objectsaddtomap', function () {
    
        // Получим данные о состоянии объекта внутри кластера.
        var geoObjectState = cluster.getObjectState(myGeoObjects[1]);
        
        // Проверяем, находится ли объект находится в видимой области карты.
        if (geoObjectState.isShown) {
            // Если объект попадает в кластер, открываем балун кластера с нужным объектом.
            if (geoObjectState.isClustered) {
                geoObjectState.cluster.state.set('activeObject', myGeoObjects[1]);
                geoObjectState.cluster.balloon.open();
    
            } else {
                // Если объект не попал в кластер, открываем его собственный балун.
                myGeoObjects[1].balloon.open();
            }
        }
    });

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

    В версии 2.1 мы шагнули в сторону разделения объектов и их отображения на карте. Кто-то мог заметить, что методы getOverlay стали асинхронными и неудобными – вот это как раз оно. В действительности асинхронная отрисовка макетов – это отличный способ оптимизировать процесс добавления объектов на карту.

    Чтобы лучше понимать суть вещей, посмотрим на путь метки от ее создания до появления на карте. Процесс можно разбить на три этапа:
    • Создание инстанции класса
    • Добавление объекта на карту
    • Отрисовка макета метки в HTML

    По первому пункту, думаю, пояснения не нужны. Не очень понятно, чем отличаются этапы два и три. Добавление объекта на карту – это процесс, при котором метка прикрепляется к родительской коллекции (чаще всего к map.geoObjects). Метка получает от этой коллеции некоторые опции, в том числе проекцию карты. После того, как объект метки узнает, в какой проекции отрисована карта, он может спроецировать свою геометрию на плоскость (что и делает). После проецирования координат метки на плоскость становится понятно, в какой пиксельной точке экрана надо нарисовать значок метки. В этот момент этап два завершается.

    Третий этап является как раз процессом рисования метки на карте в определенной пиксельной координате. В версии 2.1 мы выполняем первые два этапа синхронно, в одном потоке. А вот отрисовку объекта делаем по таймауту.

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

    Другими словами, для перехода на версию 2.1.4 нужно будет убрать из кода подписку на событие objectsaddtomap. Весь код внутри обработчика этого события теперь можно выполнять сразу синхронно после добавления объектов в кластеризатор. (В конце статьи я приведу таблицу с примерами в формате “стало-было”, кому неинтересно читать дальше – можете сразу переходить к ней.)

    Изменение публичных методов кластеризатора


    В версии 2.0 кластеризатор являлся наследником объекта ymaps.Collection. Он наследовал от коллекции методы add, remove, setParent и прочие нужные, а также each, getIterator и прочие ненужные (я поясню, почему эти методы были ненужными). Казалось, что кластеризатор вполне себе коллекция – в него можно добавлять объекты и удалять объекты обратно. Но кластеризатор мало того что содержит в себе какие-то элементы, он эти элементы может показывать или не показывать на карте, а также сам генерирует дополнительные объекты-кластеры.

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

    Теперь кластеризатор имеет простые и понятные публичные методы для доступа к объектам.
    • Clusterer.getGeoObjects — возвращает массив элементов, добавленных в кластеризатор
    • Clusterer.getClusters — возвращает массив кластеров, в данный момент добавленных на карту. Обратите внимание, что это не все кластера, а только видимые в данный момент времени.

    Примеры работы с этими методами ищите в нашей документации.

    Изменение способа разбиения карты на тайлы


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

    Карта разбивалась на квадратные ячейки. Метки, попадающие в одну ячейку, образовывали кластер. Для того чтобы не вызывать вычисления при каждом маленьком драге карты, ячейки объединялись в более крупные квадраты, которые мы называли «кластерные тайлы». Обрабатывались все кластерные тайлы, в которые полностью или частично попадала видимая область карты.

    image

    В этой версии мы решили не вводить путаницу в понятие слова «тайл». Теперь кластерные тайлы находятся точно там же, где и обычные карточные тайлы и всегда имеют размер 256х256 пикселей. Из этого следует ограничение – размер ячейки кластеризации должен быть а) не больше 256 и б) в тайл должно умещаться целое количество ячеек кластеризации. То есть допустимые значения для размеров ячейки кластеризации 2, 4, 8, 16, 32, 64, 128 и 256.

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

    Поскольку тайлы имеют небольшой размер и, вообще говоря, граница карты может совпадать с границей тайла, мы ввели дополнительный отступ для видимой области карты – mapViewport (по умолчанию 128 пикселей). То есть всегда обрабатывается немного больше, чем нужно. Зато пользователь скорее всего не заметит перестроений при перемещении карты.

    Переименование Cluster в ClusterPlacemark


    Я всегда подозревала, что никто, кроме пары человек (я и наш документатор Олеся), не может слету сказать, чем отличается Cluster от Clusterer (если вы понимаете разницу, вы большой молодец).
    • Clusterer — кластеризатор объектов, что-то вроде коллекции.
    • Cluster – группа объектов, сгенерированная кластеризатором. На карте смотрится как метка.

    Мы изучили количество переходов на разные страницы документации – страницы Clusterer и Cluster пользуется большой популярностью. И я подозреваю, что люди, кликающие на Cluster – жертвы жестокости и непонимания. Именно поэтому было решено переименовать сущность Cluster в ClusterPlacemark. Когда смотришь на Clusterer и ClusterPlacemark вроде бы становится понятнее, что к чему.

    Поскольку в клубе API Карт не проявлялись люди, пользующиеся кластерами отдельно от кластеризатора (следите за суффиксами), это изменение должно пройти абсолютно незамеченным. А ошибочные клики в документации на Cluster вместо Clusterer должны уйти в далекое прошлое. Тем не менее, если вам нравилось читать документацию к объекту Cluster и ее потерю воспримете, как потерю близкого друга, читайте документацию к ClusterPlacemark.

    Изменения в clusterer.balloon и clusterer.hint


    Начну с приятного – мы наконец добавили возможность показывать всплывающую подсказу к метке кластера. Делать это можно вот таким кодом:
    var clusterer = new ymaps.Clusterer();
    clusterer.createCluster = function (center, geoObjects) {
        // Создаем метку-кластер с помощью стандартной реализации метода. 
        var clusterPlacemark = ymaps.Clusterer.prototype.createCluster.call(this, center, geoObjects),
            geoObjectsLength = clusterPlacemark.getGeoObjects().length,
            hintContent;
        if (geoObjectsLength < 10) {
            hintContent = 'Мало меток';
        } else if (geoObjectsLength < 100) {
            hintContent = 'Нормально так меток';
        } else {
            hintContent = 'Меток навалом';
        }
        clusterPlacemark.properties.set('hintContent', hintContent);
        return clusterPlacemark;
    };

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

    Теперь про изменение хинтов и балунов в целом. Для работы с балунами в версии 2.0 у каждого кластера создавалось поле .balloon. Открытие балуна выглядело как cluster.balloon.open();.

    Недостатком этого решения являлась низкая скорость исполнения кода. Ведь если у вас 100 кластеров, у каждого из них может быть балун, а значит каждому кластеру нужно создать и приписать менеджер балуна в поле cluster.balloon. Поэтому в рамках работ по скорости было решено сделать один менеджер балунов и хинтов на кластеризатор. Теперь балун на кластере можно открыть так:
    // Открыть балун на конкретной метке-кластере.
    clusterer.balloon.open(clusterPlacemark);
    

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

    Задание произвольных иконок кластеров – что нового


    В версии 2.0 все геообъекты были равны. Но некоторые были равнее. Метки, отрисованные на canvas, обретали интерактивность с помощью активных областей. Метки, отрисованные с помощью DOM, были интерактивными сами по себе. Это рождало различия в поведении и массу неудобств.
    Поэтому в версии 2.1 было решено все объекты унести под горизонт событий (что бы это ни значило). Теперь все метки становятся интерактивными за счет активных областей, наложенных поверх карты. Из-за этого для меток теперь нужно указывать, какой формы и размера должна быть активная область над меткой (при наведении на какую часть картинки курсор должен меняться, метка должна кликаться и ховериться).

    Стандартные метки-кластеры имеют 3 вида картинок – большие, средние и маленькие. Эти картинки круглые. Если вы попробуете поводить мышкой над меткой кластера, вы увидите, что активная область метки совпадает с картинкой и является тоже кругом.

    imageimageimage

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

    Мы это поправили и теперь вы можете самостоятельно определять форму активной области для метки. Делать это можно так (пример для круглых меток).

    clusterer.options.set({
        clusterIcons: [
            {
                href: ‘images/small.png’,
                size: [20, 20],
                offset: [-10, -10],
                shape: new ymaps.shape.Circle(new ymaps.geometry.pixel.Circle([0, 0], 10))
            },
            {
                href: ‘images/medium.png’,
                size: [30, 30],
                offset: [-15, -15],
                shape: new ymaps.shape.Circle(new ymaps.geometry.pixel.Circle([0, 0], 15))
            }, 
            {
                href: ‘images/big.png’,
                size: [40, 40],
                offset: [-20, -20],
                shape: new ymaps.shape.Circle(new ymaps.geometry.pixel.Circle([0, 0], 20))
            }
         ]
    });
    

    Код получился не очень простой, поэтому есть альтернативный подход – попроще, но погрубее. Если вы не задаете параметр shape при описании иконок, активной станет прямоугольная область над иконкой, которая сформируется на основе параметров size и offset. То есть вот такой код тоже будет работать нормально, просто кликабельной будет прямоугольная область вокруг иконки.
    image
    Картинка сложная, поэтому не заморачиваемся и делаем интерактивной прямоугольную область вокруг иконки. Выбирайте решение в зависимости от степени вашего перфекционизма.

    clusterer.options.set({
        clusterIcons: [
            {
                href: ‘images/small.png’,
                size: [20, 20],
                offset: [-10, -10]
            },
            {
                href: ‘images/medium.png’,
                size: [30, 30],
                offset: [-15, -15]
            },
            {
                href: ‘images/big.png’,
                size: [40, 40],
                offset: [-20, -20] 
            }
         ]
    });
    


    Еще одно небольшое дополнение. Если вы не хотите показывать содержимое внутри метки кластера, можно выставить опцию clusterIconContentLayout в null и метка будет показываться без цифр внутри clusterer.options.set(‘clusterIconContentLayout’, null);

    Небольшая доработка preset для кластера


    В клубе API Карт попадались вопросы на тему «как задать стиль для конкретного кластера». На этот вопрос не было хорошего ответа, так как указанные в описании option.presetStorage ключи работали только если их задавать кластеризатору целиком. А для одиночных меток эти ключи не подходили. В этой версии ключи стали универсальными – подходят как для кластеризатора целиком, так и для меток-кластеров в частности.

    Изменить цвет кластера при наведении можно вот так.
    clusterer.events.add(‘mouseenter’, function (e) {
        var target = e.get(‘target’);
        if (typeof target.getGeoObjects == ‘function’) {
             target.options.set(‘preset’, ‘islands#redClusterIcons’);
        }
    });
    clusterer.events.add(‘mouseleave’, function (e) {
        var target = e.get(‘target’);
        if (typeof target.getGeoObjects == ‘function’) {
             target.options.set(‘preset’, ‘islands#blueClusterIcons’);
        }
    });


    Префиксирование опций для кластеров и меток в составе кластера


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

    В частности, в версии 2.0 можно было сделать так: clusterer.options.set(‘cursor’, ‘help’); И вид курсора менялся как для одиночных объектов, так и для меток-кластеров.

    Пытливый читатель спросит с прищуром: «А что если я хочу задать разные типы курсоров для меток-кластеров и одиночных меток?» Этот случай мы предусмотрели и решили, что метки-кластеры также будут понимать опции, которые имеют префикс «cluster».

    clusterer.options.set({
        // Сработает для геообъектов.
        сursor: ‘pointer’,
        // Сработает для меток-кластеров.
        clusterCursor: ‘help’
    });


    В этой системе все было прекрасно, кроме случая, когда вы хотели кастомизировать только одиночные метки, не затрагивая метки-кластеры. Если вы хотели поменять только опции для одиночных меток, вы писали clusterer.options.set(‘cursor’, ‘help’); И получали слишком массовый эффект – опции распространялись и на одиночные объекты, и на метки-кластеры. То есть если вы хотели повлиять только на одиночные метки, опции приходилось задавать все равно и для одиночных объектов, и для кластеров.

    В версии 2.1 стало чуть удобнее. Теперь все опции для дочерних объектов задаются с префиксами. Для меток-кластеров c префиксом ‘cluster’, для одиночных меток – с префиксом ‘geoObject’. Теперь опции дочерних объектов не зависят друг от друга. Задавайте, какие больше нравится.

    // Сработает только для одиночных меток и не тронет кластеры.
    сlusterer.options.set(‘geoObjectCursor’, ‘help’);


    Сводная таблица изменений

    Было Стало
    // Пример 1. Открытие балуна кластера c выбранным объектом.
    
    // Поскольку по умолчанию объекты добавляются асинхронно, 
    // обработку данных можно делать только после события, сигнализирующего об 
    // окончании добавления объектов на карту. 
    clusterer.events.add('objectsaddtomap', function () {      
      // Получим данные о состоянии объекта внутри кластера.     
      var geoObjectState = clusterer.getObjectState(myGeoObjects[1]);     
      // Проверяем, находится ли объект в видимой области карты.    
      if (geoObjectState.isShown) {
        // Если объект попадает в кластер, открываем балун кластера с нужным выбранным объектом. 
        if (geoObjectState.isClustered) { 
          geoObjectState.cluster.state.set('activeObject', myGeoObjects[1]);
          geoObjectState.cluster.balloon.open(); 
        } else {
          // Если объект не попал в кластер, открываем его собственный балун.
          myGeoObjects[1].balloon.open(); 
        }
      }
    });
        

    // Пример 1. Открытие балуна кластера c выбранным объектом.
    
    // Получим данные о состоянии объекта внутри кластера.
    var geoObjectState = clusterer.getObjectState(myGeoObjects[1]);  
    // Проверяем, находится ли объект в видимой области карты. 
    if (geoObjectState.isShown) { 
      // Если объект попадает в кластер, открываем балун кластера с нужным выбранным объектом. 
      if (geoObjectState.isClustered) {
        geoObjectState.cluster.state.set('activeObject', myGeoObjects[1]);
        clusterer.balloon.open(geoObjectState.cluster); 
      } else {
        // Если объект не попал в кластер, открываем его собственный балун.
        myGeoObjects[1].balloon.open();
      }
    }
    
    //  Пример 2. Изменение цвета иконки-кластера.
    
    var options = ymaps.option.presetStorage.get(‘islands#redClusterIcons’);
    cluster.options.set({
       icons: options.clusterIcons,
       iconContentLayout: options.clusterContentLayout
    });
        
    //  Пример 2. Изменение цвета иконки-кластера.
    
    cluster.options.set('preset', 'islands#redClusterIcons');
    
    // Пример 3. Создание меток-кластеров без содержимого.
       
    clusterer.options.set(‘clusterIconContentLayout’, ymaps.templateLayoutFactory.createClass(‘’));
    
    // Пример 3. Создание меток-кластеров без содержимого.
    
    clusterer.options.set(‘clusterIconContentLayout’, null);
    
    // Пример 4. Указание опций для объектов в составе кластера.
    сlusterer.options.set({
       clusterBalloonLayout: myClusterBalloonLayout,
       balloonLayout: myPlacemarkBalloonLayout
    });
        
    сlusterer.options.set({
       clusterBalloonLayout: myClusterBalloonLayout,
       geoObjectBalloonLayout: myPlacemarkBalloonLayout
    });
    

    В остальном все осталось без изменений. Все новшества описаны в документации.

    Сравнение скорости работы кластеризатора в версиях 2.0.36 и 2.1.4


    Лучше один раз увидеть, чем один раз прочитать и не поверить. Как проводились измерения. За образец был взят вот такой кейс:
    <!doctype html>
    <html>
      <head>
        <title> Скорость работы кластеризатора</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <script src="http://api-maps.yandex.ru/2.0.36/?load=package.full &lang=ru-RU&ns=ym" type="text/javascript"></script>
        <script type="text/javascript">
          ym.ready(function() {
            var map = new ym.Map('map', {
                center: [55.755381, 37.619044],
                zoom: 13
              }),
              coords = [],
              center = [55.755381, 37.619044],
              placemarks = [],
              i;
    
            for (i = 0; i < 10000; i++) {
              coords[i] = [
                center[0] + 0.5 * Math.random() * Math.random() * Math.random() * (Math.random() < 0.5 ? -1 : 1),
                center[1] + 0.7 * Math.random() * Math.random() * Math.random() * (Math.random() < 0.5 ? -1 : 1)
              ];
            }
            var startTime = +new Date();
            for (i = 0, l = coords.length; i < l; i++) {
              placemarks[i] = new ym.GeoObject({
                geometry: {
                   type: "Point",
                   coordinates: coords[i]
                }
              });
            }
    
            var clusterer = new ym.Clusterer();
            clusterer.add(placemarks);
            map.geoObjects.add(clusterer);
            var stopTime = +new Date();
           
            alert(stopTime - startTime); 
         });
    
        </script>
      </head>
      <body>
        <div id="map" style="height: 400px; width: 800px;"></div>
      </body>
    </html>
    


    Этот кусок кода не затрагивает моментов, в которых сломана обратная совместимость, поэтому его можно запускать как в версии 2.0.36, так и в версии 2.1.4 без изменений, просто переключая ссылку на версию API. Время измерялось в миллисекундах.
    image
    Хочу сделать ремарку по поводу IE11. Тесты для всех браузеров запускались на моем ноутбуке, а для IE11 на другом ноутбуке с Windows (у меня macbook). Так что сравнивать скорость его работы с остальными браузерами по этому графику не стоит. А вот оценивать, насколько ускорилось апи от версии к версии, стоит.

    Важно понимать – мы сократили только время инициализации карты с кластеризатором и метками. Браузер выполняет код, выдыхает, и потом может вернуться к отрисовке объектов. Общая нагрузка при этом не сильно поменялась – она лишь распределилась по времени, часть действий выполняется позже. Тем не менее, это важно для слабых браузеров – то, что они не могли сделать в одном потоке сразу и висли, теперь распределено по времени и браузеры могут такую нагрузку осилить.

    Заключение


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

    Сейчас мы получили немного свободы в связи с выходом новой версии 2.1. Конечно, хотелось изменить еще больше, но нас снова сдерживало то, что мы можем менять только по мелочам (это все же 2.1, а не 3.0).
    Мы надеемся, что нововведения хотя бы немного помогут вам в разработке и польза перекроет неудобства от необходимости переписывать код.

    Мне сказали, что у статьи должна быть позитивная концовка, поэтому поздравляю всех с наступающим!
    Яндекс 511,76
    Как мы делаем Яндекс
    Поделиться публикацией
    Похожие публикации
    Комментарии 41
    • –9
      Здорово!
      Вот только о своих планах отломать все обычно предупреждают заранее и дают тестовый билд «на поправить к будущему релизу» (В идеале).
      • +15
        Простите, промелькнул глазами строчку, что предупреждали.
        • 0
          Тут недавно статья была о том, что IE — сплошный костыль.

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

          Эх.
          • +8
            Я напоминаю, что речь идет о бета-версии. В обычных версиях мы себе такого хулиганства не позволяем)
            • +1
              Спасибо за напоминание!
              Я правильно понял, как бета станет релизом — останется возможность сидеть на старой версии какой-либо? (судя по комментарию ниже).
              • +6
                Когда бета станет релизом, мы об этом напишем и напишем срок, когда закроем версии беты. То есть если вы используете бету, вам нужно будет перевести свой код на продакшен-вариант в течение какого-то времени после «разбечивания». Вечно хранить у себя версии беты мы не планируем.
          • +2
            Во-первых, мы предупреждали.
            Во-вторых изменения не такие уж масштабные. Обновление беты было в четверг, пока пожаловались только единицы.
            Когда мы разбетимся, естественно, никаких таких сюрпризов не будет.
            Ну и если вы сидите на бете и не хотите под нас подстраиваться — всегда можно подключить конкретную версию беты, например 2.1.3 вместо 2.1-dev.
          • –4
            Выглядит весьма неплохо, но хотелось бы, чтобы алгоритм работы кластеризатора был все же «по-умнее». Как-то не вяжется у меня Яндекс и «разбили на квадратики и посчитали сколько меток попадет в квадратик».
            • +17
              Т.е. лучше бы написали «дискретно полигонный анализ карты с апроксимированной кластеризацией объектов»? Так сказать понятнее, что к делу подходили серьезно?
              • +8
                Отнюдь. Посмотрите на пример того, как «Стало»: есть перекрытия, как кластеров между собой, так и кластеров с метками. Хотелось бы, чтобы такие случаи разруливались и, в случае необходимости, объединялись. Тогда часть кластера, построенная по клеткам, но не попавшая в объединение, сформирует свой кластер и т.д.
                • +2
                  а чем плохи небольшие перекрытия кластеров?
                  • +6
                    На вкус и цвет, конечно, но мне не нравятся.
                    • +2
                      Можно задать отступы.
              • +4
                Нам тоже хочется сделать что-то посложнее. Но в то же время хочется, чтобы кластеризация на клиенте работала как можно быстрее.
                На момент написания алгоритма приборы показывали, что любой более сложный алгоритм ощутимо сказывается на времени исполнения клиентского кода. Мы решили, что в данном конкретном случае скорость важнее, чем сложность алгоритма.
                Сейчас картина немного поменялась — мы перестали поддерживать некоторые слабые браузеры, может быть в будущем и посмотрим в сторону усложнения алгоритмы.
              • +3
                А что за попугаи по оси Y в графике?
                • +2
                  Это милисекунды, спасибо за указание, сейчас напишу об этом
                  • +26
                    Странно что результаты Chrome и Яндекс.Браузера совершенно идентичны!
                    • +4
                      Вы тег irony забыли. Некоторые ведь и всерьез воспринять могут… :)
                      • +8
                        Попробуйте сравнить с Opera Next
                  • 0
                    Лучше бы сделали единое пространство закладок/меток на карте для смартфона и на компьютере для одного аккаунта Яндекса. А то мучаюсь: с начало забиваю метки на смартфоне, а потом на компьютере.
                    • +2
                      Если не секрет — каким образом, по-вашему, это замечание относится к API Карт?
                      • +1
                        API Карт — имеет прямое отношение к данной проблеме, так решение данной проблемы легче всего осуществить через API самой же Yandex
                        • 0
                          На компе забиваете в maps.yandex.ru? Так это «Карты Яндекса» — просто сайт использующий АПИ Карт Яндекса.
                          АПИ должен решать только свои задачи, как и любой другой нишевый инструмент.
                          • 0
                            Я хочу, чтобы была возможность, создать свою карту с закладками И использовать ее на сайте с применением API, на смартфоне Яндекс.Карты, на компе зайдя на maps.yandex.ru. На текущий момент такой возможности нет. А так я получается, что во всех ТРЕХ сферах должен забивать отдельно одни и те же закладки (бывает я их по 200 штук за день набиваю).

                            АПИ должен решать только свои задачи — поэтому и пишу, что не проще сразу везде реализовать единые метки/закладки, в тм числе и в АПИ
                            • 0
                              «Мои карты» пробовали? У них есть выгрузка в yml/kml, которую можно отобразить где-то далее.
                          • 0
                            Понятно, вопросов больше нет.
                      • +2
                        А когда планируется релиз нового API для яндекс.карт под iOS/Android?
                        • +2
                          Мы не можем вам ничего рассказать про ребят в мобильном направлении нас за это бьют. Но мы уже сами ждем-не дождемся)
                          • 0
                            Да, да, да. А то ваш API для iOS уже сильно устарел по сравнению с аналогами, а использовать хотелось бы
                        • 0
                          Когда исправите баг c svg-фоном в fillImageHref, который корректно отображается только в Сафари, плохо в Фаерфоксе и никак — в прочих браузерах?
                          • 0
                            Постараемся в ближайших релизах.
                            • 0
                              Я про такой баг, почему-то, не знаю. Можно описать проблему в личке или клубике?
                              Быть может и не баг.
                            • 0
                              Вопрос: начиная с какого количества объектов надо задумываться о кластеризации на сервере? В Вашем примере использовано 10 000 точек, отрисовка занимает секунду. Соответственно, 100 000 точек уже будут неюзабельными. Я правильно понимаю?
                              • +1
                                Я не могу точно назвать количество меток, при котором вам нужно переходить на серверную кластеризацию. Вот по какой причине.

                                Клиентское время уйдет на 4 вещи:
                                1. Загрузка списка точек с сервера на клиент
                                2. создание 100 000 меток.
                                3. кластеризация меток
                                4. добавление кластеров и одиночных меток на карту.

                                Пункт 1 зависит от формата, в котором вы передаете данные — тут ничего не могу сказать.
                                Пункт 2 всегда одинаковый для всех кейсов — тут понятно.
                                А вот пункты 3 и 4 сильно зависят от конкретных условий, а именно:
                                а) сколько объектов попадают в видимую область карты
                                б) сколько в результате меток и кластеров нужно добавить на карту

                                Если все 100 000 меток, грубо, попадут в 1 кластер, то может быть время в общем будет не так уж и велико.

                                В общем, нужно смотреть на конкретные кейсы, но при величинах порядка 100 000 объектов с большой вероятностью надо уже уносить на сервер.
                              • 0
                                А что про производительность в браузерах? Не смотрели? (В цифрах)
                                • 0
                                  Какая информация вас интересует, помимо представленной на графике?
                                  • 0
                                    Конкретно FPS в браузере при различных событиях. Можно конечно и самому посмотреть… Но может кому тоже интересно будет.
                                • +1
                                  Мы бы в своей компании потенциально хотели бы использовать Ваши карты в состав закрытой системы для отслеживания транспорта в реальном времени, плюс опрос времени пути по пробкам между двумя точками.
                                  Вы не планируете вводить подобные опции «для бизнеса»?
                                  • 0
                                    Спасибо за вопрос. Напишите пожалуйста мне на почту ache@yandex-team.ru, я маркетолог API Яндекс.Карт и смогу более детально ответить на ваш запрос.
                                  • 0
                                    К сожалению, я не знаю, какой принцип версионирования исользуется в API Карт, хотя 3 числа, разделенные точкой — это обычно Apache версионирование. В связи с этим вопрос: разве может API быть не backward compatible в рамках одной и той же мажорной версии (в данном случае это версия 2.x.x)?

                                    Логичнее тогда было бы назвать новый API 3.0.0-beta.
                                    • 0
                                      Про версионирование у нас есть отдельная страничка в документации. В 2.1 сделали много всего, где-то даже поломали чуть-чуть старые штуки, но архитектуру API особо не меняли, поэтому обновление на 3.0.0 не потянуло.

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

                                    Самое читаемое