简体   繁体   中英

Rotate D3 SVG to line up to specific angle

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

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 dx=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 dx - 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 dx

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);

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM