Создание схемы посадочных мест
Схемы посадочных мест — важная часть веб-приложений по продаже билетов, но реализовать их средствами AMP может быть сложно. В этой статье рассказывается, как создать схему посадочных мест в AMP, используя комбинацию доступных AMP-компонентов.
Требуемые AMP-компоненты
Для начала ознакомимся со списком необходимых нам компонентов:
amp-pan-zoom
amp-pan-zoom
позволяет позиционировать контент и изменять его масштаб с помощью двойного касания и разведения пальцев. Этот компонент служит основой для реализации схемы посадочных мест.
amp-list
amp-list
динамически загружает контент из конечной точки CORS JSON и производит его рендеринг с использованием заданного шаблона. Используется для загрузки данных о доступности мест в реальном времени, чтобы пользователи всегда видели актуальную информацию.
amp-bind
amp-bind
добавляет на страницу интерактивные возможности. Нужен для отслеживания количества выбранных мест.
amp-selector
amp-selector
— это элемент управления, отображающий меню и позволяющий пользователю выбрать один или несколько его пунктов. Можно представить всю схему посадочных мест в виде меню, где каждому месту соответствует один пункт. Таким образом становится гораздо проще задать стиль для выделения места, выбранного пользователем, при помощи CSS-выражений. Например, представленное ниже выражение окрашивает место, выбранное пользователем, в оранжевый цвет.
rect[selected].seat {
fill: var(--orange-theme);
}
Требования
- Чтобы отрисовать схему посадочных мест в виде SVG-изображения, где каждому месту соответствует элемент
rect
необходима информация о каждом месте: координатыx
иy
, размерыwidth
иheight
и, опционально,rx
иry
для скругления углов прямоугольников. - Уникальные идентификаторы для каждого места, необходимые для их бронирования.
- Размер (ширина и высота) всей схемы посадочных мест для использования в качестве значения атрибута
viewbox
.
Отрисовка схемы посадочных мест
Для рендеринга схемы используются компоненты amp-list
и amp-mustache
. После получения данных при помощи вызова amp-list
их можно использовать для обхода списка мест:
<svg preserveAspectRatio="xMidYMin slice" viewBox="0 0 {{width}} {{height}}"> {{#seats}} <rect option="{{id}}" role="button" tabindex="0" class="seat {{unavailable}}" x="{{x}}" y="{{y}}" width="{{width}}" height="{{height}}" rx="{{rx}}" ry="{{ry}}"/> {{/seats}} </svg>
Стилизация недоступных мест
В вышеприведенном примере на место {{unavailable}}
подставляется значение поля, возвращаемого конечной точкой JSON, благодаря чему к недоступным местам применяется соответствующий стиль. Такой подход не позволяет убирать атрибуты, такие как option=""
, в случае, если место недоступно, поскольку шаблон нельзя применить к корневому элементу <html>
страницы.
Другой, более развернутый подход состоит в том, чтобы продублировать теги:
{{#available }}<rect option="" role="button" tabindex="0" class="seat" x="" y="" width="" height="" rx="" ry=""/>{{/available }} {{^available}}<rect role="button" tabindex="0" class="seat unavailable" x="" y="" width="" height="" rx="" ry=""/>{{/available }}
Определение размера схемы посадочных мест
Если схема посадочных мест не имеет фиксированного размера, определение размеров компонента amp-list
, содержащего схему, — нетривиальная задача. Для работы компонента amp-list
требуется либо задать ему фиксированные размеры, либо использовать layout="fill"
(чтобы использовать все доступное пространство родительского контейнера). Решить эту проблему можно двумя способами:
- Рассчитать доступное пространство на странице с учетом уже известных данных о том, сколько пространства используют другие компоненты, такие как верхний и нижний колонтитулы. Сделать это можно посредством CSS, вычислив значение при помощи выражения
calc
и присвоив его атрибутуmin-height
элемента div, внутри которого расположен компонентamp-list
. - Использовать flex-макет, если известна высота макета страницы.
Стилизация компонента amp-pan-zoom
При использовании подхода, описанного в предыдущем разделе, для компонента amp-pan-zoom
также необходимо использовать layout="fill"
.
- Оберните SVG-изображение в элемент div
- Добавьте внутренний отступ
Если вместо того, чтобы обернуть SVG-изображение в элемент div, вы просто добавите к изображению внешний отступ, тогда этот отступ не станет частью области, внутри которой работают жесты изменения масштаба.
Хранение состояния
Идентификаторы (id
) мест, выбранных пользователем, можно хранить в переменной при помощи компонента amp-state
, используя один из следующих способов:
- Путем добавления к каждому месту выражения
amp-bind
, которое будет добавлять места, выбираемые пользователем, в список - Путем использования компонента
amp-selector
с действиемon="select:AMP.setState({selectedSeats: event.selectedOptions})"
, чтобы все выбираемые места добавлялись в список
Для первого способа не требуется дополнительный компонент amp-selector
, однако из-за того, что при выборе или отмене выбора места все выражения amp-bind
будут пересчитываться заново, схема посадочных мест может работать очень медленно.
Второй способ также позволяет избежать дублирования выражений amp-bind
для каждого места, отображаемого при помощи шаблона.
Окончательная структура HTML
Ниже можно ознакомиться с окончательным HTML-кодом схемы посадочных мест:
<div class="seatmap-container"> <amp-list layout="fill" src="/json/seats.json" binding="no" items="." single-item noloading> <template type="amp-mustache"> <amp-pan-zoom layout="fill" class="seatmap"> <amp-selector multiple on="select:AMP.setState({ selectedSeats: event.selectedOptions })" layout="fill"> <div class="svg-container"> <svg preserveAspectRatio="xMidYMin slice" viewBox="0 0 {{width}} {{height}}"> {{#seats}} <rect option="{{id}}" role="button" tabindex="0" class="seat {{unavailable}}" x="{{x}}" y="{{y}}" width="{{width}}" height="{{height}}" rx="{{rx}}" ry="{{ry}}"/> {{/seats}} </svg> </div> </amp-selector> </amp-pan-zoom> </template> </amp-list> </div>