rive-react icon indicating copy to clipboard operation
rive-react copied to clipboard

`onDraw` doesn't trigger

Open smblee opened this issue 2 years ago • 14 comments

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?

smblee avatar Jun 22 '23 20:06 smblee

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?

zplata avatar Jun 26 '23 15:06 zplata

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 avatar Jun 26 '23 20:06 smblee

@zplata any feedback above?

smblee avatar Jul 03 '23 19:07 smblee

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.

zplata avatar Jul 03 '23 19:07 zplata

@zplata That would be very useful!

smblee avatar Jul 03 '23 19:07 smblee

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

zplata avatar Jul 03 '23 19:07 zplata

@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

smblee avatar Jul 09 '23 22:07 smblee

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

zplata avatar Jul 10 '23 13:07 zplata

@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.

smblee avatar Jul 13 '23 01:07 smblee

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/

zplata avatar Jul 14 '23 16:07 zplata

@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 avatar Jul 17 '23 18:07 smblee

@zplata small nudge on the progress 👀

smblee avatar Jul 24 '23 18:07 smblee

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

zplata avatar Jul 24 '23 18:07 zplata

@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

smblee avatar Jul 24 '23 19:07 smblee