diff --git a/src/Playground.elm b/src/Playground.elm index 988886c..8c228b2 100644 --- a/src/Playground.elm +++ b/src/Playground.elm @@ -1,101 +1,114 @@ module Playground exposing - ( picture - , animation - , game - -- - , Shape - , circle, oval - , square, rectangle - , triangle, pentagon, hexagon, octagon, polygon - , image, words - , move, moveUp, moveDown, moveLeft, moveRight, moveX, moveY - , scale, rotate - , fade - , group - -- - , Number - -- - , Time - , spin - , wave - , zigzag - -- - , Computer - , Mouse - , Screen - , Keyboard - , toX - , toY - , toXY - -- - , Color - , red, orange, yellow, green, blue, purple, brown - , lightRed, lightOrange, lightYellow, lightGreen, lightBlue, lightPurple, lightBrown - , darkRed, darkOrange, darkYellow, darkGreen, darkBlue, darkPurple, darkBrown - , white, lightGrey, grey, darkGrey, lightCharcoal, charcoal, darkCharcoal, black - , rgb - , lightGray, gray, darkGray - ) + ( picture, animation, game + , Shape, circle, oval, square, rectangle, triangle, pentagon, hexagon, octagon, polygon + , words + , image + , move, moveUp, moveDown, moveLeft, moveRight, moveX, moveY + , scale, rotate, fade + , group + , Time, spin, wave, zigzag + , Computer, Mouse, Screen, Keyboard, toX, toY, toXY + , Color, rgb, red, orange, yellow, green, blue, purple, brown + , lightRed, lightOrange, lightYellow, lightGreen, lightBlue, lightPurple, lightBrown + , darkRed, darkOrange, darkYellow, darkGreen, darkBlue, darkPurple, darkBrown + , white, lightGrey, grey, darkGrey, lightCharcoal, charcoal, darkCharcoal, black + , lightGray, gray, darkGray + , Number + -- + -- + -- + -- + -- + ) {-| + # Playgrounds + @docs picture, animation, game + # Shapes + @docs Shape, circle, oval, square, rectangle, triangle, pentagon, hexagon, octagon, polygon + # Words + @docs words + # Images + @docs image + # Move Shapes + @docs move, moveUp, moveDown, moveLeft, moveRight, moveX, moveY + # Customize Shapes + @docs scale, rotate, fade + # Groups + @docs group + # Time + @docs Time, spin, wave, zigzag + # Computer + @docs Computer, Mouse, Screen, Keyboard, toX, toY, toXY + # Colors + @docs Color, rgb, red, orange, yellow, green, blue, purple, brown + ### Light Colors + @docs lightRed, lightOrange, lightYellow, lightGreen, lightBlue, lightPurple, lightBrown + ### Dark Colors + @docs darkRed, darkOrange, darkYellow, darkGreen, darkBlue, darkPurple, darkBrown + ### Shades of Grey + @docs white, lightGrey, grey, darkGrey, lightCharcoal, charcoal, darkCharcoal, black + ### Alternate Spellings of Gray + @docs lightGray, gray, darkGray + ### Numbers + @docs Number -} - import Browser import Browser.Dom as Dom import Browser.Events as E import Html import Html.Attributes as H -import Svg exposing (..) -import Svg.Attributes exposing (..) import Json.Decode as D import Set +import Svg exposing (..) +import Svg.Attributes exposing (..) import Task import Time @@ -109,38 +122,38 @@ import Time import Playground exposing (..) main = - picture - [ triangle green 150 - , circle white 40 - , circle black 10 - ] + picture + [ triangle green 150 + , circle white 40 + , circle black 10 + ] -} -picture : List Shape -> Program () Screen (Int, Int) +picture : List Shape -> Program () Screen ( Int, Int ) picture shapes = - let - init () = - (toScreen 600 600, Cmd.none) - - view screen = - { title = "Playground" - , body = [ render screen shapes ] - } - - update (width,height) _ = - ( toScreen (toFloat width) (toFloat height) - , Cmd.none - ) - - subscriptions _ = - E.onResize Tuple.pair - in - Browser.document - { init = init - , view = view - , update = update - , subscriptions = subscriptions - } + let + init () = + ( toScreen 600 600, Cmd.none ) + + view screen = + { title = "Playground" + , body = [ render screen shapes ] + } + + update ( width, height ) _ = + ( toScreen (toFloat width) (toFloat height) + , Cmd.none + ) + + subscriptions _ = + E.onResize Tuple.pair + in + Browser.document + { init = init + , view = view + , update = update + , subscriptions = subscriptions + } @@ -157,13 +170,14 @@ about your computer: So you can use expressions like `computer.mouse.x` and `computer.keyboard.enter` in games where you want some mouse or keyboard interaction. + -} type alias Computer = - { mouse : Mouse - , keyboard : Keyboard - , screen : Screen - , time : Time - } + { mouse : Mouse + , keyboard : Keyboard + , screen : Screen + , time : Time + } @@ -177,31 +191,33 @@ You could draw a circle around the mouse with a program like this: import Playground exposing (..) main = - game view update 0 + game view update 0 view computer memory = - [ circle yellow 40 - |> moveX computer.mouse.x - |> moveY computer.mouse.y - ] + [ circle yellow 40 + |> moveX computer.mouse.x + |> moveY computer.mouse.y + ] update computer memory = - memory + memory You could also use `computer.mouse.down` to change the color of the circle while the mouse button is down. + -} type alias Mouse = - { x : Number - , y : Number - , down : Bool - , click : Bool - } + { x : Number + , y : Number + , down : Bool + , click : Bool + } {-| A number like `1` or `3.14` or `-120`. -} -type alias Number = Float +type alias Number = + Float @@ -212,19 +228,26 @@ type alias Number = Float If someone is pressing the UP and RIGHT arrows, you will see a value like this: - { up = True, down = False, left = False, right = True - , space = False, enter = False, shift = False, backspace = False - , keys = Set.fromList ["ArrowUp","ArrowRight"] + { up = True + , down = False + , left = False + , right = True + , space = False + , enter = False + , shift = False + , backspace = False + , keys = Set.fromList [ "ArrowUp", "ArrowRight" ] } So if you want to move a character based on arrows, you could write an update like this: update computer y = - if computer.keyboard.up then - y + 1 - else - y + if computer.keyboard.up then + y + 1 + + else + y Check out [`toX`](#toX) and [`toY`](#toY) which make this even easier! @@ -237,18 +260,19 @@ names used for all the different special keys! From there, you can use [list]: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values [member]: /packages/elm/core/latest/Set#member + -} type alias Keyboard = - { up : Bool - , down : Bool - , left : Bool - , right : Bool - , space : Bool - , enter : Bool - , shift : Bool - , backspace : Bool - , keys : Set.Set String - } + { up : Bool + , down : Bool + , left : Bool + , right : Bool + , space : Bool + , enter : Bool + , shift : Bool + , backspace : Bool + , keys : Set.Set String + } {-| Turn the LEFT and RIGHT arrows into a number. @@ -263,20 +287,31 @@ So to make a square move left and right based on the arrow keys, we could say: import Playground exposing (..) main = - game view update 0 + game view update 0 view computer x = - [ square green 40 - |> moveX x - ] + [ square green 40 + |> moveX x + ] update computer x = - x + toX computer.keyboard + x + toX computer.keyboard -} toX : Keyboard -> Number toX keyboard = - (if keyboard.right then 1 else 0) - (if keyboard.left then 1 else 0) + (if keyboard.right then + 1 + + else + 0 + ) + - (if keyboard.left then + 1 + + else + 0 + ) {-| Turn the UP and DOWN arrows into a number. @@ -291,22 +326,33 @@ This can be used to move characters around in games just like [`toX`](#toX): import Playground exposing (..) main = - game view update (0,0) + game view update ( 0, 0 ) - view computer (x,y) = - [ square blue 40 - |> move x y - ] + view computer ( x, y ) = + [ square blue 40 + |> move x y + ] - update computer (x,y) = - ( x + toX computer.keyboard - , y + toY computer.keyboard - ) + update computer ( x, y ) = + ( x + toX computer.keyboard + , y + toY computer.keyboard + ) -} toY : Keyboard -> Number toY keyboard = - (if keyboard.up then 1 else 0) - (if keyboard.down then 1 else 0) + (if keyboard.up then + 1 + + else + 0 + ) + - (if keyboard.down then + 1 + + else + 0 + ) {-| If you just use `toX` and `toY`, you will move diagonal too fast. You will go @@ -325,35 +371,40 @@ Now when you go up/right, you are still going 1 pixel per update. import Playground exposing (..) main = - game view update (0,0) + game view update ( 0, 0 ) - view computer (x,y) = - [ square green 40 - |> move x y - ] + view computer ( x, y ) = + [ square green 40 + |> move x y + ] - update computer (x,y) = - let - (dx,dy) = toXY computer.keyboard - in - (x + dx, y + dy) + update computer ( x, y ) = + let + ( dx, dy ) = + toXY computer.keyboard + in + ( x + dx, y + dy ) -} -toXY : Keyboard -> (Number, Number) +toXY : Keyboard -> ( Number, Number ) toXY keyboard = - let - x = toX keyboard - y = toY keyboard - in - if x /= 0 && y /= 0 then - (x / squareRootOfTwo, y / squareRootOfTwo) - else - (x,y) + let + x = + toX keyboard + + y = + toY keyboard + in + if x /= 0 && y /= 0 then + ( x / squareRootOfTwo, y / squareRootOfTwo ) + + else + ( x, y ) squareRootOfTwo : Number squareRootOfTwo = - sqrt 2 + sqrt 2 @@ -373,15 +424,16 @@ a value like this: This can be nice when used with [`moveY`](#moveY) if you want to put something on the bottom of the screen, no matter the dimensions. + -} type alias Screen = - { width : Number - , height : Number - , top : Number - , left : Number - , right : Number - , bottom : Number - } + { width : Number + , height : Number + , top : Number + , left : Number + , right : Number + , bottom : Number + } @@ -392,8 +444,10 @@ type alias Screen = Helpful when making an [`animation`](#animation) with functions like [`spin`](#spin), [`wave`](#wave), and [`zigzag`](#zigzag). + -} -type Time = Time Time.Posix +type Time + = Time Time.Posix {-| Create an angle that cycles from 0 to 360 degrees over time. @@ -403,19 +457,20 @@ Here is an [`animation`](#animation) with a spinning triangle: import Playground exposing (..) main = - animation view + animation view view time = - [ triangle orange 50 - |> rotate (spin 8 time) - ] + [ triangle orange 50 + |> rotate (spin 8 time) + ] It will do a full rotation once every eight seconds. Try changing the `8` to a `2` to make it do a full rotation every two seconds. It moves a lot faster! + -} spin : Number -> Time -> Number spin period time = - 360 * toFrac period time + 360 * toFrac period time {-| Smoothly wave between two numbers. @@ -425,18 +480,19 @@ Here is an [`animation`](#animation) with a circle that resizes: import Playground exposing (..) main = - animation view + animation view view time = - [ circle lightBlue (wave 50 90 7 time) - ] + [ circle lightBlue (wave 50 90 7 time) + ] The radius of the circle will cycles between 50 and 90 every seven seconds. It kind of looks like it is breathing. + -} wave : Number -> Number -> Number -> Time -> Number wave lo hi period time = - lo + (hi - lo) * (1 + cos (turns (toFrac period time))) / 2 + lo + (hi - lo) * (1 + cos (turns (toFrac period time))) / 2 {-| Zig zag between two numbers. @@ -446,28 +502,32 @@ Here is an [`animation`](#animation) with a rectangle that tips back and forth: import Playground exposing (..) main = - animation view + animation view view time = - [ rectangle lightGreen 20 100 - |> rotate (zigzag -20 20 4 time) - ] + [ rectangle lightGreen 20 100 + |> rotate (zigzag -20 20 4 time) + ] It gets rotated by an angle. The angle cycles from -20 degrees to 20 degrees every four seconds. + -} zigzag : Number -> Number -> Number -> Time -> Number zigzag lo hi period time = - lo + (hi - lo) * abs (2 * toFrac period time - 1) + lo + (hi - lo) * abs (2 * toFrac period time - 1) toFrac : Float -> Time -> Float toFrac period (Time posix) = - let - ms = Time.posixToMillis posix - p = period * 1000 - in - toFloat (modBy (round p) ms) / p + let + ms = + Time.posixToMillis posix + + p = + period * 1000 + in + toFloat (modBy (round p) ms) / p @@ -482,76 +542,92 @@ try out an `animation`. Here is square that zigzags back and forth: import Playground exposing (..) main = - animation view + animation view view time = - [ square blue 40 - |> moveX (zigzag -100 100 2 time) - ] + [ square blue 40 + |> moveX (zigzag -100 100 2 time) + ] We need to define a `view` to make our animation work. Within `view` we can use functions like [`spin`](#spin), [`wave`](#wave), and [`zigzag`](#zigzag) to move and rotate our shapes. + -} animation : (Time -> List Shape) -> Program () Animation Msg animation viewFrame = - let - init () = - ( Animation E.Visible (toScreen 600 600) (Time (Time.millisToPosix 0)) - , Task.perform GotViewport Dom.getViewport - ) - - view (Animation _ screen time) = - { title = "Playground" - , body = [ render screen (viewFrame time) ] - } - - update msg model = - ( animationUpdate msg model - , Cmd.none - ) - - subscriptions (Animation visibility _ _) = - case visibility of - E.Hidden -> - E.onVisibilityChange VisibilityChanged - - E.Visible -> - animationSubscriptions - in - Browser.document - { init = init - , view = view - , update = update - , subscriptions = subscriptions - } + let + init () = + ( Animation E.Visible (toScreen 600 600) (Time (Time.millisToPosix 0)) + , Task.perform GotViewport Dom.getViewport + ) + + view (Animation _ screen time) = + { title = "Playground" + , body = [ render screen (viewFrame time) ] + } + + update msg model = + ( animationUpdate msg model + , Cmd.none + ) + + subscriptions (Animation visibility _ _) = + case visibility of + E.Hidden -> + E.onVisibilityChange VisibilityChanged + + E.Visible -> + animationSubscriptions + in + Browser.document + { init = init + , view = view + , update = update + , subscriptions = subscriptions + } -type Animation = - Animation E.Visibility Screen Time +type Animation + = Animation E.Visibility Screen Time animationSubscriptions : Sub Msg animationSubscriptions = - Sub.batch - [ E.onResize Resized - , E.onAnimationFrame Tick - , E.onVisibilityChange VisibilityChanged - ] + Sub.batch + [ E.onResize Resized + , E.onAnimationFrame Tick + , E.onVisibilityChange VisibilityChanged + ] animationUpdate : Msg -> Animation -> Animation -animationUpdate msg (Animation v s t as state) = - case msg of - Tick posix -> Animation v s (Time posix) - VisibilityChanged vis -> Animation vis s t - GotViewport {viewport} -> Animation v (toScreen viewport.width viewport.height) t - Resized w h -> Animation v (toScreen (toFloat w) (toFloat h)) t - KeyChanged _ _ -> state - MouseMove _ _ -> state - MouseClick -> state - MouseButton _ -> state +animationUpdate msg ((Animation v s t) as state) = + case msg of + Tick posix -> + Animation v s (Time posix) + + VisibilityChanged vis -> + Animation vis s t + + GotViewport { viewport } -> + Animation v (toScreen viewport.width viewport.height) t + + Resized w h -> + Animation v (toScreen (toFloat w) (toFloat h)) t + + KeyChanged _ _ -> + state + + MouseMove _ _ -> + state + + MouseClick -> + state + + MouseButton _ -> + state @@ -567,24 +643,24 @@ just moves to the right: import Playground exposing (..) main = - game view update 0 + game view update 0 view computer offset = - [ square green 40 - |> moveRight offset - ] + [ square green 40 + |> moveRight offset + ] update computer offset = - offset + 0.03 + offset + 0.03 This shows the three important parts of a game: -1. `memory` - makes it possible to store information. So with our green square, -we save the `offset` in memory. It starts out at `0`. -2. `view` - lets us say which shapes to put on screen. So here we move our -square right by the `offset` saved in memory. -3. `update` - lets us update the memory. We are incrementing the `offset` by -a tiny amount on each frame. +1. `memory` - makes it possible to store information. So with our green square, + we save the `offset` in memory. It starts out at `0`. +2. `view` - lets us say which shapes to put on screen. So here we move our + square right by the `offset` saved in memory. +3. `update` - lets us update the memory. We are incrementing the `offset` by + a tiny amount on each frame. The `update` function is called about 60 times per second, so our little changes to `offset` start to add up pretty quickly! @@ -597,62 +673,63 @@ moves based on the arrow keys: import Playground exposing (..) main = - game view update (0,0) + game view update ( 0, 0 ) - view computer (x,y) = - [ square red 40 - |> move x y - ] + view computer ( x, y ) = + [ square red 40 + |> move x y + ] - update computer (x,y) = - ( x + toX computer.keyboard - , y + toY computer.keyboard - ) + update computer ( x, y ) = + ( x + toX computer.keyboard + , y + toY computer.keyboard + ) Notice that in the `update` we use information from the keyboard to update the `x` and `y` values. These building blocks let you make pretty fancy games! + -} game : (Computer -> memory -> List Shape) -> (Computer -> memory -> memory) -> memory -> Program () (Game memory) Msg game viewMemory updateMemory initialMemory = - let - init () = - ( Game E.Visible initialMemory initialComputer - , Task.perform GotViewport Dom.getViewport - ) - - view (Game _ memory computer) = - { title = "Playground" - , body = [ render computer.screen (viewMemory computer memory) ] - } - - update msg model = - ( gameUpdate updateMemory msg model - , Cmd.none - ) - - subscriptions (Game visibility _ _) = - case visibility of - E.Hidden -> - E.onVisibilityChange VisibilityChanged - - E.Visible -> - gameSubscriptions - in - Browser.document - { init = init - , view = view - , update = update - , subscriptions = subscriptions - } + let + init () = + ( Game E.Visible initialMemory initialComputer + , Task.perform GotViewport Dom.getViewport + ) + + view (Game _ memory computer) = + { title = "Playground" + , body = [ render computer.screen (viewMemory computer memory) ] + } + + update msg model = + ( gameUpdate updateMemory msg model + , Cmd.none + ) + + subscriptions (Game visibility _ _) = + case visibility of + E.Hidden -> + E.onVisibilityChange VisibilityChanged + + E.Visible -> + gameSubscriptions + in + Browser.document + { init = init + , view = view + , update = update + , subscriptions = subscriptions + } initialComputer : Computer initialComputer = - { mouse = Mouse 0 0 False False - , keyboard = emptyKeyboard - , screen = toScreen 600 600 - , time = Time (Time.millisToPosix 0) - } + { mouse = Mouse 0 0 False False + , keyboard = emptyKeyboard + , screen = toScreen 600 600 + , time = Time (Time.millisToPosix 0) + } @@ -661,75 +738,81 @@ initialComputer = gameSubscriptions : Sub Msg gameSubscriptions = - Sub.batch - [ E.onResize Resized - , E.onKeyUp (D.map (KeyChanged False) (D.field "key" D.string)) - , E.onKeyDown (D.map (KeyChanged True) (D.field "key" D.string)) - , E.onAnimationFrame Tick - , E.onVisibilityChange VisibilityChanged - , E.onClick (D.succeed MouseClick) - , E.onMouseDown (D.succeed (MouseButton True)) - , E.onMouseUp (D.succeed (MouseButton False)) - , E.onMouseMove (D.map2 MouseMove (D.field "pageX" D.float) (D.field "pageY" D.float)) - ] + Sub.batch + [ E.onResize Resized + , E.onKeyUp (D.map (KeyChanged False) (D.field "key" D.string)) + , E.onKeyDown (D.map (KeyChanged True) (D.field "key" D.string)) + , E.onAnimationFrame Tick + , E.onVisibilityChange VisibilityChanged + , E.onClick (D.succeed MouseClick) + , E.onMouseDown (D.succeed (MouseButton True)) + , E.onMouseUp (D.succeed (MouseButton False)) + , E.onMouseMove (D.map2 MouseMove (D.field "pageX" D.float) (D.field "pageY" D.float)) + ] -- GAME HELPERS -type Game memory = - Game E.Visibility memory Computer +type Game memory + = Game E.Visibility memory Computer type Msg - = KeyChanged Bool String - | Tick Time.Posix - | GotViewport Dom.Viewport - | Resized Int Int - | VisibilityChanged E.Visibility - | MouseMove Float Float - | MouseClick - | MouseButton Bool + = KeyChanged Bool String + | Tick Time.Posix + | GotViewport Dom.Viewport + | Resized Int Int + | VisibilityChanged E.Visibility + | MouseMove Float Float + | MouseClick + | MouseButton Bool gameUpdate : (Computer -> memory -> memory) -> Msg -> Game memory -> Game memory gameUpdate updateMemory msg (Game vis memory computer) = - case msg of - Tick time -> - Game vis (updateMemory computer memory) <| - if computer.mouse.click - then { computer | time = Time time, mouse = mouseClick False computer.mouse } - else { computer | time = Time time } - - GotViewport {viewport} -> - Game vis memory { computer | screen = toScreen viewport.width viewport.height } - - Resized w h -> - Game vis memory { computer | screen = toScreen (toFloat w) (toFloat h) } - - KeyChanged isDown key -> - Game vis memory { computer | keyboard = updateKeyboard isDown key computer.keyboard } - - MouseMove pageX pageY -> - let - x = computer.screen.left + pageX - y = computer.screen.top - pageY - in - Game vis memory { computer | mouse = mouseMove x y computer.mouse } - - MouseClick -> - Game vis memory { computer | mouse = mouseClick True computer.mouse } - - MouseButton isDown -> - Game vis memory { computer | mouse = mouseDown isDown computer.mouse } - - VisibilityChanged visibility -> - Game visibility memory - { computer - | keyboard = emptyKeyboard - , mouse = Mouse computer.mouse.x computer.mouse.y False False - } + case msg of + Tick time -> + Game vis (updateMemory computer memory) <| + if computer.mouse.click then + { computer | time = Time time, mouse = mouseClick False computer.mouse } + + else + { computer | time = Time time } + + GotViewport { viewport } -> + Game vis memory { computer | screen = toScreen viewport.width viewport.height } + + Resized w h -> + Game vis memory { computer | screen = toScreen (toFloat w) (toFloat h) } + + KeyChanged isDown key -> + Game vis memory { computer | keyboard = updateKeyboard isDown key computer.keyboard } + + MouseMove pageX pageY -> + let + x = + computer.screen.left + pageX + + y = + computer.screen.top - pageY + in + Game vis memory { computer | mouse = mouseMove x y computer.mouse } + + MouseClick -> + Game vis memory { computer | mouse = mouseClick True computer.mouse } + + MouseButton isDown -> + Game vis memory { computer | mouse = mouseDown isDown computer.mouse } + + VisibilityChanged visibility -> + Game visibility + memory + { computer + | keyboard = emptyKeyboard + , mouse = Mouse computer.mouse.x computer.mouse.y False False + } @@ -738,13 +821,13 @@ gameUpdate updateMemory msg (Game vis memory computer) = toScreen : Float -> Float -> Screen toScreen width height = - { width = width - , height = height - , top = height / 2 - , left = -width / 2 - , right = width / 2 - , bottom = -height / 2 - } + { width = width + , height = height + , top = height / 2 + , left = -width / 2 + , right = width / 2 + , bottom = -height / 2 + } @@ -753,17 +836,17 @@ toScreen width height = mouseClick : Bool -> Mouse -> Mouse mouseClick bool mouse = - { mouse | click = bool } + { mouse | click = bool } mouseDown : Bool -> Mouse -> Mouse mouseDown bool mouse = - { mouse | down = bool } + { mouse | down = bool } mouseMove : Float -> Float -> Mouse -> Mouse mouseMove x y mouse = - { mouse | x = x, y = y } + { mouse | x = x, y = y } @@ -772,37 +855,55 @@ mouseMove x y mouse = emptyKeyboard : Keyboard emptyKeyboard = - { up = False - , down = False - , left = False - , right = False - , space = False - , enter = False - , shift = False - , backspace = False - , keys = Set.empty - } + { up = False + , down = False + , left = False + , right = False + , space = False + , enter = False + , shift = False + , backspace = False + , keys = Set.empty + } updateKeyboard : Bool -> String -> Keyboard -> Keyboard updateKeyboard isDown key keyboard = - let - keys = - if isDown then - Set.insert key keyboard.keys - else - Set.remove key keyboard.keys - in - case key of - " " -> { keyboard | keys = keys, space = isDown } - "Enter" -> { keyboard | keys = keys, enter = isDown } - "Shift" -> { keyboard | keys = keys, shift = isDown } - "Backspace" -> { keyboard | keys = keys, backspace = isDown } - "ArrowUp" -> { keyboard | keys = keys, up = isDown } - "ArrowDown" -> { keyboard | keys = keys, down = isDown } - "ArrowLeft" -> { keyboard | keys = keys, left = isDown } - "ArrowRight" -> { keyboard | keys = keys, right = isDown } - _ -> { keyboard | keys = keys } + let + keys = + if isDown then + Set.insert key keyboard.keys + + else + Set.remove key keyboard.keys + in + case key of + " " -> + { keyboard | keys = keys, space = isDown } + + "Enter" -> + { keyboard | keys = keys, enter = isDown } + + "Shift" -> + { keyboard | keys = keys, shift = isDown } + + "Backspace" -> + { keyboard | keys = keys, backspace = isDown } + + "ArrowUp" -> + { keyboard | keys = keys, up = isDown } + + "ArrowDown" -> + { keyboard | keys = keys, down = isDown } + + "ArrowLeft" -> + { keyboard | keys = keys, left = isDown } + + "ArrowRight" -> + { keyboard | keys = keys, right = isDown } + + _ -> + { keyboard | keys = keys } @@ -813,51 +914,63 @@ updateKeyboard isDown key keyboard = Read on to see examples of [`circle`](#circle), [`rectangle`](#rectangle), [`words`](#words), [`image`](#image), and many more! + -} -type Shape = - Shape - Number -- x - Number -- y - Number -- angle - Number -- scale - Number -- alpha - Form +type Shape + = Shape + Number + -- x + Number + -- y + Number + -- angle + Number + -- scale + Number + -- alpha + Form type Form - = Circle Color Number - | Oval Color Number Number - | Rectangle Color Number Number - | Ngon Color Int Number - | Polygon Color (List (Number, Number)) - | Image Number Number String - | Words Color String - | Group (List Shape) + = Circle Color Number + | Oval Color Number Number + | Rectangle Color Number Number + | Ngon Color Int Number + | Polygon Color (List ( Number, Number )) + | Image Number Number String + | Words Color String + | Group (List Shape) {-| Make circles: - dot = circle red 10 - sun = circle yellow 300 + dot = + circle red 10 + + sun = + circle yellow 300 You give a color and then the radius. So the higher the number, the larger the circle. + -} circle : Color -> Number -> Shape circle color radius = - Shape 0 0 0 1 1 (Circle color radius) + Shape 0 0 0 1 1 (Circle color radius) {-| Make ovals: - football = oval brown 200 100 + football = + oval brown 200 100 You give the color, and then the width and height. So our `football` example is 200 pixels wide and 100 pixels tall. + -} oval : Color -> Number -> Number -> Shape oval color width height = - Shape 0 0 0 1 1 (Oval color width height) + Shape 0 0 0 1 1 (Oval color width height) {-| Make squares. Here are two squares combined to look like an empty box: @@ -865,17 +978,18 @@ oval color width height = import Playground exposing (..) main = - picture - [ square purple 80 - , square white 60 - ] + picture + [ square purple 80 + , square white 60 + ] The number you give is the dimension of each side. So that purple square would be 80 pixels by 80 pixels. + -} square : Color -> Number -> Shape square color n = - Shape 0 0 0 1 1 (Rectangle color n n) + Shape 0 0 0 1 1 (Rectangle color n n) {-| Make rectangles. This example makes a red cross: @@ -883,17 +997,18 @@ square color n = import Playground exposing (..) main = - picture - [ rectangle red 20 60 - , rectangle red 60 20 - ] + picture + [ rectangle red 20 60 + , rectangle red 60 20 + ] You give the color, width, and then height. So the first shape is vertical part of the cross, the thinner and taller part. + -} rectangle : Color -> Number -> Number -> Shape rectangle color width height = - Shape 0 0 0 1 1 (Rectangle color width height) + Shape 0 0 0 1 1 (Rectangle color width height) {-| Make triangles. So if you wanted to draw the Egyptian pyramids, you could @@ -902,16 +1017,17 @@ do a simple version like this: import Playground exposing (..) main = - picture - [ triangle darkYellow 200 - ] + picture + [ triangle darkYellow 200 + ] The number is the "radius", so the distance from the center to each point of the pyramid is `200`. Pretty big! + -} triangle : Color -> Number -> Shape triangle color radius = - Shape 0 0 0 1 1 (Ngon color 3 radius) + Shape 0 0 0 1 1 (Ngon color 3 radius) {-| Make pentagons: @@ -919,16 +1035,17 @@ triangle color radius = import Playground exposing (..) main = - picture - [ pentagon darkGrey 100 - ] + picture + [ pentagon darkGrey 100 + ] You give the color and then the radius. So the distance from the center to each of the five points is 100 pixels. + -} pentagon : Color -> Number -> Shape pentagon color radius = - Shape 0 0 0 1 1 (Ngon color 5 radius) + Shape 0 0 0 1 1 (Ngon color 5 radius) {-| Make hexagons: @@ -936,35 +1053,37 @@ pentagon color radius = import Playground exposing (..) main = - picture - [ hexagon lightYellow 50 - ] + picture + [ hexagon lightYellow 50 + ] The number is the radius, the distance from the center to each point. If you made more hexagons, you could [`move`](#move) them around to make a honeycomb pattern! + -} hexagon : Color -> Number -> Shape hexagon color radius = - Shape 0 0 0 1 1 (Ngon color 6 radius) + Shape 0 0 0 1 1 (Ngon color 6 radius) {-| Make octogons: - import Playground exposing (..) +import Playground exposing (..) - main = - picture - [ octagon red 100 - ] +main = +picture +[ octagon red 100 +] You give the color and radius, so each point of this stop sign is 100 pixels from the center. + -} octagon : Color -> Number -> Shape octagon color radius = - Shape 0 0 0 1 1 (Ngon color 8 radius) + Shape 0 0 0 1 1 (Ngon color 8 radius) {-| Make any shape you want! Here is a very thin triangle: @@ -972,17 +1091,18 @@ octagon color radius = import Playground exposing (..) main = - picture - [ polygon [ (-10,-20), (0,100), (10,-20) ] - ] + picture + [ polygon [ ( -10, -20 ), ( 0, 100 ), ( 10, -20 ) ] + ] **Note:** If you [`rotate`](#rotate) a polygon, it will always rotate around `(0,0)`. So it is best to build your shapes around that point, and then use [`move`](#move) or [`group`](#group) so that rotation makes more sense. + -} -polygon : Color -> List (Number, Number) -> Shape +polygon : Color -> List ( Number, Number ) -> Shape polygon color points = - Shape 0 0 0 1 1 (Polygon color points) + Shape 0 0 0 1 1 (Polygon color points) {-| Add some image from the internet: @@ -990,15 +1110,16 @@ polygon color points = import Playground exposing (..) main = - picture - [ image 96 96 "https://elm-lang.org/assets/turtle.gif" - ] + picture + [ image 96 96 "https://elm-lang.org/assets/turtle.gif" + ] You provide the width, height, and then the URL of the image you want to show. + -} image : Number -> Number -> String -> Shape image w h src = - Shape 0 0 0 1 1 (Image w h src) + Shape 0 0 0 1 1 (Image w h src) {-| Show some words! @@ -1006,15 +1127,16 @@ image w h src = import Playground exposing (..) main = - picture - [ words black "Hello! How are you?" - ] + picture + [ words black "Hello! How are you?" + ] You can use [`scale`](#scale) to make the words bigger or smaller. + -} words : Color -> String -> Shape words color string = - Shape 0 0 0 1 1 (Words color string) + Shape 0 0 0 1 1 (Words color string) {-| Put shapes together so you can [`move`](#move) and [`rotate`](#rotate) @@ -1023,31 +1145,32 @@ them as a group. Maybe you want to put a bunch of stars in the sky: import Playground exposing (..) main = - picture - [ star - |> move 100 100 - |> rotate 5 - , star - |> move -120 40 - |> rotate 20 - , star - |> move 80 -150 - |> rotate 32 - , star - |> move -90 -30 - |> rotate -16 - ] + picture + [ star + |> move 100 100 + |> rotate 5 + , star + |> move -120 40 + |> rotate 20 + , star + |> move 80 -150 + |> rotate 32 + , star + |> move -90 -30 + |> rotate -16 + ] star = - group - [ triangle yellow 20 - , triangle yellow 20 - |> rotate 180 - ] + group + [ triangle yellow 20 + , triangle yellow 20 + |> rotate 180 + ] + -} group : List Shape -> Shape group shapes = - Shape 0 0 0 1 1 (Group shapes) + Shape 0 0 0 1 1 (Group shapes) @@ -1059,20 +1182,21 @@ group shapes = import Playground exposing (..) main = - picture - [ square red 100 - |> move -60 60 - , square yellow 100 - |> move 60 60 - , square green 100 - |> move 60 -60 - , square blue 100 - |> move -60 -60 - ] + picture + [ square red 100 + |> move -60 60 + , square yellow 100 + |> move 60 60 + , square green 100 + |> move 60 -60 + , square blue 100 + |> move -60 -60 + ] + -} move : Number -> Number -> Shape -> Shape move dx dy (Shape x y a s o f) = - Shape (x + dx) (y + dy) a s o f + Shape (x + dx) (y + dy) a s o f {-| Move a shape up by some number of pixels. So if you wanted to make a tree @@ -1081,15 +1205,16 @@ you could move the leaves up above the trunk: import Playground exposing (..) main = - picture - [ rectangle brown 40 200 - , circle green 100 - |> moveUp 180 - ] + picture + [ rectangle brown 40 200 + , circle green 100 + |> moveUp 180 + ] + -} moveUp : Number -> Shape -> Shape moveUp = - moveY + moveY {-| Move a shape down by some number of pixels. So if you wanted to put the sky @@ -1098,16 +1223,17 @@ above the ground, you could move the sky up and the ground down: import Playground exposing (..) main = - picture - [ rectangle lightBlue 200 100 - |> moveUp 50 - , rectangle lightGreen 200 100 - |> moveDown 50 - ] + picture + [ rectangle lightBlue 200 100 + |> moveUp 50 + , rectangle lightGreen 200 100 + |> moveDown 50 + ] + -} moveDown : Number -> Shape -> Shape moveDown dy (Shape x y a s o f) = - Shape x (y - dy) a s o f + Shape x (y - dy) a s o f {-| Move shapes to the left. @@ -1115,15 +1241,16 @@ moveDown dy (Shape x y a s o f) = import Playground exposing (..) main = - picture - [ circle yellow 10 - |> moveLeft 80 - |> moveUp 30 - ] + picture + [ circle yellow 10 + |> moveLeft 80 + |> moveUp 30 + ] + -} moveLeft : Number -> Shape -> Shape moveLeft dx (Shape x y a s o f) = - Shape (x - dx) y a s o f + Shape (x - dx) y a s o f {-| Move shapes to the right. @@ -1131,15 +1258,16 @@ moveLeft dx (Shape x y a s o f) = import Playground exposing (..) main = - picture - [ square purple 20 - |> moveRight 80 - |> moveDown 100 - ] + picture + [ square purple 20 + |> moveRight 80 + |> moveDown 100 + ] + -} moveRight : Number -> Shape -> Shape moveRight = - moveX + moveX {-| Move the `x` coordinate of a shape by some amount. Here is a square that @@ -1148,18 +1276,19 @@ moves back and forth: import Playground exposing (..) main = - animation view + animation view view time = - [ square purple 20 - |> moveX (wave 4 -200 200 time) - ] + [ square purple 20 + |> moveX (wave 4 -200 200 time) + ] Using `moveX` feels a bit nicer here because the movement may be positive or negative. + -} moveX : Number -> Shape -> Shape moveX dx (Shape x y a s o f) = - Shape (x + dx) y a s o f + Shape (x + dx) y a s o f {-| Move the `y` coordinate of a shape by some amount. Maybe you want to make @@ -1168,22 +1297,23 @@ grass along the bottom of the screen: import Playground exposing (..) main = - game view update 0 + game view update 0 update computer memory = - memory + memory view computer count = - [ rectangle green computer.screen.width 100 - |> moveY computer.screen.bottom - ] + [ rectangle green computer.screen.width 100 + |> moveY computer.screen.bottom + ] Using `moveY` feels a bit nicer when setting things relative to the bottom or top of the screen, since the values are negative sometimes. + -} moveY : Number -> Shape -> Shape moveY dy (Shape x y a s o f) = - Shape x (y + dy) a s o f + Shape x (y + dy) a s o f {-| Make a shape bigger or smaller. So if you wanted some [`words`](#words) to @@ -1192,14 +1322,15 @@ be larger, you could say: import Playground exposing (..) main = - picture - [ words black "Hello, nice to see you!" - |> scale 3 - ] + picture + [ words black "Hello, nice to see you!" + |> scale 3 + ] + -} scale : Number -> Shape -> Shape scale ns (Shape x y a s o f) = - Shape x y a (s * ns) o f + Shape x y a (s * ns) o f {-| Rotate shapes in degrees. @@ -1207,17 +1338,18 @@ scale ns (Shape x y a s o f) = import Playground exposing (..) main = - picture - [ words black "These words are tilted!" - |> rotate 10 - ] + picture + [ words black "These words are tilted!" + |> rotate 10 + ] The degrees go **counter-clockwise** to match the direction of the [unit circle](https://en.wikipedia.org/wiki/Unit_circle). + -} rotate : Number -> Shape -> Shape rotate da (Shape x y a s o f) = - Shape x y (a + da) s o f + Shape x y (a + da) s o f {-| Fade a shape. This lets you make shapes see-through or even completely @@ -1226,20 +1358,21 @@ invisible. Here is a shape that fades in and out: import Playground exposing (..) main = - animation view + animation view view time = - [ square orange 30 - , square blue 200 - |> fade (zigzag 0 1 3 time) - ] + [ square orange 30 + , square blue 200 + |> fade (zigzag 0 1 3 time) + ] The number has to be between `0` and `1`, where `0` is totally transparent and `1` is completely solid. + -} fade : Number -> Shape -> Shape fade o (Shape x y a s _ f) = - Shape x y a s o f + Shape x y a s o f @@ -1254,205 +1387,207 @@ light and dark version, so you always get a set like `lightYellow`, `yellow`, and `darkYellow`. [tango]: https://en.wikipedia.org/wiki/Tango_Desktop_Project + -} type Color - = Hex String - | Rgb Int Int Int + = Hex String + | Rgb Int Int Int -{-|-} +{-| -} lightYellow : Color lightYellow = - Hex "#fce94f" + Hex "#fce94f" -{-|-} +{-| -} yellow : Color yellow = - Hex "#edd400" + Hex "#edd400" -{-|-} +{-| -} darkYellow : Color darkYellow = - Hex "#c4a000" + Hex "#c4a000" -{-|-} +{-| -} lightOrange : Color lightOrange = - Hex "#fcaf3e" + Hex "#fcaf3e" -{-|-} +{-| -} orange : Color orange = - Hex "#f57900" + Hex "#f57900" -{-|-} +{-| -} darkOrange : Color darkOrange = - Hex "#ce5c00" + Hex "#ce5c00" -{-|-} +{-| -} lightBrown : Color lightBrown = - Hex "#e9b96e" + Hex "#e9b96e" -{-|-} +{-| -} brown : Color brown = - Hex "#c17d11" + Hex "#c17d11" -{-|-} +{-| -} darkBrown : Color darkBrown = - Hex "#8f5902" + Hex "#8f5902" -{-|-} +{-| -} lightGreen : Color lightGreen = - Hex "#8ae234" + Hex "#8ae234" -{-|-} +{-| -} green : Color green = - Hex "#73d216" + Hex "#73d216" -{-|-} +{-| -} darkGreen : Color darkGreen = - Hex "#4e9a06" + Hex "#4e9a06" -{-|-} +{-| -} lightBlue : Color lightBlue = - Hex "#729fcf" + Hex "#729fcf" -{-|-} +{-| -} blue : Color blue = - Hex "#3465a4" + Hex "#3465a4" -{-|-} +{-| -} darkBlue : Color darkBlue = - Hex "#204a87" + Hex "#204a87" -{-|-} +{-| -} lightPurple : Color lightPurple = - Hex "#ad7fa8" + Hex "#ad7fa8" -{-|-} +{-| -} purple : Color purple = - Hex "#75507b" + Hex "#75507b" -{-|-} +{-| -} darkPurple : Color darkPurple = - Hex "#5c3566" + Hex "#5c3566" -{-|-} +{-| -} lightRed : Color lightRed = - Hex "#ef2929" + Hex "#ef2929" -{-|-} +{-| -} red : Color red = - Hex "#cc0000" + Hex "#cc0000" -{-|-} +{-| -} darkRed : Color darkRed = - Hex "#a40000" + Hex "#a40000" -{-|-} +{-| -} lightGrey : Color lightGrey = - Hex "#eeeeec" + Hex "#eeeeec" -{-|-} +{-| -} grey : Color grey = - Hex "#d3d7cf" + Hex "#d3d7cf" -{-|-} +{-| -} darkGrey : Color darkGrey = - Hex "#babdb6" + Hex "#babdb6" -{-|-} +{-| -} lightCharcoal : Color lightCharcoal = - Hex "#888a85" + Hex "#888a85" -{-|-} +{-| -} charcoal : Color charcoal = - Hex "#555753" + Hex "#555753" -{-|-} +{-| -} darkCharcoal : Color darkCharcoal = - Hex "#2e3436" + Hex "#2e3436" -{-|-} +{-| -} white : Color white = - Hex "#FFFFFF" + Hex "#FFFFFF" -{-|-} +{-| -} black : Color black = - Hex "#000000" + Hex "#000000" + -- ALTERNATE SPELLING GREYS -{-|-} +{-| -} lightGray : Color lightGray = - Hex "#eeeeec" + Hex "#eeeeec" -{-|-} +{-| -} gray : Color gray = - Hex "#d3d7cf" + Hex "#d3d7cf" -{-|-} +{-| -} darkGray : Color darkGray = - Hex "#babdb6" + Hex "#babdb6" @@ -1462,26 +1597,32 @@ darkGray = {-| RGB stands for Red-Green-Blue. With these three parts, you can create any color you want. For example: - brightBlue = rgb 18 147 216 - brightGreen = rgb 119 244 8 - brightPurple = rgb 94 28 221 + brightBlue = + rgb 18 147 216 + + brightGreen = + rgb 119 244 8 + + brightPurple = + rgb 94 28 221 Each number needs to be between 0 and 255. It can be hard to figure out what numbers to pick, so try using a color picker -like [paletton][] to find colors that look nice together. Once you find nice +like [paletton] to find colors that look nice together. Once you find nice colors, click on the color previews to get their RGB values. [paletton]: http://paletton.com/ + -} rgb : Number -> Number -> Number -> Color rgb r g b = - Rgb (colorClamp r) (colorClamp g) (colorClamp b) + Rgb (colorClamp r) (colorClamp g) (colorClamp b) colorClamp : Number -> Int colorClamp number = - clamp 0 255 (round number) + clamp 0 255 (round number) @@ -1490,52 +1631,62 @@ colorClamp number = render : Screen -> List Shape -> Html.Html msg render screen shapes = - let - w = String.fromFloat screen.width - h = String.fromFloat screen.height - x = String.fromFloat screen.left - y = String.fromFloat screen.bottom - in - svg - [ viewBox (x ++ " " ++ y ++ " " ++ w ++ " " ++ h) - , H.style "position" "fixed" - , H.style "top" "0" - , H.style "left" "0" - , width "100%" - , height "100%" - ] - (List.map renderShape shapes) + let + w = + String.fromFloat screen.width + + h = + String.fromFloat screen.height + + x = + String.fromFloat screen.left + + y = + String.fromFloat screen.bottom + in + svg + [ viewBox (x ++ " " ++ y ++ " " ++ w ++ " " ++ h) + , H.style "position" "fixed" + , H.style "top" "0" + , H.style "left" "0" + , width "100%" + , height "100%" + ] + (List.map renderShape shapes) + -- TODO try adding Svg.Lazy to renderShape -- + + renderShape : Shape -> Svg msg renderShape (Shape x y angle s alpha form) = - case form of - Circle color radius -> - renderCircle color radius x y angle s alpha + case form of + Circle color radius -> + renderCircle color radius x y angle s alpha - Oval color width height -> - renderOval color width height x y angle s alpha + Oval color width height -> + renderOval color width height x y angle s alpha - Rectangle color width height -> - renderRectangle color width height x y angle s alpha + Rectangle color width height -> + renderRectangle color width height x y angle s alpha - Ngon color n radius -> - renderNgon color n radius x y angle s alpha + Ngon color n radius -> + renderNgon color n radius x y angle s alpha - Polygon color points -> - renderPolygon color points x y angle s alpha + Polygon color points -> + renderPolygon color points x y angle s alpha - Image width height src -> - renderImage width height src x y angle s alpha + Image width height src -> + renderImage width height src x y angle s alpha - Words color string -> - renderWords color string x y angle s alpha + Words color string -> + renderWords color string x y angle s alpha - Group shapes -> - g (transform (renderTransform x y angle s) :: renderAlpha alpha) - (List.map renderShape shapes) + Group shapes -> + g (transform (renderTransform x y angle s) :: renderAlpha alpha) + (List.map renderShape shapes) @@ -1544,25 +1695,25 @@ renderShape (Shape x y angle s alpha form) = renderCircle : Color -> Number -> Number -> Number -> Number -> Number -> Number -> Svg msg renderCircle color radius x y angle s alpha = - Svg.circle - ( r (String.fromFloat radius) - :: fill (renderColor color) - :: transform (renderTransform x y angle s) - :: renderAlpha alpha - ) - [] + Svg.circle + (r (String.fromFloat radius) + :: fill (renderColor color) + :: transform (renderTransform x y angle s) + :: renderAlpha alpha + ) + [] renderOval : Color -> Number -> Number -> Number -> Number -> Number -> Number -> Number -> Svg msg renderOval color width height x y angle s alpha = - ellipse - ( rx (String.fromFloat (width / 2)) - :: ry (String.fromFloat (height / 2)) - :: fill (renderColor color) - :: transform (renderTransform x y angle s) - :: renderAlpha alpha - ) - [] + ellipse + (rx (String.fromFloat (width / 2)) + :: ry (String.fromFloat (height / 2)) + :: fill (renderColor color) + :: transform (renderTransform x y angle s) + :: renderAlpha alpha + ) + [] @@ -1571,32 +1722,36 @@ renderOval color width height x y angle s alpha = renderRectangle : Color -> Number -> Number -> Number -> Number -> Number -> Number -> Number -> Svg msg renderRectangle color w h x y angle s alpha = - rect - ( width (String.fromFloat w) - :: height (String.fromFloat h) - :: fill (renderColor color) - :: transform (renderRectTransform w h x y angle s) - :: renderAlpha alpha - ) - [] + rect + (width (String.fromFloat w) + :: height (String.fromFloat h) + :: fill (renderColor color) + :: transform (renderRectTransform w h x y angle s) + :: renderAlpha alpha + ) + [] renderRectTransform : Number -> Number -> Number -> Number -> Number -> Number -> String renderRectTransform width height x y angle s = - renderTransform x y angle s - ++ " translate(" ++ String.fromFloat (-width/2) ++ "," ++ String.fromFloat (-height/2) ++ ")" + renderTransform x y angle s + ++ " translate(" + ++ String.fromFloat (-width / 2) + ++ "," + ++ String.fromFloat (-height / 2) + ++ ")" renderImage : Number -> Number -> String -> Number -> Number -> Number -> Number -> Number -> Svg msg renderImage w h src x y angle s alpha = - Svg.image - ( xlinkHref src - :: width (String.fromFloat w) - :: height (String.fromFloat h) - :: transform (renderRectTransform w h x y angle s) - :: renderAlpha alpha - ) - [] + Svg.image + (xlinkHref src + :: width (String.fromFloat w) + :: height (String.fromFloat h) + :: transform (renderRectTransform w h x y angle s) + :: renderAlpha alpha + ) + [] @@ -1605,46 +1760,52 @@ renderImage w h src x y angle s alpha = renderNgon : Color -> Int -> Number -> Number -> Number -> Number -> Number -> Number -> Svg msg renderNgon color n radius x y angle s alpha = - Svg.polygon - ( points (toNgonPoints 0 n radius "") - :: fill (renderColor color) - :: transform (renderTransform x y angle s) - :: renderAlpha alpha - ) - [] + Svg.polygon + (points (toNgonPoints 0 n radius "") + :: fill (renderColor color) + :: transform (renderTransform x y angle s) + :: renderAlpha alpha + ) + [] toNgonPoints : Int -> Int -> Float -> String -> String toNgonPoints i n radius string = - if i == n then - string - else - let - a = turns (toFloat i / toFloat n - 0.25) - x = radius * cos a - y = radius * sin a - in - toNgonPoints (i + 1) n radius (string ++ String.fromFloat x ++ "," ++ String.fromFloat y ++ " ") + if i == n then + string + + else + let + a = + turns (toFloat i / toFloat n - 0.25) + + x = + radius * cos a + + y = + radius * sin a + in + toNgonPoints (i + 1) n radius (string ++ String.fromFloat x ++ "," ++ String.fromFloat y ++ " ") -- RENDER POLYGON -renderPolygon : Color -> List (Number, Number) -> Number -> Number -> Number -> Number -> Number -> Svg msg +renderPolygon : Color -> List ( Number, Number ) -> Number -> Number -> Number -> Number -> Number -> Svg msg renderPolygon color coordinates x y angle s alpha = - Svg.polygon - ( points (List.foldl addPoint "" coordinates) - :: fill (renderColor color) - :: transform (renderTransform x y angle s) - :: renderAlpha alpha - ) - [] + Svg.polygon + (points (List.foldl addPoint "" coordinates) + :: fill (renderColor color) + :: transform (renderTransform x y angle s) + :: renderAlpha alpha + ) + [] -addPoint : (Float, Float) -> String -> String -addPoint (x,y) str = - str ++ String.fromFloat x ++ "," ++ String.fromFloat y ++ " " +addPoint : ( Float, Float ) -> String -> String +addPoint ( x, y ) str = + str ++ String.fromFloat x ++ "," ++ String.fromFloat y ++ " " @@ -1653,15 +1814,15 @@ addPoint (x,y) str = renderWords : Color -> String -> Number -> Number -> Number -> Number -> Number -> Svg msg renderWords color string x y angle s alpha = - text_ - ( textAnchor "middle" - :: dominantBaseline "central" - :: fill (renderColor color) - :: transform (renderTransform x y angle s) - :: renderAlpha alpha - ) - [ text string - ] + text_ + (textAnchor "middle" + :: dominantBaseline "central" + :: fill (renderColor color) + :: transform (renderTransform x y angle s) + :: renderAlpha alpha + ) + [ text string + ] @@ -1670,12 +1831,12 @@ renderWords color string x y angle s alpha = renderColor : Color -> String renderColor color = - case color of - Hex str -> - str + case color of + Hex str -> + str - Rgb r g b -> - "rgb(" ++ String.fromInt r ++ "," ++ String.fromInt g ++ "," ++ String.fromInt b ++ ")" + Rgb r g b -> + "rgb(" ++ String.fromInt r ++ "," ++ String.fromInt g ++ "," ++ String.fromInt b ++ ")" @@ -1684,10 +1845,11 @@ renderColor color = renderAlpha : Number -> List (Svg.Attribute msg) renderAlpha alpha = - if alpha == 1 then - [] - else - [ opacity (String.fromFloat (clamp 0 1 alpha)) ] + if alpha == 1 then + [] + + else + [ opacity (String.fromFloat (clamp 0 1 alpha)) ] @@ -1696,13 +1858,15 @@ renderAlpha alpha = renderTransform : Number -> Number -> Number -> Number -> String renderTransform x y a s = - if a == 0 then - if s == 1 then - "translate(" ++ String.fromFloat x ++ "," ++ String.fromFloat -y ++ ")" - else - "translate(" ++ String.fromFloat x ++ "," ++ String.fromFloat -y ++ ") scale(" ++ String.fromFloat s ++ ")" - else - if s == 1 then - "translate(" ++ String.fromFloat x ++ "," ++ String.fromFloat -y ++ ") rotate(" ++ String.fromFloat -a ++ ")" + if a == 0 then + if s == 1 then + "translate(" ++ String.fromFloat x ++ "," ++ String.fromFloat -y ++ ")" + + else + "translate(" ++ String.fromFloat x ++ "," ++ String.fromFloat -y ++ ") scale(" ++ String.fromFloat s ++ ")" + + else if s == 1 then + "translate(" ++ String.fromFloat x ++ "," ++ String.fromFloat -y ++ ") rotate(" ++ String.fromFloat -a ++ ")" + else - "translate(" ++ String.fromFloat x ++ "," ++ String.fromFloat -y ++ ") rotate(" ++ String.fromFloat -a ++ ") scale(" ++ String.fromFloat s ++ ")" + "translate(" ++ String.fromFloat x ++ "," ++ String.fromFloat -y ++ ") rotate(" ++ String.fromFloat -a ++ ") scale(" ++ String.fromFloat s ++ ")"