Генератор дуги: d3.arc()

Генератор дуги в D3.js представляет собой специализированный компонент для построения SVG-путей, описывающих дуги и сегменты кольцевых диаграмм. Он используется для создания круговых и секторных визуализаций, включая pie chart, donut chart, кольцевые прогресс-бары и сложные радиальные структуры.

Основная функция генератора заключается в преобразовании набора параметров (углы, радиусы, отступы) в строку path-данных SVG. Эти данные затем интерпретируются браузером для отрисовки геометрии.


Функция d3.arc() возвращает генератор дуг, который строит SVG path на основе заданных параметров:

  • начальный угол (startAngle)
  • конечный угол (endAngle)
  • внутренний радиус (innerRadius)
  • внешний радиус (outerRadius)

Каждый вызов генератора возвращает строку, совместимую с атрибутом d в SVG <path>.

const arc = d3.arc();

const pathData = arc({
  innerRadius: 50,
  outerRadius: 100,
  startAngle: 0,
  endAngle: Math.PI / 2
});

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


Геометрическая модель дуги

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

Радиусы

  • innerRadius — внутренний радиус
  • outerRadius — внешний радиус

Если innerRadius = 0, формируется сектор круга. Если значение больше нуля, формируется кольцевой сегмент.

Углы

  • startAngle — начальный угол в радианах
  • endAngle — конечный угол в радианах

Углы отсчитываются от положительной оси X по часовой стрелке.


Базовая конфигурация генератора

Генератор дуг поддерживает установку значений по умолчанию через цепочку методов:

const arc = d3.arc()
  .innerRadius(40)
  .outerRadius(80)
  .startAngle(0)
  .endAngle(Math.PI);

При таком подходе объект дуги можно вызывать без параметров:

const path = arc();

Формирование кольцевых диаграмм

Наиболее частое применение генератора — построение кольцевых диаграмм.

Базовый сектор

const arc = d3.arc()
  .innerRadius(0)
  .outerRadius(100);

const data = {
  startAngle: 0,
  endAngle: Math.PI / 3
};

const path = arc(data);

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


Кольцевая диаграмма (donut chart)

const arc = d3.arc()
  .innerRadius(60)
  .outerRadius(100);

const segment = arc({
  startAngle: 0,
  endAngle: Math.PI / 2
});

Увеличение внутреннего радиуса создаёт эффект «дырки» в центре.


Работа с d3.pie() и d3.arc()

Генератор дуг часто используется совместно с d3.pie(), который вычисляет углы на основе данных.

const pie = d3.pie();

const data = [10, 20, 30];

const arcs = pie(data);

Каждый элемент массива преобразуется в объект:

{
  value: 10,
  startAngle: ...,
  endAngle: ...
}

Далее d3.arc() превращает эти данные в SVG-пути:

const arc = d3.arc()
  .innerRadius(50)
  .outerRadius(100);

const paths = arcs.map(d => arc(d));

Центрирование и трансформация координат

По умолчанию дуга строится относительно центра (0,0). При визуализации используется перенос координат через transform:

svg.append("g")
  .attr("transform", "translate(200,200)");

Это позволяет размещать диаграмму в произвольной точке SVG-контейнера.


Padding между сегментами

Параметр padAngle задаёт зазор между сегментами:

const arc = d3.arc()
  .innerRadius(50)
  .outerRadius(100)
  .padAngle(0.02);

Эффект:

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

Скругление углов

Параметр cornerRadius позволяет сглаживать углы сегментов:

const arc = d3.arc()
  .innerRadius(60)
  .outerRadius(120)
  .cornerRadius(6);

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


Построение сложных радиальных структур

Генератор дуг используется не только для диаграмм, но и для построения:

  • радиальных меню
  • прогресс-индикаторов
  • солнечных диаграмм (sunburst-like элементы)
  • многослойных визуализаций

Пример многослойного кольца:

const arc = d3.arc()
  .innerRadius(d => d.y0)
  .outerRadius(d => d.y1);

const segments = nodes.map(d => arc(d));

Использование функций доступа (accessor functions)

Параметры генератора могут задаваться как функции:

const arc = d3.arc()
  .innerRadius(d => d.inner)
  .outerRadius(d => d.outer)
  .startAngle(d => d.a0)
  .endAngle(d => d.a1);

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


Работа с анимацией

Генератор дуг часто используется в переходах (transitions), где изменяются углы или радиусы.

path.transition()
  .duration(750)
  .attrTween("d", function(d) {
    const interpolate = d3.interpolate(d.previous, d.current);
    return t => arc(interpolate(t));
  });

Интерполяция обеспечивает плавное изменение формы сегмента.


Внутренняя структура SVG path

Результат работы генератора представляет собой набор команд:

  • M — moveTo
  • L — lineTo
  • A — arcTo
  • Z — закрытие контура

Пример сегмента:

M x y
A r r 0 0 1 x y
L x y
Z

Эти команды формируют замкнутую геометрическую фигуру.


Обработка полного круга

При значении углов, формирующих полный круг, генератор корректно обрабатывает замыкание:

const arc = d3.arc()
  .innerRadius(0)
  .outerRadius(100);

arc({
  startAngle: 0,
  endAngle: 2 * Math.PI
});

Результат — полный круг, а не артефакт разрыва.


Особенности работы с радианами

Все углы задаются в радианах, что требует преобразования при работе с градусами:

const degToRad = deg => deg * (Math.PI / 180);

const arc = d3.arc()
  .startAngle(degToRad(0))
  .endAngle(degToRad(90));

Использование радианов обеспечивает согласованность с математической моделью окружности.


Вложенные и составные дуги

Генератор поддерживает построение многослойных визуализаций, где каждый слой определяется разными радиусами:

const arc = d3.arc();

const layers = [
  { inner: 0, outer: 50 },
  { inner: 50, outer: 100 },
  { inner: 100, outer: 150 }
];

const paths = layers.map(layer =>
  arc({
    innerRadius: layer.inner,
    outerRadius: layer.outer,
    startAngle: 0,
    endAngle: Math.PI / 2
  })
);

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

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

const arc = d3.arc()
  .innerRadius(40)
  .outerRadius(90);

selection.selectAll("path")
  .data(data)
  .join("path")
  .attr("d", arc);

Такой подход снижает накладные расходы и упрощает структуру кода.


Поведение при некорректных значениях

Генератор устойчив к частичным данным, но некорректные параметры могут привести к:

  • отрицательным радиусам
  • обратным углам (endAngle < startAngle)
  • вырожденным сегментам

В таких случаях SVG-путь может быть пустым или неотображаемым.


Применение в композиционных визуализациях

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

  • sunburst диаграммы
  • radial tree layouts
  • circular packing
  • кольцевые индикаторы состояния

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