elm-canvas
elm-canvas copied to clipboard
Fullscreen, resizable canvas – not visible on page load
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 ]
]
]
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.
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.
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.
Also, I feel like maybe the animation in the game example, much like firing off keypresses in mine, is somehow masking the issue.