JavaScript

【JavaScript】chart.jsでフォントサイズをwidthに応じてレスポンシブにする方法

JavaScriptのChart.jsで、フォントサイズをチャートのwidthに応じてレスポンシブにする方法を紹介します。fontを関数で返す書き方、scales.rの設定、データ属性から値を渡す方法、親要素でサイズを制御するCSSの注意点までまとめます。

この記事の目次
  1. Chart.jsの公式サイト
  2. Chart.jsの始め方
  3. 完成コード
  4. イベントを設定
  5. レーダーチャートをセットする関数
  6. configを取得する関数
  7. configを取得する関数の大枠
  8. canvasにデータ属性をセットする
  9. ラベルの設定
  10. データの設定
  11. 見た目の設定
  12. チャートをレスポンシブにする際のCSSの注意点

JavaScriptのchart.jsの使い方を紹介します。
とくにフォントサイズをwidthに応じてレスポンシブにする方法を紹介します。

結論から書くと、Chart.jsのフォントサイズは数値ではなく関数で指定できます。font: (context) => ({ size: Math.round(context.chart.width / 28) })のように、描画時のチャート幅から文字サイズを計算して返すと、画面幅に合わせて文字も拡大縮小します。この記事ではレーダーチャートのポイントラベルを例に、データ属性からの値の受け渡しも含めて手順を説明します。
コードはChart.js 3系以降の書き方です(4.5で動作確認)。2系のscalefontSizeといった設定名はそのままでは効きません。

Chart.jsの公式サイト

https://www.chartjs.org/
デモページ
ドキュメント

スポンサーリンク

Chart.jsの始め方

cdnの場合:https://cdnjs.com/libraries/Chart.js
あとは、NPMやGitHubからChart.jsを取得できます。(上のドキュメント参照)

完成コード


document.addEventListener('DOMContentLoaded', () => {
  setChart();
});

/**
 * レーダーチャートをセットする関数
 * @return void
 */
function setChart() {
  const canvasParents = document.querySelectorAll('.jsCanvasParent');
  if (canvasParents) {
    canvasParents.forEach(canvasParent => {
      const canvas = canvasParent.querySelector('canvas');
      const ctx = canvas.getContext('2d');
      const config = getConfig(canvas);

      const myChart = new Chart(ctx, config);
    });
  }
}

/**
 * configを取得する関数
 * @param {object} - canvas
 * @return {object} - config
 */
function getConfig(canvas) {
  // ラベル
  const labels = [
    '年数', //age
    '安全性', //safety
    '快適性', //comfortability
    '利便性', //convenience
    '環境', //environment
    'おすすめ度', //recommend
  ];
  // データ
  const canvasData = canvas.dataset;
  const data = {
    labels,
    datasets: [
      {
        data: [
          canvasData.age,
          canvasData.safety,
          canvasData.comfortability,
          canvasData.convenience,
          canvasData.environment,
          canvasData.recommend,
        ],
        backgroundColor: 'rgba(0, 95, 122, 0.2)',
        borderColor: 'transparent',
        pointRadius: 0,
        // label: 'name', // chartの名前
        // pointStyle: 'circle',
        // pointBorderColor: "#fff",
        // pointBackgroundColor: "rgba(179,181,198,1)",
      },
    ],
  };

  // 見た目の設定
  const config = {
    type: 'radar',
    data: data,
    options: {
      responsive: true,
      // maintainAspectRatio: true,
      //label非表示
      plugins: {
        legend: {
          display: false,
        },
      },
      scales: {
        r: {
          min: 0, //最小値
          max: 5, //最大値
          ticks: {
            stepSize: 1, //区切り値
          },
          backgroundColor: 'white', // 背景色
          // グリッドライン
          grid: {
            color: '#231815',
            lineWidth: 0.5,
          },
          // アングルライン
          angleLines: {
            color: '#231815',
            lineWidth: 0.5,
          },
          // ポイントラベル
          pointLabels: {
            color: 'black',
            // font: {
            //   size: 10,
            //   weight: 'bold',
            // },
            font: function (context) {
              var width = context.chart.width;
              // var size = Math.round(width / 25);
              var size = Math.round(width / 28);
              return {
                size: size,
                weight: 600,
              };
            },
            // backdropColor: 'unset',
            // backdropPadding: 5,
            // padding: 20,
          },
        },
      },
    },
  };
  return config;
}

イベントを設定


document.addEventListener('DOMContentLoaded', () => {
  setChart();
});

レーダーチャートをセットする関数setChart()を、描画したいタイミングで呼び出します。ここではDOMContentLoadedでHTMLの読み込み完了を待っています。scriptタグにdeferを付けて同じ効果を得る方法は、JavaScriptのasync・deferの違いで解説しています。

レーダーチャートをセットする関数


/**
 * レーダーチャートをセットする関数
 * @return void
 */
function setChart() {
  const canvasParents = document.querySelectorAll('.jsCanvasParent');
  if (canvasParents) {
    canvasParents.forEach(canvasParent => {
      const canvas = canvasParent.querySelector('canvas');
      const ctx = canvas.getContext('2d');
      const config = getConfig(canvas);

      const myChart = new Chart(ctx, config);
    });
  }
}

チャートの数が多くて重い場合は、options.animation: falseで描画アニメーションを止められます。パフォーマンスについては、ドキュメントのパフォーマンスを参照してみてください。

上の場合、jsCanvasParentクラスが付いている要素を取得し、その子要素のcanvas要素を取得します。
canvas.getContext('2d')は、2Dグラフィックを描画するためのメソッドやプロパティを持つオブジェクトを返します。
Chart.jsはこのオブジェクトを通してcanvasに描画します。

チャートを描くための設定(config)は長くなるので、別の関数getConfig()に切り分けています。

そして、Chartをインスタンス化します。
その際、第一引数には、canvas要素のgetContext(‘2d’)を格納した変数を渡します。
第二引数には、チャートを描くための設定(config)を格納した変数を渡します。

configを取得する関数

configを取得する関数の大枠


  /**
 * configを取得する関数
 * @param {object} - canvas
 * @return {object} - config
 */
function getConfig(canvas) {
  // ラベル
  const labels = [

  ];
  // データ
  const canvasData = canvas.dataset;
  const data = {
    labels,
    datasets: [
    ],
  };

  // 見た目の設定
  const config = {

  };
  return config;
}

getConfig()という、configを取得する関数を作成します。
長くなるので、先に大枠を説明します。
チャートのラベルとデータをそれぞれ用意し、configオブジェクトに格納してreturnする関数です。

チャートのラベルになる部分を配列にします。
描画するデータは、どこかからデータを取得して、dataオブジェクトに代入します。上の場合、以下のようにcanvasにデータ属性をセットしてその値を取得しています。

canvasにデータ属性をセットする


<div class="jsCanvasParent">
  <canvas
    data-age="4"
    data-safety="5"
    data-comfortability="3"
    data-convenience="5"
    data-environment="5"
    data-recommend="5"
  ></canvas>
</div>

上のようにして、サーバーサイドからデータをセットすれば動的に表示できます。data-ageのような属性は、JavaScript側ではcanvas.dataset.ageで読み取れます。datasetの値は文字列なので、計算に使う場合はNumber()で数値に変換してください。属性の読み書きの基本は、JavaScriptでHTML属性を操作する方法にまとめています。

ラベルの設定


  /**
 * configを取得する関数
 * @param {object} - canvas
 * @return {object} - config
 */
function getConfig(canvas) {
  // ラベル
  const labels = [
    '- 築年数 -', //age
    '- 安全性 -', //safety
    '- 快適性 -', //comfortability
    '- 利便性 -', //convenience
    '- 住環境 -', //environment
    '- おすすめ度 -', //recommend
  ];

  // 見た目の設定
  const config = {

  };
  return config;
}

チャートのラベルは簡単で、labelsなどの変数を用意して、配列でそれぞれの名前を格納します。ラベルも動的にしたい場合は、JavaScriptでどこかから取得します。
そして、configオブジェクトに格納して、それを返します。

データの設定


  /**
 * configを取得する関数
 * @param {object} - canvas
 * @return {object} - config
 */
function getConfig(canvas) {
  // ラベル
  const labels = [
    '- 築年数 -', //age
    '- 安全性 -', //safety
    '- 快適性 -', //comfortability
    '- 利便性 -', //convenience
    '- 住環境 -', //environment
    '- おすすめ度 -', //recommend
  ];
  // データ
  const canvasData = canvas.dataset;
  const data = {
    labels,
    datasets: [
      {
        data: [
          canvasData.age,
          canvasData.safety,
          canvasData.comfortability,
          canvasData.convenience,
          canvasData.environment,
          canvasData.recommend,
        ],
        backgroundColor: 'rgba(0, 95, 122, 0.2)',
        borderColor: 'transparent',
        pointRadius: 0,
        // label: 'name', // chartの名前
        // pointStyle: 'circle',
        // pointBorderColor: "#fff",
        // pointBackgroundColor: "rgba(179,181,198,1)",
      },
    ],
  };

  // 見た目の設定
  const config = {

  };
  return config;
}

先程作成したラベルの変数をdataに格納します。datasets配列に、オブジェクトとして、データを格納します。
格納するデータは、上の場合、canvas要素のデータ属性に指定されたそれぞれの値です。
背景などの変更があったり、チャート名などを記載したい場合は、ここで設定します。

見た目の設定


    // 見た目の設定
    const config = {
    type: 'radar',
    data: data,
    options: {
      responsive: true,
      // maintainAspectRatio: true,
      //label非表示
      plugins: {
        legend: {
          display: false,
        },
      },
      scales: {
        r: {
          min: 0, //最小値
          max: 5, //最大値
          ticks: {
            stepSize: 1, //区切り値
          },
          backgroundColor: 'white', // 背景色
          // グリッドライン
          grid: {
            color: '#231815',
            lineWidth: 0.5,
          },
          // アングルライン
          angleLines: {
            color: '#231815',
            lineWidth: 0.5,
          },
          // ポイントラベル
          pointLabels: {
            color: 'black',
            // font: {
            //   size: 10,
            //   weight: 'bold',
            // },
            font: function (context) {
              var width = context.chart.width;
              // var size = Math.round(width / 25);
              var size = Math.round(width / 28);
              return {
                size: size,
                weight: 600,
              };
            },
            // backdropColor: 'unset',
            // backdropPadding: 5,
            // padding: 20,
          },
        },
      },
    },
  };

上で作成したdataオブジェクトをconfigのdataに格納すると、ラベル・データ・見た目の設定がひとつにまとまります。

typeでチャートの種類を指定

typeでチャートの種類を指定します。

レスポンシブにしたい場合

重要な設定としては、レスポンシブにしたい場合、responsive: trueにします。

レジェント不要な場合

レジェントが不要な場合、pluginsのlegendをdisplay: falseに設定します。

スケールをカスタマイズする

レーダーチャートの軸はscales.rで設定します。minmaxで最小値・最大値を、ticks.stepSizeで数値の区切りを指定します。Chart.js 2系のscale: { ... }は3系以降では無視されるため、古いサンプルをコピーした場合はここを直してください。

より細かい設定をしたい場合

scalesでグリッド線やアングルラインなどの色を変更したり、ポイントラベルも変更できます。

フォントサイズをwidthに応じてレスポンシブにしたい

フォントサイズもscalesで指定できます。


font: {
  size: 10,
  weight: 'bold',
},

上のようにすると、10pxで固定になります。
そこで、サイズを関数で返すようにします。


font: function (context) {
  var width = context.chart.width;
  // var size = Math.round(width / 25);
  var size = Math.round(width / 28);
  return {
    size: size,
    weight: 600,
  };
},

context.chart.widthには描画時のチャート幅が入るため、それを28で割った値をサイズとして返しています。割る数を小さくすると文字が大きくなります。
fontのように関数を受け付ける設定は、リサイズのたびに再評価されます。これで、フォントサイズをwidthに応じてレスポンシブにできます。

チャートをレスポンシブにする際のCSSの注意点

チャートをレスポンシブにする場合、canvas要素にCSSを適用するのではなく、その親要素をCSSで制御します。
responsive: trueのとき、Chart.jsは親要素のサイズに合わせてcanvasを描き直すためです。親要素の幅を可変にすれば、canvasも追従します。
高さも固定したい場合はmaintainAspectRatio: falseにして、親要素に高さを与えます。

スポンサーリンク