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

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

var s = Snap(400, 400);
var line = s.line(50, 50, 350, 350).attr({
    stroke: "#000",
    strokeWidth: 5
});

var arrow = s.marker(0, 0, 10, 10, 5, 5);
arrow.path("M0,0 L0,10 L10,5 Z").attr({
    fill: "#f00"
});

line.attr({
    markerEnd: arrow
});

В этом примере создается линия с маркером-стрелкой. Маркер определен отдельным элементом <marker> и привязан к линии через атрибут markerEnd.


Управление масштабом маркера

По умолчанию маркеры масштабируются автоматически в зависимости от ширины линии, если не заданы конкретные атрибуты markerUnits.

Типы markerUnits:

  • strokeWidth — размер маркера изменяется пропорционально толщине линии. Это поведение по умолчанию.
  • userSpaceOnUse — размер маркера фиксирован в единицах пространства SVG и не зависит от толщины линии.

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

arrow.attr({
    markerUnits: "userSpaceOnUse"
});

В этом случае маркер будет иметь фиксированный размер, даже если толщина линии изменится:

line.attr({
    strokeWidth: 10
});

Маркер останется прежнего размера, несмотря на увеличение толщины линии.


Применение трансформаций к маркерам

Маркер может быть масштабирован отдельно с помощью метода .transform():

arrow.transform("s2"); // увеличивает маркер в 2 раза

Важно помнить:

  • Трансформации применяются к самому маркеру, а не к линии.
  • Если маркер уже привязан к линии, .transform() изменит его внешний вид без изменения позиции линии.

Для одновременного масштабирования линии и маркера можно использовать комбинацию markerUnits="strokeWidth" и изменение толщины линии.


Примеры сложного масштабирования

  1. Масштабирование с сохранением пропорций линии:
var line2 = s.line(50, 100, 350, 100).attr({
    stroke: "#00f",
    strokeWidth: 3,
    markerEnd: arrow
});

// Увеличиваем толщину линии
line2.attr({ strokeWidth: 12 });

Маркер автоматически увеличится, сохраняя пропорцию к новой толщине линии.

  1. Масштабирование с независимым размером маркера:
arrow.attr({ markerUnits: "userSpaceOnUse" });
line2.attr({ strokeWidth: 12 });

Маркер останется прежнего размера, а линия станет толще.


Практические рекомендации

  • Для динамически изменяемых линий лучше использовать markerUnits="strokeWidth", чтобы стрелки масштабировались вместе с линией.
  • Для фиксированных символов на концах линий (точки, иконки) подходит markerUnits="userSpaceOnUse".
  • При сложных трансформациях лучше создавать отдельные маркеры для каждой линии, чтобы избежать непредсказуемого изменения размеров.
  • Можно комбинировать .transform() с markerUnits, чтобы добиться нестандартного визуального эффекта, например, увеличения маркера при увеличении линии, но с сохранением формы.

Взаимодействие с группами и анимацией

При добавлении линии с маркерами в группу (<g>):

var group = s.group(line, line2);
group.transform("s1.5");
  • Масштабирование группы изменяет координаты линии, но маркеры ведут себя согласно markerUnits.
  • Для анимации размера маркеров можно анимировать атрибут strokeWidth линии или отдельную трансформацию маркера.
line.animate({ strokeWidth: 20 }, 1000);
arrow.animate({ transform: "s1.5" }, 1000);

Это позволяет создавать визуально плавное увеличение стрелок вместе с линиями или независимо от них.


Итоговая схема управления

Параметр Эффект
markerUnits Определяет масштаб маркера относительно линии или пространства SVG
.transform() Позволяет масштабировать маркер независимо от линии
strokeWidth линии При markerUnits="strokeWidth" напрямую влияет на размер маркера
Группы <g> Масштабируют линии, но маркеры ведут себя согласно markerUnits
Анимации Можно анимировать линии, маркеры или оба одновременно

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