KineticJS click detection inside animated shapes
Asked Answered
F

2

6

OK, I admit I tried to be clever: I thought if I overrode Shape's drawFunc property I could simply draw whatever inside a rectangle and still use KineticJS's click detection. Here's my attempt:

var shape = new Kinetic.Shape({
  drawFunc: function(context) {
    var id = 26;  // Id of a region inside composite image.
    context.beginPath();
    context.rect(0, 0, w, h);
    context.closePath();
    this.fill(context);
    this.stroke(context);
    context.drawImage(copyCanvas, (id % 8) * w, flr(id / 8) * h, 
        w, h, 0, 0, w / 2, h / 2);
  },
  draggable: true
});

So, the idea was to draw a rectangle, and use drawImage() to draw something on top of the rectangle (like a texture, except it changes from time to time because copyCanvas itself changes). All the meanwhile, I expected event handling (drag-n-drop, in particular) to still 'just work'. Well, here's what happens: the part of the rectangle not covered by my drawImage() correctly detects clicks. However, the one fourth of the rectangle that is covered by the image refuses to respond to clicks! Now, my question is why? I dug into the KineticJS code, and looked to me that click detection simply means drawing to a buffer and seeing if a given x, y point has non-zero alpha. I can't see how this could be affected by my drawing an image on top of my rectangle.

Any ideas what's going on?

Fiore answered 24/10, 2012 at 0:52 Comment(2)
Come on, people, don't tell me I have to dig into the source and answer this myself?! What's the world coming to?Fiore
It's really hard to answer with only the info provided so far. Could you create an example at jsFiddle that shows your problem? (Like this or this) From what I could see in the sources (v4.0.4), getIntersection only considers pixels with alpha === 255 (fully opaque). Drawing an image with some transparency over an opaque shape may or may not reduce the alpha, depending on the context.globalCompositeOperation.Reddin
F
2

OK, so I went ahead and looked at the source code. Here's the definitive answer:

KineticJS assigns a random and unique RGB color to each shape that's created using a global map from RGB colors to shape objects. The draw() function of the shape is called twice: once with the 'real' canvas, and once with a 'buffer' canvas used for hit detection. When using the 'buffer' canvas, KineticJS switches the stroke and fill colors to the unique RGB color of the given shape. The same 'buffer' canvas is used for all shapes on a layer. Thus hit detection simply becomes reading the RGB value of a given point and looking up the corresponding shape in the global map. Now, in my example I drew an image in a way that circumvented KineticJS's juggling of colors used for hit detection. Thus, when I clicked on the image area, KineticJS saw some unknown RGB color on the buffer canvas with no known shape assigned to it.

The solution is not to draw the image for the 'buffer' (or 'hit detection') phase: a simple rectangle will do. In case you're wondering, here's the correct code for the drawFunc:

var width = 200;
var height = 100;
var myShape = new Kinetic.Shape({
  drawFunc: function(context) {
    if (layer.bufferCanvas.context == context) {
      context.beginPath();
      context.rect(0, 0, width, height);
      context.closePath();
      this.fill(context);
      this.stroke(context);
     } else {
       context.drawImage(someCanvasWithAnythingOnIt, 0, 0, width, height,
         0, 0, width, height);
     }
  }});

Can I collect my own reward?

Fiore answered 28/10, 2012 at 20:46 Comment(0)
O
0

I think your problem lies in the order. There is a depth associated with each object that you draw and the default ordering is like a stack, last drawn is on top. Now that you have modified the code, making 2 draws inside the shape draw function, I still think the ordering is preserved and hence, the object is not able to detect the input. Try changing the order, i.e. draw image first and then the rectangle and see if the problem is solved. Else, share a jsFiddle for an example.

Oribella answered 28/10, 2012 at 12:1 Comment(1)
Turns out, no, it's not the problem.Fiore

© 2022 - 2024 — McMap. All rights reserved.