Векторная графика в SVG поддерживает повторное использование уже
созданных элементов без их дублирования в DOM. Для этого применяется
механизм ссылок, реализуемый через элемент <use>. В
библиотеке SVG.js этот механизм представлен удобным API
для клонирования и переиспользования объектов.
В отличие от прямого копирования (clone()),
<use> создаёт ссылку на исходный элемент. Это
означает:
Исходный элемент создаётся обычным способом, после чего используется
метод use():
const draw = SVG().addTo('#canvas').size(400, 400)
const rect = draw.rect(100, 100).fill('#3498db')
const copy1 = draw.use(rect).move(120, 0)
const copy2 = draw.use(rect).move(0, 120)
const copy3 = draw.use(rect).move(120, 120)
Ключевые особенности:
rect остаётся единственным исходным объектомcopy1, copy2, copy3 — ссылки,
а не полноценные копииМетод use() создаёт SVG-элемент
<use>, который содержит ссылку на оригинал через
атрибут href (или xlink:href в старых версиях
SVG):
<use href="#SvgjsRect1001" x="120" y="0"></use>
Сам оригинал автоматически получает уникальный id, если
он не задан вручную.
use() от
clone()| Характеристика | use() |
clone() |
|---|---|---|
| Тип копии | Ссылка | Полная копия |
| Связь с оригиналом | Да | Нет |
| Изменения оригинала | Отражаются | Не отражаются |
| Производительность | Выше | Ниже |
| Использование памяти | Меньше | Больше |
Пример сравнения:
const original = draw.circle(50).fill('red')
// ссылка
const ref = draw.use(original).move(100, 0)
// копия
const clone = original.clone().move(200, 0)
original.fill('blue')
Результат:
ref станет синимclone останется краснымКаждый экземпляр <use> можно независимо
трансформировать:
const star = draw.polygon('50,0 21,90 98,35 2,35 79,90').fill('gold')
draw.use(star).move(100, 0)
draw.use(star).move(200, 0).scale(0.5)
draw.use(star).move(300, 0).rotate(45)
Трансформации применяются к <use>, а не к
оригиналу.
Любые изменения исходного элемента автоматически распространяются:
const circle = draw.circle(80).fill('green')
const a = draw.use(circle).move(100, 0)
const b = draw.use(circle).move(200, 0)
circle.fill('orange')
После изменения:
a, b) изменят цвет на
оранжевыйВажно учитывать:
<use>, могут переопределять
оригиналПример:
const rect = draw.rect(100, 100).fill('blue')
const u1 = draw.use(rect).move(120, 0)
const u2 = draw.use(rect).move(240, 0).fill('red')
Результат:
u1 — синийu2 — красный (локальное переопределение)use() работает не только с примитивами, но и с
группами:
const group = draw.group()
group.circle(50).fill('red')
group.rect(50, 50).move(25, 25).fill('blue')
draw.use(group).move(100, 0)
draw.use(group).move(200, 0)
Это особенно полезно для сложных составных объектов.
<defs>Часто используемые элементы можно помещать в
<defs>:
const defs = draw.defs()
const shape = defs.rect(80, 80).fill('#2ecc71')
draw.use(shape).move(50, 50)
draw.use(shape).move(150, 150)
Преимущества:
<use>1. Нельзя напрямую изменить содержимое
<use>
const u = draw.use(rect)
// не сработает как ожидается
u.fill('red')
Причина: <use> не содержит реального содержимого,
а лишь ссылается на него.
2. События
События можно навешивать как на оригинал, так и на
<use>:
rect.on('click', () => console.log('original'))
const u = draw.use(rect)
u.on('click', () => console.log('use'))
3. Работа с ID
Если оригинал удаляется, <use> теряет ссылку:
rect.remove()
После этого:
<use> перестанут отображатьсяconst tile = draw.rect(40, 40).fill('#9b59b6')
for (let x = 0; x < 5; x++) {
for (let y = 0; y < 5; y++) {
draw.use(tile).move(x * 50, y * 50)
}
}
Преимущества:
Анимации можно применять как к оригиналу, так и к ссылкам:
const circle = draw.circle(50).fill('blue')
draw.use(circle).move(100, 0).animate().rotate(360, true)
draw.use(circle).move(200, 0).animate().scale(1.5)
Каждый <use> анимируется независимо.
use()Оптимальные сценарии:
Когда не подходит:
// НЕэффективно
for (let i = 0; i < 1000; i++) {
draw.circle(10).move(i * 2, 0)
}
// эффективно
const dot = draw.circle(10)
for (let i = 0; i < 1000; i++) {
draw.use(dot).move(i * 2, 0)
}
Во втором случае:
use()