Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
395 views
in Technique[技术] by (71.8m points)

javascript - How can I connect two parent node into one child node and how to make a tooltip for each node in the tree pragmatically? in D3 js (SVG)

I have made a tree graph structure and it's working absolutely fine. But now I want to make a small change but unable to make that change. I want to connect the two-parent node into one child node...also I am trying to add a tooltip into each node pragmatically.

For example - if you run the code, you will see it more clearly. I wanna make a child node of Hanna and mark which will be connected to a child node named "Eric".

any idea how to achieve this?

var svg = d3
  .select("body")
  .append("svg")
  .attr("width", 600)
  .attr("height", 600)
  .append("g")
  .attr("transform", "translate(50,50)");

//tree data
var data = [
  { child: "John", parent: "" },
  { child: "Aron", parent: "Kevin" },
  { child: "Kevin", parent: "John" },
  { child: "Hannah", parent: "Anna" },
  { child: "Rose", parent: "Sarah" },
  { child: "Anna", parent: "John" },
  { child: "Sarah", parent: "Kevin" },
  { child: "Mark", parent: "Anna" },
  { child: "Angle", parent: "Sarah" },
];

//to construct
var dataStructure = d3
  .stratify()
  .id(function (d) {
    return d.child;
  })
  .parentId(function (d) {
    return d.parent;
  })(data);

//to define the size of the structure tree
var treeStructure = d3.tree().size([500, 300]);
var information = treeStructure(dataStructure);

//to make the connections curves
var connections = svg.append("g").selectAll("path").data(information.links());
connections
  .enter()
  .append("path")
  .attr("d", function (d) {
    return (
      "M" +
      d.source.x +
      "," +
      d.source.y +
      " C " +
      d.source.x +
      "," +
      (d.source.y + d.target.y) / 2 +
      " " +
      d.target.x +
      "," +
      (d.source.y + d.target.y) / 2 +
      " " +
      d.target.x +
      "," +
      d.target.y
    );
  });

//creating the circles with data info
var circles = svg
  .append("g")
  .selectAll("circle")
  .data(information.descendants());

//placing the circles
circles
  .enter()
  .append("circle")
  .attr("cx", function (d) {
    return d.x;
  })
  .attr("cy", function (d) {
    return d.y;
  })
  .attr("r", 7)
  .append("text");

//names
var names = svg.append("g").selectAll("text").data(information.descendants());
names
  .enter()
  .append("text")
  .text(function (d) {
    return d.data.child;
  })
  .attr("x", function (d) {
    return d.x + 7;
  })
  .attr("y", function (d) {
    return d.y + 4;
  });
circle {
  fill: rgb(88, 147, 0);
}

path {
  fill: none;
  stroke: black;
}
<script src="https://d3js.org/d3.v6.min.js"></script>
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

The simplest thing you can do is just assign a parent at random, then use that parent to position the nodes, and draw the links yourself.

var svg = d3
  .select("body")
  .append("svg")
  .attr("width", 600)
  .attr("height", 600)
  .append("g")
  .attr("transform", "translate(50,50)");

//tree data
var data = [
  { child: "Alice", parents: [] },
  { child: "Bob", parents: [] },
  { child: "Carol", parents: [] },
  { child: "Dave", parents: ["Alice", "Bob"] },
  { child: "Eve", parents: ["Alice", "Bob"] },
  { child: "Francis", parents: ["Bob", "Carol"] },
  { child: "Graham", parents: ["Carol"] },
  { child: "Hugh", parents: ["Eve", "Graham"] },
];

// Process the nodes, add a pseudo root node so we don't have
// multiple roots
data.forEach(function(d) {
  d.parentId = d.parents.length > 0 ? d.parents[0] : "root";
});
data.unshift({ child: "root", parentId: "" });

//to construct
var dataStructure = d3
  .stratify()
  .id(function (d) {
    return d.child;
  })
  .parentId(function (d) {
    return d.parentId;
  })(data);

//to define the size of the structure tree
var treeStructure = d3.tree().size([500, 300]);
var root = treeStructure(dataStructure);

var nodes = root.descendants()
  .filter(function(d) { return d.id !== "root"; });

// Custom way to get all links we need to draw
var links = [];
nodes.forEach(function(node) {
  node.data.parents.forEach(function(parentId) {
    var parentNode = nodes.find(function(d) { return d.id === parentId; });
    links.push({
      source: parentNode,
      target: node,
    });
  });
});

//to make the connections curves
var connections = svg.append("g").selectAll("path").data(links);
connections
  .enter()
  .append("path")
  .attr("d", function (d) {
    return (
      "M" +
      d.source.x +
      "," +
      d.source.y +
      " C " +
      d.source.x +
      "," +
      (d.source.y + d.target.y) / 2 +
      " " +
      d.target.x +
      "," +
      (d.source.y + d.target.y) / 2 +
      " " +
      d.target.x +
      "," +
      d.target.y
    );
  });

//creating the circles with data info
var circles = svg
  .append("g")
  .selectAll("circle")
  .data(nodes);

//placing the circles
circles
  .enter()
  .append("circle")
  .attr("cx", function (d) {
    return d.x;
  })
  .attr("cy", function (d) {
    return d.y;
  })
  .attr("r", 7)
  .append("text");

//names
var names = svg.append("g").selectAll("text").data(nodes);
names
  .enter()
  .append("text")
  .text(function (d) {
    return d.id;
  })
  .attr("x", function (d) {
    return d.x + 7;
  })
  .attr("y", function (d) {
    return d.y + 4;
  });
circle {
  fill: rgb(88, 147, 0);
}

path {
  fill: none;
  stroke: black;
}
<script src="https://d3js.org/d3.v6.min.js"></script>

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...