Beispiel:Animation Pythagoras WAAPI.html

Aus SELFHTML-Wiki
Wechseln zu: Navigation, Suche
<!doctype html>
<html lang="de">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>Pythagoras Animation mit WAAPI</title>
  <style>
    body {
      background: #fff;
      font-family: sans-serif;
    }
    svg { 
      width: min(460px, 96vw);
      height:auto;
    }
    line, path {
        fill: none;
        stroke-width: 1;
        stroke: rgb(0, 0, 0);
        stroke-linecap: round;
        stroke-linejoin: round;
        transform-box: fill-box;
      }
      #radien path {
        fill: none;
        stroke: orange;
        stroke-width: .5;
        stroke-dasharray: 1, 2;
      }
      text {
        fill: green;
        font-family: sans-serif;
        font-size: 10px;
        white-space: pre;
        text-anchor: middle;
      }
      #rechter_winkel, #zahlen, #radien {
        opacity: 0;
        transform-box: fill-box;
      }
  </style>
</head>
<body>

<p>Pythagoras WAAPI-Animation <button id="start_button" type="button">Neustart</button></p>

<svg viewBox="0 0 70 70">

  <g id="radien">
    <path id="radius_3" d="M 10 20 C 27 20 40 33 40 50"/>
    <path id="radius_4" d="M 20 50 C 20 28 38 10 60 10"/>
  </g>
  
  <line id="linie_5" style="transform-origin: 50% 50%;" x1="10" y1="-10" x2="60" y2="-10"/>
  <line id="linie_4" style="transform-origin: 100% 50%;" x1="10" y1="-20" x2="50" y2="-20"/>
  <line id="linie_3" style="transform-origin: 0% 100%;" x1="10" y1="-30" x2="40" y2="-30"/>

  <g id="rechter_winkel" style="transform-origin: 100% 100%;">
    <path style="fill: none; stroke: green; transform-box: fill-box;" d="M 9 19 C 9 13 13 9 19 9"/>
    <circle style="fill: green; stroke: none;" cx="15" cy="15" r="2"/>
  </g>

  <g id="zahlen">
    <text x="34" y="60" style="white-space: pre;">5</text>
    <text x="6" y="40" style="white-space: pre; font-size: 10px;">3</text>
    <text x="64" y="40" style="white-space: pre; font-size: 10px;">4</text>
  </g>

</svg>

<script>
document.addEventListener('DOMContentLoaded', function () {
  const ms = s => Math.round(s * 1000);
  const el = (id) => document.getElementById(id);

  const T = (x,y) => `translate(${x}px, ${y}px)`;
  const R = (deg) => `rotate(${deg}deg)`;

  const startBtn = el("start_button");

  let running = [];
  const cancelAll = () => {
    for (const a of running) {
      a.cancel();
    }
    running = [];
  };

  const setButtonEnabled = (enabled) => {
    if (!startBtn) return;
    startBtn.disabled = !enabled;
    startBtn.setAttribute("aria-disabled", String(!enabled));
  };

  const startAnimation = () => {
    setButtonEnabled(false);

    cancelAll();

    const animations = [];

    animations.push(
      el("linie_5").animate(
        [{ transform: T(0,0) }, { transform: T(0,60) }],
        { duration: ms(2), delay: ms(0), fill: "forwards", easing: "ease-in" }
      )
    );

    const line4KF = [
      { t: 0.0,  tx: 0,  ty: 0,  rotA: 0,  rotB: 0 },
      { t: 2.0,  tx: 5,  ty: 35, rotA: 0,  rotB: 0 },
      { t: 4.0,  tx: 10, ty: 70, rotA: 90, rotB: 0 },
      { t: 6.5,  tx: 10, ty: 70, rotA: 90, rotB: 0 },
      { t: 7.4,  tx: 10, ty: 70, rotA: 90, rotB: -66 },
      { t: 8.3,  tx: 10, ty: 70, rotA: 90, rotB: -39 },
      { t: 9.5,  tx: 10, ty: 70, rotA: 90, rotB: -53.13 },
    ];
    animations.push(
      el("linie_4").animate(
        line4KF.map(k => ({
          transform: `${T(k.tx, k.ty)} ${R(k.rotA + k.rotB)}`,
          offset: k.t / 9.5
        })),
        { duration: ms(9.5), delay: 0, fill: "forwards", easing: "linear" }
      )
    );

    const line3KF = [
      { t: 0.0,  tx: 0, ty: 0,  rotA: 0,   rotB: 0 },
      { t: 2.0,  tx: 0, ty: 0,  rotA: 0,   rotB: 0 },
      { t: 2.8,  tx: 0, ty: 21, rotA: 0,   rotB: 0 },
      { t: 5.0,  tx: 0, ty: 80, rotA: -90, rotB: 0 },
      { t: 6.0,  tx: 0, ty: 80, rotA: -90, rotB: 0 },
      { t: 7.2,  tx: 0, ty: 80, rotA: -90, rotB: 50 },
      { t: 8.4,  tx: 0, ty: 80, rotA: -90, rotB: 21 },
      { t: 10.0, tx: 0, ty: 80, rotA: -90, rotB: 36.87 },
    ];
    animations.push(
      el("linie_3").animate(
        line3KF.map(k => ({
          transform: `${T(k.tx, k.ty)} ${R(k.rotA + k.rotB)}`,
          offset: k.t / 10.0
        })),
        { duration: ms(10), delay: 0, fill: "forwards", easing: "linear" }
      )
    );

    animations.push(
      el("zahlen").animate(
        [{ opacity: 0 }, { opacity: 1 }],
        { duration: ms(2), delay: ms(5), fill: "forwards", easing: "linear" }
      )
    );

    const radien = el("radien");
    animations.push(
      radien.animate(
        [{ opacity: 0 }, { opacity: 1 }],
        { duration: ms(0.95), delay: ms(5.52), fill: "forwards", easing: "linear" }
      )
    );
    animations.push(
      radien.animate(
        [{ opacity: 1 }, { opacity: 0 }],
        { duration: ms(0.98), delay: ms(10.01), fill: "forwards", easing: "linear" }
      )
    );

    const rw = el("rechter_winkel");
    rw.style.transformBox = "fill-box";
    rw.style.transformOrigin = "100% 100%";

    animations.push(
      rw.animate(
        [{ opacity: 0 }, { opacity: 1 }],
        { duration: ms(2), delay: ms(10), fill: "forwards", easing: "linear" }
      )
    );

    animations.push(
      rw.animate(
        [
          { transform: `${R(0)} ${T(0,0)}` },
          { transform: `${R(-142)} ${T(-12,0)}` }
        ],
        { duration: ms(2), delay: ms(10), fill: "forwards", easing: "linear" }
      )
    );

    running = animations;

    Promise.allSettled(animations.map(a => a.finished)).then(() => {
      if (running === animations) setButtonEnabled(true);
    });
  };

  if (startBtn) setButtonEnabled(false);

  if (startBtn) {
    startBtn.addEventListener("pointerup", (e) => {
      e.preventDefault();
      startAnimation();
    });
    startBtn.addEventListener("click", (e) => {
      e.preventDefault();
      startAnimation();
    });
  }

  startAnimation();
});
</script>

</body>
</html>