简体   繁体   中英

Jumping behavior when dragging groups of elements using d3.drag

I can't get rid of the irritating jumping behavior in this example with d3.drag:

https://jsfiddle.net/pmeran/xjp7fyL2/

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <script src="//d3js.org/d3.v4.min.js"></script>
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<script>

var marbleBoxes = [
  { x: 50,  y: 50,  box: "box_01", n: 4, marbles: ["m_01", "m_02", "m_03", "m_04"]},
  { x: 200, y: 50, box: "box_02", n: 1, marbles: ["m_05"]},
  { x: 350, y: 50, box: "box_03", n: 5, marbles: ["m_06", "m_07", "m_08", "m_09", "m_10"]},
  { x: 500, y: 50, box: "box_04", n: 3, marbles: ["m_11", "m_12", "m_13"]}
];

var svg = d3.select("body")
  .append("svg")
  .attr("width", 800)
  .attr("height", 600)
  .attr("class", "svgClass");

var group = svg.selectAll("g")
  .data(marbleBoxes)
  .enter()
  .append("g")
  .attr("class", "gCont")
  .attr("id", function(d,i) {return i;})
  .attr("x", function(d) { return d.x;})
  .attr("y", function(d) { return d.y;})
  .attr("transform", "translate(0,0)");

group.append("rect")
  .attr("id", function(d) { return d.box;})
  .attr("x", function(d) { return d.x;})
  .attr("y", function(d) { return d.y;})
  .attr("height", 80)
  .attr("width", 120)
  .style("fill", "lightgray")
  .attr("class", "rectangle");

for (var i=0; i<4; i++) {
for (var j=0; j<marbleBoxes[i].n; j++ ) {
    var cx = marbleBoxes[i].x;
    console.log(cx);
    var cy = marbleBoxes[i].y;
    document.getElementsByClassName('gCont')[i].innerHTML+= '<circle cx="' + (10+cx) + '" cy="' + (10+cy+15*j) + '" r=7 id=' + marbleBoxes[i].marbles[j] + ' fill="red"></circle>'
}
}

var deltaX = 0;
var deltaY = 0;

var currentStart = [0,0];
var currentEnd = [0,0];

var idOnStart = -1;
var idOnEnd = -1;

var g = d3.selectAll("g")
.datum({
  x: 0,
  y: 0
})
.call(d3.drag()
    .on("start", function(d) {
      console.log('on start [d.x, d.y]', [d.x, d.y]);
      console.log('on start [d3.event.x, d3.event.y]', [d3.event.x, d3.event.y]);
      //idOnStart = d3.select(this).attr("id");
      //if (idOnStart!=idOnEnd) {
      //  console.log("DIFFERENT !");
      //} else {
      //  console.log("IDENTICAL !")}
    })
    .on("drag", function(d) {
      d3.select(this).attr("transform", "translate(" + 
        (d.x = d3.event.x + deltaX) + "," + (d.y = d3.event.y + deltaY) + ")");
    })
    .on("end", function(d) {
      idOnEnd = d3.select(this).attr("id");
    })
);

var b = []
document.addEventListener("click", function(e) {
        var c = e.target
        console.log("This is " + c.id)
        b.push(c.id)
      })


</script>

    
</body>
</html>




Dragging one group works fine. But on the first drag of another group, there is a jump.

I found multiple posts about this problem but wasn't able to use any of the solutions.

Another issue (unrelated to the above and more of stylistic concern): I had trouble to draw circles for subarrays using d3, so I resorted to loops and innerHTML. Effective but not really in the spirit of JS and d3. Suggestions are welcome.

Change your drag callback to:

.on("drag", function(d) {
  const matrix = d3.select(this).node().transform.baseVal.consolidate().matrix; 
  const x = matrix.e + d3.event.dx;
  const y = matrix.f + d3.event.dy;
  d3.select(this).attr("transform", `translate(${x},${y})`);
})

See it's working in the snippet:

 var marbleBoxes = [ { x: 50, y: 50, box: "box_01", n: 4, marbles: ["m_01", "m_02", "m_03", "m_04"]}, { x: 200, y: 50, box: "box_02", n: 1, marbles: ["m_05"]}, { x: 350, y: 50, box: "box_03", n: 5, marbles: ["m_06", "m_07", "m_08", "m_09", "m_10"]}, { x: 500, y: 50, box: "box_04", n: 3, marbles: ["m_11", "m_12", "m_13"]} ]; var svg = d3.select("body").append("svg").attr("width", 800).attr("height", 600).attr("class", "svgClass"); var group = svg.selectAll("g").data(marbleBoxes).enter().append("g").attr("class", "gCont").attr("id", function(d,i) {return i;}).attr("x", function(d) { return dx;}).attr("y", function(d) { return dy;}).attr("transform", "translate(0,0)"); group.append("rect").attr("id", function(d) { return d.box;}).attr("x", function(d) { return dx;}).attr("y", function(d) { return dy;}).attr("height", 80).attr("width", 120).style("fill", "lightgray").attr("class", "rectangle"); for (var i=0; i<4; i++) { for (var j=0; j<marbleBoxes[i].n; j++ ) { var cx = marbleBoxes[i].x; console.log(cx); var cy = marbleBoxes[i].y; document.getElementsByClassName('gCont')[i].innerHTML+= '<circle cx="' + (10+cx) + '" cy="' + (10+cy+15*j) + '" r=7 id=' + marbleBoxes[i].marbles[j] + ' fill="red"></circle>' } } var deltaX = 0; var deltaY = 0; var currentStart = [0,0]; var currentEnd = [0,0]; var idOnStart = -1; var idOnEnd = -1; let startX, startY; var g = d3.selectAll("g").call(d3.drag().on("drag", function(d) { const matrix = d3.select(this).node().transform.baseVal.consolidate().matrix; const x = matrix.e + d3.event.dx; const y = matrix.f + d3.event.dy; d3.select(this).attr("transform", `translate(${x},${y})`); }).on("end", function(d) { idOnEnd = d3.select(this).attr("id"); }) ); var b = [] document.addEventListener("click", function(e) { var c = e.target console.log("This is " + c.id) b.push(c.id) })
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.13.0/d3.min.js"></script>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM