В рамках создания reciprocal.dev я работал с Konvareact-konva), чтобы создать MVP инструментов картирования пути пользователя, чтобы проверить идею.

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

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

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

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

Создание мини-карты

Макет пользовательского интерфейса Reciprocal.dev похож на Miro, поскольку он максимально увеличивает пространство холста и имеет плавающие элементы меню по бокам экрана.

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

Выкладываем всю карту

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

Поскольку мини-карта будет использоваться только для справки, я не хотел отображать все экраны и подключения, отображаемые на полной карте, поэтому я решил просто отобразить Rect в тех же размерах, что и один из экранов на основной карте, которая сделала ясно, что он представлял.

Поскольку мне нужно было отрендерить полную карту для мини-карты, мне нужно было знать, насколько большой была вся карта, чтобы уменьшить ее масштаб, чтобы он соответствовал контейнеру. Я сделал это, вызвав getClientRect на сцене с масштабом 1 , это позволило мне использовать возвращенное значение width для расчета масштаба, необходимого для рендеринга мини-карты, на основе ширины контейнера, в котором я его рендерил. в пользовательском интерфейсе.

Отображение текущего представления пользователя

С экранами, добавленными к мини-карте, мне нужно было представить подраздел полной карты, который пользователь мог видеть в своем браузере.

Я сделал это, перехватив значения innerWidth и innerHeight браузера пользователя, а также значения x и y, возвращаемые вызовом getClientRect на сцене всякий раз, когда заканчивалось масштабирование или панорамирование (для повышения производительности по сравнению с рендерингом при каждом перемещении полной карты).

Затем я использовал контекст React, чтобы разделить значения между полной картой и мини-картой, что позволило мне обновить представление мини-карты представления пользователя при обновлении этих значений.

Добавление интерактивности

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

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

Обновление позиции просмотра

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

Это работало очень хорошо, но одна проблема, с которой я столкнулся, заключалась в том, что ось была обратной, поэтому панорамирование на мини-карте панорамировало всю карту вниз. Чтобы исправить это, я умножил значения позиции на -1, чтобы изменить их позицию.

Обновление уровня масштабирования

Подключение кнопок масштабирования было относительно тривиальным: когда кнопка нажата, я просто умножаю текущий масштаб на 1,25, чтобы увеличить масштаб, и на 0,25, чтобы уменьшить масштаб, а затем обновляю значение масштаба в общем контексте React, чтобы обновить полную карту.

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

Чтобы улучшить масштабирование, мне пришлось найти центр сцены относительно текущего положения в текущем масштабе, а затем пересчитать его в новом масштабе.

Резюме

Добавив мини-карту на свой холст Konva, я дал пользователям Reciprocal.dev возможность с легкостью перемещаться по сложным картам пути пользователя и понимать, что они в настоящее время ищут в контексте более широкой картины.

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