简体   繁体   中英

Adding marker on d3 tree layout links

I'm trying to add marker arrows on a default d3 tree layout. The tree layout is working fine.

I have defined the marker like this :

svg.append("svg:defs")
    .append("svg:marker")
    .attr("id", "arrow")    
    .attr("refX", 2)
    .attr("refY", 6)
    .attr("markerWidth", 13)
    .attr("markerHeight", 13)
    .attr("orient", "auto")
    .append("svg:path")
    .attr("d", "M2,2 L2,11 L10,6 L2,2");

and used it on the links in the tree layout like:

.attr("marker", "url(#arrow)");

But the marker arrows are not appearing. What am i doing wrong?

 var treeData = [{ "name": "Top Level", "parent": "null", "children": [{ "name": "Level 2: A", "parent": "Top Level", "children": [{ "name": "Son of A", "parent": "Level 2: A" }, { "name": "Daughter of A", "parent": "Level 2: A" }] }, { "name": "Level 2: B", "parent": "Top Level" }] }]; // ************** Generate the tree diagram ***************** var margin = { top: 20, right: 120, bottom: 20, left: 120 }, width = 960 - margin.right - margin.left, height = 500 - margin.top - margin.bottom; var i = 0, duration = 750, root; var tree = d3.layout.tree() .size([height, width]); var diagonal = d3.svg.diagonal() .projection(function(d) { return [dy, dx]; }); var svg = d3.select("body").append("svg") .attr("width", width + margin.right + margin.left) .attr("height", height + margin.top + margin.bottom) .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); svg.append("svg:defs") .append("svg:marker") .attr("id", "arrow") .attr("refX", 2) .attr("refY", 6) .attr("markerWidth", 13) .attr("markerHeight", 13) .attr("orient", "auto") .append("svg:path") .attr("d", "M2,2 L2,11 L10,6 L2,2"); root = treeData[0]; root.x0 = height / 2; root.y0 = 0; update(root); d3.select(self.frameElement).style("height", "500px"); function update(source) { // Compute the new tree layout. var nodes = tree.nodes(root).reverse(), links = tree.links(nodes); // Normalize for fixed-depth. nodes.forEach(function(d) { dy = d.depth * 180; }); // Update the nodes… var node = svg.selectAll("g.node") .data(nodes, function(d) { return d.id || (d.id = ++i); }); // Enter any new nodes at the parent's previous position. var nodeEnter = node.enter().append("g") .attr("class", "node") .attr("transform", function(d) { return "translate(" + source.y0 + "," + source.x0 + ")"; }) .on("click", click); nodeEnter.append("circle") .attr("r", 1e-6) .style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; }); nodeEnter.append("text") .attr("x", function(d) { return d.children || d._children ? -13 : 13; }) .attr("dy", ".35em") .attr("text-anchor", function(d) { return d.children || d._children ? "end" : "start"; }) .text(function(d) { return d.name; }) .style("fill-opacity", 1e-6); // Transition nodes to their new position. var nodeUpdate = node.transition() .duration(duration) .attr("transform", function(d) { return "translate(" + dy + "," + dx + ")"; }); nodeUpdate.select("circle") .attr("r", 10) .style("fill", function(d) { return d._children ? "lightsteelblue" : "#fff"; }); nodeUpdate.select("text") .style("fill-opacity", 1); // Transition exiting nodes to the parent's new position. var nodeExit = node.exit().transition() .duration(duration) .attr("transform", function(d) { return "translate(" + source.y + "," + source.x + ")"; }) .remove(); nodeExit.select("circle") .attr("r", 1e-6); nodeExit.select("text") .style("fill-opacity", 1e-6); // Update the links… var link = svg.selectAll("path.link") .data(links, function(d) { return d.target.id; }); // Enter any new links at the parent's previous position. link.enter().insert("path", "g") .attr("class", "link") .attr("d", function(d) { var o = { x: source.x0, y: source.y0 }; return diagonal({ source: o, target: o }); }) .attr("marker-mid", "url(#arrow)");; // Transition links to their new position. link.transition() .duration(duration) .attr("d", diagonal); // Transition exiting nodes to the parent's new position. link.exit().transition() .duration(duration) .attr("d", function(d) { var o = { x: source.x, y: source.y }; return diagonal({ source: o, target: o }); }) .remove(); // Stash the old positions for transition. nodes.forEach(function(d) { d.x0 = dx; d.y0 = dy; }); } // Toggle children on click. function click(d) { if (d.children) { d._children = d.children; d.children = null; } else { d.children = d._children; d._children = null; } update(d); } 
 .node { cursor: pointer; } .node circle { fill: #fff; stroke: steelblue; stroke-width: 3px; } .node text { font: 12px sans-serif; } .link { fill: none; stroke: #ccc; stroke-width: 2px; } 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script> 

The mid-markers do not appear because they are attached to paths with only a start and an end vertex, no intermediate vertex.

The marker-mid defines the arrowhead or polymarker that shall be drawn at every vertex other than the first and last vertex of the given element or basic shape.

reference

What you may do instead is:

  • do not show a marker (recommended, it clutters the visual without adding much value)
  • use an end-marker instead of a mid-marker (and adjust the position of the last vertex so that it stay to the left of the circle, not to its center)
  • or mess around with the code generating links paths, in order to add a point in the middle of the path.

Read also related question .

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