D3.js работает поверх DOM и SVG, позволяя напрямую связывать данные с графическими примитивами и управлять их атрибутами через декларативные цепочки вызовов. Базовые фигуры в D3.js строятся на SVG-элементах, где каждый графический объект представляет собой узел DOM с набором атрибутов, определяющих геометрию и визуальное поведение.
D3.js не вводит собственный графический движок. Вместо этого используется SVG (Scalable Vector Graphics), где каждая фигура описывается через XML-подобные теги. D3 лишь управляет созданием и модификацией этих тегов.
Ключевая особенность SVG:
Создание SVG-контейнера:
const svg = d3.select("body")
.append("svg")
.attr("width", 600)
.attr("height", 400);
Этот контейнер становится сценой, внутри которой размещаются все базовые фигуры.
Прямоугольник является одной из наиболее часто используемых форм в визуализации: столбчатые диаграммы, контейнеры, блоки интерфейса.
Основные атрибуты:
Создание прямоугольника:
svg.append("rect")
.attr("x", 50)
.attr("y", 50)
.attr("width", 120)
.attr("height", 80)
.attr("fill", "steelblue");
Прямоугольник часто связывается с данными через
data():
const data = [30, 80, 45, 60];
svg.selectAll("rect")
.data(data)
.enter()
.append("rect")
.attr("x", (d, i) => i * 60)
.attr("y", d => 200 - d)
.attr("width", 40)
.attr("height", d => d)
.attr("fill", "orange");
В этом случае высота каждой фигуры определяется значением массива, что формирует базовую столбчатую диаграмму.
Круг определяется координатами центра и радиусом.
Атрибуты:
svg.append("circle")
.attr("cx", 150)
.attr("cy", 100)
.attr("r", 40)
.attr("fill", "tomato");
При работе с данными круги часто используются в точечных диаграммах:
const points = [10, 40, 80, 120];
svg.selectAll("circle")
.data(points)
.enter()
.append("circle")
.attr("cx", d => d)
.attr("cy", 150)
.attr("r", 6);
Изменение радиуса через данные позволяет строить пузырьковые диаграммы, где размер кодирует дополнительную переменную.
Эллипс расширяет круг, вводя отдельные радиусы по осям X и Y.
Атрибуты:
svg.append("ellipse")
.attr("cx", 200)
.attr("cy", 120)
.attr("rx", 60)
.attr("ry", 30)
.attr("fill", "purple");
Эллипсы применяются для:
Изменение соотношения rx и ry позволяет
управлять «сжатием» формы по одной из осей.
Линия задаётся двумя точками: начальной и конечной.
Атрибуты:
svg.append("line")
.attr("x1", 50)
.attr("y1", 50)
.attr("x2", 300)
.attr("y2", 200)
.attr("stroke", "black")
.attr("stroke-width", 2);
Линии часто используются для:
В связке с данными:
const pairs = [
{ x1: 10, y1: 10, x2: 200, y2: 80 },
{ x1: 20, y1: 100, x2: 250, y2: 150 }
];
svg.selectAll("line")
.data(pairs)
.enter()
.append("line")
.attr("x1", d => d.x1)
.attr("y1", d => d.y1)
.attr("x2", d => d.x2)
.attr("y2", d => d.y2)
.attr("stroke", "gray");
Polyline представляет собой набор соединённых отрезков без замыкания фигуры.
Атрибут:
svg.append("polyline")
.attr("points", "10,10 60,40 120,20 180,80")
.attr("fill", "none")
.attr("stroke", "green");
В D3.js координаты часто формируются динамически:
const points = [
[10, 10],
[60, 40],
[120, 20],
[180, 80]
];
svg.append("polyline")
.attr("points", points.map(p => p.join(",")).join(" "))
.attr("fill", "none")
.attr("stroke", "blue");
Polyline применяется для:
Polygon аналогичен polyline, но автоматически замыкает фигуру, соединяя последнюю точку с первой.
svg.append("polygon")
.attr("points", "50,10 90,50 70,100 30,80")
.attr("fill", "lightblue")
.attr("stroke", "black");
С данными:
const shape = [
[50, 10],
[90, 50],
[70, 100],
[30, 80]
];
svg.append("polygon")
.attr("points", shape.map(d => d.join(",")).join(" "))
.attr("fill", "rgba(100, 150, 255, 0.5)");
Polygon используется для:
Основная сила D3.js заключается в механизме data binding. Каждый SVG-элемент может быть напрямую связан с элементом массива данных, что позволяет синхронизировать состояние визуализации и данных.
Типовой цикл:
Пример универсального подхода:
const dataset = [
{ type: "rect", x: 10, y: 10, w: 80, h: 40 },
{ type: "circle", cx: 200, cy: 60, r: 30 }
];
const elements = svg.selectAll("*")
.data(dataset)
.enter();
elements.append(d => d.type)
.attr("x", d => d.x)
.attr("y", d => d.y)
.attr("width", d => d.w)
.attr("height", d => d.h)
.attr("cx", d => d.cx)
.attr("cy", d => d.cy)
.attr("r", d => d.r);
Такой подход демонстрирует гибкость SVG-рендеринга, где тип элемента может определяться динамически.
Все SVG-элементы поддерживают набор визуальных атрибутов:
svg.append("rect")
.attr("x", 40)
.attr("y", 40)
.attr("width", 100)
.attr("height", 60)
.attr("fill", "#4a90e2")
.attr("stroke", "#1f3a93")
.attr("stroke-width", 3)
.attr("opacity", 0.8);
Стили могут задаваться и через CSS-классы:
svg.append("circle")
.attr("cx", 100)
.attr("cy", 100)
.attr("r", 25)
.attr("class", "node");
.node {
fill: #e74c3c;
stroke: #2c3e50;
}
Базовые фигуры в D3.js часто комбинируются с трансформациями SVG:
svg.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", 50)
.attr("height", 50)
.attr("transform", "translate(100,100) rotate(45)");
Трансформации позволяют:
Базовые примитивы часто используются совместно для построения сложных визуальных структур.
Пример композиции:
svg.append("rect")
.attr("x", 50)
.attr("y", 50)
.attr("width", 200)
.attr("height", 100)
.attr("fill", "#ecf0f1");
svg.append("circle")
.attr("cx", 150)
.attr("cy", 100)
.attr("r", 30)
.attr("fill", "#3498db");
svg.append("line")
.attr("x1", 50)
.attr("y1", 50)
.attr("x2", 250)
.attr("y2", 150)
.attr("stroke", "#2c3e50");
Такие композиции формируют основу для более сложных визуализаций, включая графы, диаграммы и интерактивные панели.