**Как использовать D3 для создания `линий`, `областей`, `наборов областей`, `пирогов` и `символов` и других часто используемых графических форм.** В этом разделе будут рассмотрены функции D3, которые используются для рисования линий и других форм:
Кривые:
! image-20220817100236300
Секторы пирога:
! image-20220817100142837
И символы:
! image-20220817100119285
### SVG
Формы в приведенных выше примерах создаются с помощью элементов SVG path
. Каждый path
имеет атрибут d
, который определяет форму пути (путь данных).
Путь данных состоит из списка команд, описывающих форму пути, например M0,80L100,100L200,30L300,50L400,40L500,80
. Каждая буква, например M
(переместиться в) или L
(нарисовать линию до), описывает команду. Подробнее см. спецификацию SVG.
Вы можете создать свои собственные данные пути, но D3 предоставляет генераторы функций, которые выполняют эту работу за вас. Они представлены в различных формах:
Line | Создает данные пути для множества линий (обычно используется для линейных графиков) |
---|---|
Area | Создает данные пути для областей (обычно используется для стековых линейных графиков и потоковых графиков) |
Stack | Создает стековые данные из множества серий данных |
Arc | Создает данные пути для дуги (обычно используется для пироговых графиков) |
Pie | Создает данные углов для пироговых графиков из массива данных |
--- | --- |
Давайте рассмотрим каждую из них подробнее: |
Генератор линий D3 создает данные пути в виде строки на основе массива координат.
Генератор линий создается с помощью команды d3.line()
:
let lineGenerator = d3.line();
d3.line()
возвращает функцию, которая принимает массив координат и возвращает строку данных пути.
Давайте определим массив координат:
let points = [
[0, 80],
[100, 100],
[200, 30]
];
Вызовите массив координат в lineGenerator
:
var pathData = lineGenerator(points);
lineGenerator
создает последовательность команд M
и L
на основе массива точек.
Вы можете использовать pathData
для установки атрибута d
элемента path
:
d3.select('path')
.attr('d', pathData);
По умолчанию каждый элемент массива представляет координату, определенную двумерным массивом (например,
[[0, 100], [100, 100]]
). Методы .x
и .y
позволяют указать, как генератор линий интерпретирует каждый элемент массива.
Если вы используете
line()
для указанияx
илиy
, соответствующий доступный метод будет установлен в указанный функциональный или числовой параметр и вернётся генератор линий. Предположим, что наша данные представляют собой массив объектов:
let data = [
{value: 80},
{value: 100},
{value: 30},
{value: 40},
{value: 20}
];
```Тогда мы можем использовать `x` и `y`, чтобы конкретизировать, как генератор будет интерпретировать данные.
let lineGenerator = d3.line()
.x(function(d, i) {
return i * 10; // Возвращает индекс объекта умноженный на 10;
})
.y(function(d) {
return d.value; // Возвращает значение свойства value
объекта;
});
// Используем lineGenerator
для генерации.
let line = lineGenerator(data);
d3.select('path')
.attr('d', line);

> На изображении видно, что ось `x` сильно сжата. Мы можем использовать **d3.scaleLinear()** для линейного масштабирования области:
let xScale = d3.scaleLinear().domain([0, 6]).range([0, 600]); let lineGenerator = d3.line() .x(function(d, i) { return xScale(i); // return i * 10; }) .y(function(d) { return d.value; });

> Функции, передаваемые методам `.x` и `.y` (и аналогичным методам), называются **доступными функциями**.
### .curve()
Если вы хотите нарисовать кривую, вы можете использовать метод `.curve()` для выбора способа интерполяции.
let lineGenerator = d3.line() .x(function(d, i) { return xScale(i); }) .y(function(d) { return d.value; }) .curve(d3.curveCardinal); // Интерполяция между двумя точками

#### .defined()
> Если в данных присутствуют аномалии (например, отсутствие определённых полей), можно использовать `.defined` для пропуска этих аномалий.
let data = [
{value: 80},
{value: 100},
{value: 30},
null,
{value: 40},
]; {value: 20}
];
Линейный генератор может выдавать ошибки парсинга во время производства. Для решения этой проблемы можно использовать метод .defined()
. Этот метод принимает функцию, которая возвращает true
, если данные определены, и false
, если нет. Если функция возвращает false
, линейный генератор пропустит этот элемент:
lineGenerator
.defined(function(d) {
return d !== null;
});
После вызова этого генератора для отрисовки, на линии может появиться пустое пространство (в данном случае, это просто пропуск): ! изображение
По умолчанию, генераторы форм создают данные SVG-пути. Однако их можно настроить для рисования на элементе холста с помощью функции .context()
:
var context = d3.select('canvas').node().getContext('2d');
lineGenerator.context(context);
context.strokeStyle = '#999';
context.beginPath();
lineGenerator(points);
context.stroke();
Создает новый радиальный линейный генератор с использованием стандартных настроек. Радиальный линейный генератор эквивалентен стандартному кардиоидальному линейному генератору, за исключением того, что доступ к x и y заменяется доступом к углу и радиусу. Радиальная линия всегда ориентирована относительно ⟨0,0⟩.
var radialLineGenerator = d3.lineRadial();
var points = [
[0, 80],
[Math.PI * 0.25, 80],
[Math.PI * 0.5, 30],
[Math.PI * 0.75, 80],
[Math.PI, 80],
[Math.PI * 1.25, 80],
[Math.PI * 1.5, 80],
[Math.PI * 1.75, 80],
[Math.PI * 2, 80]
];
``````markdown
var pathData = radialLineGenerator(points);
lineRadial и line предоставляют методы curve() и defined(), а также позволяют задать свои собственные angle и radius. Поэтому, если ваши данные представлены в виде массива объектов, вы можете использовать следующий подход:
// Примечание: этот код требует доработки
let points = [
{a: Math.PI * 0.75, r: 80},
// ...
];
radialLineGenerator
.angle(function(d) {
return d.a;
})
.radius(function(d) {
return d.r;
});
Кривые обычно не создаются и не используются напрямую, а передаются в методы
line.curve
иarea.curve
. В предыдущем разделе о линиях мы уже кратко рассмотрели эту тему, и в этом разделе мы углубимся в детали. Линия определяется как последовательность двумерных точек [x, y], и область определяется аналогично верхней и нижней линиями, но задача конвертации дискретного представления в непрерывную форму остается. Это означает, как интерполировать (добавлять больше вершин) между точками. Для достижения различных целей интерполяции, предлагается множество методов для генерации кривых.
let lineGenerator = d3.line()
.curve(d3.curveCatmullRom.alpha(0.5));
let points = [
[0, 80],
[100, 100],
[200, 30],
[300, 80],
[400, 20],
];
let pathData = lineGenerator(points);
d3.select('path')
.attr('d', pathData);
> Следующее может помочь понять, какие функции реализованы, без необходимости углубленного понимания. Для внутренней реализации интересующиеся могут обратиться к B-spline, P-spline, bezier и другим темам из компьютерной графики — [Википедия](https://en.wikipedia.org/wiki/B-spline).
- curveBasis
- curveBasisClosed
- curveBasisOpen
- curveBumpX
- curveBumpY
- curveBundle
- curveCardinal
- curveCardinalClosed
- curveCardinalOpen
- curveCatmullRom
- curveCatmullRomClosed
- curveCatmullRomOpen
- curveLinear
- curveLinearClosed
- curveMonotoneX
- curveMonotoneY
- curveNatural
- curveStep
- curveStepAfter
- curveStepBefore
// Генератор линии let lineGenerator = d3.line(); // Данные let points = [ [0, 80], [100, 100], [200, 30], [300, 80], [400, 20], ]; // Встроенные фабрики кривых (функции) let curves = ['curveBasis', 'curveBasisClosed', 'curveBasisOpen', 'curveBumpX', 'curveBumpY', 'curveBundle', 'curveCardinal', 'curveCardinalClosed', 'curveCardinalOpen', 'curveCatmullRom', 'curveCatmullRomClosed', 'curveCatmullRomOpen', 'curveLinear', 'curveLinearClosed', 'curveMonotoneX', 'curveMonotoneY', 'curveNatural', 'curveStep', 'curveStepAfter', 'curveStepBefore']; // Последовательное рендеринг let i = 0; setInterval(function(){ let pathData = lineGenerator.curve(d3[curves[i]])(points); d3.select('path') .attr('d', pathData); d3.select('text') .text(function(d) { return 'd3.' + curves[i]; }); i++; if(i === curves.length - 1){ i = 0; } }, 800)
## Области `Areas` область (площадь) генератор (`area generator`) создается двумя линиями, и результатом является путь между этими линиями.
Область (площадь) генератор создает область (площадь), как показано на диаграмме. Область (площадь) определяется двумя границами (сплайны или ломаные линии). Обычно, **две линии имеют одинаковые значения x (x0 = x1), но различаются значениями y (y0 и y1); наиболее часто y0 определяется как константа, представляющая ноль. Верхняя линия (topline) определяется x1 и y1 и отображается первой; нижняя линия (baseline) определяется x0 и y0 и отображается второй, точки отображаются в обратном порядке**. Используя кривые линии, это создает многогранник, ориентированный по часовой стрелке.
### d3. area([x][, y0][, y1])
// Генератор области let areaGenerator = d3. area(); // Координаты точек let points = [ [0, 60], [100, 100], [200, 40], [300, 60], [400, 40], [500, 90] ]; // Создание пути области let pathData = areaGenerator(points); // Отображение пути d3. select('path') . attr('d', pathData);
! [изображение](https://user-images. githubusercontent. com/32726183/199643305-4f54da59-23b4-44dc-b558-e61bca14d3d9. png)
### Areas-x, y координаты
- `x` Если указан x, то x0 устанавливается на x, а x1 на null, и возвращается этот генератор области. Если x не указан, то возвращается текущий x0 доступник.
- `x0` Если указан x, то x0 доступник устанавливается на указанную функцию или число, и возвращается этот генератор области.Если x не указан, то возвращается текущий x0 доступник, по умолчанию это: d[0]
- `x1` Если указан x, то x1 доступник устанавливается на указанную функцию или число, и возвращается этот генератор области. Если x не указан, то возвращается текущий x1 доступник, по умолчанию это null, что означает, что предыдущее значение x0 должно использоваться для x1.
- `y` Если указан y, то y0 устанавливается на y, а y1 на null, и возвращается этот генератор области. Если y не указан, то возвращается текущий y0 доступник.
- `y0` (нижняя линия baseline) Если указан y, то y0 доступник устанавливается на указанную функцию или число, и возвращается этот генератор области. Если y не указан, то возвращается текущий y0 доступник, по умолчанию это: 0
- `y1` (верхняя линия topline) Если указан y, то y1 доступник устанавливается на указанную функцию или число, и возвращается этот генератор области. Если y не указан, то возвращается текущий y1 доступник, по умолчанию это: d[1]
Простое объяснение: x, x0, x1 — это координаты x для каждого границы. Если задано x, то x0 и x1 будут равны x. y, y0, y1 — это координаты y для каждого границы. Если задано y, то y0 и y1 будут равны y.
Например, когда задано **y0 (базовая линия)**:
// Генератор области let areaGenerator = d3.area() .y0(150); // Устанавливаем базовую линию y на 150. let points = [ [0, 60], [100, 100], [200, 40], [300, 60], [400, 40], [500, 90] ]; // Генерация данных пути области let pathData = areaGenerator(points); // Отрисовка d3.select("body").append("svg") .attr("width", 600) .attr("height", 300) .append("path") .attr("d", pathData) .attr("fill", "steelblue");
select('path')
. attr('d', pathData);
```

Все доступные функции могут быть заданы как функции (решают проблемы структуры данных, преобразования и т. д.):
```javascript
// Генератор области
let areaGenerator = d3.area();
// Сетка данных точек
let points = [
{x: 0, y0: 30, y1: 60},
{x: 100, y0: 80, y1: 100},
{x: 200, y0: 20, y1: 40},
{x: 300, y0: 20, y1: 60},
{x: 400, y0: 10, y1: 40},
{x: 500, y0: 50, y1: 90}
];
// Конфигурация генератора области
areaGenerator
.x(function(d) {
return d.x;
})
.y0(function(d) {
return d.y0;
})
.y1(function(d) {
return d.y1;
});
// Генерация данных пути области
let pathData = areaGenerator(points);
// Отрисовка
d3.select('path')
.attr('d', pathData);
```

### Контекст
> Правила использования контекста и линий аналогичны.
### areaRadial
- angle — угол, эквивалентен x. **Внимание: обычно используется угол, а не отдельные начальный и конечный углы.**
- startAngle — начальный угол, эквивалентен x0. **Внимание: обычно используется угол, а не отдельные начальный и конечный углы.**
- endAngle — конечный угол, эквивалентен x1. **Внимание: обычно используется угол, а не отдельные начальный и конечный углы.**
- radius — радиус.
- innerRadius — внутренний радиус.
- outerRadius — внешний радиус.
- defined — определение по умолчанию (может обрабатывать исключительные данные, пропуская их, см. предыдущее описание).
- curve — настройка кривой, по умолчанию curveLinear.
- context — контекст рисования, см.раздел line.
> Генератор области радиуса похож на генератор области, но точки преобразуются из углов (начальная точка по умолчанию направлена на 12 часов и движется по часовой стрелке) и радиусов, а не из x и y:
```
let points = [
{angle: 0, r0: 30, r1: 70},
{angle: Math.PI * 0.5, r0: 30, r1: 70},
{angle: Math.PI, r0: 30, r1: 70},
{angle: Math.PI * 1.5, r0: 30, r1: 70},
{angle: Math.PI * 2, r0: 30, r1: 70},
];
let radialAreaGenerator = d3.radialArea()
.angle(function(d) {
return d.angle;
})
.innerRadius(function(d) {
return d.r0;
})
.outerRadius(function(d) {
return d.r1;
});
let pathData = radialAreaGenerator(points);
d3.select('path')
.attr('d', pathData);
```

## Дуги
### Arc()
**Используя генератор дуг (Arc generator), можно создать сектора круга или кольца, такие как круговые диаграммы или кольцевые диаграммы. Путь данных генерируется на основе углов и радиусов.**
Используйте следующий метод для создания генератора дуг:
```
let arcGenerator = d3.arc();
```
Затем передайте необходимые параметры startAngle (начальный угол, измеряется в радианах), endAngle (конечный угол), innerRadius (внутренний радиус) и outerRadius (внешний радиус):
> Примечание: радиан — это единица измерения угла, полный оборот равен 2π радианам, 360° = 2π радиан, поэтому 1 радиан ≈ 57.3°; 1° = π/180 радиан ≈ 0.01745 радиан, полный оборот равен 2π радианам, прямой угол (180°) равен π радианам, прямой угол (90°) равен π/2 радианам.
```
let arcGenerator = d3.arc();
// Данные для необходимых параметров
var arcs = [
{startAngle: 0, endAngle: 10, innerRadius: 10, outerRadius: 60},
];
// Привязка атрибута d к элементу path
d3.select('g')
.selectAll('path')
.data(arcs)
.join('path')
.attr('d', arcGenerator);
```

Если параметры начального угла (startAngle), конечного угла (endAngle), внутреннего радиуса (innerRadius) и внешнего радиуса (outerRadius) не требуют изменения для каждого элемента данных, можно использовать следующий подход:
```
arcGenerator
.innerRadius(10)
.outerRadius(60);
let arcs = [
{startAngle: 0, endAngle: 10}
];
d3.select('g')
.selectAll('path')
.data(arcs)
.join('path')
.attr('d', arcGenerator);
```
Также можно настроить радиус закругления (cornerRadius) и расстояние между сегментами (padAngle и padRadius). **Параметры padAngle и padRadius определяют расстояние между соседними сегментами, умножая их значения. В приведенном выше примере расстояние между сегментами равно 0.02 * 100 = 2.**
```
arcGenerator
.innerRadius(10)
.outerRadius(60)
.padAngle(0.02)
.padRadius(100)
.cornerRadius(4);
let arcs = [
{startAngle: 0, endAngle: Math.PI / 2},
{startAngle: Math.PI / 2, endAngle: Math.PI},
];
d3.select('g')
.selectAll('path')
.data(arcs)
.join('path')
.attr('d', arcGenerator);
```

Если структура данных изменяется, например, изменяются имена параметров, можно определить доступники для `startAngle` и `endAngle`. Например:
```
// Новая структура данных, изменены имена параметров
let arcs = [
{new_startAngle: 0, new_endAngle: Math.PI / 2},
{new_startAngle: Math.PI / 2, new_endAngle: Math.PI},
];
// Создание доступников
arcGenerator
.startAngle(function(d) {
return d.new_startAngle;
})
.endAngle(function(d) {
return d.new_endAngle;
});
```
### arc.centroid()
Вычисляет центральную точку линии, соединяющей центр окружности с центром дуги, заданной параметрами **[x, y]**. Аргументы произвольны; они просто передаются вместе с объектом в функции-доступники дугового генератора. Чтобы быть согласованным с сгенерированной дугой, функции-доступники должны быть детерминированными, то есть возвращать одинаковые значения при одинаковых аргументах. Центральная точка определяется как **(startAngle + endAngle) / 2** и **(innerRadius + outerRadius) / 2**. Это полезно, например, при добавлении меток с текстовой информацией.
```
let arcGenerator = d3.arc()
.innerRadius(10)
.outerRadius(60);
let arcData = [
{label: '1', startAngle: 0, endAngle: Math.PI / 2},
{label: '2', startAngle: Math.PI / 2, endAngle: Math.PI},
];
// Рисование дуги
d3.select('g')
.selectAll('path')
.data(arcData)
.join('path')
.attr('d', arcGenerator);
// Создание текста и использование centroid
d3.select('g')
.selectAll('text')
.data(arcData)
.join('text')
.each(function(d) {
let centroid = arcGenerator.centroid(d); // Использование centroid
d3.select(this)
.attr('x', centroid[0])
.attr('y', centroid[1])
.attr('dy', '0.33em')
.text(d.label);
});
```

## Пирожки
### Пирожок **Пирожковый генератор не создаёт формы напрямую, а вычисляет необходимые углы для представления набора табличных данных в виде пирожка или кольца; затем эти углы можно передать генератору дуги.** Для заданного массива данных `data` сгенерировать круговую диаграмму и вернуть массив объектов, представляющих углы каждого сегмента диаграммы. Параметры включают:- `data` — входные данные; массив данных, содержащий соответствующие элементы.
- `value` — числовое значение сегмента.
- `index` — индекс сегмента, начинающийся с нуля.
- `startAngle` — начальный угол сегмента в радианах.
- `endAngle` — конечный угол сегмента в радианах.
- `padAngle` — угол между соседними сегментами в радианах.
```js
let pieGenerator = d3.pie();
let data = [10, 40, 50];
let arcData = pieGenerator(data);
console.log(arcData);
// ==============array
// [
// {
// "data": 10,
// "endAngle": 6.283185307179586,
// "index": 2,
// "padAngle": 0,
// "startAngle": 5.654866776461628,
// "value": 10,
// },
// ...
// ]
```
Затем можно использовать генератор `arc` для создания строк пути:
```js
let arcGenerator = d3.arc()
.innerRadius(20)
.outerRadius(100);
// Используем path для отрисовки
d3.select('g')
.selectAll('path')
.data(arcData)
.enter()
.append('path')
.attr('d', arcGenerator);
```

### Конфигурационные функции для круговых диаграмм
- `value`
- `sortValues`
- `startAngle`
- `endAngle`
- `padAngle`
#### Начальный и конечный углы
Функции `startAngle()` и `endAngle()` используются для настройки начального и конечного углов круговой диаграммы. Например, чтобы нарисовать только половину круга:
```js
let pieGenerator = d3.pie()
.startAngle(0)
.endAngle(Math.PI);
// Используем arc для создания строк пути, а также path для отрисовки
let data = [10, 40, 50];
let arcData = pieGenerator(data);
let arcGenerator = d3.arc()
.innerRadius(20)
.outerRadius(100);
d3.select('g')
.selectAll('path')
.data(arcData)
.enter()
.append('path')
.attr('d', arcGenerator);
```
### Значение
Когда мы задаем значение, мы устанавливаем значение доступника на указанную функцию или число и возвращаем этот генератор круговой диаграммы:```js
// Генератор круговой диаграммы
let pieGenerator = d3.pie()
.value(function(d) { return d.val });
// Данные
let list = [
{ name: 'wlove1', val: 40 },
{ name: 'wlove2', val: 50 },
{ name: 'wlove3', val: 10 }
];
// Используем Pie для создания arcData
```javascript
let arcData = pieGenerator(list);
// arc генератор и указание внутреннего и внешнего радиусов
let arcGenerator = d3.arc()
.innerRadius(20)
.outerRadius(100);
// Используем g элемент для отрисовки path
d3.select('g')
.selectAll('path')
.data(arcData)
.enter()
.append('path')
.attr('d', arcGenerator);
```

### sortValues() и sort() для сортировки
**sortValues()** Если указан способ сравнения (compare), то значение компаратора устанавливается на указанный функционал и возвращается этот генератор круговой диаграммы. Если способ сравнения не указан, то возвращается текущий компаратор значений, по умолчанию это убывающий порядок значений (если по умолчанию убывающий, то результат будет таким, как на изображении выше):
```javascript
function(a, b) {
return b - a;
}
```
Когда мы меняем на возрастающий порядок (можно заметить, что изображение ниже противоположно изображению выше):
```javascript
let pieGenerator = d3.pie()
.value(function(d) { return d.val })
.sortValues(function(a, b) { return a - b }); // Возрастающий порядок
// .sortValues(function(a, b) { return b - a });
let list = [
{ name: 'wlove1', val: 40 },
{ name: 'wlove2', val: 50 },
{ name: 'wlove3', val: 10 }
];
let arcData = pieGenerator(list);
let arcGenerator = d3.arc()
.innerRadius(20)
.outerRadius(100);
d3.select('g')
.selectAll('path')
.data(arcData)
.enter()
.append('path')
.attr('d', arcGenerator);
```

**sort()** Если не указан, то используется убывающий порядок значений, как выше; если указан, то устанавливается компаратор данных на указанный функционал и возвращается этот генератор круговой диаграммы.
> **localeCompare()** Метод возвращает число, которое указывает, находится ли строка-ссылка перед или после строки-сравнения или равна ей. Если ссылочная строка находится перед сравнительной строкой, то возвращается отрицательное число; если ссылочная строка находится после сравнительной строки, то возвращается положительное число; если строки равны, то возвращается 0.
```javascript
let pieGenerator = d3.pie()
.sort(function(a, b) { return a.localeCompare(b) });
```
```value(function(d) { return d.val })
.sort((a, b) => a.name.localeCompare(b.name)); //сортировка
let list = [
{ name: 'wlove1', val: 40 },
{ name: 'wlove2', val: 50 },
{ name: 'wlove3', val: 10 }
];
let arcData = pieGenerator(list);
let arcGenerator = d3.arc()
.innerRadius(20)
.outerRadius(100);
// Используем path для отрисовки
d3.select('g')
.selectAll('path')
.data(arcData)
.enter()
.append('path')
.attr('d', arcGenerator);
``````markdown
selectAll('path')
.data(arcData)
.enter()
.append('path')
.attr('d', arcGenerator);
// Используем элемент text для отображения текста, а centroid для получения координат
d3.select('g')
.selectAll('text')
.data(arcData)
.join('text')
.each(function(d) {
var centroid = arcGenerator.centroid(d);
d3.select(this)
.attr('x', centroid[0])
.attr('y', centroid[1])
.attr('dy', '0.33em')
.text(d.data.name);
});
```

## Стеки
Как и генератор пирогов (`Pies`), генератор стеков не создает формы напрямую. Вместо этого он вычисляет положение, а затем вы можете передать его в генератор областей (`Areas`) или использовать напрямую, например, для позиционирования полос.
Генератор стеков принимает массив объектов и для каждого объекта создает массив значений. Каждый массив содержит нижнюю и верхнюю границы для каждого значения данных. Вычисления нижней и верхней границ выполняются таким образом, чтобы каждый ряд располагался над предыдущим рядом.
```javascript
var colors = ['#FBB65B', '#513551', '#de3163'];
var data = [
{apricots: 120, blueberries: 180, cherries: 100},
{apricots: 60, blueberries: 185, cherries: 105},
{apricots: 100, blueberries: 215, cherries: 110},
];```markdown
{apricots: 80, blueberries: 230, cherries: 105},
{apricots: 120, blueberries: 240, cherries: 105}
];
var stack = d3.stack()
.keys(['apricots', 'blueberries', 'cherries']);
var stackedSeries = stack(data);
// Создаем элемент g для каждого ряда
var g = d3.select('g')
.selectAll('.series')
.data(stackedSeries)
.enter()
.append('g')
.classed('series', true)
.style('fill', function(d, i) {
return colors[i];
});
// Для каждого ряда создаем элемент rect для каждого дня
g.selectAll('rect')
.data(function(d) {
return d;
})
.join('rect')
.attr('width', function(d) {
return d[1] - d[0];
})
.attr('x', function(d) {
return d[0];
})
.attr('y', function(d, i) {
return i * 20;
})
.attr('height', 19);
```

При использовании генератора областей, стеки представляют собой:
```javascript
var yScale = d3.scaleLinear().domain([0, 600]).range([height, 0]);
``````markdown
range([200, 0]);
var areaGenerator = d3.area()
.x(function(d, i) {
return i * 100;
})
.y0(function(d) {
return yScale(d[0]);
})
.y1(function(d) {
return yScale(d[1]);
});
var colors = ['#FBB65B', '#513551', '#de3163'];
var data = [
{day: 'Пн', apricots: 120, blueberries: 180, cherries: 100},
{day: 'Вт', apricots: 60, blueberries: 185, cherries: 105},
{day: 'Ср', apricots: 100, blueberries: 215, cherries: 110},
{day: 'Чт', apricots: 80, blueberries: 230, cherries: 105},
{day: 'Пт', apricots: 120, blueberries: 240, cherries: 105}
];
var stack = d3.stack()
.keys(['apricots', 'blueberries', 'cherries']);
var stackedSeries = stack(data);
d3.select('g')
.selectAll('path')
.data(stackedSeries)
.join('path')
.style('fill', function(d, i) {
return colors[i];
})
.attr('d', areaGenerator)
```

``````markdown

https://observablehq.com/@d3/streamgraph-transitions
```javascript
let yScale = d3.scaleLinear().domain([0, 800]).range([200, 0]);
let areaGenerator = d3.area()
.x(function(d, i) {
return i * 50;
})
.y0(function(d) {
return yScale(d[0]);
})
.y1(function(d) {
return yScale(d[1]);
})
.curve(d3.curveCatmullRom);
let colors = ['#FBB65B', '#FBCF3B', '#de3163', '#4A79A4'];
let data = [
{day: 1, абрикосы: 100, бананы: 140, вишня: 105, сливы: 80},
{day: 2, абрикосы: 110, бананы: 150, вишня: 105, сливы: 40},
{day: 3, абрикосы: 130, бананы: 160, вишня: 115, сливы: 50},
{day: 4, абрикосы: 110, бананы: 200, вишня: 110, сливы: 90},
{day: 5, абрикосы: 100, бананы: 220, вишня: 105, сливы: 120},
{day: 6, абрикосы: 120, бананы: 240, вишня: 105, сливы: 150},
{day: 7, абрикосы: 80, бананы: 230, вишня: 105, сливы: 150},
{day: 8, абрикосы: 100, бананы: 215, вишня: 110, сливы: 100},
{day: 9, абрикосы: 60, бананы: 185, вишня: 105, сливы: 150},
{day: 10, абрикосы: 120, бананы: 180, вишня: 130, сливы: 150}
];
let stack = d3.stack()
.keys(['абрикосы', 'бананы', 'вишня', 'сливы'])
.order(d3.stackOrderInsideOut)
.offset(d3.stackOffsetWiggle);
let stackedSeries = stack(data);
d3.select('g')
.selectAll('path')
.data(stackedSeries)
.join('path')
.style('fill', function(d, i) {
return colors[i];
})
.attr('d', areaGenerator);
```
```markdown

## Символы
### symbol()
Символьный генератор создает путь для данных, используемых в визуализации данных.
```Символ всегда центрируется на ⟨0,0⟩; символы перемещаются в различные позиции с помощью трансформаций (см. :[SVG](https://www.w3.org/TR/SVG/coords.html#TransformAttribute), [Canvas](https://html.spec.whatwg.org/multipage/#transformations)).
```javascript
// Символьный генератор типа star размером 80
let symbolGenerator = d3.symbol()
.type(d3.symbolStar)
.size(80);
// Вершины данных
let points = [
[0, 80],
[100, 100],
[200, 30],
[300, 50],
[400, 40],
[500, 80]
];
// Построение строки данных пути
let pathData = symbolGenerator();
// Использование path для отрисовки
d3.select('g')
.selectAll('path')
.data(points)
.join('path')
.attr('transform', function(d) {
return 'translate(' + d + ')';
})
.attr('d', pathData);
```

### Поддерживаемые типы символов
- symbolCircle круговой символ
- symbolCross крестовый символ
- symbolDiamond ромбовый символ для заполнения
- symbolDiamond2 ромбовый символ для обводки
- symbolSquare квадратный символ для заполнения
- symbolSquare2 квадратный символ для обводки
- symbolStar пятиконечный символ
- symbolTriangle треугольный символ
- symbolTriangle2 треугольный символ
- symbolWye Y-образный символ
- symbolX X-образный символ
```javascript
// Символьный генератор размером 100
let symbolGenerator = d3.symbol()
.size(100);
// Список типов символов
let symbolTypes = ['symbolCircle', 'symbolCross', 'symbolDiamond', 'symbolSquare', 'symbolStar', 'symbolTriangle', 'symbolWye'];
// Установка функции масштабирования для преобразования данных в визуальные переменные
let xScale = d3.scaleLinear().domain([0, symbolTypes.length - 1]).range([0, 700]);
``````markdown
// Использование g-path для отрисовки всех символов
d3.select('g')
.selectAll('path')
.data(symbolTypes)
.join('path')
.attr('transform', function(d, i) {
return 'translate(' + xScale(i) + ', 0)';
})
.attr('d', function(d) {
symbolGenerator
.type(d3[d]);
return symbolGenerator();
});
// Используем g-text для отображения всех символов с текстовыми описаниями
d3.select('g')
.selectAll('text')
.data(symbolTypes)
.join('text')
.attr('transform', function(d, i) {
return 'translate(' + xScale(i) + ', 40)';
})
.text(function(d) {
return 'd3.' + d;
});
```

Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )