円グラフ(Pie Chart)— カテゴリー別構成比

グラフ・チャート 初級

このコンポーネントについて

円グラフは各カテゴリーが全体に占める割合を視覚化するのに最適なグラフです。 商品別売上構成・費目別予算・アンケート回答割合など、「全体の中の内訳」を一目で伝えたい場面で広く使われます。 このページでは Chart.js v4(CDN)を使い、外部の JSON ファイルからデータを fetch して描画する実装を紹介します。 データをグラフコードから分離することで、デザインを変えずにデータだけを差し替えられる保守性の高い構成になります。

  • カテゴリー別構成比 — 商品カテゴリー6区分の売上割合を円グラフで可視化。ECサイト・小売業の月次レポートなど実務でよく使われるテーマ
  • 凡例を下部に表示 — 各スライスの色とラベルを凡例として表示。クリックで系列の表示・非表示を切り替え可能
  • ホバーでツールチップ表示 — マウスオーバーで各スライスのラベルとパーセンテージを表示
  • JSON fetch でデータ分離 — グラフコードとデータが独立しているため、JSONを差し替えるだけで別のデータに切り替えられる

実装のポイント・注意点

円グラフは Chart.js の type: 'pie' で実装します。各スライスの色は datasets[0].backgroundColor に配列で渡します。スライス間の区切り線は borderColor: '#fff'borderWidth: 2 を設定することで白い区切りが入り、スライスが視覚的に分離されて読みやすくなります。

ツールチップにパーセンテージを表示するには plugins.tooltip.callbacks.label で計算します。context.parsed に各スライスの値、context.dataset.data から合計を計算し、割り算でパーセントを求めます。Chart.js が自動で表示するデフォルトのツールチップは値のみなので、カスタムが必要です。

fetch同一オリジン または CORS を許可したサーバーからしか読み込めません。ローカルで index.html をダブルクリックして開くと file:// プロトコルになり fetch が失敗します。VS Code の Live Server や Python の http.server など、ローカルサーバーを使って http:// で開いてください。

HTML・CSS・JavaScriptで実装しており、Chart.jsライブラリ(CDN)を1本追加するだけで動きます。フレームワーク不要でコピペすぐに使えます。

デモ

データを読み込んでいます...

サンプルソース

4つのファイルを同じフォルダに保存し、ローカルサーバー(VS Code Live Server 等)で index.html を開くと動作確認できます。
ファイル名:index.html / style.css / script.js / data/data.json — 保存時の文字コードは UTF-8 を指定してください。
⚠️ fetchfile:// では動作しません。ローカルサーバー経由(http://)で開いてください。

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>円グラフ サンプル</title>
  <link rel="stylesheet" href="./style.css">
  <!-- Chart.js v4(UMD ビルド) -->
  <script src="https://cdn.jsdelivr.net/npm/chart.js@4/dist/chart.umd.min.js"></script>
</head>
<body>

<div class="chart-wrap">
  <canvas id="pie-chart" aria-label="カテゴリー別売上構成比の円グラフ" role="img"></canvas>
</div>

<script src="./script.js"></script>
</body>
</html>
body {
  font-family: sans-serif;
  padding: 24px;
  background: #F8FAFC;
}

.chart-wrap {
  max-width: 480px;
  height: 400px;
  background: #fff;
  border: 1px solid #E2E8F0;
  border-radius: 8px;
  padding: 16px;
  box-sizing: border-box;
  margin: 0 auto;
}
// data.json を fetch して円グラフを描画する
var COLORS = [
  { bg: 'rgba(43, 127, 232, 0.85)',  border: '#2B7FE8' },
  { bg: 'rgba(251, 146, 60, 0.85)',  border: '#FB923C' },
  { bg: 'rgba(34, 197, 94, 0.85)',   border: '#22C55E' },
  { bg: 'rgba(168, 85, 247, 0.85)',  border: '#A855F7' },
  { bg: 'rgba(251, 191, 36, 0.85)',  border: '#FBBF24' },
  { bg: 'rgba(100, 116, 139, 0.85)', border: '#64748B' }
];

document.addEventListener('DOMContentLoaded', function () {
  fetch('./data/data.json')
    .then(function (r) { return r.json(); })
    .then(function (data) {
      renderPie(data);
    })
    .catch(function (err) {
      console.error('データの取得に失敗しました:', err);
    });
});

function renderPie(data) {
  var total = data.datasets[0].data.reduce(function (a, b) { return a + b; }, 0);
  var ctx = document.getElementById('pie-chart');
  new Chart(ctx, {
    type: 'pie',
    data: {
      labels: data.labels,
      datasets: [{
        data: data.datasets[0].data,
        backgroundColor: COLORS.map(function (c) { return c.bg; }),
        borderColor: '#fff',
        borderWidth: 2,
        hoverOffset: 8
      }]
    },
    options: {
      responsive: true,
      maintainAspectRatio: false,
      plugins: {
        title: {
          display: true,
          text: data.label,
          font: { size: 13 },
          padding: { bottom: 12 }
        },
        legend: {
          position: 'bottom',
          labels: { padding: 16, font: { size: 12 } }
        },
        tooltip: {
          callbacks: {
            label: function (context) {
              var value = context.parsed;
              var pct = (value / total * 100).toFixed(1);
              return ' ' + context.label + ': ' + pct + '%';
            }
          }
        }
      }
    }
  });
}
{
  "label": "商品カテゴリー別売上構成比(2025年度)",
  "labels": ["食品・飲料", "家電・PC", "アパレル", "日用品", "書籍・ホビー", "その他"],
  "datasets": [
    {
      "data": [32, 24, 18, 12, 8, 6]
    }
  ]
}

AI用プロンプト

このプロンプトをコピーしてAIに渡すと、同様のコンポーネントを生成できます。

ChatGPTやClaudeにこのプロンプトを渡すと、同様のコンポーネントをゼロから生成・カスタマイズできます。ライブラリ指定やデータ変更など、要件を追記して使うのがおすすめです。

※ このプロンプトを使ってもデモとまったく同じ動作にならない場合があります。AIの解釈や生成タイミングによって差が出ることをご了承ください。

💡 jQuery・Vue・React など特定のライブラリで実装したい場合は、プロンプトの末尾に「〇〇を使って実装してください」と追記してください。

# 円グラフ(Chart.js v4)作成依頼

## 概要
Chart.js v4(CDN)と JSON fetch を使った円グラフを実装してください。
外部の data.json からデータを読み込んでグラフを描画します。

## 要件
- Chart.js v4 の UMD ビルドを CDN から読み込む
- data.json を fetch で取得してグラフを描画する
- グラフの種類は円グラフ(type: 'pie')
- 各スライスに色を設定する(6色以上のカラーパレットを配列で管理する)
- スライス間の区切りに白い border を設定する(borderColor: '#fff', borderWidth: 2)
- グラフタイトルをグラフ内(上部)に表示する
- 凡例(legend)を下部に表示する
- ホバーでツールチップにラベルとパーセンテージを表示する
- ホバー時にスライスが外側に飛び出すアニメーション(hoverOffset: 8)を設定する
- fetch 中はローディングメッセージを表示し、完了後に非表示にする
- レスポンシブ対応(responsive: true)
- canvas の親要素の高さを CSS で指定し maintainAspectRatio: false で制御する

## 技術仕様
- HTML / CSS / バニラJavaScript で実装
- 外部ライブラリ:Chart.js v4(https://cdn.jsdelivr.net/npm/chart.js@4/dist/chart.umd.min.js)
- レスポンシブ対応:必要

## データ形式(data.json)
{
  "label": "グラフタイトル",
  "labels": ["カテゴリーA", "カテゴリーB", "カテゴリーC"],
  "datasets": [
    { "data": [40, 35, 25] }
  ]
}

## 出力形式
HTML・CSS・JavaScriptを分けて出力してください。
各ファイルは単独でコピー&ペーストして使えるよう記述してください。