如何让 Elm 动画师使用 CSS 动画对 SVG 元素进行动画处理?
How do I get Elm animator to animate SVG elements using CSS animations?
我正在尝试在 Elm 中制作 CSS 动画,但我无法让它工作!
Elm 有几个 动画包。我尝试使用的是 mdgriffith/elm-animator
。遗憾的是,与许多 Elm 软件包一样,它的文档很少。它似乎提供了两种渲染方式:一种是通过 运行 使 Elm 事件循环对每一帧进行 DOM 更新,另一种是使用 CSS 动画 [我什至没有意识到存在]。我正在尝试做后者。
我试图将代码缩小到一个最小的例子:
module Main exposing (main)
import Time
import Platform.Cmd
import Browser
import Html
import Html.Attributes
import Html.Events
import Color
import Svg
import Svg.Attributes
import Animator
import Animator.Css
main =
Browser.document
{
init = \ () -> ({fill = Animator.init <| Color.rgb 1 0 0}, Platform.Cmd.none),
subscriptions = \ state -> Animator.toSubscription Tick state animator,
view = \ state -> {title = "Animation test", body = view state},
update = \ msg state -> (update msg state, Platform.Cmd.none)
}
type alias State = { fill : Animator.Timeline Color.Color }
animator : Animator.Animator State
animator =
Animator.animator
|> Animator.Css.watching (\ state -> state.fill) (\ c state -> { state | fill = c })
type Msg = Tick Time.Posix | DoSomething
update : Msg -> State -> State
update msg state0 =
case msg of
Tick t -> Animator.update t animator state0
DoSomething -> { state0 | fill = Animator.go Animator.slowly (Color.rgb 1 1 0) state0.fill }
view : State -> List (Html.Html Msg)
view state0 =
[
Html.button [Html.Events.onClick DoSomething] [Html.text "Do something"],
Svg.svg
[
Svg.Attributes.width "100px",
Svg.Attributes.height "100px"
]
[
Animator.Css.node "circle"
state0.fill
[
Animator.Css.color
"fill"
(\ x -> x)
]
[
Svg.Attributes.cx "50",
Svg.Attributes.cy "50",
Svg.Attributes.r "50"
]
[]
]
]
我很欣赏它仍然很大,但我不知道如何轻松地让它更短而不混淆它在做什么。
当我 运行 这样做时,SVG 无法呈现。当我点击按钮时,没有任何反应。
这是非常奇怪 的部分:如果我打开 Firefox Inspector window,我可以看到 SVG <circle>
元素。如果我编辑它的各种属性,什么也不会发生。但是,如果我右键单击 <circle>
和 select“编辑为 HTML...”,然后将单个 space 添加到元素文本并单击它, 圆圈突然出现!此外,如果我再次右键单击该元素,现在它显示为“Edit as SVG...”,这很可疑。
更有趣:如果我加载页面,单击按钮,然后然后执行上述技巧,彩色动画运行s !
请注意,如果我编辑 HTML 并且不做任何更改,它将不起作用。我必须对文本进行细微的更改(否则我猜浏览器决定不需要重新处理?)
我 所以 确信这最终会成为一个奇怪的 Firefox 错误......但后来我在 Chrome 和 Edge 中尝试了它,它确实如此完全一样!
有没有人知道为什么这不起作用?我对 Elm 代码做错了什么吗? (我真的非常努力地弄清楚这个库是如何工作的;我基本上只是在猜测这些类型是如何组合在一起的。所以也许我做了一些愚蠢的事情。)
这是因为 namespaces 发生了一件奇怪的事情。在 HTML 文档中(即在任何网页上),默认命名空间是 HTML 命名空间,如果您想呈现其他格式的嵌入文档,您需要确保在正确的命名空间中创建节点.
现在,当您将 HTML 写成字符串并且浏览器从文本中解析它时,它会自动为您执行此操作:
<div> <!-- HTML Namespace -->
<svg>
<circle /> <!-- SVG Namespace -->
</svg>
<math>
<mrow></mrow> <!-- MathML namespace
(not really relevant, just pointing out different NS) -->
</math>
</div>
但是,当您动态构建节点时(即从 JS 或 Elm),您需要明确请求命名空间。那就是在 JS 中你会使用 Document.createElementNS()
而不是 Document.createElement()
。如果你 look at the source of the elm/svg package 你会看到它这样做:
node : String -> List (Attribute msg) -> List (Svg msg) -> Svg msg
node =
VirtualDom.nodeNS "http://www.w3.org/2000/svg"
如果您不这样做,浏览器就会理解您想要创建一个名为 circle
的新 HTML 元素,而浏览器不会这样做'不知道。如果浏览器不知道某个元素,它基本上就像 <div>
.
一样对待
现在,如果您查看 the source of the elm-animator package,您会注意到它要求 Html.node
,因此没有命名空间!
至于如何让它与 elm-animator 一起工作,我想你做不到。但也许其他人可以提供一些解决方案...
最后,您可能需要考虑 SMIL 风格的动画,它往往不需要任何外部包就可以完成工作。
我正在尝试在 Elm 中制作 CSS 动画,但我无法让它工作!
Elm 有几个 动画包。我尝试使用的是 mdgriffith/elm-animator
。遗憾的是,与许多 Elm 软件包一样,它的文档很少。它似乎提供了两种渲染方式:一种是通过 运行 使 Elm 事件循环对每一帧进行 DOM 更新,另一种是使用 CSS 动画 [我什至没有意识到存在]。我正在尝试做后者。
我试图将代码缩小到一个最小的例子:
module Main exposing (main)
import Time
import Platform.Cmd
import Browser
import Html
import Html.Attributes
import Html.Events
import Color
import Svg
import Svg.Attributes
import Animator
import Animator.Css
main =
Browser.document
{
init = \ () -> ({fill = Animator.init <| Color.rgb 1 0 0}, Platform.Cmd.none),
subscriptions = \ state -> Animator.toSubscription Tick state animator,
view = \ state -> {title = "Animation test", body = view state},
update = \ msg state -> (update msg state, Platform.Cmd.none)
}
type alias State = { fill : Animator.Timeline Color.Color }
animator : Animator.Animator State
animator =
Animator.animator
|> Animator.Css.watching (\ state -> state.fill) (\ c state -> { state | fill = c })
type Msg = Tick Time.Posix | DoSomething
update : Msg -> State -> State
update msg state0 =
case msg of
Tick t -> Animator.update t animator state0
DoSomething -> { state0 | fill = Animator.go Animator.slowly (Color.rgb 1 1 0) state0.fill }
view : State -> List (Html.Html Msg)
view state0 =
[
Html.button [Html.Events.onClick DoSomething] [Html.text "Do something"],
Svg.svg
[
Svg.Attributes.width "100px",
Svg.Attributes.height "100px"
]
[
Animator.Css.node "circle"
state0.fill
[
Animator.Css.color
"fill"
(\ x -> x)
]
[
Svg.Attributes.cx "50",
Svg.Attributes.cy "50",
Svg.Attributes.r "50"
]
[]
]
]
我很欣赏它仍然很大,但我不知道如何轻松地让它更短而不混淆它在做什么。
当我 运行 这样做时,SVG 无法呈现。当我点击按钮时,没有任何反应。
这是非常奇怪 的部分:如果我打开 Firefox Inspector window,我可以看到 SVG <circle>
元素。如果我编辑它的各种属性,什么也不会发生。但是,如果我右键单击 <circle>
和 select“编辑为 HTML...”,然后将单个 space 添加到元素文本并单击它, 圆圈突然出现!此外,如果我再次右键单击该元素,现在它显示为“Edit as SVG...”,这很可疑。
更有趣:如果我加载页面,单击按钮,然后然后执行上述技巧,彩色动画运行s !
请注意,如果我编辑 HTML 并且不做任何更改,它将不起作用。我必须对文本进行细微的更改(否则我猜浏览器决定不需要重新处理?)
我 所以 确信这最终会成为一个奇怪的 Firefox 错误......但后来我在 Chrome 和 Edge 中尝试了它,它确实如此完全一样!
有没有人知道为什么这不起作用?我对 Elm 代码做错了什么吗? (我真的非常努力地弄清楚这个库是如何工作的;我基本上只是在猜测这些类型是如何组合在一起的。所以也许我做了一些愚蠢的事情。)
这是因为 namespaces 发生了一件奇怪的事情。在 HTML 文档中(即在任何网页上),默认命名空间是 HTML 命名空间,如果您想呈现其他格式的嵌入文档,您需要确保在正确的命名空间中创建节点.
现在,当您将 HTML 写成字符串并且浏览器从文本中解析它时,它会自动为您执行此操作:
<div> <!-- HTML Namespace -->
<svg>
<circle /> <!-- SVG Namespace -->
</svg>
<math>
<mrow></mrow> <!-- MathML namespace
(not really relevant, just pointing out different NS) -->
</math>
</div>
但是,当您动态构建节点时(即从 JS 或 Elm),您需要明确请求命名空间。那就是在 JS 中你会使用 Document.createElementNS()
而不是 Document.createElement()
。如果你 look at the source of the elm/svg package 你会看到它这样做:
node : String -> List (Attribute msg) -> List (Svg msg) -> Svg msg
node =
VirtualDom.nodeNS "http://www.w3.org/2000/svg"
如果您不这样做,浏览器就会理解您想要创建一个名为 circle
的新 HTML 元素,而浏览器不会这样做'不知道。如果浏览器不知道某个元素,它基本上就像 <div>
.
现在,如果您查看 the source of the elm-animator package,您会注意到它要求 Html.node
,因此没有命名空间!
至于如何让它与 elm-animator 一起工作,我想你做不到。但也许其他人可以提供一些解决方案...
最后,您可能需要考虑 SMIL 风格的动画,它往往不需要任何外部包就可以完成工作。