# 通知設計書 21-onLoad

## 概要

本ドキュメントは、Three.jsのLoadingManagerにおける`onLoad`コールバック通知の仕様を定義する。`onLoad`は、LoadingManagerが管理するすべてのアイテムの読み込みが完了した際に呼び出されるコールバック関数である。

### 本通知の処理概要

`onLoad`コールバックは、LoadingManagerが追跡しているすべてのリソース（テクスチャ、3Dモデル、音声ファイルなど）の読み込みが完了したタイミングで発火する通知である。これにより、アプリケーションは読み込み完了後の処理（ローディング画面の非表示化、シーンの表示開始など）を実行できる。

**業務上の目的・背景**：WebGLアプリケーションでは、複数のリソースを並行して読み込むことが一般的である。ユーザーエクスペリエンスの観点から、すべてのリソースが読み込まれるまでローディング画面を表示し、完了後にメインコンテンツを表示することが重要である。`onLoad`コールバックは、この「すべての読み込み完了」というイベントを検知するための仕組みを提供する。

**通知の送信タイミング**：`itemEnd()`メソッドが呼ばれ、`itemsLoaded`（読み込み完了アイテム数）が`itemsTotal`（総アイテム数）と等しくなった時点で発火する。つまり、最後のアイテムの読み込みが完了した直後に通知される。

**通知の受信者**：LoadingManagerインスタンスを作成した開発者、またはDefaultLoadingManagerを使用しているアプリケーションコード。コールバック関数として登録された任意の関数が受信者となる。

**通知内容の概要**：引数なしのコールバック呼び出し。読み込み完了という事実のみが通知され、詳細な情報（読み込まれたアイテムのリストなど）は含まれない。

**期待されるアクション**：受信者は、ローディングインジケーターの非表示、アプリケーションのメイン処理の開始、ユーザーインターフェースのアクティブ化などのアクションを実行することが期待される。

## 通知種別

コールバック関数（Callback Notification）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 同期 |
| 優先度 | 中 |
| リトライ | 無 |

### 送信先決定ロジック

LoadingManagerインスタンスの`onLoad`プロパティに設定された関数が送信先となる。コンストラクタの第一引数、または直接プロパティ代入で設定可能。

```javascript
// コンストラクタで設定
const manager = new LoadingManager(onLoadCallback, onProgressCallback, onErrorCallback);

// プロパティ代入で設定
manager.onLoad = () => console.log('Loading complete!');
```

## 通知テンプレート

### コールバック形式

| 項目 | 内容 |
|-----|------|
| 関数シグネチャ | `() => void` |
| 引数 | なし |
| 戻り値 | なし |

### 本文テンプレート

```javascript
// 典型的な使用例
const manager = new LoadingManager();
manager.onLoad = function() {
    console.log('Loading complete!');
    // ローディング画面を非表示
    document.getElementById('loading').style.display = 'none';
    // メインコンテンツを表示
    document.getElementById('main').style.display = 'block';
};
```

### 添付ファイル

該当なし（コールバック通知のため）

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| なし | onLoadコールバックは引数を持たない | - | - |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| 内部イベント | itemEnd()呼び出し | itemsLoaded === itemsTotal | 最後のアイテムの読み込み完了時 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| onLoadがundefined | コールバックが設定されていない場合は送信されない |
| itemsLoaded < itemsTotal | まだ読み込み中のアイテムがある場合 |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[Loaderがリソース読み込み完了] --> B[manager.itemEnd url 呼び出し]
    B --> C[itemsLoaded++]
    C --> D[onProgressコールバック実行]
    D --> E{itemsLoaded === itemsTotal?}
    E -->|Yes| F[isLoading = false]
    F --> G{onLoadが定義済み?}
    G -->|Yes| H[onLoad 実行]
    G -->|No| I[終了]
    E -->|No| I
    H --> I
```

## データベース参照・更新仕様

### 参照テーブル一覧

該当なし（Three.jsはクライアントサイドライブラリであり、データベースを使用しない）

### 更新テーブル一覧

該当なし

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| コールバック内例外 | onLoad関数内で例外発生 | 呼び出し元に例外が伝播する。try-catchでの対処は呼び出し側の責任 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 0（リトライなし） |
| リトライ間隔 | - |
| リトライ対象エラー | - |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| 1分あたり上限 | 制限なし |
| 1日あたり上限 | 制限なし |

### 配信時間帯

制限なし（クライアントサイドで即時実行）

## セキュリティ考慮事項

- コールバック関数はユーザー定義であるため、XSSなどの脆弱性を含む可能性がある
- 読み込んだリソースの検証は呼び出し側の責任
- サードパーティCDNからのリソース読み込み時はCORSポリシーを考慮すること

## 備考

- `onLoad`コールバックは引数を受け取らないため、読み込み完了したアイテムの詳細情報が必要な場合は`onProgress`コールバックで都度記録しておく必要がある
- DefaultLoadingManagerは全てのローダーで共有されるため、個別の読み込み完了を検知したい場合はカスタムLoadingManagerを使用すること
- 参考: three.js Issue #5689 - onStartがコンストラクタで設定されない理由について

---

## コードリーディングガイド

本通知を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

LoadingManagerの内部状態変数を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | LoadingManager.js | `src/loaders/LoadingManager.js` | 内部変数（isLoading, itemsLoaded, itemsTotal）の役割を理解 |

**読解のコツ**: LoadingManagerはクロージャを使用して内部状態を管理している。コンストラクタ内のlet変数（31-34行目）が状態を保持する。

#### Step 2: エントリーポイントを理解する

onLoadが呼ばれるトリガーとなるitemEnd()メソッドを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | LoadingManager.js | `src/loaders/LoadingManager.js` | itemEnd()メソッドがonLoadを呼び出す条件を確認 |

**主要処理フロー**:
1. **110行目**: `itemEnd`関数定義開始
2. **112行目**: `itemsLoaded++` - 読み込み完了カウントをインクリメント
3. **114-117行目**: `onProgress`コールバックを呼び出し
4. **120行目**: `itemsLoaded === itemsTotal`の条件判定
5. **122行目**: `isLoading = false` - 読み込み状態を終了に設定
6. **124-126行目**: `onLoad`が定義されていれば実行

#### Step 3: 呼び出し元（Loader）を理解する

FileLoaderがどのようにLoadingManagerのメソッドを呼び出すかを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | FileLoader.js | `src/loaders/FileLoader.js` | load()メソッド内でのitemStart/itemEnd呼び出しを確認 |
| 3-2 | Loader.js | `src/loaders/Loader.js` | 基底クラスの構造とDefaultLoadingManagerの参照を確認 |

**主要処理フロー**:
- **321行目**: `this.manager.itemStart(url)` - 読み込み開始を通知
- **317行目**: `this.manager.itemEnd(url)` - finally節で読み込み終了を通知

### プログラム呼び出し階層図

```
FileLoader.load(url)
    │
    ├─ manager.itemStart(url)      [LoadingManager.js:86]
    │      └─ itemsTotal++
    │      └─ onStart(url, itemsLoaded, itemsTotal)  ※初回のみ
    │
    ├─ fetch(req).then(...)        [FileLoader.js:142-319]
    │      └─ onProgress呼び出し（ストリーミング時）
    │
    └─ .finally()
           └─ manager.itemEnd(url) [LoadingManager.js:110]
                  └─ itemsLoaded++
                  └─ onProgress(url, itemsLoaded, itemsTotal)
                  └─ if (itemsLoaded === itemsTotal)
                         └─ onLoad()  ★この通知
```

### データフロー図

```
[入力]                    [処理]                         [出力]

リソースURL ───────▶ FileLoader.load() ───────────▶ 読み込みデータ
                           │
                           │ itemStart()
                           ▼
                    LoadingManager
                    ┌─────────────┐
                    │ itemsTotal++│
                    └─────────────┘
                           │
                           │ itemEnd()
                           ▼
                    ┌─────────────┐
                    │itemsLoaded++│
                    └─────────────┘
                           │
                           │ if (itemsLoaded === itemsTotal)
                           ▼
                    ┌─────────────┐
                    │  onLoad()   │ ───────────▶ アプリケーション
                    └─────────────┘              （コールバック実行）
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| LoadingManager.js | `src/loaders/LoadingManager.js` | ソース | onLoadコールバックの定義と呼び出しロジック |
| FileLoader.js | `src/loaders/FileLoader.js` | ソース | LoadingManagerのitemStart/itemEndを呼び出す実装例 |
| Loader.js | `src/loaders/Loader.js` | ソース | 全ローダーの基底クラス。DefaultLoadingManagerを参照 |
| ImageLoader.js | `src/loaders/ImageLoader.js` | ソース | 画像読み込み時のLoadingManager使用例 |
| TextureLoader.js | `src/loaders/TextureLoader.js` | ソース | テクスチャ読み込み時のLoadingManager使用例 |
| LoadingManager.tests.js | `test/unit/src/loaders/LoadingManager.tests.js` | テスト | LoadingManagerの単体テスト |
