Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Projectile motion on a path in SVG

In this SVG below, a circle moves on the given path linearly at a constant speed. I want it to move according to the curve (like a projectile, since this curve is a parabola). I have read about keySplines, keyPoints and keyTimes but cannot apply them correctly to obtain a smooth projectile motion. Is there a way to achieve this?

<svg viewBox="0 0 500 500" width="300px">
  <path fill="none" stroke="black" d="M250,250 Q356.06601717798213,143.93398282201787 462.13203435596427,487.86796564403573"> 
  </path>
  <circle r="5" fill="red">
    <animateMotion dur="5s" path="M250,250 Q356.06601717798213,143.93398282201787 462.13203435596427,487.86796564403573" fill="freeze">
    </animateMotion>
  </circle>
</svg>
like image 442
FunnelScr Avatar asked Oct 31 '25 02:10

FunnelScr


2 Answers

You need to use keyPoints. I added an <mpath> element because they are easier to maintain.

<svg viewBox="0 0 500 500" width="300px">
  <path fill="none" stroke="black" id="motionPath" d="M250,250 Q356.06601717798213,143.93398282201787 462.13203435596427,487.86796564403573"/>
  <circle r="5" fill="red">
    <animateMotion dur="5s" keyPoints="0;0.22;0.3;1" keyTimes="0;0.45;0.55;1" calcMode="linear" fill="freeze">
      <mpath xlink:href="#motionPath"/>
    </animateMotion>
  </circle>
</svg>
like image 183
JMP Avatar answered Nov 01 '25 18:11

JMP


I want it to move according to the curve (like a projectile, since this curve is a parabola).

I changed the motion path to look like a parabola.
Using the attributes keyPoints="0;0.4;0.6;1" and keyTimes="0;0.3;0.7;1" made the movement of the projectile along the trajectory uneven:
The projectile moves quickly to the top of the parabola In the upper part, the projectile slows down and accelerates again on the descent

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="svg4" width="500" height="500" viewBox="0 250 500 500">

 <path id="trace" d="M47.9 460.6C120.2 238.4 380 226.7 450.7 456"  fill="none" stroke="#000" stroke-dasharray="5 5"/>
  
 <circle cx="0" cy="0" r="5" fill="red" >
  <animateMotion   begin="0s" dur="3s"  rotate="auto" 
    keyPoints="0;0.4;0.6;1"
    keyTimes="0;0.3;0.7;1"
    calcMode="linear"
    repeatCount="5">
      <mpath xlink:href="#trace"/>
    </animateMotion>  
</circle>
</svg>

The example below is a bit more realistic. A projectile is drawn that flies out of a cannon barrel. During the shot, the gun rolls back and returns. The animation starts after the click.

enter image description here

<svg id="svg1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="svg4" width="1000" height="1000" viewBox="0 150 500 500">
<defs>
  <linearGradient id="Lg1">
     <stop offset="0%" stop-color="white" /> 
       <stop offset="100%" stop-color="black" />
   </linearGradient > 
     <linearGradient id="Lg2" x1="0" y1="0" y2="1">
     <stop offset="10%" stop-color="#D8BB00" /> 
       <stop offset="100%" stop-color="#685A00" />
   </linearGradient > 
  <linearGradient id="Lg3" x1="0" x2="0" y1="0" y2="1">
     <stop offset="80%" stop-color="dodgerblue" stop-opacity="0.8"/> 
       <stop offset="95%" stop-color="green" />
         <stop offset="100%" stop-color="brown" />
   </linearGradient >  
</defs>  
  <rect width="100%" height="100%" fill="url(#Lg3)" />
<path id="trace" d="M47.9 460.6C120.2 238.4 380 226.7 450.7 456"  fill="none" stroke-width="0.8" stroke="#000" stroke-dasharray="5 5"/>
<g id="cannon">
  <path id="wheel" d="M59.2 475.4c0 10-7 18.1-15.7 18.1-8.6 0-15.6-8-15.6-18s7-18.2 15.6-18.2c8.7 0 15.7 8.1 15.7 18.1z" opacity="1" fill="none" fill-opacity="1" stroke="#414141" stroke-width="2"  stroke-miterlimit="4"  /> 
 
  <path id="barrel" fill="url(#Lg1)" d="M54.3 434.3 39 478.5h6.2l14.6-41.3z"   stroke="none" stroke-width="1"  />
    <g stroke-width="3" stroke="#000" opacity="0.8">
   <path d="M26 479.4h29.4" id="path848" />
  <path d="M40.6 462.3v33.9" id="path850"  />
  <path d="M30.3 491.4 51 467" id="path852"  />
  <path d="m30.4 467.1 20.9 24.5" id="path854"  /> 
    </g>
  <path id="wheel" d="M56.3 479.2c0 10-7 18-15.6 18s-15.6-8-15.6-18S32 461 40.7 461c8.7 0 15.6 8 15.6 18z"  opacity="1" fill="#8B8B8B" fill-opacity="0.5" stroke="#414141" stroke-width="2"  stroke-miterlimit="4"  />

  <path id="lafet" d="m40.6 479.4-16.6 16-18.7.2" fill="none" stroke="#2C2C2C" stroke-width="5" stroke-linecap="round" />
  </g>
 <g  id="projectile">
  <path  fill="url(#Lg2)" transform="translate(0 -4)" d="M.8 1 .7 5.9l9.2.3s3.7-.4 3.7-2.4c.1-1.9-3.3-2.6-3.3-2.6z"  stroke="#A08B00" stroke-width="1"  >
  <animateMotion id="anPop"
    begin="svg1.click;rollback.end+2s"
    dur="3s"  rotate="auto" 
    keyPoints="0;0.4;0.6;1"
    keyTimes="0;0.3;0.6;1"
    calcMode="linear"
    repeatCount="1"
    restart="whenNotActive">
      <mpath xlink:href="#trace"/>
    </animateMotion>  
 </path> 
 </g>
 <animateTransform id="rollback" xlink:href="#cannon" attributeName="transform" type="translate" begin="anPop.begin+0.25s" dur="0.8s" values="0,0;-20,0;0,0" repeatCount="1" />  
 </svg>
like image 32
Alexandr_TT Avatar answered Nov 01 '25 16:11

Alexandr_TT