3

I can animate an object and then add a mouse:over event.

var canvas = new fabric.Canvas('c');
var x1 = 5;
var y1 = 5;
var x2 = 100;
var y2 = 100;

var rect = new fabric.Rect({
    width: 10,
    height: 10,
    left: x1,
    top: y1,
    stroke: '#000',
    strokeWidth: 2,
    fill: '#faa',
    selectable: false
});
canvas.add(rect);

rect.animate({
    'left': x2,
    'top': y2
}, {
    duration: 10000,
    onChange: canvas.renderAll.bind(canvas),
    onComplete: function() {
    }
});

canvas.on('mouse:over', function (e) {
    console.log('mouseover');
});
<canvas id="c"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.6.3/fabric.min.js"></script>

However the mouse:over event continues to fire from the rectangle's original position. Once the animate finishes then the mouse:over event works again over the animated object.

Is it possible to have a mouse:over event fire while an object is moving/animating?

Jake N
  • 10,535
  • 11
  • 66
  • 112

2 Answers2

1

I wasn't able to figure out a built-in way. You might want to submit this as an issue. In the meantime, I think I have a usable workaround:

// Setup

var canvas = new fabric.Canvas('c');
var x1 = 5;
var y1 = 5;
var x2 = 100;
var y2 = 100;
var rectWidth = 10;
var rectHeight = 10;

var rect = new fabric.Rect({
    width: rectWidth,
    height: rectHeight,
    left: x1,
    top: y1,
    stroke: '#000',
    strokeWidth: 2,
    fill: '#faa',
    selectable: false
});
canvas.add(rect);

rect.animate({
    'left': x2,
    'top': y2
}, {
    duration: 10000,
    onChange: canvas.renderAll.bind(canvas),
    onComplete: function() {
    }
});

// http://stackoverflow.com/questions/17130395/real-mouse-position-in-canvas
function  getMousePos(canvas, evt) {
  var rect = canvas.getBoundingClientRect(), // abs. size of element
      scaleX = canvas.width / rect.width,    // relationship bitmap vs. element for X
      scaleY = canvas.height / rect.height;  // relationship bitmap vs. element for Y

  return {
    x: (evt.clientX - rect.left) * scaleX,   // scale mouse coordinates after they have
    y: (evt.clientY - rect.top) * scaleY     // been adjusted to be relative to element
  }
}

// The important stuff

canvas.on('mouse:move', function (o) {
  var pos = getMousePos(canvas.getElement(), o.e);
  // Do math to figure out if the mouse move was inside the the object. For a Rect:
  if (
    pos.x >= rect.left &&
    pos.x <= rect.left + rectWidth &&
    pos.y >= rect.top &&
    pos.y <= rect.top + rectHeight
  ) {
    console.log('mouseover');
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.6.3/fabric.min.js"></script>
<canvas id="c"></canvas>

Essentially, I listen for mouse:move. On each mouse move, I get the cursor coordinates and check to see if it's inside the shape.

Right now, it's hard-coded to only work on Rects, but perhaps you could introduce a function like isInside(object, pos) which returns a boolean, and in there you can check what type object is and decide based on that.

Frank Tan
  • 4,234
  • 2
  • 19
  • 29
  • Thanks Frank. But ouch, this might get intensive with more objects? – Jake N Jul 20 '16 at 16:46
  • @JakeN That may very well be the case. That's the best workaround I can come up with though. Hopefully someone else can suggest something better, or maybe they'll respond if you report an issue. – Frank Tan Jul 20 '16 at 16:53
0

i realise this topic is very old, but i've just run into the same issue.

after a bit of fiddling, it turned out that calling setCoords() after the object has moved will update the internal state so that mouseover works again correctly.