В D3.js геометрические маркеры используются для обозначения точек
данных в диаграммах рассеяния, временных рядах, легендах и
комбинированных визуализациях. Для этого применяется генератор пути
d3.symbol(), который формирует SVG-путь
(<path d="...">) из набора стандартных графических
фигур.
Генератор символов работает как функция, возвращающая строку path-данных в формате SVG, и может динамически изменять форму и размер в зависимости от данных.
d3.symbol()d3.symbol() создаёт генератор, который преобразует два
параметра:
Возвращаемое значение используется как атрибут d в SVG
<path>.
Базовая структура:
const symbol = d3.symbol()
.type(d3.symbolCircle)
.size(64);
Использование в SVG:
svg.append("path")
.attr("d", symbol)
.attr("fill", "steelblue");
D3 предоставляет набор стандартных геометрических форм:
d3.symbolCircle — кругd3.symbolCross — крестd3.symbolDiamond — ромбd3.symbolSquare — квадратd3.symbolStar — звездаd3.symbolTriangle — треугольникd3.symbolWye — Y-образная фигураПример переключения формы:
const symbol = d3.symbol()
.type(d3.symbolStar)
.size(120);
size определяет площадь символа, а не
его ширину или высоту напрямую.
Это ключевая особенность генератора:
size влияет на масштаб пропорциональноПример:
d3.symbol().type(d3.symbolCircle).size(20)
d3.symbol().type(d3.symbolCircle).size(200)
Второй символ будет не в 10 раз шире, а примерно в √10 раз больше по линейным размерам.
Генератор символов часто применяется в визуализациях, где форма кодирует категорию, а размер — величину.
const data = [
{ x: 10, y: 20, type: d3.symbolCircle, size: 64 },
{ x: 40, y: 80, type: d3.symbolStar, size: 120 },
{ x: 70, y: 30, type: d3.symbolDiamond, size: 90 }
];
svg.selectAll("path")
.data(data)
.enter()
.append("path")
.attr("d", d => d3.symbol()
.type(d.type)
.size(d.size)())
.attr("transform", d => `translate(${d.x},${d.y})`)
.attr("fill", "black");
Особенность вызова: генератор возвращает функцию, поэтому требуется
дополнительный вызов ().
Тип символа может задаваться функцией, зависящей от данных:
const symbol = d3.symbol()
.type(d => d.type)
.size(d => d.size);
Использование:
.attr("d", symbol)
Такой подход позволяет унифицировать создание элементов без ручного пересоздания генератора для каждого узла.
Помимо встроенных символов, type может быть определён
как функция, возвращающая путь:
const customSymbol = d3.symbol()
.type((context, size) => {
const r = Math.sqrt(size / Math.PI);
context.moveTo(0, -r);
context.arc(0, 0, r, 0, 2 * Math.PI);
});
Функция получает:
context — SVG path contextsize — площадь символаЭто позволяет полностью контролировать геометрию.
При работе с символами важно учитывать, что:
size даёт визуально разные размеры для
разных формПример корректировки:
const symbol = d3.symbol()
.type(d3.symbolTriangle)
.size(d => d.size * 1.2);
После генерации пути внешний вид определяется SVG-атрибутами:
.attr("fill", "#4a90e2")
.attr("stroke", "#333")
.attr("stroke-width", 1)
Дополнительно возможно использование:
opacity для плотности отображенияclass для CSS-стилизацииfilter для эффектов (тень, размытие)Типичный сценарий — диаграмма рассеяния:
svg.selectAll("path")
.data(points)
.enter()
.append("path")
.attr("d", d3.symbol().type(d3.symbolCircle).size(80))
.attr("transform", d => `translate(${x(d.x)},${y(d.y)})`)
.attr("fill", "tomato");
При добавлении категорий:
const shape = d => {
if (d.group === "A") return d3.symbolCircle;
if (d.group === "B") return d3.symbolSquare;
return d3.symbolTriangle;
};
При десятках тысяч точек:
d3.symbol() внутри .attr("d")
становится затратнойОптимизированный вариант:
const circle = d3.symbol().type(d3.symbolCircle).size(64);
svg.selectAll("path")
.data(data)
.enter()
.append("path")
.attr("d", circle);
Символы часто позиционируются через
d3.scaleLinear():
.attr("transform", d =>
`translate(${xScale(d.x)},${yScale(d.y)})`
)
При изменении масштаба графика символы остаются фиксированного размера в пикселях, что отличает их от геометрически масштабируемых элементов.
Символы активно применяются в легендах:
legend.append("path")
.attr("d", d3.symbol().type(d.type).size(80))
.attr("transform", "translate(10,10)");
Это позволяет унифицировать визуальный язык графика и легенды.
Анимация символов:
selection.transition()
.duration(500)
.attr("d", d3.symbol().type(d3.symbolStar).size(120));
Также возможно плавное изменение через пересоздание пути при каждом кадре перехода.
Несмотря на это, d3.symbol() остаётся универсальным
инструментом для компактного кодирования категориальных данных в
SVG-визуализациях.