カレンダーヒートマップライブラリ比較

3つのアプローチでGitHubの草のような日別データをカレンダー形式で表示し、実装方法とスタイルを比較

📊 使用しているサンプルデータ

1年分(365日)の日別アクティビティデータを動的生成して使用しています。

// 1年分のサンプルデータを動的生成する例
const generateYearData = () => {
  const data = []
  const start = new Date('2024-01-01')
  for (let i = 0; i < 365; i++) {
    const date = new Date(start)
    date.setDate(start.getDate() + i)
    data.push({
      day: date.toISOString().split('T')[0],
      value: Math.random() < 0.3 ? 0 : Math.floor(Math.random() * 10)
    })
  }
  return data
}

出力例(一部抜粋):

[
  {
    "day": "2024-01-01",
    "value": 0
  },
  {
    "day": "2024-01-02",
    "value": 4
  },
  {
    "day": "2024-01-03",
    "value": 7
  },
  {
    "day": "2024-01-04",
    "value": 0
  },
  {
    "day": "2024-01-05",
    "value": 2
  },
  {
    "...": "(365件)"
  }
]

1. Nivo(@nivo/calendar)

@nivo/calendarパッケージでカレンダーヒートマップをネイティブサポート。fromとtoで表示期間を指定するだけで自動的に月・曜日のラベルを配置。colorScaleを使った色のカスタマイズや、ホバー時のツールチップも標準で充実している。

✓ 専用パッケージ✓ 美しいデザイン✓ D3.jsベース
import { ResponsiveCalendar } from "@nivo/calendar";

<ResponsiveCalendar
  data={data}          // [{ day: "2024-01-01", value: 5 }, ...]
  from="2024-01-01"
  to="2024-12-31"
  emptyColor="#ebedf0"
  colors={["#9be9a8", "#40c463", "#30a14e", "#216e39"]}
  margin={{ top: 20, right: 20, bottom: 20, left: 20 }}
  monthBorderColor="#ffffff"
  dayBorderWidth={2}
  dayBorderColor="#ffffff"
/>
特徴: 専用パッケージでカレンダーヒートマップに最適化。ツールチップやアニメーションが標準搭載されており、すでにNivoを使用しているプロジェクトへの追加が容易。
tsx
'use client';
import { ResponsiveCalendar } from '@nivo/calendar';

// 日付ごとのアクティビティデータを生成
const generateData = () => {
  const data = [];
  const start = new Date('2024-01-01');
  for (let i = 0; i < 365; i++) {
    const date = new Date(start);
    date.setDate(start.getDate() + i);
    data.push({
      day: date.toISOString().split('T')[0],
      value: Math.floor(Math.random() * 10),
    });
  }
  return data;
};

export function NivoCalendarHeatmap() {
  return (
    <div style={{ height: 200 }}>
      <ResponsiveCalendar
        data={generateData()}
        from="2024-01-01"
        to="2024-12-31"
        emptyColor="#ebedf0"
        colors={['#9be9a8', '#40c463', '#30a14e', '#216e39']}
        margin={{ top: 20, right: 20, bottom: 20, left: 20 }}
        monthBorderColor="#ffffff"
        dayBorderWidth={2}
        dayBorderColor="#ffffff"
      />
    </div>
  );
}

🤖 AIプロンプトテンプレート

React + Tailwind CSSで、Nivo(@nivo/calendar)を使ったカレンダーヒートマップを実装してください。

- 使用ライブラリ: @nivo/calendar の ResponsiveCalendar コンポーネント
- サンプルデータ: 1年分(365日)の日別アクティビティ数({ day: "YYYY-MM-DD", value: number }形式)を動的に生成すること
- インタラクティブ: ホバー時にツールチップで日付と値を表示すること(標準搭載)
- カラースケール: emptyColor・colors プロパティでGitHub風のグリーングラデーションを設定すること
- レスポンシブ: ResponsiveCalendar を使って親要素の幅に応じてサイズが変わるよう対応すること
- 月ラベル: from・to で表示期間を指定するだけで月・曜日ラベルが自動配置されること

⚠️ このプロンプトはあくまでたたき台です。AIの回答はモデルやバージョン、会話の文脈によって毎回異なります。意図通りに動かない場合は、条件を追記・修正してお使いください。

2. カスタムReact実装(SVG)

外部ライブラリに依存せずReact + SVGでカスタム実装。日付計算とグリッド配置をJavaScriptで処理し、色のスケールも自由に定義できる。バンドルサイズへの影響がなく、デザインを完全にコントロールしたい場合に最適。

✓ 依存ゼロ✓ 完全カスタマイズ✓ 軽量
JanFebMarAprMayJunJulAugSepOctNovDecMonWedFri2024-01-01: 72024-01-02: 92024-01-03: 02024-01-04: 92024-01-05: 72024-01-06: 82024-01-07: 82024-01-08: 52024-01-09: 02024-01-10: 72024-01-11: 02024-01-12: 02024-01-13: 62024-01-14: 02024-01-15: 82024-01-16: 92024-01-17: 02024-01-18: 02024-01-19: 72024-01-20: 42024-01-21: 52024-01-22: 42024-01-23: 72024-01-24: 02024-01-25: 42024-01-26: 52024-01-27: 72024-01-28: 02024-01-29: 62024-01-30: 62024-01-31: 62024-02-01: 02024-02-02: 02024-02-03: 82024-02-04: 02024-02-05: 02024-02-06: 62024-02-07: 62024-02-08: 92024-02-09: 02024-02-10: 72024-02-11: 72024-02-12: 02024-02-13: 02024-02-14: 02024-02-15: 82024-02-16: 72024-02-17: 42024-02-18: 42024-02-19: 02024-02-20: 02024-02-21: 02024-02-22: 02024-02-23: 02024-02-24: 42024-02-25: 42024-02-26: 62024-02-27: 72024-02-28: 32024-02-29: 82024-03-01: 82024-03-02: 02024-03-03: 52024-03-04: 02024-03-05: 02024-03-06: 42024-03-07: 82024-03-08: 72024-03-09: 02024-03-10: 92024-03-11: 52024-03-12: 02024-03-13: 02024-03-14: 52024-03-15: 02024-03-16: 02024-03-17: 02024-03-18: 72024-03-19: 82024-03-20: 02024-03-21: 02024-03-22: 02024-03-23: 62024-03-24: 92024-03-25: 02024-03-26: 42024-03-27: 82024-03-28: 92024-03-29: 62024-03-30: 92024-03-31: 82024-04-01: 32024-04-02: 02024-04-03: 42024-04-04: 62024-04-05: 82024-04-06: 02024-04-07: 02024-04-08: 92024-04-09: 32024-04-10: 02024-04-11: 02024-04-12: 82024-04-13: 72024-04-14: 62024-04-15: 52024-04-16: 82024-04-17: 02024-04-18: 42024-04-19: 52024-04-20: 42024-04-21: 02024-04-22: 02024-04-23: 82024-04-24: 32024-04-25: 62024-04-26: 02024-04-27: 42024-04-28: 92024-04-29: 02024-04-30: 02024-05-01: 02024-05-02: 92024-05-03: 02024-05-04: 52024-05-05: 92024-05-06: 32024-05-07: 32024-05-08: 02024-05-09: 92024-05-10: 92024-05-11: 82024-05-12: 62024-05-13: 02024-05-14: 62024-05-15: 62024-05-16: 82024-05-17: 42024-05-18: 82024-05-19: 32024-05-20: 72024-05-21: 02024-05-22: 52024-05-23: 72024-05-24: 42024-05-25: 62024-05-26: 42024-05-27: 62024-05-28: 52024-05-29: 02024-05-30: 42024-05-31: 02024-06-01: 02024-06-02: 72024-06-03: 82024-06-04: 02024-06-05: 52024-06-06: 02024-06-07: 02024-06-08: 02024-06-09: 92024-06-10: 42024-06-11: 82024-06-12: 32024-06-13: 92024-06-14: 92024-06-15: 42024-06-16: 02024-06-17: 02024-06-18: 42024-06-19: 92024-06-20: 52024-06-21: 82024-06-22: 32024-06-23: 62024-06-24: 52024-06-25: 82024-06-26: 72024-06-27: 02024-06-28: 42024-06-29: 42024-06-30: 02024-07-01: 82024-07-02: 82024-07-03: 02024-07-04: 72024-07-05: 02024-07-06: 72024-07-07: 02024-07-08: 92024-07-09: 02024-07-10: 62024-07-11: 42024-07-12: 02024-07-13: 52024-07-14: 32024-07-15: 02024-07-16: 02024-07-17: 02024-07-18: 02024-07-19: 02024-07-20: 02024-07-21: 02024-07-22: 02024-07-23: 02024-07-24: 52024-07-25: 92024-07-26: 62024-07-27: 62024-07-28: 02024-07-29: 52024-07-30: 52024-07-31: 02024-08-01: 92024-08-02: 42024-08-03: 52024-08-04: 02024-08-05: 72024-08-06: 82024-08-07: 92024-08-08: 32024-08-09: 52024-08-10: 52024-08-11: 72024-08-12: 02024-08-13: 52024-08-14: 52024-08-15: 02024-08-16: 62024-08-17: 32024-08-18: 02024-08-19: 02024-08-20: 32024-08-21: 02024-08-22: 82024-08-23: 62024-08-24: 42024-08-25: 02024-08-26: 92024-08-27: 42024-08-28: 62024-08-29: 82024-08-30: 92024-08-31: 62024-09-01: 82024-09-02: 52024-09-03: 02024-09-04: 52024-09-05: 32024-09-06: 72024-09-07: 02024-09-08: 02024-09-09: 02024-09-10: 92024-09-11: 02024-09-12: 92024-09-13: 42024-09-14: 32024-09-15: 92024-09-16: 32024-09-17: 02024-09-18: 02024-09-19: 52024-09-20: 02024-09-21: 02024-09-22: 52024-09-23: 62024-09-24: 62024-09-25: 52024-09-26: 52024-09-27: 02024-09-28: 52024-09-29: 02024-09-30: 82024-10-01: 02024-10-02: 02024-10-03: 02024-10-04: 02024-10-05: 82024-10-06: 92024-10-07: 42024-10-08: 52024-10-09: 52024-10-10: 62024-10-11: 72024-10-12: 82024-10-13: 52024-10-14: 92024-10-15: 72024-10-16: 42024-10-17: 02024-10-18: 02024-10-19: 92024-10-20: 92024-10-21: 02024-10-22: 62024-10-23: 62024-10-24: 32024-10-25: 02024-10-26: 42024-10-27: 32024-10-28: 52024-10-29: 32024-10-30: 02024-10-31: 92024-11-01: 32024-11-02: 62024-11-03: 02024-11-04: 02024-11-05: 82024-11-06: 72024-11-07: 02024-11-08: 92024-11-09: 02024-11-10: 32024-11-11: 82024-11-12: 32024-11-13: 32024-11-14: 02024-11-15: 42024-11-16: 02024-11-17: 02024-11-18: 02024-11-19: 32024-11-20: 62024-11-21: 82024-11-22: 32024-11-23: 82024-11-24: 32024-11-25: 02024-11-26: 02024-11-27: 92024-11-28: 72024-11-29: 72024-11-30: 32024-12-01: 42024-12-02: 92024-12-03: 02024-12-04: 02024-12-05: 02024-12-06: 02024-12-07: 32024-12-08: 02024-12-09: 02024-12-10: 02024-12-11: 42024-12-12: 62024-12-13: 62024-12-14: 52024-12-15: 62024-12-16: 02024-12-17: 42024-12-18: 02024-12-19: 52024-12-20: 62024-12-21: 02024-12-22: 02024-12-23: 02024-12-24: 02024-12-25: 02024-12-26: 82024-12-27: 92024-12-28: 42024-12-29: 02024-12-30: 42024-12-31: 0
Less
More
// 色スケールの定義
const getColor = (value: number): string => {
  if (value === 0) return "#ebedf0";
  if (value <= 2) return "#9be9a8";
  if (value <= 4) return "#40c463";
  if (value <= 6) return "#30a14e";
  return "#216e39";
};

// SVGでセルを描画
<svg width={width} height={height}>
  {weeks.map((week, wi) =>
    week.map((cell, di) => (
      <rect
        key={`${wi}-${di}`}
        x={paddingLeft + wi * (cellSize + gap)}
        y={paddingTop + di * (cellSize + gap)}
        width={cellSize}
        height={cellSize}
        rx={2}
        fill={getColor(cell.value)}
      />
    ))
  )}
</svg>
特徴: 外部依存を一切排除したピュアなReact + SVG実装。日付計算ロジックとレンダリングを自分で制御するため、完全なカスタマイズが可能。バンドルサイズへの影響がない。
tsx
'use client';
// React + SVG カスタムカレンダーヒートマップ
const getColor = (value: number): string => {
  if (value === 0) return '#ebedf0';
  if (value <= 2) return '#9be9a8';
  if (value <= 4) return '#40c463';
  if (value <= 6) return '#30a14e';
  return '#216e39';
};

// 2024年1月分のサンプルデータ
const generateMonthData = (year: number, month: number) => {
  const firstDay = new Date(year, month, 1).getDay();
  const daysInMonth = new Date(year, month + 1, 0).getDate();
  const cells = [];
  for (let i = 0; i < firstDay; i++) cells.push(null);
  for (let d = 1; d <= daysInMonth; d++) {
    cells.push({ day: d, value: Math.floor(Math.random() * 10) });
  }
  return cells;
};

export function CustomCalendarHeatmap() {
  const cells = generateMonthData(2024, 0); // 1月
  const cellSize = 28, gap = 4;

  return (
    <svg viewBox={`0 0 ${7 * (cellSize + gap)} ${6 * (cellSize + gap) + 20}`}
      className="w-full max-w-xs">
      {['日','月','火','水','木','金','土'].map((d, i) => (
        <text key={d} x={i * (cellSize + gap) + cellSize / 2} y={14}
          textAnchor="middle" fontSize={9} fill="#6b7280">{d}</text>
      ))}
      {cells.map((cell, i) => {
        if (!cell) return null;
        const col = i % 7, row = Math.floor(i / 7);
        return (
          <rect key={i}
            x={col * (cellSize + gap)} y={20 + row * (cellSize + gap)}
            width={cellSize} height={cellSize} rx={3}
            fill={getColor(cell.value)}>
            <title>{cell.day}日: {cell.value}件</title>
          </rect>
        );
      })}
    </svg>
  );
}

🤖 AIプロンプトテンプレート

React + Tailwind CSSで、カスタムReact実装(SVG)を使ったカレンダーヒートマップを実装してください。

- 使用ライブラリ: 外部ライブラリなし。React + SVGのみで日付計算・グリッド配置・色スケールをすべて自前実装すること
- サンプルデータ: 1年分(365日)の日別アクティビティ数を動的に生成すること
- インタラクティブ: SVG の title 要素を使って各セルにホバーツールチップを実装すること
- カラースケール: 値の大小に応じて5段階の色を返す getColor 関数を定義すること
- レイアウト: 週を列・曜日を行とした週×7グリッドでセルを配置し、月ラベルと曜日ラベルを表示すること
- 凡例: Less〜More のカラースケール凡例を下部に表示すること

⚠️ このプロンプトはあくまでたたき台です。AIの回答はモデルやバージョン、会話の文脈によって毎回異なります。意図通りに動かない場合は、条件を追記・修正してお使いください。

3. react-calendar-heatmap

react-calendar-heatmapはカレンダーヒートマップに特化した軽量ライブラリ。startDateとendDate、valuesを渡すだけでGitHub風のグラフを即座に実装できる。classForValueでCSSクラスを動的に割り当てることで色のカスタマイズも可能。

✓ 軽量✓ シンプルAPI✓ GitHub風
JanFebMarAprMayJunJulAugSepOctNovDecMonWedFri
import CalendarHeatmap from "react-calendar-heatmap";
import "react-calendar-heatmap/dist/styles.css";

<CalendarHeatmap
  startDate={new Date("2023-12-31")}
  endDate={new Date("2024-12-31")}
  values={[
    { date: "2024-01-01", count: 4 },
    { date: "2024-01-02", count: 7 },
    // ...
  ]}
  classForValue={(value) => {
    if (!value || value.count === 0) return "color-empty";
    if (value.count <= 2) return "color-scale-1";
    if (value.count <= 4) return "color-scale-2";
    if (value.count <= 6) return "color-scale-3";
    return "color-scale-4";
  }}
  showWeekdayLabels
/>
特徴: カレンダーヒートマップに特化したシンプルなAPI。startDate・endDate・valuesを渡すだけで動作し、CSSクラスによる色カスタマイズも直感的。
tsx
'use client';
import CalendarHeatmap from 'react-calendar-heatmap';
import 'react-calendar-heatmap/dist/styles.css';

// サンプルデータ生成
const generateValues = () => {
  const values = [];
  const start = new Date('2023-12-31');
  for (let i = 0; i < 365; i++) {
    const date = new Date(start);
    date.setDate(start.getDate() + i + 1);
    values.push({
      date: date.toISOString().split('T')[0],
      count: Math.floor(Math.random() * 10),
    });
  }
  return values;
};

export function ReactCalendarHeatmap() {
  return (
    <>
      <style>{`
        .color-empty { fill: #ebedf0; }
        .color-scale-1 { fill: #9be9a8; }
        .color-scale-2 { fill: #40c463; }
        .color-scale-3 { fill: #30a14e; }
        .color-scale-4 { fill: #216e39; }
      `}</style>
      <CalendarHeatmap
        startDate={new Date('2023-12-31')}
        endDate={new Date('2024-12-31')}
        values={generateValues()}
        classForValue={(value) => {
          if (!value || value.count === 0) return 'color-empty';
          if (value.count <= 2) return 'color-scale-1';
          if (value.count <= 4) return 'color-scale-2';
          if (value.count <= 6) return 'color-scale-3';
          return 'color-scale-4';
        }}
        showWeekdayLabels
      />
    </>
  );
}

🤖 AIプロンプトテンプレート

React + Tailwind CSSで、react-calendar-heatmap を使ったカレンダーヒートマップを実装してください。

- 使用ライブラリ: react-calendar-heatmap パッケージの CalendarHeatmap コンポーネント、および react-calendar-heatmap/dist/styles.css
- サンプルデータ: 1年分(365日)の日別アクティビティ数({ date: "YYYY-MM-DD", count: number }形式)を動的に生成すること
- インタラクティブ: ホバーで日付と値を表示すること
- カラースケール: classForValue プロパティでCSSクラス(color-empty・color-scale-1〜4)を動的に割り当て、色をCSSで定義すること
- 設定: startDate・endDate・values・showWeekdayLabels を指定するだけで動作すること

⚠️ このプロンプトはあくまでたたき台です。AIの回答はモデルやバージョン、会話の文脈によって毎回異なります。意図通りに動かない場合は、条件を追記・修正してお使いください。

ライブラリ比較

アプローチレンダリング導入コストカスタマイズ性おすすめ用途
NivoSVG低(専用パッケージ)デザイン重視のダッシュボード
カスタムReact実装SVG高(自作)非常に高独自デザインが必要な場合
react-calendar-heatmapSVG非常に低シンプルなGitHub風グラフ

選択のポイント

  • Nivo: @nivo/calendarで最も手軽に高品質なカレンダーヒートマップを実装可能。すでにNivoを使用しているプロジェクトへの追加が容易。
  • カスタムReact実装: 外部依存を排除したい場合や、完全に独自のデザインが必要な場合に選択。実装コストはかかるが柔軟性は最高。
  • react-calendar-heatmap: 導入が最もシンプルでGitHub風のグラフをすぐに実現したい場合に最適。軽量でシンプルな用途に向いている。

典型的な使用例

  • 🌱アクティビティ記録: GitHubのコントリビューショングラフのような日別活動量の可視化
  • 📊売上・アクセス分析: 日別の売上やページビューの年間トレンドをひと目で把握
  • 🏃習慣トラッキング: 運動・学習・瞑想などの日課の継続状況を可視化
  • 📅イベント密度: カレンダー上でイベントや問い合わせの集中度を色で表現

⚠️ 使用時の注意点

  • 1年分のデータ(365件)を扱うため、データ生成・取得の効率に注意する
  • 色のスケール設定が重要で、値が0の日と欠損データは明確に区別する
  • 週の始まりを日曜・月曜どちらにするか、ロケールに合わせて設定する
  • モバイル表示では横幅が足りなくなりやすいため、スクロール対応またはレスポンシブな縮小対応を検討する