Marco Foxx
Marco Foxx

Reputation: 91

Move object every few seconds using svg

Draw(one time) and move objects every five seconds as shown in figures left to right. I searched but not able to find a way to draw outer lines and move objects near to it.

<animate xlink:href="#blue-rectangle"
         attributeName="x" 
         from="50"
         to="425" 
         dur="5s"
         begin="circ-anim.repeat(2)"
         fill="freeze" 
         id="rect-anim" />

ref : https://css-tricks.com/guide-svg-animations-smil/

https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Basic_Shapes

https://developer.mozilla.org/en-US/docs/Web/SVG/Element/animateMotion

enter image description here enter image description hereenter image description here

Upvotes: 1

Views: 1181

Answers (1)

enxaneta
enxaneta

Reputation: 33044

Using animateMotion would be a solution for a continuous motion on the path. If you need to stop the movement at intervals I would use javascript. In this book: Using SVG with CSS3 and HTML5: Vector Graphics for Web Design you have a thorough description of how to use javascript to emulate animateMotion

In order to stop the rect I'n using the timestamp for the requestAnimationFrame's callback. In the next example I'm stopping the rect every 2 seconds for 1 second.

Since the timestamp is running continuously I need a way to record the moment when it stops so that I can resume the animation from here. For this I'm setting lastTime as the last time when the rect has stopped.

Please read the comments in my code.

let rid;//the request animation frame id
let track = document.getElementById("track"),
  trackLength = track.getTotalLength(),//the total length of the track
  dur = 15000; //duration of one loop of track, in ms
 
let lastTime = 0;//last time when the rect has stopped
let flag = false; 

let interval = 5000;


function update(time) {
  rid = requestAnimationFrame(update);
    // to stop the rect every 5 seconds
    var deltaT = time%interval;
    //during 1 second
    if (deltaT < interval/2){
    flag = false;
  var t = ((deltaT + lastTime) % dur) / dur, // position in repeat cycle
    distance, // distance along the path for this rect
    point, // SVGPoint for that distance
    point2; // SVGPoint for a slightly different distance

  distance = trackLength * (t % 1);
  point = track.getPointAtLength(distance);
  point2 = track.getPointAtLength((distance + 2) % trackLength);
  angle = Math.atan2(point.y - point2.y, point.x - point2.x);

  rect.setAttribute(
    "transform",
    "translate(" +
      [point.x, point.y] +
      ")" +
      "rotate(" +
      angle * 180 / Math.PI +
      ")"
  );

 }else{if(flag==false){lastTime += interval/2; flag = true;}}
  
}
rid = requestAnimationFrame(update);
svg{border:1px solid;}
path{fill:none; stroke:black;}
<svg viewBox = "0 0 150 200" width="200">
  <path id="track" d="M70,30 Q70,20 80,20L120,20 Q130,20 130,30L130,170.000 Q130,180 120,180L30,180 Q20,180 20,170L20,130 Q20,120 30,120L60,120 Q70,120 70,110Z" />
 <polygon id="rect" points="0,0 -10,0 -10,-10 0,-10 0,0" style="fill: #ff0000;"/> 
</svg>

UPDATE

And this is how I would do it using animateMotion

setInterval(()=>{ svg.pauseAnimations(); 
                  setTimeout(()=>{svg.unpauseAnimations()},1000)
                },2000);
svg{border:1px solid;}
path{fill:none; stroke:black;}
<svg id="svg" viewBox = "0 0 150 200" width="300">
  <path id="track" d="M70,30 Q70,20 80,20L120,20 Q130,20 130,30L130,170.000 Q130,180 120,180L30,180 Q20,180 20,170L20,130 Q20,120 30,120L60,120 Q70,120 70,110Z" />
  <polygon id="rect" points="0,0 10,0 10,10 0,10 0,0" style="fill: #ff0000;">
  <animateMotion id="test" begin= "0s" dur="15s" repeatCount="infinite" rotate="auto" fill="freeze">
    <mpath xlink:href= "#track" />
    </animateMotion></polygon>
</svg>

UPDATE 2

Here is how you move 5 blocks on the path: The only difference is the begin attribute for the animateMotion.

all the

setInterval(()=>{ svg.pauseAnimations(); 
                  setTimeout(()=>{svg.unpauseAnimations()},1500)
                },3000);
svg{border:1px solid;}
path{fill:none; stroke:black;}
<svg id="svg" viewBox = "30 0 360 450" width="300">
<defs>
<polygon id="theRect" points="0,0 20,0 20,20 0,20 0,0" style="fill: #ff0000;" />
</defs>

  <path id="track" d="M288.938,33 Q289,12 310,12L350,12 Q371,12 371,33L371,408 Q371,429 350,429L66,429 Q45,429 45,408L45,374 Q45,353 66,353L267,353 Q288,353 288.062,332Z" />
  
  
  <use xlink:href="#theRect">
  <animateMotion id="test" begin= "0s" dur="15s" repeatCount="infinite" rotate="auto" fill="freeze" >
    <mpath xlink:href= "#track"  />
    </animateMotion></use>
  
  <use xlink:href="#theRect">
  <animateMotion id="test" begin= "-.5s" dur="15s" repeatCount="infinite" rotate="auto" fill="freeze" >
    <mpath xlink:href= "#track"  />
    </animateMotion></use>
  
  <use xlink:href="#theRect">
  <animateMotion id="test" begin= "-1s" dur="15s" repeatCount="infinite" rotate="auto" fill="freeze" >
    <mpath xlink:href= "#track" />
    </animateMotion></use>
  
  
   <use xlink:href="#theRect">
  <animateMotion id="test" begin= "-1.5s" dur="15s" repeatCount="infinite" rotate="auto" fill="freeze" >
    <mpath xlink:href= "#track"  />
    </animateMotion></use>
  
  <use xlink:href="#theRect">
  <animateMotion id="test" begin= "-2s" dur="15s" repeatCount="infinite" rotate="auto" fill="freeze" >
    <mpath xlink:href= "#track"  />
    </animateMotion></use>
</svg>

Upvotes: 3

Related Questions