# 차트 (Chart.js)

| 항목 | 경로 |
|------|------|
| 데모 | `chart.html` |
| CSS | `css/chart.css` |
| JS | `js/chart-a11y.js` + Chart.js CDN |
| CDN | `https://cdn.jsdelivr.net/npm/chart.js@4.4.8/dist/chart.umd.min.js` |
| 참고 | 급식_개발소스_리포지토리 Chart.js (종류·접근성 패턴 재구성) |

---

## 복사 패키지

```
css/chart.css
js/chart-a11y.js
Chart.js (CDN 또는 로컬)
마크업: chart.html 의 .chart-block
(+ 대체 표 스타일이 필요하면 css/table.css)
```

---

## CDN 연결

```html
<link rel="stylesheet" href="./css/chart.css">
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.8/dist/chart.umd.min.js"></script>
<script src="./js/chart-a11y.js"></script>
```

---

## 종류별 제안

| 종류 | Chart.js `type` | 적합한 데이터 | 접근성 포인트 |
|------|-----------------|---------------|---------------|
| 세로 막대 | `bar` | 카테고리 비교 | `beginAtZero`, 대체 표, 키보드 순회 |
| 가로 막대 | `bar` + `indexAxis: 'y'` | 긴 라벨·순위 | 항목 많으면 높이 조절 또는 표 우선 |
| 선 | `line` | 시계열·추세 | 다중 시리즈는 **색 + 선스타일/포인트** |
| 원형 | `pie` | 구성비(≤5조각) | 툴팁·표에 **건수+비율** |
| 도넛 | `doughnut` | 구성비+중앙요약 | 중앙값은 **HTML 문구**로도 제공 |
| 레이더 | `radar` | 다축 균형(참고) | 표가 본정보, 차트는 보조 |
| 버블(참고) | `bubble` | 위치+크기 | 크기만으로 의미 전달 금지 |

급식 리포에서의 대응 예:
- 막대: 알레르기·설문·식품통계
- 선: 성장곡선·가격추이·일별 영양소
- 원형: 설문 응답 분포
- 도넛: 식재료 비중·역할 비율
- 레이더: 영양균형
- 버블: 성장곡선 위 학생 위치(선 차트와 조합)

---

## 접근성 필수

1. **대체 표** — canvas만으로 정보를 전달하지 않음 (`caption`, `th[scope]`)
2. **aria-label** — canvas·포커스 영역에 차트 목적 + 「상세는 표 참조」
3. **키보드 탐색** — `tabindex="0"` + 화살표/Home/End/Esc + `ChartA11y.bind`
4. **상태 알림** — `.chart-keyboard-info`에 `role="status"` `aria-live="polite"`
5. **색만으로 구분 금지** — 범례·라벨·선스타일·표 병행
6. **`prefers-reduced-motion`** — `ChartA11y.baseOptions`가 애니메이션 OFF
7. **`role="application"`** — 키보드 탐색이 필요할 때만 (스크린리더 기본 키 가로채기 주의)

---

## ChartA11y API

| 방법 | 설명 |
|------|------|
| `ChartA11y.bind({ container, chart, infoEl, getPoints, formatPoint? })` | 키보드·툴팁·aria-live 연동 |
| `ChartA11y.fillTable(tbody, rows)` | 대체 표 채우기 (`[{ th, cells }]`) |
| `ChartA11y.bindTableToggle(button, wrap)` | 표 보기/숨기기 |
| `ChartA11y.baseOptions(extra?)` | 반응형·모션·범례 기본 옵션 |
| `ChartA11y.palette` | 색각 이상 고려 6색 |

```javascript
var chart = new Chart(canvas, {
  type: 'bar',
  data: { labels: labels, datasets: [...] },
  options: ChartA11y.baseOptions({
    scales: { y: { beginAtZero: true } }
  })
});

ChartA11y.bind({
  container: document.getElementById('bar-chart-container'),
  chart: chart,
  infoEl: document.getElementById('bar-chart-keyboard-info'),
  getPoints: function () {
    return labels.map(function (label, i) {
      return {
        label: label,
        value: values[i],
        text: label + ': ' + values[i],
        datasetIndex: 0,
        index: i
      };
    });
  }
});
```

---

## 기본 마크업

```html
<div class="chart-block">
  <h3 id="chart-title">차트 제목</h3>
  <div id="chart-info" class="chart-keyboard-info"
       role="status" aria-live="polite" aria-atomic="true"></div>
  <div class="chart-canvas-wrap" tabindex="0" role="application"
       aria-labelledby="chart-title"
       aria-label="… 차트. 키보드 탐색 가능. 상세는 표 참조.">
    <canvas id="my-chart"
      aria-label="… 차트. 상세 정보는 아래 표를 참조하세요"></canvas>
  </div>
  <div class="chart-table-wrap" role="region" aria-label="… 표">
    <table>
      <caption>…</caption>
      <thead>…</thead>
      <tbody>…</tbody>
    </table>
  </div>
</div>
```

---

## 체크리스트

- [ ] 차트마다 대체 표(또는 동등한 텍스트) 존재
- [ ] canvas / 포커스 영역에 의미 있는 `aria-label`
- [ ] Tab으로 차트 영역에 진입 가능, 화살표로 값 확인
- [ ] `aria-live`로 현재 선택 값이 읽힘
- [ ] 범례·축 라벨 대비 충분 (텍스트 #222 권장)
- [ ] 다중 시리즈: 색 + 패턴(점선·포인트 모양)
- [ ] `prefers-reduced-motion`에서 애니메이션 없음
- [ ] 원형/도넛 조각 과다 시 막대·표로 전환 검토

