Search code examples
javascripthtmlperformancehtml5-canvaskineticjs

Non-blocking "intersects" in KineticJs


I am in the middle of process of making a HTML5 game. Now I have a problem related to performance.

  • I have some irregular Shapes. So detecting if {x,y} is in the Shape or not using a custom function is near impossible(At least as I think).
  • There are two big Shapes, so I need to call Shape.intersects({x,y}) twice for multiple times per second to detect if current {x,y} is in the shape or not.
  • {x,y} are variable and are not touch/mouse events. So I can not use onmousemove,etc events.
  • Each twice call of Shape.intersects({x,y}) on Nexus 5 has a ~45ms overhead. ~45ms each 100ms! This make some hiccups in game experience.

The most straight solution is to make Shape.intersects({x,y}) non-blocking. But how? or do anyone have any idea around this problem?

I am using Kinetic v5.0.1


RESULT:

.intersects will re-generate the Shape in memory, this is why it is very costly. According the to the @MarkE answer below, using native canvas function context.isPointInPath(x, y) would be very efficient. But:

Note that this will only work for the last path (after using beginPath()). If you need to iterate several paths (ie. shapes) you need to re-construct the paths (no need to stroke or fill though). This is perhaps a reason why some don't use it. Source: https://stackoverflow.com/a/17268669/172163

In my shapes, I had solid colors. Also there are multiple shapes dynamically generated. so I ended up with context.getImageData(x, y, 1, 1) to get the color of specific pixel, and if it is the color of my Shapes are not. It is more efficient than .intersects(). It costs only ~3ms.


Solution

  • Why intersects gives you a performance hit (pun intended!)

    Internally, KineticJS uses context.getImageData to do hit-tests in the intersects method.

    getImageData provides pixel-perfect hit testing but it's slow on mobile devices (as you've discovered).

    To answer your question:

    No, you cannot run KineticJS's internal methods on a background worker thread.

    But...

    If you really need to squeeze performance out of hit-testing, you can write your own custom hit-test.

    One possibility for such a custom hit test would be to maintain 2 offscreen html5 canvas elements that mirror your 2 irregular shapes.

    That way you can use canvas's context.isPointInPath(x,y) to do your hit-testing.

    The importance is that isPointInPath uses GPU acceleration and is therefore quite fast.

    If you feel ambitious you could even create an asynchronous background worker thread to execute isPointInPath while your UI thread continues.

    You mention the Nexus5. You can spawn a background worker thread with Android's AsyncTask.

    Your background task can return the results of your hit-test using it's onPostExecute(Result) callback which invokes on the UI thread.

    http://developer.android.com/reference/android/os/AsyncTask.html

    Good luck with your project!