implement opacity animation

This commit is contained in:
caleb 2025-07-21 11:10:13 +09:00
parent e4f72b5c9e
commit d50eb26b14
4 changed files with 94 additions and 3 deletions

View File

@ -1,17 +1,23 @@
namespace web_api_cookbook namespace web_api_cookbook
open WebSharper open WebSharper
open WebSharper.JavaScript
open WebSharper.UI open WebSharper.UI
open WebSharper.UI.Client open WebSharper.UI.Client
open WebSharper.UI.Html open WebSharper.UI.Html
open WebSharper.UI.Templating open Units.Animation
open Units.Time
[<JavaScript>] [<JavaScript>]
module Client = module Client =
[<SPAEntryPoint>] [<SPAEntryPoint>]
let Main () = let Main () =
let isClicked = Var.Create false
let opacityAnimated = Animate.valueWhen isClicked.View 1.0 0. 120.<frames/s> 1.<s>
let opacityStyle = View.MapCached (sprintf "opacity: %f") opacityAnimated
let onClick = on.click (fun _ _ -> Var.Set isClicked true)
div [] [ div [] [
p [] [ text "hello world!" ] UI.Components.button [attr.styleDyn opacityStyle; onClick] "Hide Me"
] ]
|> Doc.RunById "main" |> Doc.RunById "main"

31
Prelude.fs Normal file
View File

@ -0,0 +1,31 @@
namespace web_api_cookbook
open WebSharper
[<JavaScript>]
module Option =
let getOrElse def opt =
if Option.isSome opt
then Option.get opt
else def
[<JavaScript>]
module Units =
module Animation =
[<Measure>]
type frames
module Time =
[<Measure>]
type ms
[<Measure>]
type s
[<JavaScript>]
module Math =
let clamp a b c =
if c < a then a
else if c > b then b
else c
[<Inline>]
let inline lerp a b t = a + t * (b - a)

52
Ui.fs Normal file
View File

@ -0,0 +1,52 @@
namespace web_api_cookbook
open WebSharper
open WebSharper.JavaScript
open WebSharper.UI
open WebSharper.UI.Client
open WebSharper.UI.Html
[<JavaScript>]
module UI =
module Components =
let button attrs label =
button (attrs @ [attr.``type`` "button"]) [ text label ]
[<JavaScript>]
module Animate =
open Units.Animation
open Units.Time
let value (startPoint:float) endPoint (targetFps:float<frames/s>) (animationSeconds:float<s>) =
let frameInterval = 1. / targetFps * 1000.0<ms/s>
let frameCount = animationSeconds * targetFps
let diff = startPoint - endPoint
let increment = abs (diff / frameCount)
let lerp = Math.lerp startPoint endPoint
let interpolatedValue = Var.Create startPoint
let rec callback (lastRedrawAt:float<ms> option) frameNo (now:float) =
let now = now * 1.0<ms>
let lastRedrawAt = Option.getOrElse now lastRedrawAt
let elapsed = now - lastRedrawAt
let readyToRender = elapsed >= frameInterval * 1.<frames>
match readyToRender with
| false ->
JS.Window.RequestAnimationFrame (callback (Some lastRedrawAt) frameNo) |> ignore
| true ->
let t = float frameNo * increment * 1.<frames>
let nextVal = lerp t
Var.Set interpolatedValue nextVal
if nextVal <> endPoint
then
JS.Window.RequestAnimationFrame (callback (Some now) (frameNo + 1))
|> ignore
JS.Window.RequestAnimationFrame (callback None 0) |> ignore
interpolatedValue.View
let valueWhen beginAnimation startPoint endPoint targetFps animationSeconds =
function
| true -> value startPoint endPoint targetFps animationSeconds
| false -> View.Const startPoint
|> View.MapCached <| beginAnimation
|> View.Join

View File

@ -9,6 +9,8 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Prelude.fs" />
<Compile Include="Ui.fs" />
<Compile Include="Client.fs" /> <Compile Include="Client.fs" />
<Compile Include="Startup.fs" /> <Compile Include="Startup.fs" />
<None Include="package.json" /> <None Include="package.json" />