使用 SMIL 制作 SVG 动画

发布于 2024-12-01 07:02:05 字数 4113 浏览 3 评论 0原文

我正在尝试使用 SVG 为视频元素创建 UI。我正在寻找一种简单的解决方案来对控制栏进行动画处理,当鼠标位于其中时,我希望控制栏从窗口底部升起(如 YouTube)。

这是我想做的:

<svg xmlns="http://www.w3.org/2000/svg" height="100%" width="100%" viewBox="0 0 640 360" preserveAspectRatio="none" version="1.1">
  <g id="control_bar" transform="translate(0,360)">
    <animateTransform attributeName="transform" attributeType="XML" type="translate" begin="window.mouseover" from="0,360" to="0,328" dur="350ms" fill="freeze"/>
    <animateTransform attributeName="transform" attributeType="XML" type="translate" begin="window.mouseout" from="0,328" to="0,360" dur="350ms" fill="freeze"/>
    <rect x="0" y="0" width="640" height="32" fill="grey"/>
  </g>
</svg>

不幸的是,window.mouseover 不执行任何操作。相反,我创建了一个透明矩形来覆盖整个窗口,并给它一个 id="screen" 并使用 begin="screen.mouseover" 等。果然,当鼠标位于窗口中时,控制栏会按照我想要的方式进行动画处理不幸的是,屏幕阻止其下面的所有元素获取自己的鼠标事件。

我正在寻找最简单的方法来完成此任务,最好仅使用标记(SMIL),因为我想避免大量的 JavaScript 或库。

谢谢!

>>>编辑<<<为了澄清我所追求的是什么:

我想为 HTML5

我当前的解决方案:

我将

<video width="640" src="myvideo.webm"/>

然后我使用以下 JavaScipt(带有 jquery):

$(function(){
  $("video").each(function(){
    var old_video = $(this);
    var width = old_video.attr("width")
    var height = Math.floor(width / (16 / 9))
    var video = $("<object/>")
    video.addClass("video")
    video.css({
      width: width,
      height: height,
    })

    var src = old_video.attr("src")     
    video.attr("data", "video.xhtml#" + src)        
    old_video.replaceWith(video)
  })
})

这将视频元素替换为 。 who 的数据 uri 设置为: video.xhtml#myvideo.webm

那么 video.xhtml 的内容如下:

<?xml version="1.0" encoding="utf-8"?>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
  <script src="jquery.js"/>
  <script>
    $(function(){
      $(window).hover(function(){
        $("#in")[0].beginElement()
      }, function(){
        $("#out")[0].beginElement()
      })
      var video = document.createElement("video")
      video.setAttribute("src", location.hash.substr(1))
      $("div#video").replaceWith(video)
    })
  </script>
  <style>
    svg {
      position: absolute;
      top: 0;   left: 0;
    }
    video {
      position: absolute;
      top: 0;   left: 0;
      width: 100%;
      height: 100%;
      background: black;
    }
  </style>
</head>
<body>
  <div id="video"/>
  <svg xmlns="http://www.w3.org/2000/svg" height="100%" width="100%" viewBox="0 0 640 360" preserveAspectRatio="none" version="1.1">
    <g id="bar" transform="translate(0,360)">
      <animateTransform id="in" attributeName="transform" attributeType="XML" type="translate" begin="indefinite" from="0,360" to="0,328" dur="50ms" fill="freeze"/>
      <animateTransform id="out" attributeName="transform" attributeType="XML" type="translate" begin="indefinite" from="0,328" to="0,360" dur="350ms" fill="freeze"/>
      <rect x="0" y="0" width="640" height="32" fill="grey"/>
      <rect onclick="$('video')[0].play()" x="0" y="0" width="64" height="32" fill="blue">
        <set id="btn" attributeName="fill" to="red" begin="mousedown" end="mouseup;mouseout" dur="1s" fill="remove" />
      </rect>
    </g>
  </svg>
</body>
</html>

该文档从哈希中获取视频 uri,并在 SVG UI 后面注入视频元素。由于它是 XHTML 文档(而不是 SVG),我现在可以使用 jquery 来处理鼠标事件,这并不理想,但似乎可以工作。唯一的问题是我收到 JavaScript 错误:a.compareDocumentPosition 不是函数 源文件:jquery.js 行:Firefox 中的第 17 行。

这种方法有意义吗?有更好的办法吗?我还更喜欢仅使用 SMIL 而不是 JavaScript/jQuery 的动画解决方案。

谢谢!

I'm trying to greate a UI for a video element using SVG. I'm looking for a simple solution to animating the control bar, which I want to rise up from the bottom of the window when the mouse is inside of it (like YouTube).

Here is what I would like to do:

<svg xmlns="http://www.w3.org/2000/svg" height="100%" width="100%" viewBox="0 0 640 360" preserveAspectRatio="none" version="1.1">
  <g id="control_bar" transform="translate(0,360)">
    <animateTransform attributeName="transform" attributeType="XML" type="translate" begin="window.mouseover" from="0,360" to="0,328" dur="350ms" fill="freeze"/>
    <animateTransform attributeName="transform" attributeType="XML" type="translate" begin="window.mouseout" from="0,328" to="0,360" dur="350ms" fill="freeze"/>
    <rect x="0" y="0" width="640" height="32" fill="grey"/>
  </g>
</svg>

Unfortunately, window.mouseover doesn't do anything. Instead I created a transparent rectangle to cover the entire window, and gave it an id="screen" and used begin="screen.mouseover" etc. Sure enough the control bar animates like I want it to when the mouse is in the window, unfortunately though, screen prevents all the elements below it from getting their own mouse events.

I'm looking for the simplest possible way to accomplish this, preferable with just markup (SMIL) since I'd like to avoid a ton of JavaScript or libraries.

Thanks!

>>>EDIT<<< To clarify what it is I'm after:

I wanted to create a custom SVG UI for the HTML5 <video> element. My first approach was to dynamically insert SVG into the DOM using document.createElementNS, but that got messy really fast. Next I tried Raphael, but that only made it slightly less messy. I decided I wanted the UI to be a self contained document, so I decided to create a SVG document for the UI and then create a <object> element which would load it and be overlaid on top the <video> element. My problem with that was that I couldn't get the control bar to animate and then stay in position for as long was the mouse was within the window of the UI. Also, communicating with the UI from the parent document was becoming a pain.

My current solution:

I place a <video> element in my HTML document like so:

<video width="640" src="myvideo.webm"/>

then I use the following JavaScipt (with jquery):

$(function(){
  $("video").each(function(){
    var old_video = $(this);
    var width = old_video.attr("width")
    var height = Math.floor(width / (16 / 9))
    var video = $("<object/>")
    video.addClass("video")
    video.css({
      width: width,
      height: height,
    })

    var src = old_video.attr("src")     
    video.attr("data", "video.xhtml#" + src)        
    old_video.replaceWith(video)
  })
})

This replaces the video element with a <object> who's data uri is set to: video.xhtml#myvideo.webm

Then the contents of video.xhtml are so:

<?xml version="1.0" encoding="utf-8"?>
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
  <script src="jquery.js"/>
  <script>
    $(function(){
      $(window).hover(function(){
        $("#in")[0].beginElement()
      }, function(){
        $("#out")[0].beginElement()
      })
      var video = document.createElement("video")
      video.setAttribute("src", location.hash.substr(1))
      $("div#video").replaceWith(video)
    })
  </script>
  <style>
    svg {
      position: absolute;
      top: 0;   left: 0;
    }
    video {
      position: absolute;
      top: 0;   left: 0;
      width: 100%;
      height: 100%;
      background: black;
    }
  </style>
</head>
<body>
  <div id="video"/>
  <svg xmlns="http://www.w3.org/2000/svg" height="100%" width="100%" viewBox="0 0 640 360" preserveAspectRatio="none" version="1.1">
    <g id="bar" transform="translate(0,360)">
      <animateTransform id="in" attributeName="transform" attributeType="XML" type="translate" begin="indefinite" from="0,360" to="0,328" dur="50ms" fill="freeze"/>
      <animateTransform id="out" attributeName="transform" attributeType="XML" type="translate" begin="indefinite" from="0,328" to="0,360" dur="350ms" fill="freeze"/>
      <rect x="0" y="0" width="640" height="32" fill="grey"/>
      <rect onclick="$('video')[0].play()" x="0" y="0" width="64" height="32" fill="blue">
        <set id="btn" attributeName="fill" to="red" begin="mousedown" end="mouseup;mouseout" dur="1s" fill="remove" />
      </rect>
    </g>
  </svg>
</body>
</html>

This document fetches the video uri from the hash and injects a video element behind the SVG UI. Since it's a XHTML document (and not SVG) I am now able to use jquery to handle the mouse events, which isn't ideal but it seems to work. Only problem with it is that I get a JavaScript error: a.compareDocumentPosition is not a function
Source File: jquery.js Line: 17
in Firefox.

Does this approach make any sense? Is there a better way? I'd also prefer a solution to the animation using SMIL only and not JavaScript/jQuery.

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

何以心动 2024-12-08 07:02:05

开始属性中的“窗口”部分只是一个 id。 svg 的作用是在具有该 id 的元素上注册一个事件侦听器,它甚至不必位于 svg 内部,它可以是同一文档中的 HTML 元素。下面是一个示例:

<html xmlns="http://www.w3.org/1999/xhtml">
<body>
  <div id="window">hover here</div>
  <svg xmlns="http://www.w3.org/2000/svg" height="640" width="480" viewBox="0 0 640 360" preserveAspectRatio="none" version="1.1">
    <g id="control_bar" transform="translate(0,360)">
      <animateTransform attributeName="transform" attributeType="XML" type="translate" begin="window.mouseover" from="0,360" to="0,328" dur="350ms" fill="freeze"/>
      <animateTransform attributeName="transform" attributeType="XML" type="translate" begin="window.mouseout" from="0,328" to="0,360" dur="350ms" fill="freeze"/>
      <rect x="0" y="0" width="640" height="32" fill="grey"/>
    </g>
  </svg>
</body>
</html>

似乎在 Chrome、Firefox 和 Opera 中工作得很好。

The "window" part in your begin attributes is just an id. What svg does is to register an event listener on the element that has that id, and it doesn't even have to be inside the svg, it can be an HTML element in the same document. Here's an example:

<html xmlns="http://www.w3.org/1999/xhtml">
<body>
  <div id="window">hover here</div>
  <svg xmlns="http://www.w3.org/2000/svg" height="640" width="480" viewBox="0 0 640 360" preserveAspectRatio="none" version="1.1">
    <g id="control_bar" transform="translate(0,360)">
      <animateTransform attributeName="transform" attributeType="XML" type="translate" begin="window.mouseover" from="0,360" to="0,328" dur="350ms" fill="freeze"/>
      <animateTransform attributeName="transform" attributeType="XML" type="translate" begin="window.mouseout" from="0,328" to="0,360" dur="350ms" fill="freeze"/>
      <rect x="0" y="0" width="640" height="32" fill="grey"/>
    </g>
  </svg>
</body>
</html>

Seems to work just fine in Chrome, Firefox and Opera.

枯寂 2024-12-08 07:02:05

您是否尝试过为 元素本身赋予 id 属性?例如

<svg xmlns="http://www.w3.org/2000/svg" id="screen" height="100%" width="100%" viewBox="0 0 640 360" preserveAspectRatio="none" version="1.1" >
  <g id="control_bar" transform="translate(0,360)">
    <animateTransform attributeName="transform" attributeType="XML" type="translate" begin="screen.mouseover" from="0,360" to="0,328" dur="350ms" fill="freeze"/>
    <animateTransform attributeName="transform" attributeType="XML" type="translate" begin="screen.mouseout" from="0,328" to="0,360" dur="350ms" fill="freeze"/>
    <rect x="0" y="0" width="640" height="32" fill="grey"/>
  </g>
</svg>

Have you tried giving the <svg> element itself an id attribute? e.g.

<svg xmlns="http://www.w3.org/2000/svg" id="screen" height="100%" width="100%" viewBox="0 0 640 360" preserveAspectRatio="none" version="1.1" >
  <g id="control_bar" transform="translate(0,360)">
    <animateTransform attributeName="transform" attributeType="XML" type="translate" begin="screen.mouseover" from="0,360" to="0,328" dur="350ms" fill="freeze"/>
    <animateTransform attributeName="transform" attributeType="XML" type="translate" begin="screen.mouseout" from="0,328" to="0,360" dur="350ms" fill="freeze"/>
    <rect x="0" y="0" width="640" height="32" fill="grey"/>
  </g>
</svg>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文