SVG.js предоставляет гибкий и удобный способ работы с элементами SVG
через объектную модель. Каждый элемент создаётся с помощью методов типа
draw.rect(), draw.circle() или
draw.path(). После создания элемент можно присвоить
переменной для последующей манипуляции:
const draw = SVG().addTo('body').size(600, 400);
const rect = draw.rect(100, 50).fill('#f06');
Элемент rect теперь является объектом класса
SVG.Element и поддерживает методы для изменения атрибутов,
трансформаций и взаимодействия с другими элементами.
SVG.js использует иерархическую структуру, где элементы могут быть
вложенными. Вложенные элементы создаются с помощью контейнеров
group() или других контейнеров SVG. Основные методы для
обхода дерева:
children() — возвращает массив прямых
дочерних элементов.parent() — возвращает родительский
элемент.first() и last() —
возвращают первый и последний дочерний элемент.find(selector) — возвращает массив
элементов, соответствующих CSS-подобному селектору.each(callback) — выполняет функцию для
каждого дочернего элемента.Пример обхода всех дочерних элементов:
const group = draw.group();
group.rect(50, 50).fill('#0f9');
group.circle(40).fill('#09f');
group.each(el => {
console.log(el.type); // rect, circle
});
Метод find() позволяет искать элементы по тегу, классу
или атрибуту. Он поддерживает CSS-подобные селекторы:
draw.rect(50, 50).addClass('highlight');
draw.circle(30).addClass('highlight');
const highlights = draw.find('.highlight');
highlights.each(el => el.fill('#f90'));
Для поиска элементов по атрибуту применяется синтаксис
[атрибут="значение"]:
draw.rect(60, 60).attr({dataType: 'button'});
const buttons = draw.find('[dataType="button"]');
buttons.each(el => el.stroke({color: '#000', width: 2}));
Для работы с глубокими иерархиями удобно использовать рекурсивные
функции. Метод children() возвращает прямых потомков, а
рекурсия позволяет обрабатывать всех вложенных элементов:
function traverse(element, callback) {
callback(element);
element.children().forEach(child => traverse(child, callback));
}
traverse(draw, el => {
console.log(el.type, el.id());
});
Такой подход полезен для массового изменения атрибутов или добавления событий всем элементам внутри группы.
Фильтры в SVG.js можно применять не только к отдельным объектам, но и к контейнерам, что упрощает массовое оформление элементов:
const group = draw.group();
group.rect(100, 100).fill('#f06');
group.circle(50).fill('#0f9');
group.filterWith(function(add) {
add.gaussianBlur(5);
});
Метод filterWith создаёт фильтр, который применяется ко
всем дочерним элементам, сохраняя структуру дерева.
SVG.js позволяет навешивать события на отдельные элементы и на группы:
const group = draw.group();
group.rect(80, 80).fill('#ff0');
group.circle(40).fill('#0ff');
group.on('click', e => {
console.log('Нажатие на группу', e.target.type);
});
События на уровне группы позволяют отслеживать взаимодействия с любым дочерним элементом, не навешивая обработчик на каждый объект отдельно.
Рекурсивный обход позволяет изменять атрибуты всех элементов дерева одновременно. Например, изменение цвета всех элементов группы:
traverse(group, el => el.fill('#333'));
Можно также комбинировать фильтры и селекторы для избирательной модификации:
traverse(group, el => {
if (el.type === 'circle') {
el.fill('#f00');
}
});
const draw = SVG().addTo('body').size(800, 600);
const rootGroup = draw.group();
const group1 = rootGroup.group();
const group2 = rootGroup.group();
group1.rect(100, 50).fill('#f06').addClass('interactive');
group1.circle(40).fill('#0f9');
group2.rect(80, 80).fill('#09f');
group2.circle(60).fill('#ff0');
traverse(rootGroup, el => {
console.log(`Элемент: ${el.type}, Класс: ${el.attr('class')}`);
});
Такой подход обеспечивает полный контроль над деревом элементов, позволяя фильтровать, изменять, отслеживать события и применять трансформации ко всем объектам одновременно.