Символы и паттерны: defs, symbol, pattern

В SVG-спецификации элемент defs выполняет роль контейнера для объектов, которые не должны напрямую отображаться на странице, но используются повторно через ссылки. Визуальные примитивы, градиенты, паттерны, символы и фильтры часто определяются внутри defs, после чего применяются через id.

Ключевая особенность:

  • содержимое defs не участвует в рендеринге
  • элементы становятся доступны через url(#id)
  • обеспечивается повторное использование без дублирования DOM-узлов

В контексте D3.js работа с defs строится программно, через создание SVG-элементов:

const svg = d3.select("svg");

const defs = svg.append("defs");

После этого внутри defs размещаются паттерны, символы или фильтры, которые затем используются в визуализации.


Структура и назначение symbol в D3.js

Генератор d3.symbol предназначен для создания SVG-путей, представляющих геометрические маркеры. Он применяется в диаграммах рассеяния, точечных графиках и любых визуализациях, где требуется унифицированное обозначение категорий.

Базовый принцип:

  • d3.symbol() возвращает генератор пути
  • параметр type задаёт форму
  • параметр size определяет площадь фигуры
const symbol = d3.symbol()
  .type(d3.symbolCircle)
  .size(64);

Применение в связке с данными:

svg.selectAll("path")
  .data(data)
  .enter()
  .append("path")
  .attr("d", d3.symbol().type(d => d.type).size(100))
  .attr("transform", d => `translate(${d.x}, ${d.y})`);

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


Набор стандартных символов D3.js

D3 предоставляет фиксированный набор базовых форм, реализованных как константы:

  • d3.symbolCircle
  • d3.symbolSquare
  • d3.symbolDiamond
  • d3.symbolTriangle
  • d3.symbolCross
  • d3.symbolStar
  • d3.symbolWye

Каждая форма представляет собой параметризованный алгоритм генерации SVG path.

Особенность работы:

  • символы не являются готовыми SVG-элементами
  • каждый вызов генерирует строку d
  • визуальная масштабируемость зависит от параметра size, а не от transform: scale

Масштабирование и параметр size

Параметр size в d3.symbol задаёт площадь фигуры в квадратных пикселях, а не линейный размер.

d3.symbol().type(d3.symbolStar).size(200);

При увеличении size форма сохраняет пропорции, изменяя только масштаб.

Практическая особенность:

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

Привязка символов к данным

Типичная схема использования символов в графиках:

svg.selectAll("path.symbol")
  .data(dataset)
  .enter()
  .append("path")
  .attr("class", "symbol")
  .attr("d", d => symbol.type(d.category)())
  .attr("transform", d => `translate(${x(d.x)}, ${y(d.y)})`);

Здесь:

  • category определяет форму
  • координаты задаются через шкалы x и y
  • один генератор используется многократно

Визуальная кодировка достигается без изменения структуры DOM.


SVG pattern как система заливки

Элемент <pattern> определяет повторяющийся фрагмент, используемый как заливка или обводка. Он размещается внутри defs и применяется через fill: url(#patternId).

Базовая структура:

const defs = svg.append("defs");

defs.append("pattern")
  .attr("id", "diagonalHatch")
  .attr("width", 6)
  .attr("height", 6)
  .attr("patternUnits", "userSpaceOnUse")
  .append("path")
  .attr("d", "M0,6 L6,0")
  .attr("stroke", "black");

Применение:

svg.append("rect")
  .attr("width", 200)
  .attr("height", 200)
  .attr("fill", "url(#diagonalHatch)");

Координатные системы паттернов

patternUnits определяет систему координат:

  • userSpaceOnUse — абсолютные координаты SVG
  • objectBoundingBox — относительные координаты 0..1

При использовании objectBoundingBox паттерн масштабируется под объект:

.attr("patternUnits", "objectBoundingBox")

Дополнительный контроль даёт patternTransform, позволяющий вращать и масштабировать узор:

.attr("patternTransform", "rotate(45)")

Генерация паттернов в D3.js

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

Пример точечного паттерна:

const pattern = defs.append("pattern")
  .attr("id", "dots")
  .attr("width", 10)
  .attr("height", 10)
  .attr("patternUnits", "userSpaceOnUse");

pattern.append("circle")
  .attr("cx", 3)
  .attr("cy", 3)
  .attr("r", 1.5);

Такие конструкции используются для:

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

Комбинирование symbol и pattern

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

Сценарии:

  • символы в легендах поверх паттернов
  • паттерны как фон категорий
  • символы как маркеры поверх залитых областей

Пример наложения:

svg.append("rect")
  .attr("fill", "url(#dots)");

svg.append("path")
  .attr("d", d3.symbol().type(d3.symbolTriangle).size(80))
  .attr("transform", "translate(50,50)");

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

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

  • категории в stacked charts
  • сегменты pie chart
  • области на географических картах
  • различение состояний данных

Преимущество:

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

Производительность при использовании defs

Работа с defs и повторяющимися элементами требует учёта DOM-структуры:

  • каждый уникальный pattern увеличивает SVG-дерево
  • symbol генерирует path на каждый элемент данных
  • чрезмерное количество уникальных узоров снижает производительность

Оптимизация достигается через:

  • переиспользование id
  • ограничение количества уникальных паттернов
  • кеширование генераторов d3.symbol
  • группировку визуальных типов

Структура масштабируемых визуальных систем

Комбинация defs, symbol и pattern формирует основу расширяемых визуализаций:

  • defs хранит все переиспользуемые сущности
  • symbol обеспечивает компактные маркеры данных
  • pattern формирует текстурные слои и заливки

Такая архитектура позволяет отделять геометрию от данных и управлять визуальной сложностью через декларативные конструкции SVG и D3.js.