ViewBox и preserveAspectRatio

В SVG элемент viewBox определяет систему координат для содержимого внутри <svg>. Он задаётся четырьмя числами в формате: minX minY width height.

  • minX, minY — координаты верхнего левого угла области просмотра.
  • width, height — ширина и высота области просмотра.

В Snap.svg установка viewBox выполняется через метод paper.attr({ viewBox: "0 0 400 300" }), где paper — объект, созданный через Snap(). После установки viewBox содержимое SVG масштабируется и позиционируется относительно этой области.

Пример:

var s = Snap(500, 400);
s.attr({ viewBox: "0 0 200 100" });
s.rect(0, 0, 200, 100).attr({ fill: "blue" });

В этом примере прямоугольник, исходно равный области viewBox, растянется, чтобы занять всю видимую область 500×400 пикселей, сохранив пропорции при масштабировании.


Масштабирование и координатная система

Установка viewBox позволяет:

  1. Масштабировать содержимое SVG независимо от размеров контейнера.
  2. Работать с единым набором координат, не зависящим от фактической ширины и высоты SVG.
  3. Легко позиционировать элементы в абстрактной системе координат.

Важно понимать, что все координаты элементов внутри SVG интерпретируются относительно viewBox. Например, если viewBox равен "0 0 100 50", то прямоугольник rect(0,0,50,25) займёт ровно четверть ширины и половину высоты области просмотра.


Атрибут preserveAspectRatio

Атрибут preserveAspectRatio управляет тем, как содержимое SVG вписывается в область, заданную viewBox, при различном соотношении сторон контейнера и viewBox. Его значение состоит из двух частей:

  1. Выравнивание: xMinYMin, xMidYMid, xMaxYMax и их комбинации.
  2. Скейлинг: meet или slice.
  • meet — содержимое масштабируется, чтобы полностью поместиться в контейнер, сохраняя пропорции.
  • slice — содержимое масштабируется так, чтобы контейнер был полностью заполнен, часть содержимого может обрезаться.

Примеры использования:

s.attr({
    viewBox: "0 0 200 100",
    preserveAspectRatio: "xMidYMid meet"
});

xMidYMid центрирует содержимое по обеим осям, а meet гарантирует, что всё содержимое видимо, даже если контейнер имеет другое соотношение сторон.

Другой пример:

s.attr({
    viewBox: "0 0 200 100",
    preserveAspectRatio: "xMinYMin slice"
});

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


Работа с viewBox и трансформациями Snap.svg

Snap.svg предоставляет методы для управления масштабированием и позиционированием элементов внутри viewBox. Основные из них:

  • transform() — позволяет применять трансформации translate, scale, rotate и комбинировать их.
  • getBBox() — возвращает координаты и размеры элемента относительно текущей системы координат viewBox.
  • attr({ viewBox: ... }) — динамически изменяет область просмотра без пересоздания элементов.

Пример анимации элемента внутри viewBox:

var rect = s.rect(0, 0, 50, 50).attr({ fill: "red" });
rect.animate({ x: 150, y: 50 }, 1000, mina.easeinout);

Даже если размеры SVG или контейнера изменяются, анимация будет корректно соответствовать координатной системе viewBox.


Практические советы по использованию

  • Всегда определять viewBox при создании SVG, если предполагается масштабирование.
  • Использовать preserveAspectRatio для контроля расположения и видимости элементов.
  • При работе с адаптивными интерфейсами применять meet для видимости всего содержимого или slice, если важен полный контейнер.
  • Проверять координаты через getBBox(), чтобы корректно позиционировать элементы после изменения viewBox.

Совместимость и особенности

Snap.svg корректно обрабатывает viewBox и preserveAspectRatio во всех современных браузерах. Однако при сложных трансформациях стоит учитывать, что:

  • Комбинация scale и viewBox может создавать смещение элементов.
  • Использование slice может обрезать важные части графики, если контейнер сильно отличается по пропорциям.

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