Changing an arrowhead interactively

1,766 views
Skip to first unread message

JeffH

unread,
Nov 18, 2011, 3:12:34 PM11/18/11
to d3-js
Hi all,

I've been trying to change the color of a link and its arrowhead when
the user clicks on my force graph. So far, I've been successful in
changing the link line but can't figure out how to change the
arrowhead. This is the line in the code below that I thought might
work but doesn't:

d3.select(this.arrowhead).style("fill","red");

Any ideas would be most appreciated!
Thanks,
Jeff

var link = vis.selectAll("line.link")
.data(json.links)
.enter().append("svg:line")
.attr("class", "link")
.style("stroke-width", function(d) { return
Math.sqrt(d.value); })
.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; })
.attr("marker-end", "url(#arrowhead)")
.on("click", function(d) {
link.style("stroke","gray");
d3.select(this).style("stroke","red");
d3.select(this).style("fill","red");
d3.select(this.marker).style("fill","red");
clickLink(d);
});


defs.append("svg:marker")
.attr("id", "arrowhead")
.attr("viewBox","0 0 10 10")
.attr("refX","20")
.attr("refY","5")
.attr("markerUnits","strokeWidth")
.attr("markerWidth","9")
.attr("markerHeight","5")
.attr("orient","auto")
.append("svg:path")
.attr("d","M 0 0 L 10 5 L 0 10 z")
.attr("fill", "#BBBBBB");

Mike Bostock

unread,
Nov 18, 2011, 3:54:18 PM11/18/11
to d3...@googlegroups.com
> d3.select(this.arrowhead).style("fill","red");

Did you mean d3.select("#arrowhead")?

Mike

JeffH

unread,
Nov 18, 2011, 4:33:32 PM11/18/11
to d3-js
Sorry Mike... I think my last reply went to you email.

I just need to change the arrowhead of the selected link. I tried:

d3.select("#arrowhead").style("fill","red");
and
d3.this.select("#arrowhead").style("fill","red");
without success...

Mike Bostock

unread,
Nov 18, 2011, 4:45:41 PM11/18/11
to d3...@googlegroups.com
You have to select the path element within the marker, not the marker
itself. So, "#arrowhead path".

Mike

JeffH

unread,
Nov 18, 2011, 5:01:27 PM11/18/11
to d3-js
d3.select("#arrowhead path").style("fill","red");

That works but selects all markers... I can't figure out how to change
just the current (clicked) one.

Thanks for your help!

Mike Bostock

unread,
Nov 18, 2011, 5:03:30 PM11/18/11
to d3...@googlegroups.com
> That works but selects all markers... I can't figure out how to change
> just the current (clicked) one.

You can't. You have to have a different marker if you want different
colors. I believe a future version of SVG will allow the marker to
inherit the fill and stroke from the associated path, but that's not
currently the case.

Mike

JeffH

unread,
Nov 18, 2011, 5:05:36 PM11/18/11
to d3-js
Ah, so I would have to remove this marker for the selected one and
then add another? If you could show me an example, that would be
fantastic! I'm still trying to wrap my head around how you reference
these things.

Cheers,
Jeff

Erick Katzenstein

unread,
Apr 11, 2014, 6:00:58 PM4/11/14
to d3...@googlegroups.com
Here's kind of a hack that's working for me:
If the script is within a loop, i iterating:

 defs.append("svg:marker") 
                                .attr("id", "arrowhead"+i)         //create unique id for each arrowhead

  var link = vis.selectAll("line.link") 
              .data(json.links) 
            .enter().append("svg:line") 
              .attr("marker-end", "url(#arrowhead"+i+")")   //assign unique arrowhead to each object

 d3.selectAll("#arrowhead"+i+" path")  //select individual arrowhead to change color

Aaron Jones

unread,
Jan 7, 2015, 9:00:36 AM1/7/15
to d3...@googlegroups.com
Similar to what was said by Erick Katzenstein, you have to give each marker a unique ID/name so you can give that one the attribute you want.
Here is how I did it:

defs.append("svg:marker") .attr("id", function(d){ return 'arrow_' + d.name}) //-notice instead of "arrowhead" + i, I created a function to give each arrow a unique ID/name from the data. In my JSON file each edge has a name

For me I was giving it a color from a color scale so when selecting it I selected the path:

var arrows = inner.selectAll("path")
.style('stroke', function(d) { return color(d.name)}); //-colour marker depending on what name it has

This will colour every path so you need to figure out how to select each arrow like Erick did :  d3.selectAll("#arrowhead"+i+" path")  

But that doesnt work, not too sure myself how to do a function in a selectAll();
Reply all
Reply to author
Forward
0 new messages