0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【入門者向け】Canvas入門講座#10 円をボタンを押して動かそう【JavaScript】

Last updated at Posted at 2020-11-16

#問題10

中心が(150, 150)、半径50の円を塗りつぶしなさい。
塗りつぶす色はマゼンタ色(#ff00ff)であること。
rightボタン押下時に円がX方向へ-30,leftボタン押下時に円がX方向へ+30移動すること。
なお、以下のHTMLを使うこと。

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>問題10</title>
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script>
$(() => {    
    // ここにプログラムを書く
});
</script>
</head>
<body>
<canvas id="my-canvas" width="500" height="300"></canvas>
<br>
<input id="left-button" type="button" value="right" />
<input id="right-button" type="button" value="left" />
</body>
</html>

#答え

<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>問題10</title>
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script>
$(() => {

    let moveX = 0;

    // 初期表示
    drawCircle(moveX);
    
    $('#left-button, #right-button').on('click', e => {
        if($(e.target).prop('id') === 'left-button') {// left-button がクリックされた
            moveX -= 30;
        } else {// right-button がクリックされた
            moveX += 30;
        }
        drawCircle(moveX);
    });

    function drawCircle(moveX) {
        // コンテキストを取得
        const ctx = $('#my-canvas')[0].getContext('2d');

        // 現在の描画状態を保存する
        ctx.save();
        
        // canvasをクリア
        ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);

        // 塗りつぶしの色をマゼンタ色にする
        ctx.fillStyle = '#ff00ff';

        ctx.beginPath();        // 現在のパスをリセットする
        ctx.arc(150 + moveX, 150, 50, 0, Math.PI*2, true); // 円を描画する
        ctx.closePath();        // パスを閉じる
        ctx.fill();           // 現在のパスを塗りつぶす

        // 描画状態を保存した時点のものに戻す
        ctx.restore();
    }
});
</script>
</head>
<body>
<canvas id="my-canvas" width="500" height="300"></canvas>
<br>
<input id="left-button" type="button" value="left" />
<input id="right-button" type="button" value="right" />
</body>
</html>

円が移動しました!
image.png

#解説
円がどれだけ動いたか変数で保持します。

let moveX = 0;

まず円を描画します。今回は円の描画を関数にしてあります。

// 初期表示
drawCircle(moveX);

ボタンクリックをまとめてハンドリングします。
left-button がクリックされたら、moveXを-30します。
right-button がクリックされたら、moveXを+30します。

$('#left-button, #right-button').on('click', e => {
    if($(e.target).prop('id') === 'left-button') {// left-button がクリックされた
        moveX -= 30;
    } else {// right-button がクリックされた
        moveX += 30;
    }
    drawCircle(moveX);
});

drawCircleは円を描画する関数です。
引数はmoveXでX方向にどれだけ移動したかを受け取ります。

canvasへ描画する前にclearRectメソッドでcanvasをクリアしています。
これはクリアしないと1つ前の円の描画そのまま残るのを防ぐためです。
clearRectの代わりにfillRectによる塗りつぶしでも構いません。

一般的にcanvasに何かを描画するときは、canvasをクリアした後に、canvasへ描画します。

あと、描画する前にsaveメソッドを、描画が完了した後にはrestoreメソッドを呼ぶようにしたほうが良いです。
saveメソッドは描画情報(塗りつぶしや線の色など)を保存し、restoreメソッドはそれを復元します。

function drawCircle(moveX) {
    // コンテキストを取得
    const ctx = $('#my-canvas')[0].getContext('2d');

    // 現在の描画状態を保存する
    ctx.save();

    // canvasをクリア
    ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);

    // 塗りつぶしの色をマゼンタ色にする
    ctx.fillStyle = '#ff00ff';

    ctx.beginPath();        // 現在のパスをリセットする
    ctx.arc(150 + moveX, 150, 50, 0, Math.PI*2, true); // 円を描画する
    ctx.closePath();        // パスを閉じる
    ctx.fill();           // 現在のパスを塗りつぶす

    // 描画状態を保存した時点のものに戻す
    ctx.restore();
}

#補足

setTransformを使うと変数を描画処理で参照しなくてよいのですっきりします。
今回の問題は描画が単純ですので、このような工夫は必要ありませんが
setTransformは知っててほしいメソッドです。

setTransformは行列を掛けるメソッドです。
平行移動する場合はctx.setTranform(1, 0, 0, 0, x, y);のように呼び出しましょう。

今回のCanvas入門講座ではオブジェクトの変換は平行移動しかしないので、
setTransformの代わりにtranslateでもよいです。

setTranformについて詳しく知りたい方はこちらの記事をお読みください。

以下、drawCircleをsetTransformを使って書き直しました。

function drawCircle(moveX) {
    // コンテキストを取得
    const ctx = $('#my-canvas')[0].getContext('2d');

    // 現在の描画状態を保存する
    ctx.save();
        
    // canvasをクリア
    ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);

    // 塗りつぶしの色をマゼンタ色にする
    ctx.fillStyle = '#ff00ff';

    ctx.setTransform(1, 0, 0, 1, moveX, 0);

    ctx.beginPath();        // 現在のパスをリセットする
    ctx.arc(150, 150, 50, 0, Math.PI*2, true); // 円を描画する
    ctx.closePath();        // パスを閉じる
    ctx.fill();           // 現在のパスを塗りつぶす

    // 描画状態を保存した時点のものに戻す
    ctx.restore();
}
0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?