Поиск элементов внутри групп

Группы (<g>) в SVG используются для логической организации элементов и управления ими как единым целым. В библиотеке SVG.js группы играют ключевую роль при построении сложных интерфейсов и анимаций. Эффективный поиск элементов внутри групп позволяет реализовывать интерактивность, управлять состояниями и оптимизировать работу с графикой.


Создание и структура групп

Группа создаётся методом group():

const draw = SVG().addTo('#app').size(400, 400)

const group = draw.group()
group.rect(100, 100).fill('red')
group.circle(50).move(120, 120).fill('blue')

Группа содержит вложенные элементы, которые можно искать и модифицировать.


Основные методы поиска

find(selector)

Метод find() возвращает список всех элементов внутри группы, соответствующих CSS-селектору.

const circles = group.find('circle')

Результат — коллекция (SVG.List), содержащая все найденные элементы.

Поддерживаются стандартные селекторы:

  • по тегу: 'rect', 'circle'
  • по классу: '.active'
  • по id: '#myElement'

findOne(selector)

Метод findOne() возвращает только первый найденный элемент:

const firstCircle = group.findOne('circle')

Если элемент не найден — возвращается null.


children()

Метод children() возвращает всех прямых потомков группы:

const children = group.children()

Важно: возвращаются только элементы первого уровня вложенности.


each(callback)

Метод each() позволяет перебрать элементы группы:

group.each(function(i, children) {
  console.log(this.type)
})
  • this — текущий элемент
  • i — индекс
  • children — массив всех элементов

Глубокий поиск (рекурсивный)

По умолчанию children() не проходит по вложенным группам. Для рекурсивного обхода используется find():

const allRects = group.find('rect')

Этот метод проходит по всей вложенной структуре, включая группы внутри групп.


Фильтрация элементов

После поиска можно отфильтровать элементы:

const largeRects = group.find('rect').filter(function() {
  return this.width() > 50
})

Функция filter() работает аналогично массивам JavaScript.


Работа с классами и атрибутами

Поиск часто комбинируется с атрибутами:

const activeElements = group.find('.active')

Добавление классов:

group.rect(50, 50).addClass('active')

Поиск по атрибутам:

const elements = group.find('[fill="red"]')

Вложенные группы

Группы могут содержать другие группы:

const parent = draw.group()
const child = parent.group()

child.circle(30).fill('green')

Поиск внутри родительской группы:

const circles = parent.find('circle')

Поиск вернёт элементы из всех уровней вложенности.


Поиск с ограничением области

Иногда требуется искать только в конкретной подгруппе:

const subGroup = group.findOne('#sub')
const items = subGroup.find('rect')

Такой подход уменьшает область поиска и повышает производительность.


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

При работе с большим количеством элементов важно учитывать:

  • find() выполняет рекурсивный обход
  • частые вызовы поиска могут замедлять приложение
  • рекомендуется кэшировать результаты

Пример кэширования:

const cachedRects = group.find('rect')

// позже используем cachedRects вместо нового поиска
cachedRects.forEach(el => el.fill('blue'))

Динамический поиск при изменениях

Если структура группы изменяется:

group.add(draw.circle(20))

ранее сохранённые результаты поиска не обновляются автоматически. Требуется повторный вызов find().


Поиск и события

Поиск часто используется совместно с обработчиками событий:

group.find('rect').forEach(rect => {
  rect.on('click', () => {
    rect.fill('orange')
  })
})

Получение родительской группы

Для найденного элемента можно получить его группу:

const rect = group.findOne('rect')
const parentGroup = rect.parent()

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


Комбинированные селекторы

Поддерживаются сложные CSS-селекторы:

const result = group.find('g .active rect')

Это ищет:

  • rect
  • внутри элементов с классом .active
  • которые находятся внутри группы g

Практический пример

const draw = SVG().addTo('#app').size(500, 500)

const group = draw.group()

for (let i = 0; i < 10; i++) {
  group.circle(20)
    .move(i * 30, 50)
    .addClass(i % 2 === 0 ? 'even' : 'odd')
}

// Найти все чётные элементы
const evenCircles = group.find('.even')

// Изменить цвет
evenCircles.forEach(el => el.fill('blue'))

Типичные ошибки

1. Ожидание, что children() ищет рекурсивно

group.children() // только первый уровень

2. Работа с null при findOne()

const el = group.findOne('#missing')
el.fill('red') // ошибка

3. Частый вызов find() в циклах

for (...) {
  group.find('rect') // неэффективно
}

Итоговая модель работы

  • group — контейнер
  • find() — глубокий поиск
  • findOne() — первый элемент
  • children() — прямые потомки
  • each() — итерация
  • CSS-селекторы — основной инструмент фильтрации

Грамотное использование этих методов позволяет эффективно управлять сложными SVG-структурами и поддерживать читаемость кода даже при высокой вложенности элементов.