При анимация линии, как добавить еще стрелку к появляющейся линии?

У меня есть такая анимация:

@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>

Я хочу прикрепить стрелку к концу линии, чтобы она двигалась вместе с анимацией линии.

Возможно ли сделать такое?

Свободный перевод вопроса Stroke animation, how to attach another path to the appearing stroke? от участника @dimitri-kopriwa.


Ответы (2 шт):

Автор решения: Alexandr_TT

Да, возможно, но в этом случае вам понадобится JavaScript. Пожалуйста, прочтите комментарии в моем коде.

let chart = document.querySelector("#currency_chart_path");
// длина пути диаграммы
let length = currency_chart_path.getTotalLength();
// идентификатор анимации запроса
let rid = null;
// установка stroke-dasharray и stroke-dashoffset для диаграммы
chart.style.strokeDasharray = length;
chart.style.strokeDashoffset = length;
// кадры анимации
let frames = length;
// две точки на пути: фактическая точка и другая точка очень близко, используемые для расчета угла поворота стрелки
let point1, point2;
// анимация:
function Frame() {
  rid = requestAnimationFrame(Frame);
  chart.style.strokeDashoffset = frames;
  //две точки на пути: настоящая точка и другая точка очень близко
  point1 = chart.getPointAtLength(length - frames);
  point2 = chart.getPointAtLength((length - frames + 2) % length);
  //угол поворота стрелки
  angle = Math.atan2(point2.y - point1.y, point2.x - point1.x);
  // установить преобразование для стрелки
  arrow.setAttribute(
    "transform",
    "translate(" +
      [point1.x, point1.y] +
      ")" +
      "rotate(" +
      angle * 180 / Math.PI +
      ")"
  );

  frames--;
  // стоп анимации
  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>

Свободный перевод ответа от участника @enxaneta.

→ Ссылка
Автор решения: Alexandr_TT

Решение pure SVG

Для анимации роста линии можно использовать stroke-dashoffset
В качестве стрелки на конце линии обычно используют маркер, но заставить его двигаться вместе с линией невозможно, так как линия на самом деле не увеличивается. Она нарисована заранее и просто анимированно показывается её рост с помощью уменьшения отступа stroke-dashoffset от 177px до нуля.

Можно воспользоваться другой техникой: к анимации роста линии добавить анимацию движения стрелки вдоль этой линии. Нужно установить для обоих анимаций одинаковое время и поэтому будет создаваться необходимый эффект:

Анимация начинается после клика

<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 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" >
   <!--Анимация роста линии -->
<animate
  attributeName="stroke-dashoffset"
  begin="city_total_v2.click"
  dur="7s"
  values="177;0"
   repeatCount="indefinite"
  restart="whenNotActive" />
</path>
<path id="arrow" transform="rotate(180)" fill="#7C0A67" d="M0,0L0,-5L7,0L0,5">
  <!--Анимация движения стрелки -->
  <animateMotion 
   id="an"
   dur="7s"
   rotate="auto-reverse"
   begin="city_total_v2.click"
   repeatCount="indefinite"
   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" >
   <!--Анимация роста линии -->
<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">
  <!--Анимация движения стрелки -->
  <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" 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>                
              <!-- маскирующая полоса         -->
         <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" >
   <!-- Анимация линии -->
<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">
    <!-- Анимация стрелки -->
  <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>                
              <!-- маскирующая полоса         -->
         <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" >
   <!-- Анимация линии -->
<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">
    <!-- Анимация стрелки -->
  <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>

→ Ссылка