gpt4 book ai didi

javascript - 隐藏在矩形内的链接中的箭头

转载 作者:行者123 更新时间:2023-12-05 06:03:26 25 4
gpt4 key购买 nike

我正在尝试将箭头添加到我的布局中,但它不起作用。问题是箭头没有出现在正确的位置,而是出现在我为每个节点绘制的矩形内。解决这个问题的更好方法是什么?我试过更改链接的坐标但没有成功,还尝试更改对 Angular 线对象,但没有成功。

我附加了一个 MWE,以便您可以看到当前状态。

var data = {
"name": "Eve",
"children": [
{
"name": "Cain"
},
{
"name": "Seth",
"children": [
{
"name": "Enos"
},
{
"name": "Noam"
}
]
},
{
"name": "Abel"
},
{
"name": "Awan",
"children": [
{
"name": "Enoch"
}
]
},
{
"name": "Azura"
}
]
};

let width = $(document).width();
let height = $(document).height();
const DX = 80;
const DY = 80;
const MIN_ZOOM = 0.15;
const MAX_ZOOM = Infinity;

const RECT_WIDTH = 40;
const RECT_HEIGHT = 15;
const TRANSITION_DURATION = 700;

let tree = d3.tree().nodeSize([DX, DY]);

let diagonal = d3.linkVertical()
.x(d => d.x + RECT_WIDTH / 2)
.y(d => d.y + RECT_HEIGHT / 2);

function createRoot() {
let root = d3.hierarchy(data);
root.x0 = DX / 2;
root.y0 = 0;
root.descendants().forEach((d, i) => {
d.id = i;
// Auxiliar variable to hide and show nodes when user clicks
d._children = d.children;
// Only the root is displayed at first sight
if (d.depth >= 0) d.children = null;
});
return root;
}

function update(source) {
const nodes = root.descendants().reverse();
const links = root.links();

// Compute the new tree layout
tree(root);

const transition = svg.transition()
.duration(TRANSITION_DURATION)
.tween("resize", window.ResizeObserver ? null : () => () => svg.dispatch("toggle"));

/*=============================NODE SECTION============================== */
// Obtain all the nodes
const node = gNode.selectAll("g")
.data(nodes, d => d.id);

// Enter any new nodes at the parent's previous position.
const nodeEnter = node.enter().append("g")
.attr("class", "node")
.attr("transform", d => `translate(${source.x0},${source.y0})`)
.on("click", function (event, d) {
if (d.children) // Node expanded -> Collapse
collapse(d);
else // Node collapsed -> Expand
d.children = d._children
//If we want to restablish the last state is sufficient to do
//d.children = d.children ? null : d._children;
update(d);
centerNode(d);
})
.attr("pointer-events", d => d._children ? "all" : "none");

nodeEnter.append("rect")
// Two different classes, one for the leafs and another for the others
.attr("class", d => d._children ? "expandable" : "leaf")
.attr("height", RECT_HEIGHT)
.attr("width", RECT_WIDTH)

nodeEnter.append("text")
// The position of the text is centered
.attr("x", RECT_WIDTH / 2)
.attr("y", RECT_HEIGHT / 2)
.text(d => d.data.name)
.clone(true).lower();

// Transition nodes to their new position (update)
node.merge(nodeEnter).transition(transition)
.attr("transform", d => `translate(${d.x},${d.y})`)
// Show the nodes
.attr("fill-opacity", 1)
.attr("stroke-opacity", 1);

/* Transition exiting nodes to the parent's new position */
node.exit().transition(transition).remove()
.attr("transform", d => `translate(${source.x},${source.y})`)
// Hide the nodes
.attr("fill-opacity", 0)
.attr("stroke-opacity", 0);

/*=============================LINK SECTION============================== */
const link = gLink.selectAll("path")
.data(links, d => d.target.id);

// Enter any new links at the parent's previous position
const linkEnter = link.enter().append("path")
.attr("class", "link")
.attr("x", RECT_WIDTH / 2)
.attr("y", RECT_HEIGHT / 2)
.attr("marker-end", "url(#end)") // add the arrow to the link end
.attr("d", d => {
const o = {x: source.x0, y: source.y0};
return diagonal({source: o, target: o});
})

// Transition links to their new position
link.merge(linkEnter).transition(transition)
// In this case the link will be the same but moved by the transition
.attr("d", diagonal);

// Transition exiting nodes to the parent's new position
link.exit().transition(transition).remove()
.attr("d", d => {
const o = {x: source.x, y: source.y};
return diagonal({source: o, target: o});
});

// Stash the old positions for transition
root.eachBefore(d => {
d.x0 = d.x;
d.y0 = d.y;
});
}

function centerNode(source) {
let scale = d3.zoomTransform(d3.select("svg").node()).k;
let x = -source.x0 * scale + width / 2 - RECT_WIDTH / 2 * scale;
let y = -source.y0 * scale + height / 2 - RECT_HEIGHT / 2 * scale;
// Define the transition
const transition = svg.transition()
.duration(TRANSITION_DURATION)
.tween("resize", window.ResizeObserver ? null : () => () => svg.dispatch("toggle"));
// Move all the nodes based on the previous parameters
svg.transition(transition)
.call(zoomBehaviours.transform, d3.zoomIdentity.translate(x,y).scale(scale));
}

function collapse(node) {
if (node.children) { // Expanded
node.children = null;
node._children.forEach(collapse)
}
}

// Root creation
const root = createRoot();

// SVG variable that will contain all the configuration for the images.
// We need to append it to the body
const svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);

const g = svg.append("g");

// Two groups: One of links and another of nodes
const gLink = g.append("g");
const gNode = g.append("g");

const zoomBehaviours = d3.zoom()
.scaleExtent([MIN_ZOOM, MAX_ZOOM])
.on('zoom', (event) => g.attr('transform', event.transform));

// Add the zoom so that svg knows that it is available
svg.call(zoomBehaviours);

svg.append("svg:defs").selectAll("marker")
.data(["end"]) // Different link/path types can be defined here
.enter().append("marker") // This section adds in the arrows
.attr("id", String)
.attr("viewBox", "0 -5 10 10")
.attr("refX", 0)
.attr("refY", 0)
.attr("markerWidth", 5)
.attr("markerHeight", 5)
.attr("orient", "auto")
.append("path")
.attr("d", "M0,-5L10,0L0,5");

update(root);
centerNode(root);
.node {
cursor: pointer;
}
.node .expandable {
stroke: black;
stroke-width: 1.2;
fill: lightskyblue;
}
.node .leaf {
fill: lightskyblue;
}
.node text {
fill: black;
font: 10px sans-serif;
text-anchor: middle;
text-align: center;
dominant-baseline: central;
}
.link {
fill: none;
stroke: black;
stroke-width: 1.5;
stroke-opacity: 0.5;
}
body {
overflow: hidden;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<link rel="stylesheet" href="style.css">

</head>
<body>

</body>
<script src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
<script src="https://d3js.org/d3.v6.min.js"></script>
<script src="./src/main.js"></script>
</html>

最佳答案

您始终可以按照自己的方式更改sourcetarget。例如:

.attr("d", d => {
return diagonal({
source: d.source,
target: {
x: d.target.x,
y: d.target.y - RECT_HEIGHT
}
})
});

这样一来,您就可以独立于另一个进行更改,这仅使用路径生成器会比较困难。

这里是你的代码有那个变化:

var data = {
"name": "Eve",
"children": [{
"name": "Cain"
},
{
"name": "Seth",
"children": [{
"name": "Enos"
},
{
"name": "Noam"
}
]
},
{
"name": "Abel"
},
{
"name": "Awan",
"children": [{
"name": "Enoch"
}]
},
{
"name": "Azura"
}
]
};

let width = $(document).width();
let height = $(document).height();
const DX = 80;
const DY = 80;
const MIN_ZOOM = 0.15;
const MAX_ZOOM = Infinity;

const RECT_WIDTH = 40;
const RECT_HEIGHT = 15;
const TRANSITION_DURATION = 700;

let tree = d3.tree().nodeSize([DX, DY]);

let diagonal = d3.linkVertical()
.x(d => d.x + RECT_WIDTH / 2)
.y(d => d.y + RECT_HEIGHT / 2);

function createRoot() {
let root = d3.hierarchy(data);
root.x0 = DX / 2;
root.y0 = 0;
root.descendants().forEach((d, i) => {
d.id = i;
// Auxiliar variable to hide and show nodes when user clicks
d._children = d.children;
// Only the root is displayed at first sight
if (d.depth >= 0) d.children = null;
});
return root;
}

function update(source) {
const nodes = root.descendants().reverse();
const links = root.links();

// Compute the new tree layout
tree(root);

const transition = svg.transition()
.duration(TRANSITION_DURATION)
.tween("resize", window.ResizeObserver ? null : () => () => svg.dispatch("toggle"));

/*=============================NODE SECTION============================== */
// Obtain all the nodes
const node = gNode.selectAll("g")
.data(nodes, d => d.id);

// Enter any new nodes at the parent's previous position.
const nodeEnter = node.enter().append("g")
.attr("class", "node")
.attr("transform", d => `translate(${source.x0},${source.y0})`)
.on("click", function(event, d) {
if (d.children) // Node expanded -> Collapse
collapse(d);
else // Node collapsed -> Expand
d.children = d._children
//If we want to restablish the last state is sufficient to do
//d.children = d.children ? null : d._children;
update(d);
centerNode(d);
})
.attr("pointer-events", d => d._children ? "all" : "none");

nodeEnter.append("rect")
// Two different classes, one for the leafs and another for the others
.attr("class", d => d._children ? "expandable" : "leaf")
.attr("height", RECT_HEIGHT)
.attr("width", RECT_WIDTH)

nodeEnter.append("text")
// The position of the text is centered
.attr("x", RECT_WIDTH / 2)
.attr("y", RECT_HEIGHT / 2)
.text(d => d.data.name)
.clone(true).lower();

// Transition nodes to their new position (update)
node.merge(nodeEnter).transition(transition)
.attr("transform", d => `translate(${d.x},${d.y})`)
// Show the nodes
.attr("fill-opacity", 1)
.attr("stroke-opacity", 1);

/* Transition exiting nodes to the parent's new position */
node.exit().transition(transition).remove()
.attr("transform", d => `translate(${source.x},${source.y})`)
// Hide the nodes
.attr("fill-opacity", 0)
.attr("stroke-opacity", 0);

/*=============================LINK SECTION============================== */
const link = gLink.selectAll("path")
.data(links, d => d.target.id);

// Enter any new links at the parent's previous position
const linkEnter = link.enter().append("path")
.attr("class", "link")
.attr("x", RECT_WIDTH / 2)
.attr("y", RECT_HEIGHT / 2)
.attr("marker-end", "url(#end)") // add the arrow to the link end
.attr("d", d => {
const o = {
x: source.x0,
y: source.y0
};
return diagonal({
source: o,
target: o
});
})

// Transition links to their new position
link.merge(linkEnter).transition(transition)
// In this case the link will be the same but moved by the transition
.attr("d", d => {
return diagonal({
source: d.source,
target: {
x: d.target.x,
y: d.target.y - RECT_HEIGHT
}
})
});

// Transition exiting nodes to the parent's new position
link.exit().transition(transition).remove()
.attr("d", d => {
const o = {
x: source.x,
y: source.y
};
return diagonal({
source: o,
target: o
});
});

// Stash the old positions for transition
root.eachBefore(d => {
d.x0 = d.x;
d.y0 = d.y;
});
}

function centerNode(source) {
let scale = d3.zoomTransform(d3.select("svg").node()).k;
let x = -source.x0 * scale + width / 2 - RECT_WIDTH / 2 * scale;
let y = -source.y0 * scale + height / 2 - RECT_HEIGHT / 2 * scale;
// Define the transition
const transition = svg.transition()
.duration(TRANSITION_DURATION)
.tween("resize", window.ResizeObserver ? null : () => () => svg.dispatch("toggle"));
// Move all the nodes based on the previous parameters
svg.transition(transition)
.call(zoomBehaviours.transform, d3.zoomIdentity.translate(x, y).scale(scale));
}

function collapse(node) {
if (node.children) { // Expanded
node.children = null;
node._children.forEach(collapse)
}
}

// Root creation
const root = createRoot();

// SVG variable that will contain all the configuration for the images.
// We need to append it to the body
const svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);

const g = svg.append("g");

// Two groups: One of links and another of nodes
const gLink = g.append("g");
const gNode = g.append("g");

const zoomBehaviours = d3.zoom()
.scaleExtent([MIN_ZOOM, MAX_ZOOM])
.on('zoom', (event) => g.attr('transform', event.transform));

// Add the zoom so that svg knows that it is available
svg.call(zoomBehaviours);

svg.append("svg:defs").selectAll("marker")
.data(["end"]) // Different link/path types can be defined here
.enter().append("marker") // This section adds in the arrows
.attr("id", String)
.attr("viewBox", "0 -5 10 10")
.attr("refX", 0)
.attr("refY", 0)
.attr("markerWidth", 5)
.attr("markerHeight", 5)
.attr("orient", "auto")
.append("path")
.attr("d", "M0,-5L10,0L0,5");

update(root);
centerNode(root);
.node {
cursor: pointer;
}

.node .expandable {
stroke: black;
stroke-width: 1.2;
fill: lightskyblue;
}

.node .leaf {
fill: lightskyblue;
}

.node text {
fill: black;
font: 10px sans-serif;
text-anchor: middle;
text-align: center;
alignment-baseline: central;
}

.link {
fill: none;
stroke: black;
stroke-width: 1.5;
stroke-opacity: 0.5;
}

body {
overflow: hidden;
}
<!DOCTYPE html>
<html>

<head>
<meta charset="utf-8">
<title></title>
<link rel="stylesheet" href="style.css">

</head>

<body>

</body>
<script src="http://code.jquery.com/jquery-1.10.2.min.js"></script>
<script src="https://d3js.org/d3.v6.min.js"></script>
<script src="./src/main.js"></script>

</html>

关于javascript - 隐藏在矩形内的链接中的箭头,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66638863/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com