Ключевой особенностью интерактивной карты метро DC на https://dcmetropro.com является нажатие на маркеры станций на карте SVG и перемещение / масштабирование. Вот краткое изложение того, что потребовалось, чтобы это произошло!

Вы можете поиграть с картой, чтобы понять, что она делает, прежде чем читать: https://dcmetropro.com.

Начинаем медленно сейчас

Шаг 1:

У вас есть файл SVG, контент или что-то в этом роде? Для DC Metro Pro мне пришлось вручную создать SVG карты метро DC (которую я описываю в другом посте). В результате экспорта из Sketch получился большой объем svg-контента, который я поместил в файл JS следующим образом:

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

Элемент <g id="Stations"> охватывает все точки отдельных станций на карте, а id каждой точки соответствует остановке метро (C05 - это Rosslyn для всех вас, поклонников WMATA).

Это ключевой компонент в превращении визуальной карты в интерактивную, потому что теперь наши визуальные элементы имеют некоторое семантическое значение, которое мы можем использовать в коде.

Немного быстрее сейчас

Шаг 2:

Мы должны визуализировать SVG в DOM, и, поскольку мы используем React, мы должны играть по правилам React.

Итак, вот компонент React Metro Map, который использует ту большую строку HTML / SVG из прошлого. Мы визуализируем его с помощью свойства dangerouslySetInnerHTML React, которое берет нашу строку и помещает ее прямо в DOM без анализа или обновления React при повторной визуализации. Это позволяет нам использовать d3 для получения «дескриптора» элемента. Мы также заключаем его в тег ‹g› (используемый для группировки элементов), чтобы в дальнейшем мы могли справиться с некоторыми уловками с мышью.

И, наконец, фрагмент демонстрирует небольшую логику изменения размера и размера элемента svg на основе размеров окна и размера содержимого svg (жестко заданные значения области просмотра - это размеры артборда из моего файла Sketch).

Боковое примечание: когда вы читаете руководства и обзоры кода, все может показаться действительно запутанным; Частично это связано с тем, что сложно объяснить нелинейный по своей сути процесс линейным образом, как, например, сообщение в блоге. На момент написания код не выглядел так. Я проделал несколько итераций, чтобы получить этот результат. Итак, если вы поймали себя на том, что задаетесь вопросом: «Как он узнал, что нужно обернуть этот элемент?», Я хочу, чтобы вы знали, что сначала я этого не сделал! Позже я столкнулся с ошибками с событиями мыши и выделением текста, и именно так я исправил эти проблемы. Существует множество методов проб и ошибок, о которых не говорится в подобных сообщениях. Продолжая ...

Эй-эй-эй

Шаг 3:

Наконец, код d3.js + React, который вам обещали в заголовке! Что там говорится о подготовке?

Хорошая подготовка занимает больше времени, чем доставка.

- Э. Ким Небеутс

Кто такой Э. Ким Небеутс? 🤔. Ну, это не та цитата, о которой я думал, но достаточно близко.

Фрагмент о щелчке по элементам в SVG:

Комментарии в приведенном выше фрагменте показывают, что делает каждый элемент.

Почему я добавляю круг?

  • Как оказалось, визуальный круг в svg очень крошечный, а большая область попадания способствует лучшему UX. Функции изменения размера не показаны, но они размещают круг с центром над тегом g, к которому они были добавлены, а радиус круга увеличивается для того, что я называю «основными» станциями (они представляют собой более крупные точки на карте). Эти круги - это то, что вы видите, когда наводите курсор на станцию ​​на карте.

Прыгайте и кричите прямо сейчас!

Шаг 4:

Пора перетащить SVG. Хорошо, похоже, что щелчок работает (доказательство есть на веб-сайте!). Как теперь добавить перетаскивание так, чтобы оно хорошо сочеталось с щелчком?

Концептуальный план:

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

Это означает, что нажатие на кружки имеет приоритет перед перетаскиванием, но это также означает, что вы не можете начать перетаскивание круга. Я уверен, что есть способ сделать это лучше, но сейчас я хочу снять свой знак одобрения Good Enough ™.

Хорошо, достаточно забавного дела, давайте посмотрим на код для перетаскивания.

Здесь мы действительно опираемся на d3, чтобы делать тяжелую работу. Поверьте, я раньше писал собственную логику масштабирования и перетаскивания, и это может быть сложно 😉.

Для любопытных: что translateExtent делать?

  • Это просто ограничивающие координаты того, как далеко вы можете перетащить карту. Непосредственно из документации d3.js он «Устанавливает экстент перевода в указанный массив точек [[x0, y0], [x1, y1]]], где [x0, y0] - левый верхний угол мира, а [ x1, y1] - правый нижний угол мира ».

Вывод

Да, подзаголовки были о The Isely Brothers, Shout. Подсказка, если заметили!

Итак, это был небольшой обзор того, как может работать нажатие + перетаскивание svg в компоненте реакции. Надеюсь, вы смогли почерпнуть что-то полезное в том, как расширить SVG и изменить его по своему желанию с помощью d3. Если у вас есть вопросы, оставьте их в комментариях ниже!

Если вам понравилась эта статья, возможно, вам понравятся Мои размышления в Твиттере.

И, наконец, вот еще одна ссылка на веб-сайт, на котором используются эти методы: https://www.dcmetropro.com.

Хорошего дня!