---
title: "平均年齢の変遷グラフ画面設計書"
---

最終更新: 2026-09-10
関連 Issue: #1595（平均年齢の変遷グラフ追加）

---

## 1. 画面概要

| 項目 | 内容 |
|---|---|
| URL | `/average-age` |
| レンダリング方式 | SSR（動的）。Server Component（`app/average-age/page.tsx`）でVercel Blobからメンバーデータを取得し、算出済みの年次データをクライアントコンポーネントに渡す |
| ライブラリ | recharts（`LineChart`）。本リポジトリで`recharts`を使った既存グラフ（`DiscographyStatusChart.tsx`・`GeniusLinksStatusChart.tsx`）はいずれも`BarChart`のみで、`LineChart`の採用は本画面が初出 |
| 対象データ | 結成年（1997年）から現在までの、毎年の結成日（9月14日）時点における在籍メンバーの平均年齢 |

---

## 2. 表示目的

結成から加入・卒業を繰り返すことでグループの平均年齢が上がったり下がったりし、それがグループのカラーの変化に表れているという仮説を、時系列の折れ線グラフとして可視化する。

---

## 3. 集計ロジック

### 3-1. 対象日の算出

結成日（`1997-09-14`、`constants/group.ts`の`GROUP_FORMATION_DATE`として定数化）を基準に、毎年の「結成記念日」（`{年}-09-14`）を対象日とする。

- 開始年: 1997年
- 終了年: 現在の年。ただし現在の年の結成記念日（`{現在年}-09-14`）が未到来の場合（現在日 < 現在年の9/14）は、その年を対象から除外し前年までとする（起こっていない未来時点の値を確定値として表示しないため）

### 3-2. 在籍メンバーの判定

各対象日について、`lib/member-map-utils.ts`の`getActiveMemberIdsAtKeyframe(members, targetDate)`（レーダーチャート時系列化 #1308 で実装済み）をそのまま転用し、在籍メンバー（`joinDate <= 対象日 かつ (gradDate が null または gradDate > 対象日)`）を判定する。

### 3-3. 平均年齢の算出

対象日時点の在籍メンバー全員について、`profile.dob`（生年月日、必須・全メンバー公開）から満年齢を算出し、単純平均を取る。

- 満年齢の算出: 対象日の年 − 生年の年 − (対象日の月日 < 誕生日の月日 の場合は1)
- 在籍メンバーが0人の年（結成前後の理論上のエッジケース）はデータ点として出力しない

---

## 4. 画面遷移

### 4-1. 遷移元

Topページのナビゲーションリンク（メンバー・ユニット・関係性マップ・リリース…の横並び）に「平均年齢」リンクを追加し、`/average-age`へ遷移できるようにする。関係性マップと同様、メンバーデータ全体を俯瞰する機能として、ナビゲーション上は「関係性マップ」の直後に配置する。

### 4-2. 復帰導線

画面上部に「Topに戻る」リンクを設置する（他の主要一覧画面と同様のパターン）。

---

## 5. 画面構成

```
┌───────────────────────────────────────────┐
│ 「Topに戻る」                               │
├───────────────────────────────────────────┤
│ 見出し「平均年齢の変遷」＋説明文             │
│ （結成から現在まで、毎年の結成記念日時点の    │
│ 　在籍メンバーの平均年齢の推移です）          │
├───────────────────────────────────────────┤
│                                           │
│      折れ線グラフ（横軸: 年、縦軸: 平均年齢） │
│                                           │
└───────────────────────────────────────────┘
```

- 単一系列の折れ線グラフとして表示する（グループ全体の平均年齢のみ、系列の切り替えUIは設けない）
- 横軸は西暦年（例: `1997`, `1998`, ...）、縦軸は平均年齢（歳、小数第1位まで）
- グラフ上にカーソルを合わせると、その年の平均年齢をツールチップで表示する（`DiscographyStatusChart.tsx`と同様のTooltipスタイルを踏襲）

---

## 6. コンポーネント方針

- Server Component（`app/average-age/page.tsx`）で`getMembersFromBlob()`によりメンバーデータを取得し、`lib/average-age-utils.ts`の`calculateAverageAgeTimeline()`で年次データ（`{ year: number; averageAge: number }[]`）に変換してからクライアントコンポーネントに渡す（`app/sync-status/page.tsx`と同じ「Server Componentで計算 → Client Componentで描画」の分担パターン）
- 描画は新規クライアントコンポーネント`components/AverageAgeChart.tsx`（`'use client'`）で行う。recharts の`LineChart`・`CartesianGrid`・`XAxis`・`YAxis`・`Tooltip`・`ResponsiveContainer`を用い、配色・グリッド線・ツールチップのスタイルは`DiscographyStatusChart.tsx`を踏襲する

---

## 7. ローディング・エラー状態

| 状態 | 表示内容 |
|---|---|
| データ取得エラー（Blob未取得等） | 「メンバーデータが取得できませんでした」等のエラーメッセージ |
| 算出結果が空（理論上発生しない） | グラフの代わりに「表示できるデータがありません」を表示 |

本画面はServer Componentでレンダリング時に同期的にデータを取得するため、クライアント側のローディング状態（スピナー等）は発生しない。

---

## 改訂履歴（バージョン降順に記載）

| 版 | 更新日 | 変更内容 |
|---|---|---|
| 1.0 | 2026-09-10 | 初版作成（#1595） |
