I am trying to establish a 'clickToZoom' function. On node click the view should focus the clicked node. The event.transform
object returns {k, x, y}
. So far I thought I can receive those values from the clicked node and set the svg.attr("transform", "newValues")
, which I do. Obvously it does not work like expected.
The view does change but seems to reset.
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>
from D3 force graph - zoom to node
No comments:
Post a Comment