Контейнеры: g, svg, defs

Контейнеры в SVG.js — это фундаментальный механизм структурирования графики. Они позволяют группировать элементы, управлять их положением, применять трансформации и повторно использовать ресурсы. Три ключевых контейнера: g (группа), svg (вложенный SVG-контекст) и defs (определения).


Контейнер g (группировка элементов)

Назначение

Контейнер g используется для логического объединения нескольких SVG-элементов в единое целое. Все дочерние элементы наследуют трансформации и некоторые атрибуты группы.

Создание группы

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

const group = draw.group()

Добавление элементов в группу

group.rect(100, 100).fill('red')
group.circle(50).move(25, 25).fill('blue')

Все элементы теперь принадлежат группе и могут управляться совместно.


Трансформации группы

Одно из ключевых преимуществ g — применение трансформаций ко всем вложенным элементам:

group.translate(50, 50)
group.rotate(45)
group.scale(1.5)

Трансформация применяется ко всей группе, без необходимости изменять каждый элемент отдельно.


Управление атрибутами

group.fill('green')
group.opacity(0.5)

Некоторые атрибуты (например, fill, opacity) могут наследоваться дочерними элементами.


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

Группы могут быть вложенными:

const parentGroup = draw.group()
const childGroup = parentGroup.group()

childGroup.rect(50, 50).fill('orange')

Такая структура позволяет строить сложные иерархии.


Перемещение элементов между группами

element.addTo(group)

Элемент может быть динамически перемещён в другую группу.


Получение дочерних элементов

group.children()
group.first()
group.last()

Контейнер svg (вложенный SVG)

Назначение

Контейнер svg создаёт новый независимый SVG-контекст внутри текущего. Это аналог вложенного <svg> в чистом SVG.

Создание вложенного SVG

const nested = draw.nested()

Или:

const nested = draw.svg()

Особенности вложенного SVG

  • имеет собственную систему координат
  • не наследует трансформации родителя напрямую
  • может иметь собственные размеры
nested.size(200, 200)
nested.rect(100, 100).fill('purple')

Управление координатами

Вложенный SVG позволяет изолировать систему координат:

nested.viewbox(0, 0, 100, 100)

Это удобно для масштабируемых компонентов.


Отличие от g

Свойство g svg
Система координат общая с родителем независимая
Трансформации наследуются изолированы
Использование группировка вложенные сцены

Применение

  • создание виджетов
  • независимые графические блоки
  • сложные интерфейсы

Контейнер defs (определения)

Назначение

Контейнер defs используется для хранения элементов, которые не отображаются напрямую, но могут быть использованы повторно:

  • градиенты
  • паттерны
  • маркеры
  • символы

Создание defs

const defs = draw.defs()

Градиенты

const gradient = defs.gradient('linear', function(add) {
  add.stop(0, '#ff0000')
  add.stop(1, '#0000ff')
})

draw.rect(200, 100).fill(gradient)

Паттерны

const pattern = defs.pattern(20, 20, function(add) {
  add.rect(10, 10).fill('#ccc')
})

draw.rect(200, 200).fill(pattern)

Символы и повторное использование

const symbol = defs.symbol()
symbol.circle(50).fill('green')

draw.use(symbol).move(100, 100)
draw.use(symbol).move(200, 200)

use создаёт копию элемента без дублирования структуры.


Маркеры (например, стрелки)

const marker = defs.marker(10, 10, function(add) {
  add.path('M0,0 L10,5 L0,10 Z').fill('black')
})

draw.line(0, 0, 100, 100).marker('end', marker)

Преимущества defs

  • уменьшение дублирования
  • повышение производительности
  • централизованное управление стилями

Взаимодействие контейнеров

Комбинирование g и defs

const group = draw.group()
const gradient = draw.defs().gradient('linear', add => {
  add.stop(0, 'yellow')
  add.stop(1, 'red')
})

group.rect(100, 100).fill(gradient)

Вложенные SVG внутри групп

const group = draw.group()
const nested = group.nested()

nested.circle(50).fill('blue')

Архитектурный подход

  • g — логическая структура
  • svg — изоляция и масштабируемость
  • defs — повторное использование

Практические паттерны

Компонентный подход

Создание переиспользуемых блоков:

function createButton(draw, x, y) {
  const group = draw.group()
  group.rect(100, 40).fill('#eee')
  group.text('OK').move(30, 10)
  return group.move(x, y)
}

Использование defs для темы

const theme = defs.gradient('linear', add => {
  add.stop(0, '#222')
  add.stop(1, '#555')
})

draw.rect(300, 200).fill(theme)

Изоляция через svg

const widget = draw.nested().size(100, 100)
widget.viewbox(0, 0, 10, 10)
widget.circle(5).center(5, 5)

Внутренние особенности SVG.js

  • контейнеры являются наследниками базового класса Container

  • поддерживают методы:

    • .add()
    • .remove()
    • .children()
    • .clear()

Управление порядком элементов

group.front()
group.back()
group.forward()
group.backward()

Порядок влияет на визуальное наложение.


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

  • использование g уменьшает количество операций при трансформациях
  • defs снижает дублирование DOM
  • svg позволяет изолировать сложные сцены

Ошибки и особенности

  • трансформации g не влияют на координаты вложенного svg
  • элементы в defs не отображаются без use
  • неправильное использование вложенных SVG может усложнить масштабирование

Сравнение с чистым SVG

SVG.js полностью повторяет концепции:

  • <g>group()
  • <svg>nested() / svg()
  • <defs>defs()

При этом добавляет удобный API и управление объектами.


Итоговая структура

const draw = SVG().addTo('#app')

const defs = draw.defs()
const gradient = defs.gradient('linear', add => {
  add.stop(0, '#f06')
  add.stop(1, '#0ff')
})

const group = draw.group()
group.rect(100, 100).fill(gradient)

const nested = draw.nested().size(200, 200)
nested.circle(80).center(100, 100).fill('green')

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