Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how do you interpret the d3 event.x and event.y coordinates?

I'm trying to implement drag events in d3 (v6.2), and I'm having some trouble interpreting the d3 x and y coordinates. Consider the following code. When I inspect the console output, it seems to me like, in the drag handler:

  • event.x and event.y are the SUM of the user (graph) coordinate object locations and the total movement/distance in SVG coordinates?

  • event.dx and event.dy are indicator that tell you whether since the last update, you've moved left/up (-1), not moved (0), or right/down (1)?

  • event.subject.x and event.subject.y give the location of the object being dragged?

  • if I want the current coordinates of the drag (either in user/graph coordinates or SVG coordinates), I need to calculate them myself (see example in code, which seems to work)?

I can't find where the specifics of this are documented. My questions are:

  1. Are the above impressions correct?
  2. If not correct, what's the best way to get the current drag coordinates?
  3. If correct, why would one SUM the values from two different coordinate systems? That doesn't make sense to me.
<html>
<body>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/6.2.0/d3.min.js"></script>
<svg width="500" height="300"></svg>

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

<script>

function dragHandler(e, d){
    
    const objx = scaleX.invert(e.x - d.x + scaleX(d.x))
    const objy = scaleY.invert(e.y - d.y + scaleY(d.y))

    console.log(`x: ${e.x}, dx: ${e.dx} sx: ${e.subject.x} objx: ${objx}\ny: ${e.y} dy: ${e.dy} sy: ${e.subject.y} objy: ${objy}`)
}

var drag = d3
 .drag()
 .on('drag', dragHandler)

var x = [{x: 150, y: 150}]

var svg = d3.select("svg")

var margin = {
  top: 20,
  right: 80,
  bottom: 30,
  left: 50
}
var width = svg.attr("width") - margin.left - margin.right
var height = svg.attr("height") - margin.top - margin.bottom

g = svg.append("g").attr("transform", "translate(" + margin.left + "," + margin.top + ")")

var scaleX = d3.scaleLinear().range([0, width]).domain([140, 160])
var scaleY = d3.scaleLinear().range([height, 0]).domain([140, 160])

g.append("g")
  .attr("class", "axis axis--x")
  .attr("transform", "translate(0," + height + ")")
  .call(d3.axisBottom(scaleX));

g.append("g")
  .attr("class", "axis axis--y")
  .call(d3.axisLeft(scaleY))

var circ = g.selectAll(".circ")
  .data(x)
  .enter()
  .append("circle")
  .attr("r", 5)
  .attr("cx", function(d) { return scaleX(d.x) })
  .attr("cy", function(d) { return scaleY(d.y) })
  .attr("class", "circ")
  .call(drag);

</script>

</body>
<html>
like image 800
richarddmorey Avatar asked Oct 15 '25 05:10

richarddmorey


1 Answers

Your impression is right. You can either

  • compute the distance in local coordinates as the difference between event.x/y and event.subject.x/y
  • retrieve the screen distance with event.clickDistance() as a getter

These two work in different coordinate systems.

  • The client coordinate system is that of the browser viewport. They are just read from the native DOM mousemove event.
  • The user coordinate system is the one of the thing being dragged, using the same coordinates as those used when writing SVG markup. They are computed from the client coordinates with a transform matrix the SVG API provides. The source code is here.

What you did was the in-between way that normally is not needed: by applying the scaleX/Y transform, you computed the coordinates in the system of the SVG viewBox, i. e. the coordinate system that is found when the viewBox is applied to the outermost <svg> element. That can be the client coordinate system, but only if the attribute is not set, or the width and height values of the element match the contents of the viewBox.

In almost every practical use case, the two will differ. The "Scalable" in SVG is just about that distinction. Leaving out the viewBox like you did deprives you of the possibility to easily scale your grafic as a whole.

like image 67
ccprog Avatar answered Oct 16 '25 20:10

ccprog