ラベル Canvas の投稿を表示しています。 すべての投稿を表示
ラベル Canvas の投稿を表示しています。 すべての投稿を表示

2014年11月3日月曜日

Canvasによる簡易アニメーションの実装。とりあえず定番のピンポンでも。

Canvasによる単純な図形の描画

前回の記事に引き続き、今回はCanvasを用いて簡単なアニメーションを表示してみます。
定番(?)のピンポン的なあれを、JavaScript的なオブジェクト指向(で良いのでしょうか。。。)で書いてみました。

ちなみにこれまでPythonやJavaを書く機会があったのですが、PythonやJavaScriptの紳士協定的なプライベート変数の扱い方でもそれほど問題を感じていません。私は先頭にアンダースコアをつけたい派です(今回は個人的なお絵かきなので省略)。Pythonから流れてきているので。

特にマシンの性能がばらばらというウェブ上で数字を求める時なんかは、クロージャを使ってメモリ圧迫する可能性を考慮しながら実装するのは骨が折れますし。

ただ、実装者のレベルがまちまちかつ、大規模開発環境だと、Javaのきっちり感はやはり有難かったですね。

さてさて、前回はonloadを用いて、ページ読み込み時に描画していましたが、今回はJQueryを利用してボタンをつけました。

Canvas

アニメーションのポイントは、描画処理を以下のようにsetIntervalで書いてあげることです。

timer = setInterval(draw, 10);

今回の処理をまとめると、おおよそ以下の動きとなります。

①クリックイベントが発生。

②ボールのオブジェクトを作成し、そこにサイズや速度などの情報を格納。それをランダム個作成
し、配列に格納。

③配列をループ処理し、それぞれの位置を変更。

やっていることはこれだけです。その際、clearRectを使って毎回画面をリセットする必要があります。

壁でバウンドする処理は、壁に到達した際に方向を変えることで表現しています。ボールの位置がキャンバスの幅をはみ出る値に達した場合、speed(速度と方向を意味する変数です)に-1をかけることで、逆向きにします。

if(this.locX < 0 || this.locX > canvasW){
this.speedX *= -1;
}

以下が今回のソースです。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>Canvas</title>
    <style>
        canvas{
          border: solid 2px;
          background-color:rgba(0,0,0);
          margin-bottom: 5px;
        }
        button{
          margin-left: 5px;
          border-radius: 20px;
          background-color: rgba(127,181,224,0.5);
          width: 80px;
          height:30px;
          padding: 4px;
          font-size: 16px;
          text-shadow: 0, 1px, 0 rgba(0,0,0,0.5);
        }
    </style>
</head>
<body>
    <div class="container">
        <canvas id="anime" width=480 height=360></canvas>
        <div>
            <button id="play">Start</button>
            <button id="clear">Stop</button>
        </div>
    </div><!--container-->
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
    <script>
        var timer;
        var nowPlaying = false;
 
        var canvasW = 480;
        var canvasY = 360;
 
        var point = new Point(canvasW,canvasY);
 
        var ball_nums;
        var balls;
 
        $(function(){
            $('#play').click(function(){
                if (nowPlaying) return;
                init();
                nowPlaying = true;
                timer = setInterval(draw, 10);
            });
            $('#clear').click(function(){
                clearInterval(timer);
                init();
                clear();
                nowPlaying = false;
            });
        });
 
        //initialize the canvas
        function clear(){
            var canvas = document.getElementById("anime");
            //old browser does not support canvas. Avoid error.
            if (canvas.getContext){
                var context = canvas.getContext('2d');
                context.clearRect(0,0,canvasW,canvasY);
            }
        }
 
        function draw(){
            var canvas = document.getElementById("anime");
            //old browser does not support cavas. Avoid error.
            if (canvas.getContext){
                var context = canvas.getContext('2d');
                paint(context);
            }
        }
 
        //create ball objects
        function init(){
            ball_nums = Math.floor(Math.random() * 500);
            balls = [ball_nums];
            for(i = 0; i < ball_nums; i++){
                balls[i] = new Ball();
            }
        }
 
        function paint(context){
            //overwrite canvas
            context.globalCompositeOperation = "source-over";
 
            /* This makes canvas dark */
            //context.fillStyle = "rgba(10,10,8,0.2)";
            //context.fillRect(0, 0, canvasW, canvasY);
 
            //refresh the canvas
            context.clearRect(0,0,canvasW,canvasY);
 
            //This allows objects to merge, for example if there are blue and yellow,
            //it turns to be green.
            context.globalCompositeOperation = "lighter";
 
            for (i = 0; i < ball_nums; i++){
                balls[i].relocate();
 
                context.beginPath();
                context.fillStyle = balls[i].color;
                context.arc(balls[i].locX, balls[i].locY, balls[i].radius, 0, Math.PI*2.0, true);
                context.fill();
            }
        }
 
        //each ball object. locations change with being added each speed.
        function Ball(){
            this.speedX = Math.random() * 5;
            this.speedY = Math.random() * 5;
            this.locX = point.randomX();
            this.locY = point.randomY();
            this.color = randomColor();
            this.radius = Math.random() * 20;
        }
 
        Ball.prototype.relocate = function(){
            //relocate
            this.locX += this.speedX;
            this.locY += this.speedY;
 
            //to other way when this reaches a wall
            if(this.locX < 0 || this.locX > canvasW){
                this.speedX *= -1;
            }
            if(this.locY < 0 || this.locY > canvasY){
                this.speedY *= -1;
            }
        };
 
        function randomColor(){
            var r = Math.floor(Math.random() * 256);
            var g = Math.floor(Math.random() * 256);
            var b = Math.floor(Math.random() * 256);
            var a = Math.random();
            return 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')';
        }
 
        //For getting a random point on the canvas
        function Point(canvas_width, canvas_height){
            this.x = canvas_width;
            this.y = canvas_height;
        }
        Point.prototype.randomX = function(){
            return Math.random() * this.x;
        };
        Point.prototype.randomY = function(){
            return Math.random() * this.y;
        };
    </script>
  </body>
</html>

2014年10月31日金曜日

Canvasによる単純な図形の描画

HTML5とJavaScriptを連携させることで、簡単に描画することの出来る機能Canvasについて、メモを残しておきます。

詳細な仕様は以下のサイトで確認できます。
W3schools.com

drawing
まずはHTMLです。わかりやすいように、canvasの枠線だけ指定しています。
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>drawing</title>
    <style>
    canvas{
     border: solid;
    }
    </style>
  </head>
  <body onload="draw();">
      <canvas id="paint" width="400" height="300"></canvas>
      <script src="/myscript.js"></script>
  </body>
</html>

HTMLは非常にシンプルです。
①canvasタグにidとcanvasのサイズを指定する。

②bodyタグ内にonload=draw();と記載しておく。

このメソッド名は任意のもので構いません。要はJavaScriptと整合性が取れていれば良いというわけです。


やったこと

今回は、canvas内にランダムに複数の三角形を書き込む処理を書いてみました! 実際の例は本文の最後に乗せておきます。

以下、JavaScriptのコードになります。ちょっと長いですが、コメントの通りのことしかやっておりませんので、それほどややこしくはないです!

myscript.js
//これがHTMLから呼び出されるメソッドです
function draw(){
    //canvasに設定したidを元に、canvasのオブジェクトを生成します。
    var canvas = document.getElementById('paint');
    //古いブラウザーではcanvasが実装されていないため、チェックしておきます。
    if (canvas.getContext){
      //今のところ2Dしか実装されていませんが、contextを作成します。
      //描画に関する設定はこのオブジェクトを使用して指定します。
      var ctx= canvas.getContext('2d');
      //ちょっと長くなるので、paintメソッドを定義しました。
      paint(context);
    }
}

function paint(ctx){
    //Pointクラスはcanvas内のランダムな座標を取得するために定義しました。
    point = new Point(400, 300);
    //70回くらい図形を描きます。
    for(i = 0; i < 70; i++){
        //opacityです。0.0-1.0で指定するため、以下の関数で上手くいきます。
        ctx.globalAlpha = Math.random();
        //描画の開始を宣言します。
        ctx.beginPath();
        //このメソッドは図形の色をランダム指定するために定義しました。
        //線に色を付けたい場合は、strokeStyleに色を指定します。
        ctx.fillStyle = randomColor();
        //開始地点の座標です。座標はcanvasの左上から計算します。
        ctx.moveTo(point.randomX(), point.randomY());
        //二つ目の座標です。
        ctx.lineTo(point.randomX(), point.randomY());
        //三つ目の座標です。三角形ができました。
        ctx.lineTo(point.randomX(), point.randomY());
        //描画します。
        //線の場合はstroke()メソッドを使います。
        ctx.fill();
    }

//ランダムに色を取得するためのメソッドです。
function randomColor(){
    var r = Math.floor(Math.random() * 256);
    var g = Math.floor(Math.random() * 256);
    var b = Math.floor(Math.random() * 256);
    return 'rgb(' + r + ',' + g + ',' + b + ')';
}

//クラスっぽく作りました。
function Point(canvas_width, canvas_height){
    //キャンバスのサイズを取得しておきます。
    this.x = canvas_width;
    this.y = canvas_height;

    //x座標です。
    this.randomX = function (){
      return Math.random() * this.x;
    }
    //y座標です。
    this.randomY = function(){
      return Math.random() * this.y;
    }
}

思った以上に簡単に描画ができました! ちなみに曲線の描画には

arc(始点x, 始点y, 半径, 始点の角度, 終点の角度, 回る方向)

四角形には

fillRect(始点x, 始点y, 終点x, 終点y)

を使います。もちろんcontext.はお忘れなく。