HTMLMediaElement.autoplay - Web API

HTMLMediaElement.autoplay
=========================

**`HTMLMediaElement.autoplay`** 프로퍼티는 `autoplay` HTML 어트리뷰트의 값을 반환합니다. 이 프로퍼티는 미디어가 문제 없이 재생 가능한 상황이 되면 자동 재생 여부를 결정합니다.

미디어 엘리먼트의 소스가 `MediaStream` (en-US)이며 `autoplay` 프로퍼티가 `true` 일 경우 액티브 상태가 되면 재생합니다 (즉, `MediaStream.active` (en-US)가 `true`가 될 때).

**참고:** 오디오(또는 오디오가 있는 비디오)를 자동으로 재생하는 사이트는 사용자에게 그리 탐탁치 않은 경험일 수 있습니다, 그러므로 가능한 한 지양해야합니다. 자동 재생 기능을 제공하려면, 사전 동의(사용자에게 기능을 켜도록 함)를 받아야 합니다. 의외로 이 점은 사용자의 조작에 의해 미디어 엘레먼츠를 늦게 생성하는 경우 유용할 수 있습니다.

자동 재생과 자동 재생 제한, 그리고 브라우저의 자동 재생 제한에 대처하는 법에 대해 자세히 알고 싶다면 미디어 자동 재생과 Web Audio API 가이드 문서를 참조하세요.

문법
--

```js
HTMLMediaElement.autoplay = true | false;

var autoplay = HTMLMediaElement.autoplay;
```

### 값

미디어가 재생 가능할 정도로 로드되고 문제 없이 재생 가능할 때 자동 재생 여부를 `Boolean` `true` 로 반환한다.

**참고:** 특정 브라우저는 사용자 설정을 통해 `autoplay` 프로퍼티를 무시하고 비디오/오디오 자동 재생을 막는 기능을 제공합니다. 자동 재생을 위해 `autoplay` 프로퍼티를 맹신하지 마세요.

예제
--

...

```html
<video id="video" controls>
  <source
 src="https://player.vimeo.com/external/250688977.sd.mp4?s=d14b1f1a971dde13c79d6e436b88a6a928dfe26b&profile\_id=165" />
</video>
```

```js
// Disable autoplay (recommended)
// false is the default value
document.querySelector("#video").autoplay = false;
```

명세서
---

| Specification |
| --- |
| HTML Standard # dom-media-autoplay |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

더 보기
----

* 정의된 인터페이스 `HTMLMediaElement`.
* `<audio>` (en-US), `<video>` 엘리먼트


HTMLMediaElement: canplay - Web API

HTMLMediaElement: canplay
=========================

`canplay` 이벤트는 user agent 가 media 를 재생할 수 있을 때 발생된다. 그러나, 컨텐츠의 추가 버퍼링을 위한 정지 없이 media 를 끝까지 재생하기에는, 로드된 데이터가 충분하지 않을 것으로 추산한다.

General info
------------

Specification

HTML5 media

Interface

Event

Bubbles

No

Cancelable

No

Target

Element

Default Action

None.

Properties
----------

| Property | Type | Description |
| --- | --- | --- |
| `target` 읽기 전용 | `EventTarget` | The event target (the topmost target in the DOM tree). |
| `type` 읽기 전용 | `DOMString` | The type of event. |
| `bubbles` 읽기 전용 | `Boolean` | Whether the event normally bubbles or not. |
| `cancelable` 읽기 전용 | `Boolean` | Whether the event is cancellable or not. |

Related Events
--------------

* `playing (en-US)`
* `waiting (en-US)`
* `seeking (en-US)`
* `seeked (en-US)`
* `ended (en-US)`
* `loadedmetadata (en-US)`
* `loadeddata (en-US)`
* `canplay`
* `canplaythrough`
* `durationchange (en-US)`
* `timeupdate (en-US)`
* `play (en-US)`
* `pause (en-US)`
* `ratechange (en-US)`
* `volumechange (en-US)`
* `suspend (en-US)`
* `emptied (en-US)`
* `stalled (en-US)`


HTMLMediaElement.networkState - Web API

HTMLMediaElement.networkState
=============================

**`HTMLMediaElement.networkState`** 속성은 네트워크를
 통한 미디어 가져오기(fetching)의 현재 상태를 나타냅니다.

값
-

아래의 `unsigned short` 값 중 하나입니다.

| 상수 | 값 | 설명 |
| --- | --- | --- |
| `NETWORK_EMPTY` | 0 | 아직 데이터가 없습니다. 또한 `readyState`는 `HAVE_NOTHING`입니다. |
| `NETWORK_IDLE` | 1 | HTMLMediaElement가 활성 상태이고 리소스를 선택했지만 네트워크를 사용하고 있지 않습니다. |
| `NETWORK_LOADING` | 2 | 브라우저가 HTMLMediaElement 데이터를 다운로드하고 있습니다. |
| `NETWORK_NO_SOURCE` | 3 | HTMLMediaElement src를 찾을 수 없습니다. |

예제
--

 이 예제는 오디오 요소가 재생을 시작할 때까지 수신한 다음
 여전히 데이터를 로드하고 있는지 확인합니다.

```html
<audio id="example" preload="auto">
  <source src="sound.ogg" type="audio/ogg" />
</audio>
```

```js
const obj = document.getElementById("example");
obj.addEventListener("playing", () => {
  if (obj.networkState === 2) {
    // 여전히 로딩중입니다...
  }
});
```

명세
--

| Specification |
| --- |
| HTML Standard # dom-media-networkstate-dev |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

같이 보기
-----

* networkState를 정의하는 인터페이스는 `HTMLMediaElement`입니다.


HTMLMediaElement.currentSrc - Web API

HTMLMediaElement.currentSrc
===========================

**`HTMLMediaElement.currentSrc`** 속성에는 선택한 미디어 리소스의 절대 URL이
 포함되어 있습니다. 예를 들어 웹 서버가 사용자 디스플레이의 해상도에 따라
 미디어 파일을 선택하는 경우 이런 일이 발생할 수 있습니다. `networkState` 속성이
 `EMPTY`인 경우 값은 빈 문자열입니다.

값
-

 선택한 미디어 소스의 절대 URL을 포함하는 문자열 객체입니다.
 `networkState`가 `EMPTY`라면 빈 문자열, 아니라면 미디어 요소(element) 내에 포함된 `HTMLSourceElement` (en-US)로
 나열한 리소스 중 하나가 됩니다. 만약 `<source>` (en-US) 요소가
 제공되지 않은 경우 값 또는 src가 됩니다.

예제
--

```js
const obj = document.createElement("video");
console.log(obj.currentSrc); // ""
```

명세
--

| Specification |
| --- |
| HTML Standard # dom-media-currentsrc-dev |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

같이 보기
-----

* currentSrc를 정의하는 인터페이스는 `HTMLMediaElement`입니다.


HTMLMediaElement.currentTime - Web API

HTMLMediaElement.currentTime
============================

`HTMLMediaElement` 인터페이스의 **`currentTime`** 속성은
 현재 재생 시간을 초 단위로 지정합니다.

`currentTime`의 값을 변경하면 미디어를 새로운 시간으로 찾습니다.

값
-

현재 재생 시간을 초 단위로 나타내는 배정밀도 부동 소수점 값입니다.

 미디어가 아직 재생되지 않은 경우 `currentTime` 값은 `play()` (en-US)
 메서드가 호출된 후 재생이 시작되는 미디어 내의 시간 위치를 나타냅니다.

`currentTime`을 새 값으로 설정하면 미디어를 사용할 수 있는 경우
 지정된 시간으로 미디어를 찾습니다.

 라이브로 스트리밍되는 미디어와 같이 지속 시간(duration)이 없는 미디어의 경우
 브라우저가 미디어 버퍼에서 만료된 미디어의 일부를 가져오지 못할 수 있습니다.
 또한 타임라인이 0초에서 시작하지 않는 미디어는 해당 타임라인의 가장 빠른 시간
 이전으로 검색할 수 없습니다.

 미디어의 길이(초)는 `duration` 속성을
 사용하여 결정할 수 있습니다.

예제
--

```js
const video = document.createElement("video");
console.log(video.currentTime);
```

사용 일람
-----

### 시간 정밀도 감소

 타이밍 공격 및 핑거프린팅으로부터 보호하기 위해 브라우저는 `currentTime`에서
 반환된 값을 반올림하거나 조정할 수 있습니다.

명세
--

| Specification |
| --- |
| HTML Standard # dom-media-currenttime-dev |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

같이 보기
-----

* currentTime을 정의하는 인터페이스는 `HTMLMediaElement`입니다
* 시간을 설정하는 또 다른 방법은 `HTMLMediaElement.fastSeek()` (en-US)를 참고하세요
* 미디어 재생 시간(초)는 `HTMLMediaElement.duration`를 참고하세요


HTMLMediaElement.seekable - Web API

HTMLMediaElement.seekable
=========================

`HTMLMediaElement` 객체의 **`seekable`** 읽기 전용 속성은 사용자 에이전트가 `seekable` 속성에 접근할 때 찾을 수 있는 미디어 리소스의 범위를 나타내는 새로운 정적 정규화된 `TimeRanges` 객체 (en-US)를 반환합니다.

값
-

`seekable` 속성에 접근할 때 사용자 에이전트가 찾을 수 있는 미디어 리소스의 범위를 나타내는 새로운 정적 정규화된 TimeRanges 객체 (en-US)입니다.

예제
--

```js
const video = document.querySelector("video");
const timeRangesObject = video.seekable;
const timeRanges = [];
// 객체를 살펴보고 배열을 출력합니다
for (let count = 0; count < timeRangesObject.length; count++) {
  timeRanges.push([timeRangesObject.start(count), timeRangesObject.end(count)]);
}
```

명세
--

| Specification |
| --- |
| HTML Standard # dom-media-seekable-dev |
| Media Source Extensions™ # htmlmediaelement-extensions |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

같이 보기
-----

* seekable을 정의하는 인터페이스는 `HTMLMediaElement`입니다.
* 미디어 소스 확장 API (en-US)
* 미디어 버퍼링, 검색 및 시간 범위 (en-US)


HTMLMediaElement: playbackRate property - Web API

HTMLMediaElement: playbackRate property
=======================================

**`HTMLMediaElement.playbackRate`** 속성은 미디어가 재생되는 속도를 설정합니다. 이 속성은 빨리 감기, 슬로우 모션 등에 대한 사용자 컨트롤을 구현하는 데 사용됩니다. 일반적인 재생 속도에 이 값을 곱하여 현재 속도를 얻습니다. `1.0`은 정상 속도를 의미합니다.

`playbackRate`가 음수이면 미디어가 거꾸로 재생됩니다.

빨리 감기나 슬로우 모션이 유용한 범위를 벗어나면 오디오가 음 소거됩니다. (Gecko는 범위 `0.25`에서 `4.0`을 벗어나면 소리가 음 소거됩니다).

오디오의 음높이는 기본적으로 보정됩니다. 보정을 비활성화하려면 `HTMLMediaElement.preservesPitch` (en-US) 속성을 사용하세요.

값
-

`double` `1.0`이 "기본 속도"입니다. `1.0`보다 낮은경우 미디어 속도는 기본 속도보다 느리게 재생되고, 높은 경우 더 빠르게 재생됩니다. (**기본값:** `1.0`)

예시
--

```js
const obj = document.createElement("video");
console.log(obj.playbackRate); // 예상 출력값 : 1
```

명세서
---

| Specification |
| --- |
| HTML Standard # dom-media-playbackrate-dev |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

같이 보기
-----

* `HTMLMediaElement`: `HTMLMediaElement.playbackRate` 속성을 정의하기 위해 사용하는 인터페이스


HTMLMediaElement.duration - Web API

HTMLMediaElement.duration
=========================

 "읽기 전용" `HTMLMediaElement` 속성
 \*\*`duration`\*\*은 요소의 미디어 길이를 초 단위로 나타냅니다.

값
-

 미디어의 지속 시간을 초 단위로 나타내는 배정밀도 부동 소수점 값입니다.
 사용 가능한 미디어 데이터가 없으면 `NaN` 값이 반환됩니다. 만약 요소의
 미디어에 라이브 미디어 스트림과 같이 전체 길이(초)가 없는 경우
 `duration`은 `+Infinity`입니다.

예제
--

```js
const obj = document.createElement("video");
console.log(obj.duration); // NaN
```

명세
--

| Specification |
| --- |
| HTML Standard # dom-media-duration-dev |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

같이 보기
-----

* 웹 미디어 기술
* 미디어의 현재 재생 위치는 `HTMLMediaElement.currentTime`를 참고하세요.
* `<audio>` (en-US)와 `<video>` 요소들을 참고하세요.


HTMLMediaElement: canplaythrough - Web API

HTMLMediaElement: canplaythrough
================================

`canplaythrough` 이벤트는 user agent 가 media 를 재생할 수 있을 때 발생되며, 컨텐츠의 추가 버퍼링을 위한 정지 없이 media 를 끝까지 재생하기에 로드된 데이터가 충분할 것으로 추산한다.

General info
------------

Specification

HTML5 media

Interface

Event

Bubbles

No

Cancelable

No

Target

Element

Default Action

None.

Properties
----------

| Property | Type | Description |
| --- | --- | --- |
| `target` 읽기 전용 | `EventTarget` | The event target (the topmost target in the DOM tree). |
| `type` 읽기 전용 | `DOMString` | The type of event. |
| `bubbles` 읽기 전용 | `Boolean` | Whether the event normally bubbles or not. |
| `cancelable` 읽기 전용 | `Boolean` | Whether the event is cancellable or not. |

Related Events
--------------

* `playing (en-US)`
* `waiting (en-US)`
* `seeking (en-US)`
* `seeked (en-US)`
* `ended (en-US)`
* `loadedmetadata (en-US)`
* `loadeddata (en-US)`
* `canplay`
* `canplaythrough`
* `durationchange (en-US)`
* `timeupdate (en-US)`
* `play (en-US)`
* `pause (en-US)`
* `ratechange (en-US)`
* `volumechange (en-US)`
* `suspend (en-US)`
* `emptied (en-US)`
* `stalled (en-US)`


HTMLMediaElement.srcObject - Web API

HTMLMediaElement.srcObject
==========================

`HTMLMediaElement` 인터페이스의 **`srcObject`** 속성은
 `HTMLMediaElement`와 관련된 미디어 소스 역할을 하는 객체를
 설정하거나 반환합니다.

 srcObject 객체는 `MediaStream` (en-US), a `MediaSource` (en-US), a
 `Blob` 또는 `File`(`Blob`을 상속)일 수 있습니다.

**참고:** 2020년 3월 현재 Safari만이 `srcObject`를 완벽하게 지원합니다. 즉, `MediaSource`, `MediaStream`, `Blob`, 그리고 `File` 객체를 값으로 사용합니다. 다른 브라우저는 `MediaStream` 객체를 지원합니다. 다른 브라우저들이 지원할 때까지 `URL.createObjectURL()`을 사용하여 URL을 생성하고 이를 `HTMLMediaElement.src`에 할당하는 것을 고려하세요(예제는 아래에 있습니다). 또한 버전 108부터 Chromium은 해당 객체의 `MediaSourceHandle` (en-US) 인스턴스(워커에서 전송됨)를 `srcObject`에 할당하여 전용 워커 `MediaSource` 객체 연결을 지원합니다.

값
-

`MediaStream` (en-US), `MediaSource` (en-US), `Blob` 또는
 `File` 객체(실제로 지원되는 내용은 호환성 표를 참고하세요).

사용 일람
-----

 이전 버전의 미디어 소스 명세는 `createObjectURL()`을
 사용하여 객체 URL을 만든 다음 `src`를 해당 URL로
 설정합니다. 이제 `srcObject`를 `MediaStream` (en-US)으로 직접 설정할 수 있습니다.

예제
--

### 기본 예제

 이 예제에서 `MediaStream` (en-US)은 새로 생성된 `<video>` 요소에
 할당됩니다.

```js
const mediaStream = await navigator.mediaDevices.getUserMedia({ video: true });
const video = document.createElement("video");
video.srcObject = mediaStream;
```

 이 예제에서 `MediaSource` (en-US)는 새로 생성된 `<video>` 요소에
 할당됩니다.

```js
const mediaSource = new MediaSource();
const video = document.createElement("video");
video.srcObject = mediaSource;
```

### src 속성에 대한 폴백 지원

 아래 예제는 `srcObject`가 지원되지 않는 경우 객체 URL을 만들고 이를 `src`에
 할당해야 하는 이전 브라우저 버전을 지원합니다.

 먼저 카메라의 `MediaStream` (en-US)이 새로 생성된 `<video>`
 요소에 할당되고 이전 브라우저에 대한 폴백이 있습니다.

```js
const mediaStream = await navigator.mediaDevices.getUserMedia({ video: true });
const video = document.createElement("video");
if ("srcObject" in video) {
  video.srcObject = mediaStream;
} else {
  // 사라질 예정이므로 새 브라우저에서는 사용하지 마세요.
  video.src = URL.createObjectURL(mediaStream);
}
```

 둘째, 새로운 `MediaSource` (en-US)가 새로 생성된 `<video>`
 요소에 할당되며 이전 브라우저 및 아직 `MediaSource` (en-US)의 직접 할당을
 지원하지 않는 브라우저에 대한 폴백이 있습니다.

```js
const mediaSource = new MediaSource();
const video = document.createElement("video");
// 이전 브라우저는 srcObject가 없을수 있습니다.
if ("srcObject" in video) {
  try {
    video.srcObject = mediaSource;
  } catch (err) {
    if (err.name !== "TypeError") {
      throw err;
    }
    // 만약 srcObject가 있더라도 MediaStream만 지원하는 경우가 있을 수 있습니다.
    video.src = URL.createObjectURL(mediaSource);
  }
} else {
  video.src = URL.createObjectURL(mediaSource);
}
```

### 워커에서 `MediaSource`를 구성하고 재생을 위해 메인 스레드(main thread)에 전달하기

`MediaSource.handle` (en-US) 속성은 전용 워커 내에서 액세스 할 수 있으며 결과 값 `MediaSourceHandle` (en-US) 객체는 `postMessage()` (en-US) 호출을 통해 워커를 생성한 스레드(이 경우 메인 스레드)로 전송됩니다.

```js
// 내부 전용 워커
let mediaSource = new MediaSource();
let handle = mediaSource.handle;
// 워커를 만든 컨텍스트로 핸들을 전송합니다
postMessage({ arg: handle }, [handle]);

mediaSource.addEventListener("sourceopen", () => {
  // SourceBuffers를 생성하고 가져온(fetched) 미디어로 채우기 전에
  // MediaSource에서 sourceopen을 기다리세요(await). MediaSource는
  // HTMLMediaElement에 연결되고 readyState가 "open"이 될 때까지
  // SourceBuffers 생성을 수락하지 않습니다.
});
```

메인 스레드에서 `message` (en-US) 이벤트 핸들러를 통해 핸들을 수신하고 `HTMLMediaElement.srcObject` 속성을 통해 `<video>`에 첨부하고 비디오를 `play` (en-US)합니다.

```js
worker.addEventListener("message", (msg) => {
  let mediaSourceHandle = msg.data.arg;
  video.srcObject = mediaSourceHandle;
  video.play();
});
```

**참고:** `MediaSourceHandle` (en-US)는 공유 워커 또는 서비스 워커를 통해 성공적으로 전송할 수 없습니다.

명세
--

| Specification |
| --- |
| HTML Standard # dom-media-srcobject-dev |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


HTMLMediaElement.src - Web API

HTMLMediaElement.src
====================

**`HTMLMediaElement.src`** 속성은 요소(element)에서 사용할 미디어 리소스의
 URL을 나타내는 HTML 미디어 요소의 `src` 속성 값을 반영합니다.

**참고:** 현재 해당 요소에서 사용 중인 미디어 리소스의 URL을 확인하는
 가장 좋은 방법은 `currentSrc`
 속성의 값을 살펴보는 것입니다. 이 속성은 `HTMLSourceElement` (en-US)
 (`<source>` (en-US) 요소를 의미합니다)에 제공된 목록에서
 최상의 또는 선호하는 미디어 리소스의 선택도 고려합니다.

값
-

 요소에서 사용할 미디어 리소스의 URL을 포함하는 문자열 객체입니다.
 이 속성은 HTML 요소의 `src` 속성 값을 반영합니다.

예제
--

```js
const obj = document.createElement("video");
console.log(obj.src); // ""
```

명세
--

| Specification |
| --- |
| HTML Standard # dom-media-src |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

같이 보기
-----

* src를 정의하는 인터페이스는 `HTMLMediaElement`입니다.


abort - Web API

abort
=====

**`abort`** 이벤트는 리소스의 로딩이 중단되었을 때, 발생합니다.

개요
--

스펙

DOM L3

인터페이스

유저 인터페이스에서 발생하면 UIEvent, 그렇지 않으면 Event.

버블

안됨

취소 가능

안됨

타겟

Element

디폴트 액션

없음

속성
--

| 속성 | 타입 | 설명 |
| --- | --- | --- |
| `target` 읽기 전용 | `EventTarget` | 이벤트 타겟 (DOM tree의 최상위 타겟). |
| `type` 읽기 전용 | `DOMString` | 이벤트의 타입 |
| `bubbles` 읽기 전용 | `Boolean` | 이벤트가 버블링 되는지 안되는지 |
| `cancelable` 읽기 전용 | `Boolean` | 이벤트가 취소 가능한지 아닌지 |
| `view` 읽기 전용 | `WindowProxy` | `document.defaultView` (document의 `window` ) |
| `detail` 읽기 전용 | `long` (`float`) | 0. |


HTMLMediaElement.readyState - Web API

HTMLMediaElement.readyState
===========================

**`HTMLMediaElement.readyState`** 속성은 미디어의 준비 상태를 나타냅니다.

값
-

아래의 `unsigned short` 값 중 하나입니다.

| 상수 | 값 | 설명 |
| --- | --- | --- |
| `HAVE_NOTHING` | 0 | 미디어 리소스에 대한 정보가 없습니다. |
| `HAVE_METADATA` | 1 |
 메타데이터 속성이 초기화될 만큼 충분한 미디어 리소스가
 검색되었습니다. seeking에서 더 이상 예외를 발생시키지 않습니다.
  |
| `HAVE_CURRENT_DATA` | 2 |
 현재 재생 위치에 대한 데이터를 사용할 수 있지만
 실제로 한 프레임 이상을 재생하기에는 충분하지 않습니다.
  |
| `HAVE_FUTURE_DATA` | 3 |
 현재 재생 위치 및 미래의 최소한의 시간에 대한
 데이터를 사용할 수 있습니다(이 뜻은 비디오의
 최소 두 프레임이 있다는 뜻입니다).
  |
| `HAVE_ENOUGH_DATA` | 4 |
 충분한 데이터를 사용할 수 있고 다운로드 속도가 충분히
 높아 미디어를 중단 없이 끝까지 재생할 수 있습니다.
  |

예제
--

 이 예제는 `example` 요소에 대해 로드할 오디오 데이터를 수신합니다.
 그런 다음 최소한 현재 재생 위치가 로드되었는지 확인합니다.
 있는 경우 오디오가 재생됩니다.

```html
<audio id="example" preload="auto">
  <source src="sound.ogg" type="audio/ogg" />
</audio>
```

```js
const obj = document.getElementById("example");

obj.addEventListener("loadeddata", () => {
  if (obj.readyState >= 2) {
    obj.play();
  }
});
```

명세
--

| Specification |
| --- |
| HTML Standard # dom-media-readystate-dev |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

같이 보기
-----

* readyState를 정의하는 인터페이스는 `HTMLMediaElement`입니다.


Clients.claim() - Web API

Clients.claim()
===============

**실험적:** **이 기능은 실험적인 기능입니다.**
프로덕션 환경에서 사용하기 전에 브라우저 호환성 표를 주의 깊게 확인하세요.

`Clients` (en-US) 의 **`claim()`** 메소드는 active 서비스워커가 그것의 `scope` (en-US) 를 가지는 모든 클라이언트들의 `controller` (en-US) 로서 자신을 등록하는 것을 허용한다. 이것은 이 서비스워커가 제어하게 될 클라이언트들에 "`controllerchange`" 이벤트를 발생시킨다.

서비스워커가 최초에 등록되면, 페이지들은 다음 로드시까지 그것을 사용하지 않을 것이다. `claim()` 메소드는 그 페이지들을 즉시 제어될 수 있도록 한다. 이로 인해, 당신의 서비스워커는 네트워크 또는 다른 서비스워커를 통해 정기적으로 로드되는 페이지들을 제어하게 된다.

Syntax
------

```js
await clients.claim();
```

### Parameters

None.

### Returns

A `Promise` for `void`.

Example
-------

다음 예시는 서비스워커의 "`activate`" 이벤트 리스너에서 `claim()` 를 사용하므로, fetch 들이 이 서비스워커를 통과하기 전에 동일한 스코프에서 로드된 클라이언트들은 다시 로드될 필요가 없다. .

```js
self.addEventListener("activate", (event) => {
  event.waitUntil(clients.claim());
});
```

명세서
---

| Specification |
| --- |
| Service Workers # clients-claim |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* Using Service Workers (en-US)
* The service worker lifecycle
* Is ServiceWorker ready?
* `Promises`
* `self.skipWaiting()` - skip the service worker's waiting phase


URLSearchParams() - Web API

URLSearchParams()
=================

**`URLSearchParams()`** 생성자는 새로운 `URLSearchParams` 객체를 생성하고 반환합니다.

**참고:** 이 기능은 Web Worker에서 사용할 수 있습니다

구문
--

```js
new URLSearchParams();
new URLSearchParams(init);
```

### 매개변수

`init` Optional

다음 중 하나입니다.

* 문자열. `application/x-www-form-urlencoded` 형식으로 파싱합니다. 선행 `'?'` 문자는 무시합니다.
* 이름-값 문자열 쌍을 생성하는 순회기를 가지는 객체. `FormData` 등의 객체가 이 범주에 속합니다. 참고로 `File` 값은 파일 이름이 아니라 `[object File]`로 직렬화됩니다. (`application/x-www-form-urlencoded` 양식에서의 동작과 동일)
* 문자열 키와 문자열 값으로 구성된 레코드.

### 반환값

`URLSearchParams` 객체 인스턴스입니다.

예제
--

다음 예제는 URL 문자열에서 `URLSearchParams` 객체를 생성하는 모습입니다.

```js
// url 생성자에 전달된 주소를 url.search를 통해 params라는 변수로 검색합니다.
var url = new URL("https://example.com?foo=1&bar=2");
var params = new URLSearchParams(url.search);

// 문자열 리터럴을 전달합니다.
var params2 = new URLSearchParams("foo=1&bar=2");
var params2a = new URLSearchParams("?foo=1&bar=2");

// 일련의 쌍으로 전달합니다.
var params3 = new URLSearchParams([
  ["foo", "1"],
  ["bar", "2"],
]);

// 레코드로 전달합니다.
var params4 = new URLSearchParams({ foo: "1", bar: "2" });
```

다음 예제는 검색 매개변수를 포함한 URL과, 검색 매개변수 객체를 사용해 새로운 URL을 만드는 모습을 보입니다.

```js
const url = new URL("https://example.com/?a=hello&b=world");

console.log(url.href);
// https://example.com/?a=hello&b=world

console.log(url.origin);
// https://example.com

const add_params = {
  c: "a",
  d: new String(2),
  e: false.toString(),
};

const new_params = new URLSearchParams([
  ...Array.from(url.searchParams.entries()), // [["a","hello"],["b","world"]]
  ...Object.entries(add_params), // [["c","a"],["d","2"],["e","false"]]
]).toString();
console.log(new_params);
// a=hello&b=world&c=a&d=2&e=false

const new_url = new URL(`${url.origin}${url.pathname}?${new\_params}`);

console.log(new_url.href);
// https://example.com/?a=hello&b=world&c=a&d=2&e=false

// (URL, Record<string, string>)을 받는 함수
const addSearchParams = (url, params = {}) =>
  new URL(
    `${url.origin}${url.pathname}?${new URLSearchParams([
 ...Array.from(url.searchParams.entries()),
 ...Object.entries(params),
 ]).toString()}`,
  );
```

명세
--

| Specification |
| --- |
| URL Standard # dom-urlsearchparams-urlsearchparams |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


URLSearchParams.delete() - Web API

URLSearchParams.delete()
========================

`URLSearchParams` 인터페이스의 **`delete()`** 메서드는 지정한 키와 연관된 모든 값을 검색 매개변수 리스트에서 제거합니다.

**참고:** 이 기능은 Web Worker에서 사용할 수 있습니다

구문
--

```js
delete name;
```

### 매개변수

`name`

제거할 매개변수의 이름입니다.

### 반환 값

없음 (`undefined`).

예제
--

```js
let url = new URL("https://example.com?foo=1&bar=2&foo=3");
let params = new URLSearchParams(url.search);

// foo 매개변수 제거
params.delete("foo"); // 이제 쿼리 문자열이 'bar=2'
```

명세
--

| Specification |
| --- |
| URL Standard # dom-urlsearchparams-delete |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


URLSearchParams.set() - Web API

URLSearchParams.set()
=====================

`URLSearchParams` 인터페이스의 **`set()`** 메서드는 주어진 검색 매개변수의 값을 지정한 값으로 설정합니다. 만약 해당 검색 매개변수에 연관된 값이 여러 개라면, 설정한 값을 제외한 나머지는 모두 제거됩니다. 반대로 검색 매개변수가 존재하지 않으면 새로 생성합니다.

**참고:** 이 기능은 Web Worker에서 사용할 수 있습니다

구문
--

```js
set(name, value);
```

### 매개변수

`name`

설정할 매개변수의 이름입니다.

`value`

설정할 매개변수의 값입니다.

### 반환 값

없음 (`undefined`).

예제
--

```js
let url = new URL("https://example.com?foo=1&bar=2");
let params = new URLSearchParams(url.search);

// 세 번째 매개변수 추가
params.set("baz", 3);
params.toString(); // "foo=1&bar=2&baz=3"
```

명세
--

| Specification |
| --- |
| URL Standard # dom-urlsearchparams-set |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


URLSearchParams.get() - Web API

URLSearchParams.get()
=====================

`URLSearchParams` 인터페이스의 **`get()`** 메서드는 지정한 키와 연관된 첫 번째 값을 반환합니다.

**참고:** 이 기능은 Web Worker에서 사용할 수 있습니다

구문
--

```js
get(name);
```

### 매개변수

`name`

반환할 매개변수의 이름입니다.

### Return value

검색 매개변수를 찾으면 문자열, 아니면 \*\*`null`\*\*입니다.

예제
--

페이지 URL이 `https://example.com/?name=Jonathan&age=18`이라고 가정할 때, 다음 코드로 'name'과 'age' 매개변수를 가져올 수 있습니다.

```js
let params = new URLSearchParams(document.location.search);
let name = params.get("name"); // 문자열 "Jonathan"
let age = parseInt(params.get("age"), 10); // 숫자 18
```

쿼리 문자열에 존재하지 않는 매개변수를 가져오려고 시도하면 \*\*`null`\*\*을 반환합니다.

```js
let address = params.get("address"); // null
```

명세
--

| Specification |
| --- |
| URL Standard # dom-urlsearchparams-get |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


URLSearchParams.toString() - Web API

URLSearchParams.toString()
==========================

`URLSearchParams` 인터페이스의 **`toString()`** 메서드는 URL에 사용할 수 있는 쿼리 문자열을 반환합니다.

**참고:** 이 메서드는 선행 `'?'`를 붙이지 않은 쿼리 문자열을 반환합니다. 이 동작은 `'?'`를 포함한 값을 반환하는 `window.location.search` (en-US)와 다릅니다.

**참고:** 이 기능은 Web Worker에서 사용할 수 있습니다

구문
--

```js
toString();
```

### 매개변수

없음.

### 반환 값

물음표 없는 문자열입니다. 아무런 검색 매개변수도 설정하지 않은 경우에는 빈 문자열을 반환합니다.

예제
--

```js
const url = new URL("https://example.com?foo=1&bar=2");
const params = new URLSearchParams(url.search);

// 두 번째 foo 매개변수 추가
params.append("foo", 4);
console.log(params.toString()); // 'foo=1&bar=2&foo=4' 출력
```

명세
--

| Specification |
| --- |
| URL Standard # urlsearchparams-stringification-behavior |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

같이 보기
-----

* `URL` 인터페이스.
* Google Developers: Easy URL manipulation with URLSearchParams


URLSearchParams.append() - Web API

URLSearchParams.append()
========================

`URLSearchParams` 인터페이스의 **`append()`** 메서드는 지정한 키/값 쌍을 새로운 검색 매개변수로서 추가합니다.

아래 예제에서도 볼 수 있듯, 같은 키를 여러 번 추가하면 매개변수 문자열에 각각의 키와 함께 여러 번 나타나게 됩니다.

**참고:** 이 기능은 Web Worker에서 사용할 수 있습니다

구문
--

```js
append(name, value);
```

### 매개변수

`name`

추가할 매개변수의 이름입니다.

`value`

추가할 매개변수의 값입니다.

### 반환 값

없음 (`undefined`).

예제
--

```js
let url = new URL("https://example.com?foo=1&bar=2");
let params = new URLSearchParams(url.search);

// 두 번째 foo 매개변수 추가
params.append("foo", 4);
// 이제 쿼리 문자열이 'foo=1&bar=2&foo=4'
```

명세
--

| Specification |
| --- |
| URL Standard # dom-urlsearchparams-append |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

같이 보기
-----

* URL 관련 다른 인터페이스: `URL`, `HTMLHyperlinkElementUtils`.
* Google Developers: Easy URL manipulation with URLSearchParams


Navigator: geolocation 속성 - Web API

Navigator: geolocation 속성
=========================

**Secure context:** This feature is available only in secure contexts (HTTPS), in some or all supporting browsers.

**`Navigator.geolocation`** 읽기 전용 속성은 웹에서 장치의 위치를 알아낼 때 사용할 수 있는 `Geolocation` 객체를 반환합니다. 웹 사이트나 웹 앱은 위치정보를 사용해 결과 화면을 맞춤 설정할 수 있습니다.

**참고:** 보안 상의 문제로, 웹 페이지가 위치 정보에 접근을 시도하면 사용자에게 알림을 보내고 권한을 허용할지 묻습니다. 각 브라우저는 자신만의 권한 정책과 요청 방식을 가지고 있으므로 주의해야 합니다.

명세
--

| Specification |
| --- |
| Geolocation API # dom-navigator-geolocation |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

같이 보기
-----

* Geolocation API 사용하기


window.navigator.battery - Web API

window.navigator.battery
========================

`battery` 객체는 시스템의 배터리 충전 상태에 대한 정보를 제공합니다. 배터리의 충전 상태가 변화할때 발생하는 이벤트에 대한 처리도 가능 합니다. 이 객체는 Battery Status API 의 구현입니다. 보다 자세한 내용, API, 샘플 코드 등은 문서를 참고 해 주세요.

문법
--

```js
var battery = window.navigator.battery;
```

값
-

`navigator.battery` 는 `BatteryManager` 객체 입니다.

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

같이 보기
-----

* `BatteryManager`
* Battery Status API 문서
* 블로그 - Using the Battery API
* David Walsh 가 쓴 the JavaScript Battery Api
* battery.js - 경량의 크로스 브라우저 랩퍼(wrapper)


window.navigator.connection - Web API

window.navigator.connection
===========================

**실험적:** **이 기능은 실험적인 기능입니다.**
프로덕션 환경에서 사용하기 전에 브라우저 호환성 표를 주의 깊게 확인하세요.

요약
--

네트워크 정보 API는 사용자 기기의 현재 대역폭이나 연결이 과금되는 지와 같은 정보를 알려줍니다. 이를 이용해서 사용자의 연결에 기반해서 높은 품질의 콘텐츠를 제공할지 낮은 품질의 콘텐츠를 제공할지 선택할 수 있습니다.

속성
--

`connection.bandwidth` 읽기 전용

현재 연결에 대한 다운로드 대역폭을 MB/s 단위의 double 형태로 알려줍니다. 사용자가 오프라인일 경우는 `0`이고 알 수 없을 경우에는 `infinity`로 나옵니다.

`connection.metered` 읽기 전용

연결이 과금이 되는 경우(예를 들어 pay-per-use) `Boolean` 형의 `true`가 반환됩니다.

### 이벤트 핸들러

`connection.onchange`

`change (en-US)` 이벤트에 대한 이벤트 핸들러 속성입니다. 연결 정보가 변경될 때 이벤트가 발생합니다.

**참고:** **주의:** `connection` 객체는 이벤트를 다루기 위한 `addEventListener` 메서드를 사용할 수 있는 `EventTarget`을 상속받습니다.

명세
--

| Specification |
| --- |
| Network Information API # connection-attribute |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

관련 내용
-----

* Network Information API
* Online and offline events


Navigator: sendBeacon() 메서드 - Web API

Navigator: sendBeacon() 메서드
===========================

**`navigator.sendBeacon()`** 메서드는 적은 양의 데이터를 포함하는 HTTP POST 요청을 비동기적으로 웹 서버에 보냅니다.

`XMLHttpRequest` 같은 오래된 기술로 웹 서버에 분석 정보를 전송할 때 생길 수 있는 일부 문제를 피하기 위해 고안됐습니다.

**참고:** 요청을 `POST` 외의 다른 메서드로 보내야 하거나, 어떤 요청 속성을 바꾸어서 보내야 하거나, 서버로부터의 응답을 받아야 하면 `fetch()`의 `keepalive`를 `true`로 설정한 것을 대신 사용하세요.

구문
--

```js
sendBeacon(url)
sendBeacon(url, data)
```

### 매개변수

`url`

*data* 를 받을 서버의 URL 입니다. 상대 주소와 절대 주소 모두 가능합니다.

`data` Optional

`ArrayBuffer`, `TypedArray`, `DataView`, `Blob`,
 문자열 또는 객체 리터럴, `FormData`, `URLSearchParams` 등, 전송할 데이터를 담은 객체입니다.

### 반환 값

**`sendBeacon()`** 메서드는 사용자 에이전트가 전송할 `data`를 대기열에 성공적으로 추가하면 `true`를 반환하고, 아니면 `false`를 반환합니다.

설명
--

이 메서드는 분석 정보나 진단 데이터를 서버에 보내기 위해 고안됐습니다.

많은 경우, 사이트에서 분석/진단 데이터 전송을 바라는 시점은 사용자가 다른 페이지로 이동할 때처럼 이탈 순간입니다. 기존 방법으로 분석 정보를 보낼 때의 문제는, 이탈 시 전송의 경우 페이지가 언로딩되기 직전인 순간일 수도 있으므로, 브라우저가 재량에 따라 비동기적인 `XMLHttpRequest` 요청을 보내지 않을 수도 있다는 점입니다.

과거 웹 페이지들은 데이터를 모두 보낼 수 있을 정도로 페이지의 언로딩을 지연시키기도 했습니다. 정확히는 아래와 같은 기법이 있었습니다.

* 블로킹하도록 동기적 `XMLHttpRequest`로 데이터 전송
* `<img>` 태그를 만들고 `src`를 설정하기. 대부분의 사용자 에이전트는 이미지를 로드하기 위해 페이지 언로드를 미룹니다.
* 의미 없는 무한 반복 루프를 몇 초동안 실행하기.

이러한 방법들은 모두 문서의 언로딩을 막으므로 다음 페이지로의 탐색 속도가 저하됩니다. 다음 페이지에는 이를 피하기 위해 할 수 있는 게 없습니다. 따라서 성능 문제는 이전 페이지에 있는데도 새로운 페이지가 느리게 느껴질 것입니다.

`sendBeacon()` 메서드를 사용하면, 언로딩이나 다음 탐색 지연 없이, 사용자 에이전트가 적절한 순간에 데이터를 비동기적으로 전송합니다. 따라서...

* 데이터가 안정적으로 전송됨
* 비동기적임
* 다음 페이지에 영향을 끼치지 않음

데이터는 HTTP POST 요청으로 보내집니다.

### 세션 끝에서 분석 정보 보내기

웹 사이트는 대개 사용자가 페이지에서 이탈할 때 진단이나 분석 정보를 보내고자 합니다. 가장 안정적인 방법은 `visibilitychange` 이벤트에서 데이터를 전송하는 것입니다.

```js
document.addEventListener("visibilitychange", function logData() {
  if (document.visibilityState === "hidden") {
    navigator.sendBeacon("/log", analyticsData);
  }
});
```

#### unload와 beforeunload 지양

과거에는 많은 웹 사이트들이 세션 끝에 분석 정보를 보내기 위한 용도로 `unload`나 `beforeunload`를 사용했습니다. 그러나 이 방법은 극히 불안정합니다. 많은 경우, 특히 모바일에서, 브라우저는 `unload`, `beforeunload`, `pagehide` 등의 이벤트들을 전송하지 않습니다. 예를 들어, 아래의 세 경우에는 이 이벤트들을 수신할 수 없습니다.

1. 사용자가 페이지를 불러오고 상호작용합니다.
2. 사용자가 이탈할 때, 탭을 닫지 않고 다른 앱으로 전환합니다.
3. 사용자가 나중에 기기의 앱 관리자를 통해 브라우저를 닫습니다.

추가적으로, `unload` 이벤트는 최신 브라우저들에서 구현된 뒤로/앞으로 캐시(bfcache)와 호환되지 않습니다. Firefox를 포함한 일부 브라우저들에서는 `unload` 이벤트 처리기가 포함되어 있는 페이지를 bfcache에서 제외함으로써 호환성 문제를 해소하므로, 성능이 저하됩니다. Safari와 Chrome 등 나머지 브라우저들은 사용자가 하나의 탭에서 다른 페이지로 탐색하는 경우 `unload` 이벤트를 아예 전송하지 않습니다.

Firefox는 `beforeunload` 처리기로도 페이지를 bfcache에서 제외합니다.

#### pagehide를 대비책으로 사용하기

`visibilitychange`를 지원하지 않는 브라우저들을 지원하려면 `pagehide` (en-US) 이벤트를 사용하세요. `beforeunload`, `unload`와 같이 `pagehide`도 특히 모바일에서 불안정합니다. 하지만 적어도 bfcache와는 호환됩니다.

예제
--

다음 예제에서는 `sendBeacon()`을 호출해 분석 정보를 전송하는 `visibilitychange` 이벤트 처리기를 지정합니다.

```js
document.addEventListener("visibilitychange", function logData() {
  if (document.visibilityState === "hidden") {
    navigator.sendBeacon("/log", analyticsData);
  }
});
```

명세서
---

| Specification |
| --- |
| Beacon # sendbeacon-method |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

같이 보기
-----

* `visibilitychange` 이벤트.
* Beacon API 개요.
* Don't lose user and app state, use Page Visibility에서는 왜 `beforeunload`/`unload` 대신 `visibilitychange`를 사용해야 하는지 자세히 설명합니다.
* Page Lifecycle API에서는 웹 애플리케이션에서 페이지의 수명 주기 동작을 처리하는 최선의 방법들을 제시합니다.
* PageLifecycle.js: 페이지 수명 주기의 브라우저간 불일치를 처리하기 위한 JavaScript 라이브러리입니다.
* Back/forward cache. 뒤로/앞으로 캐시가 뭔지, 다양한 페이지 수명 주기 이벤트에서 이 캐시가 갖는 의미가 뭔지 설명합니다.


Navigator.share - Web API

Navigator.share
===============

**실험적:** **이 기능은 실험적인 기능입니다.**
프로덕션 환경에서 사용하기 전에 브라우저 호환성 표를 주의 깊게 확인하세요.

**`Navigator.share()`** 메소드는 Web Share API 의 부분으로서 디바이스의 네이티브 공유하기 메커니즘을 작동시킨다. Web Share API 가 지원되지 않는다면, 이 메소드는 `undefined` 일 것이다.

Syntax
------

```js
var sharePromise = window.navigator.share(data);
```

### Parameters

* *data*
    + : 공유할 데이터가 담긴 객체. 아래의 필드들 중 적어도 하나는 명시되어야 한다. 사용 가능한 옵션들은:
* `url`: 공유될 URL을 나타내는 `USVString`.
* `text`: 공유될 본문을 나타내는 `USVString`.
* `title`: 공유될 제목을 나타내는 `USVString`.
### Return value

사용자가 공유하기 액션을 완료하면 resolve 될 `Promise` (en-US). *data* 파라메터가 정확하게 명시되지 않는다면 즉시 reject 될 것이다.

예를 들어, 안드로이드용 크롬에서 반환되는 `Promise` 는 사용자가 공유할 애플리케이션을 선택한 후에 resolve 될 것이다.

Examples
--------

```js
navigator.share({
  title: document.title,
  text: "Hello World",
  url: "https://developer.mozilla.org",
}); // share the URL of MDN
```

명세서
---

| Specification |
| --- |
| Web Share API # share-method |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


Navigator.registerProtocolHandler() - Web API

Navigator.registerProtocolHandler()
===================================

**Secure context:** This feature is available only in secure contexts (HTTPS), in some or all supporting browsers.

**`Navigator.registerProtocolHandler()`** 메서드는 웹 사이트가 특정 URL 스킴("프로토콜")을 열거나 처리할 수 있도록 등록합니다. 이를테면, 이메일 사이트가 `mailto:` URL에, VoIP 사이트가 `tel:` URL에 자신을 등록할 때 사용할 수 있습니다.

구문
--

```js
navigator.registerProtocolHandler(protocol, url, title);
```

### 매개변수

`protocol`

웹 사이트가 처리하고자 하는 프로토콜 문자열. 예컨대 SMS 문자 메시지를 처리하고자 한다면 `"sms"`를 전달하세요.

`url`

처리기의 URL. **플레이스홀더로 사용할 `%s`를 반드시 포함**해야 합니다. 실제 사용 시, `%s`에는 처리 대상 URL을 이스케이프 처리해 대입합니다.> **참고:** 처리기의 URL은 반드시 `http` 또는 `https` 스킴을 필요로 합니다. 일부 브라우저는 보안상 `https`를 요구하므로 `https`를 사용하는 편이 좋습니다.

`title`

사람이 읽을 수 있는 형태의 처리기 이름. 브라우저 설정 등 처리기 목록에서 **사용자에게 보이는 이름**입니다.

### 예외

`SecurityError`

사용자 에이전트가 등록을 막았습니다. 다음 상황에서 발생할 수 있습니다.\* 등록하려는 스킴(프로토콜)이 유효하지 않습니다. 브라우저가 직접 처리하는 스킴을 등록하려 하면 발생합니다. (`https:`, `about:`, ...)

* 처리기 URL의 출처가 API를 호출한 페이지 출처와 일치하지 않습니다.
* 브라우저가 보안 맥락에서의 `registerProtocolHandler()` 호출을 요구합니다.
* 브라우저가 처리기 URL의 HTTPS 사용을 요구합니다.

`SyntaxError`

처리기 URL에 `%s` 플레이스홀더가 없습니다.

가능한 스킴
------

보안상의 이유로, `registerProtocolHandler()`가 등록할 수 있는 스킴은 제한적입니다.

**사용자 지정 스킴**은 다음 조건을 만족해야 합니다.

* 스킴이 `web+`로 시작합니다.
* `web+` 접두사 뒤에 다른 글자가 최소 하나 존재해야 합니다.
* 소문자 ASCII 문자로만 구성해야 합니다.

아래 예제에서 사용한 `web+burger`는 제약조건을 만족하는 사용자 지정 스킴입니다.

그 외에는 다음 스킴을 등록할 수 있습니다.

* `bitcoin`
* `geo`
* `im`
* `irc`
* `ircs`
* `magnet`
* `mailto`
* `mms`
* `news`
* `nntp`
* `openpgp4fpr`
* `sip`
* `sms`
* `smsto`
* `ssh`
* `tel`
* `urn`
* `webcal`
* `wtai`
* `xmpp`
예제
--

사이트 주소가 `burgers.example.com`인 경우, 아래 코드로 `web+burger:` 스킴에 대한 처리기를 등록할 수 있습니다.

```js
navigator.registerProtocolHandler(
  "web+burger",
  "https://burgers.example.com/?burger=%s",
  "Burger handler",
);
```

이제, `web+burger:` 링크는 사용자를 `burgers.example.com`로 보내고, 자신의 URL을 `%s` 위치에 삽입합니다.

이때, 예제 코드는 처리기 URL과 같은 출처를 가져야 하므로 `https://burgers.example.com`의 페이지 안에서 호출해야 하며, 처리기 URL은 `http`/`https`를 사용해야 합니다.

명세
--

| Specification |
| --- |
| HTML Standard # custom-handlers |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


Online and offline events - Web API

Online and offline events
=========================

In progress Firefox 3는 WHATWG 웹 애플리케이션 1.0 명세에 기술된 온라인/오프라인 이벤트를 구현합니다.

### 개요

좋은 오프라인 가능(offline-capable) 웹 애플리케이션을 작성하려면 여러분의 애플리케이션이 실제로 오프라인이 되는 때를 알아야 합니다. 덧붙여, 여러분의 애플리케이션이 '온라인' 상태로 돌아오는 때도 알아야 합니다. 사실, 이 요구사항은 다음과 같이 정리할 수 있습니다.

1. 여러분이 서버와 재동기화할 수 있도록 사용자가 온라인으로 돌아오는 때를 알아야 합니다.
2. 여러분의 서버 요청을 나중에 처리하기 위해 대기시킬 수 있도록 사용자가 오프라인이 되는 때를 알아야 합니다.

온라인/오프라인 이벤트는 이 과정을 단순하게 만드는 것을 도와줍니다.

여러분의 웹 애플리케이션은 특정 문서가 오프라인 자원 캐시에 보관되는 것을 확실하게 할 필요도 있습니다. 이를 위해서는 다음과 같이 `HEAD` 섹션에 `LINK` 요소를 포함합니다.

```html
<link rel="offline-resource" href="myresource" />
```

이는 Firefox 3 및 이후 버전에서 HTML을 처리할 때, 참조하는 자원을 오프라인에서 사용할 수 있도록 특별한 오프라인 자원 캐시에 저장하도록 합니다.

### API

#### `navigator.onLine`

`navigator.onLine`는 `true`/`false`(온라인은 `true`, 오프라인은 `false`)를 보관하는 속성입니다. 이 속성은 사용자가 해당 메뉴 항목(파일 -> 오프라인 작업)을 선택하여 "오프라인 모드"로 전환할 때마다 갱신됩니다.

또한 이 속성은 브라우저가 네트워크에 더 이상 연결할 수 없을 때마다 갱신됩니다. 명세에 따르면:

>
> 사용자가 링크를 따라가거나 스크립트가 원격 페이지를 요청할 때 사용자 에이전트가 네트워크에 접속할 수 없으면 (혹은 그러한 시도가 실패할 것이라는 것을 안다면) `navigator.onLine` 속성은 false를 반환해야 합니다...
>
>
>

Firefox 2는 윈도우와 리눅스에서 브라우저의 온라인/오프라인 모드가 바뀔 때와 네트워크가 끊어지거나 다시 접속될 때 이 속성을 갱신합니다.

이 속성은 Firefox와 Internet Explorer의 이전 버전에도 있으므로 (명세는 이러한 기존 구현을 바탕으로 합니다) 이를 즉시 사용할 수 있습니다. 네트워크 상태의 자동 감지는 Firefox 2에서 구현되었습니다.

#### "`online`"과 "`offline`" 이벤트

Firefox 3는 두 가지 새로운 이벤트를 도입하고 있습니다: 바로 "`online`"과 "`offline`"입니다. 이 두 가지 이벤트는 브라우저가 온라인과 오프라인 모드를 전환할 때 각 페이지의 `<body>`에서 발생합니다. 덧붙여, 이 이벤트는 `document.body`에서 `document`로 전달되고 `window`에서 끝납니다. 두 가지 이벤트 모두 취소 불가능한(non-cancellable) 이벤트입니다(여러분은 사용자가 온라인이 되거나 오프라인이 되는 것을 막을 수 없습니다).

널리 알려진 몇 가지 방법으로 해당 이벤트에 대한 리스너(listener)를 등록할 수 있습니다.

* `window`, `document`, `document.body`에서 `addEventListener`를 이용
* JavaScript의 `Function` 개체에서 `document`나 `document.body`에 `.ononline` 혹은 `.onoffline` 속성을 설정 (**참고:** 호환성 때문에`window.ononline`이나 `window.onoffline`은 올바로 동작하지 않습니다.)
* HTML 마크업의 `<body>` 태그에 `ononline="..."` 혹은 `onoffline="..."` 속성을 지정
### 예제

이벤트가 동작하는지 확인할 수 있는 간단한 테스트 케이스가 있습니다. XXX When mochitests for this are created, point to those instead and update this example -nickolay

```html
<!doctype html>
<html>
  <head>
    <script>
 function updateOnlineStatus(msg) {
 var status = document.getElementById("status");
 var condition = navigator.onLine ? "ONLINE" : "OFFLINE";
 status.setAttribute("class", condition);
 var state = document.getElementById("state");
 state.innerHTML = condition;
 var log = document.getElementById("log");
 log.appendChild(
 document.createTextNode(
 "Event: " + msg + "; status=" + condition + "\n",
 ),
 );
 }
 function loaded() {
 updateOnlineStatus("load");
 document.body.addEventListener(
 "offline",
 function () {
 updateOnlineStatus("offline");
 },
 false,
 );
 document.body.addEventListener(
 "online",
 function () {
 updateOnlineStatus("online");
 },
 false,
 );
 }
 </script>
    <style>
 ...
 </style>
  </head>
  <body onload="loaded()">
    <div id="status"><p id="state"></p></div>
    <div id="log"></div>
  </body>
</html>
```

### 참고

* 'Online/Offline events' section from the WHATWG Web Applications 1.0 Specification
* The bug tracking online/offline events implementation in Firefox and a follow-up
* A simple test case
* An explanation of Online/Offline events


Navigator.mediaDevices - Web API

Navigator.mediaDevices
======================

**`Navigator.mediaDevices`** 읽기 전용 속성은 카메라, 마이크, 화면 공유와 같이 현재 연결된 미디어 입력 장치에 접근할 수 있는 `MediaDevices` 객체를 반환합니다.

구문
--

```js
var mediaDevices = navigator.mediaDevices;
```

### 반환 값

`MediaDevices` 싱글톤 객체.

명세
--

| Specification |
| --- |
| Media Capture and Streams # mediadevices |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

참조
--

* Media Capture and Streams API: 전체 미디어 스트림 API 문서의 시작 지점.
* WebRTC API: 밀접한 관련이 있는 WebRTC API 문서.


Navigator.language - Web API

Navigator.language
==================

**`Navigator.language`** 읽기 전용 속성은 사용자의 선호 언어(일반적으로 브라우저 UI의 언어)를 나타내는 문자열을 반환합니다.

구문
--

```js
const lang = navigator.language;
```

### 값

RFC 5646: Tags for Identifying Languages(BCP 47)가 정의한 언어 태그의 `DOMString`입니다. 유효한 값은 "en", "en-US", "ko", "ko-KR" 등입니다.

iOS Safari 버전 10.2 이전에서는 "en-us", "ko-kr"처럼 국가 코드를 소문자로 반환합니다.

예제
--

```js
if (/^en\b/.test(navigator.language)) {
  doLangSelect(window.navigator.language);
}
```

명세
--

| Specification |
| --- |
| HTML Standard # dom-navigator-language-dev |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

같이 보기
-----

* `navigator.languages` (en-US)
* `navigator`


KeyboardEvent.key - Web API

KeyboardEvent.key
=================

`KeyboardEvent` 인터페이스의 읽기 전용 속성인 **`key`** 는 키보드 로케일과 레이아웃뿐만 아니라 `Shift`와 같은 보조 키의 상태까지 고려하여, 사용자가 누른 키의 값을 반환합니다.

값
-

문자열입니다.

이 값은 다음과 같이 결정됩니다.

* 만약 눌린 키의 값이 인쇄 가능할 경우, 반환되는 값은 키의 인쇄 가능한 값을 나타내는 비어 있지 않은 유니코드 문자열입니다.
* 만약 눌린 키가 제어 문자 또는 특수 문자라면, 반환되는 값은 사전 정의된 key 값들의 목록 (en-US) 중의 하나입니다.
* 만약 `KeyboardEvent` 가 dead key의 눌림을 나타낸다면, 키의 값은 "`Dead`"여야 합니다.
* Windows에서는 일부 특수 키보드의 키(멀티미디어 키보드에서 미디어를 제어하는 확장 키 등)들의 키 코드가 만들어지지 않습니다. 대신에 이 키들은 `WM_APPCOMMAND` 이벤트를 발생시킵니다. 이 이벤트들은 실제 키 코드가 아니더라도 DOM 키보드 이벤트에 매핑되어 있으며, Windows의 "Virtual key codes"에 명시되어 있습니다.
* 키를 식별할 수 없는 경우, 반환되는 값은 `Unidentified`입니다.

>
> **콜아웃:**
>
>
> key 값들의 전체 목록을 확인하려면 누르세요 (en-US).
>
>
>

KeyboardEvent 시퀀스
-----------------

모든 `KeyboardEvent` 는 미리 정해진 시퀀스 안에서 발생합니다. 키가 눌렸을 때, `Event.preventDefault`가 호출되지 않았다고 가정하면 `KeyboardEvent` 의 시퀀스는 다음과 같습니다.

1. `keydown` (en-US) 이벤트가 먼저 발생합니다. 만약 키가 추가로 눌리고 그 키가 문자 키를 생성한다면, 이벤트는 플랫폼 구현에 의존하는 간격으로 계속 발생하고, 읽기 전용 속성인 `KeyboardEvent.repeat` (en-US)는 `true`로 설정됩니다.
2. 만약 키가 `<input>` (en-US), `<textarea>` (en-US) 또는 `HTMLElement.contentEditable`이 true로 설정된 요소 안에 삽입될 수 있는 문자 키를 생성하는 경우, `beforeinput` (en-US) 과 `input` 이벤트 타입이 순서대로 실행됩니다. 일부 다른 구현에서는 `keypress` 이벤트가 지원된다면 `keypress` (en-US)를 발생시킬 수 있음에 주의해야 합니다. 이 이벤트들은 키를 누르고 있는 동안 반복해서 발생하게 됩니다.
3. 키를 떼면 `keyup` 이벤트가 발생합니다. 이것으로 프로세스가 완료됩니다.

시퀀스 1과 3에서 `KeyboardEvent.key` 속성이 정의되고, 앞서 정의되어 있는 규칙에 따라 적절한 값으로 설정됩니다.

KeyboardEvent 시퀀스 예제
--------------------

영국식 키보드 레이아웃을 사용할 때와 비교해서, 미국식 키보드 레이아웃을 사용한 `Shift` 와 `2` 키의 상호작용에서 발생하는 이벤트 시퀀스에 대해 고려해 보겠습니다.

다음의 두 개의 테스트 케이스를 사용하여 실험해 보세요.

1. `Shift` 키를 누르면서,
 `2` 키를 누른 다음 떼세요. 그 다음
 `Shift` 키를 떼세요.
2. `Shift` 키를 누르면서,
 `2` 키를 누르고 있으세요. 그 다음
 `Shift` 키를 떼세요. 마지막으로
 `2` 키를 떼세요.
### HTML

```html
<div class="fx">
  <div>
    <textarea rows="5" name="test-target" id="test-target"></textarea>
    <button type="button" name="btn-reset" id="btn-reset">Reset</button>
  </div>
  <div class="flex">
    <pre id="console-log"></pre>
  </div>
</div>
```

### CSS

```css
.fx {
  -webkit-display: flex;
  display: flex;
  margin-left: -20px;
  margin-right: -20px;
}

.fx > div {
  padding-left: 20px;
  padding-right: 20px;
}

.fx > div:first-child {
  width: 30%;
}

.flex {
  -webkit-flex: 1;
  flex: 1;
}

#test-target {
  display: block;
  width: 100%;
  margin-bottom: 10px;
}
```

### JavaScript

```js
let textarea = document.getElementById("test-target"),
  consoleLog = document.getElementById("console-log"),
  btnReset = document.getElementById("btn-reset");

function logMessage(message) {
  consoleLog.innerHTML += message + "<br>";
}

textarea.addEventListener("keydown", (e) => {
  if (!e.repeat) logMessage(`Key "${e.key}" pressed [event: keydown]`);
  else logMessage(`Key "${e.key}" repeating [event: keydown]`);
});

textarea.addEventListener("beforeinput", (e) => {
  logMessage(`Key "${e.data}" about to be input [event: beforeinput]`);
});

textarea.addEventListener("input", (e) => {
  logMessage(`Key "${e.data}" input [event: input]`);
});

textarea.addEventListener("keyup", (e) => {
  logMessage(`Key "${e.key}" released [event: keyup]`);
});

btnReset.addEventListener("click", (e) => {
  let child = consoleLog.firstChild;
  while (child) {
    consoleLog.removeChild(child);
    child = consoleLog.firstChild;
  }
  textarea.value = "";
});
```

### 결과

**참고:** `beforeinput` (en-US) 과 `input` 이벤트에 사용되는 `InputEvent` 인터페이스가 완전히 구현되지 않은 브라우저에서는 잘못된 출력 결과를 얻을 수도 있습니다.

### Case 1

`shift` 키가 눌렸을 때 `keydown` (en-US) 이벤트가 먼저 발생하고, `key` 속성의 값은 문자열 `Shift`가 됩니다. `shift` 키를 계속 누르고 있더라도, 문자 키가 아니기 때문에 `keydown` (en-US) 이벤트가 반복적으로 발생하지는 않습니다.

`key 2`가 눌리면 또 하나의 새로운 `keydown` (en-US) 이벤트가 발생하고, 활성화된 보조 키 `shift` 때문에 이 이벤트의 `key` 속성의 값은 미국식 키보드에서의 `@` 또는 영국식 키보드에서의 `"`로 변경됩니다. 문자 키가 생성되었기 때문에 그 다음은 `beforeinput` (en-US) 와 `input` 이벤트들이 발생합니다.

`key 2`를 떼면 `keyup` 이벤트가 발생하고, `key` 속성은 키보드 레이아웃에 따라서 `@` 나 `"` 의 문자열 값을 유지합니다.

마지막으로 `shift` 키를 떼면 또 다른 `keyup` 이벤트가 발생하고, `key` 속성의 값은 `Shift`로 유지됩니다.

### Case 2

`shift` 키가 눌렸을 때 `keydown` (en-US) 이벤트가 먼저 발생하고, `key` 속성의 값은 문자열 `Shift`가 됩니다. `shift` 키를 계속 누르고 있더라도, 문자 키가 아니기 때문에 `keydown` (en-US) 이벤트가 반복적으로 발생하지는 않습니다.

`key 2`가 눌리면 또 하나의 새로운 `keydown` (en-US) 이벤트가 발생하고, 활성화된 보조 키 `shift` 때문에 이 이벤트의 `key` 속성의 값은 미국식 키보드에서의 `@` 또는 영국식 키보드에서의 `"`로 변경됩니다. 문자 키가 생성되었기 때문에 그 다음은 `beforeinput` (en-US) 와 `input` 이벤트들이 발생합니다. 키가 계속 눌리는 동안 `keydown` (en-US) 이벤트가 반복적으로 발생하고, `KeyboardEvent.repeat` (en-US) 속성은 `true`가 됩니다. 또한 `beforeinput` (en-US)과 `input` 이벤트도 반복적으로 발생합니다.

`shift` 키를 떼면 `keyup` 이벤트가 발생하고, `key` 속성은 `Shift`로 유지됩니다. 이 때, 보조 키인 `shift`가 더 이상 활성화되어 있지 않기 때문에 `key 2`의 반복되는 `keydown` (en-US) 이벤트에 대한 `key` 속성의 값이 이제 "2"가 되었다는 것에 주의해야 합니다. 이것은 `beforeinput` (en-US)과 `input` 이벤트의 `InputEvent.data` (en-US) 속성에도 똑같이 적용됩니다.

마지막으로 `key 2`를 떼면 `keyup` 이벤트가 발생하지만, 보조 키인 `shift`가 더 이상 활성화되어 있지 않으므로 `key` 속성은 두 키보드 모두에서 문자열 `2`로 설정됩니다.

예제
--

이 예제는 `keydown` (en-US) 이벤트를 처리하기 위해 `EventTarget.addEventListener()`를 사용합니다. 이벤트가 발생하면 키의 값이 코드에서 언급된 키 중의 하나인지 확인하고, 만약 그렇다면 각각의 방식(게임에서 우주선을 조종하거나, 스프레드시트에서 선택한 셀을 변경하는 등)으로 처리됩니다.

```js
window.addEventListener(
  "keydown",
  function (event) {
    if (event.defaultPrevented) {
      return; // 이미 이벤트가 실행되는 중이라면 아무 동작도 하지 않습니다.
    }

    switch (event.key) {
      case "Down": // IE/Edge에서 사용되는 값
      case "ArrowDown":
        // "아래 화살표" 키가 눌렸을 때의 동작입니다.
        break;
      case "Up": // IE/Edge에서 사용되는 값
      case "ArrowUp":
        // "위 화살표" 키가 눌렸을 때의 동작입니다.
        break;
      case "Left": // IE/Edge에서 사용되는 값
      case "ArrowLeft":
        // "왼쪽 화살표" 키가 눌렸을 때의 동작입니다.
        break;
      case "Right": // IE/Edge에서 사용되는 값
      case "ArrowRight":
        // "오른쪽 화살표" 키가 눌렸을 때의 동작입니다.
        break;
      case "Enter":
        // "enter" 또는 "return" 키가 눌렸을 때의 동작입니다.
        break;
      case "Esc": // IE/Edge에서 사용되는 값
      case "Escape":
        // "esc" 키가 눌렸을 때의 동작입니다.
        break;
      default:
        return; // 키 이벤트를 처리하지 않는다면 종료합니다.
    }

    // 두 번 동작하는 것을 막기 위해 기본 동작을 취소합니다.
    event.preventDefault();
  },
  true,
);
```

명세서
---

| Specification |
| --- |
| UI Events # dom-keyboardevent-key |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.


SVGGraphicsElement.getBBox() - Web API

SVGGraphicsElement.getBBox()
============================

**`SVGGraphicsElement.getBBox()`** 메서드는 객체가 들어가는 가장 작은 직사각형의 좌표를 알아냅니다. 반환되는 좌표는 (목표 요소에 포함된 모든 요소의 모든 기하 특성의 적용 이후의) 현재 SVG 공간에 관련되어 있습니다.

**참고:** `getBBox()` 는 요소가 아직 렌더링되지 않은 경우일지라도
 반드시 메서드가 호출된 시점에서의 실제 바운딩 박스를 반환해야 합니다.
 이 메서드는 또한 요소나 부모 요소에 적용된 어떠한 변형도 고려하지 않습니다.

**참고:** `getBBox` 는 `getBoundingClientRect()`와
 다른 값을 반환하는데, `getBoundingClientRect()`는
 뷰포트에 관련된 값을 반환합니다.

구문
--

```js
let bboxRect = object.getBBox();
```

### 매개변수

`Options`
Experimental
 Optional

요소의 어떤 부분들이 바운딩 박스에 포함되는지를 제어하는 데 쓰이는 옵션 dictionary. 가능한 옵션은 아래와 같습니다.

`fill`

fill이 바운딩 박스에 포함되어야 함을 나타내는 boolean 값. 기본 값은 `true` 입니다.

`stroke`

stroke가 바운딩 박스에 포함되어야 함을 나타내는 boolean 값. 기본 값은 `false` 입니다.

`markers`

markers가 바운딩 박스에 포함되어야 함을 나타내는 boolean 값. 기본 값은 `false` 입니다.

`clipped`

바운딩 박스가 클리핑되어야 함을 나타내는 boolean 값. 기본 값은 `false` 입니다.

### 반환 값

반환 값은 `SVGRect` 객체인데, 이 객체는 바운딩 박스를 정의합니다. 이 값은 요소 혹은 부모 요소에 적용된 어떠한 변형 특성과도 관계없습니다.

예제
--

### HTML

```html
<svg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg">
  <g id="group\_text\_1">
    <text x="5" y="16" transform="scale(2, 2)">Hello World!</text>
    <text x="8" y="32" transform="translate(0 20) scale(1.25 1)">
      Hello World Again!
    </text>
  </g>
  <!-- 녹색으로 BBox를 보여줍니다 -->
  <rect id="rect\_1" stroke="#00ff00" stroke-width="3" fill="none"></rect>
  <!-- 적색으로 BoundingClientRect를 보여줍니다 -->
  <rect id="rect\_2" stroke="#ff0000" stroke-width="3" fill="none"></rect>
</svg>
```

### JavaScript

```js
var rectBBox = document.querySelector("#rect\_1");
var rectBoundingClientRect = document.querySelector("#rect\_2");
var groupElement = document.querySelector("#group\_text\_1");

var bboxGroup = groupElement.getBBox();
rectBBox.setAttribute("x", bboxGroup.x);
rectBBox.setAttribute("y", bboxGroup.y);
rectBBox.setAttribute("width", bboxGroup.width);
rectBBox.setAttribute("height", bboxGroup.height);

var boundingClientRectGroup = groupElement.getBoundingClientRect();
rectBoundingClientRect.setAttribute("x", boundingClientRectGroup.x);
rectBoundingClientRect.setAttribute("y", boundingClientRectGroup.y);
rectBoundingClientRect.setAttribute("width", boundingClientRectGroup.width);
rectBoundingClientRect.setAttribute("height", boundingClientRectGroup.height);
```

명세서
---

| Specification |
| --- |
| Scalable Vector Graphics (SVG) 2 # \_\_svg\_\_SVGGraphicsElement\_\_getBBox |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

같이 보기
-----

* SVG Primer 내의 getBBox


FormData.set() - Web API

FormData.set()
==============

`FormData` 인터페이스의 **`set()`** 메서드는 `FormData` 객체 내에 있는 기존 키에 새 값을 설정하거나, 존재하지 않을 경우 key/value을 추가합니다.

`set()` 과 `FormData.append` 의 차이점은 지정된 키가 이미 존재할 경우에, `set()` 은 모든 기존 값들을 새로운 값으로 덮어쓰기하는 반면, `FormData.append` 는 기존 값의 끝에 새 값을 추가합니다.

**참고:** 이 메서드는 Web Worker에서 사용할 수 있습니다.

Syntax
------

이 메서드에는 두 가지 버전이 있습니다: 매개변수가 두 개인 버전과 세 개인 버전입니다:

```js
formData.set(name, value);
formData.set(name, value, filename);
```

### Parameters

`name`

`value` 에 포함되는 데이터 필드의 이름입니다.

`value`

필드의 값입니다. 파라미터가 두 개인 버전에서는 `USVString`이고, 그렇지 않은 경우 문자열로 변환됩니다. 파라미터가 세 개인 버전에서는 `Blob`, `File`, `USVString`이 될 수 있습니다. 이들 중 어느것도 지정되지 않으면 값은 문자열로 변환됩니다.

`filename` Optional

`Blob` 또는 `File` 이 두 번째 매개 변수로 전달될 때, 서버에 리포트하는 파일 이름(a `USVString`)입니다. `Blob` 객체의 기본 파일 이름은 "blob"입니다.

**참고:** `Blob` 을 `FormData` 객체에 추가할 데이터로 지정하면, "Content-Disposition" 헤더에서 서버에 리포트하는 파일 이름이 브라우저마다 다를 수 있습니다.

Example
-------

다음 코드를 따라 빈 `FormData` 객체를 만듭니다:

```js
var formData = new FormData(); // Currently empty
```

`FormData.set`를 사용하여 key/value 쌍을 추가할 수 있습니다::

```js
formData.set("username", "Chris");
formData.set("userpic", myFileInput.files[0], "chris.jpg");
```

명세서
---

| Specification |
| --- |
| XMLHttpRequest Standard # dom-formdata-set |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* `XMLHTTPRequest`
* Using XMLHttpRequest (en-US)
* Using FormData objects (en-US)
* `<form>`


FormData.getAll() - Web API

FormData.getAll()
=================

`FormData` 인터페이스의 **`getAll()`** 메서드는 `FormData` 객체에서 지정된 키와 연관된 모든 값을 반환합니다.

**참고:** 이 메서드는 Web Worker에서 사용할 수 있습니다.

Syntax
------

```js
formData.getAll(name);
```

### Parameters

`name`

검색하고 싶은 키의 이름을 나타내는 `USVString` 입니다.

### Returns

`FormDataEntryValue` (en-US)의 배열입니다.

Example
-------

다음 코드를 따라 빈 `FormData` 객체를 만듭니다:

```js
var formData = new FormData();
```

`FormData.append`를 사용하여 `username` 에 두 개의 값을 추가합니다:

```js
formData.append("username", "Chris");
formData.append("username", "Bob");
```

`getAll()` 함수는 `username` 의 값들을 배열로 반환합니다:

```js
formData.getAll("username"); // Returns ["Chris", "Bob"]
```

명세서
---

| Specification |
| --- |
| XMLHttpRequest Standard # dom-formdata-getall |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* `XMLHTTPRequest`
* Using XMLHttpRequest (en-US)
* Using FormData objects (en-US)
* `<form>`


FormData.values() - Web API

FormData.values()
=================

**`FormData.values()`** 메서드는 이 객체에 포함 된 모든 value를 통과하는 `iterator`를 반환합니다. value는 `USVString` 또는 `Blob` 객체입니다.

**참고:** 이 메서드는 Web Worker에서 사용할 수 있습니다.

Syntax
------

```js
formData.values();
```

### Return value

`iterator`를 반환합니다.

Example
-------

```js
// Create a test FormData object
var formData = new FormData();
formData.append("key1", "value1");
formData.append("key2", "value2");

// Display the values
for (var value of formData.values()) {
  console.log(value);
}
```

결과는 다음과 같습니다:
```

value1
value2
```

명세서
---

#### No specification found

No specification data found for `api.FormData.values`.
Check for problems with this page or contribute a missing `spec_url` to mdn/browser-compat-data. Also make sure the specification is included in w3c/browser-specs.

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* `XMLHTTPRequest`
* Using XMLHttpRequest (en-US)
* Using FormData objects (en-US)
* `<form>`


FormData.append() - Web API

FormData.append()
=================

`FormData` 인터페이스의 **`append()`** 메서드는 `FormData` 객체의 기존 키에 새 값을 추가하거나, 키가 없는 경우 키를 추가합니다.

`FormData.set` 과 `append()` 의 차이점은 지정된 키가 이미 있으면, `FormData.set` 은 모든 기존 값을 새 값으로 덮어쓰기를 합니다. 반면 `append()` 는 기존 값 집합의 끝에 새로운 값을 추가합니다.

**참고:** 이 메서드는 Web Worker에서 사용할 수 있습니다.

Syntax
------

이 메서드에는 두 가지 버전이 있습니다: 매개변수가 두 개인 버전과 세 개인 버전입니다:

```js
formData.append(name, value);
formData.append(name, value, filename);
```

### Parameters

`name`

`value` 에 포함되는 데이터 필드의 이름입니다.

`value`

필드의 값입니다. `USVString` 또는 `Blob` (`File`과 같은 sublcass를 포함하여) 일 수 있습니다.

`filename` Optional

`Blob` 또는 `File` 이 두 번째 매개 변수로 전달될 때, 서버에 리포트하는 파일 이름(a `USVString`)입니다. `Blob` 객체의 기본 파일 이름은 "blob" 입니다. `File` 객체의 기본 파일 이름은 파일의 이름이 됩니다.

**참고:** `Blob` 을 `FormData` 객체에 추가할 데이터로 지정하면, "Content-Disposition" 헤더에서 서버에 리포트하는 파일 이름이 브라우저마다 다를 수 있습니다.

### Returns

Void.

Example
-------

다음 코드를 따라 빈 `FormData` 객체를 만듭니다:

```js
var formData = new FormData(); // Currently empty
```

`FormData.append`를 사용하여 key/value 쌍을 추가할 수 있습니다:

```js
formData.append("username", "Chris");
formData.append("userpic", myFileInput.files[0], "chris.jpg");
```

일반 form 데이터와 마찬가지로 동일한 이름의 여러 값을 추가할 수 있습니다. 예를들면 (그리고 이름에 []를 추가하여 PHP의 명명 규칙과 호환이 가능합니다):

```js
formData.append("userpic[]", myFileInput.files[0], "chris1.jpg");
formData.append("userpic[]", myFileInput.files[1], "chris2.jpg");
```

이 기술을 사용하면 서버에 올라간 결과 데이터가 루프를 도는데 도움이 되는 구조이기 때문에, 이 기술을 사용하면 다중 -파일 업로드를 보다 쉽게 처리할 수 있습니다.

명세서
---

| Specification |
| --- |
| XMLHttpRequest Standard # dom-formdata-append |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* `XMLHTTPRequest`
* Using XMLHttpRequest (en-US)
* Using FormData objects (en-US)
* `<form>`


FormData.delete() - Web API

FormData.delete()
=================

`FormData` 인터페이스의 **`delete()`** 메서드는 `FormData` 객체에서 key와 그 값에 해당하는 것을 지웁니다.

**참고:** 이 메서드는 Web Worker에서 사용할 수 있습니다.

Syntax
------

```js
formData.delete(name);
```

### Parameters

`name`

삭제할 key의 이름 입니다.

### Returns

Void.

Example
-------

다음 코드를 따라 빈 `FormData` 객체를 만들고, form의 key/value 쌍을 미리 채웁니다:

```js
var formData = new FormData(myForm);
```

`delete()`를 사용하여 키와 값을 삭제할 수 있습니다:

```js
formData.delete("username");
```

명세서
---

| Specification |
| --- |
| XMLHttpRequest Standard # dom-formdata-delete |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* `XMLHTTPRequest`
* Using XMLHttpRequest (en-US)
* Using FormData objects (en-US)
* `<form>`


FormData() - Web API

FormData()
==========

**`FormData()`** 생성자(Constructor)는 새로운 `FormData`객체를 만듭니다.

**참고:** 이 기능은 Web Worker에서 사용할 수 있습니다.

Syntax
------

```js
var formData = new FormData(form);
```

### Parameters

`form` Optional

HTML `<form>` 요소 — 지정된 경우 `FormData` 객체는 form의 현재 key/value 들로 채워집니다. key/value는 submit한 각 요소의 name property와 value를 사용합니다. 또한 파일 입력 내용을 인코딩합니다.

Example
-------

다음 코드는 빈 `FormData` 객체를 만듭니다:

```js
var formData = new FormData(); // Currently empty
```

`FormData.append`을 사용하여 key/value 쌍을 추가할 수 있습니다:

```js
formData.append("username", "Chris");
```

또는 `FormData` 객체를 만들 때 선택적으로 `form` argument를 지정할 수 있는데, 지정된 양식대로 value를 미리 채우는 것입니다:

```html
<form id="myForm" name="myForm">
  <div>
    <label for="username">Enter name:</label>
    <input type="text" id="username" name="username" />
  </div>
  <div>
    <label for="useracc">Enter account number:</label>
    <input type="text" id="useracc" name="useracc" />
  </div>
  <div>
    <label for="userfile">Upload file:</label>
    <input type="file" id="userfile" name="userfile" />
  </div>
  <input type="submit" value="Submit!" />
</form>
```

**참고:** 모든 입력 요소는 'name' 속성(attribute) 을 갖고 있습니다. 나중에 value에 접근하는데 필요합니다.

```js
var myForm = document.getElementById("myForm");
formData = new FormData(myForm);
```

명세서
---

| Specification |
| --- |
| XMLHttpRequest Standard # dom-formdata |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* `XMLHTTPRequest`
* Using XMLHttpRequest (en-US)
* Using FormData objects (en-US)
* `<form>`


FormData.keys() - Web API

FormData.keys()
===============

**`FormData.keys()`** 메서드는 이 객체에 포함된 모든 키를 통과하는 `iterator` 를 반환합니다. 키는 `USVString` 객체입니다.

**참고:** 이 메서드는 Web Worker에서 사용할 수 있습니다.

Syntax
------

```js
formData.keys();
```

### Return value

`iterator`를 반환합니다.

Example
-------

```js
// Create a test FormData object
var formData = new FormData();
formData.append("key1", "value1");
formData.append("key2", "value2");

// Display the keys
for (var key of formData.keys()) {
  console.log(key);
}
```

결과는 다음과 같습니다:
```

key1
key2
```

명세서
---

#### No specification found

No specification data found for `api.FormData.keys`.
Check for problems with this page or contribute a missing `spec_url` to mdn/browser-compat-data. Also make sure the specification is included in w3c/browser-specs.

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* `XMLHTTPRequest`
* Using XMLHttpRequest (en-US)
* Using FormData objects (en-US)
* `<form>`


FormData.get() - Web API

FormData.get()
==============

`FormData` 인터페이스의 **`get()`** 메서드는 `FormData` 객체에서 지정한 키와 연관된 첫 번째 값을 반환합니다. 값이 여러개이고, 모든 값을 원하면 이 메서드 대신 `getAll()` 메서드를 사용하십시오.

**참고:** 이 메서드는 Web Worker에서 사용할 수 있습니다.

Syntax
------

```js
formData.get(name);
```

### Parameters

`name`

검색하고 싶은 키의 이름을 나타내는 `USVString` 입니다.

### Return value

값을 포함하는 `FormDataEntryValue` (en-US) 입니다.

Example
-------

다음 코드를 따라 빈 `FormData` 객체를 만듭니다:

```js
var formData = new FormData();
```

`FormData.append`를 사용하여 `username` 에 두 개의 값을 추가합니다:

```js
formData.append("username", "Chris");
formData.append("username", "Bob");
```

`get()` 함수를 사용하면 `username` 의 첫 번째 value만 반환합니다:

```js
formData.get("username"); // Returns "Chris"
```

명세서
---

| Specification |
| --- |
| XMLHttpRequest Standard # dom-formdata-get |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* `XMLHTTPRequest`
* Using XMLHttpRequest (en-US)
* Using FormData objects (en-US)
* `<form>`


FormData.entries() - Web API

FormData.entries()
==================

**`FormData.entries()`** 메서드는 이 객체에 포함된 모든 key/value 쌍을 통과하는 `iterator` 를 반환합니다. 각 쌍의 key는 `USVString` 객체입니다; value는 `USVString` 또는 `Blob` 중 하나입니다.

**참고:** 이 메서드는 Web Worker에서 사용할 수 있습니다.

Syntax
------

```js
formData.entries();
```

### Return value

`iterator`를 리턴합니다.

Example
-------

```js
// Create a test FormData object
var formData = new FormData();
formData.append("key1", "value1");
formData.append("key2", "value2");

// Display the key/value pairs
for (var pair of formData.entries()) {
  console.log(pair[0] + ", " + pair[1]);
}
```

결과는 다음과 같습니다:
```

key1, value1
key2, value2
```

명세서
---

#### No specification found

No specification data found for `api.FormData.entries`.
Check for problems with this page or contribute a missing `spec_url` to mdn/browser-compat-data. Also make sure the specification is included in w3c/browser-specs.

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* `XMLHTTPRequest`
* Using XMLHttpRequest (en-US)
* Using FormData objects (en-US)
* `<form>`


FormData.has() - Web API

FormData.has()
==============

`FormData` 인터페이스의 **`has()`** 메서드는 `FormData` 객체에 특정 키가 들어 있는지 여부를 나타내는 boolean 을 반환합니다.

**참고:** 이 메서드는 Web Worker에서 사용할 수 있습니다.

Syntax
------

```js
formData.has(name);
```

### Parameters

`name`

테스트 하려는 키의 이름을 나타내는 `USVString` 입니다.

### Returns

`Boolean`.

Example
-------

다음 코드를 따라 빈 `FormData` 객체를 만듭니다:

```js
var formData = new FormData();
```

다음 스니펫(코드 조각)은 `FormData` 객체안에 `username` 이 존재하는지 테스트한 결과와, `FormData.append`를 사용하여 `username` 에 값을 추가한 이후의 결과를 보여줍니다 :

```js
formData.has("username"); // Returns false
formData.append("username", "Chris");
formData.has("username"); // Returns true
```

명세서
---

| Specification |
| --- |
| XMLHttpRequest Standard # dom-formdata-has |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

See also
--------

* `XMLHTTPRequest`
* Using XMLHttpRequest (en-US)
* Using FormData objects (en-US)
* `<form>`


AnalyserNode.getByteFrequencyData() - Web API

AnalyserNode.getByteFrequencyData()
===================================

`AnalyserNode` 인터페이스의 **`getByteFrequencyData()`** 메서드는 전달된 `Uint8Array` (en-US) (unsigned byte array) 내로 현재 주파수 데이터를 복사합니다.

주파수 데이터는 0에서 255 스케일의 정수로 구성되어 있습니다.

배열 내의 각 원소는 특정한 주파수에 대한 데시벨 값을 나타냅니다. 주파수들은 0에서 샘플 레이트의 1/2까지 선형적으로 퍼져 있습니다. 예를 들자면, `48000` 샘플 레이트에 대해서, 배열의 마지막 원소는 `24000` Hz에 대한 데시벨 값을 나타냅니다.

만약 배열이 `AnalyserNode.frequencyBinCount`보다 더 적은 요소를 가지고 있다면, 초과한 요소는 탈락됩니다. 만약 이것이 필요한 것보다 더 많은 요소를 가지고 있다면, 초과한 요소는 무시됩니다.

구문
--

```js
var audioCtx = new AudioContext();
var analyser = audioCtx.createAnalyser();
var dataArray = new Uint8Array(analyser.frequencyBinCount); // Uint8Array는 frequencyBinCount와 같은 길이여야만 합니다

void analyser.getByteFrequencyData(dataArray); // getByteFrequencyData()로부터 반환된 데이터로 Uint8Array를 채웁니다
```

### 매개변수

`array`

 주파수 영역 데이터가 복사될 `Uint8Array` (en-US). 소리가 없는 모든 샘플에 대해서, 값은 `-Infinity`입니다.
 만약 배열이 `AnalyserNode.frequencyBinCount`보다 더 적은 요소를 가지고 있다면, 초과한 요소는 탈락됩니다. 만약 이것이 필요한 것보다 더 많은 요소를 가지고 있다면, 초과한 요소는 무시됩니다.

### 반환 값

없음.

예제
--

다음의 예제는 `AnalyserNode`를 생성하기 위한 `AudioContext`와 그리고 나서 반복적으로 주파수 데이터를 수집하고 현재 오디오 입력의 "winamp 막대그래프 스타일의" 출력을 그리기 위한 `requestAnimationFrame`과 `<canvas>`의 기본 사용을 보여줍니다. 더 완벽한 응용 예제/정보를 보려면 Voice-change-O-matic 데모를 확인하세요 (관련된 코드를 보려면 app.js 라인 128–205를 참고하세요).

```js
var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
var analyser = audioCtx.createAnalyser();

  ...

analyser.fftSize = 256;
var bufferLength = analyser.frequencyBinCount;
console.log(bufferLength);
var dataArray = new Uint8Array(bufferLength);

canvasCtx.clearRect(0, 0, WIDTH, HEIGHT);

function draw() {
  drawVisual = requestAnimationFrame(draw);

  analyser.getByteFrequencyData(dataArray);

  canvasCtx.fillStyle = 'rgb(0, 0, 0)';
  canvasCtx.fillRect(0, 0, WIDTH, HEIGHT);

  var barWidth = (WIDTH / bufferLength) \* 2.5;
  var barHeight;
  var x = 0;

  for(var i = 0; i < bufferLength; i++) {
    barHeight = dataArray[i];

    canvasCtx.fillStyle = 'rgb(' + (barHeight+100) + ',50,50)';
    canvasCtx.fillRect(x,HEIGHT-barHeight/2,barWidth,barHeight/2);

    x += barWidth + 1;
  }
};

draw();
```

명세
--

| Specification |
| --- |
| Web Audio API # dom-analysernode-getbytefrequencydata |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

같이 보기
-----

* Web Audio API 사용하기


AnalyserNode.getByteTimeDomainData() - Web API

AnalyserNode.getByteTimeDomainData()
====================================

`AnalyserNode` 인터페이스의 **`getByteTimeDomainData()`** 메서드는 전달된 `Uint8Array` (en-US) (unsigned byte array) 내로 현재 파형, 즉 시간 영역 데이터를 복사합니다.

만약 배열이 `AnalyserNode.fftSize`보다 더 적은 요소를 가지고 있다면, 초과한 요소는 탈락됩니다. 만약 이것이 필요한 것보다 더 많은 요소를 가지고 있다면, 초과한 요소는 무시됩니다.

구문
--

```js
const audioCtx = new AudioContext();
const analyser = audioCtx.createAnalyser();
const dataArray = new Uint8Array(analyser.fftSize); // Uint8Array는 fftSize와 같은 길이여야만 합니다
analyser.getByteTimeDomainData(dataArray); // getByteTimeDomainData()로부터 반환된 데이터로 Uint8Array를 채웁니다
```

### 매개변수

`array`

 시간 영역 데이터가 복사될 `Uint8Array` (en-US).
 만약 배열이 `AnalyserNode.fftSize`보다 더 적은 요소를 가지고 있다면, 초과한 요소는 탈락됩니다. 만약 이것이 필요한 것보다 더 많은 요소를 가지고 있다면, 초과한 요소는 무시됩니다.

### 반환 값

**`void`** | 없음

예제
--

다음의 예제는 `AnalyserNode`를 생성하기 위한 `AudioContext`와 그리고 나서 반복적으로 시간 영역 데이터를 수집하고 현재 오디오 입력의 "오실로스코프 스타일의" 출력을 그리기 위한 `requestAnimationFrame`과 `<canvas>`의 기본 사용을 보여줍니다. 더 완벽한 응용 예제/정보를 보려면 Voice-change-O-matic 데모를 확인하세요 (관련된 코드를 보려면 app.js 라인 128–205를 참고하세요).

```js
const audioCtx = new (window.AudioContext || window.webkitAudioContext)();
const analyser = audioCtx.createAnalyser();

  ...

analyser.fftSize = 2048;
const bufferLength = analyser.fftSize;
const dataArray = new Uint8Array(bufferLength);
analyser.getByteTimeDomainData(dataArray);

// 현재 오디오 소스의 오실로스코프를 그립니다
function draw() {
  drawVisual = requestAnimationFrame(draw);
  analyser.getByteTimeDomainData(dataArray);

  canvasCtx.fillStyle = 'rgb(200, 200, 200)';
  canvasCtx.fillRect(0, 0, WIDTH, HEIGHT);

  canvasCtx.lineWidth = 2;
  canvasCtx.strokeStyle = 'rgb(0, 0, 0)';

  const sliceWidth = WIDTH \* 1.0 / bufferLength;
  let x = 0;

  canvasCtx.beginPath();
  for(var i = 0; i < bufferLength; i++) {
    const v = dataArray[i]/128.0;
    const y = v \* HEIGHT/2;

    if(i === 0)
      canvasCtx.moveTo(x, y);
    else
      canvasCtx.lineTo(x, y);

    x += sliceWidth;
  }

  canvasCtx.lineTo(WIDTH, HEIGHT/2);
  canvasCtx.stroke();
};

draw();
```

명세
--

| Specification |
| --- |
| Web Audio API # dom-analysernode-getbytetimedomaindata |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

같이 보기
-----

* Web Audio API 사용하기


AnalyserNode.smoothingTimeConstant - Web API

AnalyserNode.smoothingTimeConstant
==================================

`AnalyserNode` 인터페이스의 **`smoothingTimeConstant`** 속성은 마지막 분석 프레임의 에버리징(averaging) 상수를 나타내는 double 값입니다. 이것은 기본적으로 현재 버퍼와 `AnalyserNode`가 처리한 마지막 버퍼 사이의 평균이고, 더욱 매끄러운 시간에 대한 값 변화의 집합을 결과로 낳습니다.

구문
--

```js
var smoothValue = analyserNode.smoothingTimeConstant;
analyserNode.smoothingTimeConstant = newValue;
```

### 값

`0`에서 `1`까지의 범위 내의 double (`0`은 시간 에버리징이 없음을 의미). 기본값은 `0.8`입니다.

만약 0이 설정된다면, 완료된 에버리징이 없는 것이지만, 1의 값은 "값을 계산하는 동안 이전과 현재 버퍼를 많이 겹치기"를 의미하는데, 이는 근본적으로 `AnalyserNode.getFloatFrequencyData`/`AnalyserNode.getByteFrequencyData` 호출에 걸쳐 변화들을 매끄럽게 합니다.

기술적인 측면에서, 우리는 Blackman window를 적용했고 값들을 시간에 대해 매끄럽게 합니다. 기본값은 대부분의 경우에 적합합니다.

**참고:** 만약 범위 0-1 바깥의 값이 설정된다면, `INDEX_SIZE_ERR` 예외가 발생합니다.

예제
--

다음의 예제는 `AnalyserNode`를 생성하기 위한 `AudioContext`와 그리고 나서 반복적으로 주파수 데이터를 수집하고 현재 오디오 입력의 "winamp 막대그래프 스타일의" 출력을 그리기 위한 `requestAnimationFrame`과 `<canvas>`의 기본 사용을 보여줍니다. 더 완벽한 응용 예제/정보를 보려면 Voice-change-O-matic 데모를 확인하세요 (관련된 코드를 보려면 app.js 라인 128–205를 참고하세요).

만약 여러분이 `smoothingTimeConstant()`이 가진 영향에 대해 궁금하다면, 위의 예제를 복사해서 `analyser.smoothingTimeConstant = 0;`을 대신 설정해 보세요. 값 변화가 더욱 삐걱거리는 것을 인지하실 것입니다.

```js
var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
var analyser = audioCtx.createAnalyser();
analyser.minDecibels = -90;
analyser.maxDecibels = -10;
analyser.smoothingTimeConstant = 0.85;

  ...

analyser.fftSize = 256;
var bufferLength = analyser.frequencyBinCount;
console.log(bufferLength);
var dataArray = new Uint8Array(bufferLength);

canvasCtx.clearRect(0, 0, WIDTH, HEIGHT);

function draw() {
  drawVisual = requestAnimationFrame(draw);

  analyser.getByteFrequencyData(dataArray);

  canvasCtx.fillStyle = 'rgb(0, 0, 0)';
  canvasCtx.fillRect(0, 0, WIDTH, HEIGHT);

  var barWidth = (WIDTH / bufferLength) \* 2.5;
  var barHeight;
  var x = 0;

  for(var i = 0; i < bufferLength; i++) {
    barHeight = dataArray[i];

    canvasCtx.fillStyle = 'rgb(' + (barHeight+100) + ',50,50)';
    canvasCtx.fillRect(x,HEIGHT-barHeight/2,barWidth,barHeight/2);

    x += barWidth + 1;
  }
};

draw();
```

명세
--

| Specification |
| --- |
| Web Audio API # dom-analysernode-smoothingtimeconstant |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

같이 보기
-----

* Web Audio API 사용하기


AnalyserNode.maxDecibels - Web API

AnalyserNode.maxDecibels
========================

`AnalyserNode` 인터페이스의 **`maxDecibels`** 속성은 unsigned byte 값으로의 전환에 대해서, FFT 분석 데이터의 스케일링 범위에서의 최대 power 값을 나타내는 double 값입니다 — 기본적으로, 이것은 `getByteFrequencyData()`를 사용할 때 결과의 범위에 대한 최대 값을 명시합니다.

구문
--

```js
var curValue = analyserNode.maxDecibels;
analyserNode.maxDecibels = newValue;
```

### 값

FFT 분석 데이터를 스케일링하는 것에 대한 최대 데시벨 값을 나타내는 double인데, `0` dB는 가능한 가장 큰 소리를 나타내고, `-10` dB는 그것의 10번째, 등등입니다. 기본 값은 `-30` dB입니다.

`getByteFrequencyData()`로부터 데이터를 얻을 때, `maxDecibels` 또는 더 높은 진폭을 가진 모든 주파수는 `255`로 반환됩니다.

**참고:** 만약 `AnalyserNode.minDecibels`보다 더 작거나 같은 값이 설정된다면, `IndexSizeError` 예외가 발생합니다.

예제
--

다음의 예제는 `AnalyserNode`를 생성하기 위한 `AudioContext`와 그리고 나서 반복적으로 주파수 데이터를 수집하고 현재 오디오 입력의 "winamp 막대그래프 스타일의" 출력을 그리기 위한 `requestAnimationFrame`과 `<canvas>`의 기본 사용을 보여줍니다. 더 완벽한 응용 예제/정보를 보려면 Voice-change-O-matic 데모를 확인하세요 (관련된 코드를 보려면 app.js 라인 128–205를 참고하세요).

```js
var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
var analyser = audioCtx.createAnalyser();
analyser.minDecibels = -90;
analyser.maxDecibels = -10;

  ...

analyser.fftSize = 256;
var bufferLength = analyser.frequencyBinCount;
console.log(bufferLength);
var dataArray = new Uint8Array(bufferLength);

canvasCtx.clearRect(0, 0, WIDTH, HEIGHT);

function draw() {
  drawVisual = requestAnimationFrame(draw);

  analyser.getByteFrequencyData(dataArray);

  canvasCtx.fillStyle = 'rgb(0, 0, 0)';
  canvasCtx.fillRect(0, 0, WIDTH, HEIGHT);

  var barWidth = (WIDTH / bufferLength) \* 2.5;
  var barHeight;
  var x = 0;

  for(var i = 0; i < bufferLength; i++) {
    barHeight = dataArray[i];

    canvasCtx.fillStyle = 'rgb(' + (barHeight+100) + ',50,50)';
    canvasCtx.fillRect(x,HEIGHT-barHeight/2,barWidth,barHeight/2);

    x += barWidth + 1;
  }
};

draw();
```

명세
--

| Specification |
| --- |
| Web Audio API # dom-analysernode-maxdecibels |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

같이 보기
-----

* Web Audio API 사용하기


AnalyserNode: getFloatFrequencyData() 메서드 - Web API

AnalyserNode: getFloatFrequencyData() 메서드
=========================================

`AnalyserNode` 인터페이스의 **`getFloatFrequencyData()`** 메서드는 전달된 `Float32Array` (en-US) 배열 내로 현재 주파수 데이터를 복사합니다. 이 배열은 샘플, 즉 어느 한 시점에 신호의 강도입니다.

배열 내의 각 원소는 특정한 주파수에 대한 데시벨 값을 나타냅니다. 주파수들은 0에서 샘플 레이트의 1/2까지 선형적으로 퍼져 있습니다. 예를 들자면, `48000` Hz 샘플 레이트에 대해서, 배열의 마지막 원소는 `24000` Hz에 대한 데시벨 값을 나타냅니다.

정밀성이 떨어지더라도 성능이 더 중요하다면 `AnalyserNode.getByteFrequencyData()`를 사용하세요. `Uint8Array` (en-US)에서 동작합니다.

구문
--

```js
getFloatFrequencyData(array)
```

### 매개변수

`array`

주파수 영역 데이터가 복사될 `Float32Array` (en-US). 소리가 없는 모든 샘플의 값은 `-Infinity`입니다. 배열의 요소 수가 `AnalyserNode.frequencyBinCount`보다 더 적으면, 초과한 요소들은 탈락됩니다. 반대로, 배열의 요소 수가 더 크면, 초과한 요소들은 무시됩니다.

### 반환 값

없음 (`undefined`).

예제
--

```js
const audioCtx = new AudioContext();
const analyser = audioCtx.createAnalyser();
// Float32Array의 길이가 frequencyBinCount와 같아야 함
const myDataArray = new Float32Array(analyser.frequencyBinCount);
// getFloatFrequencyData()가 반환한 데이터로 Float32Array 채우기
analyser.getFloatFrequencyData(myDataArray);
```

### 스펙트럼 그리기

다음의 예제는 `AudioContext`를 사용해서 `MediaElementAudioSourceNode` (en-US)를 `AnalyserNode`에 연결하는 기본 방법을 보입니다. 오디오가 재생되는 동안, 예제에서는 `requestAnimationFrame()`으로 주파수 데이터를 반복해 수집하고, "Winamp 막대그래프 스타일"을 `<canvas>` 요소에 그립니다.

보다 완전한 응용 예제/정보를 보려면 Voice-change-O-matic 데모를 확인하세요. (app.js의 108-193번째 줄에서 관련 코드 확인)

```html
<!doctype html>
<body>
  <script>
 const audioCtx = new AudioContext();

 //오디오 소스 생성
 //여기서는 오디오 파일을 사용하지만, 마이크 입력같은 것도 가능
 const audioEle = new Audio();
 audioEle.src = "my-audio.mp3"; //여기에 파일명 입력
 audioEle.autoplay = true;
 audioEle.preload = "auto";
 const audioSourceNode = audioCtx.createMediaElementSource(audioEle);

 //분석 노드 생성
 const analyserNode = audioCtx.createAnalyser();
 analyserNode.fftSize = 256;
 const bufferLength = analyserNode.frequencyBinCount;
 const dataArray = new Float32Array(bufferLength);

 //오디오 노드 네트워크 설정
 audioSourceNode.connect(analyserNode);
 analyserNode.connect(audioCtx.destination);

 //2D 캔버스 생성
 const canvas = document.createElement("canvas");
 canvas.style.position = "absolute";
 canvas.style.top = "0";
 canvas.style.left = "0";
 canvas.width = window.innerWidth;
 canvas.height = window.innerHeight;
 document.body.appendChild(canvas);
 const canvasCtx = canvas.getContext("2d");
 canvasCtx.clearRect(0, 0, canvas.width, canvas.height);

 function draw() {
 //다음 그리기 예약
 requestAnimationFrame(draw);

 //스펙트럼 데이터 가져오기
 analyserNode.getFloatFrequencyData(dataArray);

 //검은색 배경 그리기
 canvasCtx.fillStyle = "rgb(0, 0, 0)";
 canvasCtx.fillRect(0, 0, canvas.width, canvas.height);

 //스펙트럼 그리기
 const barWidth = (canvas.width / bufferLength) \* 2.5;
 let posX = 0;
 for (let i = 0; i < bufferLength; i++) {
 const barHeight = (dataArray[i] + 140) \* 2;
 canvasCtx.fillStyle =
 "rgb(" + Math.floor(barHeight + 100) + ", 50, 50)";
 canvasCtx.fillRect(
 posX,
 canvas.height - barHeight / 2,
 barWidth,
 barHeight / 2,
 );
 posX += barWidth + 1;
 }
 }

 draw();
 </script>
</body>
```

명세서
---

| Specification |
| --- |
| Web Audio API # dom-analysernode-getfloatfrequencydata |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

같이 보기
-----

* Web Audio API 사용하기


AnalyserNode.fftSize - Web API

AnalyserNode.fftSize
====================

`AnalyserNode` 인터페이스의 **`fftSize`** 속성은 unsigned long 값이고 주파수 영역 데이터를 얻기 위해 고속 푸리에 변환(FFT)을 수행할 때 사용될 샘플에서의 window 사이즈를 나타냅니다.

구문
--

```js
var curValue = analyserNode.fftSize;
analyserNode.fftSize = newValue;
```

### 값

FFT의 window 사이즈를 나타내는 샘플의 수로 주어지는 unsigned 정수입니다. 값이 높을수록 주파수 영역의 자세함이 커지는 결과를 낳으나 시간 영역에서의 자세함은 떨어집니다.

반드시

2
5

2^5

와

2
15

2^15

 사이의 2의 제곱이여야만 합니다. 즉 다음 중 하나여야 합니다: `32`, `64`, `128`, `256`, `512`, `1024`, `2048`, `4096`, `8192`, `16384`, 그리고 `32768`. 기본값은 `2048`입니다.

**참고:** 만약 값이 2의 제곱이 아니거나 이 명시된 범위의 바깥에 있다면, `IndexSizeError`라는 이름의 `DOMException` (en-US)이 발생합니다.

예제
--

다음의 예제는 `AnalyserNode`를 생성하기 위한 `AudioContext`와 그리고 나서 반복적으로 시간 영역의 데이터를 수집하고 현재 오디오 입력의 "오실로스코프 스타일의" 출력을 그리기 위한 `requestAnimationFrame`과 `<canvas>`의 기본 사용을 보여줍니다. 더 완벽한 응용 예제/정보를 보려면 Voice-change-O-matic 데모를 확인하세요 (관련된 코드를 보려면 app.js 라인 128–205를 참고하세요).

```js
var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
var analyser = audioCtx.createAnalyser();

  ...

analyser.fftSize = 2048;
var bufferLength = analyser.frequencyBinCount ;
var dataArray = new Uint8Array(bufferLength);
analyser.getByteTimeDomainData(dataArray);

// 현재 오디오 소스의 오실로스코프를 그립니다

function draw() {

      drawVisual = requestAnimationFrame(draw);

      analyser.getByteTimeDomainData(dataArray);

      canvasCtx.fillStyle = 'rgb(200, 200, 200)';
      canvasCtx.fillRect(0, 0, WIDTH, HEIGHT);

      canvasCtx.lineWidth = 2;
      canvasCtx.strokeStyle = 'rgb(0, 0, 0)';

      canvasCtx.beginPath();

      var sliceWidth = WIDTH \* 1.0 / bufferLength;
      var x = 0;

      for(var i = 0; i < bufferLength; i++) {

        var v = dataArray[i] / 128.0;
        var y = v \* HEIGHT/2;

        if(i === 0) {
          canvasCtx.moveTo(x, y);
        } else {
          canvasCtx.lineTo(x, y);
        }

        x += sliceWidth;
      }

      canvasCtx.lineTo(canvas.width, canvas.height/2);
      canvasCtx.stroke();
    };

    draw();
```

명세
--

| Specification |
| --- |
| Web Audio API # dom-analysernode-fftsize |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

같이 보기
-----

* Web Audio API 사용하기


AnalyserNode.getFloatTimeDomainData() - Web API

AnalyserNode.getFloatTimeDomainData()
=====================================

`AnalyserNode` 인터페이스의 **`getFloatTimeDomainData()`** 메서드는 전달된 `Float32Array` (en-US) 배열 내로 현재 파형, 즉 시간 영역 데이터를 복사합니다.

구문
--

```js
var audioCtx = new AudioContext();
var analyser = audioCtx.createAnalyser();
var dataArray = new Float32Array(analyser.fftSize); // Float32Array는 fftSize와 같은 길이일 필요가 있습니다
analyser.getFloatTimeDomainData(dataArray); // getFloatTimeDomainData()로부터 반환된 데이터로 Float32Array를 채웁니다
```

### 매개변수

`array`

 시간 영역 데이터가 복사될 `Float32Array` (en-US).
 만약 배열이 `AnalyserNode.frequencyBinCount`보다 더 적은 요소를 가지고 있다면, 초과한 요소는 탈락됩니다. 만약 이것이 필요한 것보다 더 많은 요소를 가지고 있다면, 초과한 요소는 무시됩니다.

### 반환 값

없음.

예제
--

다음의 예제는 `AnalyserNode`를 생성하기 위한 `AudioContext`와 그리고 나서 반복적으로 시간 영역 데이터를 수집하고 현재 오디오 입력의 "오실로스코프 스타일의" 출력을 그리기 위한 `requestAnimationFrame`과 `<canvas>`의 기본 사용을 보여줍니다. 더 완벽한 응용 예제/정보를 보려면 Voice-change-O-matic-float-data 데모를 확인하세요 (소스 코드도 보세요).

```js
var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
var analyser = audioCtx.createAnalyser();

  ...

analyser.fftSize = 1024;
var bufferLength = analyser.fftSize;
console.log(bufferLength);
var dataArray = new Float32Array(bufferLength);

canvasCtx.clearRect(0, 0, WIDTH, HEIGHT);

function draw() {
  drawVisual = requestAnimationFrame(draw);
  analyser.getFloatTimeDomainData(dataArray);

  canvasCtx.fillStyle = 'rgb(200, 200, 200)';
  canvasCtx.fillRect(0, 0, WIDTH, HEIGHT);
  canvasCtx.lineWidth = 2;
  canvasCtx.strokeStyle = 'rgb(0, 0, 0)';
  canvasCtx.beginPath();

  var sliceWidth = WIDTH \* 1.0 / bufferLength;
  var x = 0;

  for(var i = 0; i < bufferLength; i++) {
    var v = dataArray[i] \* 200.0;
    var y = HEIGHT/2 + v;

    if(i === 0) {
      canvasCtx.moveTo(x, y);
    } else {
      canvasCtx.lineTo(x, y);
    }
    x += sliceWidth;
  }

  canvasCtx.lineTo(canvas.width, canvas.height/2);
  canvasCtx.stroke();
};

draw();
```

명세
--

| Specification |
| --- |
| Web Audio API # dom-analysernode-getfloattimedomaindata |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

같이 보기
-----

* Web Audio API 사용하기


AnalyserNode() - Web API

AnalyserNode()
==============

Web Audio API의 **`AnalyserNode()`** 생성자는 새로운 `AnalyserNode` 객체 인스턴스를 생성합니다.

구문
--

```js
var analyserNode = new AnalyserNode(context, ?options);
```

### 매개변수

*`AudioNodeOptions` (en-US) dictionary로부터 매개변수를 상속받습니다.*

*context*

`AudioContext` 또는 `OfflineAudioContext`에의 참조.

*options* Optional

 \* **`fftSize`**: 주파수 영역 분석에 대한 FFT의 원하는 초기 사이즈.
 기본값은 `2048`입니다.

* **`maxDecibels`**: FFT 분석에 대한 dB단위로의 원하는 초기 최대 power.
 기본값은 `-30`입니다.
* **`minDecibels`**: FFT 분석에 대한 dB단위로의 원하는 초기 최소 power.
 기본값은 `-100`입니다.
* **`smoothingTimeConstant`**: FFT 분석에 대한 원하는 초기 smoothing 상수. 기본값은 `0.8`입니다.

### 반환 값

새로운 `AnalyserNode` 객체 인스턴스.

명세
--

| Specification |
| --- |
| Web Audio API # dom-analysernode-analysernode |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

같이 보기
-----

* `BaseAudioContext.createAnalyser()` (en-US), 동등한 팩토리 메서드


AnalyserNode.frequencyBinCount - Web API

AnalyserNode.frequencyBinCount
==============================

`AnalyserNode` 인터페이스의 **`frequencyBinCount`** 읽기 전용 속성은 `AnalyserNode.fftSize` 값의 절반인 unsigned 정수입니다. 이것은 일반적으로 시각화를 위해 사용할 데이터 값의 수와 동일시됩니다.

구문
--

```js
var arrayLength = analyserNode.frequencyBinCount;
```

### 값

`AnalyserNode.getByteFrequencyData()`와 `AnalyserNode.getFloatFrequencyData()`가 제공된 `TypedArray`내로 복사하는 값의 수와 동일한 unsigned 정수.

고속 푸리에 변환이 정의된 방법에 관계된 기술적인 이유로, 이것은 언제나 `AnalyserNode.fftSize` 값의 절반입니다. 그러므로, 이것은 다음 중 하나입니다: `16`, `32`, `64`, `128`, `256`, `512`, `1024`, `2048`, `4096`, `8192`, 그리고 `16384`.

예제
--

다음의 예제는 `AnalyserNode`를 생성하기 위한 `AudioContext`와 그리고 나서 반복적으로 주파수 데이터를 수집하고 현재 오디오 입력의 "winamp 막대그래프 스타일의" 출력을 그리기 위한 `requestAnimationFrame`과 `<canvas>`의 기본 사용을 보여줍니다. 더 완벽한 응용 예제/정보를 보려면 Voice-change-O-matic 데모를 확인하세요 (관련된 코드를 보려면 app.js 라인 128–205를 참고하세요).

```js
var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
var analyser = audioCtx.createAnalyser();
analyser.minDecibels = -90;
analyser.maxDecibels = -10;

  ...

analyser.fftSize = 256;
var bufferLength = analyser.frequencyBinCount;
console.log(bufferLength);
var dataArray = new Uint8Array(bufferLength);

canvasCtx.clearRect(0, 0, WIDTH, HEIGHT);

function draw() {
  drawVisual = requestAnimationFrame(draw);

  analyser.getByteFrequencyData(dataArray);

  canvasCtx.fillStyle = 'rgb(0, 0, 0)';
  canvasCtx.fillRect(0, 0, WIDTH, HEIGHT);

  var barWidth = (WIDTH / bufferLength) \* 2.5 - 1;
  var barHeight;
  var x = 0;

  for(var i = 0; i < bufferLength; i++) {
    barHeight = dataArray[i];

    canvasCtx.fillStyle = 'rgb(' + (barHeight+100) + ',50,50)';
    canvasCtx.fillRect(x,HEIGHT-barHeight/2,barWidth,barHeight/2);

    x += barWidth;
  }
};

draw();
```

명세
--

| Specification |
| --- |
| Web Audio API # dom-analysernode-frequencybincount |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

같이 보기
-----

* Web Audio API 사용하기


AnalyserNode.minDecibels - Web API

AnalyserNode.minDecibels
========================

`AnalyserNode` 인터페이스의 **`minDecibels`** 속성은 unsigned byte 값으로의 전환에 대해서, FFT 분석 데이터의 스케일링 범위에서의 최소 power 값을 나타내는 double 값입니다 — 기본적으로, 이것은 `getByteFrequencyData()`를 사용할 때 결과의 범위에 대한 최소 값을 명시합니다.

구문
--

```js
var curValue = analyserNode.minDecibels;
analyserNode.minDecibels = newValue;
```

### 값

FFT 분석 데이터를 스케일링하는 것에 대한 최소 데시벨 값을 나타내는 double인데, `0` dB는 가능한 가장 큰 소리를 나타내고, `-10` dB는 그것의 10번째, 등등입니다. 기본 값은 `-100` dB입니다.

`getByteFrequencyData()`로부터 데이터를 얻을 때, `minDecibels` 또는 더 낮은 진폭을 가진 모든 주파수는 `0`으로 반환됩니다.

**참고:** 만약 `AnalyserNode.maxDecibels`보다 더 큰 값이 설정된다면, `INDEX_SIZE_ERR` 예외가 발생합니다.

예제
--

다음의 예제는 `AnalyserNode`를 생성하기 위한 `AudioContext`와 그리고 나서 반복적으로 주파수 데이터를 수집하고 현재 오디오 입력의 "winamp 막대그래프 스타일의" 출력을 그리기 위한 `requestAnimationFrame`과 `<canvas>`의 기본 사용을 보여줍니다. 더 완벽한 응용 예제/정보를 보려면 Voice-change-O-matic 데모를 확인하세요 (관련된 코드를 보려면 app.js 라인 128–205를 참고하세요).

```js
var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
var analyser = audioCtx.createAnalyser();
analyser.minDecibels = -90;
analyser.maxDecibels = -10;

  ...

analyser.fftSize = 256;
var bufferLength = analyser.frequencyBinCount;
console.log(bufferLength);
var dataArray = new Uint8Array(bufferLength);

canvasCtx.clearRect(0, 0, WIDTH, HEIGHT);

function draw() {
  drawVisual = requestAnimationFrame(draw);

  analyser.getByteFrequencyData(dataArray);

  canvasCtx.fillStyle = 'rgb(0, 0, 0)';
  canvasCtx.fillRect(0, 0, WIDTH, HEIGHT);

  var barWidth = (WIDTH / bufferLength) \* 2.5;
  var barHeight;
  var x = 0;

  for(var i = 0; i < bufferLength; i++) {
    barHeight = dataArray[i];

    canvasCtx.fillStyle = 'rgb(' + (barHeight+100) + ',50,50)';
    canvasCtx.fillRect(x,HEIGHT-barHeight/2,barWidth,barHeight/2);

    x += barWidth + 1;
  }
};

draw();
```

명세
--

| Specification |
| --- |
| Web Audio API # dom-analysernode-mindecibels |

브라우저 호환성
--------

BCD tables only load in the browser with JavaScript enabled. Enable JavaScript to view data.

같이 보기
-----

* Web Audio API 사용하기


WebGL tutorial - Web API

WebGL tutorial
==============

WebGL 은 WebGL을 지원하는 브라우져에서 plugin을 사용하지 않고도, 웹 콘텐츠가 OpenGL ES 2.0 기반의 API를 이용하여 HTML `<canvas>`에서 3D 랜더링을 할 수 있도록 해 줍니다. WebGL 프로그램은 JavaScripts로 작성 된 제어 코드와 컴퓨터의 Graphics Processing Unit (GPU)에서 실행되는 특수한 효과를 내는 코드(Shader code)로 구성 됩니다. WebGL 요소들은 다른 HTML요소들과 섞어서 함께 사용 할 수 있으며 페이지의 다른 부분이나 페이지 배경과 함께 사용 할 수 있습니다.

이 튜토리얼은 WebGL 그래픽을 그리기 위해 <canvas>요소를 어떻게 사용하는지에 관해 기본부터 기술합니다. 제공된 예제들은 여러분이 WebGL로 무엇을 할 수 있는지를 명확히하고, 여러분 소유의 콘텐츠를 제작할 수 있도록 작은 코드들을 제공 할 것입니다.

시작하기 전에
-------

`<canvas>` 요소를 사용하는 것은 크게 어렵진 않지만, 여러분은 HTML 과 JavaScript에 대하여 기본적인 이해가 꼭 필요합니다. `<canvas>` 요소와 WebGL은 일부 오래된 브라우저에서 지원되지 않으나, 최근 버전의 모든 주요 브라우저에서 지원됩니다. 우리는 canvas에 그림을 그리기 위해 그림을 신속하게 생성하는 JavaScript 콘텍스트 객체를 사용합니다.

In this tutorial
----------------

Getting started with WebGL

How to set up a WebGL context.

Adding 2D content to a WebGL context

How to render simple flat shapes using WebGL.

Using shaders to apply color in WebGL

Demonstrates how to add color to shapes using shaders.

Animating objects with WebGL

Shows how to rotate and translate objects to create simple animations.

Creating 3D objects using WebGL

Shows how to create and animate a 3D object (in this case, a cube).

Using textures in WebGL

Demonstrates how to map textures onto the faces of an object.

Lighting in WebGL

How to simulate lighting effects in your WebGL context.

Animating textures in WebGL

Shows how to animate textures; in this case, by mapping an Ogg video onto the faces of a rotating cube.


WebGL 컨텍스트에 2D 컨텐츠 추가하기 - Web API

WebGL 컨텍스트에 2D 컨텐츠 추가하기
=======================

* « 이전
* 다음 »

일단 성공적으로 WebGL컨텍스트를 생성하면 그 안에 렌더링을 시작할 수 있습니다. 가장 간단히 해볼 수 있는 것은 텍스쳐가 없는 2D 객체를 렌더링 하는 것입니다. 한번 사각형을 그리는 코드를 작성하는 것으로 시작해봅시다.

장면(scene)에 조명효과 추가하기
--------------------

시작 하기전에 반드시 이해해야할 것은 예제에서 오직 2차원 객체만 랜더링을 하더라도 3D 공간에서 그리고 있다는 것 입니다. 이처럼 여전히 객체가 그려질 간단한 장면에 조명 쉐이더를 설정하는것이 필요합니다. 여기서 어떻게 사각형에 조명효과를 줄 수 있는지 확인해보겠습니다.

### 쉐이더 초기화

쉐이더는OpenGL ES 쉐이딩 언어를 사용하여 지정됩니다. 컨텐츠의 유지보수와 업데이트를 쉽게하기 위해 쉐이더를 '불러오기위한' 코드를 직접 작성하겠습니다. 다시 말하자면 쉐이더를 직접 새로 만드는 것이 아니라 HTML문서에서 쉐이더를 '찾아오는' JavaScript 코드입니다. 이 작업을 처리하는 initShaders()함수의 일반적인 형태를 살펴보겠습니다.

```js
function initShaders() {
  var fragmentShader = getShader(gl, "shader-fs");
  var vertexShader = getShader(gl, "shader-vs");

  // Create the shader program

  shaderProgram = gl.createProgram();
  gl.attachShader(shaderProgram, vertexShader);
  gl.attachShader(shaderProgram, fragmentShader);
  gl.linkProgram(shaderProgram);

  // If creating the shader program failed, alert

  if (!gl.getProgramParameter(shaderProgram, gl.LINK\_STATUS)) {
    alert("Unable to initialize the shader program.");
  }

  gl.useProgram(shaderProgram);

  vertexPositionAttribute = gl.getAttribLocation(
    shaderProgram,
    "aVertexPosition",
  );
  gl.enableVertexAttribArray(vertexPositionAttribute);
}
```

이 방식을 통해 로딩되는 쉐이더는 두가지가 있습니다. 첫번째는 조각 쉐이더(fragment shader)로 "shader-fs"라는 ID를 가진 script 엘리먼트에서 불러옵니다. 두번째는 정점 쉐이더(vertex shader)로 "shader-vs"라는 ID를 가진 script엘리먼트에서 불러옵니다. getShader()함수는 다음 섹션에서 다룰 것입니다. 이 과정은 쉐이더 프로그램을 DOM에서 가저오는 것을 다룹니다.

그 다음 우리는 WebGL 객체의 createProgram()함수를 호출하여 쉐이더 프로그램을 생성 할 것입니다. WebGL 객체에 두개의 쉐이더를 붙인다음 서로 연결할 것입니다. 그 다음 프로그램이 성공적으로 연결되었는지 확인하기 위해 gl 객체의 LINK\_STATUS 매개변수를 체크합니다. 이것이 성공적이라면 새로운 쉐이더 프로그램을 활성화 합니다.

### DOM에서 쉐이더 불러오기

getShader()함수는 DOM에서 지정된 이름을 가진 쉐이더 프로그램을 가져와 컴파일된 쉐이더 프로그램을 호출자에 반환 합니다. 컴파일이나 불러올 수 없는 경우에는 null을 반환 합니다.

```js
function getShader(gl, id) {
  var shaderScript, theSource, currentChild, shader;

  shaderScript = document.getElementById(id);

  if (!shaderScript) {
    return null;
  }

  theSource = "";
  currentChild = shaderScript.firstChild;

  while(currentChild) {
    if (currentChild.nodeType == currentChild.TEXT\_NODE) {
      theSource += currentChild.textContent;
    }

    currentChild = currentChild.nextSibling;
  }
```

특정 ID를 가진 엘리먼트를 찾으면 텍스트 컨텐츠가 `theSource 변수에 저장됩니다.`

```js
if (shaderScript.type == "x-shader/x-fragment") {
  shader = gl.createShader(gl.FRAGMENT\_SHADER);
} else if (shaderScript.type == "x-shader/x-vertex") {
  shader = gl.createShader(gl.VERTEX\_SHADER);
} else {
  // Unknown shader type
  return null;
}
```

쉐이더를 위한 코드가 읽혀지면 쉐이더가 정점 쉐이더(MIME type "x-shader/x-vertex")인지 조각 쉐이더(MIME type "x-shader/x-fragment")인지 결정하기 위해 쉐이더 객체의 MIME 형식을 살펴봅니다. 그 다음 소스 코드에서 얻어진 것을 가지고 적절한 타입의 쉐이더를 생성합니다.

```js
  gl.shaderSource(shader, theSource);

  // Compile the shader program
  gl.compileShader(shader);

  // See if it compiled successfully
  if (!gl.getShaderParameter(shader, gl.COMPILE\_STATUS)) {
      alert("An error occurred compiling the shaders: " + gl.getShaderInfoLog(shader));
      return null;
  }

  return shader;
}
```

마지막으로 소스는 쉐이더로 전달되고 컴파일됩니다. 만약 쉐이더가 컴파일하는 동안 에러가 발생하면 경고 메세지를 출력하고 null을 반환합니다. 그러지 않으면 새롭게 컴파일된 쉐이더가 호출자로 반환됩니다.

### 쉐이더

그 다음 쉐이더 프로그램을 HTML 표현에 추가해야 합니다. 쉐이더가 구체적으로 어떻게 작동하는지에 대한 내용은 이 문서에서 다루지 않습니다. 다음은 쉐이더 언어 문법입니다.

#### 조각 쉐이더(Fragment shader)

다각형 안에 있는 각각의 픽셀은 GL 전문용어로 **fragment**이라고 부릅니다. fragment shader가 하는 일은 각 픽셀의 색상을 설정하는 것입니다. 우리는 간단하게 각 픽셀을 하얀색으로 지정하겠습니다.

fragment의 색상에서 사용되는 gl\_FragColor는 GL에서 만들어진 변수입니다. 아래와 같이 값을 설정하면 픽셀의 색상이 설정됩니다.

```html
<script id="shader-fs" type="x-shader/x-fragment">

 void main(void) {

 gl\_FragColor = vec4(1.0, 1.0, 1.0, 1.0);

 }
</script>
```

#### 정점 쉐이더(Vertex Shader)

정점 쉐이더는 각 정점의 위치과 모양을 정의합니다.

```html
<script id="shader-vs" type="x-shader/x-vertex">
 attribute vec3 aVertexPosition;

 uniform mat4 uMVMatrix;
 uniform mat4 uPMatrix;

 void main(void) {
 gl\_Position = uPMatrix \* uMVMatrix \* vec4(aVertexPosition, 1.0);
 }
</script>
```

객체 생성
-----

사각형 렌더링을 하기 전에 사각형의 각 정점들을 저장할 버퍼를 만들어야 합니다. 이를 **initBuffers()** 라는 함수를 이용해 해보도록 하겠습니다. 앞으로 고급 WebGL 개념을 살펴보면서, 더욱 다양하고 복잡한 3D 오브젝트를 생성하고자 할 때 이 루틴을 많이 사용하게 될 것입니다.

```js
var horizAspect = 480.0 / 640.0;

function initBuffers() {
  squareVerticesBuffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY\_BUFFER, squareVerticesBuffer);

  var vertices = [
    1.0, 1.0, 0.0, -1.0, 1.0, 0.0, 1.0, -1.0, 0.0, -1.0, -1.0, 0.0,
  ];

  gl.bufferData(gl.ARRAY\_BUFFER, new Float32Array(vertices), gl.STATIC\_DRAW);
}
```

이 예제에서는 장면(scene)의 기본적인 속성만을 보여주기 위해, 루틴이 다소 지나치게 단순화되어있습니다. 정점들을 저장할 버퍼를 얻기 위해 `gl` 객체의 createBuffer() 메서드를 호출하는 것으로 시작합니다. 그 다음 `bindBuffer()` 메서드를 불러와 컨텍스트에 연결합니다.

이 과정이 끝난 뒤 사각형의 각 정점 좌표를 담고있는 JavaScript 배열을 생성합니다. 그런 다음 배열을 WebGL floats 배열로 변환한 뒤 gl객체의 bufferData() 메서드로 전달해 객체의 정점을 설정합니다.

장면(Scene) 그리기
-------------

쉐이더가 설정되고 객체가 생성되면 실제로 장면을 렌더링 할 수 있습니다. 이 예제에서 어떠한 애니메이팅도 안 할 것이기 떄문에 drawScene()함수는 매우 간단합니다. 이는 우리가 곧 다룰 몇 가지 유용한 루틴만 사용합니다?.

```js
function drawScene() {
  gl.clear(gl.COLOR\_BUFFER\_BIT | gl.DEPTH\_BUFFER\_BIT);

  perspectiveMatrix = makePerspective(45, 640.0 / 480.0, 0.1, 100.0);

  loadIdentity();
  mvTranslate([-0.0, 0.0, -6.0]);

  gl.bindBuffer(gl.ARRAY\_BUFFER, squareVerticesBuffer);
  gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0);
  setMatrixUniforms();
  gl.drawArrays(gl.TRIANGLE\_STRIP, 0, 4);
}
```

첫번째 과정은 배경색에 컨텍스트를 clear하는 것입니다. 그 다음 카메라의 원근을 설정합니다. 시점을 45°로, 종횡비를 640/480(캔버스의 크기)로 설정합니다. 또한 카메라로부터 0.1에서 100단위 사이에 있는 오브젝트만 렌더링하도록 정합니다.

그런 다음 identity(항등) position을 불러오고 카메라에서 6단위 만큼 translate(변환)하여 사각형의 위치를 정합니다 . 그 다음 사각형 정점 버퍼를 컨텍스트에 연결해 구성한 뒤 drawArrays() 메서드를 불러와 객체를 그립니다.

브라우저가 웹GL을 지원한다면 다음 링크에서 확인 할 수 있습니다. try out this demo by clicking here

행렬 유틸리티를 이용한 연산
---------------

행렬 연산은 꽤 복잡합니다. 행렬을 다루기 위한 코드를 직접 작성하고 싶은 사람은 아무도 없을 것입니다. 다행히도 벡터와 행렬 연산을 JavaScript에서 다루는 데 아주 편리한 라이브러리인 Sylvester가 있습니다.

이 데모에서 사용한glUtils.js 파일은 웹에 떠돌아 다니는 많은 WebGL 데모에서 사용하고 있습니다. 이 파일이 어디서 나온 것인지 명확히 아는 사람은 아무도 없는것 같습니다만, HTML 로 출력하기 위한 메소드 뿐만 아니라 특별한 형태의 행렬을 만들기 위한 메소드를 추가되어 있어 Sylvester를 보다 정말 단순화 시켜놓았습니다.

게다가 이 데모는 특정 작업을 위한 라이브러리를 이용할 때 도움될만한 몇가지 루틴을 정의하고 있습니다. 정확히 이것들이 어떤 일을 하는 것인지는 이 데모에서 다룰 범위는 아닙니다. 하지만 온라인에서 참고할만 한 좋은 레퍼런스가 많이 있습니다. 아래 See also 섹션에 그 중 몇 개를 소개하고 있습니다.

```js
function loadIdentity() {
  mvMatrix = Matrix.I(4);
}

function multMatrix(m) {
  mvMatrix = mvMatrix.x(m);
}

function mvTranslate(v) {
  multMatrix(Matrix.Translation($V([v[0], v[1], v[2]])).ensure4x4());
}

function setMatrixUniforms() {
  var pUniform = gl.getUniformLocation(shaderProgram, "uPMatrix");
  gl.uniformMatrix4fv(
    pUniform,
    false,
    new Float32Array(perspectiveMatrix.flatten()),
  );

  var mvUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix");
  gl.uniformMatrix4fv(mvUniform, false, new Float32Array(mvMatrix.flatten()));
}
```

See also
--------

* Matrices on Wolfram MathWorld
* Matrix on Wikipedia
* « 이전
* 다음 »


WebGL로 3D 객체 만들기 - Web API

WebGL로 3D 객체 만들기
================

* « 이전
* 다음 »

이제 우리가 만든 정사각형에 5개의 면을 더해서 3차원 정육면체를 만들어 보겠습니다. 이 작업을 조금 더 효율적으로 하기 위해서 `drawArray()` 메서드를 호출해서 정점을 직접 핸들링하는 대신에, 정점 배열을 인덱스와 값으로 정의된 테이블이라고 생각하고, 각 정점을 인덱스로 참조해서 정육면체 각 면의 정점 위치를 정의하고 `gl.drawElements()`를 호출해서 그려보겠습니다.

고려 사항 : 정육면체의 각 면은 4개의 정점이 필요하고, 정육면체에는 6개의 면이 있으므로 총 24개의 정점이 필요할 것 같지만, 하나의 정점이 세 개의 면에 공통적으로 사용되므로 실제로는 8개의 정점만 있으면 됩니다. 그리고 이 8개의 정점 각각에 인덱스 번호를 매겨서 참조하면 한 개의 정점을 세 개의 면에 재사용할 수 있습니다. 하지만 이번 예제에서는 8개가 아니라 24개의 정점을 사용하는데, 그 이유는 한 꼭지점에서 만나는 세 개의 면마다 다른 색상을 적용할 것이기 때문입니다. 하나의 정점은 한 개의 색상만을 가질 수 있으므로, 세 개의 색상을 표시하려면 세 개의 정점이 필요합니다. 따라서 기하학적으로는 하나의 꼭지점일지라도 세 개의 색상을 표시하기 위해서는 세 개의 정점이 필요 합니다.

정육면체의 정점 위치 정의
--------------

먼저 `initBuffers()` 내부에 있는 코드를 수정해서 정육면체의 정점 버퍼를 만듭니다. 방식은 정사각형을 그릴 때와 거의 비슷하지만, 정점의 수는 하나의 면에 4개 씩, 총 24개로 정사각형보다 더 많습니다:

```js
var vertices = [
  // 앞면(Front face)
  -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0,

  // 뒤면(Back face)
  -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0,

  // 위면(Top face)
  -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0,

  // 아래면(Bottom face)
  -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, -1.0, -1.0, 1.0,

  // 오른쪽면(Right face)
  1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0,

  // 왼쪽면(Left face)
  -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0,
];
```

정점의 색상 정의
---------

24개 정점의 색상 배열도 만들어야 합니다. 각 면의 색상을 하나의 배열로 정의하고, 반복문을 돌면서 모든 정점의 색상 정보를 하나의 배열로 만듭니다.

```js
var colors = [
  [1.0, 1.0, 1.0, 1.0], // 앞면 : 흰색
  [1.0, 0.0, 0.0, 1.0], // 뒤면 : 빨간색
  [0.0, 1.0, 0.0, 1.0], // 위면 : 녹색
  [0.0, 0.0, 1.0, 1.0], // 아래면 : 파란색
  [1.0, 1.0, 0.0, 1.0], // 오른쪽면 : 노란색
  [1.0, 0.0, 1.0, 1.0], // 왼쪽면 : 보라색
];

var generatedColors = [];

for (j = 0; j < 6; j++) {
  var c = colors[j];

  for (var i = 0; i < 4; i++) {
    generatedColors = generatedColors.concat(c);
  }
}

cubeVerticesColorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY\_BUFFER, cubeVerticesColorBuffer);
gl.bufferData(
  gl.ARRAY\_BUFFER,
  new Float32Array(generatedColors),
  gl.STATIC\_DRAW,
);
```

인덱스 배열 정의
---------

정점 배열을 만들었으면 인덱스 배열(원문 : element array)을 만들어야 합니다.

```js
cubeVerticesIndexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT\_ARRAY\_BUFFER, cubeVerticesIndexBuffer);

// 인덱스 배열은 하나의 면을 두 개의 삼각형으로 정의합니다.
// 인덱스 배열의 원소인 각 숫자는 정점 배열에서 한 정점의 위치를 나타냅니다.
// 즉, 아래의 인덱스 배열에서의 0, 1, 2, 0, 2, 3은
// 정점 배열에서 0, 1, 2번째의 정점으로 이루어진 삼각형과
// 0, 2, 3번째 정점으로 이루어진 삼각형 두 개로
// 하나의 면을 나타낸다는 의미입니다.

var cubeVertexIndices = [
  0,
  1,
  2,
  0,
  2,
  3, // front
  4,
  5,
  6,
  4,
  6,
  7, // back
  8,
  9,
  10,
  8,
  10,
  11, // top
  12,
  13,
  14,
  12,
  14,
  15, // bottom
  16,
  17,
  18,
  16,
  18,
  19, // right
  20,
  21,
  22,
  20,
  22,
  23, // left
];

// 인덱스 배열을 GL에 전달

gl.bufferData(
  gl.ELEMENT\_ARRAY\_BUFFER,
  new Uint16Array(cubeVertexIndices),
  gl.STATIC\_DRAW,
);
```

`cubeVertexIndices` 배열은 정육면체 정점 배열의 인덱스값을 원소로 가지며, 각 인덱스 값에 해당하는 정점을 순서대로 세 개씩 묶어서 하나의 삼각형을 구성하고, 삼각형 두 개를 순서대로 묶어서 하나의 면으로 정의합니다. 따라서 6개의 면을 가진 정육면체는 12개의 삼각형의 조합으로 표현할 수 있습니다.

정육면체 그리기
--------

다음 단계로 정육면체의 인덱스 버퍼를 이용해서 정육면체를 그릴 수 있도록 `drawScene()` 함수 내부에 코드를 추가 합니다. 인덱스 버퍼를 사용하기 위한 `bindBuffer()`와 정육면체를 그리기 위한 `drawElements()` 호출문을 추가합니다:

```js
gl.bindBuffer(gl.ELEMENT\_ARRAY\_BUFFER, cubeVerticesIndexBuffer);
setMatrixUniforms();
gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED\_SHORT, 0);
```

정육면체의 각 면이 두 개의 삼각형으로 이루어져 있으므로, 한 면에는 6개의 정점이 있으며, 정육면체 전체로는 총 36개의 정점이 존재합니다. 정점 배열에는 24개의 정점이 있었으므로 36개의 정점을 구성하려면 하나의 정점이 여러번 중복되어 사용 되었을 것 입니다. 비효율적이라고 생각될 수도 있지만, 인덱스 배열은 처리가 단순한 정수형 데이터로만 구성되어 있으므로, 36개의 정수형 배열이 하나의 애니메이션 프레임에서 처리하기에 지나치게 많은 수준의 데이터는 아닙니다.

이제 지금까지 만든 정육면체를 확인 해 보겠습니다. WebGL을 지원하는 브라우저에서는 여기에서 6개의 면이 원색으로 채색된 정육면체를 볼 수 있습니다.

* « 이전
* 다음 »


WebGL에서 조명 효과 적용하기 - Web API

WebGL에서 조명 효과 적용하기
==================

* « 이전
* 다음 »

WebGL은 OpenGL 표준과는 다르게 자체적인 조명 효과를 제공하지 않습니다. 따라서 WebGL에서의 조명 효과는 개발자 스스로 만들어야 합니다. 다행스럽게도 조명 효과를 만드는 것이 아주 어려운 일은 아니며, 이 글을 통해 몇 가지 기초적인 부분을 이해할 수 있을 것입니다.

3D에서의 조명 시뮬레이션과 명암 효과
---------------------

3D 그래픽의 조명 시뮬레이션에 대한 이론적 바탕에 대해 상세하게 알아보는 것은 이 글의 범위를 많이 벗어난다고 할 수 있지만, 그 동작 원리에 대해서는 조금이나마 알아볼 필요가 있습니다. 먼저 가장 널리 사용되는 조명 모델인 퐁 셰이딩(Phong shading)에 대한 위키피디아 자료를 한 번 읽어보시기 바랍니다.

조명에는 세 가지 기본 타입이 있습니다:

**주변광**(**Ambient light**)은 장면(scene) 전반에 걸쳐 스며드는 빛으로, 방향성이 없으며 장면 내에 있는 모든 표면을 그 표면의 방향과 관계없이 동일한 밝기로 비춰줍니다.

**방향광**(**Directional light**)은 특정한 방향으로만 비춰지는 빛입니다. 방향광은 아주 먼 곳에서 비춰지기 때문에 모든 빛 입자(photon, 광자)가 서로 평행한 방향으로 움직입니다. 방향광의 대표적인 예는 바로 태양광입니다.

**점광**(**Point light**)은 한 지점에서 모든 방향으로 퍼지면서 발산하는 빛입니다. 실생활에서 접할 수 있는 대부분의 빛이 이 점광에 해당합니다. 전구에서 나오는 빛이 점광의 대표적인 예라고 할 수 있겠습니다.

이 글에서는 반사광 하이라이트(specular highlight)나 점광원에 대해서는 다루지 않고, 단순한 방향광 조명과 주변광 조명만 알아 보겠습니다. 주변광에 방향광원(directional light source)을 더한 조명 효과를 앞 단원의 예제에 있던 회전하는 정육면체에 적용해보겠습니다.

점광원이나 반사광을 고려하지 않는다면, 방향광 조명을 구현하기 위한 정보는 크게 두 가지가 있습니다:

1. 각 정점의 표면에 수직인 벡터를 의미하는 **표면 법선 벡터(surface normal vector)**.
2. 빛이 쪼여지는 방향을 나타내는 **방향 벡터**.

위 두 가지 정보를 구하고나면, 방향광의 방향과 정육면체의 표면이 만나는 각도에 따라 달라지는 방향광 조명 효과와 모든 표면에 균일하게 적용되는 주변광 조명 효과를 반영해서 각 정점의 색상을 조정할 수 있도록 정점 셰이더를 수정해야 합니다. 셰이더 코드를 어떻게 수정하는지는 조금 이따가 살펴보기로 하고, 먼저 정점의 법선 벡터를 만드는 방법부터 알아보겠습니다.

정점 별 법선 구성
----------

조명 효과 적용을 위해 첫번째로 해야할 일은 정육면체를 이루는 모든 정점의 법선 배열을 구성하는 것입니다. 정육면체는 아주 단순한 객체이므로 정육면체의 법선 배열 역시 쉽게 만들 수 있습니다. 하지만 복잡하게 생긴 객체의 법선을 계산하는 것은 상당히 어렵습니다.

```js
cubeVerticesNormalBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY\_BUFFER, cubeVerticesNormalBuffer);

var vertexNormals = [
  // 앞
  0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0,

  // 뒤
  0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0,

  // 위
  0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0,

  // 아래
  0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0,

  // 오른쪽
  1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0,

  // 왼쪽
  -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0,
];

gl.bufferData(
  gl.ARRAY\_BUFFER,
  new WebGLFloatArray(vertexNormals),
  gl.STATIC\_DRAW,
);
```

이런 배열의 처리는 앞 단원에서 여러 번 다뤄왔으므로 이젠 꽤 친숙해 보일 것입니다. 새로운 버퍼를 생성하고, 버퍼와 법선 배열을 바인딩하고, `bufferData()`를 호출해서 법선 배열을 버퍼에 전달합니다.

그 다음에 법선 배열과 셰이더 attribute 변수에 바인딩해서 셰이더가 법선 배열 정보에 접근할 수 있도록 해주는 코드를 `drawScene()`에 추가합니다:

```js
gl.bindBuffer(gl.ARRAY\_BUFFER, cubeVerticesNormalBuffer);
gl.vertexAttribPointer(vertexNormalAttribute, 3, gl.FLOAT, false, 0, 0);
```

마지막으로 uniform 행렬을 구성하는 `setMatrixUniforms()`에 **법선 행렬**을 만들고 셰이더에게 전달하는 코드를 추가합니다. 법선 행렬은 광원을 기준으로 정육면체의 상대적인 방향에 따라 법선을 변환하는 데 사용됩니다:

```js
var normalMatrix = mvMatrix.inverse();
normalMatrix = normalMatrix.transpose();
var nUniform = gl.getUniformLocation(shaderProgram, "uNormalMatrix");
gl.uniformMatrix4fv(
  nUniform,
  false,
  new WebGLFloatArray(normalMatrix.flatten()),
);
```

셰이더 수정
------

조명 효과 구현을 위해 셰이더가 필요로 하는 데이터가 모두 준비되었으므로, 이제 셰이더 코드를 수정해보겠습니다.

### 정점 셰이더

제일 먼저 방향광 조명과 주변광 조명에 의한 각 정점의 명암 값을 계산해야 합니다. 일단 소스 코드부터 보겠습니다:

```html
<script id="shader-vs" type="x-shader/x-vertex">
 attribute highp vec3 aVertexNormal;
 attribute highp vec3 aVertexPosition;
 attribute highp vec2 aTextureCoord;

 uniform highp mat4 uNormalMatrix;
 uniform highp mat4 uMVMatrix;
 uniform highp mat4 uPMatrix;

 varying highp vec2 vTextureCoord;
 varying highp vec3 vLighting;

 void main(void) {
 gl\_Position = uPMatrix \* uMVMatrix \* vec4(aVertexPosition, 1.0);
 vTextureCoord = aTextureCoord;

 // 조명 효과 적용

 highp vec3 ambientLight = vec3(0.6, 0.6, 0.6);
 highp vec3 directionalLightColor = vec3(0.5, 0.5, 0.75);
 highp vec3 directionalVector = vec3(0.85, 0.8, 0.75);

 highp vec4 transformedNormal = uNormalMatrix \* vec4(aVertexNormal, 1.0);

 highp float directional = max(dot(transformedNormal.xyz, directionalVector), 0.0);
 vLighting = ambientLight + (directionalLightColor \* directional);
 }
</script>
```

정점의 위치 계산이 끝나고, 정점의 텍셀(texel) 좌표값을 얻고나면, 그 값을 기준으로 정점의 명암을 계산할 수 있습니다.

정점의 명암을 계산하려면 먼저 정육면체의 현재 위치와 방향을 기준으로 법선을 변환해야 합니다. 정점의 법선에 법선 행렬을 곱하면 법선이 변환됩니다. 그 다음에 변환된 법선과 방향 벡터(광원으로부터 빛이 비춰지는 방향)를 내적(dot product)하면 정점에 비춰지는 방향광의 양을 계산할 수 있습니다. 빛의 양이 음수일 수는 없으므로, 계산된 방향광의 양이 음수일 때는 방향광의 양을 0으로 설정해줍니다.

방향광의 양을 계산하고 나면, 방향광의 색상과 방향광의 양을 곱한 값에 주변광의 값을 더해서 정점에 비춰지는 최종 빛의 양을 구할 수 있습니다. 결과적으로 RGB값이 나오는데, 이 RGB값은 프래그먼트 셰이더가 우리가 그릴 모든 픽셀에 대한 색상값을 계산하는데 사용됩니다.

### 프래그먼트 셰이더

이제 정점 셰이더에서 계산한 빛의 양을 반영해서 조명 효과를 표현할 수 있도록 프래그먼트 셰이더를 수정해야 합니다:

```js
<script id="shader-fs" type="x-shader/x-fragment">
  varying highp vec2 vTextureCoord;
  varying highp vec3 vLighting;

  uniform sampler2D uSampler;

  void main(void) {
    mediump vec4 texelColor = texture2D(uSampler, vec2(vTextureCoord.s, vTextureCoord.t));

    gl_FragColor = vec4(texelColor.rgb \* vLighting, texelColor.a);
  }
</script>
```

앞 단원의 예제에서 했던 것처럼 텍셀의 색상값을 계산합니다. 하지만 이번에는 텍셀의 색상값을 바로 프래그먼트의 색상값으로 설정하지 않고, 조명 효과를 표현할 수 있도록 텍셀의 색상값에 빛의 양을 곱한 값을 프래그먼트의 색상값으로 설정합니다.

자 이제 다 완성했습니다! WebGL을 지원하는 브라우저라면 여기에서 실제 동작하는 예제를 확인할 수 있습니다.

연습해보기
-----

알다시피 이번 예제는 정점 단위의 기본적인 조명 효과를 구현한 단순한 예제입니다. 더 수준 높은 컴퓨터 그래픽을 만들려면 정점 단위가 아니라 픽셀 단위의 조명 효과가 필요할 것입니다. 하지만 정점 단위의 조명 효과를 다룬 이 글이 고급 그래픽을 만드는데 도움이 될 것입니다.

빛의 방향이나 광원의 색상 등을 다른 값으로 바꿔보는 등 다양하게 실험해보는 것도 조명 효과를 이해하는데 도움이 될 것입니다.

* « 이전
* 다음 »