Reputation: 420
I have a force
function that works in d3 V3 and I'd like to convert it to V5. I'll show the solution that works right now and then go into what's broken.
This works in v3
var force = d3.layout.force()
.nodes(nodes)
.size([width, height])
.gravity(0)
.charge(0)
.friction(.9)
.on("tick", tick)
.start();
function tick(e) {
var k = 0.03 * e.alpha;
// Push nodes toward their designated focus.
nodes.forEach(function(o, i) {
var curr_act = o.act;
var damper = .85;
o.x += (x(+o.decade) - o.x) * k * damper;
o.y += (y('met') - o.y) * k * damper;
o.color = color('met');
});
circle
.each(collide(.5))
.style("fill", function(d) { return d.color; })
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
}
// Resolve collisions between nodes.
function collide(alpha) {
var quadtree = d3.geom.quadtree(nodes);
return function(d) {
var r = d.radius + maxRadius + padding,
nx1 = d.x - r,
nx2 = d.x + r,
ny1 = d.y - r,
ny2 = d.y + r;
quadtree.visit(function(quad, x1, y1, x2, y2) {
if (quad.point && (quad.point !== d)) {
var x = d.x - quad.point.x,
y = d.y - quad.point.y,
l = Math.sqrt(x * x + y * y),
r = d.radius + quad.point.radius + (d.act !== quad.point.act) * padding;
if (l < r) {
l = (l - r) / l * alpha;
d.x -= x *= l;
d.y -= y *= l;
quad.point.x += x;
quad.point.y += y;
}
}
return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1;
});
};
}
where the object circles
is defined as.
var circle = svg.selectAll("circle")
.data(nodes)
.enter().append("circle")
And this is an example of a node.
This is my attempt to convert it to v5
var force = d3.forceSimulation(nodes)
.velocityDecay(.9)
.force("center", d3.forceCenter(width / 2,height / 2))
.force("charge", d3.forceManyBody().strength())
.on("tick", tick)
I kept everything else the same except that I replaced d3.geom.quadtree(nodes)
with d3.quadtree(nodes)
.
I am having trouble with the tick
function. In the old version, the e
argument prints something like this.
In the new version, it prints undefined and the function breaks with Uncaught TypeError: Cannot read property 'alpha' of undefined
.
Does tick()
have a new format or a new way of passing arguments in v5?
Upvotes: 2
Views: 594
Reputation: 38231
If you are trying to access simulation properties during the simulation's ticks, you no longer use an event passed as a parameter to the tick function. Instead you can access the simulation directly with this
.
From the docs:
When a specified event is dispatched, each listener will be invoked with the this context as the simulation. (docs).
Which means that you can access alpha, for example, with this.alpha()
(or simulation.alpha()
), within the tick function in v4/v5:
d3.forceSimulation()
.velocityDecay(.9)
.force("charge", d3.forceManyBody().strength())
.on("tick", tick)
.nodes([{},{}]);
function tick() {
console.log(this.alpha());
}
.as-console-wrapper {
min-height: 100%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
Upvotes: 3