SVG манипуляция

Atomico предоставляет лёгкий и декларативный способ работы с компонентами в стиле Web Components. Одной из сильных сторон библиотеки является интеграция с SVG, что позволяет создавать интерактивные и динамические графические элементы напрямую через JSX-подобный синтаксис.

Создание SVG-элементов

В Atomico SVG создаются как обычные JSX-элементы. Для этого используется функция c для объявления компонентов и возвращается дерево элементов:

import { c } from "atomico";

function Icon() {
    return (
        <svg width="50" height="50" viewBox="0 0 24 24">
            <circle cx="12" cy="12" r="10" fill="blue" />
            <line x1="12" y1="6" x2="12" y2="18" stroke="white" strokeWidth="2" />
            <line x1="6" y1="12" x2="18" y2="12" stroke="white" strokeWidth="2" />
        </svg>
    );
}

customElements.define("my-icon", c(Icon));

Ключевые моменты:

  • Атрибуты SVG указываются напрямую, без camelCase для свойств (например, stroke-width, cx).
  • Любые стандартные SVG-теги (circle, rect, path, line, polygon) поддерживаются нативно.
  • Для динамических значений используется обычная интерполяция {}.

Управление состоянием

Atomico позволяет связать атрибуты SVG с реактивными свойствами с помощью useState. Это открывает возможности для анимации и интерактивных графиков:

import { c, useState } from "atomico";

function AnimatedCircle() {
    const [radius, setRadius] = useState(10);

    return (
        <svg width="100" height="100" onCl ick={() => setRadius(radius === 10 ? 40 : 10)}>
            <circle cx="50" cy="50" r={radius} fill="orange" />
        </svg>
    );
}

customElements.define("animated-circle", c(AnimatedCircle));

Особенности:

  • Состояние компонента (radius) напрямую обновляет атрибут r круга.
  • События DOM (onClick) можно использовать как обычные обработчики JSX.
  • Изменения состояния автоматически перерисовывают SVG без ручного управления DOM.

Использование ref для прямой манипуляции

Иногда требуется доступ к нативному DOM-узлу SVG для сложных анимаций или интеграции с библиотеками вроде GSAP. Atomico поддерживает useRef:

import { c, useRef, useEffect } from "atomico";
import gsap from "gsap";

function AnimatedLine() {
    const lineRef = useRef();

    useEffect(() => {
        gsap.to(lineRef.current, { x: 50, duration: 2, repeat: -1, yoyo: true });
    }, []);

    return (
        <svg width="100" height="100">
            <line ref={lineRef} x1="0" y1="50" x2="100" y2="50" stroke="red" stroke-width="4" />
        </svg>
    );
}

customElements.define("animated-line", c(AnimatedLine));

Важные моменты:

  • ref возвращает ссылку на нативный SVG-элемент.
  • Любые внешние библиотеки анимации можно применять к SVG-узлам напрямую.
  • useEffect позволяет инициализировать анимацию после монтирования компонента.

Динамическая генерация SVG

Для построения графиков и диаграмм часто необходимо динамически создавать элементы. Atomico позволяет это делать через массивы и map:

import { c } from "atomico";

function BarChart({ data }) {
    return (
        <svg width="200" height="100">
            {data.map((value, index) => (
                <rect
                    key={index}
                    x={index * 30}
                    y={100 - value}
                    width="20"
                    height={value}
                    fill="teal"
                />
            ))}
        </svg>
    );
}

customElements.define("bar-chart", c(BarChart));

Особенности:

  • Каждый элемент получает key для корректной перерисовки.
  • Атрибуты x, y, width, height могут быть вычислены динамически.
  • Позволяет создавать полностью реактивные графические компоненты, изменяющиеся при обновлении данных.

Стилизация SVG

Стили SVG можно задавать несколькими способами:

  1. Через атрибут style:
<circle cx="50" cy="50" r="40" style={{ fill: "green", stroke: "black", strokeWidth: 3 }} />
  1. Через CSS внутри компонента:
import { c, css } from "atomico";

function StyledCircle() {
    return (
        <svg width="100" height="100">
            <circle class="my-circle" cx="50" cy="50" r="40" />
        </svg>
    );
}

StyledCircle.styles = css`
    .my-circle {
        fill: purple;
        stroke: gold;
        stroke-width: 4;
    }
`;

customElements.define("styled-circle", c(StyledCircle));
  • Стили полностью инкапсулируются в компоненте.
  • Можно комбинировать с динамическими классами и реактивными свойствами для анимации цвета или формы.

Интерактивные события

SVG в Atomico поддерживает любые стандартные события DOM: onClick, onMouseEnter, onMouseLeave, onMouseMove и т.д. Это делает возможным создание сложных интерфейсов без использования сторонних библиотек:

function HoverCircle() {
    const [color, setColor] = useState("red");

    return (
        <svg width="100" height="100">
            <circle
                cx="50"
                cy="50"
                r="40"
                fill={color}
                onMouseEn ter={() => setColor("blue")}
                onMouseLe ave={() => setColor("red")}
            />
        </svg>
    );
}

customElements.define("hover-circle", c(HoverCircle));
  • Состояние напрямую меняет атрибут fill.
  • Обработчики событий привязываются на уровне JSX, не требуя прямого DOM-доступа.

Итоговые возможности

Atomico превращает работу с SVG в декларативный процесс, сохраняя доступ к нативным возможностям DOM. Поддерживаются:

  • Динамическое создание и обновление элементов.
  • Управление атрибутами через реактивное состояние.
  • Прямой доступ к DOM через ref для сложных анимаций.
  • Полная инкапсуляция стилей и событий.

Такой подход упрощает создание интерактивной графики и визуализаций без лишнего кода и сложных API.