---
title: "メンバー関係性マップ レーダーチャート画面設計書"
---

最終更新: 2026-08-06
関連 Issue: #1198（関係性スコアリングマップ）/ #1268（関係性スコアリング設計書作成）/ #1271（レーダーチャート画面の新設）/ #1282（関係性ランキングモードの追加）/ #1290（ランキングモードのモバイル表示改善）/ #1308（歴史構造の時系列化）/ #11（時系列化設計書作成）

---

## 1. 画面概要

| 項目 | 内容 |
|---|---|
| URL | `/member-map/radar` |
| レンダリング方式 | Client Side（`'use client'`） |
| ライブラリ | 自作 SVG コンポーネント `components/MemberMapRadarChart.tsx`（既存 `TimelineActivityChart` 等と同様、外部チャートライブラリは追加しない） |
| 表示モード | 「比較グループ（手動）」（§2〜§8）／「関係性ランキング（自動）」（§9） の2モードをタブ切り替え |
| 対象データ | 比較グループモード: ユーザーが選択した任意のメンバー集合の関係性スコア平均値。ランキングモード: 選択した1名と他の全メンバーとのペアスコア |

---

## 2. 表示目的

ユーザーが選んだメンバー同士の「関係性の形状」を比較できるようにする。選択したメンバー集合内の全ペアスコア（データ設計書 §8 参照）を4軸で平均し、レーダーチャートとして可視化する。

### 期(generation)単位の平均集計を採用しなかった理由

初版では期ごとに全メンバーを自動集計する方式を検討したが、以下の理由で軸の情報量が乏しくなるため不採用とした。

- 師弟関係は世代を跨いだ関係が中心のため、同期内のペアではほぼ0ptになる
- 出身地距離も、同期内でたまたま同じ都道府県・地方でない限り0ptになりやすい
- 結果として「在籍重なり」以外の軸が潰れ、期ごとの形状の違いが見えにくい

そのため、ユーザーが世代を跨いで任意にメンバーを選べる方式とし、師弟関係・出身地距離の軸にも意味のある値が出せるようにした。

---

## 3. 軸定義（4軸固定）

| 軸 | 対応するスコア | 配点上限 |
|---|---|---|
| 在籍重なり | 在籍期間重なりスコア | 40pt |
| 師弟関係 | 師弟関係スコア | 30pt |
| カラー距離 | メンバーカラー距離スコア | 20pt |
| 出身地距離 | 出身地距離スコア | 10pt |

> 各軸の配点上限が異なるため（40/30/20/10pt）、レーダーチャート上では各軸を 0〜100% に正規化して表示する（`value / axisMax × 100`）。上限の異なる軸をそのまま重ねると軸間の比較が誤読を招くため。

---

## 4. データ集計ロジック

1. ユーザーが「比較グループ」を作成し、任意のメンバー（現役 + OG、ステータスによる絞り込みは行わない）を2名以上追加する
2. グループ内の全メンバーペアを列挙し、各ペアについて4軸のスコアを算出する（データ設計書 §8 参照）
3. 軸ごとにペア平均を算出する（`sum(score) / pairCount`）
4. メンバーが1名以下でペアが作れないグループは、レーダーチャート・凡例に表示しない
5. 複数の比較グループを作成すると、グループごとに多角形を重ねて表示する（比較表示）

### 現役限定にしない理由

既存の相関図（`/member-map`）には「OGを含む」トグルがあるが、これは**表示上の切り替え**であり、`member_relationships` 自体は現役・OG を区別せず全メンバーの関係性を保持している（データ設計書 §2-1）。

レーダーチャートは任意のメンバー同士の関係性を比較する機能であり、現役・OGを問わず比較したいという利用目的を妨げないよう、相関図のような Active/OG 切り替えトグルは設けず、**選択肢は常に全メンバーを対象**とする。

---

## 5. 画面遷移

### 5-1. 遷移元

`/member-map`（メンバー関係性マップ画面）のヘッダーに「↗ レーダーチャートで見る」リンクを追加し、`/member-map/radar` へ遷移できるようにする（既存のタイムラインパネルの「↗ タイムラインで見る」リンクと同様のパターン。画面設計書 §9-1 参照）。

### 5-2. 復帰導線

レーダーチャート画面のヘッダーに「← メンバー関係性マップに戻る」リンクを設置し、`/member-map` に戻れるようにする。

---

## 6. 画面構成

```
┌───────────────────────────────────────────┐
│ ヘッダー（タイトル + タイトル右の説明文）    │
├───────────────────────────────────────────┤
│ 「比較するメンバーを選択してください         │
│   （グループごとに2名以上）」+ グループ追加  │
│ ┌─ グループ1 ─────────────────────────┐   │
│ │ [Aさん ×][Bさん ×]  [+ メンバーを追加▼] │  │
│ │                          [グループを削除]│  │
│ └───────────────────────────────────┘   │
│ ┌─ グループ2 ─────────────────────────┐   │
│ │ ...                                  │  │
│ └───────────────────────────────────┘   │
├───────────────────────────────────────────┤
│                                           │
│         レーダーチャート本体（SVG）         │
│         ・4軸: 在籍重なり/師弟/色/出身地    │
│         ・グループごとに色分けした多角形    │
│                                           │
├───────────────────────────────────────────┤
│ 「凡例」                                   │
│ 凡例（グループごとの色 + メンバー名一覧）    │
└───────────────────────────────────────────┘
```

- タイトル「メンバー関係性レーダーチャート」の右に、画面の目的を説明するテキスト（「在籍重なり・師弟関係・カラー距離・出身地距離の4軸で、選択したメンバー同士の関係性を比較できます」）を表示する
- 「比較するメンバーを選択してください（グループごとに2名以上）」という見出しと「+ グループを追加」ボタンを表示する。グループが1つもない場合はその旨の案内文を表示する
- 各グループカードには以下を表示する
  - グループの識別色（凡例と共通のスウォッチ）
  - グループ名（「グループN」、Nは表示上の連番。グループ削除で繰り上がる）
  - 選択済みメンバーのチップ一覧（チップ内の「×」ボタンでそのメンバーをグループから外す）
  - メンバー追加用の `<select>`（既存 `MemberSelect` と同様、現役/OGのoptgroup構成。既にグループに含まれるメンバーは選択肢から除外する）
  - 「グループを削除」ボタン（グループごと削除）
- メンバーの追加・削除・グループの追加・削除を行うと、レーダーチャート・凡例に即時反映する（API再フェッチは行わず、取得済みデータをクライアント側で再計算するのみ）
- 凡例の上に見出し「凡例」を表示する。各グループの色とメンバー名一覧（「Aさん・Bさん」形式）を表示する
- グループの識別色は固定パレット（`GROUP_COLOR_PALETTE`、8色）から表示順に割り当てる。9グループ目以降は先頭から色を再利用する

---

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

既存の `TimelineActivityChart` 等と同様、外部チャートライブラリ（recharts 等）を追加せず、SVG の `<polygon>`（多角形）・`<line>`（軸線）・`<text>`（軸ラベル）を組み合わせた自作コンポーネント `components/MemberMapRadarChart.tsx` として実装する。このコンポーネントはグループ・期などのデータ種別に依存しない汎用的な props（軸ラベル・系列データ）で構成し、比較対象の単位（グループ／期など）を問わず再利用できる。

- 4軸は上（在籍重なり）から時計回りに90度間隔で配置する（師弟関係→右、カラー距離→下、出身地距離→左）
- 目盛りは4段階のグリッド多角形（25%/50%/75%/100%）を表示する
- グループごとの多角形は塗り15%不透明度＋輪郭線2pxで重ね描画し、複数グループを選択しても重なりが視認できるようにする
- 配色は既存のダークテーマ（背景 `#0f0f0f`、テキスト白系半透明）を踏襲し、グリッド線・軸線は低コントラストの白系半透明線とする

---

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

| 状態 | 表示内容 |
|---|---|
| 初期ロード中 | 「読み込み中...」 |
| グループ未作成・ペアが作れないグループのみ | レーダーチャートは多角形なしで表示（グリッド・軸のみ）。「+ グループを追加」からメンバーを選ぶよう案内文を表示 |
| API 取得エラー | エラーメッセージ |

---

## 9. 関係性ランキングモード（自動・#1282）

### 9-1. 概要

比較グループモード（§2〜§8）とは別に、選択した1名のメンバーと関係性が高いメンバーを自動抽出する「関係性ランキング（自動）」モードを設ける。画面上部のタブで「比較グループ（手動）」／「関係性ランキング（自動）」を切り替える。

### 9-2. 集計ロジック

1. ユーザーが基準メンバーを1名選択する（`<select>`、現役/OGのoptgroup構成。比較グループモードのメンバー追加セレクトと同様の構成）
2. 基準メンバーと、それ以外の全メンバー（現役 + OG）とのペアスコア（§4のデータ設計と同じ4軸・`getRelationshipScore` の `total`）を算出する
3. 総合スコア（`total`）降順に**標準競技順位方式**で順位付けする（同率は同順位。同率が N 人いた場合、次の異なるスコアの順位は N 人分スキップする。例: 1位が2名タイの場合、次のスコアは3位になる）
4. 順位が3以内（`rank <= 3`）のメンバーのみを表示対象とする（タイにより4人以上になることもある）

対象範囲は既存の比較グループモードと同様、現役・OGを区別せず全メンバーを対象とする（Active/OG切り替えトグルは設けない、§4「現役限定にしない理由」と同じ方針）。

### 9-2-1. 同率タイの表示順（#1291）

同一順位内で複数名がタイになった場合、以下の優先順位でタイブレークして並べる（`memberId` のアルファベット順は使わない）。

1. **グループの優先順位**: 現役グループ → OGグループ の順
2. **現役同士のタイブレーク**: 基準メンバーの `joinDate` との差（絶対値）が小さい順
3. **OG同士のタイブレーク**: `gradDate` が新しい（最近卒業した）順。卒業日が同一の場合は、基準メンバーの `joinDate` との差が小さい順で副次タイブレーク

「加入期が近い順」は期番号（`generation`）ではなく、加入日（`joinDate`）ベースで統一する（OG側の卒業日という日付ベースの基準と揃えるため）。

### 9-3. 画面構成

```
┌───────────────────────────────────────────┐
│ 「基準メンバーを選択してください」            │
│ [<select> 基準メンバー▼]                    │
├───────────────────────────────────────────┤
│  1位          │  2位          │  3位        │
│ ┌──────────┐ │ ┌──────────┐ │ ┌────────┐ │
│ │ 氏名      │ │ │ 氏名      │ │ │ 氏名    │ │
│ │ NNpt      │ │ │ NNpt      │ │ │ NNpt    │ │
│ │ レーダー   │ │ │ レーダー   │ │ │ レーダー │ │
│ └──────────┘ │ └──────────┘ │ └────────┘ │
│ （同率タイの場合は同じ列に縦に複数枚並ぶ）      │
└───────────────────────────────────────────┘
```

- グリッドは横3列（1位・2位・3位）。各列の見出しに「N位」を表示する
- 同率タイで同じ順位に複数名いる場合、その列内に縦に複数のカードを積む
- 各カードには、対象メンバーの氏名・総合スコア（`NNpt`）・4軸レーダーチャート（基準メンバーとのペアスコアを正規化した単一系列）を表示する
- レーダーチャートの色は `getScoreColor`（総合スコアに応じてグレー〜琥珀のグラデーション）を用いる。比較グループモードのグループ識別色パレットとは異なる配色軸のため区別する
- 基準メンバー未選択時は案内文（「メンバーを選択すると、関係性が高い上位3人を表示します。」）を表示する

### 9-4. モバイル表示（#1290）

3列固定グリッドは最小幅240px×3列＝720pxを要求するため、モバイル幅では2位・3位の列が画面外にはみ出し、かつ本画面はページ全体で横スクロールを許可していない（`overflow-x: hidden`）ため閲覧できなくなる。

- `@media (min-width: 768px)` 未満（モバイル幅）ではグリッドを1列縦積みにする（既存の `app/timeline/page.module.css` と同様、PC幅でのみ複数列グリッドに切り替えるmobile-firstパターンに合わせる）
- `@media (min-width: 768px)` 以上では現状通り3列グリッドを維持する
- 縦積み時も「1位→2位→3位」の順で上から表示する。順位ごとの見出し（「N位」）は1つのみ表示し、同率タイのカードはその見出しの下に複数枚並べる（列の概念自体は変えず、単に画面幅に応じて列数を切り替えるのみ）

---

## 10. 時系列表示（#1308）

### 10-1. 概要

比較グループモード（§2〜§8）・関係性ランキングモード（§9）の両方に対し、メンバーの加入・卒業に伴うスコア変化をアニメーションで可視化する機能を追加する。§2〜9で定義した静的な表示に、時間軸操作（キーフレーム送り・自動再生）を追加する形で提供し、既存の静的表示自体は変更しない。

年表／タイムラインとの連携は本設計の対象外とする（詳細は§10-7）。

### 10-2. キーフレーム算出ロジック（共通）

- 対象（比較グループモードではグループ内の各メンバー、ランキングモードでは基準メンバー1名）の加入日・卒業日をキーフレームの基点とする
- 直近のキーフレームから半年以上間隔が空く場合、その間を半年おきの定期チェックポイントで補完する
- 4軸（在籍重なり・師弟関係・カラー距離・出身地距離）のうち、時間で変化するのは「在籍重なり」のみ（既存の `getOverlapScore` が `now` 引数を持つ設計のため）。他3軸は時間不変のまま常時表示する（4軸構成自体の見直しは行わない）

このロジックは比較グループモード・ランキングモード共通とし、#1310（計算ロジックの実装）で具体化する。

### 10-3. アニメーション・UI操作

- キーフレーム間の値はなめらかに線形補間する
- 画面下部に時系列操作バーを新設し、以下の操作方法を両方提供する
  - **手動スライダー**: つまみをドラッグして任意のキーフレーム位置へ直接移動できる
  - **自動再生（Playボタン）**: 押下すると現在位置から最終キーフレームまで一定間隔で自動的に進行する。再生中は一時停止ボタンに切り替わる
- スライダー上には算出済みキーフレームの位置をマーカーとして表示する
- 現在のキーフレーム日付（例:「2015年4月」）を操作バー付近に表示する

```
┌───────────────────────────────────────────┐
│  （既存のレーダーチャート・凡例。§6/§9-3）    │
├───────────────────────────────────────────┤
│ 現在位置: 2015年4月                         │
│ [▶再生] ●━━━━━━━◯───────────────           │
│         ↑キーフレームマーカー                │
└───────────────────────────────────────────┘
```

この操作バーは#1311（アニメーションUIの実装）で具体化する。

### 10-4. 比較グループモード固有仕様

### 10-4-1. グループ種別の再編

既存の「手動選択によるグループ作成」に加え、以下2種類の自動生成グループ種別を新設する。既存の手動選択グループは、時系列表示の主眼ではないオプション（補助的な使い方）に位置づけを変更する。

| グループ種別 | 生成方法 | メンバー構成 |
|---|---|---|
| 期グループ | 自動（期ごとに1グループ） | 同一期のメンバーで固定（時間に依存せず不変） |
| グループ全体 | 自動（現役・OGを問わず全メンバーを対象） | キーフレーム日付ごとに動的算出（加入日 ≤ キーフレーム日 ＜ 卒業日 を満たすメンバーを再計算） |
| 手動選択グループ | ユーザー操作（既存同様、オプション） | ユーザー選択のまま固定 |

「グループ全体」は「モーニング娘。が年々どう変化してきたか」を検証する趣旨のため、今日時点の固定ロスター（現役メンバーのみ）ではなく、現役・OGを問わず、各キーフレーム時点で実際に在籍していたメンバーに動的に変える。期グループ・手動選択グループはメンバー構成自体は固定だが、「在籍重なり」軸は時間で変化するため、キーフレーム送りによる形状変化は起こりうる。

### 10-4-2. 初期表示・表示開始キーフレーム

| グループ種別 | 初期表示 | 表示開始キーフレーム |
|---|---|---|
| （未選択） | グループ未選択（案内文を表示。§8と同様） | - |
| 期グループ選択時 | そのグループの最初のキーフレームから表示 | グループ内メンバーの最も早い加入日 |
| グループ全体選択時 | グループ結成年のキーフレームから表示 | 1997年（モーニング娘。結成年） |
| 手動選択グループ選択時 | そのグループの最初のキーフレームから表示 | グループ内メンバーの最も早い加入日 |

### 10-4-3. 卒業後のスコア凍結表現

追加ロジックは不要。両者が卒業済みのペアは `now` を進めても `overlapEnd` が過去の固定値になるため、既存関数（`getOverlapScore`）の性質として自然に凍結する（期グループ・手動選択グループ共通）。

### 10-5. 関係性ランキングモード固有仕様

- キーフレーム基点は基準メンバー本人の加入日・卒業日（§10-2の「対象」を基準メンバー1名とする）
- 時系列の表示開始点は基準メンバーの加入日以降のみとする（加入前は表示しない）
- 上位ランクインメンバー自体の入れ替わり:
  - ランク外に出るメンバー: フェードアウト
  - 新規ランクインするメンバー: フェードイン（浮かび上がる演出）
- 同一メンバー内の順位変動: 順位が変わったメンバーの氏名テキストを強調表示する（§9-3のカード内氏名表示に適用）

### 10-6. 終端日設定機能

#### 10-6-1. 概要

§10-2のキーフレーム算出における配列の終端日（`keyframeEndDate`）を、コード改修なしに更新できるようにする設定機能。メンバーの卒業"時期"が発表されても正確な卒業日が確定するまでの期間、最新の状況を反映した終端日を暫定的に設定できるようにする。

#### 10-6-2. データ

Vercel Blobファイル `radar-chart-timeline-config.json` を新設する。

```json
{
  "keyframeEndDate": "2026-12-31"
}
```

キーフレーム算出関数（#1310）は、対象内の最後の既知イベント日（加入日・卒業日）と `keyframeEndDate` のうち遅い方をキーフレーム配列の終端とする。

#### 10-6-3. 画面

デスクトップモード限定（`DESKTOP_MODE=1` 時のみ）で、レーダーチャート画面（比較グループ・ランキング両モード共通）に設定アイコンを表示する。

```
┌───────────────────────────────────────────┐
│  （既存のレーダーチャート・凡例。§6/§9-3）    │  ⚙
├───────────────────────────────────────────┤
│ 現在位置: 2015年4月                         │
│ [▶再生] ●━━━━━━━◯───────────────           │
└───────────────────────────────────────────┘
```

設定アイコンをクリックすると、`keyframeEndDate` を変更するダイアログを表示する。日付入力は `<input type="date">` を用いる（本画面の期セレクタ等と同様、新規ライブラリは導入しない）。

保存すると `keyframeEndDate` がBlobに書き込まれ、画面はこの値を使ってキーフレームを再計算する。

#### 10-6-4. 警告表示

現在日時が `keyframeEndDate` を過ぎている場合、デスクトップモード限定で警告を表示する（例:「終端日が過去の日付になっています。設定を更新してください」）。一般ユーザーには表示しない（設定変更の権限がなく対処できないため）。

#### 10-6-5. API

##### GET /api/radar-chart-timeline-config

`keyframeEndDate` を取得する。公開（本画面の表示処理・#1310のロジック双方から参照する）。

- **実装:** `app/api/radar-chart-timeline-config/route.ts`
- **レスポンス:** `{ "keyframeEndDate": "2026-12-31" }`
- **未設定時:** Blobファイル未作成（初回アクセス）の場合は `{ "keyframeEndDate": null }` を200で返す（設定UI・#1310のロジックともに、`null` は「終端日未設定」として扱う）
- **エラー:** 500 → `{ "error": "終端日設定の取得に失敗しました。" }`

##### PUT /api/radar-chart-timeline-config

`keyframeEndDate` を更新する。デスクトップモード限定（`app/link-editor` の `requireDesktopMode()` パターンを踏襲し、`DESKTOP_MODE=1` でない場合は403を返す）。

- **実装:** `app/api/radar-chart-timeline-config/route.ts`
- **リクエストボディ:** `{ "keyframeEndDate": "2026-12-31" }`
- **レスポンス:** `{ "keyframeEndDate": "2026-12-31" }`
- **エラー:** 400 → `{ "error": "keyframeEndDate は YYYY-MM-DD 形式で指定してください。" }`（不正な日付形式の場合）
- **エラー:** 403 → `{ "error": "この操作はデスクトップモードでのみ使用できます。" }`（`DESKTOP_MODE=1` でない場合）
- **エラー:** 500 → `{ "error": "終端日設定の保存に失敗しました。" }`

### 10-7. スコープ外（別Issueで対応）

年表／タイムラインとの連携（比較グループモード: #1312、ランキングモード: #1316）は本設計の対象外とし、保留とする。

---

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

| バージョン | 日付 | 変更内容 |
|---|---|---|
| 2.7 | 2026-08-06 | §10-6-5 GET APIに「未設定時」の仕様を追加。Blobファイル未作成（初回アクセス）の場合は `{ "keyframeEndDate": null }` を200で返す実装（#1477実装時に判明した、設計書に明記のなかったエッジケース） |
| 2.6 | 2026-08-06 | §10-6「終端日設定機能」を追加。キーフレーム配列の終端日（`keyframeEndDate`）を、Vercel Blobファイル・デスクトップモード限定の設定UIからコード改修なしに更新できる仕組みを新設。「スコープ外」節を§10-7へ移動し、in-scope機能を先に配置する構成に整理。API仕様にエンドポイントパス・実装ファイルパス・リクエスト/レスポンス例・エラーケースを明記（#34） |
| 2.5 | 2026-08-05 | PR #33 レビュー指摘を反映。§10-4「グループ全体」の候補メンバーを「現役・OGを問わず全メンバー」に修正（説明文の「実際に在籍していたメンバー」と矛盾していたOG除外の記載を削除）。§10-1 の年表／タイムライン連携に関する記述を §10-6 への参照に統一し重複を解消。§10-4 配下の見出しに節番号を付与 |
| 2.4 | 2026-08-05 | §10「時系列表示」を追加。比較グループ・ランキング両モードに、加入・卒業に伴うスコア変化をキーフレームアニメーション（手動スライダー＋自動再生の両対応）で可視化する仕様を追記。比較グループモードのグループ種別を「期グループ」「グループ全体」「手動選択グループ」の3種に再編（#1308、#11） |
| 2.3 | 2026-07-09 | §9-2-1「同率タイの表示順」を追加。`memberId` アルファベット順だったタイブレークを、グループ優先順位（現役→OG）と加入日・卒業日ベースの順序に変更（#1291） |
| 2.2 | 2026-07-07 | §9-4「モバイル表示」を追加。ランキングモードの3列グリッドがモバイル幅で閲覧不能になる問題を修正するため、768px未満は1列縦積みにするmobile-firstのブレークポイントを新設（#1290） |
| 2.1 | 2026-07-07 | §9「関係性ランキングモード（自動）」を追加。選択した1名と関係性が高い上位3人（同率タイ含む）を標準競技順位方式で自動抽出するモードを新設（#1282） |
| 2.0 | 2026-07-05 | 期(generation)単位の自動平均集計から、ユーザーが任意のメンバーを選択して比較グループを作る方式に変更。師弟関係・出身地距離の軸が同期内でほぼ0ptになり情報量が乏しくなるため（#1271） |
| 1.2 | 2026-07-05 | §6 に、期セレクタ・凡例の見分けがつきにくいというレビュー指摘を受けた見出しテキスト（タイトル右の説明文・「表示する期を選択してください」・「凡例」）を追記（#1271） |
| 1.1 | 2026-07-05 | §1 URL・§7 コンポーネント方針（配色・軸配置等）を実装確定内容に更新。§6 に期セレクタのインタラクション詳細を追記し、§9「フェーズ・実装予定」を削除（#1271） |
| 1.0 | 2026-07-04 | 初版作成（#1268） |
