Spec-Zone.ru › D3.js 5

Изменения в 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, для управления конкурентностью.

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

D3 теперь предоставляет реализации метода марширующих квадратов и оценки плотности через d3-contour! Существуют два новых метода d3-selection: selection.clone для вставки клонов выбранных узлов и d3.create для создания отсоединённых элементов. Географические проекции d3-geo теперь поддерживают 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 с помощью обычных тегов 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 UMD теперь безымянный. Никакой d3 глобальный объект не экспортируется, если обнаруживается AMD или CommonJS. В обычной среде, микробиблиотеки D3 используют d3 глобальный объект, даже если вы загружаете их независимо; таким образом, ваш код будет одинаковым, независимо от того, используете ли вы основной пакет.

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

К раздражению некоторых пользователей, 3.x использовал Unicode-переменные, такие как λ, φ, τ и π, для компактного представления математических операций. Недостатком этого подхода было то, что ошибка SyntaxError возникала, если вы загружали не сжатый D3, используя ISO-8859-1 вместо UTF-8. 3.x также использовал Unicode-строковые литералы, такие как префикс 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 больше не предпринимает сложных попыток избежать ошибки с плавающей запятой, когда step не является целым числом. Возвращаемые значения строго определяются как start + i * step, где i — целое число. (Узнайте больше о математике с плавающей запятой.) d3.range возвращает пустой массив для бесконечных диапазонов вместо вывода ошибки.

Подпись метода для необязательных аксессоров была изменена для большей согласованности с методами массивов, такими как массив.forEach: аксессор получает текущий элемент (d), индекс (i) и массив (data), а 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 в режиме частоты. Для вычисления распределения вероятностей разделите количество элементов в каждом бине на общее количество элементов.

Метод histogram.range был переименован в histogram.domain для согласованности со шкалами. Метод histogram.bins был переименован в histogram.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.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 undefined. Например:

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 также был изменён на значение, ключ и карта, а порядок аргументов для set.each теперь значение, значение и множество. Это ближе к 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 теперь возвращает объекты {ключ, значение} для листов записей вместо {ключ, значения}. Это упрощает использование 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 использовала строки, такие как «cubic-in-out», для идентификации методов сглаживания; эти строки можно было передавать 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, параметризуемые функции плавного перехода теперь имеют именованные параметры: поли.показатель, эластик.амплитуда, эластик.период и бек.перескок. Например, в D3 3.x вы могли бы сказать:

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

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

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

Многие функции плавного перехода были оптимизированы для производительности и точности. Также были исправлены несколько ошибок, например, интерпретация параметра перескока для плавного перехода «бек» и параметра периода для плавного перехода «эластик». Кроме того, 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, чтобы зафиксировать позицию узла. В качестве альтернативы Вороной 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 теперь предназначена для символьных данных (т.е., литеральных строк), а не для кодов символов. Это полезно, если вы просто хотите применить заполнение и выравнивание и вам не нужно форматировать числа. Например, печально известный левый дозаполнитель (а также центральный и правый!) может быть удобно реализован как:

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; нулевая проекция используется с предобработанной геометрией и обычно быстрее отрисовывается.

«Проекции по умолчанию» — когда вы передаёте функцию, а не проекцию в 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 format», используемый во многих примерах D3), новый оператор d3.stratify упрощает преобразование табличных данных в иерархические данные! Это удобно, если у вас уже есть данные в табличной форме, например, результат запроса SQL или CSV-файла:

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

Чтобы преобразовать это в корневой узел узел:

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

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

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

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

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

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

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

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

Макет кругового размещения 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, рекомендуемый шаблон — реализовать оберточный метод и проверить возвращаемое значение. Например, учитывая компонент, использующий внутренний диспетчер, 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 attribute, так и свойство стиля преобразования CSS transform style property. (Обратите внимание, что поддерживаются только 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 больше нет, но если необходимо вычисление обрезки по методу Сазерленда-Хогмана, пожалуйста, отправьте запрос на добавление функции.

Оператор 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 для реализации приближения Барнса–Хатта.

END_OF_DOCUMENT_MARKER

Теперь вы можете удалять данные из древовидного квадранта с помощью 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, эта ошибка теперь сообщается слушателям ошибок, а не возвращается пустой ответ.

Методы 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 теперь имеет viridis, inferno, magma, plasma интерполяторы для использования с последовательными шкалами. Используя 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; теперь они могут рендериться на холсте! Генераторы фигур теперь поддерживают необязательный контекст: при предоставлении CanvasRenderingContext2D вы можете отрисовать фигуру как путь холста для заполнения или обводки. Например, диаграмма с круговыми секторами на холсте может использовать генератор дуг:

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 для сериализации методов пути холста в данные пути SVG, когда контекст равен null; таким образом, фигуры оптимизированы для рендеринга на холсте. Теперь вы также можете получить линии из областей. Линия разделяет большинство тех же аксессоров, таких как line.defined и line.curve, с областью, из которой она получена. Например, чтобы отрисовать верхнюю линию области, используйте area.lineY1; для нижней линии — area.lineY0.

4.0 представляет новый API кривых для задания того, как линейные и площадные фигуры интерполируются между точками данных. Методы line.interpolate и area.interpolate были заменены на line.curve и area.curve. Кривые реализованы с помощью интерфейса 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 теперь предоставляет параметризованные сплайны Catmull–Rom, как предложили Yuksel и др.. Они доступны как 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; натяжение, равное единице, даёт линейную кривую. Первый и последний сегменты кривых basis и cardinal также были исправлены! Недокументированное поле 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 теперь анализируется правильно, когда имя периода в локали длиннее двух символов (например, «ч.д.»).

По умолчанию в локали США используется 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) было изменено, когда шаг больше единицы. Вместо фильтрации возвращаемых дат по номеру поля, 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, который может быть использован для синхронизации нового перехода с существующим переходом. (Это изменение подробно обсуждается в Что делает программное обеспечение хорошим?) Например:

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 есть переменное время, например, ступенчатая задержка. Этот метод заменяет глубоко магическое поведение transition.each в 3.x; в 4.0, transition.each идентичен selection.each. Используйте новый метод transition.on для прослушивания событий перехода.

Значение перехода.delay изменилось для цепочечных переходов, созданных с помощью перехода.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.

Метод выбор.interrupt теперь отменяет все запланированные переходы на выбранных элементах, помимо прерывания любого активного перехода. При прерывании переходов все ресурсы, связанные с переходом, теперь освобождаются немедленно, а не ожидая начала перехода, что улучшает производительность. (См. также таймер.stop.) Новый метод d3.interrupt — это альтернатива методу выбор.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);
      });

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

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

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

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

Для экономии места методы карты с несколькими значениями были вынесены в d3-selection-multi и больше не являются частью основного пакета. Методы карты с несколькими значениями также были переименованы в множественное число, чтобы уменьшить перегрузку: переход.attrs и переход.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.

У генератора Вороного наконец-то появилось определённое поведение для совпадающих вершин: у первой из набора совпадающих точек есть определённая ячейка, а у последующих дублированных точек — пустые ячейки. Возвращаемый массив многоугольников является разреженным, поэтому с помощью 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–2018 Michael Bostock
Licensed under the BSD License.
https://github.com/d3/d3/blob/master/CHANGES.md

Spec-Zone.ru

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