Search code examples
javascriptraphael

Detect snap to grid in Raphael only once per left coordinate


In this jsFiddle I have a Raphael canvas with a rect that can be moved around. The rect snaps to the vertical lines when it is moved to the left.

If you take a look at the console log, you will see that the rect snaps to the same vertical line many times, and in my code I need to get this event only once per vertical line.

For example in the log you should see:

snapped to 280
snapped to 240
snapped to 200

Instead, it displays each row many times.

If I add these lines:

 if (last_snap == i)
      return;

It shows one line for each snap, however the rect bounces back and forth.

Any ideas how to make this work?

var w = 500,
    h = 340;
var paper = Raphael("the_canvas", w, h);

// draw vertical lines
for (var i = 0; i < 14; i++) {
  paper.path('M' + (i * 40) + ' ' + 0 + 'L' + (i * 40) + ' ' + 300).attr({
    'stroke': 'black'
  });
}

var rect = paper.rect(280, 40, 80, 40);
rect.attr({
  'fill': 'black',
  'cursor': 'move'
});


var ox = 0,
    oy = 0,
    lastdx = 0,
    lastdy = 0;
var last_snap = -9999;

var start = function() {
  ox = rect.attr("x");
  oy = rect.attr("y");
};

var move = function(dx, dy) {

  if (lastdx !== dx)
    rect.attr("x", ox + dx);

  rect.attr("y", oy + dy);

  if ((dx - lastdx) < 0) {
      seeMoveLeft(rect);
  }

  lastdx = dx ;
};

var up = function() {};

rect.drag(move, start, up);

var seeMoveLeft = function(rect) {

  var left = rect.attr('x');  
  var found = false;
  var min = left - 40;
  for (var i = left; i >= min; i--) {
    if (i % 40 == 0) {
      found = true;
      break;
    }
  }

 /*  if (last_snap == i)
      return;
  */

  if (found) {
      rect.attr('x', i);
      last_snap = i;
      console.log("snapped to " + i)
   }      
}

Solution

  • Update last_snap only when it's different from i. Every repeated iteration should be ignored. If you skip setting x too it will start bouncing as expected.

      if (found) {
          rect.attr('x', i);
          if (last_snap == i) return;
    
          console.log("snapped to " + i);
          last_snap = i;
       }   
    

    https://jsfiddle.net/4k5z0avu/