Размещение маркеров

Для работы с библиотекой Snap.svg необходимо создать объект SVG, который будет контейнером для всех графических элементов. Это достигается с помощью функции Snap(width, height):

var s = Snap(800, 600); // создаёт SVG размером 800x600 пикселей

Контейнер можно привязать к существующему элементу HTML:

var s = Snap("#svgContainer"); // привязка к <svg id="svgContainer"></svg>

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


Создание базовых маркеров

Маркеры в SVG чаще всего реализуются через небольшие геометрические объекты: круги, прямоугольники, треугольники или пользовательские фигуры. В Snap.svg создание маркера выглядит так:

var marker = s.circle(0, 0, 5); // круг радиусом 5
marker.attr({
    fill: "#ff0000", // заливка красным
    stroke: "#000000", // контур чёрный
    strokeWidth: 1
});

Ключевые моменты:

  • attr() позволяет устанавливать атрибуты SVG-элемента.
  • Координаты (0,0) означают начало локальной системы координат объекта. Позицию на холсте задают трансформации.

Для треугольного маркера можно использовать polygon:

var triangle = s.polygon([0,0, 10,0, 5,10]);
triangle.attr({ fill: "blue" });

Размещение маркеров на линии

Для равномерного распределения маркеров вдоль линии необходимо вычислить координаты точек. Простейший пример:

var line = s.line(50, 50, 750, 50).attr({ stroke: "#333", strokeWidth: 2 });
var numMarkers = 10;
for (var i = 0; i <= numMarkers; i++) {
    var x = 50 + (700 / numMarkers) * i;
    var y = 50;
    s.circle(x, y, 5).attr({ fill: "red" });
}

Пояснения:

  • (50,50) — старт линии, (750,50) — конец.
  • Разница 700 — длина линии.
  • Деление на numMarkers обеспечивает равное расстояние между маркерами.

Использование групп для маркеров

Snap.svg позволяет объединять элементы в группы через group(). Это облегчает управление множественными маркерами:

var markers = s.group();
for (var i = 0; i <= numMarkers; i++) {
    var x = 50 + (700 / numMarkers) * i;
    var y = 50;
    var m = s.circle(x, y, 5).attr({ fill: "green" });
    markers.add(m);
}

Преимущества групп:

  • Можно сразу трансформировать все маркеры (translate, rotate, scale).
  • Удобно менять стиль сразу для всей группы.
markers.attr({ fill: "orange" });
markers.transform("t0,20"); // сдвигает все маркеры вниз на 20 пикселей

Динамическое размещение маркеров по кривой

Для кривых линий (например, path) координаты маркеров вычисляются через длину пути:

var path = s.path("M50,300 C200,100 600,500 750,300").attr({ stroke: "#000", fill: "none", strokeWidth: 2 });
var pathLength = path.getTotalLength();
var numMarkers = 15;

for (var i = 0; i <= numMarkers; i++) {
    var point = path.getPointAtLength((pathLength / numMarkers) * i);
    s.circle(point.x, point.y, 5).attr({ fill: "purple" });
}

Объяснение:

  • getTotalLength() возвращает длину пути.
  • getPointAtLength(d) возвращает точку на пути с расстоянием d от начала.
  • Такой подход позволяет равномерно распределять маркеры по любой кривой.

Применение пользовательских маркеров

Snap.svg поддерживает определение маркеров через <marker> SVG-элемент для линий и кривых:

var s = Snap(800, 600);
var arrow = s.marker(0, 0, 10, 10, 5, 5);
arrow.add(s.path("M0,0 L10,5 L0,10 Z").attr({ fill: "black" }));

var line = s.line(50, 500, 750, 500).attr({
    stroke: "#000",
    strokeWidth: 2,
    markerEnd: arrow
});

Ключевые моменты:

  • markerEnd присваивает стрелку на конец линии.
  • markerStart и markerMid позволяют добавлять маркеры в начале и середине пути.
  • Размер маркера и точка привязки определяются параметрами marker(width, height, refX, refY).

Анимация маркеров

Snap.svg позволяет анимировать маркеры через метод animate:

var movingMarker = s.circle(50, 50, 8).attr({ fill: "red" });
var path = s.path("M50,50 C200,300 600,100 750,400").attr({ fill: "none", stroke: "#999" });
var pathLength = path.getTotalLength();

Snap.animate(0, pathLength, function(value) {
    var point = path.getPointAtLength(value);
    movingMarker.attr({ cx: point.x, cy: point.y });
}, 5000); // анимация 5 секунд

Особенности:

  • Параметр value последовательно изменяется от 0 до длины пути.
  • Метод getPointAtLength позволяет плавно перемещать маркер по кривой.
  • Можно комбинировать с rotate для создания эффектов следования по траектории.

Управление слоями и z-index маркеров

Snap.svg управляет порядком отображения через порядок добавления элементов и метод insertBefore / insertAfter:

var background = s.rect(0,0,800,600).attr({ fill: "#eee" });
var topMarker = s.circle(400,300,20).attr({ fill: "blue" });

// Перемещение маркера на передний план
topMarker.appendTo(s); // элемент становится последним в контейнере, выше других

Для групп:

markers.appendTo(s); // группа маркеров перемещается выше остальных элементов

Итоговая схема размещения

Основные шаги при работе с маркерами в Snap.svg:

  1. Создать SVG-контейнер (Snap(width, height)).
  2. Определить маркеры (круги, треугольники, кастомные фигуры или <marker>).
  3. Распределить маркеры по линии или кривой с помощью координат или getPointAtLength.
  4. Объединять маркеры в группы для удобства управления.
  5. При необходимости использовать анимацию для движения маркеров.
  6. Контролировать порядок отображения через appendTo, insertBefore и insertAfter.
  7. Применять стили и трансформации через attr и transform.

Эти инструменты позволяют создавать сложные диаграммы, интерактивные графики и визуализации, управляемые полностью через JavaScript и Snap.svg.