Ci-dessous se trouve mon extrait de code où je voudrais avoir plusieurs marqueurs de pointe de flèche à la fin de mon chemin le pointant vers les enfants au lieu du parent. Mais j'ai pu pointer un seul marqueur de flèche vers mon parent mais pas un enfant. S'il vous plaît laissez-moi savoir ce qui doit être fait L'image ci-dessous montre la flèche pointant vers le parent. Je voudrais qu'il pointe vers les enfants.

L'image ci-dessous montre le code brut sans marqueurs de flèche Schéma en arbre

J'aimerais voir l'image ci-dessous comme une fonctionnalité de type dans mon code Code avec marqueurs

<!DOCTYPE html>
<meta charset="UTF-8">
<style>
    .node circle {
        fill: #fff;
        stroke: steelblue;
        stroke-width: 3px;
    }

    .node text {
        font: 12px sans-serif;
    }

    .link {
        fill: none;
        stroke: #ccc;
        stroke-width: 2px;
    }

    .link path {
        fill: none;
        stroke: #ccc;
        stroke-width: 2px;
    }

    .link text {
        font: 12px sans-serif;
        stroke: #333;
        stroke-width: 1;
    }
</style>

<body>

    <!-- load the d3.js library -->
    <script src="https://d3js.org/d3.v4.min.js"></script>
    <script>

        var treeData =
        {
            "name": "Top Level",
            "linkname": "null",
            "children": [
                {
                    "name": "Level 2: A",
                    "linkname": "Link_1",
                    "children": [
                        { "name": "Son of A", "linkname": "Link_2.1" },
                        { "name": "Daughter of A", "linkname": "Link_2.2" }
                    ]
                },
                { "name": "Level 2: B", "linkname": "Link_3", }
            ]
        };

        // Set the dimensions and margins of the diagram
        var margin = { top: 20, right: 90, bottom: 30, left: 90 },
            width = 960 - margin.left - margin.right,
            height = 500 - margin.top - margin.bottom;

        // append the svg object to the body of the page
        // appends a 'group' element to 'svg'
        // moves the 'group' element to the top left margin
        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 + ")");

        var i = 0,
            duration = 750,
            root;

        // declares a tree layout and assigns the size
        var treemap = d3.tree().size([height, width]);

        // Assigns parent, children, height, depth
        root = d3.hierarchy(treeData, function (d) { return d.children; });
        root.x0 = height / 2;
        root.y0 = 0;

        // Collapse after the second level
        root.children.forEach(collapse);

        update(root);

        // Collapse the node and all it's children
        function collapse(d) {
            if (d.children) {
                d._children = d.children
                d._children.forEach(collapse)
                d.children = null
            }
        }

        function update(source) {

            // Assigns the x and y position for the nodes
            var treeData = treemap(root);

            // Compute the new tree layout.
            var nodes = treeData.descendants(),
                links = treeData.descendants().slice(1);

            // Normalize for fixed-depth.
            nodes.forEach(function (d) {
                d.y = d.depth * 180
            });

            // ****************** Nodes section ***************************

            // Update the nodes...
            var node = svg.selectAll('g.node')
                .data(nodes, function (d) {
                    return d.id || (d.id = ++i);
                });

            // Enter any new modes 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);

            // Add Circle for the nodes
            nodeEnter.filter(function (d) {
                return (!d.data.type || d.data.type !== 'data');
            }).append('circle')
                .attr('class', 'node')
                .attr('r', 1e-6)
                .style("fill", function (d) {
                    return d._children ? "lightsteelblue" : "#fff";
                });

            nodeEnter.filter(function (d) {
                return (d.data.type && d.data.type === 'data');
            }).append('rect')
                .attr('class', 'node')
                .attr('width', 20)
                .attr('height', 20)
                .attr('y', -10)
                .attr('x', -10)
                .style("fill", function (d) {
                    return d._children ? "lightsteelblue" : "#fff";
                });

            // Add labels for the nodes
            nodeEnter.append('text')
                .attr("dy", "2em")
                .attr("x", function (d) {
                    return d.children || d._children ? 13 : 13;
                })
                .attr("text-anchor", function (d) {
                    return d.children || d._children ? "start" : "start";
                })
                .text(function (d) {
                    return d.data.name;
                });

            // UPDATE
            var nodeUpdate = nodeEnter.merge(node);

            // Transition to the proper position for the node
            nodeUpdate.transition()
                .duration(duration)
                .attr("transform", function (d) {
                    return "translate(" + d.y + "," + d.x + ")";
                });

            // Update the node attributes and style
            nodeUpdate.select('circle.node')
                .attr('r', 10)
                .style("fill", function (d) {
                    return d._children ? "lightsteelblue" : "#fff";
                })
                .attr('cursor', 'pointer');


            // Remove any exiting nodes
            var nodeExit = node.exit().transition()
                .duration(duration)
                .attr("transform", function (d) {
                    return "translate(" + source.y + "," + source.x + ")";
                })
                .remove();

            // On exit reduce the node circles size to 0
            nodeExit.select('circle')
                .attr('r', 1e-6);

            // On exit reduce the opacity of text labels
            nodeExit.select('text')
                .style('fill-opacity', 1e-6);

            // ****************** links section ***************************

            // Update the links...
            var link = svg.selectAll('g.link')
                .data(links, function (d) {
                    return d.id;
                });

            // Enter any new links at the parent's previous position.
            var linkEnter = link.enter().insert('g', 'g')
                .attr("class", "link");

            linkEnter.append('text')
                .attr("class","linkLabels")
                .text(function (d, i) {
                    if (d.parent && d.parent.children.length > 1) {
                        if (!d.parent.index) d.parent.index = 0;
                        return d.data.linkname;
                    }
                })
                .attr("opacity",0)
                .attr('dy', "-1em");

            linkEnter.append('path')
                .attr('d', function (d) {
                    var o = {
                        x: source.x0,
                        y: source.y0
                    }
                    return diagonal(o, o)
                })
                .on("mouseover", function(){
                    d3.select(this.parentNode).select("text").attr("opacity",1);
                })
                .on("mouseleave", function(){
                    d3.select(this.parentNode).select("text").attr("opacity",0);
                })


            // UPDATE
            var linkUpdate = linkEnter.merge(link);

            // Transition back to the parent element position
            linkUpdate.select('path').transition()
                .duration(duration)
                .attr('d', function (d) {
                    return diagonal(d, d.parent)
                });

            linkUpdate.select('text').transition()
                .duration(duration)
                .attr('transform', function (d) {
                    if (d.parent) {
                        return 'translate(' + ((d.parent.y + d.y) / 2) + ',' + ((d.parent.x + d.x) / 2) + ')'
                    }
                })

            // Remove any exiting links
            link.exit().each(function (d) {
                d.parent.index = 0;
            })

            var linkExit = link.exit()
                .transition()
                .duration(duration);

            linkExit.select('path')
                .attr('d', function (d) {
                    var o = {
                        x: source.x,
                        y: source.y
                    }
                    return diagonal(o, o)
                })

            linkExit.select('text')
                .style('opacity', 0);

            linkExit.remove();

            // Store the old positions for transition.
            nodes.forEach(function (d) {
                d.x0 = d.x;
                d.y0 = d.y;
            });

            // Creates a curved (diagonal) path from parent to the child nodes
            function diagonal(s, d) {
                path = `M ${s.y} ${s.x}
                        C ${(s.y + d.y) / 2} ${s.x},
                            ${(s.y + d.y) / 2} ${d.x},
                            ${d.y} ${d.x}`
                return path
            }

            // 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);
            }
        }


    </script>
</body>
0
Aryama I 21 févr. 2020 à 10:24

1 réponse

Meilleure réponse

Probablement pas à 100% ce que vous voulez, mais peut être un point de départ pour vous, en gros je l'ai fait en manipulant les attributs des marqueurs .attr("orient", "auto-start-reverse") vérifiez la MDN documentation pour plus d'informations sur cet attribut, également refX, et refY enfin le path attribut j'ai utilisé marker-start au lieu de marker-end car dans cet exemple le chemin tracé des enfants au parent et non l'inverse

Si ce n'est pas ce que vous voulez, il y a une autre question de débordement de pile qui est un peu proche de votre cas mais ce n'est pas un arbre mais peut vous aider :

Aligner le marqueur sur les bords des nœuds D3 Forcer la disposition

var treeData = {
  name: "Top Level",
  linkname: "null",
  children: [
    {
      name: "Level 2: A",
      linkname: "Link_1",
      children: [
        { name: "Son of A", linkname: "Link_2.1" },
        { name: "Daughter of A", linkname: "Link_2.2" }
      ]
    },
    { name: "Level 2: B", linkname: "Link_3" }
  ]
};

// Set the dimensions and margins of the diagram
var margin = { top: 20, right: 90, bottom: 30, left: 90 },
  width = 960 - margin.left - margin.right,
  height = 500 - margin.top - margin.bottom;

// append the svg object to the body of the page
// appends a 'group' element to 'svg'
// moves the 'group' element to the top left margin
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")
  .selectAll("marker")
  .data(["end"]) // Different link/path types can be defined here
  .enter()
  .append("svg:marker") // This section adds in the arrows
  .attr("id", String)
  .attr("viewBox", "0 -5 10 10")
  .attr("refX", 15)
  .attr("refY", 0)
  .attr("markerWidth", 6)
  .attr("markerHeight", 6)
  .attr("orient", "auto-start-reverse")
  .append("svg:path")
  .attr("d", "M0,-5L10,0L0,5");

var i = 0,
  duration = 750,
  root;

// declares a tree layout and assigns the size
var treemap = d3.tree().size([height, width]);

// Assigns parent, children, height, depth
root = d3.hierarchy(treeData, function(d) {
  return d.children;
});
root.x0 = height / 2;
root.y0 = 0;

// Collapse after the second level
root.children.forEach(collapse);

update(root);

// Collapse the node and all it's children
function collapse(d) {
  if (d.children) {
    d._children = d.children;
    d._children.forEach(collapse);
    d.children = null;
  }
}

function update(source) {
  // Assigns the x and y position for the nodes
  var treeData = treemap(root);

  // Compute the new tree layout.
  var nodes = treeData.descendants(),
    links = treeData.descendants().slice(1);

  // Normalize for fixed-depth.
  nodes.forEach(function(d) {
    d.y = d.depth * 180;
  });

  // ****************** Nodes section ***************************

  // Update the nodes...
  var node = svg.selectAll("g.node").data(nodes, function(d) {
    return d.id || (d.id = ++i);
  });

  // Enter any new modes 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);

  // Add Circle for the nodes
  nodeEnter
    .filter(function(d) {
      return !d.data.type || d.data.type !== "data";
    })
    .append("circle")
    .attr("class", "node")
    .attr("r", 1e-6)
    .style("fill", function(d) {
      return d._children ? "lightsteelblue" : "#fff";
    });

  nodeEnter
    .filter(function(d) {
      return d.data.type && d.data.type === "data";
    })
    .append("rect")
    .attr("class", "node")
    .attr("width", 20)
    .attr("height", 20)
    .attr("y", -10)
    .attr("x", -10)
    .style("fill", function(d) {
      return d._children ? "lightsteelblue" : "#fff";
    });

  // Add labels for the nodes
  nodeEnter
    .append("text")
    .attr("dy", "2em")
    .attr("x", function(d) {
      return d.children || d._children ? 13 : 13;
    })
    .attr("text-anchor", function(d) {
      return d.children || d._children ? "start" : "start";
    })
    .text(function(d) {
      return d.data.name;
    });

  // UPDATE
  var nodeUpdate = nodeEnter.merge(node);

  // Transition to the proper position for the node
  nodeUpdate
    .transition()
    .duration(duration)
    .attr("transform", function(d) {
      return "translate(" + d.y + "," + d.x + ")";
    });

  // Update the node attributes and style
  nodeUpdate
    .select("circle.node")
    .attr("r", 10)
    .style("fill", function(d) {
      return d._children ? "lightsteelblue" : "#fff";
    })
    .attr("cursor", "pointer");

  // Remove any exiting nodes
  var nodeExit = node
    .exit()
    .transition()
    .duration(duration)
    .attr("transform", function(d) {
      return "translate(" + source.y + "," + source.x + ")";
    })
    .remove();

  // On exit reduce the node circles size to 0
  nodeExit.select("circle").attr("r", 1e-6);

  // On exit reduce the opacity of text labels
  nodeExit.select("text").style("fill-opacity", 1e-6);

  // ****************** links section ***************************

  // Update the links...
  var link = svg.selectAll("g.link").data(links, function(d) {
    return d.id;
  });

  // Enter any new links at the parent's previous position.
  var linkEnter = link
    .enter()
    .insert("g", "g")
    .attr("class", "link");

  linkEnter
    .append("text")
    .attr("class", "linkLabels")
    .text(function(d, i) {
      if (d.parent && d.parent.children.length > 1) {
        if (!d.parent.index) d.parent.index = 0;
        return d.data.linkname;
      }
    })
    .attr("opacity", 0)
    .attr("dy", "-1em");

  linkEnter
    .append("path")
    .attr("d", function(d) {
      var o = {
        x: source.x0,
        y: source.y0
      };
      return diagonal(o, o);
    })
    .on("mouseover", function() {
      d3.select(this.parentNode)
        .select("text")
        .attr("opacity", 1);
    })
    .on("mouseleave", function() {
      d3.select(this.parentNode)
        .select("text")
        .attr("opacity", 0);
    })
    .attr("stroke-linecap", "round")
    .attr("marker-start", "url(#end)");

  // UPDATE
  var linkUpdate = linkEnter.merge(link);

  // Transition back to the parent element position
  linkUpdate
    .select("path")
    .transition()
    .duration(duration)
    .attr("d", function(d) {
      return diagonal(d, d.parent);
    });

  linkUpdate
    .select("text")
    .transition()
    .duration(duration)
    .attr("transform", function(d) {
      if (d.parent) {
        return (
          "translate(" +
          (d.parent.y + d.y) / 2 +
          "," +
          (d.parent.x + d.x) / 2 +
          ")"
        );
      }
    });

  // Remove any exiting links
  link.exit().each(function(d) {
    d.parent.index = 0;
  });

  var linkExit = link
    .exit()
    .transition()
    .duration(duration);

  linkExit.select("path").attr("d", function(d) {
    var o = {
      x: source.x,
      y: source.y
    };
    return diagonal(o, o);
  });

  linkExit.select("text").style("opacity", 0);

  linkExit.remove();

  // Store the old positions for transition.
  nodes.forEach(function(d) {
    d.x0 = d.x;
    d.y0 = d.y;
  });

  // Creates a curved (diagonal) path from parent to the child nodes
  function diagonal(s, d) {
    path = `M ${s.y} ${s.x}
            C ${(s.y + d.y) / 2} ${s.x},
                ${(s.y + d.y) / 2} ${d.x},
                ${d.y} ${d.x}`;
    return path;
  }

  // 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 circle {
  fill: #fff;
  stroke: steelblue;
  stroke-width: 3px;
}

.node text {
  font: 12px sans-serif;
}

.link {
  fill: none;
  stroke: #ccc;
  stroke-width: 2px;
}

.link path {
  fill: none;
  stroke: #ccc;
  stroke-width: 2px;
}

.link text {
  font: 12px sans-serif;
  stroke: #333;
  stroke-width: 1;
}
<!DOCTYPE html>
<meta charset="UTF-8">
<style>
    
</style>

<body>
  <!-- load the d3.js library -->
  <script src="https://d3js.org/d3.v4.min.js"></script>
</body>
0
ROOT 21 févr. 2020 à 13:16