Search code examples
javascripthtmlsvgsvg-animate

SVG animate(move) text from point A to B while its content is changing


I'd like to animate(move) the text element from point A to B while its content is changing

SVG :

   <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"  viewBox="300 160 350 150" height="80px" width="100%" xml:space="preserve">
     <text id="text_animated"  x="422" y="280" fill="white" font-size="17">
          <animate attributeName="y" from="150" to="250" begin="3s" dur="5.5s" repeatCount="1" fill="freeze"/> 
      </text>

<circle cx="422" cy="280" fill="red" r="5">
  <animate id="animation_depth_circle" attributeName="cy" from="150" to="250" begin="indefinite" dur="1.5s" repeatCount="1" fill="freeze" onend="endAnimate()" /> 
  </circle>
</svg>

JS:

             var counter=0;
             var test_t = setInterval(function(){
                document.getElementById('text_animated').textContent = ""+counter;

                    if(counter===120){
                        clearInterval(test_t);
                    }

                     counter=counter+1;

             },10);

My goal is to move the text (inside a circle) as the text is changing. The problem is that the text doesn't move. Only the circle does move.

btw. I can't use

document.getElementById('text_animated').setAttribuite('y',something);

because it is not synchronized with the SVG animation (if network bottleneck issues occur). I'm using Chrome.

EDIT :

I managed to move my text using dy as so :

 <text   x="422" y="280" fill="white" >
       <animate  attributeName="dy" from="0" to="250"  dur="1.5s" repeatCount="indefinite"/> 
  </text>

The problem is that It doesn't move if I change the text with my javascript. So It's either change or move.


Solution

  • When you do textContent = "" + counter; you remove the animation from inside the text element. However you can declare the animation outside the animated element (the text in this case) and give an explicit target element for the animation by using the xlink:href attribute to reference the target's id: xlink:href="#text_animated".

    Also you are animating the cy attribute. I prefer to use animateTransform and animate a translation instead

    var counter = 0;
    var test_t = setInterval(function() {
      document.getElementById("text_animated").textContent = "" + counter;
    
      if (counter === 120) {
        clearInterval(test_t);
      }
    
      counter = counter + 1;
    }, 10);
    svg{background:black}
    <svg viewBox="350 120 150 250" width="200">
         <text id="text_animated"  x="422" y="150" fill="white" font-size="17" transform="translate(0,0)">    
          </text>
       
       <animateTransform 
        	attributeType="XML" 
            attributeName="transform" 
            type="translate"
            values="0,0; 0,100" 
            begin="3s"
            dur="5.5s" 
            repeatCount="1" fill="freeze"
            xlink:href="#text_animated" />
    
    <circle cx="422" cy="280" fill="red" r="5">
      <animateTransform id="animation_depth_circle"
        	  attributeType="XML" 
            attributeName="transform" 
            type="translate"
            values="0,0; 0,100" 
            begin="3s"
            dur="1.5s" 
            repeatCount="1" fill="freeze"/> 
      
     </circle>
    </svg>

    Yet another solution would have been puting the text inside a tspan element <tspan id="text_animated"></tspan>

    var counter = 0;
    var test_t = setInterval(function() {
      document.getElementById("text_animated").textContent = "" + counter;
    
      if (counter === 120) {
        clearInterval(test_t);
      }
    
      counter = counter + 1;
    }, 10);
    svg{background:black}
    <svg viewBox="350 120 150 250" width="200">
         <text   x="422" y="150" fill="white" font-size="17" transform="translate(0,0)"> 
            <animateTransform 
        	  attributeType="XML" 
            attributeName="transform" 
            type="translate"
            values="0,0; 0,100" 
            begin="3s"
            dur="5.5s" 
            repeatCount="1" fill="freeze"
             />
           <tspan id="text_animated"></tspan>
          </text>
       
      
    
    <circle cx="422" cy="280" fill="red" r="5">
      <animateTransform id="animation_depth_circle"
        	  attributeType="XML" 
            attributeName="transform" 
            type="translate"
            values="0,0; 0,100" 
            begin="3s"
            dur="1.5s" 
            repeatCount="1" fill="freeze"/> 
      
     </circle>
    </svg>

    I've chanved the viewBox value because I wanted to see what I am doing. You can use what you want.