0

我在 HTML 文档中嵌入了 SVG。(SVG)圆使用<animate>. 我试图找到一种方法,仅当它水平移动时才将某种事件侦听器放在那个圆圈上。

移动(水平)后,我想找到圆形的 x 坐标,并将第三个(外部)矩形宽度设置为圆形的相对位置。这第三个矩形就像一个进度条,跟踪圆圈的水平进度。

SVG圆圈(顺便说一下,圆圈在SVG g组内)是否被触发某种事件移动我可以设置一个侦听器,以便我可以更改进度条的宽度属性?

我曾认为,如果<animate>移动/更改的元素或元素触发某种事件,我可以尝试捕捉它,然后更改栏的宽度。

我发现在矩形上使用“独立”动画效果并不好,因为当圆圈向上移动时,增长的速度非常不同。我没有使用 canvas 元素,因为我试图保持可伸缩性和形状语义。(我更喜欢 javascript 解决方案,但我会感谢其他方法。)

回答后编辑:分析器非常适合 piint 并且(我认为)很有帮助。我对 SVG 很陌生,我可能误解了一些东西。出于这个原因,我包括代码。

我已尝试实施您的建议,但似乎没有成功。应用于圆圈的 .cx.animVal.value 似乎没有得到我需要的东西。我将包含我的代码的截断版本,它应该沿着本身水平移动的路径移动球;两个矩形(inBar 和 outBar)应该跟踪水平位移或多或少地以与球相同的速率增长。为了确保 setInterval 工作并正确收集位置,添加了一行来列出 oBall..animVal 和 oball..baseVal。在 FF 21.0 中,animVal 沿位移没有变化。我是否正确理解了您的建议?这里遵循代码(包括标题等,因为我特别是 SVG 中的菜鸟):

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" dir="ltr">
    <head><title>Motion</title>
    <script>function beginAnim(anim,sPos){anim.beginElement();}</script>
    </head>
    <body>
    <div id="here">
    <button onclick="beginAnim(document.getElementById('anim'),'out');">START</button>
    </div>
    <div style="height:350px;">
    <svg width="100%" height="100%" version="1.1" xmlns="http://www.w3.org/2000/svg">
    <script type="text/ecmascript">
    <![CDATA[
      function trckngBars(){
        oDiv=document.getElementById('here');
        var oBall=document.getElementById('ball');
        var oBar=[document.getElementById('inBar'),document.getElementById('outBar')];
        idTimer=self.setInterval(function(){updtBars(oBall,oBar);},100);
      }
      function updtBars(oBall,oBar){
        var xCoor=String(oBall.cx.animVal.value);
        oDiv.innerHTML+='==>'+oBall.cx.animVal.value+'..'+oBall.cx.baseVal.value;
        oBar[0].setAttribute("width",xCoor);
        oBar[1].setAttribute("width",xCoor);
      }
    // ]]>
    </script>
    <defs>
    <path id="throw" d="M0,0 q 80,-55 200,20" style="fill: none; stroke: blue;" />
    </defs>
    <g>
      <g>
        <rect x="2" y="50" width="400" height="110" style="fill: yellow; stroke: black;"></rect>
      </g>
      <g>
        <!-- show the path along which the circle will move -->
        <use id="throw_path" visibility="hidden" xlink:href="#throw" x="50" y="130" />
        <circle id="ball" cx="50" cy="130" r="10" style="fill: red; stroke: black;">
          <animateMotion id="ball_anim" begin="anim.begin+1s" dur="6s" fill="freeze" onbegin="trckngBars();" onend="window.clearInterval(idTimer);">
            <mpath xlink:href="#throw" />
          </animateMotion>
        </circle>
        <rect id="inBar" x="50" y="205" width="20" height="30" style="fill: purple;stroke-linecap: butt;">
    <!-- <animate attributeType="XML" attributeName="width" from="0" to="200" begin="ball_anim.begin" dur="6s" fill="freeze" /> -->
</rect>
      </g>
      <animateTransform id="anim" attributeType="XML" attributeName="transform" type="translate" from="0" to="200" begin="indefinite" dur="10s" fill="freeze" />
    </g>
    <rect id="outBar" x="50" y="235" width="10" height="30" style="fill: orange;stroke-linecap: butt;">
    <!-- <animate attributeType="XML" attributeName="width" from="0" to="400" begin="anim.begin+1s" dur="10s" fill="freeze" /> -->
</rect>
    </svg> 
    </div>
    </body>
    </html>

如果代码运行,似乎移动#ball 的 animVal 保持在相同的 x 坐标 (50) 上,而显然它正在移动。

4

3 回答 3

1

当动画开始、结束或重复时会触发一个事件,但在动画值发生变化时不会(如您所愿)。

由于动画是确定性的,尽管您可以在圆形动画开始后几秒钟内开始矩形形状动画。

var cx = myCircle.cx.animVal.value;

如果您需要,它将为您提供动画值,前提是您正在制作动画的属性。

您正在使用 animateMotion 而不是自己为 cx 和 cy 属性设置动画。我认为获得转换后的圆形位置的唯一方法是调用 getBBox。

于 2013-06-20T15:16:48.033 回答
0

不久前,我遇到了您描述的相同问题。我希望能够根据用户触发的事件中途停止动画并将元素保持在其到达的位置。由于 SMIL 无法做到这一点,我决定为svg.js打造我自己的动画系统,这是我一直在研究的一个小型 javascript 库:

http://documentup.com/wout/svg.js#animating-elements

它可能对您想要实现的目标有用。

于 2013-06-27T07:57:07.377 回答
0

@Robert 非常感谢您的帮助。您的回答是对 SVG 和 SMIL 的一次很好的投入(让我补充一下)。我无法使用getBBox,但检查路径([链接] http://www.w3.org/TR/SVG11/paths.html)和animateMotion(同一站点)的规范,似乎可以实现正如您的答案中所建议的那样,SMIL 动画是确定性的。

动画只有很少的事件触发器,并且在设计上似乎与动画目标的基本状态一样关注当前位置(它们似乎被称为“基本值”和“表示值”)。(以下所有工作都在 FF 21 运行的 javascript 中运行。)我们可以在 animateMotion 对象上应用 getCurrentTime 来轮询动画的当前时间。我假设动画以恒定速度进行,因此,我们确定对象沿路径移动了多少并获得遍历的长度(因为我们可以使用 getTotalLength 方法获得整个路径的总长度)。

然后知道长度,我们可以确定路径上的当前位置(使用方法 getPointAtLength)。请注意,返回的值(时间和位置)都相对于容器对象,因此它们是可扩展的和/或需要转换)。

对于(简单)工作示例,问题示例代码中的 javascript 代码可以替换为以下内容。它似乎适用于我所做的极少数测试:

  function trckngBars(){
    /* Upon beginning an animation (onbegin event), the required objects are gathered
    and an interval is set */
    var oBall=[document.getElementById('throw'),document.getElementById('ball_anim')];
    var oBar=document.getElementById('inBar');
    /* idTimer is set as a global variable so that it can be accessed from anywhere
    to clear the interval*/
    idTimer=self.setInterval(function(){updtBars(oBall,oBar);},50);
  }
  function updtBars(oBall,oBar){
    /* This function, whose purpose is only to illustrate path method getPointLength 
    and animateMotion method getCurentTime, is quick and dirty. Note that oBall[0] is
    the path and oBall[1] is the animate(Motion) */
    //Calculates the amount of time passed as a ratio to the total time of the animation
    var t_ratio=((oBall[1].getCurrentTime()-oBall[1].getStartTime())/oBall[1].getSimpleDuration());
    // As mentioned, it assumes that animateMotion performs uniform motion along path
    var l=oBall[0].getTotalLenth()*t_ratio;
    // Gets (relative referred as user in documentation) horizontal coordinate
    var xCoor=oBall[0].getPointAtLength(l).x;
    oBar.setAttribute("width",xCoor);
  }
  function endTAnim(){
    /* This function can be triggered _onend_ of an animation to clear the interval
    and leave bars with the exact last dimensions */
    window.clearInterval(idTimer);
    var oBar=[document.getElementById('inBar'),document.getElementById('outBar')];
    oBar[0].setAttribute("width",200); //hardcoded for convenience
  }

因此,我能够找到的最简单的方法需要动画对象(获取时间)和路径对象(“​​预测”位置),并且它不涉及动画移动的实际元素。(在使用组合动画时避免讨论不同的坐标系,从最初的问题有所简化——这可能会更好地讨论一个独立的方式。)

虽然我没有注意到任何延迟(因为实际的 SVG 并不复杂),但我有兴趣了解计算成本更低的方法,因为我正在考虑使用这种方法来查找和绘制两个 SMIL 动画对象之间的距离段。

当然,所有这一切都依赖于沿路径均匀运动的假设,如果不是这样,并且在更大的图像中,人们可能会注意到并偏移我也会感谢任何关于它的指针(最好直接在 javascript 中制作动画/编程语言,因此您可以完全控制)。感谢您为避免陷入泥潭所做的所有编辑 - 三天前我对 SVG 的唯一了解就是它是 XML。

于 2013-06-23T14:04:31.080 回答