入力値に合わせて即描画!canvasとJSを使ってレーダーチャートを作ってみよう -実践後編-

新年明けましておめでとうございます!ユアサです。
今年もarms inc. Engineer's Blogをどうぞよろしくお願いします。
前回の記事ではレーダーチャートのベース部分となる枠線の描画をしましたので、今回は実践の後編ということで動的に表示するレーダーチャートへと完成させます。
前回の記事はこちら↓
tech.arms-soft.co.jp

入力値に合わせたレーダーチャートの描画

今回想定しているのは五角形のレーダーチャートでした。ベースの枠線を作成した時のように引数を用意して表示する方法がありますが、レーダーチャートである以上どうせなら実用性のあるものにしていきたいので、当初の目的通り入力値に応じて描画される仕様を目指していきます。
枠線で用意した目盛りは5段階なので入力値が1〜5で選択できるセレクトボックスを五角形の5つ分用意します。

<form action="">
  <ul>
    <li>
      <label for="data01">data01(上)</label>
      <select id="data01">
        <option value="1">1</option>
        <option value="2">2</option>
        <option value="3">3</option>
        <option value="4">4</option>
        <option value="5">5</option>
      </select>
    </li>
    <li>
      <label for="data02">data02(右上)</label>
      <select id="data02">
        <option value="1">1</option>
        <option value="2">2</option>
        <option value="3">3</option>
        <option value="4">4</option>
        <option value="5">5</option>
      </select>
    </li>
    <li>
      <label for="data03">data03(右下)</label>
      <select id="data03">
        <option value="1">1</option>
        <option value="2">2</option>
        <option value="3">3</option>
        <option value="4">4</option>
        <option value="5">5</option>
      </select>
    </li>
    <li>
      <label for="data04">data04(左下)</label>
      <select id="data04">
        <option value="1">1</option>
        <option value="2">2</option>
        <option value="3">3</option>
        <option value="4">4</option>
        <option value="5">5</option>
      </select>
    </li>
    <li>
      <label for="data05">data05(左上)</label>
      <select id="data05">
        <option value="1">1</option>
        <option value="2">2</option>
        <option value="3">3</option>
        <option value="4">4</option>
        <option value="5">5</option>
      </select>
    </li>
  </ul>
  <button type="button" id="form_submit">送信</button>
</form>

JSの方で入力値を受け取れる記述を追加します。あらかじめそれぞれの入力項目にid名を付与していたので、getElementByIdで各項目のvalue値を取得し入力値が複数なので配列にします。
この時入力項目の入力後に送信ボタンをクリックすることで動作させるので、クリックで動作するaddEventListenerの中に上記の内容を記述して、最後に関数に渡す戻り値を用意します。

const submit = document.getElementById('form_submit');

submit.addEventListener("click", ()=>{
  canvas = document.getElementById("canvas_pentagon");
  context = canvas.getContext("2d");
  let dataList = [];
  const input01 = document.getElementById('data01');
  const input02 = document.getElementById('data02');
  const input03 = document.getElementById('data03');
  const input04 = document.getElementById('data04');
  const input05 = document.getElementById('data05');
  
  dataList.push(input01.value)
  dataList.push(input02.value)
  dataList.push(input03.value)
  dataList.push(input04.value)
  dataList.push(input05.value)
  
  drawData(5, 100, 110, dataList, 5, "#FF7B54")
});

次にレーダーチャート描画用の関数を用意します。こちらは枠線描画用に作成していた関数を真似て作成します。

// 入力値のレーダーチャート描画
const drawData = function(n, cx, cy, r, lineWidth, color) {
  const p = Math.floor(360 / n)
  let theta = -90;    // 角度修正(キャンバスでは3時方向が0度扱いのため12時方向を0度とする)
  let polygon = [];
  let data = 0;    // 配列のn番目
  
  while(theta<360-90) {
    const pos = {
      x: r[data] * 20 * Math.cos(theta*Math.PI/180) + cx,    // 各目盛りが20px間隔なのでr[data]*20(半径×20)
      y: r[data] * 20 * Math.sin(theta*Math.PI/180) + cy,   // 各目盛りが20px間隔なのでr[data]*20(半径×20)
    };
    
    polygon.push(pos);
    theta += p;
    data = data + 1;
  }
  
  // 多角形を描画する
  context.strokeStyle = color;
  context.lineWidth = lineWidth;
  context.beginPath();
  for(let i=0; i<polygon.length; i++){
    if(i==0){
      context.moveTo(polygon[i].x, polygon[i].y);
    }
    else{
      context.lineTo(polygon[i].x, polygon[i].y);
    }
  }
  context.closePath();  // パスを閉じる
  context.stroke();
}

上記を反映させたコードが以下になります。実際に触ってみましょう!

See the Pen radar chart_data by felly (@felly00505) on CodePen.

描画はできますが、再度数値を変えて送信ボタンを押しても描画済みのレーダーチャートが消えない状態ですね。これを参考にして修正しなければいけないポイントとしては

  1. 再度入力→送信ボタンを押した際にレーダーチャートがリセットしてほしい
  2. リセットされた上で、再度入力された入力値でレーダーチャートを描画したい

になるので、これらを踏まえて修正します。

再入力の度に再度描画されるレーダーチャートへの修正

入力項目に再度入力する際、既に描画されているレーダーチャートを削除したいのでclearRect(開始するx座標, 開始するy座標, x軸方向に◯◯pxの範囲, y軸方向に◯◯pxの範囲)を使用します。clearRect()が動作するタイミングは送信ボタンが押された時なので、レーダーチャート描画用関数内の最初に記述を追加します。

See the Pen Untitled by felly (@felly00505) on CodePen.

描画済みのものはリセットされるようになりましたが、今度は枠線が消えてしまいました・・・。これはhtmlの共通のcanvasタグ内での動作になっているので、一度clearRect()を動作させてしまうとcanvasの対象範囲内の描画を全て削除してしまいます。(本来は別々で作成・削除をしたい対象A・Bを同じレイヤー内で全て行ってしまっていたといえば分かりやすいかと思います)
枠線描画用のcanvasタグとは別にレーダーチャート描画用のcanvasタグを新規で用意し、その中で先ほどの関数が動作するようにします。実際に触ってみましょう。

See the Pen radar chart_complete by felly (@felly00505) on CodePen.

ちゃんと本来の目的通り動作しました!これにて完成となります。

まとめ

全3回に分けて続いたcanvasとJSを仕様したレーダーチャート作りですが、今回で完成となりました。
自分一人で入力から動作まで一貫したツールを作成したのは初めてだったので正直完成するか不安でしたが、どうにか目標達成できてよかったです・・・!
最後まで読んでいただきありがとうございました(^人^)