Elm 中的全屏、可调整大小的画布在页面加载时不可见



我正在使用Elm 0.19和joakin/elm-canvas包。

我所要做的就是绘制一个跨越屏幕整个宽度和高度的画布,并随着窗口大小的变化动态调整大小。我花了几个小时进行调试和研究,但我只是卡住了。 我已经尝试了多种实现,我可以让它工作,但不是在初始页面加载时。 相反,它仅在调用更新函数后呈现。 我觉得我错过了一些明显的东西,因为我对Elm还很陌生。

这是显示问题的工作 Ellie 代码/演示的链接:https://ellie-app.com/6JZDxnQWPLSa1 请注意,在按键事件触发更新之前,屏幕是空白的,然后显示画布。

编辑:从艾莉演示中添加代码。

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 ]
]
]

这里有一个工作的例子:https://ellie-app.com/6KrhJjGLwc5a1。它闪烁了一下,但画布在调整大小时进行了调整。这篇文章帮助我找到了这个解决方法。

我在模型中添加了一个busy道具:

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

我添加了一个PostScreenSize,以强制视图在完成后重新加载ScreenSize

ScreenSize w h ->
( { model | screen = { width = w, height = h }, busy = True }
, delay PostScreenSize
)
PostScreenSize ->
( { model | busy = False }
, Cmd.none
)

最新更新