Elm resizeable SVG canvas filling the screen
August 26, 2016 [Elm, Games, JavaScript, Programming, Programming Languages]I am toying with writing an SVG-based game in (exciting-looking JavaScript-replacement) Elm, and I wanted an SVG that filled the whole screen and resized when the screen resized. I found it harder than I expected, so here is what I came up with for your information and comment.
Because I was using Html.App.programWithFlags I was not able to shortcut the process and use just elm-reactor - I needed to create an HTML file and compile my code with elm-make.
index.html sets up a full-screen app and passes in the window size:
<!DOCTYPE HTML> <html> <head> <meta charset="UTF-8"/> <title>Sootl</title> <script src="sootl.js"></script> <style> html, body, svg { margin: 0px; padding: 0px; border: 0px; overflow: hidden; } </style> </head> <body> </body> <script> var app = Elm.Main.fullscreen( { width: window.innerWidth, height: window.innerHeight } ); </script> </html>
elm-package.json requires the Html, Svg and Window packages:
{ "version": "1.0.0", "summary": "Stay out of the light!", "repository": "https://github.com/andybalaam/sootl.git", "license": "GPL2", "source-directories": [ "." ], "exposed-modules": [], "dependencies": { "elm-lang/core": "4.0.5 <= v < 5.0.0", "elm-lang/html": "1.1.0 <= v < 2.0.0", "elm-lang/svg": "1.1.1 <= v < 2.0.0", "elm-lang/window": "1.0.0 <= v < 2.0.0" }, "elm-version": "0.17.1 <= v < 0.18.0" }
Main.elm contains the Elm code, which starts off with the window size from JavaScript, and then listens to resize events using the Window module.
import Html exposing (Html) import Html.App exposing (programWithFlags) import Svg exposing (..) import Svg.Attributes exposing (..) import Window type alias Flags = { width : Int , height : Int } type Msg = Resize Int Int type alias Model = { screen : { width : Int , height : Int } } init : Flags -> (Model, Cmd Msg) init flags = ( { screen = { width = flags.width , height = flags.height } } , Cmd.none ) view : Model -> Html Msg view model = let sw = model.screen.width - 0 sh = model.screen.height - 0 in svg [ width <| toString sw , height <| toString sh ] [ rect [ x "0" , y "0" , width (toString model.screen.width) , height (toString model.screen.height) , fill "#eeffee" ] [] , text' [ x <| toString <| sw / 2 , y <| toString <| sh / 2 , fontSize <| toString <| sh / 10 , textAnchor "middle" ] [ text ((toString model.screen.width) ++ ", " ++ (toString model.screen.height)) ] ] update : Msg -> Model -> (Model, Cmd Msg) update msg model = let m = case msg of Resize w h -> {model | screen = {width = w, height = h}} in (m, Cmd.none) subscriptions : Model -> Sub Msg subscriptions model = Window.resizes (\size -> Resize size.width size.height) main = programWithFlags { init = init , view = view , update = update , subscriptions = subscriptions }
I installed all the packages with:
elm-package install
Then I compiled the code with:
elm-make --output=sootl.js Main.elm
Now I launched elm-reactor:
elm-reactor
And navigated my browser to http://localhost:8000/index.html to see it working.