# 機能設計書 36-Canvas

## 概要

本ドキュメントは、Avalonia UIフレームワークにおけるCanvas（キャンバスレイアウト）の機能設計を定義するものである。Canvasは子要素を任意の座標位置に配置するシンプルなレイアウトパネルを提供する。

### 本機能の処理概要

Canvasは、Left/Top/Right/Bottom添付プロパティで指定された絶対座標に子要素を配置するレイアウトパネルを提供する。他のパネルとは異なり、自動的なレイアウト計算を行わず、開発者が明示的に各要素の位置を指定する。

**業務上の目的・背景**：グラフィックエディタ、ゲームUI、図形描画、ドラッグ＆ドロップインターフェースなど、要素の位置を精密に制御する必要があるシーンでは、自動レイアウトではなく絶対座標指定が必要となる。Canvasは、このような位置指定の自由度が求められるUIを実現するための基盤を提供する。

**機能の利用シーン**：
- 図形描画エディタ
- ゲームUI（スプライト配置）
- フローチャートやダイアグラム
- ドラッグ＆ドロップによる要素配置

**主要な処理内容**：
1. Left/Top添付プロパティによる左上基準の配置
2. Right/Bottom添付プロパティによる右下基準の配置
3. 無制限サイズでの子要素計測
4. DesiredSizeは常に(0,0)を返却（サイズは親で決定）

**関連システム・外部連携**：Panel基底クラスを継承し、INavigableContainerインターフェースを実装。

**権限による制御**：特になし。UIコンポーネントとしてアプリケーション側で必要に応じて実装。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | Canvasは絶対座標配置が必要な画面で使用される |

## 機能種別

レイアウト制御 / UIコンテナ

## 入力仕様

### 添付プロパティ

| プロパティ名 | 型 | 説明 | デフォルト値 |
|-------------|-----|------|-------------|
| Canvas.Left | double | 子要素の左端からの距離 | NaN |
| Canvas.Top | double | 子要素の上端からの距離 | NaN |
| Canvas.Right | double | 子要素の右端からの距離 | NaN |
| Canvas.Bottom | double | 子要素の下端からの距離 | NaN |

### 特記事項

- ClipToBoundsのデフォルト値はfalse（Canvas外にはみ出る要素も表示）
- Left/Rightの両方が指定された場合、Leftが優先
- Top/Bottomの両方が指定された場合、Topが優先

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| DesiredSize | Size | 常に(0,0)を返却 |
| 子要素の最終位置 | Rect | 配置フェーズで決定された各子要素の位置とサイズ |

## 処理フロー

### 処理シーケンス

```
1. MeasureOverrideフェーズ
   ├─ 利用可能サイズを無限大に設定
   ├─ 各子要素を計測
   └─ (0,0)を返却
2. ArrangeOverrideフェーズ
   ├─ 各子要素についてArrangeChild呼び出し
   │   ├─ Left/Right値からX座標決定
   │   ├─ Top/Bottom値からY座標決定
   │   └─ 子要素を配置
   └─ finalSizeを返却
```

### フローチャート

```mermaid
flowchart TD
    A[ArrangeChild開始] --> B{Left指定?}
    B -->|Yes| C[x = Left]
    B -->|No| D{Right指定?}
    D -->|Yes| E[x = finalSize.Width - child.Width - Right]
    D -->|No| F[x = 0]
    C --> G{Top指定?}
    E --> G
    F --> G
    G -->|Yes| H[y = Top]
    G -->|No| I{Bottom指定?}
    I -->|Yes| J[y = finalSize.Height - child.Height - Bottom]
    I -->|No| K[y = 0]
    H --> L[child.Arrange]
    J --> L
    K --> L
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-36-01 | Left優先 | Left/Rightの両方が指定された場合、Leftが優先される | 両方指定時 |
| BR-36-02 | Top優先 | Top/Bottomの両方が指定された場合、Topが優先される | 両方指定時 |
| BR-36-03 | デフォルト位置 | Left/Right、Top/Bottomいずれも指定がない場合は0 | 未指定時 |
| BR-36-04 | サイズゼロ返却 | MeasureOverrideは常に(0,0)を返却し、親がサイズ決定 | 常時 |

### 計算ロジック

**X座標計算**:
```
if (Left != NaN) x = Left
else if (Right != NaN) x = finalSize.Width - childWidth - Right
else x = 0
```

**Y座標計算**:
```
if (Top != NaN) y = Top
else if (Bottom != NaN) y = finalSize.Height - childHeight - Bottom
else y = 0
```

## データベース操作仕様

該当なし（UIコンポーネントのためDB操作は行わない）

## エラー処理

特になし（NaN値は適切に処理される）

## パフォーマンス要件

- 非常に軽量なレイアウト計算（O(n)）
- 自動レイアウト計算がないため高速

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

特になし

## 備考

- INavigableContainer.GetControlは未実装（TODO）
- ClipToBounds=false がデフォルトのため、Canvas外にはみ出た要素も表示される

---

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

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

### 推奨読解順序

#### Step 1: クラス定義とプロパティを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | Canvas.cs | `src/Avalonia.Controls/Canvas.cs` | クラス定義とコメント（5-13行目） |

**読解のコツ**: 8-13行目のコメントで、Canvasが他のPanelと異なりレイアウトを行わないことを明確に説明している。

#### Step 2: 添付プロパティを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Canvas.cs | `src/Avalonia.Controls/Canvas.cs` | 添付プロパティ定義（19-38行目） |

**主要処理フロー**:
- **14行目**: `Canvas`クラス定義。`Panel`, `INavigableContainer`を実装
- **19-20行目**: LeftProperty（デフォルトNaN）
- **25-26行目**: TopProperty（デフォルトNaN）
- **31-32行目**: RightProperty（デフォルトNaN）
- **37-38行目**: BottomProperty（デフォルトNaN）
- **43-47行目**: 静的コンストラクタ - ClipToBounds=false設定、AffectsParentArrange登録

#### Step 3: MeasureOverride - 計測処理

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Canvas.cs | `src/Avalonia.Controls/Canvas.cs` | MeasureOverrideメソッド（147-157行目） |

**主要処理フロー**:
- **149行目**: 利用可能サイズを無限大に設定
- **151-154行目**: 各子要素を無限大サイズで計測
- **156行目**: 常に(0,0)を返却

**読解のコツ**: Canvasは自身のサイズを持たず、親要素がサイズを決定する設計。

#### Step 4: ArrangeOverride - 配置処理

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | Canvas.cs | `src/Avalonia.Controls/Canvas.cs` | ArrangeChildメソッド（164-199行目） |
| 4-2 | Canvas.cs | `src/Avalonia.Controls/Canvas.cs` | ArrangeOverrideメソッド（206-214行目） |

**主要処理フロー**:
- **166-182行目**: X座標計算 - Left優先、なければRight、なければ0
- **184-196行目**: Y座標計算 - Top優先、なければBottom、なければ0
- **198行目**: 計算した座標で子要素を配置
- **208-211行目**: 全子要素についてArrangeChild呼び出し

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

```
Canvas (レイアウトパネル)
    │
    ├─ MeasureOverride()
    │      ├─ availableSize = (∞, ∞)
    │      ├─ 子要素ループ
    │      │      └─ child.Measure(∞, ∞)
    │      └─ return Size(0, 0)
    │
    ├─ ArrangeOverride()
    │      └─ 子要素ループ
    │             └─ ArrangeChild()
    │                    ├─ GetLeft/GetRight → X座標
    │                    ├─ GetTop/GetBottom → Y座標
    │                    └─ child.Arrange()
    │
    └─ INavigableContainer.GetControl()
           └─ return null (未実装)
```

### データフロー図

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

Canvas.Left/Top ─────────▶ ArrangeChild()
Canvas.Right/Bottom ─────▶ │
                              │
                    ┌─────────┴─────────┐
                    ▼                   ▼
         X座標計算             Y座標計算
         (Left優先)            (Top優先)
                    │                   │
                    └─────────┬─────────┘
                              ▼
                     child.Arrange(x, y, width, height)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Canvas.cs | `src/Avalonia.Controls/Canvas.cs` | ソース | メインクラス |
| Panel.cs | `src/Avalonia.Controls/Panel.cs` | ソース | 基底クラス |
| INavigableContainer.cs | `src/Avalonia.Input/INavigableContainer.cs` | ソース | ナビゲーションインターフェース（未実装） |
