Изменения в 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.
- Порог бинов теперь игнорирует 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.
- Для d3.randomBates разрешены дробные значения n.
- Для d3.randomIrwinHall разрешены дробные значения n.
- Функция Math.random не обернута в стандартном источнике.
Спасибо @Lange, @p-v-d-Veeken, @svanschooten, @Parcly-Taxel и @jrus за ваши contributions!
d3-scale
- Поддержка итерируемых объектов.
- Добавлена diverging.rangeRound.
- Добавлена sequential.range (для совместимости с d3-axis).
- Добавлена sequential.rangeRound.
- Добавлена sequentialQuantile.quantiles.
- Добавлена d3.scaleRadial.
- diverging.range теперь может использоваться для установки интерполятора.
- sequential.range теперь может использоваться для установки интерполятора.
- d3.scaleDiverging теперь может принимать массив значений диапазона вместо интерполятора.
- d3.scaleSequential теперь может принимать массив значений диапазона вместо интерполятора.
- Исправлена continuous.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]; теперь selections можно перебирать!
- Поддерживать итерируемые объекты с 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 на отслеживание событий колеса, если нажата клавиша управления.
- Изменить значение по умолчанию zoom.wheelDelta, чтобы ускорить прокрутку, если нажата клавиша управления.
- Не устанавливать touch-action: none.
- Обновить до d3-selection 2.
Разрывающие изменения
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
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 для создания отсоединённых элементов. Географические проекции теперь поддерживают projection.angle, что позволило реализовать несколько замечательных новых полиэдрических проекций Филиппом Ривьером.
Наконец, в package.json D3 больше нет привязки к точным версиям зависимых модулей D3. Это исправляет проблему с дублированием установок модулей D3.
Изменения в D3 4.0
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 набор теперь безымянный. Никакой d3 глобальный объект не экспортируется, если обнаружен AMD или CommonJS. В стандартной среде микробиблиотеки D3 используют d3 глобальный объект, даже если вы загружаете их независимо; таким образом, написанный вами код одинаков, используете ли вы стандартный набор или нет. (Подробнее см. Давайте создадим (D3) плагин.) Сгенерированный набор больше не хранится в репозитории Git; Bower перенаправлен на d3-bower, и вы можете найти сгенерированные файлы на npm или в последней версии. Нескомпилированный стандартный набор больше не искажен, что делает его более читаемым и сохраняет встроенные комментарии.
К неудовольствию некоторых пользователей, 3.x использовал имена переменных Юникода, такие как λ, φ, τ и π, для краткого представления математических операций. Недостатком этого подхода было то, что ошибка SyntaxError возникала при загрузке нескомпилированного D3 с использованием ISO-8859-1 вместо UTF-8. 3.x также использовал литералы строк Юникода, такие как префикс СИ µ для 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) и массив (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 — это просто массив элементов из входных данных, поэтому 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.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)
В соответствии с общим сглаживанием пространства имен:
Для согласованности с 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 также был изменен на значение, ключ и карта, а порядок аргументов для 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 в сочетании с иерархиями, как в этом примере древовидной карты.
Цвета (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);
Многие функции сплайна были оптимизированы для производительности и точности. Также было исправлено несколько ошибок, таких как интерпретация параметра перескока для обратного сплайна и параметра периода для упругого сплайна. Кроме того, 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 и поддерживает новый параметр минимального расстояния и улучшения производительности благодаря новым quadtrees версии 4.0. Также существуют совершенно новые силы для центрирования узлов и разрешения коллизий.
Новые силы и симуляция были тщательно разработаны для предотвращения недетерминированности. Вместо случайной инициализации узлов, если узлы не имеют заданных положений, они размещаются по схеме филлотаксиса:
Случайные колебания по-прежнему необходимы для разрешения связей, столкновений и сил многочастичных взаимодействий, если существуют совпадающие узлы, но по крайней мере в общем случае, симуляция сил (и результирующая компоновка графа с направленными силами) теперь согласована между браузерами и перезагрузками. 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)
Если точность не указана, поведение форматирования изменилось: теперь для всех директив, кроме none, существует значение точности по умолчанию 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
Для преобразования в корневой узел:
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) теперь расширяемо через treemap.tile! Алгоритм разбиения на прямоугольники, d3.treemapSquarify, по умолчанию был полностью переписан, улучшена производительность и исправлены ошибки в отступах и округлениях. Метод treemap.sticky был заменен методом d3.treemapResquarify, который идентичен d3.treemapSquarify, за исключением того, что он выполняет стабильные обновления, сохраняя соседние элементы. Метод treemap.ratio был заменен на squarify.ratio. И есть новый d3.treemapBinary для бинарных treemap!
Отступы treemap также были улучшены. Теперь treemap различает внешний отступ, который отделяет родителя от его детей, и внутренний отступ, который отделяет смежных братьев и сестер. Вы можете задать верхний, правый, нижний и левый внешний отступ раздельно. Есть новые примеры традиционной вложенной treemap и для treemap Lü и Fogarty каскадной treemap. И есть новый пример, демонстрирующий d3.nest с d3.treemap.
Макеты заполнения пространства d3.treemap и d3.partition теперь выводят x0, x1, y0, y1 для каждого узла вместо x0, dx, y0, dy. Это повышает точность, гарантируя, что края смежных ячеек точно равны, а не иногда немного отличаются из-за операций с плавающей точкой. Макет partition теперь поддерживает округление и отступ.
Макет компоновки кругов, d3.pack, был полностью переписан для лучшего выполнения алгоритма Wang et al., исправлены серьезные ошибки и улучшены результаты! Теперь используется алгоритм Welzl для вычисления точного наименьшего охватывающего круга для каждого родителя, а не приближенного ответа, использованного Wang et al. Вывод 3.x показан слева; 4.0 показан справа:
Неиерархическая реализация также доступна как d3.packSiblings, а реализация наименьшего охватывающего круга доступна как d3.packEnclose. Отступ при компоновке кругов теперь применяется между родителем и его детьми, а также между смежными братьями и сестрами. Кроме того, теперь вы можете указать отступ как функцию, которая вычисляется динамически для каждого родителя.
Внутренние компоненты
Метод d3.rebind был удален. (См. исходный код 3.x.) Если вы хотите обернуть метод getter-setter, рекомендуемым шаблоном является реализация метода-обертки и проверка возвращаемого значения. Например, если у компонента используется внутренний диспетчер, компонент.on может переопределить диспетчер.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 в функцию, если это не функция:
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 равны undefined или не являются объектами, они теперь неявно преобразуются в пустой объект или пустой массив соответственно, а не вызывают 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. Например, данный код для рисования в canvas:
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 для реализации приближения Барнса–Хата.
Теперь можно удалять данные из квадродерева с помощью 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 были заменены новым подклассом шкалы ordinal: шкалами типа band. Следующий код в 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 были заменены новым подклассом шкалы ordinal: шкалами типа point. Следующий код в 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 возвращает интервал между смежными точками.
Конструктор шкалы ordinal теперь принимает необязательный range для более короткой альтернативы ordinal.range. Это особенно полезно сейчас, когда цветовые шкалы категорий были изменены на простые массивы цветов вместо специализированных конструкторов ordinal:
- 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, эти интерполяторы также могут быть применены к квантильным, квантизующим и пороговым шкалам.
4.0 также поставляется с новыми схемами Cubehelix, включая стандартные значения Дэва Грина и циклическую радугу, вдохновлённую Мэттео Никколи:
Для ещё большего числа последовательных и категориальных цветовых схем см. 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 вы можете отобразить фигуру как путь холста для заливки или обводки. Например, диаграмма круговой диаграммы на холсте может использовать генератор дуг:
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. Кривые реализуются с помощью интерфейса кривой, а не как функция, возвращающая строку данных пути SVG; это позволяет кривым отображаться как в SVG, так и на холсте. Кроме того, 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 теперь предоставляет параметризованные сплайны Катмулла-Рома, как предложено Yuksel и др.. Они доступны как d3.curveCatmullRom, d3.curveCatmullRomClosed и d3.curveCatmullRomOpen.
Каждый тип кривой может определять свои собственные именованные параметры, заменяя line.tension и area.tension. Например, сплайны Катмулла-Рома параметризуются с помощью catmullRom.alpha и по умолчанию равны 0,5, что соответствует центробежному сплайну, который избегает самопересечений и перескока. Для однородного сплайна Катмулла-Рома вместо этого:
var line = d3.line()
.curve(d3.curveCatmullRom.alpha(0)); В версии 4.0 исправлена интерпретация параметра натяжения кардинального сплайна, который теперь задается как cardinal.tension и по умолчанию равен нулю для однородного сплайна Катмулла-Рома; натяжение 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)
В соответствии с большим сглаживанием пространства имён, интервалы локального времени были переименованы:
- ADDED ↦ 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 времени:
- ADDED ↦ 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: он просто пропускает, возвращая каждую шаг-ю дату. Например, следующий код в версии 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.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) и группа элемента (узлы), а this — это сам элемент. Это особенно касается transition.attrTween и transition.styleTween, которые больше не передают функции интерполяции текущее значение атрибута или стиля в качестве третьего аргумента. Методы transition.attrTween и transition.styleTween теперь могут вызываться в режиме получения для отладки или для совместного определения интерполяции между переходами.
Однородные переходы теперь оптимизированы! Если все элементы в переходе используют одни и те же интерполяторы, интерполяторы или обработчики событий, это состояние теперь совместно используется для всего перехода, а не выделяется отдельно для каждого элемента. 4.0 также использует оптимизированный интерполятор по умолчанию вместо d3.interpolate для transition.attr и transition.style. Теперь переходы могут интерполировать как CSS, так и SVG преобразования.
END_OF_DOCUMENT_MARKERДля многократно используемых компонентов, поддерживающих переходы, таких как оси, новый метод 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, которое представляет элемент входных данных data, соответствующий многоугольнику, было переименовано в polygon.data.
Вызов voronoi теперь возвращает полную диаграмму Вороного, которая включает топологическую информацию: каждый край Вороного экспонирует edge.left и edge.right, указывающие узлы по обе стороны края, и каждая ячейка Вороного определяется как массив этих рёбер и соответствующего узла. Диаграмма Вороного может быть использована для эффективного вычисления как тесселяции Вороного, так и Делоне для набора точек: diagram.polygons, diagram.links и diagram.triangles. Новая топология также полезна в сочетании с TopoJSON; см. пример топологии Вороного.
Методы voronoi.polygons и diagram.polygons теперь требуют extent; неявного значения extent ±1e6 больше нет. Методы voronoi.links, voronoi.triangles, diagram.links и diagram.triangles теперь зависят от clip extent: поскольку триангуляция Делоне вычисляется как двойственная к Вороного, два узла связаны только в том случае, если обрезанные ячейки соприкасаются. Чтобы вычислить триангуляцию Делоне без учёта обрезки, установите extent в null.
У генератора Вороного теперь определенное поведение для совпадающих вершин: первая из набора совпадающих точек имеет определённую ячейку, в то время как последующие дублированные точки имеют пустые ячейки. Возвращаемый массив многоугольников разреженный, поэтому с помощью array.forEach или array.map можно легко пропустить неопределённые ячейки. Генератор Вороного также теперь правильно обрабатывает случай, когда ни один край ячейки не пересекает область extent.
Масштабирование (d3-zoom)
Поведение масштабирования d3.behavior.zoom было переименовано в d3.zoom. Поведение масштабирования больше не хранит активное преобразование масштабирования (т.е., видимую область; масштаб и смещение) внутри. Теперь преобразование масштабирования хранится на любых элементах, к которым применено поведение масштабирования. Преобразование масштабирования доступно как event.transform в событии масштабирования или с помощью вызова d3.zoomTransform для данного element. Для программного масштабирования используйте 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–2020 Michael Bostock
Licensed under the BSD License.
https://github.com/d3/d3/blob/master/CHANGES.md