Skip to content
Advertisement

D3v6 get g element position

I am trying to retrieve the x, y position for the “g” element of the nodes. As provided in the screenshot a browser inspector gets the transform="translate(x,y)" values and I want to return those in a console.log too. To do so I added a .on("click", getPosition) function and tried different approaches. Unfortunately the official D3.js API removed d3.transform without any replacement explanation.

What I am hoping to get from stackoverflow is a practical example, as I am lost.

enter image description here

Code snippet:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <title>D3v6 Pack</title>
    <script src="https://d3js.org/d3.v6.min.js"></script>
</head>

<style>
    body {
        background-color: #e6e7ee;
    }

    circle {
        fill: whitesmoke;
        stroke: black;
        stroke-width: 1px;
    }
</style>

<body>
    <script>
        var svg = d3.select("body").append("svg")
            .attr("width", window.innerWidth)
            .attr("height", window.innerHeight)
            .attr("class", "svg")
            .call(d3.zoom().on("zoom", function (event) {
                svg.attr("transform", event.transform)
            }))
            .append("g")

        var linkContainer = svg.append("g").attr("class", "linkContainer")
        var nodeContainer = svg.append("g").attr("class", "nodeContainer")

        var data = {
            "nodes": [
                { "id": "A" },
                { "id": "B" },
                { "id": "C" },
                { "id": "D" }
            ],
            "links": [
                { "source": "B", "target": "A" },
                { "source": "C", "target": "A" },
                { "source": "D", "target": "A" }
            ]
        }

        var force = d3.forceSimulation()
            .force("link", d3.forceLink().id(function (d) {
                return d.id;
            }).distance(200))
            .force("charge", d3.forceManyBody().strength(-650))
            .force("center", d3.forceCenter(window.innerWidth / 2, window.innerHeight / 2))
            .force("collision", d3.forceCollide().radius(50))

        var links = linkContainer.selectAll(".link")
            .data(data.links)
            .join("line")
            .attr("class", "link")
            .style("stroke", "black")
            .style("opacity", 0.2)

        var nodes = nodeContainer.selectAll(".node")
            .data(data.nodes, function (d) { return d.id; })
            .enter()
            .append("g")
            .attr("class", "node")
            .attr("id", function (d) { return d.id; })
            .on("click", getPosition)
            .call(d3.drag()
                .on("start", dragStarted)
                .on("drag", dragged)
                .on("end", dragEnded)
            )

        nodes
            .append("circle")
            .attr("r", 40);

        force
            .nodes(data.nodes)
            .on("tick", tick)

        force
            .force("link")
            .links(data.links)




        function getPosition(event, d) {
            
            var xPos = "xPos from any node"
            
            //var xPos = this.x
            //var xPos = d3.select("#A").svg.x
            //var xPos = d3.select("#A").transfor.x
            //var xPos = d3.select("#A").transform.translate[0]
            //var xPos = d3.select("#A").translate[0]
            //var xPos = d3.select("#A").x
            
            console.log(xPos)
        }



        function tick() {
            links
                .attr("x1", function (d) {
                    return d.source.x;
                })
                .attr("y1", function (d) {
                    return d.source.y;
                })
                .attr("x2", function (d) {
                    return d.target.x;
                })
                .attr("y2", function (d) {
                    return d.target.y;
                });

            nodes.attr("transform", function (d) {
                return "translate(" + d.x + "," + d.y + ")";
            });
        }

        function dragStarted(event, d) {
            if (!event.active) force.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) force.alphaTarget(0);

            d.fx = undefined;
            d.fy = undefined;
        }

    </script>
</body>

</html>

Advertisement

Answer

This code works:

function getPosition(event, d) {
  const element = d3.select(this);
  const val = element.attr('transform').split(/[s,()]+/);
  const x = parseFloat(val[1]);
  const y = parseFloat(val[2]);
  console.log(x, y)
}

You can see it in a fiddle

Advertisement