メンバー関係性マップ レーダーチャート画面設計書
最終更新: 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. データ集計ロジック
- ユーザーが「比較グループ」を作成し、任意のメンバー(現役 + OG、ステータスによる絞り込みは行わない)を2名以上追加する
- グループ内の全メンバーペアを列挙し、各ペアについて4軸のスコアを算出する(データ設計書 §8 参照)
- 軸ごとにペア平均を算出する(
sum(score) / pairCount) - メンバーが1名以下でペアが作れないグループは、レーダーチャート・凡例に表示しない
- 複数の比較グループを作成すると、グループごとに多角形を重ねて表示する(比較表示)
現役限定にしない理由
既存の相関図(/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名選択する(
<select>、現役/OGのoptgroup構成。比較グループモードのメンバー追加セレクトと同様の構成) - 基準メンバーと、それ以外の全メンバー(現役 + OG)とのペアスコア(§4のデータ設計と同じ4軸・
getRelationshipScoreのtotal)を算出する - 総合スコア(
total)降順に標準競技順位方式で順位付けする(同率は同順位。同率が N 人いた場合、次の異なるスコアの順位は N 人分スキップする。例: 1位が2名タイの場合、次のスコアは3位になる) - 順位が3以内(
rank <= 3)のメンバーのみを表示対象とする(タイにより4人以上になることもある)
対象範囲は既存の比較グループモードと同様、現役・OGを区別せず全メンバーを対象とする(Active/OG切り替えトグルは設けない、§4「現役限定にしない理由」と同じ方針)。
9-2-1. 同率タイの表示順(#1291)
同一順位内で複数名がタイになった場合、以下の優先順位でタイブレークして並べる(memberId のアルファベット順は使わない)。
- グループの優先順位: 現役グループ → OGグループ の順
- 現役同士のタイブレーク: 基準メンバーの
joinDateとの差(絶対値)が小さい順 - 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 を新設する。
{
"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) |