HTML

HTMLのcanvasとJavaScriptでお絵かきアプリ【線の太さ機能編】

oekaki-part3

今回はHTMLのcanvas・JavaScriptを使って作る「お絵かきアプリ」シリーズの最後の記事です。

前回・前々回の記事で使用したコードをベースにしているので、まだ読んでいない方は以下の記事を読むことでより理解が深まるかと思います。

今回作成するものの完成形は次の画像になります。

線の太さの変更と太さを表現する「○」を組み合わせた挙動線の太さの変更と太さを表現する「○」を組み合わせた挙動

 

上のアニメーション画像で新しく追加された機能は次の2つです。

新機能
  1. 「文字の太さ」スライダーで太さを変更できる
  2. canvas上にマウスカーソルが乗ると現在の線の太さが「○」の形で表示される

今回の記事で作成したコードと、公開されているアプリは以下のリンクからアクセスできます。

今回の記事を読むことで身につくスキルは次の通りです。

身につくスキル
  1. HTMLの「 <input type=”range”> 」を使ったイベント処理
  2. style(CSS)の「 position: absolute 」を使ったHTML要素を重ねるやり方
  3. canvas上でマウスカーソルについてくる円の描画方法
  4. 2つのcanvasを重ねて使うテクニック

③と④に関してはゲームを作るときにも利用できるスキルになるので、「将来ゲーム作ってみたいな」と思っている方にとっても参考になる記事になります。

それでは、今回の記事は次の内容で話を進めていきます。

今回の記事内容
  • 線の太さを変更できる機能を作る
  • マウスカーソルについてくる円の描画用のcanvasを用意する

それでは1つ目の内容から見ていきましょう。

線の太さを変更できる機能を作る

線の太さを変更するには、線の太さを表す「数値」を変更すれば良いので、今回使った「<input type=”range”>」でなくても、次のような選択肢もあります。

他の選択肢

どれを使うかは好みの問題になりますが、今回「<input type=”range”>」を選んだ理由は次の理由からです。

rangeを選択した理由
  • マウス操作だけで完結させたかった
  • 「0.1」単位で数の調整を行えるようにしたかったが、「<input type=”radio”>」と「<select>, <option>」を利用する場合はあらかじめ要素をたくさん準備する必要がある
  • 「<input type=”range”>」を使うと、スライドバーで数を選択できて直感的だった

今回言っている「スライドバー」とは以下の画像でいうと、canvasの下にある値変更に使っているパーツのことです。

線の太さの変更と太さを表現する「○」を組み合わせた挙動

サンプルコードを使って解説

HTMLファイル、JavaScriptファイルの両方で、今回追加した機能の部分にのみコメントが書かれています。

今回の記事以外部分の機能を詳細を知りたい方は、前回・前々回の記事で使用するサンプルコードの中に細かくコメントで説明しているのでそちらを参考にしていただけたらと思います。

HTML

それではHTMLの内容から見ていきましょう。

上記のコードのうち、線の太さ変更に関わる部分は、32~44行目の部分になり、2つのパーツに分けられます。

  1. 34~40行目: 「<input type=”range”>」 を使ってスライドバーを用意
  2. 43行目: 「<span id=”line-width”>」で現在のスライドバーで選択している値を目視できるようにする

①の「<input type=”range”>」では、スライドバーの基本設定を行っています。それぞれの意味は次のとおりです。

設定内容
  • id: JavaScriptでこのinput要素を操作するための値
  • type: range(スライドバー)を使うことを宣言
  • value: デフォルト値
  • min: スライドバーで選択できる最小値
  • max: スライドバーで選択できる最大値
  • step: 値の細かさの設定(0.01まで可能(ドキュメントより))

スライドバーを動かすことで値の変更を行うことが出来るのですが、「<input type=”range”>」だけだとページ上に現在の値を表示することが出来ません。

そこで、現在の値を表示するための要素として②の「<span id=”line-width”>」を追加して、JavaScript経由で値を更新出来るようにしています。

JavaScript

それでは、どのように値を更新しているのかJavaScriptのコードを確認しましょう。

上記のコードの内、線の太さの更新に該当する箇所は以下の部分です。

該当箇所
  1. 21行目: 線の太さの値を保持する「currentLineWidth」変数
  2. 135~153行目: 線の太さの値の更新処理をまとめている「initConfigOfLineWidth」関数
    • <input type=”range”>、<span id=”line-width”>のDOM操作
    • 太さ情報を保持している「currentLineWidth」変数の値の更新
  3. 159行目: 「initConfigOfLineWidth」関数を実行して、線の太さの値の更新処理を有効化

①で用意した「currentLineWidth」変数を使って線の太さを表現して、値が小さいほど線が細くなり、値が大きいほど線が太くなります。

この「currentLineWidth」変数は線を引く時に実行されるdraw関数内の29行目で線の太さを定義する時に使われます。

②では、HTML内で値変更用に用意した「<input type=”range”>」、現在選択している数値を表示するための「<span id=”line-width”>」のDOM操作と、値に変更があったときのイベント処理の定義をしています。

144行目のaddEventListenerで「’input’」イベントをセットすることで、スライドを動かしている最中も値を取得することが出来ます。

次のアニメーション画像は、スライドバーを動かしている時に上記145行目のwidthの値を「console.log」を使って確認しているところです。

range-slidebarスライドバーを動かしているときに画面の右側で値が更新されているのがわかる

 

③で行っていることは②で用意した「initConfigOfLineWidth」を呼び出して有効化しているだけです。

以上で線の太さを変更する実装は完了です。

次にマウスカーソルについてくる円の描画方法について説明します。

マウスカーソルについてくる円の描画用のcanvasを用意する

「マウスカーソルについてくる円」とはちょっと言葉だけだとわかりにくいので、次の画像を見てください。

show-line-width-indicator画面左のcanvas上にマウスカーソルが乗ったら「○」がマウスについてくる

 

上の画像を見ると、左側にあるcanvasにマウスカーソルが乗った時に「○(円)」がついてきているのがわかるかと思います。

この「○(円)」は現在の線の太さを表現しているのですが、この機能を実現するためにもう一つ別のcanvasを用意しています。

以下のHTMLは先程のHTMLファイルの中からcanvasの部分だけ抜粋したものです。

上記2つのcanvasの役割はそれぞれの次のとおりです。

それぞれの役割
  1. 4~8行目のcanvas: 線を書くためのもの
  2. 9~13行目のcanvas: 「○(円)」を描画するためのもの

2つのcanvasを使う理由

なぜ役割がことなるだけで2つのcanvasが必要になるのでしょうか?

①の機能に関しては、「全消し」ボタンを押さない限りは、過去に引いた線を残し続ける必要があります

線を引くたびに過去に書いた線が消されたらただの点の移動になってしまうからです。

しかし、②の機能に関しては、過去に描画した「○(円)」をマウスカーソルが移動するたびに削除する必要があります。

過去に描画した「○(円)」を削除しなかった場合は次の画像のように「○(円)」が足跡のように残ってしまいます

過去の描画を削除しなかった時の「○」の表示の挙動過去の描画を削除しなかった時の「○」の表示の挙動

 

上記までに話した内容をまとめると次の通りです。

  1. 線を引くときは過去の描画を削除してはいけない。削除するとただの点の移動になる。
  2. 「○(円)」を描画するとき、過去の「○(円)」を消さないと、足跡のように残り続けてします。

このように、①線を書く機能と、②「○(円)」を描画する機能で正反対のことをしなければいけないのです。

その理由より「○(円)」描画用にcanvasを追加しました。

2つのcanvasを重ねる

2つのcanvasを重ねることで、マウスドラッグを開始した時に、「○(円)」の位置から線を書くことが出来ます。

しかし、どのようにして2つのHTML要素を重ねているのでしょうか?

CSSの「position: absolute;」を使うことで実現できます。

今回はサンプルコードなので8行目のcanvas要素のstyle値に直接指定しています。

JavaScriptで○(円)を描画する

先程共有したJavaScriptのコードの内、「○(円)」の描画に関係する部分のコードだけ抜粋します。

「○(円)」を描画するために必要なことは大きく分けると以下の3つになります。

円描画で必要な3点
  1. 2~3行目: 円描画用のcanvas情報取得
  2. 7~28行目: 円描画のための「showLineWidthIndicator」関数の用意
  3. 30~65行目: canvasを2つ使うようになったため、マウスイベントをcanvas2つの親要素である「<span id=”layerd-canvas-area”>」に定義する

①は、線を書くためのcanvasと同じように、円描画用のcanvas情報から描画するために必要なcontext情報を取得します。

context」とはcanvasに図や線などを描画するのに必要なものという認識で大丈夫です。

②は、線引くときと同じようにcanvasに描画を行う処理をまとめたものですが、2点線を引くときと異なる部分があります。

線描画と異なる2点
  1. 18行目: 描画が実行されるたびcontextの「clearRect」メソッドを使って、canvas上に描画されているものを全て削除する
  2. 25行目: contextの「arc」メソッドを使って、マウスカーソルの位置(x, y座標)を中心に円を描画する

上記2つの機能により、「showLineWidthIndicator」関数が実行されるたびに、canvasがリセットされた後に、マウスカーソル位置を中心に円の描画が実現されます。

そして、③で行っているマウスイベントによって実行される56行目のコールバック関数内で、②で定義した「showLineWidthIndicator」関数は実行されます。

前回までは、線を書くためのcanvasに対してマウスイベントを定義していましたが、今回の追加機能により2つのcanvasを利用することになったため、

2つのcanvasの共通の親要素である「<span id=”layerd-canvas-area”>」に対してマウスイベントを定義するように変更しました。

仮に前回から変更せずに、線をかくためのcanvasに対してイベントを定義していたとしても同じように動くかと思いますが、以下の理由より親要素である「<span id=”layerd-canvas-area”>」に対して変更しました。

イベント対象の変更理由
  1. 1つのcanvasに対してのイベント定義の場合、指定したcanvasのみを対象とする意味合いになる
  2. 親要素に対してイベントを定義すると、親が内包している子要素(今回の場合は2つのcanvas)もイベント対象に含まれる意味合いになる

上記の理由のように、ただ動くことだけを考えるのではなく、イベントで実行する処理内容の意味まで考えて適切だと思われる要素に対してイベントを定義しています。

まとめ

あらためて、今まで作成したお絵かきアプリの内容を振り返ってみましょう。

今まで実装した機能
  1. 絵を描くために必要な最低限の機能を実装(1つ目の記事)
  2. 色の変更と、部分消しをするための消しゴム機能を追加(2つ目の記事)
  3. 線の太さの変更と、現在選択している線の太さを直感にわかるようにするために「○(円)」をマウスカーソルを中心に描画する機能(今回の記事)

以下にこれまで説明してきたコードのGithubレポジトリのリンクと、実際に機能を確認できるリンクを貼っておきます。

これまでcanvasで出来ることの説明として「お絵かき」アプリを題材にして説明しましたが、canvasで出来ることたくさんありその一例は次のとおりです。

ぜひ、HTMLのcanvasを使ったアプリケーションづくりにもチャレンジしてみてください^^

【やる気満々な方向け】学習サポートとオンライン講義やってます!

Webエンジニアになりたい人向けに、MENTA にて『【やる気満々な方向け】未経験からのWebエンジニア育成コース』というプランを用意しております。

このプランでは、主に「【学習コンテンツ】Web開発」を使って学習を進めていただきます。

あわせて読みたい
Web開発Webエンジニアになるために必要な知識・スキルを学習できるコンテンツを用意しました。未経験者でも、①開発環境の準備、②Webの基本的な仕組み、③HTML、④CSS、⑤JavaScriptと順を追って学習することでスキルが身につくことを目的に教材を作成しています。...

誰向けのプラン?

こちらのプランは次のような方に向けて作られています。

プラン対象者
  1. Progateやドットインストールで一通り学習したけど、次に何をすればよいかわからない
  2. Webエンジニアになるまでの学習プランがあると助かる
  3. 学習していてわからないところが出てきたときに質問したい
  4. コードレビューして欲しい
  5. オンライン講義に参加したい
  6. 学習した内容をアウトプットした際に、フィードバックがもらえたら嬉しい
  7. おすすめの学習教材を知りたい
  8. Webフロントエンド・バックエンドを学習したい
  9. フルスタックエンジニアになりたい
  10. 文系出身で今までプログラミングをしてこなかったけど、将来Webエンジニアになりたい
  11. 将来フリーランスになることを目指している

プラン内容は?

【やる気満々な方向け】未経験からのWebエンジニア育成コース』では次のことを行っております。

プラン内容
  1. Web白熱教室の学習コンテンツをメインに、指定した教材を使って学習する (学習プランに沿って学習を進めていただきます。)
  2. 学習コンテンツの課題をこなしたあとは、僕にコードレビュー依頼を投げていただくことで、コードを添削する(課題クリア後は、引き続き学習プランの内容を続けていただきます。)
  3. プラン契約者が参加するSlackグループにて質問し放題
  4. Slack内にある「アウトプットの場」チャンネルにて、学習したことをアウトプットをしていただくことで、それに対しフィードバックをする (学習内容のアウトプットは復習にもなるため、アウトプットすることを強く推奨します。)
  5. 画面共有を使ったオンライン講義 (オンライン講義は録画して、いつでもふり返れるようにしています。(オンライン講義動画(ウェビナー動画)))
  6. 学習プラン以外の内容に対しての質疑応答 (内容によっては回答できないものもありますが、まずは気軽に質問していただけたらと思います。)
  7. 不定期で行うオフラインでの勉強会に参加(僕自身が東京住みのため、東京・もしくは東京近郊で開催します)

1日1回カフェでコーヒー1杯頼むくらいの金額で参加できます

1日1回、カフェでコーヒー1杯分くらいの値段(約330円)」で以下の環境が手に入るとイメージして頂けたらと思います。

  1. コードを添削してもらえる
  2. 学習したことのアウトプットに対してフィードバックしてもらえる
  3. いつでも質問出来る
  4. 週1のオンライン講義に参加できる
  5. 過去のオンライン講義動画を好きな時間に復習できる(いつでも閲覧可能)
  6. 不定期で行うオフラインでの勉強会に参加できる(僕自身が東京住みのため、東京・もしくは東京近郊で開催します)
  7. 自分の住まいの近場のメンティーさん同士で集まって、オフラインで勉強会を開くのも可能(初めて開催する場合は事前に僕に連絡をいただけたらと思います)

学習教材には、このサイトで用意している「【学習コンテンツ】Web開発」を使います。

【学習コンテンツ】Web開発」を使って学習を進めることで、Webのフロントエンドとバックエンドのスキルを身につけていくことができます。

プログラミングスクールとの比較

プログラミングスクールに通う場合は1ヶ月で10万円以上するところも多いですし、3ヶ月で50万円、更には100万円するところもあります。

プログラミングスクールの値段が高い理由は、「プログラミングスクールで働いている人の人件費」「就職のサポート」なども含まれているからです。

10万円50万円100万円」のいずれの場合も、自己投資とはいえ、支払うのにはだいぶ勇気がいる金額かと思います。

オススメの学習方法

個人的にオススメするのは、プログラミングのできるメンター(師匠)を見つけて、まずは1ヶ月プログラミング学習をしてみて、自分にプログラミングが向いているかどうか確かめてみることです。

10万円50万円100万円」を払って、学習していく中で「やっぱり自分にはプログラミングは向いてない」と判断した場合、その金額はかなりの痛手となります。

そのため、まずは「これくらいの金額なら最悪失っても痛くないな」の値段で教えてくれるメンターを見つけて、そのメンターに色々と質問をしてみましょう。

それで、「良さそうだな」と思ったら教えてもらうといった流れで学習を始めると、金額もだいぶ節約できます。

注意点

ただし、参加者が増えてきたら、1人1人へのサポートの質を維持するのが難しくなるので、値上げする可能性もあります。

値上げする理由は次の以下の理由となります。

  • 値段を上げて参加ハードルをあげることで、自己解決スキルも身につけたいと考えている学習意欲の高い人だけが参加するようになる
    • 調べたらすぐにわかることを、自分で調べずに何でもかんでも質問すると、自己解決スキルも身につかない
    • 更に、他のメンティーさんの対応する時間が取れなくなりサポートの質の低下にも繋がる

詳しく話を聞いてみたい方は

以下のいずれかでメッセージをいただけたらと思います^^

 

プラン内容については以下のリンク先からも確認することが出来ます^^

【やる気満々な方向け】未経験からのWebエンジニア育成コース

COMMENT

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です