我正在尝试建立一个'clickToZoom'函数。在节点单击时,视图应该关注被单击的节点。event.transform
对象返回{k, x, y}
。到目前为止,我认为我可以从被单击的节点接收这些值并设置svg.attr("transform", "newValues")
,我确实这样做了。显然它不像预期的那样工作。
景色确实改变了,但似乎重新设定了。
var width = window.innerWidth,
height = window.innerHeight;
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.call(d3.zoom().on("zoom", function (event) {
svg.attr("transform", event.transform)
console.log(event.transform)
}))
.append("g")
////////////////////////
// outer force layout
var data = {
"nodes": [{
"id": "A",
},
{
"id": "B",
},
{
"id": "C",
},
{
"id": "D",
},
{
"id": "E",
},
{
"id": "F",
},
{
"id": "G",
},],
"links": [{
"source": "A",
"target": "B"
},
{
"source": "B",
"target": "C"
},
{
"source": "C",
"target": "D"
},
{
"source": "D",
"target": "E"
},
{
"source": "E",
"target": "F"
},
{
"source": "F",
"target": "G"
},]
}
var simulation = d3.forceSimulation()
.force("size", d3.forceCenter(width / 2, height / 2))
.force("charge", d3.forceManyBody().strength(-5000))
.force("link", d3.forceLink().id(function (d) {
return d.id
}).distance(250))
linksContainer = svg.append("g").attr("class", "linkscontainer")
nodesContainer = svg.append("g").attr("class", "nodesContainer")
links = linksContainer.selectAll(".linkPath")
.data(data.links)
.enter()
.append("path")
.attr("class", "linkPath")
.attr("stroke", "red")
.attr("fill", "transparent")
.attr("stroke-width", 3)
nodes = nodesContainer.selectAll(".nodes")
.data(data.nodes, function (d) {
return d.id;
})
.enter()
.append("g")
.attr("class", "nodes")
.call(d3.drag()
.on("start", dragStarted)
.on("drag", dragged)
.on("end", dragEnded)
)
.on("click", function(d) {
//d3.zoomTransform(d3.select(this))
let nodeX = d.srcElement.__data__.x
let nodeY = d.srcElement.__data__.y
zoomToNode(nodeX, nodeY)
})
nodes.selectAll("circle")
.data(d => [d])
.enter()
.append("circle")
.attr("class", "circle")
.style("stroke", "blue")
.attr("r", 40)
simulation
.nodes(data.nodes)
.on("tick", tick)
simulation
.force("link")
.links(data.links)
function tick() {
links.attr("d", function (d) {
var dx = (d.target.x - d.source.x),
dy = (d.target.y - d.source.y),
dr = Math.sqrt(dx * dx + dy * dy)
return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y;
})
nodes
.attr("transform", d => `translate(${d.x}, ${d.y})`);
}
function dragStarted(event, d) {
if (!event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
function dragged(event, d) {
d.fx = event.x;
d.fy = event.y;
}
function dragEnded(event, d) {
if (!event.active) simulation.alphaTarget(0);
d.fx = null;
d.fy = null;
}
function zoomToNode(thisX, thisY) {
let transformValue = {"k": 2, "x": thisX, "y": thisY}
console.log(transformValue)
svg.attr("transform", transformValue)
svg.attr("transform", event.transform)
}
.link {
stroke: #000;
stroke-width: 1.5px;
}
.nodes {
fill: whitesmoke;
cursor: pointer;
}
.buttons {
margin: 0 1em 0 0;
}
<!DOCTYPE html>
<html lang="de">
<head>
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0">
<meta charset="utf-8">
<!-- jQuery -->
<script src="https://code.jquery.com/jquery-3.6.3.js"></script>
<!-- D3 -->
<script src="https://d3js.org/d3.v7.min.js"></script>
<!-- fontawesome stylesheet https://fontawesome.com/ -->
<script src="https://kit.fontawesome.com/98a5e27706.js" crossorigin="anonymous"></script>
</head>
<body>
</body>
</html>
1条答案
按热度按时间svmlkihl1#
这个example对于您想要的结果有合理的效用。基于此对您的原始更改是:
d3.zoom
分配给变量,而不是在创建svg
时调用它svg
的第一个g
分配给一个单独的变量,然后将linksContainer
和nodesContainer
附加到该g
zoom
引用作用于此g
,而不是svg
。然后,您可以在点击处理程序中使用Observable中的代码(签名为
function(event, d)
):字符串
"重置“是因为使用
svg.attr("transform", ..some translation..)
不会更新缩放,所以在设置此变换后再次平移/缩放时,它会重置为使用普通zoom
时的最后一个点。单击处理程序逻辑调用
zoom.transform
并将缩放设置为1.2(您可以调整),并相对于单击节点的x
和y
进行平移。如果在
click
处理程序中使用function(event, d)
的签名,则可以比通过event
更容易地引用d
的坐标。