maxence-charriere / go-app

A package to build progressive web apps with Go programming language and WebAssembly.
https://go-app.dev
MIT License
7.75k stars 354 forks source link

Load static files to Canvas #927

Closed riprsa closed 3 months ago

riprsa commented 3 months ago

First of all, thank you for this package. It is soo cool that I can write Go code for browsers!

I am writing a simple bullet-hell game. I almost finished basic logic and now want to add textures. However, I do not understand how to add an image to Canvas.

I have a variable of type app.HTMLImg, which is initialised with image := app.Img().Src("/web/assets/rat.png"). I tried to render only the image as a separate component and it works, so issue is not with an empty variable. Also I can locate it by path through address bar.

I cannot figure out how to use this image variable with context2D.Call("drawImage", image, 0, 0). I also tried to use image.JSValue(), but it did not help. I get this error:

panic: JavaScript error: Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The provided value is not of type '(CSSImageValue or HTMLCanvasElement or HTMLImageElement or HTMLVideoElement or ImageBitmap or OffscreenCanvas or SVGImageElement or VideoFrame)'.

I have no idea how to correctly get drawImage to work.

oderwat commented 3 months ago
    cvEl := app.Window().GetElementByID(c.Id)
    cvCtx := cvEl.Call("getContext", "2d")
    c.done = make(chan struct{})
    img := app.Window().Get("document").Call("createElement", "img")
    img.Set("src", "/web/logo-512.png")
    //app.Window().Get("document").Get("body").Call("appendChild", img)
    img.Call("addEventListener", "load", app.FuncOf(func(app.Value, []app.Value) interface{} {
        dbg.Log("image is loaded")
        ctx.Async(func() {
            var renderFrame app.Func
            c.running = true
            renderFrame = app.FuncOf(func(this app.Value, args []app.Value) interface{} {
                if c.running {
                    app.Window().Call("requestAnimationFrame", renderFrame)
                } else {
                    close(c.done)
                }
                cvCtx.Call("drawImage", img, 0, 0)
                return nil
            })
            defer renderFrame.Release()
            // start the rendering
            app.Window().Call("requestAnimationFrame", renderFrame)
            // wait till the channel gets closed
            <-c.done
            dbg.Log("closed")
        })
        return nil
    }))
riprsa commented 3 months ago

Works like a charm, thank you!