Активные и неактивные дуги: анимация выделения

Визуальные компоненты Nivo для круговых и радиальных диаграмм опираются на концепцию взаимодействия состояний сегментов: каждый сектор может находиться в активном, неактивном или нейтральном состоянии. Эта модель используется для управления визуальным фокусом пользователя и построения интерактивной анимации, где внимание направляется на конкретную дугу, а остальные элементы приглушаются.

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


Каждый сектор диаграммы в Nivo описывается набором геометрических параметров: углы начала и конца, радиус, цвет и идентификатор. Поверх этого базового описания накладываются состояния:

Активная дуга — сегмент, который находится в фокусе взаимодействия. Характеризуется увеличением радиуса, усилением контраста и возможным изменением тени или смещения.

Неактивные дуги — остальные сегменты, которые теряют визуальную значимость. Обычно они становятся полупрозрачными или слегка уменьшаются визуально.

Ключевой принцип — сохранение структуры данных при изменении только визуального представления.


Базовые параметры выделения в Nivo Pie

Компонент ResponsivePie предоставляет набор свойств, отвечающих за поведение активных и неактивных сегментов:

  • activeOuterRadiusOffset — увеличение внешнего радиуса активного сегмента
  • activeInnerRadiusOffset — изменение внутреннего радиуса (для кольцевых диаграмм)
  • inactiveOuterRadiusOffset — смещение неактивных сегментов внутрь
  • inactiveOuterRadiusOpacity — прозрачность неактивных дуг
  • inactiveInnerRadiusOffset — дополнительная деформация внутреннего радиуса

Комбинация этих параметров формирует эффект «выдвижения» активного сектора на передний план.

<ResponsivePie
    data={data}
    margin={{ top: 40, right: 80, bottom: 80, left: 80 }}
    innerRadius={0.6}
    activeOuterRadiusOffset={8}
    inactiveOuterRadiusOffset={4}
    inactiveOuterRadiusOpacity={0.4}
    animate={true}
    motionConfig="gentle"
/>

В этом примере активный сектор визуально «поднимается», а остальные теряют насыщенность.


Механика hover-состояния

Интерактивность чаще всего строится вокруг события наведения. Nivo использует внутренний механизм управления состоянием activeIndex или activeId, который изменяется при событиях мыши.

Типовой сценарий:

  1. Пользователь наводит курсор на сектор
  2. Сектор становится активным
  3. Остальные получают состояние inactive
  4. Происходит анимационный переход между состояниями

Дополнительно можно управлять активным сегментом вручную:

const [activeId, setActiveId] = useState(null);

<ResponsivePie
    data={data}
    activeId={activeId}
    onMouseEn ter={(datum) => setActiveId(datum.id)}
    onMouseLe ave={() => setActiveId(null)}
/>

Такой подход позволяет синхронизировать график с внешними компонентами интерфейса.


Анимация переходов между состояниями

Nivo использует react-spring для построения плавных переходов между геометрическими состояниями дуг. При смене активного сегмента происходит интерполяция:

  • радиуса
  • угловых координат
  • прозрачности
  • смещения

Анимация не является дискретной, что позволяет избежать резких скачков при переключении активных элементов.

motionConfig="stiff"

Конфигурации анимации определяют поведение переходов:

  • gentle — плавные и медленные переходы
  • stiff — быстрые, более резкие изменения
  • wobbly — с небольшим эффектом «пружины»

Визуальное выделение через масштабирование дуг

Помимо стандартных offset-параметров, часто применяется стратегия масштабирования через кастомные слои или модификацию радиуса.

Активная дуга может:

  • увеличивать внешний радиус
  • изменять толщину кольца
  • получать дополнительный stroke

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

const CustomLayer = ({ arcs, activeId }) => {
    return arcs.map(arc => {
        const isActive = arc.data.id === activeId;

        return (
            <path
                key={arc.data.id}
                d={arc.path}
                fill={arc.color}
                opacity={isActive ? 1 : 0.3}
                transform={isActive ? "scale(1.05)" : "scale(1)"}
            />
        );
    });
};

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


Управление неактивными дугами через прозрачность

Одним из наиболее эффективных способов визуального разделения является управление opacity. В Nivo это реализуется через параметры неактивного состояния, однако часто требуется более тонкая настройка.

Логика обычно строится так:

  • активный сектор: opacity = 1
  • соседние сектора: opacity = 0.5–0.7
  • остальные: opacity = 0.2–0.4
inactiveOuterRadiusOpacity={0.35}

В более сложных интерфейсах прозрачность может зависеть от расстояния до активного сектора в данных или от категории.


Синхронизация активных дуг с внешним состоянием

В реальных интерфейсах график редко существует изолированно. Активная дуга часто синхронизируется с:

  • таблицами данных
  • карточками описания
  • фильтрами
  • легендой

Пример синхронизации:

const [active, setActive] = useState(null);

<ResponsivePie
    data={data}
    activeOuterRadiusOffset={10}
    onMouseEn ter={(d) => setActive(d.id)}
    onMouseLe ave={() => setActive(null)}
/>

<DataPanel activeId={active} />

Изменение активного сектора становится триггером для обновления других частей интерфейса.


Использование кастомных арок для усиления эффекта

Стандартная визуализация Nivo ограничена геометрией SVG-дуг. Для более выразительных эффектов применяется переопределение слоя arcLinkLabels или создание полностью кастомного слоя.

Расширенные эффекты включают:

  • тень, следящая за активной дугой
  • градиентное усиление цвета
  • динамическое смещение центра диаграммы
const CustomArc = ({ arc }) => {
    return (
        <g>
            <path d={arc.path} fill={arc.color} />
            {arc.isActive && (
                <path
                    d={arc.path}
                    fill="none"
                    stroke={arc.color}
                    strokeWidth={4}
                />
            )}
        </g>
    );
};

Поведение при множественной активации

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

Логика в этом случае меняется:

  • activeIds вместо activeId
  • массив состояний
  • проверка принадлежности к активному набору
const isActive = activeIds.includes(arc.data.id);

Визуально такие дуги могут не увеличиваться, а лишь менять цветовую интенсивность, чтобы избежать перегрузки композиции.


Оптимизация анимации при большом количестве сегментов

При работе с большими наборами данных (50–200 сегментов) важно контролировать производительность анимации.

Практики оптимизации:

  • отключение лишних transition эффектов
  • уменьшение motion complexity
  • использование более простого easing
  • ограничение active-only анимации без затрагивания всех сегментов
animate={true}
motionConfig="gentle"

Дополнительно можно анимировать только активный сектор, оставляя остальные статичными.


Комбинирование состояния активности с цветовой логикой

Цвет часто используется как дополнительный канал выделения. При активации дуги происходит:

  • усиление насыщенности
  • изменение яркости
  • переход в акцентный цвет

Неактивные элементы переходят в приглушённую палитру, что усиливает иерархию данных.

Логика может строиться на функциях:

fill: (d) =>
    d.id === activeId
        ? d.color
        : lighten(d.color, 0.4)

Глубина восприятия через многослойную анимацию

Наиболее сложные визуальные схемы строятся через комбинацию:

  • геометрического увеличения дуги
  • изменения прозрачности соседей
  • смещения центра диаграммы
  • усиления границ

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