D3树状图,每个节点上都有左右节点



我有一个d3图表,它同时具有左右路径/节点。现在我要做的是,在点击一个节点时,我想附加相同的数据(具有左右节点的同一棵树(,这个新树将根据点击的节点x和y值进行填充/居中,所以我尝试添加一个新的g,其中包含我从点击的对象中获得的x和y的值。

像这个

var g = svg.append("g")
.attr("transform", "translate(" + d.x * 2 + "," + d.y + ")");
drawTree2(left, "left", d);
drawTree2(right, "right", d);

但它不起作用,请帮助

var data = {
"name": "Root",
"children": [{
"name": "Branch 1"
}, {
"name": "Branch 2",
}, {
"name": "Branch 3"
}, {
"name": "Branch 4",
}, {
"name": "Branch 5"
},

{
"name": "Branch 6"
}, {
"name": "Branch 7",
}, {
"name": "Branch 8"
}, {
"name": "Branch 9",
}, {
"name": "Branch 10"
}
]
};

var split_index = Math.round(data.children.length / 2)
// Left data
var data1 = {
"name": data.name,
"children": JSON.parse(JSON.stringify(data.children.slice(0, split_index)))
};
// Right data
var data2 = {
"name": data.name,
"children": JSON.parse(JSON.stringify(data.children.slice(split_index)))
};
// Create d3 hierarchies
var right = d3.hierarchy(data1);
var left = d3.hierarchy(data2);
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height");
var g = svg.append("g")
.attr("transform", "translate(" + width / 2 + ",0)");
// Render both trees
drawTree(right, "right")
drawTree(left, "left")

function drawTree(root, pos) {
var SWITCH_CONST = 1;
if (pos === "left") {
SWITCH_CONST = -1;
}
// Create new default tree layout
var tree = d3.tree()
// Set the size
// Remember the tree is rotated
// so the height is used as the width
// and the width as the height
.size([height, SWITCH_CONST * (width - 150) / 2]);
tree(root)
var nodes = root.descendants();
var links = root.links();
// Set both root nodes to be dead center vertically
nodes[0].x = height / 2
// Create links
var link = g.selectAll(".link." + pos)
.data(links)
.join(
enter => enter.append("path"),
update => update,
exit => exit.remove()
)
.attr("class", "link " + pos)
.attr("d", function(d) {
return "M" + d.target.y + "," + d.target.x + "C" + (d.target.y + d.source.y) / 2.5 + "," + d.target.x + " " + (d.target.y + d.source.y) / 2 + "," + d.source.x + " " + d.source.y + "," + d.source.x;
});
// Create nodes
var node = g.selectAll(".node." + pos)
.data(nodes)
.join(
enter => {
const n = enter
.append("g")
.on("click", (e, d) => {
drawSecondTree(d);
});
n.append("circle").attr("r", 2.5);
n.append("text").attr("y", -10).style("text-anchor", "middle");
return n;
},
update => update,
exit => exit.remove()
)
.attr("class", function(d) {
return "node " + pos + (d.children ? " node--internal" : " node--leaf");
})
.attr("transform", function(d) {
return "translate(" + d.y + "," + d.x + ")";
})
.select("text")
.text(function(d) {
return d.data.name
});
}
function drawSecondTree(d) {
var g = svg.append("g")
.attr("transform", "translate(" + d.x * 2 + "," + d.y + ")");
drawTree2(left, "left", d);
drawTree2(right, "right", d);
function drawTree2(root, pos, d) {
console.log(d.x, d.y);
//return false;
var SWITCH_CONST = 1;
if (pos === "left") {
SWITCH_CONST = -1;
}
// Create new default tree layout
var tree = d3.tree()
// Set the size
// Remember the tree is rotated
// so the height is used as the width
// and the width as the height
.size([height, SWITCH_CONST * (width - 150) / 2]);
tree(root)
var nodes = root.descendants();
var links = root.links();
// Set both root nodes to be dead center vertically
nodes[0].x = d.y;
// Create links
var link = g.selectAll(".link." + pos)
.data(links)
.join(
enter => enter.append("path"),
update => update,
exit => exit.remove()
)
.attr("class", "link " + pos)
.attr("d", function(d) {
return "M" + d.target.y + "," + d.target.x + "C" + (d.target.y + d.source.y) / 2.5 + "," + d.target.x + " " + (d.target.y + d.source.y) / 2 + "," + d.source.x + " " + d.source.y + "," + d.source.x;
});
// Create nodes
var node = g.selectAll(".node." + pos)
.data(nodes)
.join(
enter => {
const n = enter
.append("g")
.on("click", (e, d) => toggle(d, pos, pos === "left" ? left : right));
n.append("circle").attr("r", 2.5);
n.append("text").attr("y", -10).style("text-anchor", "middle");
return n;
},
update => update,
exit => exit.remove()
)
.attr("class", function(d) {
return "node " + pos + (d.children ? " node--internal" : " node--leaf");
})
.attr("transform", function(d) {
return "translate(" + d.y + "," + d.x + ")";
})
.select("text")
.text(function(d) {
return d.data.name
});
}
}
.node circle {
fill: #999;
}
.node text {
font: 12px sans-serif;
}
.node--internal circle {
fill: #555;
}
.link {
fill: none;
stroke: #555;
stroke-opacity: 0.4;
stroke-width: 1.5px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.2.0/d3.min.js"></script>
<svg width="900" height="600"></svg>

认为我理解你的意图。

这很难解释,因为这种设置方式有点令人困惑。基本上,主要问题是如何创建新的g元素的";中心点";(translate(x,y)部分(。它之所以令人困惑,是因为你在某些地方切换X和Y坐标。也许你无法通过你想要的地图外观来绕过这一点,这很好,只是很难跟上。

我在drawSecondTree函数中做了以下更改(注意"添加"one_answers"更新"项(:

function drawSecondTree(d) {
var gX = (width / 2) + d.y; // ********** added
var gY = d.x - gX; // ********** added

var g = svg.append("g")
.attr("transform", "translate(" + gX + "," + gY + ")"); // ********** updated
drawTree2(left, "left", d);
drawTree2(right, "right", d);
function drawTree2(root, pos, d) {
console.log(d.x, d.y);
//return false;
var SWITCH_CONST = 1;
if (pos === "left") {
SWITCH_CONST = -1;
}
// Create new default tree layout
var tree = d3.tree()
// Set the size
// Remember the tree is rotated
// so the height is used as the width
// and the width as the height
.size([height, SWITCH_CONST * (width - 150) / 2]);
tree(root)
var nodes = root.descendants();
var links = root.links();
// Set both root nodes to be dead center vertically
// nodes[0].x = d.y;
nodes[0].x = (width / 2) + d.y; // ********** updated
// Create links
var link = g.selectAll(".link." + pos)
.data(links)
.join(
enter => enter.append("path"),
update => update,
exit => exit.remove()
)
.attr("class", "link " + pos)
.attr("d", function(d) {
return "M" + d.target.y + "," + d.target.x + "C" + (d.target.y + d.source.y) / 2.5 + "," + d.target.x + " " + (d.target.y + d.source.y) / 2 + "," + d.source.x + " " + d.source.y + "," + d.source.x;
});
// Create nodes
var node = g.selectAll(".node." + pos)
.data(nodes)
.join(
enter => {
const n = enter
.append("g")
.on("click", (e, d) => toggle(d, pos, pos === "left" ? left : right));
n.append("circle").attr("r", 2.5);
n.append("text").attr("y", -10).style("text-anchor", "middle");
return n;
},
update => update,
exit => exit.remove()
)
.attr("class", function(d) {
return "node " + pos + (d.children ? " node--internal" : " node--leaf");
})
.attr("transform", function(d) {
return "translate(" + d.y + "," + d.x + ")";
})
.select("text")
.text(function(d) {
return d.data.name
});
}
}

这是一个完整代码的代码笔(节点重叠(。

我还建议您考虑使用svg元素的viewBox,并了解如何在添加更多节点时通过单击它们来缩小。

最新更新