Spec-Zone.ru › D3.js 7

Изменения в D3 7.0

Выпущено 11 июня 2021 года.

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

D3 теперь поставляется в виде чистых ES-модулей и требует Node.js 12 или выше. Для получения дополнительной информации, пожалуйста, прочтите часто задаваемые вопросы Синдре Соруса.

d3.bin теперь игнорирует значения null. d3.ascending и d3.descending больше не рассматривают null как сравнимое значение.

Шкалы порядковых значений теперь используют InternMap для областей значений; значения области теперь уникальны, преобразуясь в примитивное значение через object.valueOf вместо преобразования в строку через object.toString.

Используемые объекты (например, живой NodeList, такой как element.childNodes) преобразуются в массивы в d3.selectAll и selection.selectAll.

Изменения в D3 6.0

Выпущено 26 августа 2020 года.

D3 теперь использует собственные коллекции (Map и Set) и принимает итерируемые объекты. d3.group и d3.rollup — это мощные новые функции агрегирования, которые заменяют d3.nest и прекрасно работают с d3-hierarchy и d3-selection. Также в d3-array есть множество новых вспомогательных функций, таких как d3.greatest, d3.quickselect и d3.fsum.

D3 теперь передает события непосредственно слушателям, заменяя глобальную переменную d3.event и приравнивая D3 к обычной JavaScript и большинству других фреймворков.

d3-delaunay (на основе отличного Delaunator Владимира Агафонкина) заменяет d3-voronoi, предлагая значительные улучшения производительности, надёжности и поиска. И есть новая библиотека d3-geo-voronoi для сферических (географических) данных! d3-random значительно расширена и включает быстрый линейный конгруэнтный генератор для генерации случайных чисел с заданным зерном. В d3-chord добавлены новые макеты для направленных и транспонированных диаграмм со взаимными соединениями. d3-scale добавляет новый тип радиальной шкалы.

… и различные другие небольшие улучшения. Более 450 примеров были обновлены до D3 6.0!

d3-array

  • Принимает итерируемые объекты.
  • Добавлена d3.group.
  • Добавлена d3.groups.
  • Добавлена d3.index.
  • Добавлена d3.indexes.
  • Добавлена d3.rollup.
  • Добавлена d3.rollups.
  • Добавлена d3.maxIndex.
  • Добавлена d3.minIndex.
  • Добавлена d3.greatest.
  • Добавлена d3.greatestIndex.
  • Добавлена d3.least.
  • Добавлена d3.leastIndex.
  • Добавлена d3.bin.
  • Добавлена d3.count.
  • Добавлена d3.cumsum.
  • Добавлена d3.fsum.
  • Добавлена d3.Adder.
  • Добавлена d3.quantileSorted.
  • Добавлена d3.quickselect.
  • Добавлена bisector.center.
  • Допускается более двух итерируемых объектов для d3.cross.
  • Принимаются неотсортированные входные данные с d3.quantile.
  • Исправлена ошибка в array.sort в Safari.
  • Исправлены пороги bin, чтобы игнорировать NaN.
  • Исправлен d3.ticks, чтобы не возвращать отметки вне области.
  • Улучшена производительность d3.median.

Подробности см. на https://observablehq.com/@d3/d3-array-2-0.

d3-brush

  • Добавлена event.mode.
  • Изменена brush.on на передачу события непосредственно слушателям.
  • Улучшено взаимодействие с несколькими касаниями (двумя касаниями).

d3-chord

  • Добавлена d3.chordDirected.
  • Добавлена d3.chordTranspose.
  • Добавлена d3.ribbonArrow.
  • Добавлена ribbon.padAngle.
  • Добавлена ribbon.sourceRadius.
  • Добавлена ribbon.targetRadius.

d3-delaunay

  • Добавлена d3.Delaunay.

d3-drag

  • Изменена drag.on на передачу события непосредственно слушателям.

d3-force

  • Добавлен аргумент iterations к simulation.tick.
  • Добавлена forceCenter.strength.
  • Добавлена forceSimulation.randomSource.
  • Все встроенные силы теперь полностью детерминированы (включая «дрожание» совпадающих узлов).
  • Незначительно улучшен стандартный макет phyllotaxis, смещённый на половину радиуса.
  • Улучшено сообщение об ошибке, когда ссылка на связь указывает на неизвестный узел.
  • force.initialize теперь получает случайный источник.
  • Исправлена ошибка при инициализации узлов с фиксированными позициями.

d3-format

  • Изменено значение знака минус по умолчанию на минус (−) вместо дефиса (-).
  • Исправлена проблема с форматированием десятичных знаков d для чисел, больших или равных 1e21.

d3-geo

  • Исправлено обрезание некоторых вырожденных полигонов.

d3-hierarchy

  • Принимает итерируемые объекты.
  • Добавлен node[Symbol.iterator]; теперь иерархии являются итерируемыми.
  • Добавлен node.find.
  • Изменено node.each на передачу индекса обхода.
  • Изменено node.eachAfter на передачу индекса обхода.
  • Изменено node.eachBefore на передачу индекса обхода.
  • Исправлен d3.packSiblings для очень больших окружностей.
  • Исправлена ошибка деления на ноль в d3.treemapBinary.
  • Исправлена ошибка деления на ноль в d3.treemapResquarify.

d3-interpolate

  • Добавлена interpolateZoom.rho. (#25)
  • Разрешено d3.piecewise по умолчанию использовать d3.interpolate. #90
  • Изменено d3.interpolateTransformCss на использование DOMMatrix и требование абсолютных единиц. #83

d3-quadtree

  • Исправлена бесконечная петля при значительном отклонении координат.

d3-random

  • Добавлена d3.randomLcg.
  • Добавлена d3.randomGamma.
  • Добавлена d3.randomBeta.
  • Добавлена d3.randomWeibull.
  • Добавлена d3.randomCauchy.
  • Добавлена d3.randomLogistic.
  • Добавлена d3.randomPoisson.
  • Добавлена d3.randomInt.
  • Добавлена d3.randomBinomial.
  • Добавлена d3.randomGeometric.
  • Добавлена d3.randomPareto.
  • Добавлена d3.randomBernoulli.
  • Допускается дробное n для d3.randomBates.
  • Допускается дробное n для d3.randomIrwinHall.
  • Функция Math.random не обернута в исходный код по умолчанию.

Благодарим @Lange, @p-v-d-Veeken, @svanschooten, @Parcly-Taxel и @jrus за ваш вклад!

d3-scale

  • Принимать итерируемые объекты.
  • Добавить расходящееся.rangeRound.
  • Добавить последовательное.range (для совместимости с d3-axis).
  • Добавить последовательное.rangeRound.
  • Добавить sequentialQuantile.quantiles.
  • Добавить d3.scaleRadial.
  • расходящееся.range теперь можно использовать для задания интерполятора.
  • последовательное.range теперь можно использовать для задания интерполятора.
  • d3.scaleDiverging теперь может принимать массив значений диапазона вместо интерполятора.
  • d3.scaleSequential теперь может принимать массив значений диапазона вместо интерполятора.
  • Исправить непрерывное.nice, чтобы гарантировать, что области с улучшенными доменными значениями всегда охватывают метки.
  • Исправить log.ticks для небольших областей.
  • Исправить log.ticks для небольших областей. #44
  • Исправить scale.clamp для последовательных квантильных шкал. Спасибо, @Fil!
  • Исправить scale.clamp для непрерывных шкал с большим количеством значений домена, чем значений диапазона.
  • Исправить расходящиеся шкалы с убывающими областями.
  • Удалить устаревший аргумент step из time.ticks и time.nice.

d3-selection

  • Добавить selection.selectChild.
  • Добавить selection.selectChildren.
  • Добавить d3.pointer.
  • Добавить d3.pointers.
  • Добавить selection[Symbol.iterator]; теперь выборки являются итерируемыми!
  • Принимать итерируемые объекты с selection.data.
  • Принимать итерируемые объекты с d3.selectAll.
  • Изменить selection.on на непосредственное передачу события слушателям.
  • Удалить индекс и группу из слушателей selection.on!
  • Удалить d3.event!
  • Удалить d3.mouse.
  • Удалить d3.touch.
  • Удалить d3.touches.
  • Удалить d3.customEvent.
  • Удалить d3.clientPoint.
  • Удалить d3.sourceEvent.
  • Исправить selection.merge(transition) для выдачи ошибки.

Для обзора изменений см. https://observablehq.com/@d3/d3-selection-2-0.

d3-shape

  • Принимать итерируемые объекты.
  • Добавить d3.line(x, y) сокращение.
  • Добавить d3.area(x, y0, y1) сокращение.
  • Добавить d3.symbol(type, size) сокращение.

d3-time-format

  • Добавить ISO 8601 «год недели» (%G и %g).

d3-timer

  • Исправить interval.restart для перезапуска как интервала.

d3-transition

  • Добавить transition.easeVarying.
  • Добавить transition[Symbol.iterator]; переходы теперь являются итерируемыми.
  • Исправить selection.transition для выдачи ошибки, если указанный для наследования переход не найден.
  • Исправить transition.end для немедленного разрешения, если выборка пуста.

d3-zoom

  • Добавить zoom.tapDistance.
  • Изменить zoom.on на непосредственное передачу события слушателям.
  • Изменить значение по умолчанию zoom.filter на наблюдение событий wheel, если нажата клавиша управления.
  • Изменить значение по умолчанию zoom.wheelDelta на более быстрое перемещение, если нажата клавиша управления.
  • Не устанавливать touch-action: none.
  • Обновить до d3-selection 2.

Изменения в API

D3 6.0 вводит несколько изменений, несовместимых с предыдущими версиями.

  • Удалить d3.event.
  • Изменить selection.on на непосредственное передачу события слушателям.
  • Изменить transition.on на непосредственное передачу события слушателям.
  • Изменить brush.on на непосредственное передачу события слушателям.
  • Изменить drag.on на непосредственное передачу события слушателям.
  • Изменить zoom.on на непосредственное передачу события слушателям.
  • Удалить d3.mouse; использовать d3.pointer.
  • Удалить d3.touch; использовать d3.pointer.
  • Удалить d3.touches; использовать d3.pointers.
  • Удалить d3.clientPoint; использовать d3.pointer.
  • Удалить d3.voronoi; использовать d3.Delaunay.
  • Удалить d3.nest; использовать d3.group и d3.rollup.
  • Удалить d3.map; использовать Map.
  • Удалить d3.set; использовать Set.
  • Удалить d3.keys; использовать Object.keys.
  • Удалить d3.values; использовать Object.values.
  • Удалить d3.entries; использовать Object.entries.
  • Переименовать d3.histogram в d3.bin.
  • Переименовать d3.scan в d3.leastIndex.
  • Изменить d3.interpolateTransformCss на использование абсолютных единиц.
  • Изменить d3.format по умолчанию на использование минуса вместо тире для отрицательных значений.

D3 теперь требует браузера, поддерживающего ES2015. Для старых браузеров вам необходимо использовать транспилятор.

Наконец, поддержка Bower была прекращена; D3 теперь публикуется только в npm и на GitHub.

Обратитесь к нашему руководству по миграции для получения помощи при обновлении.

Изменения в D3 5.0

Выпущено 22 марта 2018 года.

D3 5.0 вводит лишь несколько изменений, несовместимых с предыдущими версиями.

D3 теперь использует Promises вместо асинхронных обратных вызовов для загрузки данных. Promises упрощают структуру асинхронного кода, особенно в современных браузерах, которые поддерживают async и await. (См. это введение в Promises на Observable.) Например, для загрузки CSV-файла в v4, можно было сказать:

d3.csv("file.csv", function(error, data) {
  if (error) throw error;
  console.log(data);
});

В v5, используя Promises:

d3.csv("file.csv").then(function(data) {
  console.log(data);
});

Обратите внимание, что вам не нужно повторно выбрасывать ошибку — promise будет отклоняться автоматически, и вы можете использовать promise.catch, если это необходимо. Используя await, код становится еще проще:

const data = await d3.csv("file.csv");
console.log(data);

С принятием Promises, D3 теперь использует Fetch API вместо XMLHttpRequest: модуль d3-request был заменён на d3-fetch. Fetch поддерживает множество мощных новых функций, таких как потоковая передача ответов. D3 5.0 также устаревает и удаляет модуль d3-queue. Используйте Promise.all для одновременного выполнения набора асинхронных задач или вспомогательную библиотеку, такую как p-queue, для управления параллелизмом.

END_OF_DOCUMENT_MARKER

Библиотека D3 больше не предоставляет категориальные цветовые схемы d3.schemeCategory20*. Эти двадцатицветные схемы были несовершенны, так как их группировка могла ложно указывать на отношения в данных: общий оттенок может подразумевать, что закодированные данные являются частью группы (суперкатегории), а относительная светлота может подразумевать порядок. Вместо этого, D3 теперь включает d3-scale-chromatic, который реализует отличные схемы из ColorBrewer, включая категориальные, расходящиеся, последовательные однотонные и последовательные многотонные схемы. Эти схемы доступны как в дискретном, так и в непрерывном вариантах.

D3 теперь предоставляет реализации алгоритма марширующих квадратов и оценки плотности через d3-contour! Есть два новых метода d3-selection: selection.clone для вставки клонов выбранных узлов и d3.create для создания отсоединённых элементов. Географические проекции теперь поддерживают projection.angle, что позволило создать несколько фантастических новых полиэдральных проекций Филиппом Ривьером.

Наконец, в package.json D3 больше нет привязки к точным версиям зависимых модулей D3. Это исправляет проблему с дублирующими установками модулей D3.

Изменения в D3 4.0

Выпущено 28 июня 2016 года.

D3 4.0 — модульная. Вместо одной библиотеки, D3 теперь множество небольших библиотек, разработанных для совместной работы. Вы можете выбирать, какие части использовать, как вам нужно. Каждая библиотека поддерживается в собственном репозитории, что позволяет децентрализованному владению и независимым циклам выпуска. Стандартный набор объединяет около тридцати из этих микробиблиотек.

<script src="https://d3js.org/d3.v4.js"></script>

Как и прежде, вы можете загружать дополнительные плагины поверх стандартного набора, такие как масштабы ColorBrewer:

<script src="https://d3js.org/d3.v4.js"></script>
<script src="https://d3js.org/d3-scale-chromatic.v0.3.js"></script>

Вам не обязательно использовать стандартный набор! Если вы используете только d3-selection, используйте ее как самостоятельную библиотеку. Как и стандартный набор, вы можете загружать микробиблиотеки D3 с помощью тегов vanilla script или RequireJS (отлично для HTTP/2!):

<script src="https://d3js.org/d3-selection.v1.js"></script>

Вы также можете cat микробиблиотеки D3 в пользовательский набор или использовать инструменты, такие как Webpack и Rollup, чтобы создать оптимизированные наборы. Пользовательские наборы отлично подходят для приложений, которые используют подмножество функций D3; например, библиотека диаграмм React может использовать D3 для масштабирования и форм, а React для манипулирования DOM. Микробиблиотеки D3 написаны как ES6 модули, а Rollup позволяет выбирать символы на уровне символов для создания более компактных наборов.

Небольшие файлы хороши, но модульность также направлена на то, чтобы сделать D3 более увлекательным. Микробиблиотеки легче понять, разработать и протестировать. Это облегчает вовлечение новых людей и вклад в проект. Это уменьшает различие между «ядерным модулем» и «плагином» и ускоряет разработку функций D3.

Если вы не заинтересованы в модульности, вы можете в основном проигнорировать это изменение и продолжить использование стандартного набора. Однако есть одно неизбежное следствие принятия ES6 модулей: каждый символ в D3 4.0 теперь использует плоскую область имен, а не вложенную область имен D3 3.x. Например, d3.scale.linear теперь d3.scaleLinear, а d3.layout.treemap теперь d3.treemap. Принятие ES6 модулей также означает, что D3 теперь написан исключительно в строгом режиме и обладает лучшей читаемостью. И было много других существенных улучшений функций D3! (Практически весь код из D3 3.x был переписан.) Эти изменения описаны ниже.

Другие глобальные изменения

Стандартный UMD набор теперь анонимный. Если обнаружен AMD или CommonJS, ни один d3 глобальный объект не экспортируется. В обычной среде микробиблиотеки D3 используют d3 глобальный объект, даже если вы загружаете их независимо; таким образом, ваш код одинаковый независимо от того, используете ли вы стандартный набор (см. Давайте создадим (D3) плагин для получения более подробной информации).

Сгенерированный набор больше не хранится в репозитории Git; Bower перенаправлен на d3-bower, и вы можете найти сгенерированные файлы на npm или в последнем релизе. Неминифицированный стандартный набор больше не искажается, что делает его более читаемым и сохраняет встроенные комментарии.

К неудовольствию некоторых пользователей, 3.x использовал имена переменных Юникода, такие как λ, φ, τ и π для компактного представления математических операций. Недостатком этого подхода было то, что ошибка SyntaxError возникала, если вы загружали неминифицированный D3 с помощью ISO-8859-1 вместо UTF-8. 3.x также использовал литералы строк Юникода, такие как префикс SI µ для 1e-6. 4.0 использует только имена переменных ASCII и литералы строк ASCII (см. rollup-plugin-ascii), избегая проблем с кодировкой.

Содержание

  • Массивы
  • Оси
  • Щетки
  • Аккорды
  • Коллекции
  • Цвета
  • Передачи
  • Перетаскивание
  • Значения, разделённые разделителями
  • Сглаживания
  • Силы
  • Форматы чисел
  • Географические объекты
  • Иерархии
  • Внутренние компоненты
  • Интерполяторы
  • Пути
  • Многоугольники
  • Четвертичные деревья
  • Очереди
  • Случайные числа
  • Запросы
  • Масштабирования
  • Выбор
  • Фигуры
  • Форматы времени
  • Интервалы времени
  • Таймеры
  • Переходы
  • Диаграммы Вороного
  • Масштабирование

Массивы (d3-array)

Новый метод d3.scan выполняет линейный проход по массиву, возвращая индекс наименьшего элемента в соответствии с указанным компаратором. Это аналогично методам d3.min и d3.max, за исключением того, что вы можете использовать его для нахождения позиции экстремального элемента, а не просто вычисления экстремального значения.

var data = [
  {name: "Alice", value: 2},
  {name: "Bob", value: 3},
  {name: "Carol", value: 1},
  {name: "Dwayne", value: 5}
];

var i = d3.scan(data, function(a, b) { return a.value - b.value; }); // 2
data[i]; // {name: "Carol", value: 1}

Новые методы d3.ticks и d3.tickStep полезны для генерации удобочитаемых числовых меток. Эти методы являются низкоуровневой альтернативой методу continuous.ticks из d3-scale. Новая реализация также более точна, возвращая оптимальное количество меток, измеряемое относительной ошибкой.

var ticks = d3.ticks(0, 10, 5); // [0, 2, 4, 6, 8, 10]

Метод d3.range больше не пытается сложным образом избежать ошибок с плавающей точкой, когда шаг не является целым числом. Возвращаемые значения строго определяются как начало + i * шаг, где i — целое число. (Узнайте больше о математике с плавающей точкой.) d3.range возвращает пустой массив для бесконечных диапазонов, а не выводит ошибку.

Подпись метода для опциональных аксессоров была изменена для большей согласованности с методами массивов, такими как array.forEach: аксессор получает текущий элемент (d), индекс (i) и массив (данные), при этом this равно undefined. Это влияет на d3.min, d3.max, d3.extent, d3.sum, d3.mean, d3.median, d3.quantile, d3.variance и d3.deviation. Метод d3.quantile ранее не принимал аксессор. Некоторые методы с опциональными аргументами теперь рассматривают эти аргументы как отсутствующие, если они равны null или undefined, а не проверяют строго arguments.length.

Новый API d3.histogram заменяет d3.layout.histogram. Вместо того, чтобы экспонировать bin.x и bin.dx для каждой возвращённой ячейки, гистограмма экспонирует bin.x0 и bin.x1, гарантируя, что bin.x0 точно равен bin.x1 в предыдущей ячейке. Режимы «частота» и «вероятность» больше не поддерживаются; каждая ячейка — это просто массив элементов из входных данных, поэтому bin.length равен bin.y из D3 3.x в режиме частоты. Чтобы вычислить распределение вероятностей, разделите количество элементов в каждой ячейке на общее количество элементов.

Метод гистограммы.range был переименован в гистограмма.domain для согласованности со шкалами. Метод гистограммы.bins был переименован в гистограмма.thresholds и больше не принимает верхнее значение: n пороговых значений будут создавать n + 1 интервалов. Если вы укажете желаемое количество интервалов вместо пороговых значений, d3.histogram теперь использует d3.ticks для вычисления хороших пороговых значений интервалов. В дополнение к формуле Стерджеса по умолчанию, D3 теперь реализует правило Фридмана-Диакониса и правило Скотта.

Оси (d3-axis)

Для правильного отображения осей в D3 3.x, вам нужно было стилизовать их:

<style>

.axis path,
.axis line {
  fill: none;
  stroke: #000;
  shape-rendering: crispEdges;
}

.axis text {
  font: 10px sans-serif;
}

</style>
<script>

d3.select(".axis")
    .call(d3.svg.axis()
        .scale(x)
        .orient("bottom"));

</script>

Если вы этого не сделали, вы видели это:

D3 4.0 предоставляет стили по умолчанию и более короткий синтаксис. Вместо d3.svg.axis и axis.orient, D3 4.0 теперь предоставляет четыре конструктора для каждой ориентации: d3.axisTop, d3.axisRight, d3.axisBottom, d3.axisLeft. Эти конструкторы принимают шкалу, поэтому вы можете сократить всё вышеперечисленное до:

<script>

d3.select(".axis")
    .call(d3.axisBottom(x));

</script>

И получите это:

Как и прежде, вы можете настроить внешний вид оси, применив таблицы стилей или изменив элементы оси. Значение внешнего вида по умолчанию было немного изменено, чтобы сместить ось на полпикселя; это исправляет проблему отображения чётких краёв в Safari, где ось отображалась толщиной в два пикселя.

Теперь есть метод axis.tickArguments в качестве альтернативы методу axis.ticks, который также позволяет просмотреть аргументы шкалы деления оси. Метод axis.tickSize был изменён, чтобы принимать только один аргумент при установке размера деления. Методы axis.innerTickSize и axis.outerTickSize были переименованы в axis.tickSizeInner и axis.tickSizeOuter соответственно.

Щетки (d3-brush)

Заменив d3.svg.brush, теперь есть три класса щеток для обработки по оси x, оси y или по обеим осям: d3.brushX, d3.brushY, d3.brush. Щетки больше не зависят от шкал; вместо этого каждая щётка определяет выделение в координатах экрана. Это выделение может быть обращено, если вы хотите вычислить соответствующую область значений данных. И вместо того, чтобы полагаться на диапазоны шкал для определения области обработки, теперь есть метод brush.extent для её установки. Если вы не устанавливаете область обработки, она по умолчанию соответствует всей области элемента SVG. Метод brush.clamp также был удалён; обработка всегда ограничена областью обработки, определённой областью щётки.

Щетки больше не хранят активное выделение щётки (т.е., выделенную область; положение щётки) внутри. Положение щётки теперь хранится в любом элементе, к которому была применена щётка. Положение щётки доступно как event.selection в событии щётки или вызовом d3.brushSelection на данном элементе. Чтобы переместить щётку программно, используйте brush.move с заданным выделением или переходом; см. пример фиксации щётки. Метод brush.event был удалён.

Взаимодействие со щетками было улучшено. По умолчанию щётки теперь игнорируют щелчки правой кнопкой мыши, предназначенные для контекстного меню; вы можете изменить это поведение с помощью brush.filter. Щетки также игнорируют эмулированные события мыши на iOS. Удерживание клавиши SHIFT (⇧) во время обработки блокирует положение x или y щётки. Удерживание клавиши META (⌘) при нажатии и перетаскивании запускает новое выделение вместо перемещения существующего выделения.

Внешний вид щётки по умолчанию также был улучшен и немного упрощён. Раньше необходимо было применять стили к щётке, чтобы придать ей разумный вид, например:

.brush .extent {
  stroke: #fff;
  fill-opacity: .125;
  shape-rendering: crispEdges;
}

Эти стили теперь применяются по умолчанию как атрибуты; если вы хотите настроить внешний вид щётки, вы по-прежнему можете применять внешние стили или изменять элементы щётки. (D3 4.0 имеет аналогичное улучшение для осей.) Новый метод brush.handleSize позволяет переопределить размер ручки щётки; по умолчанию он равен шести пикселям.

Щетка теперь потребляет обработанные события, что упрощает её сочетание с другими интерактивными действиями, такими как перетаскивание и приближение. События brushstart и brushend были переименованы соответственно в start и end. Событие щётки больше не сообщает о event.mode для различения изменения размера и перетаскивания щётки.

Хорды (d3-chord)

В соответствии с большим сглаживанием пространства имён:

  • d3.layout.chord ↦ d3.chord
  • d3.svg.chord ↦ d3.ribbon

Для согласованности с arc.padAngle, chord.padding также был переименован в ribbon.padAngle. Новый метод ribbon.context позволяет отображать диаграммы хорд в Canvas! См. также d3-path.

Коллекции (d3-collection)

Конструктор d3.set теперь принимает существующий набор для создания копии. Если вы передаёте массив в d3.set, вы также можете передать функцию доступа к значению. Эта функция доступа принимает стандартные аргументы: текущий элемент (d), индекс (i) и массив (data), где this не определено. Например:

var yields = [
  {yield: 22.13333, variety: "Manchuria",        year: 1932, site: "Grand Rapids"},
  {yield: 26.76667, variety: "Peatland",         year: 1932, site: "Grand Rapids"},
  {yield: 28.10000, variety: "No. 462",          year: 1931, site: "Duluth"},
  {yield: 38.50000, variety: "Svansota",         year: 1932, site: "Waseca"},
  {yield: 40.46667, variety: "Svansota",         year: 1931, site: "Crookston"},
  {yield: 36.03333, variety: "Peatland",         year: 1932, site: "Waseca"},
  {yield: 34.46667, variety: "Wisconsin No. 38", year: 1931, site: "Grand Rapids"}
];

var sites = d3.set(yields, function(d) { return d.site; }); // Grand Rapids, Duluth, Waseca, Crookston

Конструктор d3.map также следует стандартной схеме аргументов функции доступа к значению массива.

Методы map.forEach и set.forEach были переименованы в map.each и set.each соответственно. Порядок аргументов для map.each также был изменён на value, key и map, а порядок аргументов для set.each теперь value, value и set. Это ближе к ES6 map.forEach и set.forEach. Также, как и ES6 Map и Set, map.set и set.add теперь возвращают текущую коллекцию (а не добавленное значение), что облегчает цепочку вызовов методов. Новые методы map.clear и set.clear могут использоваться для очистки коллекций.

Метод nest.map теперь всегда возвращает экземпляр d3.map. Для простого объекта используйте nest.object вместо этого. При использовании в сочетании с nest.rollup, nest.entries теперь возвращает объекты {key, value} для листовых элементов, а не {key, values}. Это делает nest.rollup проще использовать в сочетании с иерархиями, как в этом примере древовидной карты Nest.

Цвета (d3-color)

Все цвета теперь имеют непрозрачность, представленную как color.opacity, которая является числом в [0, 1]. Вы можете передать необязательный аргумент непрозрачности в конструкторы цветовых пространств d3.rgb, d3.hsl, d3.lab, d3.hcl или d3.cubehelix.

Теперь вы можете анализировать спецификаторы цвета CSS rgba(…) и hsla(…) или строку “transparent” с помощью d3.color. Цвет “transparent” определяется как цвет RGB с нулевой непрозрачностью и неопределёнными каналами красного, зелёного и синего; это немного отличается от CSS, который определяет его как прозрачный чёрный, но полезно для упрощения логики интерполяции цвета, где либо начальный, либо конечный цвет имеют неопределённые каналы. Метод color.toString теперь также возвращает строку rgb(…) или rgba(…) с целочисленными значениями каналов, а не шестнадцатеричный формат RGB, в соответствии с вычисленными значениями CSS. Это повышает производительность, исключая переходы, когда начальный стиль элемента соответствует конечному стилю.

Новый метод d3.color является основным методом для анализа цветов: он возвращает экземпляр d3.color в соответствующем цветовом пространстве или null, если спецификатор цвета CSS недействителен. Например:

var red = d3.color("hsl(0, 80%, 50%)"); // {h: 0, l: 0.5, s: 0.8, opacity: 1}

Реализация анализа теперь более надёжна. Например, вы больше не можете смешивать целые числа и проценты в rgb(…), и она правильно обрабатывает пробелы, десятичные точки, знаки чисел и другие граничные случаи. Конструкторы цветовых пространств d3.rgb, d3.hsl, d3.lab, d3.hcl и d3.cubehelix теперь всегда возвращают копию входного цвета, преобразованного в соответствующее цветовое пространство. Хотя color.rgb остаётся, rgb.hsl был удалён; используйте d3.hsl для преобразования цвета в RGB цветовое пространство.

Цветовое пространство RGB больше не жадно квантует и не ограничивает значения каналов при создании цветов, что повышает точность при преобразовании цветовых пространств. Квантование и ограничение теперь происходит в color.toString при форматировании цвета для отображения. Вы можете использовать новый color.displayable, чтобы проверить, является ли цвет вне гаммы.

Метод rgb.brighter больше не обрабатывает черный цвет как специальный случай. Это оператор умножения, определяющий новый цвет r′, g′, b′ где r′ = r × pow(0.7, k), g′ = g × pow(0.7, k) и b′ = b × pow(0.7, k); более яркий черный цвет по-прежнему остается черным.

Появился новый цветовой пространство d3.cubehelix, обобщающий цветовую схему Дейва Грина! (См. также d3.interpolateCubehelixDefault из d3-scale.) Вы также можете продолжать определять свои собственные пользовательские цветовые пространства; см. d3-hsv для примера.

Обработчики событий (d3-dispatch)

Вместо того, чтобы украшать объект dispatch каждым типом события, объект dispatch теперь предоставляет универсальные методы dispatch.call и dispatch.apply, которые принимают строку type в качестве первого аргумента. Например, в D3 3.x вы могли бы сказать:

dispatcher.foo.call(that, "Hello, Foo!");

Чтобы отправить событие foo в D3 4.0, вы бы сказали:

dispatcher.call("foo", that, "Hello, Foo!");

Метод dispatch.on теперь принимает несколько типов имен, позволяя добавлять или удалять слушателей для нескольких событий одновременно. Например, чтобы отправить события foo и bar одному слушателю:

dispatcher.on("foo bar", function(message) {
  console.log(message);
});

Это соответствует новому поведению selection.on в d3-selection. Метод dispatch.on теперь проверяет, является ли указатель listener функцией, а не выбрасывает ошибку в будущем.

Новая реализация d3.dispatch быстрее, используя меньше замыканий для повышения производительности. Также есть новый метод dispatch.copy для создания копии диспетчера; он используется d3-transition для повышения производительности переходов в общем случае, когда все элементы в переходе имеют одинаковые слушателей событий перехода.

Перетаскивание (d3-drag)

Поведение перетаскивания d3.behavior.drag переименовано в d3.drag. Метод drag.origin заменен на drag.subject, который позволяет определять элемент, который перетаскивается в начале жеста перетаскивания. Это особенно полезно с Canvas, где перетаскиваемые объекты обычно используют один элемент Canvas (в отличие от SVG, где перетаскиваемые объекты обычно имеют отдельные DOM-элементы); см. пример перетаскивания круга.

Новый метод drag.container позволяет переопределять родительский элемент, который определяет систему координат жеста перетаскивания. По умолчанию это родительский узел элемента, к которому было применено поведение перетаскивания. Для перетаскивания на элементах Canvas, вероятно, вы захотите использовать элемент Canvas в качестве контейнера.

События перетаскивания теперь предоставляют метод event.on для регистрации временных слушателей на время текущего жеста перетаскивания; эти слушатели могут получать состояние текущего жеста, например, элемент, который перетаскивается. Новая свойство event.active позволяет обнаружить, являются ли несколько (мультитач) жестов перетаскивания активными одновременно. События dragstart и dragend переименованы в start и end. По умолчанию, поведение перетаскивания теперь игнорирует щелчки правой кнопкой мыши, предназначенные для контекстного меню; используйте drag.filter для управления событиями, которые игнорируются. Поведение перетаскивания также игнорирует эмулированные события мыши на iOS. Поведение перетаскивания теперь потребляет обработанные события, что упрощает сочетание с другими интерактивными действиями, такими как приближение.

Новые методы d3.dragEnable и d3.dragDisable предоставляют низкоуровневый API для реализации жестов перетаскивания в различных браузерах и устройствах. Эти методы также используются другими компонентами D3, такими как кисть.

Значения, разделенные разделителями (d3-dsv)

В соответствии с объединением пространств имен, различные методы CSV и TSV получили новые имена:

  • d3.csv.parse ↦ d3.csvParse
  • d3.csv.parseRows ↦ d3.csvParseRows
  • d3.csv.format ↦ d3.csvFormat
  • d3.csv.formatRows ↦ d3.csvFormatRows
  • d3.tsv.parse ↦ d3.tsvParse
  • d3.tsv.parseRows ↦ d3.tsvParseRows
  • d3.tsv.format ↦ d3.tsvFormat
  • d3.tsv.formatRows ↦ d3.tsvFormatRows

Методы d3.csv и d3.tsv для загрузки файлов соответствующих форматов не были переименованы! Они определены в d3-request. Больше нет метода d3.dsv, который выполнял тройную задачу определения форматера DSV, парсера DSV и запрашивателя DSV; вместо этого есть только d3.dsvFormat, который вы можете использовать для определения форматера и парсера DSV. Вы можете использовать request.response для отправки запроса, а затем разобрать тело ответа, или просто использовать d3.text.

Метод dsv.parse теперь предоставляет имена столбцов и их порядок ввода в виде data.columns. Например:

d3.csv("cars.csv", function(error, data) {
  if (error) throw error;
  console.log(data.columns); // ["Year", "Make", "Model", "Length"]
});

Вы также можете передать необязательный массив имён столбцов в dsv.format для форматирования только подмножества столбцов или для явного указания порядка столбцов:

var string = d3.csvFormat(data, ["Year", "Model", "Length"]);

Парсер немного быстрее, а форматер немного более устойчив: входные данные приводятся к строкам перед форматированием, что исправляет скрытую ошибку, и удалена устаревшая поддержка обратного вызова dsv.formatRows, когда входные данные data являются массивом массивов.

Сглаживания (d3-ease)

D3 3.x использовала строки, такие как «кубический-в-наружу», для идентификации методов сглаживания; эти строки могли быть переданы в d3.ease или transition.ease. D3 4.0 использует символы вместо этого, такие как d3.easeCubicInOut. Символы проще и чище. Они хорошо работают с Rollup для создания более компактных пользовательских пакетов. Если нужно, вы по-прежнему можете определять свои собственные пользовательские функции сглаживания.

Вот полный список эквивалентов:

  • линейный ↦ d3.easeLinear¹
  • линейный-вход ↦ d3.easeLinear¹
  • линейный-выход ↦ d3.easeLinear¹
  • линейный-вход-выход ↦ d3.easeLinear¹
  • линейный-выход-вход ↦ d3.easeLinear¹
  • поли-вход ↦ d3.easePolyIn
  • поли-выход ↦ d3.easePolyOut
  • поли-вход-выход ↦ d3.easePolyInOut
  • поли-выход-вход ↦ УДАЛЕНО²
  • квадратный-вход ↦ d3.easeQuadIn
  • квадратный-выход ↦ d3.easeQuadOut
  • квадратный-вход-выход ↦ d3.easeQuadInOut
  • квадратный-выход-вход ↦ УДАЛЕНО²
  • кубический-вход ↦ d3.easeCubicIn
  • кубический-выход ↦ d3.easeCubicOut
  • кубический-вход-выход ↦ d3.easeCubicInOut
  • кубический-выход-вход ↦ УДАЛЕНО²
  • синусоидальный-вход ↦ d3.easeSinIn
  • синусоидальный-выход ↦ d3.easeSinOut
  • синусоидальный-вход-выход ↦ d3.easeSinInOut
  • синусоидальный-выход-вход ↦ УДАЛЕНО²
  • экспоненциальный-вход ↦ d3.easeExpIn
  • экспоненциальный-выход ↦ d3.easeExpOut
  • экспоненциальный-вход-выход ↦ d3.easeExpInOut
  • экспоненциальный-выход-вход ↦ УДАЛЕНО²
  • круговой-вход ↦ d3.easeCircleIn
  • круговой-выход ↦ d3.easeCircleOut
  • круговой-вход-выход ↦ d3.easeCircleInOut
  • круговой-выход-вход ↦ УДАЛЕНО²
  • упругий-вход ↦ d3.easeElasticOut²
  • упругий-выход ↦ d3.easeElasticIn²
  • упругий-вход-выход ↦ УДАЛЕНО²
  • упругий-выход-вход ↦ d3.easeElasticInOut²
  • обратный-вход ↦ d3.easeBackIn
  • обратный-выход ↦ d3.easeBackOut
  • обратный-вход-выход ↦ d3.easeBackInOut
  • обратный-выход-вход ↦ УДАЛЕНО²
  • отскок-вход ↦ d3.easeBounceOut²
  • отскок-выход ↦ d3.easeBounceIn²
  • отскок-вход-выход ↦ УДАЛЕНО²
  • отскок-выход-вход ↦ d3.easeBounceInOut²

¹ Варианты -вход, -выход и -вход-выход линейного сглаживания идентичны, поэтому есть только d3.easeLinear.
² Упругие и отражающие сглаживания были непреднамеренно перевернуты в 3.x, поэтому в 4.0 удалено сглаживание -выход-вход!

Для удобства также существуют стандартные псевдонимы для каждого метода сглаживания. Например, d3.easeCubic является псевдонимом d3.easeCubicInOut. Большинство по умолчанию имеют значение -вход-выход; исключения составляют d3.easeBounce и d3.easeElastic, которые по умолчанию имеют значение -выход.

Вместо передачи необязательных аргументов в d3.ease или transition.ease, параметризуемые функции сглаживания теперь имеют именованные параметры: poly.exponent, elastic.amplitude, elastic.period и back.overshoot. Например, в D3 3.x вы могли бы сказать:

var e = d3.ease("elastic-out-in", 1.2);

Эквивалент в D3 4.0:

var e = d3.easeElastic.amplitude(1.2);

Многие функции сглаживания были оптимизированы для производительности и точности. Также были исправлены несколько ошибок, такие как интерпретация параметра перехвата для сглаживания "back" и параметра периода для сглаживания "elastic". Кроме того, d3-transition теперь явно гарантирует, что последняя итерация перехода происходит ровно при t = 1, избегая ошибок с плавающей точкой в некоторых функциях сглаживания.

Теперь есть удобная визуальная справка и анимированная справка по новым функциям сглаживания!

Силы (d3-force)

Макет сил d3.layout.force был переименован в d3.forceSimulation. Теперь симуляция сил использует интеграцию по методу Верлета со скоростью вместо интеграции по методу Верлета с позицией, отслеживая позиции узлов (node.x, node.y) и скорости (node.vx, node.vy) вместо их предыдущих позиций (node.px, node.py).

Вместо жёсткого кодирования набора встроенных сил, симуляция сил теперь расширяема: вы указываете, какие силы вам нужны! Этот подход обеспечивает большую гибкость за счёт композиции. Новые силы также более гибкие: параметры сил обычно могут настраиваться на узел или на связь. Существуют отдельные силы позиционирования для x и y, которые заменяют force.gravity; x.x и y.y заменяют force.size. Новая сила связи заменяет force.linkStrength и использует лучшие эвристики по умолчанию для повышения стабильности. Новая сила многих тел заменяет force.charge и поддерживает новый параметр минимального расстояния и улучшения производительности благодаря новым квадродеревьям 4.0. Также есть совершенно новые силы для центрирования узлов и разрешения коллизий.

Новые силы и симуляция тщательно разработаны, чтобы избежать недетерминизма. Вместо случайной инициализации узлов, если узлы не имеют предопределённых позиций, они размещаются в соответствии с рисунком филлотаксиса:

Phyllotaxis

Случайная вибрация всё ещё необходима для разрешения сил связи, столкновения и множества тел, если есть совпадающие узлы, но, по крайней мере, в общем случае, симуляция сил (и полученная макетная графика с силами) теперь согласованна в разных браузерах и при перезагрузках. D3 больше не играет в кости!

Симуляция сил имеет несколько новых методов для большего контроля над нагревом, таких как simulation.alphaMin и simulation.alphaDecay, а также внутренний таймер. Вызов simulation.alpha теперь не влияет на внутренний таймер, который управляется независимо через simulation.stop и simulation.restart. Внутренний таймер макета сил теперь запускается автоматически при создании, удаляя force.start. Как и в 3.x, вы можете вручную продвинуть симуляцию с помощью simulation.tick. Параметр force.friction заменён на simulation.velocityDecay. Новый метод simulation.alphaTarget позволяет задать желаемую альфа (температуру) симуляции таким образом, чтобы симуляция могла плавно нагреваться во время взаимодействия и затем плавно охлаждаться снова. Это улучшает стабильность графика во время взаимодействия.

Макет сил больше не зависит от поведения перетаскивания, хотя вы, безусловно, можете создать перетаскиваемые макеты сил! Установите node.fx и node.fy, чтобы зафиксировать положение узла. В качестве альтернативы Voronoi SVG-наложению, вы теперь можете использовать simulation.find для поиска ближайшего узла к указателю.

Форматы чисел (d3-format)

Если точность не указана, поведение форматирования изменилось: теперь существует точность по умолчанию 6 для всех директив, кроме none, которая по умолчанию равна 12. В 3.x, если вы не указали точность, число форматировалось с использованием его кратчайшего уникального представления (по number.toString); это могло привести к неожиданным цифрам из-за математики с плавающей точкой. Новая точность по умолчанию в 4.0 даёт более согласованные результаты:

var f = d3.format("e");
f(42);        // "4.200000e+1"
f(0.1 + 0.2); // "3.000000e-1"

Чтобы обрезать незначительные хвостовые нули, используйте директиву none, которая похожа g. Например:

var f = d3.format(".3");
f(0.12345);   // "0.123"
f(0.10000);   // "0.1"
f(0.1 + 0.2); // "0.3"

Внутри, форматирование чисел улучшило точность очень больших и очень маленьких чисел, используя number.toExponential вместо Math.log для извлечения мантиссы и экспоненты. Отрицательный ноль (-0, конструкция IEEE 754) и очень маленькие числа, которые округляются до нуля, теперь форматируются как беззнаковый ноль.

Встроенный небезопасный метод d3.round был удалён, а также d3.requote.

Метод d3.formatPrefix был изменён. Вместо возвращения строки с префиксом СИ, он возвращает функцию форматирования с префиксом СИ для заданного specifier и эталонного value. Например, для форматирования тысяч:

var f = d3.formatPrefix(",.0", 1e3);
f(1e3); // "1k"
f(1e4); // "10k"
f(1e5); // "100k"
f(1e6); // "1,000k"

В отличие от s директив форматирования, d3.formatPrefix всегда использует тот же префикс СИ, создавая согласованные результаты:

var f = d3.format(".0s");
f(1e3); // "1k"
f(1e4); // "10k"
f(1e5); // "100k"
f(1e6); // "1M"

Новая ( опция знака использует скобки для отрицательных значений. Это особенно полезно в сочетании с $. Например:

d3.format("+.0f")(-42);  // "-42"
d3.format("(.0f")(-42);  // "(42)"
d3.format("+$.0f")(-42); // "-$42"
d3.format("($.0f")(-42); // "($42)"

Новая = опция выравнивания помещает любой знак и символ слева от любой подписи:

d3.format(">6d")(-42);  // "   -42"
d3.format("=6d")(-42);  // "-   42"
d3.format(">(6d")(-42); // "  (42)"
d3.format("=(6d")(-42); // "(  42)"

Директивы b, o, d и x теперь округляются до ближайшего целого числа, а не возвращают пустую строку для нецелых чисел:

d3.format("b")(41.9); // "101010"
d3.format("o")(41.9); // "52"
d3.format("d")(41.9); // "42"
d3.format("x")(41.9); // "2a"

Директива c теперь предназначена для данных символов (т.е., литеральных строк), а не для кодов символов. Это полезно, если вы просто хотите применить выравнивание и форматирование, но не заботитесь о форматировании чисел. Например, печально известный left-pad (а также center- и right-pad!) может быть удобно реализован как:

d3.format(">10c")("foo"); // "       foo"
d3.format("^10c")("foo"); // "   foo    "
d3.format("<10c")("foo"); // "foo       "

Существует несколько новых методов для вычисления рекомендуемых десятичных точностей; они используются d3-scale для форматирования делений и полезны для реализации пользовательских форматов чисел: d3.precisionFixed, d3.precisionPrefix и d3.precisionRound. Также есть новый метод d3.formatSpecifier для парсинга, проверки и отладки спецификаторов формата; он также полезен для получения связанных спецификаторов формата, например, когда вы хотите автоматически заменить точность.

Теперь вы можете установить язык по умолчанию с помощью d3.formatDefaultLocale! Языки публикуются как JSON в npm.

Географические данные (d3-geo)

В соответствии с большой обработкой имён пространств, различные методы получили новые имена:

  • d3.geo.graticule ↦ d3.geoGraticule
  • d3.geo.circle ↦ d3.geoCircle
  • d3.geo.area ↦ d3.geoArea
  • d3.geo.bounds ↦ d3.geoBounds
  • d3.geo.centroid ↦ d3.geoCentroid
  • d3.geo.distance ↦ d3.geoDistance
  • d3.geo.interpolate ↦ d3.geoInterpolate
  • d3.geo.length ↦ d3.geoLength
  • d3.geo.rotation ↦ d3.geoRotation
  • d3.geo.stream ↦ d3.geoStream
  • d3.geo.path ↦ d3.geoPath
  • d3.geo.projection ↦ d3.geoProjection
  • d3.geo.projectionMutator ↦ d3.geoProjectionMutator
  • d3.geo.albers ↦ d3.geoAlbers
  • d3.geo.albersUsa ↦ d3.geoAlbersUsa
  • d3.geo.azimuthalEqualArea ↦ d3.geoAzimuthalEqualArea
  • d3.geo.azimuthalEquidistant ↦ d3.geoAzimuthalEquidistant
  • d3.geo.conicConformal ↦ d3.geoConicConformal
  • d3.geo.conicEqualArea ↦ d3.geoConicEqualArea
  • d3.geo.conicEquidistant ↦ d3.geoConicEquidistant
  • d3.geo.equirectangular ↦ d3.geoEquirectangular
  • d3.geo.gnomonic ↦ d3.geoGnomonic
  • d3.geo.mercator ↦ d3.geoMercator
  • d3.geo.orthographic ↦ d3.geoOrthographic
  • d3.geo.stereographic ↦ d3.geoStereographic
  • d3.geo.transverseMercator ↦ d3.geoTransverseMercator

Также переименованы для согласованности:

  • circle.origin ↦ circle.center
  • circle.angle ↦ circle.radius
  • graticule.majorExtent ↦ graticule.extentMajor
  • graticule.minorExtent ↦ graticule.extentMinor
  • graticule.majorStep ↦ graticule.stepMajor
  • graticule.minorStep ↦ graticule.stepMinor

Проекции теперь имеют более подходящие значения по умолчанию. Например, d3.geoOrthographic по умолчанию имеет угол обрезки 90°, показывая только переднюю полусферу, а d3.geoGnomonic имеет угол обрезки по умолчанию 60°. Значение по умолчанию для проекции в d3.geoPath теперь равно null, а не d3.geoAlbersUsa; проекция null используется с предварительно спроецированной геометрией и обычно быстрее для отрисовки.

«Проекции по умолчанию» — когда вы передаете функцию, а не проекцию, в path.projection — больше не поддерживаются. Для географических проекций используйте d3.geoProjection или d3.geoProjectionMutator, чтобы определить пользовательскую проекцию. Для произвольных преобразований геометрии реализуйте интерфейс потока; см. также d3.geoTransform. «Сырые» проекции (например, d3.geo.equirectangular.raw) больше не экспортируются.

Иерархии (d3-hierarchy)

В соответствии с большим сглаживанием пространства имен:

  • d3.layout.cluster ↦ d3.cluster
  • d3.layout.hierarchy ↦ d3.hierarchy
  • d3.layout.pack ↦ d3.pack
  • d3.layout.partition ↦ d3.partition
  • d3.layout.tree ↦ d3.tree
  • d3.layout.treemap ↦ d3.treemap

В качестве альтернативы использованию JSON для представления иерархических данных (например, «формат flare.json», используемый во многих примерах D3), новый оператор d3.stratify упрощает преобразование табличных данных в иерархические данные! Это удобно, если у вас уже есть данные в табличном формате, например, результат запроса SQL или CSV-файл:

name,parent
Eve,
Cain,Eve
Seth,Eve
Enos,Seth
Noam,Seth
Abel,Eve
Awan,Eve
Enoch,Awan
Azura,Eve

Для преобразования этого в корневой узел node:

var root = d3.stratify()
    .id(function(d) { return d.name; })
    .parentId(function(d) { return d.parent; })
    (nodes);

Полученный корневой узел можно передать в d3.tree для создания древовидной диаграммы, подобной этой:

Корневые узлы также могут быть созданы из данных JSON с помощью d3.hierarchy. Иерархические макеты теперь принимают эти корневые узлы в качестве входных данных, а не работают напрямую с JSON-данными, что способствует более чистому разделению входных данных и вычисляемого макета. (Например, используйте node.copy для изоляции изменений макета.) Это также упрощает API: вместо того, чтобы каждый макет иерархии нуждался в акцессорах значения и сортировки, теперь есть общие методы node.sum и node.sort, которые работают с любым макетом иерархии.

Новый API d3.hierarchy также предоставляет более богатый набор методов для обработки иерархических данных. Например, для генерации массива всех узлов в топологическом порядке используйте node.descendants; для только листов — node.leaves. Чтобы выделить предков заданного узла при наведении курсора, используйте node.ancestors. Чтобы сгенерировать массив {source, target} связей для заданной иерархии, используйте node.links; это заменяет treemap.links и аналогичные методы других макетов. Новый метод node.path заменяет d3.layout.bundle; см. также d3.curveBundle для связывания ребер иерархических.

Иерархические макеты были переписаны с использованием новых нерекурсивных методов обхода (node.each, node.eachAfter и node.eachBefore), улучшая производительность на больших наборах данных. Макет d3.tree больше не использует поле node._ для хранения временного состояния во время макета.

Разбиение на прямоугольники теперь расширяемо через treemap.tile! Алгоритм разбиения на прямоугольники по умолчанию, d3.treemapSquarify, был полностью переписан, улучшая производительность и исправляя ошибки в отступах и округлениях. Метод treemap.sticky был заменен на d3.treemapResquarify, который идентичен d3.treemapSquarify, за исключением того, что он выполняет стабильные обновления соседей. Метод treemap.ratio был заменен на squarify.ratio. И есть новый d3.treemapBinary для двоичных разбиений на прямоугольники!

Отступы разбиения на прямоугольники также были улучшены. Разбиение на прямоугольники теперь различает внешний отступ, который отделяет родителя от его детей, и внутренний отступ, который отделяет смежные элементы. Вы можете задать верхний, правый, нижний и левый внешние отступы отдельно. Есть новые примеры традиционного вложенного разбиения на прямоугольники и разбиения на прямоугольники Lü и Fogarty’s каскадного разбиения на прямоугольники. И есть новый пример, демонстрирующий d3.nest с d3.treemap.

Макеты заполнения пространства d3.treemap и d3.partition теперь выводят x0, x1, y0, y1 на каждом узле вместо x0, dx, y0, dy. Это повышает точность, гарантируя, что края смежных ячеек будут точно равны, а не иногда будут немного отличаться из-за математики с плавающей точкой. Макет разбиения теперь поддерживает округление и отступ.

Макет круговой упаковки d3.pack был полностью переписан для лучшего реализации алгоритма Ванга и др., исправляя основные ошибки и улучшая результаты! Алгоритм Вельца теперь используется для вычисления точного наименьшего охватывающего круга для каждого родителя, а не приближенного ответа, используемого Вангом и др. Вывод 3.x показан слева; 4.0 показан справа:

Circle Packing in 3.x Circle Packing in 4.0

Неиерархическая реализация также доступна как d3.packSiblings, а реализация наименьшего охватывающего круга доступна как d3.packEnclose. Отступ упаковки теперь применяется между родителем и его детьми, а также между смежными элементами. Кроме того, теперь вы можете указать отступ как функцию, которая динамически вычисляется для каждого родителя.

Внутренние механизмы

Метод d3.rebind был удален. (См. исходный код 3.x.) Если вы хотите обернуть метод getter-setter, рекомендуется реализовать метод-обертку и проверить возвращаемое значение. Например, задан компонент, использующий внутренний dispatch, component.on может пересвязать dispatch.on следующим образом:

component.on = function() {
  var value = dispatch.on.apply(dispatch, arguments);
  return value === dispatch ? component : value;
};

Метод d3.functor был удален. (См. исходный код 3.x.) Если вы хотите преобразовать константное значение в функцию, рекомендуется реализовать замыкание, которое возвращает константное значение. При необходимости вы можете использовать вспомогательный метод следующим образом:

function constant(x) {
  return function() {
    return x;
  };
}

Учитывая значение x, для преобразования x в функцию, если это не так:

var fx = typeof x === "function" ? x : constant(x);

Интерполяторы (d3-interpolate)

Метод d3.interpolate больше не делегирует d3.interpolators, который был удален; его поведение теперь определено библиотекой. В обычном случае, когда b — число, он немного быстрее. Он использует d3.interpolateRgb только в том случае, если b является допустимым спецификатором цвета CSS (а не приблизительно таким). И если конечное значение b равно null, undefined, true или false, d3.interpolate теперь возвращает константную функцию, которая всегда возвращает b.

Поведение d3.interpolateObject и d3.interpolateArray немного изменилось по отношению к свойствам или элементам в начальном значении a, которые не существуют в конечном значении b: эти свойства и элементы теперь игнорируются, так что конечное значение интерполятора в t = 1 теперь точно равно b. Итак, в 3.x:

d3.interpolateObject({foo: 2, bar: 1}, {foo: 3})(0.5); // {bar: 1, foo: 2.5} in 3.x

В то время как в 4.0, a.bar игнорируется:

d3.interpolateObject({foo: 2, bar: 1}, {foo: 3})(0.5); // {foo: 2.5} in 4.0

Если a или b не определены или не являются объектами, они теперь неявно преобразуются в пустой объект или пустой массив соответственно, а не в исключение TypeError.

Интерполятор d3.interpolateTransform был переименован в d3.interpolateTransformSvg, и появился новый интерполятор d3.interpolateTransformCss для интерполяции CSS-преобразований! Это позволяет d3-transition автоматически интерполировать как атрибут SVG transform, так и свойство стиля CSS transform. (Обратите внимание, что поддерживаются только 2D преобразования CSS.) Метод d3.transform был удален.

Интерполяторы цветовых пространств теперь интерполируют непрозрачность (см. d3-color) и возвращают строки CSS-заданий цвета rgb(…) или rgba(…), а не используя шестнадцатеричный формат RGB. Это необходимо для поддержки интерполяции непрозрачности, но также выгодно, поскольку это соответствует вычисленным значениям CSS. Когда какой-либо канал в начальном цвете a не определен, интерполяторы цветов теперь используют соответствующее значение канала из конечного цвета b, или наоборот. Этот логика ранее применялась к некоторым каналам (таким как насыщенность в HSL), но теперь применяется ко всем каналам во всех цветовых пространствах, и особенно полезна при интерполяции к прозрачному или из прозрачного цвета.

Теперь существуют «длинные» версии интерполяторов цилиндрического цветового пространства: d3.interpolateHslLong, d3.interpolateHclLong и d3.interpolateCubehelixLong. Эти интерполяторы используют линейную интерполяцию оттенка, а не кратчайший путь вокруг цветового круга оттенка 360°. См. d3.interpolateRainbow для примера. Цветовое пространство Cubehelix теперь поддерживается d3-color, поэтому теперь существуют интерполяторы d3.interpolateCubehelix и d3.interpolateCubehelixLong.

Интерполяция цвета с учётом гамма-коррекции теперь поддерживается для цветовых пространств RGB и Cubehelix как interpolate.gamma. Например, чтобы интерполировать от фиолетового к оранжевому с гамма-коррекцией 2.2 в пространстве RGB:

var interpolate = d3.interpolateRgb.gamma(2.2)("purple", "orange");

Теперь есть новые интерполяторы для униформных нерациональных B-сплайнов! Они полезны для плавной интерполяции между произвольной последовательностью значений от t = 0 до t = 1, например, для создания плавного цветового градиента из дискретного набора цветов. Интерполяторы d3.interpolateBasis и d3.interpolateBasisClosed генерируют одномерные B-сплайны, в то время как d3.interpolateRgbBasis и d3.interpolateRgbBasisClosed генерируют трёхмерные B-сплайны через цветовое пространство RGB. Эти интерполяторы используются d3-scale-chromatic для генерации непрерывных цветовых шкал из дискретных цветовых схем ColorBrewer, таких как PiYG.

Также есть метод d3.quantize для генерации равномерно распределённых дискретных выборок из непрерывного интерполятора. Это полезно для взятия одной из встроенных цветовых шкал (например, d3.interpolateViridis) и квантования её для использования с d3.scaleQuantize, d3.scaleQuantile или d3.scaleThreshold.

Пути (d3-path)

Сериализатор d3.path реализует API CanvasPathMethods, позволяя вам писать код, который может отображаться как в Canvas, так и в SVG. Например, с учётом кода, который рисует на холсте:

function drawCircle(context, radius) {
  context.moveTo(radius, 0);
  context.arc(0, 0, radius, 0, 2 * Math.PI);
}

Вы можете отобразить его в SVG следующим образом:

var context = d3.path();
drawCircle(context, 40);
pathElement.setAttribute("d", context.toString());

Сериализатор путей позволяет d3-shape поддерживать как Canvas, так и SVG; см. line.context и area.context, например.

Многоугольники (d3-polygon)

Конструктор d3.geom.polygon больше не используется; вместо этого вы просто передаёте массив вершин методам многоугольника. Итак, вместо polygon.area и polygon.centroid теперь есть d3.polygonArea и d3.polygonCentroid. Также есть новые методы d3.polygonContains и d3.polygonLength. Больше нет эквивалента polygon.clip, но если нужна обрезка Sutherland–Hodgman, пожалуйста, отправьте запрос на новую функцию.

Оператор d3.geom.hull упрощен: вместо оператора с hull.x и hull.y доступами, теперь есть просто метод d3.polygonHull, который принимает массив точек и возвращает выпуклую оболочку.

Квадродеревья (d3-quadtree)

Метод d3.geom.quadtree был заменён на d3.quadtree. В версии 4.0 убрано понятие «генераторов» квадродеревьев (настраиваемые функции, которые строят квадродерево из массива данных); теперь есть только квадродеревья, которые вы можете создать с помощью d3.quadtree и добавить данные в них с помощью quadtree.add и quadtree.addAll. Этот код из версии 3.x:

var quadtree = d3.geom.quadtree()
    .extent([[0, 0], [width, height]])
    (data);

Может быть переписан в версии 4.0 как:

var quadtree = d3.quadtree()
    .extent([[0, 0], [width, height]])
    .addAll(data);

Новая реализация квадродеревьев значительно улучшена! Она больше не рекурсивна, что предотвращает переполнение стека при большом количестве совпадающих точек. Внутреннее хранилище теперь более эффективное, и реализация также быстрее; построение квадродерева из 1 млн нормально распределённых точек занимает около секунды в версии 4.0 по сравнению с тремя секундами в версии 3.x.

Изменение структуры внутренних узлов влияет на quadtree.visit: используйте node.length для различения листовых узлов от внутренних узлов. Например, чтобы перебрать все данные в квадродереве:

quadtree.visit(function(node) {
  if (!node.length) {
    do {
      console.log(node.data);
    } while (node = node.next)
  }
});

Есть новый метод quadtree.visitAfter для посещения узлов в постфиксной обходе. Эта функция используется в d3-force для реализации приближения Барнса–Хатта.

Теперь можно удалять данные из квадродерева с помощью quadtree.remove и quadtree.removeAll. При добавлении данных в квадродерево, квадродерево теперь увеличивает свой предел в два раза, если новая точка находится за пределами существующего предела квадродерева. Также есть методы quadtree.extent и quadtree.cover для явного увеличения предела квадродерева после создания.

Квадродеревья поддерживают несколько новых служебных методов: quadtree.copy возвращает копию квадродерева, которая использует те же данные; quadtree.data генерирует массив всех данных в квадродереве; quadtree.size возвращает количество точек данных в квадродереве; и quadtree.root возвращает корневой узел, что полезно для ручного обхода квадродерева. Метод quadtree.find теперь принимает необязательный радиус поиска, который полезен для выбора на основе указателя в графах с силами.

Очереди (d3-queue)

Раньше известный как Queue.js и queue-async, d3.queue теперь включён в стандартный набор, что упрощает загрузку файлов данных параллельно. Он был переписан с меньшим количеством замыканий для повышения производительности, и теперь есть более строгие проверки для обеспечения хорошо определённого поведения. Теперь можно использовать instanceof d3.queue и просмотреть внутреннее состояние очереди.

Генераторы случайных чисел (d3-random)

В соответствии с большим сглаживанием пространства имён, генераторы случайных чисел получили новые имена:

  • d3.random.normal ↦ d3.randomNormal
  • d3.random.logNormal ↦ d3.randomLogNormal
  • d3.random.bates ↦ d3.randomBates
  • d3.random.irwinHall ↦ d3.randomIrwinHall

Также существуют новые генераторы случайных чисел для экспоненциального и равномерного распределений. Генераторы случайных чисел нормального и логарифмически-нормального распределений были оптимизированы.

Запросы (d3-request)

Метод d3.xhr был переименован в d3.request. Теперь поддерживается базовая аутентификация с помощью request.user и request.password. Теперь можно настроить таймаут с помощью request.timeout.

Если произошла ошибка, соответствующий ProgressEvent типа “error” теперь передаётся в обработчик ошибок, а не в XMLHttpRequest. Аналогично, ProgressEvent передаётся обработчикам событий прогресса, а не с использованием d3.event. Если d3.xml сталкивается с ошибкой при парсинге XML, эта ошибка теперь сообщается обработчикам ошибок, а не возвращает null в ответ.

Методы d3.request, d3.text и d3.xml больше не принимают необязательный тип MIME в качестве второго аргумента; используйте request.mimeType вместо этого. Например:

d3.xml("file.svg").mimeType("image/svg+xml").get(function(error, svg) {
  …
});

За исключением d3.html и d3.xml, Node теперь поддерживается через node-XMLHttpRequest.

Масштабирование (d3-scale)

В соответствии с большим сглаживанием имен пространств:

  • d3.scale.linear ↦ d3.scaleLinear
  • d3.scale.sqrt ↦ d3.scaleSqrt
  • d3.scale.pow ↦ d3.scalePow
  • d3.scale.log ↦ d3.scaleLog
  • d3.scale.quantize ↦ d3.scaleQuantize
  • d3.scale.threshold ↦ d3.scaleThreshold
  • d3.scale.quantile ↦ d3.scaleQuantile
  • d3.scale.identity ↦ d3.scaleIdentity
  • d3.scale.ordinal ↦ d3.scaleOrdinal
  • d3.time.scale ↦ d3.scaleTime
  • d3.time.scale.utc ↦ d3.scaleUtc

Теперь масштабы генерируют метки в том же порядке, что и область: если у вас есть убывающая область, теперь вы получаете убывающие метки. Это изменение влияет на порядок элементов меток, генерируемых осями. Например:

d3.scaleLinear().domain([10, 0]).ticks(5); // [10, 8, 6, 4, 2, 0]

Форматирование меток логарифмического масштаба теперь предполагает значение по умолчанию count равное десяти, а не бесконечности, если не указано другое. Логарифмические масштабы с областями, охватывающими множество степеней (например, от 1e+3 до 1e+29), теперь возвращают только одну метку на степень, а не возвращают base меток на степень. Нелинейные количественные масштабы немного точнее.

Теперь вы можете управлять тем, расширяется ли область определения порядкового масштаба неявно, когда масштабу передаётся значение, которого ещё нет в его области определения. По умолчанию, ordinal.unknown равен d3.scaleImplicit, что приводит к добавлению неизвестных значений в область определения:

var x = d3.scaleOrdinal()
    .domain([0, 1])
    .range(["red", "green", "blue"]);

x.domain(); // [0, 1]
x(2); // "blue"
x.domain(); // [0, 1, 2]

Установив ordinal.unknown, вы вместо этого определяете выходное значение для неизвестных входов. Это особенно полезно для картограмм, где вы хотите назначить цвет отсутствующим данным.

var x = d3.scaleOrdinal()
    .domain([0, 1])
    .range(["red", "green", "blue"])
    .unknown(undefined);

x.domain(); // [0, 1]
x(2); // undefined
x.domain(); // [0, 1]

Методы ordinal.rangeBands и ordinal.rangeRoundBands были заменены новым подклассом порядкового масштаба: масштабами полос. Следующий код в 3.x:

var x = d3.scale.ordinal()
    .domain(["a", "b", "c"])
    .rangeBands([0, width]);

Эквивалентен этому в 4.0:

var x = d3.scaleBand()
    .domain(["a", "b", "c"])
    .range([0, width]);

Новые методы band.padding, band.paddingInner и band.paddingOuter заменяют необязательные аргументы для ordinal.rangeBands. Новые методы band.bandwidth и band.step заменяют ordinal.rangeBand. Также есть новый метод band.align, который вы можете использовать для управления тем, как распределяется дополнительное пространство за пределами полос, например, чтобы сдвинуть столбцы ближе к оси y.

Аналогично, методы ordinal.rangePoints и ordinal.rangeRoundPoints были заменены новым подклассом порядкового масштаба: масштабами точек. Следующий код в 3.x:

var x = d3.scale.ordinal()
    .domain(["a", "b", "c"])
    .rangePoints([0, width]);

Эквивалентен этому в 4.0:

var x = d3.scalePoint()
    .domain(["a", "b", "c"])
    .range([0, width]);

Новый метод point.padding заменяет необязательный аргумент padding в ordinal.rangePoints. Как и ordinal.rangeBand с ordinal.rangePoints, метод point.bandwidth всегда возвращает ноль; новый метод point.step возвращает интервал между соседними точками.

Конструктор порядкового масштаба теперь принимает необязательный range для более короткой альтернативы ordinal.range. Это особенно полезно сейчас, когда категориальные цветовые шкалы были изменены на простые массивы цветов, а не специализированные конструкторы порядковых масштабов:

  • d3.scale.category10 ↦ d3.schemeCategory10
  • d3.scale.category20 ↦ d3.schemeCategory20
  • d3.scale.category20b ↦ d3.schemeCategory20b
  • d3.scale.category20c ↦ d3.schemeCategory20c

Следующий код в 3.x:

var color = d3.scale.category10();

Эквивалентен этому в 4.0:

var color = d3.scaleOrdinal(d3.schemeCategory10);

Последовательные масштабы — это новый класс масштабов с фиксированным выходным интерполятором вместо диапазона. Обычно эти масштабы используются для реализации непрерывных последовательных или дивергирующих цветовых схем. На вдохновляясь новыми воспринимающими цветовыми картами Matplotlib, 4.0 теперь включает виридис, инферно, магма, плазма интерполяторы для использования с последовательными масштабами. Используя d3.quantize, эти интерполяторы также могут быть применены к масштабам квантилей, квантизации и пороговым масштабам.

viridis inferno magma plasma

4.0 также поставляется с новыми схемами Cubehelix, включая по умолчанию Дейва Грина и циклическую радугу, вдохновленную Маттео Никколи:

cubehelix rainbow warm cool

Для ещё большего количества последовательных и категориальных цветовых схем см. d3-scale-chromatic.

Для ознакомления с масштабами см. Введение в d3-scale.

Выборки (d3-selection)

Выборки больше не являются подклассами массива с использованием вставки в цепочку прототипов; теперь они являются обычными объектами, что повышает производительность. Внутренние поля (selection._groups, selection._parents) являются закрытыми; пожалуйста, используйте документированный публичный API для управления выборками. Новый метод selection.nodes генерирует массив всех узлов в выборке.

Выборки теперь являются неизменяемыми: элементы и родители в выборке никогда не изменяются. (Атрибуты и содержимое элементов, конечно, всё ещё будут изменяться!) Методы selection.sort и selection.data теперь возвращают новые выборки, а не изменяют выборку на месте. Кроме того, selection.append больше не объединяет входящие узлы в выборку обновления; используйте selection.merge для объединения входящих и обновлённых после объединения данных. Например, следующий шаблон общего обновления в 3.x:

var circle = svg.selectAll("circle").data(data) // UPDATE
    .style("fill", "blue");

circle.exit().remove(); // EXIT

circle.enter().append("circle") // ENTER; modifies UPDATE! 🌶
    .style("fill", "green");

circle // ENTER + UPDATE
    .style("stroke", "black");

В 4.0 будет переписан как:

var circle = svg.selectAll("circle").data(data) // UPDATE
    .style("fill", "blue");

circle.exit().remove(); // EXIT

circle.enter().append("circle") // ENTER
    .style("fill", "green")
  .merge(circle) // ENTER + UPDATE
    .style("stroke", "black");

Об этом изменении подробнее в Что делает программное обеспечение хорошим.

В 3.x методы selection.enter и selection.exit были не определены, пока вы не вызовете selection.data, что приводило к ошибке TypeError, если вы пытались получить к ним доступ. В 4.0 теперь они просто возвращают пустую выборку, если выборка не была связана с данными.

В 3.x, selection.append всегда добавлял новый элемент в качестве последнего потомка родителя. Небольшая хитрость заключалась в использовании selection.insert без указания селектора before при входе узлов, что приводило к вставке входящих узлов перед следующим элементом в выборке обновления. В 4.0 это теперь стандартное поведение selection.append; если вы не указываете селектор before для selection.insert, вставленный элемент добавляется в качестве последнего потомка. Это изменение сохраняет относительный порядок элементов и данных в шаблоне общего обновления. Например, при следующем DOM:

<div>a</div>
<div>b</div>
<div>f</div>

И следующем коде:

var div = d3.select("body").selectAll("div")
  .data(["a", "b", "c", "d", "e", "f"], function(d) { return d || this.textContent; });

div.enter().append("div")
    .text(function(d) { return d; });

Результирующий DOM будет:

<div>a</div>
<div>b</div>
<div>c</div>
<div>d</div>
<div>e</div>
<div>f</div>

Таким образом, входящие c, d и e вставляются перед f, так как f — следующий элемент в обновленном выборе. Хотя этого поведения достаточно для сохранения порядка, если порядок новых данных стабилен, если порядок данных меняется, вам всё равно необходимо использовать selection.order для переупорядочения элементов.

Теперь существует только один класс выбора. 3.x реализовывал выборы ввода с использованием специального класса с различным поведением для enter.append и enter.select; следствием этого проектирования стало то, что выборы ввода в 3.x лишены некоторых методов. В 4.0 выборы ввода являются просто обычными выборами; они имеют те же методы и то же поведение. Заполнитель узлов ввода теперь реализует node.appendChild, node.insertBefore, node.querySelector и node.querySelectorAll.

Метод selection.data был слегка изменён по отношению к дублирующим ключам. В 3.x, если несколько данных имели одинаковый ключ, дублирующиеся данные игнорировались и не включались в ввод, обновление или выход; в 4.0 дублирующиеся данные всегда помещаются в выбор ввода. В обоих версиях 3.x и 4.0, если несколько элементов имеют одинаковый ключ, дублирующиеся элементы помещаются в выбор выхода. Таким образом, поведение 4.0 теперь является симметричным для ввода и выхода, и общий шаблон обновления теперь будет создавать DOM, соответствующий данным, даже если есть дублирующие ключи.

Выборы имеют несколько новых методов! Используйте selection.raise для перемещения выбранных элементов вперёд своих соседей, чтобы они отображались сверху; используйте selection.lower для перемещения их назад. Используйте selection.dispatch для отправки пользовательского события в обработчики событий.

При вызове в режиме получения selection.data теперь возвращает данные для всех элементов в выборе, а не только данные для первой группы элементов. Метод selection.call больше не устанавливает this контекст при вызове указанной функции; выбор передаётся в качестве первого аргумента функции, поэтому используйте его. Метод selection.on теперь принимает несколько типов событий, разделённых пробелами, так что вы можете добавлять или удалять несколько обработчиков одновременно. Например:

selection.on("mousedown touchstart", function() {
  console.log(d3.event.type);
});

Аргументы, передаваемые функциям обратного вызова, слегка изменились в 4.0 для большей согласованности. Стандартные аргументы — это данные элемента (d), индекс элемента (i) и группа элемента (nodes), при этом this является элементом. Небольшое исключение из этого соглашения — selection.data, которое оценивается для каждой группы, а не для каждого элемента; ему передаются данные родителя группы (d), индекс группы (i) и родители выбора (parents), при этом this является родителем группы.

Новый d3.local предоставляет механизм для определения локальных переменных: состояния, привязанного к элементам DOM, и доступного любому дочернему элементу. Это может быть удобная альтернатива использованию selection.each или хранению локального состояния в данных.

Пространство имён d3.ns.prefix было переименовано в d3.namespaces, а метод d3.ns.qualify — в d3.namespace. Также доступны несколько новых методов низкого уровня.

d3.matcher используется внутренне методом selection.filter; d3.selector — методом selection.select; d3.selectorAll — методом selection.selectAll; d3.creator — методами selection.append и selection.insert. Новый d3.window возвращает окно владельца для данного элемента, окна или документа. Новый d3.customEvent временно устанавливает d3.event при вызове функции, позволяя вам реализовать элементы управления, которые отправляют пользовательские события; это используется в d3-drag, d3-zoom и d3-brush.

В целях экономии многозначные методы (где вы передаёте объект для одновременной установки нескольких атрибутов, стилей или свойств) были выделены в d3-selection-multi и больше не являются частью основного набора. Методы отображения карты многозначных значений также были переименованы во множественное число, чтобы уменьшить перегрузку: selection.attrs, selection.styles и selection.properties.

Фигуры (d3-shape)

В соответствии с большим слиянием пространств имён:

  • d3.svg.line ↦ d3.line
  • d3.svg.line.radial ↦ d3.radialLine
  • d3.svg.area ↦ d3.area
  • d3.svg.area.radial ↦ d3.radialArea
  • d3.svg.arc ↦ d3.arc
  • d3.svg.symbol ↦ d3.symbol
  • d3.svg.symbolTypes ↦ d3.symbolTypes
  • d3.layout.pie ↦ d3.pie
  • d3.layout.stack ↦ d3.stack
  • d3.svg.diagonal ↦ УДАЛЕНО (см. d3/d3-shape#27)
  • d3.svg.diagonal.radial ↦ УДАЛЕНО

Фигуры больше не ограничены SVG; теперь они могут рендериться в Canvas! Генераторы фигур теперь поддерживают необязательный контекст: при наличии CanvasRenderingContext2D вы можете рендерить фигуру как путь canvas для заливки или обводки. Например, круговая диаграмма canvas может использовать генератор дуг:

var arc = d3.arc()
    .outerRadius(radius - 10)
    .innerRadius(0)
    .context(context);

Для рендеринга дуги для заданных данных d:

context.beginPath();
arc(d);
context.fill();

См. line.context, area.context и arc.context для получения дополнительной информации. Под капотом фигуры используют d3-path для сериализации методов пути canvas в данные пути SVG, когда контекст равен null; таким образом, фигуры оптимизированы для рендеринга в canvas. Вы также можете теперь выводить линии из областей. Линия разделяет большинство тех же аксессоров, таких как line.defined и line.curve, с областью, из которой она получена. Например, для рендеринга верхней линии области используйте area.lineY1; для нижней — area.lineY0.

4.0 представляет новую API кривых для указания того, как линейные и площадные фигуры интерполируют между точками данных. Методы line.interpolate и area.interpolate были заменены на line.curve и area.curve. Кривые реализуются с использованием интерфейса кривых, а не как функция, которая возвращает строку данных пути SVG; это позволяет кривым рендерить как в SVG, так и в Canvas. Кроме того, line.curve и area.curve теперь принимают функцию, которая создаёт кривую для заданного контекста, а не строку. Полный список эквивалентов:

  • linear ↦ d3.curveLinear
  • linear-closed ↦ d3.curveLinearClosed
  • step ↦ d3.curveStep
  • step-before ↦ d3.curveStepBefore
  • step-after ↦ d3.curveStepAfter
  • basis ↦ d3.curveBasis
  • basis-open ↦ d3.curveBasisOpen
  • basis-closed ↦ d3.curveBasisClosed
  • bundle ↦ d3.curveBundle
  • cardinal ↦ d3.curveCardinal
  • cardinal-open ↦ d3.curveCardinalOpen
  • cardinal-closed ↦ d3.curveCardinalClosed
  • monotone ↦ d3.curveMonotoneX

Но это ещё не всё! 4.0 теперь предоставляет параметризованные сплайны Катмулла–Рома, как предложили Юксель и др.. Они доступны как d3.curveCatmullRom, d3.curveCatmullRomClosed и d3.curveCatmullRomOpen.

catmullRom

catmullRomOpen

catmullRomClosed

Каждый тип кривой может определять свои именованные параметры, заменяя line.tension и area.tension. Например, сплайны Catmull–Rom параметризуются с помощью catmullRom.alpha и по умолчанию равны 0,5, что соответствует центробежному сплайну, который избегает самопересечений и перескоков. Для равномерного сплайна Catmull–Rom вместо этого:

var line = d3.line()
    .curve(d3.curveCatmullRom.alpha(0));

Версия 4.0 исправляет интерпретацию параметра натяжения кардинального сплайна, который теперь задается как cardinal.tension и по умолчанию равен нулю для равномерного сплайна Catmull–Rom; значение натяжения 1 создает линейную кривую. Также были исправлены первый и последний сегменты базисных и кардинальных кривых! Удалено недокументированное поле interpolate.reverse. Кривые могут определять различное поведение для верхних и нижних линий, считая последовательность curve.lineStart внутри curve.areaStart. См. реализацию d3.curveStep для примера.

Версия 4.0 исправляет множество ошибок в реализации монотонной кривой и вводит d3.curveMonotoneY; это похоже на d3.curveMonotoneX, за исключением того, что требует, чтобы входные точки были монотонными по y, а не по x, например, для диаграммы вертикальной линии. Новый d3.curveNatural производит естественный кубический сплайн. Значение по умолчанию β для d3.curveBundle теперь равно 0,85, а не 0,7, что соответствует значениям, используемым Holten. Версия 4.0 также имеет более надежную реализацию отступа дуги; см. arc.padAngle и arc.padRadius.

Версия 4.0 вводит новый API типа символа. Типы символов передаются в symbol.type вместо строк. Эквиваленты:

  • circle ↦ d3.symbolCircle
  • cross ↦ d3.symbolCross
  • diamond ↦ d3.symbolDiamond
  • square ↦ d3.symbolSquare
  • triangle-down ↦ УДАЛЕНО
  • triangle-up ↦ d3.symbolTriangle
  • ДОБАВЛЕНО ↦ d3.symbolStar
  • ДОБАВЛЕНО ↦ d3.symbolWye

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

Наконец, версия 4.0 перерабатывает API структуры стека, заменяя d3.layout.stack на d3.stack. Генератор стека больше не нуждается в x-акцессоре. Кроме того, API был упрощен: генератор stack теперь принимает табличные данные, такие как этот массив объектов:

var data = [
  {month: new Date(2015, 0, 1), apples: 3840, bananas: 1920, cherries: 960, dates: 400},
  {month: new Date(2015, 1, 1), apples: 1600, bananas: 1440, cherries: 960, dates: 400},
  {month: new Date(2015, 2, 1), apples:  640, bananas:  960, cherries: 640, dates: 400},
  {month: new Date(2015, 3, 1), apples:  320, bananas:  480, cherries: 640, dates: 400}
];

Для генерации структуры стека сначала определите генератор стека, а затем примените его к данным:

var stack = d3.stack()
    .keys(["apples", "bananas", "cherries", "dates"])
    .order(d3.stackOrderNone)
    .offset(d3.stackOffsetNone);

var series = stack(data);

Полученный массив имеет один элемент на серию. Каждая серия имеет одну точку за месяц, и каждая точка имеет нижнее и верхнее значение, определяющие нижнюю и верхнюю линии:

[
  [[   0, 3840], [   0, 1600], [   0,  640], [   0,  320]], // apples
  [[3840, 5760], [1600, 3040], [ 640, 1600], [ 320,  800]], // bananas
  [[5760, 6720], [3040, 4000], [1600, 2240], [ 800, 1440]], // cherries
  [[6720, 7120], [4000, 4400], [2240, 2640], [1440, 1840]], // dates
]

Затем каждая серия обычно передается в генератор области, чтобы отобразить диаграмму области, или используется для построения прямоугольников для столбчатой диаграммы. Генераторы стеков больше не изменяют входные данные, поэтому stack.out был удален.

Для введения в формы, см. Введение в d3-shape.

Форматы времени (d3-time-format)

В соответствии с большим сглаживанием пространства имен, конструкторы форматов получили новые имена:

  • d3.time.format ↦ d3.timeFormat
  • d3.time.format.utc ↦ d3.utcFormat
  • d3.time.format.iso ↦ d3.isoFormat

Метод format.parse также был удален в пользу отдельных конструкторов анализаторов d3.timeParse, d3.utcParse и d3.isoParse. Таким образом, этот код в 3.x:

var parseTime = d3.time.format("%c").parse;

Может быть переписан в 4.0 как:

var parseTime = d3.timeParse("%c");

Формат времени с несколькими шкалами d3.time.format.multi был заменен на формат сетки d3.scaleTime. Форматы времени теперь приводят входные данные к датам, а парсеры времени приводят входные данные к строкам. Директива %Z теперь позволяет более гибкий разбор смещений часовых поясов, таких как -0700, -07:00, -07, и Z. Директива %p теперь правильно анализируется, когда имя периода в языке имеет более двух символов (например, «a.m.»).

По умолчанию в английском языке США теперь используется 12-часовой формат времени и более краткая запись даты. Это соответствует местной традиции и согласуется с date.toLocaleString в Chrome, Firefox и Node:

var now = new Date;
d3.timeFormat("%c")(new Date); // "6/23/2016, 2:01:33 PM"
d3.timeFormat("%x")(new Date); // "6/23/2016"
d3.timeFormat("%X")(new Date); // "2:01:38 PM"

Теперь вы можете установить язык по умолчанию с помощью d3.timeFormatDefaultLocale! Локали публикуются как JSON в npm.

Производительность форматирования и анализа времени была улучшена, и форматировщик и анализатор UTC имеют более чистую реализацию (что предотвращает временное переопределение глобальной переменной Date).

Временные интервалы (d3-time)

В соответствии с большим сглаживанием пространства имен, интервалы локального времени были переименованы:

  • ДОБАВЛЕНО ↦ d3.timeMillisecond
  • d3.time.second ↦ d3.timeSecond
  • d3.time.minute ↦ d3.timeMinute
  • d3.time.hour ↦ d3.timeHour
  • d3.time.day ↦ d3.timeDay
  • d3.time.sunday ↦ d3.timeSunday
  • d3.time.monday ↦ d3.timeMonday
  • d3.time.tuesday ↦ d3.timeTuesday
  • d3.time.wednesday ↦ d3.timeWednesday
  • d3.time.thursday ↦ d3.timeThursday
  • d3.time.friday ↦ d3.timeFriday
  • d3.time.saturday ↦ d3.timeSaturday
  • d3.time.week ↦ d3.timeWeek
  • d3.time.month ↦ d3.timeMonth
  • d3.time.year ↦ d3.timeYear

Аналогичным образом были переименованы интервалы времени UTC:

  • ДОБАВЛЕНО ↦ d3.utcMillisecond
  • d3.time.second.utc ↦ d3.utcSecond
  • d3.time.minute.utc ↦ d3.utcMinute
  • d3.time.hour.utc ↦ d3.utcHour
  • d3.time.day.utc ↦ d3.utcDay
  • d3.time.sunday.utc ↦ d3.utcSunday
  • d3.time.monday.utc ↦ d3.utcMonday
  • d3.time.tuesday.utc ↦ d3.utcTuesday
  • d3.time.wednesday.utc ↦ d3.utcWednesday
  • d3.time.thursday.utc ↦ d3.utcThursday
  • d3.time.friday.utc ↦ d3.utcFriday
  • d3.time.saturday.utc ↦ d3.utcSaturday
  • d3.time.week.utc ↦ d3.utcWeek
  • d3.time.month.utc ↦ d3.utcMonth
  • d3.time.year.utc ↦ d3.utcYear

Псевдонимы диапазона локального времени были переименованы:

  • d3.time.seconds ↦ d3.timeSeconds
  • d3.time.minutes ↦ d3.timeMinutes
  • d3.time.hours ↦ d3.timeHours
  • d3.time.days ↦ d3.timeDays
  • d3.time.sundays ↦ d3.timeSundays
  • d3.time.mondays ↦ d3.timeMondays
  • d3.time.tuesdays ↦ d3.timeTuesdays
  • d3.time.wednesdays ↦ d3.timeWednesdays
  • d3.time.thursdays ↦ d3.timeThursdays
  • d3.time.fridays ↦ d3.timeFridays
  • d3.time.saturdays ↦ d3.timeSaturdays
  • d3.time.weeks ↦ d3.timeWeeks
  • d3.time.months ↦ d3.timeMonths
  • d3.time.years ↦ d3.timeYears

Псевдонимы диапазона времени UTC были переименованы:

  • d3.time.seconds.utc ↦ d3.utcSeconds
  • d3.time.minutes.utc ↦ d3.utcMinutes
  • d3.time.hours.utc ↦ d3.utcHours
  • d3.time.days.utc ↦ d3.utcDays
  • d3.time.sundays.utc ↦ d3.utcSundays
  • d3.time.mondays.utc ↦ d3.utcMondays
  • d3.time.tuesdays.utc ↦ d3.utcTuesdays
  • d3.time.wednesdays.utc ↦ d3.utcWednesdays
  • d3.time.thursdays.utc ↦ d3.utcThursdays
  • d3.time.fridays.utc ↦ d3.utcFridays
  • d3.time.saturdays.utc ↦ d3.utcSaturdays
  • d3.time.weeks.utc ↦ d3.utcWeeks
  • d3.time.months.utc ↦ d3.utcMonths
  • d3.time.years.utc ↦ d3.utcYears

Поведение метода interval.range (и удобных алиасов, таких как d3.timeDays) изменилось, когда step больше единицы. Вместо фильтрации возвращаемых дат по номеру поля, interval.range теперь ведет себя как d3.range: он просто пропускает, возвращая каждую step-ую дату. Например, следующий код в версии 3.x возвращает только нечётные дни месяца:

d3.time.days(new Date(2016, 4, 28), new Date(2016, 5, 5), 2);
// [Sun May 29 2016 00:00:00 GMT-0700 (PDT),
//  Tue May 31 2016 00:00:00 GMT-0700 (PDT),
//  Wed Jun 01 2016 00:00:00 GMT-0700 (PDT),
//  Fri Jun 03 2016 00:00:00 GMT-0700 (PDT)]

Обратите внимание, что возвращаемый массив дат не начинается с даты start, так как 28 мая — чётное число. Также обратите внимание, что 31 мая и 1 июня находятся в один день, а не в два! Поведение d3.timeDays в версии 4.0, вероятно, ближе к тому, чего вы ожидаете:

d3.timeDays(new Date(2016, 4, 28), new Date(2016, 5, 5), 2);
// [Sat May 28 2016 00:00:00 GMT-0700 (PDT),
//  Mon May 30 2016 00:00:00 GMT-0700 (PDT),
//  Wed Jun 01 2016 00:00:00 GMT-0700 (PDT),
//  Fri Jun 03 2016 00:00:00 GMT-0700 (PDT)]

Если вам нужен отфильтрованный просмотр временного интервала (скажем, для гарантии согласованности двух перекрывающихся диапазонов, например, при генерации метки шкалы времени), вы можете использовать новый метод interval.every или его более общий аналог interval.filter:

d3.timeDay.every(2).range(new Date(2016, 4, 28), new Date(2016, 5, 5));
// [Sun May 29 2016 00:00:00 GMT-0700 (PDT),
//  Tue May 31 2016 00:00:00 GMT-0700 (PDT),
//  Wed Jun 01 2016 00:00:00 GMT-0700 (PDT),
//  Fri Jun 03 2016 00:00:00 GMT-0700 (PDT)]

Временные интервалы теперь предоставляют метод interval.count для подсчёта количества границ интервалов после даты start и до или равной дате end. Это заменяет методы d3.time.dayOfYear и аналогичные методы в версии 3.x. Например, этот код из версии 3.x:

var now = new Date;
d3.time.dayOfYear(now); // 165

Может быть переписан в версии 4.0 как:

var now = new Date;
d3.timeDay.count(d3.timeYear(now), now); // 165

Аналогично, вместо d3.time.weekOfYear версии 3.x в версии 4.0 вы напишете:

d3.timeWeek.count(d3.timeYear(now), now); // 24

Новый метод interval.count, конечно, более общий. Например, вы можете использовать его для вычисления часа недели для тепловой карты:

d3.timeHour.count(d3.timeWeek(now), now); // 64

Вот все эквивалентности с 3.x на 4.0:

  • d3.time.dayOfYear ↦ d3.timeDay.count
  • d3.time.sundayOfYear ↦ d3.timeSunday.count
  • d3.time.mondayOfYear ↦ d3.timeMonday.count
  • d3.time.tuesdayOfYear ↦ d3.timeTuesday.count
  • d3.time.wednesdayOfYear ↦ d3.timeWednesday.count
  • d3.time.thursdayOfYear ↦ d3.timeThursday.count
  • d3.time.fridayOfYear ↦ d3.timeFriday.count
  • d3.time.saturdayOfYear ↦ d3.timeSaturday.count
  • d3.time.weekOfYear ↦ d3.timeWeek.count
  • d3.time.dayOfYear.utc ↦ d3.utcDay.count
  • d3.time.sundayOfYear.utc ↦ d3.utcSunday.count
  • d3.time.mondayOfYear.utc ↦ d3.utcMonday.count
  • d3.time.tuesdayOfYear.utc ↦ d3.utcTuesday.count
  • d3.time.wednesdayOfYear.utc ↦ d3.utcWednesday.count
  • d3.time.thursdayOfYear.utc ↦ d3.utcThursday.count
  • d3.time.fridayOfYear.utc ↦ d3.utcFriday.count
  • d3.time.saturdayOfYear.utc ↦ d3.utcSaturday.count
  • d3.time.weekOfYear.utc ↦ d3.utcWeek.count

В D3 4.0 теперь вы также можете определять пользовательские временные интервалы с помощью d3.timeInterval. Интервалы d3.timeYear, d3.utcYear, d3.timeMillisecond и d3.utcMillisecond имеют оптимизированные реализации метода interval.every, что необходимо для эффективной генерации меток времени для очень больших или очень малых областей. Более общим образом, производительность временных интервалов была улучшена, и временные интервалы теперь лучше справляются с летним временем в различных локалях.

Таймеры (d3-timer)

В D3 3.x единственный способ остановить таймер — это если его обратный вызов вернёт true. Например, этот таймер останавливается через секунду:

d3.timer(function(elapsed) {
  console.log(elapsed);
  return elapsed >= 1000;
});

В 4.0 используйте timer.stop вместо этого:

var t = d3.timer(function(elapsed) {
  console.log(elapsed);
  if (elapsed >= 1000) {
    t.stop();
  }
});

Основное преимущество timer.stop заключается в том, что таймеры не обязаны самоликвидироваться: их можно остановить извне, что позволяет немедленно и синхронно освободить связанные ресурсы и разделить обязанности. Вышеприведенное эквивалентно:

var t = d3.timer(function(elapsed) {
  console.log(elapsed);
});

d3.timeout(function() {
  t.stop();
}, 1000);

Это улучшение распространяется на d3-transition: теперь, когда переход прерывается, его ресурсы освобождаются немедленно, а не нужно ждать начала перехода.

4.0 также вводит новый метод timer.restart для перезапуска таймеров, для замены обратного вызова работающего таймера или для изменения его задержки или времени отсчёта. В отличие от timer.stop, за которым следует d3.timer, timer.restart сохраняет приоритет вызова существующего таймера: он гарантирует, что порядок вызова активных таймеров останется прежним. Метод d3.timer.flush переименован в d3.timerFlush.

Некоторые шаблоны использования в D3 3.x могли привести к зависанию браузера, когда фоновый сайт возвращался в фокус. Например, следующий код планирует переход каждую секунду:

setInterval(function() {
  d3.selectAll("div").transition().call(someAnimation); // BAD
}, 1000);

Если такой код работает в фоновом режиме в течение нескольких часов, тысячи запланированных переходов будут пытаться запуститься одновременно при возвращении страницы в фокус. D3 4.0 избегает этого зависания, замораживая время в фоновом режиме: когда страница находится в фоновом режиме, время не идёт вперёд, и поэтому очередь таймеров не накапливается для выполнения при возвращении страницы в фокус. Используйте d3.timer вместо переходов для планирования длительной анимации или используйте d3.timeout и d3.interval вместо setTimeout и setInterval, чтобы предотвратить планирование переходов в фоновом режиме:

d3.interval(function() {
  d3.selectAll("div").transition().call(someAnimation); // GOOD
}, 1000);

Замораживая время в фоновом режиме, таймеры фактически «не замечают» перехода в фоновый режим. Словно ничего не произошло! 4.0 также теперь использует высокоточное время (performance.now), если оно доступно; текущее время доступно как d3.now.

Переходы (d3-transition)

Метод selection.transition теперь принимает необязательный экземпляр transition, который можно использовать для синхронизации нового перехода с существующим переходом. (Это изменение подробно обсуждается в What Makes Software Good?) Например:

var t = d3.transition()
    .duration(750)
    .ease(d3.easeLinear);

d3.selectAll(".apple").transition(t)
    .style("fill", "red");

d3.selectAll(".orange").transition(t)
    .style("fill", "orange");

Переходы, созданные таким образом, наследуют временные параметры от ближайшего родительского элемента и, таким образом, синхронизируются, даже если у перехода, на который ссылаются, есть переменные временные параметры, такие как ступенчатая задержка. Этот метод заменяет глубоко магическое поведение transition.each в 3.x; в 4.0, transition.each идентично selection.each. Используйте новый метод transition.on для прослушивания событий перехода.

Значение transition.delay изменилось для цепочек переходов, созданных с помощью transition.transition. Указанная задержка теперь относительна к предыдущему переходу в цепочке, а не к первому; это упрощает вставку промежуточных пауз. Например:

d3.selectAll(".apple")
  .transition() // First fade to green.
    .style("fill", "green")
  .transition() // Then red.
    .style("fill", "red")
  .transition() // Wait one second. Then brown, and remove.
    .delay(1000)
    .style("fill", "brown")
    .remove();

Время теперь заморожено в фоновом режиме; см. d3-timer для получения дополнительной информации. Хотя раньше переходы не выполнялись в фоновом режиме, теперь они возобновляют выполнение там, где остановились, когда страница возвращается в фокус. Это предотвращает зависание страницы, не планируя неограниченное количество переходов в фоновом режиме. Если вы хотите запланировать бесконечно повторяющийся переход, используйте события перехода или используйте d3.timeout и d3.interval вместо setTimeout и setInterval.

Метод selection.interrupt теперь отменяет все запланированные переходы на выбранных элементах, помимо прерывания любого активного перехода. При прерывании переходов все ресурсы, связанные с переходом, теперь освобождаются немедленно, а не ожидают начала перехода, что повышает производительность. (См. также timer.stop.) Новый метод d3.interrupt — альтернатива методу selection.interrupt для быстрого прерывания отдельного узла.

Новый метод d3.active позволяет выбрать текущий активный переход на заданном узле, если таковой имеется. Это полезно для изменения текущих переходов и для планирования бесконечно повторяющихся переходов. Например, этот переход непрерывно колеблется между красным и синим:

d3.select("circle")
  .transition()
    .on("start", function repeat() {
        d3.active(this)
            .style("fill", "red")
          .transition()
            .style("fill", "blue")
          .transition()
            .on("start", repeat);
      });

Жизненный цикл перехода жизненный цикл перехода теперь более формально определен и применяется. Например, попытка изменить продолжительность работающего перехода теперь приводит к ошибке, а не к тихому провалу. Метод transition.remove был исправлен, если используются несколько имён переходов: элемент удаляется только в том случае, если у него нет запланированных переходов, независимо от имени. Метод transition.ease теперь всегда принимает функцию сглаживания, а не строку. По окончании перехода интерполяции вызываются один последний раз со значением t, равным ровно 1, независимо от связанной функции сглаживания.

Как и в случае с выборками в версии 4.0, все функции обратного вызова перехода теперь принимают стандартные аргументы: данные элемента (d), индекс элемента (i) и группу элементов (nodes), где this — сам элемент. Это существенно затрагивает transition.attrTween и transition.styleTween, которые больше не передают функции интерполяции текущее значение атрибута или стиля в качестве третьего аргумента. Методы transition.attrTween и transition.styleTween теперь могут вызываться в режиме получения для отладки или для совместного использования определений интерполяций между переходами.

Однородные переходы теперь оптимизированы! Если все элементы в переходе используют одни и те же интерполяции, интерполяторы или обработчики событий, это состояние теперь совместно используется для перехода, а не выделяется отдельно для каждого элемента. Версия 4.0 также использует оптимизированный интерполятор по умолчанию вместо d3.interpolate для transition.attr и transition.style. Теперь переходы могут интерполировать как CSS, так и SVG преобразования.

Для повторно используемых компонентов, поддерживающих переходы, таких как оси, новый метод transition.selection возвращает выборку, соответствующую данному переходу. Также имеется новый метод transition.merge, который эквивалентен selection.merge.

Для экономии места методы карт множественных значений были извлечены в d3-selection-multi и больше не являются частью стандартного набора. Методы карт множественных значений также были переименованы в множественное число, чтобы уменьшить перегрузку: transition.attrs и transition.styles.

Диаграммы Вороного (d3-voronoi)

Метод d3.geom.voronoi был переименован в d3.voronoi, а метод voronoi.clipExtent — в voronoi.extent. Недокументированное свойство polygon.point в версии 3.x, которое представляет собой элемент в исходных данных, соответствующий многоугольнику, было переименовано в polygon.data.

Вызов voronoi теперь возвращает полную диаграмму Вороного, которая включает топологическую информацию: каждый край Вороного предоставляет edge.left и edge.right, указывающие сайты с обеих сторон края, а каждая ячейка Вороного определяется как массив таких рёбер и соответствующего сайта. Диаграмма Вороного может быть использована для эффективного вычисления как разбиения Вороного, так и Делоне для набора точек: diagram.polygons, diagram.links и diagram.triangles. Новая топология также полезна в сочетании с TopoJSON; см. пример топологии диаграммы Вороного.

Методы voronoi.polygons и diagram.polygons теперь требуют объема; неявный объём ±1e6 больше не используется. Методы voronoi.links, voronoi.triangles, diagram.links и diagram.triangles теперь учитывают объем обрезки: поскольку триангуляция Делоне вычисляется как двойственная к диаграмме Вороного, два сайта соединены только тогда, когда обрезанные ячейки соприкасаются. Чтобы вычислить триангуляцию Делоне без учёта обрезки, задайте объем равным null.

У генератора Вороного наконец-то появилось чётко определённое поведение для совпадающих вершин: первая из набора совпадающих точек имеет определённую ячейку, а последующие дубликаты точек имеют ячейки со значением null. Возвращаемый массив многоугольников является разреженным, поэтому, используя array.forEach или array.map, вы можете легко пропустить неопределённые ячейки. Генератор Вороного также теперь правильно обрабатывает случай, когда никакие края ячеек не пересекают объём.

Масштабирование (d3-zoom)

Поведение масштабирования d3.behavior.zoom было переименовано в d3.zoom. Поведение масштабирования больше не хранит активное преобразование масштабирования (т.е., видимую область; масштаб и смещение) внутренне. Теперь преобразование масштабирования хранится на любых элементах, к которым было применено поведение масштабирования. Преобразование масштабирования доступно как event.transform внутри события масштабирования или путём вызова d3.zoomTransform на заданном элементе. Для программного масштабирования используйте zoom.transform со заданной выборкой или переходом; см. пример переходов масштабирования. Метод zoom.event был удалён.

Для упрощения программного масштабирования доступны несколько новых удобных методов на базе zoom.transform: zoom.translateBy, zoom.scaleBy и zoom.scaleTo. Также есть новый API для описания преобразований масштабирования. Поведение масштабирования больше не зависит от шкал, но вы можете использовать transform.rescaleX, transform.rescaleY, transform.invertX или transform.invertY для преобразования области определения шкалы. Вместо event.scale в версии 3.x используется event.transform.k, а вместо event.translate — event.transform.x и event.transform.y. Метод zoom.center был удалён в пользу программного масштабирования.

Поведение масштабирования теперь наконец поддерживает простые ограничения на перемещение! Новый метод zoom.translateExtent позволяет определить видимый объём мира: текущий видимый объём (объём области просмотра, как определено методом zoom.extent) всегда находится в пределах объёма перемещения. Метод zoom.size был заменён методом zoom.extent, а поведение по умолчанию теперь более разумное: оно по умолчанию соответствует объёму элемента владельца поведения масштабирования, а не жёстко задаётся в 960×500. (Это также улучшает путь по умолчанию, выбранный во время плавных переходов масштабирования!)

Взаимодействие с поведением масштабирования также улучшилось. Теперь оно правильно обрабатывает одновременное прокручивание и перетаскивание, а также одновременное касание и нажатие мыши. Поведение масштабирования теперь игнорирует события прокрутки колесика в пределах пределов области масштабирования, позволяя прокручивать область, подлежащую масштабированию. События zoomstart и zoomend были переименованы в start и end. По умолчанию, поведение масштабирования теперь игнорирует щелчки правой кнопкой мыши, предназначенные для контекстного меню; используйте zoom.filter для управления событиями, которые будут игнорироваться. Поведение масштабирования также игнорирует эмулированные события мыши на устройствах iOS. Поведение масштабирования теперь потребляет обработанные события, что облегчает его комбинирование с другими интерактивными поведением, такими как перетаскивание.

© 2010–2023 Michael Bostock
Licensed under the BSD License.
https://github.com/d3/d3/blob/master/CHANGES.md

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API