# 고급 레이아웃 만들기

## Content

기본 제공 뷰로 시간 및 리소스 데이터를 원하는 방식으로 표시하기 어렵다면 사용자 지정 `SchedulerDefinition`을 사용합니다. `SchedulerDefinition`에서는 행과 열 축에 시간 및 리소스 필드를 순서대로 배치해 원하는 레이아웃을 구성할 수 있습니다.

## 사용자 정의 레이아웃 정의

| 바인딩 유형 | 정의하는 항목 | 일반적인 값 | 필수 속성 | 선택적 속성 |
| ------ | ------- | ------ | ----- | ------ |
| Time | 날짜 또는 시간 슬롯 | `Hour`, `Day`, `DayOfWeek`, `DayOfMonth` | `type`, `unit` | `visible` 콜백 |
| Resource | `scheduler.resources`의 그룹 | `roomId`, `teamId` | `type`, `fieldExpr` | 없음 |

바인딩 순서에 따라 바깥쪽 그룹이 결정됩니다. 리소스 바인딩의 `fieldExpr`는 설정된 리소스 설명자의 `fieldExpr`와 일치해야 합니다.

```ts
const definition: wjScheduler.SchedulerDefinition = {
  key: 'weekByRoom',
  rows: {
    bindings: [{
      type: wjScheduler.SchedulerAxisBindingType.Time,
      unit: wjScheduler.SchedulerTimeUnit.Hour,
    }],
  },
  columns: {
    bindings: [
      { type: wjScheduler.SchedulerAxisBindingType.Time, unit: wjScheduler.SchedulerTimeUnit.DayOfWeek },
      { type: wjScheduler.SchedulerAxisBindingType.Resource, fieldExpr: 'roomId' },
    ],
  },
  cellSemantic: wjScheduler.SchedulerCellSemantic.Timed,
};

scheduler.definition = definition;
```

![레이아웃정의](https://gcdocumentsitekrblob.blob.core.windows.net/document-site-files/images/8ecc18d2-feec-4d15-bd72-3d98a7b4cefa/5-1-20261019.ab356d.png)

## 렌더링 전 레이아웃 확인

뷰를 동적으로 구성하거나 설정을 통해 전달하는 경우 `planSchedulerProjection`을 사용합니다. 이 함수는 스케줄러의 상태를 변경하지 않고 정의를 분석합니다.

```ts
const plan = wjScheduler.planSchedulerProjection(definition);
console.log(plan.slotAxis);
console.log(plan.integrity.level);
console.log(plan.integrity.reasons);
```

`plan.integrity.level`은 정의된 대로 뷰를 렌더링할 수 있는지 알려줍니다.

| 무결성 수준 | 의미 | 결과 |
| ------ | --- | --- |
| `faithful` | 축 구조와 바인딩 순서를 그대로 유지할 수 있습니다. | 구성된 대로 렌더링됩니다. |
| `lossy` | 뷰를 렌더링할 수 있지만 요청된 순서의 일부가 정규화됩니다. | 그룹화 순서가 정규화되어 렌더링됩니다. |
| `unsupported` | 정의가 모호하거나 투영할 수 없습니다. | 할당 시 오류가 발생하고 이전에 활성화된 정의가 유지됩니다. |

스케줄러가 지정된 바인딩 순서를 유지할 수 없는 경우, 레이아웃을 조정하고 `plan.integrity.reasons`에 그 이유를 기록합니다.
메시지에 바인딩이 정규화되거나 바깥쪽 그룹으로 표시된다고 나올 수 있습니다. 이는 해당 바인딩이 시간 축을 감싸는 상위 그룹으로 배치되었다는 의미입니다.

## 시간 기반 정의 규칙

시간 기반 레이아웃은 이벤트를 시간 범위에 따라 배치하며, 하나의 연속적인 시간 단위(Hour) 축이 필요합니다.

| 규칙 | 유효한 구성 | 잘못되었거나 정규화되는 구성 |
| --- | ------ | --------------- |
| 시간 축 | `time:hour` 바인딩이 정확히 하나 있어야 합니다. | `time:hour` 바인딩이 없거나 반복되면 지원되지 않습니다. |
| 시간 바인딩 배치 | Hour 바인딩은 행 또는 열 축 중 하나에 단독으로 있어야 합니다. | 다른 바인딩과 같은 축을 공유하면 `lossy`로 처리됩니다. 스케줄러는 선언된 혼합 순서를 유지하지 않고 다른 바인딩을 별도 그룹으로 분리합니다. |
| 리소스 식별자 | 각 리소스 필드는 두 축 전체에서 한 번만 나타나야 합니다. | 동일한 리소스 필드를 반복하면 지원되지 않습니다. |
| 달력 컨텍스트 | 섹션에 구체적인 날짜가 필요하면 날짜 수준 바인딩을 포함합니다. | 날짜 수준 바인딩 없이 `weekOfMonth`와 `hour`를 함께 사용하면 지원되지 않습니다. |

시간 기반 정의에서는 `time:hour` 바인딩을 통해 연속적인 시간 축을 구성해야 합니다. 시간 바인딩은 행 축 또는 열 축 중 한 곳에 단독으로 배치하고, 다른 바인딩은 반대쪽 축에 배치합니다. 스케줄러가 레이아웃을 정규화하는지 확인하려면 `planSchedulerProjection`을 사용하세요.

## 요약 정의 규칙

요약 레이아웃은 셀 안에 고정 크기 항목을 배치하며 `time:hour` 바인딩이 필요하지 않습니다.

| 규칙 | 동작 |
| --- | --- |
| 시간 단위 반복 | 동일한 단위가 두 번 이상 나타나면 지원되지 않습니다. |
| 리소스 필드 반복 | 동일한 리소스 필드가 두 번 이상 나타나면 지원되지 않습니다. |
| 크기 조정 | Summary 항목에서는 지원되지 않습니다. |
| 단일 레인 | `time:hour` 바인딩 하나가 있고 반대쪽 축에 바인딩이 없는 시간 기반 정의는 `displayDate`에 해당하는 하나의 레인을 렌더링합니다. |

## 지원되지 않는 정의 처리

사용자가 입력한 설정을 적용할 때는 사용자 지정 정의가 유효한지 먼저 확인하고, 지원되지 않는 경우 사용할 수 있는 대체 뷰를 제공하세요. 정의를 동적으로 생성하는 경우에는 `try/catch`를 사용해 할당 과정에서 발생하는 오류에 대비할 수도 있습니다.

```ts
const plan = wjScheduler.planSchedulerProjection(definition);

if (plan.integrity.level === 'unsupported') {
  scheduler.definition = wjScheduler.createSchedulerDefinitionPreset(
    wjScheduler.SchedulerBuiltInViewItem.Week
  );
} else {
  scheduler.definition = definition;
}
```

새 레이아웃을 테스트할 때는 정의를 최소한으로 유지하세요. 시간 바인딩 하나로 시작한 다음 리소스 바인딩을 하나씩 추가하고, 축을 더 추가하기 전에 결과 그룹화가 예상대로 표시되는지 확인합니다.