Skip to content

Instantly share code, notes, and snippets.

@deadfoxygrandpa
Last active January 28, 2016 17:08
Show Gist options
  • Save deadfoxygrandpa/111dacb14e08ca5bce07 to your computer and use it in GitHub Desktop.
Save deadfoxygrandpa/111dacb14e08ca5bce07 to your computer and use it in GitHub Desktop.
React Animation Example with elm-html-animation
module Button (Model, Action, init, update, view) where
import Html
import Html.Attributes
import Html.Events
import Html.Animation
import Easing
import Effects
-- Model
type alias Model =
{ open : Bool
, children : List { style : Html.Animation.Animation, txt : String }
, style : Html.Animation.Animation
, radius : Float
}
type alias ID =
Int
init : Float -> ( Model, Effects.Effects Action )
init radius =
let
anim =
Html.Animation.init
[ Html.Animation.Width radius Html.Animation.Px
, Html.Animation.Height radius Html.Animation.Px
, Html.Animation.Top (-radius / 2) Html.Animation.Px
, Html.Animation.Left (-radius / 2) Html.Animation.Px
]
in
( { open = False
, children = List.map (\i -> { style = anim, txt = Basics.toString i }) [1..5]
, style =
Html.Animation.init
[ Html.Animation.Width 90 Html.Animation.Px
, Html.Animation.Height 90 Html.Animation.Px
, Html.Animation.Top (-90 / 2) Html.Animation.Px
, Html.Animation.Left (-90 / 2) Html.Animation.Px
, Html.Animation.Rotate 0 Html.Animation.Deg
]
, radius = radius
}
, Effects.none
)
-- Update
type Action
= NoOp
| Open
| Close
| Toggle
| OpenChild Int
| CloseChild Int
| AnimateChild Int Html.Animation.Action
| Animate Html.Animation.Action
children =
5
flyOutRadius =
120
separationAngle =
40
fanAngle =
(children - 1) * separationAngle
baseAngle =
((180 - fanAngle) / 2)
update : Action -> Model -> ( Model, Effects.Effects Action )
update action model =
case action of
NoOp ->
( model, Effects.none )
Animate action ->
let
( anim, fx ) = Html.Animation.update action model.style
in
( { model | style = anim }, Effects.map Animate fx )
AnimateChild i action ->
let
( children, fx ) =
forwardToChild i model.children action
in
( { model | children = children }, Effects.map (AnimateChild i) fx )
OpenChild i ->
let
( x, y ) = finalPosition model.radius i
( children, fx ) =
Html.Animation.animate
|> Html.Animation.duration (100 * toFloat i)
|> Html.Animation.andThen
|> Html.Animation.props
[ Html.Animation.Left (Html.Animation.to x) Html.Animation.Px
, Html.Animation.Top (Html.Animation.to -y) Html.Animation.Px
]
|> Html.Animation.easing Easing.easeOutSine
|> Html.Animation.duration 100
|> forwardToChild i model.children
in
( { model | children = children }, Effects.map (AnimateChild i) fx )
CloseChild i ->
let
( children, fx ) =
Html.Animation.animate
|> Html.Animation.duration (100 * toFloat i)
|> Html.Animation.andThen
|> Html.Animation.props
[ Html.Animation.Left (Html.Animation.to (-model.radius / 2)) Html.Animation.Px
, Html.Animation.Top (Html.Animation.to (-model.radius / 2)) Html.Animation.Px
]
|> Html.Animation.easing Easing.easeOutSine
|> Html.Animation.duration 100
|> forwardToChild i model.children
in
( { model | children = children }, Effects.map (AnimateChild i) fx )
Open ->
let
( anim, fx ) =
Html.Animation.animate
|> Html.Animation.props
[ Html.Animation.Rotate (Html.Animation.to 45) Html.Animation.Deg ]
|> Html.Animation.duration 100
|> Html.Animation.on model.style
in
List.foldl
(\i ( model, fx ) ->
let
( model', fx' ) = update (OpenChild i) model
in
( model', Effects.batch [ fx, fx' ] )
)
( { model | style = anim }, Effects.map Animate fx )
[0..List.length model.children]
Close ->
let
( anim, fx ) =
Html.Animation.animate
|> Html.Animation.props
[ Html.Animation.Rotate (Html.Animation.to 0) Html.Animation.Deg ]
|> Html.Animation.duration 100
|> Html.Animation.on model.style
in
List.foldl
(\i ( model, fx ) ->
let
( model', fx' ) = update (CloseChild i) model
in
( model', Effects.batch [ fx, fx' ] )
)
( { model | style = anim }, Effects.map Animate fx )
[0..List.length model.children]
Toggle ->
if model.open then
update Close { model | open = False }
else
update Open { model | open = True }
forwardToChild =
Html.Animation.forwardTo .style (\model style -> { model | style = style })
finalPosition : Float -> Int -> ( Float, Float )
finalPosition radius i =
let
angle = (baseAngle + (toFloat i * separationAngle)) |> Basics.degrees
in
( flyOutRadius * (Basics.cos angle) - (radius / 2)
, flyOutRadius * (Basics.sin angle) + (radius / 2)
)
-- View
view : Signal.Address Action -> Model -> Html.Html
view address model =
Html.div
[ Html.Attributes.style
[ ( "position", "absolute" ) ]
]
<| [ Html.div
[ Html.Attributes.style
<| [ ( "position", "absolute" )
, ( "zIndex", "999" )
, ( "borderRadius", "50%" )
, ( "background", "#68AEF0" )
, ( "textAlign", "center" )
, ( "verticalAlign", "middle" )
, ( "lineHeight", "90px" )
, ( "color", "#FFFFFF" )
, ( "fontSize", "40px" )
]
++ (Html.Animation.render model.style)
, Html.Events.onClick address Toggle
]
[ Html.text "+" ]
]
++ (List.map
(\child ->
Html.div
[ Html.Attributes.style
<| [ ( "position", "absolute" )
, ( "borderRadius", "50%" )
, ( "background", "#DDDDDD" )
]
++ (Html.Animation.render child.style)
]
[]
)
model.children
)
module Main (..) where
import Html
import Html.Attributes
import Task
import Effects
import StartApp
import Button
-- Model
type alias Model =
{ button : Button.Model }
init : ( Model, Effects.Effects Action )
init =
( { button = fst (Button.init 50) }, Effects.none )
-- Update
type Action
= NoOp
| ButtonAction Button.Action
update : Action -> Model -> ( Model, Effects.Effects Action )
update action model =
case action of
NoOp ->
( model, Effects.none )
ButtonAction action ->
let
( button, fx ) = Button.update action model.button
in
( { model | button = button }, Effects.map ButtonAction fx )
-- View
view : Signal.Address Action -> Model -> Html.Html
view address model =
Html.div
[ Html.Attributes.style
[ ( "position", "absolute" )
, ( "top", "250px" )
, ( "left", "250px" )
]
]
[ Button.view (Signal.forwardTo address ButtonAction) model.button
]
-- App
app : StartApp.App Model
app =
StartApp.start
{ init = init
, update = update
, view = view
, inputs = []
}
port tasks : Signal (Task.Task Effects.Never ())
port tasks =
app.tasks
main : Signal Html.Html
main =
app.html
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment