Snap.svg предоставляет мощный и удобный интерфейс для работы с векторной графикой, однако трансформации объектов часто становятся источником ошибок и неожиданных результатов. Трансформации включают смещение (translate), масштабирование (scale), вращение (rotate) и наклон (skew), и их комбинации.
В Snap.svg порядок применения трансформаций критически важен. Каждая трансформация применяется относительно текущей системы координат объекта, а не глобальных координат SVG.
Пример некорректного применения:
var s = Snap("#svg");
var rect = s.rect(50, 50, 100, 50);
rect.transform('r45t100,0'); // Поворот, затем смещение
В данном случае сначала выполняется поворот относительно начала координат, затем смещение. Если необходимо поворачивать объект вокруг его центра, требуется:
rect.transform('t100,0r45,' + (rect.attr("x") + rect.attr("width")/2) + ',' + (rect.attr("y") + rect.attr("height")/2));
Ключевой момент: Snap.svg применяет трансформации в последовательности слева направо, и результат часто отличается от математически ожидаемого, если не учитывать центр вращения или локальные координаты.
Snap.svg хранит все трансформации объекта в виде строки
transform. Например:
rect.transform('t50,50r30s2,2');
При необходимости добавить новую трансформацию, важно использовать
метод transform() правильно. Простое присваивание новой
строки заменяет старую трансформацию:
rect.transform('s3,3'); // предыдущие t и r пропадут
Чтобы сочетать старые и новые трансформации, следует использовать:
rect.transform(rect.transform().localMatrix.toTransformString() + 's3,3');
Или применять метод matrix напрямую для точного
контроля.
Многие ошибки связаны с неправильным определением центра вращения. В Snap.svg поворот без указания центра выполняется вокруг (0,0) SVG-контейнера, а не центра объекта.
Пример корректного вращения вокруг центра прямоугольника:
var cx = rect.attr("x") + rect.attr("width") / 2;
var cy = rect.attr("y") + rect.attr("height") / 2;
rect.transform('r45,' + cx + ',' + cy);
Если объект уже трансформирован, координаты центра могут быть
смещены, и прямое вычисление x + width/2 не даст ожидаемого
результата. В таких случаях необходимо использовать текущую
матрицу трансформации:
var bbox = rect.getBBox();
rect.transform('r45,' + (bbox.cx) + ',' + (bbox.cy));
Масштабирование в Snap.svg изменяет размер объекта относительно его начала координат. При комбинировании с смещением или вращением часто возникают неожиданные сдвиги.
Например:
rect.transform('s2,2t50,50'); // объект масштабируется относительно (0,0), затем смещается
Чтобы масштабировать объект относительно его центра, необходимо выполнить последовательность:
var bbox = rect.getBBox();
rect.transform('t' + (-bbox.cx) + ',' + (-bbox.cy) + 's2,2t' + bbox.cx + ',' + bbox.cy);
Это переносит объект в начало координат, масштабирует, затем возвращает на место.
Snap.svg поддерживает анимацию трансформаций через
animate(). Ошибки возникают при попытке анимировать объект,
уже имеющий трансформации:
rect.animate({ transform: 't100,0' }, 1000);
Если rect уже имеет поворот или масштаб, простое задание
transform заменяет предыдущие трансформации. Решение —
использовать матрицы или относительные
трансформации:
var m = rect.transform().localMatrix.clone();
m.translate(100, 0);
rect.animate({ transform: m.toTransformString() }, 1000);
Snap.svg применяет наклон через skewX и
skewY, но они ведут себя неинтуитивно при комбинации с
поворотом или масштабом. Часто возникает эффект “смещения объекта”.
Для корректного наклона рекомендуется использовать матрицы трансформации:
var matrix = new Snap.Matrix();
matrix.skewX(30);
matrix.translate(50, 50);
rect.transform(matrix);
Преимущество: точный контроль последовательности операций и центра координат, минимизация ошибок.
getBBox() для вычисления центра
объекта перед вращением или масштабированием.transform.transform.<g> для разделения трансформаций и упрощения
координатной системы.Эти подходы минимизируют непредсказуемое поведение, которое часто встречается при работе с Snap.svg, особенно при динамическом изменении графики.