Markers with D3
Every time I look at the examples page of D3, I’m simply go…
@mbostock has transformed how visualizations are created for web.
Today I learnt how to use svg markers with D3. I was using force layout to analyze graphs, just like this example. But I wanted a directed graph!
Later, I came across another example which had direction. I was happy because a ready-made solution solved the problem. But soon I ran into problem as I wanted a custom tree like structure with every path being directed i.e I wanted the arrow markers at the end of each path.
I went back to the ready-made solution and had a look at the part of code which was generating the arrows.
// build the arrow.
svg.append("svg:defs").selectAll("marker")
// Different link/path types can be defined here .data(["end"])
// This section adds in the arrows
//this makes the id as 'end', coming from data
.attr("id", String) .enter().append("svg:marker") .attr("viewBox", "0 -5 10 10") .attr("refX", 15) .attr("refY", -1.5) .attr("markerWidth", 6) .attr("markerHeight", 6) .attr("orient", "auto") .append("svg:path") .attr("d", "M0,-5L10,0L0,5");
Thanks to d3noob for adding comments to the code
The above code just creates an arrow. This can be added to any element later by adding the below code as its attribute.
svgElement.attr("marker-end", "url(#end)");
So what is the magic happening here? Lets look closely at what we are doing while building the arrow.
svg.append("svg:defs").selectAll("marker") .data(["end"]) .attr("id", String) .enter().append("svg:marker") .attr("viewBox", "0 -5 10 10") .attr("refX", 15) .attr("refY", -1.5) .attr("markerWidth", 6) .attr("markerHeight", 6) .attr("orient", "auto") .append("svg:path") .attr("d", "M0,-5L10,0L0,5");
We are creating an SVG def which will generate the arrow head. SVG defs are a way of defining graphical objects which can be applied to elements. The definition can be anything like defining a marker or defining a gradient as specified in MDN example. Now that we have created a definition, this can be easily applied to any element.
We will use the defined marker and apply it to every path we have by altering the path’s attribute
svg.selectAll(".link") .attr("marker-end", "url(#end)");
We use the marker-end attribute and assign the definition id as its value (in our case it is #end). marker-end attribute is used to add arrowhead or any other object at the final vertex of the path.
Now that we have added arrows to the path, lets see the output
A peek into DOM
Thanks to mbostock, d3noob, MDN