mirror of
https://github.com/mdgriffith/elm-animator.git
synced 2024-09-11 12:47:52 +03:00
A bunch of elm-review cleanup
This commit is contained in:
parent
65b635e9ef
commit
963d415161
@ -118,16 +118,6 @@ opacity o =
|
||||
InternalAnim.Css.Props.float
|
||||
|
||||
|
||||
{-| -}
|
||||
xAsSingleProp : Float -> Attribute
|
||||
xAsSingleProp o =
|
||||
Css.Prop
|
||||
InternalAnim.Css.Props.ids.opacity
|
||||
"transform"
|
||||
(Move.to o)
|
||||
InternalAnim.Css.Props.translateX
|
||||
|
||||
|
||||
{-| -}
|
||||
scale : Float -> Attribute
|
||||
scale s =
|
||||
@ -189,6 +179,7 @@ rotationAround axis n =
|
||||
(InternalAnim.Css.Props.turns axis)
|
||||
|
||||
|
||||
zAxis : { x : Float, y : Float, z : Float }
|
||||
zAxis =
|
||||
{ x = 0, y = 0, z = 1 }
|
||||
|
||||
@ -261,21 +252,6 @@ ms =
|
||||
Duration.milliseconds
|
||||
|
||||
|
||||
{-| When transitioning to this state, start with a little extra velocity!
|
||||
|
||||
This takes a number from 0-1.
|
||||
|
||||
-}
|
||||
withImpulse : Float -> Attribute -> Attribute
|
||||
withImpulse impulse prop =
|
||||
case prop of
|
||||
Css.Prop id name move format ->
|
||||
Css.Prop id name (Move.withVelocities impulse 0 move) format
|
||||
|
||||
Css.ColorProp name move ->
|
||||
Css.ColorProp name (Move.withVelocities impulse 0 move)
|
||||
|
||||
|
||||
{-| -}
|
||||
delay : Duration -> Animation -> Animation
|
||||
delay dur (Animation now attrs) =
|
||||
@ -340,7 +316,7 @@ keyframes steps =
|
||||
[] ->
|
||||
[]
|
||||
|
||||
(Step dur props) :: _ ->
|
||||
(Step _ props) :: _ ->
|
||||
props
|
||||
, now = imminent
|
||||
, delay = Time.zeroDuration
|
||||
@ -508,12 +484,12 @@ formatColorSteps steps prop pastSteps =
|
||||
Nothing ->
|
||||
List.reverse pastSteps
|
||||
|
||||
Just (Css.Prop id name _ format) ->
|
||||
Just (Css.Prop _ _ _ _) ->
|
||||
formatColorSteps next
|
||||
prop
|
||||
pastSteps
|
||||
|
||||
Just (Css.ColorProp name (Move.Pos trans value _)) ->
|
||||
Just (Css.ColorProp _ (Move.Pos trans value _)) ->
|
||||
formatColorSteps next
|
||||
prop
|
||||
(Move.stepWith dur trans value :: pastSteps)
|
||||
@ -534,12 +510,12 @@ formatSteps steps prop pastSteps =
|
||||
Nothing ->
|
||||
List.reverse pastSteps
|
||||
|
||||
Just (Css.Prop id name (Move.Pos trans value _) format) ->
|
||||
Just (Css.Prop _ _ (Move.Pos trans value _) _) ->
|
||||
formatSteps next
|
||||
prop
|
||||
(Move.stepWith dur trans value :: pastSteps)
|
||||
|
||||
Just (Css.ColorProp name movement) ->
|
||||
Just (Css.ColorProp _ _) ->
|
||||
formatSteps next
|
||||
prop
|
||||
pastSteps
|
||||
@ -683,7 +659,7 @@ pinging dur =
|
||||
]
|
||||
|
||||
|
||||
{-| Animate an element on a specific timeline. Check out [`Animator.Timeline`](#Animator/Timeline) for more details.
|
||||
{-| Animate an element on a specific timeline. Check out [`Animator.Timeline`](https://package.elm-lang.org/packages/mdgriffith/elm-animator/latest/Animator-Timeline) for more details.
|
||||
|
||||
This will
|
||||
|
||||
|
@ -6,6 +6,7 @@ module Animator.Timeline exposing
|
||||
, Step, wait, transitionTo
|
||||
, scale, delay
|
||||
, current, previous, upcoming, upcomingWith, arrived, arrivedAt, arrivedAtWith
|
||||
, Duration
|
||||
)
|
||||
|
||||
{-|
|
||||
|
@ -93,11 +93,8 @@ movement : Timeline state -> (state -> Movement) -> { position : Float, velocity
|
||||
movement timeline lookup =
|
||||
Timeline.foldpAll lookup
|
||||
Move.init
|
||||
(\_ prev target now startTransition interruptedOrEnd future state ->
|
||||
(\_ _ target now startTransition interruptedOrEnd future state ->
|
||||
let
|
||||
arrived =
|
||||
Timeline.startTime target
|
||||
|
||||
isHappening =
|
||||
Time.thisAfterOrEqualThat now startTransition
|
||||
|| (List.isEmpty future
|
||||
@ -106,6 +103,9 @@ movement timeline lookup =
|
||||
in
|
||||
if isHappening then
|
||||
let
|
||||
arrived =
|
||||
Timeline.startTime target
|
||||
|
||||
progress =
|
||||
Time.progress startTransition arrived now
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
module InternalAnim.Bits exposing (Bits, has, init, off, on, store4, store4Float, value, zeroes)
|
||||
module InternalAnim.Bits exposing (Bits, store4Float, value)
|
||||
|
||||
{-| Let's make storing values within a single Int a bit easier to do while not compromising performance.
|
||||
|
||||
@ -24,14 +24,6 @@ type Bits bits
|
||||
= Bits Int
|
||||
|
||||
|
||||
type Size
|
||||
= Flag
|
||||
|
||||
|
||||
type Offset
|
||||
= Offset
|
||||
|
||||
|
||||
|
||||
-- flip : Int -> Bool -> Bits bits -> Bits bits
|
||||
-- flip offset on (Bits b) =
|
||||
@ -40,43 +32,6 @@ type Offset
|
||||
-- |> Bits
|
||||
|
||||
|
||||
init : Bits bits
|
||||
init =
|
||||
Bits zeroes
|
||||
|
||||
|
||||
has : Int -> Bits bits -> Bool
|
||||
has offset (Bits b) =
|
||||
let
|
||||
target =
|
||||
zeroes |> store offset 1 ones
|
||||
in
|
||||
Bitwise.and target b - target == 0
|
||||
|
||||
|
||||
on : Int -> Bits bits -> Bits bits
|
||||
on offset (Bits b) =
|
||||
b
|
||||
|> store offset 1 ones
|
||||
|> Bits
|
||||
|
||||
|
||||
off : Int -> Bits bits -> Bits bits
|
||||
off offset (Bits b) =
|
||||
b
|
||||
|> store offset 1 zeroes
|
||||
|> Bits
|
||||
|
||||
|
||||
bool : Bool -> Int
|
||||
bool yes =
|
||||
if yes then
|
||||
ones
|
||||
|
||||
else
|
||||
zeroes
|
||||
|
||||
|
||||
store4Float : Float -> Float -> Float -> Float -> Bits bits
|
||||
store4Float one two three four =
|
||||
Bitwise.and top8 (round one)
|
||||
@ -89,28 +44,6 @@ store4Float one two three four =
|
||||
|> Bits
|
||||
|
||||
|
||||
store4 : Int -> Int -> Int -> Int -> Bits bits
|
||||
store4 one two three four =
|
||||
Bitwise.and top8 one
|
||||
|> Bitwise.or
|
||||
(Bitwise.shiftLeftBy 8 (Bitwise.and top8 two))
|
||||
|> Bitwise.or
|
||||
(Bitwise.shiftLeftBy 16 (Bitwise.and top8 three))
|
||||
|> Bitwise.or
|
||||
(Bitwise.shiftLeftBy 24 (Bitwise.and top8 four))
|
||||
|> Bits
|
||||
|
||||
|
||||
store : Int -> Int -> Int -> Int -> Int
|
||||
store offset length val target =
|
||||
target
|
||||
|
||||
|
||||
get : Int -> Int -> Int -> Int
|
||||
get offset length val =
|
||||
val
|
||||
|
||||
|
||||
{-| -}
|
||||
ones : Int
|
||||
ones =
|
||||
@ -124,21 +57,6 @@ zeroes =
|
||||
Bitwise.or 0 0
|
||||
|
||||
|
||||
top10 : Int
|
||||
top10 =
|
||||
Bitwise.shiftRightZfBy (32 - 10) ones
|
||||
|
||||
|
||||
top8 : Int
|
||||
top8 =
|
||||
Bitwise.shiftRightZfBy (32 - 8) ones
|
||||
|
||||
|
||||
top6 : Int
|
||||
top6 =
|
||||
Bitwise.shiftRightZfBy (32 - 6) ones
|
||||
|
||||
|
||||
top5 : Int
|
||||
top5 =
|
||||
Bitwise.shiftRightZfBy (32 - 5) ones
|
||||
|
@ -1,7 +1,6 @@
|
||||
module InternalAnim.Css exposing
|
||||
( Prop(..)
|
||||
, RenderedProp(..)
|
||||
, cssFromProps
|
||||
, match
|
||||
, propsToRenderedProps
|
||||
, toCss
|
||||
@ -9,21 +8,15 @@ module InternalAnim.Css exposing
|
||||
|
||||
{-| -}
|
||||
|
||||
import Bezier
|
||||
import Color
|
||||
import Html
|
||||
import Html.Attributes as Attr exposing (id)
|
||||
import InternalAnim.Bits as Bits
|
||||
import InternalAnim.Css.Props as Props
|
||||
import InternalAnim.Duration as Duration
|
||||
import InternalAnim.Hash as Hash
|
||||
import InternalAnim.Move as Move
|
||||
import InternalAnim.Quantity as Quantity
|
||||
import InternalAnim.Time as Time
|
||||
import InternalAnim.Timeline as Timeline
|
||||
import InternalAnim.Transition as Transition
|
||||
import InternalAnim.Units as Units
|
||||
import Set exposing (Set)
|
||||
|
||||
|
||||
{-| An id representing a prop type.
|
||||
@ -68,16 +61,6 @@ type Prop
|
||||
| ColorProp String (Move.Move Color.Color)
|
||||
|
||||
|
||||
isTransformProp : Prop -> Bool
|
||||
isTransformProp prop =
|
||||
case prop of
|
||||
Prop id name _ _ ->
|
||||
Props.isTransformId id
|
||||
|
||||
ColorProp _ _ ->
|
||||
False
|
||||
|
||||
|
||||
isGroupProp : Id -> Prop -> Bool
|
||||
isGroupProp groupId prop =
|
||||
case prop of
|
||||
@ -162,21 +145,6 @@ toCss now renderedProps =
|
||||
}
|
||||
|
||||
|
||||
cssFromProps : Timeline.Timeline state -> (state -> List Prop) -> CssAnim
|
||||
cssFromProps timeline lookup =
|
||||
let
|
||||
present =
|
||||
getInitial timeline lookup
|
||||
|
||||
renderedProps =
|
||||
Timeline.foldpAll lookup
|
||||
(\_ -> present)
|
||||
toPropCurves2
|
||||
timeline
|
||||
in
|
||||
props2Css (Timeline.getCurrentTime timeline) renderedProps emptyAnim
|
||||
|
||||
|
||||
getInitial : Timeline.Timeline event -> (event -> List Prop) -> List RenderedProp
|
||||
getInitial timeline lookup =
|
||||
let
|
||||
@ -185,7 +153,7 @@ getInitial timeline lookup =
|
||||
(\props ->
|
||||
toInitialProps props { props = [], translation = Nothing, scale = Nothing }
|
||||
)
|
||||
(\get prev target now startTime endTime future cursor ->
|
||||
(\get _ target _ _ _ _ cursor ->
|
||||
addInitialProps (get (Timeline.getEvent target)) cursor
|
||||
)
|
||||
timeline
|
||||
@ -205,6 +173,7 @@ addMaybeVector maybeVector renderedProps =
|
||||
VectorProp vector :: renderedProps
|
||||
|
||||
|
||||
initState : Float -> Move.State
|
||||
initState x =
|
||||
{ position =
|
||||
Units.pixels x
|
||||
@ -233,12 +202,7 @@ toInitialProps props rendered =
|
||||
[] ->
|
||||
rendered
|
||||
|
||||
(Prop id name movement format) :: remaining ->
|
||||
let
|
||||
state =
|
||||
Move.init
|
||||
(Props.default id)
|
||||
in
|
||||
(Prop id name _ format) :: remaining ->
|
||||
toInitialProps remaining
|
||||
(if Props.isTranslateId id then
|
||||
case rendered.translation of
|
||||
@ -279,6 +243,11 @@ toInitialProps props rendered =
|
||||
rendered
|
||||
|
||||
else
|
||||
let
|
||||
state =
|
||||
Move.init
|
||||
(Props.default id)
|
||||
in
|
||||
{ props =
|
||||
RenderedProp
|
||||
{ id = id
|
||||
@ -313,29 +282,23 @@ matchProp id renderedProp =
|
||||
RenderedProp details ->
|
||||
details.id - id == 0
|
||||
|
||||
RenderedColorProp details ->
|
||||
RenderedColorProp _ ->
|
||||
False
|
||||
|
||||
TransformProp details ->
|
||||
False
|
||||
|
||||
VectorProp details ->
|
||||
VectorProp _ ->
|
||||
False
|
||||
|
||||
|
||||
matchColor : String -> RenderedProp -> Bool
|
||||
matchColor name renderedProp =
|
||||
case renderedProp of
|
||||
RenderedProp details ->
|
||||
RenderedProp _ ->
|
||||
False
|
||||
|
||||
RenderedColorProp details ->
|
||||
details.name == name
|
||||
|
||||
TransformProp details ->
|
||||
False
|
||||
|
||||
VectorProp details ->
|
||||
VectorProp _ ->
|
||||
False
|
||||
|
||||
|
||||
@ -347,7 +310,7 @@ addInitialProps props rendered =
|
||||
[] ->
|
||||
rendered
|
||||
|
||||
(Prop id name movement format) :: remaining ->
|
||||
(Prop id name _ format) :: remaining ->
|
||||
let
|
||||
new =
|
||||
if Props.isTranslateId id then
|
||||
@ -537,36 +500,6 @@ props2Css now renderedProps anim =
|
||||
|> combine anim
|
||||
)
|
||||
|
||||
(TransformProp details) :: remain ->
|
||||
props2Css now
|
||||
remain
|
||||
(case details.sections of
|
||||
[] ->
|
||||
{ anim
|
||||
| hash = transformToHash (stateToTransform details.state) ++ anim.hash
|
||||
, props =
|
||||
( "transform"
|
||||
, renderTransformState details.state
|
||||
)
|
||||
:: anim.props
|
||||
}
|
||||
|
||||
_ ->
|
||||
Move.cssForSections now
|
||||
(stateToTransform details.state)
|
||||
"transform"
|
||||
(\t one two ->
|
||||
"transform: "
|
||||
++ transformToString
|
||||
(Move.lerpTransform t one two)
|
||||
)
|
||||
transformToString
|
||||
transformToHash
|
||||
(List.reverse details.sections)
|
||||
emptyAnim
|
||||
|> combine anim
|
||||
)
|
||||
|
||||
|
||||
vectorToHash : Props.Id -> Vector -> String
|
||||
vectorToHash group vec =
|
||||
@ -594,38 +527,6 @@ vectorToHash group vec =
|
||||
++ Hash.float vec.z
|
||||
|
||||
|
||||
transformToHash : { a | x : Float, y : Float, rotation : Float, scale : Float } -> String
|
||||
transformToHash trans =
|
||||
let
|
||||
scaleStr =
|
||||
if trans.scale == 1 then
|
||||
""
|
||||
|
||||
else
|
||||
"s" ++ String.fromInt (round (trans.scale * 100))
|
||||
|
||||
rotationStr =
|
||||
if trans.rotation == 0 then
|
||||
""
|
||||
|
||||
else
|
||||
"r" ++ String.fromInt (round (trans.rotation * 100))
|
||||
|
||||
translateStr =
|
||||
if trans.x == 0 && trans.y == 0 then
|
||||
""
|
||||
|
||||
else
|
||||
"t"
|
||||
++ String.fromInt (round trans.x)
|
||||
++ "-"
|
||||
++ String.fromInt (round trans.y)
|
||||
in
|
||||
translateStr
|
||||
++ rotationStr
|
||||
++ scaleStr
|
||||
|
||||
|
||||
vectorStateToVector : VectorState -> Vector
|
||||
vectorStateToVector state =
|
||||
{ x =
|
||||
@ -637,99 +538,6 @@ vectorStateToVector state =
|
||||
}
|
||||
|
||||
|
||||
stateToTransform : TransformState -> Transform
|
||||
stateToTransform state =
|
||||
{ x =
|
||||
Units.inPixels state.x.position
|
||||
, y =
|
||||
Units.inPixels state.y.position
|
||||
, scale =
|
||||
Units.inPixels state.scale.position
|
||||
, rotation =
|
||||
Units.inPixels state.rotation.position
|
||||
}
|
||||
|
||||
|
||||
renderTransformState :
|
||||
{ a
|
||||
| x : { b | position : Units.Pixels }
|
||||
, y : { c | position : Units.Pixels }
|
||||
, rotation : { d | position : Units.Pixels }
|
||||
, scale : { e | position : Units.Pixels }
|
||||
}
|
||||
-> String
|
||||
renderTransformState state =
|
||||
"translate("
|
||||
++ pixelsToString state.x.position
|
||||
++ "px, "
|
||||
++ pixelsToString state.y.position
|
||||
++ "px) rotate("
|
||||
++ pixelsToString state.rotation.position
|
||||
++ "turn)"
|
||||
++ " scale("
|
||||
++ pixelsToString state.scale.position
|
||||
++ ")"
|
||||
|
||||
|
||||
pixelsToString : Units.Pixels -> String
|
||||
pixelsToString pixels =
|
||||
floatToString (Units.inPixels pixels)
|
||||
|
||||
|
||||
floatToString : Float -> String
|
||||
floatToString plusMinus =
|
||||
let
|
||||
float =
|
||||
abs plusMinus
|
||||
|
||||
base =
|
||||
floor float
|
||||
|
||||
decimal =
|
||||
floor (100 * (float - toFloat base))
|
||||
|
||||
toString f =
|
||||
if plusMinus < 0 then
|
||||
"-" ++ String.fromInt f
|
||||
|
||||
else
|
||||
String.fromInt f
|
||||
in
|
||||
if decimal == 0 then
|
||||
toString base
|
||||
|
||||
else
|
||||
toString base ++ "." ++ String.fromInt decimal
|
||||
|
||||
|
||||
transformToString trans =
|
||||
"translate("
|
||||
++ floatToString trans.x
|
||||
++ "px, "
|
||||
++ floatToString trans.y
|
||||
++ "px) rotate("
|
||||
++ floatToString trans.rotation
|
||||
++ "turn)"
|
||||
++ " scale("
|
||||
++ floatToString trans.scale
|
||||
++ ")"
|
||||
|
||||
|
||||
infinite : String
|
||||
infinite =
|
||||
"infinite"
|
||||
|
||||
|
||||
isEmptyAnim : { css | keyframes : String } -> Bool
|
||||
isEmptyAnim anim =
|
||||
case anim.keyframes of
|
||||
"" ->
|
||||
True
|
||||
|
||||
_ ->
|
||||
False
|
||||
|
||||
|
||||
emptyAnim : CssAnim
|
||||
emptyAnim =
|
||||
{ hash = ""
|
||||
@ -824,37 +632,6 @@ toPropCurves2 lookup prev target now startTime endTime future cursor =
|
||||
|> lookup
|
||||
|> stateOrDefault rendered.id
|
||||
rendered.name
|
||||
|
||||
finalProp =
|
||||
-- this is the check for being a transition
|
||||
if not (Time.equal (Timeline.endTime prev) startTime) then
|
||||
-- adjust the transition by taking into account
|
||||
-- the intro and exit velocity
|
||||
-- but only if this is an interruption
|
||||
targetProp
|
||||
|> Move.withVelocities
|
||||
(normalizeVelocity
|
||||
startTime
|
||||
targetTime
|
||||
startPosition
|
||||
targetPosition
|
||||
rendered.state.velocity
|
||||
)
|
||||
-- If we do any transition smoothing
|
||||
-- we'll need to normalize this velocity too
|
||||
--Estimation.velocityAtTarget lookupState target future
|
||||
0
|
||||
|
||||
else
|
||||
targetProp
|
||||
|
||||
startPosition =
|
||||
Units.inPixels rendered.state.position
|
||||
|
||||
targetPosition =
|
||||
case targetProp of
|
||||
Move.Pos _ x _ ->
|
||||
x
|
||||
in
|
||||
RenderedProp
|
||||
{ id = rendered.id
|
||||
@ -865,6 +642,39 @@ toPropCurves2 lookup prev target now startTime endTime future cursor =
|
||||
rendered.sections
|
||||
|
||||
else
|
||||
let
|
||||
finalProp =
|
||||
-- this is the check for being a transition
|
||||
if not (Time.equal (Timeline.endTime prev) startTime) then
|
||||
-- adjust the transition by taking into account
|
||||
-- the intro and exit velocity
|
||||
-- but only if this is an interruption
|
||||
let
|
||||
startPosition =
|
||||
Units.inPixels rendered.state.position
|
||||
|
||||
targetPosition =
|
||||
case targetProp of
|
||||
Move.Pos _ x _ ->
|
||||
x
|
||||
in
|
||||
targetProp
|
||||
|> Move.withVelocities
|
||||
(normalizeVelocity
|
||||
startTime
|
||||
targetTime
|
||||
startPosition
|
||||
targetPosition
|
||||
rendered.state.velocity
|
||||
)
|
||||
-- If we do any transition smoothing
|
||||
-- we'll need to normalize this velocity too
|
||||
--Estimation.velocityAtTarget lookupState target future
|
||||
0
|
||||
|
||||
else
|
||||
targetProp
|
||||
in
|
||||
Move.sequences
|
||||
startTime
|
||||
targetTime
|
||||
@ -933,11 +743,6 @@ toPropCurves2 lookup prev target now startTime endTime future cursor =
|
||||
targetProps
|
||||
Transition.standard
|
||||
|
||||
commonSequence =
|
||||
getCommonVectorSequence details.group
|
||||
targetProps
|
||||
[]
|
||||
|
||||
targets =
|
||||
{ x =
|
||||
getVectorSlot details.group Props.X targetProps
|
||||
@ -946,11 +751,6 @@ toPropCurves2 lookup prev target now startTime endTime future cursor =
|
||||
, z =
|
||||
getVectorSlot details.group Props.Z targetProps
|
||||
}
|
||||
|
||||
commonMovement =
|
||||
Move.move commonTransition
|
||||
targets
|
||||
commonSequence
|
||||
in
|
||||
VectorProp
|
||||
{ group = details.group
|
||||
@ -961,6 +761,17 @@ toPropCurves2 lookup prev target now startTime endTime future cursor =
|
||||
details.sections
|
||||
|
||||
else
|
||||
let
|
||||
commonSequence =
|
||||
getCommonVectorSequence details.group
|
||||
targetProps
|
||||
[]
|
||||
|
||||
commonMovement =
|
||||
Move.move commonTransition
|
||||
targets
|
||||
commonSequence
|
||||
in
|
||||
Move.sequences
|
||||
startTime
|
||||
targetTime
|
||||
@ -995,139 +806,6 @@ toPropCurves2 lookup prev target now startTime endTime future cursor =
|
||||
details.state.z
|
||||
}
|
||||
}
|
||||
|
||||
TransformProp details ->
|
||||
-- for each prop
|
||||
-- calculate a new state
|
||||
-- calculate a new transition
|
||||
-- (for now), take the most "different" curve
|
||||
-- Compose a new `Move Transform` with the transition
|
||||
--
|
||||
let
|
||||
targetProps : List Prop
|
||||
targetProps =
|
||||
Timeline.getEvent target
|
||||
|> lookup
|
||||
|> List.filter isTransformProp
|
||||
|
||||
commonTransition =
|
||||
if not (Time.equal (Timeline.endTime prev) startTime) then
|
||||
let
|
||||
fastestVelocity =
|
||||
firstNonZero
|
||||
[ normalizeVelocity
|
||||
startTime
|
||||
targetTime
|
||||
(Units.inPixels details.state.x.position)
|
||||
targets.x
|
||||
details.state.x.velocity
|
||||
, normalizeVelocity
|
||||
startTime
|
||||
targetTime
|
||||
(Units.inPixels details.state.y.position)
|
||||
targets.y
|
||||
details.state.y.velocity
|
||||
, normalizeVelocity
|
||||
startTime
|
||||
targetTime
|
||||
(Units.inPixels details.state.rotation.position)
|
||||
targets.rotation
|
||||
details.state.rotation.velocity
|
||||
, normalizeVelocity
|
||||
startTime
|
||||
targetTime
|
||||
(Units.inPixels details.state.scale.position)
|
||||
targets.scale
|
||||
details.state.scale.velocity
|
||||
]
|
||||
in
|
||||
getCommonTransformTransition
|
||||
targetProps
|
||||
Transition.standard
|
||||
|> Transition.withVelocities fastestVelocity
|
||||
-- If we do any transition smoothing
|
||||
-- we'll need to normalize this velocity too
|
||||
--Estimation.velocityAtTarget lookupState target future
|
||||
0
|
||||
|
||||
else
|
||||
getCommonTransformTransition
|
||||
targetProps
|
||||
Transition.standard
|
||||
|
||||
commonSequence =
|
||||
getCommonTransformSequence
|
||||
targetProps
|
||||
[]
|
||||
|
||||
targets =
|
||||
{ x =
|
||||
transformOrDefault Props.ids.x
|
||||
targetProps
|
||||
, y =
|
||||
transformOrDefault Props.ids.y
|
||||
targetProps
|
||||
, scale =
|
||||
transformOrDefault Props.ids.scale
|
||||
targetProps
|
||||
, rotation =
|
||||
transformOrDefault Props.ids.rotation
|
||||
targetProps
|
||||
}
|
||||
|
||||
commonMovement =
|
||||
Move.move commonTransition
|
||||
targets
|
||||
commonSequence
|
||||
in
|
||||
TransformProp
|
||||
{ sections =
|
||||
if finished then
|
||||
details.sections
|
||||
|
||||
else
|
||||
Move.sequences
|
||||
startTime
|
||||
targetTime
|
||||
now
|
||||
endTime
|
||||
commonMovement
|
||||
details.sections
|
||||
, state =
|
||||
{ x =
|
||||
Move.at progress
|
||||
startTime
|
||||
targetTime
|
||||
(Move.toWith commonTransition
|
||||
targets.x
|
||||
)
|
||||
details.state.x
|
||||
, y =
|
||||
Move.at progress
|
||||
startTime
|
||||
targetTime
|
||||
(Move.toWith commonTransition
|
||||
targets.y
|
||||
)
|
||||
details.state.y
|
||||
, scale =
|
||||
Move.at progress
|
||||
startTime
|
||||
targetTime
|
||||
(Move.toWith commonTransition
|
||||
targets.scale
|
||||
)
|
||||
details.state.scale
|
||||
, rotation =
|
||||
Move.at progress
|
||||
startTime
|
||||
targetTime
|
||||
(Move.toWith commonTransition
|
||||
targets.rotation
|
||||
)
|
||||
details.state.rotation
|
||||
}
|
||||
}
|
||||
)
|
||||
cursor
|
||||
|
||||
@ -1158,7 +836,7 @@ getCommonVectorSequence :
|
||||
-> List (Move.Sequence Vector)
|
||||
getCommonVectorSequence groupId props sequences =
|
||||
case props of
|
||||
(Prop id name (Move.Pos trans v propSeq) format) :: _ ->
|
||||
(Prop _ _ (Move.Pos _ _ propSeq) _) :: _ ->
|
||||
-- sequences
|
||||
vectorSeq groupId props propSeq 0 []
|
||||
|
||||
@ -1210,7 +888,7 @@ gatherVectorSteps groupId seqLevel stepLevel steps props transforms =
|
||||
[] ->
|
||||
transforms
|
||||
|
||||
(Move.Step dur trans target) :: remainingSteps ->
|
||||
(Move.Step dur trans _) :: remainingSteps ->
|
||||
gatherVectorSteps groupId
|
||||
seqLevel
|
||||
(stepLevel + 1)
|
||||
@ -1221,6 +899,7 @@ gatherVectorSteps groupId seqLevel stepLevel steps props transforms =
|
||||
)
|
||||
|
||||
|
||||
getVectorStepAt : Id -> Duration.Duration -> Transition.Transition -> Int -> Int -> List Prop -> Move.Step Vector
|
||||
getVectorStepAt groupId dur trans seqLevel stepLevel props =
|
||||
let
|
||||
x =
|
||||
@ -1262,109 +941,6 @@ getVectorStepAt groupId dur trans seqLevel stepLevel props =
|
||||
{- END VECTOR -}
|
||||
|
||||
|
||||
{-|
|
||||
|
||||
*warning! this need to be called with pre-filtered props that are only transform props!
|
||||
|
||||
-}
|
||||
getCommonTransformSequence :
|
||||
List Prop
|
||||
-> List (Move.Sequence Transform)
|
||||
-> List (Move.Sequence Transform)
|
||||
getCommonTransformSequence props sequences =
|
||||
case props of
|
||||
(Prop id name (Move.Pos trans v propSeq) format) :: _ ->
|
||||
-- sequences
|
||||
transformSeq props propSeq 0 []
|
||||
|
||||
_ ->
|
||||
sequences
|
||||
|
||||
|
||||
transformSeq :
|
||||
List Prop
|
||||
-> List (Move.Sequence Float)
|
||||
-> Int
|
||||
-> List (Move.Sequence Transform)
|
||||
-> List (Move.Sequence Transform)
|
||||
transformSeq props pilotSequence seqLevel renderedTransforms =
|
||||
case pilotSequence of
|
||||
[] ->
|
||||
renderedTransforms
|
||||
|
||||
(Move.Sequence n delay dur steps) :: remain ->
|
||||
transformSeq props
|
||||
remain
|
||||
(seqLevel + 1)
|
||||
(Move.Sequence n
|
||||
delay
|
||||
dur
|
||||
(gatherSequenceSteps seqLevel
|
||||
0
|
||||
steps
|
||||
props
|
||||
[]
|
||||
)
|
||||
:: renderedTransforms
|
||||
)
|
||||
|
||||
|
||||
gatherSequenceSteps :
|
||||
Int
|
||||
-> Int
|
||||
-> List (Move.Step Float)
|
||||
-> List Prop
|
||||
-> List (Move.Step Transform)
|
||||
-> List (Move.Step Transform)
|
||||
gatherSequenceSteps seqLevel stepLevel steps props transforms =
|
||||
case steps of
|
||||
[] ->
|
||||
transforms
|
||||
|
||||
(Move.Step dur trans target) :: remainingSteps ->
|
||||
gatherSequenceSteps seqLevel
|
||||
(stepLevel + 1)
|
||||
remainingSteps
|
||||
props
|
||||
(getTransformStepAt dur trans seqLevel stepLevel props
|
||||
:: transforms
|
||||
)
|
||||
|
||||
|
||||
getTransformStepAt dur trans seqLevel stepLevel props =
|
||||
Move.Step dur
|
||||
trans
|
||||
{ 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 -> Maybe Props.Id -> Props.Id -> List Prop -> Maybe Float -> Float
|
||||
getTransformSequenceValueAt seqLevel stepLevel maybeDefaultId targetId props defaultValue =
|
||||
case props of
|
||||
@ -1376,7 +952,7 @@ getTransformSequenceValueAt seqLevel stepLevel maybeDefaultId targetId props def
|
||||
Just default ->
|
||||
default
|
||||
|
||||
(Prop id name move _) :: remain ->
|
||||
(Prop id _ move _) :: remain ->
|
||||
if id - targetId == 0 then
|
||||
case move of
|
||||
Move.Pos _ v seq ->
|
||||
@ -1420,7 +996,7 @@ getTransformSequenceValueAt seqLevel stepLevel maybeDefaultId targetId props def
|
||||
else
|
||||
getTransformSequenceValueAt seqLevel stepLevel maybeDefaultId targetId remain defaultValue
|
||||
|
||||
(ColorProp name movement) :: remain ->
|
||||
(ColorProp _ _) :: remain ->
|
||||
getTransformSequenceValueAt seqLevel stepLevel maybeDefaultId targetId remain defaultValue
|
||||
|
||||
|
||||
@ -1447,7 +1023,7 @@ getCommonTransformTransition props currentTrans =
|
||||
[] ->
|
||||
currentTrans
|
||||
|
||||
(Prop id _ (Move.Pos trans _ _) _) :: remain ->
|
||||
(Prop _ _ (Move.Pos trans _ _) _) :: remain ->
|
||||
if Transition.isStandard trans then
|
||||
getCommonTransformTransition remain currentTrans
|
||||
|
||||
@ -1478,7 +1054,7 @@ valueOrDefault maybeDefaultid targetId props defaultVal =
|
||||
Just val ->
|
||||
val
|
||||
|
||||
(Prop id name move _) :: remain ->
|
||||
(Prop id _ move _) :: remain ->
|
||||
if id - targetId == 0 then
|
||||
case move of
|
||||
Move.Pos _ v _ ->
|
||||
@ -1498,30 +1074,10 @@ valueOrDefault maybeDefaultid targetId props defaultVal =
|
||||
else
|
||||
valueOrDefault maybeDefaultid targetId remain defaultVal
|
||||
|
||||
(ColorProp name movement) :: remain ->
|
||||
(ColorProp _ _) :: remain ->
|
||||
valueOrDefault maybeDefaultid targetId remain defaultVal
|
||||
|
||||
|
||||
{-| -}
|
||||
transformOrDefault : Id -> List Prop -> Float
|
||||
transformOrDefault targetId props =
|
||||
case props of
|
||||
[] ->
|
||||
Props.defaultPosition targetId
|
||||
|
||||
(Prop id name move _) :: remain ->
|
||||
if id - targetId == 0 then
|
||||
case move of
|
||||
Move.Pos _ v _ ->
|
||||
v
|
||||
|
||||
else
|
||||
transformOrDefault targetId remain
|
||||
|
||||
(ColorProp name movement) :: remain ->
|
||||
transformOrDefault targetId remain
|
||||
|
||||
|
||||
{-| -}
|
||||
stateOrDefault : Id -> String -> List Prop -> Move.Move Float
|
||||
stateOrDefault targetId targetName props =
|
||||
@ -1543,7 +1099,7 @@ stateOrDefault targetId targetName props =
|
||||
else
|
||||
stateOrDefault targetId targetName remain
|
||||
|
||||
(ColorProp name movement) :: remain ->
|
||||
(ColorProp _ _) :: remain ->
|
||||
stateOrDefault targetId targetName remain
|
||||
|
||||
|
||||
@ -1554,7 +1110,7 @@ colorOrDefault targetName default props =
|
||||
[] ->
|
||||
default
|
||||
|
||||
(Prop id _ move _) :: remain ->
|
||||
(Prop _ _ _ _) :: remain ->
|
||||
colorOrDefault targetName default remain
|
||||
|
||||
(ColorProp name (Move.Pos _ clr _)) :: remain ->
|
||||
@ -1565,30 +1121,6 @@ colorOrDefault targetName default props =
|
||||
colorOrDefault targetName default remain
|
||||
|
||||
|
||||
matchForMovement : Id -> String -> List Prop -> Maybe (Move.Move Float)
|
||||
matchForMovement onlyId onlyName props =
|
||||
case props of
|
||||
[] ->
|
||||
Nothing
|
||||
|
||||
(ColorProp name move) :: remain ->
|
||||
matchForMovement onlyId onlyName remain
|
||||
|
||||
((Prop id name movement _) as top) :: remain ->
|
||||
if id + 1 == 0 then
|
||||
if name == onlyName then
|
||||
Just movement
|
||||
|
||||
else
|
||||
matchForMovement onlyId onlyName remain
|
||||
|
||||
else if id - onlyId == 0 then
|
||||
Just movement
|
||||
|
||||
else
|
||||
matchForMovement onlyId onlyName remain
|
||||
|
||||
|
||||
{-| A group of curves represents the trail of one scalar property
|
||||
|
||||
(Scalar property meaning something like opacity, or just the `R` channel of rgb.)
|
||||
@ -1597,7 +1129,6 @@ matchForMovement onlyId onlyName props =
|
||||
type RenderedProp
|
||||
= RenderedProp RenderedPropDetails
|
||||
| RenderedColorProp RenderedColorPropDetails
|
||||
| TransformProp TransformPropDetails
|
||||
-- transform can now be deconstructed into its parts
|
||||
-- This is for translation and scaling
|
||||
-- Rotation is a RenderedProp
|
||||
@ -1645,33 +1176,6 @@ type alias RenderedColorPropDetails =
|
||||
}
|
||||
|
||||
|
||||
type alias TransformPropDetails =
|
||||
{ sections :
|
||||
List (Move.Sequence Transform)
|
||||
, state : TransformState
|
||||
}
|
||||
|
||||
|
||||
type alias TransformState =
|
||||
{ x : Move.State
|
||||
, y : Move.State
|
||||
, scale : Move.State
|
||||
, rotation : Move.State
|
||||
}
|
||||
|
||||
|
||||
type alias Transform =
|
||||
{ x : Float
|
||||
, y : Float
|
||||
, scale : Float
|
||||
, rotation : Float
|
||||
}
|
||||
|
||||
|
||||
type alias TransformPresence =
|
||||
Bits.Bits Transform
|
||||
|
||||
|
||||
{-| Slightly different than CssAnim in that we can also have style properties
|
||||
This is for when a property has not changed and so a full animation is not necessary
|
||||
-}
|
||||
|
@ -1,22 +1,19 @@
|
||||
module InternalAnim.Css.Props exposing
|
||||
( Id, ids, hash, default, defaultPosition, groups
|
||||
, isTransformId, isTranslateId, isRotateId, isScaleId
|
||||
, isTranslateId, isScaleId
|
||||
, Format, format, float, int, px, turns
|
||||
, roundFloat, floatToString
|
||||
, isGroup
|
||||
, VectorSlot(..), colorHash, groupToCompoundId, name, noId, toStr, translateX, transparent, vectorSlotToId, vectorToString, zero
|
||||
, VectorSlot(..), colorHash, groupToCompoundId, noId, transparent, vectorSlotToId, vectorToString
|
||||
)
|
||||
|
||||
{-|
|
||||
|
||||
@docs Id, ids, hash, default, defaultPosition, groups
|
||||
|
||||
@docs isTransformId, isTranslateId, isRotateId, isScaleId
|
||||
@docs isTranslateId, isScaleId
|
||||
|
||||
@docs Format, format, float, int, px, turns
|
||||
|
||||
@docs roundFloat, floatToString
|
||||
|
||||
@docs translateToString, isGroup
|
||||
|
||||
-}
|
||||
@ -139,12 +136,9 @@ hashFormat form num =
|
||||
Px ->
|
||||
String.fromInt (round num) ++ "px"
|
||||
|
||||
Turns vec ->
|
||||
Turns _ ->
|
||||
String.fromInt (round num)
|
||||
|
||||
TranslateX ->
|
||||
"translateX(" ++ String.fromInt (round num) ++ "px)"
|
||||
|
||||
|
||||
format : Format -> Float -> String
|
||||
format form num =
|
||||
@ -162,15 +156,11 @@ format form num =
|
||||
-- Number here is 1/1000 of a turn
|
||||
vectorToCssString vec ++ " " ++ String.fromFloat (num / 1000) ++ "turn"
|
||||
|
||||
TranslateX ->
|
||||
"translateX(" ++ String.fromInt (round num) ++ "px)"
|
||||
|
||||
|
||||
type Format
|
||||
= AsFloat
|
||||
| AsInt
|
||||
| Px
|
||||
| TranslateX
|
||||
| Turns Vector
|
||||
|
||||
|
||||
@ -194,11 +184,6 @@ px =
|
||||
Px
|
||||
|
||||
|
||||
translateX : Format
|
||||
translateX =
|
||||
TranslateX
|
||||
|
||||
|
||||
{-| We make this huge because we want it last.
|
||||
|
||||
The order of the ids matters, as it's the order that they're rendered in.
|
||||
@ -249,12 +234,24 @@ isGroup groupId id =
|
||||
False
|
||||
|
||||
|
||||
groups : { scaling : Id, translation : Id }
|
||||
groups =
|
||||
{ scaling = 20
|
||||
, translation = 10
|
||||
}
|
||||
|
||||
|
||||
ids :
|
||||
{ x : Id
|
||||
, y : Id
|
||||
, z : Id
|
||||
, rotation : Id
|
||||
, scale : Id
|
||||
, scaleX : Id
|
||||
, scaleY : Id
|
||||
, scaleZ : Id
|
||||
, opacity : Id
|
||||
}
|
||||
ids =
|
||||
{ x = 0
|
||||
, y = 1
|
||||
@ -268,30 +265,15 @@ ids =
|
||||
}
|
||||
|
||||
|
||||
firstTransform : Id
|
||||
firstTransform =
|
||||
ids.x
|
||||
|
||||
|
||||
type alias Id =
|
||||
Int
|
||||
|
||||
|
||||
isTransformId : Id -> Bool
|
||||
isTransformId id =
|
||||
id < 12
|
||||
|
||||
|
||||
isTranslateId : Id -> Bool
|
||||
isTranslateId id =
|
||||
id < 3
|
||||
|
||||
|
||||
isRotateId : Id -> Bool
|
||||
isRotateId id =
|
||||
id == 3
|
||||
|
||||
|
||||
isScaleId : Id -> Bool
|
||||
isScaleId id =
|
||||
id == 4 || id == 5 || id == 6 || id == 7
|
||||
@ -382,60 +364,6 @@ hashId id =
|
||||
"unknown"
|
||||
|
||||
|
||||
name : Id -> String
|
||||
name id =
|
||||
case id of
|
||||
13 ->
|
||||
"opacity"
|
||||
|
||||
14 ->
|
||||
"background-color"
|
||||
|
||||
_ ->
|
||||
"unknown"
|
||||
|
||||
|
||||
toStr : Id -> (Float -> String)
|
||||
toStr id =
|
||||
case id of
|
||||
0 ->
|
||||
\f ->
|
||||
"translateX(" ++ String.fromFloat f ++ "px)"
|
||||
|
||||
1 ->
|
||||
\f ->
|
||||
"translateY(" ++ String.fromFloat f ++ "px)"
|
||||
|
||||
2 ->
|
||||
\f ->
|
||||
"translateZ(" ++ String.fromFloat f ++ "px)"
|
||||
|
||||
3 ->
|
||||
\f ->
|
||||
"rotate(" ++ String.fromFloat f ++ "rad)"
|
||||
|
||||
4 ->
|
||||
\f ->
|
||||
"scale(" ++ String.fromFloat f ++ ")"
|
||||
|
||||
5 ->
|
||||
\f ->
|
||||
"scaleX(" ++ String.fromFloat f ++ ")"
|
||||
|
||||
6 ->
|
||||
\f ->
|
||||
"scaleY(" ++ String.fromFloat f ++ ")"
|
||||
|
||||
13 ->
|
||||
-- opacity
|
||||
\f ->
|
||||
String.fromFloat f
|
||||
|
||||
_ ->
|
||||
\f ->
|
||||
String.fromFloat f
|
||||
|
||||
|
||||
defaultPosition : Id -> Float
|
||||
defaultPosition id =
|
||||
case id of
|
||||
|
@ -1,130 +0,0 @@
|
||||
module InternalAnim.Estimation exposing (velocity, velocityAtTarget)
|
||||
|
||||
{-| -}
|
||||
|
||||
import Animator
|
||||
import Animator.Timeline
|
||||
import Animator.Value
|
||||
import InternalAnim.Duration as Duration
|
||||
import InternalAnim.Move as Move
|
||||
import InternalAnim.Quantity as Quantity
|
||||
import InternalAnim.Time as Time
|
||||
import InternalAnim.Timeline as Timeline
|
||||
import InternalAnim.Units as Units exposing (Pixels, PixelsPerSecond)
|
||||
import Time
|
||||
|
||||
|
||||
mapTime fn time =
|
||||
Time.millisToPosix (fn (Time.posixToMillis time))
|
||||
|
||||
|
||||
{-| Estimate velocity in pixels/second
|
||||
-}
|
||||
velocity : Int -> Time.Posix -> Animator.Timeline.Timeline event -> (event -> Animator.Value.Movement) -> Float
|
||||
velocity resolution time timeline toPosition =
|
||||
let
|
||||
before =
|
||||
mapTime (\t -> t - resolution) time
|
||||
|
||||
after =
|
||||
mapTime (\t -> t + resolution) time
|
||||
|
||||
zero =
|
||||
Animator.Value.movement (Timeline.atTime before timeline) toPosition
|
||||
|
||||
one =
|
||||
Animator.Value.movement (Timeline.atTime time timeline) toPosition
|
||||
|
||||
two =
|
||||
Animator.Value.movement (Timeline.atTime after timeline) toPosition
|
||||
|
||||
first =
|
||||
(one.position - zero.position) / toFloat resolution
|
||||
|
||||
second =
|
||||
(two.position - one.position) / toFloat resolution
|
||||
|
||||
expected =
|
||||
-- 1000 * avg first second
|
||||
1000 * (two.position - zero.position) / (2 * toFloat resolution)
|
||||
in
|
||||
expected
|
||||
|
||||
|
||||
{-| -}
|
||||
velocityAtTarget :
|
||||
(state -> Move.Move Float)
|
||||
-> Timeline.Occurring state
|
||||
-> List (Timeline.Occurring state)
|
||||
-> PixelsPerSecond
|
||||
velocityAtTarget lookup target future =
|
||||
let
|
||||
movement =
|
||||
lookup (Timeline.getEvent target)
|
||||
in
|
||||
case future of
|
||||
[] ->
|
||||
case movement of
|
||||
Move.Pos _ _ [] ->
|
||||
zeroVelocity
|
||||
|
||||
Move.Pos _ _ (seq :: _) ->
|
||||
Move.initialSequenceVelocity seq
|
||||
|
||||
next :: _ ->
|
||||
let
|
||||
targetPosition =
|
||||
case movement of
|
||||
Move.Pos _ x _ ->
|
||||
Units.pixels x
|
||||
in
|
||||
case lookup (Timeline.getEvent next) of
|
||||
Move.Pos _ aheadPosition [] ->
|
||||
-- our target velocity is the linear velocity between target and lookahead
|
||||
velocityBetween
|
||||
targetPosition
|
||||
(Timeline.endTime target)
|
||||
(Units.pixels aheadPosition)
|
||||
(Timeline.startTime next)
|
||||
|
||||
Move.Pos _ aheadPosition (seq :: _) ->
|
||||
if Timeline.isResting target then
|
||||
Move.initialSequenceVelocity seq
|
||||
|
||||
else
|
||||
velocityBetween
|
||||
targetPosition
|
||||
(Timeline.endTime target)
|
||||
(Units.pixels aheadPosition)
|
||||
(Timeline.startTime next)
|
||||
|
||||
|
||||
velocityBetween :
|
||||
Pixels
|
||||
-> Time.Absolute
|
||||
-> Pixels
|
||||
-> Time.Absolute
|
||||
-> PixelsPerSecond
|
||||
velocityBetween one oneTime two twoTime =
|
||||
let
|
||||
distance =
|
||||
two
|
||||
|> Quantity.minus one
|
||||
|
||||
duration =
|
||||
Time.duration oneTime twoTime
|
||||
|
||||
vel =
|
||||
Units.inPixels distance
|
||||
/ Duration.inSeconds duration
|
||||
in
|
||||
if isNaN vel || isInfinite vel then
|
||||
Quantity.zero
|
||||
|
||||
else
|
||||
Units.pixelsPerSecond vel
|
||||
|
||||
|
||||
zeroVelocity : PixelsPerSecond
|
||||
zeroVelocity =
|
||||
Units.pixelsPerSecond 0
|
@ -1,15 +1,14 @@
|
||||
module InternalAnim.Move exposing
|
||||
( Move(..), to, toWith
|
||||
, State, init
|
||||
, lerpColor, lerpFloat, lerpTransform, lerpVector
|
||||
, lerpColor, lerpFloat, lerpVector
|
||||
, Sequence(..)
|
||||
, Step(..), step, stepWith, set
|
||||
, Step(..), stepWith
|
||||
, sequences
|
||||
, addSequence, cssForSections
|
||||
, withTransition, withVelocities
|
||||
, at, atX, transitionTo
|
||||
, denormalize, normalizeOver, toReal
|
||||
, floatToString, initialSequenceVelocity, move
|
||||
, at, transitionTo
|
||||
, move
|
||||
)
|
||||
|
||||
{-|
|
||||
@ -18,10 +17,10 @@ module InternalAnim.Move exposing
|
||||
|
||||
@docs State, init
|
||||
|
||||
@docs lerpColor, lerpFloat, lerpTransform, lerpVector
|
||||
@docs lerpColor, lerpFloat, lerpVector
|
||||
|
||||
@docs Sequence
|
||||
@docs Step, step, stepWith, set
|
||||
@docs Step, stepWith
|
||||
|
||||
@docs sequences, goto
|
||||
|
||||
@ -29,9 +28,7 @@ module InternalAnim.Move exposing
|
||||
|
||||
@docs withTransition, withVelocities
|
||||
|
||||
@docs at, atX, transitionTo
|
||||
|
||||
@docs denormalize, normalizeOver, toReal
|
||||
@docs at, transitionTo
|
||||
|
||||
-}
|
||||
|
||||
@ -121,6 +118,7 @@ toWith t v =
|
||||
Pos t v []
|
||||
|
||||
|
||||
move : value -> Move value
|
||||
move =
|
||||
Pos
|
||||
|
||||
@ -140,27 +138,12 @@ withSequenceDelay delay (Sequence i _ dur steps) =
|
||||
Sequence i delay dur steps
|
||||
|
||||
|
||||
set : value -> Step value
|
||||
set =
|
||||
Step zeroDuration Transition.standard
|
||||
|
||||
|
||||
step : Duration.Duration -> value -> Step value
|
||||
step dur value =
|
||||
Step dur Transition.standard value
|
||||
|
||||
|
||||
stepWith : Duration.Duration -> Transition.Transition -> value -> Step value
|
||||
stepWith =
|
||||
Step
|
||||
|
||||
|
||||
{--}
|
||||
zeroVelocity : Units.PixelsPerSecond
|
||||
zeroVelocity =
|
||||
Units.pixelsPerSecond 0
|
||||
|
||||
|
||||
type alias State =
|
||||
{ position : Units.Pixels
|
||||
, velocity : Units.PixelsPerSecond
|
||||
@ -185,14 +168,6 @@ addDelayToSequence delay seqs captured =
|
||||
)
|
||||
|
||||
|
||||
type alias Transform =
|
||||
{ x : Float
|
||||
, y : Float
|
||||
, scale : Float
|
||||
, rotation : Float
|
||||
}
|
||||
|
||||
|
||||
lerpFloat : Float -> Float -> Float -> Float
|
||||
lerpFloat t one two =
|
||||
one + ((two - one) * t)
|
||||
@ -237,30 +212,6 @@ lerpVector t one two =
|
||||
}
|
||||
|
||||
|
||||
lerpTransform : Float -> Transform -> Transform -> Transform
|
||||
lerpTransform t one two =
|
||||
{ x =
|
||||
lerpFloat t one.x two.x
|
||||
, y =
|
||||
lerpFloat t one.y two.y
|
||||
, scale =
|
||||
lerpFloat t one.scale two.scale
|
||||
, rotation =
|
||||
lerpFloat t one.rotation two.rotation
|
||||
}
|
||||
|
||||
|
||||
atX :
|
||||
Float
|
||||
-> Move Float
|
||||
->
|
||||
{ position : Bezier.Point
|
||||
, velocity : Bezier.Point
|
||||
}
|
||||
atX progress (Pos trans value dwell) =
|
||||
Transition.atX2 progress trans
|
||||
|
||||
|
||||
at :
|
||||
Float
|
||||
-> Time.Absolute
|
||||
@ -273,7 +224,7 @@ at progress startTime targetTime (Pos transition targetPosition dwell) startingS
|
||||
startPosition =
|
||||
Units.inPixels startingState.position
|
||||
in
|
||||
Transition.atX2 progress transition
|
||||
Transition.atX progress transition
|
||||
|> denormalize startTime
|
||||
targetTime
|
||||
startPosition
|
||||
@ -313,7 +264,7 @@ transitionTo progress startTime targetTime (Pos trans targetPosition dwell) star
|
||||
else
|
||||
Transition.withVelocities introVelocity 0 trans
|
||||
in
|
||||
Transition.atX2 progress transition
|
||||
Transition.atX progress transition
|
||||
|> denormalize startTime
|
||||
targetTime
|
||||
startPosition
|
||||
@ -389,26 +340,6 @@ scaleXYBy { x, y } point =
|
||||
{ x = point.x * x, y = point.y * y }
|
||||
|
||||
|
||||
{-|
|
||||
|
||||
Map a value to 0:1 given a range it should be in.
|
||||
|
||||
-}
|
||||
normalizeOver : Float -> Float -> Float -> Float
|
||||
normalizeOver start end current =
|
||||
let
|
||||
total =
|
||||
abs (end - start)
|
||||
in
|
||||
if total == 0 then
|
||||
0
|
||||
|
||||
else
|
||||
((current - start) / total)
|
||||
|> max 0
|
||||
|> min 1
|
||||
|
||||
|
||||
{-| The opposite of `normalizeOver`.
|
||||
|
||||
I guess this is denormalization? Though i was always confused by that term :/
|
||||
@ -481,162 +412,160 @@ sequences :
|
||||
-> List (Sequence value)
|
||||
-> List (Sequence value)
|
||||
sequences startTime targetTime now stopTime movement existingSequence =
|
||||
let
|
||||
durationToNow =
|
||||
Time.duration startTime now
|
||||
in
|
||||
if Time.equal now stopTime && not (Time.equal targetTime stopTime) then
|
||||
-- We've probably been interrupted
|
||||
[]
|
||||
|
||||
else if Time.thisAfterOrEqualThat startTime now then
|
||||
-- We've definitely started, so we want to report the full sequence
|
||||
-- most common case will be startTime == now
|
||||
case movement of
|
||||
Pos trans value [] ->
|
||||
let
|
||||
transitionDuration =
|
||||
Time.duration startTime targetTime
|
||||
|
||||
seq =
|
||||
Sequence 1
|
||||
durationToNow
|
||||
transitionDuration
|
||||
[ Step transitionDuration trans value
|
||||
]
|
||||
in
|
||||
push seq existingSequence
|
||||
|
||||
Pos trans value [ Sequence 1 delay dur steps ] ->
|
||||
let
|
||||
stepDuration =
|
||||
Time.duration startTime targetTime
|
||||
|
||||
transitionDuration =
|
||||
stepDuration
|
||||
|> Time.expand dur
|
||||
|
||||
transitionSequence =
|
||||
Sequence 1
|
||||
(Time.expand durationToNow delay)
|
||||
transitionDuration
|
||||
(Step stepDuration trans value
|
||||
:: steps
|
||||
)
|
||||
in
|
||||
push transitionSequence
|
||||
existingSequence
|
||||
|
||||
Pos trans value dwell ->
|
||||
let
|
||||
transitionDuration =
|
||||
Time.duration startTime targetTime
|
||||
|
||||
transitionSequence =
|
||||
Sequence 1
|
||||
durationToNow
|
||||
transitionDuration
|
||||
[ Step transitionDuration trans value
|
||||
]
|
||||
in
|
||||
if Time.isZeroDuration transitionDuration && not (List.isEmpty dwell) then
|
||||
existingSequence
|
||||
|> append (addDelayToSequence durationToNow dwell [])
|
||||
|
||||
else
|
||||
existingSequence
|
||||
|> push transitionSequence
|
||||
|> append (addDelayToSequence (Time.expand durationToNow transitionDuration) dwell [])
|
||||
|
||||
else if after startTime stopTime now movement then
|
||||
-- we've completely passed this state, no splines are returned
|
||||
[]
|
||||
|
||||
else
|
||||
-- now is during the new sequence
|
||||
-- so let's compose the new sequence and then split it at the new time
|
||||
-- we also know that existingSequence should be [] here
|
||||
case movement of
|
||||
Pos trans value [] ->
|
||||
let
|
||||
splitTime =
|
||||
Time.progress startTime targetTime now
|
||||
|
||||
transitionDuration =
|
||||
Time.duration startTime targetTime
|
||||
|
||||
newSequence =
|
||||
Sequence 1 Quantity.zero transitionDuration [ Step transitionDuration trans value ]
|
||||
|> takeAfter durationToNow
|
||||
in
|
||||
case newSequence.following of
|
||||
Nothing ->
|
||||
[ newSequence.base ]
|
||||
|
||||
Just following ->
|
||||
[ newSequence.base ]
|
||||
|> push
|
||||
(following
|
||||
|> withSequenceDelay (getSequenceDuration newSequence.base)
|
||||
)
|
||||
|
||||
Pos trans value [ Sequence 1 delay dur steps ] ->
|
||||
let
|
||||
stepDuration =
|
||||
Time.duration startTime targetTime
|
||||
|
||||
transitionDuration =
|
||||
stepDuration
|
||||
|> Time.expand dur
|
||||
|
||||
new =
|
||||
Sequence 1 Quantity.zero transitionDuration (Step stepDuration trans value :: steps)
|
||||
|> takeAfter durationToNow
|
||||
in
|
||||
case new.following of
|
||||
Nothing ->
|
||||
[ new.base
|
||||
]
|
||||
|
||||
Just following ->
|
||||
[ new.base ]
|
||||
|> push
|
||||
(following |> withSequenceDelay (getSequenceDuration new.base))
|
||||
|
||||
Pos trans value dwell ->
|
||||
let
|
||||
transitionDuration =
|
||||
Time.duration startTime targetTime
|
||||
in
|
||||
if Time.thisAfterThat now targetTime then
|
||||
takeAfterSequenceList durationToNow dwell
|
||||
|
||||
else
|
||||
let
|
||||
durationToNow =
|
||||
Time.duration startTime now
|
||||
in
|
||||
if Time.thisAfterOrEqualThat startTime now then
|
||||
-- We've definitely started, so we want to report the full sequence
|
||||
-- most common case will be startTime == now
|
||||
case movement of
|
||||
Pos trans value [] ->
|
||||
let
|
||||
new =
|
||||
transitionDuration =
|
||||
Time.duration startTime targetTime
|
||||
|
||||
seq =
|
||||
Sequence 1
|
||||
durationToNow
|
||||
transitionDuration
|
||||
[ Step transitionDuration trans value
|
||||
]
|
||||
in
|
||||
push seq existingSequence
|
||||
|
||||
Pos trans value [ Sequence 1 delay dur steps ] ->
|
||||
let
|
||||
stepDuration =
|
||||
Time.duration startTime targetTime
|
||||
|
||||
transitionDuration =
|
||||
stepDuration
|
||||
|> Time.expand dur
|
||||
|
||||
transitionSequence =
|
||||
Sequence 1
|
||||
(Time.expand durationToNow delay)
|
||||
transitionDuration
|
||||
(Step stepDuration trans value
|
||||
:: steps
|
||||
)
|
||||
in
|
||||
push transitionSequence
|
||||
existingSequence
|
||||
|
||||
Pos trans value dwell ->
|
||||
let
|
||||
transitionDuration =
|
||||
Time.duration startTime targetTime
|
||||
in
|
||||
if Time.isZeroDuration transitionDuration && not (List.isEmpty dwell) then
|
||||
existingSequence
|
||||
|> append (addDelayToSequence durationToNow dwell [])
|
||||
|
||||
else
|
||||
let
|
||||
transitionSequence =
|
||||
Sequence 1
|
||||
durationToNow
|
||||
transitionDuration
|
||||
[ Step transitionDuration trans value
|
||||
]
|
||||
in
|
||||
existingSequence
|
||||
|> push transitionSequence
|
||||
|> append (addDelayToSequence (Time.expand durationToNow transitionDuration) dwell [])
|
||||
|
||||
else if after startTime stopTime now movement then
|
||||
-- we've completely passed this state, no splines are returned
|
||||
[]
|
||||
|
||||
else
|
||||
-- now is during the new sequence
|
||||
-- so let's compose the new sequence and then split it at the new time
|
||||
-- we also know that existingSequence should be [] here
|
||||
case movement of
|
||||
Pos trans value [] ->
|
||||
let
|
||||
transitionDuration =
|
||||
Time.duration startTime targetTime
|
||||
|
||||
newSequence =
|
||||
Sequence 1 Quantity.zero transitionDuration [ Step transitionDuration trans value ]
|
||||
|> takeAfter durationToNow
|
||||
in
|
||||
case newSequence.following of
|
||||
Nothing ->
|
||||
[ newSequence.base ]
|
||||
|
||||
Just following ->
|
||||
[ newSequence.base ]
|
||||
|> push
|
||||
(following
|
||||
|> withSequenceDelay (getSequenceDuration newSequence.base)
|
||||
)
|
||||
|
||||
Pos trans value [ Sequence 1 _ dur steps ] ->
|
||||
let
|
||||
stepDuration =
|
||||
Time.duration startTime targetTime
|
||||
|
||||
transitionDuration =
|
||||
stepDuration
|
||||
|> Time.expand dur
|
||||
|
||||
new =
|
||||
Sequence 1 Quantity.zero transitionDuration (Step stepDuration trans value :: steps)
|
||||
|> takeAfter durationToNow
|
||||
in
|
||||
case new.following of
|
||||
Nothing ->
|
||||
new.base
|
||||
:: addDelayToSequence (getSequenceDuration new.base) dwell []
|
||||
[ new.base
|
||||
]
|
||||
|
||||
Just following ->
|
||||
let
|
||||
delayToFollowing =
|
||||
getSequenceDuration new.base
|
||||
in
|
||||
[ new.base ]
|
||||
|> push (following |> withSequenceDelay delayToFollowing)
|
||||
|> append
|
||||
(addDelayToSequence
|
||||
(Time.expand (getSequenceDuration following)
|
||||
delayToFollowing
|
||||
|> push
|
||||
(following |> withSequenceDelay (getSequenceDuration new.base))
|
||||
|
||||
Pos trans value dwell ->
|
||||
if Time.thisAfterThat now targetTime then
|
||||
takeAfterSequenceList durationToNow dwell
|
||||
|
||||
else
|
||||
let
|
||||
transitionDuration =
|
||||
Time.duration startTime targetTime
|
||||
|
||||
new =
|
||||
Sequence 1 Quantity.zero transitionDuration [ Step transitionDuration trans value ]
|
||||
|> takeAfter durationToNow
|
||||
in
|
||||
case new.following of
|
||||
Nothing ->
|
||||
new.base
|
||||
:: addDelayToSequence (getSequenceDuration new.base) dwell []
|
||||
|
||||
Just following ->
|
||||
let
|
||||
delayToFollowing =
|
||||
getSequenceDuration new.base
|
||||
in
|
||||
[ new.base ]
|
||||
|> push (following |> withSequenceDelay delayToFollowing)
|
||||
|> append
|
||||
(addDelayToSequence
|
||||
(Time.expand (getSequenceDuration following)
|
||||
delayToFollowing
|
||||
)
|
||||
dwell
|
||||
[]
|
||||
)
|
||||
dwell
|
||||
[]
|
||||
)
|
||||
|
||||
|
||||
takeAfterSequenceList :
|
||||
@ -648,7 +577,7 @@ takeAfterSequenceList durationToNow seqs =
|
||||
[] ->
|
||||
[]
|
||||
|
||||
((Sequence n delay duration steps) as top) :: remain ->
|
||||
((Sequence n _ duration _) as top) :: remain ->
|
||||
let
|
||||
floatN =
|
||||
toFloat n
|
||||
@ -824,7 +753,7 @@ afterSequenceList durationTillNow seq remaining =
|
||||
[] ->
|
||||
True
|
||||
|
||||
((Sequence n delay duration steps) as top) :: rest ->
|
||||
((Sequence n _ duration _) as top) :: rest ->
|
||||
let
|
||||
durationOfUnrolledSeq =
|
||||
duration |> Quantity.multiplyBy (toFloat n)
|
||||
@ -838,6 +767,7 @@ afterSequenceList durationTillNow seq remaining =
|
||||
False
|
||||
|
||||
|
||||
afterSequence : Duration.Duration -> Sequence value -> Bool
|
||||
afterSequence durationTillNow (Sequence n delay duration steps) =
|
||||
let
|
||||
floatN =
|
||||
@ -863,21 +793,6 @@ zeroDuration =
|
||||
{- CSS KEYFRAMES -}
|
||||
|
||||
|
||||
initialSequenceVelocity : Sequence value -> Units.PixelsPerSecond
|
||||
initialSequenceVelocity seq =
|
||||
case seq of
|
||||
Sequence 0 _ _ _ ->
|
||||
zeroVelocity
|
||||
|
||||
Sequence _ _ _ [] ->
|
||||
zeroVelocity
|
||||
|
||||
Sequence n _ _ ((Step dur trans _) :: _) ->
|
||||
Transition.initialVelocity trans
|
||||
|> (*) 1000
|
||||
|> Units.pixelsPerSecond
|
||||
|
||||
|
||||
hash : Time.Absolute -> String -> Sequence value -> (value -> String) -> String
|
||||
hash now name (Sequence n delay dur steps) toString =
|
||||
-- we need to encode the current time in the animations name so the browser doesn't cache anything
|
||||
@ -914,16 +829,6 @@ stepHash steps toString hashed =
|
||||
)
|
||||
|
||||
|
||||
roundFloat : Float -> Float
|
||||
roundFloat f =
|
||||
toFloat (round (f * 100)) / 100
|
||||
|
||||
|
||||
floatToString : Float -> String
|
||||
floatToString f =
|
||||
String.fromFloat (roundFloat f)
|
||||
|
||||
|
||||
hashDuration : String -> Duration.Duration -> String
|
||||
hashDuration prefix dur =
|
||||
let
|
||||
@ -939,38 +844,6 @@ hashDuration prefix dur =
|
||||
(round (Duration.inSeconds dur))
|
||||
|
||||
|
||||
lastPosOr : value -> Sequence value -> value
|
||||
lastPosOr x (Sequence _ _ _ steps) =
|
||||
case steps of
|
||||
[] ->
|
||||
x
|
||||
|
||||
_ ->
|
||||
lastPosOrHelper x steps
|
||||
|
||||
|
||||
lastPosOrHelper : value -> List (Step value) -> value
|
||||
lastPosOrHelper x steps =
|
||||
case steps of
|
||||
[] ->
|
||||
x
|
||||
|
||||
(Step _ _ v) :: [] ->
|
||||
v
|
||||
|
||||
(Step _ _ _) :: (Step _ _ v) :: [] ->
|
||||
v
|
||||
|
||||
(Step _ _ _) :: (Step _ _ _) :: (Step _ _ v) :: [] ->
|
||||
v
|
||||
|
||||
(Step _ _ _) :: (Step _ _ _) :: (Step _ _ _) :: (Step _ _ v) :: [] ->
|
||||
v
|
||||
|
||||
(Step _ _ _) :: (Step _ _ _) :: (Step _ _ _) :: (Step _ _ v) :: remain ->
|
||||
lastPosOrHelper v remain
|
||||
|
||||
|
||||
type alias CssAnim =
|
||||
{ hash : String
|
||||
, animation : String
|
||||
@ -1005,7 +878,7 @@ cssForSections now startPos name lerp toString toHashString sections anim =
|
||||
[] ->
|
||||
anim
|
||||
|
||||
[ (Sequence 1 delay dur [ Step stepDur (Transition.Transition spline) v ]) as seq ] ->
|
||||
[ (Sequence 1 delay _ [ Step stepDur (Transition.Transition spline) v ]) as seq ] ->
|
||||
-- NOTE, we're not using the above `dur` because it's the total duration of the sequence
|
||||
-- and therefore equal to stepDur in this case
|
||||
{ anim
|
||||
@ -1156,7 +1029,7 @@ initialProps name toString startPos (Sequence _ _ _ steps) =
|
||||
[] ->
|
||||
[]
|
||||
|
||||
(Step dur transition val) :: _ ->
|
||||
(Step dur _ val) :: _ ->
|
||||
if Duration.isZero dur then
|
||||
[ ( name, toString val ) ]
|
||||
|
||||
@ -1219,16 +1092,6 @@ keyframeHelper name lerp startPos sequenceDuration currentDur steps rendered =
|
||||
(rendered ++ frames)
|
||||
|
||||
|
||||
emptyAnim : CssAnim
|
||||
emptyAnim =
|
||||
{ hash = ""
|
||||
, animation = ""
|
||||
, transition = ""
|
||||
, keyframes = ""
|
||||
, props = []
|
||||
}
|
||||
|
||||
|
||||
combine : CssAnim -> CssAnim -> CssAnim
|
||||
combine one two =
|
||||
if String.isEmpty one.hash && List.isEmpty one.props then
|
||||
|
@ -4,12 +4,7 @@ module InternalAnim.Quantity exposing
|
||||
, equalWithin
|
||||
, greaterThan
|
||||
, greaterThanOrEqualTo
|
||||
, greaterThanOrEqualToZero
|
||||
, greaterThanZero
|
||||
, lessThan
|
||||
, lessThanOrEqualTo
|
||||
, lessThanOrEqualToZero
|
||||
, lessThanZero
|
||||
, max
|
||||
, minus
|
||||
, multiplyBy
|
||||
@ -38,12 +33,6 @@ minus (Quantity y) (Quantity x) =
|
||||
Quantity (x - y)
|
||||
|
||||
|
||||
{-| -}
|
||||
lessThan : Quantity number units -> Quantity number units -> Bool
|
||||
lessThan (Quantity y) (Quantity x) =
|
||||
x < y
|
||||
|
||||
|
||||
{-| -}
|
||||
greaterThan : Quantity number units -> Quantity number units -> Bool
|
||||
greaterThan (Quantity y) (Quantity x) =
|
||||
@ -62,30 +51,6 @@ greaterThanOrEqualTo (Quantity y) (Quantity x) =
|
||||
x >= y
|
||||
|
||||
|
||||
{-| -}
|
||||
lessThanZero : Quantity number units -> Bool
|
||||
lessThanZero (Quantity x) =
|
||||
x < 0
|
||||
|
||||
|
||||
{-| -}
|
||||
greaterThanZero : Quantity number units -> Bool
|
||||
greaterThanZero (Quantity x) =
|
||||
x > 0
|
||||
|
||||
|
||||
{-| -}
|
||||
lessThanOrEqualToZero : Quantity number units -> Bool
|
||||
lessThanOrEqualToZero (Quantity x) =
|
||||
x <= 0
|
||||
|
||||
|
||||
{-| -}
|
||||
greaterThanOrEqualToZero : Quantity number units -> Bool
|
||||
greaterThanOrEqualToZero (Quantity x) =
|
||||
x >= 0
|
||||
|
||||
|
||||
max : Quantity number units -> Quantity number units -> Quantity number units
|
||||
max (Quantity x) (Quantity y) =
|
||||
Quantity (Basics.max x y)
|
||||
|
@ -3,6 +3,7 @@ module InternalAnim.Random exposing (random)
|
||||
{-| -}
|
||||
|
||||
|
||||
fract : Float -> Float
|
||||
fract x =
|
||||
x - toFloat (floor x)
|
||||
|
||||
@ -20,4 +21,4 @@ random seed low high =
|
||||
0
|
||||
|
||||
else
|
||||
(fract (sin seed * 100000.0) + 1.5707) / pi
|
||||
low + (((fract (sin seed * 100000.0) + 1.5707) / pi) * (high - low))
|
||||
|
@ -2,8 +2,8 @@ module InternalAnim.Time exposing
|
||||
( thisBeforeOrEqualThat, thisAfterOrEqualThat, equal
|
||||
, Absolute, AbsoluteTime(..), Duration, absolute, duration, progress
|
||||
, inMilliseconds
|
||||
, latest, earliest, toPosix, durationToString, reduceDurationBy
|
||||
, advanceBy, equalDuration, expand, isZeroDuration, maxDuration, millis, numberOfFrames, positiveDuration, progressWithin, rollbackBy, scaleDuration, thisAfterThat, thisBeforeThat, zeroDuration
|
||||
, latest, toPosix, durationToString
|
||||
, advanceBy, expand, isZeroDuration, maxDuration, millis, positiveDuration, progressWithin, rollbackBy, scaleDuration, thisAfterThat, thisBeforeThat, zeroDuration
|
||||
)
|
||||
|
||||
{-|
|
||||
@ -14,7 +14,7 @@ module InternalAnim.Time exposing
|
||||
|
||||
@docs inMilliseconds
|
||||
|
||||
@docs latest, earliest, toPosix, durationToString, reduceDurationBy
|
||||
@docs latest, toPosix, durationToString
|
||||
|
||||
-}
|
||||
|
||||
@ -74,11 +74,6 @@ expand one two =
|
||||
Quantity.plus one two
|
||||
|
||||
|
||||
reduceDurationBy : Duration -> Duration -> Duration
|
||||
reduceDurationBy one two =
|
||||
Quantity.minus one two
|
||||
|
||||
|
||||
advanceBy : Duration -> Absolute -> Absolute
|
||||
advanceBy dur time =
|
||||
Quantity.plus time (Quantity.Quantity (Duration.inMilliseconds dur))
|
||||
@ -147,15 +142,6 @@ latest ((Quantity.Quantity one) as oneQty) ((Quantity.Quantity two) as twoQty) =
|
||||
oneQty
|
||||
|
||||
|
||||
earliest : Absolute -> Absolute -> Absolute
|
||||
earliest ((Quantity.Quantity one) as oneQty) ((Quantity.Quantity two) as twoQty) =
|
||||
if (one - two) >= 0 then
|
||||
twoQty
|
||||
|
||||
else
|
||||
oneQty
|
||||
|
||||
|
||||
thisBeforeThat : Absolute -> Absolute -> Bool
|
||||
thisBeforeThat (Quantity.Quantity this) (Quantity.Quantity that) =
|
||||
(this - that) < 0
|
||||
@ -189,34 +175,3 @@ isZeroDuration (Quantity.Quantity dur) =
|
||||
equal : Absolute -> Absolute -> Bool
|
||||
equal (Quantity.Quantity this) (Quantity.Quantity that) =
|
||||
(this - that) == 0
|
||||
|
||||
|
||||
equalDuration : Duration -> Duration -> Bool
|
||||
equalDuration (Quantity.Quantity this) (Quantity.Quantity that) =
|
||||
(this - that) == 0
|
||||
|
||||
|
||||
{-| The number of frames, and the offset that's needed to preserve the framerate.
|
||||
|
||||
Offset
|
||||
|
||||
-}
|
||||
numberOfFrames : Float -> Absolute -> Absolute -> Absolute -> ( Float, Int )
|
||||
numberOfFrames fps lastFrameTime startAt endAt =
|
||||
let
|
||||
millisecondsPerFrame =
|
||||
1000 / fps
|
||||
|
||||
totalDurationInMs =
|
||||
Duration.inMilliseconds (duration startAt endAt)
|
||||
|
||||
framesSinceLastFrame =
|
||||
max 0 (Duration.inMilliseconds (duration lastFrameTime startAt))
|
||||
/ millisecondsPerFrame
|
||||
|
||||
offset =
|
||||
1 - (framesSinceLastFrame - toFloat (floor framesSinceLastFrame))
|
||||
in
|
||||
( offset * millisecondsPerFrame
|
||||
, max 1 (round (totalDurationInMs / millisecondsPerFrame))
|
||||
)
|
||||
|
@ -1,35 +1,40 @@
|
||||
module InternalAnim.Timeline exposing
|
||||
( Timeline(..), TimelineDetails, Occurring(..), getEvents
|
||||
( Timeline(..), TimelineDetails, Occurring(..)
|
||||
, Schedule(..), Event(..)
|
||||
, needsUpdate, update, updateWith
|
||||
, startTime, endTime, getEvent, extendEventDwell, hasDwell, isResting
|
||||
, update, updateWith
|
||||
, startTime, endTime, getEvent, extendEventDwell
|
||||
, addToDwell
|
||||
, sendPing
|
||||
, current, arrivedAt, arrived, previous, upcoming
|
||||
, progress
|
||||
, Line(..), Timetable(..)
|
||||
, foldpAll, captureTimeline
|
||||
, ActualDuration(..), Animator(..), Description(..), Frame(..), Frames(..), FramesSummary, Interp, LookAhead, Period(..), Previous(..), Resting(..), Summary, SummaryEvent(..), Transition, atTime, combineRunning, dwellingTime, gc, getCurrentTime, hasChanged, justInitialized, linesAreActive, periodDuration, progress
|
||||
, foldpAll
|
||||
, gc, atTime, dwellingTime, getCurrentTime, linesAreActive
|
||||
, Transition
|
||||
)
|
||||
|
||||
{-|
|
||||
|
||||
@docs Timeline, TimelineDetails, Occurring, getEvents
|
||||
@docs Timeline, TimelineDetails, Occurring
|
||||
|
||||
@docs Schedule, Event
|
||||
|
||||
@docs needsUpdate, update, updateWith
|
||||
@docs update, updateWith
|
||||
|
||||
@docs startTime, endTime, getEvent, extendEventDwell, hasDwell, isResting
|
||||
@docs startTime, endTime, getEvent, extendEventDwell
|
||||
|
||||
@docs addToDwell
|
||||
|
||||
@docs sendPing
|
||||
|
||||
@docs current, arrivedAt, arrived, previous, upcoming
|
||||
|
||||
@docs progress
|
||||
|
||||
@docs Line, Timetable
|
||||
|
||||
@docs foldpAll, captureTimeline
|
||||
@docs foldpAll
|
||||
|
||||
@docs gc, atTime, dwellingTime, getCurrentTime, linesAreActive
|
||||
|
||||
@docs Transition
|
||||
|
||||
-}
|
||||
|
||||
@ -50,21 +55,6 @@ type Event event
|
||||
= Event Time.Duration event (Maybe Time.Duration)
|
||||
|
||||
|
||||
type Period
|
||||
= Loop Time.Duration
|
||||
| Repeat Int Time.Duration
|
||||
|
||||
|
||||
periodDuration : Period -> Time.Duration
|
||||
periodDuration per =
|
||||
case per of
|
||||
Loop dur ->
|
||||
dur
|
||||
|
||||
Repeat i dur ->
|
||||
dur
|
||||
|
||||
|
||||
getScheduledEvent : Event event -> event
|
||||
getScheduledEvent (Event _ ev _) =
|
||||
ev
|
||||
@ -121,29 +111,6 @@ type Occurring event
|
||||
{- TYPES FOR INTERPOLATION -}
|
||||
|
||||
|
||||
{-| First, let's cover what the type parameters are
|
||||
|
||||
Examples:
|
||||
|
||||
The symbolic state of the timeline entry.
|
||||
state -> MenuOpen
|
||||
|
||||
The description of how to animate that symbolic state
|
||||
anchor ->
|
||||
= Osc Personality Period (Float -> Float)
|
||||
| Pos Personality Float
|
||||
|
||||
The actual value that's moving
|
||||
motion -> { x:34, y: 34 }
|
||||
|
||||
-}
|
||||
type alias Interp state anchor motion =
|
||||
{ start : anchor -> motion
|
||||
, visit : Visit state anchor motion
|
||||
, transition : Lerp anchor motion
|
||||
}
|
||||
|
||||
|
||||
type alias Transition state anchor motion =
|
||||
(state -> anchor)
|
||||
-- previous event
|
||||
@ -167,74 +134,6 @@ type alias Transition state anchor motion =
|
||||
-> motion
|
||||
|
||||
|
||||
type alias Visit state anchor motion =
|
||||
(state -> anchor)
|
||||
-> Occurring state
|
||||
-> Time.Absolute
|
||||
-> Maybe (LookAhead anchor)
|
||||
-> motion
|
||||
-> motion
|
||||
|
||||
|
||||
type alias LookAhead state =
|
||||
{ anchor : state
|
||||
, time : Time.Absolute
|
||||
, resting : Bool
|
||||
}
|
||||
|
||||
|
||||
mapLookAhead : (a -> b) -> LookAhead a -> LookAhead b
|
||||
mapLookAhead fn look =
|
||||
{ anchor = fn look.anchor
|
||||
, time = look.time
|
||||
, resting = look.resting
|
||||
}
|
||||
|
||||
|
||||
type alias Lerp anchor motion =
|
||||
Time.Absolute
|
||||
-> anchor
|
||||
-> anchor
|
||||
-> Time.Absolute
|
||||
-> Time.Absolute
|
||||
-> Maybe (LookAhead anchor)
|
||||
-> motion
|
||||
-> motion
|
||||
|
||||
|
||||
type Previous event
|
||||
= Previous (Occurring event)
|
||||
| PreviouslyInterrupted Time.Absolute
|
||||
|
||||
|
||||
mapTable : (Occurring a -> Occurring b) -> Timetable a -> Timetable b
|
||||
mapTable fn (Timetable lines) =
|
||||
Timetable (List.map (mapLine fn) lines)
|
||||
|
||||
|
||||
mapLine : (Occurring a -> Occurring b) -> Line a -> Line b
|
||||
mapLine fn (Line t startEvent els) =
|
||||
Line t (fn startEvent) (List.map fn els)
|
||||
|
||||
|
||||
mapLineWith : (Occurring a -> state -> ( Occurring b, state )) -> state -> Line a -> ( Line b, state )
|
||||
mapLineWith fn initial (Line start startingEvent remaining) =
|
||||
let
|
||||
onLine occur ( events, state ) =
|
||||
let
|
||||
( newOccur, newState ) =
|
||||
fn occur state
|
||||
in
|
||||
( newOccur :: events, newState )
|
||||
|
||||
( newStartingEvent, startingState ) =
|
||||
fn startingEvent initial
|
||||
in
|
||||
case List.foldl onLine ( [], startingState ) remaining of
|
||||
( reversedEvents, newState ) ->
|
||||
( Line start newStartingEvent (List.reverse reversedEvents), newState )
|
||||
|
||||
|
||||
getEvent : Occurring event -> event
|
||||
getEvent (Occurring ev _ _) =
|
||||
ev
|
||||
@ -249,16 +148,6 @@ extendEventDwell extendBy ((Event at ev maybeDwell) as thisEvent) =
|
||||
Event at ev (addToDwell extendBy maybeDwell)
|
||||
|
||||
|
||||
hasDwell : Occurring event -> Bool
|
||||
hasDwell (Occurring _ (Quantity.Quantity start) (Quantity.Quantity end)) =
|
||||
(start - end) /= 0
|
||||
|
||||
|
||||
isResting : Occurring event -> Bool
|
||||
isResting (Occurring _ (Quantity.Quantity start) (Quantity.Quantity end)) =
|
||||
(end - start) == 0
|
||||
|
||||
|
||||
startTime : Occurring event -> Time.Absolute
|
||||
startTime (Occurring _ time _) =
|
||||
time
|
||||
@ -269,26 +158,6 @@ endTime (Occurring _ _ end) =
|
||||
end
|
||||
|
||||
|
||||
type Description event
|
||||
= DescribeStartTransition Time.Posix
|
||||
| DescribeEvent Time.Posix event
|
||||
| DescribeInterruption
|
||||
{ interruption : Time.Posix
|
||||
, target : event
|
||||
, newTarget : event
|
||||
, newTargetTime : Time.Posix
|
||||
}
|
||||
|
||||
|
||||
getEvents : Timeline event -> List (List ( Time.Posix, event ))
|
||||
getEvents (Timeline timeline) =
|
||||
case timeline.events of
|
||||
Timetable lines ->
|
||||
lines
|
||||
|> List.map (\(Line _ start ev) -> start :: ev)
|
||||
|> List.map (List.map (\(Occurring evt time _) -> ( Time.toPosix time, evt )))
|
||||
|
||||
|
||||
atTime : Time.Posix -> Timeline event -> Timeline event
|
||||
atTime now (Timeline timeline) =
|
||||
Timeline { timeline | now = Time.absolute now }
|
||||
@ -334,11 +203,6 @@ updateWith withGC possiblyNow (Timeline timeline) =
|
||||
clean : Bool -> TimelineDetails event -> TimelineDetails event
|
||||
clean runGC details =
|
||||
let
|
||||
events =
|
||||
case details.events of
|
||||
Timetable evs ->
|
||||
evs
|
||||
|
||||
running =
|
||||
case details.events of
|
||||
Timetable lines ->
|
||||
@ -349,6 +213,12 @@ clean runGC details =
|
||||
running
|
||||
, events =
|
||||
if runGC then
|
||||
let
|
||||
events =
|
||||
case details.events of
|
||||
Timetable evs ->
|
||||
evs
|
||||
in
|
||||
Timetable (garbageCollectOldEvents details.now [] events)
|
||||
|
||||
else
|
||||
@ -597,7 +467,7 @@ scaleEvent scale (Event dur event maybeDur) =
|
||||
|
||||
-}
|
||||
scheduleMatchesExisting : Schedule event -> Line event -> Bool
|
||||
scheduleMatchesExisting (Schedule scheduleDelay event schedulUpcoming) (Line lineStart lineStartEvent lineUpcoming) =
|
||||
scheduleMatchesExisting (Schedule _ event schedulUpcoming) (Line _ lineStartEvent lineUpcoming) =
|
||||
let
|
||||
equalStartEvent =
|
||||
scheduledEventEqual event lineStartEvent
|
||||
@ -619,7 +489,7 @@ scheduleMatchesExisting (Schedule scheduleDelay event schedulUpcoming) (Line lin
|
||||
|
||||
|
||||
scheduledEventEqual : Event event -> Occurring event -> Bool
|
||||
scheduledEventEqual (Event dur schedEvent maybeDwell) (Occurring occurEvent occurStart occurEnd) =
|
||||
scheduledEventEqual (Event _ schedEvent _) (Occurring occurEvent _ _) =
|
||||
schedEvent == occurEvent
|
||||
|
||||
|
||||
@ -685,17 +555,17 @@ interrupt timeline scheduled =
|
||||
|
||||
interruptLines : Time.Absolute -> Schedule event -> List (Line event) -> List (Line event) -> Maybe (List (Line event))
|
||||
interruptLines now scheduled pastLines lines =
|
||||
let
|
||||
startInterruption =
|
||||
case scheduled of
|
||||
Schedule scheduleDelay _ _ ->
|
||||
Time.advanceBy scheduleDelay now
|
||||
in
|
||||
case lines of
|
||||
[] ->
|
||||
Nothing
|
||||
|
||||
startLine :: remaining ->
|
||||
let
|
||||
startInterruption =
|
||||
case scheduled of
|
||||
Schedule scheduleDelay _ _ ->
|
||||
Time.advanceBy scheduleDelay now
|
||||
in
|
||||
if interruptionHappensLater startInterruption remaining then
|
||||
interruptLines now scheduled (startLine :: pastLines) remaining
|
||||
|
||||
@ -731,14 +601,14 @@ interruptionHappensLater startInterruption remaining =
|
||||
|
||||
interruptLine : Time.Absolute -> Schedule event -> Line event -> List (Line event) -> Maybe (List (Line event))
|
||||
interruptLine now scheduled line future =
|
||||
let
|
||||
startInterruption =
|
||||
case scheduled of
|
||||
Schedule scheduleDelay _ _ ->
|
||||
Time.advanceBy scheduleDelay now
|
||||
in
|
||||
case line of
|
||||
Line start startEvent trailing ->
|
||||
let
|
||||
startInterruption =
|
||||
case scheduled of
|
||||
Schedule scheduleDelay _ _ ->
|
||||
Time.advanceBy scheduleDelay now
|
||||
in
|
||||
if Time.thisAfterOrEqualThat startInterruption start then
|
||||
-- this line starts before the interruption
|
||||
case future of
|
||||
@ -803,18 +673,19 @@ getTransitionAt interruptionTime prev trailing =
|
||||
|
||||
|
||||
interruptAtExactly : Time.Absolute -> Schedule event -> LastTwoEvents event -> Line event
|
||||
interruptAtExactly now scheduled ((LastTwoEvents penultimateTime penultimate lastEventTime lastEvent) as last) =
|
||||
interruptAtExactly now scheduled (LastTwoEvents penultimateTime penultimate lastEventTime _) =
|
||||
case scheduled of
|
||||
Schedule delay_ startingEvent reverseQueued ->
|
||||
let
|
||||
amountProgress =
|
||||
Time.progress penultimateTime
|
||||
lastEventTime
|
||||
(Time.advanceBy delay_ now)
|
||||
|
||||
newStartingEvent =
|
||||
-- we apply the discount if we are returning to a state
|
||||
if penultimate == getScheduledEvent startingEvent then
|
||||
let
|
||||
amountProgress =
|
||||
Time.progress penultimateTime
|
||||
lastEventTime
|
||||
(Time.advanceBy delay_ now)
|
||||
in
|
||||
startingEvent
|
||||
|> adjustScheduledDuration (Quantity.multiplyBy amountProgress)
|
||||
|
||||
@ -1008,33 +879,6 @@ addToDwell duration maybeDwell =
|
||||
Just (Quantity.plus duration existing)
|
||||
|
||||
|
||||
rescale : Time.Absolute -> Float -> List (Line event) -> List (Line event)
|
||||
rescale now scale lines =
|
||||
if scale == 1 then
|
||||
lines
|
||||
|
||||
else
|
||||
List.map (rescaleLine now scale) lines
|
||||
|
||||
|
||||
rescaleLine : Time.Absolute -> Float -> Line event -> Line event
|
||||
rescaleLine now scale (Line lineStart firstEvent remain) =
|
||||
Line
|
||||
(rescaleTime now scale lineStart)
|
||||
(rescaleEvent now scale firstEvent)
|
||||
(List.map (rescaleEvent now scale) remain)
|
||||
|
||||
|
||||
rescaleTime : Time.Absolute -> Float -> Time.Absolute -> Time.Absolute
|
||||
rescaleTime (Quantity.Quantity now) scale (Quantity.Quantity time) =
|
||||
Time.millis (now + ((time - now) * scale))
|
||||
|
||||
|
||||
rescaleEvent : Time.Absolute -> Float -> Occurring event -> Occurring event
|
||||
rescaleEvent now scale (Occurring event start end) =
|
||||
Occurring event (rescaleTime now scale start) (rescaleTime now scale end)
|
||||
|
||||
|
||||
foldpAll :
|
||||
(state -> anchor)
|
||||
-> (anchor -> motion)
|
||||
@ -1052,7 +896,7 @@ foldpAll lookup toStart transitionTo (Timeline timelineDetails) =
|
||||
[] ->
|
||||
start
|
||||
|
||||
(Line lineStart firstEvent remain) :: _ ->
|
||||
(Line lineStart _ _) :: _ ->
|
||||
visitAll2
|
||||
lookup
|
||||
transitionTo
|
||||
@ -1238,176 +1082,6 @@ visitAll2 toAnchor transitionTo details prev queue future state =
|
||||
new
|
||||
|
||||
|
||||
type alias FramesSummary motion =
|
||||
{ frames : List (Frame motion)
|
||||
, duration : Time.Duration
|
||||
, dwell :
|
||||
Maybe
|
||||
{ period : Period
|
||||
, frames : List (Frame motion)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
type Frame motion
|
||||
= Frame Float motion
|
||||
|
||||
|
||||
type alias Summary event =
|
||||
{ events : List (SummaryEvent event)
|
||||
, now : Time.Absolute
|
||||
, startTime : Time.Absolute
|
||||
}
|
||||
|
||||
|
||||
type SummaryEvent event
|
||||
= EventSummary event Time.Absolute ActualDuration
|
||||
| InterruptionSummary
|
||||
{ target : event
|
||||
, targetTime : Time.Absolute
|
||||
, interruptedAt : Time.Absolute
|
||||
, newTarget : event
|
||||
, newTargetTime : Time.Absolute
|
||||
, newTargetDuration : ActualDuration
|
||||
}
|
||||
|
||||
|
||||
type ActualDuration
|
||||
= OpenDuration
|
||||
| KnownDuration Time.Duration
|
||||
|
||||
|
||||
{-| -}
|
||||
type Frames item
|
||||
= Single item
|
||||
| Hold Int item
|
||||
| Walk item (List (Frames item))
|
||||
| WithRest (Resting item) (Frames item)
|
||||
|
||||
|
||||
{-| -}
|
||||
type Resting item
|
||||
= Cycle Period (List (Frames item))
|
||||
|
||||
|
||||
captureTimeline :
|
||||
(state -> anchor)
|
||||
-> Timeline state
|
||||
-> Summary anchor
|
||||
captureTimeline lookup (Timeline timelineDetails) =
|
||||
case timelineDetails.events of
|
||||
Timetable timetable ->
|
||||
case timetable of
|
||||
[] ->
|
||||
-- I believe this case is fleeting because as soon as we have a real time,
|
||||
-- we add a line to the timetable.
|
||||
-- However, maybe it is awkwardly rendered once?
|
||||
{ events =
|
||||
[ EventSummary
|
||||
(lookup timelineDetails.initial)
|
||||
timelineDetails.now
|
||||
OpenDuration
|
||||
]
|
||||
, now = timelineDetails.now
|
||||
, startTime = timelineDetails.now
|
||||
}
|
||||
|
||||
(Line start startEv remain) :: remainingLines ->
|
||||
let
|
||||
events =
|
||||
captureTimelineHelper lookup
|
||||
(startEv :: remain)
|
||||
remainingLines
|
||||
[]
|
||||
in
|
||||
{ events = List.reverse events
|
||||
, now = timelineDetails.now
|
||||
, startTime = start
|
||||
}
|
||||
|
||||
|
||||
{-| Summarize all the events on the current timeline.
|
||||
|
||||
Note, this does not take into account time adjustments!
|
||||
|
||||
Essentially this is only used for sprite animation, which currently dont have leaveLate or arriveEarly.
|
||||
|
||||
-}
|
||||
captureTimelineHelper :
|
||||
(state -> anchor)
|
||||
-> List (Occurring state)
|
||||
-> List (Line state)
|
||||
-> List (SummaryEvent anchor)
|
||||
-> List (SummaryEvent anchor)
|
||||
captureTimelineHelper lookup events futureLines summary =
|
||||
-- futureStart starts a new line.
|
||||
-- if an interruption occurs, we want to interpolate to the point of the interruption
|
||||
-- then transition over to the new line.
|
||||
case events of
|
||||
[] ->
|
||||
case futureLines of
|
||||
[] ->
|
||||
summary
|
||||
|
||||
(Line futureStart futureStartEv futureRemain) :: restOfFuture ->
|
||||
captureTimelineHelper lookup (futureStartEv :: futureRemain) restOfFuture summary
|
||||
|
||||
(Occurring event start eventEnd) :: remain ->
|
||||
case futureLines of
|
||||
[] ->
|
||||
case remain of
|
||||
[] ->
|
||||
let
|
||||
newEvent =
|
||||
EventSummary (lookup event) start OpenDuration
|
||||
in
|
||||
newEvent :: summary
|
||||
|
||||
_ ->
|
||||
let
|
||||
newEvent =
|
||||
EventSummary (lookup event) start (KnownDuration (Time.duration start eventEnd))
|
||||
in
|
||||
captureTimelineHelper lookup remain futureLines (newEvent :: summary)
|
||||
|
||||
(Line futureStart futureStartEv futureRemain) :: restOfFuture ->
|
||||
if Time.thisBeforeOrEqualThat futureStart start then
|
||||
-- interruption
|
||||
let
|
||||
newEvent =
|
||||
InterruptionSummary
|
||||
{ target = lookup event
|
||||
, targetTime = start
|
||||
, interruptedAt = futureStart
|
||||
, newTarget = lookup (getEvent futureStartEv)
|
||||
, newTargetTime = startTime futureStartEv
|
||||
, newTargetDuration =
|
||||
case futureRemain of
|
||||
[] ->
|
||||
case restOfFuture of
|
||||
[] ->
|
||||
OpenDuration
|
||||
|
||||
_ ->
|
||||
KnownDuration (Time.duration start eventEnd)
|
||||
|
||||
_ ->
|
||||
KnownDuration (Time.duration start eventEnd)
|
||||
}
|
||||
in
|
||||
captureTimelineHelper lookup futureRemain restOfFuture (newEvent :: summary)
|
||||
|
||||
else
|
||||
-- queue up new events
|
||||
let
|
||||
newEvent =
|
||||
EventSummary (lookup event)
|
||||
start
|
||||
(KnownDuration (Time.duration start eventEnd))
|
||||
in
|
||||
captureTimelineHelper lookup remain futureLines (newEvent :: summary)
|
||||
|
||||
|
||||
|
||||
{- BOOKKEEPING -}
|
||||
|
||||
@ -1418,10 +1092,10 @@ type Status
|
||||
|
||||
|
||||
status : Timeline event -> Status
|
||||
status ((Timeline details) as timeline) =
|
||||
status timeline =
|
||||
foldpAll identity
|
||||
(\_ -> Dwelling Time.zeroDuration)
|
||||
(\lookup prev target now start end future state ->
|
||||
(\_ _ _ now start end _ _ ->
|
||||
if Time.thisAfterThat now end then
|
||||
Dwelling (Time.duration now end)
|
||||
|
||||
@ -1466,7 +1140,7 @@ arrived : Timeline event -> event
|
||||
arrived ((Timeline details) as timeline) =
|
||||
foldpAll identity
|
||||
(\_ -> details.initial)
|
||||
(\lookup prev target now start end future state ->
|
||||
(\_ _ target now _ end _ state ->
|
||||
-- This is the current event when
|
||||
-- we have started toward an event or arrived at it.
|
||||
-- A tricky aspect is that css timelines are only updated on transition
|
||||
@ -1484,7 +1158,7 @@ current : Timeline event -> event
|
||||
current ((Timeline details) as timeline) =
|
||||
foldpAll identity
|
||||
(\_ -> details.initial)
|
||||
(\lookup prev target now start end future state ->
|
||||
(\_ _ target now start end future state ->
|
||||
-- This is the current event when
|
||||
-- we have started toward an event or arrived at it.
|
||||
-- A tricky aspect is that css timelines are only updated on transition
|
||||
@ -1508,7 +1182,7 @@ previous : Timeline event -> event
|
||||
previous ((Timeline details) as timeline) =
|
||||
foldpAll identity
|
||||
(\_ -> details.initial)
|
||||
(\lookup prev target now start end future state ->
|
||||
(\_ _ target now _ _ future state ->
|
||||
if Time.thisAfterThat now (endTime target) then
|
||||
case future of
|
||||
[] ->
|
||||
@ -1527,7 +1201,7 @@ arrivedAt : (event -> Bool) -> Time.Posix -> Timeline event -> Bool
|
||||
arrivedAt matches newTime ((Timeline details) as tl) =
|
||||
foldpAll identity
|
||||
(\_ -> False)
|
||||
(\lookup prev target now start end future state ->
|
||||
(\_ _ target _ _ end _ state ->
|
||||
state
|
||||
|| (matches (getEvent target)
|
||||
&& Time.thisBeforeOrEqualThat details.now end
|
||||
@ -1553,7 +1227,7 @@ matchesEvent matches (Event _ event _) =
|
||||
|
||||
|
||||
anyScheduled : (event -> Bool) -> Schedule event -> Bool
|
||||
anyScheduled matches (Schedule dur startEvent remainingEvents) =
|
||||
anyScheduled matches (Schedule _ startEvent remainingEvents) =
|
||||
if matchesEvent matches startEvent then
|
||||
True
|
||||
|
||||
@ -1576,149 +1250,10 @@ upcoming matches ((Timeline details) as tl) =
|
||||
else
|
||||
foldpAll identity
|
||||
(\_ -> False)
|
||||
(\lookup prev target now start end future state ->
|
||||
(\_ _ target now _ end _ state ->
|
||||
state
|
||||
|| (matches (getEvent target)
|
||||
&& Time.thisBeforeThat now end
|
||||
)
|
||||
)
|
||||
tl
|
||||
|
||||
|
||||
|
||||
{- ANIMATOR -}
|
||||
{- The animator checks to see if any timelines are running and also has the ability to update the animation state.
|
||||
|
||||
|
||||
Different animators can do different things
|
||||
|
||||
|
||||
- Normal -> always on
|
||||
- Inline -> on when moving (require anotation of dwelling events)
|
||||
- CSS -> single update when timeline is updated
|
||||
|
||||
|
||||
-}
|
||||
|
||||
|
||||
{-| -}
|
||||
type Animator model
|
||||
= Animator (model -> Running) (Time.Posix -> model -> model)
|
||||
|
||||
|
||||
type alias Running =
|
||||
{ running : Bool
|
||||
, ping : Maybe { delay : Float, target : Time.Posix }
|
||||
}
|
||||
|
||||
|
||||
combineRunning : Running -> Running -> Running
|
||||
combineRunning one two =
|
||||
{ running = one.running || two.running
|
||||
, ping =
|
||||
case two.ping of
|
||||
Nothing ->
|
||||
one.ping
|
||||
|
||||
Just twoPing ->
|
||||
case one.ping of
|
||||
Nothing ->
|
||||
Just twoPing
|
||||
|
||||
Just onePing ->
|
||||
if onePing.delay < twoPing.delay then
|
||||
Just onePing
|
||||
|
||||
else
|
||||
Just twoPing
|
||||
}
|
||||
|
||||
|
||||
sendPing : Timeline event -> Maybe { delay : Float, target : Time.Posix }
|
||||
sendPing ((Timeline details) as timeline) =
|
||||
Maybe.andThen (encodeStamp details.now) (findNextTransitionTime timeline)
|
||||
|
||||
|
||||
findNextTransitionTime : Timeline event -> Maybe Time.Absolute
|
||||
findNextTransitionTime ((Timeline details) as timeline) =
|
||||
foldpAll identity
|
||||
(\_ -> Nothing)
|
||||
(\lookup prev target now start end future state ->
|
||||
if Time.thisBeforeThat now end && (startTime target == end) then
|
||||
Just (startTime target)
|
||||
|
||||
else
|
||||
state
|
||||
)
|
||||
timeline
|
||||
|
||||
|
||||
{-| This is to account for a bug in `Time.every` where it uses the provided delay time as a key to keep track of a time.
|
||||
|
||||
To get around this, we encode the current time as a really small part of the given time.
|
||||
|
||||
-}
|
||||
encodeStamp : Time.Absolute -> Time.Absolute -> Maybe { delay : Float, target : Time.Posix }
|
||||
encodeStamp now target =
|
||||
let
|
||||
millis =
|
||||
Time.inMilliseconds target - nowInMillis
|
||||
|
||||
nowInMillis =
|
||||
Time.inMilliseconds now
|
||||
|
||||
nowTail =
|
||||
nowInMillis / 1000000
|
||||
|
||||
pingDelay =
|
||||
millis + (1 / nowTail)
|
||||
in
|
||||
if pingDelay <= 0 then
|
||||
Nothing
|
||||
|
||||
else
|
||||
Just
|
||||
{ delay = pingDelay
|
||||
, target =
|
||||
Time.millisToPosix (round (Time.inMilliseconds target + 1))
|
||||
}
|
||||
|
||||
|
||||
{-| -}
|
||||
needsUpdate : Timeline event -> Bool
|
||||
needsUpdate ((Timeline timeline) as tl) =
|
||||
case timeline.queued of
|
||||
Nothing ->
|
||||
case timeline.interruption of
|
||||
[] ->
|
||||
timeline.running
|
||||
|
||||
_ ->
|
||||
True
|
||||
|
||||
Just _ ->
|
||||
True
|
||||
|
||||
|
||||
{-| -}
|
||||
hasChanged : Timeline event -> Bool
|
||||
hasChanged (Timeline timeline) =
|
||||
case timeline.queued of
|
||||
Nothing ->
|
||||
case timeline.interruption of
|
||||
[] ->
|
||||
False
|
||||
|
||||
_ ->
|
||||
True
|
||||
|
||||
Just _ ->
|
||||
True
|
||||
|
||||
|
||||
{-| -}
|
||||
justInitialized : Timeline event -> Bool
|
||||
justInitialized (Timeline timeline) =
|
||||
case timeline.now of
|
||||
Quantity.Quantity qty ->
|
||||
qty == 0
|
||||
|
@ -1,10 +1,10 @@
|
||||
module InternalAnim.Transition exposing
|
||||
( Transition(..)
|
||||
, linear, standard, wobble, bezier
|
||||
, initialVelocity, atX
|
||||
, split, before
|
||||
, hash, keyframes
|
||||
, atX2, isStandard, takeAfter, withVelocities
|
||||
, atX
|
||||
, isStandard
|
||||
, takeAfter, withVelocities
|
||||
)
|
||||
|
||||
{-|
|
||||
@ -13,12 +13,14 @@ module InternalAnim.Transition exposing
|
||||
|
||||
@docs linear, standard, wobble, bezier
|
||||
|
||||
@docs initialVelocity, atX
|
||||
|
||||
@docs split, before
|
||||
|
||||
@docs hash, keyframes
|
||||
|
||||
@docs atX
|
||||
|
||||
@docs isStandard
|
||||
|
||||
@docs takeAfter, withVelocities
|
||||
|
||||
Current bezier formats for elm-animator
|
||||
|
||||
Standard:
|
||||
@ -62,11 +64,7 @@ Goals:
|
||||
|
||||
import Bezier
|
||||
import Bezier.Spring as Spring
|
||||
import InternalAnim.Duration as Duration
|
||||
import InternalAnim.Hash as Hash
|
||||
import InternalAnim.Quantity as Quantity
|
||||
import InternalAnim.Time as Time
|
||||
import InternalAnim.Units as Units
|
||||
|
||||
|
||||
{-| A transition are all the bezier curves between A and B that we want to transition through.
|
||||
@ -197,76 +195,15 @@ isStandard trans =
|
||||
False
|
||||
|
||||
|
||||
type alias TimeDomain =
|
||||
{ start : PointInTime
|
||||
, end : PointInTime
|
||||
}
|
||||
|
||||
|
||||
type alias PointInTime =
|
||||
{ x : Time.Absolute
|
||||
, y : Units.Pixels
|
||||
}
|
||||
|
||||
|
||||
{-| -}
|
||||
atX :
|
||||
Float
|
||||
-> TimeDomain
|
||||
-> Units.PixelsPerSecond
|
||||
-> Units.PixelsPerSecond
|
||||
-> Transition
|
||||
->
|
||||
{ position : Units.Pixels
|
||||
, velocity : Units.PixelsPerSecond
|
||||
}
|
||||
atX progress domain introVelocity exitVelocity transition =
|
||||
case transition of
|
||||
Transition spline ->
|
||||
if domain.start.x == domain.end.x then
|
||||
{ position = domain.end.y
|
||||
, velocity =
|
||||
exitVelocity
|
||||
}
|
||||
|
||||
else
|
||||
spline
|
||||
|> inTimeDomain domain introVelocity exitVelocity
|
||||
|> posVel (toTimeProgress domain progress)
|
||||
|
||||
Wobble wob ->
|
||||
let
|
||||
totalX =
|
||||
Time.inMilliseconds domain.end.x - Time.inMilliseconds domain.start.x
|
||||
|
||||
params =
|
||||
Spring.new
|
||||
{ wobble = wob.wobble
|
||||
, quickness = wob.quickness
|
||||
, settleMax = totalX
|
||||
}
|
||||
in
|
||||
Spring.at
|
||||
{ spring = params
|
||||
, initial =
|
||||
{ position = Units.inPixels domain.start.y
|
||||
, velocity = Units.inPixelsPerMs introVelocity
|
||||
}
|
||||
, target = Units.inPixels domain.end.y
|
||||
}
|
||||
(totalX * progress)
|
||||
|> wrapUnits
|
||||
|
||||
|
||||
{-| -}
|
||||
atX2 :
|
||||
Float
|
||||
-> Transition
|
||||
->
|
||||
{ position : Bezier.Point
|
||||
, velocity : Bezier.Point
|
||||
}
|
||||
atX2 progress transition =
|
||||
atX progress transition =
|
||||
case transition of
|
||||
Transition spline ->
|
||||
let
|
||||
@ -327,146 +264,6 @@ withVelocities intro exit transition =
|
||||
}
|
||||
|
||||
|
||||
toTimeProgress :
|
||||
TimeDomain
|
||||
-> Float
|
||||
-> Float
|
||||
toTimeProgress domain factor =
|
||||
let
|
||||
start =
|
||||
Time.inMilliseconds domain.start.x
|
||||
|
||||
end =
|
||||
Time.inMilliseconds domain.end.x
|
||||
in
|
||||
((end - start) * factor) + start
|
||||
|
||||
|
||||
wrapUnits state =
|
||||
{ position =
|
||||
Units.pixels state.position
|
||||
, velocity =
|
||||
Units.pixelsPerSecond (state.velocity * 1000)
|
||||
}
|
||||
|
||||
|
||||
posVel :
|
||||
Float
|
||||
-> Bezier.Spline
|
||||
->
|
||||
{ position : Units.Pixels
|
||||
, velocity : Units.PixelsPerSecond
|
||||
}
|
||||
posVel progress spline =
|
||||
let
|
||||
current =
|
||||
Bezier.atX progress spline
|
||||
|
||||
firstDeriv =
|
||||
Bezier.firstDerivative spline current.t
|
||||
in
|
||||
{ position =
|
||||
Units.pixels current.point.y
|
||||
, velocity =
|
||||
Units.pixelsPerSecond ((firstDeriv.y / firstDeriv.x) * 1000)
|
||||
}
|
||||
|
||||
|
||||
zeroVelocity : Float
|
||||
zeroVelocity =
|
||||
0
|
||||
|
||||
|
||||
initialVelocity : Transition -> Float
|
||||
initialVelocity transition =
|
||||
case transition of
|
||||
Transition spline ->
|
||||
let
|
||||
firstDeriv =
|
||||
-- at t == 0, the first derivative vector will always be 0,0
|
||||
-- so we cheat in slightly.
|
||||
Bezier.firstDerivative spline 0.001
|
||||
in
|
||||
if firstDeriv.x == 0 then
|
||||
zeroVelocity
|
||||
|
||||
else
|
||||
firstDeriv.y / firstDeriv.x
|
||||
|
||||
Wobble wob ->
|
||||
zeroVelocity
|
||||
|
||||
|
||||
type alias Domain =
|
||||
{ start : Bezier.Point
|
||||
, end : Bezier.Point
|
||||
}
|
||||
|
||||
|
||||
third : Float
|
||||
third =
|
||||
1 / 3
|
||||
|
||||
|
||||
negativeThird : Float
|
||||
negativeThird =
|
||||
-1 / 3
|
||||
|
||||
|
||||
{-| Note, we only rotate the control point to match the desired velocity.
|
||||
|
||||
However, there is the question of the magnitude of the control point.
|
||||
|
||||
I _think_ the magnitude is roughly equivalent to momentum.
|
||||
|
||||
It's possible that we override the built-in control points when there is a non-0 intro/exit Velocity.
|
||||
|
||||
Maybe it's a constant like 1/3 or something....
|
||||
|
||||
-}
|
||||
toDomain : Domain -> Float -> Float -> Bezier.Spline -> Bezier.Spline
|
||||
toDomain domain introVelocity exitVelocity spline =
|
||||
let
|
||||
{ two, three } =
|
||||
toBezierPoints spline
|
||||
|
||||
totalX =
|
||||
domain.end.x - domain.start.x
|
||||
|
||||
totalY =
|
||||
domain.end.y - domain.start.y
|
||||
|
||||
ctrl1 =
|
||||
let
|
||||
angle =
|
||||
atan2 introVelocity 1
|
||||
in
|
||||
{ x =
|
||||
(totalX * two.x) + domain.start.x
|
||||
, y =
|
||||
(totalY * two.y) + domain.start.y
|
||||
}
|
||||
|> rotateAround angle domain.start
|
||||
|
||||
ctrl2 =
|
||||
let
|
||||
angle =
|
||||
atan2 exitVelocity 1
|
||||
in
|
||||
{ x =
|
||||
(totalX * three.x) + domain.start.x
|
||||
, y =
|
||||
(totalY * three.y) + domain.start.y
|
||||
}
|
||||
|> rotateAround angle domain.end
|
||||
in
|
||||
Bezier.fromPoints
|
||||
domain.start
|
||||
ctrl1
|
||||
ctrl2
|
||||
domain.end
|
||||
|
||||
|
||||
toBezierPoints : Bezier.Spline -> { one : Bezier.Point, two : Bezier.Point, three : Bezier.Point, four : Bezier.Point }
|
||||
toBezierPoints spline =
|
||||
{ one = Bezier.first spline
|
||||
@ -476,136 +273,6 @@ toBezierPoints spline =
|
||||
}
|
||||
|
||||
|
||||
inTimeDomain : TimeDomain -> Units.PixelsPerSecond -> Units.PixelsPerSecond -> Bezier.Spline -> Bezier.Spline
|
||||
inTimeDomain domain introVelocity exitVelocity spline =
|
||||
let
|
||||
{ one, two, three, four } =
|
||||
toBezierPoints spline
|
||||
|
||||
totalX =
|
||||
Time.inMilliseconds domain.end.x - Time.inMilliseconds domain.start.x
|
||||
|
||||
totalY =
|
||||
Units.inPixels domain.end.y - Units.inPixels domain.start.y
|
||||
|
||||
ctrl1 =
|
||||
let
|
||||
angle =
|
||||
atan2 (Units.inPixelsPerMs introVelocity) 1
|
||||
in
|
||||
{ x =
|
||||
(totalX * two.x) + Time.inMilliseconds domain.start.x
|
||||
, y =
|
||||
(totalY * two.y) + Units.inPixels domain.start.y
|
||||
}
|
||||
|> rotateAroundTimePoint angle domain.start
|
||||
|
||||
ctrl2 =
|
||||
let
|
||||
angle =
|
||||
atan2 (Units.inPixelsPerMs exitVelocity) 1
|
||||
in
|
||||
{ x =
|
||||
(totalX * three.x) + Time.inMilliseconds domain.start.x
|
||||
, y =
|
||||
(totalY * three.y) + Units.inPixels domain.start.y
|
||||
}
|
||||
|> rotateAroundTimePoint angle domain.end
|
||||
in
|
||||
Bezier.fromPoints
|
||||
{ x = Time.inMilliseconds domain.start.x
|
||||
, y = Units.inPixels domain.start.y
|
||||
}
|
||||
ctrl1
|
||||
ctrl2
|
||||
{ x = Time.inMilliseconds domain.end.x
|
||||
, y = Units.inPixels domain.end.y
|
||||
}
|
||||
|
||||
|
||||
{-| -}
|
||||
rotateAroundTimePoint : Float -> PointInTime -> Bezier.Point -> Bezier.Point
|
||||
rotateAroundTimePoint radians center point =
|
||||
let
|
||||
centerX =
|
||||
Time.inMilliseconds center.x
|
||||
|
||||
centerY =
|
||||
Units.inPixels center.y
|
||||
in
|
||||
{ x = cos radians * (point.x - centerX) - sin radians * (point.y - centerY) + centerX
|
||||
, y = sin radians * (point.x - centerX) + cos radians * (point.y - centerY) + centerY
|
||||
}
|
||||
|
||||
|
||||
{-| -}
|
||||
rotateAround : Float -> Bezier.Point -> Bezier.Point -> Bezier.Point
|
||||
rotateAround radians center point =
|
||||
{ x = cos radians * (point.x - center.x) - sin radians * (point.y - center.y) + center.x
|
||||
, y = sin radians * (point.x - center.x) + cos radians * (point.y - center.y) + center.y
|
||||
}
|
||||
|
||||
|
||||
translateBy : Bezier.Point -> Bezier.Point -> Bezier.Point
|
||||
translateBy one two =
|
||||
{ x = one.x + two.x
|
||||
, y = one.y + two.y
|
||||
}
|
||||
|
||||
|
||||
scaleBy : Float -> Bezier.Point -> Bezier.Point
|
||||
scaleBy k v =
|
||||
{ x = k * v.x
|
||||
, y = k * v.y
|
||||
}
|
||||
|
||||
|
||||
scaleAbout : Bezier.Point -> Float -> Bezier.Point -> Bezier.Point
|
||||
scaleAbout p0 k p =
|
||||
{ x = p0.x + k * (p.x - p0.x)
|
||||
, y = p0.y + k * (p.y - p0.y)
|
||||
}
|
||||
|
||||
|
||||
{-| We are vector v and want the component in the direction d.
|
||||
-}
|
||||
componentIn : Bezier.Point -> Bezier.Point -> Float
|
||||
componentIn d v =
|
||||
v.x * d.x + v.y * d.y
|
||||
|
||||
|
||||
zeroPoint : Bezier.Point
|
||||
zeroPoint =
|
||||
{ x = 0
|
||||
, y = 0
|
||||
}
|
||||
|
||||
|
||||
scaleTo : Float -> Bezier.Point -> Bezier.Point
|
||||
scaleTo q v =
|
||||
let
|
||||
largestComponent =
|
||||
max (abs v.x) (abs v.y)
|
||||
in
|
||||
if largestComponent == 0 then
|
||||
zeroPoint
|
||||
|
||||
else
|
||||
let
|
||||
scaledX =
|
||||
v.x / largestComponent
|
||||
|
||||
scaledY =
|
||||
v.y / largestComponent
|
||||
|
||||
scaledLength =
|
||||
sqrt (scaledX * scaledX + scaledY * scaledY)
|
||||
in
|
||||
{ x = q * scaledX / scaledLength
|
||||
, y = q * scaledY / scaledLength
|
||||
}
|
||||
|
||||
|
||||
{-| -}
|
||||
hash : Transition -> String
|
||||
hash transition =
|
||||
@ -788,20 +455,6 @@ keyframeListFromNonNormalizedBezier steps toString str =
|
||||
)
|
||||
|
||||
|
||||
{-| -}
|
||||
before : Float -> Transition -> Transition
|
||||
before t transition =
|
||||
transition
|
||||
|
||||
|
||||
{-| -}
|
||||
split : Float -> Transition -> { before : Transition, after : Transition }
|
||||
split t transition =
|
||||
{ before = transition
|
||||
, after = transition
|
||||
}
|
||||
|
||||
|
||||
takeAfter : Float -> Transition -> Transition
|
||||
takeAfter t transition =
|
||||
case transition of
|
||||
|
@ -2,11 +2,9 @@ module InternalAnim.Units exposing
|
||||
( Pixels
|
||||
, PixelsPerSecond
|
||||
, inPixels
|
||||
, inPixelsPerMs
|
||||
, inPixelsPerSecond
|
||||
, pixels
|
||||
, pixelsPerSecond
|
||||
, zero
|
||||
)
|
||||
|
||||
{-| -}
|
||||
@ -22,30 +20,6 @@ type InPixels
|
||||
= InPixels
|
||||
|
||||
|
||||
zero =
|
||||
Quantity.Quantity 0
|
||||
|
||||
|
||||
type Unit guard
|
||||
= Unit Float
|
||||
|
||||
|
||||
type alias Position =
|
||||
Unit Pos
|
||||
|
||||
|
||||
type Pos
|
||||
= Pos
|
||||
|
||||
|
||||
type alias Velocity =
|
||||
Unit Vel
|
||||
|
||||
|
||||
type Vel
|
||||
= Vel
|
||||
|
||||
|
||||
type alias Pixels =
|
||||
Quantity.Quantity Float InPixels
|
||||
|
||||
@ -59,11 +33,6 @@ inPixelsPerSecond (Quantity.Quantity pps) =
|
||||
pps
|
||||
|
||||
|
||||
inPixelsPerMs : PixelsPerSecond -> Float
|
||||
inPixelsPerMs (Quantity.Quantity pps) =
|
||||
1000 * pps
|
||||
|
||||
|
||||
inPixels : Pixels -> Float
|
||||
inPixels (Quantity.Quantity pixs) =
|
||||
pixs
|
||||
|
Loading…
Reference in New Issue
Block a user