Новый интерфейс Яндекс.Метро и технологии, с помощью которых он работает

в 6:09, , рубрики: javascript, Блог компании Яндекс, Веб-разработка, метки:

Сегодня мы запустили новую версию веб-интерфейса сервиса Яндекс.Метро. Теперь в новом «островном» дизайне доступны схемы метрополитена пяти городов. Но мы обновили не только визуальную часть, но и перенесли всю логику с серверной стороны на клиентскую.

image

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

Сервис Яндекс.Метро был запущен в далеком 2007 году. С тех пор веб-интерфейс практически не развивался, дизайн выглядел откровенно устаревшим. Почтенный возраст сервиса сказывался и на технической стороне. Все схемы представляли собой наборы изображений в формате GIF, на которых при помощи координат размещались объекты. Из-за этого возникали трудности с обновлением графа, нельзя было самостоятельно вносить изменения в схему (приходилось привлекать аутсорсеров, заказывать у них картинки). Так как названия станций также были вшиты в картинки, локализация схем потребовала бы генерации полных наборов GIF-изображений.

Никто из разработчиков серверной части сейчас над этим сервисом не работает, а документирована она очень слабо. Так что бэкэнд старого Яндекс.Метро — это в некотором роде черный ящик, который умел принимать параметры и возвращать маршруты. Однако поддерживать его при этом было крайне трудно. Сервис определенно требовал обновления, и главный вопрос заключался в том, как максимально приблизить его по уровню технологий к мобильным приложениям.

Нельзя сказать, что Яндекс.Метро было совершенно заброшено, у него есть достаточно широкая аудитория. Веб-интерфейс ежедневно посещает около 220 тысяч человек, приложение для Android скачано 3 миллиона раз, для iOS – 1 миллион загрузок. Стоит отметить, что мобильные приложения разрабатывались несколько позже веб-версии, и лишены большинства ее недостатков.

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

  • Технологии визуализации в браузерах шагнули далеко вперед, отрендерить карту на стороне клиента уже не составляет никаких проблем.
  • Сильно улучшилась производительность JavaScript-движков. Многие задачи, которые раньше можно было делать только на сервере, теперь вполне выполнимы на клиентской стороне.
  • Снизилась доля устаревших браузеров. IE6 и IE8 почти не встречаются, а значит, нет причин использовать GIF.

Как разрабатывалась новая версия

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

В самом начале разработки встал вопрос о том, какую технологию использовать для отрисовки схемы: canvas, SVG или CSS3. Рассматривался также способ отрисовки через визуализационную библиотеку RahaelJS. Эта библиотека рисует в SVG, но если она обнаруживает IE8, отрисовка происходит в VML, чем обеспечивается максимальная кроссбраузерность.

Сначала на основе XML-файлов было написано три прототипа схемы: на canvas, SVG и RaphaelJS. Все три варианта были прогнаны через бенчмарки. По результатам самым быстрым оказался SVG-вариант, за ним с не очень значительным отставанием последовал canvas, а самым медленным оказался вариант на основе RaphaelJS. Слишком уж много времени тратится на подгрузку и исполнение кода, проверяющего, какие функции доступны в используемом браузере. На ста итерациях отрисовки у нас получились следующие результаты в Chrome и Firefox соответственно:

image

image

Таким образом, окончательный выбор стоял между canvas и SVG. У canvas есть свои преимущества, но для рисования векторных схем SVG подходит лучше. Дело в том, что SVG-элементы хорошо вписываются в DOM страницы. А значит, можно обращаться к ним как к обычным DOM-нодам со знакомым интерфейсом, отлавливать события и т.д. Кроме того, в векторном формате отпадает необходимость перерисовывать схему при изменении масштаба.

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

image

Позже для удобства разработки и присваивания CSS-стилей слой с общей схемой был разбит на три: с перегонами, станциями и переходами.
У новой схемы есть неоспоримые преимущества: она векторная, ее можно масштабировать без написания дополнительного кода, ее проще поддерживать и добавлять дополнительные фичи. К сожалению, изменения в схему пока вносятся вручную через XML-файлы, но даже это проще, чем было в изначальной версии.

Поиск путей на графе

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

Примерно тот же алгоритм использовался и при создании мобильных приложений, но так как разрабатывались они несколько позже, в них применены более современные технологии и подходы. Там вся логика уже перенесена в клиентскую часть. В iOS-версии граф представлен в виде матрицы смежности, в Android-клиенте реализована объектно-ориентированная модель. Станции представлены в виде JS-объектов, у каждого из которых есть массив линков — перегонов. Эти соединения также являются объектами.

При выборе основы для веб-интерфейса рассматривались оба варианта. Но модель из приложения под Android показалась нам более оптимальной.

Фильтрация результатов поиска

На каждый запрос маршрутизатор возвращает порядка 30 маршрутов. Релевантных из них очень мало – не больше 10%. Но проблема заключается в том, что у многих пользователей разное понимание об «оптимальном маршруте». Некоторые предпочитают скорость, а некоторые – комфорт. Девушка на высоких каблуках будет готова потратить лишние 10 минут, чтобы не идти по длинному переходу, а вот для человека, опаздывающего на самолет, эта разница будет критичной. А значит, маршруты нужно оценивать по разным критериям.

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

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

image

Архитектура клиентского приложения

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

Планы

Непосредственно после запуска нового варианта сервиса мы планируем привести нашу схему в соответствие с официальной. Далее мы внедрим некоторые функции которые уже есть в мобильных приложениях. Например, информацию о том, из каких вагонов удобнее всего делать пересадку. Также мы реализуем уже заложенные в архитектуре фичи: возможность выбора маршрутов и перевод схем на несколько языков. Кроме того, в планах разработка визуального инструмента для внесения изменений в схему. Пока что любые изменения вносятся путем правки xml-файлов. Если же появится визуальный редактор, один контент-менеджер сможет оперативно вносить изменения одновременно под все платформы.

Автор: genarcho

Источник


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js