【问题标题】: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-width="3px" 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查看动画。

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

这怎么可能?

【问题讨论】:

    标签: html css animation svg


    【解决方案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();
    svg{border:1px solid}
    <svg id="city-total-v2" viewBox="400 370 250 100" >
    <g id="Chartline">
    <path id="currency_chart_path" stroke="#7C0A67" stroke-width="3px" 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-width="3px" 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-width="3px" 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-width="0.25" 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-width="0.25" 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" width="19" height="23" fill="red" />
           <rect x="28" y="-30" width="19" height="29" fill="crimson" />
            <rect x="53" y="-43" width="19" height="42" fill="gold" /> 
             <rect x="78" y="-38" width="19" height="37" fill="orange" />
             <rect x="103" y="-52" width="19" height="51" fill="skyblue" /> 
              <rect x="128" y="-48" width="19" height="47" fill="yellowgreen" /> 
              <rect x="153" y="-41" width="19" height="40" fill="orange" />
       </g>
    <g id="Chartline">
    <path id="currency_chart_path" stroke-dasharray="177" stroke-dashoffset="177" stroke="#7C0A67" stroke-width="3px" 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-width="0.25" 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-width="0.25" stroke="black" />
      </marker>
    </defs>   
       <g transform="translate(440 465)">
             <rect x="3" y="0" width="19" height="23" 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" width="19" height="29" 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" width="19" height="42" 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" width="19" height="37" 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" width="19" height="51" 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" width="19" height="47" 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" width="19" height="40" 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" width="100%" height="100%" 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-width="3px" 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-width="0.25" 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-width="0.25" stroke="black" />
      </marker>
    </defs>   
       <g transform="translate(440 465)">
          <rect x="3" y="0" width="19" height="23" 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" width="19" height="29" 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" width="19" height="42" 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" width="19" height="37" 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" width="19" height="51" 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" width="19" height="47" 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" width="19" height="40" 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" width="100%" height="100%" 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-width="3px" 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>

    【讨论】:

      最近更新 更多