見出し画像

『JavaScriptを極める3ヶ月 アプリ開発に使える知識を徹底的に学ぶ』という勉強会の3日目をまとめる①

X-HACK様の主催する勉強会の『JavaScriptを極める3ヶ月 アプリ開発に使える知識を徹底的に学ぶ』という勉強会の学んだことについて備忘録&復習としてまとめてみようと思います。


※この記事を見る前提知識としてJavaScriptの基本文法とオブジェクト指向&プロパティの概念、簡単なchromeデベロッパー・ツール、の使い方を覚えておくと読みやすいと思います。


※第三回からの内容となるので1、2回目も内容も書いていければ良いですが長くなりますので省略したいと思います。機会があれば書こうと思います。

※まとめると長くなりますので①、②と分けております。

1、自己紹介と勉強会へ参加したきっかけ


初めまして、りょうと申します。Webアプリケーションを作る会社に入るためにJavaScriptを勉強しています。


9月から独学を始めITの就職をするために10月から広島から東京へ引っ越して勉強をしてきました。


が、勉強しているうちになかなか成長を感じられなくなってきたのでどこか勉強会へ行こうかなと感じたところ
こちらのツイートを見ました


こちらの勉強会の説明会へ行ったのですが「実践的な力が身につけれる!」と感じ速攻で申し込みをしました。


2、何の勉強会なのか?


ざっくり言いますと『三ヶ月かけてJava scriptとVue.jsの基礎を学び、それらを使ったアプリを作っていく!』という勉強会です。
オブジェクト設計、デバック等独学では学びにくい実用的な力がつきますし、参加者の皆さんも意欲をもって質問をされています。

Java scriptの文法基礎しか学んでなかった私からすれば難しく追いつかない時がよくありますが、主催の松田さんを初めスタッフ、参加者の皆様に助けて頂いています。本当にありがとうございます。
(特にたつごんさん(@tatsugon14)は横についてもらいながら分かりやすく教えてくださり、頭が上がりません、、、!)

3、今回のゴール


さて、今回学んだことを書いていきます。
今回のゴールは大きく分けて2つあり


・canvas APIを使いアートを作る
・ぐるなびAPIを使い店の情報を取得し検索機能を作る。


今回は1番目の「canvas APIを使いアートを作る」についてまとめていきたいと思います。


4、canvas APIを使いアートを作る(その1)

これらをフレームワークなどを使わずにJavaScriptだけで書いていきます。

※canvas APIのリファレンスはこちら


さて、始めの「■をランダムに表示させる」に行きましょう。

動画を見てくださるとわかるように、カラフルな■が並んでいて、更新するたびに色が変わってますね!
最初に完成したコードを見てみましょう。

<!DOCTYPE html>
<html lang="jp">
 <head>
   <meta charset="UTF-8" />
   <meta name="viewport" content="width=device-width, initial-scale=1.0" />
   <meta http-equiv="X-UA-Compatible" content="ie=edge" />
   <title>Document</title>
 </head>
 <body>
   <canvas id="canvas" width="400" height="400"></canvas>
   <script>
     const canvas = document.getElementById("canvas");
     const ctx = canvas.getContext("2d");
     ctx.fillStyle = "#FF0000";
     ctx.fillRect(20, 20, 150, 100);

     for (let i = 0; i < 10; i++) {
       for (let j = 0; j < 10; j++) {
         let r = getRandomInt(255);
         let g = getRandomInt(255);
         let b = getRandomInt(255);
         ctx.fillStyle = `rgb(${r}, ${g}, ${b})`;
         ctx.fillRect(i * 50, j * 50, 50, 50);
       }
     }

     function getRandomInt(max) {
       let num = Math.random() * max;
       return Math.floor(num);
     }
   </script>
 </body>
</html>

まず初めに、基礎となるコードを見ていきましょう。

<!DOCTYPE html>
<html lang="jp">
 <head>
   <meta charset="UTF-8" />
   <meta name="viewport" content="width=device-width, initial-scale=1.0" />
   <meta http-equiv="X-UA-Compatible" content="ie=edge" />
   <title>Document</title>
 </head>
 <body>
   <canvas id="canvas" width="400" height="400"></canvas>
   <script>
     const canvas = document.getElementById("canvas");
     const ctx = canvas.getContext("2d");
     ctx.fillStyle = "#FF0000";
     ctx.fillRect(20, 20, 150, 100);
   </script>
 </body>
</html>

これを実行すると

画像1

となります。

それでは上のコードを解説していきましょう。
まずbodyのところに

<canvas id="canvas" width="400" height="400"></canvas>


を入れていきます。このコードは<id = canvas> 幅400px 高さ400pxのキャンバス部分であることを示しています。


デベロッパー・ツールのelementsタブで見てみましょう。

画像2

400px×400pxの範囲を示していますね!

次にscriptを1行ずつ見てみます。
const canvas = document.getElementById("canvas");の
=の右の方へ注目してみましょう。
documentというのは「Html文章」のことを指していますgetElementByIdはid要素を取得することを表しています。

それに+("canvas")とついています。

これは「Html文章のcanvasと紐づいているid要素を引っ張ってきてね!」

(ここでいうHtml文章は<canvas id="canvas" width="400" height="400"></canvas>の部分)ということを表しています!(これを参照といいます)

この一連を JavaScriptのDOM操作といいます。

JavaScriptを使ってHTMLを「動的」に動かすためには必須の操作ですね!

このようなメソッドは他にもありますが長くなりますので下記のサイトを参考にしてください。
(でも参照する考え方はほぼ同じ!)

これを定数canvasに入れていきます。

次に
const ctx = canvas.getContext("2d");
を見てみましょう。
このgetContext("2d")
というのは ブラウザ上に絵を描くためのメソッドです。
これを定数「ctx」に渡し、あとで書かれているfillStyle fillRectというオブジェクトを「ctx」に渡していきます。
これらのオブジェクトは後述するように色と 四角形の塗りつぶし範囲を指定して四角形を書いていきます。
詳しくはこちら。


ctx.fillStyle = "#FF0000";
ctx.fillRect(20, 20, 150, 100);

色(fillStyle)と、四角形の塗りつぶし範囲(fillRect)を指定していきます。
(fillRect)の数字って何を表しているのかはこちらにお任せします↓


こっちの方が分かりやすいかも?↓


その結果が上の画像になるわけですね!

画像3

次にこのコードを加えていきます!

       for (let i = 0; i < 10; i++) {
       for (let j = 0; j < 10; j++) {
         let r = getRandomInt(255);
         let g = getRandomInt(255);
         let b = getRandomInt(255);
         ctx.fillStyle = `rgb(${r}, ${g}, ${b})`;
         ctx.fillRect(i * 50, j * 50, 50, 50);
       }
     }

     function getRandomInt(max) {
       let num = Math.random() * max;
       return Math.floor(num);
    }

これを大雑把にステップごとに見てみると


①変数「r」「g」「b」にgetRandomInt関数を使用し0~255のランダムの数字を決める。
②rgbカラーに一つずつランダムに決めた数を各{}に入れ、色を決める。
③x軸に50px、y軸に50pxのところで塗りつぶされた四角を入れる。
④①~③を9回繰り返す。
④y軸が9回回るとx軸が+50pxとなるので隣に■が描かれる。


という流れです。
ちなみに②のように${変数}の形はテンプレートリテラルの一種でよく見るので覚えておきましょう!
テンプレートリテラルの参考↓


次にgetRandomInt関数を見てみましょう。
1、Math.random()というメソッドを使い0~1の間の乱数×max(ここではどれも引数である255となる)で変数numを取得
2、変数numをMath.floor()で整数にして上のコードに戻り値を渡す
という流れです。
以下今回使ったメソッドの解説になります。


よく使用するので使いこなせれるようになりたいですね!

ここで重要なことがひとつ。色の決め方です。
CSS等を扱うときに、色を決める時があると思います。
その時色の決め方は3種類あるのですが。


①色の名前で指定する
color: red;


②16進数RGBで指定する
color: #FF0000;


③色をRGBで直接指定する
color: rgb(255, 0, 0);


の3種類あります。今回は③の方法ですね!

熟練者なら1発でわかると思いますが、僕ら実務未経験者からすると「どんな風に動いてんの?」と疑問をもちますよね。
この部分だとfor文の入れ子の部分とかでどんな繰り返しなんだろう?とかとか。
その時はデベロッパー・ツールで、ステップ実行をしましょう!
デベロッパー・ツールの上のsaucesタブをクリックしてソースコードを表示させてみましょう。

画像4

(もしコードが出ない場合Pageタブを出してファイルを表示させましょう)
「 for (let i = 0; i < 10; i++) { 」の行の数字をクリックしてみましょう。

画像5


その状態でF5で更新してみましょう。

このように一つ一つ実行されていることがわかりますね!これをステップ実行といいます!
(また、チェックしたところをブレークポイントといいます。)
これでコードの流れが分かるようになりましたね!
と、ここまでみて理解した人の中には疑問を持つ方がいると思います。
「なんで「i」が8、9の時から■が表示されなくなったの?」と。
鋭い質問ですね笑
id = canvasを思い出してみましょう。
幅400px 高さ400pxのキャンバスが表示されたと画像で表示しました。

画像6


ここで「あっ!」っ思う人もいると思います。

そうです、「i」が7の時点で高さ400pxの範囲にちょうど収まっているので「i」が8、9の時は描写されないのですね!
このようにコンソールを使いこなせばデバックが超はかどるわけですね!
(scopeタブ、watchタブ、コンソール機能など、まだまだ機能があるのですが機会があれば少しづつ書いていきます。)


5、canvas APIを使いアートを作る(その2)


次に図2のコードを見てみましょう。(関数が分かりにくい場所へ書いていますが、説明しやすいようにコードの順番を変化させています。が、実行順序は変更ありません。)

<!DOCTYPE html>
<html lang="en">
 <head>
   <meta charset="UTF-8" />
   <meta name="viewport" content="width=device-width, initial-scale=1.0" />
   <meta http-equiv="X-UA-Compatible" content="ie=edge" />
   <title>Generative Art</title>
 </head>

 <body>
   <canvas id="canvas" width="400" height="400"></canvas>
   <script>
     const canvas = document.getElementById("canvas");
     const ctx = canvas.getContext("2d");
     const BALL_NUM = 100;
     let balls = [];

     for (let i = 0; i < BALL_NUM; i++) {
       let x = 200;
       let y = 200;
       let speed_x = getRandomInt(10) - 5;
       let speed_y = getRandomInt(10) - 5;
       let radius = getRandomInt(30);
       let color = getColor();
       balls.push(new BallObject(x, y, speed_x, speed_y, radius, color));
     }

     // 色をrgb形式で返す関数
     function getColor() {
       const colorInt = 96;
       let red = getRandomInt(colorInt);
       let green = getRandomInt(colorInt);
       let blue = getRandomInt(colorInt);
       return `rgb(${red}, ${green}, ${blue})`;
     }

     // 引数maxの値までのランダムな値を返す関数
     function getRandomInt(max) {
       let num = Math.random() * max;
       return Math.floor(num);
     }

     // 全てのボールの位置を移動させる    
     setInterval(() => {
       for (let i = 0; i < BALL_NUM; i++) {
         balls[i].move();
       }
       // 背景を塗りつぶす処理
       ctx.globalCompositeOperation = "source-over";
       ctx.fillStyle = "rgba(8,8,12,.2)";
       ctx.fillRect(0, 0, 400, 400);
     }, 100);

     function BallObject(x, y, x_speed, y_speed, radius, color) {
       this.x = x;
       this.y = y;
       this.x_speed = x_speed;
       this.y_speed = y_speed;
       this.radius = radius;
       this.color = color;

       this.move = function() {
         // 移動スピードを閾値をまたいだら、反転させることで跳ね返りを表現している
         if (this.x > 400 || this.x < 0) {
           // this.x_speed = this.x_speed * -1;
           this.x_speed *= -1;
         }
         if (this.y > 400 || this.y < 0) {
           this.y_speed *= -1;
         }

         this.x = this.x + this.x_speed;
         this.y = this.y + this.y_speed;
         this.drawCircle(this.x, this.y, this.radius, this.color);
       };

       this.drawCircle = function(x, y, radius, color) {
         ctx.globalCompositeOperation = "lighter";
         ctx.fillStyle = color;
         ctx.beginPath();
         ctx.arc(x, y, radius, 0, Math.PI * 2, false);
         ctx.fill();
       };
     }
   </script>
 </body>
</html>

ちょっと長いですね笑
ひとつずつ見ていきましょう。

 <body>
   <canvas id="canvas" width="400" height="400"></canvas>
   <script>
     const canvas = document.getElementById("canvas");
     const ctx = canvas.getContext("2d");
     const BALL_NUM = 100;
    let balls = [];

上は図1と同じですが、加えて定数BALL_NUMと変数ballsを取得します。これは、ボールの数を表しています。

また変数ballsは配列の形にしていきます。

      for (let i = 0; i < BALL_NUM; i++) {
       let x = 200;
       let y = 200;
       let speed_x = getRandomInt(10) - 5;
       let speed_y = getRandomInt(10) - 5;
       let radius = getRandomInt(30);
       let color = getColor();
       balls.push(new BallObject(x, y, speed_x, speed_y, radius, color));
       }

次にfor文を使いボールを配置していきます。「i < BALL_NUM」とありますので
100個のボールの、最初の地点を表す200、動き、半径、色を決める数値を変数へ入力していきます。これらはgetRandomInt関数、getColor関数を使ってますね!
そのあと、変数ballsの配列にpushメソッドを入れています。これは配列の末尾に 1 つ以上の要素を追加することができます。
その配列1つ1つにnewをつかいBallObjectを配置しているのですね!
そしてこれらの変数はBallObjectの引数となります。


これらのメソッドは下記で



インスタンスの意味が分かりにくいと思うのでこちらも併せてみたほうがいいかも。


      // 色をrgb形式で返す関数
     function getColor() {
       const colorInt = 96; 
       let red = getRandomInt(colorInt);
       let green = getRandomInt(colorInt);
       let blue = getRandomInt(colorInt);
       return `rgb(${red}, ${green}, ${blue})`;
     }

     // 引数maxの値までのランダムな値を返す関数
     function getRandomInt(max) {
       let num = Math.random() * max;
       return Math.floor(num);
       }

前述したMath.random()、Math.floor()が出てきてますね!
そして、それらの戻り値をBallObjectへ入力しています。
BallObjectについては後述します。

      setInterval(() => {
       // 全てのボールの位置を移動させる
       for (let i = 0; i < BALL_NUM; i++) {
         balls[i].move();
       }
       // 背景を塗りつぶす処理
       ctx.globalCompositeOperation = "source-over";
       ctx.fillStyle = "rgba(8,8,12,.2)";
       ctx.fillRect(0, 0, 400, 400);
      }, 100);

setIntervalというあたらしいメソットが出てきましたね!そのうえ=>という見慣れないものがありますね。
実はsetIntervalの中に引数のない無名関数を入っているのです。コードで表すと

      setInterval(function(){
    // 全てのボールの位置を移動させる
       for (let i = 0; i < BALL_NUM; i++) {
         balls[i].move();
       }
       // 背景を塗りつぶす処理
       ctx.globalCompositeOperation = "source-over";
       ctx.fillStyle = "rgba(8,8,12,.2)";
       ctx.fillRect(0, 0, 400, 400);
       }, 100);

という形になります。これを=>を使いfunctionを省略した関数をアロー関数といいます。アロー関数は引数がある場合など、いろいろな形があるのでMDNで確認するといいですね!

そのアロー関数の中にfor文が入っています。
このコードは大まかに2つ分かれています。


①For文を使い100個のボール1つ1つに動きを与える(このmoveというのはBallObjectの中に入っています。詳しくは後述で。)


②source-overを使い、新しい動きを上書きする。背景を表しているfillStyle、fillRectは固定となる。


この一連の動きをsetIntervalで0.1秒で繰り返しているということです。
ということは、この数値をいじれば、ボールの動きを調整できるということですね!



さて次はこのコードのミソであるBallObjectを見てみましょう!
これらは、ボールが動く前に動き等をあらかじめセットするためのオブジェクトとなります!

    function BallObject(x, y, x_speed, y_speed, radius, color) {
       this.x = x;
       this.y = y;
       this.x_speed = x_speed;
       this.y_speed = y_speed;
       this.radius = radius;
       this.color = color;

       this.move = function() {
         // 移動スピードを閾値をまたいだら、反転させることで跳ね返りを表現している
         if (this.x > 400 || this.x < 0) {
           // this.x_speed = this.x_speed * -1;
           this.x_speed *= -1;
         }
         if (this.y > 400 || this.y < 0) {
           this.y_speed *= -1;
         }

         this.x = this.x + this.x_speed;
         this.y = this.y + this.y_speed;
         this.drawCircle(this.x, this.y, this.radius, this.color);
       };

       this.drawCircle = function(x, y, radius, color) {
         ctx.globalCompositeOperation = "lighter";
         ctx.fillStyle = color;
         ctx.beginPath();
         ctx.arc(x, y, radius, 0, Math.PI * 2, false);
         ctx.fill();
       };
     }

thisが多く見にくいですが一つずつ見てみましょう

⑤-①

      function BallObject(x, y, x_speed, y_speed, radius, color) {
       this.x = x;
       this.y = y;
       this.x_speed = x_speed;
       this.y_speed = y_speed;
       this.radius = radius;
       this.color = color;

まず②で引数として取った変数をしていきます。
ん?このthisってなんなの?って思う方が多数でしょう。
このthisというのは、1個のボールにセットされているBallObjectを表しています。
???と思う方もいると思いますので、デベロッパー・ツールで見てみましょう!

画像7

ここからステップ実行で見ていきます

画像8

四角の枠を見てもらえば良いと思いますが②で出された数値が出てますね!
コンソールで詳しく見てみましょう

画像9

詳しくthisの詳細が出てますね!

コンソールはthisだけではなく配列の中身等を調べられるので、とても便利ですね!

ちなみにscopeタブでもこの情報が見れます。

画像10

さて、コードに戻りましょう。


      function BallObject(x, y, x_speed, y_speed, radius, color) {
       this.x = x;
       this.y = y;
       this.x_speed = x_speed;
       this.y_speed = y_speed;
       this.radius = radius;
       this.color = color;

これらは、BallObjectであるthisに各引数を渡していることを表しています。
よって、BallObjectに数値を持たせることができています。

        this.move = function() {
         // x、y閾値をまたいだら、移動スピード数値を反転させることで跳ね返りを表現している
         if (this.x > 400 || this.x < 0) {
           // this.x_speed = this.x_speed * -1;
           this.x_speed *= -1;
         }
         if (this.y > 400 || this.y < 0) {
           this.y_speed *= -1;
         }

         this.x = this.x + this.x_speed;
         this.y = this.y + this.y_speed;
         this.drawCircle(this.x, this.y, this.radius, this.color);
       };

ここで④に出てきたmoveの関数となります。
ここではif文を使って、this.x_speed *= -1という風に数字を反転させボールの跳ね返りを表現しています。

ちなみに松田さんによると、ゲームアプリを作るときによく作られるコードとのことです。
ゲームに限らずコードを作るときにこのような発想が必要になってくるんだなぁと感じました。

下のコードを見ていきます。this.x = this.x + this.x_speedというのは
今時点でいるxの数値+xのスピード=次の動きのxを左のthis.xへ代入しているということを表しています。
ここまで理解していれば一目でわかりますね!。

それではdrawCircleの方へ行きましょう。これは円を書くための関数が入っています。

        this.drawCircle = function(x, y, radius, color) {
         ctx.globalCompositeOperation = "lighter";
         ctx.fillStyle = color;
         ctx.beginPath();
         ctx.arc(x, y, radius, 0, Math.PI * 2, false);
         ctx.fill();
       };

ここではglobalCompositeOperation にlighterという値を入力して
「両方のイメージの領域が描画され、重なった部分は混色して描画される。」

という状態をctxに渡しています。
ctx.fillStyle = color;で②で渡された値で色を決めます。
ctx.beginPath();というのを説明すると「パス」という概念から説明しないといけなくなるので
説明はMDNとHTMLリファレンスに譲ります。



ここでは新しく図形が作られるというイメージが良いでしょう。

ctx.arcで円を描くように指示をします。

そしてctx.fill()で円を塗りつぶします。

これで完成です。お疲れさまでした。


6、まとめ


学んだことは様々ありましたが特に
・canvas APIで図形の表現を通して様々なコードレシピを学べた
・オブジェクト指向の考えを学べた
・chromeデベロッパー・ツールを深く学べた
特にこの3つのことを学べましたね!

(追記:めっちゃ重要なこと書き忘れた、、、)

特にまとめの2つ目は重要です!

データ設計の基礎として、関数ごとに
色をランダムに表示する
色をrgb形式に返す変数
rgbの価をランダムに返すetc...
という風に処理で関数分けしたほうが読みやすいコードになるでしょう!

またJavaScriptのES2015から「class」という概念が出てきてますので
これらを意識したコードを書けば見やすいコードになりそうですね!

実は内容としてはほぼこちらの2つの記事と同じです。
りゅーそう氏のノート↓



きわっち氏のノート↓



お二人方の記事もとても分かりやすく書かれています!(僕もこのように分かりやすく書いてみたい、、、!)
興味がある方は是非見てください!

学んだことを文章化してアウトプットをすることは初めてですので
分かりにくい文章になりましたが、ここまで見てくださりありがとうございました。
次回はぐるなびAPIを使い店の情報を取得し検索機能をつけたWebページを書いていきたいと思います!


この記事が気に入ったらサポートをしてみませんか?