wyc
wyc

Reputation: 55283

Initial "jumpy" dragging behavior

The following code creates a background and a rectangle. The rectangle can be dragged:

var p = {
  x: 0,
  y: 0
} 

var width = 400
var height = 400

var svg = d3.select('body').append('svg')
  .attr('width', width)
  .attr('height', height)

svg.append('rect')
  .attr('class', 'bg')
  .attr('width', width)
  .attr('height', height)

var drag = d3.behavior.drag()
  .on('drag', dragmove)

svg.append('rect')
  .attr('class', 'btn')
  .attr('width', 100)
  .attr('height', 50)
  .attr('transform', 'translate(' + p.x + ',' + p.y + ')')
  .call(drag)

function dragmove (d) {
  var x = d3.event.x
  var y = d3.event.y
  d3.select(this)
    .attr('transform', 'translate(' + x + ',' + y + ')')
}

The dragging event works, but there's an initial "jump" each time I drag the object (e.g the rectangle starts on the left of the cursor and then suddenly jumps to the right).

You can see it here: https://jsfiddle.net/alexcheninfo/5rnv7ww5/

What is causing it and how to prevent it (make the rectangle being dragged smoothly from the beginning)?

Upvotes: 2

Views: 651

Answers (3)

bergee
bergee

Reputation: 121

For those who struggling this, my 50 cents. In d3 js v7 there is no event.dx or event.dy properties, instead you have to read event.movementX and event.movementY properties. Here is my working code (I only needed x position). The getTokenizedTransformAttributeValue method is taken from here: https://www.it-swarm-es.com/es/javascript/sustitucion-de-d3.transform-en-d3-v4/825493251/

self=this; 
const consty = 100; //example
let dragHandler = this.d3.drag()
     .on("drag", function() {
          const inputTrasformString = self.d3.select(this).attr("transform");
          var transformObject = self.getTokenizedTransformAttributeValue(inputTrasformString);     
          x = event.movementX+parseInt(transformObject.translate[0])
                     
          self.d3.select(this)
              .attr("transform", "translate("+x+","+consty+")");
          }).on("start",function() {
        //something
                }).on("end", function() {
        //something
              });
            
dragHandler(svg.select(".myclass"));

Upvotes: 1

eagor
eagor

Reputation: 10035

you need to specify origin of the drag behaviour. By default the underlying data object is used. In you case - it's the p object. So you would need to do this:

var drag = d3.behavior.drag()
    .origin(function() { return p; })
    .on('drag', dragmove)

and update it's x and y properties on every drag

function dragmove (d) {
    // ...
    // normally you would update d.x and d.y
    p.x = d3.event.x;
    p.y = d3.event.y;
    // ...
}

See updated fiddle.

In d3 v4 this is called drag subject.

Upvotes: 1

Cyril Cherian
Cyril Cherian

Reputation: 32327

It should be this way:

//get the translate on the dragged rectangle
var translate = d3.transform(d3.select(this).attr("transform")).translate;
//to that add the mouse move deltax 
                x = d3.event.dx + translate[0],
                y = d3.event.dy + translate[1];

working code here

when you do

var x = d3.event.x
  var y = d3.event.y
  d3.select(this)
    .attr('transform', 'translate(' + x + ',' + y + ')')

It will translate the rectangle to the mouse position thus the jump.

Upvotes: 4

Related Questions