【個人開発】キャンバスが回るお絵描きサイトを作りました〜Webでろくろ絵〜
記事概要
プログラミングに入門した私がお絵描きサイトを個人開発する流れと、その中で感じたことを振り返りも兼ねてまとめました。
成果物「Webでろくろ絵」
一部のスマートフォンでは表示が崩れる可能性があります。
About me
趣味としてWebの開発を触り始めた2009年生まれのGyozaです。初めての技術記事で拙い文章ですがご容赦ください。競技プログラミングが好きです。
製作動機
某動画アップロードサイトで、「ろくろアート」というものを制作している動画を目にしました(とても美しかったです)。私も挑戦してみたいと思ったのですが、家には肝心のろくろがなかったのでこの願いは叶いませんでした。そこで、作ればいいじゃん!となりました。
アプリの仕様技術
使用言語 | 開発環境 | デプロイ先 |
---|---|---|
HTML5+CSS3+JavaScript | Glitch | GitHub Actions |
順に説明していきます。
使用言語の選定
今までに一番触ったことのあるプログラミング言語がJavaScriptであったこともありますが、Webアプリケーションの手軽さに惹かれたことも、これらの言語を選んだ理由です。
開発環境について
開発環境にはGlitchというサービスを使用させていただきました。
Web上のエディタで、Web開発に特化しています。非課金であってものびのびと開発を行えるので愛用しています。デプロイ先について
お世話になっているGitHub Actionsです。手軽さで選びました。
工夫した点
- わかりやすいUI、目に優しい配色
- 回転するキャンバスの実装
開発中に行き詰まったところ
- 配色をどうするか
- キャンバスが「回る」をどう実装するか
- キャンバス上に描いた絵をどうやってGIFファイルにするか
1. 配色をどうするか
サイトの印象を左右すると考えられる配色は、「いい感じ」のものにしたいわけですが、私は自分のセンスにあまり自信がありませんでした。
そこで使わせていただいたものが以下のサイトです。
こちらのサイトでは、いくつかの配色の例が示されています。この中から、自分の作りたいサイトのイメージによく合うものを選ぶことにしました。
2. キャンバスが「回る」をどう実装するか
まずキャンバスについては、HTMLに<canvas>要素というそのままな要素があるため、こちらを利用しました。指やマウスカーソルで触れたところに線を描画する方法については、高速にいくつもの点を打つ方法を採用しました。しかし、この方法だと指を速く動かしたときに点が散らばってしまう問題が発生するのでどうすればよいか疑問です。
さて、少し話題がずれました。
私は、今回のサイトの肝であるキャンパスの「回る」機能について以下のことを考えました。
- canvasコンテキストのrotate関数(以後単にrotate関数と表記)を使用する
- <canvas>要素そのものをスタイル属性で回転させてしまえばいいのでは
最終的には、2つ目の要素そのものを回転させる方法を取りました。
理由は、rotate関数で回転が適用されるのはrotate関数の実行後に描画したもののみだったからです。「Webでろくろ絵」の仕様を考えると、いままでに描いた部分も一緒に回ってほしいので適しませんでした。
「キャンバス自体を回転させる方法」の詳細
「キャンバス自体を回転させる」ということで、実装はJavaScriptからキャンバスのDOMを取得し、CSSスタイルを書き換える方法を取りました。しかしこの解決方法には1つ課題がありました。
それは、キャンバス上のクリックされた座標をどうやって取得するかでした。
もともと、キャンバス要素がページ上端から何pxか等の情報から取得をしていましたが、回転することでややこしいことになっていました。ここで助けてくれたのが三角関数でした。
雑な説明になってしまいますが、
- クリックされた座標をキャンバスの中心を原点とする座標に変換
- クリックされるまでに何度回転していたかを保持しておき、その分、手順1で変換した座標を原点中心で回転させたときの座標を三角関数で計算
という手順で行いました。
また、キャンバス上でいわゆる「長押し」されたときも、描画する点を変更しなければいけませんでしたので、三角関数にはお世話になりました。
3. キャンバス上に描いた絵をどうやってGIFファイルにするか
静止画として保存する方法については、検索をするとたくさんの情報が出てきました。
また、キャンバスに表示した内容を順にGIFファイルのフレームにする方法は以下のサイトがとても勉強になりました。
しかし、要素自体を回転させているキャンバスをGIFファイルとして保存している事例は(自分の調べた中には)ありませんでした。
そこで、GIF保存用の第二キャンバスを用意しました。
この実装方法ですが以下の手順を繰り返しました。
- 第二キャンバスにrotate関数を適用
- お絵描きキャンバスの内容を第二キャンバスにdrawImage()
- GIFのエンコーダに第二キャンバスのコンテキストを渡す
- 第二キャンバスの内容をキャンバスいっぱいの白い長方形で上書き(描画内容の削除)
課題
- 指、マウスカーソルを速く動かしたときに、描画がまばらになる(点々になる)
- ウィンドウのサイズが変わったときにキャンバスへの描画がうまく動かない
- 白いペンのプレビューではペンのサイズがよくわからない
- GIFの保存に尋常じゃない時間がかかる
おわりに
ここまで読んでくださりありがとうございました。ご指摘等ありましたらぜひよろしくお願いいたします。これからも技術力向上のために、開発を続けていきたいです。また、今回開発記を書いてみて、自分の製作物と向き合うきっかけになりましたので、こちらもまた行いたいと思います。
Discussion