transformation issues when implementing fisheye distortion in a radial tree

人走茶凉 提交于 2019-12-01 06:44:05

Following the direction I'd suggested in the comments, this is the result:

http://fiddle.jshell.net/7TPhq/7/

Instead of using rotations and translations to position the nodes, I created two trigonometry-based functions to calculate horizontal and vertical position from the data (x,y) values, which are treated as polar coordinates.

Then I had to set the fisheye function to use my positioning functions as "accessor" functions instead of reading d.x and d.y directly. Unfortunately, the basic plug-in you were using for the fisheye didn't include a way to get and set x/y accessor functions, so I had to modify that too. I was surprised it wasn't already in the code; it's a standard functionality on most d3 layout objects.

(When I get github set up, I will have to make a pull request to add it in. I'll need to figure out how the fisheye scale/zoom function works, though -- I took that out of this example since you weren't using it.)

The positioning functions were as follows:

function getHPosition(d){
    //calculate the transformed (Cartesian) position (H, V)
    //(without fisheye effect)
    //from the polar coordinates (x,y) where 
    //x is the angle
    //y is the distance from (radius,radius)
    //See http://www.engineeringtoolbox.com/converting-cartesian-polar-coordinates-d_1347.html

    return (d.y)*Math.cos(d.x);
}
function getVPosition(d){
    return (d.y)*Math.sin(d.x);
};

The functions are used to set the original position of the nodes and links, and then once the fisheye kicks in it uses these functions internally, returning the results (with distortion if appropriate) as d.fisheye.x and d.fisheye.y.

For example, for links that means the projection setting the d3.svg.diagonal function like this for initialization:

var diagonal = d3.svg.diagonal()
    .projection(function(d) { 
        return [getHPosition(d), getVPosition(d)]; 
});

But like this for update:

diagonal.projection(function(d) { 
    d.fisheye = fisheye(d); 
    return [d.fisheye.x, d.fisheye.y]; 
});

There are a couple other little changes:

I simplified the dimensions of the plotting area a bit.

I added a background rectangle with pointer-events:all; so that the fisheye doesn't turn on and off as the mouse moves between nodes and empty background.

I didn't bother rotating the text (since the node groups are no longer rotating, it doesn't happen by default), but you could easily add in a rotate transformation on the individual text elements.

Finally, and this one stumped me for longer than I'd like to admit, the angles have to be in radians for the Javascript trig functions. Couldn't figure out why my layouts were so ugly, with overlapping lines. I thought it was something to do with switching between d3.svg.diagonal() and d3.svg.diagonal.radial() and spent a lot of time trying to do inverse-trig and all sorts of things...

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!