В JavaScript делегирование событий — это подход, при котором обработчики назначаются не каждому элементу по отдельности, а на их общий контейнер. Snap.svg предоставляет собственные методы для работы с событиями, которые полностью поддерживают концепцию делегирования, что позволяет создавать интерактивные SVG-графики с высокой производительностью.
Snap.svg использует метод element.click(),
element.hover() и element.drag() для
назначения обработчиков. Любой элемент, созданный через Snap,
поддерживает стандартный метод element.data() для хранения
дополнительной информации, что облегчает работу при делегировании.
Пример базовой установки события:
var s = Snap("#svg");
var circle = s.circle(50, 50, 40);
circle.attr({
fill: "red",
stroke: "#000",
strokeWidth: 2
});
circle.click(function() {
this.attr({ fill: "blue" });
});
В этом примере событие назначено конкретному элементу. При большом количестве элементов такой подход снижает производительность и усложняет поддержку кода.
Делегирование основывается на использовании родительского контейнера
для перехвата событий от дочерних элементов. В Snap.svg контейнером
может быть как сам <svg> элемент, так и группа
g.
Создание группы и делегирование:
var s = Snap("#svg");
var group = s.group();
var circle1 = s.circle(30, 30, 20).attr({ fill: "green" });
var circle2 = s.circle(80, 30, 20).attr({ fill: "orange" });
group.add(circle1, circle2);
group.click(function(event) {
var target = event.target;
Snap(target).attr({ stroke: "#000", strokeWidth: 3 });
});
Здесь обработчик установлен на группу group. Событие
click от каждого дочернего круга всплывает до группы, где
можно определить конкретный элемент через event.target.
event.target и element.data()Для эффективного делегирования важно различать элементы, на которых
произошло событие. Snap.svg позволяет хранить идентификаторы или типы
объектов в element.data().
var s = Snap("#svg");
var group = s.group();
var rect = s.rect(10, 10, 50, 50).attr({ fill: "blue" });
rect.data("type", "rect");
var circle = s.circle(100, 30, 25).attr({ fill: "red" });
circle.data("type", "circle");
group.add(rect, circle);
group.click(function(event) {
var target = Snap(event.target);
var type = target.data("type");
if (type === "rect") {
target.attr({ fill: "yellow" });
} else if (type === "circle") {
target.attr({ fill: "green" });
}
});
Использование data() позволяет разграничивать обработку
событий для разных типов объектов в одной группе, что особенно важно при
создании сложных интерфейсов.
При добавлении элементов после установки обработчика делегирование обеспечивает автоматическую обработку новых элементов. Так как событие слушается на родительском контейнере, новые дочерние элементы автоматически попадают под действие обработчика.
var s = Snap("#svg");
var group = s.group();
group.click(function(event) {
Snap(event.target).attr({ stroke: "black", strokeWidth: 2 });
});
// Динамическое добавление круга
var circle = s.circle(150, 50, 30).attr({ fill: "pink" });
group.add(circle);
Даже без повторного назначения обработчиков клики по новому кругу будут обработаны через группу.
Snap.svg поддерживает плавные анимации через метод
element.animate(). Делегирование позволяет комбинировать
обработку событий с анимацией без необходимости назначать отдельные
обработчики каждому элементу.
group.click(function(event) {
var target = Snap(event.target);
target.animate({ transform: "s1.5" }, 500, mina.easeinout);
});
Здесь при клике на любой элемент группы он масштабируется плавно, а обработчик остаётся один для всей группы.
element.data().event.target перед изменением
атрибутов, чтобы избежать случайного изменения группы.click,
hover и drag на уровне контейнера.Snap.svg позволяет работать с любыми стандартными событиями SVG:
click — щелчок мышьюdblclick — двойной кликmouseover / mouseout — наведение мышиmousedown / mouseup — нажатие и отпускание
кнопки мышиmousemove — движение мышиtouchstart, touchend,
touchmove — сенсорные событияДелегирование применяется ко всем этим событиям через родительский контейнер, что обеспечивает единообразное управление взаимодействием.
Snap.select() и Snap.selectAll() с
делегированиемПри необходимости обращаться к отдельным элементам или их наборам удобно использовать:
var circle = Snap.select("#myCircle");
var allRects = Snap.selectAll(".rectClass");
allRects.forEach(function(rect) {
rect.data("type", "rect");
});
Далее события можно делегировать на общий контейнер, а внутри
обработчика различать элементы по данным из data().
Такой подход обеспечивает модульность, сокращает код и повышает производительность, особенно при работе с интерактивными графиками и динамически изменяющимися SVG-элементами.