Расположение сил
Справочник API ▸ Макеты ▸ Расположение сил
Гибкая реализация макета графа с направленными силами, использующая интегрирование Verlet для применения простых ограничений. Более подробную информацию о физических симуляциях см. на странице Томаса Якобсена. В этой реализации используется quadtree для ускорения взаимодействия зарядов с использованием приближения Barnes–Hut. В дополнение к силе отталкивания заряда, псевдосила гравитации удерживает узлы в центре видимой области и предотвращает выброс несвязанных подграфов, а связи имеют фиксированное геометрическое ограничение расстояния. Дополнительные пользовательские силы и ограничения могут быть применены в событии «тик» путем простого обновления атрибутов x и y узлов.

Для получения подробного обзора возможностей с примерами см. эту презентацию и соответствующую презентацию.
Некоторые интересные примеры:
- расходящиеся силы
- множественные фокусы
- конструктор графов
- дерево с направленными силами
- символы с направленными силами
- изображения и метки с направленными силами
- состояния с направленными силами
- макет с силой прилипания
Как и другие классы в D3, макеты следуют шаблону цепочки методов, где методы-установщики возвращают сам макет, позволяя вызывать несколько установщиков в одном выражении. В отличие от некоторых других реализаций макетов, которые не имеют состояния, макет с силами сохраняет ссылку на связанные узлы и связи внутри; таким образом, экземпляр данного макета с силами может быть использован только с одним набором данных.
d3.layout.force()
Создает новый макет с направленными силами с настройками по умолчанию: размер 1×1, сила связи 1, трение 0.9, расстояние 20, сила заряда -30, сила гравитации 0.1 и параметр тета 0.8. Узлы и связи по умолчанию — пустой массив, а при запуске макета внутренний параметр охлаждения альфа устанавливается в 0.1. Общий шаблон для создания макетов с направленными силами — установить все свойства конфигурации, а затем вызвать start:
var force = d3.layout.force()
.nodes(nodes)
.links(links)
.size([w, h])
.linkStrength(0.1)
.friction(0.9)
.linkDistance(20)
.charge(-30)
.gravity(0.1)
.theta(0.8)
.alpha(0.1)
.start(); Обратите внимание, что, как и другие макеты D3, макет с направленными силами не навязывает определенного визуального представления. Чаще всего узлы отображаются в виде элементов SVG circle, а связи — в виде элементов SVG line. Но вы также можете отображать узлы как символы или изображения.
force.size([width, height])
Если размер указан, задает доступный размер макета на заданный двухэлементный массив чисел, представляющий x и y. Если размер не указан, возвращает текущий размер, который по умолчанию равен [1, 1]. Размер влияет на два аспекта макета с направленными силами: центр гравитации и начальную случайную позицию. Центр тяжести — это просто [ x / 2, y / 2 ]. Когда узлы добавляются в макет с силами, если у них еще нет атрибутов x и y, то эти атрибуты инициализируются с помощью равномерного распределения случайных чисел в диапазоне [0, x] и [0, y] соответственно.
force.linkDistance([distance])
Если расстояние указано, устанавливает целевое расстояние между связанными узлами до указанного значения. Если расстояние не указано, возвращает текущее расстояние связи макета, которое по умолчанию равно 20. Если расстояние является константой, то все связи имеют одинаковое расстояние. В противном случае, если расстояние является функцией, то функция вычисляется для каждой связи (по порядку), принимая в качестве аргументов связь и её индекс, с контекстом this в качестве макета с силами; возвращаемое значение функции используется для установки расстояния каждой связи. Функция вычисляется всякий раз, когда макет запускается.
Связи не реализуются как «силы пружин», как это обычно делается в других макетах с направленными силами, а как слабые геометрические ограничения. На каждом тике макета вычисляется и сравнивается расстояние между каждой парой связанных узлов с целевым расстоянием; затем связи перемещаются друг к другу или друг от друга, чтобы сойтись к нужному расстоянию. Этот метод релаксации ограничений на основе интегрирования Verlet для позиций значительно стабильнее предыдущих методов, использующих силы пружин, а также позволяет гибко реализовывать другие ограничения в обработчике события тика, например, иерархическое упорядочивание.
force.linkStrength([strength])
Если сила указана, устанавливает силу (жёсткость) связей до указанного значения в диапазоне [0,1]. Если сила не указана, возвращает текущую силу связи макета, которая по умолчанию равна 1. Если сила является константой, то все связи имеют одинаковую силу. В противном случае, если сила является функцией, то функция вычисляется для каждой связи (по порядку), принимая в качестве аргументов связь и её индекс, с контекстом this в качестве макета с силами; возвращаемое значение функции используется для установки силы каждой связи. Функция вычисляется всякий раз, когда макет запускается.
force.friction([friction])
Если трение указано, устанавливает коэффициент трения до указанного значения. Если трение не указано, возвращает текущий коэффициент, который по умолчанию равен 0.9. Название этого параметра, возможно, вводит в заблуждение; он не соответствует стандартному физическому коэффициенту трения. Вместо этого он более точно приближает затухание скорости: на каждом тике симуляции скорость частицы масштабируется на указанное трение. Таким образом, значение 1 соответствует безтрениевой среде, а значение 0 замораживает все частицы на месте. Значения за пределами диапазона [0,1] не рекомендуются и могут иметь дестабилизирующие последствия.
force.charge([charge])
Если заряд указан, устанавливает силу заряда до указанного значения. Если заряд не указан, возвращает текущую силу заряда, которая по умолчанию равна -30. Если заряд является константой, то все узлы имеют одинаковый заряд. В противном случае, если заряд является функцией, то функция вычисляется для каждого узла (по порядку), принимая в качестве аргументов узел и его индекс, с контекстом this в качестве макета с силами; возвращаемое значение функции используется для установки заряда каждого узла. Функция вычисляется всякий раз, когда макет запускается.
Отрицательное значение приводит к отталкиванию узлов, а положительное — к притяжению узлов. Для макета графа следует использовать отрицательные значения; для симуляции n-тел можно использовать положительные значения. Все узлы предполагаются бесконечно малыми точками с одинаковым зарядом и массой. Силы заряда реализуются эффективно с помощью алгоритма Barnes–Hut, вычисляющего quadtree на каждом тике. Установка силы заряда в ноль отключает вычисление quadtree, что может заметно повысить производительность, если вам не нужны силы n-тел.
force.chargeDistance([distance])
Если расстояние указано, устанавливает максимальное расстояние, на котором применяются силы заряда. Если расстояние не указано, возвращает текущее максимальное расстояние заряда, которое по умолчанию равно бесконечности. Указание конечного расстояния заряда повышает производительность макета с силами и приводит к более локальному макету; расстояние заряда, ограниченное по расстоянию, особенно полезно в сочетании с пользовательской гравитацией. Пример см. в “Созвездия режиссеров и их звезд” (The New York Times).
force.theta([theta])
Если тета указано, устанавливает критерий приближения Barnes–Hut до указанного значения. Если тета не указано, возвращает текущее значение, которое по умолчанию равно 0.8. В отличие от связей, которые влияют только на два связанных узла, сила заряда глобальна: каждый узел влияет на каждый другой узел, даже если они находятся в разных несвязанных подграфах.
Чтобы избежать квадратичного замедления производительности для больших графов, макет с силами использует приближение Barnes–Hut, которое занимает O(n log n) на каждый тик. На каждом тике создается quadtree для хранения текущих позиций узлов; затем для каждого узла вычисляется суммарная сила заряда всех других узлов на данном узле. Для кластеров узлов, которые находятся далеко друг от друга, сила заряда аппроксимируется путем обработки кластера узлов как одного, большего узла. Тета определяет точность вычислений: если отношение площади квадранта в quadtree к расстоянию между узлом и центром массы квадранта меньше, чем тета, все узлы в данном квадранте обрабатываются как один больший узел вместо индивидуальных вычислений.
force.gravity([gravity])
Если гравитация указана, устанавливает силу гравитации до указанного числового значения. Если гравитация не указана, возвращает текущую силу гравитации, которая по умолчанию равна 0.1. Название этого параметра, возможно, вводит в заблуждение; он не соответствует физической гравитации (которую можно смоделировать с помощью положительного параметра заряда). Вместо этого гравитация реализуется как слабое геометрическое ограничение, аналогичное виртуальной пружине, соединяющей каждый узел с центром размера макета. Этот подход имеет хорошие свойства: вблизи центра макета сила гравитации практически равна нулю, что исключает локальную деформацию макета; по мере удаления узлов от центра сила гравитации становится сильнее в линейной зависимости от расстояния. Таким образом, гравитация всегда будет превосходить силы отталкивания зарядов на некотором пороге, предотвращая выход несвязанных узлов за пределы макета.
Гравитация может быть отключена, установив силу гравитации в ноль. Если вы отключаете гравитацию, рекомендуется реализовать другие геометрические ограничения, чтобы предотвратить выход узлов за пределы макета, например, ограничив их пределами макета.
force.nodes([nodes])
Если указаны узлы, устанавливает связанные с макетом узлы в указанный массив. Если узлы не указаны, возвращает текущий массив, который по умолчанию является пустым массивом. Каждый узел имеет следующие атрибуты:
- индекс — нулевой индекс узла в массиве узлы.
- x — координата x текущего положения узла.
- y — координата y текущего положения узла.
- px — координата x предыдущего положения узла.
- py — координата y предыдущего положения узла.
- fixed — логическое значение, указывающее, заблокировано ли положение узла.
- weight — вес узла; количество связанных связей.
Эти атрибуты не нужно устанавливать перед передачей узлов в макет; если они не установлены, макет инициализирует подходящие значения по умолчанию при вызове start. Однако имейте в виду, что если вы храните другие данные в узлах, ваши атрибуты данных не должны конфликтовать с вышеуказанными свойствами, используемыми макетом.
force.links([links])
Если указаны связи, устанавливает связанные с макетом связи в указанный массив. Если связи не указаны, возвращает текущий массив, который по умолчанию является пустым массивом. Каждая связь имеет следующие атрибуты:
- source — исходный узел (элемент в узлах).
- target — целевой узел (элемент в узлах).
Примечание: значения атрибутов source и target могут быть первоначально указаны как индексы в массиве узлы; они будут заменены ссылками после вызова start. Объекты связей могут иметь дополнительные поля, которые вы указываете; эти данные могут использоваться для вычисления силы связи strength и расстояния связи distance для каждой связи с помощью функции доступа.
force.start()
Запускает симуляцию; этот метод должен быть вызван при первом создании макета после назначения узлов и связей. Кроме того, он должен быть вызван снова всякий раз, когда узлы или связи изменяются. Внутри макета используется параметр охлаждения alpha, который управляет температурой макета: по мере того, как физическая симуляция сходится к стабильному макету, температура снижается, заставляя узлы перемещаться медленнее. В конечном итоге alpha опускается ниже порога, и симуляция полностью останавливается, освобождая процессор и предотвращая разряд батареи. Макет можно подогреть с помощью resume или перезапуском; это происходит автоматически при использовании поведения drag.
При запуске макет инициализирует различные атрибуты связанных узлов. Индекс каждого узла вычисляется путем итерации по массиву, начиная с нуля. Начальные координаты x и y, если они еще не установлены внешне как допустимое число, вычисляются путем проверки соседних узлов: если связанный узел уже имеет начальную позицию в x или y, соответствующие координаты применяются к новому узлу. Это повышает устойчивость макета графика при добавлении новых узлов, а не использования по умолчанию, которое заключается в случайной инициализации позиции внутри размера макета. Предыдущее положение px и py устанавливается на начальное положение, если оно еще не задано, что дает новым узлам начальную скорость нулевую. Наконец, булево значение fixed по умолчанию равно false.
Макет также инициализирует атрибуты source и target связанных связей: для удобства эти атрибуты могут быть указаны как числовой индекс, а не как прямая связь, так что узлы и связи можно считывать из файла JSON или другого статического описания, которое может не допускать циклического связывания. Атрибуты source и target входящих связей заменяются соответствующими записями в узлах только если эти атрибуты являются числами; таким образом, эти атрибуты в существующих связях остаются неизменными при перезапуске макета. Расстояния связей и силы связей также вычисляются при запуске.
force.alpha([value])
Получает или устанавливает параметр охлаждения макета сил, alpha. Если указано значение, устанавливает alpha на указанное значение и возвращает макет сил. Если значение больше нуля, этот метод также перезапускает макет сил, если он еще не запущен, отправляя событие «start» и включая таймер тиков. Если значение неположительно, и макет сил запущен, этот метод останавливает макет сил на следующем тике и отправляет событие «end». Если значение не указано, этот метод возвращает текущее значение alpha.
force.resume()
Эквивалентно:
force.alpha(.1);
Устанавливает параметр охлаждения alpha в 0,1. Этот метод устанавливает внутренний параметр alpha в 0,1, а затем перезапускает таймер. Как правило, вам не нужно вызывать этот метод напрямую; он вызывается автоматически методом start. Он также вызывается автоматически методом drag во время жеста перетаскивания.
force.stop()
Эквивалентно:
force.alpha(0);
Завершает симуляцию, устанавливая параметр охлаждения alpha в ноль. Это можно использовать для явного остановки симуляции, например, если вы хотите показать анимацию или разрешить другое взаимодействие. Если вы не остановите макет явно, он все равно остановится автоматически после того, как параметр охлаждения макета опустится ниже некоторого порога.
force.tick()
Выполняет симуляцию макета сил на один шаг. Этот метод можно использовать совместно с методами start и stop для вычисления статического макета. Например:
force.start(); for (var i = 0; i < n; ++i) force.tick(); force.stop();
Количество итераций зависит от размера и сложности графика. Выбор начальных позиций также может существенно повлиять на то, насколько быстро график сойдется к хорошему решению. Например, здесь узлы расположены по диагонали:
var n = nodes.length;
nodes.forEach(function(d, i) {
d.x = d.y = width / n * i;
}); Если вы не инициализируете позиции вручную, макет сил инициализирует их случайным образом, что приводит к несколько непредсказуемому поведению.
force.on(type, listener)
Регистрирует указанный слушатель для получения событий указанного типа от макета сил. В настоящее время поддерживаются только события «start», «tick» и «end».
Объекты событий, которые будут переданы функциям слушателей, являются пользовательскими объектами, созданными с помощью процесса d3.dispatch(). Каждый объект события имеет два свойства: type (строка, либо "start", либо "tick", либо "end" ) и alpha, которое представляет собой текущее значение параметра охлаждения alpha (число от 0 до 1). Свойство event.alpha может использоваться для отслеживания прогресса макета или для управления своими собственными пользовательскими корректировками.
Событие «start» отправляется как для начального запуска симуляции, так и всякий раз, когда симуляция перезапускается.
События «tick» отправляются для каждого тика симуляции. Прислушивайтесь к событиям «tick», чтобы обновлять отображаемые позиции узлов и связей. Например, если вы первоначально отображаете узлы и связи так:
var link = vis.selectAll("line")
.data(links)
.enter().append("line");
var node = vis.selectAll("circle")
.data(nodes)
.enter().append("circle")
.attr("r", 5); Вы можете установить их позиции при тике:
force.on("tick", function() {
link.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });
node.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
}); В этом случае мы сохранили выделения node и link при инициализации, чтобы нам не нужно было повторно выделять узлы на каждом тике. Если вы предпочитаете, вы можете отображать узлы и связи по-другому; например, вы можете использовать символы вместо кругов.
Событие «end» отправляется, когда внутренний параметр охлаждения симуляции alpha опускается ниже порогового значения (0,005) и устанавливается в ноль.
force.drag()
Связывает поведение с узлами, чтобы разрешить интерактивное перетаскивание с помощью мыши или сенсорного экрана. Используйте это в сочетании с оператором call для узлов; например, скажем node.call(force.drag) при инициализации. Событие перетаскивания устанавливает атрибут fixed узлов при наведении курсора, так что как только курсор наводится на узел, он перестает двигаться. Фиксация при наведении, а не при нажатии, упрощает захват перемещаемых узлов. При получении события нажатия мыши и на каждом последующем перемещении мыши до отпускания мыши центр узла устанавливается в текущее положение курсора. Кроме того, каждое перемещение мыши запускает resume макета сил, подогревая симуляцию. Если вы хотите, чтобы перетаскиваемые узлы оставались фиксированными после перетаскивания, установите атрибут fixed в true при dragstart, как в примере sticky force layout.
Замечание по реализации: обработчики событий mousemove и mouseup регистрируются в текущем окне, таким образом, когда пользователь начинает перетаскивать узел, он может продолжать перетаскивать его, даже если курсор покидает окно. Каждый обработчик событий использует пространство имен «force», чтобы избежать конфликтов с другими обработчиками событий, которые вы, возможно, захотите связать с узлами или с окном. Если узел перемещается поведением перетаскивания, последующее событие щелчка, которое было бы вызвано окончательным отпусканием мыши, перехватывается, и поведение по умолчанию предотвращается. Если вы зарегистрируете обработчик событий щелчка, вы можете проигнорировать эти щелчки при перетаскивании, проверив, было ли предотвращено поведение по умолчанию:
selection.on("click", function(d) {
if (d3.event.defaultPrevented) return; // ignore drag
otherwiseDoAwesomeThing();
}); См. примеры collapsible force layout и divergent forces.
© 2010–2016 Michael Bostock
Licensed under the BSD License.
https://github.com/d3/d3-3.x-api-reference/blob/master/Force-Layout.md