Установка атрибутов: .attr(), .style(), .classed(), .property()

В D3.js управление элементами DOM строится вокруг механизма выборок (selection). После выбора элементов библиотека предоставляет набор методов для изменения их атрибутов, CSS-стилей, классов и свойств. Основные инструменты для этого:

  • .attr() — работа с HTML- и SVG-атрибутами;
  • .style() — управление CSS-стилями;
  • .classed() — добавление и удаление CSS-классов;
  • .property() — работа со свойствами DOM-объектов.

Эти методы поддерживают:

  • установку фиксированных значений;
  • вычисление значений через функции;
  • динамическое изменение элементов на основе данных;
  • цепочки вызовов (method chaining).

Метод .attr()

Назначение .attr()

Метод .attr() используется для установки, чтения и удаления HTML- или SVG-атрибутов.

Общий синтаксис:

selection.attr(name, value)

Где:

  • name — имя атрибута;
  • value — значение атрибута.

Установка атрибута

d3.select("div")
  .attr("id", "container");

Результат:

<div id="container"></div>

Цепочки вызовов

D3.js активно использует цепочки методов:

d3.select("svg")
  .attr("width", 600)
  .attr("height", 400)
  .attr("viewBox", "0 0 600 400");

.attr() и SVG

Метод особенно важен при работе с SVG, поскольку SVG практически полностью управляется атрибутами.

Пример создания круга

d3.select("svg")
  .append("circle")
  .attr("cx", 100)
  .attr("cy", 100)
  .attr("r", 50);

Установка цвета

d3.select("circle")
  .attr("fill", "steelblue");

Работа с координатами

d3.select("rect")
  .attr("x", 50)
  .attr("y", 30)
  .attr("width", 200)
  .attr("height", 100);

Получение значения атрибута

Если второй аргумент отсутствует, метод возвращает значение атрибута.

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

console.log(width);

Удаление атрибута

Если передать null, атрибут удаляется.

d3.select("div")
  .attr("id", null);

Использование функций в .attr()

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

Синтаксис

.attr(name, function(d, i) {
    return value;
})

Аргументы функции:

  • d — связанные данные;
  • i — индекс элемента;
  • nodes — массив элементов;
  • this — текущий DOM-элемент.

Пример с данными

const data = [50, 120, 80];

d3.select("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("data-index", (d, i) => i)

Результат:

<div data-index="0"></div>
<div data-index="1"></div>
<div data-index="2"></div>

Работа с пользовательскими атрибутами

Атрибуты data-*

d3.selectAll("li")
  .attr("data-active", "true");

Пользовательские SVG-атрибуты

.attr("stroke-width", 3)
.attr("stroke", "black")

Метод .style()

Назначение .style()

Метод .style() управляет встроенными CSS-стилями элемента.

Синтаксис:

selection.style(name, value)

Установка CSS-стилей

d3.select("div")
  .style("color", "white")
  .style("background", "black");

Результат:

<div style="color:white; background:black;"></div>

Разница между .attr() и .style()

Через .attr()

.attr("fill", "red")

Это SVG-атрибут.


Через .style()

.style("fill", "red")

Это CSS-свойство.


Приоритет

CSS-стили часто имеют более высокий приоритет, чем атрибуты.

Например:

.attr("fill", "red")
.style("fill", "blue")

Итоговый цвет:

blue

Чтение стиля

const color = d3.select("div").style("color");

Удаление стиля

d3.select("div")
  .style("color", null);

Динамические стили

Изменение цвета по данным

const data = [10, 50, 90];

d3.select("body")
  .selectAll("div")
  .data(data)
  .enter()
  .append("div")
  .style("width", d => `${d}px`)
  .style("background", d => d > 50 ? "red" : "green");

Использование единиц измерения

D3 не добавляет единицы автоматически.

Неверно:

.style("width", 100)

Верно:

.style("width", "100px")

Работа с CSS-переменными

d3.select(":root")
  .style("--main-color", "orange");

Важность CSS-классов

Хотя .style() удобен, массовое оформление чаще выполняют через классы.

Причины:

  • разделение логики и оформления;
  • упрощение поддержки;
  • уменьшение дублирования;
  • повышение производительности.

Метод .classed()

Назначение .classed()

Метод .classed() добавляет, удаляет и проверяет CSS-классы.

Синтаксис:

selection.classed(name, value)

Добавление класса

d3.select("div")
  .classed("active", true);

Результат:

<div class="active"></div>

Удаление класса

d3.select("div")
  .classed("active", false);

Проверка класса

Если второй аргумент отсутствует:

const hasClass = d3.select("div")
  .classed("active");

Несколько классов

d3.select("div")
  .classed("visible selected highlighted", true);

Динамические классы

Пример с данными

const scores = [20, 70, 90];

d3.select("body")
  .selectAll("p")
  .data(scores)
  .enter()
  .append("p")
  .text(d => d)
  .classed("high-score", d => d > 50);

Практический пример

CSS

.high-score {
    color: red;
    font-weight: bold;
}

JavaScript

.classed("high-score", d => d > 50)

Отличие .classed() от .attr("class")

Через .attr()

.attr("class", "box")

Полностью заменяет список классов.


Через .classed()

.classed("box", true)

Работает точечно и безопасно.


Переключение классов

selection.classed("active", function() {
    return !d3.select(this).classed("active");
});

Метод .property()

Назначение .property()

.property() работает со свойствами DOM-объектов, а не с HTML-атрибутами.

Синтаксис:

selection.property(name, value)

Разница между атрибутами и свойствами

Это один из самых важных моментов при работе с DOM.

Атрибут

<input value="Hello">

HTML хранит исходное значение.


Свойство

input.value

DOM хранит текущее состояние элемента.


Работа с формами

Получение значения поля

const value = d3.select("input")
  .property("value");

Установка значения

d3.select("input")
  .property("value", "Новое значение");

Чекбоксы

Установка состояния

d3.select("input[type='checkbox']")
  .property("checked", true);

Получение состояния

const checked = d3.select("input")
  .property("checked");

Работа с disabled

d3.select("button")
  .property("disabled", true);

Работа с selected

d3.select("option")
  .property("selected", true);

Когда использовать .property()

.property() предпочтителен для:

  • value
  • checked
  • selected
  • disabled
  • selectedIndex
  • files

Когда использовать .attr()

.attr() подходит для:

  • SVG-атрибутов;
  • id;
  • data-*;
  • href;
  • src;
  • viewBox;
  • width;
  • height.

Совместное использование методов

Пример комплексного оформления

d3.select("svg")
  .append("circle")
  .attr("cx", 150)
  .attr("cy", 100)
  .attr("r", 40)
  .style("fill", "orange")
  .style("stroke", "black")
  .style("stroke-width", "2px")
  .classed("animated", true);

Работа с функцией обратного вызова

Все методы поддерживают вычисляемые значения.

Комплексный пример

const data = [30, 60, 90];

d3.select("svg")
  .selectAll("circle")
  .data(data)
  .enter()
  .append("circle")
  .attr("cx", (d, i) => i * 100 + 50)
  .attr("cy", 100)
  .attr("r", d => d / 3)
  .style("fill", d => d > 50 ? "tomato" : "steelblue")
  .classed("large", d => d > 70);

Использование this

Внутри callback-функций:

.attr("width", function() {
    console.log(this);
})

this указывает на текущий DOM-элемент.


Доступ к узлам

.style("opacity", function(d, i, nodes) {
    console.log(nodes[i]);
    return 1;
})

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

Минимизация операций DOM

Изменения DOM являются дорогими операциями.

Эффективнее:

selection
  .attr("x", 10)
  .attr("y", 20)
  .attr("width", 100);

чем многократные повторные выборки:

d3.select("rect").attr("x", 10);
d3.select("rect").attr("y", 20);
d3.select("rect").attr("width", 100);

Использование классов вместо inline-стилей

Предпочтительно:

.classed("bar", true)

вместо:

.style("fill", "steelblue")
.style("stroke", "black")
.style("stroke-width", "1px")

Частые ошибки

Путаница между .attr() и .property()

Неверно:

.attr("checked", true)

Корректнее:

.property("checked", true)

Отсутствие единиц измерения

Неверно:

.style("height", 200)

Верно:

.style("height", "200px")

Перезапись классов

Опасно:

.attr("class", "active")

Это удалит остальные классы.

Безопаснее:

.classed("active", true)

Практический пример: интерактивная диаграмма

HTML

<svg width="500" height="300"></svg>

CSS

.bar {
    fill: steelblue;
}

.bar:hover {
    fill: orange;
}

.large {
    stroke: black;
    stroke-width: 2px;
}

JavaScript

const data = [40, 90, 130, 70, 160];

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

svg.selectAll("rect")
   .data(data)
   .enter()
   .append("rect")
   .attr("x", (d, i) => i * 90)
   .attr("y", d => 300 - d)
   .attr("width", 70)
   .attr("height", d => d)
   .classed("bar", true)
   .classed("large", d => d > 100)
   .style("cursor", "pointer");

Сравнение методов

Метод Назначение Пример
.attr() HTML/SVG-атрибуты attr("width", 300)
.style() CSS-стили style("color", "red")
.classed() CSS-классы classed("active", true)
.property() DOM-свойства property("checked", true)

Рекомендации по использованию

Для SVG

Предпочтительно:

.attr()

Для оформления

Предпочтительно:

.classed()

и CSS.


Для интерактивных форм

Предпочтительно:

.property()

Для временных динамических стилей

Подходит:

.style()

Архитектурный подход в D3

Типичный современный стиль работы с D3:

  1. Данные связываются с DOM.
  2. Атрибуты вычисляются через .attr().
  3. Визуальное оформление управляется через .classed().
  4. Временные состояния задаются через .style().
  5. Интерактивные элементы формы контролируются через .property().

Такой подход обеспечивает:

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