michimani.net

CSS だけで正弦曲線を描いてみる

2019-01-28

CSS だけでアニメーションを描画することができるということで、前回は単位円を描く点のアニメーションを作成しました。

今回はその続きというか、応用というか、正弦曲線を描く点のアニメーションを作成してみます。

正弦曲線

その名の通り、正弦関数によって表される曲線で、式にすると

$${y} = \sin({x})$$

で表される曲線のことです。

描いてみた

正弦曲線は周期を持つ曲線なので、今回は以下の条件で表される曲線を描く点のアニメーションを作成してみます。

$${y} = \sin({x}), -\pi \leq {x} \leq \pi$$

※以下、正弦曲線 "風" というイメージでご覧ください


html, css

まず、次のような HTML 要素と、それに対するスタイルを用意しておきます。

<div id="graph-area">
    <div id="dot" class="sinx"></div>
    <hr id="x-axis" class="axis"></hr>
    <hr id="y-axis" class="axis"></hr>
</div>
#graph-area {
    position: relative;
    height: 320px;
    margin: 50px 0px 50px calc(50% - 160px);
    width: 320px;
}
.axis {
    border: 0.5px solid #959595;
    margin: 0px;
    position: absolute;
    width: 100%;
    top: 160px;
}
#x-axis {
}
#y-axis {
    transform: rotate(90deg);
}
#dot {
    border-radius: 50%;
    height: 10.5px;
    left: -46px;
    position: absolute;
    top: 155px;
    width: 10.5px;
    z-index: 100;
    background-color: #000000;
}
#dot.sinx {
    animation-duration: 1500ms;
    animation-fill-mode: forwards;
    animation-iteration-count: infinite;
    animation-name: drawSin;
}

前回と同様に、アニメーションとして drawSin という名前で keyframe を定義します。

@keyframes drawSin {
    0% {
        left: 29px;
        top: 155.0px;
    }
    2.0% {
        left: 34px;
        top: 174.499px;
    }
    4.0% {
        left: 39px;
        top: 193.708px;
    }
    6.0% {
        left: 44px;
        top: 212.339px;
    }
/* 途中省略 */
    97.0% {
        left: 274px;
        top: 127.216px;
    }
    99.0% {
        left: 279px;
        top: 146.626px;
    }
    100.0% {
        left: 281px;
        top: 155px;
    }
}

これまた前回と同様に、上の keyframe は下記スクリプトで生成しました。(100% の部分に関してはちょっと手で修正しました)

import math

ACCURACY = 50
BASE_LEFT = 155
BASE_TOP = 155
RADIUS = 160
PER = round(360 / ACCURACY, 0)

percent = 0
rad = 0
style = '@keyframes drawSin {\n'
print('per:', PER)
# -180 <= rad <= 180
while (percent <= 100):
    tmp_rad = rad - 180
    print(tmp_rad)
    x = math.radians(tmp_rad)
    print('sin({}) = {}'.format(x, math.sin(x)))
    top = round(BASE_TOP - math.sin(x) * RADIUS, 3)
    left = round(BASE_LEFT + x * (RADIUS / 4))
    style += '''    {}% {{
        left: {}px;
        top: {}px;
    }}\n'''.format(percent, left, top,)

    rad += PER
    percent = round((rad / 360) * 100, 0)
    print(percent, '%')

style += '}'
keyframe_css = './keyframe.css'
with open(keyframe_css, mode='w') as f:
    f.write(style)

今回は見た目の都合上、 x 軸の値に対して y 軸の値の 1/4 の値としています。(left = round(BASE_LEFT + x * (RADIUS / 4)) の部分)
なので、見た目的には下記のような式に近い形になっています。

$${y} = \sin\left(4{x}\right), -\frac{\pi}{4} \leq {x} \leq \frac{\pi}{4}$$

ひとこと

CSS だけで正弦曲線を描いてみた話でした。
CSS というよりは三角関数の話がメインみたいなところもありますが、計算で各状態での座標の位置さえ決まれば、 CSS だけでも複雑なアニメーションが描けることがわかりました。


comments powered by Disqus