rive-app/rive-react

`onDraw` doesn't trigger

smblee opened this issue · 14 comments

smblee commented

I noticed one of the EventType is Draw but can't seem to get any callbacks.

    rive.on(EventType.Draw, (ctx) => {
      console.log(ctx);
    });

^ this is the code i am running. I can't really find much documentation around this either.

Does this properly not exist?

zplata commented

Hi @smblee - I don't believe this is an exposed event you can subscribe to. Mind sharing where you found this property so we can fix up documentation?

smblee commented

Found it in the typescript definition. I believe it's an existing Enum under EventType

Then are there any similar event i can subscribe to without opting to the advanced libraries? I just need to add some frame color detection every screen without interfering with the actual render itself

smblee commented

@zplata any feedback above?

zplata commented

Ahh I see what you mean - our Android and iOS runtimes have a concept of reporting back at the end of a render loop/frame after it has drawn onto the canvas/texture. We can provide an onAdvance / EventType.Advance that you can hook into similarly if that might be of help here? It'll need to be added to the rive-wasm web runtime first then propagated here.

smblee commented

@zplata That would be very useful!

zplata commented

Cool - will comment on this thread once that lands. Thanks for bringing this up!

smblee commented

@zplata thanks! Do you know the ETA for this? I can also try to contribute if you can point me to the best place to hook into the render loop

zplata commented

We should target having this change land downstream on rive-wasm this week - from there, it should be a quick update to React

smblee commented

@zplata while at this, is it possible to also add a hook to draw different elements during the canvas draw cycle? (Without having to ditch the whole React library and use the raw canvas lib)

I am imagining adding some hooks to mainAnimationCallback function in animation_callback_handler (https://github.com/rive-app/rive-wasm/blob/9bb60e900f3dcdcef0c8b6314fc3698a316a0c84/wasm/js/animation_callback_handler.js#L28)

like (super trivial example)

    function mainAnimationCallback(time) {
        // Snap off and reset the sub-callbacks first, since they might call requestAnimationFrame
        // recursively.
        const flushingSubCallbacks = _animationSubCallbacks;
        _mainAnimationCallbackID = 0;
        _lastAnimationSubCallbackID = 0;
        _animationSubCallbacks = new Map();

        // Invoke all pending animation callbacks.
        flushingSubCallbacks.forEach((callback) => {
            try {
                callback(time);
            } catch (err) {
                console.error(err);
            }
        });

+      this.onFrameDraw(context); // pass anything else that could be useful
        this.onAfterCallbacks();


        if (_fpsCounter) {
            _fpsCounter.frameComplete();
        }
    }

And consume it like

rive.onFrameDraw((ctx) => {
  // draw other dynamic stuff outside of rive
  ctx.beginPath();
  ...
  
  if (... game logic ...) { ... }
})

Would love to leverage the existing React niceties like screen resize, fit, start/reset functions, and etc.

My use case here is drawing the mouse cursor location every frame to customize the look of the mouse within the canvas, and also check for collision detection.

zplata commented

Hi! Sorry for the delay - just as an update, we've landed the onAdvance downstream, but will need a few more days to get a separately even lower-level cpp issue fixed up. Will make sure to release to React as soon as we've got that in.

Regarding your other comment, there isn't a straightforward way to hook into when individual elements draw. The mainAnimationCallback is mainly for coordinating some offscreen canvases that might handle raster/mesh assets. You should be able to achieve what you're looking for however in the Rive editor using Rive Listeners (Pointer Move associated with a target node, and Pointer Enter for the node you want to have hit detection for). Here's a community example showing this: https://rive.app/community/4761-9624-maze-game/

smblee commented

@zplata Thanks for getting around to this.

i think the problem with pointer based events (whether within rive or within the code) is the events don't trigger until the mouse actually "moves".

E.g. https://rive.app/community/3571-7464-tunnel-dodger/ if you don't move your cursor at all, the collision detection actually won't get triggered even upon collision.

This is why I need to run the collision detection upon every frame render using a separate state to track the cursor position. With the onAdvance hook I should be able to do this. If you have some other ideas on this it would be greatly appreciated!

smblee commented

@zplata small nudge on the progress 👀

zplata commented

Oh sorry, I totally dropped the ball on updating this thread - should be in v3.0.55+!

smblee commented

@zplata amazing! Thank you. Could you also comment on my comment above? What are your thoughts on best way to resolving that collision detection? Maybe the new onAdvance hook would work i can give a try