mirror of
https://github.com/mdgriffith/elm-animator.git
synced 2024-09-11 12:47:52 +03:00
Compare commits
8 Commits
92161e952a
...
22fb914de9
Author | SHA1 | Date | |
---|---|---|---|
|
22fb914de9 | ||
|
4d296736de | ||
|
57605f4380 | ||
|
b19ce307c2 | ||
|
4e100456ed | ||
|
e7a0b4bbb8 | ||
|
2049391907 | ||
|
6f15554870 |
@ -3,81 +3,95 @@ module Basic exposing (main)
|
||||
{-| -}
|
||||
|
||||
import Animator
|
||||
import Browser
|
||||
import Animator.Transition as Transition
|
||||
import Color
|
||||
import Html exposing (..)
|
||||
import Html exposing (Html)
|
||||
import Html.Attributes as Attr
|
||||
import Html.Events as Events
|
||||
import Time
|
||||
|
||||
|
||||
type alias Model =
|
||||
{}
|
||||
|
||||
|
||||
main =
|
||||
Browser.sandbox
|
||||
{ init =
|
||||
{}
|
||||
, view = view
|
||||
, update = update
|
||||
}
|
||||
|
||||
|
||||
type Msg
|
||||
= Check Bool
|
||||
|
||||
|
||||
update : Msg -> Model -> Model
|
||||
update msg model =
|
||||
case msg of
|
||||
Check newChecked ->
|
||||
model
|
||||
|
||||
|
||||
view : Model -> Html Msg
|
||||
view model =
|
||||
div
|
||||
[ Attr.class "root"
|
||||
Html.div
|
||||
[ Attr.style "display" "flex"
|
||||
, Attr.style "flex-direction" "column"
|
||||
, Attr.style "gap" "40px"
|
||||
, Attr.style "width" "100vw"
|
||||
, Attr.style "height" "100vh"
|
||||
, Attr.style "justify-content" "center"
|
||||
, Attr.style "align-items" "center"
|
||||
]
|
||||
[ stylesheet
|
||||
, box (Animator.spinning (Animator.ms 2000))
|
||||
, box (Animator.spinning (Animator.ms 1500))
|
||||
, box (Animator.spinning (Animator.ms 1000))
|
||||
, title "Some built-in animations"
|
||||
, Html.div [ Attr.style "display" "flex", Attr.style "gap" "40px" ]
|
||||
[ box (Animator.spinning (Animator.ms 500))
|
||||
, box (Animator.pulsing (Animator.ms 2000))
|
||||
, box (Animator.pinging (Animator.ms 1000))
|
||||
, box (Animator.bouncing (Animator.ms 1000) 40)
|
||||
]
|
||||
, title "Animating with springs"
|
||||
, Html.div [ Attr.style "display" "flex", Attr.style "gap" "40px" ]
|
||||
[ box (spinning { wobble = 0, duration = Animator.ms 1000 })
|
||||
, box (spinning { wobble = 0.5, duration = Animator.ms 1000 })
|
||||
, box (spinning { wobble = 1, duration = Animator.ms 1000 })
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
box animation =
|
||||
Animator.div animation
|
||||
[ Attr.class "box"
|
||||
title : String -> Html msg
|
||||
title text =
|
||||
Html.h1
|
||||
[ Attr.style "font-size" "2em"
|
||||
, Attr.style "font-weight" "bold"
|
||||
]
|
||||
[ Html.text text ]
|
||||
|
||||
|
||||
spinning : { wobble : Float, duration : Animator.Duration } -> Animator.Animation
|
||||
spinning { wobble, duration } =
|
||||
Animator.keyframes
|
||||
[ Animator.loop
|
||||
[ Animator.set
|
||||
[ Animator.rotation 0
|
||||
]
|
||||
, Animator.step duration
|
||||
[ Animator.rotation 0.5
|
||||
|> Animator.withTransition
|
||||
(Transition.spring
|
||||
{ wobble = wobble
|
||||
, quickness = 0
|
||||
}
|
||||
)
|
||||
]
|
||||
]
|
||||
]
|
||||
[]
|
||||
|
||||
|
||||
stylesheet : Html msg
|
||||
stylesheet =
|
||||
Html.node "style"
|
||||
[]
|
||||
[ text """@import url('https://fonts.googleapis.com/css?family=Roboto&display=swap');
|
||||
[ Html.text """
|
||||
|
||||
.root {
|
||||
display: flex;
|
||||
|
||||
}
|
||||
.root > * {
|
||||
margin-right: 20px;
|
||||
body {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
font-family: "EB Garamond", serif;
|
||||
}
|
||||
|
||||
.box {
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
border-radius: 20%;
|
||||
background-color:red;
|
||||
border-color: black;
|
||||
border-style: solid;
|
||||
}
|
||||
|
||||
"""
|
||||
]
|
||||
|
||||
|
||||
box animation =
|
||||
Animator.div animation
|
||||
[ Attr.class "box"
|
||||
, Attr.style "box-sizing" "border-box"
|
||||
, Attr.style "position" "relative"
|
||||
, Attr.style "width" "100px"
|
||||
, Attr.style "height" "100px"
|
||||
, Attr.style "border-radius" "20%"
|
||||
, Attr.style "background-color" "red"
|
||||
, Attr.style "border-color" "black"
|
||||
, Attr.style "border-style" "solid"
|
||||
]
|
||||
[]
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"type": "application",
|
||||
"source-directories": [
|
||||
".",
|
||||
"src",
|
||||
"../src"
|
||||
],
|
||||
"elm-version": "0.19.1",
|
||||
@ -9,33 +9,35 @@
|
||||
"direct": {
|
||||
"avh4/elm-color": "1.0.0",
|
||||
"elm/browser": "1.0.2",
|
||||
"elm/core": "1.0.2",
|
||||
"elm/core": "1.0.5",
|
||||
"elm/html": "1.0.0",
|
||||
"elm/json": "1.1.3",
|
||||
"elm/svg": "1.0.1",
|
||||
"elm/time": "1.0.0",
|
||||
"elm/url": "1.0.0",
|
||||
"ianmackenzie/elm-geometry": "2.0.0",
|
||||
"ianmackenzie/elm-units": "2.2.0",
|
||||
"terezka/line-charts": "2.0.0"
|
||||
"ianmackenzie/elm-geometry": "4.0.0",
|
||||
"ianmackenzie/elm-units": "2.10.0",
|
||||
"mdgriffith/elm-bezier": "1.0.0",
|
||||
"terezka/line-charts": "2.0.2"
|
||||
},
|
||||
"indirect": {
|
||||
"debois/elm-dom": "1.3.0",
|
||||
"elm/parser": "1.1.0",
|
||||
"elm/virtual-dom": "1.0.2",
|
||||
"elm/random": "1.0.0",
|
||||
"elm/virtual-dom": "1.0.3",
|
||||
"ianmackenzie/elm-1d-parameter": "1.0.1",
|
||||
"ianmackenzie/elm-float-extra": "1.1.0",
|
||||
"ianmackenzie/elm-interval": "2.0.0",
|
||||
"ianmackenzie/elm-triangular-mesh": "1.0.2",
|
||||
"ianmackenzie/elm-units-interval": "1.0.0",
|
||||
"justinmimbs/date": "3.2.0",
|
||||
"justinmimbs/time-extra": "1.1.0",
|
||||
"myrho/elm-round": "1.0.4",
|
||||
"ryannhg/date-format": "2.3.0"
|
||||
"ianmackenzie/elm-interval": "3.1.0",
|
||||
"ianmackenzie/elm-triangular-mesh": "1.1.0",
|
||||
"ianmackenzie/elm-units-interval": "3.2.0",
|
||||
"justinmimbs/date": "4.1.0",
|
||||
"justinmimbs/time-extra": "1.2.0",
|
||||
"myrho/elm-round": "1.0.5",
|
||||
"ryan-haskell/date-format": "1.0.0"
|
||||
}
|
||||
},
|
||||
"test-dependencies": {
|
||||
"direct": {},
|
||||
"indirect": {}
|
||||
}
|
||||
}
|
||||
}
|
92
examples-new/src/AnimationX.elm
Normal file
92
examples-new/src/AnimationX.elm
Normal file
@ -0,0 +1,92 @@
|
||||
module AnimationX exposing (main)
|
||||
|
||||
import Animator
|
||||
import Animator.Timeline
|
||||
import Animator.Transition
|
||||
import Animator.Value
|
||||
import Browser
|
||||
import Browser.Events
|
||||
import Html
|
||||
import Html.Events
|
||||
import Time
|
||||
|
||||
|
||||
main : Program () Model Msg
|
||||
main =
|
||||
Browser.element
|
||||
{ init = always init
|
||||
, update = update
|
||||
, subscriptions = subscriptions
|
||||
, view = view
|
||||
}
|
||||
|
||||
|
||||
type alias Model =
|
||||
{ timeline : Animator.Timeline.Timeline Float }
|
||||
|
||||
|
||||
type Msg
|
||||
= NewPosix Time.Posix
|
||||
| Start
|
||||
|
||||
|
||||
init : ( Model, Cmd Msg )
|
||||
init =
|
||||
let
|
||||
initialTimeline : Animator.Timeline.Timeline Float
|
||||
initialTimeline =
|
||||
Animator.Timeline.init 10
|
||||
|
||||
queuedSteps : List (Animator.Timeline.Step Float)
|
||||
queuedSteps =
|
||||
[ Animator.Timeline.transitionTo (Animator.ms 1000) 100
|
||||
, Animator.Timeline.transitionTo (Animator.ms 1000) 50
|
||||
, Animator.Timeline.transitionTo (Animator.ms 1000) 5
|
||||
]
|
||||
|
||||
timelineWithSteps : Animator.Timeline.Timeline Float
|
||||
timelineWithSteps =
|
||||
Animator.Timeline.scale 3 <| Animator.Timeline.queue queuedSteps initialTimeline
|
||||
in
|
||||
( { timeline = timelineWithSteps }
|
||||
, Cmd.none
|
||||
)
|
||||
|
||||
|
||||
update : Msg -> Model -> ( Model, Cmd Msg )
|
||||
update msg model =
|
||||
case msg of
|
||||
NewPosix posix ->
|
||||
( { model | timeline = Animator.Timeline.update posix model.timeline }, Cmd.none )
|
||||
|
||||
Start ->
|
||||
init
|
||||
|
||||
|
||||
subscriptions : Model -> Sub Msg
|
||||
subscriptions model =
|
||||
if Animator.Timeline.isRunning model.timeline then
|
||||
Browser.Events.onAnimationFrame NewPosix
|
||||
|
||||
else
|
||||
Sub.none
|
||||
|
||||
|
||||
view : Model -> Html.Html Msg
|
||||
view model =
|
||||
let
|
||||
positionStandard : Float
|
||||
positionStandard =
|
||||
Animator.Value.float model.timeline Animator.Value.to
|
||||
|
||||
positionLinear : Float
|
||||
positionLinear =
|
||||
Animator.Value.float model.timeline (Animator.Value.withTransition Animator.Transition.linear << Animator.Value.to)
|
||||
in
|
||||
Html.div []
|
||||
[ Html.div []
|
||||
[ Html.div [] [ Html.text ("Position Standard: " ++ String.fromFloat positionStandard) ]
|
||||
, Html.div [] [ Html.text ("Position Linear: " ++ String.fromFloat positionLinear) ]
|
||||
]
|
||||
, Html.button [ Html.Events.onClick Start ] [ Html.text "Re-Start" ]
|
||||
]
|
83
examples-new/src/Basic.elm
Normal file
83
examples-new/src/Basic.elm
Normal file
@ -0,0 +1,83 @@
|
||||
module Basic exposing (main)
|
||||
|
||||
{-| -}
|
||||
|
||||
import Animator
|
||||
import Browser
|
||||
import Color
|
||||
import Html exposing (..)
|
||||
import Html.Attributes as Attr
|
||||
import Html.Events as Events
|
||||
import Time
|
||||
|
||||
|
||||
type alias Model =
|
||||
{}
|
||||
|
||||
|
||||
main =
|
||||
Browser.sandbox
|
||||
{ init =
|
||||
{}
|
||||
, view = view
|
||||
, update = update
|
||||
}
|
||||
|
||||
|
||||
type Msg
|
||||
= Check Bool
|
||||
|
||||
|
||||
update : Msg -> Model -> Model
|
||||
update msg model =
|
||||
case msg of
|
||||
Check newChecked ->
|
||||
model
|
||||
|
||||
|
||||
view : Model -> Html Msg
|
||||
view model =
|
||||
div
|
||||
[ Attr.class "root"
|
||||
]
|
||||
[ stylesheet
|
||||
, box (Animator.spinning (Animator.ms 2000))
|
||||
, box (Animator.spinning (Animator.ms 1500))
|
||||
, box (Animator.spinning (Animator.ms 1000))
|
||||
]
|
||||
|
||||
|
||||
box animation =
|
||||
Animator.div animation
|
||||
[ Attr.class "box"
|
||||
]
|
||||
[]
|
||||
|
||||
|
||||
stylesheet : Html msg
|
||||
stylesheet =
|
||||
Html.node "style"
|
||||
[]
|
||||
[ text """@import url('https://fonts.googleapis.com/css?family=Roboto&display=swap');
|
||||
|
||||
.root {
|
||||
display: flex;
|
||||
|
||||
}
|
||||
.root > * {
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.box {
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
border-radius: 20%;
|
||||
background-color:red;
|
||||
border-color: black;
|
||||
border-style: solid;
|
||||
}
|
||||
|
||||
"""
|
||||
]
|
@ -168,13 +168,14 @@ scaleZ s =
|
||||
InternalAnim.Css.Props.float
|
||||
|
||||
|
||||
{-| -}
|
||||
{-| Given as 'turns'.
|
||||
-}
|
||||
rotation : Float -> Attribute
|
||||
rotation n =
|
||||
Css.Prop
|
||||
InternalAnim.Css.Props.ids.rotation
|
||||
"rotate"
|
||||
(Move.to n)
|
||||
(Move.to (1000 * n))
|
||||
(InternalAnim.Css.Props.turns zAxis)
|
||||
|
||||
|
||||
@ -184,7 +185,7 @@ rotationAround axis n =
|
||||
Css.Prop
|
||||
InternalAnim.Css.Props.ids.rotation
|
||||
"rotate"
|
||||
(Move.to n)
|
||||
(Move.to (1000 * n))
|
||||
(InternalAnim.Css.Props.turns axis)
|
||||
|
||||
|
||||
@ -605,6 +606,8 @@ spinning dur =
|
||||
]
|
||||
, step dur
|
||||
[ rotation 1
|
||||
|> withTransition
|
||||
Animator.Transition.linear
|
||||
]
|
||||
]
|
||||
]
|
||||
@ -613,13 +616,21 @@ spinning dur =
|
||||
{-| -}
|
||||
pulsing : Duration -> Animation
|
||||
pulsing dur =
|
||||
let
|
||||
half =
|
||||
dur
|
||||
|> Quantity.divideBy 2
|
||||
in
|
||||
keyframes
|
||||
[ loop
|
||||
[ set
|
||||
[ opacity 1
|
||||
]
|
||||
, step dur
|
||||
[ opacity 0.5
|
||||
, step half
|
||||
[ opacity 0.4
|
||||
]
|
||||
, step half
|
||||
[ opacity 1
|
||||
]
|
||||
]
|
||||
]
|
||||
@ -661,11 +672,11 @@ pinging dur =
|
||||
keyframes
|
||||
[ loop
|
||||
[ set
|
||||
[ rotation 0
|
||||
[ scale 1
|
||||
, opacity 1
|
||||
]
|
||||
, step dur
|
||||
[ rotation 1
|
||||
[ scale 1.2
|
||||
, opacity 0
|
||||
]
|
||||
]
|
||||
@ -688,7 +699,7 @@ import Html.Attributes
|
||||
Anim.div
|
||||
(Anim.onTimeline model.timeline
|
||||
(\state ->
|
||||
if state.open
|
||||
if state.open then
|
||||
[ Anim.opacity 1
|
||||
]
|
||||
|
||||
|
@ -99,9 +99,7 @@ movement timeline lookup =
|
||||
Timeline.startTime target
|
||||
|
||||
isHappening =
|
||||
(Time.thisAfterOrEqualThat now startTransition
|
||||
&& Time.thisBeforeOrEqualThat now arrived
|
||||
)
|
||||
Time.thisAfterOrEqualThat now startTransition
|
||||
|| (List.isEmpty future
|
||||
&& Time.thisAfterThat now interruptedOrEnd
|
||||
)
|
||||
|
@ -1237,18 +1237,24 @@ getVectorStepAt groupId dur trans seqLevel stepLevel props =
|
||||
{ x =
|
||||
getTransformSequenceValueAt seqLevel
|
||||
stepLevel
|
||||
(Props.groupToCompoundId groupId)
|
||||
x
|
||||
props
|
||||
Nothing
|
||||
, y =
|
||||
getTransformSequenceValueAt seqLevel
|
||||
stepLevel
|
||||
(Props.groupToCompoundId groupId)
|
||||
y
|
||||
props
|
||||
Nothing
|
||||
, z =
|
||||
getTransformSequenceValueAt seqLevel
|
||||
stepLevel
|
||||
(Props.groupToCompoundId groupId)
|
||||
z
|
||||
props
|
||||
Nothing
|
||||
}
|
||||
|
||||
|
||||
@ -1331,31 +1337,44 @@ getTransformStepAt dur trans seqLevel stepLevel props =
|
||||
{ x =
|
||||
getTransformSequenceValueAt seqLevel
|
||||
stepLevel
|
||||
Nothing
|
||||
Props.ids.x
|
||||
props
|
||||
Nothing
|
||||
, y =
|
||||
getTransformSequenceValueAt seqLevel
|
||||
stepLevel
|
||||
Nothing
|
||||
Props.ids.y
|
||||
props
|
||||
Nothing
|
||||
, scale =
|
||||
getTransformSequenceValueAt seqLevel
|
||||
stepLevel
|
||||
Nothing
|
||||
Props.ids.scale
|
||||
props
|
||||
Nothing
|
||||
, rotation =
|
||||
getTransformSequenceValueAt seqLevel
|
||||
stepLevel
|
||||
Nothing
|
||||
Props.ids.rotation
|
||||
props
|
||||
Nothing
|
||||
}
|
||||
|
||||
|
||||
getTransformSequenceValueAt : Int -> Int -> Props.Id -> List Prop -> Float
|
||||
getTransformSequenceValueAt seqLevel stepLevel targetId props =
|
||||
getTransformSequenceValueAt : Int -> Int -> Maybe Props.Id -> Props.Id -> List Prop -> Maybe Float -> Float
|
||||
getTransformSequenceValueAt seqLevel stepLevel maybeDefaultId targetId props defaultValue =
|
||||
case props of
|
||||
[] ->
|
||||
Props.defaultPosition targetId
|
||||
case defaultValue of
|
||||
Nothing ->
|
||||
Props.defaultPosition targetId
|
||||
|
||||
Just default ->
|
||||
default
|
||||
|
||||
(Prop id name move _) :: remain ->
|
||||
if id - targetId == 0 then
|
||||
@ -1374,10 +1393,35 @@ getTransformSequenceValueAt seqLevel stepLevel targetId props =
|
||||
stepValue
|
||||
|
||||
else
|
||||
getTransformSequenceValueAt seqLevel stepLevel targetId remain
|
||||
case maybeDefaultId of
|
||||
Nothing ->
|
||||
getTransformSequenceValueAt seqLevel stepLevel maybeDefaultId targetId remain defaultValue
|
||||
|
||||
Just defaultId ->
|
||||
if id - defaultId == 0 then
|
||||
let
|
||||
newDefaultValue =
|
||||
case move of
|
||||
Move.Pos _ v seq ->
|
||||
case getAt seqLevel seq of
|
||||
Nothing ->
|
||||
v
|
||||
|
||||
Just (Move.Sequence _ _ _ seqSteps) ->
|
||||
case getAt stepLevel seqSteps of
|
||||
Nothing ->
|
||||
v
|
||||
|
||||
Just (Move.Step _ _ stepValue) ->
|
||||
stepValue
|
||||
in
|
||||
getTransformSequenceValueAt seqLevel stepLevel Nothing targetId remain (Just newDefaultValue)
|
||||
|
||||
else
|
||||
getTransformSequenceValueAt seqLevel stepLevel maybeDefaultId targetId remain defaultValue
|
||||
|
||||
(ColorProp name movement) :: remain ->
|
||||
getTransformSequenceValueAt seqLevel stepLevel targetId remain
|
||||
getTransformSequenceValueAt seqLevel stepLevel maybeDefaultId targetId remain defaultValue
|
||||
|
||||
|
||||
getAt : Int -> List a -> Maybe a
|
||||
|
@ -140,7 +140,7 @@ hashFormat form num =
|
||||
String.fromInt (round num) ++ "px"
|
||||
|
||||
Turns vec ->
|
||||
Hash.float num
|
||||
String.fromInt (round num)
|
||||
|
||||
TranslateX ->
|
||||
"translateX(" ++ String.fromInt (round num) ++ "px)"
|
||||
@ -159,7 +159,8 @@ format form num =
|
||||
String.fromInt (round num) ++ "px"
|
||||
|
||||
Turns vec ->
|
||||
vectorToCssString vec ++ " " ++ String.fromFloat (roundFloat num) ++ "turn"
|
||||
-- Number here is 1/1000 of a turn
|
||||
vectorToCssString vec ++ " " ++ String.fromFloat (num / 1000) ++ "turn"
|
||||
|
||||
TranslateX ->
|
||||
"translateX(" ++ String.fromInt (round num) ++ "px)"
|
||||
|
Loading…
Reference in New Issue
Block a user