[69-6] canvasにマウスの動きに合わせて描画しよう (クリックやマウスムーブとの組み合わせと Math.random)

<canvas>要素に関するここまでの記事は、単にカンバス上に画像を描画するだけでした。
まあ基礎をやっているので、仕方が無いんですが。これだと<img>要素で画像を貼っても同じかも。
でも、<canvas>って Javascript を使うので、本来はもっと「動的」な描画をするモノだと思うんですよ。クリックしたタイミングで描画するとか。

そこで、マウスの動作でどうやって描画するんだろう...と調べてサンプルを作ってみました。
ですので今回は、<canvas>の基礎からちょっとはずれます。基礎ばっかりでだいぶ飽きちゃいましたからw

今回のサンプルはこちら。
クリックで別ウィンドウで開きます。

私は Javascript の基礎がまったく無いので、試行錯誤してこの程度ですが、プロの方はもっといろんなことが<canvas>で出来るんでしょうね。「お絵描きソフト」とか作れそう。

<canvas>の可能性ってスゴいと思うんですよ。IllustratorやPhotoshopなどの高価なソフトを持っていなくても、Javascriptの知識とセンスさえあれば、<canvas>上でいろんな描画ができ、それ以上の動的表現ができるのですから。

私のような Javascript がサッパリのデザイナーでも Math.random は覚えておくべき。
これは乱数をゲットするメソッドで、ランダムな位置・カタチ・色などで描画できます。
FlashのActionScriptでもよく使いました。このマス・ランダム。
サイトの背景にランダムにパターンを描画するのは、コレを使うんだなと思い、Flaの時には適当に使っていたのですが、今回まじめに調べてメモっておきました。

本日のINDEX
  1. ボタンクリックでランダムな位置に描画する
    1. キャンバス上の x, y 座標をランダムに指定する
    2. Math.random() について
    3. 複数の色指定を適用する
  2. クリックした位置に描画する
    1. addEventListener() でclickイベントを登録する
    2. getBoundingClientRect() でキャンバスの座標をゲットして、クリック位置を取得
    3. 複数の色指定をランダムに適用する
    4. クリック位置に描画させる
  3. マウスムーブで描画する
    1. addEventListener() でmousemoveイベントを登録する
    2. 複数の半径をランダムに適用する

ボタンクリックでランダムな位置に描画する

サンプル1は、カラー名のボタンをクリックすると、
キャンバス上のランダムな位置に、グラデーションの円形が描画されます。

HTMLはこちら。<canvas>の背景は、CSSで黒にしています。

<p>クリックしてください→
<input type="button" value="Orange" onclick="draw1(1)">
<input type="button" value="Green" onclick="draw1(2)">
<input type="button" value="Yellow" onclick="draw1(3)">
</p>
<canvas id="canvas1" class="bk" width="678" height="150">
<p>お使いのブラウザはcanvas要素に対応していないので描画できませんでした</p>
</canvas>
<input type="button" value="クリア" onclick="clear1()">

ボタン(ここでは<input>要素を使っていますが、テキストでも画像でもなんでもOK)をクリックして使うので、
onload イベント(ページがロードされたタイミングで適用する)ではなく、
ボタンの onclick イベント(2,3,4行目)を使っているのが、前回までの使い方と違うところです。

キャンバス上の x, y 座標をランダムに指定する

x, y座標をランダムに設定するために「Math.random()」というメソッドを使っています。

/*描画のためのx,yをランダムにつくる*/
    var x = Math.round(Math.random()*678);
    var y = Math.round(Math.random()*150);
/*〜中略〜*/
/*正円を描画*/
    ctx.beginPath();
    ctx.fillStyle = gra;
    ctx.arc(x, y, 100, 0, Math.PI*2, false);
    ctx.fill();

2行目で ランダムなx座標を「変数x」に、3行目で ランダムなy座標を「変数y」に代入しています。
その変数xとyを8行目の、正円の中心点の x, y座標に利用しているため、ランダムな場所に円が描かれる仕組みです。
ココに数字を(ctx.arc(70, 70, 100, 0, Math.PI*2, false); とか)書く代わりに、変数xと変数yを書いています。

「Math.random()」に678や150という数値をかけていますが、
これはこのキャンバスの横幅(678px)と高さ(150px)です。
この式を「Math.round()」の中に入れたりしていますが、これは「Math.random()」の特徴のせい。
この件は次項へ↓。

Math.random() について

「Math.random()」は、Mathオブジェクトの「メソッド」の1つで、
0から1未満の範囲で、ランダムな数値(乱数)をゲットします。
変数に数値型として「Math.random()」と書いた時点で、乱数が変数に代入されるんですって。
(例:変数a なら、var a = Math.random(); で、変数aに乱数が代入されます。)

ここで発生する乱数は「1未満」なのがミソ。要するに小数です。 「浮動小数点数」と言うんだそうです。
とにかく、0.000...から 0.999...までの範囲で乱数が発生するわけです。
なので、乱数を「1以上の数」または「整数」として使いたい場合は、ひと工夫必要です。

●1から10の乱数にしたいとき、10をかけて1を足す
発生した乱数は、0.000...から0.999...の数値なので、10をかけます
そうすると、0.000...から9.999...という数値になります。
まだ10に足りないので、1を足してみます。これで 1.000...から10.999...になりました。

●0から10の乱数にしたいとき、10+1をかける。または四捨五入しちゃえ
座標だと、x,y が、0,0 ってこともあるわけで、1からじゃまずいです。
0から10の乱数が欲しいときは、10+1をかければいいわけです。
発生した乱数が、0.000...から0.999...なので、11をかければ、0.000...から10.999...になるわけで。

または、小数点以下が不用なら、10をかけて四捨五入してもOK。サンプル1はこの方法です。

●整数にしたいとき、「Math.floor()」で切り捨てるか、「Math.round()」で四捨五入する
小数点以下がジャマなときは、他の「Math.メソッド」を併用します。
「Math.floor()」は小数点以下切り捨て。Math.floor(n) で n の小数点以下を切り捨てます。
「Math.round()」は四捨五入。Math.round(n) で n を四捨五入します。

ちなみに、
「Math.ceil()」は小数点以下切り上げ、
「Math.abs()」は絶対値を返します。
 *絶対値とは0からどんだけ離れてるかの値。-10の絶対値は10。Math.abs()はマイナスを取りたい時に便利。

●幅678、高さ150pxのキャンバス内でのランダムな座標
というわけで、キャンバス内のx, y座標を、ランダムな整数にしたい場合は、
発生した乱数に、「キャンバスの横幅」または「高さ」をかけて、Math.round() で四捨五入します。

    var x = Math.round(Math.random()*678);
    var y = Math.round(Math.random()*150);

これで、x座標は0から678まで、y座標は0から150までの乱数がゲットできました。

複数の色指定を適用する

このサンプルは、ボタンの onclickイベントで、draw1(g)という関数を呼び出し、
draw1(1)でオレンジ色、draw1(2)でグリーン、draw1(3)でイエローの「色」を適用します。
引数gが、1,2,3と替わる仕組みをソースで見てみましょう。
(引数gは任意に。ここではグラデーションなのでgにしました)

function draw1(g) {
    var cnvs = document.getElementById('canvas1');
    var ctx = cnvs.getContext('2d');
/*描画のためのx,yをランダムにつくる*/
    var x = Math.round(Math.random()*678);
    var y = Math.round(Math.random()*150);
/*グラデーションを3種類つくる*/
    var grad1  = ctx.createRadialGradient(x,y,0,x,y,100);
    grad1.addColorStop(0,'rgba(255,147,38,1)');
    grad1.addColorStop(1,'rgba(255,147,38,0)');
    var grad2  = ctx.createRadialGradient(x,y,0,x,y,100);
    grad2.addColorStop(0,'rgba(92,255,38,1)');
    grad2.addColorStop(1,'rgba(92,255,38,0)');
    var grad3  = ctx.createRadialGradient(x,y,0,x,y,100);
    grad3.addColorStop(0,'rgba(255,255,115,1)');
    grad3.addColorStop(1,'rgba(255,255,115,0)');	
/*引数「g」に各グラデを指定*/
    var gra;
    if (g == 1) gra = grad1;
    if (g == 2) gra = grad2;
    if (g == 3) gra = grad3;
/*正円を描画*/
    ctx.beginPath();
    ctx.fillStyle = gra;
    ctx.arc(x, y, 100, 0, Math.PI*2, false);
    ctx.fill();
}

先にグラデーションを3つ作っておきます。(8行目から16行目まで)
変数grad1で、オレンジ色の(8〜10行目)、
変数grad2にはグリーンの(11〜13行目)、
変数grad3にはイエローの(14〜16行目)グラデーションを指定しています。
それぞれ、乱数で取得した 変数x、yをグラデーションの中心点に利用しています。
これでクリックしたところを中心点にしたグラデーションができるわけです。

次に、変数graを新たに作り、これを利用して、
この関数「draw1(g)」の引数gが、
もしも g==1(gが1と同一)だったら、変数graは grad1(オレンジのグラデ)
もしも g==2 だったら、変数graは grad2(グリーンのグラデ)
もしも g==3 だったら、変数graは grad3(イエローのグラデ)
と設定します。(18〜21行目)

で、最後の色指定のところで(24行目)、円のfillStyleに 変数gra を指定します。
この後、乱数で取得した 変数x、yを中心点にした正円を描く指定をすれば完了です。

クリックした位置に描画する

サンプル2は、キャンバス上をクリックして、その地点に描画されるようにします。
ということは、クリックした座標をゲットする必要があります。

addEventListener() でclickイベントを登録する

●イベントとは

JavaScript の「イベント」は、どのタイミングで○○させるかを指定するためのもの。○○は関数です。
ユーザがページや要素などを操作したときに、イベントが起こります。
これまで出てきた load(ロード完了時)や click(クリック時)などがイベントです。

マウスやキーボードの操作に関係あるイベントには、他に下記のものがあります。
mousemove(ポインタが移動する時)、 mousedown(マウスを押した時)、 mouseup(マウスボタンを離した時)、
mouseover(ロールオーバー時)、 mouseout(ロールアウト時)、 dragdrop(ドラッグ&ドロップ時)、
scroll(スクロール時)、 dblclick(ダブルクリック時)、
keydown(キーを押してる間)、 keypress(キーを押した時)、 keyup(キーを離した時)。
(他にページの読み込みやフォームに関する abort, unload, error, submit, reset, change,, resize, blur, focus などがあります)

●addEventListener() は何度でもイベントや関数を登録できる

イベントが起こった時に関数が動くようにするには、
ボタンなどの要素に「onclick」で指定する方法をサンプル1でやりましたが、
このサンプルでは「addEventListener() 」を使ってみました。
「addEventListener() 」は、複数書いて、エレメントに何度でもイベントと関数を登録できるのが利点なのだそうです。書いた順番で実行されます。(今回は、1つだけしか使いませんけどね。)

それに比べて onclick など、HTMLのイベント属性(または script内のイベントプロパティ)は、
複数書くと、前のものを後から書いたものが上書きして、1コしか使えません。

●addEventListener() の3つの引数

サンプル2のイベントリスナー登録の部分を見てみると、

function draw2() {
    var cnvs2 = document.getElementById('canvas2');
    var ctx2 = cnvs2.getContext('2d');
    /*イベントリスナー登録_イベントはclickに*/
    cnvs2.addEventListener('click', onClick, false);
    function onClick(e) {
    /*この部分に関数「onClick()」の内容を書きます*/
    };
}

addEventListener() の () 内に、3つの引数があるのが分かります。
第1引数は「イベントタイプ」
上で紹介したイベント名を書きます。この場合は 'click' にしています。
第2引数は「イベントリスナー」
ここには呼び出す関数名を書きます。サンプルでは「onClick」という関数名を登録しています。
第3引数はとりあえず false でOK
これは「フェーズ」という、イベントが伝わって行く順番と言うか方法を決める引数だそうです。
真偽値 true か false の2択で、デフォルトは false。
trueなら「Captureフェーズ」
falseなら「Targetフェーズ」か「 Bubblingフェーズ」
だそうですが、フェーズについての理解があやふやなので、説明は割愛します(謝)。
とりあえず false(Captureフェーズにしない)でOKみたい。今回のところは。

なお、この第3引数は省略可能だそうですが、(デフォルトが false なので、省略すると falseになる)
古めのブラウザだと、第3引数が省略されているとエラーになるそうなので、ちゃんと false と書いといたほうが良さそう

さて、これで「canvas2」というID名の<canvas>要素に、
クリックで「onClick」という名前の関数を実行する準備ができました。

getBoundingClientRect() でカンバスの座標をゲットして、クリック位置を取得

これから「onClick」という名前の関数を書いて行きます。
まず、キャンバスをクリックした位置の座標をゲットしなくてはなりません。

●getBoundingClientRect() でキャンバスの座標情報をゲット

「getBoundingClientRect() 」を使うと、要素の絶対座標値を取得する事ができます。
BoundingClientRect とは、囲まれた(Bounding)領域のボックス情報...といった意味。
ボックスの「幅、高さ、ブラウザウィンドウの左上からの距離」のx,y座標を取得します。

ソースの8行目で「e.target.getBoundingClientRect();」として、
この指定のターゲットのキャンバス( ID名 canvas2 )の領域の座標を取得して、
これを var rect(変数「rect」)に代入しています。
(引数はべつに e じゃなくても何でもOK。ここではイベントの e にしました。)

    function onClick (e) {
      /*このキャンバスの絶対座標値をゲットして、マウスの位置を取得*/
      var rect = e.target.getBoundingClientRect();
      var mouseX =  Math.round(e.clientX - rect.left);
      var mouseY =  Math.round(e.clientY - rect.top);
      /*このあと、色指定を作ります*/
      };

次に、(上のソースの ↑ 9行目と10行目)
変数「mouseX」と変数「mouseY」にキャンバス上をクリックした座標を代入します。
これには「clientX」「clientY」を利用します。

●clientX clientX からキャンバス上のクリック位置を割り出す

「client(クライアント)」とはブラウザの「ウィンドウ」のこと。
clientX は、イベントが発生したときのブラウザウィンドウのx座標、
clientY は、y座標の値を表します。

というわけで、
clientX から、先ほど取得した変数rect(キャンバスの座標情報)のうち、左側の空き(rect.left)を引くことで、キャンバス上のクリックされた x座標がわかります。
同じく clientY から、キャンバスの上の空き(rect.top)を引けば、キャンバス上の y座標がゲットできるってわけです。

このままでは、x, y座標に小数点以下の数字が含まれた状態なので(ブラウザによっては小数でもOKらしいけど)、一応、Math.round() の中にぶっ込んで、四捨五入しています。

これで、ID名 canvas2 のキャンバス上をクリックしたら、その座標がゲットできるようになりました。

複数の色指定をランダムに適用する

あとは、グラフィクスの描画をするだけですが、
その前に、Math.random() を使って、色をランダムに適用するようにしてみました。
(サンプル1では「位置」がランダムでしたが、今回はその応用です)

      /*色指定を5種類作ってランダム化する*/
      var color1 = '#f00';
      var color2 = '#ffeb00';
      var color3 = '#f0f';
	  var color4 = '#0096ff';
	  var color5 = '#0f0';
      var clr = Math.floor(Math.random()*5+1);
      var thisColor;
      if (clr == 1) thisColor = color1;
      if (clr == 2) thisColor = color2;
      if (clr == 3) thisColor = color3;
	  if (clr == 4) thisColor = color4;
	  if (clr == 5) thisColor = color5;
      /*色指定と、正円の描画*/
	  ctx2.globalAlpha = 0.2;
      ctx2.fillStyle = thisColor;
      ctx2.beginPath();
      ctx2.arc(mouseX,mouseY,40,0,Math.PI*2,false);
      ctx2.fill();

変数 color1〜5 まで、5種類の色指定をします。(12〜16行目)

変数 clr に、1から5までの乱数を Math.random() で発生させます。(17行目)
乱数は0.000...から0.999...の範囲なので、5をかけて1足せば、1.000...から5.999...になります。
これを Math.floor() に入れて、小数点以下を切り捨てれば、1から5までの乱数になるわけです。

次に、変数 thisColor っていうのを決めて、
もしも clr==1(clrが1と同一)だったら、変数thisColorは color1(#f00)
といった具合で、5色をランダムに割り当てた thisColor を作ります。

で、描画の前の色指定で「ctx2.fillStyle = thisColor;」(26行目)とすればOK。
コレの前に「ctx2.globalAlpha = 0.2;」(25行目)として、透明度を20%にしています。

クリック位置に描画させる

上のソースの28行目を見てください。
正円の x座標, y座標を書くところに、変数 mouseX、mouseY を指定しています。
これでOK。変数 mouseX、mouseY は、キャンバス上のクリックされた座標ですから、
ここを中心点にして円が描かれます。

マウスムーブで描画する

サンプル3は、キャンバス上で「マウスを動かす(mousemove)」と描画するようにしました。
サンプル1、サンプル2 の応用です。

addEventListener() でmousemoveイベントを登録する

addEventListener() の第1引数で「mousemove」を指定すれば、マウスポインタが移動している時に関数を実行することができます。
addEventListener() についてはサンプル2で詳細を説明しています。

ソースを見てみましょう。
5行目で、addEventListener() で「mousemove」イベントで「onMove」という関数を実行するよう指定しています。

function draw3() {
    var cnvs3 = document.getElementById('canvas3');
    var ctx3 = cnvs3.getContext('2d');
    /*イベントリスナー登録_イベントはmousemove*/
    cnvs3.addEventListener('mousemove', onMove, false);
    function onMove (m) {
      /*このキャンバスの絶対座標値をゲットして、マウスの位置を取得*/
      var rect3 = m.target.getBoundingClientRect();
      var mx =  Math.round(m.clientX - rect3.left);
      var my =  Math.round(m.clientY - rect3.top);
      /*色指定を5種類作ってランダム化*/
      var clor1 = '#f00';
      var clor2 = '#ff0';
      var clor3 = '#f0f';
      var clor4 = '#0ff';
      var clor5 = '#0f0';
      var cl = Math.floor(Math.random()*5+1);
      var tColor;
      if (cl == 1) tColor = clor1;
      if (cl == 2) tColor = clor2;
      if (cl == 3) tColor = clor3;
      if (cl == 4) tColor = clor4;
      if (cl == 5) tColor = clor5;
      /*円の半径のランダム化*/
      var hank = Math.floor(Math.random()*8+3);
      /*色指定と、正円の描画*/
      ctx3.globalAlpha = 0.4;
      ctx3.fillStyle = tColor;
      ctx3.beginPath();
      ctx3.globalCompositeOperation = 'lighter';
      ctx3.arc(mx,my,hank,0,Math.PI*2,false);
      ctx3.fill();
    };
}

それから、8,9,10行目で「getBoundingClientRect()」や「clientX」「clientY」を使って、
キャンバス上のマウスポインタの位置を取得しています。

複数の半径をランダムに適用する

上のソースの25行目で、
var hank = Math.floor(Math.random()*8+3);
と指定しています。
これは、描画する正円の半径を 3px〜10px までの範囲でランダムにするための指定です。

Math.random() で発生する乱数は、0.000...から0.999...の範囲なので、
8をかけると0.000...から7.999...になります。
これに3を足して、3.000...から10.999...の範囲の乱数にして、
Math.floor() に入れて小数点以下を切り捨てているので、3から10までの半径になるわけです。
Math.random() などについての詳細はサンプル1で。)
これで、直径にすると6pxから20pxまでの正円がランダムに描かれるようになりました。

今回参考にさせていただいたサイト

今回は、いろんなサイトでJavaScriptについて勉強させていただき、各サイト様のサンプルスクリプトを元に、私なりにアレンジいたしました。

今回参考にさせていただいたサイトの1部を記載。お世話になりました。ありがとうございます!
ブックマークしておいたものをザーッとコピペしています。順番に意味はございません。

次回予告

今回のサンプル3で、ctx3.globalCompositeOperation = 'lighter';と指定しています。(30行目)
「globalCompositeOperation」は、カンバス上で複数のグラフィックスが重なった際の処理を指定するプロパティで、値は「lighter」以外にもいろいろ決められているんです。

次回はこの「globalCompositeOperation」の値を全部(11コ)試してみます。

関連記事
この記事をはてなブックマークに追加

やる気を保つためにランキングに参加しています。
応援してくださると すっごいやる気を出します! (笑)

初心者にも使いやすい(と思う)レンタルサーバー

最近よく「レンタルサーバーはどこがいい?」とご質問が来ます。
自分でも使っていてオススメなのはミニバード。管理画面がわかりやすくていい感じす。
仕事で使ってるロリポップもわかりやすい管理画面で、初めてでもすんなり使えると思います。
両方とも、なんといっても料金が安いです。初めてだとなるべく安いほうがイイですからね。

それよりちょっと料金は高いけど、高スペックでコスパが良く、信頼性も高いサーバといえば、やはりさくらのレンタルサーバと、XSERVER(エックスサーバー)だと思う。この2つは老舗でユーザーも多いので、質問する場がたくさんあり、初心者の方でもイケるだろうと思います。

レンタルサーバーは、たくさんあり過ぎて迷いますよね。近いうちに、初心者にも良さげなサーバーについて記事にまとめます。*記事をアップしたらココにもリンクを貼ります。

スポンサーリンク

コメントの投稿

スポンサーリンク
最新記事
Category
オススメの本
Links
Calendar
05 | 2017/06 | 07
- - - - 1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 -
Archive
RSS Link
Profile

yuki★hata

Author : yuki★hata
せめて月1回の更新をめざします~。

メールフォームはこちら

スポンサーリンク
スポンサーリンク
Copyright © ほんっとにはじめてのHTML5とCSS3 All Rights Reserved.