Создание собственных расширений

SVG.js предоставляет мощный API для работы с векторной графикой, но его возможности можно значительно расширить за счёт создания собственных плагинов. Расширения позволяют добавлять новые методы к объектам SVG.js, работать с кастомными атрибутами и интегрировать специализированные функции для сложной графики.


Подключение и структура плагина

Плагин в SVG.js представляет собой функцию, которая принимает объект библиотеки в качестве аргумента. Стандартная структура выглядит следующим образом:

SVG.extend(SVG.Element, {
  myCustomMethod: function() {
    // Логика метода
    return this; // Возврат this для цепочек вызовов
  }
});
  • SVG.Element — базовый класс для всех элементов SVG.
  • myCustomMethod — название нового метода, доступного у любого элемента SVG.
  • Метод должен возвращать this для поддержания цепочек вызовов, характерных для SVG.js.

Добавление методов к конкретным элементам

Методы можно добавлять не ко всем элементам, а только к определённым классам, например SVG.Circle или SVG.Rect:

SVG.extend(SVG.Circle, {
  pulse: function(duration = 1000, scale = 1.5) {
    this.animate(duration).scale(scale).animate(duration).scale(1);
    return this;
  }
});

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


Работа с кастомными атрибутами

SVG.js поддерживает возможность создания собственных атрибутов через метод attr. Для удобства можно обернуть логику в плагин:

SVG.extend(SVG.Element, {
  setShadow: function(color = '#000', blur = 5, dx = 2, dy = 2) {
    const shadowId = `shadow-${Math.random().toString(36).substr(2, 9)}`;
    
    if (!this.node.ownerSVGElement.querySelector(`#${shadowId}`)) {
      const filter = this.node.ownerSVGElement.defs().element('filter').id(shadowId);
      filter.element('feDropShadow', {
        dx: dx,
        dy: dy,
        stdDeviation: blur,
        floodColor: color
      });
      this.attr('filter', `url(#${shadowId})`);
    }
    
    return this;
  }
});

Метод setShadow добавляет фильтр тени к любому элементу, используя встроенные SVG-фильтры. Такой подход демонстрирует гибкость SVG.js в работе с атрибутами и эффектами.


Создание комплексных анимаций

Плагины позволяют объединять последовательные анимации в удобные методы. Например, метод для плавного появления и движения:

SVG.extend(SVG.Rect, {
  flyIn: function(x, y, duration = 1000) {
    this.opacity(0).move(x - 50, y).animate(duration).move(x, y).opacity(1);
    return this;
  }
});

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


Расширения для групп элементов

SVG.js поддерживает группы (SVG.G), к которым тоже можно добавлять методы:

SVG.extend(SVG.G, {
  staggerFade: function(delay = 100) {
    this.each(function(i, children) {
      this.animate(500).delay(i * delay).opacity(1);
    });
    return this;
  }
});

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


Подключение внешних плагинов

Для разделения кода и повторного использования расширений стоит оформлять их в виде отдельных модулей:

// myPlugin.js
export default function(MySVG) {
  MySVG.extend(MySVG.Circle, {
    bounce: function() {
      this.animate(500, '<>').move(this.x(), this.y() - 20).animate(500, '<>').move(this.x(), this.y());
      return this;
    }
  });
}

Использование:

import SVG from '@svgdotjs/svg.js';
import myPlugin from './myPlugin.js';

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

const circle = draw.circle(50).fill('#f06').center(200, 200);
circle.bounce();

Такой подход обеспечивает модульность, позволяет поддерживать чистую архитектуру и упрощает тестирование пользовательских расширений.


Рекомендации по написанию плагинов

  1. Возврат this — обязательный для всех методов, чтобы сохранить цепочки вызовов.
  2. Минимизация изменения глобального состояния — изменения должны быть локальными для элемента.
  3. Использование встроенных методов — анимации, трансформации, атрибуты SVG.js лучше использовать через API, а не напрямую через DOM.
  4. Проверка существования фильтров и элементов — чтобы избежать дублирования элементов в defs.
  5. Модульность — каждый плагин лучше оформлять в отдельный файл и экспортировать как функцию.

Расширения позволяют создавать высокоуровневые функции для сложной графики, упрощая работу с SVG и превращая библиотеку SVG.js в полноценный инструмент для динамических визуализаций и интерактивных интерфейсов.