views:

83

answers:

3

I am writing an html5 app which manipulates video on a canvas. I am also showing a custom (self-drawn) mouse cursor over it. To update my app I am calling the setInterval function to draw stuff to the canvas.

As I am manipulating video I need: Very high refresh rates + Lot's of processor time to draw. (~50ms per frame).

My draw function causes my on-mouse function to starve. (this is acceptable by me).

But... After it is finished starving it responds to old events. It can take up to 3 frames for the mouse to catch so that I can render it in the right position. Meaning you can see the cursor "crawling" after you've stopped moving the mouse.

  1. Is there a way to give the onmousemove events a higher priority then my setInterval(drawFunction)?

  2. When in the draw function, Can I "ask" if there are pending mouse events, and revoke my current call to draw?

Is there some-other hack I can use? (I can draw to back-buffer in a webWorker, but as I understand from reading up on html5 this is only thread abstraction [threads are not concurrent] )

+1  A: 

You can't prioritize event handling, at least not directly.

What you might consider would be having your own timer-driven code check for pending mouse events. The mouse event handler would just put a work request into a queue. Your video manipulating could could just check that queue and handle operations as it sees fit. Thus, the real mouse work would also be done in the timer code.

edit Here's what I'm thinking. You'd still have handlers for your mouse events:

var eventQueue = [];

canvasElement.onmousemove = function(evt) {
  evt = evt || event;
  eventQueue.push({ type: evt.type, x: evt.clientX, y: evt.clientY, when: new Date() });
};

Thus the mouse handlers would not do any actual work. They just record the details in a list of events and then return.

The main, timer-driven loop can then just check the queue of events and decide what to do. For example if it sees a whole string of "mousemove" events, it could compute the net change in position over all of them and update the cursor position just once.

Pointy
This would solve my problem. But how would I check for pending mouse events? I failed to find an API for this. I can only get mouse coordintes through events.
eshalev
You'd still have handlers for your mouse events - I'll update my answer.
Pointy
This solution will not help. The problem is that my onmousemove function is not being called until the end of my setTimer function. Also as far as I can see the next setTimer function will be called before the onMouse event. Now, if I could know that there are unhandled mouse events then I could skip my setTimer function.
eshalev
Well you might want to use `setTimeout()` instead of `setInterval()`. When you use `setTimeout()`, you can guarantee that you'll leave a gap between one iteration of your timed loop and the next. During that gap, mouse events can get through and be handled by the small, fast handler as I suggested.
Pointy
Oh, and of course if you switch to `setTimeout()`, then the timer function itself must set up its next trigger by another call to `setTimeout()`.
Pointy
A: 

You certainly can use a Web Worker to manipulate your pixels in the background. Web Workers do run concurrently. It doesn't seem to be part of the spec, but every implementation runs workers in a separate process. So your main script will be responsible for updating your custom cursor, but you'd pass the canvas ImageData off to the background worker for the video processing. Note that you can't send an actual Canvas or Context to the worker, as workers have no DOM access.

Angiosperm
A: 

There is no way to give events higher priority, they seem to be serviced on a first come, first serve basic. Assuming you are using setTimeout, one thing that might help though is to break up your tasks into smaller restartable chunks, e.g. if you are processing an image like this:

for(y=0; y<height; y++) {
   // Deal with rows of pixels
}
// Show image

You could do this instead:

var INTERVAL = height/4;

for(y = old_y; y<height && y<old_y+INTERVAL ; y++) {
  // Deal with row of pixels
}
if (y == height) {
  // show image
}
old_y = (y == height) ? 0 : y;

Then the other events will have 4x (or whatever, depending on the INTERVAL) greater chance of being dealt with.

andrewmu