Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a simulation.isFixed(node) function #35

Closed
thatismatt opened this issue Jun 15, 2016 · 10 comments
Closed

Add a simulation.isFixed(node) function #35

thatismatt opened this issue Jun 15, 2016 · 10 comments
Assignees

Comments

@thatismatt
Copy link

The usage of simulation.fix/unfix to move nodes means that fixed nodes become unfixed. It would be nice if there was a simulation.isFixed(node) function, so that you could restore the correct fixedness state after the drag completes.

Here is an example that works around this issue with some external state: http://bl.ocks.org/thatismatt/e855ccb68ae8fc4df75d04c3d02a0865

@mbostock
Copy link
Member

Hmm, maybe. In that example, though, I’m not sure how helpful simulation.isFixed would be. If you tried to use it on dragended, for example:

function dragended() {
  if (!d3.event.active) simulation.alphaTarget(0);
  if (simulation.isFixed(d3.event.subject)) simulation.unfix(d3.event.subject);
}

It would always be true because the drag subject is fixed in dragstarted. So it’s already the case that you’re going to need to track some external state to record the nodes that were fixed prior to the start of a drag event.

And if that’s the case, why not just store a node.fixed boolean yourself, like this?

https://gist.github.com/mbostock/4e4a31f132bc6b27634234dc935a7252

@thatismatt
Copy link
Author

That is true. The reason I'd really like this is that I'd prefer the node creation code to be agnostic of how drag is implemented. i.e. the node creation code can call .fix(node) without having to be aware of updating any extra state.

To work around the if (simulation.isFixed(d3.event.subject)) simulation.unfix(d3.event.subject); issue I was planning to store the previous fixedness on node._fix or similar, and then restore that state.

An alternative would be "onfix/onunfix" hooks, so that I could add that state and then modify it at a later point, that really feels hacky though.

@curran
Copy link
Contributor

curran commented Jun 16, 2016

I also encountered a similar issue when trying to serialize/deserialize the "fixedness" of nodes in this Graph Diagram Editor. Related issue there - Store fixed node positions in files.

I was looking for a way to get the fixedness out of the simulation, but have not yet managed to do so. It seems like isFixed would be a great companion to simulation.fix. I feel like the "fixedness state" lives inside the simulation, so it would be great to be able to retrieve it from there, rather than duplicating the work of tracking the fixed state.

@mbostock
Copy link
Member

mbostock commented Jun 19, 2016

Probably there should be a way to inspect not just the fix state of a node (a boolean) but to retrieve the current fixed position {x, y} (or null) for a given node. Perhaps this should be a matter of calling simulation.fix(node) without arguments x and y, similar to other getter-setter methods in D3. That would mean it’s a little harder to fix a node in its current position, though it’d be easy to say simulation.fix(node, node) to fix a node in its current position.

@thatismatt
Copy link
Author

I like he idea of getter/setters for these properties. But then I feel like it is wrong to conflate setting the position which happens to also set the fixed state to true. So, how about:

  • fixed(node, bool) - set the fixed state
  • fixed(node) - get the fixed state
  • position(node, {x,y}) - set position
  • position(node) - get position

Then for convenience you could add a fix(node) method that would be equivalent to:

fixed(node, true);
position(node, node);

The names may not be ideal, the fix/fixed distinction could be confusing.

@mbostock
Copy link
Member

I feel like it is wrong to conflate setting the position which happens to also set the fixed state to true.

It’s not conflating them because simulation.fix isn’t setting the position of the node: it’s setting the fixed position of the node, which is independent of its current position. The current position of the node is node.x and node.y. When forces apply to that node subsequently, they typically modify node.x and node.y (and possibly the node’s velocity, node.vx and node.vy). The simulation then restores the position of the node back to its fixed position, if any.

@mbostock
Copy link
Member

It felt like we were designing a lot of API to expose and manipulate something that should just be a node property—like the node’s position (node.x, node.y) and velocity (node.vx, node.vy). So that’s what I’ve done: if you set node.fx and/or node.fx, you can fix a node’s position. By clearing these properties, you unfix a node. It’s very similar to how node.fixed worked in D3 3.x.

@thatismatt
Copy link
Author

Yes, great observation, much cleaner.

Any idea when this will appear in a d3.v4 alpha release? Thanks.

@mbostock
Copy link
Member

mbostock commented Jun 20, 2016

Soon… D3 4.0 should be released by the end of the month. I’ll cut another alpha release before then; probably later this week. But I don’t want to cut too many releases since it’s inefficient and I need to focus on finishing 4.0.

@mbostock
Copy link
Member

(You can clone this repo, run npm run prepublish and then load a copy of d3-force.js after d3.js and get the latest code in the interim.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

3 participants