正弦波形成的可视化

Published on
/
/趣玩前端
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>正弦波形成的可视化</title>
    <style>
      * {
        box-sizing: border-box;
      }

      body {
        --border: calc(1vmin / 4);
        --sine-ease: cubic-bezier(0.37, 0, 0.63, 1);
        --dur: 4s;
        --size: 40vmin;
        --gap: 4vmin;
        background-color: #fcecc9;
        margin: 0;
        min-height: 100vh;
        display: flex;
        align-items: center;
        justify-content: center;
        transform: translate3d(0, 0, 0);
        overflow: hidden;
      }

      .grid {
        position: relative;
        display: grid;
        grid-template:
          'c y' auto
          'x b' auto
          / auto auto;
        gap: var(--gap);
        animation: var(--dur) var(--sine-ease) calc(-0.5 * var(--dur)) infinite
            alternate x,
          var(--dur) var(--sine-ease) infinite alternate y,
          calc(var(--dur) * 2) linear infinite rot;
      }

      .circle {
        --color: rgb(123, 0, 126);
        --top: calc(var(--y) * 100%);
        --left: calc(var(--x) * 100%);
        grid-area: c;
        height: var(--size);
        width: var(--size);
        background-color: var(--color);
        border: var(--border) solid var(--color);
        border-radius: 50%;

        &:after {
          height: calc(var(--size) * 0.5);
          width: var(--border);
          background-color: #fcecc9;
          left: 50%;
          top: 0;
          transform-origin: 50% 100%;
          transform: rotate(calc(var(--rot) * 1turn));
        }
      }

      .x-bar {
        --color: rgb(126, 178, 221);
        --dim: var(--y);
        --top: 50%;
        --left: calc(var(--x) * 100%);
        grid-area: x;
        height: var(--border);
        width: var(--size);
        background-color: var(--color);

        &:after {
          left: calc(var(--x) * 100%);
          bottom: 0;
          height: var(--length);
          width: var(--width);
          transform: translate(-50%, 0);
        }
      }

      .x-wave {
        grid-area: x;
        top: 0;
        background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1 2' preserveAspectRatio='none'><path fill='rgb(126, 178, 221)' d='M 0 0 C 0 .37, 1 .63, 1 1 C 1 1.37, 0 1.63, 0 2 Z'></path></svg>");
        background-size: 100% 200%;
        background-position: top
          calc(var(--size) * 0.5 + (var(--rot) * 2 * var(--size))) center;
        background-repeat: repeat-y;
        border-radius: 0 0 calc(var(--size) * 0.125) calc(var(--size) * 0.125);
      }

      .y-bar {
        --color: rgb(249, 57, 67);
        --dim: var(--x);
        --top: calc(var(--y) * 100%);
        --left: 50%;
        grid-area: y;
        width: var(--border);
        height: var(--size);
        background-color: var(--color);

        &:after {
          top: calc(var(--y) * 100%);
          right: 50%;
          width: var(--length);
          height: var(--width);
          transform: translate(0, -50%);
        }
      }

      .y-wave {
        grid-area: y;
        left: 0;
        background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 2 1' preserveAspectRatio='none'><path fill='rgb(249, 57, 67)' d='M 0 0 C .37 0, .63 1, 1 1 C 1.37 1, 1.63 0, 2 0 Z'></path></svg>");
        background-size: 200% 100%;
        background-position: center left calc(var(--rot) * 2 * var(--size));
        background-repeat: repeat-x;
        border-radius: 0 calc(var(--size) * 0.125) calc(var(--size) * 0.125) 0;
      }

      .xy-wave {
        grid-area: b;
        left: 0;
        background-blend-mode: color-burn;
        background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 2 1' preserveAspectRatio='none'><path fill='rgb(249, 57, 67)' d='M 0 1 C .37 1, .63 0, 1 0 C 1.37 0, 1.63 1, 2 1 Z'></path></svg>"),
          url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 2 1' preserveAspectRatio='none'><path fill='rgb(126, 178, 221)' d='M 0 1 C .37 1, .63 0, 1 0 C 1.37 0, 1.63 1, 2 1 Z'></path></svg>");
        background-size: 200% 100%;
        background-repeat: repeat-x;
        background-position: center left calc(var(--rot) * 2 * var(--size)),
          center left calc(var(--size) * 0.5 + (var(--rot) * 2 * var(--size)));
        border-radius: calc(var(--size) * 0.125);
      }

      .x-wave,
      .y-wave,
      .xy-wave {
        position: relative;
        width: var(--size);
        height: var(--size);
      }

      .circle,
      .x-bar,
      .y-bar {
        position: relative;

        &:before {
          content: '';
          position: absolute;
          top: var(--top);
          left: var(--left);
          height: calc(var(--size) / 32);
          width: calc(var(--size) / 32);
          background-color: #fcecc9;
          border: var(--border) solid var(--color);
          border-radius: 50%;
          transform: translate(-50%, -50%);
          z-index: 1;
        }

        &:after {
          content: '';
          position: absolute;
        }
      }

      .x-bar,
      .y-bar {
        --length: calc(var(--gap) + ((1 - var(--dim)) * var(--size)));
        --width: var(--border);

        &:after {
          background-color: var(--color);
        }
      }

      @keyframes x {
        from {
          --x: 0;
        }
        to {
          --x: 1;
        }
      }

      @keyframes y {
        from {
          --y: 0;
        }
        to {
          --y: 1;
        }
      }

      @keyframes rot {
        from {
          --rot: 0;
        }
        to {
          --rot: 1;
        }
      }

      @property --x {
        syntax: '<number>';
        inherits: true;
        initial-value: 0.5;
      }

      @property --y {
        syntax: '<number>';
        inherits: true;
        initial-value: 0;
      }

      @property --rot {
        syntax: '<number>';
        inherits: true;
        initial-value: 0;
      }
    </style>
  </head>
  <body>
    <div class="grid">
      <div class="circle"></div>
      <div class="x-bar"></div>
      <div class="x-wave"></div>
      <div class="y-bar"></div>
      <div class="y-wave"></div>
      <div class="xy-wave"></div>
    </div>
  </body>
</html>