joakin / elm-canvas

A canvas drawing library for Elm
https://package.elm-lang.org/packages/joakin/elm-canvas/latest/
BSD 3-Clause "New" or "Revised" License
163 stars 30 forks source link

Fullscreen, resizable canvas – not visible on page load #10

Open toakleaf opened 4 years ago

toakleaf commented 4 years ago

I'm trying to draw a canvas that spans the entire width and height of the window and resizes dynamically when the window size changes. However, the canvas isn't getting painted on the initial page load, but only on subsequent updates. I've tried multiple implementations but the same problem keeps recurring.

Here's an Ellie showing the issue. Notice how the screen is blank until after a keypress event fires the update, and then the canvas appears.

As a work-around, I can change the screen record into a Maybe, however that just shifts the problem from occurring on initial screen load to on resize.

And just for the sake of good record-keeping here's the code from the Ellie linked above:

module Main exposing (..)

import Browser
import Browser.Dom exposing (Viewport, getViewport)
import Browser.Events exposing (onKeyDown, onResize)
import Canvas exposing (..)
import Canvas.Settings exposing (..)
import Canvas.Settings.Advanced exposing (..)
import Color
import Html exposing (Html, div)
import Html.Attributes exposing (style)
import Json.Decode as Decode
import Task

main : Program () Model Msg
main =
    Browser.element
        { init = init
        , view = view
        , subscriptions = subscriptions
        , update = update
        }

-- MODEL

type alias Model =
    { screen : { width : Int, height : Int }
    }

init : () -> ( Model, Cmd Msg )
init _ =
    ( { screen = { width = 800, height = 600 }
      }
    , Task.perform (\{ viewport } -> ScreenSize (round viewport.width) (round viewport.height)) getViewport
    )

-- UPDATE

type Msg
    = TurnLeft
    | TurnRight
    | MoveForward
    | Other
    | ScreenSize Int Int

update : Msg -> Model -> ( Model, Cmd Msg )
update msg model =
    case msg of
        TurnLeft ->
            ( model, Cmd.none )

        TurnRight ->
            ( model, Cmd.none )

        MoveForward ->
            ( model, Cmd.none )

        ScreenSize w h ->
            ( { model | screen = { width = w, height = h } }
            , Cmd.none
            )

        Other ->
            ( model, Cmd.none )

-- SUBSCRIPTIONS

subscriptions : Model -> Sub Msg
subscriptions model =
    Sub.batch
        [ onKeyDown keyDecoder
        , onResize ScreenSize
        ]

keyDecoder : Decode.Decoder Msg
keyDecoder =
    Decode.map toDirection (Decode.field "key" Decode.string)

toDirection : String -> Msg
toDirection string =
    case string of
        "ArrowLeft" ->
            TurnLeft

        "ArrowRight" ->
            TurnRight

        "ArrowUp" ->
            MoveForward

        _ ->
            Other

-- VIEW

clearScreen : Float -> Float -> Renderable
clearScreen width height =
    shapes [ fill Color.black ] [ rect ( 0, 0 ) width height ]

view : Model -> Html Msg
view { screen } =
    div
        [ style "display" "flex"
        , style "justify-content" "center"
        , style "align-items" "center"
        ]
        [ Canvas.toHtml
            ( screen.width, screen.height )
            []
            [ clearScreen (toFloat screen.width) (toFloat screen.height)
              , shapes [ fill Color.red ] [ rect ( 30, 30 ) 200 200 ]
            ]
        ]
joakin commented 4 years ago

Very strange!

This would be a great feature to add to the Fullscreen.elm example once we figure it out.

I’m in the move and checked the Ellie on the phone, and what I see is multiple resize events being triggered with the size increasing each time. I see the canvas flicker black and red to white to finally nothing.

Do you see multiple resize events too? If you do it may be that changing the canvas dimensions is re-triggering a resize event for some reason.

joakin commented 4 years ago

I have a game example that does full screen and resizes and doesn’t seem to have a problem: https://github.com/joakin/elm-basic-platformer-game/blob/master/src/Main.elm

The setup seems very similar, so I’m not sure what may be going wrong.

toakleaf commented 4 years ago

In the Ellie debugger, I only see singular updates to the Model when resizing screen by a single pixel. However, you're correct that it does seem like the canvas gets drawn every time and then erased, as it flashes on screen before going white. I have a pretty busy day, but if I can find the time I'll try making a copy of your game and pairing it back to just a blank canvas to see if I can spot the problem.

toakleaf commented 4 years ago

Also, I feel like maybe the animation in the game example, much like firing off keypresses in mine, is somehow masking the issue.