Как стать автором
Обновить

Комментарии 30

Титаническая работа, сколько человеко-часов на это ушло? Полезно было бы это знать прежде чем браться повторять ваш путь.
Спасибо за вопрос. Точных чисел у меня, к сожалению, нет. Могу сказать так — путь от идеи до раскатки фичи занял около полугода, работала над задачей одна команда (но мы работали не только над этой фичей, конечно, у нас были и другие затратные задачи). Одна команда — все функции в количестве 1 человека.

Стоит отметить, что достаточно много времени занимали ресерчи и прототипы: мы смотрели, подойдет ли нам решение через тайлы, писали прототип на NodeJS, писали и переделывали кликабельность и ховер. Ну, и еще большой кусок ушел на оптимизацию бэкенда. Кроме того, мы делали не только веб-реализацию, но и мобилки.
На сколько я вижу, сейчас рисование в тайлах не используется, на фронт приходит массив точек и он сам его рисует. От подхода с тайловым слоем уже отказались? Или наоборот, еще не выкатили для всех?
Не отказались, фронт использует тайлы, по объектам рисует пины. Решение выкачено на всех.

Массив rash в ответе /map/marker нужен для того, чтобы сделать ховер и просмотренные точки. Если отфильтровать запросы по картинкам и /map/tiles — можно увидеть svg, которые отдаются с бэкенда.
Увидел, спасибо. Не обратил внимания, что тайлы в svg, фильтровал png. Возникают вопросы к производительности. Сетевые задержки + ungzip + парсинг и рендер svg, в результате видно как тайлы появляются на карте поочередно. Ховер по точке происходит с ощутимой задержкой (~0.5 sec). Почему бы не рисовать точки в canvas, раз уж все равно приходится их все передавать на фронт? Циан рисует 5000 точек и проблем с производительностью это не вызывает.
Мы отдаем на фронт не все точки, а только точки из видимой области. Если мы будем отдавать сразу много точек (большую область) — запрос за данными будет выполняться долго, а юзер может никогда и не сдвинуть карту. Тогда зачем он столько времени ждал?

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

На метриках видим, что в среднем запрос за тайлами выполняется примерно в три раза быстрее запроса за маркерами. Загрузка квадратами не выглядит красивой, согласна, но приходится чем-то жертвовать =)
Ховер по точке происходит с ощутимой задержкой

На уровне города да, на уровнях ближе ощутимой задержки не наблюдаю.
Я так понимаю по mousemove поиск точки отнимает много времени. Пространственный индекс не используется?
Нет. Возможно, в дальнейшем оптимизируем, если поймем, что это является проблемой.
Откуда информация про ЦИАН? Судя по запросам, их бекенд использует тот же подход с технологией хотспотов, как и в Авито, просто у них эти тайлы с точками приходят в base64. А слой с canvas нужен лишь для отображения этих тайлов поверх карты, как и у автора статьи. Кроме того, у ЦИАН проще: точки не кликабельны и не меняют своего состояния при наведении.

Буду счастлив, если кто-нибудь из ЦИАН поделится особенностями реализации их карты и поправит меня, если я ошибаюсь.
Сейчас мы экспериментируем с новой реализацией карты. Возможно, в ближайшем будущем, тоже напишем статью на эту тему ;)
Интересно. Тоже сталкивался со сложностью, когда тысячи пинов дают проблемы с производительностью. Всё из-за того, что каждый пин представляет из себя отдельную DOM-ноду, и в результате жуткие тормоза.

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

С учётом того, что на клиенте всё равно живут все необходимые данные, не рассматривали такой вариант? Ну там минус лишние сервера и всё такое.
Рассматривали такой вариант на этапе прототипа. Тут дело в том, что на клиенте живут не все данные, а только данные по видимой области.

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

А данные на фронт отдавались только для видимой области? Т е например, при сдвиге был новый запрос за данными?
Если речь о поиске, инициированном с карты на основе её координат, то да — из видимой области. Но в общем случае это скорее наиболее подходящие данные, которые могут включать в том числе данные, несколько выходящие за границы исходной карты. Скажем, если делаем поиск объявлений по Москве, то прислать всё, что мы считаем объявлениями по Москве, даже если весь полигон Москвы не планируется умещать в изначально открытую карту.

Всё уже зависит от решаемой задачи и бизнес-требований. Можно прислать необходимый минимум данных и ходить в бекенд в любой непонятной ситуации. Можно прислать с запасом, но нельзя забывать, что запас не может быть бесконечным.
Ну вот да, тут бы приходилось балансировать между тем, что при сдвиге карты нам не хватает данных, и мы ждем ответ от бэкенда и тем, что мы изначально запрашиваем много данных и долго ждем. Поэтому выбрали решение через бэк — где запрашиваем в самом запросе за маркерами ровно столько, сколько нужно для видимой области (ровно для того, чтобы сделать просмотренность и ховер), а каждый тайл запрашивается отдельно по требованию. При этом запрос по тайлу выполняется существенно быстрее запроса по данным.
Тоже делал похожий продукт, и использовал canvas для отрисовки, всё работало быстро на ~500 000 объектов.
А если координата дома, например, у пяти объявлений одинаковая. Точки друг на друге? Как тогда отображаете не/просмотренные?
Нет, будет одна точка. Кластеризуются до дома на бэкенде. Если хотя бы одно объявление просмотрено, точка рисуется просмотренной (это было продуктовым решением).
Да, посмотрел в оригинале. Возможно так удобнее, с точками, удобнее созерцать картину в целом. Но папасть в мелкую точку сложнее чем в кластер или стандартный маркер. И теряется главное предназначение кластеров — заспамленность маркерами. При некоторых масштабах уже не видно ни карты, ни названий улиц и прочего. Т.е. фактически, вы просто убрали кластеры, а стандартные маркеры сделали кружками и уменьшили их размер? Спорное решение.
Вообще, если судить только по скриншотам, заспамленность наблюдается только на уровне зума, где помешается Москва целиком и немного области. В таком масштабе улиц и так не особо видно. А на более крупных масштабах (опять же — я сужу по скриншотам, на сайт не лазал) вроде особо и не замусорено? Особенно с учетом того, что названия улиц написаны на самих улицах, и с домами (и точками) не пересекаются.
вы просто убрали кластеры, а стандартные маркеры сделали кружками и уменьшили их размер

Точки — это не совсем маркеры. При клике на точку отображаются объявления в доме. А кластер — это объединение по сетке с достаточно большим радиусом, поэтому клики по кластерам зумят карту вместо того, чтобы сразу отобразить объявления.
Вы точно мне хотели ответить? Это цитата не моя была.
Да, простите, это ответ на другое сообщение.
вы просто убрали кластеры, а стандартные маркеры сделали кружками и уменьшили их размер

Точки — это не совсем маркеры. При клике на точку отображаются объявления в доме. А кластер — это объединение по сетке с достаточно большим радиусом, поэтому клики по кластерам зумят карту вместо того, чтобы сразу отобразить объявления.
Ребят Вы конечно крутые и реализация интересная, однако мне кажется, Вы всё несколько переусложнили.
По моему мнению, нужно было делать проще:

У Вас каждое объявление имеет координату по широте и долготе.
Переводим Широту и долготу в экранные координаты в проекции Меркатора на самом большём уровне приближения для карт, и храним в БД и Кэшируем по необходимости.
(в принципе можно не переводить координаты, а рассчитывать на лету во фронте, но при большём количестве точек будут явные просадки).

При выводе карты отправляем запрос с БД на выбор точек (можно кэшировать). Затем отрисовываем слой svg c токенами поверх карты. А при нажатии мышкой выбирать в окрестности нажатия ближайший токен и обрабатывать выдачу.

В своём старом проекте уже реализовывал подобную схему. Более ста тысяч точек спокойно обрабатывается на одном экране. Только это был Pascal, а не javascript.
Почему не использовали deck.gl?
Если я правильно поняла, это библиотека, которая управляет визуализацией данных, и для нее можно подключать любые слои. Тут проблема в том, что слои Яндекс-карт нельзя использовать вне их API. Мы используем Яндекс-карты, поскольку у них лучшее покрытие гео-объектов по России, это важный момент для нас.

Глубоко не изучала API deck.gl, но кажется, что для них требуется загружать все данные сразу, а они сами будут кластеризовать их. Это так?
Я в свое время для похожей задачи (стоимость подключения к интернету от географии абонента) делал heatmap с динамически перестраивающимся цветом — paste.pics/806e865012d0e94d7caf18888d413628 — пробовали что-то подобное?
Не пробовали. Посмотрим в сторону тепловых карт, если решим делать на карте что-то подобное.

Хаб "Высокая производительность" подошёл бы ещё.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий