Возможность масштабировать элементы страницы и детально рассматривать их – это очень крутой пользовательский опыт. Существует множество готовых библиотек с подобной функциональностью, но сегодня мы напишем собственный велосипед на чистом JavaScript! Зачем?
- Сторонние решения часто предлагают избыточную функциональность, которая вам не нужна, но бандл приложения увеличивает.
- К тому же это замечательный челлендж, который расшевелит ваш мозг и прокачает навыки программирования.
В результате мы получим очень маленькую (всего 69 строчек кода!), простую и удобную библиотечку для масштабирования и панорамирования.
Разметка и стили
Создадим HTML-страницу и разместим на ней элемент-контейнер ( #container ). Внутрь поместим рабочую область ( .area ), которую мы и будем непосредственно масштабировать и панорамировать.
Внутри рабочей области находятся несколько элементов, которые не несут никакой смысловой нагрузки, а просто предназначены для демонстрации работы кода.
Добавим также немного стилей для оформления страницы:
Для body устанавливаем overflow: hidden . Это нужно, чтобы избежать переполнения страницы и появления прокрутки при чрезмерном увеличении элемента.
Также добавим рамку для визуального обозначения рабочей области ( .area ) и немного облагородим демо-контент (классы .circle , .rectangle и .text-area ).
Скрипт библиотеки
Код самой библиотеки будет располагаться в файле renderer.js . Экспортируем из модуля главную функцию renderer :
Она принимает базовые параметры:
- minScale – минимальный масштаб;
- maxScale – максимальный масштаб;
- element – DOM-элемент, с которым будут производиться манипуляции;
- scaleSensitivity – коэффициент чувствительность масштабирования, по умолчанию 10.
В замыкании функции создается объект состояния – state , который хранит настройки и совершенные над элементом преобразования (поле transformation ).
Из функции возвращается объект с набором методов. При этом возможности масштабирования и панорамирования разделены на отдельные функции-конструкторы – makeZoom и makePan , которые мы разберем чуть позже. Конструкторы получают общий объект состояния и возвращают отдельный набор методов для взаимодействия с ним.
Такой подход называется композицией и позволяет проще добавлять новую функциональность и легче тестировать приложение.
Трансформации
Все манипуляции с элементом будут производиться через изменение свойства transform . Для этого используем CSS-функцию matrix , которой нужно передать правильные параметры масштаба ( scale ) и сдвига ( translateX и translateY ):
Вспомогательная функция getMatrix просто формирует шаблонную строку правильного формата, которую нужно установить в свойство style.transform элемента.
Панорамирование
При панорамировании должно изменяться положение элемента на странице, то есть производиться его сдвиг. Функция pan принимает текущее состояние элемента ( state ), а также новые координаты. Затем она обновляет состояние, прибавляя новый сдвиг к текущему положению и обновляет свойство style элемента.
Теперь реализуем два метода:
- panBy – простой сдвиг на указанные координаты;
- panTo – сдвиг с одновременным масштабированием.
При сдвиге с масштабированием координаты элемента нужно скорректировать.
Масштабирование
Для изменения размера элемента нам потребуется несколько вспомогательных функций для расчетов:
Метод getScale рассчитывает новый масштаб на основе предыдущего значения, минимального и максимального ограничений ( minScale , maxScale ) и коэффициентов ( scaleSensitivity , deltaScale ).
Метод getTranslate рассчитывает новый сдвиг на основе масштаба и текущей и предыдущей позиции.
А вот и реализация функции makeZoom :
Она возвращает только один метод zoom , предназначенный для масштабирования элемента. Он получает координаты курсора, а также параметр deltaScale – коэффициент, который определяет направление масштабирования ( 1 для увеличения, -1 для уменьшения).
Функция вычисляет новые параметры трансформации и обновляет свойство style элемента.
При масштабировании кроме style.transform нужно изменять также свойство style.transformOrigin , чтобы скорректировать позицию элемента. В качестве эксперимента вы можете закомментировать 14 строчку и посмотреть, что будет.
Главный файл
Кроме того мы сделаем главный файл приложения index.js :
Клиентский код создает экземпляр renderer и передает ему базовую конфигурацию:
- элемент, размер которого будет изменяться;
- минимальный и максимальный масштаб;
- коэффициент чувствительности масштабирования.
Затем устанавливаются слушатели событий мыши и в нужный момент вызываются нужные методы:
- для масштабирования используйте колесико мыши или сенсорную панель, зажав клавишу CTRL.
- для перемещения – перемещайте мышь или используйте тачпад, зажав клавишу SHIFT.
- Двойной щелчок мыши восстановит исходное состояние элемента.
Тестирование
Проверим реализованные функции с помощью библиотеки Mocha:
Перед каждым тестом ( beforeEach ) создается объект _element с дефолтными значениями.
Кейсы тестирования для удобства вынесены в отдельный файл renderer.testCases.js .
В итоге у нас получился очень простой и удобный инструмент для масштабирования и панорамирования на JavaScript, состоящий всего из 69 строк кода. Его можно сократить больше, но не хочется терять читабельность.