虎の穴開発室ブログ

虎の穴ラボ株式会社所属のエンジニアが書く技術ブログです

MENU

Canvas初心者がエンジニアのスキルシートをキャラクターシート風に作れるサイトを作ってみた

こんにちは、虎の穴ラボのH.Kです。
最近はお友達とオンラインで『Among Us』を楽しんでいます。
そのお友達は以前より人狼(汝は人狼なりや?)やTRPGを楽しんできた仲間で、キャラクターシートで自己紹介したいという話題になったので作ってみることにしました。
なお、2021/01/06に行われた【とらのあなLT】オタクが最新技術を追うLTイベント#20【テーマフリー】でも、こちらの内容について話させていただいたので、ご興味があればご視聴いただけると嬉しいです。

www.youtube.com

作ったもの

百聞は一見にしかず、ということでこちらのGitHub Pagesのページでキャラクターシートが作れます。
※PC版のChromeでしか動作確認していません。

デフォルト値は私のプロフィールに近いものが入っていますので、迷わず入力できるかと思います。

f:id:toranoana-lab:20210126113305p:plain
こんな感じのものが作れます

言語やフレームワークの選定は思い浮かんだものを入れていっただけで他意はありません。
RDBMSとかNoSQLとかも入れておけばよかったかなと思っています。

動機などの背景、導入

興味がなければ、この章は飛ばしていただいて大丈夫です。
最初に記載したとおり、仲間内で「キャラクターシートのような形で自己紹介できたら、趣味や特技がわかりやすくて良いのになぁ」というような話をしていたのがきっかけです。
ちなみにキャラクターシートとは、世界観を共有して行う創作企画やTRPG(クトゥルフ神話TRPGやシノビガミ)などで使われる、キャラクターの情報を簡単にまとめた資料です。

キャラクターシートの作成は手書きするか、レイヤーを管理できるイラストツールで作るかで作成します。しかし、手書きだとオンラインでの共有が難しいですし、イラストツールは使いこなせる人が限られてしまい、全員にキャラクターシートを作ってもらい、自己紹介とするのは大変です。

上記の経緯から、オンライン上で簡単につくれるキャラクターシートを作ってみようと思いました。
ただ、キャラクターシートをすべてフリーで入力できるようにしてしまうと実装がなかなか大変なので、今回はエンジニアのスキルシートをキャラクターシート風に、というコンセプトで作りました。
また、キャンバスを使ったことがなかったので、キャンバスの実装のお試しという面も大きいです。
余談ですが、背景になっているテンプレート画像は例のお友達メンバーのうちの1人に依頼して作ってもらったものになります。

技術的な話

ソースの管理も一緒にできて手軽なためGitHub Pages(Githubの静的ホスティングサービス)で公開する前提で、HTMLと素のJavaScript(いわゆるVanillaJS)のみで動作するようにしています。
(後述しますが、レーダーチャート描画のみライブラリを使っています。)
一番下にテンプレートとなる画像があり、その上に"アイコン画像"、"レーダーチャート"、"入力値"を上から描画しています。
また最終的に仲間内で共有することが目的なので、生成した画像のダウンロード機能のみを提供し、サーバでの保存は行わないようにしています。

テンプレート画像の読み込み

// Imageクラスで画像を読み込み
const baseImage = new Image();
baseImage.src = "image0.png";
baseImage.onload = function (event) {
  // 画像が読み込まれてからキャンバスに描画する
  const ctx = document.getElementById("canvas").getContext("2d");
  ctx.drawImage(baseImage, 0, 0);
};

これだけで画像をキャンバスに描画することができます。
画像がロードされてからではないと、表示されないので注意が必要です。

レーダーチャートの描画

レーダーチャートはChart.jsというライブラリで作っています。

www.chartjs.org

このライブラリで描画したレーダーチャートはキャンバスになるので、テンプレート画像を読み込んだキャンバスにレーダーチャートのキャンバスを重ねます。

const ctx = document.getElementById("canvas").getContext("2d");
// 画像は事前にロードしておく
ctx.drawImage(baseImage, 0, 0);
// レーダーチャート用のキャンバス
const radarElement = document.getElementById("myChart")
const radar = radarElement.getContext("2d");
// radarにチャートを描画する
new Chart(radar, {
  type: "radar",
  data: {
    // データの設定省略
  },
  // オプションの設定省略
});
// 作ったキャンバスを重ねる
ctx.drawImage(radarElement, 610, 50);

キャンバスにキャンバスを重ねることはdrawImageで実現できます。
上に重ねるキャンバスを画像として扱う(CanvasImageSource)ことでdrawImageで画像ソースとして読み込めます。
今回は画像としてダウンロードしたかったので、キャンバス上で重ねて、1つのキャンバスにまとめるように実装していますが、描画するだけであれば、position: absolutez-indexを使い表現することもできます。

position: absolutez-indexを使った実装の参考リンク developer.mozilla.org

文字(入力値)の描画

単純に文字を描画するだけであれば以下の記述で可能です。

const ctx = document.getElementById("canvas").getContext("2d");
ctx.font = "serif"; // フォントの指定
ctx.fillText("テストです", 0, 0); // 文字の書き込み

fillTextの第2, 第3引数は描画する座標を表しています。

今回作ったものでは、テンプレートの画像ファイルに文字を描画しているので、文字色と背景の色の都合で読みにくくなってしまいました。
そこで文字に対して白い縁取りをしています。

ctx.lineWidth = 3; // 縁取りの太さ
ctx.strokeStyle = "#FFF"; // 白
ctx.strokeText("テストです", 0, 0); // 枠のみの文字を描画
ctx.fillStyle = "#000"; // 黒
ctx.fillText("テストです", 0, 0); // 実態の文字を描画

実際には上記の処理をメソッド化して、"キャンバス", "文字列", "x座標", "y座標", "文字サイズ"を指定することで、すべて縁取りの文字を描画するようにしています。

function drawTextBase(ctx, text, x, y, size) {
  ctx.font = `bold ${size}px serif`;
  ctx.lineWidth = 3;
  ctx.strokeStyle = "#FFF";
  ctx.strokeText(text, x, y);
  ctx.fillStyle = "#000";
  ctx.fillText(text, x, y);
}

ダウンロード機能

const canvas = document.getElementById("canvas");
const link = document.createElement("a");
link.href = canvas.toDataURL(); // 直接画像のURLを発行
link.download = "ファイル名"; // ファイル名を指定
link.click(); // aタグのダウンロードを実施

aタグを生成し、そこにダウンロードリンクをつけ、イベントを発火させることで実現します。
もちろんキャンバスの描画後に実行する必要があります。
少し話は逸れるのですが、HTMLと素のJavaScriptだったので、ここまではローカルのファイルを直接ブラウザでアクセスして試していました。 ただ、ファイルを直接参照する場合、セキュリティの関係で、ファイルダウンロードはできません。
そのため、localhostを経由するようにサーバを建てるか何かしないと、ダウンロード機能はテストできなくなります。

公開する

GitHub Pagesを使って公開しました。
リポジトリを作って、設定を1つ追加するだけなので、お手軽ですね。
ちなみに元のリポジトリはこちらです。

今後の機能改善案・展望

今回は最低限の実装のみを行ったため、改善点はまだまだあります。
最低限やらなきゃいけないと思うことでも、以下のような点が挙げられ、

  1. バリデーションをつける
  2. 入力しやすいUIへの変更
  3. 他のブラウザ、スマホでの動作を安定させる
  4. 全体的なリファクタリング

以下のようなことも今後やっていきたいと考えています。

  1. ローカルストレージなどを使ったデータ保存
  2. 他のテンプレートへの切り替え

ただ、キャンバスの実装は目に見えるものができるので、とても楽しく、想像していたよりも簡単なため、これからも勉強して、改善を進めていけたらと思います。
また、大変だったところとして、座標指定を1つずつしていく必要があったことが挙げられます。
座標指定を簡略化する仕組みが作れれば、他テンプレートへの切り替えも楽になるので、方法を検討していきたいです。

P.S.

直近のイベント情報

1/29(金):とらのあなエンジニア&マーケター採用説明会
虎の穴ラボの業務、社内のことについて知ることができる採用説明会です!
yumenosora.connpass.com

2/5(金):とらのあなラボエンジニア座談会Vol.5.5【〜CTO&PdM対談〜】
とらのあなが運営するWebサービスについてCTOとマネージャーがその想いをエンジニア視点で語るイベントです! yumenosora.connpass.com

2/12(金):とらのあなラボエンジニア座談会Vol.6【〜オタク向けプラットフォームを作ってみた〜】
先日オープンした新規サービスの立ち上げと開発の舞台裏が聞けます!
yumenosora.connpass.com

どのイベントもオンラインでの開催となりますので、お気軽にご参加ください!!

カジュアル面談

弊社エンジニアと1on1で話せます、カジュアル面談も現在受付中です!こちらも是非ご検討ください。 news.toranoana.jp

その他採用情

虎の穴ラボでの開発に少しでも興味を持っていただけた方は、採用説明会やカジュアル面談という場でもっと深くお話しすることもできます。ぜひお気軽に申し込みいただければ幸いです。
カジュアル面談では虎の穴ラボのエンジニアが、開発プロセスの内容であったり、「今期何見ました?」といったオタクトークから業務の話まで何でもお応えします。

カジュアル面談や採用情報はこちらをご確認ください。
yumenosora.co.jp