Catch changes on SVG element circle and change attributes elsewhere via js

前端 未结 3 1426
感情败类
感情败类 2021-01-26 17:12

I have an embedded SVG in an HTML document. An (SVG) circle is animated using . I was trying to find a way to put some kind of event listener on that

相关标签:
3条回答
  • A while ago I ran into the same problem you are describing. I wanted to be able to stop animations halfway, based on events triggered by the user and keep elements at their reached position. Unable to do so with SMIL I decided to forge my own animation system for svg.js, a small javascript library I have been working on:

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

    It might be useful for what you are trying to achieve.

    0 讨论(0)
  • 2021-01-26 17:37

    An event is fired when animations begin, end or repeat but not (as you want) whenever there is a change of animation value.

    As animations are deterministic though you can just start the rect shape animation so many seconds after the circle animation starts.

    var cx = myCircle.cx.animVal.value;
    

    will give you the animated value if you need it, provided that's the attribute you're animating.

    You're using animateMotion rather than animating the cx and cy attributes on their own though. I'm think the only way to get the circle position post that transform is to call getBBox.

    0 讨论(0)
  • 2021-01-26 17:39

    @Robert Thank you very much for your help. Your answer has been a good plunge into SVG and SMIL (and let me add cold). I have not been able to use getBBox, but inspecting the specification on paths ([link] http://www.w3.org/TR/SVG11/paths.html) and animateMotion (same site), it apears that can be achieved as SMIL animations are deterministic as suggested in your answer.

    An animation has very few event triggers and by design seem as much concerned with the base state of the animation target as it is with the current position (theseem to be referred as "base values" and "presentation values"). (All the following works in javascript run by FF 21.) We can poll the current time of the animation applying getCurrentTime on the animateMotion object. I am assuming that the animation does it at constant velocity, so with that, we determine how much the object has moved along the path and obtain the length traversed (as we can get the total length of the whole path with method getTotalLength).

    Then knowing the length, we can determine the current position on the path (using method getPointAtLength). Note, that the values returned, both time and position are relative to the container object, and thus they are scalable and/or require transformation).

    For a (simple) working example, the javascript code in the Question sample code can be replaced by the following. It appears to work with the very few tests I have made:

      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
      }
    

    Thus the simplest method I have been able to find requires the animation object (to obtain the time) and the path object (to "predict" the position) and it does not involve the actual element being moved by the animation. (It is somewhat simplifiedfrom the initial question to avoid discussing different coordinate systems when composed animations are used - this might be better discussed ia a stand-alone way.)

    Though I have not noticed any lag (as the actual SVG is not much more complicated), I would be interested in knowing computationally cheaper methods as I was considering using this approach to find and draw a distance segment between two SMIL animated objects.

    Of course all this relies on the assumption of a uniform movement aong the path, if that were not so and in larger images one might notice and offset I would also be grateful for any pointers on that (short of better do the animation directly in javascript/programming language and so you have total control). Thank you for all te edits you did avoiding getting into a quagmire - the only thing I knew about SVG three days ago is that it was XML.

    0 讨论(0)
提交回复
热议问题