Reputation: 441
I'm working with D3 to create a edge hierarchical model of some data.
What I want to be able to do is click on a edge node and have it line up with the red line.
What I've tried so far is trying to calculate the angle difference between the (x,y) locations of the middle, and the (x,y) locations of the edge node. This didn't give me the right results.
I think the right way to to this to get the angle of a node (in relation to the middle). Though I'm having a lot of trouble doing this since I cannot find which property stores this information. The edge hierarchy is based off this one:
http://bl.ocks.org/mbostock/7607999
The text is generated with the following piece of code:
node = node
.data(nodes.filter(function(n) { return !n.children; }))
.enter().append("text")
.attr("class", "node")
.attr("dy", ".31em")
.attr("transform", function(d) { return "rotate(" + (d.x - 90) + ")translate(" + (d.y + 8) + ",0)" + (d.x < 180 ? "" : "rotate(180)"); })
.style("text-anchor", function(d) { return d.x < 180 ? "start" : "end"; })
.text(function(d) { return d.key; })
.on("mouseover", mouseovered)
.on("mouseout", mouseouted);
Any information would be greatly helpful. Thanks
Upvotes: 4
Views: 1694
Reputation: 1588
I think the right way to to this to get the angle of a node (in relation to the middle)
You already have the angle of the node, maybe it has been confusing since you are assigning the rotation twice. But it can be unified into one by doing the following:
.attr("transform", function(d) {
var r = d.x < 180 ? d.x - 90 : (d.x - 90) + 180;
return "rotate(" + r + ")translate(" + (d.y + 8) + ",0)";
})
r
will be the angle, but there are potential "problems" (or just makes the animation code a bit more cumbersome) with this version because some r
values will be negative.
A better approach to avoid that is to translate your Y Axis and not the X Axis as you are doing now.
.attr("transform", function(d) {
// Simpler version for assigning the r value and avoid negatives.
var r = d.x > 180 ? d.x + 180 : d.x;
// Notice the negative value for the Y Axis.
return "rotate(" + r + ")translate(0, -" + (d.y + 8) + ")";
})
Now you have the nodes angles in relation to the center as you wanted.
Extra note to help you figure how to align it. Your red line is in the angle 180. So the way to rotate your graphic is to find the difference between r and 180.
Upvotes: 1
Reputation: 2100
The line taking care of rotating the whole wheel is the following:
.attr("transform", function(d) { return "rotate(" + (d.x - 90) + ")translate(" + (d.y + 8) + ",0)" + (d.x < 180 ? "" : "rotate(180)"); })
The data is aligned with the red line when d.x=270. In your case, calling "origin" the selected piece of data (the one that must be on the red line), you need to give an angle of d.x - origin.x + 270.
To keep values between 0 and 360, the following trick works:
(d.x - origin.x + 270 +360) % 360
So the easiest way in my opinion is to add an "angle" field in your data, and then use it in lieu of d.x.
node = node
.data(nodes.filter(function(n) { return !n.children; }))
.enter().append("text")
.attr("class", "node")
.attr("dy", ".31em")
.each(function(d) { d.angle = (d.x - origin.x + 270 +360) % 360 })
.attr("transform", function(d) { return "rotate(" + d.angle - 90 + ")translate(" + (d.y + 8) + ",0)" + (d.angle < 180 ? "" : "rotate(180)"); })
.style("text-anchor", function(d) { return d.angle < 180 ? "start" : "end"; })
.text(function(d) { return d.key; })
.on("mouseover", mouseovered)
.on("mouseout", mouseouted);
Upvotes: 3