Marker don't orient properly at the end of SVG path

1,279 views
Skip to first unread message

Shubham Gupta

unread,
Apr 26, 2012, 6:00:51 PM4/26/12
to d3...@googlegroups.com

I am trying to create a visualization where the lines between 2 nodes are connected via path using d3.svg.diagonal as shown in http://www.isi.edu/~shubhamg/d3-test-6.html

In this example: bl.ocks.org/1153292 the markers orient properly according to the angle at the end of path.

As it can be seen, the markers do not orient properly at the end of the SVG path (by markers I mean the arrows at the end of paths) Any suggestions to fix it? Thanks a lot.

Gian

unread,
Jul 11, 2012, 11:58:39 AM7/11/12
to d3...@googlegroups.com
Hi Shubham,

Having exactly the same issue and posted a question before seeing this one.

A simple copy paste of the patent example does not orient properly the markers.

Did you manage to solve this?

Shubham Gupta

unread,
Jul 11, 2012, 12:08:10 PM7/11/12
to d3...@googlegroups.com
Nopes, I ended up using straight lines :(

Shuby

Chris Michael

unread,
Jul 12, 2012, 4:34:07 AM7/12/12
to d3...@googlegroups.com
I had problems with the math behind an arrow. It would align ok, but sometimes would be upside down. I ran out of patience at this point and cheated by using a diamond instead.

In the end I used a diamond shape set nearer to one end of the link that the other and used a transform on the tick event to change the orientation. Maybe the code below will help.


linkArrow.attr("transform", function(d)
{
var sx = d.source.x; var sy = d.source.y; var tx = d.target.x; var ty = d.target.y; 
var dx=tx-sx; var dy=ty-sy;
var gradient=dy/dx;
var theta=Math.atan(gradient)
var x = tx-(dx/4);
var y = ty-(dy/4);
var angle=(theta*(180/Math.PI))-270
angle = angle%360
var tempAngle=angle
return "translate("+x+" "+y+") rotate("+tempAngle+" 0 0)"
})

Gianluca Bisceglie

unread,
Jul 12, 2012, 11:24:35 AM7/12/12
to d3...@googlegroups.com
I just filed filed a Firefox bug as suggested on stackoverflow (it renders correctly on other browsers): http://stackoverflow.com/questions/11444558/d3-arrows-in-force-directed-graph#comment15107168_11444558

Chris, is it possible to show your solution applied to the patent example on jsfiddle or bitbucket?

Thanks,
Gian

Chris Michael

unread,
Jul 12, 2012, 11:45:07 AM7/12/12
to d3...@googlegroups.com
Hi Gian, 
I am not familiar with either of these. I am happy to email you the JS file though. 

In the meantime here is a bit more detail:

// create one diamond shape for each link
// initially all arrows occupy the same spot in the top left of the screen
var linkArrow = vis.selectAll(".linkArrow").data(data.links)
linkArrow.enter().append("polygon").attr("class","linkArrow")
.attr("points","0,0 5,10 0,20 -5,10").attr("style","fill:black;stroke:black;stroke-width:1")
// in the tick event of the force diagram
.force.on("tick", function (a) 
{
     // add a transform to each of the diamonds/(arrows) created above
     linkArrow.attr("transform", function(d)
{
                                       // get the x and y points of the source and destination nodes
var sx = d.source.x; var sy = d.source.y; var tx = d.target.x; var ty = d.target.y; 
                                       // calculate dx and dy
var dx=tx-sx; var dy=ty-sy;
                                       // calculate the gradient of the line
var gradient=dy/dx;
                                       // calculate the angle of the line
var theta=Math.atan(gradient)
                                       // the diamond is going to be three quarters of the way along the line (an arbitary design decision)
                                      // calculate the x and y of where this diamond needs to translated to
var x = tx-(dx/4);
var y = ty-(dy/4);
                                      // as well as translating the diamond to the correct position, we also need to rotate it so that it aligns with the link line
                                     // the angle was calculated in radians initially so not convert it to degrees
var angle=(theta*(180/Math.PI))-270
                                    // we are not interested in anything over 360 degrees so modulo divide by 360 to get the remainder
angle = angle%360
                                    // we now have all the info we need to first translate the diamond to the correct position
                                   // and then rotate it to the appropriate angle such that it aligns with the link
return "translate("+x+" "+y+") rotate("+angle+" 0 0)"
}
}

With a bit more work, this can be added to to work on arrows rather than diamonds. Using the above on arrows however, sometimes the arrow faces the wrong way. I "cheated" by using a diamond (two arrows back to back) so that there is no "wrong way". The problem is to do with the fact that in normal maths, the y increases as you go up, whereas of course in html, y increases as you go down. 

I hope this helps. I shall investigate hosting my source somewhere.

Chris

Chris Michael

unread,
Jul 12, 2012, 11:47:41 AM7/12/12
to d3...@googlegroups.com
On the firefox/chrome issue I have been developing on Chrome and when I try my app in Firefox the view window of the SVG is tiny whereas it is full screen (as expected) in Chrome.
Reply all
Reply to author
Forward
0 new messages