笔画动画,如何为出现的笔画附加另一条路径?

Posted

技术标签:

【中文标题】笔画动画,如何为出现的笔画附加另一条路径?【英文标题】:Stroke animation, how to attach another path to the appearing stroke? 【发布时间】:2019-05-13 06:46:38 【问题描述】:

我有以下动画:

@keyframes dash 
  to 
    stroke-dashoffset: 0;
  


#currency-chart-path 
  stroke-dasharray: 1000;
  stroke-dashoffset: 1000;
  animation: dash 30s linear forwards;
<svg id="city-total-v2" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 1000 1000" enable-background="new 0 0 1000 1000" xml:space="preserve">
<g id="Chartline">
  <path id="currency-chart-path" stroke="#7C0A67" stroke- fill="none" d="M443,439 L464,435 487,421 511,416 532,424 552,408 572,414 591,413 606,419" />
	<path id="chart-arrow" fill="#7C0A67" d="M604.4,423.5l6.88-2.26l-2.44-3.3c-0.1-0.22-0.25-0.41-0.43-0.58l0.01,0.02l-0.02-0.02
		c0,0,0,0.01,0.01,0.01l-2.48-3.36l-0.08,0.42l-0.27,1.66l-0.03-0.01l-0.68,3.8l0.09,0.04L604.4,423.5z"/>
</g>
</svg>

运行代码sn-p查看动画。

我想将箭头附加到笔划上,使其看起来像跟随路径。

这怎么可能?

【问题讨论】:

【参考方案1】:

是的,这是可能的,但是在这种情况下,您将需要 javascript。请重新输入我的代码中的 cmets。

let chart = document.querySelector("#currency_chart_path");
// the length of the chart path
let length = currency_chart_path.getTotalLength();
// the request animation id
let rid = null;
// setting the stroke-dasharray and the stroke-dashoffset for the chart
chart.style.strokeDasharray = length;
chart.style.strokeDashoffset = length;
// the animation frames
let frames = length;
// two points on the path: the actual point and an other point very near used to calculate the angle of rotation for the arrow
let point1, point2;
// the animation:
function Frame() 
  rid = requestAnimationFrame(Frame);
  chart.style.strokeDashoffset = frames;
  //two points on the path: the actual point and an other point very near
  point1 = chart.getPointAtLength(length - frames);
  point2 = chart.getPointAtLength((length - frames + 2) % length);
  //the angle of rotation for the arrow
  angle = Math.atan2(point2.y - point1.y, point2.x - point1.x);
  // set the transformation for the arrow
  arrow.setAttribute(
    "transform",
    "translate(" +
      [point1.x, point1.y] +
      ")" +
      "rotate(" +
      angle * 180 / Math.PI +
      ")"
  );

  frames--;
  // stop the animation
  if (frames <= 2) 
    cancelAnimationFrame(rid);
    rid = null;
  


Frame();
svgborder:1px solid
<svg id="city-total-v2" viewBox="400 370 250 100" >
<g id="Chartline">
<path id="currency_chart_path" stroke="#7C0A67" stroke- fill="none" d="M443,439 L464,435 487,421 511,416 532,424 552,408 572,414 591,413 606,419" />
<path id="arrow" fill="#7C0A67" d="M0,0L0,-5L7,0L0,5"/>
</g>
</svg>

这是受Using SVG with CSS3 and html5: Vector Graphics for Web Design中的演示启发

【讨论】:

arrowchart 路径后面的箭头。我无法在您的代码中使用它,因为它不合适。当你做这种事情时,你需要在 svg 画布的原点绘制箭头(在这种情况下)。 嗨,谢谢,这正是我所需要的。有没有办法可以玩动画持续时间? 我尝试增加frame,但效果不佳 Insetad 将frames 每一步减少一个 (frames--),尝试将其减少小于 1。例如,减去 0.5 (frames -= 0.5;) 将使动画长度加倍.【参考方案2】:

一个想法是在进行翻译时以相反的方向运行动画

@keyframes dash 
  to 
    stroke-dasharray: 190;
  


@keyframes move 
  to 
    transform: translateX(0);
  


#currency-chart-path 
  stroke-dasharray: 279;
  stroke-dashoffset: 381;
  animation: dash 10s linear forwards;


#Chartline 
  animation: move 10s linear forwards;
  transform: translateX(-200px);
<svg id="city-total-v2" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="300 300 400 400">
<g id="Chartline">
  <path id="currency-chart-path" stroke="#7C0A67" stroke- fill="none" d="M443,439 L464,435 487,421 511,416 532,424 552,408 572,414 591,413 606,419" />
	<path id="chart-arrow" fill="#7C0A67" d="M604.4,423.5l6.88-2.26l-2.44-3.3c-0.1-0.22-0.25-0.41-0.43-0.58l0.01,0.02l-0.02-0.02
		c0,0,0,0.01,0.01,0.01l-2.48-3.36l-0.08,0.42l-0.27,1.66l-0.03-0.01l-0.68,3.8l0.09,0.04L604.4,423.5z"/>
</g>
</svg>

【讨论】:

谢谢,这很有趣,我会选择@enxaneta 解决方案,因为它更接近我想要的。【参考方案3】:

纯 SVG Smil 解决方案

您可以使用 stroke-dashoffset 动画线的增长。 标记用作线条末端的箭头,但它不能随线条移动,因为线条实际上并没有增长。

这条线是预先画好的,它的增长只是通过将 stroke-dashoffset 从 177px 减少到零来实现的。

您可以使用另一种技术:将箭头沿这条线移动的动画添加到线增长的动画中。需要为两个动画设置相同的时间,因此将创建所需的效果:

<svg id="city-total-v2" viewBox="400 370 250 100" style="border:1px solid;" >
<g id="Chartline">
<path id="currency_chart_path" stroke-dasharray="177" stroke="#7C0A67" stroke- fill="none" d="M443,439 L464,435 487,421 511,416 532,424 552,408 572,414 591,413 606,419" >
  <!-- Line growth animation -->
<animate
 attributeName="stroke-dashoffset"
 begin="0s"
 dur="4s"
 values="177;0"
 repeatCount="indefinite" />
</path>
<path id="arrow" transform="rotate(180)" fill="#7C0A67" d="M0,0L0,-5L7,0L0,5">
  <!-- Animate an arrow along a line   -->
 <animateMotion
   id="an"
   dur="4s"
   repeatCount="indefinite"
   rotate="auto-reverse"
   begin="0s"
   restart="whenNotActive">
       <mpath xlink:href="#currency_chart_path"/>
</animateMotion>
</path>
</g> 
</svg>

带有附加图表元素的选项

点击后动画会开始

<svg id="city_total_v2" viewBox="400 370 250 100" style="border:1px solid;" >
    <defs>
  <marker id="mark" markerWidth="6.5" markerHeight="8" refX="5.5" refY="1"
           orient="45">
        
        <polygon points="0,3.25 3.25,6.5 6.5,0" fill="black" stroke- stroke="black" />
  </marker> 
  <marker id="mark2" markerWidth="7" markerHeight="7" refX="3.5" refY="3"
           orient="-45">
        
        <polygon points="0,3.25 3.25,6.5 6.5,0" fill="black" stroke- stroke="black" />
  </marker>
</defs>   
    <g transform="translate(440 465)">
     <polyline  points="0,0 190,0" marker-end ="url(#mark)" fill="none" stroke="black" />
      <polyline  points="0,0 0,-85" marker-end ="url(#mark2)" fill="none" stroke="black" /> 
       <rect x="3" y="-24"   fill="red" />
       <rect x="28" y="-30"   fill="crimson" />
        <rect x="53" y="-43"   fill="gold" /> 
         <rect x="78" y="-38"   fill="orange" />
         <rect x="103" y="-52"   fill="skyblue" /> 
          <rect x="128" y="-48"   fill="yellowgreen" /> 
          <rect x="153" y="-41"   fill="orange" />
   </g>
<g id="Chartline">
<path id="currency_chart_path" stroke-dasharray="177" stroke-dashoffset="177" stroke="#7C0A67" stroke- fill="none" d="M443,439 L464,435 487,421 511,416 532,424 552,408 572,414 591,413 606,419" >
   <!--Line growth animation -->
<animate
  attributeName="stroke-dashoffset"
  begin="city_total_v2.click"
  dur="7s"
  values="177;0"
  fill="freeze"
  restart="whenNotActive" />
</path>
<path id="arrow" transform="rotate(180)" fill="#7C0A67" d="M0,0L0,-5L7,0L0,5">
  <!--Arrow movement animation -->
  <animateMotion 
   id="an"
   dur="7s"
   repeatCount="1"
   rotate="auto-reverse"
   begin="city_total_v2.click"
   fill="freeze"
   restart="whenNotActive">
       <mpath xlink:href="#currency_chart_path"/>
</animateMotion>
</path>
</g> 
</svg>

为箭头动画添加了矩形动画

<svg id="city_total_v2" viewBox="400 370 250 100" style="border:1px solid;" >
<defs>
  <marker id="mark" markerWidth="6.5" markerHeight="8" refX="5.5" refY="1" orient="45">        
        <polygon points="0,3.25 3.25,6.5 6.5,0" fill="black" stroke- stroke="black" />
  </marker> 
  <marker id="mark2" markerWidth="7" markerHeight="7" refX="3.5" refY="3"   orient="-45">        
        <polygon points="0,3.25 3.25,6.5 6.5,0" fill="black" stroke- stroke="black" />
  </marker>
</defs>   
   <g transform="translate(440 465)">
         <rect x="3" y="0"   fill="red" >
            <!-- Animating the first rectangle -->
          <animate id="an1" attributeName="y" begin="city_total_v2.click" dur="1s" values="-1;-24" fill="freeze" restart="whenNotActive" />
       </rect>
      
       <rect x="28" y="0"   fill="crimson" >
           <!-- Animating the second rectangle -->
         <animate id="an2" attributeName="y" begin="an1.end" dur="1s" values="-1;-30" fill="freeze" restart="whenNotActive" />
       </rect>
        <rect x="53" y="0"   fill="gold" >
           <animate id="an3" attributeName="y" begin="an2.end" dur="1s" values="-1;-43" fill="freeze" restart="whenNotActive" />
       </rect>          
         <rect x="78" y="0"   fill="orange" >
            <animate id="an4" attributeName="y" begin="an3.end" dur="1s" values="-1;-37" fill="freeze" restart="whenNotActive" />
         </rect>        
           <rect x="103" y="0"   fill="skyblue" >
             <animate id="an5" attributeName="y" begin="an4.end" dur="1s" values="-1;-52" fill="freeze" restart="whenNotActive" />
           </rect>       
          <rect x="128" y="0"   fill="yellowgreen" >
              <animate id="an6" attributeName="y" begin="an5.end" dur="1s" values="-1;-48" fill="freeze" restart="whenNotActive" />
          </rect>    
          <rect x="153" y="0"   fill="orange" >
             <animate id="an7" attributeName="y" begin="an6.end" dur="1s" values="-1;-41" fill="freeze" restart="whenNotActive" />
       </rect>                
              <!-- masking strip          -->
         <rect x="1" y="0"   fill="white" />
        <polyline  marker-end ="url(#mark)" points="0,0 200,0" fill="none" stroke="black" />
      <polyline  marker-end ="url(#mark2)" points="0,0 0,-85" fill="none" stroke="black" />   
   </g>
<g id="Chartline">
<path id="currency_chart_path" stroke-dasharray="177" stroke-dashoffset="177" stroke="#7C0A67" stroke- fill="none" d="M443,439 L464,435 487,421 511,416 532,424 552,408 572,414 591,413 606,419" >
   <!-- Line animation -->
<animate attributeName="stroke-dashoffset" begin="city_total_v2.click" dur="7s" values="177;0" fill="freeze" restart="whenNotActive" />
</path>
<path id="arrow" transform="rotate(180)" fill="#7C0A67" d="M0,0L0,-5L7,0L0,5">
    <!-- Arrow animation -->
  <animateMotion
   id="an"
   dur="7s"
   repeatCount="1"
   rotate="auto-reverse"
   begin="city_total_v2.click"
   fill="freeze"
   restart="whenNotActive">
       <mpath xlink:href="#currency_chart_path"/>
</animateMotion>
</path>
</g> 
</svg>

图表动画循环

<svg id="city_total_v2" viewBox="400 370 250 100" style="border:1px solid;" >
<defs>
  <marker id="mark" markerWidth="6.5" markerHeight="8" refX="5.5" refY="1" orient="45">        
        <polygon points="0,3.25 3.25,6.5 6.5,0" fill="black" stroke- stroke="black" />
  </marker> 
  <marker id="mark2" markerWidth="7" markerHeight="7" refX="3.5" refY="3"  orient="-45">        
        <polygon points="0,3.25 3.25,6.5 6.5,0" fill="black" stroke- stroke="black" />
  </marker>
</defs>   
   <g transform="translate(440 465)">
      <rect x="3" y="0"   fill="red" >
          <animate id="an1" attributeName="y" begin="city_total_v2.click;an7.end" dur="1s" values="-1;-24" fill="freeze" restart="whenNotActive" />
       </rect>
      
       <rect x="28" y="0"   fill="crimson" >
         <animate id="an2" attributeName="y" begin="an1.end" dur="1s" values="-1;-30" fill="freeze" restart="whenNotActive" />
       </rect>
        <rect x="53" y="0"   fill="gold" >
           <animate id="an3" attributeName="y" begin="an2.end" dur="1s" values="-1;-43" fill="freeze" restart="whenNotActive" />
       </rect>          
         <rect x="78" y="0"   fill="orange" >
            <animate id="an4" attributeName="y" begin="an3.end" dur="1s" values="-1;-37" fill="freeze" restart="whenNotActive" />
         </rect>        
           <rect x="103" y="0"   fill="skyblue" >
             <animate id="an5" attributeName="y" begin="an4.end" dur="1s" values="-1;-52" fill="freeze" restart="whenNotActive" />
           </rect>       
          <rect x="128" y="0"   fill="yellowgreen" >
              <animate id="an6" attributeName="y" begin="an5.end" dur="1s" values="-1;-48" fill="freeze" restart="whenNotActive" />
          </rect>    
          <rect x="153" y="0"   fill="orange" >
             <animate id="an7" attributeName="y" begin="an6.end" dur="1s" values="-1;-41" fill="freeze" restart="whenNotActive" />
       </rect>                
              <!-- masking strip          -->
         <rect x="1" y="0"   fill="white" />
        <polyline  marker-end ="url(#mark)" points="0,0 200,0" fill="none" stroke="black" />
      <polyline  marker-end ="url(#mark2)" points="0,0 0,-85" fill="none" stroke="black" />   
   </g>
<g id="Chartline">
<path id="currency_chart_path" stroke-dasharray="177" stroke-dashoffset="177" stroke="#7C0A67" stroke- fill="none" d="M443,439 L464,435 487,421 511,416 532,424 552,408 572,414 591,413 606,419" >
   <!-- Line animation -->
<animate attributeName="stroke-dashoffset" begin="city_total_v2.click;an7.end" dur="7s" values="177;0" fill="freeze" restart="whenNotActive" />
</path>
<path id="arrow" transform="rotate(180)" fill="#7C0A67" d="M0,0L0,-5L7,0L0,5">
    <!-- Arrow animation -->
  <animateMotion
   id="an"
   dur="7s"
   repeatCount="1"
   rotate="auto-reverse"
   begin="city_total_v2.click;an7.end"
   fill="freeze"
   restart="whenNotActive">
       <mpath xlink:href="#currency_chart_path"/>
</animateMotion>
</path>
</g> 
</svg>

【讨论】:

以上是关于笔画动画,如何为出现的笔画附加另一条路径?的主要内容,如果未能解决你的问题,请参考以下文章

尝试在 SVG 笔画出现时对其进行动画处理,但没有运气

为啥绘图路径的笔画会随着设备旋转动画而变形

1341:例题一笔画问题

圆段笔画动画以完整笔画结束

计算机视觉之--使用opencv生成简笔画小视频

题解 P2731 骑马修栅栏 Riding the Fences