MacCASOutreach / graphicsvg / GraphicSVG.App

A module using the SVG graphics library to implement easily usable apps, which includes built-in functions for creating plain graphics, interactions, games and other applications including response to time, keyboard presses, and mouse actions.

Apps

graphicsApp : { view : GraphicSVG.Collage () } -> GraphicsApp

The simplest way to render graphics to the screen. These graphics will be static (they don't move) and cannot be interacted with. This is great for beginners or for when only need static graphics are needed. Note that your view function is bare, with no parameters: view = collage 500 500 [ circle 10 |> filled red ][ circle 10 |> filled red ] graphicsApp takes a parameter like { view = view } so the main program that would get the whole thing started for the above view would be: main = graphicsApp { view = view }


type alias GraphicsApp =
GraphicSVG.App () () (HiddenMsg ())

This type alias is only used as a target for a user main type signature to make the type signature more clear and concise when main calls graphicsApp: main : GraphicsApp userMsg main = graphicsApp { view = view } Note that userMsg can be anything as no messages are used in this type of program.

notificationsApp : { model : userModel, view : userModel -> GraphicSVG.Collage userMsg, update : userMsg -> userModel -> userModel } -> NotificationsApp userModel userMsg

Like graphicsApp, but you can add interactivity to your graphics by using the notify* functions. This allows you to learn Elm's architecture in a fun way with graphics. Note that your view function needs a model parameter now, which in this example is the colour of the shape: view model = collage 500 500 [ circle 10 |> filled model |> notifyTap Change ][ circle 10 |> filled model |> notifyTap Change ] notificationsApp takes a parameter like: { model = model , view = view , update = update } so the functions that would be required to make the above view function work are as follows: type Msg = Change update msg model = case msg of Change -> green main = notificationsApp { model = red -- causes circle to start red , update = update -- function which changes the model , view = view } which will cause the drawn red circle to change to green the first time it is mouse clicked or tapped.


type alias NotificationsApp userModel userMsg =
GraphicSVG.App () userModel (HiddenMsg userMsg)

This type alias is only used as a target for a user main type signature to make the type signature more clear and concise when main calls notificationsApp: main : NotificationsApp Model MyMsg main = notificationsApp { model = init, update = update, view = view } where Model is the type alias of the user persistent model, and MyMsg is the name of the user defined message type; if other names are used, they can be substituted for these names.

gameApp : InputHandler userMsg -> { model : userModel, view : userModel -> GraphicSVG.Collage userMsg, update : userMsg -> userModel -> userModel, title : String } -> GameApp userModel userMsg

Automatically maps time and keyboard presses to your program. This should be all you need for making complex interactive games and animations. gameApp takes two parameters: one is your own type of InputHandler message which will be automatically called each time the browser window is refreshed (30 times per second) of the form Float -> GetKeyState -> UserMsg and the other is

{
  model = model
, view = view
, update = update
}

The following program causes animation of the drawn line, causing it to spin around; also, a press of the "r" key causes the direction of the spin to reverse:

type Msg
    = Tick Float GetKeyState

type alias Model = { angle : Float, speed : Float }

init = { angle = 0, speed = 1 }

update msg model =
    case msg of
        Tick _ ( keys, _, _ ) ->
            case keys (Key "r") of
                JustDown ->
                    { model
                    | angle = model.angle - model.speed
                    , speed = -model.speed
                    }
            _ -> { model | angle = model.angle + model.speed }

view model =
    collage 500 500
        [ line ( 0, 0 ) ( 250, 0 )
            |> outlined (solid 1) green
            |> rotate (degrees model.angle)
        ]

main =
    gameApp Tick
        { model = init
        , update = update
        , view = view
        }


type alias GameApp userModel userMsg =
GraphicSVG.App () ( userModel
, HiddenModel userMsg ) (HiddenMsg userMsg
}

This type alias is only used as a target for a user main type signature to make the type signature more clear and concise when main calls gameApp: main : GameApp Model Msg main = gameApp Tick { model = init , update = update , view = view } where Tick is the message handler called once per browser window update, Model is the type alias of the user persistent model, and Msg is the name of the user message type; if other names are used, they can be substituted for these names.

Time and Keyboard interactions


type alias InputHandler userMsg =
Basics.Float -> GetKeyState -> userMsg

The InputHandler type alias descripts a message that contains a Float representing the time in seconds from the time the program started and the GetKeyState type alias used for returning key actions. This type is used for by the gameApp fully interactive application.


type alias GetKeyState =
( Keys -> KeyState
, ( Basics.Float
, Basics.Float )
, ( Basics.Float
, Basics.Float ) 
)

GetKeyState returns a triple where the first argument is of type Keys -> KeyState so you can ask if a certain key is pressed. The other two are tuples of arrow keys and WASD keys, respectively. They're in the form (x,y) which represents the key presses of each player. For example, (0,-1) represents the left arrow (or "A") key, and (1,1) would mean the up (or "W") and right (or "D") key are being pressed at the same time.


type Keys
    = Key String
    | Backspace
    | Tab
    | Enter
    | Shift
    | Ctrl
    | Alt
    | Caps
    | LeftArrow
    | UpArrow
    | RightArrow
    | DownArrow
    | Delete
    | Space

Includes all the regular keys. Ask for letters and numbers using Key String, e.g. Key "a" or Key "3".


type KeyState
    = JustDown
    | Down
    | JustUp
    | Up

The possible states when you ask for a key's state:

Barebones app with keyboard and time


type alias AppWithTick flags userModel userMsg =
GraphicSVG.App flags ( userModel
, HiddenModel userMsg ) (HiddenMsg userMsg
}

This type alias is only used as a target for a user main type signature to make the type signature more clear and concise when main calls gameApp: main : GameApp Model Msg main = appWithTick Tick { model = init , update = update , view = view , subscriptions = subscriptions , onUrlRequest = OnUrlRequest , onUrlChange = OnUrlChange } where Tick is the message handler called once per browser window update, Model is the type alias of the user persistent model, and Msg is the name of the user message type; if other names are used, they can be substituted for these names.

appWithTick : InputHandler userMsg -> { init : flags -> Url -> Browser.Navigation.Key -> ( userModel, Platform.Cmd.Cmd userMsg ), update : userMsg -> userModel -> ( userModel, Platform.Cmd.Cmd userMsg ), view : userModel -> { title : String, body : GraphicSVG.Collage userMsg }, subscriptions : userModel -> Platform.Sub.Sub userMsg, onUrlRequest : Browser.UrlRequest -> userMsg, onUrlChange : Url -> userMsg } -> AppWithTick flags userModel userMsg

A GraphicSVG.app with automatic time and keyboard presses passed into the update function. appWithTick takes two parameters: one is your own type of InputHandler message which will be automatically called each time the browser window is refreshed (30 times per second) of the form Float -> GetKeyState -> UserMsg and the other is ``` { init = model , view = view , update = update , subscriptions = subscriptions , onUrlRequest = OnUrlRequest , onUrlChange = OnUrlChange } where init is the model and initial commands, view is a collage and a title, update is the usual update function with commands, subscriptions are things which you'd like to be notified about on a regular basis (e.g. changes in time, incoming WebSocket messages), onUrlRequest is sent whenever the user initiates a URL action (e.g. clicks a link) and onUrlChange is when the user changes the url in the browser. See https://package.elm-lang.org/packages/elm/browser/latest/Browser#application for a more clear description of these.