D3-force-layout (力布局)
модуль использует алгоритм velocity Verlet
для реализации числового интегратора, который моделирует физические силы, действующие на частицы. Внутреннее моделирование упрощено, предполагая, что каждый шаг
имеет временной шаг Δt = 1, а масса всех частиц m = 1. Таким образом, сила F, действующая на частицу, эквивалентна постоянному ускорению a за интервал времени Δt, которое можно моделировать путем простого добавления к скорости частицы, а затем добавления к её положению.
Проще говоря, D3-force-layout
использует определённые физические правила для позиционирования элементов визуализации (узлов и ребер)
.
D3 использует физическое моделирование для позиционирования визуальных элементов.
Можно настроить силу
между элементами, например:
центру
, что означает, что среднее положение всех узлов близко к центру
.фиксированного расстояния
детекцию столкновений
, элементы могут быть настроены для предотвращения перекрытия
Настройка позволяет force-layout
позиционировать элементы в определённом способе. В этой статье мы рассмотрим, как использовать D3-force-layout
и как создавать сетевые визуализации (network visualisations), кластеры (clusters).
Рассмотрим следующий пример force-layout
: предположим, что у нас есть много circle
, которые разделены на три категории (через поле category
), затем мы добавляем forces
:circle
притягиваются друг к другу (группировка circle
)circle
)circle
притягиваются к одному из трёх центров (поле category
: A
, B
или C
)
! [image-20220829141644227](. /image/image-20220829141644227. png)https://codepen. io/wantnocode/pen/jOzjXqB? editors=1111
force-layout
требует больше вычислительных ресурсов по сравнению с другими алгоритмами размещения, так как его реализация внутри является итеративной. Шаги постепенно приводят к оптимальному результату.
Обычно настройка силового моделирования включает 4 шага:
узлов и ребер
)forceSimulation
, передача массива объектов (узлов
)force functions(функций силы)
(например, forceManyBody
, forceCenter
)tick
)
Рассмотрим простой пример:let width = 300, height = 300
let nodes = [{}, {}, {}, {}, {}]
let simulation = d3. forceSimulation(nodes)
.В данном примере мы создаем простой массив из 5 объектов и добавляем два силовых функционала `forceManyBody` и `forceCenter` (где первый заставляет элементы отталкиваться друг от друга, а второй притягивает элементы к центру).Каждый раз, когда происходит итерация симуляции, вызывается функция `ticked`. Эта функция связывает массив `nodes` с элементами `circle` и обновляет их положение:
```javascript
function ticked() {
var u = d3.select('svg')
.selectAll('circle')
.data(nodes)
.join('circle')
.attr('r', 5)
.attr('cx', function(d) {
return d.x
})
.attr('cy', function(d) {
return d.y
});
}
Сила симуляций обладает мощью и гибкостью, сосредоточенными на силовых функциях, которые могут изменять положение и скорость элементов для достижения эффектов притяжения, отталкивания и обнаружения столкновений.
D3 включает множество полезных функций:
forceCenter
(для установки центра системы)forceManyBody
(для притяжения или отталкивания элементов друг от друга)forceCollide
(для предотвращения перекрытия элементов)forceX
и forceY
(для притяжения элементов к определенной точке)forceLink
(для создания фиксированного расстояния между связанными элементами)Силовые функции добавляются к симуляции с помощью .force()
, где первый параметр — это определенный идентификатор, а второй параметр — сама силовая функция:
simulation.force('charge', d3.forceManyBody())
Давайте рассмотрим встроенную силовую функцию forceManyBody
более подробно.
forceCenter
полезен для центрирования всех элементов вокруг определенного центра. Если центр не задан, то по умолчанию используется [0, 0].Можно задать положение [x, y]
при инициализации:
d3.forceCenter(100, 100)
Или использовать методы конфигурации .x()
и .y()
:
d3.forceCenter().x(100).y(100)
Затем добавьте его к симуляции:
simulation.force('center', d3.forceCenter(100, 100))
forceManyBody
заставляет все элементы притягиваться или отталкиваться друг от друга. Можно задать силу притяжения или отталкивания, используя метод .strength()
, где положительное значение приводит к притяжению элементов друг к другу, а отрицательное значение — к отталкиванию. По умолчанию значение силы равно -30
.```javascript
simulation.force('charge', d3.forceManyBody().strength(-20))
> При создании сетевого графика обычно конфигурируются элементы, которые взаимоисключают друг друга. Однако для потребностей, когда элементы должны собираться вместе, необходимо конфигурировать притяжение (сила притяжения) элементов.
>
> https://codepen.io/wantnocode/pen/qBozLjv
### forceCollide
`forceCollide` используется для предотвращения перекрытия элементов (в данном случае это `circle`) и может "собирать" их вместе.
`radius` элемента передается в `forceCollide` с помощью метода `.radius` доступника функции. Первый параметр `d` этого метода используется для `data join`, из которого можно получить `radius`.
Например:
let numNodes = 100 let nodes = d3.range(numNodes).map(function(d) { return {radius: Math.random() * 25} }) let simulation = d3.forceSimulation(nodes) .force('charge', d3.forceManyBody().strength(5)) .force('center', d3.forceCenter(width / 2, height / 2)) .force('collision', d3.forceCollide().radius(function(d) { return d.radius }))
! [изображение-20220829155113093](./image/изображение-20220829155113093.png)
> https://codepen.io/wantnocode/pen/GRxbzMM
> `forceManyBody` собирает все узлы вместе и удерживает узлы в центре контейнера, `forceCollide` предотвращает перекрытие узлов.
### forceX и forceY
`forceX` и `forceY` устанавливают притяжение элементов к определенной позиции. Можно использовать один центр для всех элементов или добавлять его на основе каждого элемента. Также можно использовать `.strength()` для настройки силы притяжения. Например, предположим, что у вас есть множество элементов, каждый из которых имеет свойство `category` со значением `0`, `1` или `2`. Вы можете добавить силу `forceX`, которая притягивает элементы к координатам `100`, `300` или `500` в зависимости от значения `category`:
let xCenter = [100, 300, 500]; let simulation = d3.forceSimulation(nodes) .force('charge', d3.forceManyBody().strength(5)) .force('x', d3.forceX().x(function(d) { return xCenter[d.category]; })) .force('collision', d3.forceCollide().radius(function(d) { return d.radius; }));
! [изображение-20220829141644227](. /image/изображение-20220829141644227. png)
> https://codepen.io/wantnocode/pen/jOzjXqB
> `forceManyBody` собирает все узлы вместе, а затем `forceX` притягивает узлы к определенной координате x. `forceCollide` предотвращает перекрытие (организует) узлов.
Если у данных есть связанные координаты, конечно, можно использовать `forceX` или `forceY` одновременно для позиционирования элементов.
. . . .force('x', d3.forceX().x(function(d) {
вернуть d.x;
})))
.сила('y', d3.силаY().y(функция(d) { вернуть d.y; })) . . .
```markdown
### силаLink
`силаLink` перемещает элементы, связанные с одной **фиксированной дистанции (distance)**. Она требует **связей (массив связей)** для указания, какие элементы должны быть связаны. Каждый объект связи указывает `источник` (источник) элемента и `цель` (цель) элемента, где значения являются **идентификаторами id** (id) элементов (`если id отсутствует, можно использовать индексы массива`):
```markdown
let links = d3.range(nodes.length - 1).map(function(i) {
``` вернуть {
источник: Math.floor(Math.sqrt(i)),
цель: i + 1,
};
});
let links = [
{источник: 0, цель: 1},
...
]
Затем, используя метод .links()
, передайте links (массив связей)
в функцию силаLink
:
let симуляция = d3.силаSimulation(nodes)
.сила('charge', d3.силаManyBody().сила(-100))
.сила('center', d3.силаCenter(width / 2, height / 2))
.сила('link', d3.силаLink().links(links));
> https://codepen.io/wantnocode/pen/QWmXYqZ?editors=1111
силаManyBody
разделяет узлы,силаCenter
поддерживает центрирование узлов относительно контейнера,силаLink
поддерживает фиксированное расстояние между связанными узлами.
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )