LoginSignup
3
4

More than 5 years have passed since last update.

canvasで曲線を描いて動かす

Posted at

概要

曲線を描きながら要素を動かすのに色々試したので自分用にメモ

環境

PixiJS v4
pixi.jsをよく使うので。。。
requestAnimationFrameで要素を動かす。

曲線を描くために

基本

今回は、二次関数で波のような動きにする。
学生時代に数学で習ったやつですが、あまり覚えておらず。。。

公式

グラフの頂点が(p,q)である2次関数は下記で表されるようです。

y = a ( x - p )^2 + q

画面端から画面中央を通り、画面端の対偶に移動させたい。
例えば、画面右上から曲線を描いて画面中心に移動し、曲線を描いて左下に移動していく感じ。

計算は割愛します。

右上から左下に移動

index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>波のアニメーション</title>

<!-- JS -->
<script src="scripts/lib/jquery-1.11.1.min.js"></script>
<script src="scripts/lib/pixi.min.js"></script>
<script src="scripts/script.js"></script>

</head>

<body>

<div id="word"></div>

</body>
</html>

いたって普通だと思います.

パターン1

script.js
$(() => {
    // AnimationFrame Prefix
    const animationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.setTimeout;
    const cancelAnimationFrame = window.cancelAnimationFrame || window.mozcancelAnimationFrame || window.webkitcancelAnimationFrame || window.mscancelAnimationFrame;

    const render = () => {            
        // Canvas Size
        const width = window.innerWidth;
        const height = window.innerHeight;
        $('#canvas').attr( 'width', width );
        $('#canvas').attr( 'height', height );

        // Canvas Settings
        const stage = new PIXI.Container();
        const renderer = PIXI.autoDetectRenderer( width, height, { antialias: true, transparent: true } );
        document.getElementById( 'word' ).appendChild( renderer.view );

        const draw = () => {
            // Words Settings
            const themeWord = '';
            const themeStyle = { font: '40pt YuMincho', fill: '#000' };
            const themeTxt = new PIXI.Text( themeWord, themeStyle );
            themeTxt.position.x = width;
            themeTxt.position.y = 0;
            themeTxt.anchor.x = 0.5;
            themeTxt.anchor.y = 0.5;
            themeTxt.alpha = 1;

            // Slope Settings 
            const first_slope = 2 / Math.pow( width, 2 ) * height;
            const secound_slope =  -( 2 * height / Math.pow( width, 2 ) );

            stage.addChild( themeTxt );

            // Word Animation
            const wordAnimate = () => {
                themeTxt.position.x -= 3;

                if( themeTxt.position.x > width / 2 ){
                    const first_exponential = themeTxt.position.x - width;
                    themeTxt.position.y = first_slope * Math.pow( first_exponential, 2 );
                }
                if( themeTxt.position.x < width / 2 ){
                    const secound_exponential = themeTxt.position.x
                    themeTxt.position.y = secound_slope * Math.pow( secound_exponential, 2 ) + height;
                }
                if( themeTxt.position.x <= 0 ){
                    themeTxt.position.x = width;
                }
                renderer.render( stage );
                requestAnimationFrame( wordAnimate );
            }
            wordAnimate();
        }
        draw();
    }

    const init = () => {
        render();
    }

    init();
});

ざっくり書きましたが、Slope Settingsの箇所とexponentialを組み合わせてthemeTxt .position.yを変更させています。
画面中央に来たときに二次関数の式を変更させて曲線を描いています。
一度で描ける式が思い浮かばなかったので、数学に詳しい方教えてください。

これで動かしてみると
1.gif

こんな動きになりました。

パターン2

頂点と傾きを変更して計算してみます。

script.js
// Slope Settings 
const first_slope = -2 * height / Math.pow( width, 2 );
const secound_slope =  2 * height / Math.pow( width, 2 );

// Word Animation
const wordAnimate = () => {
    themeTxt.position.x -= 3;

    if( themeTxt.position.x > width / 2 ){
        const first_exponential = themeTxt.position.x - ( width / 2 );
         themeTxt.position.y = first_slope * Math.pow( first_exponential, 2 ) + ( height / 2 );
    }
    if( themeTxt.position.x < width / 2 ){
        const secound_exponential = themeTxt.position.x - ( width / 2 );
        themeTxt.position.y = secound_slope * Math.pow( secound_exponential, 2 ) + ( height / 2 );
    }
    if( themeTxt.position.x <= 0 ){
        themeTxt.position.x = width;
    }
    renderer.render( stage );
    requestAnimationFrame( wordAnimate );
}
wordAnimate();

主な変更箇所だけ記述しました。

こうすると、
2.gif

傾き方が変わりました。

左上から右下に移動

始点を変えてみます。

パターン1

script.js
const draw = () => {
    // Words Settings
    const themeWord = '';
    const themeStyle = { font: '40pt YuMincho', fill: '#000' };
    const themeTxt = new PIXI.Text( themeWord, themeStyle );
    themeTxt.position.x = 0;
    themeTxt.position.y = 0;
    themeTxt.anchor.x = 0.5;
    themeTxt.anchor.y = 0.5;
    themeTxt.alpha = 1;

    // Slope Settings 
    const first_slope = 2 * height / Math.pow( width, 2 );
    const secound_slope =  -2 * height / Math.pow( width, 2 );

    stage.addChild( themeTxt );

        // Word Animation
    const wordAnimate = () => {
        themeTxt.position.x += 3;

        if( themeTxt.position.x < width / 2 ){
            const first_exponential = themeTxt.position.x;
            themeTxt.position.y = first_slope * Math.pow( first_exponential, 2 );
        }
        if( themeTxt.position.x > width / 2 ){
            const secound_exponential = themeTxt.position.x - width;
            themeTxt.position.y = secound_slope * Math.pow( secound_exponential, 2 ) + height;
        }
        if( themeTxt.position.x >= width ){
            themeTxt.position.x = 0;
        }
        renderer.render( stage );
        requestAnimationFrame( wordAnimate );
    }
    wordAnimate();
}
draw();

最初の始点の指定やxを増加させているところも変えました。

3.gif

左上からになりました。

パターン2

今までと同様に

script.js
const draw = () => {
    // Words Settings
    const themeWord = '';
    const themeStyle = { font: '40pt YuMincho', fill: '#000' };
    const themeTxt = new PIXI.Text( themeWord, themeStyle );
    themeTxt.position.x = 0;
    themeTxt.position.y = 0;
    themeTxt.anchor.x = 0.5;
    themeTxt.anchor.y = 0.5;
    themeTxt.alpha = 1;

    // Slope Settings 
    const first_slope = -2 * height / Math.pow( width, 2 );
    const secound_slope =  2 * height / Math.pow( width, 2 );

    stage.addChild( themeTxt );

        // Word Animation
    const wordAnimate = () => {
        themeTxt.position.x += 3;

        if( themeTxt.position.x < width / 2 ){
            const first_exponential = themeTxt.position.x - ( width / 2 );
            themeTxt.position.y = first_slope * Math.pow( first_exponential, 2 ) + height / 2;
        }
        if( themeTxt.position.x > width / 2 ){
            const secound_exponential = themeTxt.position.x - ( width / 2 );
            themeTxt.position.y = secound_slope * Math.pow( secound_exponential, 2 ) + height / 2;
        }
        if( themeTxt.position.x >= width ){
            themeTxt.position.x = 0;
        }
        renderer.render( stage );
        requestAnimationFrame( wordAnimate );
    }
    wordAnimate();
}
draw();

4.gif

傾き方が変わりました。

まとめ

二次関数を駆使して曲線を描くことができました。
同じようにすれば下から上に移動するのもできそうです。
どちらかというと数学の問題ですね。
学生のときはピンと来ませんでしたが、こうしてみると少し数学が楽しくなるかもしれません。

3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4