SVG animateTransform масштабирует keySplines для соответствия компоненту Y вращающегося вектора (стрелки)

Мне нужно смоделировать вращающуюся стрелку в 2D. Она должна быть синхронизирована с вращающейся синей стрелкой.
Я начал с keySplines, показанной красной стрелкой, которая давала хороший квадрант при просмотре с помощью
http://franzheidl.github.io/keysplines/

<!DOCTYPE html>
<body>

<svg width="800" height="400" viewBox="0 0 800 400" version="1.1" id="svg5">

  <defs>
     <g id="layer1a">
      <path id="vect1a"
        style="stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
        d="m 0,0 h -10 v -80 h -10 l 20,-20 20,20 h -10 v 80 z" />
      <animateTransform additive=sum attributeName="transform" type="rotate"
       begin="0s" dur="12s"
       from="0 0 0" to="360 0 0"
       repeatCount="2.125" fill="freeze" />
    </g>
    <g id="line1">
      <line x1="0" y1="0" x2="800" y2="0">
    </g>
  </defs>
 
  <g id="layer3" transform="translate(0,200)">
    <path
      style="fill:#ffffff;stroke:#0000ff;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
      d="m 0,0 h 800"
      id="line"
      />
  </g>
  <use href="#layer1a" style="fill:#0000ff" transform="translate(150,200)" />
  <use href="#line1" style="stroke:rgb(255,0,0);stroke-width:2" transform="translate(0,200)">
    <animateTransform
        additive="sum"
        id="line1at0"
        attributeName="transform"
        type="translate"
        calcMode="spline"
        begin="0s"
        dur="12s"
        values="0 -100 ; 0 0 ; 0 100 ;0 0 ; 0 -100"
        keyTimes="0 ; 0.25 ; 0.5 ; 0.75 ; 1" 
        keySplines="0.5 0 1 .5 ; 0 0.5 0.5 1 ; 0.5 0 1 .5 ; 0 0.5 0.5 1"
        repeatCount="2.125"
        fill="freeze" />
  </use>
  <use xlink:href="#vect1a" style="fill:#ff0000" transform="translate(300,200)" >
      <animateTransform
        additive="sum"
        id="arrow1at0"
        attributeName="transform"
        type="scale"
        calcMode="spline"
        begin="0s"
        dur="12s"
        values="1 1 ; 1 0 ; 1 -1 ; 1 0 ; 1 1"
        keyTimes="0 ; 0.25 ; 0.5 ; 0.75 ; 1" 
        keySplines="0.5 0 1 .5 ; 0 0.5 0.5 1 ; 0.5 0 1 .5 ; 0 0.5 0.5 1"
        repeatCount="2.125"
        fill="freeze" />
  </use>
  <use href="#line1" style="stroke:rgb(255,0,0);stroke-width:2" transform="translate(0,200)">
    <animateTransform
        additive="sum"
        id="line1at0"
        attributeName="transform"
        type="translate"
        calcMode="spline"
        begin="0s"
        dur="12s"
        values="0 -100 ; 0 0 ; 0 100 ;0 0 ; 0 -100"
        keyTimes="0 ; 0.25 ; 0.5 ; 0.75 ; 1" 
        keySplines="0.5 0 1 .5 ; 0 0.5 0.5 1 ; 0.5 0 1 .5 ; 0 0.5 0.5 1"
        repeatCount="2.125"
        fill="freeze" />
  </use>
  <use xlink:href="#vect1a" style="fill:#00ff00" transform="translate(450,200)" >
      <animateTransform
        additive="sum"
        id="arrow1bt0"
        attributeName="transform"
        type="scale"
        calcMode="spline"
        begin="0s"
        dur="12s"
        values="1 1 ; 1 0 ; 1 -1 ; 1 0 ; 1 1"
        keyTimes="0 ; 0.25 ; 0.5 ; 0.75 ; 1" 
        keySplines="1 .75 .25 0 ; 0 .25 .75 1 ; 1 .75 .25 0 ; 0 .25 .75 1"
        repeatCount="2.125"
        fill="freeze" />
  </use>
  <use href="#line1" style="stroke:rgb(0,255,0);stroke-width:2" transform="translate(0,200)">
    <animateTransform
        additive="sum"
        id="line1bt0"
        attributeName="transform"
        type="translate"
        calcMode="spline"
        begin="0s"
        dur="12s"
        values="0 -100 ; 0 0 ; 0 100 ;0 0 ; 0 -100"
        keyTimes="0 ; 0.25 ; 0.5 ; 0.75 ; 1" 
        keySplines="1 .75 .25 0 ; 0 .25 .75 1 ; 1 .75 .25 0 ; 0 .25 .75 1"
        repeatCount="2.125"
        fill="freeze" />
  </use>
 
</svg>

</body>
</html>

У кого-нибудь есть идеи о том, как установить keySplines для получения желаемого результата?

Свободный перевод вопроса SVG animateTransform scaling keySplines to match Y component of rotating vector от участника @Peter Hill.


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

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

Вместо использования SMIL вам нужно будет использовать какой-либо другой вид анимации, который позволит вам вычислить значение y кончика стрелки. Поскольку у вас есть вращение вокруг точки {0,0}, y = 100 * Math.sin(rad), где 100 — длина стрелки, а rad — угол поворота в радианах.

В этом случае значение масштаба будет y/100. Также вам нужно будет учесть тот факт, что стрелка имеет начальный угол (-90)

В следующем примере я использую javascript для расчета:

let a = 0;//the angle 

function anim() {
  a++;//increasing the angle with each frame
  use1.setAttribute("transform", `rotate(${a})`);
  let rad = (a + 90) * (Math.PI / 180);//the angle in radians
  use2.setAttribute("transform", `scale(1,${Math.sin(rad)})`);
  use3.setAttribute("transform", `translate(0,${100 * Math.sin(-rad)})`);
  window.requestAnimationFrame(anim);
}

window.requestAnimationFrame(anim);
<svg width="800" height="400" viewBox="-120 -101 800 400" version="1.1" id="svg5">

  <defs>
    <path id="vect1a" d="m 0,0 h -10 v -80 h -10 l 20,-20 20,20 h -10 v 80 z" />
  </defs>

  <line id="line" x1="-120" x2="800" stroke="black" />

  <use id="use1" xlink:href="#vect1a" />
  <g transform="translate(200,0)">
    <use id="use2" xlink:href="#vect1a" />
  </g>
  <use id="use3" xlink:href="#line" />

</svg>

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

→ Ссылка