Trying to animate SVG gradient

2019-05-19 07:10发布

问题:

I am using SVG to try and animate a gradient path - to create a tail / shooting star effect. In doing this, I want to animate an object at the front of the tail, which I have shown in my example below (the circles).

The example works barely in Google Chrome, haven't checked others... You can see I've got 5 circles/paths and only 1 of them is working properly. The curved one animates the gradient at a different speed to the object and the others don't work properly at all except for the "almost-horizontal" one.

Can someone please provide some insight into why this doesn't work, recommend a way I could do this and provide an example if possible?

I'm almost to the point where i'll just write my own render code in canvas and using a JS library... :(

<svg style="height: 400px; width: 100%" viewBox="0 0 500 200">
    <path id="circlePath1" stroke-width="2" d="M10 100 Q 100 10, 150 80 T 300 100" stroke="url(#grad)" fill="transparent"></path>
	<path id="circlePath2" stroke-width="2" d="M30 20 L 130 19" stroke="url(#grad)" fill="transparent"></path>
	<path id="circlePath3" stroke-width="2" d="M30 10 L 130 10" stroke="url(#grad)" fill="transparent"></path>
	<path id="circlePath4" stroke-width="2" d="M10 10 L 10 110" stroke="url(#grad)" fill="transparent"></path>
	<path id="circlePath5" stroke-width="2" d="M10 20 L 20 110" stroke="url(#grad)" fill="transparent"></path>
	
	<linearGradient id='grad'>
		<stop stop-opacity="0" stop-color='#800'>
			<animate attributeName="offset" dur="2s" values='-0.20;0.80' repeatCount="indefinite" ></animate>
		</stop>
		<stop stop-color='#800' stop-opacity=".5">
			<animate attributeName="offset" dur="2s" values='-0.02;0.98' repeatCount="indefinite" ></animate>
		</stop>
		<stop stop-opacity="0.5" stop-color='#800'>
			<animate attributeName="offset" dur="2s" values='-0;1' repeatCount="indefinite" ></animate>
		</stop>
		<stop stop-opacity="0" stop-color='#800'>
			<animate attributeName="offset" dur="2s" values='-0;1' repeatCount="indefinite" ></animate>
		</stop>
	</linearGradient>
	
	<circle id="c1" r="2.5" cx="" cy="" fill="#880000">
		<animateMotion dur="2s" repeatCount="indefinite">
			<mpath href="#circlePath1"></mpath>
		</animateMotion>
	</circle>
	<circle id="c2" r="2.5" cx="" cy="" fill="#880000">
		<animateMotion dur="2s" repeatCount="indefinite">
			<mpath href="#circlePath2"></mpath>
		</animateMotion>
	</circle>
	<circle id="c3" r="2.5" cx="" cy="" fill="#880000">
		<animateMotion dur="2s" repeatCount="indefinite">
			<mpath href="#circlePath3"></mpath>
		</animateMotion>
	</circle>
	<circle id="c4" r="2.5" cx="" cy="" fill="#880000">
		<animateMotion dur="2s" repeatCount="indefinite">
			<mpath href="#circlePath4"></mpath>
		</animateMotion>
	</circle>
	<circle id="c5" r="2.5" cx="" cy="" fill="#880000">
		<animateMotion dur="2s" repeatCount="indefinite">
			<mpath href="#circlePath5"></mpath>
		</animateMotion>
	</circle>
</svg>

回答1:

In this attempt I use a radial gradient that is masked by the line to create the trail, then a separate dot.

<svg width="500" height="300" viewBox="0 0 500 300" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
  <defs>
    <path id="motion-path" stroke-width="2" d="M202.4 58.3c-13.8.1-33.3.4-44.8 9.2-14 10.7-26.2 29.2-31.9 45.6-7.8 22.2-13.5 48-3.5 70.2 12.8 28.2 47.1 43.6 68.8 63.6 19.6 18.1 43.4 26.1 69.5 29.4 21.7 2.7 43.6 3.3 65.4 4.7 19.4 1.3 33.9-7.7 51.2-15.3 24.4-10.7 38.2-44 40.9-68.9 1.8-16.7 3.4-34.9-10.3-46.5-9.5-8-22.6-8.1-33.2-14.1-13.7-7.7-27.4-17.2-39.7-26.8-5.4-4.2-10.4-8.8-15.8-12.9-4.5-3.5-8.1-8.3-13.2-11-6.2-3.3-14.3-5.4-20.9-8.2-5-2.1-9.5-5.2-14.3-7.6-6.5-3.3-12.1-7.4-19.3-8.9-6-1.2-12.4-1.3-18.6-1.5-10.2-.3-20.2-1.5-30.3-1" stroke="#666" fill="none"/>
    <mask id="path-mask">
      <use xlink:href="#motion-path" stroke="#666"/>
    </mask>
    <symbol id="ball">
      <circle id="ball" r="2.5" fill="#800">
        <animateMotion dur="5s" repeatCount="indefinite">
          <mpath xlink:href="#motion-path"/>
        </animateMotion>
      </circle>
    </symbol>
    <symbol id="trail">
      <circle r="30" fill="url(#grad)">
        <animateMotion dur="5s" repeatCount="indefinite" rotate="auto">
          <mpath xlink:href="#motion-path"/>
        </animateMotion>
      </circle>
    </symbol>
    <linearGradient id="grad">
      <stop offset="0" stop-opacity="0" stop-color="#800"/>
      <stop offset=".5" stop-opacity=".8" stop-color="#800"/>
      <stop offset=".5" stop-opacity="0" stop-color="#800"/>
    </linearGradient>
  </defs>
  <use xlink:href="#ball"/>
  <use xlink:href="#trail" mask="url(#path-mask)"/>
</svg>

It has its limitations (if the path gets too close you get the trail showing on both bits) but hopefully this gives you an idea to play with.