Некоторое время назад я создал версию d3.forceRadial
, которая принимает функцию для установки позиций x
и y
.Вы можете увидеть запрос здесь , а код здесь
Этот запрос на получение еще не был принят, так как он довольно старый и не имеет комментариевот Майка Бостока (создатель D3), я думаю, этого никогда не будет.Итак, если вы хотите, вы можете использовать этот пользовательский d3.forceRadial
, скопировав функцию по ссылке: https://pastebin.com/75j8vj3C
Затем просто используйте ваши функции позиционирования с настраиваемой силой, например:
simulation.force("radial", customRadial(radius, foo, bar))
//positioning functions--------------------------^----^
Или:
simulation.force("radial", customRadial()
.radius(radius)
.x(foo)
.y(bar))
Где foo
и bar
- ваши функции для позиций x
и y
.
Вот пример:
var svg = d3.select("body")
.append("svg")
.attr("width", 600)
.attr("height", 200);
var data = d3.range(500).map(function(d) {
return {
node: "foo" + d,
centerX: 100 + ~~((d / 100) % 20) * 100
}
});
var simulation = d3.forceSimulation(data)
.force("radius", customRadial().radius(40)
.x(function(d) {
return d.centerX
})
.y(100)
.strength(1))
.force("collide", d3.forceCollide().radius(3).strength(.8));
var nodes = svg.selectAll(null)
.data(data)
.enter()
.append("circle")
.attr("r", 2.5)
.style("fill", "teal")
simulation.on("tick", tick);
function tick() {
nodes.attr("cx", function(d) {
return d.x
})
.attr("cy", function(d) {
return d.y
});
}
function customRadial(radius, x, y) {
var constant = function(x) {
return function() {
return x;
};
};
var nodes,
strength = constant(0.1),
strengths,
radiuses,
xs,
ys;
if (typeof radius !== "function") radius = constant(+radius);
if (typeof x !== "function") x = constant(x == null ? 0 : +x);
if (typeof y !== "function") y = constant(y == null ? 0 : +y);
function force(alpha) {
for (var i = 0, n = nodes.length; i < n; ++i) {
var node = nodes[i],
dx = node.x - xs[i] || 1e-6,
dy = node.y - ys[i] || 1e-6,
r = Math.sqrt(dx * dx + dy * dy),
k = (radiuses[i] - r) * strengths[i] * alpha / r;
node.vx += dx * k;
node.vy += dy * k;
}
}
function initialize() {
if (!nodes) return;
var i, n = nodes.length;
strengths = new Array(n);
radiuses = new Array(n);
xs = new Array(n);
ys = new Array(n);
for (i = 0; i < n; ++i) {
radiuses[i] = +radius(nodes[i], i, nodes);
xs[i] = +x(nodes[i], i, nodes);
ys[i] = +y(nodes[i], i, nodes);
strengths[i] = isNaN(radiuses[i]) ? 0 : +strength(nodes[i], i, nodes);
}
}
force.initialize = function(_) {
nodes = _, initialize();
};
force.strength = function(_) {
return arguments.length ? (strength = typeof _ === "function" ? _ : constant(+_), initialize(), force) : strength;
};
force.radius = function(_) {
return arguments.length ? (radius = typeof _ === "function" ? _ : constant(+_), initialize(), force) : radius;
};
force.x = function(_) {
return arguments.length ? (x = typeof _ === "function" ? _ : constant(+_), initialize(), force) : x;
};
force.y = function(_) {
return arguments.length ? (y = typeof _ === "function" ? _ : constant(+_), initialize(), force) : y;
};
return force;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
Если вы не хотите (или не можете по какой-либо причине) использовать этот пользовательский код, простой обходной путь создает несколькосимуляции , по одному для каждой группы элементов, как я делал в этой визуализации данных .