diff options
author | Florian Merz <me@fiji-flo.de> | 2021-02-11 14:48:24 +0100 |
---|---|---|
committer | Florian Merz <me@fiji-flo.de> | 2021-02-11 14:48:24 +0100 |
commit | ee778d6eea54935fd05022e0ba8c49456003381a (patch) | |
tree | 151a4cef804d8823cc8fc753b8edc693b7078241 /files/ko/web/api | |
parent | 8260a606c143e6b55a467edf017a56bdcd6cba7e (diff) | |
download | translated-content-ee778d6eea54935fd05022e0ba8c49456003381a.tar.gz translated-content-ee778d6eea54935fd05022e0ba8c49456003381a.tar.bz2 translated-content-ee778d6eea54935fd05022e0ba8c49456003381a.zip |
unslug ko: move
Diffstat (limited to 'files/ko/web/api')
61 files changed, 7102 insertions, 34 deletions
diff --git a/files/ko/web/api/ambient_light_events/index.html b/files/ko/web/api/ambient_light_events/index.html new file mode 100644 index 0000000000..b033d4f80d --- /dev/null +++ b/files/ko/web/api/ambient_light_events/index.html @@ -0,0 +1,64 @@ +--- +title: Using Light Events +slug: WebAPI/Using_Light_Events +tags: + - Ambient Light +translation_of: Web/API/Ambient_Light_Events +--- +<div>{{DefaultAPISidebar("Ambient Light Events")}}{{SeeCompatTable}}</div> + +<p>주변의 빛을 감지하는 이벤트를 활용해서 웹페이지나 어플리케이션이 주변 빛의 세기를 감지할 수 있습니다. 사용자 인터페이스의 색상 대비나 사진의 노출을 변경하는 용도로 사용할 수 있습니다.</p> + +<h2 id="빛_이벤트">빛 이벤트</h2> + +<p>기기의 빛 센서가 빛의 변화를 감지하면 브라우저에 변화를 전달합니다. 브라우저가 이러한 알림을 받으면 정확한 빛의 세기를 알려주는 {{domxref("DeviceLightEvent")}} 이벤트를 발생시킵니다.</p> + +<p>이 이벤트는 {{domxref("EventTarget.addEventListener","addEventListener")}} 메서드 ({{event("devicelight")}} 이벤트 이름 사용)를 사용하거나 {{domxref("window.ondevicelight")}} 속성에 이벤트 핸들러를 사용함으로서 <code>window</code> 객체 수준에서 캡춰됩니다.</p> + +<p>캡춰가 되면 이벤트 객체의 {{domxref("DeviceLightEvent.value")}} 속성을 통해서 럭스(lux) 단위의 빛의 세기를 사용할 수 있습니다.</p> + +<h2 id="예제">예제</h2> + +<pre class="brush: js">window.addEventListener('devicelight', function(event) { + var html = document.getElementsByTagName('html')[0]; + + if (event.value < 50) { + html.classList.add('darklight'); + html.classList.remove('brightlight'); + } else { + html.classList.add('brightlight'); + html.classList.remove('darklight'); + } +});</pre> + +<h2 id="Specifications" name="Specifications">명세</h2> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Specification</th> + <th scope="col">Status</th> + <th scope="col">Comment</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{ SpecName('AmbientLight', '', 'Ambient Light Events') }}</td> + <td>{{ Spec2('AmbientLight') }}</td> + <td>Initial specification</td> + </tr> + </tbody> +</table> + +<h2 id="브라우저_호환성">브라우저 호환성</h2> + + + +<p>{{Compat("api.DeviceLightEvent")}}</p> + +<h2 id="같이_보기">같이 보기</h2> + +<ul> + <li>{{domxref("DeviceLightEvent")}}</li> + <li>{{event("devicelight")}}</li> +</ul> diff --git a/files/ko/web/api/battery_status_api/index.html b/files/ko/web/api/battery_status_api/index.html new file mode 100644 index 0000000000..12347b0f20 --- /dev/null +++ b/files/ko/web/api/battery_status_api/index.html @@ -0,0 +1,75 @@ +--- +title: Battery Status API +slug: WebAPI/Battery_Status +tags: + - API + - Apps + - Battery API + - Battery Status API + - Obsolete + - 가이드 + - 개요 + - 모바일 + - 배터리 + - 어플리케이션 +translation_of: Web/API/Battery_Status_API +--- +<div>{{DefaultAPISidebar("Battery API")}}{{Obsolete_Header}}</div> + +<p><strong>Battery API </strong>만큼이나 자주 언급되는 <strong>Battery Status API</strong>는 시스템의 배터리 충전 상태에 대한 정보를 제공하고, 배터리 상태에 따라 발생하는 이벤트를 다룰 수 있도록 해 줍니다. 배터리가 얼마남지 않은 상황에서, 앱에서 배터리의 소모를 줄인다거나 배터리가 방전되기 전에 데이터를 저장하거나 하는 것들이 가능합니다.</p> + +<p>Battery Status API 는 {{domxref("window.navigator.battery")}} 를 제공 합니다. 이는 {{domxref("BatteryManager")}} 객체이며 배터리 상태를 감시하고 전달받아 처리할 수 있는 이벤트를 가지고 있습니다.</p> + +<h2 id="예제">예제</h2> + +<p>아래 예제에서는 배터리가 충전중인 상태 (전원 케이블을 연결하여 충전 중인지) 와 배터리 수준의 변화를 감시합니다. 각각 {{event("chargingchange")}} 와 {{event("levelchange")}} 이벤트가 발생하면 완료 됩니다.</p> + +<pre class="brush: js notranslate">var battery = navigator.battery || navigator.mozBattery || navigator.webkitBattery; + +function updateBatteryStatus() { + console.log("Battery status: " + battery.level * 100 + " %"); + + if (battery.charging) { + console.log("Battery is charging"); + } +} + +battery.addEventListener("chargingchange", updateBatteryStatus); +battery.addEventListener("levelchange", updateBatteryStatus); +updateBatteryStatus(); +</pre> + +<p>명세서의 예제도 <strong><a href="http://dev.w3.org/2009/dap/system-info/battery-status.html#introduction" title="http://dev.w3.org/2009/dap/system-info/battery-status.html#introduction">확인</a></strong>해보세요.</p> + +<h2 id="사양">사양</h2> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Specification</th> + <th scope="col">Status</th> + <th scope="col">Comment</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{SpecName("Battery API")}}</td> + <td>{{Spec2("Battery API")}}</td> + <td>Initial definition.</td> + </tr> + </tbody> +</table> + +<h2 id="브라우저_호환성">브라우저 호환성</h2> + +<div class="hidden">이 페이지의 호환성 표는 구조화된 데이터에서 생성됩니다. 만약 데이터의 기여하고 싶다면, <a href="https://github.com/mdn/browser-compat-data">https://github.com/mdn/browser-compat-data</a>를 확인하고 pull 요청을 우리에게 보내세요.</div> + +<p>{{Compat("api.BatteryManager")}}</p> + +<h2 id="더보기">더보기</h2> + +<ul> + <li><a class="external" href="http://hacks.mozilla.org/2012/02/using-the-battery-api-part-of-webapi/">Hacks blog post - Using the Battery API</a></li> + <li>{{domxref("BatteryManager")}}</li> + <li>{{domxref("window.navigator.battery","navigator.battery")}}</li> +</ul> diff --git a/files/ko/web/api/broadcastchannel/message_event/index.html b/files/ko/web/api/broadcastchannel/message_event/index.html new file mode 100644 index 0000000000..1796b8ee0c --- /dev/null +++ b/files/ko/web/api/broadcastchannel/message_event/index.html @@ -0,0 +1,152 @@ +--- +title: message +slug: Web/Events/message +translation_of: Web/API/BroadcastChannel/message_event +--- +<p>메시지 이벤트는 메시지가 수신되었음을 알리는 메시지, {{domxref("WebSocket")}}, {{domxref("RTCDataConnection")}} 또는 {{domxref("BroadcastChannel")}} 개체를 알려 줍니다.</p> + +<p>대상이 {{domxref("RTCDataConnection")}}, 인 경우 이 이벤트에 대한 이벤트 핸들러를 {{domxref("RTCDataConnection.onmessage")}}속성을 통해 추가할 수 있습니다.</p> + +<p>대상이 {{domxref("BroadcastChannel")}}인 경우, 이 이벤트에 대한 이벤트 핸들러를 {{domxref("BroadcastChannel.onmessage")}} 속성을 통해 추가할 수 있습니다.</p> + +<h2 id="일반_정보">일반 정보</h2> + +<dl> + <dt style="width: 120px; text-align: right; float: left;">인터페이스</dt> +</dl> + +<dl> + <dd style="margin: 0px 0px 0px 120px;">{{domxref("MessageEvent")}}</dd> + <dt style="width: 120px; text-align: right; float: left;">Bubbles</dt> + <dd style="margin: 0px 0px 0px 120px;">No</dd> + <dt style="width: 120px; text-align: right; float: left;">Cancelable</dt> + <dd style="margin: 0px 0px 0px 120px;">No</dd> + <dt style="width: 120px; text-align: right; float: left;">Target</dt> + <dd style="margin: 0px 0px 0px 120px;">{{domxref("RTCDataChannelEvent")}}, {{domxref("WebSocket")}}, {{domxref("BroadcastChannel")}}</dd> + <dt style="width: 120px; text-align: right; float: left;">Default Action</dt> + <dd style="margin: 0px 0px 0px 120px;">None</dd> +</dl> + +<h2 id="특성">특성</h2> + +<p><em>{{domxref("Event")}}</em>가 진행되는 동안 <em> {{domxref("MessageEvent")}} </em>이러한 속성을 구현합니다.</p> + +<dl> + <dt><code>data</code> {{readOnlyInline}}</dt> + <dd>수신된 메시지를 포함하는 {{domxref("DOMString")}} 가 있습니다.</dd> +</dl> + +<h2 id="방법">방법</h2> + +<p><em>{{domxref("Event")}}</em>가 진행되는 동안 <em> {{domxref("MessageEvent")}} </em>이러한 속성을 구현합니다.</p> + +<h2 id="관련_자료">관련 자료</h2> + +<ul> + <li>{{event("open")}}, {{event("close")}}.</li> +</ul> + +<h2 id="사양">사양</h2> + +<table class="standard-table"> + <tbody> + <tr> + <th scope="col">사양</th> + <th scope="col">상황</th> + <th scope="col">Comment</th> + </tr> + <tr> + <td>{{ SpecName('WebRTC 1.0', '#event-datachannel-message', 'message on RTCDataChannel') }}</td> + <td>{{Spec2('WebRTC 1.0')}}</td> + <td>{{domxref("RTCDataChannel")}} 를 {{domxref("EventTarget")}}로 추가하고 이 이벤트가 전송될 시기를 정의합니다.</td> + </tr> + <tr> + <td>{{SpecName('HTML WHATWG', '#', 'message on BroadcastChannel')}}</td> + <td>{{Spec2('HTML WHATWG')}}</td> + <td>{{domxref("RTCDataChannel")}} 를 {{domxref("EventTarget")}}로 추가하고 이 이벤트가 전송될 시기를 정의합니다.</td> + </tr> + </tbody> +</table> + +<h2 id="브라우저_호환성">브라우저 호환성</h2> + +<p>{{ CompatibilityTable() }}</p> + +<div id="compat-desktop"> +<table class="compat-table"> + <tbody> + <tr> + <th>Feature</th> + <th>Chrome</th> + <th>Edge</th> + <th>Firefox (Gecko)</th> + <th>Internet Explorer</th> + <th>Opera</th> + <th>Safari</th> + </tr> + <tr> + <td>Basic support</td> + <td>{{ CompatVersionUnknown() }}</td> + <td>{{CompatVersionUnknown}}</td> + <td>{{ CompatVersionUnknown }}</td> + <td>{{ CompatNo() }}</td> + <td>{{ CompatVersionUnknown() }}</td> + <td>{{ CompatUnknown() }}</td> + </tr> + <tr> + <td>on {{domxref("BroadcastChannel")}} {{experimental_inline}}</td> + <td>{{CompatNo}}</td> + <td>{{CompatNo}}</td> + <td>{{CompatGeckoDesktop(38)}}</td> + <td>{{CompatNo}}</td> + <td>{{CompatNo}}</td> + <td>{{CompatNo}}</td> + </tr> + </tbody> +</table> +</div> + +<div id="compat-mobile"> +<table class="compat-table"> + <tbody> + <tr> + <th>Feature</th> + <th>Android</th> + <th>Chrome for Android</th> + <th>Edge</th> + <th>Firefox Mobile (Gecko)</th> + <th>IE Mobile</th> + <th>Opera Mobile</th> + <th>Safari Mobile</th> + </tr> + <tr> + <td>Basic support</td> + <td>{{ CompatUnknown() }}</td> + <td>{{ CompatUnknown() }}</td> + <td>{{CompatVersionUnknown}}</td> + <td>{{ CompatUnknown() }}</td> + <td>{{ CompatNo() }}</td> + <td>{{ CompatUnknown() }}</td> + <td>{{ CompatUnknown() }}</td> + </tr> + <tr> + <td>on {{domxref("BroadcastChannel")}} {{experimental_inline}}</td> + <td>{{CompatNo}}</td> + <td>{{CompatNo}}</td> + <td>{{CompatNo}}</td> + <td>{{CompatGeckoMobile(38)}}</td> + <td>{{CompatNo}}</td> + <td>{{CompatNo}}</td> + <td>{{CompatNo}}</td> + </tr> + </tbody> +</table> +</div> + +<h2 id="보기">보기</h2> + +<ul> + <li><a href="/en-US/docs/Web/Guide/API/WebRTC" title="/en-US/docs/CSS/Using_CSS_animations">WebRTC</a></li> + <li>BroadcastChannel API</li> + <li>WebSockets</li> +</ul> diff --git a/files/ko/web/api/canvas_api/a_basic_ray-caster/index.html b/files/ko/web/api/canvas_api/a_basic_ray-caster/index.html new file mode 100644 index 0000000000..950b0f5366 --- /dev/null +++ b/files/ko/web/api/canvas_api/a_basic_ray-caster/index.html @@ -0,0 +1,53 @@ +--- +title: A basic ray-caster +slug: A_Basic_RayCaster +tags: + - Advanced + - Canvas + - Example + - Graphics + - HTML + - Web +translation_of: Web/API/Canvas_API/A_basic_ray-caster +--- +<div>{{CanvasSidebar}}</div> + +<p>This article provides an interesting real-world example of using the {{HTMLElement("canvas")}} element to do software rendering of a 3D environment using ray-casting.</p> + +<p>{{EmbedGHLiveSample("canvas-raycaster/index.html", 900, 300)}}</p> + +<p><strong><a href="http://mdn.github.io/canvas-raycaster/">Open in new window</a></strong></p> + +<h2 id="Why.3F" name="Why.3F">Why?</h2> + +<p>After realizing, to my delight, that the nifty <code><canvas></code> element I'd been <a class="external" href="http://www.whatwg.org/specs/web-apps/current-work/#dynamic">reading about</a> was not only soon to be supported in Firefox, but was <strong>already</strong> supported in the current version of Safari, I had to try a little experiment.</p> + +<p>The canvas <a href="/en-US/docs/Web/API/Canvas_API">overview</a> and <a href="https://developer.mozilla.org/en-US/docs/Canvas_tutorial">tutorial</a> I found here at MDN are great, but nobody had written about animation yet, so I thought I'd try a port of a basic raycaster I'd worked on a while ago, and see what sort of performance we can expect from a JavaScript-controlled pixel buffer.</p> + +<h2 id="How.3F" name="How.3F">How?</h2> + +<p>The basic idea is to use {{domxref("window.setInterval","setInterval()")}} at some arbitrary delay that corresponds to a desired frame rate. After every interval an update function will repaint the canvas showing the current view. I know I could have started with a simpler example, but I'm sure the canvas tutorial will <a href="/en-US/docs/Web/API/Canvas_API/Tutorial/Basic_animations">get to that</a>, and I wanted to see if I could do this.</p> + +<p>So every update, the raycaster looks to see if you've pressed any keys lately, to conserve calculations by not casting if you're idle. If you have, then the canvas is cleared, the ground and sky are drawn, the camera position and/or orientation are updated, and the rays are cast out. As the rays intersect walls, then they render a vertical sliver of canvas in the color of the wall they've hit, blended with a darker version of the color according to the distance to the wall. The height of the sliver is also modulated by the distance from the camera to the wall, and is drawn centered over the horizon line.</p> + +<p>The code I ended up with is a regurgitated amalgam of the raycaster chapters from an old André LaMothe<em>Tricks of the Game Programming Gurus</em> book (<small>ISBN: 0672305070</small>), and a <a class="external" href="http://www.shinelife.co.uk/java-maze/">java raycaster</a> I found online, filtered through my compulsion to rename everything so it makes sense to me, and all the tinkering that had to be done to make things work well.</p> + +<h2 id="Results" name="Results">Results</h2> + +<p>The canvas in Safari 2.0.1 performed surprisingly well. With the blockiness factor cranked up to render slivers 8 pixels wide, I can run a 320 x 240 window at 24 fps on my Apple mini. Firefox 1.5 Beta 1 is even faster; I can run 320 x 240 at 24 fps with 4 pixel slivers. Not exactly a new member of the ID software family, but pretty decent considering it's a fully interpreted environment, and I didn't have to worry about memory allocation or video modes or coding inner routines in assembler or anything. The code does attempt to be very efficient, using array look-ups of pre-computed values, but I'm no optimization guru, so things could probably be written faster.</p> + +<p>Also, it leaves a lot to be desired in terms of trying to be any sort of game engine—there are no wall textures, no sprites, no doors, not even any teleporters to get to another level. But I'm pretty confident all those things could be added given enough time. The canvas API supports pixel copying of images, so textures seem feasible. I'll leave that for another article, probably from another person. =)</p> + +<h2 id="The_RayCaster" name="The_RayCaster">The ray-caster</h2> + +<p>The nice people here have manually copied my files up so you can take a <a href="http://mdn.github.io/canvas-raycaster/">look</a>, and for your hacking enjoyment I've posted the individual file contents as code listings (see below).</p> + +<p>So there you are, fire up Safari 1.3+ or Firefox 1.5+ or some other browser that supports the <code><canvas></code> element and enjoy!<br> + <br> + <small><a href="https://github.com/mdn/canvas-raycaster/blob/master/input.js">input.js</a> | <a href="https://github.com/mdn/canvas-raycaster/blob/master/Level.js">Level.js</a> | <a href="https://github.com/mdn/canvas-raycaster/blob/master/Player.js">Player.js</a> | <a href="https://github.com/mdn/canvas-raycaster/blob/master/index.html">RayCaster.html</a> | <a href="https://github.com/mdn/canvas-raycaster/blob/master/RayCaster.js">RayCaster.js</a> | <a href="https://github.com/mdn/canvas-raycaster/blob/master/trace.css">trace.css</a> | <a href="https://github.com/mdn/canvas-raycaster/blob/master/trace.js">trace.js</a> </small></p> + +<h2 id="See_also" name="See_also">See also</h2> + +<ul> + <li><a href="/en-US/docs/Web/API/Canvas_API/Tutorial">Canvas tutorial</a></li> +</ul> diff --git a/files/ko/web/api/canvas_api/index.html b/files/ko/web/api/canvas_api/index.html new file mode 100644 index 0000000000..bbe466e58d --- /dev/null +++ b/files/ko/web/api/canvas_api/index.html @@ -0,0 +1,135 @@ +--- +title: Canvas API +slug: Web/HTML/Canvas +tags: + - API + - Canvas + - JavaScript + - 개요 + - 레퍼런스 +translation_of: Web/API/Canvas_API +--- +<div>{{CanvasSidebar}}</div> + +<p><strong>Canvas API</strong>는 <a href="https://developer.mozilla.org/ko/docs/Web/JavaScript">JavaScript</a>와 <a href="https://developer.mozilla.org/ko/docs/Web/HTML">HTML </a>{{HtmlElement("canvas")}} 엘리먼트를 통해 그래픽을 그리기위한 수단을 제공합니다. 무엇보다도 애니메이션, 게임 그래픽, 데이터 시각화, 사진 조작 및 실시간 비디오 처리를 위해 사용됩니다.</p> + +<p>Canvas API는 주로 2D 그래픽에 중점을 두고 있습니다. <a href="https://developer.mozilla.org/ko/docs/Web/WebGL">WebGL API</a> 또한 <code><canvas></code> 엘리먼트를 사용하며, 하드웨어 가속 2D 및 3D 그래픽을 그립니다.</p> + +<h2 id="기본_예시">기본 예시</h2> + +<p>canvas에 초록색 사각형을 그리는 간단한 예시입니다.</p> + +<h3 id="HTML">HTML</h3> + +<pre class="brush: html"><canvas id="canvas"></canvas> +</pre> + +<h3 id="JavaScript">JavaScript</h3> + +<p>{{domxref("Document.getElementById()")}} 메소드는 HTML <code><canvas></code> 엘리먼트에 대한 참조를 얻습니다. 그 다음, {{domxref("HTMLCanvasElement.getContext()")}} 메소드는 엘리먼트의 컨텍스트(렌더링될 그리기의 대상)를 얻습니다.</p> + +<p>실제 그리기는 {{domxref("CanvasRenderingContext2D")}} 인터페이스를 사용해 수행됩니다. {{domxref("CanvasRenderingContext2D.fillStyle", "fillStyle")}} 프로퍼티는 사각형을 초록색으로 만듭니다. {{domxref("CanvasRenderingContext2D.fillRect()", "fillRect()")}} 메소드는 좌측 상단 코너를 (10, 10) 위치에 놓으며, 너비를 150, 높이를 100으로 지정합니다.</p> + +<pre class="brush: js">const canvas = document.getElementById('canvas'); +const ctx = canvas.getContext('2d'); + +ctx.fillStyle = 'green'; +ctx.fillRect(10, 10, 150, 100); +</pre> + +<h3 id="결과">결과</h3> + +<p>{{ EmbedLiveSample('기본_예시', 700, 180) }}</p> + +<h2 id="레퍼런스">레퍼런스</h2> + +<div class="index"> +<ul> + <li>{{domxref("HTMLCanvasElement")}}</li> + <li>{{domxref("CanvasRenderingContext2D")}}</li> + <li>{{domxref("CanvasGradient")}}</li> + <li>{{domxref("CanvasImageSource")}}</li> + <li>{{domxref("CanvasPattern")}}</li> + <li>{{domxref("ImageBitmap")}}</li> + <li>{{domxref("ImageData")}}</li> + <li>{{domxref("RenderingContext")}}</li> + <li>{{domxref("TextMetrics")}}</li> + <li>{{domxref("OffscreenCanvas")}} {{experimental_inline}}</li> + <li>{{domxref("Path2D")}} {{experimental_inline}}</li> + <li>{{domxref("ImageBitmapRenderingContext")}} {{experimental_inline}}</li> +</ul> +</div> + +<div class="blockIndicator note"> +<p><strong>노트:</strong> <code>WebGLRenderingContext</code>에 관련된 인터페이스는 <a href="/ko/docs/Web/WebGL" title="/en-US/docs/Web/WebGL">WebGL</a> 하위에 참조되어있습니다.</p> +</div> + +<p>{{domxref("CanvasCaptureMediaStream")}}은 관련된 인터페이스입니다.</p> + +<h2 id="가이드_및_튜토리얼">가이드 및 튜토리얼</h2> + +<dl> + <dt><a href="/ko/docs/Web/API/Canvas_API/Tutorial">Canvas 튜토리얼</a></dt> + <dd>Canvas API의 기본적인 사용과 고급 기능 모두를 다루는 이해하기 쉬운 튜토리얼.</dd> + <dt><a href="http://joshondesign.com/p/books/canvasdeepdive/title.html">HTML5 Canvas 깊이 살펴보기</a></dt> + <dd>Canvas API 및 WebGL의 실습, 자세한 소개.</dd> + <dt><a href="http://bucephalus.org/text/CanvasHandbook/CanvasHandbook.html">Canvas 핸드북</a></dt> + <dd>Canvas API에 대한 유용한 레퍼런스.</dd> + <dt><a href="/ko/docs/Web/API/Canvas_API/A_basic_ray-caster">데모: A basic ray-caster</a></dt> + <dd>Canvas를 사용한 ray-tracing 애니메이션 데모.</dd> + <dt><a href="/ko/docs/Web/API/Canvas_API/Manipulating_video_using_canvas">Canvas를 사용하여 비디오 조작</a></dt> + <dd>{{HTMLElement("video")}}와 {{HTMLElement("canvas")}}를 조합하여 실시간으로 비디오 데이터를 조작.</dd> +</dl> + +<h2 id="라이브러리">라이브러리</h2> + +<p>Canvas API는 굉장히 강력하지만, 사용하는 것이 항상 간단하지 않습니다. 아래에 나열된 라이브러리들은 캔버스 기반 프로젝트를 더 빠르고 더 쉽게 생성할 수 있게 해줍니다.</p> + +<ul> + <li><a href="http://www.createjs.com/easeljs">EaselJS</a>는 게임, 생성 예술 및 기타 고도의 그래픽 경험을 쉽게 생성할 수 있게 해주는 오픈소스 캔버스 라이브러리입니다.</li> + <li><a href="http://fabricjs.com">Fabric.js</a>는 SVG 파싱 기능을 갖춘 오픈소스 캔버스 라이브러리입니다.</li> + <li><a href="https://www.patrick-wied.at/static/heatmapjs/">heatmap.js</a>는 캔버스 기반 데이터 열지도를 생성하기위한 오픈소스 라이브러리입니다.</li> + <li><a href="http://thejit.org/">JavaScript InfoVis Toolkit</a>은 인터렉티브한 데이터 시각화를 생성합니다.</li> + <li><a href="https://konvajs.github.io/">Konva.js</a>는 데스크탑 및 모바일 애플리케이션을 위한 2D 캔버스 라이브러리입니다.</li> + <li><a href="https://p5js.org/">p5.js</a>는 예술가, 디자이너, 교육자 및 입문자를 위한 캔버스 그리기 기능의 모든 세트를 포함하고 있습니다.</li> + <li><a href="http://paperjs.org/">Paper.js</a>는 HTML5 Canvas 위에서 실행되는 오픈소스 벡터 그래픽 스크립팅 프레임워크입니다.</li> + <li><a href="https://phaser.io/">Phaser</a>는 Canvas 및 WebGL 기반의 브라우저 게임을 위한 빠르고, 자유롭고, 재미있는 오픈소스 프레임워크입니다.</li> + <li><a href="http://processingjs.org">Processing.js</a>는 Processing 시각화 언어의 포트입니다.</li> + <li><a href="https://ptsjs.org">Pts.js</a>는 canvas 및 SVG를 사용한 창의적인 코딩 및 시각화를 위한 라이브러리입니다.</li> + <li><a class="link-https" href="https://github.com/jeremyckahn/rekapi">Rekapi</a>는 Canvas를 위한 애니메이션 키 프레임 API입니다.</li> + <li><a href="http://scrawl.rikweb.org.uk/">Scrawl-canvas</a>는 2D 캔버스 엘리먼트를 생성하고 조작하기위한 오픈소스 JavaScript 라이브러리입니다.</li> + <li><a href="http://zimjs.com">ZIM</a> 프레임워크는 canvas에서의 창의적인 코딩을 위한 편의성, 컴포넌트 및 컨트롤을 제공하는 프레임워크입니다. 접근성 및 다채로운 튜토리얼을 포함합니다.</li> +</ul> + +<div class="blockIndicator note"> +<p><strong>노트:</strong> WebGL을 사용하는 2D 및 3D를 위한 <a href="/ko/docs/Web/WebGL" title="/en-US/docs/Web/WebGL">WebGL API</a>를 확인하세요.</p> +</div> + +<h2 id="명세">명세</h2> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">명세</th> + <th scope="col">상태</th> + <th scope="col">코멘트</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{SpecName('HTML WHATWG', '#2dcontext', 'the 2D rendering context')}}</td> + <td>{{Spec2('HTML WHATWG')}}</td> + <td></td> + </tr> + </tbody> +</table> + +<h2 id="브라우저_호환성">브라우저 호환성</h2> + +<p>Mozilla 애플리케이션은 Gecko 1.8(<a href="/ko/docs/Mozilla/Firefox/Releases/1.5">Firefox 1.5</a>)을 시작으로 <code><canvas></code>에 대한 지원을 받았습니다. OS X Dashboard 및 Safari를 위해 Apple이 소개한 것이 캔버스 엘리먼트의 기원입니다. Internet Explorer는 9버전부터 <code><canvas></code>를 지원하며, 이전 버전의 IE에서는 Google의 <a href="https://github.com/arv/explorercanvas">Explorer Canvas</a> 프로젝트의 스크립트를 추가하여 <code><canvas></code>에 대한 지원을 효과적으로 추가할 수 있습니다. Google Chrome 및 Opera 9 또한 <code><canvas></code>를 지원합니다.</p> + +<h2 id="함께_보기">함께 보기</h2> + +<ul> + <li><a href="/ko/docs/Web/WebGL">WebGL</a></li> +</ul> diff --git a/files/ko/web/api/canvas_api/manipulating_video_using_canvas/index.html b/files/ko/web/api/canvas_api/manipulating_video_using_canvas/index.html new file mode 100644 index 0000000000..7851f86154 --- /dev/null +++ b/files/ko/web/api/canvas_api/manipulating_video_using_canvas/index.html @@ -0,0 +1,164 @@ +--- +title: 캔버스(canvas)를 이용한 비디오 조작하기 +slug: Web/HTML/Canvas/Manipulating_video_using_canvas +tags: + - Canvas + - Video + - 비디오 + - 캔버스 +translation_of: Web/API/Canvas_API/Manipulating_video_using_canvas +--- +<div>{{CanvasSidebar}}</div> + +<div class="summary"> +<p>비디오에서 다양한 시각적 효과를 보여주기 위해,<code> <a class="internal" href="/ko/docs/Web/HTML/Element/canvas" title="Ko/Canvas">캔버스</a></code>와 <code><a class="internal" href="/ko/docs/Web/HTML/Element/video" title="Ko/HTML/Element/Video">비디오</a></code>의 기능을 결합하여 실시간으로 비디오 데이터를 조작할 수 있습니다. 이 튜토리얼에서는 자바스크립트 코드로 어떻게 크로마 키잉(chroma-keying, 또한 "녹색 스크린 효과, green screen effect")을 구현할 수 있는지 보여줍니다. </p> +</div> + +<p><a class="external" href="/samples/video/chroma-key/index.xhtml" title="https://developer.mozilla.org/editor/fckeditor/core/editor/samples/video/chroma-key/index.xhtml">라이브 예제 보기</a></p> + +<h2 id="문서(document)_내용">문서(document) 내용</h2> + +<p>이 내용을 보여주기 위한 XHTML 문서는 아래와 같습니다.</p> + +<pre class="brush: html"><!DOCTYPE html> +<html> + <head> + <style> + body { + background: black; + color:#CCCCCC; + } + #c2 { + background-image: url(foo.png); + background-repeat: no-repeat; + } + div { + float: left; + border :1px solid #444444; + padding:10px; + margin: 10px; + background:#3B3B3B; + } + </style> + <script type="text/javascript" src="main.js"></script> + </head> + + <body onload="processor.doLoad()"> + <div> + <video id="video" src="video.ogv" controls="true"/> + </div> + <div> + <canvas id="c1" width="160" height="96"></canvas> + <canvas id="c2" width="160" height="96"></canvas> + </div> + </body> +</html> +</pre> + +<p>여기에서 중요한 요소는:</p> + +<ol> + <li>이 문서에는 ID가 c1, c2인 두 개의 <a class="internal" href="/ko/docs/Web/HTML/Element/canvas" title="Ko/Canvas"><code>캔버스</code></a>가 있습니다. 캔버스 c1은 비디오 원본의 현재 프레임을 보여주기 위해 사용되고, c2는 크로마 키잉 효과를 수행한 결과를 보여줍니다. c2에서 비디오의 녹색 배경을 대체할 정지 이미지를 미리 로드합니다.</li> + <li>자바스크립트 코드는 main.js에서 가져옵니다. 이 스크립트는 자바스크립트 1.8 기능을 사용했기 때문에 스크립트를 가져오는 22번째 줄에서 버전이 명시됩니다(원문: this script uses JavaScript 1.8 features, so that version is specified in line 22 when importing the script).</li> + <li>문서가 로드되면, processor.doLoad() 메서드가 실행됩니다.</li> +</ol> + +<h2 id="자바스크립트_코드">자바스크립트 코드</h2> + +<p>main.js에 있는 자바스크립트 코드는 3개의 메서드로 구성됩니다.</p> + +<h3 id="크로마_키잉_플레이어_초기화">크로마 키잉 플레이어 초기화</h3> + +<p><code>doLoad()</code> 메서드는 문서가 최초에 로드될 때 호출됩니다. 이 메서드가 하는 일은 크로마 키잉 처리에서 쓰일 변수를 준비하고, 이벤트 리스너를 등록함으로써 사용자가 비디오 재생을 시작할 때 감지할 수 있도록 해줍니다. </p> + +<pre class="brush: js"> var processor; + + processor.doLoad = function doLoad() { + this.video = document.getElementById('video'); + this.c1 = document.getElementById('c1'); + this.ctx1 = this.c1.getContext('2d'); + this.c2 = document.getElementById('c2'); + this.ctx2 = this.c2.getContext('2d'); + let self = this; + this.video.addEventListener('play', function() { + self.width = self.video.videoWidth / 2; + self.height = self.video.videoHeight / 2; + self.timerCallback(); + }, false); + }, +</pre> + +<p>이코드는 XHTML에서 중요한 요소인 비디오와 캔버스의 참조를 가져옵니다. 두 개의 캔버스에 대한 그래픽 컨텍스트의 참조도 가져옵니다. 이 참조들은 뒤에서 크로마 키잉 효과를 구현할 때 사용됩니다.</p> + +<p>그리고 <code>addEventListener()</code>는 비디오가 재생을 시작하기 위해 호출되기 때문에 사용자가 재생 버튼을 누를 때 알림을 받습니다. 재생이 시작되면 이 코드는 비디오의 가로, 세로를 이등분 한 값을 가져오고(크로마 키잉 효과를 수행할 때 이등분 함), <code>timerCallback()</code> 메서드를 호출하여 비디오를 보고 시각적 효과를 계산하기 시작합니다.</p> + +<h3 id="타이머_콜백">타이머 콜백</h3> + +<p>타이머 콜백은 비디오가 재생되기 시작("재생" 이벤트가 발생)할 때 호출되는데, 매 프레임마다 키잉 효과를 주기 위해 주기적으로 호출 될 수 있도록 설정해 주어야 합니다.</p> + +<pre class="brush: js"> processor.timerCallback = function timerCallback() { + if (this.video.paused || this.video.ended) { + return; + } + this.computeFrame(); + let self = this; + setTimeout(function() { + self.timerCallback(); + }, 0); + }, +</pre> + +<p>콜백에서 하는 첫 번 째 일은 비디오가 재생되고 있는지 확인하는 것인데, 만약 그렇지 않다면 콜백은 아무 일도 하지 않고 즉시 반환됩니다.</p> + +<p>그 후에 현재 비디오 프레임에서 크로마 키잉 효과를 주기 위한 <code>computeFrame()</code> 메서드를 호출합니다.</p> + +<p>콜백에서 마지막으로 하는 일은 <code>setTimeout()</code>을 호출하여 가능한 한 빨리 <code>timerCallback()</code> 메서드를 다시 호출할 수 있도록 하는 것입니다. 실제로는, 비디오 프레임 속도에 대한 기반 지식으로 호출할 수 있도록 합니다. </p> + +<h3 id="비디오_프레임_데이터_조작">비디오 프레임 데이터 조작</h3> + +<p>아래의 <code>computeFrame()</code> 메서드는 프레임 데이터를 가져와서 크로마 키잉 효과를 수행하는 역할을 합니다. </p> + +<pre class="brush: js"> processor.computeFrame = function computeFrame() { + this.ctx1.drawImage(this.video, 0, 0, this.width, this.height); + let frame = this.ctx1.getImageData(0, 0, this.width, this.height); + let l = frame.data.length / 4; + + for (let i = 0; i < l; i++) { + let r = frame.data[i * 4 + 0]; + let g = frame.data[i * 4 + 1]; + let b = frame.data[i * 4 + 2]; + if (g > 100 && r > 100 && b < 43) + frame.data[i * 4 + 3] = 0; + } + this.ctx2.putImageData(frame, 0, 0); + return; + } +</pre> + +<p>위 과정이 계속 호출 되면, 아래와 같이 비디오 요소에 가장 최근 프레임의 비디오 데이터가 표출됩니다.</p> + +<p><img alt="video.png" class="default internal" src="/@api/deki/files/3282/=video.png" style="height: 192px; width: 320px;"></p> + +<p>2번째 줄에서, 첫 번째 캔버스의 그래픽 컨텍스트 ctx1에 비디오 프레임이 복사 되는데, 원본의 절반 크기로 프레임을 그리기 위해 이전에 저장한 가로, 세로 값으로 지정합니다. 컨텍스트의 <code>drawImage()</code> 메서드에 비디오 요소를 전달하기만 하면 현재 비디오 프레임을 그릴 수 있습니다. 결과는 아래와 같습니다: </p> + +<p><img alt="sourcectx.png" class="default internal" src="/@api/deki/files/3284/=sourcectx.png" style="height: 96px; width: 160px;"></p> + +<p>3번째 줄에서는 첫 번째 컨텍스트의 <code>getImageData()</code> 메서드를 호출해서 현재 비디오 프레임의 원시 그래픽 데이터 복사본을 가져옵니다. 이것은 조작할 수 있는 원시 32비트 픽셀 이미지 데이터를 제공합니다. 4번째 줄에서는 프레임의 이미지 데이터 전체 크기를 4로 나누어 이미지의 픽셀 수를 계산합니다.</p> + +<p>6번째 줄에서 시작하는 <code>for</code> 문은 프레임의 픽셀을 스캔하여, 빨간색, 녹색, 파란색 값을 추출하여 사전에 정의된 숫자와 비교합니다. 이 숫자는 <code>foo.png</code>에서 가져온 배경 이미지로 대체될 녹색 스크린 영역을 감지합니다.</p> + +<p>녹색 스크린이라고 간주된 매개변수 내의 프레임 이미지 데이터의 모든 픽셀은 투명해질 수 있도록 알파값이 0으로 대체됩니다. 결과적으로 최종 이미지는 100% 투명해진 녹색 스크린 영역을 갖게 되고, 13번째 줄에서 대상 컨텍스트에 고정된 배경 위로 올려져 그려집니다.</p> + +<p>결과 이미지는 아래와 같습니다:</p> + +<p><img alt="output.png" class="default internal" src="/@api/deki/files/3283/=output.png" style="height: 96px; width: 161px;"></p> + +<p>이 과정은 비디오가 재생될 때마다 반복되므로, 매 프레임마다 처리되어 크로마 키잉 효과가 나타나는 것입니다.</p> + +<p><a class="external" href="/samples/video/chroma-key/index.xhtml" title="https://developer.mozilla.org/editor/fckeditor/core/editor/samples/video/chroma-key/index.xhtml">라이브 예제 보기</a></p> + +<h2 id="더_보기">더 보기</h2> + +<ul> + <li><a class="internal" href="/en-US/docs/Web/Guide/HTML/Using_HTML5_audio_and_video" title="En/Using audio and video in Firefox">오디오와 비디오 사용하기</a></li> +</ul> diff --git a/files/ko/web/api/canvas_api/tutorial/advanced_animations/index.html b/files/ko/web/api/canvas_api/tutorial/advanced_animations/index.html new file mode 100644 index 0000000000..1779e63b2c --- /dev/null +++ b/files/ko/web/api/canvas_api/tutorial/advanced_animations/index.html @@ -0,0 +1,376 @@ +--- +title: 발전된 애니메이션 +slug: Web/HTML/Canvas/Tutorial/Advanced_animations +translation_of: Web/API/Canvas_API/Tutorial/Advanced_animations +--- +<div>{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Basic_animations", "Web/API/Canvas_API/Tutorial/Pixel_manipulation_with_canvas")}}</div> + +<div class="summary"> +<p>마지막 챕터에서 우리는 몇가지 <a href="/en-US/docs/Web/API/Canvas_API/Tutorial/Basic_animations">간단한 애니메이션들</a>을 만들었고 이제 이것들을 어떻게 움직이게 하는지 안다. 이 챕터에서 우리는 각각의 모션들을 자세히 살펴보고 애니메이션을 더 발전시키기 위해 몇가지 물리 동작을 추가할 것이다.</p> +</div> + +<h2 id="공_그리기">공 그리기</h2> + +<p>우리는 애니메이션 공부를 위해 공을 사용할 것이다. 먼저 캔버스에 공을 그려보자. 다음 코드를 통해 준비해보자.</p> + +<pre class="brush: html notranslate"><canvas id="canvas" width="600" height="300"></canvas> +</pre> + +<p>언제나처럼, 우리는 context를 먼저 그려야 한다. 공을 그리기 위해 우리는 캔버스에 그림을 그리기 위한 프로퍼티와 <code>draw()</code> 메소드를 가진 <code>ball</code> 오브젝트를 생성할 것이다.</p> + +<pre class="brush: js notranslate">var canvas = document.getElementById('canvas'); +var ctx = canvas.getContext('2d'); + +var ball = { + x: 100, + y: 100, + radius: 25, + color: 'blue', + draw: function() { + ctx.beginPath(); + ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true); + ctx.closePath(); + ctx.fillStyle = this.color; + ctx.fill(); + } +}; + +ball.draw();</pre> + +<p>특이할 건 없다. 이공은 사실상 간단한 원이고 그리는 방법은 다음{{domxref("CanvasRenderingContext2D.arc()", "arc()")}} 메소드에서 참고할 수 있다.</p> + +<h2 id="속도_추가하기">속도 추가하기</h2> + +<p>우리한테는 이제 공이 있다. 이제 이 튜토리얼 <a href="/en-US/docs/Web/API/Canvas_API/Tutorial/Basic_animations">마지막 챕터</a>에서 배웠던 것과 같은 기본 애니메이션을 추가할 준비가 되었다. 다시 한 번, 애니메이션 컨트롤은 {{domxref("window.requestAnimationFrame()")}}가 도와주 것이다. 공은 위치에 속도 벡터를 추가하여 움직일 수 있게 된다. 각각의 프레임에, 우리는{{domxref("CanvasRenderingContext2D.clearRect", "clear", "", 1)}}를 캔버스에 주어 오래된 원을 이전 프래임에서 지운다.</p> + +<pre class="brush: js; highlight:[8,9,24,25] notranslate">var canvas = document.getElementById('canvas'); +var ctx = canvas.getContext('2d'); +var raf; + +var ball = { + x: 100, + y: 100, + vx: 5, + vy: 2, + radius: 25, + color: 'blue', + draw: function() { + ctx.beginPath(); + ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true); + ctx.closePath(); + ctx.fillStyle = this.color; + ctx.fill(); + } +}; + +function draw() { + ctx.clearRect(0,0, canvas.width, canvas.height); + ball.draw(); + ball.x += ball.vx; + ball.y += ball.vy; + raf = window.requestAnimationFrame(draw); +} + +canvas.addEventListener('mouseover', function(e) { + raf = window.requestAnimationFrame(draw); +}); + +canvas.addEventListener('mouseout', function(e) { + window.cancelAnimationFrame(raf); +}); + +ball.draw(); +</pre> + +<h2 id="경계">경계</h2> + +<p>경게 충돌 테스트의 필요 없이 우리가 만든 공은 캔버스 밖으로 빠르게 빠져나갈 것입니다. 우리는 공의 <code>x</code> 와 <code>y</code> 위치가 캔버스 차원을 빠져나갔는지 체크해서 방향과 속도를 바꿔주어야 합니다. 그러기 위해서 우리는 <code>draw</code> 메소드에 다음 확인사항을 추가할 것입니다.:</p> + +<pre class="brush: js notranslate">if (ball.y + ball.vy > canvas.height || ball.y + ball.vy < 0) { + ball.vy = -ball.vy; +} +if (ball.x + ball.vx > canvas.width || ball.x + ball.vx < 0) { + ball.vx = -ball.vx; +}</pre> + +<h3 id="First_demo">First demo</h3> + +<p>이제 동작을 확인해 봅시다. 시작하려먼 마우스를 캔버스 안으로 움직여 주세요.</p> + +<div class="hidden"> +<pre class="brush: html notranslate"><canvas id="canvas" style="border: 1px solid" width="600" height="300"></canvas></pre> + +<pre class="brush: js notranslate">var canvas = document.getElementById('canvas'); +var ctx = canvas.getContext('2d'); +var raf; + +var ball = { + x: 100, + y: 100, + vx: 5, + vy: 2, + radius: 25, + color: 'blue', + draw: function() { + ctx.beginPath(); + ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true); + ctx.closePath(); + ctx.fillStyle = this.color; + ctx.fill(); + } +}; + +function draw() { + ctx.clearRect(0,0, canvas.width, canvas.height); + ball.draw(); + ball.x += ball.vx; + ball.y += ball.vy; + + if (ball.y + ball.vy > canvas.height || + ball.y + ball.vy < 0) { + ball.vy = -ball.vy; + } + if (ball.x + ball.vx > canvas.width || + ball.x + ball.vx < 0) { + ball.vx = -ball.vx; + } + + raf = window.requestAnimationFrame(draw); +} + +canvas.addEventListener('mouseover', function(e) { + raf = window.requestAnimationFrame(draw); +}); + +canvas.addEventListener('mouseout', function(e) { + window.cancelAnimationFrame(raf); +}); + +ball.draw();</pre> +</div> + +<p>{{EmbedLiveSample("First_demo", "610", "310")}}</p> + +<h2 id="가속">가속</h2> + +<p>움직임을 좀 더 리얼하게 만들기 위해, 우리는 속도를 다음과 같이 줄 겁니다. 예를들어:</p> + +<pre class="brush: js notranslate">ball.vy *= .99; +ball.vy += .25;</pre> + +<p>이것은 각 프레임의 세로 속도를 줄여주어, 공이 결국 바닥에서 튀게 만듭니다.</p> + +<div class="hidden"> +<h6 id="Second_demo">Second demo</h6> + +<pre class="brush: html notranslate"><canvas id="canvas" style="border: 1px solid" width="600" height="300"></canvas></pre> + +<pre class="brush: js notranslate">var canvas = document.getElementById('canvas'); +var ctx = canvas.getContext('2d'); +var raf; + +var ball = { + x: 100, + y: 100, + vx: 5, + vy: 2, + radius: 25, + color: 'blue', + draw: function() { + ctx.beginPath(); + ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true); + ctx.closePath(); + ctx.fillStyle = this.color; + ctx.fill(); + } +}; + +function draw() { + ctx.clearRect(0,0, canvas.width, canvas.height); + ball.draw(); + ball.x += ball.vx; + ball.y += ball.vy; + ball.vy *= .99; + ball.vy += .25; + + if (ball.y + ball.vy > canvas.height || + ball.y + ball.vy < 0) { + ball.vy = -ball.vy; + } + if (ball.x + ball.vx > canvas.width || + ball.x + ball.vx < 0) { + ball.vx = -ball.vx; + } + + raf = window.requestAnimationFrame(draw); +} + +canvas.addEventListener('mouseover', function(e) { + raf = window.requestAnimationFrame(draw); +}); + +canvas.addEventListener('mouseout', function(e) { + window.cancelAnimationFrame(raf); +}); + +ball.draw();</pre> +</div> + +<p>{{EmbedLiveSample("Second_demo", "610", "310")}}</p> + +<h2 id="후행_효과">후행 효과</h2> + +<p>지금까지 우리는 {{domxref("CanvasRenderingContext2D.clearRect", "clearRect")}}메소드를 사용해서 이전 프레임을 지웠다. 만약 당신이 {{domxref("CanvasRenderingContext2D.fillRect", "fillRect")}}르 사용하여 약간 투명도를 준다면, 쉽게 후행 효과(Trailing effect)를 만들 수 있을 것이다.</p> + +<pre class="brush: js notranslate">ctx.fillStyle = 'rgba(255, 255, 255, 0.3)'; +ctx.fillRect(0, 0, canvas.width, canvas.height);</pre> + +<div class="hidden"> +<h6 id="Third_demo">Third demo</h6> + +<pre class="brush: html notranslate"><canvas id="canvas" style="border: 1px solid" width="600" height="300"></canvas></pre> + +<pre class="brush: js notranslate">var canvas = document.getElementById('canvas'); +var ctx = canvas.getContext('2d'); +var raf; + +var ball = { + x: 100, + y: 100, + vx: 5, + vy: 2, + radius: 25, + color: 'blue', + draw: function() { + ctx.beginPath(); + ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true); + ctx.closePath(); + ctx.fillStyle = this.color; + ctx.fill(); + } +}; + +function draw() { + ctx.fillStyle = 'rgba(255, 255, 255, 0.3)'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + ball.draw(); + ball.x += ball.vx; + ball.y += ball.vy; + ball.vy *= .99; + ball.vy += .25; + + if (ball.y + ball.vy > canvas.height || + ball.y + ball.vy < 0) { + ball.vy = -ball.vy; + } + if (ball.x + ball.vx > canvas.width || + ball.x + ball.vx < 0) { + ball.vx = -ball.vx; + } + + raf = window.requestAnimationFrame(draw); +} + +canvas.addEventListener('mouseover', function(e) { + raf = window.requestAnimationFrame(draw); +}); + +canvas.addEventListener('mouseout', function(e) { + window.cancelAnimationFrame(raf); +}); + +ball.draw();</pre> +</div> + +<p>{{EmbedLiveSample("Third_demo", "610", "310")}}</p> + +<h2 id="마우스_컨트롤_추가하기">마우스 컨트롤 추가하기</h2> + +<p>공을 컨트롤 하기 위해, 우리는 <code><a href="/en-US/docs/Web/Reference/Events/mousemove">mousemove</a></code> 이벤트를 사용하여 마우스를 따라오게 할 것이다. <code><a href="/en-US/docs/Web/Events/click">click</a></code> 이벤트를 통해 공을 놓으면 다시 공이 튀도록 할 것이다.</p> + +<div class="hidden"> +<pre class="brush: html notranslate"><canvas id="canvas" style="border: 1px solid" width="600" height="300"></canvas></pre> +</div> + +<pre class="brush: js notranslate">var canvas = document.getElementById('canvas'); +var ctx = canvas.getContext('2d'); +var raf; +var running = false; + +var ball = { + x: 100, + y: 100, + vx: 5, + vy: 1, + radius: 25, + color: 'blue', + draw: function() { + ctx.beginPath(); + ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true); + ctx.closePath(); + ctx.fillStyle = this.color; + ctx.fill(); + } +}; + +function clear() { + ctx.fillStyle = 'rgba(255, 255, 255, 0.3)'; + ctx.fillRect(0,0,canvas.width,canvas.height); +} + +function draw() { + clear(); + ball.draw(); + ball.x += ball.vx; + ball.y += ball.vy; + + if (ball.y + ball.vy > canvas.height || ball.y + ball.vy < 0) { + ball.vy = -ball.vy; + } + if (ball.x + ball.vx > canvas.width || ball.x + ball.vx < 0) { + ball.vx = -ball.vx; + } + + raf = window.requestAnimationFrame(draw); +} + +canvas.addEventListener('mousemove', function(e) { + if (!running) { + clear(); + ball.x = e.clientX; + ball.y = e.clientY; + ball.draw(); + } +}); + +canvas.addEventListener('click', function(e) { + if (!running) { + raf = window.requestAnimationFrame(draw); + running = true; + } +}); + +canvas.addEventListener('mouseout', function(e) { + window.cancelAnimationFrame(raf); + running = false; +}); + +ball.draw(); +</pre> + +<p>마우스로 공을 움직이고, 클릭을 통해 놓아보자.</p> + +<p>{{EmbedLiveSample("Adding_mouse_control", "610", "310")}}</p> + +<h2 id="Breakout">Breakout</h2> + +<p>이 짧은 챕터는 발전된 애니메이션을 만들기 위한 조금의 기술을 설명했다. 여기에 더 많은 것들이 있다! 노나 벽돌을 추가해서 이 튜토리얼을 <a href="http://en.wikipedia.org/wiki/Breakout_%28video_game%29">Breakout</a> 으로 발전시키는 건 어떨까? <a href="/en-US/docs/Games">Game development</a>에서 게임에 관련된 글들을 찾아보자.</p> + +<h2 id="더보기">더보기</h2> + +<ul> + <li>{{domxref("window.requestAnimationFrame()")}}</li> + <li><a href="/en-US/docs/Games/Techniques/Efficient_animation_for_web_games">Efficient animation for web games</a></li> +</ul> + +<p>{{PreviousNext("Web/API/Canvas_API/Tutorial/Basic_animations", "Web/API/Canvas_API/Tutorial/Pixel_manipulation_with_canvas")}}</p> diff --git a/files/ko/web/api/canvas_api/tutorial/applying_styles_and_colors/index.html b/files/ko/web/api/canvas_api/tutorial/applying_styles_and_colors/index.html new file mode 100644 index 0000000000..df094acb71 --- /dev/null +++ b/files/ko/web/api/canvas_api/tutorial/applying_styles_and_colors/index.html @@ -0,0 +1,732 @@ +--- +title: 스타일과 색 적용하기 +slug: Web/HTML/Canvas/Tutorial/Applying_styles_and_colors +tags: + - HTML5 + - 그래픽 + - 캔버스 +translation_of: Web/API/Canvas_API/Tutorial/Applying_styles_and_colors +--- +<div>{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Drawing_shapes", "Web/API/Canvas_API/Tutorial/Drawing_text")}}</div> + +<div class="summary"> +<p><a href="/ko/docs/Web/HTML/Canvas/Tutorial/Drawing_shapes">도형 그리기</a> 장에서는 기본 선과 채우기 스타일만 사용했습니다. 여기서 우리는 그리기를 조금 더 매력적으로 만들 수있는 캔버스 옵션을 살펴볼 것입니다. 그리기에 다른 색상, 선 스타일, 그라디언트, 패턴 및 그림자를 추가하는 방법을 배우게됩니다.</p> +</div> + +<h2 id="Colors" name="Colors">색상</h2> + +<p>지금까지는 그리기 메소드만 살펴봤습니다. 도형에 색을 적용하고자 하면, <code>fillStyle</code>과 <code>strokeStyle</code> 두 가지 중요한 속성을 사용할 수 있습니다.</p> + +<dl> + <dt>{{domxref("CanvasRenderingContext2D.fillStyle", "fillStyle = color")}}</dt> + <dd>도형을 채우는 색을 설정합니다.</dd> + <dt>{{domxref("CanvasRenderingContext2D.strokeStyle", "strokeStyle = color")}}</dt> + <dd>도형의 윤곽선 색을 설정합니다.</dd> +</dl> + +<p>여기서의 <code>color</code>는 CSS의 {{cssxref("<color>")}}, 그라디언트 객체, 패턴 객체를 뜻합니다. 그라디언트 객체와 패턴 객체는 페이지 아래에서 설명합니다. 윤곽선과 채움 색의 초기 설정값은 검은색입니다. (CSS 색상 값 <code>#000000</code>)</p> + +<div class="note"> +<p><strong>참고:</strong> <code>strokeStyle</code> 또는 <code>fillStyle</code> 속성을 설정하면, 새로 설정된 값이 앞으로 그려질 도형의 기본 값이 됩니다. 각 도형에 다른 색을 적용하려면 <code>fillStyle</code> 또는 <code>strokeStyle</code> 속성을 다시 적용해야 합니다.</p> +</div> + +<p>색의 올바른 값은 CSS3 사양에 나오는 {{cssxref("<color>")}} 값입니다. 아래에 나오는 색은 모두 한가지 색을 다르게 표현한 것입니다.</p> + +<pre class="brush: js">// fillStyle에 적용되는 색은 모두 '오렌지' + +ctx.fillStyle = "orange"; +ctx.fillStyle = "#FFA500"; +ctx.fillStyle = "rgb(255, 165, 0)"; +ctx.fillStyle = "rgba(255, 165, 0, 1)"; +</pre> + +<h3 id="A_fillStyle_example" name="A_fillStyle_example"><code>fillStyle</code> 예제</h3> + +<p>이 예제에서 <code>for</code> 반복문을 두 번 사용하여 사각형 격자를 그릴 것입니다. 결과는 스크린샷과 같을 것입니다. 결과가 그리 대단한 것은 아닙니다. 각 사각형의 RGB 색상값에서 붉은색과 녹색 값만을 변수 <code>i</code>와 <code>j</code>를 사용하여 변경합니다. 파란색 채널은 고정된 값입니다. 채널 값들을 변경함으로써, 모든 종류의 팔레트를 생성할 수 있습니다. 단계를 늘리면 Photoshop에서 사용하는 색상 팔레트와 비슷한 모양을 얻을 수 있습니다.</p> + +<pre class="brush: js;highlight[5,6]">function draw() { + var ctx = document.getElementById('canvas').getContext('2d'); + for (var i = 0; i < 6; i++){ + for (var j = 0; j < 6; j++){ + ctx.fillStyle = 'rgb(' + Math.floor(255 - 42.5 * i) + ', ' + + Math.floor(255 - 42.5 * j) + ', 0)'; + ctx.fillRect(j*25,i*25,25,25); + } + } +}</pre> + +<div class="hidden"> +<pre class="brush: html"><canvas id="canvas" width="150" height="150"></canvas></pre> + +<pre class="brush: js">draw();</pre> +</div> + +<p>결과는 아래와 같습니다.</p> + +<p>{{EmbedLiveSample("A_fillStyle_example", 160, 160, "https://mdn.mozillademos.org/files/5417/Canvas_fillstyle.png")}}</p> + +<h3 id="A_strokeStyle_example" name="A_strokeStyle_example"><code>strokeStyle</code> 예제</h3> + +<p>이번 예제는 위에 나온 예제와 비슷하지만, <code>strokeStyle</code> 속성을 사용하여 윤곽선의 색을 바꿉니다. 사각형 대신, 원을 그리는 <code>arc()</code> 메소드를 사용합니다.</p> + +<pre class="brush: js;highlight[5,6]">function draw() { + var ctx = document.getElementById('canvas').getContext('2d'); + for (var i = 0; i < 6; i++) { + for (var j = 0; j < 6; j++) { + ctx.strokeStyle = 'rgb(0, ' + Math.floor(255 - 42.5 * i) + ', ' + + Math.floor(255 - 42.5 * j) + ')'; + ctx.beginPath(); + ctx.arc(12.5 + j * 25, 12.5 + i * 25, 10, 0, Math.PI * 2, true); + ctx.stroke(); + } + } +}</pre> + +<div class="hidden"> +<pre class="brush: html"><canvas id="canvas" width="150" height="150"></canvas></pre> + +<pre class="brush: js">draw();</pre> +</div> + +<p>결과는 아래와 같습니다.</p> + +<p>{{EmbedLiveSample("A_strokeStyle_example", "180", "180", "https://mdn.mozillademos.org/files/253/Canvas_strokestyle.png")}}</p> + +<h2 id="Transparency" name="Transparency">투명도</h2> + +<p>캔버스에는 불투명한 도형을 그릴 수도 있고, 반투명한 도형도 그릴 수도 있습니다. <code>globalAlpha</code> 값을 설정하거나 윤곽선 또는 채움 스타일에 반투명 색을 적용하면 됩니다.</p> + +<dl> + <dt>{{domxref("CanvasRenderingContext2D.globalAlpha", "globalAlpha = transparencyValue")}}</dt> + <dd>투명도 값이 설정되면 이후 캔버스에 그려지는 모든 도형들의 투명도가 바뀝니다. 설정하는 값은 0.0(완전히 투명)과 1.0(완전히 불투명) 사이에 있어야 하며, 초기 설정값은 1.0(완전히 투명)입니다.</dd> +</dl> + +<p><code>globalAlpha</code>는 모두 같은 투명도로 캔버스에 많은 도형을 그릴 때 유용합니다. 하지만, 보통은 각각의 도형마다 투명도를 설정하는 것이 더 유용할 것입니다.</p> + +<p><code>strokeStyle</code>과 <code>fillStyle</code> 값에 CSS rgba 색상값을 적용할 수 있으므로, 투명한 색을 적용하려면 아래와 같은 표기법을 사용할 수 있습니다.</p> + +<pre class="brush: js">// 외곽선과 채움 스타일에 투명 적용 + +ctx.strokeStyle = 'rgba(255, 0, 0, 0.5)'; +ctx.fillStyle = 'rgba(255, 0, 0, 0.5)'; +</pre> + +<p><code>rgba()</code> 함수는 <code>rgb()</code> 함수와 비슷하지만, 인자가 하나 더 있습니다. 마지막 인자는 투명도 값을 설정하는 인자입니다. 올바른 범위는 0.0(완전히 투명)에서 1.0(완전히 불투명)입니다.</p> + +<h3 id="A_globalAlpha_example" name="A_globalAlpha_example"><code>globalAlpha</code> 예제</h3> + +<p>이 예제에서, 네 가지 다른 색을 가진 사각형을 배경에 그릴 것입니다. 그 위에, 반투명한 원을 여러 개 그릴 것입니다. <code>globalAlpha</code> 값을 <code>0.2</code>로 설정하면 이후 그려질 도형은 이 값을 사용합니다. <code>for</code> 반복문을 사용하여 점점 큰 반지름의 원을 그립니다. 최종 결과물은 원형 그레이디언트가 됩니다. 원이 겹쳐지면서 점점 불투명해지는 것을 볼 수 있으며, 최종적으로 한 가운데에 있는 원에서는 뒷 배경이 거의 보이지 않게 됩니다.</p> + +<pre class="brush: js;highlight[15]">function draw() { + var ctx = document.getElementById('canvas').getContext('2d'); + // 배경을 그린다 + ctx.fillStyle = '#FD0'; + ctx.fillRect(0, 0, 75, 75); + ctx.fillStyle = '#6C0'; + ctx.fillRect(75, 0, 75, 75); + ctx.fillStyle = '#09F'; + ctx.fillRect(0, 75, 75, 75); + ctx.fillStyle = '#F30'; + ctx.fillRect(75, 75, 75, 75); + ctx.fillStyle = '#FFF'; + + // 투명값을 설정한다 + ctx.globalAlpha = 0.2; + + // 반투명한 원을 그린다 + for (var i = 0; i < 7; i++){ + ctx.beginPath(); + ctx.arc(75, 75, 10 + 10 * i, 0, Math.PI * 2, true); + ctx.fill(); + } +}</pre> + +<div class="hidden"> +<pre class="brush: html"><canvas id="canvas" width="150" height="150"></canvas></pre> + +<pre class="brush: js">draw();</pre> +</div> + +<p>{{EmbedLiveSample("A_globalAlpha_example", "180", "180", "https://mdn.mozillademos.org/files/232/Canvas_globalalpha.png")}}</p> + +<h3 id="An_example_using_rgba()" name="An_example_using_rgba()"><code>rgba()</code>를 사용한 예제</h3> + +<p>두번째 예제에서는 위의 예제와 비슷한 일을 하지만, 겹쳐진 원을 그리는 대신, 불투명도가 증가하는 작은 사각형을 그릴 것입니다. 각각의 도형마다 윤곽선이나 채움 스타일을 따로따로 설정할 수 있기 때문에, <code>rgba()</code>를 사용할 때는 조금 더 제어가 쉽고 융통성도 있습니다.</p> + +<pre class="brush: js;highlight[16]">function draw() { + var ctx = document.getElementById('canvas').getContext('2d'); + + // 배경을 그린다 + ctx.fillStyle = 'rgb(255,221,0)'; + ctx.fillRect(0,0,150,37.5); + ctx.fillStyle = 'rgb(102,204,0)'; + ctx.fillRect(0,37.5,150,37.5); + ctx.fillStyle = 'rgb(0,153,255)'; + ctx.fillRect(0,75,150,37.5); + ctx.fillStyle = 'rgb(255,51,0)'; + ctx.fillRect(0,112.5,150,37.5); + + // 반투명한 사각형을 그린다 + for (var i=0;i<10;i++){ + ctx.fillStyle = 'rgba(255,255,255,'+(i+1)/10+')'; + for (var j=0;j<4;j++){ + ctx.fillRect(5+i*14,5+j*37.5,14,27.5) + } + } +}</pre> + +<div class="hidden"> +<pre class="brush: html"><canvas id="canvas" width="150" height="150"></canvas></pre> + +<pre class="brush: js">draw();</pre> +</div> + +<p>{{EmbedLiveSample("An_example_using_rgba()", "180", "180", "https://mdn.mozillademos.org/files/246/Canvas_rgba.png")}}</p> + +<h2 id="Line_styles" name="Line_styles">선 모양</h2> + +<p>선의 스타일을 바꾸는 방법이 몇가지 있습니다.</p> + +<dl> + <dt>{{domxref("CanvasRenderingContext2D.lineWidth", "lineWidth = value")}}</dt> + <dd>이후 그려질 선의 두께를 설정합니다.</dd> + <dt>{{domxref("CanvasRenderingContext2D.lineCap", "lineCap = type")}}</dt> + <dd>선의 끝 모양을 설정합니다.</dd> + <dt>{{domxref("CanvasRenderingContext2D.lineJoin", "lineJoin = type")}}</dt> + <dd>선들이 만나는 "모서리"의 모양을 설정합니다.</dd> + <dt>{{domxref("CanvasRenderingContext2D.miterLimit", "miterLimit = value")}}</dt> + <dd>두 선이 예각으로 만날 때 접합점의 두께를 제어할 수 있도록, 연결부위의 크기를 제한하는 값을 설정합니다.</dd> + <dt>{{domxref("CanvasRenderingContext2D.getLineDash", "getLineDash()")}}</dt> + <dd>음수가 아닌 짝수를 포함하는 현재 선의 대시 패턴 배열을 반환합니다.</dd> + <dt>{{domxref("CanvasRenderingContext2D.setLineDash", "setLineDash(segments)")}}</dt> + <dd>현재 선의 대시 패턴을 설정합니다.</dd> + <dt>{{domxref("CanvasRenderingContext2D.lineDashOffset", "lineDashOffset = value")}}</dt> + <dd>선의 대시 배열이 어디서 시작될지 지정합니다.</dd> +</dl> + +<p>아래 예제들을 보면 어떻게 동작하는지 이해할 수 있을 것입니다.</p> + +<h3 id="A_lineWidth_example" name="A_lineWidth_example"><code>lineWidth</code> 예제</h3> + +<p>현재 선의 두께를 설정합니다. 설정값은 반드시 양수이어야 하며, 초기 설정값은 1.0 단위입니다.</p> + +<p>선의 두께는 지정된 경로의 가운데에 있는 획의 두께입니다. 이 말의 뜻은, 경로의 좌우로, 설정된 두께 반 만큼의 폭 영역이 그려진다는 것입니다. 캔버스 좌표는 픽셀을 직접 참조하지 않으므로, 선명한 수평 및 수직선을 얻기 위해 특별히 주의를 기울여야 합니다.</p> + +<p>아래에 나오는 예제에서는, 선의 두께가 점점 증가하는 10개의 직선이 그려집니다. 가장 왼쪽의 선은 1.0 단위 폭입니다. 그러나, 경로의 위치 때문에 가장 왼쪽과 다른 모든 홀수 폭 두께 선은 선명하게 보이지 않습니다.</p> + +<pre class="brush: js;highlight[4]">function draw() { + var ctx = document.getElementById('canvas').getContext('2d'); + for (var i = 0; i < 10; i++){ + ctx.lineWidth = 1 + i; + ctx.beginPath(); + ctx.moveTo(5 + i * 14, 5); + ctx.lineTo(5 + i * 14, 140); + ctx.stroke(); + } +} +</pre> + +<div class="hidden"> +<pre class="brush: html"><canvas id="canvas" width="150" height="150"></canvas></pre> + +<pre class="brush: js">draw();</pre> +</div> + +<p>{{EmbedLiveSample("A_lineWidth_example", "180", "180", "https://mdn.mozillademos.org/files/239/Canvas_linewidth.png")}}</p> + +<p>선명한 선을 얻으려면 경로에 획을 어떻게 그려지는지 이해해야 합니다. 아래의 이미지를 보면, 격자는 캔버스의 좌표 격자를 나타냅니다. 격자선 사이에 있는 사각형은 실제 픽셀과 딱 맞아 떨어집니다. 아래에 있는 첫번째 이미지를 보면, (2,1)에서 (5,5)로 사각형이 채워져 있습니다. 사각형의 전체 영역(연한 붉은 색)은 픽셀 경계선 사이에 딱 맞아 떨어지기 때문에 채워진 사각형은 선명한 가장자리를 갖습니다.</p> + +<p><img alt="" class="internal" src="https://mdn.mozillademos.org/files/201/Canvas-grid.png"></p> + +<p>만일 (3,1)에서 (3,5)로 그리는 직선의 두께가 1.0이라면, 두번째 이미지와 같은 상황이 됩니다. 채워진 실제 영역 (진한 파란색)은 패스의 양쪽에있는 픽셀의 절반까지만 확장됩니다. 이것은 1 픽셀을 채우는 것이 아니므로 근사값으로 화면에 그려지게 됩니다. 그래서 양옆의 영역(연한 파란색과 짙은 파란 색)으로, 실제 설정한 색과는 다른 흐릿한 색으로 채워지는 것입니다. 이전 예제에서 보듯이 선 두께가 <code>1.0</code>인 선에서 일어난 일입니다.</p> + +<p>이렇게 되는 것을 막으려면, 경로를 아주 정밀하게 생성해야 합니다. 선의 두께가 1.0이면 경로의 양쪽으로 0.5 단위만큼이라는 것을 알고 있으니, (3.5,1)에서 (3.5,5)로 그리는 경로를 생성하는 세번째 이미지의 결과는 완벽히 정밀하게 1 픽셀 두께의 수직선이 됩니다.</p> + +<div class="note"> +<p><strong>참고:</strong> 위에 나온 수직선 그리기 예제를 살펴보면, Y 위치는 정수로 된 격자선 위치를 참조하고 있습니다. 그렇지 않았다면, 끝점에서 픽셀의 반을 차지한 상태로 보였을 것입니다. (초기값이 <code>butt</code>인 <code>lineCap</code> 스타일의 설정값에 따라 다르게 보입니다. 홀수 두께 선들의 좌표를 0.5 픽셀씩 조정하여 다시 계산하고 싶을지도 모릅니다. <code>lineCap</code> 스타일을 <code>square</code>로 설정함으로써, 끝점에서 선의 외곽 경계선은 픽셀에 딱 맞게 자동적으로 확장될 것입니다.)</p> + +<p>경로의 시작 지점과 종료 지점의 끝점만이 영향을 받는다는 것에 주목하세요. 만약 <code>closePath()</code>로 경로가 닫힌다면, 시작 지점과 종료 지점은 없는 것입니다. 그 대신, 경로 안에 있는 모든 끝점들은, 초기 설정값이 <code>miter</code>인 <code>lineJoin</code> 스타일의 설정값을 사용하여 이전 부분 및 다음 부분과 이어지는데, 교차되는 점들로 이어진 부분들의 외곽 경계선을 자동적으로 확장하는 효과가 생깁니다. 그렇기 때문에 만약 이들 이어진 부분들이 수직 또는 수평이라면, 그려지는 선들은 각 끝점의 중심에 놓인 픽셀을 가득 채우게 될 것입니다. 이들 선 스타일에 대한 예제는 아래에 나옵니다.</p> +</div> + +<p>짝수 두께의 선들은 반으로 나누어도 각각의 반은 정수의 양만큼이기 때문에 픽셀을 조정할 필요가 없습니다.</p> + +<p>비트맵이 아닌 벡터 2D 그래픽으로 작업할 때, 작업을 시작할 때는 약간 힘들겠지만, 격자와 경로의 위치에 주의를 기울인다면, 크기를 키우거나 줄이거나 또는 어떠한 변형을 하더라도 그리려는 이미지는 똑바로 보일 것입니다. 1.0 두께의 수직선은 2배로 크기를 키웠을 때, 정확히 2 픽셀 두께의 선이 되며, 올바른 위치에 나타날 것입니다.</p> + +<h3 id="A_lineCap_example" name="A_lineCap_example"><code>lineCap</code> 예제</h3> + +<p><code>lineCap</code> 속성은 그리려는 모든 선의 끝점 모양을 결정합니다. <code>butt</code>, <code>round</code>, <code>square</code>라는 세 가지 값을 가지며, 초기 설정값은 <code>butt</code>입니다.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/236/Canvas_linecap.png" style="float: right; height: 190px; width: 190px;"></p> + +<dl> + <dt><code>butt</code></dt> + <dd>선의 끝이 좌표에 딱맞게 잘립니다.</dd> + <dt><code>round</code></dt> + <dd>선의 끝이 동그랗습니다.</dd> + <dt><code>square</code></dt> + <dd>선 끝에, 선 두께 반만큼의 사각형 영역이 더해집니다.</dd> +</dl> + +<p>이 예제에서는, 각기 다른 <code>lineCap</code> 속성 값을 가진 선 세개가 그려집니다. 또한 각 선들의 차이점을 정확히 보이기 위한 안내선이 추가로 그려집니다. 세개의 선 모두, 이 안내선 위에 시작과 종료 좌표가 있습니다.</p> + +<p>맨 왼쪽에 있는 선은 초기 설정값인 <code>butt</code>을 사용합니다. 안내선에 딱 맞게 선이 시작되고 끝이 납니다. 가운데에 있는 선은 <code>round</code>를 사용합니다. 선 두께의 반을 반지름으로 하는 반원이 끝에 붙습니다. 맨 오른쪽에 있는 선은 <code>square</code>를 사용합니다. 선 두께 만큼의 너비와 선 두께 반 만큼의 높이를 가진 네모 상자가 끝에 붙습니다.</p> + +<pre class="brush: js;highlight[18]">function draw() { + var ctx = document.getElementById('canvas').getContext('2d'); + var lineCap = ['butt','round','square']; + + // 안내선을 그린다 + ctx.strokeStyle = '#09f'; + ctx.beginPath(); + ctx.moveTo(10, 10); + ctx.lineTo(140, 10); + ctx.moveTo(10, 140); + ctx.lineTo(140, 140); + ctx.stroke(); + + // 선을 그린다 + ctx.strokeStyle = 'black'; + for (var i=0;i<lineCap.length;i++){ + ctx.lineWidth = 15; + ctx.lineCap = lineCap[i]; + ctx.beginPath(); + ctx.moveTo(25 + i * 50, 10); + ctx.lineTo(25 + i * 50,140); + ctx.stroke(); + } +} +</pre> + +<div class="hidden"> +<pre class="brush: html"><canvas id="canvas" width="150" height="150"></canvas></pre> + +<pre class="brush: js">draw();</pre> +</div> + +<p>{{EmbedLiveSample("A_lineCap_example", "180", "180", "https://mdn.mozillademos.org/files/236/Canvas_linecap.png")}}</p> + +<h3 id="A_lineJoin_example" name="A_lineJoin_example"><code>lineJoin</code> 예제</h3> + +<p><code>lineJoin</code> 속성은, 도형을 이루는 선이나 호나 곡선들이 연결되는 지점의 모양을 결정합니다. 끝점과 제어점이 정확히 같은 위치인, 길이가 0인 부분들은 제외된다.</p> + +<p>이 속성에는 세 가지 값이 있는데, <code>round</code>, <code>bevel</code>, <code>miter</code>이며, 초기 설정값은 <code>miter</code>입니다. 두 부분들이 같은 방향으로 연결되어 있는 경우에는, <code>lineJoin</code>을 설정해도 아무런 효과가 나타나지 않습니다.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/237/Canvas_linejoin.png" style="float: right; height: 190px; width: 190px;"></p> + +<dl> + <dt><code>round</code></dt> + <dd>도형의 모서리를, 연결되는 부분들의 공통 끝점을 중심으로 하는 원 모양으로 만듭니다. 이때 원의 반지름은 선의 두께와 같습니다.</dd> + <dt><code>bevel</code></dt> + <dd>도형의 모서리를, 연결되는 부분들의 공통 끝점에서 세모 모양으로 만듭니다.</dd> + <dt><code>miter</code></dt> + <dd>도형의 모서리를, 두 부분의 바깥쪽 테두리 선을 각각 연장하여 교차된 점으로 생긴 마름모꼴 모양으로 만듭니다. <code>miterLimit</code> 속성값에 따라 모양이 달라집니다.</dd> +</dl> + +<p>아래 예제에서 세 개의 경로를 그릴 것입니다. 세 경로는 각각 다른 <code>lineJoin</code> 속성값을 가집니다.</p> + +<pre class="brush: js;highlight[6]">function draw() { + var ctx = document.getElementById('canvas').getContext('2d'); + var lineJoin = ['round', 'bevel', 'miter']; + ctx.lineWidth = 10; + for (var i=0;i<lineJoin.length;i++){ + ctx.lineJoin = lineJoin[i]; + ctx.beginPath(); + ctx.moveTo(-5, 5 + i * 40); + ctx.lineTo(35, 45 + i * 40); + ctx.lineTo(75, 5 + i * 40); + ctx.lineTo(115, 45 + i * 40); + ctx.lineTo(155, 5 + i * 40); + ctx.stroke(); + } +} +</pre> + +<div class="hidden"> +<pre class="brush: html"><canvas id="canvas" width="150" height="150"></canvas></pre> + +<pre class="brush: js">draw();</pre> +</div> + +<p>{{EmbedLiveSample("A_lineJoin_example", "180", "180", "https://mdn.mozillademos.org/files/237/Canvas_linejoin.png")}}</p> + +<h3 id="A_demo_of_the_miterLimit_property" name="A_demo_of_the_miterLimit_property"><code>miterLimit</code> 속성 예제</h3> + +<p>위의 예제에서 볼 수 있듯이, 속성값을 <code>miter</code>로 하여 두 선이 연결되면, 연결되는 두 선의 바깥쪽 테두리는 연장선이 만나는 지점까지 확장됩니다. 연결된 두 선이 이루는 각도가 크면, 확장되는 영역이 크지 않지만, 각도가 작아짐(끝이 뾰족해짐)에 따라서 이 영역이 기하급수적으로 커질 수도 있습니다.</p> + +<p><code>miterLimit</code> 속성은 끝점이 만나는 지점과 테두리 연장선이 만나는 지점이 얼마나 떨어져 있을지를 결정합니다. 두 선이 이 값을 넘게 되면, <code>lineJoin</code> 속성의 <code>bevel</code> 값 모양이 적용됩니다. <code>miterLimit</code> 속성값(HTML {{HTMLElement("canvas")}}에서, 초기 설정값은 10.0)에 의해, 현재 좌표 방식 안에서, 선의 두께에 따라, 어느 정도까지 뾰족해질 수 있는지가 계산됩니다. 그래서 <code>miterLimit</code>은 현재 디스플레이 비율이나 경로의 변형 같은 것으로 각각 설정될 수 있습니다. 그렇게 하여 선의 모서리에만 영향을 줍니다.</p> + +<p>더 자세히 얘기하자면, 뾰족함 제한(miter limit)은, 선 두께의 반과 확장되는 길이(HTML 캔버스에서, 선이 연결되는 바깥쪽 끝부분과, 경로에서 연결되는 두 부분의 공통 끝점 사이로 측정합니다.)의 최대 허용 비율입니다. 이것은 두 부분의 외곽선이 만나는 안쪽 점과 바깥쪽 점 사이 거리와, 선 두께의 최대 허용 비율과 같습니다. miter 값 모양이 아닌 bevel 값 모양으로 연결되는 지점의 최소 안쪽 각 반 만큼의 값과 같은 것입니다.</p> + +<ul> + <li><code>miterLimit</code> = <strong>max</strong> <code>miterLength</code> / <code>lineWidth</code> = 1 / <strong>sin</strong> ( <strong>min</strong> <em>θ</em> / 2 )</li> + <li>초기 설정값이 10.0인 뾰족함 제한(miter limit)값은 약 11도보다 낮은 예각인 곳을 bevel 값 모양으로 만듭니다.</li> + <li>뾰족함 제한 값이 √2 ≈ 1.4142136(반올림)과 같다면 연결되는 곳이 둔각이거나 직각인 곳을 제외한 모든 곳을 bevel 값 모양으로 만듭니다.</li> + <li>뾰족함 제한 값이 1.0과 같다면 모든 곳을 bevel 값 모양으로 만듭니다.</li> + <li>뾰족함 제한 값에는 1.0보다 작은 값이 올 수 없습니다.</li> +</ul> + +<p>다음 예제에서는 <code>miterLimit</code> 값을 바꾸고 그 결과가 어떤지 바로 확인할 수 있습니다. 파란색 선은 지그재그 무늬 안에서 선들의 시작 지점과 종료 지점을 나타냅니다.</p> + +<p>이 예제에서 <code>miterLimit</code> 값을 4.2보다 낮게 설정하면, 모든 연결 지점은 bevel 값 모양이 되어 파란색 선에 붙을 것입니다. <code>miterLimit</code> 값이 10보다 높다면, 거의 모든 연결 지점들이 파란색 선 바깥쪽에 있을 것입니다. 왼쪽으로 갈수록 파란색 선에서 더 많이 튀어나오는데, 왼쪽으로 갈수록 연결되는 각이 더 작아지기 때문입니다. 값을 5로 설정하면, 반은 bevel 값 모양으로, 반은 miter 값 모양이 됩니다.</p> + +<pre class="brush: js;highlight[18]">function draw() { + var ctx = document.getElementById('canvas').getContext('2d'); + + // 캔버스를 비운다 + ctx.clearRect(0,0,150,150); + + // 안내선을 그린다 + ctx.strokeStyle = '#09f'; + ctx.lineWidth = 2; + ctx.strokeRect(-5,50,160,50); + + // 선 스타일을 설정한다 + ctx.strokeStyle = '#000'; + ctx.lineWidth = 10; + + // 입력 값을 검사한다 + if (document.getElementById('miterLimit').value.match(/\d+(\.\d+)?/)) { + ctx.miterLimit = parseFloat(document.getElementById('miterLimit').value); + } else { + alert('Value must be a positive number'); + } + + // 선을 그린다 + ctx.beginPath(); + ctx.moveTo(0,100); + for (i=0;i<24;i++){ + var dy = i%2==0 ? 25 : -25 ; + ctx.lineTo(Math.pow(i,1.5)*2,75+dy); + } + ctx.stroke(); + return false; +} +</pre> + +<div class="hidden"> +<pre class="brush: html"><table> + <tr> + <td><canvas id="canvas" width="150" height="150"></canvas></td> + <td>Change the <code>miterLimit</code> by entering a new value below and clicking the redraw button.<br><br> + <form onsubmit="return draw();"> + <label>Miter limit</label> + <input type="text" size="3" id="miterLimit"/> + <input type="submit" value="Redraw"/> + </form> + </td> + </tr> +</table></pre> + +<pre class="brush: js">document.getElementById('miterLimit').value = document.getElementById('canvas').getContext('2d').miterLimit; +draw();</pre> +</div> + +<p>{{EmbedLiveSample("A_demo_of_the_miterLimit_property", "400", "180", "https://mdn.mozillademos.org/files/240/Canvas_miterlimit.png")}}</p> + +<p> </p> + +<h3 id="대시라인_사용하기">대시라인 사용하기</h3> + +<p><code>setLineDash</code> 메소드와 <code>lineDashOffset</code> 속성은 선의 대시 패턴을 지정합니다. <code>setLineDash</code> 메소드는 거리를 지정하는 숫자 목록을 받아 선과 틈을 교대로 그리며 <code>lineDashOffset</code> 속성은 패턴을 시작할 위치를 오프셋으로 설정합니다.</p> + +<p>이 예제에서 우리는 행진하는 개미 효과를 만들고 있습니다. 컴퓨터 그래픽 프로그램의 선택 도구에서 흔히 볼 수있는 애니메이션 기술입니다. 테두리를 애니메이션화하여 사용자가 선택 테두리와 이미지 배경을 구별하는 데 도움이됩니다. 이 튜토리얼의 뒷부분에서 이 작업 및 다른 <a href="/ko/docs/docs/Web/API/Canvas_API/Tutorial/Basic_animations">기본 애니메이션</a>을 수행하는 방법을 배울 수 있습니다.</p> + +<div class="hidden"> +<pre class="brush: html"><canvas id="canvas" width="110" height="110"></canvas> +</pre> +</div> + +<pre class="brush: js;highlight[6]">var ctx = document.getElementById('canvas').getContext('2d'); +var offset = 0; + +function draw() { + ctx.clearRect(0, 0, canvas.width, canvas.height); + ctx.setLineDash([4, 2]); + ctx.lineDashOffset = -offset; + ctx.strokeRect(10, 10, 100, 100); +} + +function march() { + offset++; + if (offset > 16) { + offset = 0; + } + draw(); + setTimeout(march, 20); +} + +march();</pre> + +<p>{{EmbedLiveSample("Using_line_dashes", "120", "120", "https://mdn.mozillademos.org/files/9853/marching-ants.png")}}</p> + +<h2 id="Gradients" name="Gradients">그라디언트(Gradient)</h2> + +<p>다른 그래픽 프로그램들과 마찬가지로, 선형 및 원형의 그레이디언트를 사용할 수 있습니다. 다음 메소드 중 하나를 사용하여 {{domxref("CanvasGradient")}} 객체를 생성합니다. 그런 다음 이 객체를 <code>fillStyle</code> 또는 <code>strokeStyle</code> 속성에 할당 할 수 있습니다.</p> + +<dl> + <dt>{{domxref("CanvasRenderingContext2D.createLinearGradient", "createLinearGradient(x1, y1, x2, y2)")}}</dt> + <dd>시작점 좌표를 (<code>x1</code>, <code>y1</code>)로 하고, 종료점 좌표를 (<code>x2</code>, <code>y2</code>)로 하는 선형 그라디언트 오브젝트를 생성합니다.</dd> + <dt>{{domxref("CanvasRenderingContext2D.createRadialGradient", "createRadialGradient(x1, y1, r1, x2, y2, r2)")}}</dt> + <dd>반지름이 <code>r1</code>이고 좌표 (<code>x1</code>, <code>y1</code>)을 중심으로 하는 원과, 반지름이 <code>r2</code>이고 좌표 (<code>x2</code>, <code>y2</code>)를 중심으로 하는 원을 사용하여 그라디언트가 생성됩니다.</dd> +</dl> + +<p>예를 들면 다음과 같습니다.</p> + +<pre class="brush: js">var lineargradient = ctx.createLinearGradient(0, 0, 150, 150); +var radialgradient = ctx.createRadialGradient(75, 75, 0, 75, 75, 100); +</pre> + +<p><code>CanvasGradient</code> 객체를 만들었다면, <code>addColorStop()</code> 메소드를 사용하여, 오브젝트에 색을 적용할 수 있습니다.</p> + +<dl> + <dt>{{domxref("CanvasGradient.addColorStop", "gradient.addColorStop(position, color)")}}</dt> + <dd><code>gradient</code> 오브젝트에 새로운 색 중단점(color stop)을 생성합니다. <code>position</code>은 0.0에서 1.0 사이의 숫자이고 그라디언트에서 색상의 상대적인 위치를 정의합니다. <code>color</code> 인자는 CSS {{cssxref("<color>")}}를 나타내는 문자열이어야하고, 그라디언트가 (전환효과로) 진행되면서 도달한 지점의 색상을 의미합니다.</dd> +</dl> + +<p>색 중단점은 원하는 만큼 마음대로 추가할 수 있습니다. 흰 색에서 검은 색으로 변하는 선형 그레이디언트를 만들려면 아래와 같이 합니다.</p> + +<pre class="brush: js">var lineargradient = ctx.createLinearGradient(0, 0, 150, 150); +lineargradient.addColorStop(0, 'white'); +lineargradient.addColorStop(1, 'black'); +</pre> + +<h3 id="A_createLinearGradient_example" name="A_createLinearGradient_example"><code>createLinearGradient</code> 예제</h3> + +<p>이 예제에서 그레이디언트 두 개를 만들 것입니다. 예제에서 볼 수 있듯이, <code>strokeStyle</code>과 <code>fillStyle</code> 속성 모두 <code>canvasGradient</code> 오브젝트를 속성 값으로 가질 수 있습니다.</p> + +<pre class="brush: js;highlight[5,11]">function draw() { + var ctx = document.getElementById('canvas').getContext('2d'); + + // 그레이디언트를 생성한다 + var lingrad = ctx.createLinearGradient(0, 0, 0, 150); + lingrad.addColorStop(0, '#00ABEB'); + lingrad.addColorStop(0.5, '#fff'); + lingrad.addColorStop(0.5, '#26C000'); + lingrad.addColorStop(1, '#fff'); + + var lingrad2 = ctx.createLinearGradient(0, 50, 0, 95); + lingrad2.addColorStop(0.5, '#000'); + lingrad2.addColorStop(1, 'rgba(0, 0, 0, 0)'); + + // 외곽선과 채움 스타일에 그레이디언트를 적용한다 + ctx.fillStyle = lingrad; + ctx.strokeStyle = lingrad2; + + // 도형을 그린다 + ctx.fillRect(10, 10, 130, 130); + ctx.strokeRect(50, 50, 50, 50); + +} +</pre> + +<div class="hidden"> +<pre class="brush: html"><canvas id="canvas" width="150" height="150"></canvas></pre> + +<pre class="brush: js">draw();</pre> +</div> + +<p>첫번째 그라디언트는 배경 그라디언트입니다. 보시다시피 같은 위치에 두 가지 색상을 지정했습니다. 매우 선명한 색상 전환을 만들기 위해 이 작업을 수행합니다(이 경우 흰색에서 녹색으로). 일반적으로 색상 중단점을 정의하는 순서는 중요하지 않지만, 이 특별한 경우에는 의미가 있습니다.</p> + +<p>두 번째 그래디언트에서는 시작 색상 (위치 0.0)을 지정하지 않았는데, 자동으로 다음 색상 중단점의 색상으로 가정하기 때문에 반드시 필요하지는 않기 때문입니다. 따라서 위치 0.5에 검은색을 지정하면 시작부터 중단점까지 자동으로 검정색 그라이언트를 만듭니다.</p> + +<p>{{EmbedLiveSample("A_createLinearGradient_example", "180", "180", "https://mdn.mozillademos.org/files/235/Canvas_lineargradient.png")}}</p> + +<h3 id="A_createRadialGradient_example" name="A_createRadialGradient_example"><code>createRadialGradient</code> 예제</h3> + +<p>이 예제에서는 원형 그레이디언트를 4개 만들 것입니다. 포토샵같은 프로그램에서 원형 그레이디언트를 만들 때는 하나의 점을 중심으로 그레이디언트를 만드는데, 캔버스의 원형 그레이디언트에서는 시작과 종료 지점 두군데를 제어할 수 있기 때문에, 기존의 프로그램에서 볼 수 있는 원형 그레이디언트보다는 더 복잡한 효과를 만들어 낼 수 있습니다.</p> + +<pre class="brush: js;highlight[5,10,15,20]">function draw() { + var ctx = document.getElementById('canvas').getContext('2d'); + + // 그라디언트를 생성한다 + var radgrad = ctx.createRadialGradient(45,45,10,52,50,30); + radgrad.addColorStop(0, '#A7D30C'); + radgrad.addColorStop(0.9, '#019F62'); + radgrad.addColorStop(1, 'rgba(1,159,98,0)'); + + var radgrad2 = ctx.createRadialGradient(105,105,20,112,120,50); + radgrad2.addColorStop(0, '#FF5F98'); + radgrad2.addColorStop(0.75, '#FF0188'); + radgrad2.addColorStop(1, 'rgba(255,1,136,0)'); + + var radgrad3 = ctx.createRadialGradient(95,15,15,102,20,40); + radgrad3.addColorStop(0, '#00C9FF'); + radgrad3.addColorStop(0.8, '#00B5E2'); + radgrad3.addColorStop(1, 'rgba(0,201,255,0)'); + + var radgrad4 = ctx.createRadialGradient(0,150,50,0,140,90); + radgrad4.addColorStop(0, '#F4F201'); + radgrad4.addColorStop(0.8, '#E4C700'); + radgrad4.addColorStop(1, 'rgba(228,199,0,0)'); + + // 도형을 그린다 + ctx.fillStyle = radgrad4; + ctx.fillRect(0,0,150,150); + ctx.fillStyle = radgrad3; + ctx.fillRect(0,0,150,150); + ctx.fillStyle = radgrad2; + ctx.fillRect(0,0,150,150); + ctx.fillStyle = radgrad; + ctx.fillRect(0,0,150,150); +} +</pre> + +<div class="hidden"> +<pre class="brush: html"><canvas id="canvas" width="150" height="150"></canvas></pre> + +<pre class="brush: js">draw();</pre> +</div> + +<p>이 예제에서는 원형 그레이디언트에 사용되는 두 원의 중심을 달리하여 입체적인 공처럼 보이게 했습니다. 안쪽 원과 바깥쪽 원은 겹치지 않게 하는 것이 좋습니다. 왜냐하면 예상하기 힘든 이상한 결과가 나타날 수 있기 때문입니다.</p> + +<p>그레이디언트의 마지막 색 적용 지점에서는 투명도를 적용하였습니다. 투명도가 적용된 지점에서 이전 지점까지의 색 변화를 보기 좋게 만들려면, 두 지점에 똑같은 색을 적용하면 되는데, 이 예제에서는 색의 값을 다른 방식으로 입력하여 헷갈릴 수도 있습니다. 첫번째 그레이디언트에 사용된 <code>#019F62</code>와 <code>rgba(1,159,98,1)</code>은 같은 색입니다.</p> + +<p>{{EmbedLiveSample("A_createRadialGradient_example", "180", "180", "https://mdn.mozillademos.org/files/244/Canvas_radialgradient.png")}}</p> + +<h2 id="Patterns" name="Patterns">패턴(Patterns)</h2> + +<p>이전 페이지의 예제 중 하나에서 일련의 루프를 사용하여 이미지 패턴을 만들었습니다. 그러나 훨씬 간단한 메소드 인 createPattern () 메소드가 있습니다.</p> + +<dl> + <dt>{{domxref("CanvasRenderingContext2D.createPattern", "createPattern(image, type)")}}</dt> + <dd>새 캔버스 패턴 객체를 만들어 반환합니다. <code>image</code>는 {{domxref("CanvasImageSource")}}(즉, {{domxref("HTMLImageElement")}}, 다른 캔버스, {{HTMLElement("video")}} 요소 등등)입니다. <code>type</code>은 이미지 사용 방법을 나타내는 문자열입니다.</dd> +</dl> + +<p><code>type</code>은 패턴을 만들기 위해 이미지를 사용하는 방법을 지정하며, 다음 문자열 값 중 하나 여야합니다.</p> + +<dl> + <dt><code>repeat</code></dt> + <dd>수직 및 수평 방향으로 이미지를 이어 붙입니다.</dd> + <dt><code>repeat-x</code></dt> + <dd>수평 방향으로만 이미지를 이어 붙입니다.</dd> + <dt><code>repeat-y</code></dt> + <dd>수직 방향으로만 이미지를 이어 붙입니다.</dd> + <dt><code>no-repeat</code></dt> + <dd>이미지를 이어 붙이지 않습니다. 이미지는 한번만 사용됩니다.</dd> +</dl> + +<p>이 메소드를 사용하여 위에서 본 그라디언트 메소드와 매우 유사한 {{domxref ( "CanvasPattern")}} 객체를 생성합니다. 패턴을 생성하면 <code>fillStyle</code> 또는 <code>strokeStyle</code> 속성에 패턴을 할당 할 수 있습니다. 예를 들면 다음과 같습니다.</p> + +<pre class="brush: js">var img = new Image(); +img.src = 'someimage.png'; +var ptrn = ctx.createPattern(img, 'repeat'); +</pre> + +<div class="note"> +<p><strong>참고:</strong> <code>drawImage ()</code> 메서드와 마찬가지로 이 메소드를 호출하기 전에 이미지가 로드되었는지 확인해야합니다. 그렇지 않으면 패턴이 잘못 그려 질 수 있습니다.</p> +</div> + +<h3 id="A_createPattern_example" name="A_createPattern_example"><code>createPattern</code> 예제</h3> + +<p>이 마지막 예제에서, <code>fillStyle</code> 속성에 적용할 패턴을 만들 것입니다. 한 가지 눈여겨 볼 것은, 이미지 <code>onload</code> 핸들러 사용한다는 것입니다. 이미지를 패턴에 적용하기 전에 불러오기가 완료되었는지 확인하는 것입니다.</p> + +<pre class="brush: js;highlight[10]">function draw() { + var ctx = document.getElementById('canvas').getContext('2d'); + + // 패턴으로 사용할 이미지 오브젝트를 생성한다 + var img = new Image(); + img.src = 'https://mdn.mozillademos.org/files/222/Canvas_createpattern.png'; + img.onload = function() { + + // 패턴을 생성한다 + var ptrn = ctx.createPattern(img,'repeat'); + ctx.fillStyle = ptrn; + ctx.fillRect(0,0,150,150); + + } +} +</pre> + +<div class="hidden"> +<pre class="brush: html"><canvas id="canvas" width="150" height="150"></canvas></pre> + +<pre class="brush: js">draw();</pre> + +<p>The result looks like this:</p> +</div> + +<p>{{EmbedLiveSample("A_createPattern_example", "180", "180", "https://mdn.mozillademos.org/files/222/Canvas_createpattern.png")}}</p> + +<h2 id="그림자">그림자</h2> + +<p>그림자 사용에는 네 개의 속성이 있습니다.</p> + +<dl> + <dt>{{domxref("CanvasRenderingContext2D.shadowOffsetX", "shadowOffsetX = float")}}</dt> + <dd>그림자가 객체에서 연장되어야하는 수평 거리를 나타냅니다. 이 값은 변환 행렬의 영향을 받지 않습니다. 기본값은 0입니다.</dd> + <dt>{{domxref("CanvasRenderingContext2D.shadowOffsetY", "shadowOffsetY = float")}}</dt> + <dd>그림자가 객체에서 연장되어야하는 수직 거리를 나타냅니다. 이 값은 변환 행렬의 영향을 받지 않습니다. 기본값은 0입니다.</dd> + <dt>{{domxref("CanvasRenderingContext2D.shadowBlur", "shadowBlur = float")}}</dt> + <dd>흐림(blur) 효과의 크기를 나타냅니다. 이 값은 픽셀 수와 일치하지 않으며 현재 변환 행렬의 영향을 받지 않습니다. 기본값은 0입니다.</dd> + <dt>{{domxref("CanvasRenderingContext2D.shadowColor", "shadowColor = color")}}</dt> + <dd>그림자 효과의 색상을 나타내는 표준 CSS 색상 값. 기본적으로 완전 검은색입니다.</dd> +</dl> + +<p><code>shadowOffsetX</code> 및 <code>shadowOffsetY</code> 속성은 그림자가 X 및 Y 방향으로 객체에서 얼마나 멀리 떨어져야하는지 나타냅니다. 이 값은 현재 변환 행렬의 영향을받지 않습니다. 음수값을 사용하면 그림자가 위로 또는 왼쪽으로 확장되고 양수값을 사용하면 그림자가 아래로 또는 오른쪽으로 확장됩니다. 기본값은 모두 0입니다.</p> + +<p><code>shadowBlur</code> 속성은 흐림 효과의 크기를 나타냅니다. 이 값은 픽셀 수와 일치하지 않으며 현재 변환 행렬의 영향을받지 않습니다. 기본값은 0입니다.</p> + +<p><code>shadowColor</code> 속성은 그림자 효과의 색상을 나타내는 표준 CSS 색상 값입니다. 기본값은 완전 검은색입니다.</p> + +<div class="note"> +<p><strong>알아둘 것:</strong> 음영은 <code>source-over</code> <a href="/ko/docs/docs/Web/API/Canvas_API/Tutorial/Compositing">합성 작업</a>에만 사용됩니다.</p> +</div> + +<h3 id="그림자_있는_글자_예제">그림자 있는 글자 예제</h3> + +<p>이 예제에서는 그림자가 있는 글자를 그립니다.</p> + +<pre class="brush: js;highlight[4,5,6,7]">function draw() { + var ctx = document.getElementById('canvas').getContext('2d'); + + ctx.shadowOffsetX = 2; + ctx.shadowOffsetY = 2; + ctx.shadowBlur = 2; + ctx.shadowColor = "rgba(0, 0, 0, 0.5)"; + + ctx.font = "20px Times New Roman"; + ctx.fillStyle = "Black"; + ctx.fillText("Sample String", 5, 30); +} +</pre> + +<div class="hidden"> +<pre class="brush: html"><canvas id="canvas" width="150" height="80"></canvas></pre> + +<pre class="brush: js">draw();</pre> +</div> + +<p>{{EmbedLiveSample("A_shadowed_text_example", "180", "100", "https://mdn.mozillademos.org/files/2505/shadowed-string.png")}}</p> + +<p>다음 장에서 <a href="/ko/docs/Web/API/Canvas_API/Tutorial/Drawing_text">텍스트 그리기</a>에 대한 <code>font</code> 속성과 <code>fillText</code> 메소드를 살펴 보겠습니다.</p> + +<h2 id="캔버스_채우기_규칙">캔버스 채우기 규칙</h2> + +<p><code>fill</code> (혹은 {{domxref("CanvasRenderingContext2D.clip", "clip")}} 및 {{domxref("CanvasRenderingContext2D.isPointInPath", "isPointinPath")}})을 사용할 때 한 점이 경로 안쪽 또는 바깥에 있는지 그리고 따라서 채워지는지 여부를 결정하기 위한 채우기 규칙 알고리즘을 선택적으로 제공 할 수 있습니다. 경로가 교차하거나 중첩 된 경우에 유용합니다.<br> + <br> + 다음 두가지 값을 사용할 수 있습니다:</p> + +<ul> + <li><code><strong>"nonzero</strong></code>": <a href="http://en.wikipedia.org/wiki/Nonzero-rule">non-zero winding rule</a> 알고리즘. 기본값.</li> + <li><code><strong>"evenodd"</strong></code>: <a href="http://en.wikipedia.org/wiki/Even%E2%80%93odd_rule">even-odd winding rule</a> 알고리즘.</li> +</ul> + +<p>In this example we are using the <code>evenodd</code> rule.</p> + +<pre class="brush: js;highlight[6]">function draw() { + var ctx = document.getElementById('canvas').getContext('2d'); + ctx.beginPath(); + ctx.arc(50, 50, 30, 0, Math.PI * 2, true); + ctx.arc(50, 50, 15, 0, Math.PI * 2, true); + ctx.fill('evenodd'); +}</pre> + +<div class="hidden"> +<pre class="brush: html"><canvas id="canvas" width="100" height="100"></canvas></pre> + +<pre class="brush: js"><code>draw();</code></pre> +</div> + +<p>{{EmbedLiveSample("Canvas_fill_rules", "110", "110", "https://mdn.mozillademos.org/files/9855/fill-rule.png")}}</p> + +<p>{{PreviousNext("Web/API/Canvas_API/Tutorial/Drawing_shapes", "Web/API/Canvas_API/Tutorial/Drawing_text")}}</p> diff --git a/files/ko/web/api/canvas_api/tutorial/basic_animations/index.html b/files/ko/web/api/canvas_api/tutorial/basic_animations/index.html new file mode 100644 index 0000000000..457d658172 --- /dev/null +++ b/files/ko/web/api/canvas_api/tutorial/basic_animations/index.html @@ -0,0 +1,310 @@ +--- +title: 기본 애니메이션 +slug: Web/HTML/Canvas/Tutorial/Basic_animations +tags: + - HTML5 + - 그래픽 + - 캔버스 +translation_of: Web/API/Canvas_API/Tutorial/Basic_animations +--- +<p>{{HTMLElement("canvas")}} 요소는 자바스크립트로 제어하는 것이므로, 애니메이션도 쉽게 만들 수 있습니다. 복잡한 애니메이션을 만드는 것은 추가 작업이 더 필요하고, 앞으로 그에 대한 페이지도 머지 않아 추가되기를 기대합니다.</p> +<p>도형은 한번 만들어 놓으면 그 모습 그대로 있다는 것이 애니메이션을 만들 때의 가장 큰 제약일 것입니다. 그 도형을 움직이고자 하면 그 도형뿐만이 아니라 그 도형이 그려지기 전에 그려진 모든 것을 다시 그려야 합니다. 복잡한 장면을 다시 그리는 것은 시간도 많이 걸리며, 코드를 실행하는 컴퓨터의 능력에 따라 달라집니다.</p> +<h2 id="Basic_animation_steps" name="Basic_animation_steps">기본 애니메이션 단계</h2> +<p>한 장면을 그리려면 아래와 같은 단계를 밟습니다.</p> +<ol> + <li><strong>캔버스를 비웁니다.</strong><br> + 그리려는 도형이 (배경 이미지를 만들 때처럼) 캔버스를 가득 채우는 것이 아니라면, 이전에 그려진 모든 도형을 지울 필요가 있습니다. 가장 쉬운 방법은 <code>clearRect()</code> 메소드를 사용하는 것입니다.</li> + <li><strong>캔버스 상태를 저장합니다.</strong><br> + 캔버스 상태에 영향을 주는 (스타일 변경, 모양 변형 등의) 설정값을 바꾸려고 하고, 바뀐 값을 각 장면마다 사용하려고 한다면, 원래 상태를 저장할 필요가 있습니다.</li> + <li><strong>애니메이션할 도형을 그립니다.</strong><br> + 실제 장면을 그리는 단계입니다.</li> + <li><strong>캔버스 상태를 복원합니다.</strong><br> + 새로운 장면을 그리기 전에 저장된 상태를 복원합니다.</li> +</ol> +<h2 id="Controlling_an_animation" name="Controlling_an_animation">애니메이션 제어하기</h2> +<p>캔버스 메소드를 사용하거나 사용자 함수를 사용하여 캔버스에 도형들을 그립니다. 보통의 경우에서는, 코드 실행이 완료되면 캔버스에 나타나는 결과만을 보게 됩니다. 예를 들어, <code>for</code> 반복문 안에서 애니메이션을 실행하는 것은 불가능합니다.</p> +<p>그래서 정해진 시간마다 그리기 함수를 실행하는 방법이 필요한 것입니다. 아래와 같이 애니메이션을 제어하는 두 가지 방법이 있습니다.</p> +<h3 id="예정된_변경">예정된 변경</h3> +<p>정해진 시간마다 특정 함수를 부를 때 사용할 수 있는 {{domxref("window.setInterval()")}}과 {{domxref("window.setTimeout()")}} 함수가 있습니다.</p> +<div class="note"> + <p>알아둘 것: 현재는 애니메이션을 만드는 방법으로 {{domxref("window.requestAnimationFrame()")}} 메소드를 추천합니다. 이에 대한 튜토리얼은 곧 업데이트할 것입니다.</p> +</div> +<dl> + <dt> + <code>setInterval(<em>function</em>, <em>delay</em>)</code></dt> + <dd> + <code>delay</code> 밀리세컨드(1,000분의 1초)마다 <code>function</code> 함수 반복 실행을 시작합니다.</dd> + <dt> + <code>setTimeout(<em>function</em>, <em>delay</em>)</code></dt> + <dd> + <code>delay</code> 밀리세컨드(1,000분의 1초) 경과후, <code>function</code> 함수를 실행합니다.</dd> +</dl> +<p>사용자의 제어를 <strong>필요로 하지 않는</strong> 반복 실행에는 <code>setInterval()</code> 함수가 알맞을 것입니다.</p> +<h3 id="사용자_상호_작용_변경">사용자 상호 작용 변경</h3> +<p>애니메이션을 제어하는 두번째 방법은 사용자 입력입니다. 게임을 만들려고 한다면, 애니메이션을 제어하기 위해 키보드나 마우스 이벤트를 사용할 수 있을 것입니다. {{domxref("EventListener")}}를 설정하여, 사용자와 상호 작용하여 애니메이션 함수를 실행합니다.</p> +<p>사용자 상호 작용이 <strong>필요하다면</strong>, 우리가 만든 <a href="/en-US/docs/JavaScript/Timers/Daemons" title="/en-US/docs/JavaScript/Timers/Daemons">애니메이션용 프레임웍(framework)</a>의 <a href="/en-US/docs/DOM/window.setInterval#A_little_framework" title="/en-US/docs/DOM/window.setInterval#A_little_framework">최소 기능 버전</a> 또는 <a href="/en-US/docs/JavaScript/Timers/Daemons" title="/en-US/docs/JavaScript/Timers/Daemons">최대 기능 버전</a>을 사용할 수 있을 것입니다.</p> +<pre>var myAnimation = new MiniDaemon(null, animateShape, 500, Infinity);</pre> +<p>또는</p> +<pre>var myAnimation = new Daemon(null, animateShape, 500, Infinity);</pre> +<p>아래 예제에서는, 애니메이션을 제어하기 위해 {{domxref("window.setInterval()")}}을 사용할 것입니다. 페이지 제일 아래쪽에 {{domxref("window.setTimeout()")}}을 사용한 예제 링크도 있습니다.</p> +<h4 id="태양계_애니메이션">태양계 애니메이션</h4> +<p>이 예제에서는 달이 지구를 돌고 지구가 태양을 도는 애니메이션을 만듭니다.</p> +<pre class="brush: js">var sun = new Image(); +var moon = new Image(); +var earth = new Image(); +function init(){ + sun.src = 'https://mdn.mozillademos.org/files/1456/Canvas_sun.png'; + moon.src = 'https://mdn.mozillademos.org/files/1443/Canvas_moon.png'; + earth.src = 'https://mdn.mozillademos.org/files/1429/Canvas_earth.png'; + setInterval(draw,100); +} + +function draw() { + var ctx = document.getElementById('canvas').getContext('2d'); + + ctx.globalCompositeOperation = 'destination-over'; + ctx.clearRect(0,0,300,300); // 캔버스를 비운다 + + ctx.fillStyle = 'rgba(0,0,0,0.4)'; + ctx.strokeStyle = 'rgba(0,153,255,0.4)'; + ctx.save(); + ctx.translate(150,150); + + // 지구 + var time = new Date(); + ctx.rotate( ((2*Math.PI)/60)*time.getSeconds() + ((2*Math.PI)/60000)*time.getMilliseconds() ); + ctx.translate(105,0); + ctx.fillRect(0,-12,50,24); // Shadow + ctx.drawImage(earth,-12,-12); + + // 달 + ctx.save(); + ctx.rotate( ((2*Math.PI)/6)*time.getSeconds() + ((2*Math.PI)/6000)*time.getMilliseconds() ); + ctx.translate(0,28.5); + ctx.drawImage(moon,-3.5,-3.5); + ctx.restore(); + + ctx.restore(); + + ctx.beginPath(); + ctx.arc(150,150,105,0,Math.PI*2,false); // 지구 궤도 + ctx.stroke(); + + ctx.drawImage(sun,0,0,300,300); +} +</pre> +<div class="hidden"> + <pre class="brush: html"><canvas id="canvas" width="300" height="300"></canvas></pre> + <pre class="brush: js">init();</pre> +</div> +<p>{{EmbedLiveSample("An_animated_solar_system", "310", "310", "https://mdn.mozillademos.org/files/202/Canvas_animation1.png")}}</p> +<h4 id="시계_애니메이션">시계 애니메이션</h4> +<p>이 예제에서는, 현재 시각을 보여주는 움직이는 시계를 만듭니다.</p> +<pre class="brush: js">function init(){ + clock(); + setInterval(clock,1000); +} + +function clock(){ + var now = new Date(); + var ctx = document.getElementById('canvas').getContext('2d'); + ctx.save(); + ctx.clearRect(0,0,150,150); + ctx.translate(75,75); + ctx.scale(0.4,0.4); + ctx.rotate(-Math.PI/2); + ctx.strokeStyle = "black"; + ctx.fillStyle = "white"; + ctx.lineWidth = 8; + ctx.lineCap = "round"; + + // 시계판 - 시 + ctx.save(); + for (var i=0;i<12;i++){ + ctx.beginPath(); + ctx.rotate(Math.PI/6); + ctx.moveTo(100,0); + ctx.lineTo(120,0); + ctx.stroke(); + } + ctx.restore(); + + // 시계판 - 분 + ctx.save(); + ctx.lineWidth = 5; + for (i=0;i<60;i++){ + if (i%5!=0) { + ctx.beginPath(); + ctx.moveTo(117,0); + ctx.lineTo(120,0); + ctx.stroke(); + } + ctx.rotate(Math.PI/30); + } + ctx.restore(); + + var sec = now.getSeconds(); + var min = now.getMinutes(); + var hr = now.getHours(); + hr = hr>=12 ? hr-12 : hr; + + ctx.fillStyle = "black"; + + // 시간 표시 - 시 + ctx.save(); + ctx.rotate( hr*(Math.PI/6) + (Math.PI/360)*min + (Math.PI/21600)*sec ) + ctx.lineWidth = 14; + ctx.beginPath(); + ctx.moveTo(-20,0); + ctx.lineTo(80,0); + ctx.stroke(); + ctx.restore(); + + // 시간 표시 - 분 + ctx.save(); + ctx.rotate( (Math.PI/30)*min + (Math.PI/1800)*sec ) + ctx.lineWidth = 10; + ctx.beginPath(); + ctx.moveTo(-28,0); + ctx.lineTo(112,0); + ctx.stroke(); + ctx.restore(); + + // 시간 표시 - 초 + ctx.save(); + ctx.rotate(sec * Math.PI/30); + ctx.strokeStyle = "#D40000"; + ctx.fillStyle = "#D40000"; + ctx.lineWidth = 6; + ctx.beginPath(); + ctx.moveTo(-30,0); + ctx.lineTo(83,0); + ctx.stroke(); + ctx.beginPath(); + ctx.arc(0,0,10,0,Math.PI*2,true); + ctx.fill(); + ctx.beginPath(); + ctx.arc(95,0,10,0,Math.PI*2,true); + ctx.stroke(); + ctx.fillStyle = "rgba(0,0,0,0)"; + ctx.arc(0,0,3,0,Math.PI*2,true); + ctx.fill(); + ctx.restore(); + + ctx.beginPath(); + ctx.lineWidth = 14; + ctx.strokeStyle = '#325FA2'; + ctx.arc(0,0,142,0,Math.PI*2,true); + ctx.stroke(); + + ctx.restore(); +}</pre> +<div class="hidden"> + <pre class="brush: html"><canvas id="canvas" width="150" height="150"></canvas></pre> + <pre class="brush: js">init();</pre> +</div> +<p>{{EmbedLiveSample("An_animated_clock", "180", "180", "https://mdn.mozillademos.org/files/203/Canvas_animation2.png")}}</p> +<h4 id="움직이는_파노라마_사진">움직이는 파노라마 사진</h4> +<p>이 예제에서는, 움직이는 파노라마 사진을 만듭니다. 사용할 그림은 위키피디어(Wikipedia)에서 구한 <a href="http://commons.wikimedia.org/wiki/File:Capitan_Meadows,_Yosemite_National_Park.jpg" title="http://commons.wikimedia.org/wiki/File:Capitan_Meadows,_Yosemite_National_Park.jpg">요세미티 국립공원</a>입니다. 캔버스보다 큰 그림을 사용할 수도 있습니다.</p> +<pre class="brush: js">var img = new Image(); + +// 변수 +// 스크롤될 이미지, 방향, 속도를 바꾸려면 변수값을 바꾼다. + +img.src = 'https://mdn.mozillademos.org/files/4553/Capitan_Meadows,_Yosemite_National_Park.jpg'; +var CanvasXSize = 800; +var CanvasYSize = 200; +var speed = 30; // 값이 작을 수록 빨라진다 +var scale = 1.05; +var y = -4.5; // 수직 옵셋 + +// 주요 프로그램 + +var dx = 0.75; +var imgW; +var imgH; +var x = 0; +var clearX; +var clearY; +var ctx; + +img.onload = function() { + imgW = img.width*scale; + imgH = img.height*scale; + if (imgW > CanvasXSize) { x = CanvasXSize-imgW; } // 캔버스보다 큰 이미지 + if (imgW > CanvasXSize) { clearX = imgW; } // 캔버스보다 큰 이미지 + else { clearX = CanvasXSize; } + if (imgH > CanvasYSize) { clearY = imgH; } // 캔버스보다 큰 이미지 + else { clearY = CanvasYSize; } + // 캔버스 요소 얻기 + ctx = document.getElementById('canvas').getContext('2d'); + // 새로 그리기 속도 설정 + return setInterval(draw, speed); +} + +function draw() { + // 캔버스를 비운다 + ctx.clearRect(0,0,clearX,clearY); + // 이미지가 캔버스보다 작거나 같다면 (If image is <= Canvas Size) + if (imgW <= CanvasXSize) { + // 재설정, 처음부터 시작 + if (x > (CanvasXSize)) { x = 0; } + // 추가 이미지 그리기 + if (x > (CanvasXSize-imgW)) { ctx.drawImage(img,x-CanvasXSize+1,y,imgW,imgH); } + } + // 이미지가 캔버스보다 크다면 (If image is > Canvas Size) + else { + // 재설정, 처음부터 시작 + if (x > (CanvasXSize)) { x = CanvasXSize-imgW; } + // 추가 이미지 그리기 + if (x > (CanvasXSize-imgW)) { ctx.drawImage(img,x-imgW+1,y,imgW,imgH); } + } + // 이미지 그리기 + ctx.drawImage(img,x,y,imgW,imgH); + // 움직임 정도 + x += dx; +} +</pre> +<p>예제에 사용된 {{HTMLElement("canvas")}}의 크기는 아래와 같다. 캔버스의 너비가 변수 <code>CanvasXSize</code>값과 같고, 캔버스의 높이는 변수 <code>CanvasYSize</code>값과 같다는 것에 주목하라.</p> +<pre class="brush: html"><canvas id="canvas" width="800" height="200"></canvas></pre> +<p><strong>Live sample</strong></p> +<p>{{EmbedLiveSample("A_looping_panorama", "830", "230")}}</p> +<h2 id="Other_examples" name="Other_examples">또 다른 예제들</h2> +<dl> + <dt> + <a class="external" href="http://www.gartic.net/" title="http://www.gartic.net/">Gartic</a></dt> + <dd> + 다중 사용자 지원 그리기 놀이.</dd> + <dt> + <a class="external" href="http://www.abrahamjoffe.com.au/ben/canvascape/">Canvascape</a></dt> + <dd> + 3D 어드벤처 게임 (1인칭 슈팅).</dd> + <dt> + <a href="/en-US/docs/Web/Guide/HTML/A_basic_ray-caster" title="/en-US/docs/Web/Guide/HTML/A_basic_ray-caster">A basic ray-caster</a></dt> + <dd> + 키보드를 사용한 애니메이션 제어 방법에 대한 좋은 예제.</dd> + <dt> + <a class="external" href="http://andrewwooldridge.com/canvas/canvasgame001/canvasgame002.html">canvas adventure</a></dt> + <dd> + 키보드 제어를 사용하는 또다른 좋은 예제.</dd> + <dt> + <a class="external" href="http://www.blobsallad.se/">An interactive Blob</a></dt> + <dd> + 물방울 갖고 놀기.</dd> + <dt> + <a class="external" href="http://arapehlivanian.com/wp-content/uploads/2007/02/canvas.html">Flying through a starfield</a></dt> + <dd> + 별, 동그라미, 네모가 떠다니는 우주를 누벼라.</dd> + <dt> + <a class="external" href="http://igrapher.com/" title="http://igrapher.com/">iGrapher</a></dt> + <dd> + 주식 시장 자료 차트 예제.</dd> +</dl> +<h2 id="이것도_보세요">이것도 보세요</h2> +<ul> + <li><a href="/en-US/docs/JavaScript/Timers" title="/en-US/docs/JavaScript/Timers">JavaScript timers</a></li> + <li><a href="/en-US/docs/DOM/window.setInterval#A_little_framework" title="/en-US/docs/DOM/window.setInterval#A_little_framework"><code>setInterval</code> – A little framework</a></li> + <li><a href="/en-US/docs/JavaScript/Timers/Daemons" title="/en-US/docs/JavaScript/Timers/Daemons">JavaScript Daemons Management</a></li> + <li><a href="/en-US/docs/DOM/HTMLCanvasElement" title="/en-US/docs/DOM/HTMLCanvasElement">HTMLCanvasElement</a></li> +</ul> +<p>{{PreviousNext("Web/Guide/HTML/Canvas_tutorial/Compositing", "Web/Guide/HTML/Canvas_tutorial/Optimizing_canvas")}}</p> diff --git a/files/ko/web/api/canvas_api/tutorial/basic_usage/index.html b/files/ko/web/api/canvas_api/tutorial/basic_usage/index.html new file mode 100644 index 0000000000..f455563e87 --- /dev/null +++ b/files/ko/web/api/canvas_api/tutorial/basic_usage/index.html @@ -0,0 +1,154 @@ +--- +title: 캔버스(Canvas) 기본 사용법 +slug: Web/HTML/Canvas/Tutorial/Basic_usage +translation_of: Web/API/Canvas_API/Tutorial/Basic_usage +--- +<div>{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial", "Web/API/Canvas_API/Tutorial/Drawing_shapes")}}</div> + +<div class="summary"> +<p>{{HTMLElement ( "canvas")}} {{Glossary ( "HTML")}} 엘리먼트를 살펴보는 것으로 이 튜토리얼을 시작해 보겠습니다. 이 페이지의 끝에서 캔버스 2D 컨텍스트를 설정하는 방법을 알게되고, 여러분의 브라우저에서 첫 번째 예제를 그리게 될 것입니다.</p> +</div> + +<h2 id="<canvas>_요소"><code><canvas></code> 요소</h2> + +<pre class="brush: html"><canvas id="tutorial" width="150" height="150"></canvas> +</pre> + +<p>{{HTMLElement ( "canvas")}}는 처음에는 src 및 alt 속성이 없다는 점만 제외하면 {{HTMLElement ( "img")}} 요소처럼 보입니다. 실제로 <code><canvas></code> 요소에는 {{htmlattrxref ( "width", "canvas")}}와 {{htmlattrxref ( "height", "canvas")}}의 두 속성만 있습니다. 이것들은 모두 선택사항이며 {{Glossary ( "DOM")}} <a href="ko/docs/Web/API/HTMLCanvasElement">프로퍼티</a>를 사용하여 설정할 수도 있습니다. width 및 height 속성을 지정하지 않으면 캔버스의 처음 너비는 <strong>300 픽셀</strong>이고 높이는 <strong>150 픽셀</strong>입니다. 요소는 {{Glossary ( "CSS")}}에 의해 임의로 크기를 정할 수 있지만 렌더링하는 동안 이미지는 레이아웃 크기에 맞게 크기가 조정됩니다. CSS 크기 지정이 초기 캔버스의 비율을 고려하지 않으면 왜곡되어 나타납니다 .</p> + +<div class="note"> +<p><strong>노트:</strong> 만약 렌더링이 왜곡된 것처럼 보이는 경우 CSS를 사용하지 않고 <code><canvas></code> 속성에서 <code>width</code> 및 <code>height</code> 속성을 명시적으로 지정하십시오.</p> +</div> + +<p> </p> + +<p><a href="/en-US/docs/Web/HTML/Global_attributes/id"><code>id</code></a> 속성(어트리뷰트)는 <code><canvas></code> 요소에 국한되지 않는 글로벌HTML 속성 (<a href="/en-US/docs/Web/HTML/Global_attributes">global HTML attributes</a> )중 하나로, 모든 HTML 요소에 적용 ( <code><a href="/en-US/docs/Web/HTML/Global_attributes/class">class</a></code> 등등)될 수 있습니다. 대체로 항상 <code>id</code> 속성을 사용해 주는것이 좋은데, 이는 스크립트 내에서 구분을 쉽게 해 줄 수 있기 때문입니다.</p> + +<p><code><canvas></code>요소는 일반적인 이미지 ({{cssxref("margin")}}, {{cssxref("border")}}, {{cssxref("background")}}…) 처럼 스타일을 적용시킬 수 있습니다. 하지만 이 방법은 실제 캔버스 위에 그리는 것에는 영향을 끼치지 않습니다. 이 방법이 어떻게 사용되는지는 <a href="/ko/docs/Web/API/Canvas_API/Tutorial/Applying_styles_and_colors">해당 챕터</a>에서 확인 할 수 있습니다. 캔버스에 스타일링이 따로 지정 되있지 않았다면, 캔버스 스타일은 투명으로 설정되어있습니다.</p> + +<div id="section_2"> +<h3 id="대체_콘텐츠">대체 콘텐츠</h3> + +<p><code><canvas></code> 요소는 {{HTMLElement("video")}}, {{HTMLElement("audio")}} 혹은 {{HTMLElement("picture")}}처럼 {{HTMLElement("img")}}와는 달리, 인터넷 익스플로러 9 이하의 버전이나 텍스트기반 브라우저 등과 같은, 캔버스를 지원하지 않는 오래된 브라우저들을 위한 대체 컨텐츠를 정의하기 쉽습니다. 여러분은 그러한 브라우저들을 위한 대체 컨텐츠를 제공해야 합니다.</p> + +<p>대체 컨텐츠를 제공하는 것은 매우 간단합니다. <code><canvas></code>태그 안에 대체 컨텐츠를 삽입합니다. <code><canvas></code>태그 를 지원하지 않는 브라우저는 컨테이너를 무시하고 컨테이너 내부의 대체 콘텐츠를 렌더링 합니다. <code><canvas></code>를 지원하는 브라우저는 컨테이너 내부의 내용을 무시하고 캔버스를 정상적으로 렌더링합니다.</p> + +<p>예를 들어, 캔버스 내용에 대한 텍스트 설명을 제공하거나 동적으로 렌더링 된 내용의 정적 이미지를 제공 할 수 있습니다. 이것은 다음과 같이 보일 수있습니다:</p> + +<pre class="brush: html"><canvas id="stockGraph" width="150" height="150"> + current stock price: $3.15 +0.15 +</canvas> + +<canvas id="clock" width="150" height="150"> + <img src="images/clock.png" width="150" height="150" alt=""/> +</canvas> +</pre> + +<p>사용자에게 캔버스를 지원하는 다른 브라우저를 사용하도록 하는 것은 캔버스를 해석하지 못하는 사용자에게 전혀 도움이 되지 않습니다. 유용한 대체 텍스트나 하위 DOM을 제공하는 것이 <a href="/ko/docs/Web/API/Canvas_API/Tutorial/Hit_regions_and_accessibility">캔버스에 더 쉽게 접근할수 있도록</a> 도움이 될 것입니다.</p> + +<h3 id="<canvas>_태그_필수"><code></canvas></code> 태그 필수</h3> + +<p>대체 컨텐츠가 제공되는 방식때문에, {{HTMLElement("img")}} 요소와 달리, {{HTMLElement("canvas")}} 요소는 닫는 태그(<code></canvas></code>)가 필요합니다. 닫는 태그가 없다면, 문서의 나머지 부분이 대체 컨텐츠로 간주되고 보이지 않을 것입니다.</p> + +<p>대체 컨텐츠가 필요하지 않다면, 단순히 <code><canvas id="foo" ...></canvas></code>가 모든 미지원 브라우저에서 완전하게 호환됩니다.</p> + +<h2 id="렌더링_컨텍스트">렌더링 컨텍스트</h2> + +<p>{{HTMLElement("canvas")}} 엘리먼트는 고정 크기의 드로잉 영역을 생성하고 하나 이상의 <strong>렌더링 컨텍스(rendering contexts)</strong>를 노출하여, 출력할 컨텐츠를 생성하고 다루게 됩니다. 본 튜토리얼에서는, 2D 렌더링 컨텍스트를 집중적으로 다룹니다. 다른 컨텍스트는 다른 렌더링 타입을 제공합니다. 예를 들어, <a href="https://developer.mozilla.org/ko/docs/Web/WebGL">WebGL</a>은 <a class="external" href="http://www.khronos.org/opengles/" rel="external" title="http://en.wikipedia.org/wiki/OpenGL_ES">OpenGL ES</a> 을 기반으로 하는 3D 컨텍스트를 사용합니다.</p> + +<p>캔버스는 처음에 비어있습니다. 무언가를 표시하기 위해서, 어떤 스크립트가 랜더링 컨텍스트에 접근하여 그리도록 할 필요가 있습니다. {{HTMLElement("canvas")}} 요소는 {{domxref("HTMLCanvasElement.getContext", "getContext()")}} 메서드를 이용해서, 랜더링 컨텍스트와 (렌더링 컨텍스트의) 그리기 함수들을 사용할 수 있습니다. getContext() 메서드는 렌더링 컨텍스트 타입을 지정하는 하나의 파라메터를 가집니다. 본 튜토리얼에서 다루고 있는 2D 그래픽의 경우, {{domxref("CanvasRenderingContext2D")}}을 얻기위해 <code>"2d"</code>로 지정합니다.</p> + +<pre class="brush: js">var canvas = document.getElementById('tutorial'); +var ctx = canvas.getContext('2d'); +</pre> + +<p>첫 번째 줄의 스크립트는 {{domxref ( "document.getElementById()")}} 메서드를 호출하여 {{HTMLElement ( "canvas")}} 요소를 표시할 DOM을 검색합니다. 요소가 있으면 <code>getContext()</code> 메서드를 사용하여 드로잉 컨텍스트에 액세스 할 수 있습니다.</p> + +<div id="section_5"> +<h2 id="지원여부_검사">지원여부 검사</h2> + +<p>대체 콘텐츠는 {{HTMLElement ( "canvas")}}를 지원하지 않는 브라우저에 표시됩니다. 스크립트 역시 간단하게 <code>getContext()</code> 메소드의 존재 여부를 테스트함으로써 프로그래밍 방식으로 지원하는지를 확인할 수 있습니다. 위의 코드 예제는 다음과 같이 될 수 있습니다:</p> + +<pre class="brush: js">var canvas = document.getElementById('tutorial'); + +if (canvas.getContext){ + var ctx = canvas.getContext('2d'); + // drawing code here +} else { + // canvas-unsupported code here +} +</pre> +</div> +</div> + +<h2 id="템플릿_뼈대">템플릿 뼈대</h2> + +<p>다음은 이후의 예제들에서 시작점으로 사용될 수 있는 가장 최소한의 템플릿입니다.</p> + +<div class="note"> +<p><strong>알아두기:</strong> HTML 내에 스크립트(script)를 사용하는것은 좋은 연습 방법이 아닙니다. 다음의 예시에서는 간결하게 나타내기 위해 사용 한 것입니다.</p> +</div> + +<pre class="brush: html"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"/> + <title>Canvas tutorial</title> + <script type="text/javascript"> + function draw(){ + var canvas = document.getElementById('tutorial'); + if (canvas.getContext){ + var ctx = canvas.getContext('2d'); + } + } + </script> + <style type="text/css"> + canvas { border: 1px solid black; } + </style> + </head> + <body onload="draw();"> + <canvas id="tutorial" width="150" height="150"></canvas> + </body> +</html> +</pre> + +<p>위 스크립트에 <code>draw()</code> 함수 문서가 호출되었는데, 이는 문서가 {{event("load")}} 이벤트를 수신하여 페이지 로딩이 완료될 때 한번 실행됩니다. 이 함수 혹은 이와 유사한 함수는, 페이지가 처음 로딩되는 한, {{domxref("WindowTimers.setTimeout", "window.setTimeout()")}}, {{domxref("WindowTimers.setInterval", "window.setInterval()")}}, 혹은 또 다른 이벤트 핸들러 등을 이용하여 호출될 수 있습니다.</p> + +<p>다음은 템플릿이 실제로 어떻게 실행되는지를 보여줍니다. 보이는 바와 같이, 초기에 blank 로 보여집니다.</p> + +<p>{{EmbedLiveSample("A_skeleton_template", 160, 160)}}</p> + +<h2 id="기본_예제">기본 예제</h2> + +<p>먼저 두 개의 직사각형을 그린 간단한 예제를 보도록하겠습니다. 그 중 하나는 투명도(alpha transparency)를가집니다. 나중에 이 예제가 어떻게 작동하는지 자세히 살펴 보겠습니다.</p> + +<pre class="brush: html"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"/> + <script type="application/javascript"> + function draw() { + var canvas = document.getElementById("canvas"); + if (canvas.getContext) { + var ctx = canvas.getContext("2d"); + + ctx.fillStyle = "rgb(200,0,0)"; + ctx.fillRect (10, 10, 50, 50); + + ctx.fillStyle = "rgba(0, 0, 200, 0.5)"; + ctx.fillRect (30, 30, 50, 50); + } + } + </script> + </head> + <body onload="draw();"> + <canvas id="canvas" width="150" height="150"></canvas> + </body> +</html> +</pre> + +<p>이 예제는 다음과 같습니다.</p> + +<p>{{EmbedLiveSample("A_simple_example", 160, 160, "https://mdn.mozillademos.org/files/228/canvas_ex1.png")}}</p> + +<p>{{PreviousNext("Web/API/Canvas_API/Tutorial", "Web/API/Canvas_API/Tutorial/Drawing_shapes")}}</p> diff --git a/files/ko/web/api/canvas_api/tutorial/compositing/example/index.html b/files/ko/web/api/canvas_api/tutorial/compositing/example/index.html new file mode 100644 index 0000000000..e3d74f5220 --- /dev/null +++ b/files/ko/web/api/canvas_api/tutorial/compositing/example/index.html @@ -0,0 +1,293 @@ +--- +title: 도형 합성 예제 +slug: Web/HTML/Canvas/Tutorial/Compositing/Example +tags: + - HTML5 + - 그래픽 + - 예제 + - 캔버스 +translation_of: Web/API/Canvas_API/Tutorial/Compositing/Example +--- +<div>{{CanvasSidebar}}</div> + +<p>이 샘플 프로그램에서는 여러 가지 <a href="/en-US/docs/Web/API/CanvasRenderingContext2D.globalCompositeOperation">도형 합성 방법</a>을 보여줍니다. 출력은 다음과 같습니다:</p> + +<p>{{ EmbedLiveSample('도형_합성_예제', '100%', '7250', '', 'Web/HTML/Canvas/Tutorial/Compositing/Example') }}</p> + +<h2 id="도형_합성_예제">도형 합성 예제</h2> + +<p>다음 코드에서는 프로그램의 나머지 부분에서 사용할 전역 값을 설정합니다.</p> + +<pre class="brush: js">var canvas1 = document.createElement("canvas"); +var canvas2 = document.createElement("canvas"); +var gco = [ 'source-over','source-in','source-out','source-atop', + 'destination-over','destination-in','destination-out','destination-atop', + 'lighter', 'copy','xor', 'multiply', 'screen', 'overlay', 'darken', + 'lighten', 'color-dodge', 'color-burn', 'hard-light', 'soft-light', + 'difference', 'exclusion', 'hue', 'saturation', 'color', 'luminosity' + ].reverse(); +var gcoText = [ +'기본 설정으로, 새로운 도형이 원래 도형 위에 그려집니다.', +'새로운 도형이 원래 도형과 겹치는 부분에만 그려지며, 나머지는 투명하게 설정됩니다.', +'새로운 도형이 원래 도형과 겹치지 않는 부분에만 그려집니다.', +'새로운 도형이 원래 도형과 겹치는 부분에만 그려집니다.', +'새로운 도형이 원래 도형 아래에 그려집니다.', +'원래 도형 중 새로운 도형과 겹치는 부분이 유지되며, 나머지는 투명하게 설정됩니다.', +'원래 도형 중 새로운 도형과 겹치지 않는 부분이 유지됩니다.', +'원래 도형 중 새로운 도형과 겹치는 부분만 유지됩니다. 새로운 도형은 원래 도형 아래에 그려집니다.', +'두 도형이 겹치는 곳의 색상이 두 색상값을 합한 값으로 결정됩니다.', +'새로운 도형만 그려집니다.', +'두 도형이 겹치는 곳이 투명하게 변하며, 나머지는 평범하게 그려집니다.', +'위쪽 레이어의 픽셀값이 아래쪽 레이어의 해당하는 픽셀값과 곱해지며, 결과적으로 어두운 이미지가 생성됩니다.', +'픽셀값을 뒤집고 곱한 다음 도로 뒤집습니다. 결과적으로 밝은 이미지가 생성됩니다(multiply의 반대).', +'multiply와 screen의 조합입니다. 아래쪽 레이어의 어두운 부분은 더 어두워지고, 밝은 부분은 더 밝아집니다.', +'두 레이어 중 어두운 픽셀값을 취합니다.', +'두 레이어 중 밝은 픽셀값을 취합니다.', +'아래쪽 레이어의 픽셀값을 위쪽 레이어의 뒤집힌 픽셀값으로 나눕니다.', +'아래쪽 레이어의 뒤집힌 픽셀값을 위쪽 레이어의 픽셀값으로 나누고, 그 값을 도로 뒤집습니다.', +'overlay와 같이 multiply와 screen의 조합이지만, 위아래 레이어의 순서가 바뀐 상태입니다.', +'조금 더 부드러운 hard-light입니다. 완전한 검은색/흰색에서 무조건 완전한 검은색/흰색이 나오지 않습니다.', +'한쪽 레이어의 픽셀값에서 다른 쪽 레이어의 픽셀값을 뺍니다. 빼는 순서는 결과값이 양수가 나오는 순서입니다.', +'difference와 비슷하지만 대비가 덜합니다.', +'아래쪽 레이어의 채도(chroma)와 명도(luma)를 보존하고 위쪽 레이어의 색상(hue)을 적용합니다.', +'아래쪽 레이어의 색상과 명도를 보존하고 위쪽 레이어의 채도를 적용합니다.', +'아래쪽 레이어의 명도를 보존하고 위쪽 레이어의 색상과 채도를 적용합니다.', +'아래쪽 레이어의 색상과 채도를 보존하고 위쪽 레이어의 명도를 적용합니다.' + ].reverse(); +var width = 320; +var height = 340; +</pre> + +<h3 id="메인_프로그램">메인 프로그램</h3> + +<p>페이지를 불러오고 나면 다음 코드에서 예제를 준비하고 실행합니다:</p> + +<pre class="brush: js">window.onload = function() { + // lum in sRGB + var lum = { + r: 0.33, + g: 0.33, + b: 0.33 + }; + // 캔버스 크기 변경 + canvas1.width = width; + canvas1.height = height; + canvas2.width = width; + canvas2.height = height; + lightMix() + colorSphere(); + runComposite(); + return; +}; +</pre> + +<p>또한 다음 코드의 <code>runComposite()</code>가 여러 가지 작업을 처리하며, 어려운 부분은 보조 함수를 사용합니다.</p> + +<pre class="brush: js">function createCanvas() { + var canvas = document.createElement("canvas"); + canvas.style.background = "url("+op_8x8.data+")"; + canvas.style.border = "1px solid #000"; + canvas.style.margin = "5px"; + canvas.width = width/2; + canvas.height = height/2; + return canvas; +} + +function runComposite() { + var dl = document.createElement("dl"); + document.body.appendChild(dl); + while(gco.length) { + var pop = gco.pop(); + var dt = document.createElement("dt"); + dt.textContent = pop; + dl.appendChild(dt); + var dd = document.createElement("dd"); + var p = document.createElement("p"); + p.textContent = gcoText.pop(); + dd.appendChild(p); + + var canvasToDrawOn = createCanvas(); + var canvasToDrawFrom = createCanvas(); + var canvasToDrawResult = createCanvas(); + + var ctx = canvasToDrawResult.getContext('2d'); + ctx.clearRect(0, 0, width, height) + ctx.save(); + ctx.drawImage(canvas1, 0, 0, width/2, height/2); + ctx.globalCompositeOperation = pop; + ctx.drawImage(canvas2, 0, 0, width/2, height/2); + ctx.globalCompositeOperation = "source-over"; + ctx.fillStyle = "rgba(0,0,0,0.8)"; + ctx.fillRect(0, height/2 - 20, width/2, 20); + ctx.fillStyle = "#FFF"; + ctx.font = "14px arial"; + ctx.fillText(pop, 5, height/2 - 5); + ctx.restore(); + + var ctx = canvasToDrawOn.getContext('2d'); + ctx.clearRect(0, 0, width, height) + ctx.save(); + ctx.drawImage(canvas1, 0, 0, width/2, height/2); + ctx.fillStyle = "rgba(0,0,0,0.8)"; + ctx.fillRect(0, height/2 - 20, width/2, 20); + ctx.fillStyle = "#FFF"; + ctx.font = "14px arial"; + ctx.fillText('기존 도형', 5, height/2 - 5); + ctx.restore(); + + var ctx = canvasToDrawFrom.getContext('2d'); + ctx.clearRect(0, 0, width, height) + ctx.save(); + ctx.drawImage(canvas2, 0, 0, width/2, height/2); + ctx.fillStyle = "rgba(0,0,0,0.8)"; + ctx.fillRect(0, height/2 - 20, width/2, 20); + ctx.fillStyle = "#FFF"; + ctx.font = "14px arial"; + ctx.fillText('새로운 도형', 5, height/2 - 5); + ctx.restore(); + + dd.appendChild(canvasToDrawOn); + dd.appendChild(canvasToDrawFrom); + dd.appendChild(canvasToDrawResult); + + dl.appendChild(dd); + } +}; +</pre> + +<h3 id="보조_함수">보조 함수</h3> + +<p>이 프로그램에서는 몇몇 보조 함수를 사용합니다.</p> + +<pre class="brush: js">var lightMix = function() { + var ctx = canvas2.getContext("2d"); + ctx.save(); + ctx.globalCompositeOperation = "lighter"; + ctx.beginPath(); + ctx.fillStyle = "rgba(255,0,0,1)"; + ctx.arc(100, 200, 100, Math.PI*2, 0, false); + ctx.fill() + ctx.beginPath(); + ctx.fillStyle = "rgba(0,0,255,1)"; + ctx.arc(220, 200, 100, Math.PI*2, 0, false); + ctx.fill() + ctx.beginPath(); + ctx.fillStyle = "rgba(0,255,0,1)"; + ctx.arc(160, 100, 100, Math.PI*2, 0, false); + ctx.fill(); + ctx.restore(); + ctx.beginPath(); + ctx.fillStyle = "#f00"; + ctx.fillRect(0,0,30,30) + ctx.fill(); +}; +</pre> + +<pre class="brush: js">var colorSphere = function(element) { + var ctx = canvas1.getContext("2d"); + var width = 360; + var halfWidth = width / 2; + var rotate = (1 / 360) * Math.PI * 2; // per degree + var offset = 0; // scrollbar offset + var oleft = -20; + var otop = -20; + for (var n = 0; n <= 359; n ++) { + var gradient = ctx.createLinearGradient(oleft + halfWidth, otop, oleft + halfWidth, otop + halfWidth); + var color = Color.HSV_RGB({ H: (n + 300) % 360, S: 100, V: 100 }); + gradient.addColorStop(0, "rgba(0,0,0,0)"); + gradient.addColorStop(0.7, "rgba("+color.R+","+color.G+","+color.B+",1)"); + gradient.addColorStop(1, "rgba(255,255,255,1)"); + ctx.beginPath(); + ctx.moveTo(oleft + halfWidth, otop); + ctx.lineTo(oleft + halfWidth, otop + halfWidth); + ctx.lineTo(oleft + halfWidth + 6, otop); + ctx.fillStyle = gradient; + ctx.fill(); + ctx.translate(oleft + halfWidth, otop + halfWidth); + ctx.rotate(rotate); + ctx.translate(-(oleft + halfWidth), -(otop + halfWidth)); + } + ctx.beginPath(); + ctx.fillStyle = "#00f"; + ctx.fillRect(15,15,30,30) + ctx.fill(); + return ctx.canvas; +}; +</pre> + +<pre class="brush: js">// HSV (1978) = H: Hue / S: Saturation / V: Value +Color = {}; +Color.HSV_RGB = function (o) { + var H = o.H / 360, + S = o.S / 100, + V = o.V / 100, + R, G, B; + var A, B, C, D; + if (S == 0) { + R = G = B = Math.round(V * 255); + } else { + if (H >= 1) H = 0; + H = 6 * H; + D = H - Math.floor(H); + A = Math.round(255 * V * (1 - S)); + B = Math.round(255 * V * (1 - (S * D))); + C = Math.round(255 * V * (1 - (S * (1 - D)))); + V = Math.round(255 * V); + switch (Math.floor(H)) { + case 0: + R = V; + G = C; + B = A; + break; + case 1: + R = B; + G = V; + B = A; + break; + case 2: + R = A; + G = V; + B = C; + break; + case 3: + R = A; + G = B; + B = V; + break; + case 4: + R = C; + G = A; + B = V; + break; + case 5: + R = V; + G = A; + B = B; + break; + } + } + return { + R: R, + G: G, + B: B + }; +}; + +var createInterlace = function (size, color1, color2) { + var proto = document.createElement("canvas").getContext("2d"); + proto.canvas.width = size * 2; + proto.canvas.height = size * 2; + proto.fillStyle = color1; // top-left + proto.fillRect(0, 0, size, size); + proto.fillStyle = color2; // top-right + proto.fillRect(size, 0, size, size); + proto.fillStyle = color2; // bottom-left + proto.fillRect(0, size, size, size); + proto.fillStyle = color1; // bottom-right + proto.fillRect(size, size, size, size); + var pattern = proto.createPattern(proto.canvas, "repeat"); + pattern.data = proto.canvas.toDataURL(); + return pattern; +}; + +var op_8x8 = createInterlace(8, "#FFF", "#eee");</pre> diff --git a/files/ko/web/api/canvas_api/tutorial/compositing/index.html b/files/ko/web/api/canvas_api/tutorial/compositing/index.html new file mode 100644 index 0000000000..108c493d9d --- /dev/null +++ b/files/ko/web/api/canvas_api/tutorial/compositing/index.html @@ -0,0 +1,106 @@ +--- +title: 도형 합성 +slug: Web/HTML/Canvas/Tutorial/Compositing +tags: + - HTML5 + - 그래픽 + - 캔버스 +translation_of: Web/API/Canvas_API/Tutorial/Compositing +--- +<p>이전 페이지들에서 나온 모든 예제에서, 새로 그리는 도형은 언제나 이미 그려진 도형의 위에 그려졌습니다. 대부분의 상황에서는 이렇게 하는 것이 적절하지만, 도형을 합성하기 위한 순서를 제한하게 되는데, <code>globalCompositeOperation</code> 속성을 설정함으로써 이러한 상태를 바꿀 수 있습니다.</p> + +<h2 id="globalCompositeOperation" name="globalCompositeOperation"><code>globalCompositeOperation</code></h2> + +<p>기존 도형 뒤에 새로운 도형을 그릴 수 있을 뿐만 아니라, 도형의 일정 영역을 가려 보이지 않게 하거나 캔버스의 특정 부분을 지우는 (<code>clearRect()</code> 메소드는 사각형의 영역만을 지우지만, 이같은 제한도 없다.) 등의 효과를 얻을 수도 있습니다.</p> + +<dl> + <dt><code>globalCompositeOperation = <em>type</em></code></dt> + <dd>새로운 도형을 그릴 때, 도형 합성 방법을 설정합니다. type은 다음 26종류의 합성 방법 중에서 선택할 수 있습니다.</dd> +</dl> + +<p>다음 예제의 코드를 확인하려면 <a href="/ko/docs/Web/HTML/Canvas/Tutorial/Compositing/Example">도형 합성 예제</a>를 확인해 주세요.</p> + +<p>{{ EmbedLiveSample('도형_합성_예제', 750, 6750, '', 'Web/HTML/Canvas/Tutorial/Compositing/Example') }}</p> + +<h2 id="Clipping_paths" name="Clipping_paths">잘라내기 경로(Clipping path)</h2> + +<p><img alt="" class="internal" src="https://mdn.mozillademos.org/files/209/Canvas_clipping_path.png" style="float: right;"> 잘라내기 경로는 다른 캔버스 도형과 비슷하지만, 다른 도형에서 원하지 않는 부분을 가리는 가면과 같은 역할을 합니다. 오른쪽에 있는 그림을 보면 어떤 역할을 하는지 알 수 있을 것입니다. 붉은 별 모양이 잘라내기 경로입니다. 이 경로 밖에 있는 모든 것은 캔버스에 그려지지 않을 것입니다.</p> + +<p>잘라내기 경로와 위에서 살펴본 <code>globalCompositeOperation</code> 속성을 비교해 보면, <code>source-in</code>과 <code>source-atop</code>에서 비슷한 효과가 보입니다. 이들과 잘라내기 경로와의 가장 중요한 차이점은, 잘라내기 경로 자체는 캔버스에 전혀 그려지지 않는다는 것입니다. 잘라내기 경로는 제한된 영역 안에서 여러 가지 도형을 그리는 데에 적합합니다.</p> + +<p><a href="/en-US/docs/Web/Guide/HTML/Canvas_tutorial/Drawing_shapes#Drawing_paths" title="Web/Guide/HTML/Canvas_tutorial/Drawing_shapes#Drawing_paths">캔버스에 도형 그리기</a>에서는 <code>stroke()</code>과 <code>fill()</code> 메소드만을 설명했었는데, <code>clip()</code>이라는 세 번째 메소드도 있습니다.</p> + +<dl> + <dt><code>clip()</code></dt> + <dd>현재 그려지는 경로를 현재 잘라내기 경로로 만듭니다.</dd> +</dl> + +<p>경로를 닫기 위해 <code>closePath()</code> 대신 <code>clip()</code>을 사용하고, 경로를 채우거나 윤곽선을 만드는 대신 잘라내기 경로로 만들 수 있습니다.</p> + +<p>{{HTMLElement("canvas")}} 요소의 초기 설정값으로써, 캔버스는 캔버스와 똑같은 크기의 잘라내기 경로를 가집니다. 크기가 똑같기 때문에 잘라내기 효과는 나타나지 않습니다.</p> + +<h3 id="A_clip_example" name="A_clip_example"><code>clip</code> 예제</h3> + +<p>다음 예제에서는 특정 영역의 별들만 보이도록 동그란 모양의 잘라내기 경로를 사용할 것입니다.</p> + +<pre class="brush: js">function draw() { + var ctx = document.getElementById('canvas').getContext('2d'); + ctx.fillRect(0,0,150,150); + ctx.translate(75,75); + + // 동그란 모양의 잘라내기 경로를 생성한다 + ctx.beginPath(); + ctx.arc(0,0,60,0,Math.PI*2,true); + ctx.clip(); + + // 배경을 그린다 + var lingrad = ctx.createLinearGradient(0,-75,0,75); + lingrad.addColorStop(0, '#232256'); + lingrad.addColorStop(1, '#143778'); + + ctx.fillStyle = lingrad; + ctx.fillRect(-75,-75,150,150); + + // 별을 그린다 + for (var j=1;j<50;j++){ + ctx.save(); + ctx.fillStyle = '#fff'; + ctx.translate(75-Math.floor(Math.random()*150), + 75-Math.floor(Math.random()*150)); + drawStar(ctx,Math.floor(Math.random()*4)+2); + ctx.restore(); + } + +} + +function drawStar(ctx,r){ + ctx.save(); + ctx.beginPath() + ctx.moveTo(r,0); + for (var i=0;i<9;i++){ + ctx.rotate(Math.PI/5); + if(i%2 == 0) { + ctx.lineTo((r/0.525731)*0.200811,0); + } else { + ctx.lineTo(r,0); + } + } + ctx.closePath(); + ctx.fill(); + ctx.restore(); +} +</pre> + +<div class="hidden"> +<pre class="brush: html"><canvas id="canvas" width="150" height="150"></canvas></pre> + +<pre class="brush: js">draw();</pre> +</div> + +<p>코드의 위쪽 몇 줄에서는 배경으로 캔버스 크기와 같은 검은색 네모를 그리고, 가운데로 원점을 옮깁니다. 그런 다음 호를 그리고 <code>clip()</code>을 사용하여 동그란 모양의 잘라내기 경로를 생성합니다. 캔버스 상태를 저장할 때 잘라내기 경로도 같이 저장됩니다. 이전의 잘라내기 경로를 보존하려면, 새로운 잘라내기 경로를 만들기 전에 캔버스 상태를 저장하면 됩니다.</p> + +<p>잘라내기 경로를 만든 후에 그려지는 모든 것들은, 그 경로의 안쪽에서만 보입니다. 이는 그 다음에 그려지는 선형 그라디언트에서 확실히 볼 수 있습니다. 이렇게 하고 나서, <code>drawStar()</code> 함수를 사용하여 위치와 크기가 모두 다른 50개의 별을 그립니다. 이 별들은 잘라내기 경로 안쪽에만 나타납니다.</p> + +<p>{{EmbedLiveSample("A_clip_example", "180", "180", "https://mdn.mozillademos.org/files/208/Canvas_clip.png")}}</p> + +<p>{{PreviousNext("Web/Guide/HTML/Canvas_tutorial/Transformations", "Web/Guide/HTML/Canvas_tutorial/Basic_animations")}}</p> diff --git a/files/ko/web/api/canvas_api/tutorial/drawing_shapes/index.html b/files/ko/web/api/canvas_api/tutorial/drawing_shapes/index.html new file mode 100644 index 0000000000..09df4b829d --- /dev/null +++ b/files/ko/web/api/canvas_api/tutorial/drawing_shapes/index.html @@ -0,0 +1,577 @@ +--- +title: 캔버스(canvas)를 이용한 도형 그리기 +slug: Web/HTML/Canvas/Tutorial/Drawing_shapes +tags: + - Canvas + - 그래픽 + - 중급 + - 캔버스 + - 튜토리얼 +translation_of: Web/API/Canvas_API/Tutorial/Drawing_shapes +--- +<div>{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Basic_usage", "Web/API/Canvas_API/Tutorial/Applying_styles_and_colors")}}</div> + +<div class="summary"> +<p>앞서 캔버스 환경 설정(<a href="/en-US/docs/Web/API/Canvas_API/Tutorial/Basic_usage">canvas environment</a>)을 완료 하였다면, 이제 어떻게 캔버스에 그릴수 있는지에 대하여 자세하게 알아봅시다. 이 글을 끝내고 난 후, 여러분은 어떻게 사각형, 삼각형, 선, 아치, 곡선 등 의 기본적인 도형을 그릴수 있는지 익히실 수 있을 것 입니다. 캔버스 위에 물체를 그릴 때에는 path를 사용하는것이 필수적이므로 우리는 이것이 어떻게 사용되는지 볼 것입니다.</p> +</div> + +<h2 id="그리드">그리드</h2> + +<p><img alt="" class="internal" src="https://mdn.mozillademos.org/files/224/Canvas_default_grid.png" style="float: right; height: 220px; width: 220px;">드로잉을 시작 하기에 앞서, 캔버스 그리드 혹은 좌표공간 (<strong>coordinate space) </strong>에 대하여 이야기 해보겠습니다. 이전 페이지에서 이야기 했던 HTML 골격(skeleton)는 가로 세로 각각 150 픽셀의 캔버스 요소를 가지고 있습니다. 오른쪽에 보시면, 캔버스와 기본 그리드가 놓인것을 보실 수 있습니다. 기본적으로 그리드의 1단위는 캔버스의 1픽셀과 같습니다. 이 그리드의 원점은 좌측상단의 (0,0) 입니다. 모든 요소들은 이 원점을 기준으로 위치됩니다. 그렇기 때문에, 파란 사각형의 좌측상단은 왼쪽에서 x 픽셀, 위에서 y 픽셀 떨어진 것이라 볼 수 있고, 이 사각형의 좌표는 (x,y)가 됩니다. 이 튜토리얼 후반부에서 어떻게 원점을 이동하며, 그리드를 회전하고 같은 비율로 확대/축소할 수 있는지 살펴볼 것이지만, 지금은 기본에 충실하도록 합시다.</p> + +<h2 id="직사각형_그리기">직사각형 그리기</h2> + +<p>{{Glossary("SVG")}} 와는 다르게, {{HTMLElement("canvas")}}는 오직 하나의 원시적인 도형만을 제공합니다. 바로 <u>직사각형</u> 입니다. 다른 모든 도형들은 무조건 하나 혹은 하나 이상의 path 와 여러 점으로 이어진 선으로 만들어집니다. 다행히도, 우리는 여러 path drawing 함수(function)들을 통해 아주 어려운 도형들도 그릴수 있습니다.</p> + +<p>첫번째로, 직사각형을 봅시다. 캔버스 위에 직사각형을 그리는데에는 세가지 함수(function)가 있습니다:</p> + +<dl> + <dt>{{domxref("CanvasRenderingContext2D.fillRect", "fillRect(x, y, width, height)")}}</dt> + <dd>색칠된 직사각형을 그립니다.</dd> + <dt>{{domxref("CanvasRenderingContext2D.strokeRect", "strokeRect(x, y, width, height)")}}</dt> + <dd>직사각형 윤곽선을 그립니다.</dd> + <dt>{{domxref("CanvasRenderingContext2D.clearRect", "clearRect(x, y, width, height)")}}</dt> + <dd>특정 부분을 지우는 직사각형이며, 이 지워진 부분은 완전히 투명해집니다.</dd> +</dl> + +<p>각각의 세 함수는 모두 같은 변수를 가집니다. <code>x</code>와 <code>y</code>는 캔버스의 좌측상단에서 사각형의 (원점으로부터 상대적인) 위치를 뜻하며, <code>width</code> 와 <code>height</code>는 사각형의 크기를 뜻하게 됩니다.</p> + +<p>전 페이지에서 보여드렸던 <code>draw()</code> 함수(function)를 이용하여 위의 세가지 함수를 아래의 예제에 적용해 보았습니다.</p> + +<h3 id="직사각형_도형_예제">직사각형 도형 예제</h3> + +<div class="hidden"> +<pre class="brush: html"><html> + <body onload="draw();"> + <canvas id="canvas" width="150" height="150"></canvas> + </body> +</html> +</pre> +</div> + +<pre class="brush: js">function draw() { + var canvas = document.getElementById('canvas'); + if (canvas.getContext) { + var ctx = canvas.getContext('2d'); + + ctx.fillRect(25, 25, 100, 100); + ctx.clearRect(45, 45, 60, 60); + ctx.strokeRect(50, 50, 50, 50); + } +}</pre> + +<p>위 예제의 결과는 다음과 같습니다.</p> + +<p>{{EmbedLiveSample("Rectangular_shape_example", 160, 160, "https://mdn.mozillademos.org/files/245/Canvas_rect.png")}}</p> + +<p><code>fillRect()</code> 함수는 가로 세로 100 픽셀 사이즈의 검정 사각형을 그립니다. 이후 <code>clearRect()</code> 함수가 60x60 픽셀의 사각형 크기로 도형 중앙을 지우게 되고, <code>strokeRect()</code>은 이 빈 사각형 공간 안에 50x50 픽셀 사이즈의 윤곽선만 있는 사각형을 만들게 됩니다.</p> + +<p>다음 페이지에서, 우리는 <code>clearRect()</code>를 대신하는 두개의 함수에 대해 살펴보고, 만들어진 도형의 색이나 <font face="Open Sans, Arial, sans-serif">윤곽선의 스타일을 </font>바꾸는 방법들에 대하여 알아보도록 하겠습니다.</p> + +<p>우리가 다음 섹션에서 보게될 path 함수와 다르게 세개의 직사각형 함수는 캔버스에 바로 그릴 수 있습니다.</p> + +<h2 id="경로_그리기">경로 그리기</h2> + +<p><em>경로(path)</em>는 직사각형 이외의 유일한 원시적인(primitive) 도형입니다. 경로는 점들의 집합이며, 선의 한 부분으로 연결되어 여러가지 도형, 곡선을 이루고 두께와 색을 나타내게 됩니다. 경로나 하위 경로(sub-path)는 닫힐 수 있습니다. 경로를 이용하여 도형을 만들 때에는 몇가지 추가적인 단계를 거쳐야 합니다:</p> + +<ol> + <li>경로를 생성합니다.</li> + <li><a href="/ko/docs/Web/API/CanvasRenderingContext2D#Paths">그리기 명령어</a>를 사용하여 경로상에 그립니다.</li> + <li>경로가 한번 만들어졌다면, 경로를 렌더링 하기 위해서 윤곽선을 그리거나 도형 내부를 채울수 있습니다.</li> +</ol> + +<p>다음은 위의 단계들을 실행하기 위해 사용되는 함수입니다:</p> + +<dl> + <dt>{{domxref("CanvasRenderingContext2D.beginPath", "beginPath()")}}</dt> + <dd>새로운 경로를 만듭니다. 경로가 생성됬다면, 이후 그리기 명령들은 경로를 구성하고 만드는데 사용하게 됩니다.</dd> + <dt>Path 메소드 (<a href="/en-US/docs/Web/API/CanvasRenderingContext2D#Paths">Path methods</a>)</dt> + <dd>물체를 구성할 때 필요한 여러 경로를 설정하는데 사용하는 함수입니다.</dd> + <dt>{{domxref("CanvasRenderingContext2D.closePath", "closePath()")}}</dt> + <dd>현재 하위 경로의 시작 부분과 연결된 직선을 추가합니다.</dd> + <dt>{{domxref("CanvasRenderingContext2D.stroke", "stroke()")}}</dt> + <dd>윤곽선을 이용하여 도형을 그립니다.</dd> + <dt>{{domxref("CanvasRenderingContext2D.fill", "fill()")}}</dt> + <dd>경로의 내부를 채워서 내부가 채워진 도형을 그립니다.</dd> +</dl> + +<p>경로를 만들기 위한 첫번째 단계는 <code>beginPath()</code> 메소드를 사용하는 것 입니다. 내부적으로, 경로는 도형을 이루는 하위경로(선, 아치 등)들의 집합으로 이루어져있습니다. 이 메소드가 호출될 때 마다, 하위 경로의 모음은 초기화되며, 우리는 새로운 도형을 그릴 수 있게 됩니다.</p> + +<div class="note"><strong>참고:</strong> 현재 열린 path가 비어있는 경우 ( <code>beginPath()</code> 메소드를 사용한 직 후, 혹은캔버스를 새로 생성한 직후), 첫 경로 생성 명령은 실제 동작에 상관 없이 <code>moveTo()</code>로 여겨지게 됩니다. 그렇기 때문에 경로를 초기화한 직후에는 항상 명확하게 시작 위치를 설정해 두는것이 좋습니다.</div> + +<p>두번째 단계는 실제로 경로가 그려지는 위치를 설정하는 메소드를 호출하는 것 입니다. 이 내용에 대해서는 곧 보실수 있습니다.</p> + +<p>세번째 단계는 선택사항으로 <code>closePath()</code> 메소드를 호출하는 것 입니다. 이 메소드는 현재 점 위치와 시작점 위치를 직선으로 이어서 도형을 닫습니다. 이미 도형이 닫혔거나 한 점만 존재한다면, 이 메소드는 아무것도 하지 않습니다.</p> + +<div class="note"><strong>참고:</strong> <code>fill()</code> 메소드 호출 시, 열린 도형은 자동으로 닫히게 되므로 <code>closePath()</code>메소드를 호출하지 않아도 됩니다. 이것은 <code>stroke()</code> 메소드에는 <strong>적용되지 않습니다</strong>.</div> + +<h3 id="삼각형_그리기">삼각형 그리기</h3> + +<p>예를 들어, 삼각형을 그리기 위한 코드는 다음과 같습니다:</p> + +<div class="hidden"> +<pre class="brush: html"><html> + <body onload="draw();"> + <canvas id="canvas" width="100" height="100"></canvas> + </body> +</html> +</pre> +</div> + +<pre class="brush: js">function draw() { + var canvas = document.getElementById('canvas'); + if (canvas.getContext) { + var ctx = canvas.getContext('2d'); + + ctx.beginPath(); + ctx.moveTo(75, 50); + ctx.lineTo(100, 75); + ctx.lineTo(100, 25); + ctx.fill(); + } +} +</pre> + +<p>위 코드의 실행 결과는 다음과 같습니다:</p> + +<p>{{EmbedLiveSample("Drawing_a_triangle", 110, 110, "https://mdn.mozillademos.org/files/9847/triangle.png")}}</p> + +<h3 id="펜(pen)_이동하기">펜(pen) 이동하기</h3> + +<p>가장 유용한 함수중에 실제로 어떤 것도 그리지 않지만 위에서 언급한 경로의 일부가 되는 <code>moveTo()</code> 함수가 있습니다. 이는 펜이나 연필을 종이위에서 들어 옆으로 옮기는것이라고 보시면 됩니다.</p> + +<dl> + <dt>{{domxref("CanvasRenderingContext2D.moveTo", "moveTo(x, y)")}}</dt> + <dd>펜을 x와 y 로 지정된 좌표로 옮깁니다.</dd> +</dl> + +<p>캔버스가 초기화 되었거나 <code>beginPath()</code> 메소드가 호출되었을 때, 특정 시작점 설정을 위해 <code>moveTo()</code> 함수를 사용하는것이 좋습니다. 또한 <code>moveTo()</code> 함수는 연결되지 않은 경로를 그리는데에도 사용 할 수 있습니다. 아래의 스마일 아이콘을 봅시다.</p> + +<p>코드 snippet을 사용해하여 직접 시도하여 보세요. 앞에서 보았던 <code>draw()</code> 함수(function)를 붙혀넣기 해 보세요.</p> + +<div class="hidden"> +<pre class="brush: html"><html> + <body onload="draw();"> + <canvas id="canvas" width="150" height="150"></canvas> + </body> +</html> +</pre> +</div> + +<pre class="brush: js;highlight:[8,10,12]">function draw() { + var canvas = document.getElementById('canvas'); + if (canvas.getContext) { + var ctx = canvas.getContext('2d'); + + ctx.beginPath(); + ctx.arc(75, 75, 50, 0, Math.PI * 2, true); // Outer circle + ctx.moveTo(110, 75); + ctx.arc(75, 75, 35, 0, Math.PI, false); // Mouth (clockwise) + ctx.moveTo(65, 65); + ctx.arc(60, 65, 5, 0, Math.PI * 2, true); // Left eye + ctx.moveTo(95, 65); + ctx.arc(90, 65, 5, 0, Math.PI * 2, true); // Right eye + ctx.stroke(); + } +} +</pre> + +<p>결과는 다음과 같습니다:</p> + +<p>{{EmbedLiveSample("Moving_the_pen", 160, 160, "https://mdn.mozillademos.org/files/252/Canvas_smiley.png")}}</p> + +<p> <code>moveTo()</code>를 사용한 코드라인을 지우면 연결된 선들을 확인 할 수 있습니다</p> + +<div class="note"> +<p><strong>참고:</strong> <code>arc()</code> function에 대하여 더 알아보고 싶다면 아래의 {{anch("Arcs")}} 를 확인하세요.</p> +</div> + +<h3 id="선">선</h3> + +<p>직선을 그리기 위해서는 <code>lineTo()</code> 메소드를 사용할 수 있습니다.</p> + +<dl> + <dt>{{domxref("CanvasRenderingContext2D.lineTo", "lineTo(x, y)")}}</dt> + <dd>현재의 드로잉 위치에서 x와 y로 지정된 위치까지 선을 그립니다.</dd> +</dl> + +<p>이 메소드는 선의 끝점의 좌표가 되는 x와 y의 두개의 인자가 필요합니다. 시작점은 이전에 그려진 경로에 의해 결정 되며, 이전 경로의 끝점이 다음 그려지는 경로의 시작점이 됩니다. 또한 시작점은 <code>moveTo()</code> 메소드를 통해 변경될 수 있습니다.</p> + +<p>아래의 예시는 하나의 두 삼각형 (윤곽선 삼각형, 색칠된 삼각형)을 그립니다.</p> + +<div class="hidden"> +<pre class="brush: html"><html> + <body onload="draw();"> + <canvas id="canvas" width="150" height="150"></canvas> + </body> +</html> +</pre> +</div> + +<pre class="brush: js;highlight[9,10,16,17]">function draw() { + var canvas = document.getElementById('canvas'); + if (canvas.getContext) { + var ctx = canvas.getContext('2d'); + + // Filled triangle + ctx.beginPath(); + ctx.moveTo(25, 25); + ctx.lineTo(105, 25); + ctx.lineTo(25, 105); + ctx.fill(); + + // Stroked triangle + ctx.beginPath(); + ctx.moveTo(125, 125); + ctx.lineTo(125, 45); + ctx.lineTo(45, 125); + ctx.closePath(); + ctx.stroke(); + } +} +</pre> + +<p>새로운 경로를 지정하기 위해 <code>beginPath()</code> 메소드를 먼저 실행합니다. 그 다음 <code>moveTo()</code> 메소드를 가지고 시작점을 원하는 위치로 새롭게 지정 해 줍니다. 다음은, 두선을 그어 삼각형의 두 면을 그려줍니다.</p> + +<p>{{EmbedLiveSample("Lines", 160, 160, "https://mdn.mozillademos.org/files/238/Canvas_lineTo.png")}}</p> + +<p>여러분은 채워진 삼각형과 윤곽선 삼각형의 차이를 확인 하셨을 겁니다. 위에 언급했던 것 처럼, 경로가 채워지게 되면 그 도형은 자동으로 닫히게 되지만 윤곽선 삼각형에서는 그렇지 않기 때문입니다. 만약에 <code>closePath()</code> 메소드를 윤곽선 삼각형 코드에서 지운다면, 오직 두 선만 그려지게 되며 완벽한 삼각형으로 만들어지지 않습니다.</p> + +<h3 id="호(arc)">호(arc)</h3> + +<p>호나 원을 그리기위해서는 <code>arc()</code> 혹은 <code>arcTo()</code> 메소드를 사용합니다..</p> + +<dl> + <dt>{{domxref("CanvasRenderingContext2D.arc", "arc(x, y, radius, startAngle, endAngle, anticlockwise)")}}</dt> + <dd><em>(x, y)</em> 위치에 원점을 두면서, 반지름 r을 가지고, <em>startAngle</em> 에서 시작하여 <em>endAngle </em>에서 끝나며 주어진 <em>anticlockwise</em> 방향으로 향하는 (기본값은 시계방향 회전) 호를 그리게 됩니다.</dd> + <dt>{{domxref("CanvasRenderingContext2D.arcTo", "arcTo(x1, y1, x2, y2, radius)")}}</dt> + <dd>주어진 제어점들과 반지름으로 호를 그리고, 이전 점과 직선으로 연결합니다.</dd> +</dl> + +<p><code>arc</code> 메소드의 여섯개의 매개변수에 대하여 좀 더 자세하게 알아봅시다: <code>x</code> 와 <code>y</code>는 호를 그릴 때 필요한 원점 좌표입니다. 반지름(<code>radius</code>) 은 말 그대로 호의 반지름을 뜻합니다. <code>startAngle</code> 및 <code>endAngle</code> 매개 변수는 원의 커브를 따라 호의 시작점과 끝점을 라디안 단위로 정의합니다. 이 변수들은 x축을 기준으로 계산됩니다. Boolean 값을 가지는 <code>anticlockwise</code> 변수는 <code>true</code>일 때 호를 반시계 방향으로 그리게 되며, 그렇지 않을 경우에는 시계 방향으로 그리게 됩니다.</p> + +<div class="note"> +<p><strong>참고</strong>: <code>arc</code> 함수에서 각도는 각이 아닌 라디안 값을 사용합니다. 각도를 라디안으로 바꾸려면 다음의 자바스크립트(JavaScript) 코드를 사용하실 수 있습니다: <code>radians = (Math.PI/180)*degrees</code>.</p> +</div> + +<p>다음의 예제는 우리가 이제껏 봐 왔던 예제들 보다 약간 더 복잡합니다. 이 예제는 12가지의 다양한 각도로 채워진 각기 다른 호를 그립니다.</p> + +<p>두개의 <a href="/en-US/docs/Web/JavaScript/Reference/Statements/for"><code>for</code> loops</a>은 루프를 통해 호(arc)들의 행과 열을 읽기 위해 사용되었습니다. <code>beginPath()</code>를 사용해 각 호의 새로운 경로를 만듭니다. 코드 내에서, 각각의 매개변수들을 명확하게 보여주기 위해 변수로 정의 하였지만, 실제로 사용할때 꼭 필요한 것은 아닙니다.</p> + +<p><code>x</code>와 <code>y</code> 좌표는 충분히 명확하게 표기되어야 합니다. <code>radius</code> 와 <code>startAngle</code>은 고정되어 있습니다. <code>endAngle</code>는 처음 180도 (반원) 에서 시작하고 이후 매번 90도씩 증가하다가 마지막 열에서 완벽한 원을 그립니다.</p> + +<p><code>clockwise</code> 매개 변수를 지정한 결과로 첫번째와 세번째 줄은 시계방향으로 원호들이 그려졌고 두번째와 네번째 줄에는 반시계방향의 원호들이 그려졌습니다. 마지막으로 <code>if</code> 문은 위 반쪽이 윤곽선으로, 아래 반쪽이 색으로 채워진 호들을 만들어 냅니다.</p> + +<div class="note"> +<p><strong>참고:</strong> 이 예제는 다른 예제들 보다 더 큰사이즈의 캔버스가 필요합니다: 150 x 200 픽셀</p> +</div> + +<div class="hidden"> +<pre class="brush: html"><html> + <body onload="draw();"> + <canvas id="canvas" width="150" height="200"></canvas> + </body> +</html> +</pre> +</div> + +<pre class="brush: js;highlight[16]">function draw() { + var canvas = document.getElementById('canvas'); + if (canvas.getContext) { + var ctx = canvas.getContext('2d'); + + for (var i = 0; i < 4; i++) { + for (var j = 0; j < 3; j++) { + ctx.beginPath(); + var x = 25 + j * 50; // x coordinate + var y = 25 + i * 50; // y coordinate + var radius = 20; // Arc radius + var startAngle = 0; // Starting point on circle + var endAngle = Math.PI + (Math.PI * j) / 2; // End point on circle + var anticlockwise = i % 2 == 0 ? false : true; // clockwise or anticlockwise + + ctx.arc(x, y, radius, startAngle, endAngle, anticlockwise); + + if (i > 1) { + ctx.fill(); + } else { + ctx.stroke(); + } + } + } + } +} +</pre> + +<p>{{EmbedLiveSample("Arcs", 160, 210, "https://mdn.mozillademos.org/files/204/Canvas_arc.png")}}</p> + +<h3 id="베지어(Bezier)_곡선과_이차(Quadratic_)곡선">베지어(Bezier) 곡선과 이차(Quadratic )곡선</h3> + +<p>다음 경로 타입은 베지어 곡선 (<a class="external" href="https://ko.wikipedia.org/wiki/%EB%B2%A0%EC%A7%80%EC%97%90_%EA%B3%A1%EC%84%A0" rel="external" title="http://en.wikipedia.org/wiki/B%C3%A9zier_curve">Bézier curves</a>)으로, 삼차(cubic)와 이차(quadric) 변수가 모두 가능합니다. 이 타입은 대게 복잡한 유기체적 형태 (organic shape)를 그리는데 사용됩니다.</p> + +<dl> + <dt>{{domxref("CanvasRenderingContext2D.quadraticCurveTo", "quadraticCurveTo(cp1x, cp1y, x, y)")}}</dt> + <dd><code>cp1x</code> 및 <code>cp1y</code>로 지정된 제어점을 사용하여 현재 펜의 위치에서 <code>x</code>와 <code>y</code>로 지정된 끝점까지 이차 베지어 곡선을 그립니다.</dd> + <dt>{{domxref("CanvasRenderingContext2D.bezierCurveTo", "bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)")}}</dt> + <dd>(<code>cp1x</code>, <code>cp1y</code>) 및 (cp2x, cp2y)로 지정된 제어점을 사용하여 현재 펜 위치에서 <code>x</code> 및 <code>y</code>로 지정된 끝점까지 삼차 베지어 곡선을 그립니다.</dd> +</dl> + +<p><img alt="" class="internal" src="https://mdn.mozillademos.org/files/223/Canvas_curves.png" style="float: right; height: 190px; width: 190px;">오른쪽의 사진은 두 곡선의 차이를 가장 잘 설명해주고 있습니다. 이차 베지에 곡선은 시작점과 끝점 (파란색 점) 그리고 하나의 <strong>제어점</strong> (control point, 빨간 점으로 표시)을 가지고 있지만, 삼차 베지에 곡선은 두개의 제어점을 사용하고 있습니다.</p> + +<p>두 메소드에 모두 사용되는 <code>x</code>와 <code>y</code> 변수는 모두 끝점의 좌표를 나타냅니다. 첫번째 제어점은 <code>cp1x</code> 와 <code>cp1y</code> 좌표로, 두번째 제어점은 <code>cp2x</code> 와 <code>cp2y</code> 좌표로 표시되었습니다.</p> + +<p>이차 및 삼차 베지어 곡선을 사용하는 것은 매우 어려울 수 있습니다. Adobe Illustrator와 같은 벡터 드로잉 소프트웨어와는 달리, 우리는 현재 수행중인 작업에 대해 직접적인 시각적 피드백을 받을 수 없기 때문입니다. 이런 점은 복잡한 모양을 그리기 어렵도록 합니다. 다음 예제에서 우리는 간단한 유기체적 형태만 그리도록 하겠지만, 여러분이 연습과 시간을 투자 하신다면, 이후에 더욱 복잡한 도형을 그릴수 있게 될 것입니다.</p> + +<p>이 예제는 아주 어려운 점은 없습니다. 두 경우 모두 연속된 곡선이 그려지면서 최종 모양이 완성됩니다.</p> + +<h4 id="이차_베지에_곡선(Quadratic_Bezier_curves)">이차 베지에 곡선(Quadratic Bezier curves)</h4> + +<p>이 예제는 여러개의 이차 베지어 곡선을 이용해 말풍선을 만들어 냅니다.</p> + +<div class="hidden"> +<pre class="brush: html"><html> + <body onload="draw();"> + <canvas id="canvas" width="150" height="150"></canvas> + </body> +</html> +</pre> +</div> + +<pre class="brush: js;highlight[9,10,11,12,13,14]">function draw() { + var canvas = document.getElementById('canvas'); + if (canvas.getContext) { + var ctx = canvas.getContext('2d'); + + // Quadratric curves example + ctx.beginPath(); + ctx.moveTo(75, 25); + ctx.quadraticCurveTo(25, 25, 25, 62.5); + ctx.quadraticCurveTo(25, 100, 50, 100); + ctx.quadraticCurveTo(50, 120, 30, 125); + ctx.quadraticCurveTo(60, 120, 65, 100); + ctx.quadraticCurveTo(125, 100, 125, 62.5); + ctx.quadraticCurveTo(125, 25, 75, 25); + ctx.stroke(); + } +} +</pre> + +<p>{{EmbedLiveSample("Quadratic_Bezier_curves", 160, 160, "https://mdn.mozillademos.org/files/243/Canvas_quadratic.png")}}</p> + +<h4 id="삼차_베지어_곡선_(Cubic_Bezier_curves)">삼차 베지어 곡선 (Cubic Bezier curves)</h4> + +<p>이 예제는 삼차 곡선을 이용하여 하트를 그립니다.</p> + +<div class="hidden"> +<pre class="brush: html"><html> + <body onload="draw();"> + <canvas id="canvas" width="150" height="150"></canvas> + </body> +</html> +</pre> +</div> + +<pre class="brush: js;highlight[9,10,11,12,13,14]">function draw() { + var canvas = document.getElementById('canvas'); + if (canvas.getContext) { + var ctx = canvas.getContext('2d'); + + // Cubic curves example + ctx.beginPath(); + ctx.moveTo(75, 40); + ctx.bezierCurveTo(75, 37, 70, 25, 50, 25); + ctx.bezierCurveTo(20, 25, 20, 62.5, 20, 62.5); + ctx.bezierCurveTo(20, 80, 40, 102, 75, 120); + ctx.bezierCurveTo(110, 102, 130, 80, 130, 62.5); + ctx.bezierCurveTo(130, 62.5, 130, 25, 100, 25); + ctx.bezierCurveTo(85, 25, 75, 37, 75, 40); + ctx.fill(); + } +} +</pre> + +<p>{{EmbedLiveSample("Cubic_Bezier_curves", 160, 160, "https://mdn.mozillademos.org/files/207/Canvas_bezier.png")}}</p> + +<h3 id="직사각형">직사각형</h3> + +<p>직사각형을 캔버스에 직접 그리는 {{anch("직사각형 그리기")}}에서 본 세 가지 메소드 외에 <code>rect()</code> 메소드도 있습니다. 이 메소드는 현재 열린 패스에 직사각형 경로를 추가합니다.</p> + +<dl> + <dt>{{domxref("CanvasRenderingContext2D.rect", "rect(x, y, width, height)")}}</dt> + <dd>좌측상단이 (x, y)이고 폭과 높이가 <code>width</code>와 <code>height</code>인 직사각형을 그립니다.</dd> +</dl> + +<p>이 메소드가 실행되기 전에, (x,y) 매개변수를 가진 <code>moveTo()</code> 메소드가 자동으로 호출됩니다. 즉, 현재의 펜위치가 자동으로 기본 좌표로 초기화 됩니다.</p> + +<h3 id="조합하기">조합하기</h3> + +<p>이제까지 이 페이지의 예제들은 각각의 도형마다 하나의 path 함수를 가지고 있었습니다. 하지만 도형을 만드는데에 사용되는 경로의 종류와 개수는 제한이 없습니다. 그렇기 때문에 이 마지막 예제에서는 모든 경로 함수를 합쳐 여러 게임 캐릭터들을 그려보도록 하겠습니다.</p> + +<div class="hidden"> +<pre class="brush: html"><html> + <body onload="draw();"> + <canvas id="canvas" width="150" height="150"></canvas> + </body> +</html> +</pre> +</div> + +<pre class="brush: js">function draw() { + var canvas = document.getElementById('canvas'); + if (canvas.getContext) { + var ctx = canvas.getContext('2d'); + + roundedRect(ctx, 12, 12, 150, 150, 15); + roundedRect(ctx, 19, 19, 150, 150, 9); + roundedRect(ctx, 53, 53, 49, 33, 10); + roundedRect(ctx, 53, 119, 49, 16, 6); + roundedRect(ctx, 135, 53, 49, 33, 10); + roundedRect(ctx, 135, 119, 25, 49, 10); + + ctx.beginPath(); + ctx.arc(37, 37, 13, Math.PI / 7, -Math.PI / 7, false); + ctx.lineTo(31, 37); + ctx.fill(); + + for (var i = 0; i < 8; i++) { + ctx.fillRect(51 + i * 16, 35, 4, 4); + } + + for (i = 0; i < 6; i++) { + ctx.fillRect(115, 51 + i * 16, 4, 4); + } + + for (i = 0; i < 8; i++) { + ctx.fillRect(51 + i * 16, 99, 4, 4); + } + + ctx.beginPath(); + ctx.moveTo(83, 116); + ctx.lineTo(83, 102); + ctx.bezierCurveTo(83, 94, 89, 88, 97, 88); + ctx.bezierCurveTo(105, 88, 111, 94, 111, 102); + ctx.lineTo(111, 116); + ctx.lineTo(106.333, 111.333); + ctx.lineTo(101.666, 116); + ctx.lineTo(97, 111.333); + ctx.lineTo(92.333, 116); + ctx.lineTo(87.666, 111.333); + ctx.lineTo(83, 116); + ctx.fill(); + + ctx.fillStyle = 'white'; + ctx.beginPath(); + ctx.moveTo(91, 96); + ctx.bezierCurveTo(88, 96, 87, 99, 87, 101); + ctx.bezierCurveTo(87, 103, 88, 106, 91, 106); + ctx.bezierCurveTo(94, 106, 95, 103, 95, 101); + ctx.bezierCurveTo(95, 99, 94, 96, 91, 96); + ctx.moveTo(103, 96); + ctx.bezierCurveTo(100, 96, 99, 99, 99, 101); + ctx.bezierCurveTo(99, 103, 100, 106, 103, 106); + ctx.bezierCurveTo(106, 106, 107, 103, 107, 101); + ctx.bezierCurveTo(107, 99, 106, 96, 103, 96); + ctx.fill(); + + ctx.fillStyle = 'black'; + ctx.beginPath(); + ctx.arc(101, 102, 2, 0, Math.PI * 2, true); + ctx.fill(); + + ctx.beginPath(); + ctx.arc(89, 102, 2, 0, Math.PI * 2, true); + ctx.fill(); + } +} + +// A utility function to draw a rectangle with rounded corners. + +function roundedRect(ctx, x, y, width, height, radius) { + ctx.beginPath(); + ctx.moveTo(x, y + radius); + ctx.lineTo(x, y + height - radius); + ctx.arcTo(x, y + height, x + radius, y + height, radius); + ctx.lineTo(x + width - radius, y + height); + ctx.arcTo(x + width, y + height, x + width, y + height-radius, radius); + ctx.lineTo(x + width, y + radius); + ctx.arcTo(x + width, y, x + width - radius, y, radius); + ctx.lineTo(x + radius, y); + ctx.arcTo(x, y, x, y + radius, radius); + ctx.stroke(); +} +</pre> + +<p>결과 이미지는 다음과 같습니다:</p> + +<p>{{EmbedLiveSample("Making_combinations", 160, 160, "https://mdn.mozillademos.org/files/9849/combinations.png")}}</p> + +<p>이 예제는 보기보다 아주 간단하기 때문에 자세한 설명은 생략하겠습니다. 알아 두어야할 가장 중요한 부분은 <code>fillStyle</code> 코드와 사용된 유틸리티 함수 (<code>roundedRect()</code> 부분) 입니다. 유틸리티 함수를 사용하게 되면, 사용해야 할 코드의 양과 복잡함을 줄여주는데 도움을 줍니다.</p> + +<p>이 튜토리얼에서 나중에 <code>fillStyle</code>에 대하여 조금 더 자세하게 알아보도록 하겠지만, 지금은 경로의 채우는 색을 기본값(흑백)에서 바꾸었다가 다시 기본값으로 바꾸는 정도로만 사용하였습니다.</p> + +<h2 id="Path2D_오브젝트_(Path2D_objects)">Path2D 오브젝트 (Path2D objects)</h2> + +<p>마지막 예제에서 보았 듯이, 캔버스에 객체를 그리는 일련의 경로와 그리기 명령이 있을 수 있습니다. 코드를 단순화하고 성능을 향상시키기 위해 최근 버전의 브라우저에서 사용할 수있는 {{domxref("Path2D")}} 객체를 사용하여 이러한 드로잉 명령을 캐시하거나 기록 할 수 있습니다. 이로써 여러분은 경로를 빠르게 다시 실행 시킬 수 있습니다.</p> + +<p>어떻게 <code>Path2D</code> object를 생성 할 수 있는지 확인해 봅시다:</p> + +<dl> + <dt>{{domxref("Path2D.Path2D", "Path2D()")}}</dt> + <dd><code><strong>Path2D()</strong></code> 생성자는 새로운 <code>Path2D</code> 객체를 반환합니다. 선택적으로 다른 경로를 인수로 받거나(복사본을 생성), SVG 경로 데이터로 구성된 문자열을 받아서 객체로 반환합니다.</dd> +</dl> + +<pre class="brush: js">new Path2D(); // empty path object +new Path2D(path); // copy from another Path2D object +new Path2D(d); // path from SVG path data</pre> + +<p><code>moveTo</code>, <code>rect</code>, <code>arc</code> 혹은 <code>quadraticCurveTo</code> 등과 같은 모든 경로 메소드 (<a href="/en-US/docs/Web/API/CanvasRenderingContext2D#Paths">path methods</a>)들은 <code>Path2D</code> 객체에서 사용 가능합니다.</p> + +<p><code>Path2D</code> API는 또한 <code>addPath</code> 메소드를 사용하여 경로를 결합하는 방법을 추가합니다. 예를 들자면, 여러 요소를 사용하는 오브젝트를 만들 때 유용하게 사용 될 수 있습니다.</p> + +<dl> + <dt>{{domxref("Path2D.addPath", "Path2D.addPath(path [, transform])")}}</dt> + <dd>옵션으로 변환 행렬(transformation matrix)을 사용하여 현재 경로에 경로를 추가합니다.</dd> +</dl> + +<h3 id="Path2D_예제">Path2D 예제</h3> + +<p>이 예제에서는, 직사각형과 원을 만들어 볼 것입니다. 나중에 사용할 것을 고려하여, 두 도형 모두 <code>Path2D</code> object로 저장 될 것입니다. 새로운 버전의 <code>Path2D</code> API에서는 여러 메소드들이 지금 사용하고있는 path가 아닌 <code>Path2D</code> object를 옵션으로 선택하여 사용 할 수 있도록 업데이트 되었습니다. 아래의 예제에서 보시면, <code>stroke</code> 와 <code>fill</code> 메소드가 오브젝트를 캔버스 위에 그리도록 path 변수와 함께 사용되었습니다.</p> + +<div class="hidden"> +<pre class="brush: html"><html> + <body onload="draw();"> + <canvas id="canvas" width="130" height="100"></canvas> + </body> +</html> +</pre> +</div> + +<pre class="brush: js;highlight[6,9]">function draw() { + var canvas = document.getElementById('canvas'); + if (canvas.getContext) { + var ctx = canvas.getContext('2d'); + + var rectangle = new Path2D(); + rectangle.rect(10, 10, 50, 50); + + var circle = new Path2D(); + circle.moveTo(125, 35); + circle.arc(100, 35, 25, 0, 2 * Math.PI); + + ctx.stroke(rectangle); + ctx.fill(circle); + } +} +</pre> + +<p>{{EmbedLiveSample("Path2D_example", 130, 110, "https://mdn.mozillademos.org/files/9851/path2d.png")}}</p> + +<h3 id="SVG_paths_사용하기">SVG paths 사용하기</h3> + +<p>새로운 캔버스 path2D API 또다른 강력한 특징 중 하나는, 캔버스의 path를 초기화 하기 위해 <a href="https://developer.mozilla.org/en-US/docs/Web/SVG/Tutorial/Paths">SVG path data</a>를 사용한다는 것입니다. 이는 path 데이터를 이동시키며, SVG와 canvas 에서 재사용 할 수 있도록 해줍니다. </p> + +<p>path는 (<code>M10 10</code>) 점으로 이동한 다음, 수평하게 오른쪽으로 으로 80 포인트 (<code>h 80</code>) 만큼 이동합니다. 이후 수직으로 80포인트 (v 80) 내려간 다음, 80 포인트 왼쪽으로 (<code>h -80</code>) 수평하게 이동하고 다시 시작점 (<code>z</code>)으로 돌아갑니다. 예시는 <a href="/en-US/docs/Web/API/Path2D.Path2D#Using_SVG_paths">이곳</a>( <code>Path2D</code> constructor )에서 확인하실 수 있습니다.</p> + +<pre class="brush: js;">var p = new Path2D('M10 10 h 80 v 80 h -80 Z');</pre> + +<div>{{PreviousNext("Web/API/Canvas_API/Tutorial/Basic_usage", "Web/API/Canvas_API/Tutorial/Applying_styles_and_colors")}}</div> diff --git a/files/ko/web/api/canvas_api/tutorial/drawing_text/index.html b/files/ko/web/api/canvas_api/tutorial/drawing_text/index.html new file mode 100644 index 0000000000..2c789e85a4 --- /dev/null +++ b/files/ko/web/api/canvas_api/tutorial/drawing_text/index.html @@ -0,0 +1,164 @@ +--- +title: 텍스트 그리기 +slug: Drawing_text_using_a_canvas +tags: + - HTML + - 'HTML:Canvas' + - NeedsContent +translation_of: Web/API/Canvas_API/Tutorial/Drawing_text +--- +<div>{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Applying_styles_and_colors", "Web/API/Canvas_API/Tutorial/Using_images")}}</div> + +<div class="summary"> +<p>이전 챕터에서 <a href="/ko/docs/Web/API/Canvas_API/Tutorial/Applying_styles_and_colors">스타일과 컬러를 적용하는 방법</a>에 대해서 보았고 이번에는 캔버스에 텍스트를 그리는 방법에 대해서 볼 예정입니다.</p> +</div> + +<h2 id="텍스트_그리기">텍스트 그리기</h2> + +<p>캔버스 렌더링 컨텍스트(canvas rendering context)는 텍스트를 렌더링하는 두 가지 방법을 제공합니다.</p> + +<dl> + <dt>{{domxref("CanvasRenderingContext2D.fillText", "fillText(text, x, y [, maxWidth])")}}</dt> + <dd>주어진 (x, y) 위치에 주어진 텍스트를 채웁니다. 최대 폭(width)은 옵션 값 입니다.</dd> + <dt>{{domxref("CanvasRenderingContext2D.strokeText", "strokeText(text, x, y [, maxWidth])")}}</dt> + <dd>주어진 (x, y) 위치에 주어진 텍스트를 칠(stroke)합니다. 최대 폭(width)은 옵션 값 입니다.</dd> +</dl> + +<h3 id="fillText_예제"><code>fillText</code> 예제</h3> + +<p>텍스트는 현재의 <code>fillStyle</code>을 사용하여 채워집니다.</p> + +<pre class="brush: js;highlight[4]">function draw() { + var ctx = document.getElementById('canvas').getContext('2d'); + ctx.font = '48px serif'; + ctx.fillText('Hello world', 10, 50); +}</pre> + +<div class="hidden"> +<pre class="brush: html"><canvas id="canvas" width="300" height="100"></canvas></pre> + +<pre class="brush: js">draw();</pre> +</div> + +<p>{{EmbedLiveSample("A_fillText_example", 310, 110)}}</p> + +<h3 id="strokeText_예제"><code>strokeText</code> 예제</h3> + +<p>텍스트는 현재의 <code>strokeStyle</code>을 이용하여 채워집니다.</p> + +<pre class="brush: js;highlight[4]">function draw() { + var ctx = document.getElementById('canvas').getContext('2d'); + ctx.font = '48px serif'; + ctx.strokeText('Hello world', 10, 50); +}</pre> + +<div class="hidden"> +<pre class="brush: html"><canvas id="canvas" width="300" height="100"></canvas></pre> + +<pre class="brush: js">draw();</pre> +</div> + +<p>{{EmbedLiveSample("A_strokeText_example", 310, 110)}}</p> + +<h2 id="텍스트_스타일_적용하기">텍스트 스타일 적용하기</h2> + +<p> 위의 예제에서 우리는 이미 텍스트를 기본 사이즈를 키우기 위하여 <code>font</code> 프로퍼티를 사용하였습니다. 그리고 캔버스에 표시되는 텍스트를 조정할 수 있는 속성이 더 있습니다. </p> + +<dl> + <dt>{{domxref("CanvasRenderingContext2D.font", "font = value")}}</dt> + <dd>텍스트를 그릴 때 사용되는 현재 텍스트 스타일. 이 문자열은 <a href="/en-US/docs/Web/CSS">CSS</a> {{cssxref("font")}} 프로퍼티와 동일한구문을 사용합니다. 기본값으로 sans-serif의 10px가 설정되어 있습니다.</dd> + <dt>{{domxref("CanvasRenderingContext2D.textAlign", "textAlign = value")}}</dt> + <dd>텍스트 정렬 설정. 사용가능한 값: <code>start</code>, <code>end</code>, <code>left</code>, <code>right</code>, <code>center</code>. 기본 값은 <code>start</code> 입니다.</dd> + <dt>{{domxref("CanvasRenderingContext2D.textBaseline", "textBaseline = value")}}</dt> + <dd>베이스라인 정렬 설정. 사용가능한 값: <code>top</code>, <code>hanging</code>, <code>middle</code>, <code>alphabetic</code>, <code>ideographic</code>, <code>bottom</code>. 기본 값은 <code>alphabetic</code> 입니다</dd> + <dt>{{domxref("CanvasRenderingContext2D.direction", "direction = value")}}</dt> + <dd>글자 방향. 사용가능한 값: <code>ltr</code>, <code>rtl</code>, <code>inherit</code>. 기본 값은 <code>inherit</code> 입니다.</dd> +</dl> + +<p>만약 CSS를 다뤄보신적이 있다면 이러한 프로퍼티들은 익숙하실겁니다.</p> + +<p>다음에 나오는 <a class="external" href="http://www.whatwg.org/" title="http://www.whatwg.org/">WHATWG</a> 예제 다이어그램은 <code>textBaseline</code>를 이용하여 다양한 베이스라인 설정을 보여줍니다.<img alt="The top of the em square is +roughly at the top of the glyphs in a font, the hanging baseline is +where some glyphs like आ are anchored, the middle is half-way +between the top of the em square and the bottom of the em square, +the alphabetic baseline is where characters like Á, ÿ, +f, and Ω are anchored, the ideographic baseline is +where glyphs like 私 and 達 are anchored, and the bottom +of the em square is roughly at the bottom of the glyphs in a +font. The top and bottom of the bounding box can be far from these +baselines, due to glyphs extending far outside the em square." src="http://www.whatwg.org/specs/web-apps/current-work/images/baselines.png"></p> + +<h3 id="textBaseline_예제">textBaseline 예제</h3> + +<p>아래의 코드를 수정하여 캔버스에서 어떻게 바뀌는지 실시간으로 확인해 보세요.</p> + +<pre class="brush: js;highlight[2]">ctx.font = '48px serif'; +ctx.textBaseline = 'hanging'; +ctx.strokeText('Hello world', 0, 100); +</pre> + +<div class="hidden"> +<h6 id="Playable_code" name="Playable_code">Playable code</h6> + +<pre class="brush: html"><canvas id="canvas" width="400" height="200" class="playable-canvas"></canvas> +<div class="playable-buttons"> + <input id="edit" type="button" value="Edit" /> + <input id="reset" type="button" value="Reset" /> +</div> +<textarea id="code" class="playable-code"> +ctx.font = "48px serif"; +ctx.textBaseline = "hanging"; +ctx.strokeText("Hello world", 0, 100);</textarea> +</pre> + +<pre class="brush: js">var canvas = document.getElementById('canvas'); +var ctx = canvas.getContext('2d'); +var textarea = document.getElementById('code'); +var reset = document.getElementById('reset'); +var edit = document.getElementById('edit'); +var code = textarea.value; + +function drawCanvas() { + ctx.clearRect(0, 0, canvas.width, canvas.height); + eval(textarea.value); +} + +reset.addEventListener('click', function() { + textarea.value = code; + drawCanvas(); +}); + +edit.addEventListener('click', function() { + textarea.focus(); +}) + +textarea.addEventListener('input', drawCanvas); +window.addEventListener('load', drawCanvas); +</pre> +</div> + +<p>{{ EmbedLiveSample('Playable_code', 700, 360) }}</p> + +<h2 id="어드밴스드_텍스트_측정">어드밴스드 텍스트 측정</h2> + +<p>만약 텍스트에대해 조금 더 디테일한 것들을 얻고 싶다면 다음의 메소드를 이용해보세요.</p> + +<dl> + <dt>{{domxref("CanvasRenderingContext2D.measureText", "measureText()")}}</dt> + <dd>현재 스타일로 특정 텍스트가 그려질 때의 폭, 픽셀 등을 포함하는 {{domxref("TextMetrics")}} 객체 리턴. </dd> +</dl> + +<p>다음의 코드는 어떻게 텍스트를 측정하는 지, 그리고 폭을 구하는 예제입니다.</p> + +<pre class="brush: js;highlight[3]">function draw() { + var ctx = document.getElementById('canvas').getContext('2d'); + var text = ctx.measureText('foo'); // TextMetrics object + text.width; // 16; +} +</pre> + +<h2 id="Gecko_사용시_주의점">Gecko 사용시 주의점</h2> + +<p>Gecko(Firefox, Firefox OS외 Mozilla 기반의 에플리케이션 렌더링 엔진)에서는 캔버스에 텍스트를 그리기 위한 몇몇의 <a href="https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D#Prefixed_APIs">prefixed APIs</a>가 구현되어 있습니다. 그리고 지금은 사용되지 않아 제거되었거나 작동을 보장하지 않는 것들도 있습니다. </p> + +<p>{{PreviousNext("Web/API/Canvas_API/Tutorial/Applying_styles_and_colors", "Web/API/Canvas_API/Tutorial/Using_images")}}</p> diff --git a/files/ko/web/api/canvas_api/tutorial/finale/index.html b/files/ko/web/api/canvas_api/tutorial/finale/index.html new file mode 100644 index 0000000000..1241680c5c --- /dev/null +++ b/files/ko/web/api/canvas_api/tutorial/finale/index.html @@ -0,0 +1,51 @@ +--- +title: Finale +slug: Web/HTML/Canvas/Tutorial/Finale +tags: + - 그래픽 + - 캔버스 + - 튜토리얼 +translation_of: Web/API/Canvas_API/Tutorial/Finale +--- +<div>{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Optimizing_canvas")}}</div> + +<div class="summary"> +<p>축하합니다 <a href="/en-US/docs/Web/API/Canvas_API/Tutorial">Canvas </a>튜토리얼을 모두 끝마쳤습니다! 이 정보는 웹에서 더 나은 2D 그래픽을 만드는데 도움이 됩니다.</p> +</div> + +<h2 id="더_많은_예시와_튜토리얼">더 많은 예시와 튜토리얼</h2> + +<p>이 사이트에는 다양한 데모와 canvas에 대한 추가 설명이 있다.</p> + +<dl> + <dt><a href="https://codepen.io/search/pens?q=canvas">Codepen.io</a></dt> + <dd>프론트 엔드 개발자 playground 및 브라우저의 코드 편집기.</dd> + <dt><a href="http://www.html5canvastutorials.com/">HTML5 Canvas Tutorials</a></dt> + <dd>대부분 canvas API의 예시</dd> + <dt><a href="/en-US/docs/Games">Game development</a></dt> + <dd>게임은 가장 인기있는 컴퓨터 활동 중 하나이다. 어떤 표준 규격의 웹 브라우저에서도 실행할 수 있는 더 나은 게임을 개발할 수 있도록 하기 위한 신기술이 끊임없이 등장하고 있다.</dd> +</dl> + +<h2 id="기타_웹API">기타 웹API</h2> + +<p>이 API들는 canvas 및 그래픽으로 작업할 때 유용하다.</p> + +<dl> + <dt><a href="/en-US/docs/Web/WebGL">WebGL</a></dt> + <dd>3D를 포함한 복잡한 그래픽 렌더링을 위한 고급 API.</dd> + <dt><a href="/en-US/docs/Web/SVG">SVG</a></dt> + <dd>확장 가능한 Vector Graphics는 이미지를 벡터(선)과 형태의 집합으로 묘사하여 이미지를 그리는 크기에 상관없이 원활하게 확장할 수 있다.</dd> + <dt><a href="/en-US/docs/Web/API/Web_Audio_API">Web Audio</a></dt> + <dd>Web Audio API는 개발자들이 오디오 소스 선택, 오디오에 효과 추가, 오디오 시각화 생성, 공간 효과 적용(예: 패닝)등을 할 수 있도록 웹 상에서 오디오를 제어하기 위한 다양하고 좋은 시스템을 제공한다.</dd> +</dl> + +<h2 id="문의사항">문의사항</h2> + +<dl> + <dt><a href="http://stackoverflow.com/questions/tagged/canvas">Stack Overflow</a></dt> + <dd>"canvas"가 태그된 문의사항.</dd> + <dt><a href="/en-US/docs/MDN">Comments about this tutorial – the MDN documentation community</a></dt> + <dd>이 튜토리얼에 대해 의견이 있으시거나 저희에게 감사를 표하고 싶다면 언제든지 연락해주세요!</dd> +</dl> + +<p>{{PreviousNext("Web/API/Canvas_API/Tutorial/Optimizing_canvas")}}</p> diff --git a/files/ko/web/api/canvas_api/tutorial/hit_regions_and_accessibility/index.html b/files/ko/web/api/canvas_api/tutorial/hit_regions_and_accessibility/index.html new file mode 100644 index 0000000000..e720af3159 --- /dev/null +++ b/files/ko/web/api/canvas_api/tutorial/hit_regions_and_accessibility/index.html @@ -0,0 +1,97 @@ +--- +title: 히트(Hit) 영역과 접근성 +slug: Web/HTML/Canvas/Tutorial/Hit_regions_and_accessibility +translation_of: Web/API/Canvas_API/Tutorial/Hit_regions_and_accessibility +--- +<div>{{CanvasSidebar}} {{ PreviousNext("Web/API/Canvas_API/Tutorial/Pixel_manipulation_with_canvas", "Web/API/Canvas_API/Tutorial/Optimizing_canvas") }}</div> + +<div class="summary">{{HTMLElement("canvas")}} 엘리먼트는 비트맵이며 그려진 객체에 대한 정보는 제공하지 않습니다. 캔버스 컨텐츠는 시멘틱 HTML과 같은 접근성 도구에 노출되지 않습니다. 일반적으로 접근성을 위한 웹 사이트 또는 앱에서는 캔버스를 사용하지 않는 것이 좋습니다. 본 가이드라인은 접근성이 향상된 캔버스를 만드는데 도움이 될 것입니다.</div> + +<h2 id="대체_컨텐츠">대체 컨텐츠</h2> + +<p><code><canvas> ... </ canvas></code> 태그 안의 내용은 캔버스 렌더링을 지원하지 않는 브라우저의 대체 컨텐츠로 사용할 수 있습니다. 또한 하위 DOM을 읽고 해석 할 수있는 보조 기술 사용자 (스크린 리더와 같은)에게도 매우 유용합니다. <a href="https://www.html5accessibility.com/tests/canvas.html">html5accessibility.com</a>의 좋은 예가 이를 수행 할 수있는 방법을 보여줍니다.</p> + +<pre class="brush: html"><canvas> + <h2>Shapes</h2> + <p>A rectangle with a black border. + In the background is a pink circle. + Partially overlaying the <a href="http://en.wikipedia.org/wiki/Circle" onfocus="drawCircle();" onblur="drawPicture();">circle</a>. + Partially overlaying the circle is a green + <a href="http://en.wikipedia.org/wiki/Square" onfocus="drawSquare();" onblur="drawPicture();">square</a> + and a purple <a href="http://en.wikipedia.org/wiki/Triangle" onfocus="drawTriangle();" onblur="drawPicture();">triangle</a>, + both of which are semi-opaque, so the full circle can be seen underneath.</p> +</canvas> </pre> + +<p><a href="https://www.youtube.com/watch?v=ABeIFlqYiMQ">Steve Faulkner의 NVDA가 이 예제를 어떻게 읽는지를 보여주는 동영상</a>을 참고하시기 바랍니다.</p> + +<h2 id="ARIA_규칙">ARIA 규칙</h2> + +<p><a href="/ko/docs/Web/Accessibility/ARIA">ARIA</a>(Accessible Rich Internet Application)는 장애인이 사용자가 웹 콘텐츠 및 웹 응용 프로그램을보다 쉽게 사용할 수 있도록하는 방법을 정의합니다. ARIA 속성을 사용하여 캔버스 엘리먼트의 동작 및 용도를 설명 할 수 있습니다. 자세한 내용은 <a href="/ko/docs/Web/Accessibility/ARIA">ARIA</a> 및 <a href="/ko/docs/Web/Accessibility/ARIA/ARIA_Techniques">ARIA 기술</a>을 참조하십시오.</p> + +<pre class="brush: html"><canvas id="button" tabindex="0" role="button" aria-pressed="false" aria-label="Start game"></canvas> +</pre> + +<h2 id="히트(Hit)_영역">히트(Hit) 영역</h2> + +<p>마우스 좌표가 캔버스의 특정 영역 내에 있는지 여부는 문제를 해결하는 데 공통적입니다. 히트 영역 API를 사용하면 캔버스 영역을 정의 할 수 있으며 캔버스에 대화형 컨텐츠를 접근성 도구에 표시 할 수 있습니다. 히트 영역 API는 여러분이 히트 감지를 쉽게 할 수 있도록 하며 DOM 엘리먼트에 이벤트를 전달할 수 있도록 합니다. API에는 다음 세 가지 메소드가 있습니다 (현재 웹 브라우저에서는 아직 실험 중이며 브라우저 호환성 테이블을 확인하십시오).</p> + +<dl> + <dt>{{domxref("CanvasRenderingContext2D.addHitRegion()")}} {{experimental_inline}}</dt> + <dd>히트 영역을 캔버스에 추가합니다.</dd> + <dt>{{domxref("CanvasRenderingContext2D.removeHitRegion()")}} {{experimental_inline}}</dt> + <dd>캔버스에서 해당 <code>id</code>를 가진 히트 영역을 제거합니다.</dd> + <dt>{{domxref("CanvasRenderingContext2D.clearHitRegions()")}} {{experimental_inline}}</dt> + <dd>캔버스에서 모든 히트 영역을 제거합니다.</dd> +</dl> + +<p>경로에 히트 영역을 추가하고 {{domxref("MouseEvent.region")}} 속성을 확인하여 마우스가 영역을 히트하는지 테스트 할 수 있습니다.</p> + +<pre class="brush: html"><canvas id="canvas"></canvas> +<script> +var canvas = document.getElementById('canvas'); +var ctx = canvas.getContext('2d'); + +ctx.beginPath(); +ctx.arc(70, 80, 10, 0, 2 * Math.PI, false); +ctx.fill(); +ctx.addHitRegion({id: 'circle'}); + +canvas.addEventListener('mousemove', function(event) { + if (event.region) { + alert('hit region: ' + event.region); + } +}); +</script></pre> + +<p><code>addHitRegion()</code> 메소드는 <code>control</code> 옵션을 이용하여 이벤트를 엘리먼트(즉, 캔버스의 자식으로)로 전달합니다.</p> + +<pre class="brush: js">ctx.addHitRegion({control: element});</pre> + +<p>예를 들어 {{HTMLElement("input")}} 엘리먼트로 전달하는 데 유용 할 수 있습니다. <a href="https://codepen.io/peterj35/pen/PEdLKx">codepen 데모</a>를 참조하십시오.</p> + +<h2 id="포커스_링(Focus_rings)">포커스 링(Focus rings)</h2> + +<p>키보드로 작업 할 때 포커스 링은 페이지 탐색에 도움이되는 편리한 표시기입니다. 캔버스 드로잉에 포커스 링을 그리려면 <code>drawFocusIfNeeded</code> 속성을 사용할 수 있습니다.</p> + +<dl> + <dt>{{domxref("CanvasRenderingContext2D.drawFocusIfNeeded()")}} {{experimental_inline}}</dt> + <dd>지정된 엘리먼트에 포커스가있는 경우,이 메소드는 현재 경로 주위에 포커스 링을 그립니다.</dd> +</dl> + +<p>또한 <code>scrollPathIntoView()</code> 메서드를 사용하여 포커스가있는 경우 엘리먼트를 화면에 표시 할 수 있습니다.</p> + +<dl> + <dt>{{domxref("CanvasRenderingContext2D.scrollPathIntoView()")}} {{experimental_inline}}</dt> + <dd>현재 경로 또는 지정된 경로를 뷰로 스크롤합니다.</dd> +</dl> + +<h2 id="See_also">See also</h2> + +<ul> + <li><a href="https://www.w3.org/WAI/PF/HTML/wiki/Canvas_Accessibility_Use_Cases">Canvas accessibility use cases</a></li> + <li><a href="https://www.w3.org/html/wg/wiki/AddedElementCanvas">Canvas element accessibility issues</a></li> + <li><a href="http://www.paciellogroup.com/blog/2012/06/html5-canvas-accessibility-in-firefox-13/">HTML5 Canvas Accessibility in Firefox 13 – by Steve Faulkner</a></li> + <li><a href="https://html.spec.whatwg.org/multipage/scripting.html#best-practices">Best practices for interactive canvas elements</a></li> +</ul> + +<div>{{ PreviousNext("Web/API/Canvas_API/Tutorial/Pixel_manipulation_with_canvas", "Web/API/Canvas_API/Tutorial/Optimizing_canvas") }}</div> diff --git a/files/ko/web/api/canvas_api/tutorial/index.html b/files/ko/web/api/canvas_api/tutorial/index.html new file mode 100644 index 0000000000..03077163aa --- /dev/null +++ b/files/ko/web/api/canvas_api/tutorial/index.html @@ -0,0 +1,62 @@ +--- +title: 캔버스 튜토리얼 +slug: Web/HTML/Canvas/Tutorial +tags: + - Canvas + - Graphic + - Guide + - HTML + - HTML5 + - Intermediate + - Web +translation_of: Web/API/Canvas_API/Tutorial +--- +<div>{{CanvasSidebar}}</div> + +<div><a href="/en-US/docs/HTML/Canvas" title="HTML/Canvas"><img alt="" src="https://mdn.mozillademos.org/files/257/Canvas_tut_examples.jpg" style="float: right; height: 450px; width: 200px;"></a></div> + +<div class="summary"> +<p><a href="/en-US/docs/HTML/Canvas" title="HTML/Canvas"><strong><code><canvas></code></strong></a>는 <a href="/en-US/docs/HTML" title="HTML">HTML</a> 요소 중 하나로서, 스크립트(보통은 <a href="/en-US/docs/JavaScript" title="JavaScript">자바스크립트</a>)를 사용하여 그림을 그리는 데에 사용됩니다. 예를 들면, 그래프를 그리거나 사진을 합성하거나, 간단한(혹은 <a href="/en-US/docs/HTML/Canvas/A_Basic_RayCaster" title="A_Basic_RayCaster">복잡할 수도 있는</a>) 애니메이션을 만드는 데에 사용될 수 있습니다. 오른쪽에 보이는 이미지들은 앞으로 설명하게 될 <a href="/en-US/docs/HTML/Canvas" title="HTML/Canvas"><strong><code><canvas></code></strong></a>를 사용하여 만들 수 있는 것들의 일부입니다.</p> +</div> + +<p><span class="seoSummary">이 튜토리얼은 <code><canvas></code> 요소를 사용하여 2D 그래픽을 어떻게 그리는지 기초부터 설명합니다. 예제들을 통하여 캔버스로 할 수 있는 것이 무엇인지 알려주며, 바로 사용할 수 있도록 코드도 제공합니다.</span></p> + +<p><code><canvas></code>는 Apple의 Webkit에 처음 도입되어 Mac OS X 대시보드(Dashboard)에 사용되었고, 이후 다른 브라우저에도 구현되어 왔습니다. 현재 대부분의 주요 브라우저에서 지원됩니다.</p> + +<h2 id="Before_you_start" name="Before_you_start">시작하기 전 알아두어야 할 것</h2> + +<p><code><canvas></code> 요소를 사용하는 것이 어려운 일은 아니지만, <a href="/en-US/docs/HTML" title="HTML">HTML</a>과 <a href="/en-US/docs/JavaScript" title="JavaScript">자바스크립트</a>에 대한 기본 지식을 갖추고 있어야 합니다. 몇몇 오래된 브라우저는 <code><canvas></code> 요소를 지원하지 않지만, 최근 버전의 주요 브라우저들은 모두 지원하고 있습니다. 캔버스의 크기는 300px * 150px (너비 * 높이)가 초기 설정값이며, HTML <code>height</code>와 <code>width</code> 속성을 사용하여 바꿀 수 있습니다. 캔버스에 그림을 그리려면 자바스크립트 컨텍스트 오브젝트를 사용하며, 즉석에서 그림을 생성할 수 있습니다.</p> + +<h2 id="In_this_tutorial" name="In_this_tutorial">튜토리얼 내용</h2> + +<ul> + <li><a href="/ko/docs/Web/API/Canvas_API/Tutorial/Basic_usage" title="Canvas_tutorial/Basic_usage">캔버스(Canvas) 기본 사용법</a></li> + <li><a href="/ko/docs/Web/API/Canvas_API/Tutorial/Drawing_shapes" title="Canvas_tutorial/Drawing_shapes">캔버스에 도형 그리기</a></li> + <li><a href="/ko/docs/Web/API/Canvas_API/Tutorial/Applying_styles_and_colors" title="Canvas_tutorial/Applying_styles_and_colors">스타일과 색 적용하기</a></li> + <li><a href="/ko/docs/Web/API/Canvas_API/Tutorial/Drawing_text">텍스트 그리기</a></li> + <li><a href="/ko/docs/Web/API/Canvas_API/Tutorial/Using_images" title="Canvas_tutorial/Using_images">이미지 사용하기</a></li> + <li><a href="/ko/docs/Web/API/Canvas_API/Tutorial/Transformations" title="Canvas_tutorial/Transformations">모양 변환</a></li> + <li><a href="/ko/docs/Web/API/Canvas_API/Tutorial/Compositing" title="Canvas_tutorial/Compositing">도형 합성</a></li> + <li><a href="/ko/docs/Web/API/Canvas_API/Tutorial/Basic_animations" title="Canvas_tutorial/Basic_animations">애니메이션 기본</a></li> + <li><a href="/ko/docs/Web/API/Canvas_API/Tutorial/Advanced_animations">애니메이션 고급</a></li> + <li><a href="/ko/docs/Web/API/Canvas_API/Tutorial/Pixel_manipulation_with_canvas">픽셀 다루기</a></li> + <li><a href="/ko/docs/Web/API/Canvas_API/Tutorial/Hit_regions_and_accessibility">Hit 영역과 accessibility</a></li> + <li><a href="/ko/docs/Web/API/Canvas_API/Tutorial/Optimizing_canvas" title="https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Canvas_tutorial/Optimizing_canvas">캔버스 최적화</a></li> + <li><a href="/ko/docs/Web/API/Canvas_API/Tutorial/Finale">마무리</a></li> +</ul> + +<h2 id="See_also" name="See_also">같이 보기</h2> + +<ul> + <li><a href="/en-US/docs/Web/API/Canvas_API" title="HTML/Canvas">캔버스 주제 페이지</a></li> + <li><a class="external" href="http://visitmix.com/labs/ai2canvas/" title="http://visitmix.com/labs/ai2canvas/">Adobe 일러스트레이터와 캔버스 플러그인</a></li> + <li><a class="external" href="http://www.html5canvastutorials.com/" title="http://www.html5canvastutorials.com/">HTML5 캔버스 튜토리얼</a></li> +</ul> + +<div class="hidden"> +<h2 id="페이지_작성에_기여하신_분들에게_알리는_말씀">페이지 작성에 기여하신 분들에게 알리는 말씀</h2> + +<p>2013년 6월 17일에 일어난 기술적인 오류로 인해, 이 튜토리얼에 대한 그 동안의 내역이 사라졌습니다. 사라진 내역에는 이 페이지 작성에 기여한 모든 분들의 기록도 포함됩니다. 이에 대해 사과드리며, 여러분들의 용서를 구합니다. (이상은 영문 페이지의 내용이므로 이 페이지와는 상관 없음을 밝힙니다.)</p> +</div> + +<div>{{ Next("Web/API/Canvas_API/Tutorial/Basic_usage") }}</div> diff --git a/files/ko/web/api/canvas_api/tutorial/optimizing_canvas/index.html b/files/ko/web/api/canvas_api/tutorial/optimizing_canvas/index.html new file mode 100644 index 0000000000..460b5e893f --- /dev/null +++ b/files/ko/web/api/canvas_api/tutorial/optimizing_canvas/index.html @@ -0,0 +1,110 @@ +--- +title: 캔버스 최적화 +slug: Web/HTML/Canvas/Tutorial/Optimizing_canvas +translation_of: Web/API/Canvas_API/Tutorial/Optimizing_canvas +--- +<div>{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Hit_regions_and_accessibility", "Web/API/Canvas_API/Tutorial/Finale")}}</div> + +<div class="summary"> +<p>{{HTMLElement("canvas")}} 엘리먼트는 웹에서 2D 그래픽을 렌더링하는 데 가장 널리 사용되는 도구 중 하나입니다. 그러나 웹 사이트와 앱이 Canvas API를 최대한으로 밀면 성능이 저하되기 시작합니다. 그러나 웹 사이트 및 앱이 Canvas API를 한계치까지 사용하면 성능이 저하되기 시작합니다. <span class="seoSummary">이 글에서는 그래픽이 잘 동작하도록 보장하기 위해 캔버스 엘리먼트의 사용을 최적화하기위한 제안 사항을 제공합니다.</span></p> +</div> + +<h2 id="성능_팁">성능 팁</h2> + +<p>다음은 캔버스 성능을 개선하기 위한 팁 모음입니다.</p> + +<h3 id="캔버스에_표시되지_않는_비슷한_원시_혹은_반복_객체를_미리_그려라">캔버스에 표시되지 않는 비슷한 원시 혹은 반복 객체를 미리 그려라</h3> + +<p>만약 당신이 캔버스에 애니메이션 프레임을 그리면서 반복적인 작업이 발견된다면, 눈에 보이지 않는 숨겨진 캔버스 요소를 새로 만들고 그 캔버스에 미리 그려 넣는 방법을 고려하세요. 그렇게 하면 필요한 순간에 숨긴 캔버스에 그려진 이미지를 다시 주 캔버스 이미지에 그려넣어, 불필요한 렌더링 반복 작업을 줄여 성능 향상을 꾀할 수 있습니다.</p> + +<pre class="brush: js">myCanvas.offscreenCanvas = document.createElement('canvas'); +myCanvas.offscreenCanvas.width = myCanvas.width; +myCanvas.offscreenCanvas.height = myCanvas.height; + +myCanvas.getContext('2d').drawImage(myCanvas.offScreenCanvas, 0, 0);</pre> + +<h3 id="부동_소수점_좌표를_피하고_대신_정수를_사용하라.">부동 소수점 좌표를 피하고 대신 정수를 사용하라.</h3> + +<p>정수값들 없이 캔버스 상의 객체를 렌더링할 때 부가적인 픽셀 렌더링이 발생합니다.</p> + +<pre class="brush: js">ctx.drawImage(myImage, 0.3, 0.5); +</pre> + +<p>이렇게하면 앤티 앨리어싱(anti-aliasing) 효과를 만들기 위해 브라우저에서 추가 연산을 수행해야합니다. 예제에서 이를 방지하려면 {{jsxref("Math.floor()")}}를 사용하여 {{domxref("CanvasRenderingContext2D.drawImage", "drawImage()")}} 호출에 사용된 모든 좌표를 반올림해야합니다.</p> + +<h3 id="drawImage에서_이미지_크기를_조정하지_마라."><code>drawImage</code>에서 이미지 크기를 조정하지 마라.</h3> + +<p>{{domxref("CanvasRenderingContext2D.drawImage", "drawImage()")}}에서 즉시 크기를 조정하지 말고 다양한 이미지 크기를 오프스크린(offscreen) 캔버스에 캐시하십시오.</p> + +<h3 id="복잡한_장면에_여러_개의_레이어_캔버스를_사용하라.">복잡한 장면에 여러 개의 레이어 캔버스를 사용하라.</h3> + +<p>어플리케이션에서 일부 객체는 자주 이동하거나 변경해야하지만 다른 객체는 상대적으로 고정 위치에 남아야 합니다. 이런 상황에서 대응 가능한 최적화는 여러 <code><canvas></code> 엘리먼트를 사용하여 항목을 겹쳐서 만드는 것입니다.</p> + +<p>예를 들어 상단에 UI, 중간에 게임 플레이 액션, 하단에 정적 배경이있는 게임이 있다고 가정 해 보겠습니다. 이 경우 게임을 세 개의 <code><canvas></code> 레이어로 나눌 수 있습니다. UI는 사용자 입력시에만 변경되며 게임 플레이 레이어는 모든 새 프레임마다 변경되며 배경은 일반적으로 변경되지 않습니다.</p> + +<pre class="brush: html"><div id="stage"> + <canvas id="ui-layer" width="480" height="320"></canvas> + <canvas id="game-layer" width="480" height="320"></canvas> + <canvas id="background-layer" width="480" height="320"></canvas> +</div> + +<style> + #stage { + width: 480px; + height: 320px; + position: relative; + border: 2px solid black; + } + + canvas { position: absolute; } + #ui-layer { z-index: 3; } + #game-layer { z-index: 2; } + #background-layer { z-index: 1; } +</style> +</pre> + +<h3 id="큰_배경_이미지는_일반_CSS를_사용하라.">큰 배경 이미지는 일반 CSS를 사용하라.</h3> + +<p>정적 배경 이미지가있는 경우 CSS {{cssxref("background")}} 속성을 사용하여 일반 {{HTMLElement("div")}} 요소에 그릴 수 있으며 캔버스 아래에 배치 할 수 있습니다. 이렇게하면 모든 틱 마다 배경을 캔버스에 렌더링 할 필요가 없어집니다.</p> + +<h3 id="CSS_변환transform을_사용하여_캔버스_크기_조정하라.">CSS 변환(transform)을 사용하여 캔버스 크기 조정하라.</h3> + +<p><a href="/en-US/docs/Web/Guide/CSS/Using_CSS_transforms">CSS 변환(transform)</a>은 GPU를 사용하기 때문에 더 빠릅니다. 가장 좋은 경우는 캔버스를 스케일링하지 않거나, 큰 캔버스를 축소하기보다 작은 캔버스를 확대하는 것입니다.</p> + +<pre class="brush: js">var scaleX = window.innerWidth / canvas.width; +var scaleY = window.innerHeight / canvas.height; + +var scaleToFit = Math.min(scaleX, scaleY); +var scaleToCover = Math.max(scaleX, scaleY); + +stage.style.transformOrigin = '0 0'; //scale from top left +stage.style.transform = 'scale(' + scaleToFit + ')'; +</pre> + +<h3 id="투명도를_사용하지_마라.">투명도를 사용하지 마라.</h3> + +<p>응용 프로그램이 캔버스를 사용하고 투명 배경을 필요로하지 않는 경우 <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/getContext" title="The HTMLCanvasElement.getContext() method returns a drawing context on the canvas, or null if the context identifier is not supported."><code>HTMLCanvasElement.getContext()</code></a>를 사용하여 드로잉 컨텍스트를 만들 때 alpha 옵션을 false로 설정합니다. 이 정보는 렌더링을 최적화하기 위해 브라우저에서 내부적으로 사용할 수 있습니다.</p> + +<pre class="brush: js">var ctx = canvas.getContext('2d', { alpha: false });</pre> + +<h3 id="추가_팁들">추가 팁들</h3> + +<ul> + <li>배치 캔버스를 함께 호출합니다. 예를 들어 여러 개의 개별 선 대신 다각형 선을 그립니다.</li> + <li>불필요한 캔버스 상태 변경을 피하십시오.</li> + <li>화면의 차이만 렌더링하고 완전히 새로운 상태로 렌더링하지 마십시오.</li> + <li>가능하면 {{domxref("CanvasRenderingContext2D.shadowBlur", "shadowBlur")}} 속성을 사용하지 마십시오.</li> + <li>가능하면 <a href="/ko/docs/Web/API/Canvas_API/Tutorial/Drawing_text">텍스트 렌더링</a>을 피하십시오.</li> + <li>캔버스를 지우는 여러 가지 방법을 시도해보십시오 ({{domxref("CanvasRenderingContext2D.clearRect", "clearRect()")}} vs. {{domxref("CanvasRenderingContext2D.fillRect", "fillRect()")}} vs. 캔버스 크기 조정).</li> + <li>애니메이션에서는 {{domxref("window.setInterval()")}} 대신 {{domxref("window.requestAnimationFrame()")}}을 사용하십시오.</li> + <li>무거운 물리 연산 라이브러리를 주의하십시오.</li> +</ul> + +<h2 id="See_also">See also</h2> + +<ul> + <li><a href="http://www.html5rocks.com/en/tutorials/canvas/performance/#toc-ref">Improving HTML5 Canvas Performance – HTML5 Rocks</a></li> + <li><a href="https://hacks.mozilla.org/2013/05/optimizing-your-javascript-game-for-firefox-os/">Optimizing your JavaScript game for Firefox OS – Mozilla Hacks</a></li> +</ul> + +<p>{{PreviousNext("Web/API/Canvas_API/Tutorial/Hit_regions_and_accessibility", "Web/API/Canvas_API/Tutorial/Finale")}}</p> diff --git a/files/ko/web/api/canvas_api/tutorial/transformations/index.html b/files/ko/web/api/canvas_api/tutorial/transformations/index.html new file mode 100644 index 0000000000..b93747b581 --- /dev/null +++ b/files/ko/web/api/canvas_api/tutorial/transformations/index.html @@ -0,0 +1,286 @@ +--- +title: 변형 (transformations) +slug: Web/HTML/Canvas/Tutorial/변형 +tags: + - CSS + - HTML + - 이동 + - 축소 + - 캔버스 + - 크기변형 + - 트랜스폼 + - 확대 +translation_of: Web/API/Canvas_API/Tutorial/Transformations +--- +<div>{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Using_images", "Web/API/Canvas_API/Tutorial/Compositing")}}</div> + +<div class="summary">이 튜토리얼에 앞서 <a href="/ko/docs/Web/HTML/Canvas/Tutorial/Drawing_shapes">canvas 그리드</a>와 <strong>좌표 공간</strong>에 대해 알아 보았습니다. 지금까지는 기본적인 그리드를 사용해 요구에 맞추어 전체 canvas의 크기를 바꾸기만 했습니다. Transformation(변형)에는 그리드를 원점에서 다른 위치로 옮기고, 회전하며, 확대·축소까지 하는 더 강력한 방법들이 있습니다.</div> + +<h2 id="Saving_and_restoring_state" name="Saving_and_restoring_state">상태(state)의 저장과 복원</h2> + +<p>변형(transformation) 메소드을 살펴보기 전에 두 가지 다른 메소드를 보도록 하지요. 일단 여러분이 더 복잡한 그림(drawings)을 그리기 시작하면 반드시 있어야 하는 메소드들입니다.</p> + +<dl> + <dt>{{domxref("CanvasRenderingContext2D.save", "save()")}}</dt> + <dd>canvas의 모든 상태를 저장합니다.</dd> + <dt>{{domxref("CanvasRenderingContext2D.restore", "restore()")}}</dt> + <dd>가장 최근에 저장된 canvas 상태를 복원합니다.</dd> +</dl> + +<p>Canvas 상태는 스택(stack)에 쌓입니다. <code>save()</code> 메소드가 호출될 때마다 현재 drawing 상태가 스택 위로 푸시됩니다. drawing 상태는 다음과 같이 이루어집니다.</p> + +<ul> + <li>이전부터 적용된 변형(가령, <code>translate</code>과 <code>rotate</code>와 <code>scale</code> 같은 – 아래의 내용을 보세요).</li> + <li>다음 속성(attributes)의 현재 값:<br> + {{domxref("CanvasRenderingContext2D.strokeStyle", "strokeStyle")}}, {{domxref("CanvasRenderingContext2D.fillStyle", "fillStyle")}}, {{domxref("CanvasRenderingContext2D.globalAlpha", "globalAlpha")}}, {{domxref("CanvasRenderingContext2D.lineWidth", "lineWidth")}}, {{domxref("CanvasRenderingContext2D.lineCap", "lineCap")}}, {{domxref("CanvasRenderingContext2D.lineJoin", "lineJoin")}}, {{domxref("CanvasRenderingContext2D.miterLimit", "miterLimit")}}, {{domxref("CanvasRenderingContext2D.lineDashOffset", "lineDashOffset")}}, {{domxref("CanvasRenderingContext2D.shadowOffsetX", "shadowOffsetX")}}, {{domxref("CanvasRenderingContext2D.shadowOffsetY", "shadowOffsetY")}}, {{domxref("CanvasRenderingContext2D.shadowBlur", "shadowBlur")}}, {{domxref("CanvasRenderingContext2D.shadowColor", "shadowColor")}}, {{domxref("CanvasRenderingContext2D.globalCompositeOperation", "globalCompositeOperation")}}, {{domxref("CanvasRenderingContext2D.font", "font")}}, {{domxref("CanvasRenderingContext2D.textAlign", "textAlign")}}, {{domxref("CanvasRenderingContext2D.textBaseline", "textBaseline")}}, {{domxref("CanvasRenderingContext2D.direction", "direction")}}, {{domxref("CanvasRenderingContext2D.imageSmoothingEnabled", "imageSmoothingEnabled")}}.</li> + <li>현재의 <a href="/en-US/docs/Web/API/Canvas_API/Tutorial/Compositing#Clipping_paths">clipping path</a>, 이것은 다음 섹션에서 다루겠습니다.</li> +</ul> + +<p>여러분은 원하는 만큼 <code>save()</code> 메소드를 많이 호출할 수 있습니다. <code>restore()</code> 메소드를 호출할 때마다 마지막으로 저장된 상태가 스택에서 튀어나와 저장된 설정들을 모두 복원시킵니다.</p> + +<h3 id="A_save_and_restore_canvas_state_example" name="A_save_and_restore_canvas_state_example"><code>save</code>와 <code>restore</code> canvas 상태(state) 예제</h3> + +<p>사각형 세트를 연이어 그려서 drawing 상태를 가진 스택이 어떻게 기능하는지를 이 예제에서 설명하고자 합니다.</p> + +<pre class="brush: js; highlight:[5,10,15,18]">function draw() { + var ctx = document.getElementById('canvas').getContext('2d'); + + ctx.fillRect(0, 0, 150, 150); // 기본 설정으로 사각형을 그리기 + ctx.save(); // 기본 상태를 저장하기 + + ctx.fillStyle = '#09F'; // 설정 변경하기 + ctx.fillRect(15, 15, 120, 120); // 새로운 설정으로 사각형 그리기 + + ctx.save(); // 현재 상태 저장하기 + ctx.fillStyle = '#FFF'; // 설정 변경하기 + ctx.globalAlpha = 0.5; + ctx.fillRect(30, 30, 90, 90); // 새로운 설정으로 사각형 그리기 + + ctx.restore(); // 이전 상태 복원하기 + ctx.fillRect(45, 45, 60, 60); // 복원된 설정으로 사각형 그리기 + + ctx.restore(); // 초기 상태를 복원하기 + ctx.fillRect(60, 60, 30, 30); // 복원된 설정으로 사각형 그리기 +}</pre> + +<div class="hidden"> +<pre class="brush: html"><canvas id="canvas" width="150" height="150"></canvas></pre> + +<pre class="brush: js">draw();</pre> +</div> + +<p>첫 단계로 기본 설정으로 커다란 사각형을 그립니다. 그다음에는 이 상태를 저장하고 fill color를 바꿉니다. 그런 후에 두 번째이자 크기가 더 작은 파란 사각형을 그리고 그 상태를 저장합니다. 다시 한번 일부 drawing 설정을 바꾸고 세 번째 반투명한 흰 사각형을 그립니다. </p> + +<p>여기까지는 이전 섹션에서 했던 작업과 매우 유사합니다. 하지만 일단 첫 번째 <code>restore()</code> 문을 호출하면 스택에서 맨 위의 drawing 상태가 지워지고 설정이 복원됩니다. 만일 <code>save()</code>로 저장하지 않았다면, 이전 상태로 되돌리기 위해 fill color와 투명도를 일일이 바꿔주어야 했을 것입니다. 두 속성이라서 간단했을 테지만 그보다 더 많았으면 코드가 급속히 길어졌겠지요. </p> + +<p>두 번째 <code>restore()</code>문이 호출될 때, 초기 상태( 처음으로 <code>save</code>를 호출하기 전에 설정한 상태)가 복원되고 마지막 사각형은 한번 더 검게 그려집니다.</p> + +<p>{{EmbedLiveSample("A_save_and_restore_canvas_state_example", "180", "180", "https://mdn.mozillademos.org/files/249/Canvas_savestate.png")}}</p> + +<h2 id="Translating" name="Translating">이동(translating)</h2> + +<p><img alt="" class="internal" src="https://mdn.mozillademos.org/files/234/Canvas_grid_translate.png" style="float: right;">우리가 살펴볼 첫 번째 변형 메소드는 <code>translate()</code>입니다. 이 메소드는 그리드에서 canvas를 원점에서 다른 점으로 옮기는 데 사용됩니다. </p> + +<dl> + <dt>{{domxref("CanvasRenderingContext2D.translate", "translate(x, y)")}}</dt> + <dd>그리드에서 canvas와 그 원점을 이동합니다. <code>x</code>는 이동시킬 수평 거리를 가리키고, <code>y</code>는 그리드에서 수직으로 얼마나 멀리 떨어지는지를 표시합니다. </dd> +</dl> + +<p>변형하기 전에 canvas 상태를 저장하는 것이 좋습니다. 대다수의 경우, 원래 상태로 되돌리려고 역이동(reverse translation)을 시키는 것보다 <code>restore</code> 메소드를 호출하는 것이 더욱 간편합니다. 게다가 루프(loop) 안에서 이동하는 거라면 canvas 상태를 저장하고 복원하지 마세요. canvas 모서리 밖에서 그려지는 바람에 drawing의 일부를 잃어버리게 될지 모릅니다. </p> + +<h3 id="A_translate_example" name="A_translate_example"><code>translate</code> 예제</h3> + +<p>이 예제에서 canvas 원점의 이동에 관한 좋은 점을 일부 보여드리겠습니다. <code>translate()</code> 메소드를 쓰지 않으면 모든 사각형은 같은 위치 (0, 0)에 그려집니다. 또한, <code>translate()</code> 메소드는 사각형을 <code>fillRect()</code> function에서 좌표를 일일이 적으며 바꾸지 않아도 어디에나 위치할 수 있게 해줍니다. 이렇게 하면 이해하고 사용하기가 좀 더 쉽습니다. </p> + +<p> <code>draw()</code> function에서 두 개의 루프(loops)를 이용해 <code>fillRect()</code> function을 아홉 번 호출합니다. 루프마다 canvas가 이동하고 사각형이 그려지며, canvas는 원래 상태로 되돌아 갑니다. <code>fillRect()</code>로의 호출이 <code>translate()</code>에 의지해 drawing 위치를 바꾸는데 어떻게 매번 같은 좌표를 사용하는지 눈여겨 보세요.</p> + +<pre class="brush: js; highlight:[7]">function draw() { + var ctx = document.getElementById('canvas').getContext('2d'); + for (var i = 0; i < 3; i++) { + for (var j = 0; j < 3; j++) { + ctx.save(); + ctx.fillStyle = 'rgb(' + (51 * i) + ', ' + (255 - 51 * i) + ', 255)'; + ctx.translate(10 + j * 50, 10 + i * 50); + ctx.fillRect(0, 0, 25, 25); + ctx.restore(); + } + } +} +</pre> + +<div class="hidden"> +<pre class="brush: html"><canvas id="canvas" width="150" height="150"></canvas></pre> + +<pre class="brush: js">draw();</pre> +</div> + +<p>{{EmbedLiveSample("A_translate_example", "160", "160", "https://mdn.mozillademos.org/files/9857/translate.png")}}</p> + +<h2 id="Rotating" name="Rotating">회전(rotating)</h2> + +<p><img alt="" class="internal" src="https://mdn.mozillademos.org/files/233/Canvas_grid_rotate.png" style="float: right;">두 번째 변형 메소드는 <code>rotate()</code>입니다. canvas를 현재의 원점 둘레로 회전하는 데 사용합니다.</p> + +<dl> + <dt>{{domxref("CanvasRenderingContext2D.rotate", "rotate(angle)")}}</dt> + <dd>canvas를 현재 원점을 기준으로 라디안의 <code>angle</code> 숫자만큼 시계방향으로 회전시킵니다.</dd> +</dl> + +<p>회전의 중심점은 언제나 canvas 원점입니다. 중심점을 바꾸려면 <code>translate()</code> 메소드를 써서 canvas를 이동해야 합니다.</p> + +<h3 id="A_rotate_example" name="A_rotate_example"><code>rotate</code> 예제</h3> + +<p>이 예제는 사각형을 canvas 원점에서 먼저 회전하고 그다음에 <code>translate()</code>의 도움을 받아 사각형 자체의 중심에서 회전하는 데 <code>rotate()</code>를 사용합니다.</p> + +<div class="note"> +<p><strong>주의</strong>: 각도의 단위는 도(degree)가 아닌 라디안(radian)입니다. 변환하려면 <code>radians = (Math.PI/180)*degrees</code>.를 사용합니다.</p> +</div> + +<pre class="brush: js; highlight:[9, 23]">function draw() { + var ctx = document.getElementById('canvas').getContext('2d'); + + // 좌측 사각형, canvas 원점에서 회전하기 + ctx.save(); + // 파란 사각형 + ctx.fillStyle = '#0095DD'; + ctx.fillRect(30, 30, 100, 100); + ctx.rotate((Math.PI / 180) * 25); + // 회색 사각형 + ctx.fillStyle = '#4D4E53'; + ctx.fillRect(30, 30, 100, 100); + ctx.restore(); + + // 우측 사각형, 사각형 중심에서 회전하기 + // 파란 사각형 그리기 + ctx.fillStyle = '#0095DD'; + ctx.fillRect(150, 30, 100, 100); + + ctx.translate(200, 80); // 사각형 중심으로 이동하기 + // x = x + 0.5 * width + // y = y + 0.5 * height + ctx.rotate((Math.PI / 180) * 25); // 회전 + ctx.translate(-200, -80); // 예전 위치로 이동하기 + + // 회색 사각형 그리기 + ctx.fillStyle = '#4D4E53'; + ctx.fillRect(150, 30, 100, 100); +} +</pre> + +<p>사각형 자체의 중심 둘레로 회전하려면 사각형의 중심으로 canvas를 옮기세요. 그런 후에 canvas를 회전하고, 그 canvas를 0, 0로 되돌려 이동합니다. 그다음에 사각형을 그리세요.</p> + +<div class="hidden"> +<pre class="brush: html"><canvas id="canvas" width="300" height="200"></canvas></pre> + +<pre class="brush: js">draw();</pre> +</div> + +<p>{{EmbedLiveSample("A_rotate_example", "310", "210", "https://mdn.mozillademos.org/files/9859/rotate.png")}}</p> + +<h2 id="Scaling" name="Scaling">확대·축소(scaling)</h2> + +<p>다음 변형 메소드는 확대·축소(scaling)입니다. canvas 그리드에서 단위(units)를 키우거나 줄이는 데 사용합니다. 이는 벡터 모양과 비트맵(bitmaps) 요소를 축소하거나 확대해서 그리는 데 사용될 수 있습니다.</p> + +<dl> + <dt>{{domxref("CanvasRenderingContext2D.scale", "scale(x, y)")}}</dt> + <dd>canvas 단위를 수평으로 x만큼, 수직으로 y만큼 크기를 확대·축소합니다. 둘의 매개 변수는 실수입니다. 1.0보다 작은 값이면 단위의 크기를 축소하고, 1.0보다 큰 값이면 단위의 크기를 확대합니다. 값이 1.0이면 단위의 크기는 그대로입니다.</dd> +</dl> + +<p>음수를 이용해서 축을 대칭 시킬 수 있습니다(가령 <code>translate(0,canvas.height); scale(1,-1);</code>로 쓰는 것처럼 말이죠. 좌측 하단 모서리에 있는 원점을 이용한, 잘 알려진 카르테시안 좌표계(Cartesian coordinate)인 것이지요.</p> + +<p>기본적으로 canvas에서 하나의 단위는 정확히 1픽셀입니다. 예를 들어 0.5라는 확대·축소 비율을 적용한다면, 결과로 나오는 단위는 0.5 픽셀이 될 것이고, 고로 모양도 절반 크기로 그려질 것입니다. 이런 방식으로 크기 비율을 2.0으로 잡으면 단위 크기가 확대되어 하나의 단위는 이제 2픽셀이 되겠지요. 이 결과로 모양은 그만큼 2배로 커집니다.</p> + +<h3 id="A_scale_example" name="A_scale_example"><code>scale</code> 예제</h3> + +<p>마지막 예제로 다양한 확대·축소 비율을 이용해 모양을 그려보겠습니다.</p> + +<pre class="brush: js; highlight:[6,11]">function draw() { + var ctx = document.getElementById('canvas').getContext('2d'); + + // 간단하지만 확대·축소 비율을 적용한 사각형 그리기 + ctx.save(); + ctx.scale(10, 3); + ctx.fillRect(1, 10, 10, 10); + ctx.restore(); + + // 수평으로 대칭하기 + ctx.scale(-1, 1); + ctx.font = '48px serif'; + ctx.fillText('MDN', -135, 120); +} + +</pre> + +<div class="hidden"> +<pre class="brush: html"><canvas id="canvas" width="150" height="150"></canvas></pre> + +<pre class="brush: js">draw();</pre> +</div> + +<p>{{EmbedLiveSample("A_scale_example", "160", "160", "https://mdn.mozillademos.org/files/9861/scale.png")}}</p> + +<h2 id="Transforms" name="Transforms">변형(transforms)</h2> + +<p>마지막으로, 다음의 변형(transform) 메소드들은 변환 행렬(transformation matrix)로 변경할 사항을 즉시 적용할 수 있습니다.</p> + +<dl> + <dt>{{domxref("CanvasRenderingContext2D.transform", "transform(a, b, c, d, e, f)")}}</dt> + <dd>인수(arguments)에 표시된 행렬을 이용해 현재 변환 행렬을 곱합니다. 변환 행렬은 다음과 같이 작성됩니다. <br> + <math><semantics><mrow><mo>[</mo><mtable columnalign="center center center" rowspacing="0.5ex"><mtr><mtd><mi>a</mi></mtd><mtd><mi>c</mi></mtd><mtd><mi>e</mi></mtd></mtr><mtr><mtd><mi>b</mi></mtd><mtd><mi>d</mi></mtd><mtd><mi>f</mi></mtd></mtr><mtr><mtd><mn>0</mn></mtd><mtd><mn>0</mn></mtd><mtd><mn>1</mn></mtd></mtr></mtable><mo>]</mo></mrow><annotation encoding="TeX">\left[ \begin{array}{ccc} a & c & e \\ b & d & f \\ 0 & 0 & 1 \end{array} \right]</annotation></semantics></math></dd> +</dl> + +<dl> + <dd>만일 인수 중에 <code><a href="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Infinity" title="/en-US/docs/Web/JavaScript/Reference/Global_Objects/Infinity">Infinity</a></code>가 있다면, 변환 행렬은 예외 처리하는 메소드 대신에 반드시 infinite로 표시되어야 합니다.</dd> +</dl> + +<p>이 function의 매개 변수들은 다음과 같습니다.</p> + +<dl> + <dt><code>a (m11)</code></dt> + <dd>수평으로 확대·축소하기</dd> + <dt><em><code>b (m12)</code></em></dt> + <dd>수평으로 비스듬히 기울이기</dd> + <dt><code>c (m21)</code></dt> + <dd>수직으로 비스듬히 기울이기</dd> + <dt><code>d (m22)</code></dt> + <dd>수직으로 확대·축소하기</dd> + <dt><code>e (dx)</code></dt> + <dd>수평으로 이동하기</dd> + <dt><code>f (dy)</code></dt> + <dd>수직으로 이동하기</dd> + <dt>{{domxref("CanvasRenderingContext2D.setTransform", "setTransform(a, b, c, d, e, f)")}}</dt> + <dd>현재 변형 상태를 단위 행렬로 재설정하고 나서 동일한 인수로 <code>transform()</code> 메소드를 적용합니다. 이는 기본적으로 현재의 변형을 무효로 한 후에 명시된 변형으로 바뀌는데, 한번에 모든 게 진행됩니다.</dd> + <dt>{{domxref("CanvasRenderingContext2D.resetTransform", "resetTransform()")}}</dt> + <dd>현재 변형 상태를 단위 행렬로 재설정합니다. 이는 <code>ctx.setTransform(1, 0, 0, 1, 0, 0);</code> 호출과 같습니다.</dd> +</dl> + +<h3 id="transform과_setTransform_예제"><code>transform</code>과 <code>setTransform</code> 예제</h3> + +<pre class="brush: js; highlight:[12,15]">function draw() { + var ctx = document.getElementById('canvas').getContext('2d'); + + var sin = Math.sin(Math.PI / 6); + var cos = Math.cos(Math.PI / 6); + ctx.translate(100, 100); + var c = 0; + for (var i = 0; i <= 12; i++) { + c = Math.floor(255 / 12 * i); + ctx.fillStyle = 'rgb(' + c + ', ' + c + ', ' + c + ')'; + ctx.fillRect(0, 0, 100, 10); + ctx.transform(cos, sin, -sin, cos, 0, 0); + } + + ctx.setTransform(-1, 0, 0, 1, 100, 100); + ctx.fillStyle = 'rgba(255, 128, 255, 0.5)'; + ctx.fillRect(0, 50, 100, 100); +} +</pre> + +<div class="hidden"> +<pre class="brush: html"><canvas id="canvas" width="200" height="250"></canvas></pre> + +<pre class="brush: js">draw();</pre> +</div> + +<p>{{EmbedLiveSample("Example_for_transform_and_setTransform", "230", "280", "https://mdn.mozillademos.org/files/255/Canvas_transform.png")}}</p> + +<p>{{PreviousNext("Web/API/Canvas_API/Tutorial/Using_images", "Web/API/Canvas_API/Tutorial/Compositing")}}</p> diff --git a/files/ko/web/api/canvas_api/tutorial/using_images/index.html b/files/ko/web/api/canvas_api/tutorial/using_images/index.html new file mode 100644 index 0000000000..d9aae1c993 --- /dev/null +++ b/files/ko/web/api/canvas_api/tutorial/using_images/index.html @@ -0,0 +1,347 @@ +--- +title: Using images +slug: Web/HTML/Canvas/Tutorial/Using_images +tags: + - Advanced + - Canvas + - Graphics + - HTML + - Tutorial +translation_of: Web/API/Canvas_API/Tutorial/Using_images +--- +<div>{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Drawing_text", "Web/API/Canvas_API/Tutorial/Transformations" )}}</div> + +<div class="summary"> +<p>지금까지 우리는 Canvas를 가지고 스스로 <a href="/ko/docs/Web/API/Canvas_API/Tutorial/Drawing_shapes">도형</a>을 만들고 그 도형에 <a href="/ko/docs/Web/HTML/Canvas/Tutorial/Applying_styles_and_colors">스타일 적용</a> 해 보았습니다. 이미지를 사용 하는 기능은 {{HTMLElement("canvas")}}의 가장 흥미로운 기능중 하나입니다. 이 기능은 게임의 그래픽 배경이나 혹은 다이나믹한 사진 도음들을 위해 사용 될 수 있습니다. PNG,GIF, JPEG등 브라우저에서 지원되는 포맷형태라면 어떠한 외부 이미지라도 사용 될 수 있습니다. 같은 페이지 소스에서 다른 Canvas요소로 만들어진 이미지 또한 사용할수 있습니다!</p> +</div> + +<p>이미지를 캔버스로 불러오는것은 기본적으로 두 단계를 필요로 합니다:</p> + +<ol> + <li>{{domxref("HTMLImageElement")}} object를 참조하거나 다른 캔버스 요소를 소스로 사용합니다. 이는 URL을 가지고 이미지를 사용 할 수 있습니다.</li> + <li><code>drawImage()</code> function을 사용하여 캔버스에 나타난 이미지 위에 그림을 그립니다.</li> +</ol> + +<p>이 과정이 어떻게 되는지 봅시다.</p> + +<h2 id="이미지_불러오기">이미지 불러오기</h2> + +<p>canvas API는 아래의 데이터 타입을 이미지 소스로 사용 할 수 있습니다:</p> + +<dl> + <dt>{{domxref("HTMLImageElement")}}</dt> + <dd>{{HTMLElement("img")}} element와 마찬가지로, <code>Image()</code> constructor를 통해 만들어진 이미지입니다.</dd> +</dl> + +<dl> + <dt>{{domxref("SVGImageElement")}}</dt> + <dd>{{SVGElement("image")}} element 를 사용해 불러온 이미지입니다.</dd> +</dl> + + + +<dl> + <dt>{{domxref("HTMLVideoElement")}}</dt> + <dd>HTML {{HTMLElement("video")}} 요소를 이미지 소스로 사용하여 비디오의 현재 프레임을 이미지로 불러옵니다.</dd> + <dt>{{domxref("HTMLCanvasElement")}}</dt> + <dd>다른 {{HTMLElement("canvas")}} 요소를 이미지 소스로 사용합니다.</dd> +</dl> + +<p>이렇게 얻은 소스들은 {{domxref("CanvasImageSource")}}.를 사용하여 불러 올 수 있습니다.</p> + +<p>다음은 캔버스에 놓인 이미지를 사용하는 여러가지 방법입니다.</p> + +<h3 id="같은_페이지의_이미지_사용하기">같은 페이지의 이미지 사용하기</h3> + +<p>우리는 다음을 사용하여 같은 페이지에 있는 캔버스나 이미지를 참고 할 수 있습니다.</p> + +<ul> + <li>{{domxref("document.images")}} 모음</li> + <li>{{domxref("document.getElementsByTagName()")}} 메소드</li> + <li>사용 하고자 하는 특정한 이미지의 ID를 알고 있다면, {{domxref("document.getElementById()")}} 를 사용하여 특정한 이미지를 참고할 수 있습니다.</li> +</ul> + +<h3 id="다른_도메인의_이미지_사용하기">다른 도메인의 이미지 사용하기</h3> + +<p>Using the {{htmlattrxref("crossorigin", "img")}} attribute of an {{HTMLElement("img")}} element (reflected by the {{domxref("HTMLImageElement.crossOrigin")}} property), you can request permission to load an image from another domain for use in your call to <code>drawImage()</code>. If the hosting domain permits cross-domain access to the image, the image can be used in your canvas without tainting it; otherwise using the image will <a href="https://developer.mozilla.org/en-US/docs/HTML/CORS_Enabled_Image#What_is_a_.22tainted.22_canvas.3F" rel="internal">taint the canvas</a>.</p> + +<h3 id="다른_캔버스_요소_canvas_elements_사용하기">다른 캔버스 요소 (canvas elements) 사용하기</h3> + +<p>Just as with normal images, we access other canvas elements using either the {{domxref("document.getElementsByTagName()")}} or {{domxref("document.getElementById()")}} method. Be sure you've drawn something to the source canvas before using it in your target canvas.</p> + +<p>One of the more practical uses of this would be to use a second canvas element as a thumbnail view of the other larger canvas.</p> + +<h3 id="처음부터_이미지_만들기">처음부터 이미지 만들기</h3> + +<p>Another option is to create new {{domxref("HTMLImageElement")}} objects in our script. To do this, you can use the convenient <code>Image()</code> constructor:</p> + +<pre class="brush: js notranslate">var img = new Image(); // Create new img element +img.src = 'myImage.png'; // Set source path +</pre> + +<p>When this script gets executed, the image starts loading.</p> + +<p>If you try to call <code>drawImage()</code> before the image has finished loading, it won't do anything (or, in older browsers, may even throw an exception). So you need to be sure to use the load event so you don't try this before the image has loaded:</p> + +<pre class="brush: js notranslate">var img = new Image(); // Create new img element +img.addEventListener('load', function() { + // execute drawImage statements here +}, false); +img.src = 'myImage.png'; // Set source path +</pre> + +<p>If you're only using one external image this can be a good approach, but once you need to track more than one we need to resort to something more clever. It's beyond the scope of this tutorial to look at image pre-loading tactics, but you should keep that in mind.</p> + +<h3 id="데이터를_사용하여_이미지_불러오기Embedding_an_image_via_data_URL">데이터를 사용하여 이미지 불러오기Embedding an image via data: URL</h3> + +<p>Another possible way to include images is via the <a class="external" href="/en-US/docs/Web/HTTP/data_URIs" rel="external" title="http://en.wikipedia.org/wiki/Data:_URL">data: url</a>. Data URLs allow you to completely define an image as a Base64 encoded string of characters directly in your code.</p> + +<pre class="brush: js notranslate">var img = new Image(); // Create new img element +img.src = 'data:image/gif;base64,R0lGODlhCwALAIAAAAAA3pn/ZiH5BAEAAAEALAAAAAALAAsAAAIUhA+hkcuO4lmNVindo7qyrIXiGBYAOw=='; +</pre> + +<p>One advantage of data URLs is that the resulting image is available immediately without another round trip to the server. Another potential advantage is that it is also possible to encapsulate in one file all of your <a href="/en-US/docs/Web/CSS" title="/en-US/docs/Web/CSS">CSS</a>, <a href="/en-US/docs/Web/JavaScript" title="/en-US/docs/Web/JavaScript">JavaScript</a>, <a href="/en-US/docs/Web/HTML" title="/en-US/docs/Web/HTML">HTML</a>, and images, making it more portable to other locations.</p> + +<p>Some disadvantages of this method are that your image is not cached, and for larger images the encoded url can become quite long.</p> + +<h3 id="비디오_프레임_사용하기Using_frames_from_a_video">비디오 프레임 사용하기Using frames from a video</h3> + +<p>You can also use frames from a video being presented by a {{HTMLElement("video")}} element (even if the video is not visible). For example, if you have a {{HTMLElement("video")}} element with the ID "myvideo", you can do this:</p> + +<pre class="brush: js notranslate">function getMyVideo() { + var canvas = document.getElementById('canvas'); + if (canvas.getContext) { + var ctx = canvas.getContext('2d'); + + return document.getElementById('myvideo'); + } +} +</pre> + +<p>This returns the {{domxref("HTMLVideoElement")}} object for the video, which, as covered earlier, is one of the objects that can be used as a <code>CanvasImageSource</code>.</p> + +<h2 id="이미지_그리기">이미지 그리기</h2> + +<p>Once we have a reference to our source image object we can use the <code>drawImage()</code> method to render it to the canvas. As we will see later the <code>drawImage()</code> method is overloaded and has several variants. In its most basic form it looks like this:</p> + +<dl> + <dt>{{domxref("CanvasRenderingContext2D.drawImage", "drawImage(image, x, y)")}}</dt> + <dd>Draws the <code>CanvasImageSource</code> specified by the <code>image</code> parameter at the coordinates (<code>x</code>, <code>y</code>).</dd> +</dl> + +<div class="note"> +<p>SVG images must specify a width and height in the root <svg> element.</p> +</div> + +<h3 id="예제_기본_선_그래프">예제: 기본 선 그래프</h3> + +<p>In the following example, we will use an external image as the backdrop for a small line graph. Using backdrops can make your script considerably smaller because we can avoid the need for code to generate the background. In this example, we're only using one image, so I use the image object's <code>load</code> event handler to execute the drawing statements. The <code>drawImage()</code> method places the backdrop at the coordinate (0, 0), which is the top-left corner of the canvas.</p> + +<div class="hidden"> +<pre class="brush: html notranslate"><html> + <body onload="draw();"> + <canvas id="canvas" width="180" height="150"></canvas> + </body> +</html> +</pre> +</div> + +<pre class="brush: js;highlight[5] notranslate">function draw() { + var ctx = document.getElementById('canvas').getContext('2d'); + var img = new Image(); + img.onload = function() { + ctx.drawImage(img, 0, 0); + ctx.beginPath(); + ctx.moveTo(30, 96); + ctx.lineTo(70, 66); + ctx.lineTo(103, 76); + ctx.lineTo(170, 15); + ctx.stroke(); + }; + img.src = 'https://mdn.mozillademos.org/files/5395/backdrop.png'; +}</pre> + +<p>The resulting graph looks like this:</p> + +<p>{{EmbedLiveSample("Example_A_simple_line_graph", 220, 160, "https://mdn.mozillademos.org/files/206/Canvas_backdrop.png")}}</p> + +<h2 id="비례_크기_조정">비례 크기 조정</h2> + +<p>The second variant of the <code>drawImage()</code> method adds two new parameters and lets us place scaled images on the canvas.</p> + +<dl> + <dt>{{domxref("CanvasRenderingContext2D.drawImage", "drawImage(image, x, y, width, height)")}}</dt> + <dd>This adds the <code>width</code> and <code>height</code> parameters, which indicate the size to which to scale the image when drawing it onto the canvas.</dd> +</dl> + +<h3 id="예제_이미지를_타일처럼_배치">예제: 이미지를 타일처럼 배치</h3> + +<p>In this example, we'll use an image as a wallpaper and repeat it several times on the canvas. This is done simply by looping and placing the scaled images at different positions. In the code below, the first <code>for</code> loop iterates over the rows. The second <code>for</code> loop iterates over the columns. The image is scaled to one third of its original size, which is 50x38 pixels.</p> + +<div class="note"> +<p><strong>Note</strong>: Images can become blurry when scaling up or grainy if they're scaled down too much. Scaling is probably best not done if you've got some text in it which needs to remain legible.</p> +</div> + +<div class="hidden"> +<pre class="brush: html notranslate"><html> + <body onload="draw();"> + <canvas id="canvas" width="150" height="150"></canvas> + </body> +</html> +</pre> +</div> + +<pre class="brush: js notranslate">function draw() { + var ctx = document.getElementById('canvas').getContext('2d'); + var img = new Image(); + img.onload = function() { + for (var i = 0; i < 4; i++) { + for (var j = 0; j < 3; j++) { + ctx.drawImage(img, j * 50, i * 38, 50, 38); + } + } + }; + img.src = 'https://mdn.mozillademos.org/files/5397/rhino.jpg'; +}</pre> + +<p>The resulting canvas looks like this:</p> + +<p>{{EmbedLiveSample("Example_Tiling_an_image", 160, 160, "https://mdn.mozillademos.org/files/251/Canvas_scale_image.png")}}</p> + +<h2 id="이미지_자르기">이미지 자르기</h2> + +<p>The third and last variant of the <code>drawImage()</code> method has eight parameters in addition to the image source. It lets us cut out a section of the source image, then scale and draw it on our canvas.</p> + +<dl> + <dt>{{domxref("CanvasRenderingContext2D.drawImage", "drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)")}}</dt> + <dd>Given an <code>image</code>, this function takes the area of the source image specified by the rectangle whose top-left corner is (<code>sx</code>, <code>sy</code>) and whose width and height are <code>sWidth</code> and <code>sHeight</code> and draws it into the canvas, placing it on the canvas at (<code>dx</code>, <code>dy</code>) and scaling it to the size specified by <code>dWidth</code> and <code>dHeight</code>.</dd> +</dl> + +<p><img alt="" class="internal" src="https://mdn.mozillademos.org/files/225/Canvas_drawimage.jpg" style="float: right; height: 290px; width: 300px;">To really understand what this does, it may help to look at the image to the right. The first four parameters define the location and size of the slice on the source image. The last four parameters define the rectangle into which to draw the image on the destination canvas.</p> + +<p>Slicing can be a useful tool when you want to make compositions. You could have all elements in a single image file and use this method to composite a complete drawing. For instance, if you want to make a chart you could have a PNG image containing all the necessary text in a single file and depending on your data could change the scale of your chart fairly easily. Another advantage is that you don't need to load every image individually, which can improve load performance.</p> + +<h3 id="예제_이미지_프레임_넣기">예제: 이미지 프레임 넣기</h3> + +<p>In this example, we'll use the same rhino as in the previous example, but we'll slice out its head and composite it into a picture frame. The picture frame image is a 24-bit PNG which includes a drop shadow. Because 24-bit PNG images include a full 8-bit alpha channel, unlike GIF and 8-bit PNG images, it can be placed onto any background without worrying about a matte color.</p> + +<pre class="brush: html notranslate"><html> + <body onload="draw();"> + <canvas id="canvas" width="150" height="150"></canvas> + <div style="display:none;"> + <img id="source" src="https://mdn.mozillademos.org/files/5397/rhino.jpg" width="300" height="227"> + <img id="frame" src="https://mdn.mozillademos.org/files/242/Canvas_picture_frame.png" width="132" height="150"> + </div> + </body> +</html> +</pre> + +<pre class="brush: js notranslate">function draw() { + var canvas = document.getElementById('canvas'); + var ctx = canvas.getContext('2d'); + + // Draw slice + ctx.drawImage(document.getElementById('source'), + 33, 71, 104, 124, 21, 20, 87, 104); + + // Draw frame + ctx.drawImage(document.getElementById('frame'), 0, 0); +}</pre> + +<p>We took a different approach to loading the images this time. Instead of loading them by creating new {{domxref("HTMLImageElement")}} objects, we included them as {{HTMLElement("img")}} tags directly in our HTML source and retrieved the images from those. The images are hidden from output by setting the CSS property {{cssxref("display")}} to none for those images.</p> + +<p>{{EmbedLiveSample("Example_Framing_an_image", 160, 160, "https://mdn.mozillademos.org/files/226/Canvas_drawimage2.jpg")}}</p> + +<p>The script itself is very simple. Each {{HTMLElement("img")}} is assigned an ID attribute, which makes them easy to select using {{domxref("document.getElementById()")}}. We then simply use <code>drawImage()</code> to slice the rhino out of the first image and scale him onto the canvas, then draw the frame on top using a second <code>drawImage()</code> call.</p> + +<h2 id="아트_갤러리_예제">아트 갤러리 예제</h2> + +<p>In the final example of this chapter, we'll build a little art gallery. The gallery consists of a table containing several images. When the page is loaded, a {{HTMLElement("canvas")}} element is inserted for each image and a frame is drawn around it.</p> + +<p>In this case, every image has a fixed width and height, as does the frame that's drawn around them. You could enhance the script so that it uses the image's width and height to make the frame fit perfectly around it.</p> + +<p>The code below should be self-explanatory. We loop through the {{domxref("document.images")}} container and add new canvas elements accordingly. Probably the only thing to note, for those not so familiar with the DOM, is the use of the {{domxref("Node.insertBefore")}} method. <code>insertBefore()</code> is a method of the parent node (a table cell) of the element (the image) before which we want to insert our new node (the canvas element).</p> + +<pre class="brush: html notranslate"><html> + <body onload="draw();"> + <table> + <tr> + <td><img src="https://mdn.mozillademos.org/files/5399/gallery_1.jpg"></td> + <td><img src="https://mdn.mozillademos.org/files/5401/gallery_2.jpg"></td> + <td><img src="https://mdn.mozillademos.org/files/5403/gallery_3.jpg"></td> + <td><img src="https://mdn.mozillademos.org/files/5405/gallery_4.jpg"></td> + </tr> + <tr> + <td><img src="https://mdn.mozillademos.org/files/5407/gallery_5.jpg"></td> + <td><img src="https://mdn.mozillademos.org/files/5409/gallery_6.jpg"></td> + <td><img src="https://mdn.mozillademos.org/files/5411/gallery_7.jpg"></td> + <td><img src="https://mdn.mozillademos.org/files/5413/gallery_8.jpg"></td> + </tr> + </table> + <img id="frame" src="https://mdn.mozillademos.org/files/242/Canvas_picture_frame.png" width="132" height="150"> + </body> +</html> +</pre> + +<p>And here's some CSS to make things look nice:</p> + +<pre class="brush: css notranslate">body { + background: 0 -100px repeat-x url(https://mdn.mozillademos.org/files/5415/bg_gallery.png) #4F191A; + margin: 10px; +} + +img { + display: none; +} + +table { + margin: 0 auto; +} + +td { + padding: 15px; +} +</pre> + +<p>Tying it all together is the JavaScript to draw our framed images:</p> + +<pre class="brush: js notranslate">function draw() { + + // Loop through all images + for (var i = 0; i < document.images.length; i++) { + + // Don't add a canvas for the frame image + if (document.images[i].getAttribute('id') != 'frame') { + + // Create canvas element + canvas = document.createElement('canvas'); + canvas.setAttribute('width', 132); + canvas.setAttribute('height', 150); + + // Insert before the image + document.images[i].parentNode.insertBefore(canvas,document.images[i]); + + ctx = canvas.getContext('2d'); + + // Draw image to canvas + ctx.drawImage(document.images[i], 15, 20); + + // Add frame + ctx.drawImage(document.getElementById('frame'), 0, 0); + } + } +}</pre> + +<p>{{EmbedLiveSample("Art_gallery_example", 725, 400)}}</p> + +<h2 id="이미지_비율_습성scaling_behavior_제어하기">이미지 비율 습성(scaling behavior) 제어하기</h2> + +<p>As mentioned previously, scaling images can result in fuzzy or blocky artifacts due to the scaling process. You can use the drawing context's {{domxref("CanvasRenderingContext2D.imageSmoothingEnabled", "imageSmoothingEnabled")}} property to control the use of image smoothing algorithms when scaling images within your context. By default, this is <code>true</code>, meaning images will be smoothed when scaled. You can disable this feature like this:</p> + +<pre class="brush: js notranslate">ctx.mozImageSmoothingEnabled = false; +ctx.webkitImageSmoothingEnabled = false; +ctx.msImageSmoothingEnabled = false; +ctx.imageSmoothingEnabled = false; +</pre> + +<p>{{PreviousNext("Web/API/Canvas_API/Tutorial/Drawing_text", "Web/API/Canvas_API/Tutorial/Transformations")}}</p> diff --git a/files/ko/web/api/css_object_model/determining_the_dimensions_of_elements/index.html b/files/ko/web/api/css_object_model/determining_the_dimensions_of_elements/index.html new file mode 100644 index 0000000000..c9bb8b32ba --- /dev/null +++ b/files/ko/web/api/css_object_model/determining_the_dimensions_of_elements/index.html @@ -0,0 +1,28 @@ +--- +title: Determining the dimensions of elements +slug: Determining_the_dimensions_of_elements +translation_of: Web/API/CSS_Object_Model/Determining_the_dimensions_of_elements +--- +<p>엘리먼트의 너비와 높이를 알기 위해 살펴볼 수 있는 여러 속성이 있습니다. 또한, 요구하는 사항에 딱 맞는 것을 고르기 다소 까다로울 수도 있습니다. 이 글은 여러분이 필요에 맞는 속성을 고르는데 도움을 주기 위해 작성했습니다.</p> + +<h3 id="How_much_room_does_it_use_up.3F" name="How_much_room_does_it_use_up.3F">공간을 얼마나 차지하나요?</h3> + +<p>표시된 컨텐트의 너비, 스크롤바, 패딩까지 포함해서 엘리먼트가 차지하는 전체 공간을 알고 싶다면, <code><a href="/en/DOM/element.offsetWidth" title="en/DOM/element.offsetWidth">offsetWidth</a></code>와 <code><a href="/en/DOM/element.offsetHeight" title="en/DOM/element.offsetHeight">offsetHeight</a> 속성을 사용하세요:</code></p> + +<p><img alt="Image:Dimensions-offset.png" class="internal" src="/@api/deki/files/186/=Dimensions-offset.png"></p> + +<h3 id="What.27s_the_size_of_the_displayed_content.3F" name="What.27s_the_size_of_the_displayed_content.3F">보이는 컨텐트의 크기는요?</h3> + +<p>패딩은 포함하되 경계선, 여백, 스크롤바는 포함시키지 않고 보이는 컨텐트가 실제로 차지하는 공간이 알고 싶다면, <code><a href="/en/DOM/element.clientWidth" title="en/DOM/element.clientWidth">clientWidth</a></code>와 <code><a href="/en/DOM/element.clientHeight" title="en/DOM/element.clientHeight">clientHeight</a></code> 속성을 사용하세요:</p> + +<p><img alt="Image:Dimensions-client.png" class="internal" src="/@api/deki/files/185/=Dimensions-client.png"></p> + +<h3 id="How_big_is_the_content.3F" name="How_big_is_the_content.3F">컨텐트는 얼마나 크나요?</h3> + +<p>컨텐트의 실제 크기를 알고 싶다면(보여지는 부분만이 아닌 전체 컨텐트 크기), <code><a href="/en/DOM/element.scrollWidth" title="en/DOM/element.scrollWidth">scrollWidth</a></code>와 <code><a href="/en/DOM/element.scrollHeight" title="en/DOM/element.scrollHeight">scrollHeight</a></code> 속성을 사용하세요. 이 속성들은 엘리먼트 컨텐트의 전체 크기에 해당하는 너비와 높이를 반환합니다. 보여지는 영역이 작아서 스크롤바를 사용하고 있다해도 관계없습니다.</p> + +<p>예를 들어, 600x400 픽셀 크기의 엘리먼트가 300x300 픽셀의 스크롤박스에서 보여진다면 <code>scrollWidth</code>는 600을, <code>scrollHeight</code>는 400을 각각 반환합니다.</p> + +<h3 id="References" name="References">참고자료</h3> + +<p><a href="https://docs.microsoft.com/en-us/previous-versions//hh781509(v=vs.85)">MSDN: Measuring Element Dimension and Location</a></p> diff --git a/files/ko/web/api/css_object_model/managing_screen_orientation/index.html b/files/ko/web/api/css_object_model/managing_screen_orientation/index.html new file mode 100644 index 0000000000..934384d0bf --- /dev/null +++ b/files/ko/web/api/css_object_model/managing_screen_orientation/index.html @@ -0,0 +1,136 @@ +--- +title: Managing screen orientation +slug: WebAPI/Managing_screen_orientation +translation_of: Web/API/CSS_Object_Model/Managing_screen_orientation +--- +<p>{{SeeCompatTable}}</p> +<h2 id="Summary">Summary</h2> +<p>Screen orientation 은 <a href="/en-US/docs/WebAPI/Detecting_device_orientation" title="/en-US/docs/WebAPI/Detecting_device_orientation">device orientation</a> 과는 조금 다르다. 비록 장치가 방향을 감지 못하더라도 화면은 언제나 방향을 가지고 있다. 그리고 만약 장치가 방향을 알 수 있더라도 웹 어플리케이션의 인터페이스를 유지하거나 적응하기 위해 화면의 방향을 조정하는 능력을 갖는게 좋다.</p> +<p>화면의 방향을 다루기 위한 여러 방법이 있는데, CSS 와 JavaScript 이다. 첫 번째는 <a href="/en-US/docs/CSS/Media_queries#orientation" title="en-US/CSS/Media queries#orientation">orientation media query</a> 이다. 이것은 내용이 CSS를 사용해서 레이아웃을 조정하게 하는데, 브라우저 창이 가로 모드 (너비가 높이보다 큼) 또는 세로모드 (높이가 너비보다 큼) 여부에 달려 있다.</p> +<p>두번째 방법은 JavaScript Screen orientation API 인데 이것은 화면의 현재 방향을 구하고 잠그는데 사용할 수 있다.</p> +<h2 id="Adjusting_layout_based_on_the_orientation">Adjusting layout based on the orientation</h2> +<p>방향 변환에서 가장 흔한 케이스 중 하나는 장치의 방향에 따라 내용의 레이아웃을 조정 하는 것이다. 예를 들자면, 당신은 버튼바를 장치 화면의 가장 긴 크기로 펼치고 싶어 할 수 있는데, media query를 이용해서 쉽고 자동으로 할 수 있다.</p> +<p>다음의 HTML code 예제를 보자</p> +<pre class="brush: html"><ul id="toolbar"> + <li>A</li> + <li>B</li> + <li>C</li> +</ul> + +<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis lacinia nisi nec sem viverra vitae fringilla nulla ultricies. In ac est dolor, quis tincidunt leo. Cras commodo quam non tortor consectetur eget rutrum dolor ultricies. Ut interdum tristique dapibus. Nullam quis malesuada est.</p> +</pre> +<p>CSS 는 화면 방향에 따라 <span style="line-height: inherit;">특정 스타일을 을 </span><span style="line-height: inherit;">다루기 위해 orientation media query 에 의존한다</span></p> +<pre class="brush: css">/* First let's define some common styles */ + +html, body { + width : 100%; + height: 100%; +} + +body { + border: 1px solid black; + + -moz-box-sizing: border-box; + box-sizing: border-box; +} + +p { + font : 1em sans-serif; + margin : 0; + padding: .5em; +} + +ul { + list-style: none; + + font : 1em monospace; + margin : 0; + padding: .5em; + + -moz-box-sizing: border-box; + box-sizing: border-box; + + background: black; +} + +li { + display: inline-block; + margin : 0; + padding: 0.5em; + background: white; +} +</pre> +<p>Once we have some common styles we can start defining a special case for the orientation</p> +<pre class="brush: css">/* For portrait, we want the tool bar on top */ + +@media screen and (orientation: portrait) { + #toolbar { + width: 100%; + } +} + +/* For landscape, we want the tool bar stick on the left */ + +@media screen and (orientation: landscape) { + #toolbar { + position: fixed; + width: 2.65em; + height: 100%; + } + + p { + margin-left: 2em; + } + + li + li { + margin-top: .5em; + } +} +</pre> +<p>실행 결과를 보자</p> +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Portrait</th> + <th scope="col">Landscape</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{ EmbedLiveSample('Adjusting_layout_based_on_the_orientation', 180, 350) }}</td> + <td>{{ EmbedLiveSample('Adjusting_layout_based_on_the_orientation', 350, 180) }}</td> + </tr> + </tbody> +</table> +<div class="note"> + <p><strong>Note:</strong> orientation media query 는 실제로 브라우저 창 (또는 iframe) 의 방향에 따라 적용한다. 장치의 방향이 아니다.</p> +</div> +<h2 id="Locking_the_screen_orientation">Locking the screen orientation</h2> +<div class="warning"> + <p><strong>Warning:</strong> 이 API 는 실험적이며 현재 <a href="/en-US/docs/Mozilla/Firefox_OS" title="/en-US/docs/Mozilla/Firefox_OS">Firefox OS</a> 와 <a href="/en-US/docs/Mozilla/Firefox_for_Android" title="/en-US/docs/Mozilla/Firefox_for_Android">Firefox for Android</a> 에서 <code>moz</code> 접두사를 이용하여 사용할 수 있다.</p> +</div> +<p>몇몇 장치들은 (주로 모바일 장치) 사용자가 언제나 화면을 읽을 수 있게 장치의 방향에 따라 동적으로 화면의 방향을 변화시킬 수 있다. 만약 이러한 행위가 텍스트 컨텐츠에 적합하다면, 이러한 변화 때문에 고통 받을 수 있는 켄텐츠도 있다. 예를 들어, 장치의 방향에 따른 게임들은 이러한 방향전환 때문에 혼란스러울 수 있다.</p> +<p>Screen Orientation API 는 정확히 그러한 변화를 방지하기 위해 만들어졌다.</p> +<h3 id="Listening_orientation_change">Listening orientation change</h3> +<p>{{event("orientationchange")}} 이벤트는 장치가 화면의 방향을 변환할 때와 <span style="line-height: inherit;">방향이 {{domxref("window.screen.orientation","screen.orientation")}} 속성과 함께 읽혀질 때 </span><span style="line-height: inherit;">마다 불려 진다. </span></p> +<pre class="brush: js">screen.addEventListener("orientationchange", function () { + console.log("The orientation of the screen is: " + screen.orientation); +}); +</pre> +<h3 id="Preventing_orientation_change">Preventing orientation change</h3> +<p>모든 웹 어플리케이션은 필요에 따라 스크린을 잠굴 수 있다. 화면은 {{domxref("window.screen.lockOrientation","screen.lockOrientation()")}} 함수를 사용하여 잠그고 {{domxref("window.screen.unlockOrientation","screen.unlockOrientation()")}}. 함수로 잠금 해제 한다.</p> +<p>{{domxref("window.screen.lockOrientation","screen.lockOrientation()")}} 는 적용 할 잠금의 종류를 정의하는 문자열 <span style="line-height: inherit;"> (또는 일련의 문자열) </span><span style="line-height: inherit;">을 수용한다. 수용하는 값들: </span><code style="font-size: 14px; line-height: inherit;">portrait-primary</code><span style="line-height: inherit;">, </span><code style="font-size: 14px; line-height: inherit;">portrait-secondary</code><span style="line-height: inherit;">, </span><code style="font-size: 14px; line-height: inherit;">landscape-primary</code><span style="line-height: inherit;">, </span><code style="font-size: 14px; line-height: inherit;">landscape-secondary</code><span style="line-height: inherit;">, </span><code style="font-size: 14px; line-height: inherit;">portrait</code><span style="line-height: inherit;">, </span><code style="font-size: 14px; line-height: inherit;">landscape</code><span style="line-height: inherit;"> (각각의 값들에 대해 좀 더 알려면 {{domxref("window.screen.lockOrientation","lockOrientation")}} 를 보라).</span></p> +<pre class="brush: js">screen.lockOrientation('landscape');</pre> +<div class="note"> + <p><strong>Note:</strong> 화면 잠금은 웹 어플리케이션에 따라 다르다. 어플레케이션 A이 가로모드로 잠겨 있고 어플레케이션 B가 세로모드로 잠겨 있을 때, 어플리케이션을 A 에서 B 로 또는 B 에서 A 로 전환하면 {{event("orientationchange")}} 를 호출하지 않는다. 왜냐하면 각 어플리케이션은 각자의 방향을 유지 하기 때문이다.</p> + <p>그러나, 만약 잠금요구를 만족하기 위해 방향이 바뀌어야한다면 화면잠금은 {{event("orientationchange")}} 이벤트를 호출 할 수 있다.</p> +</div> +<h2 id="See_also">See also</h2> +<ul> + <li>{{domxref("window.screen.orientation","screen.orientation")}}</li> + <li>{{domxref("window.screen.lockOrientation()","screen.lockOrientation()")}}</li> + <li>{{domxref("window.screen.unlockOrientation()","screen.unlockOrientation()")}}</li> + <li>{{domxref("window.screen.onorientationchange","screen.onorientationchange")}}</li> + <li><a href="/en-US/docs/CSS/Media_queries#orientation" title="en-US/CSS/Media queries#orientation">The orientation media query</a></li> + <li><a class="external" href="http://hacks.mozilla.org/2009/06/media-queries/" title="http://hacks.mozilla.org/2009/06/media-queries/">A short introduction to media queries in Firefox 3.5</a></li> +</ul> diff --git a/files/ko/web/api/detecting_device_orientation/index.html b/files/ko/web/api/detecting_device_orientation/index.html new file mode 100644 index 0000000000..664842f66d --- /dev/null +++ b/files/ko/web/api/detecting_device_orientation/index.html @@ -0,0 +1,273 @@ +--- +title: 기기 방향 감지하기 +slug: WebAPI/Detecting_device_orientation +translation_of: Web/API/Detecting_device_orientation +--- +<div>{{SeeCompatTable}}</div> + +<h2 id="요약">요약</h2> + +<p>웹을 이용 가능한 기기들은 자신들의 방향을 알 수 있게 되었다. 즉, 중력과의 관계에서 자신의 방향의 변화를 나타내는 데이터를 알 수 있다는 뜻이다. 특히, 휴대 전화와 같이 손에 쥐고 쓸 수 있는 기기들은 이 정보를 화면을 수직으로 유지하기 위해 자동으로 회전시키는데 사용할 수 있고, 기기가 회전되어서 폭이 높이보다 길 때는 와이드 스크린으로 표시할 수 있게 된다.</p> + +<p>방향 정보를 다루는 두 가지 방법의 JavaScript 이벤트가 있다. 첫 번째는 {{domxref("DeviceOrientationEvent")}}로 가속도계가 기기의 방향의 변화를 감지했을 때 발생한다. 이 방향 이벤트들에 의해 보고되는 데이터를 받아서 처리함으로써, 사용자들이 기기를 움직이여서 생기는 방향과 높이의 변화를 상호 작용적으로 응답할 수 있게 된다.</p> + +<p>두 번째 이벤트는 {{domxref("DeviceMotionEvent")}}로 가속도에 변화가 일어났을 때 발생한다. 이 이벤트는 {{domxref("DeviceOrientationEvent")}}와는 방향이 아닌 가속도를 감지하고 있다는 점에서 다르다. 일반적으로{{domxref("DeviceMotionEvent")}}를 감지할 수 있는 센서들은 저장 장치들을 충격으로부터 보호하기 위해 노트북에서 사용되는 센서들을 포함한다. {{domxref("DeviceOrientationEvent")}}는 모바일 기기에서 주로 더 많이 나타난다.</p> + +<h2 id="방향_이벤트_처리하기">방향 이벤트 처리하기</h2> + +<p>방향의 변화를 받기 위해 여러분이 해야하는 것은 {{ event("deviceorientation") }} 이벤트에 리스너를 등록하는 것 뿐이다:</p> + +<pre class="brush: js">window.addEventListener("deviceorientation", handleOrientation, true); +</pre> + +<p>이벤트 리스너를 등록한 후에는 (여기에서는 JavaScript 함수 handleOrientation()), 리스너 함수가 업데이트 된 방향 데이터와 함께 주기적으로 호출된다.</p> + +<p>방향 이벤트는 다음 네 개의 값을 가진다:</p> + +<ul> + <li>{{ domxref("DeviceOrientationEvent.absolute") }}</li> + <li>{{ domxref("DeviceOrientationEvent.alpha") }}</li> + <li>{{ domxref("DeviceOrientationEvent.beta") }}</li> + <li>{{ domxref("DeviceOrientationEvent.gamma") }}</li> +</ul> + +<p>이벤트 핸들러 함수는 보통 다음과 같다:</p> + +<pre class="brush: js">function handleOrientation(event) { + var absolute = event.absolute; + var alpha = event.alpha; + var beta = event.beta; + var gamma = event.gamma; + + // Do stuff with the new orientation data +} +</pre> + +<h3 id="방향_값_설명">방향 값 설명</h3> + +<p>각 축으로부터 보고된 값은 표준 좌표계 축을 중심으로 회전한 양을 가리킨다. 더 자세한 내용은 <a href="/en-US/DOM/Orientation_and_motion_data_explained" title="Orientation and motion data explained">Orientation and motion data explained</a> 문서에 나와있으며, 다음은 이를 간략하게 요약한 것이다.</p> + +<ul> + <li>{{ domxref("DeviceOrientationEvent.alpha") }} 값은 0도부터 360도까지 범위의 z축을 중심으로 한 기기의 움직임을 나타낸다.</li> + <li>{{ domxref("DeviceOrientationEvent.beta") }} 값은 -180도부터 180도까지 범위의 x축을 줌심으로 한 기기의 움직임을 나타낸다. 이는 기기의 앞뒤 움직임을 나타낸다.</li> + <li>{{ domxref("DeviceOrientationEvent.gamma") }} 값은 -90도부터 90도까지 범위의 y축을 중심으로 한 기기의 움직임을 나타낸다. 이는 기기의 좌우 움직임을 나타낸다.</li> +</ul> + +<h3 id="방향_예제">방향 예제</h3> + +<p>이 예제는 {{event("deviceorientation")}} 이벤트를 지원하고 방향을 감지할 수 있는 기기에서 실행중인 모든 브라우저에서 작동한다.</p> + +<p>자 그럼, 정원에 공이 하나 있다고 상상해보자:</p> + +<pre class="brush: html"><div class="garden"> + <div class="ball"></div> +</div> + +<pre class="output"></pre> +</pre> + +<p>이 정원은 가로 세로 200 픽셀이고(그렇다, 작은 정원이다), 정 중앙에 공이 있다:</p> + +<pre class="brush: css">.garden { + position: relative; + width : 200px; + height: 200px; + border: 5px solid #CCC; + border-radius: 10px; +} + +.ball { + position: absolute; + top : 90px; + left : 90px; + width : 20px; + height: 20px; + background: green; + border-radius: 100%; +} +</pre> + +<p>이제, 우리가 기기를 움직이면 공도 따라서 움직일 것이다:</p> + +<pre class="brush: js">var ball = document.querySelector('.ball'); +var garden = document.querySelector('.garden'); +var output = document.querySelector('.output'); + +var maxX = garden.clientWidth - ball.clientWidth; +var maxY = garden.clientHeight - ball.clientHeight; + +function handleOrientation(event) { + var x = event.beta; // In degree in the range [-180,180] + var y = event.gamma; // In degree in the range [-90,90] + + output.innerHTML = "beta : " + x + "\n"; + output.innerHTML += "gamma: " + y + "\n"; + + // Because we don't want to have the device upside down + // We constrain the x value to the range [-90,90] + if (x > 90) { x = 90}; + if (x < -90) { x = -90}; + + // To make computation easier we shift the range of + // x and y to [0,180] + x += 90; + y += 90; + + // 10 is half the size of the ball + // It center the positionning point to the center of the ball + ball.style.top = (maxX*x/180 - 10) + "px"; + ball.style.left = (maxY*y/180 - 10) + "px"; +} + +window.addEventListener('deviceorientation', handleOrientation); +</pre> + +<p>여기 실제로 실행해 볼 수 있는 예제이다:</p> + +<div>{{ EmbedLiveSample('Orientation_example', '230', '260') }}</div> + +<div class="warning"> +<p><strong>경고:</strong> Chrome과 Firefox는 동일한 방식으로 각을 다루지 않습니다. 그래서 어떤 축의 방향은 반대가 됩니다.</p> +</div> + +<h2 id="모션_이벤트_처리하기">모션 이벤트 처리하기</h2> + +<p>모션 이벤트는 이벤트 이름이 {{ event("devicemotion") }}으로 다르다는 점을 제외하면, 방향 이벤트를 처리하는 방법과 동일하다.</p> + +<pre class="brush: js">window.addEventListener("devicemotion", <em>handleMotion</em>, true);</pre> + +<p><em>HandleMotion</em> 함수의 파라미터로 넘겨진 {{ domxref("DeviceMotionEvent") }} 객체에 실제로 변화된 정보들이 담겨져 있다.</p> + +<p>모션 이벤트는 다음 네 가지 속성을 가진다:</p> + +<ul> + <li>{{ domxref("DeviceMotionEvent.acceleration") }}</li> + <li>{{ domxref("DeviceMotionEvent.accelerationIncludingGravity") }}</li> + <li>{{ domxref("DeviceMotionEvent.rotationRate") }}</li> + <li>{{ domxref("DeviceMotionEvent.interval") }}</li> +</ul> + +<h3 id="모션_값_설명">모션 값 설명</h3> + +<p>{{ domxref("DeviceMotionEvent") }} 객체는 웹 개발자들에게 기기의 위치와 방향의 변화 속도에 관한 정보를 제공한다. 세 개의 축에 따라 변화한 정보가 제공된다 (자세한 내용은 <a href="/en-US/docs/Web/Guide/DOM/Events/Orientation_and_motion_data_explained" title="/en-US/docs/Web/Guide/DOM/Events/Orientation_and_motion_data_explained">Orientation and motion data explained</a> 문서를 참조).</p> + +<p>{{domxref("DeviceMotionEvent.acceleration","acceleration")}}과 {{domxref("DeviceMotionEvent.accelerationIncludingGravity","accelerationIncludingGravity")}}에서, 각 축은 다음에 해당된다:</p> + +<ul> + <li><code>x</code>: 서쪽에서 동쪽으로 나타나는 축을 의미한다</li> + <li><code>y</code>: 남쪽에서 북쪽으로 나타나는 축을 의미한다</li> + <li><code>z</code>: 땅에서 수직으로 나타나는 축을 의미한다</li> +</ul> + +<p>{{domxref("DeviceMotionEvent.rotationRate","rotationRate")}}에서, 조금은 다르게, 각 값들은 다음에 해당된다:</p> + +<ul> + <li><code>alpha</code>: 화면(또는 데스크탑의 키보드)에 수직인 축을 따른 회전율을 의미한다</li> + <li><code>beta</code>: 화면(또는 데스크탑의 키보드)의 평면의 왼쪽에서 오른쪽으로 나타나는 축을 따른 회전율을 의미한다</li> + <li><code>gamma</code>: 화면(또는 데스크탑의 키보드)의 평면의 아래에서 위쪽으로 나타나는 축을 따른 회전율을 의미한다</li> +</ul> + +<p>마지막으로, {{domxref("DeviceMotionEvent.interval","interval")}}은 기기에서 데이터를 얻을 수 있는 시간 간격(단위는 밀리초)을 의미한다.</p> + +<h2 id="스펙">스펙</h2> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Specification</th> + <th scope="col">Status</th> + <th scope="col">Comment</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{SpecName('Device Orientation')}}</td> + <td>{{Spec2('Device Orientation')}}</td> + <td>Initial specification.</td> + </tr> + </tbody> +</table> + +<h2 id="브라우저_호환성">브라우저 호환성</h2> + +<p>{{ CompatibilityTable() }}</p> + +<div id="compat-desktop"> +<table class="compat-table"> + <tbody> + <tr> + <th>Feature</th> + <th>Chrome</th> + <th>Firefox (Gecko)</th> + <th>Internet Explorer</th> + <th>Opera</th> + <th>Safari (WebKit)</th> + </tr> + <tr> + <td>{{domxref("DeviceOrientationEvent")}}</td> + <td>7.0</td> + <td>3.6<sup>[1]</sup><br> + 6</td> + <td>{{ CompatUnknown() }}</td> + <td>{{ CompatUnknown() }}</td> + <td>{{ CompatUnknown() }}</td> + </tr> + <tr> + <td>{{domxref("DeviceMotionEvent")}}</td> + <td>{{ CompatVersionUnknown() }}</td> + <td>6</td> + <td>{{ CompatUnknown() }}</td> + <td>{{ CompatUnknown() }}</td> + <td>{{ CompatUnknown() }}</td> + </tr> + </tbody> +</table> +</div> + +<div id="compat-mobile"> +<table class="compat-table"> + <tbody> + <tr> + <th>Feature</th> + <th>Android</th> + <th>Firefox Mobile (Gecko)</th> + <th>IE Phone</th> + <th>Opera Mobile</th> + <th>Safari Mobile</th> + </tr> + <tr> + <td>{{domxref("DeviceOrientationEvent")}}</td> + <td>3.0</td> + <td>3.6<sup>[1]</sup><br> + 6</td> + <td>{{ CompatNo() }}</td> + <td>{{ CompatNo() }}</td> + <td>4.2</td> + </tr> + <tr> + <td>{{domxref("DeviceMotionEvent")}}</td> + <td>{{ CompatVersionUnknown() }}</td> + <td>6</td> + <td>{{ CompatUnknown() }}</td> + <td>{{ CompatUnknown() }}</td> + <td><span style="font-size: 12px; line-height: 18px;">4.2</span></td> + </tr> + </tbody> +</table> +</div> + +<h3 id="Gecko_구현_참고_사항">Gecko 구현 참고 사항</h3> + +<ol> + <li>Firefox 3.6, 4, 5는 표준인 {{domxref("DeviceOrientationEvent")}} 이벤트가 아닌 <a href="/en-US/DOM/MozOrientation" title="MozOrientation">mozOrientation </a>을 지원한다</li> +</ol> + +<h2 id="참고_자료">참고 자료</h2> + +<ul> + <li>{{domxref("DeviceOrientationEvent")}}</li> + <li>{{domxref("DeviceMotionEvent")}}</li> + <li>The legacy <code><a href="/en-US/DOM/MozOrientation" title="en-US/DOM/MozOrientation">MozOrientation</a></code> event.</li> + <li><a href="/en-US/docs/Web/Guide/DOM/Events/Orientation_and_motion_data_explained" title="Orientation and motion data explained">Orientation and motion data explained</a></li> + <li><a href="/en-US/docs/Web/Guide/DOM/Events/Using_device_orientation_with_3D_transforms" title="Using Deviceorientation In 3D Transforms">Using deviceorientation in 3D Transforms</a></li> +</ul> diff --git a/files/ko/web/api/event/createevent/index.html b/files/ko/web/api/document/createevent/index.html index 549a51bfdc..549a51bfdc 100644 --- a/files/ko/web/api/event/createevent/index.html +++ b/files/ko/web/api/document/createevent/index.html diff --git a/files/ko/web/api/document_object_model/소개/index.html b/files/ko/web/api/document_object_model/introduction/index.html index b31dbc43d9..b31dbc43d9 100644 --- a/files/ko/web/api/document_object_model/소개/index.html +++ b/files/ko/web/api/document_object_model/introduction/index.html diff --git a/files/ko/web/api/document/getselection/index.html b/files/ko/web/api/documentorshadowroot/getselection/index.html index c4d219fbde..c4d219fbde 100644 --- a/files/ko/web/api/document/getselection/index.html +++ b/files/ko/web/api/documentorshadowroot/getselection/index.html diff --git a/files/ko/web/api/element/blur_event/index.html b/files/ko/web/api/element/blur_event/index.html new file mode 100644 index 0000000000..3bbcc6acb0 --- /dev/null +++ b/files/ko/web/api/element/blur_event/index.html @@ -0,0 +1,154 @@ +--- +title: blur +slug: Web/Events/blur +translation_of: Web/API/Element/blur_event +--- +<p><code>blur</code> 이벤트는 엘리먼트의 포커스가 해제되었을때 발생합니다. 이 이벤트와 <code><a href="/en-US/docs/Mozilla_event_reference/focusout">focusout</a></code> 이벤트의 가장 다른점은 <code><a href="/en-US/docs/Mozilla_event_reference/focusout">focusout</a></code> 은 이벤트 버블링이 발생합니다.</p> + +<h2 id="General_info">General info</h2> + +<dl> + <dt style="float: left; text-align: right; width: 120px;">Specification</dt> + <dd style="margin: 0 0 0 120px;"><a class="external" href="http://www.w3.org/TR/DOM-Level-3-Events/#event-type-blur">DOM L3</a></dd> + <dt style="float: left; text-align: right; width: 120px;">Interface</dt> + <dd style="margin: 0 0 0 120px;">{{domxref("FocusEvent")}}</dd> + <dt style="float: left; text-align: right; width: 120px;">Bubbles</dt> + <dd style="margin: 0 0 0 120px;">No</dd> + <dt style="float: left; text-align: right; width: 120px;">Cancelable</dt> + <dd style="margin: 0 0 0 120px;">No</dd> + <dt style="float: left; text-align: right; width: 120px;">Target</dt> + <dd style="margin: 0 0 0 120px;">Element</dd> + <dt style="float: left; text-align: right; width: 120px;">Default Action</dt> + <dd style="margin: 0 0 0 120px;">None.</dd> +</dl> + +<p>{{NoteStart}} 이 이벤트가 처리될때 {{domxref("Document.activeElement")}}의 값이 브라우저마다 다릅니다 ({{bug(452307)}}): IE10은 이 값을 포커스가 옮겨가는 엘리먼트에 추가하지만, 파이어폭스와 크롬은 도큐먼트의 <code>body</code> 에 추가합니다.{{NoteEnd}}</p> + +<h2 id="Properties">Properties</h2> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Property</th> + <th scope="col">Type</th> + <th scope="col">Description</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>target</code> {{readonlyInline}}</td> + <td>{{domxref("EventTarget")}}</td> + <td>Event target (DOM element)</td> + </tr> + <tr> + <td><code>type</code> {{readonlyInline}}</td> + <td>{{domxref("DOMString")}}</td> + <td>The type of event.</td> + </tr> + <tr> + <td><code>bubbles</code> {{readonlyInline}}</td> + <td>{{jsxref("Boolean")}}</td> + <td>Whether the event normally bubbles or not.</td> + </tr> + <tr> + <td><code>cancelable</code> {{readonlyInline}}</td> + <td>{{jsxref("Boolean")}}</td> + <td>Whether the event is cancellable or not.</td> + </tr> + <tr> + <td><code>relatedTarget</code> {{readonlyInline}}</td> + <td>{{domxref("EventTarget")}} (DOM element)</td> + <td>null</td> + </tr> + </tbody> +</table> + +<h2 id="이벤트_위임">이벤트 위임</h2> + +<p>이 이벤트에 이벤트 위임을 적용하는 방법은 두가지가 있습니다 : 브라우저가 지원한다면 <code>focusout</code> 이벤트를 사용하거나, <code><a href="/en-US/docs/DOM/element.addEventListener">addEventListener</a></code>의 "useCapture" 파라미터를 <code>true</code>로 설정하세요:</p> + +<h3 id="HTML_Content">HTML Content</h3> + +<pre class="brush:html;"><form id="form"> + <input type="text" placeholder="text input"> + <input type="password" placeholder="password"> +</form></pre> + +<h3 id="JavaScript_Content">JavaScript Content</h3> + +<pre class="brush: js">var form = document.getElementById("form"); +form.addEventListener("focus", function( event ) { + event.target.style.background = "pink"; +}, true); +form.addEventListener("blur", function( event ) { + event.target.style.background = ""; +}, true);</pre> + +<p>{{EmbedLiveSample('Event_delegation')}}</p> + +<h2 id="Browser_compatibility">Browser compatibility</h2> + +<div>{{CompatibilityTable}}</div> + +<div id="compat-desktop"> +<table class="compat-table"> + <tbody> + <tr> + <th>Feature</th> + <th>Chrome</th> + <th>Edge</th> + <th>Firefox (Gecko)</th> + <th>Internet Explorer</th> + <th>Opera</th> + <th>Safari</th> + </tr> + <tr> + <td>Basic support</td> + <td>5</td> + <td>{{CompatVersionUnknown}}</td> + <td>{{CompatVersionUnknown}}<sup>[1]</sup></td> + <td>6</td> + <td>12.1</td> + <td>5.1</td> + </tr> + </tbody> +</table> +</div> + +<div id="compat-mobile"> +<table class="compat-table"> + <tbody> + <tr> + <th>Feature</th> + <th>Android</th> + <th>Chrome for Android</th> + <th>Edge</th> + <th>Firefox Mobile (Gecko)</th> + <th>IE Mobile</th> + <th>Opera Mobile</th> + <th>Safari Mobile</th> + </tr> + <tr> + <td>Basic support</td> + <td>4.0</td> + <td>53</td> + <td>{{CompatVersionUnknown}}</td> + <td>{{CompatUnknown}}</td> + <td>10.0</td> + <td>12.1</td> + <td>5.1</td> + </tr> + </tbody> +</table> +</div> + +<p>[1] Prior to Gecko 24 {{geckoRelease(24)}} the interface for this event was {{domxref("Event")}}, not {{domxref("FocusEvent")}}. See ({{bug(855741)}}).</p> + +<h2 id="Related_Events">Related Events</h2> + +<ul> + <li>{{event("focus")}}</li> + <li>{{event("blur")}}</li> + <li>{{event("focusin")}}</li> + <li>{{event("focusout")}}</li> +</ul> diff --git a/files/ko/web/api/htmlelement/style/index.html b/files/ko/web/api/elementcssinlinestyle/style/index.html index 5976dd66bc..5976dd66bc 100644 --- a/files/ko/web/api/htmlelement/style/index.html +++ b/files/ko/web/api/elementcssinlinestyle/style/index.html diff --git a/files/ko/web/api/fetch_api/fetch의_사용법/index.html b/files/ko/web/api/fetch_api/using_fetch/index.html index 403c340413..403c340413 100644 --- a/files/ko/web/api/fetch_api/fetch의_사용법/index.html +++ b/files/ko/web/api/fetch_api/using_fetch/index.html diff --git a/files/ko/web/api/fullscreen_api/index.html b/files/ko/web/api/fullscreen_api/index.html new file mode 100644 index 0000000000..d7f561a95c --- /dev/null +++ b/files/ko/web/api/fullscreen_api/index.html @@ -0,0 +1,198 @@ +--- +title: Using fullscreen mode +slug: Web/Guide/DOM/Using_full_screen_mode +translation_of: Web/API/Fullscreen_API +--- +<div>{{DefaultAPISidebar("Fullscreen API")}}</div> + +<p><strong>Fullscreen API</strong> 는 특정 요소{{DOMxRef("Element")}}(와 해당 자손들을)를 full-screen mode로 표시하고, 더 이상 필요하지 않으면 full-screen mode를 종료하는 메서드를 추가합니다. 이렇게 하면 사용자의 전체 화면을 사용하여, 온라인 게임과 같은 원하는 내용을 표시할 수 있습니다. full-screen mode가 종료될 때까지 화면에서 브라우저의 모든 유저 인터페이스 요소와 기타 응용 프로그램을 제거할 수 있습니다.</p> + +<p>API 사용 방법에 대한 자세한 내용은 <a href="/ko/docs/Web/API/Fullscreen_API/Guide">Guide to the Fullscreen API</a> 문서를 참조하세요.</p> + +<div class="blockIndicator note"> +<p><strong>주의:</strong> 이 API에 대한 지원은 여러 브라우저에서 이루어지며, 다양한 업체의 접두사(prefix)가 필요하거나, 최신 사양을 구현하지 않는 경우가 많습니다. 이 API 지원에 대한 자세한 내용은 아래에 있는 {{anch("Browser compatibility")}} 섹션을 참조하세요. Fullscreen API를 지원하지 않는 업체의 경우, <a href="https://github.com/rafrex/fscreen">Fscreen</a> 과 같은 라이브러리를 사용할 수 있습니다.</p> +</div> + +<h2 id="Interfaces">Interfaces</h2> + +<p><em>Fullscreen API 에는 자체 인터페이스가 없습니다. 대신에, full-screen 기능을 제공하는데 필요한 메서드, 속성(property), 이벤트 핸들러를 추가하기 위해, 다음 섹션에 나열된 것과 같은 몇 가지 다른 인터페이스를 추가합니다. </em></p> + +<h2 id="Methods">Methods</h2> + +<p>Fullscreen API 는 {{DOMxRef("Document")}}, {{DOMxRef("Element")}} 인터페이스에 메서드를 추가하여 full-screen mode를 설정하거나 해제할 수 있습니다.</p> + +<h3 id="Methods_on_the_Document_interface">Methods on the Document interface</h3> + +<dl> + <dt>{{DOMxRef("Document.exitFullscreen()")}}</dt> + <dd>{{Glossary("user agent")}} 가 full-screen mode에서 창 모드로 다시 전환되도록 요청합니다. full-screen mode가 완전히 종료되면 {{jsxref("Promise")}} resolved 를 반환합니다.</dd> +</dl> + +<h3 id="Methods_on_the_Element_interface">Methods on the Element interface</h3> + +<dl> + <dt>{{DOMxRef("Element.requestFullscreen()")}}</dt> + <dd>유저 에이전트가 지정한 요소(그리고 그 자손들까지)를 full-screen mode로 설정하고, 브라우저의 모든 UI 요소와 다른 모든 애플리케이션을 화면에서 제거하도록 요구합니다. full-screen mode가 활성화되면 {{jsxref("Promise")}} resolved를 반환합니다.</dd> +</dl> + +<h2 id="Properties">Properties</h2> + +<p><em>{{DOMxRef("Document")}} 인터페이스는 full-screen mode가 지원되고 사용 가능한지, full-screen mode가 현재 활성화 되어있는지, 어떤 요소가 스크린을 사용하고 있는지 확인하는데 사용할 수 있는 속성(property)을 제공합니다.</em></p> + +<dl> + <dt>{{DOMxRef("DocumentOrShadowRoot.fullscreenElement")}}</dt> + <dd><code>fullscreenElement</code> 속성은 DOM(혹은 shadow DOM)에서 현재 full-screen mode로 표시되는 요소{{DOMxRef("Element")}}를 알려줍니다. 이것이 <code>null</code>인 경우, document는 full-screen mode가 아닙니다.</dd> + <dt>{{DOMxRef("Document.fullscreenEnabled")}}</dt> + <dd><code>fullscreenEnabled</code> 속성(property)은 full-screen mode를 사용할 수 있는지 여부를 알려줍니다. 이유가 어떻든(예를들어, <code>"fullscreen"</code> 기능이 허락되지 않거나, full-screen mode가 지원되지 않는 경우) full-screen mode를 사용할 수 없으면 <code>false</code> 입니다.</dd> +</dl> + +<h3 id="Event_handlers">Event handlers</h3> + +<p><em>Fullscreen API는 full-screen mode를 켜고 끌 때 혹은, full-screen mode와 window mode간에 변경하는 과정에서 오류가 발생하는 것을 감지하는데 사용할 수 있는 두 가지 이벤트를 정의합니다. 이러한 이벤트에 대한 이벤트 핸들러는 {{DOMxRef("Document")}} 와{{DOMxRef("Element")}} 인터페이스 에서 사용할 수 있습니다.</em></p> + +<div class="blockIndicator note"> +<p><strong>주의:</strong> 이러한 이벤트 핸들러 속성(property)은 HTML 컨텐트 속성(attribute)으로 사용할 수 없습니다. 즉, HTML 컨텐트에서 {{Event("fullscreenchange")}} 및 {{Event("fullscreenerror")}} 이벤트를 지정할 수 없습니다. 자바스크립트 코드로 추가해야만 합니다.</p> +</div> + +<h4 id="Event_handlers_on_documents">Event handlers on documents</h4> + +<dl> + <dt>{{DOMxRef("Document.onfullscreenchange")}}</dt> + <dd>문서(document)가 full-screen mode로 전환되거나 full-screen mode를 종료할 때 {{DOMxRef("Document")}}로 보내지는 {{Event("fullscreenchange")}} 이벤트에 대한 이벤트 핸들러 입니다. 이 핸들러는 오직 전체 문서가 full-screen mode로 표시될 때만 호출됩니다.</dd> + <dt>{{DOMxRef("Document.onfullscreenerror")}}</dt> + <dd>전체 문서에 대해 full-screen mode를 사용하거나, 사용하지 않도록 설정하는 동안 오류가 발생하면, {{DOMxRef("Document")}}로 보내지는 {{Event("fullscreenerror")}} 이벤트의 이벤트 핸들러입니다.</dd> +</dl> + +<h4 id="Event_handlers_on_elements">Event handlers on elements</h4> + +<dl> + <dt>{{DOMxRef("Element.onfullscreenchange")}}</dt> + <dd>{{Event("fullscreenchange")}} 이벤트가 요소(element)로 전송되면, 요소가 full-screen mode로 배치되거나 제거되었음을 나타내는 이벤트 핸들러입니다.</dd> + <dt>{{DOMxRef("Element.onfullscreenerror")}}</dt> + <dd>full-screen mode 를 사용하거나, 사용하지 않도록 설정하는 동안 오류가 발생하면 요소로 보내지는 {{Event("fullscreenerror")}} 이벤트의 이벤트 핸들러입니다.</dd> +</dl> + +<h3 id="Obsolete_properties">Obsolete properties</h3> + +<dl> + <dt>{{DOMxRef("Document.fullscreen")}} {{Deprecated_Inline}}</dt> + <dd>문서에 현재 full-screen mode로 표시되는 요소가 있는 경우 <code>true</code>, 그렇지 않으면 <code>false</code>의 Boolean 값입니다. + <div class="note"><strong>주의:</strong> 대신에 {{DOMxRef("Document")}} 나 {{DOMxRef("ShadowRoot")}} 에서 {{DOMxRef("Document.fullscreenElement", "fullscreenElement")}} 속성(property)을 사용하세요. 그것이 <code>null</code>이 아닌 경우 {{DOMxRef("Element")}}가 full-screen mode로 표시됩니다.</div> + </dd> +</dl> + +<h2 id="Things_your_users_want_to_know" name="Things_your_users_want_to_know">Events</h2> + +<p><em>Fullscreen API는 full-screen mode를 켜고 끌 때 혹은, full-screen mode와 window mode간에 변경하는 과정에서 오류가 발생하는 것을 감지하는데 사용할 수 있는 두 가지 이벤트를 정의합니다.</em></p> + +<dl> + <dt>{{Event("fullscreenchange")}}</dt> + <dd>full-screen mode를 사용하거나, 사용하지 않도록 전환할 때 {{DOMxRef("Document")}} 혹은{{DOMxRef("Element")}} 로 보냅니다.</dd> + <dt>{{Event("fullscreenerror")}}</dt> + <dd>full-screen mode를 사용하거나, 사용하지 않도록 전환하려고 시도하는 중에 오류가 발생하면 <code>Document</code> 또는 <code>Element</code> 로 보냅니다.</dd> +</dl> + +<h2 id="Dictionaries">Dictionaries</h2> + +<dl> + <dt>{{DOMxRef("FullscreenOptions")}}</dt> + <dd>{{DOMxRef("Element.requestFullscreen", "requestFullscreen()")}}을 호출할 때 지정할 수 있는 옵션 설정을 제공합니다.</dd> +</dl> + +<h2 id="Controlling_access">Controlling access</h2> + +<p><a href="/ko/docs/Web/HTTP/Feature_Policy">Feature Policy</a>을 사용하여 full-screen mode의 유효성을 제어할 수 있습니다. full-screen mode는 <code>"fullscreen"</code>으로 식별되고, 기본 허용 목록 값은 <code>"self"</code> 입니다. 이는 최상위(top-level) 문서 컨텍스트에서 full-screen mode가 허용된다는 것을 의미하며, 최상위(top-most) 문서와 같은 출처에서 로드 된 중첩 된 컨텍스트에도 적용됩니다.</p> + +<p>기능 정책을 사용하여 API에 대한 액세스를 제어하는 자세한 내용은 <a href="/ko/docs/Web/HTTP/Feature_Policy/Using_Feature_Policy">Using Feature Policy</a>을 참조하세요.</p> + +<h2 id="Things_your_users_want_to_know" name="Things_your_users_want_to_know">Usage notes</h2> + +<p>사용자는 <kbd>ESC</kbd> (혹은 <kbd>F11</kbd>) 키를 누르기만하면 사이트 또는 앱이 프로그래밍 방식으로 기다리는 대신에, full-screen mode를 종료하도록 선택할 수 있습니다. 유저 인터페이스의 어딘가에 사용자에게 이 옵션을 사용할 수 있음을 알리는, 적절한 유저 인터페이스 요소를 제공해야 합니다.</p> + +<div class="note"> +<p><strong>주의:</strong> 다른 페이지로 이동하거나, 탭을 변경하거나, 응용 프로그램 전환기(또는 <kbd>Alt</kbd>-<kbd>Tab</kbd>)를 사용하여, 다른 응용 프로그램으로 전환하면 마찬가지로 full-screen mode가 종료됩니다.</p> +</div> + +<h2 id="Example">Example</h2> + +<p>이 예제에서는 비디오가 웹 페이지에 표시됩니다. <kbd>Return</kbd> 또는 <kbd>Enter</kbd> 키를 누르면, 사용자가 비디오의 창과 full-screen 표시를 전환할 수 있습니다.</p> + +<p><a href="/samples/domref/fullscreen.html">View Live Examples</a></p> + +<h3 id="Watching_for_the_Enter_key">Watching for the Enter key</h3> + +<p>페이지가 로드되면, 이 코드가 실행되어 <kbd>Enter</kbd> 키 를 주시하는 이벤트 리스너를 설정합니다.</p> + +<pre class="brush: js">document.addEventListener("keypress", function(e) { + if (e.keyCode === 13) { + toggleFullScreen(); + } +}, false); +</pre> + +<h3 id="Toggling_full-screen_mode">Toggling full-screen mode</h3> + +<p>이 코드는 사용자가 <kbd>Enter</kbd> 키를 누를 때, 위의 이벤트 핸들러에 의해 호출됩니다.</p> + +<pre class="brush: js">function toggleFullScreen() { + if (!document.fullscreenElement) { + document.documentElement.requestFullscreen(); + } else { + if (document.exitFullscreen) { + document.exitFullscreen(); + } + } +}</pre> + +<p>먼저 {{DOMxRef("Document", "document")}}의 <code>fullscreenElement</code> 속성(attribute)값을 살펴보겠습니다. 실제 배포 시에는 이 시점에 접두어가 붙은 버전(예를들어, <code>mozFullscreenElement</code>, <code>msFullscreenElement</code>, <code>webkitFullscreenElement</code>)을 확인해야 합니다. 값이 <code>null</code>인 경우, 문서는 현재 window mode에 있으므로, full-screen mode로 전환해야 합니다. 그렇지 않으면, 이 요소는 지금 full-screen mode 상태입니다. full-screen mode로 전환하는 작업은, {{HTMLElement("video")}}요소에서 {{DOMxRef("Element.requestFullscreen()")}}을 호출하여 수행합니다.</p> + +<p>full-screen mode가 이미 활성화 된 경우(<code>fullscreenElement</code> 가 <code>null</code>이 아닌 경우), <code>document</code>에서 {{DOMxRef("Document.exitFullscreen", "exitFullscreen()")}}을 호출하여 full-screen mode를 종료합니다.</p> + +<h2 id="Specifications">Specifications</h2> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Specification</th> + <th scope="col">Status</th> + <th scope="col">Comment</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{SpecName("Fullscreen")}}</td> + <td>{{Spec2("Fullscreen")}}</td> + <td>Initial version.</td> + </tr> + </tbody> +</table> + +<h2 id="Browser_compatibility" name="Browser_compatibility">Browser compatibility</h2> + +<h3 id="Document.fullscreen"><code>Document.fullscreen</code></h3> + +<div> + + +<p>{{Compat("api.Document.fullscreen")}}</p> + +<h3 id="Document.fullscreenEnabled"><code>Document.fullscreenEnabled</code></h3> + +<div> +<div class="hidden">The compatibility table on this page is generated from structured data. If you'd like to contribute to the data, please check out <a href="https://github.com/mdn/browser-compat-data">https://github.com/mdn/browser-compat-data</a> and send us a pull request.</div> + +<p>{{Compat("api.Document.fullscreenEnabled")}}</p> +</div> +</div> + +<h2 id="See_also">See also</h2> + +<ul> + <li><a href="/en-US/docs/Web/API/Fullscreen_API">Using full-screen mode</a></li> + <li>{{DOMxRef("Element.requestFullscreen()")}}</li> + <li>{{DOMxRef("Document.exitFullscreen()")}}</li> + <li>{{DOMxRef("Document.fullscreen")}}</li> + <li>{{DOMxRef("Document.fullscreenElement")}}</li> + <li>{{CSSxRef(":fullscreen")}}, {{CSSxRef("::backdrop")}}</li> + <li>{{HTMLAttrXRef("allowfullscreen", "iframe")}}</li> +</ul> diff --git a/files/ko/web/api/geolocation_api/using_the_geolocation_api/index.html b/files/ko/web/api/geolocation_api/using_the_geolocation_api/index.html new file mode 100644 index 0000000000..e5f9913376 --- /dev/null +++ b/files/ko/web/api/geolocation_api/using_the_geolocation_api/index.html @@ -0,0 +1,165 @@ +--- +title: Geolocation API 사용하기 +slug: WebAPI/Using_geolocation +tags: + - Geolocation API + - Guide + - Intermediate +translation_of: Web/API/Geolocation_API/Using_the_Geolocation_API +--- +<p>{{securecontext_header}}{{APIRef("Geolocation API")}}<br> + <strong>Geolocation API</strong>는 사용자의 현재 위치를 가져오는 API로, 지도에 사용자 위치를 표시하는 등 다양한 용도로 사용할 수 있습니다. 이 안내서는 Geolocation API의 기초적 사용법을 설명합니다.</p> + +<h2 id="geolocation_객체"><code>geolocation</code> 객체</h2> + +<p><a href="/ko/docs/Web/API/Geolocation_API">Geolocation API</a>는 {{domxref("navigator.geolocation")}} 객체를 통해 사용할 수 있습니다.</p> + +<p><code>geolocation</code> 객체가 존재하는 경우 위치 정보 서비스를 지원하는 것입니다. 존재 여부는 다음과 같이 알아낼 수 있습니다.</p> + +<pre class="brush: js">if('geolocation' in navigator) { + /* 위치정보 사용 가능 */ +} else { + /* 위치정보 사용 불가능 */ +} +</pre> + +<h3 id="현재_위치_가져오기">현재 위치 가져오기</h3> + +<p>{{domxref("Geolocation.getCurrentPosition()","getCurrentPosition()")}} 메서드를 호출해서 사용자의 현재 위치를 얻을 수 있습니다. <code>getCurrentPosition()</code>은 사용자의 위치를 탐지하는 비동기 요청을 초기화하고, 위치 관련 하드웨어에 최신 정보를 요청합니다. 위치를 알아낸 후에는 지정한 콜백 함수를 호출합니다. 선택적으로, 이 과정 중 오류가 발생하면 호출할 오류 콜백을 두 번째 매개변수로 지정할 수도 있습니다. 세 번째 매개변수 역시 선택 항목이며, 위치 정보의 최대 수명, 요청의 최대 대기시간, 고정밀 위치정보 여부 등의 옵션을 담은 객체입니다.</p> + +<div class="note"> +<p><strong>참고:</strong> {{domxref("Geolocation.getCurrentPosition", "getCurrentPosition()")}}의 기본값에서는 최대한 빠르게 낮은 정밀도의 응답을 반환합니다. 정확하지 않더라도 빠른 정보가 필요한 상황에서 유용합니다. 예를 들어, GPS 기능을 가진 장비는 보정 과정에 수 분이 걸릴 수도 있으므로 IP 위치와 WiFi 등 정확하지 않은 출처에 기반한 위치 정보를 반환할 수 있습니다.</p> +</div> + +<pre class="brush: js">navigator.geolocation.getCurrentPosition((position) => { + doSomething(position.coords.latitude, position.coords.longitude); +});</pre> + +<p>위의 예제는 사용자 위치가 확인되면 <code>doSomething()</code> 함수를 실행합니다.</p> + +<h3 id="현재_위치_추적하기">현재 위치 추적하기</h3> + +<p>장치가 이동했거나 더 정확한 정보를 사용할 수 있어서 위치 정보가 바뀐 경우 호출할 콜백 함수를 {{domxref("Geolocation.watchPosition","watchPosition()")}} 메서드로 설정할 수 있으며, {{domxref("Geolocation.getCurrentPosition","getCurrentPosition()")}}과 같은 매개변수를 받습니다. 콜백은 계속해서 호출될 수 있으므로, 브라우저가 사용자의 이동 시, 또는 고정밀 위치 기술을 사용할 수 있는 시점에 새로운 위치 정보를 제공할 수 있습니다. <code>getCurrentPosition()</code>과 마찬가지로 선택 사항인 오류 콜백 역시 여러 번 호출할 수 있습니다.</p> + +<div class="note"> +<p><strong>참고:</strong> {{domxref("Geolocation.getCurrentPosition", "getCurrentPosition()")}}을 먼저 호출하지 않고도 {{domxref("Geolocation.watchPosition", "watchPosition()")}}을 사용할 수 있습니다.</p> +</div> + +<pre class="brush: js">const watchID = navigator.geolocation.watchPosition((position) => { + doSomething(position.coords.latitude, position.coords.longitude); +});</pre> + +<p>{{domxref("Geolocation.watchPosition","watchPosition()")}} 메서드는 위치 추적 요청의 고유 식별자를 나타내는 숫자값을 반환합니다. 해당 식별자를 {{domxref("Geolocation.clearWatch","clearWatch()")}} 메서드에 전달해서 추적을 종료할 수 있습니다.</p> + +<pre class="brush: js">navigator.geolocation.clearWatch(watchID); +</pre> + +<h3 id="응답_미세_조정">응답 미세 조정</h3> + +<p>{{domxref("Geolocation.getCurrentPosition","getCurrentPosition()")}}과 {{domxref("Geolocation.watchPosition","watchPosition()")}} 둘 다 성공 콜백, 실패 콜백 외에도 <a href="/ko/docs/Web/API/PositionOptions"><code>PositionOptions</code></a> 객체를 받을 수 있습니다.</p> + +<p><code>PositionsOptions</code> 객체를 사용하면 고정밀도 활성화 여부, 위치 정보의 캐시 수명(수명이 끝나기 전까지는 이전에 반환한 위치 정보를 저장해뒀다가, 같은 요청을 또 받을 경우 그대로 반환합니다), 그리고 위치 정보 요청의 응답을 대기할 최대 대기시간을 지정할 수 있습니다.</p> + +<p>옵션 객체를 사용한 {{domxref("Geolocation.watchPosition","watchPosition")}}의 호출 예시는 다음과 같습니다.</p> + +<pre class="brush: js">function success(position) { + doSomething(position.coords.latitude, position.coords.longitude); +} + +function error() { + alert('Sorry, no position available.'); +} + +const options = { + enableHighAccuracy: true, + maximumAge: 30000, + timeout: 27000 +}; + +const watchID = navigator.geolocation.watchPosition(success, error, options);</pre> + +<h2 id="위치_표현">위치 표현</h2> + +<p>사용자의 위치는 {{domxref("GeolocationPosition")}} 객체를 담은 {{domxref("GeolocationCoordinates")}} 객체를 사용하여 표현합니다.</p> + +<p><code>GeolocationPosition</code>은 단 두 가지만 가집니다. 하나는 <code>GeolocationCoordinates</code> 인스턴스를 가진 <code>coords</code> 속성이고, 다른 하나는 위치 정보의 기록 시점을 나타내는 {{domxref("DOMTimeStamp")}} 인스턴스입니다.</p> + +<p>GeolocationCoordinates 인스턴스는 다수의 속성을 갖지만, 그 중 가장 많이 쓰게 될 항목은 지도의 지점을 가리킬 때 사용할 <code>latitude</code>와 <code>longitude</code>입니다. 따라서 대부분의 <code>Geolocation</code> 성공 콜백은 아래와 같이 꽤 간단한 형태입니다.</p> + +<pre class="brush: js">function success(position) { + const latitude = position.coords.latitude; + const longitude = position.coords.longitude; + + // Do something with your latitude and longitude +}</pre> + +<p>그러나 <code>GeolocationCoordinates</code> 객체에서 고도, 속도, 장치의 방향, 위경도와 고도의 정확도 등 다른 다양한 정보도 가져올 수 있습니다.</p> + +<h2 id="오류_처리">오류 처리</h2> + +<p><code>getCurrentPosition()</code> 또는 <code>watchPosition()</code>에 오류 콜백을 제공한 경우, 콜백은 첫 번째 매개변수로 <a href="/ko/docs/Web/API/GeolocationPositionError"><code>GeolocationPositionError</code></a> 객체를 받습니다. 해당 객체는 오류의 유형을 나타내는 <code>code</code> 속성과, 사람이 읽을 수 있는 형태로 오류 코드의 뜻을 설명한 <code>message</code> 속성을 갖습니다.</p> + +<p>다음 형태로 사용할 수 있습니다.</p> + +<pre class="brush: js">function errorCallback(error) { + alert(`ERROR(${error.code}): ${error.message}`); +};</pre> + +<h2 id="예제">예제</h2> + +<p>다음 예제는 Geolocation API를 사용해 사용자의 위경도를 가져옵니다. 성공한 경우, 사용자의 위치를 가리키는 <code>openstreetmap.org</code> 링크를 생성해 하이퍼링크에 할당합니다.</p> + +<div class="hidden"> +<pre class="brush: css">body { + padding: 20px; + background-color:#ffffc9 +} + +button { + margin: .5rem 0; +}</pre> +</div> + +<h3 id="HTML">HTML</h3> + +<pre class="brush: html"><button id = "find-me">Show my location</button><br/> +<p id = "status"></p> +<a id = "map-link" target="_blank"></a></pre> + +<h3 id="JavaScript">JavaScript</h3> + +<pre class="brush: js">function geoFindMe() { + + const status = document.querySelector('#status'); + const mapLink = document.querySelector('#map-link'); + + mapLink.href = ''; + mapLink.textContent = ''; + + function success(position) { + const latitude = position.coords.latitude; + const longitude = position.coords.longitude; + + status.textContent = ''; + mapLink.href = `https://www.openstreetmap.org/#map=18/${latitude}/${longitude}`; + mapLink.textContent = `Latitude: ${latitude} °, Longitude: ${longitude} °`; + } + + function error() { + status.textContent = 'Unable to retrieve your location'; + } + + if(!navigator.geolocation) { + status.textContent = 'Geolocation is not supported by your browser'; + } else { + status.textContent = 'Locating…'; + navigator.geolocation.getCurrentPosition(success, error); + } + +} + +document.querySelector('#find-me').addEventListener('click', geoFindMe);</pre> + +<h3 id="결과">결과</h3> + +<p>{{EmbedLiveSample('예제', 350, 150)}}</p> diff --git a/files/ko/web/api/html_드래그_앤_드롭_api/drag_operations/index.html b/files/ko/web/api/html_drag_and_drop_api/drag_operations/index.html index 122e835b75..122e835b75 100644 --- a/files/ko/web/api/html_드래그_앤_드롭_api/drag_operations/index.html +++ b/files/ko/web/api/html_drag_and_drop_api/drag_operations/index.html diff --git a/files/ko/web/api/html_드래그_앤_드롭_api/index.html b/files/ko/web/api/html_drag_and_drop_api/index.html index 70a4295284..70a4295284 100644 --- a/files/ko/web/api/html_드래그_앤_드롭_api/index.html +++ b/files/ko/web/api/html_drag_and_drop_api/index.html diff --git a/files/ko/web/api/element/accesskey/index.html b/files/ko/web/api/htmlelement/accesskey/index.html index 0fc48bd749..0fc48bd749 100644 --- a/files/ko/web/api/element/accesskey/index.html +++ b/files/ko/web/api/htmlelement/accesskey/index.html diff --git a/files/ko/web/api/node/innertext/index.html b/files/ko/web/api/htmlelement/innertext/index.html index 414fab5c00..414fab5c00 100644 --- a/files/ko/web/api/node/innertext/index.html +++ b/files/ko/web/api/htmlelement/innertext/index.html diff --git a/files/ko/web/api/htmlmediaelement/abort_event/index.html b/files/ko/web/api/htmlmediaelement/abort_event/index.html new file mode 100644 index 0000000000..2278a24c24 --- /dev/null +++ b/files/ko/web/api/htmlmediaelement/abort_event/index.html @@ -0,0 +1,74 @@ +--- +title: abort +slug: Web/Events/abort +tags: + - DOM + - Event + - Reference + - 레퍼런스 + - 이벤트 +translation_of: Web/API/HTMLMediaElement/abort_event +translation_of_original: Web/Events/abort +--- +<p><strong><code>abort</code></strong> 이벤트는 리소스의 로딩이 중단되었을 때, 발생합니다.</p> + +<h2 id="개요">개요</h2> + +<dl> + <dt style="float: left; text-align: right; width: 120px;">스펙</dt> + <dd style="margin: 0 0 0 120px;"><a class="external" href="http://www.w3.org/TR/DOM-Level-3-Events/#event-type-abort">DOM L3</a></dd> + <dt style="float: left; text-align: right; width: 120px;">인터페이스</dt> + <dd style="margin: 0 0 0 120px;">유저 인터페이스에서 발생하면 UIEvent, 그렇지 않으면 Event.</dd> + <dt style="float: left; text-align: right; width: 120px;">버블</dt> + <dd style="margin: 0 0 0 120px;">안됨</dd> + <dt style="float: left; text-align: right; width: 120px;">취소 가능</dt> + <dd style="margin: 0 0 0 120px;">안됨</dd> + <dt style="float: left; text-align: right; width: 120px;">타겟</dt> + <dd style="margin: 0 0 0 120px;">Element</dd> + <dt style="float: left; text-align: right; width: 120px;">디폴트 액션</dt> + <dd style="margin: 0 0 0 120px;">없음</dd> +</dl> + +<h2 id="속성">속성</h2> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">속성</th> + <th scope="col">타입</th> + <th scope="col">설명</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>target</code> {{readonlyInline}}</td> + <td><a href="/en-US/docs/Web/API/EventTarget" title="EventTarget is an interface implemented by objects that can receive events and may have listeners for them."><code>EventTarget</code></a></td> + <td>이벤트 타겟 (DOM tree의 최상위 타겟).</td> + </tr> + <tr> + <td><code>type</code> {{readonlyInline}}</td> + <td><a href="/en-US/docs/Web/API/DOMString" title="DOMString is a UTF-16 String. As JavaScript already uses such strings, DOMString is mapped directly to a String."><code>DOMString</code></a></td> + <td>이벤트의 타입</td> + </tr> + <tr> + <td><code>bubbles</code> {{readonlyInline}}</td> + <td><a href="/en-US/docs/Web/API/Boolean" title="The Boolean object is an object wrapper for a boolean value."><code>Boolean</code></a></td> + <td>이벤트가 버블링 되는지 안되는지</td> + </tr> + <tr> + <td><code>cancelable</code> {{readonlyInline}}</td> + <td><a href="/en-US/docs/Web/API/Boolean" title="The Boolean object is an object wrapper for a boolean value."><code>Boolean</code></a></td> + <td>이벤트가 취소 가능한지 아닌지</td> + </tr> + <tr> + <td><code>view</code> {{readonlyInline}}</td> + <td><a class="new" href="/en-US/docs/Web/API/WindowProxy" rel="nofollow" title="The documentation about this has not yet been written; please consider contributing!"><code>WindowProxy</code></a></td> + <td><a href="/en-US/docs/Web/API/Document/defaultView" title="In browsers, document.defaultView returns the window object associated with a document, or null if none is available."><code>document.defaultView</code></a> (document의 <code>window</code> )</td> + </tr> + <tr> + <td><code>detail</code> {{readonlyInline}}</td> + <td><code>long</code> (<code>float</code>)</td> + <td>0.</td> + </tr> + </tbody> +</table> diff --git a/files/ko/web/api/htmlelement/dataset/index.html b/files/ko/web/api/htmlorforeignelement/dataset/index.html index 2b2a891dca..2b2a891dca 100644 --- a/files/ko/web/api/htmlelement/dataset/index.html +++ b/files/ko/web/api/htmlorforeignelement/dataset/index.html diff --git a/files/ko/web/api/htmlelement/tabindex/index.html b/files/ko/web/api/htmlorforeignelement/tabindex/index.html index 7cbb0fa1f0..7cbb0fa1f0 100644 --- a/files/ko/web/api/htmlelement/tabindex/index.html +++ b/files/ko/web/api/htmlorforeignelement/tabindex/index.html diff --git a/files/ko/web/api/navigation_timing_api/index.html b/files/ko/web/api/navigation_timing_api/index.html new file mode 100644 index 0000000000..c9a0c1465b --- /dev/null +++ b/files/ko/web/api/navigation_timing_api/index.html @@ -0,0 +1,137 @@ +--- +title: 내비게이션 타이밍(Navigation Timing) +slug: Navigation_timing +translation_of: Web/API/Navigation_timing_API +--- +<p><strong>Navigation Timing API</strong>는 웹 사이트의 성능을 측정하는 데 사용할 수 있는 데이터를 제공합니다. 같은 목적에 사용했던 다른 JavaScript 기반 메커니즘과 다르게 이 API는 더 유용하고 정확한 종단 간(end-to-end) 대기 시간(latency)을 제공할 수 있습니다.</p> +<p>다음 예제는 지각하는(perceived) 로딩 시간을 측정하는 법을 보여줍니다.</p> +<pre>function onLoad() { + var now = new Date().getTime(); + var page_load_time = now - performance.timing.navigationStart; + console.log("User-perceived page loading time: " + page_load_time); +} +</pre> +<p>{{domxref("PerformanceTiming")}} 인터페이스로 접근할 수 있는 밀리 초 단위로 주어진 측정된 이벤트가 많이 있습니다. 발생하는 순서로 된 이벤트 목록입니다.</p> +<ul> + <li>navigationStart</li> + <li>unloadEventStart</li> + <li>unloadEventEnd</li> + <li>redirectStart</li> + <li>redirectEnd</li> + <li>fetchStart</li> + <li>domainLookupStart</li> + <li>domainLookupEnd</li> + <li>connectStart</li> + <li>connectEnd</li> + <li>secureConnectionStart</li> + <li>requestStart</li> + <li>responseStart</li> + <li>responseEnd</li> + <li>domLoading</li> + <li>domInteractive</li> + <li>domContentLoadedEventStart</li> + <li>domContentLoadedEventEnd</li> + <li>domComplete</li> + <li>loadEventStart</li> + <li>loadEventEnd</li> +</ul> +<p><code>window.performance.navigation</code> 객체는 리다이렉트(redirect), 앞/뒤 버튼, 혹은 보통의 URL 로딩이 어떤 페이지 로드를 일으키는지(trigger) 아는 데 사용할 수 있는 두 속성을 저장합니다.</p> +<p>window.performance.navigation.type:</p> +<table class="standard-table" style="font-size: 14px;"> + <thead> + <tr> + <th scope="col">상수</th> + <th scope="col">값</th> + <th scope="col">설명</th> + </tr> + </thead> + <tbody> + <tr> + <td><a name="const_next"><code>TYPE_NAVIGATENEXT</code></a></td> + <td>0</td> + <td>아래 목록의 TYPE_RELOAD과 TYPE_BACK_FORWARD가 사용하는 것 외에, 링크 클릭하기, 사용자 에이전트(UA) 주소 바에 URL 입력하기, 폼 전송, 스크립트 연산으로 초기화하기로 시작한 내비게이션.</td> + </tr> + <tr> + <td><a name="const_next_no_duplicate"><code>TYPE_RELOAD</code></a></td> + <td>1</td> + <td>리로드(reload) 연산 혹은 location.reload() 메소드를 통한 내비게이션.</td> + </tr> + <tr> + <td><a name="const_prev"><code>TYPE_BACK_FORWARD</code></a></td> + <td>2</td> + <td>히스토리 순회(traversal) 연산을 통한 내비게이션</td> + </tr> + <tr> + <td><a name="const_prev_no_duplicate"><code>TYPE_UNDEFINED</code></a></td> + <td>255</td> + <td>위 값으로 정의되지 않는 어떠한 내비게이션 타입.</td> + </tr> + </tbody> +</table> +<p><code>window.performance.navigation.redirectCount</code>는 마지막 페이지에 도달할 때까지, 만일 있다면 몇 번의 리다이렉션이 일어났는지를 나타냅니다.</p> +<p>Navigation Timing API는 XHR로 서버에 보낸 클라이언트 쪽 성능 데이터를 모을 뿐 아니라 이전 페이지 언로드(unload) 시간, 도메인 룩업(look up) 시간, window.onload 전체 시간 등 다른 방법으로 측정하기 매우 어려운 데이터를 측정하는 데 사용할 수 있습니다.</p> +<h3 id="예제">예제</h3> +<p>어떤 페이지를 로딩하는 데 필요한 전체 시간 계산하기.</p> +<pre>var perfData = window.performance.timing; +var pageLoadTime = perfData.loadEventEnd - perfData.navigationStart; +</pre> +<p>요청 응답 시간 계산하기.</p> +<pre>var connectTime = perfData.responseEnd - perfData.requestStart;</pre> +<h3 id="Browser_Compatibility" name="Browser_Compatibility">링크</h3> +<ul> + <li><a class="external" href="http://webtimingdemo.appspot.com/" title="http://webtimingdemo.appspot.com/">Test Page</a></li> + <li><a class="external" href="http://w3c-test.org/webperf/specs/NavigationTiming/" title="http://w3c-test.org/webperf/specs/NavigationTiming/">http://w3c-test.org/webperf/specs/NavigationTiming/</a></li> + <li><a class="external" href="http://www.w3.org/TR/navigation-timing/" title="http://www.w3.org/TR/navigation-timing/">http://www.w3.org/TR/navigation-timing/</a></li> +</ul> +<h3 id="Browser_Compatibility" name="Browser_Compatibility">브라우저 호환</h3> +<p style="margin-top: 0px; margin-right: 0px; margin-bottom: 1.286em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px;">{{ CompatibilityTable() }}</p> +<div id="compat-desktop"> + <table class="compat-table" style="font-size: 14px; margin-bottom: 1.286em; border-collapse: collapse; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: dotted; border-right-style: dotted; border-bottom-style: dotted; border-left-style: dotted;"> + <tbody> + <tr> + <th style="font-family: inherit; font-size: inherit; color: inherit; padding-top: 0px; padding-right: 5px; padding-bottom: 0px; padding-left: 5px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: dotted; border-right-style: dotted; border-bottom-style: dotted; border-left-style: dotted; background-clip: initial; background-color: rgb(238, 238, 238); text-align: left; font-weight: bold;">Feature</th> + <th style="font-family: inherit; font-size: inherit; color: inherit; padding-top: 0px; padding-right: 5px; padding-bottom: 0px; padding-left: 5px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: dotted; border-right-style: dotted; border-bottom-style: dotted; border-left-style: dotted; background-clip: initial; background-color: rgb(238, 238, 238); text-align: left; font-weight: bold;">Chrome**</th> + <th style="font-family: inherit; font-size: inherit; color: inherit; padding-top: 0px; padding-right: 5px; padding-bottom: 0px; padding-left: 5px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: dotted; border-right-style: dotted; border-bottom-style: dotted; border-left-style: dotted; background-clip: initial; background-color: rgb(238, 238, 238); text-align: left; font-weight: bold;">Firefox (Gecko)*</th> + <th style="font-family: inherit; font-size: inherit; color: inherit; padding-top: 0px; padding-right: 5px; padding-bottom: 0px; padding-left: 5px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: dotted; border-right-style: dotted; border-bottom-style: dotted; border-left-style: dotted; background-clip: initial; background-color: rgb(238, 238, 238); text-align: left; font-weight: bold;">Internet Explorer</th> + <th style="font-family: inherit; font-size: inherit; color: inherit; padding-top: 0px; padding-right: 5px; padding-bottom: 0px; padding-left: 5px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: dotted; border-right-style: dotted; border-bottom-style: dotted; border-left-style: dotted; background-clip: initial; background-color: rgb(238, 238, 238); text-align: left; font-weight: bold;">Opera*</th> + <th style="font-family: inherit; font-size: inherit; color: inherit; padding-top: 0px; padding-right: 5px; padding-bottom: 0px; padding-left: 5px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: dotted; border-right-style: dotted; border-bottom-style: dotted; border-left-style: dotted; background-clip: initial; background-color: rgb(238, 238, 238); text-align: left; font-weight: bold;">Safari (WebKit)</th> + </tr> + <tr> + <td style="font-family: inherit; font-size: inherit; color: inherit; padding-top: 5px; padding-right: 5px; padding-bottom: 5px; padding-left: 5px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: dotted; border-right-style: dotted; border-bottom-style: dotted; border-left-style: dotted; text-align: left; background-clip: initial; background-color: rgb(255, 255, 255); vertical-align: top; word-wrap: break-word;">Basic support</td> + <td style="font-family: inherit; font-size: inherit; color: inherit; padding-top: 5px; padding-right: 5px; padding-bottom: 5px; padding-left: 5px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: dotted; border-right-style: dotted; border-bottom-style: dotted; border-left-style: dotted; text-align: left; background-clip: initial; background-color: rgb(255, 255, 255); vertical-align: top; word-wrap: break-word;"> + <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 1.286em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px;">6</p> + </td> + <td style="font-family: inherit; font-size: inherit; color: inherit; padding-top: 5px; padding-right: 5px; padding-bottom: 5px; padding-left: 5px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: dotted; border-right-style: dotted; border-bottom-style: dotted; border-left-style: dotted; text-align: left; background-clip: initial; background-color: rgb(255, 255, 255); vertical-align: top; word-wrap: break-word;"> + <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 1.286em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px;">7</p> + <p style="margin-top: 0px; margin-right: 0px; margin-bottom: 1.286em; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px;"> </p> + </td> + <td style="font-family: inherit; font-size: inherit; color: inherit; padding-top: 5px; padding-right: 5px; padding-bottom: 5px; padding-left: 5px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: dotted; border-right-style: dotted; border-bottom-style: dotted; border-left-style: dotted; text-align: left; background-clip: initial; background-color: rgb(255, 255, 255); vertical-align: top; word-wrap: break-word;">9</td> + <td style="font-family: inherit; font-size: inherit; color: inherit; padding-top: 5px; padding-right: 5px; padding-bottom: 5px; padding-left: 5px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: dotted; border-right-style: dotted; border-bottom-style: dotted; border-left-style: dotted; text-align: left; background-clip: initial; background-color: rgb(255, 255, 255); vertical-align: top; word-wrap: break-word;">15</td> + <td style="font-family: inherit; font-size: inherit; color: inherit; padding-top: 5px; padding-right: 5px; padding-bottom: 5px; padding-left: 5px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: dotted; border-right-style: dotted; border-bottom-style: dotted; border-left-style: dotted; text-align: left; background-clip: initial; background-color: rgb(255, 255, 255); vertical-align: top; word-wrap: break-word;">{{ CompatNo() }}</td> + </tr> + </tbody> + </table> +</div> +<div id="compat-mobile"> + <table class="compat-table" style="font-size: 14px; margin-bottom: 1.286em; border-collapse: collapse; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: dotted; border-right-style: dotted; border-bottom-style: dotted; border-left-style: dotted;"> + <tbody> + <tr> + <th style="font-family: inherit; font-size: inherit; color: inherit; padding-top: 0px; padding-right: 5px; padding-bottom: 0px; padding-left: 5px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: dotted; border-right-style: dotted; border-bottom-style: dotted; border-left-style: dotted; background-clip: initial; background-color: rgb(238, 238, 238); text-align: left; font-weight: bold;">Feature</th> + <th style="font-family: inherit; font-size: inherit; color: inherit; padding-top: 0px; padding-right: 5px; padding-bottom: 0px; padding-left: 5px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: dotted; border-right-style: dotted; border-bottom-style: dotted; border-left-style: dotted; background-clip: initial; background-color: rgb(238, 238, 238); text-align: left; font-weight: bold;">Android</th> + <th style="font-family: inherit; font-size: inherit; color: inherit; padding-top: 0px; padding-right: 5px; padding-bottom: 0px; padding-left: 5px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: dotted; border-right-style: dotted; border-bottom-style: dotted; border-left-style: dotted; background-clip: initial; background-color: rgb(238, 238, 238); text-align: left; font-weight: bold;">Firefox Mobile (Gecko)</th> + <th style="font-family: inherit; font-size: inherit; color: inherit; padding-top: 0px; padding-right: 5px; padding-bottom: 0px; padding-left: 5px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: dotted; border-right-style: dotted; border-bottom-style: dotted; border-left-style: dotted; background-clip: initial; background-color: rgb(238, 238, 238); text-align: left; font-weight: bold;">IE Phone</th> + <th style="font-family: inherit; font-size: inherit; color: inherit; padding-top: 0px; padding-right: 5px; padding-bottom: 0px; padding-left: 5px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: dotted; border-right-style: dotted; border-bottom-style: dotted; border-left-style: dotted; background-clip: initial; background-color: rgb(238, 238, 238); text-align: left; font-weight: bold;">Opera Mobile</th> + <th style="font-family: inherit; font-size: inherit; color: inherit; padding-top: 0px; padding-right: 5px; padding-bottom: 0px; padding-left: 5px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: dotted; border-right-style: dotted; border-bottom-style: dotted; border-left-style: dotted; background-clip: initial; background-color: rgb(238, 238, 238); text-align: left; font-weight: bold;">Safari Mobile</th> + </tr> + <tr> + <td style="font-family: inherit; font-size: inherit; color: inherit; padding-top: 5px; padding-right: 5px; padding-bottom: 5px; padding-left: 5px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: dotted; border-right-style: dotted; border-bottom-style: dotted; border-left-style: dotted; text-align: left; background-clip: initial; background-color: rgb(255, 255, 255); vertical-align: top; word-wrap: break-word;">Basic support</td> + <td style="font-family: inherit; font-size: inherit; color: inherit; padding-top: 5px; padding-right: 5px; padding-bottom: 5px; padding-left: 5px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: dotted; border-right-style: dotted; border-bottom-style: dotted; border-left-style: dotted; text-align: left; background-clip: initial; background-color: rgb(255, 255, 255); vertical-align: top; word-wrap: break-word;">4.0</td> + <td style="font-family: inherit; font-size: inherit; color: inherit; padding-top: 5px; padding-right: 5px; padding-bottom: 5px; padding-left: 5px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: dotted; border-right-style: dotted; border-bottom-style: dotted; border-left-style: dotted; text-align: left; background-clip: initial; background-color: rgb(255, 255, 255); vertical-align: top; word-wrap: break-word;">15.0</td> + <td style="font-family: inherit; font-size: inherit; color: inherit; padding-top: 5px; padding-right: 5px; padding-bottom: 5px; padding-left: 5px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: dotted; border-right-style: dotted; border-bottom-style: dotted; border-left-style: dotted; text-align: left; background-clip: initial; background-color: rgb(255, 255, 255); vertical-align: top; word-wrap: break-word;">{{ CompatUnknown() }}</td> + <td style="font-family: inherit; font-size: inherit; color: inherit; padding-top: 5px; padding-right: 5px; padding-bottom: 5px; padding-left: 5px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: dotted; border-right-style: dotted; border-bottom-style: dotted; border-left-style: dotted; text-align: left; background-clip: initial; background-color: rgb(255, 255, 255); vertical-align: top; word-wrap: break-word;">{{ CompatUnknown() }}</td> + <td style="font-family: inherit; font-size: inherit; color: inherit; padding-top: 5px; padding-right: 5px; padding-bottom: 5px; padding-left: 5px; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: dotted; border-right-style: dotted; border-bottom-style: dotted; border-left-style: dotted; text-align: left; background-clip: initial; background-color: rgb(255, 255, 255); vertical-align: top; word-wrap: break-word;">{{ CompatUnknown() }}</td> + </tr> + </tbody> + </table> +</div> +<p> </p> diff --git a/files/ko/web/api/networkinformation/connection/index.html b/files/ko/web/api/navigator/connection/index.html index 1afa39d9c1..1afa39d9c1 100644 --- a/files/ko/web/api/networkinformation/connection/index.html +++ b/files/ko/web/api/navigator/connection/index.html diff --git a/files/ko/web/api/network_information_api/index.html b/files/ko/web/api/network_information_api/index.html new file mode 100644 index 0000000000..9526bd2d5f --- /dev/null +++ b/files/ko/web/api/network_information_api/index.html @@ -0,0 +1,46 @@ +--- +title: Network Information API +slug: WebAPI/Network_Information +translation_of: Web/API/Network_Information_API +--- +<p>{{ SeeCompatTable() }}</p> +<p>네트워크 정보 API는 사용자 기기의 현재 대역폭이나 과금이 되는 연결인지와 같은 시스템의 연결 정보를 알려줍니다. 이를 이용해서 사용자에게 높은 용량의 콘텐츠를 제공할지 낮은 용량의 콘텐츠를 제공할지 사용자의 연결 상태에 따라서 제공할 수 있습니다. 전체 API는 DOM에 추가된 단일한 객체로 구성되어 있습니다: {{domxref("window.navigator.connection")}}.</p> +<h2 id="연결상태_변경_감지">연결상태 변경 감지</h2> +<p>이 예제는 사용자의 연결상태 변화를 감시합니다. 사용자가 비싼 망에서 싼 망으로 이동할 때 사용자가 추가적인 비용을 지불하지 않게 하기 위해서 전송량을 감소시키는 등과 같은 행동을 할 수 있게 앱이 경고를 하는 일과 비슷합니다.</p> +<pre class="brush: js">var connection = navigator.connection || navigator.mozConnection || navigator.webkitConnection; + +function updateConnectionStatus() { + alert("Connection bandwidth: " + connection.bandwidth + " MB/s"); + if (connection.metered) { + alert("The connection is metered!"); + } +} + +connection.addEventListener("change", updateConnectionStatus); +updateConnectionStatus(); +</pre> +<h2 id="Specifications" name="Specifications">명세</h2> +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Specification</th> + <th scope="col">Status</th> + <th scope="col">Comment</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{ SpecName('Network Information', '', 'Network Information API') }}</td> + <td>{{ Spec2('Network Information') }}</td> + <td>Initial specification</td> + </tr> + </tbody> +</table> +<h2 id="브라우저_호환성">브라우저 호환성</h2> +<p>{{Page('/en-US/docs/Web/API/window.navigator.connection','Browser compatibility')}}</p> +<h2 id="관련_내용">관련 내용</h2> +<ul> + <li>{{ spec("http://dvcs.w3.org/hg/dap/raw-file/tip/network-api/Overview.html", "Network Information API Specification", "ED") }}</li> + <li><a href="/en/Online_and_offline_events" title="en/Online_and_offline_events">Online and offline events</a></li> + <li>{{domxref("window.navigator.connection")}}</li> +</ul> diff --git a/files/ko/web/api/notifications_api/using_the_notifications_api/index.html b/files/ko/web/api/notifications_api/using_the_notifications_api/index.html new file mode 100644 index 0000000000..351361d2af --- /dev/null +++ b/files/ko/web/api/notifications_api/using_the_notifications_api/index.html @@ -0,0 +1,265 @@ +--- +title: 알림 API 사용하기 +slug: WebAPI/Using_Web_Notifications +translation_of: Web/API/Notifications_API/Using_the_Notifications_API +--- +<p>{{APIRef("Web Notifications")}}{{AvailableInWorkers}}{{securecontext_header}}</p> + +<p>웹 페이지나 앱에서 <a href="/ko/docs/Web/API/Notifications_API">알림(Notifications) API</a>를 사용하면 페이지 외부에 표시되는 알림을 보낼 수 있습니다. 이것은 시스템 레벨에서 처리되는 것으로 애플리케이션이 유휴 상태거나 백그라운드에 있더라도 웹 앱이 사용자에게 정보를 보낼 수 있습니다. 이 글에서는 여러분의 앱에서 이 API를 사용하기 위한 기초를 알아봅니다.</p> + +<p>일반적으로 시스템 알림은 운영 체계의 표준 알림 메커니즘을 말합니다. 예를 들어 일반적인 데스크톱 시스템이나 모바일 장치의 브로드캐스트 알림을 생각해봅시다.</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/10959/android-notification.png" style="display: block; height: 184px; margin: 0px auto; width: 300px;"></p> + +<p>물론 시스템 알림 시스템은 플랫폼 및 브라우저에 따라 다양하지만 괜찮습니다. 알림 API는 범용적으로 작성돼서 대부분의 시스템 알림 시스템과 호환됩니다.</p> + +<h2 id="예시">예시</h2> + +<p>웹 알림의 대표적인 사용 사례는 웹 기반 메일이나 IRC 애플리케이션입니다. 새 메시지가 도착하면 사용자가 다른 애플리케이션으로 다른 일을 하더라도 사용자에게 알릴 필요가 있습니다. 요즘은 <a href="https://slack.com/">Slack</a> 등 이러한 사례를 많이 찾아볼 수 있습니다.</p> + +<p>우리는 웹 알림을 사용하는 방법을 좀더 잘 알 수 있도록 실제적인 예시 — 할 일 목록 앱 —를 작성했습니다. 데이터는 로컬에서 <a href="/ko/docs/Web/API/IndexedDB_API">IndexedDB</a>로 저장하고 사용자 알림은 할 일 기한이 됐을 때 시스템 알림을 사용합니다. <a href="https://github.com/mdn/to-do-notifications/tree/gh-pages">할 일 목록 코드를 다운로드하거나</a>, <a href="https://mdn.github.io/to-do-notifications/">앱의 라이브 실행을 보세요</a>.</p> + +<h2 id="권한_요청하기">권한 요청하기</h2> + +<p><span style="line-height: inherit;">앱이 알림을 보내려면 먼저 사용자가 애플리케이션에 해당 권한을 허용해줘야 합니다. 이는 API가 웹페이지 외부와 상호작용할 때 통상적인 요구 사항입니다. 최소 한번은 사용자가 해당 애플리케이션이 알림을 표시할 수 있는 권한을 허용해줄 필요가 있으며 이로써 사용자는 어떤 앱/사이트가 알림을 보일 수 있는지 제어할 수 있습니다.</span></p> + +<p><span style="line-height: inherit;">과거에 푸시 알림에 대한 악용 때문에 웹 브라우저와 개발자는 그런 문제를 완화할 수 있는 전략을 구현하게 되었습니다. 알림을 발생시키려면 사용자 제스처(예: 단추 클릭)에 대한 응답으로만 가능합니다. 이것은 모범적인 방식일 뿐 아니라 </span>— 사용자에게 미동의 알림으로 스팸을 보내면 안됩니다 — 실제로도 전향적인 브라우저는 사용자 제스처에 대한 응답으로 촉발되지 않은 알림은 명시적으로 불허합니다. 파이어폭스는 이미 72 버전부터 이렇게 하고 있으며 사파리도 하고 있습니다.</p> + +<p>또한 크롬과 파이어폭스에서는 사이트가 보안 콘텍스트(즉, HTTPS)가 아니면 알림을 아예 요청할 수 없으며 크로스 오리진 {{htmlelement("iframe")}}으로부터의 알림 권한은 요청할 수 없게 되었습니다. </p> + +<h3 id="현재_권한_상태_확인하기">현재 권한 상태 확인하기</h3> + +<p><span style="line-height: inherit;">권한을 이미 가지고 있는지 확인하려면 </span>{{domxref("Notification.permission")}} 읽기 전용 속성의 값을 확인하면 됩니다. 다음 세 가지 값이 있을 수 있습니다.</p> + +<dl> + <dt><code>default</code></dt> + <dd>사용자에게 아직 권한을 요구하지 않았으며 따라서 알림을 표시하지 않습니다.</dd> + <dt><code>granted</code></dt> + <dd>사용자에게 알림 표시 권한을 요구했으며 사용자는 권한을 허용했습니다.</dd> + <dt><code>denied</code></dt> + <dd>사용자가 명시적으로 알림 표시 권한을 거부했습니다.</dd> +</dl> + +<h3 id="권한_획득하기">권한 획득하기</h3> + +<p>아직 알림 표시 권한이 허용되지 않았다면 애플리케이션은 {{domxref("Notification.requestPermission()")}} 메서드를 사용하여 사용자에게 권한을 요청할 필요가 있습니다. 간단하게는 아래와 같이 넣습니다.</p> + +<pre>Notification.requestPermission().then(function(result) { + console.log(result); +});</pre> + +<p>여기서는 프로미스 방식의 메서드 버전을 사용합니다. 과거 버전을 지원하려면 아래와 같이 과거의 콜백 버전을 사용해야 할 수 있습니다.</p> + +<pre>Notification.requestPermission();</pre> + +<p>콜백 버전은 콜백 함수를 옵셔널하게 받을 수 있으며 사용자가 표시 권한 요청에 응답한 후에 호출됩니다.</p> + +<h3 id="예시_2">예시</h3> + +<p>우리가 만드는 할 일 데모에서는 "알림 허용" 단추를 둬서 누르면 앱의 알림 권한을 요청합니다.</p> + +<pre><button id="enable">알림 허용</button></pre> + +<p>누르면 다음 <code>askNotificationPermission()</code> 함수를 호출합니다.</p> + +<pre>function askNotificationPermission() { + // 권한을 실제로 요구하는 함수 + function handlePermission(permission) { + // 사용자의 응답에 관계 없이 크롬이 정보를 저장할 수 있도록 함 + if(!('permission' in Notification)) { + Notification.permission = permission; + } + + // 사용자 응답에 따라 단추를 보이거나 숨기도록 설정 + if(Notification.permission === 'denied' || Notification.permission === 'default') { + notificationBtn.style.display = 'block'; + } else { + notificationBtn.style.display = 'none'; + } + } + + // 브라우저가 알림을 지원하는지 확인 + if (!('Notification' in window)) { + console.log("이 브라우저는 알림을 지원하지 않습니다."); + } else { + if(checkNotificationPromise()) { + Notification.requestPermission() + .then((permission) => { + handlePermission(permission); + }) + } else { + Notification.requestPermission(function(permission) { + handlePermission(permission); + }); + } + } +}</pre> + +<p>두 번째 메인 블록을 먼저 보면 알림이 지원되는지 확인하는 것을 알 수 있습니다. 지원하는 경우 그에 따라 <code>Notification.requestPermission()</code>의 프로미스 기반 버전이 지원되는지 보는 확인을 실행합니다. 맞다면 프로미스 기반 버전을 실행하고(사파리 외에는 전부 지원됨) 아니라면 과거의 콜백 기반 버전을 실행합니다(사파리에서 지원).</p> + +<p>코드 중복을 피하기 위해 뒷 처리 수행 코드를 <code>handlePermission()</code> 함수에 넣었는데 이 함수가 코드에서 첫 번째 메인 블록입니다. 그 안에서는 <code>Notification.permission</code> 값을 명시적으로 설정하고(크롬의 일부 과거 버전에서는 이게 자동으로 안됩니다) 사용자가 권한 대화창에서 선택한 결과에 따라 단추를 보이거나 숨깁니다. 권한이 이미 허용됐는지 보여주려는 것은 아니고 사용자가 권한을 거부한 경우 나중에 다시 선택할 수 있도록 해주는 것입니다.</p> + +<p><strong>참고:</strong> 크롬 37 버전 전에는 <code>load</code> 이벤트 핸들러에서 {{domxref("Notification.requestPermission()")}}을 호출할 수 없었습니다(<a href="https://code.google.com/p/chromium/issues/detail?id=274284" title="https://code.google.com/p/chromium/issues/detail?id=274284">이슈 274284</a> 참고).</p> + +<h3 id="requestPermission_프로미스_기능_알아내기">requestPermission() 프로미스 기능 알아내기</h3> + +<p>위에서 우리는 브라우저가 <code>Notification.requestPermission()</code>의 프로미스 버전을 지원하는지 확인해야 한다고 했습니다. 아래와 같이 했습니다.</p> + +<pre>function checkNotificationPromise() { + try { + Notification.requestPermission().then(); + } catch(e) { + return false; + } + + return true; + }</pre> + +<p>기본적으로 <code>requestPermission()</code>에 <code>.then()</code> 메서드가 있는지 알아보는 것입니다. 맞다면 계속 진행하고 <code>true</code>를 반환합니다. 실패라면 <code>catch() {}</code> 블록에서 <code>false</code>를 반환합니다.</p> + +<h2 id="알림_만들기">알림 만들기 </h2> + +<p>알림 만들기는 쉬워서 {{domxref("Notification")}} 생성자만 사용하면 됩니다. 이 생성자는 알림에 표시할 제목과 {{domxref("Notification.icon","icon")}}이나 텍스트 {{domxref("Notification.body","body")}} 같은 알림 조작 옵션 몇 가지를 받도록 돼 있습니다.</p> + +<p>예를 들어 할일 목록 예시에서 아래 코드로 필요시 알림을 만듭니다(<code>createNotification()</code> 함수에서 찾을 수 있음).</p> + +<pre>var img = '/to-do-notifications/img/icon-128.png'; +var text = '아! "' + title + '" 작업 기한이 만료됐습니다.'; +var notification = new Notification('할 일 목록', { body: text, icon: img }); +</pre> + +<h2 id="알림_닫기">알림 닫기</h2> + +<p>파이어폭스와 사파리는 알림을 자동으로 금방(약 4초) 닫습니다. 이것은 운영 체계 수준에서도 발생합니다. 그런데 크롬 같은 다른 브라우저는 그렇지 않습니다. 모든 브라우저에서 알림이 닫히게 하려면 {{domxref("WindowTimers.setTimeout","setTimeout()")}} 함수에서 {{domxref("Notification.close")}} 함수를 호출하여 알림을 4초 후에 닫으면 됩니다. <code><a href="/ko/docs/Web/JavaScript/Reference/Global_Objects/Function/bind">bind()</a></code>를 사용하여 <code>close()</code> 호출이 알림에 연동되게 하는 것도 해줘야 합니다.</p> + +<pre>setTimeout(notification.close.bind(notification), 4000);</pre> + +<div class="note"> +<p><strong>참고</strong>: "close" 이벤트를 받았을 때 알림을 닫은 것이 사용자인지는 보장할 수 없습니다. 이것은 규격과도 일치합니다. 규격에서는 "알림이 닫힐 때 그것이 기반 알림 플랫폼에 의한 것이든지 사용자에 의한 것이든지 닫기 절차가 실행돼야 한다."고 기술하고 있습니다.</p> +</div> + +<h2 id="알림_이벤트">알림 이벤트</h2> + +<p><span style="line-height: inherit;">{{domxref("Notification")}} 인스턴스에 촉발되는 이벤트는 다음 네 가지입니다.</span></p> + +<dl> + <dt><code>click</code></dt> + <dd>사용자가 알림을 클릭하면 촉발됩니다.</dd> + <dt><code>close</code></dt> + <dd>알림이 닫힌 후 촉발됩니다.</dd> + <dt><code>error</code></dt> + <dd>알림에 문제가 있을 경우 촉발되며 대개 어떤 이유에 의해 알림을 표시할 수 없는 경우입니다.</dd> + <dt><code>show</code></dt> + <dd>알림이 사용자에게 표시되면 촉발됩니다.</dd> +</dl> + +<p>이 이벤트들은 {{domxref("Notification.onclick","onclick")}}, {{domxref("Notification.onclose","onclose")}}, {{domxref("Notification.onerror","onerror")}}, {{domxref("Notification.onshow","onshow")}} 핸들러로 추적할 수 있습니다. <span style="line-height: inherit;">{{domxref("Notification")}}이 {{domxref("EventTarget")}}을 상속하기 때문에 </span>{{domxref("EventTarget.addEventListener","addEventListener()")}} 메서드를 사용할 수 있습니다.</p> + +<h2 id="기존_알림_대체하기">기존 알림 대체하기</h2> + +<p>사용자가 잠깐 사이에 알림을 많이 받는 것은 바람직하지 않습니다. 예를 들어 메신저 애플리케이션이 모든 수신 메시지를 사용자에게 알리는데 그게 아주 많다면요? 사용자가 알림 때문에 대량 스팸을 받지 않도록 알림 대기열(큐)을 수정해서 걸려 있는 알림 하나나 여럿을 새로운 알림 하나로 대체할 수 있습니다.</p> + +<p>이를 위해 새 알림에 태그를 붙일 수 있습니다. 알림에 이미 같은 태그가 있고 표시되지 않았다면 새 알림으로 이전 알림을 대체하는 것입니다. 같은 태그의 알림이 이미 표시됐다면 이전 알림을 닫고 새 알림을 표시합니다.</p> + +<h3 id="태그_예시">태그 예시</h3> + +<p>다음과 같은 간단한 HTML을 봅시다.</p> + +<pre class="brush: html"><button>알림 실행!</button></pre> + +<p>다수의 알림을 아래 방법으로 처리할 수 있습니다.</p> + +<pre class="brush: js">window.addEventListener('load', function () { + // 처음에는 알림 권한이 있는지 확인함 + // 없으면 권한 요구 + if (Notification && Notification.permission !== "granted") { + Notification.requestPermission(function (status) { + if (Notification.permission !== status) { + Notification.permission = status; + } + }); + } + + var button = document.getElementsByTagName('button')[0]; + + button.addEventListener('click', function () { + // 사용자가 알림을 받는 데 동의한 경우 + // 알림 10개를 보내본다 + if (Notification && Notification.permission === "granted") { + var i = 0; + // 어떤 브라우저(파이어폭스 등)는 일정 시간 동안 알림이 너무 많은 경우 차단하기 때문에 인터벌 사용. + var interval = window.setInterval(function () { + // 태그 덕분에 "안녕! 9" 알림만 보여야 함 + var n = new Notification("안녕! " + i, {tag: '알림너무많음'}); + if (i++ == 9) { + window.clearInterval(interval); + } + }, 200); + } + + // 사용자가 알림을 받을지 말지 답하지 않은 경우 + // 참고: 크롬 때문에 권한 속성이 설정됐는지 알 수 없으므로 + // "기본" 값을 확인하는 것은 안전하지 않음 + else if (Notification && Notification.permission !== "denied") { + Notification.requestPermission(function (status) { + // 사용자가 ok한 경우 + if (status === "granted") { + var i = 0; + // 어떤 브라우저(파이어폭스 등)는 일정 시간 동안 알림이 너무 많은 경우 차단하기 때문에 인터벌 사용. + var interval = window.setInterval(function () { + // 태그 덕분에 "안녕! 9" 알림만 보여야 함 + var n = new Notification("안녕! " + i, {tag: '알림너무많음'}); + if (i++ == 9) { + window.clearInterval(interval); + } + }, 200); + } + + // 그 외의 경우 일반적인 모달 alert로 폴백 + else { + alert("안녕!"); + } + }); + } + + // 사용자가 알림을 거부한 경우 + else { + // 일반적인 모달 alert로 폴백 + alert("안녕!"); + } + }); +});</pre> + +<p>라이브 결과는 아래에서 보세요.</p> + +<p>{{ EmbedLiveSample('Tag_example', '100%', 30) }}</p> + +<h2 id="규격">규격</h2> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">규격</th> + <th scope="col">상태</th> + <th scope="col">비고</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{SpecName('Web Notifications')}}</td> + <td>{{Spec2('Web Notifications')}}</td> + <td>현행 표준</td> + </tr> + </tbody> +</table> + +<h2 id="브라우저_호환성">브라우저 호환성</h2> + +<p>{{page("/en-US/Web/API/Notification","Browser compatibility")}}</p> + +<h2 id="참고">참고</h2> + +<ul> + <li><a href="/ko/Apps/Build/User_notifications">사용자 알림 편람</a></li> + <li>{{ domxref("Notification") }}</li> +</ul> diff --git a/files/ko/web/api/proximity_events/index.html b/files/ko/web/api/proximity_events/index.html new file mode 100644 index 0000000000..ad1687ddd2 --- /dev/null +++ b/files/ko/web/api/proximity_events/index.html @@ -0,0 +1,119 @@ +--- +title: Proximity +slug: WebAPI/Proximity +translation_of: Web/API/Proximity_Events +--- +<p>{{ SeeCompatTable }}</p> +<h2 id="Summary">Summary</h2> +<p>근접 이벤트는 사용자가 디바이스에 가까이 갔을때를 알 수 있는 간단한 벙법이다.</p> +<p>예를 들어, 사용자가 전화가 걸려왔을 때 디바이스에 귀를 가까이 하면, 근접 이벤트들은 스마트폰의 화면이 꺼지게 하여 이러한 변화에 대응할 수 있게 해준다.</p> +<div class="note"> + <p><strong>Note:</strong> 당연히 이 API는 근접 센서를 가진 장치를 필요로 하며, 이 근접 센서는 대게 모바일 다비이스들에서만 이용 가능하다. 근접 센서가 없는 장치들에서는 근접 이벤트들을 지원할 수는 있을 지 몰라도 해당 이벤트들은 절대 발생하지 않을 것이다.</p> +</div> +<h2 id="Proximity_Events">Proximity Events</h2> +<p>다비이스 근접 센서가 장치와 대상 사이의 변화를 감지했을 때, 센서는 그 변화를 브라우저에게 알린다. 브라우저는 그 알림을 받으면 그 변화에 대해 {{domxref("DeviceProximityEvent")}} 이벤트를 발생시킨다. 그리고 더 대략적인 변화(more rough change)를 알리기 위해 {{domxref("UserProximityEvent")}} 이벤트를 발생시킨다.</p> +<p>window object 레벨에서 {{domxref("EventTarget.addEventListener","addEventListener")}} 메소드 ({{event("deviceproximity")}} 또는 {{event("userproximity")}} 이벤트명) 를 이용하여 근접 이벤트를 전달받을 수 있다. 또한 {{domxref("window.ondeviceproximity")}} 또는 {{domxref("window.onuserproximity")}} 프로퍼티에 이벤트 핸들러를 붙이는 방법으로도 이벤트를 전달받을 수 있다.</p> +<p>일단 이벤트가 전달되면, 그 이벤트 오브젝트는 다음과 같은 여러 종류의 정보에 접근할 수 있게 해준다:</p> +<ul> + <li> {{domxref("DeviceProximityEvent")}} 이벤트는 {{domxref("DeviceProximityEvent.value","value")}} 프로퍼티를 통해 디바이스와 대상 사이의 거리에 정확히 매치되는 값을 제공한다. 또한 이 이벤트는 장치가 감지할 수 있는 가장 가까운 거리, 가장 먼거리에 대한 정보를 {{domxref("DeviceProximityEvent.min","min")}} 와 {{domxref("DeviceProximityEvent.max","max")}} 프로퍼티 값을 통해 제공한다.</li> + <li>{{domxref("UserProximityEvent")}} 이벤트는 거리에 대한 대략적인 추정치를 boolean 형태로 제공한다. 대상과 디바이스가 가까운면 {{domxref("UserProximityEvent.near")}} 프로퍼티 값은 true 가 되고, 대상과의 거리가 멀다면 그 값은 false가 된다.</li> +</ul> +<h2 id="Example">Example</h2> +<pre class="brush: js">window.addEventListener('userproximity', function(event) { + if (event.near) { + // let's power off the screen + navigator.mozPower.screenEnabled = false; + } else { + // Otherwise, let's power on the screen + navigator.mozPower.screenEnabled = true; + } +});</pre> +<h2 id="Specifications" name="Specifications">Specifications</h2> +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Specification</th> + <th scope="col">Status</th> + <th scope="col">Comment</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{ SpecName('Proximity Events', '', 'Proximity Events') }}</td> + <td>{{ Spec2('Proximity Events') }}</td> + <td>Initial specification</td> + </tr> + </tbody> +</table> +<h2 id="Browser_compatibility">Browser compatibility</h2> +<p>{{ CompatibilityTable() }}</p> +<div id="compat-desktop"> + <table class="compat-table"> + <tbody> + <tr> + <th>Feature</th> + <th>Chrome</th> + <th>Firefox (Gecko)</th> + <th>Internet Explorer</th> + <th>Opera</th> + <th>Safari</th> + </tr> + <tr> + <td>{{domxref("DeviceProximityEvent")}}</td> + <td>{{CompatNo()}}</td> + <td>{{CompatVersionUnknown()}}</td> + <td>{{CompatNo()}}</td> + <td>{{CompatNo()}}</td> + <td>{{CompatNo()}}</td> + </tr> + <tr> + <td>{{domxref("UserProximityEvent")}}</td> + <td>{{CompatNo()}}</td> + <td>{{CompatVersionUnknown()}}</td> + <td>{{CompatNo()}}</td> + <td>{{CompatNo()}}</td> + <td>{{CompatNo()}}</td> + </tr> + </tbody> + </table> +</div> +<div id="compat-mobile"> + <table class="compat-table"> + <tbody> + <tr> + <th>Feature</th> + <th>Android</th> + <th>Chrome for Android</th> + <th>Firefox Mobile (Gecko)</th> + <th>IE Mobile</th> + <th>Opera Mobile</th> + <th>Safari Mobile</th> + </tr> + <tr> + <td>{{domxref("DeviceProximityEvent")}}</td> + <td>{{CompatNo()}}</td> + <td>{{CompatNo()}}</td> + <td>{{ CompatGeckoMobile("15.0") }}</td> + <td>{{CompatNo()}}</td> + <td>{{CompatNo()}}</td> + <td>{{CompatNo()}}</td> + </tr> + <tr> + <td>{{domxref("UserProximityEvent")}}</td> + <td>{{CompatNo()}}</td> + <td>{{CompatNo()}}</td> + <td>{{CompatVersionUnknown()}}</td> + <td>{{CompatNo()}}</td> + <td>{{CompatNo()}}</td> + <td>{{CompatNo()}}</td> + </tr> + </tbody> + </table> +</div> +<h2 id="See_also">See also</h2> +<ul> + <li>{{domxref("DeviceProximityEvent")}}</li> + <li>{{domxref("UserProximityEvent")}}</li> + <li>{{event("deviceproximity")}}</li> + <li>{{event("userproximity")}}</li> +</ul> diff --git a/files/ko/web/api/screen.onorientationchange/index.html b/files/ko/web/api/screen/onorientationchange/index.html index dc1a76013f..dc1a76013f 100644 --- a/files/ko/web/api/screen.onorientationchange/index.html +++ b/files/ko/web/api/screen/onorientationchange/index.html diff --git a/files/ko/web/api/streams_api/컨셉/index.html b/files/ko/web/api/streams_api/concepts/index.html index 9c993b81a3..9c993b81a3 100644 --- a/files/ko/web/api/streams_api/컨셉/index.html +++ b/files/ko/web/api/streams_api/concepts/index.html diff --git a/files/ko/web/api/vibration_api/index.html b/files/ko/web/api/vibration_api/index.html new file mode 100644 index 0000000000..16271ff248 --- /dev/null +++ b/files/ko/web/api/vibration_api/index.html @@ -0,0 +1,100 @@ +--- +title: Vibration API +slug: Web/Guide/API/Vibration/Vibration +translation_of: Web/API/Vibration_API +--- +<div>{{DefaultAPISidebar("Vibration API")}}</div> + +<p>요즘 나오는 대부분은 모바일 디바이스는 바이브레이션 하드웨어를 포함하고 있다. 소프트웨어 코드를 이용해 바이브레이션 하드웨어를 제어하면, 모바일 디바이스를 흔들리게 만들어 사용자에게 물리적인 피드백을 제공할 수 있다.</p> + +<p><strong>Vibration API</strong>는 웹앱들이 기기에 장착된 물리 진동장치를 통해 진동을 전달할 수 있도록 해줍니다. 하지만 대응하는 진동 장치가 없는 기기일 경우 아무일도 일어나지 않습니다.</p> + +<h2 id="Describing_vibrations">Describing vibrations</h2> + +<p>바이브레이션은 온오프 펄스들의 패턴이라고 할 수 있는데, 이 펄스들은 아마도 다양한 길이를 가질 것이다. 이 패턴은 아마 하나의 정수값으로 구성될 수 있는데 이 정수값은 진동이 일어날 밀리세컨드 수를 의미한다. 또한 이 패턴은 정수 배열이 될 수도 있는데 이것은 진동과 정지들의 패턴을 의미한다. 바이브레이션은 {{domxref("window.navigator.vibrate()")}} 라는 하나의 메소드로 제어된다.</p> + +<h3 id="한번_진동시키기">한번 진동시키기</h3> + +<p>여러분은 다음과 같이 하나의 값 또는 하나의 값으로 구성된 배열을 명시함으로써 바이브레이션 하드웨어를 1회 진동시킬 수 있을 것이다.</p> + +<pre class="brush:js">window.navigator.vibrate(200); +window.navigator.vibrate([200]); +</pre> + +<p>이 두 가지 예제들은 디바이스를 200ms 동안 진동시킨다.</p> + +<h3 id="패턴이_있는_진동_만들기">패턴이 있는 진동 만들기</h3> + +<p>배 열에 있는 값들은 다바이스가 진동해야 하는 시간과 진동하지 않아야 하는 시간을 번갈아가며 적어놓은 것이다. 배열에 있는 각 값은 하나의 정수로 변환된 후 차례대로 장치가 진동해야 하는 시간, 장치가 진동하지 않아야 하는 시간으로 해석된다. 다음 예제를 보자.</p> + +<pre class="brush: js">window.navigator.vibrate([200, 100, 200]); +</pre> + +<p>이 예제는 장치를 200ms 동안 진동시킨 후 100ms 동안 멈추게 하고 그 후 다시 200ms 동안 장치를 진동시킨다.</p> + +<p>여 러분은 여러분이 원하는 진동/정지 페어를 명시할 수 있다. 그리고 배열 내에 홀수 또는 짝수개의 값들을 명시할 수도 있다. 이렇게 하는 이유는 각각의 진동 시간이 끝나면 디바이스의 진동은 자동적으로 멈추게 되므로 배열의 마지막 값이 정지에 해당하는 값이라면 그 값은 아무 의미가 없기 때문이다.</p> + +<h3 id="이미_실행중인_진동_캔슬하기">이미 실행중인 진동 캔슬하기</h3> + +<p>{{domxref("window.navigator.vibrate()")}} <code>메소드를 0값을 호출하거나, 빈 배열, 0값으로 구성된 배열로 호출하면 </code>현재 진행중인 진동패턴은 취소될 것이다.</p> + +<h3 id="지속적인_진동_내보내기">지속적인 진동 내보내기</h3> + +<p>Some basic <code>setInterval</code> and <code>clearInterval</code> action will allow you to create persistent vibration:</p> + +<pre><code>var vibrateInterval; + +// Starts vibration at passed in level +function startVibrate(duration) { + navigator.vibrate(duration); +} + +// Stops vibration +function stopVibrate() { + // Clear interval and stop persistent vibrating + if(vibrateInterval) clearInterval(vibrateInterval); + navigator.vibrate(0); +} + +// Start persistent vibration at given duration and interval +// Assumes a number value is given +function startPeristentVibrate(duration, interval) { + vibrateInterval = setInterval(function() { + startVibrate(duration); + }, interval); +}</code></pre> + +<p>Of course the snippet above doesn't take into account the array method of vibration; persistent array-based vibration will require calculating the sum of the array items and creating an interval based on that number (with an additional delay, probably).</p> + +<h3 id="Why_use_Vibration_API">Why use Vibration API?</h3> + +<p>This API is clearly targeted toward mobile devices. The Vibration API would be good for alerts within mobile web applications, and would be especially awesome when used in games or media-heavy applications. Imagine watching a video on your mobile device, and during an explosion scene, your phone got a bit of a shake. Or playing Bomberman and feeling a gentle kick when a block explodes!</p> + +<h2 id="Specifications">Specifications</h2> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">Specification</th> + <th scope="col">Status</th> + <th scope="col">Comment</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{SpecName('Vibration API')}}</td> + <td>{{Spec2('Vibration API')}}</td> + <td>Initial specification.</td> + </tr> + </tbody> +</table> + +<h2 id="브라우저_호환성">브라우저 호환성</h2> + +<div>{{Compat("api.Navigator.vibrate")}}</div> + +<h2 id="같이_보기">같이 보기</h2> + +<ul> + <li>{{domxref("window.navigator.vibrate()")}}</li> +</ul> diff --git a/files/ko/web/api/web_workers_api/basic_usage/index.html b/files/ko/web/api/web_workers_api/using_web_workers/index.html index eb0e309e8e..eb0e309e8e 100644 --- a/files/ko/web/api/web_workers_api/basic_usage/index.html +++ b/files/ko/web/api/web_workers_api/using_web_workers/index.html diff --git a/files/ko/web/api/webgl_api/cross-domain_textures/index.html b/files/ko/web/api/webgl_api/cross-domain_textures/index.html deleted file mode 100644 index 94e969e37a..0000000000 --- a/files/ko/web/api/webgl_api/cross-domain_textures/index.html +++ /dev/null @@ -1,34 +0,0 @@ ---- -title: 크로스-도메인 텍스쳐 -slug: Web/API/WebGL_API/Cross-Domain_Textures -tags: - - WebGL - - 웹지엘 - - 크로스 도메인 - - 텍스쳐 -translation_of: Web/API/WebGL_API/Tutorial/Using_textures_in_WebGL#Cross-domain_textures -translation_of_original: Web/API/WebGL_API/Cross-Domain_Textures ---- -<p>WebGL 텍스쳐 로딩은 크로스-도메인 접근 규칙에 따라 제약을 받습니다. 여러분이 만든 컨텐츠에서 다른 도메인의 텍스쳐,<span style="line-height: 16.7999992370605px;"> 즉, 크로스-도메인 텍스쳐를 로딩</span>하려면 CORS 승인이 필요합니다. CORS에 대한 자세한 내용은 <a href="/En/HTTP_access_control">HTTP access control</a>을 참고하시기 바랍니다.</p> - -<p>CORS 승인된 이미지를 WebGL 텍스쳐에 사용하는 방법에 대한 설명은 <a href="http://hacks.mozilla.org/2011/11/using-cors-to-load-webgl-textures-from-cross-domain-images/">hacks.mozilla.org 문서</a>와 <a href="http://people.mozilla.org/~bjacob/webgltexture-cors-js.html">예제</a>를 참고하시기 바랍니다.</p> - -<blockquote> -<p>역자 주 : 예제 링크가 깨져있는데, 원문에도 깨진 링크가 포함되어 있습니다.</p> -</blockquote> - -<div class="note"> -<p><strong>Note:</strong> WebGL 텍스쳐에 대한 CORS 지원과 이미지 요소의 crossOrigin 속성이 {{Gecko("8.0")}}에 구현되어 있습니다.</p> -</div> - -<p>내용이 변경되어 오염된(tainted) 쓰기 전용의 2D 캔버스는 WebGL 텍스쳐로 사용될 수 없습니다. 예를 들어 크로스-도메인 이미지가 그려진 2D <span style="line-height: 16.7999992370605px;">{{ HTMLElement("canvas") }}는 오염된 2D 캔버스라고 할 수 있습니다.</span></p> - -<div class="note"> -<p><strong>Note:</strong> 캔버스 2D의 drawImage에 대한 CORS 지원은 {{Gecko("9.0")}}에 구현되어 있습니다. 따라서 {{Gecko("9.0")}}에서부터는, CORS 승인된 크로스-도메인 이미지는 2D 캔버스를 오염시키지 않으며, CORS 승인된 크로스-도메인 이미지가 그려진 2D 캔버스도 WebGL 텍스쳐로 사용할 수 있습니다.</p> -</div> - -<div class="note"> -<p><strong>Note:</strong> 크로스-도메인 비디오에 대한 CORS 지원과 {{ HTMLElement("video") }}요소의 crossorigin 속성은 {{Gecko("12.0")}}에 구현되어 있습니다.</p> -</div> - -<p>{{ languages( { "ja": "ja/WebGL/Cross-Domain_Textures", "ko": "ko/Web/WebGL/Cross-Domain_Textures"} ) }}</p> diff --git a/files/ko/web/api/websockets_api/index.html b/files/ko/web/api/websockets_api/index.html new file mode 100644 index 0000000000..8b6fd20b1a --- /dev/null +++ b/files/ko/web/api/websockets_api/index.html @@ -0,0 +1,172 @@ +--- +title: 웹 소켓 +slug: WebSockets +translation_of: Web/API/WebSockets_API +--- +<p>웹 소켓은 사용자의 브라우저와 서버 사이의 인터액티브 통신 세션을 설정할 수 있게 하는 고급 기술입니다. 개발자는 웹 소켓 API를 통해 서버로 메시지를 보내고 서버의 응답을 위해 서버를 폴링하지 않고도 이벤트 중심 응답을 받는 것이 가능합니다.</p> + +<div class="cleared row topicpage-table"> +<h2 class="Interfaces" id="Interfaces" name="Interfaces"><code>인터페이스</code></h2> + +<dl> + <dt><code><code><a href="/ko/docs/Web/API/WebSocket" title="ko/WebSockets/WebSockets reference/WebSocket"><code>WebSocket</code></a></code></code></dt> + <dd>웹 소켓 서버로 연결하고 연결을 통해 데이터를 보내고 받는 기본 인터페이스</dd> + <dt><code><code><code><a href="/ko/docs/Web/API/CloseEvent" title="ko/WebSockets/WebSockets reference/CloseEvent"><code>CloseEvent</code></a></code></code></code></dt> + <dd>연결이 종료 되었을 때 웹 소켓 객체에 의해 전달된 이벤트</dd> + <dt><code><code><code><a href="/ko/docs/Web/API/MessageEvent" title="ko/WebSockets/WebSockets reference/MessageEvent"><code>MessageEvent</code></a></code></code></code></dt> + <dd>서버로 부터 메시지가 수신 되었을 때 웹 소켓 객체에 의해 전달된 이벤트</dd> +</dl> +</div> + +<div class="section"> +<h2 class="Tools" id="Tools" name="Tools"><code><code>도구</code></code></h2> + +<ul> + <li><a class="external" href="http://socket.io" title="http://socket.io/">Socket.IO</a>: <a class="external" href="http://nodejs.org" title="http://nodejs.org/">Node.js</a>를 위한 강력한 크로스 플랫폼 웹 소켓 API</li> + <li><a class="link-https" href="https://github.com/Worlize/WebSocket-Node" title="https://github.com/Worlize/WebSocket-Node">WebSocket-Node</a>: <a class="external" href="http://nodejs.org" title="http://nodejs.org/">Node.js</a>를 위한 웹 소켓 서버 API 구현</li> + <li><a href="http://ajf.me/websocket/#libs" title="http://websocket.us/#libs">더 많은 프레임워크, 라이브러리 보기</a></li> +</ul> + +<h2 class="Related_Topics" id="Related_Topics" name="Related_Topics"><code><code>관련 주제</code></code></h2> + +<ul> + <li><a href="/en-US/docs/AJAX" title="AJAX">AJAX</a>, <a href="/en-US/docs/JavaScript" title="JavaScript">JavaScript</a></li> +</ul> +</div> + +<h2 id="같이_보기"><code><code>같이 보기</code></code></h2> + +<ul> + <li><a class="external" href="http://tools.ietf.org/html/rfc6455">RFC 6455 - 웹 소켓 프로토콜</a></li> + <li><a class="external" href="http://www.w3.org/TR/websockets/">웹 소켓 API 규격</a></li> + <li><a href="/en-US/docs/Server-sent_events" title="Server-sent_events">서버로부터의 이벤트</a></li> + <li><a class="external" href="http://websocket.us/">WebSocket.us</a> - 웹 소켓에 대한 비영리 커뮤니티</li> +</ul> + +<h2 id="브라우저_호환성"><code><code>브라우저 호환성</code></code></h2> + +<p><code><code>{{CompatibilityTable}}</code></code></p> + +<div id="compat-desktop"> +<table class="compat-table"> + <tbody> + <tr> + <th><code><code>기능</code></code></th> + <th><code><code>Chrome</code></code></th> + <th><code><code>Firefox (Gecko)</code></code></th> + <th><code><code>Internet Explorer</code></code></th> + <th><code><code>Opera</code></code></th> + <th><code><code>Safari</code></code></th> + </tr> + <tr> + <td><code><code>버전 76 지원 {{obsolete_inline}}</code></code></td> + <td><code><code>6</code></code></td> + <td><code><code>{{CompatGeckoDesktop("2.0")}}</code></code></td> + <td><code><code>{{CompatNo}}</code></code></td> + <td><code><code>11.00 (disabled)</code></code></td> + <td><code><code>5.0.1</code></code></td> + </tr> + <tr> + <td><code><code>버전 7 지원 {{obsolete_inline}}</code></code></td> + <td><code><code>{{CompatNo}}</code></code></td> + <td><code><code>{{CompatGeckoDesktop("6.0")}}<br> + {{property_prefix("Moz")}}</code></code></td> + <td><code><code>{{CompatNo}}</code></code></td> + <td><code><code>{{CompatNo}}</code></code></td> + <td><code><code>{{CompatNo}}</code></code></td> + </tr> + <tr> + <td><code><code>버전 10 지원 {{obsolete_inline}}</code></code></td> + <td><code><code>14</code></code></td> + <td><code><code>{{CompatGeckoDesktop("7.0")}}<br> + {{property_prefix("Moz")}}</code></code></td> + <td><code><code>HTML5 Labs</code></code></td> + <td><code><code>{{CompatUnknown}}</code></code></td> + <td><code><code>{{CompatUnknown}}</code></code></td> + </tr> + <tr> + <td><code><code>표준 - RFC 6455 지원</code></code></td> + <td><code><code>16</code></code></td> + <td><code><code>{{CompatGeckoDesktop("11.0")}}</code></code></td> + <td><code><code>10</code></code></td> + <td><code><code>12.10</code></code></td> + <td><code><code>6.0</code></code></td> + </tr> + </tbody> +</table> +</div> + +<div id="compat-mobile"> +<table class="compat-table"> + <tbody> + <tr> + <th><code><code>기능</code></code></th> + <th><code><code>Android</code></code></th> + <th><code><code>Firefox Mobile (Gecko)</code></code></th> + <th><code><code>IE Mobile</code></code></th> + <th><code><code>Opera Mobile</code></code></th> + <th><code><code>Safari Mobile</code></code></th> + </tr> + <tr> + <td><code><code>버전 76 지원 {{obsolete_inline}}</code></code></td> + <td><code><code>{{CompatUnknown}}</code></code></td> + <td><code><code>{{CompatUnknown}}</code></code></td> + <td><code><code>{{CompatUnknown}}</code></code></td> + <td><code><code>{{CompatUnknown}}</code></code></td> + <td><code><code>{{CompatUnknown}}</code></code></td> + </tr> + <tr> + <td><code><code>버전 7 지원 {{obsolete_inline}}</code></code></td> + <td><code><code>{{CompatUnknown}}</code></code></td> + <td><code><code>{{CompatUnknown}}</code></code></td> + <td><code><code>{{CompatUnknown}}</code></code></td> + <td><code><code>{{CompatUnknown}}</code></code></td> + <td><code><code>{{CompatUnknown}}</code></code></td> + </tr> + <tr> + <td><code><code>버전 8 지원 (IETF draft 10) {{obsolete_inline}}</code></code></td> + <td><code><code>{{CompatUnknown}}</code></code></td> + <td><code><code>{{CompatGeckoMobile("7.0")}}</code></code></td> + <td><code><code>{{CompatUnknown}}</code></code></td> + <td><code><code>{{CompatUnknown}}</code></code></td> + <td><code><code>{{CompatUnknown}}</code></code></td> + </tr> + <tr> + <td><code><code>표준 - RFC 6455 지원</code></code></td> + <td><code><code>16 (Chrome)</code></code></td> + <td><code><code>{{CompatGeckoDesktop("11.0")}}</code></code></td> + <td><code><code>{{CompatUnknown}}</code></code></td> + <td><code><code>12.10</code></code></td> + <td><code><code>6.0</code></code></td> + </tr> + </tbody> +</table> +</div> + +<h3 id="Gecko"><code><code>Gecko</code></code></h3> + +<p><code><code>파이어폭스는 발전하는 웹 소켓 규격을 지속적으로 지원하고 있습니다. 파이어폭스 6은 웹 소켓 프로토콜 버전 7을, 파이어폭스 7은 버전 8을 지원합니다. (IETF 초안 10) 파이어폭스 모바일은 7.0부터 웹 소켓을 지원합니다.</code></code></p> + +<h4 id="Gecko_6.0"><code><code>Gecko 6.0</code></code></h4> + +<p><code><code>Gecko 6.0 {{geckoRelease("6.0")}} 이전엔 <code>WebSocket </code>객체가 존재하였으며, 일부 사이트가 <code>WebSocket </code>서비스는 접두어가 붙지 않는 것이라고 생각하기도 했습니다. 이 객체는 <code>MozWebSocket</code>으로 개명되었습니다.</code></code></p> + +<h4 id="Gecko_7.0"><code><code>Gecko 7.0</code></code></h4> + +<p><code><code>Gecko 7.0 {{geckoRelease("7.0")}} 이후로 고급 환경 설정의 <code>network.websocket.max-connections</code> 항목을 통해 동시에 열릴 수 있는 웹 소켓 연결의 최대값을 지정할 수 있습니다. 기본값은 200입니다.</code></code></p> + +<h4 id="Gecko_8.0"><code><code>Gecko 8.0</code></code></h4> + +<p><code><code>Gecko 8.0 {{geckoRelease("8.0")}} 이후로 웹 소켓 규격 초안의 변경에 따라 웹 소켓의 deflate 스트림 확장이 비활성화 되었습니다. 이는 일부 사이트의 호환성 문제를 해결합니다.</code></code></p> + +<h4 id="Gecko_11.0"><code><code>Gecko 11.0</code></code></h4> + +<p><code><code>Gecko 11.0 이전에는 모든 메시지가 16 MB를 넘을 수 없었으나, 지금은 최대 2 GB까지 가능합니다. 그러나 (특히 모바일에서) 권장되는 방법은 아닙니다. 충분한 메모리를 가지지 못한 장치에서는 통신이 실패하게 될 것입니다.</code></code></p> + +<p><code><code>추가적으로 바이너리 데이터를 위한 ArrayBuffer 지원이 구현되었습니다.</code></code></p> + +<p><code><code>Gecko 11.0부터 웹 소켓 API는 더이상 접두사가 붙지 않습니다.</code></code></p> + +<div class="warning"><code><code><strong>주의:</strong> 파이어폭스 4, 5에서 웹 소켓이 비활성화 돼있었던 가장 주요한 이유는 <a class="external" href="http://www.ietf.org/mail-archive/web/hybi/current/msg04744.html" title="http://www.ietf.org/mail-archive/web/hybi/current/msg04744.html">프로토콜 설계의 보안성 문제</a> 때문이었습니다. 이는 파이어폭스 6에서 상위 버전의 프로토콜을 구현함으로써 해결되었습니다.</code></code></div> + +<div><code><code>{{HTML5ArticleTOC}}</code></code></div> diff --git a/files/ko/web/api/websockets_api/writing_websocket_client_applications/index.html b/files/ko/web/api/websockets_api/writing_websocket_client_applications/index.html new file mode 100644 index 0000000000..e7826d8595 --- /dev/null +++ b/files/ko/web/api/websockets_api/writing_websocket_client_applications/index.html @@ -0,0 +1,191 @@ +--- +title: WebSocket을 이용하여 클라이언트 애플리케이션 작성하기 +slug: WebSockets/Writing_WebSocket_client_applications +tags: + - 가이드 + - 네트워킹 + - 예제 + - 웹소켓 + - 웹소켓API + - 클라이언트 +translation_of: Web/API/WebSockets_API/Writing_WebSocket_client_applications +--- +<p>WebSocket은 ws 프로토콜을 기반으로 클라이언트와 서버 사이에 지속적인 완전 양방향 연결 스트림을 만들어 주는 기술입니다. 일반적인 웹소켓 클라이언트는 사용자의 브라우저일 것이지만, 그렇다고 해서 이 프로토콜이 플랫폼에 종속적이지는 않습니다.</p> + +<div class="note"><strong>Note:</strong> 우리에게는 작동하는 chat/server 시스템 예제 코드 조각이 있습니다. 이는 우리의 인프라가 WebSocket 예제들을 제대로 호스팅할 수 있는 환경이 되면 공유할 것입니다.</div> + +<p>{{AvailableInWorkers}}</p> + +<h2 id="WebSocket_객체_생성하기">WebSocket 객체 생성하기</h2> + +<p>WebSocket 프로토콜을 사용하여 통신하기 위해서는 <code><a href="/en/WebSockets/WebSockets_reference/WebSocket" title="en/WebSockets/WebSockets reference/WebSocket">WebSocket</a></code>객체를 생성해야 합니다. 이 객체는 자동으로 서버로의 연결을 열려고 할 것입니다.</p> + +<p>WebSocket 생성자는 하나의 필수 파라미터와 하나의 선택 파라미터를 받습니다.</p> + +<pre class="notranslate">WebSocket WebSocket( + in DOMString url, + in optional DOMString protocols +); +</pre> + +<dl> + <dt><code>url</code></dt> + <dd>연결할 URL으로, 이것은 WebSocket 서버가 응답할 URL이어야 합니다.</dd> + <dt><code>protocols</code> {{ optional_inline() }}</dt> + <dd>하나의 프로토콜 문자열, 또는 프로토콜 문자열의 배열입니다. 이 문자열들은 서브 프로토콜을 지정하는데 사용되어, 하나의 서버가 여러 개의 WebSocket 서브 프로토콜을 구현할 수 있도록 해줍니다. 예를 들어, 하나의 서버가 처리하는 상호작용이 지정된 <code>protocols</code>에 따라 달라지도록 할 수 있습니다. 만약 프로토콜 문자열을 지정하지 않으면 빈 문자열을 넣은 것으로 간주됩니다.</dd> +</dl> + +<p>생성자는 예외를 발생시킬 수 있습니다:</p> + +<dl> + <dt><code>SECURITY_ERR</code></dt> + <dd>접속을 시도하고 있는 포트가 차단되었습니다.</dd> +</dl> + +<dl> +</dl> + +<h3 id="연결_에러">연결 에러</h3> + +<p>만약 연결 시도 중 에러가 발생하면, 먼저 "error"란 이름의 이벤트가 <code><a href="/en/WebSockets/WebSockets_reference/WebSocket" title="WebSocket">WebSocket</a></code> 오브젝트로 전달되고, 그로 인해 <code>onerror</code> 핸들러가 실행됩니다. 그 후에 연결이 종료되는 이유를 가리키는 <a href="/en/WebSockets/WebSockets_reference/CloseEvent" title="CloseEvent"><code>CloseEvent</code></a> 이벤트가 <code><a href="/en/WebSockets/WebSockets_reference/WebSocket" title="WebSocket">WebSocket</a></code> 오브젝트로 전달되고, 그로 인해 <code>onclose</code> 핸들러가 실행됩니다.</p> + +<p>Firefox 11부터는 보통 에러 메세지에 대한 설명이 Mozillia 플랫폼의 콘솔에 표시되며, <code><a href="/en/WebSockets/WebSockets_reference/CloseEvent" title="CloseEvent">CloseEvent</a></code>로부터는 <a class="external" href="http://tools.ietf.org/html/rfc6455#section-7.4" title="RFC 6455 Section 7.4">RFC 6455, Section 7.4</a>에 정의되어 있는 연결 종료 코드를 받게 됩니다.</p> + +<h3 id="예제">예제</h3> + +<p>이 간단한 예제는 새 웹소켓 오브젝트를 생성하여 <code><span class="nowiki">ws://www.example.com/socketserver </span></code><span class="nowiki">서버에 접속하는</span>것을 보여줍니다. 이 예제에서는 커스텀 프로토콜인 "protocolOne" 을 리퀘스트에 같이 지정합니다. (이 프로토콜을 지정하는 부분은 생략될 수 있습니다.)</p> + +<pre class="brush: js notranslate">var exampleSocket = new WebSocket("ws://www.example.com/socketserver", "protocolOne"); +</pre> + +<p>반환된 <code>exampleSocket </code>오브젝트의<code> exampleSocket</code>.<code>readyState </code>값은<code> CONNECTING </code>입니다.<code> readyState</code> 값은 연결이 수립되어 데이터가 전송 가능한 상태가 되면 <code>OPEN</code> 으로 변경됩니다.</p> + +<p>만약 여러개의 프로토콜을 유연하게 대응할 수 있는 구조를 가지고 있다면, 연결 시에 배열을 통해 프로토콜의 목록을 지정할 수 있습니다.</p> + +<pre class="brush: js notranslate">var exampleSocket = new WebSocket("ws://www.example.com/socketserver", ["protocolOne", "protocolTwo"]); +</pre> + +<p>연결이 수립되면(<code>readyState</code> 가 <code>OPEN</code> 이 되었을 때<code>), exampleSocket.protocol </code>값을 조사하여 서버가 어떤 프로토콜을 선택했는지 알아낼 수 있습니다.</p> + +<p>위의 예제에서 ws 는 http 를 대체합니다. 비슷하게 wss 는 https 를 대체합니다. 웹소켓 연결은 HTTP 업그레이드 메카니즘에 의해 수행되기 때문에 HTTP 서버 주소 지정에 대한 프로토콜 업그레이드 요청은 암시적입니다. (<code><span class="nowiki">ws://www.example.com</span></code> 또는 <code><span class="nowiki">wss://www.example.com</span></code>. 같이)</p> + +<h2 id="서버에_데이터_전송하기">서버에 데이터 전송하기</h2> + +<p>한번 연결이 수립되면 이제부터는 서버로 데이터를 전송할 수 있습니다. 이것을 하기 위해서는 단순히 <code>WebSocket</code> 오브젝트의 <a href="/en/WebSockets/WebSockets_reference/WebSocket#send()" title="en/WebSockets/WebSockets reference/WebSocket#send()"><code>send()</code></a> 호출하여 보내고 싶은 메세지를 지정하기만 하면 됩니다.:</p> + +<pre class="brush: js notranslate">exampleSocket.send("Here's some text that the server is urgently awaiting!"); +</pre> + +<p>보낼 수 있는 데이터는 String , {{ domxref("Blob") }}, 또는 <code><a href="/en/JavaScript_typed_arrays/ArrayBuffer" title="en/JavaScript typed arrays/ArrayBuffer">ArrayBuffer</a> </code>입니다.</p> + +<div class="note"><strong>Note:</strong> 버전 11 아래의 파이어폭스는 String 데이터 전송만을 지원합니다.</div> + +<p>연결을 맺는것은 비동기 작업이고 실패하기 쉬운 작업이기 때문에, WebSocket 오브젝트를 생성하자마자 <code>send()</code> 로 데이터 전송을 시도하는것은 성공하지 않을 가능성이 있습니다. 우리는 연결이 수립된 이후에만 데이터를 전송하도록 하기 위해 <code>onopen</code> 핸들러를 정의하고, 이 위에서 작업합니다.</p> + +<pre class="brush: js notranslate">exampleSocket.onopen = function (event) { + exampleSocket.send("Here's some text that the server is urgently awaiting!"); +}; +</pre> + +<h3 id="데이터_전송에_JSON_사용하기">데이터 전송에 JSON 사용하기</h3> + +<p><a href="/en/JSON" title="en/JSON">JSON</a> 을 사용하면 서버에 복잡한 데이터를 편리하게 보낼 수 있습니다. 예를 들어, 채팅 프로그램이 서버와 JSON으로 캡슐화된 패킷 데이터를 주고받는 프로토콜을 구현한것을 상상해 볼 수 있습니다.:</p> + +<pre class="brush: js notranslate">// Send text to all users through the server +function sendText() { + // Construct a msg object containing the data the server needs to process the message from the chat client. + var msg = { + type: "message", + text: document.getElementById("text").value, + id: clientID, + date: Date.now() + }; + + // Send the msg object as a JSON-formatted string. + exampleSocket.send(JSON.stringify(msg)); + + // Blank the text input element, ready to receive the next line of text from the user. + document.getElementById("text").value = ""; +} +</pre> + +<h2 id="서버로부터_데이터_수신하기">서버로부터 데이터 수신하기</h2> + +<p>WebSockets는 event-driven API 입니다; 메세지가 수신되면 "message" 이벤트가 <code>onmessage</code> 함수로 전달되게 됩니다. 아래와 같은 코드를 작성하여 수신되는 데이터를 받아볼 수 있습니다.:</p> + +<pre class="brush: js notranslate">exampleSocket.onmessage = function (event) { + console.log(event.data); +} +</pre> + +<h3 id="JSON_오브젝트를_받아서_처리하기">JSON 오브젝트를 받아서 처리하기</h3> + +<p>상단의 {{ anch("데이터 전송에 JSON 사용하기") }} 에서 작업한 코드와 연관되는 클라이언트를 생각해 봅시다. 클라이언트에서 받을 수 있는 패킷들의 목록은 다음과 같을 것 입니다.:</p> + +<ul> + <li>로그인 핸드쉐이크</li> + <li>메세지 텍스트</li> + <li>유저 목록 업데이트</li> +</ul> + +<p>위의 메세지들을 받아서 처리하는 코드는 아래와 같을 것 입니다.:</p> + +<pre class="brush: js notranslate">exampleSocket.onmessage = function(event) { + var f = document.getElementById("chatbox").contentDocument; + var text = ""; + var msg = JSON.parse(event.data); + var time = new Date(msg.date); + var timeStr = time.toLocaleTimeString(); + + switch(msg.type) { + case "id": + clientID = msg.id; + setUsername(); + break; + case "username": + text = "<b>User <em>" + msg.name + "</em> signed in at " + timeStr + "</b><br>"; + break; + case "message": + text = "(" + timeStr + ") <b>" + msg.name + "</b>: " + msg.text + "<br>"; + break; + case "rejectusername": + text = "<b>Your username has been set to <em>" + msg.name + "</em> because the name you chose is in use.</b><br>" + break; + case "userlist": + var ul = ""; + for (i=0; i < msg.users.length; i++) { + ul += msg.users[i] + "<br>"; + } + document.getElementById("userlistbox").innerHTML = ul; + break; + } + + if (text.length) { + f.write(text); + document.getElementById("chatbox").contentWindow.scrollByPages(1); + } +}; +</pre> + +<p>여기서 우리는 <a href="/en/JavaScript/Reference/Global_Objects/JSON/parse" title="en/JavaScript/Reference/Global Objects/JSON/parse"><code>JSON.parse()</code></a> 를 통해 JSON 오브젝트를 자바스크립트 오브젝트로 변환합니다. 그 다음 콘텐츠에 따라 분기하고 처리하는 로직을 가집니다.</p> + +<h3 id="Text_data_format">Text data format</h3> + +<p>웹소켓을 통해 전달되는 텍스트들은 UTF-8 포멧을 가집니다.</p> + +<p>Gecko 9.0 {{ geckoRelease("9.0") }} 먼저 버전들은 유효한 UTF-8 텍스트가 아닌 문자가 들어올 경우 연결이 종료되었습니다. 지금은 이 값들을 정상적으로 허용합니다.</p> + +<h2 id="연결을_종료하기">연결을 종료하기</h2> + +<p><code><font face="Open Sans, Arial, sans-serif">웹 소켓 사용을 마쳤다면 </font><a href="/en/WebSockets/WebSockets_reference/WebSocket#close()" title="en/WebSockets/WebSockets reference/WebSocket#close()">close()</a> 메소드를 호출해 연결을 종료합니다.</code>:</p> + +<pre class="brush: js notranslate">exampleSocket.close(); +</pre> + +<p>연결을 닫아버리기 전에 <code>bufferedAmount </code>어트리뷰트를 조사하여 아직 네트워크에 전달되지 않은 데이터가 있는지 검사하는것도 좋은 방법입니다.</p> + +<h2 id="보안에_대한_고려_사항">보안에 대한 고려 사항</h2> + +<p>웹소켓은 혼합된 연결 환경에서 이용되어서는안됩니다. 예를들어 HTTPS를 이용해 로드된 페이지에서 non-secure 웹소켓 연결을 수립하는것(또는 반대) 처럼 말입니다. 몇몇 브라우저들은 이를 강제로 금지하고 있습니다. 파이어폭스 버전 8이상도 이를 금지합니다.</p> + +<p>{{ languages ( {"zh-tw": "zh_tw/WebSockets/Writing_WebSocket_client_applications"} ) }}</p> diff --git a/files/ko/web/api/websockets_api/writing_websocket_servers/index.html b/files/ko/web/api/websockets_api/writing_websocket_servers/index.html new file mode 100644 index 0000000000..24c3cbe6c0 --- /dev/null +++ b/files/ko/web/api/websockets_api/writing_websocket_servers/index.html @@ -0,0 +1,258 @@ +--- +title: 웹소켓 서버 작성하기 +slug: WebSockets/Writing_WebSocket_servers +translation_of: Web/API/WebSockets_API/Writing_WebSocket_servers +--- +<p>{{gecko_minversion_header("2")}}</p> + +<h2 id="개요">개요</h2> + +<p>웹 소켓 서버는 특정한 프로토콜을 따르는 서버의 임의 포트를 리스닝하고 있는 TCP 어플리케이션입니다. 사용자 서버를 만드는 작업은 두려운 일일수도 있습니다. 하지만, 당신이 선택한 플랫폼상에서 간단한 웹 소켓 서버를 구현하는것은 쉬울것입니다. </p> + +<p>웹 소켓 서버는 C(++), Python, <a href="/en-US/docs/PHP">PHP</a>, <a href="/en-US/docs/Web/JavaScript/Server-Side_JavaScript">server-side JavaScript</a>등과 같은 <a href="https://en.wikipedia.org/wiki/Berkeley_sockets">Berkeley sockets</a>을 지원하는 어떠한 server-side 프로그래밍 언어로도 개발될 수 있습니다. 이것은 어느 특정한 언어의 자습서는 아니지만, 당신 자신의 서버를 개발하는것을 용이하게 하는 지침으로써의 역할을 합니다.</p> + +<p>당신은 HTTP가 작동하는 방식과 중간정도의 개발 경험이 있어야만 합니다. 개발언어에서 제공하는 TCP 소켓에 대한 지식이 요구될 수도 있습니다. 이 지침의 범위는 당신이 웹 소켓서버를 개발하기위해 필요한 최소한의 지식에 대해 소개하는것입니다.</p> + +<div class="note"> +<p>최신의 공식 웹 소켓 문서인 <a href="http://datatracker.ietf.org/doc/rfc6455/?include_text=1">RFC 6455</a>를 읽으세요. 1과 4-7 섹션이 특별히 서버개발자에게 흥미로운 부분입니다. 10 섹션에서는 보안에 대해 논의하며, 당신의 서버를 공개하기전 해당 부분을 반드시 정독하여 읽어보셔야만합니다.</p> +</div> + +<p>이 페이지에서 웹 소켓 서버는 매우 약간만 설명되어 있습니다. 웹 소켓 서버는 종종 다른 특정한 이유로 인해 분리되거나 전문화됩니다. 따라서 웹 소켓과의 핸드 쉐이크를 감지하거나 미리 처리하거나 또는 클라이언트들을 실제 웹 소켓 서버에 보내기위해 일반적으로 HTTP 서버와 같은 <a href="https://en.wikipedia.org/wiki/Reverse_proxy">reverse proxy</a>를 사용합니다. 이는 쿠키나 인증을 처리하기 위해 당신의 서버 코드를 잔뜩 작성하지 않아도 된다는 것을 의미합니다.</p> + +<h2 id="Step_1_The_WebSocket_Handshake"><a name="Handshake">Step 1: The WebSocket Handshake</a></h2> + +<p>먼저 서버는 표준 TCP 소켓을 사용하여 연결하려는 소켓을 위해 반드시 듣고 있어야 합니다. 당신의 플랫폼에 따라 서버는 이미 준비가 되어있을수도 있습니다. 예를들어, 당신의 서버가 example.com에 port가 8000인 채로 듣고 있다고 가정해봅시다. </p> + +<div class="warning"> +<p><strong>경고:</strong> 서버에서 아무 포트나 선택하여 연결할 수 있지만, 80 또는 443 포트가 아닌 다른 연결은 방화벽/프록시에 의해 문제를 일으킬 수 있습니다. TLS/SSL 보안 연결인 443 포트와의 연결이 가장 쉬울 것입니다. 현재 대부분의 브라우저(특히 Firefox 8+)는 안전한 페이지라 할지라도 보안 연결이 아닌 웹소켓 연결은 허용되지 않습니다.</p> +</div> + +<p>웹소켓의 핸드셰이크 과정은 HTTP를 바탕으로 이루어집니다. 자세한 연결 과정은 다루지 않으나, 각 요청자는 연결 과정이 제대로 이루어질때까지 요청을 보류합니다. 서버는 클라이언트가 요청하는 모든 것을 주의깊게 이해해야 하고, 그렇지 않을 경우 보안 이슈가 일어날 수 있습니다.</p> + +<h3 id="클라이언트_핸드쉐이크_요청">클라이언트 핸드쉐이크 요청</h3> + +<p>당신이 웹 소켓 서버를 개발 중이라도, 클라이언트는 여전히 웹 소켓 핸드쉐이킹 과정을 시작합니다. 따라서, 당신은 클라이언트의 요청을 이해하기 위한 방법을 이해해야합니다. 클라이언트는 아래와 같아 보이는 매우 표준적인 HTTP 요청을 보낼것입니다.(HTTP 버전은 반드시 1.1. 혹은 그 이상이어하며, 반드시 GET방식이어야합니다.)</p> + +<pre class="notranslate">GET /chat HTTP/1.1 +Host: example.com:8000 +<strong>Upgrade: websocket</strong> +<strong>Connection: Upgrade</strong> +Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== +Sec-WebSocket-Version: 13 + +</pre> + +<p>이외에도 클라이언트는 여러 메세지나 서브프로토콜을 추가해 보낼 수도 있습니다. <code>User-Agent</code>, <code>Referer</code>, <code>Cookie</code>와 같은 공통 헤더나, 인증 헤더도 말이죠. 자세한 <a href="#Miscellaneous">사항</a>은 다음을 참조하세요. 원하는 대로 요청에 무엇이든지 첨부하여 보낼 수 있으며 웹소켓과 관련이 없을 경우 무시합니다. 통상적으로, 리버스 프록시가 이미 그런 기능을 담당하고 있을 겁니다.</p> + +<p>잘못된 값을 가지거나 형식이 잘못된 헤더의 경우, 서버는 "<a href="https://developer.mozilla.org/en-US/docs/HTTP/Response_codes#400">400 Bad Request</a>" 응답을 보내 즉시 소켓을 종료시켜야 합니다. HTTP 응답 바디에 핸드셰이크에 실패한 이유가 명시되어 있지만, 브라우저 상에서 명시적으로 나타내진 않습니다. 서버가 웹소켓의 버전 인식을 실패할 경우, 인식 가능한 버전을 명시해 <code>Sec-WebSocket-Version</code> 요청을 보내야 합니다. (최신 가이드 v13에서 설명되어 있습니다) 이제, 가장 흥미로운 헤더인 <code>Sec-WebSocket-Key</code>을 살펴봅니다.</p> + +<div class="note"> +<p><strong>팁:</strong> 모든 <strong>브라우저는</strong> <a href="https://developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS#Origin"><code>Origin</code> header</a>를 보냅니다. 이 헤더는 보안을 위해 활용되며, (checking for same origin, whitelisting/ blacklisting, etc.) 활용하고 싶지 않다면 <a href="https://developer.mozilla.org/en-US/docs/HTTP/Response_codes#403">403 Forbidden</a>을 보냅니다. 하지만 non-browser 에이전트가 위조된 <code>Origin</code>을 보낼수도 있다는 것을 명심해야 합니다. 따라서 대부분의 애플리케이션은 이 헤더가 없는 요청을 거부합니다.</p> +</div> + +<div class="note"> +<p><strong>Tip:</strong> The request-uri (<code>/chat</code> here) has no defined meaning in the spec. So many people cleverly use it to let one server handle multiple WebSocket applications. For example, <code>example.com/chat</code> could invoke a multiuser chat app, while <code>/game</code> on the same server might invoke a multiplayer game.</p> +</div> + +<div class="note"> +<p><strong>Note:</strong> <a href="https://developer.mozilla.org/en-US/docs/HTTP/Response_codes">Regular HTTP status codes</a> can only be used before the handshake. After the handshake succeeds, you have to use a different set of codes (defined in section 7.4 of the spec).</p> +</div> + +<h3 id="서버가_보내는_핸드쉐이크_응답">서버가 보내는 핸드쉐이크 응답</h3> + +<p>위와 같은 요청을 받으면 서버 역시도 HTTP 구조의 응답을 보내주어야 합니다. 자세한 내용은 아래와 같습니다.(각각의 헤더 끝에는 \r\n을 그리고 가장 마지막에는 한번 더 \r\n을 넣는걸 잊지 마세요.)</p> + +<pre class="notranslate"><strong>HTTP/1.1 101 Switching Protocols</strong> +Upgrade: websocket +Connection: Upgrade +<strong>Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo= + +</strong></pre> + +<p>Additionally, the server can decide on extension/subprotocol requests here; see <a href="#Miscellaneous">Miscellaneous</a> for details. The <code>Sec-WebSocket-Accept</code> part is interesting. The server must derive it from the <code>Sec-WebSocket-Key</code> that the client sent. To get it, c<span style="line-height: 1.5em;">oncatenate the client's </span><code style="font-size: 14px;">Sec-WebSocket-Key</code><span style="line-height: 1.5em;"> and "</span><code style="font-size: 14px;">258EAFA5-E914-47DA-95CA-C5AB0DC85B11</code><span style="line-height: 1.5em;">" together (it's a "</span><a href="https://en.wikipedia.org/wiki/Magic_string" style="line-height: 1.5em;">magic string</a><span style="line-height: 1.5em;">"), </span><span style="line-height: 1.5em;">take the </span><a href="https://en.wikipedia.org/wiki/SHA-1" style="line-height: 1.5em;">SHA-1 hash</a><span style="line-height: 1.5em;"> of the result, and </span><span style="line-height: 1.5em;">return the </span><a href="https://en.wikipedia.org/wiki/Base64" style="line-height: 1.5em;">base64</a><span style="line-height: 1.5em;"> encoding of the hash.</span></p> + +<div class="note"> +<p><strong>FYI:</strong> This seemingly overcomplicated process exists so that it's obvious to the client whether or not the server supports WebSockets. This is important because security issues might arise if the server accepts a WebSockets connection but interprets the data as a HTTP request.</p> +</div> + +<p>So if the Key was "<code>dGhlIHNhbXBsZSBub25jZQ==</code>", the Accept will be "<code>s3pPLMBiTxaQ9kYGzzhZRbK+xOo=</code>". Once the server sends these headers, the handshake is complete and you can start swapping data!</p> + +<div class="note"> +<p>The server can send other headers like Set-Cookie, or ask for authentication or redirects via other status codes, before sending the reply handshake.</p> +</div> + +<h3 id="클라이언트_추적">클라이언트 추적</h3> + +<p>웹소켓 프로토콜과 직접적인 연관은 없지만, 이 항목에서 언급할만한 의미가 있습니다. 웹소켓 서버는 이미 연결된 클라이언트들의 반복적인 연결(hand shaking)을 막기위해 클라이언트의 소켓 상태를 추적해야합니다. 같은 IP 주소를 가지는 클라이언트는 여러번 연결을 시도 할 수 있습니다.(하지만, 서버는 <a href="https://en.wikipedia.org/wiki/Denial_of_service">Denial-of-Service attacks</a> 을 위해 너무 많은 연결 요청을 거부할 수 있습니다).</p> + +<h2 id="Step_2_데이터_프레임_교환">Step 2: 데이터 프레임 교환</h2> + +<p>Either the client or the server can choose to send a message at any time — that's the magic of WebSockets. However, extracting information from these so-called "frames" of data is a not-so-magical experience. Although all frames follow the same specific format, data going from the client to the server is masked using <a href="https://en.wikipedia.org/wiki/XOR_cipher">XOR encryption</a> (with a 32-bit key). Section 5 of the specification describes this in detail.</p> + +<h3 id="데이터_프레임_포멧">데이터 프레임 포멧</h3> + +<p>모든 데이터 프레임 (서버->클라이언트 / 클라이언트 -> 서버) 은 아래의 구조를 따릅니다:</p> + +<pre style="float: left; margin-right: 20px;"> <strong>0</strong> <strong>1</strong> <strong>2</strong> 3 + 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 ++-+-+-+-+-------+-+-------------+-------------------------------+ +|F|R|R|R| opcode|M| Payload len | Extended payload length | +|I|S|S|S| (4) |A| (7) | (16/64) | +|N|V|V|V| |S| | (if payload len==126/127) | +| |1|2|3| |K| | | ++-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - + + 4 5 6 7 ++ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +| Extended payload length continued, if payload len == 127 | ++ - - - - - - - - - - - - - - - +-------------------------------+ + 8 9 <strong>10</strong> 11 ++ - - - - - - - - - - - - - - - +-------------------------------+ +| |Masking-key, if MASK set to 1 | ++-------------------------------+-------------------------------+ + 12 13 <strong>14</strong> 15 ++-------------------------------+-------------------------------+ +| Masking-key (continued) | Payload Data | ++-------------------------------- - - - - - - - - - - - - - - - + +: Payload Data continued ... : ++ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +| Payload Data continued ... | ++---------------------------------------------------------------+</pre> + +<p>RSV1-3 는 사용되지 않습니다. 이 필드들은 확장 프로토콜 또는 미래를 위해 예약되었습니다.</p> + +<p>MASK 비트는 메세지가 인코딩되어있는지의 여부를 나타냅니다.클라이언트가 서버로 보내는 메세지는 항상 마스킹되어야합니다. 따라서 서버는 클라이언트로부터 받은 이 필드가 항상 1임을 기대할 수 있습니다. (만약 클라이언트가 마스킹되지 않은 메세지를 보낸다면 서버는 연결을 종료해야 합니다. 참고 : <a href="http://tools.ietf.org/html/rfc6455#section-5.1">section 5.1 of the spec</a> ).<br> + 서버가 클라이언트에게 보내는 메세지는 MASK 필드가 항상 0이고 데이터는 마스킹되지 않은 상태여야 합니다. 마스킹이 어떻게 이루어지는지 / 마스킹된 메세지를 어떻게 디코딩하는지는 나중에 설명합니다.<br> + (주의: wss 연결이라고 하더라도 클라이언트가 보내는 패킷은 항상 마스킹되어야 합니다.)</p> + +<p>opcode 필드는 뒤따라오는 payload 데이터가 어떠한 포멧인지를 나타냅니다. 0x0은 <span style="line-height: 1.5;">continuation, 0x1은 텍스트(항상 UTF-8), 0x2는 바이너리 데이터 / 나머지 값은 "컨트롤 코드"에 사용됩니다. (컨트롤 코드에 대해서는 나중에 다루게 됩니다.) 현재 버전의 웹소켓 프로토콜에서는 0x3 / 0x7 / 0xB~0xF는 아무런 의미도 지니고있지 않습니다.</span></p> + +<p>FIN 비트는 이 메세지가 마지막임을 나타냅니다. 만약 FIN 비트가 0이라면 서버는 뒤에 더 따라오게 될 메세지들까지 수신해야 합니다. FIN 비트가 1일 경우에는 전체 메세지가 수신되었으므로 이를 처리합니다. 이 부분에 대해서는 뒤에 다시 설명합니다.</p> + +<h3 id="Payload_길이_알아내기">Payload 길이 알아내기</h3> + +<p>수신한 프레임으로부터 payload 데이터를 읽기 위해서는 payload length 필드를 읽어야 합니다. 불행히도 이는 약간 복잡한 작업을 거치는데 아래 순서대로 처리해 주세요.</p> + +<ol> + <li>9번째부터 15번재까지의 비트를 읽습니다. 이를 unsigned integer로 취급한 다음 값이 125거나 이보다 작을 경우 이 자체가 payload length 입니다. 이 경우에는 2, 3 과정은 필요 없습니다. 하지만 126이면 2번으로, 127일 경우 3번으로 가주세요</li> + <li>다음 16비트를 읽습니다. 이를 unsigned integer로 처리하고 payload length 값으로 사용합니다.</li> + <li>다음 64비트를 읽습니다. 이를 unsigned integer로 처리하고 payload length 값으로 사용합니다. (<a href="https://ko.wikipedia.org/wiki/%EC%B5%9C%EC%83%81%EC%9C%84_%EB%B9%84%ED%8A%B8">최상위 비트</a>는 항상 0이어야 합니다.)</li> +</ol> + +<h3 id="마스킹된_Payload_데이터_디코딩하기">마스킹된 Payload 데이터 디코딩하기</h3> + +<p>MASK 비트가 설정되어 있디만 32비트 사이즈의 Masking-Key 필드 또한 존재하게 됩니다. <br> + 아래 의사코드는 Payload 데이터를 <strong>ENCODED </strong>/ Masking-Key 필드를 <strong>MASK </strong>라고 가정하고 데이터를 디코딩하는 방법을 보여줍니다. <strong>ENCODED</strong>값을 0부터 순회하면서 <strong>MASK</strong>의 i % 4에 해당하는 1바이트와 XOR 연산을 수행합니다.</p> + +<p>If the MASK bit was set (and it should be, for client-to-server messages), read the next 4 octets (32 bits); this is the masking key. <span style="line-height: 1.5;">Once the payload length and masking key is decoded, you can go ahead and read that number of bytes from the socket. Let's call the data <strong>ENCODED</strong>, and the key <strong>MASK</strong>. To get <strong>DECODED</strong>, loop through the octets (bytes a.k.a. characters for text data) of <strong>ENCODED</strong> and XOR the octet with the (i modulo 4)th octet of MASK. In pseudo-code (that happens to be valid JavaScript):</span></p> + +<pre class="notranslate">var DECODED = ""; +for (var i = 0; i < ENCODED.length; i++) { + DECODED[i] = ENCODED[i] ^ MASK[i % 4]; +<span style="line-height: 1.5;">}</span></pre> + +<p>이제 <strong>DECODED</strong> 데이터를 가지고 프로토콜에 맞게 활용하면 됩니다.</p> + +<h3 id="Message_Fragmentation">Message Fragmentation</h3> + +<p>The FIN and opcode fields work together to send a message split up into separate frames. This is called message fragmentation. Fragmentation is only available on opcodes <code>0x0</code> to <code>0x2</code>.</p> + +<p><span style="line-height: 1.5;">Recall that the opcode tells what a frame is meant to do. If it's <code>0x1</code>, the payload is text. If it's <code>0x2</code>, the payload is binary data.</span><span style="line-height: 1.5;"> However, if it's </span><code style="font-style: normal; line-height: 1.5;">0x0,</code><span style="line-height: 1.5;"> the frame is a continuation frame. This means the server should concatenate the frame's payload to the last frame it received from that client.</span><span style="line-height: 1.5;"> Here is a rough sketch, in which a server reacts to a client sending text messages. The first message is sent in a single frame, while the second message is sent across three frames. FIN and opcode details are shown only for the client:</span></p> + +<pre style="font-size: 14px;"><strong>Client:</strong> FIN=1, opcode=0x1, msg="hello" +<strong>Server:</strong> <em>(process complete message immediately) </em>Hi. +<strong>Client:</strong> FIN=0, opcode=0x1, msg="and a" +<strong>Server:</strong> <em>(listening, new message containing text started)</em> +<strong>Client:</strong> FIN=0, opcode=0x0, msg="happy new" +<strong>Server:</strong> <em>(listening, payload concatenated to previous message)</em> +<strong>Client:</strong> FIN=1, opcode=0x0, msg="year!" +<strong>Server:</strong> <em>(process complete message) </em>Happy new year to you too!</pre> + +<p>Notice the first frame contains an entire message (has <code>FIN=1</code> and <code>opcode!=0x0</code>), so the server can process or respond as it sees fit. The second frame sent by the client has a text payload (<code>opcode=0x1</code>), but the entire message has not arrived yet (<code>FIN=0</code>). All remaining parts of that message are sent with continuation frames (<code>opcode=0x0</code>), and the final frame of the message is marked by <code>FIN=1</code>. <a href="http://tools.ietf.org/html/rfc6455#section-5.4">Section 5.4 of the spec</a> describes message fragmentation.</p> + +<h2 id="Pings_and_Pongs_The_Heartbeat_of_WebSockets">Pings and Pongs: The Heartbeat of WebSockets</h2> + +<p>핸드쉐이크가 끝난 시점부터 서버 혹은 클라이언트는 언제든지 ping 패킷을 보낼 수 있습니다. 만약 ping 패킷이 수신되면 수신자는 가능한 빨리 응답으로 pong 패킷을 보내야 합니다. (ping에서 전달된 payload와 동일한 payload를 붙여서 pong을 보냅니다. 이 경우 최대 payload length는 125입니다.) 서버는 주기적으로 ping을 보내 클라이언트가 아직 살아있는 상태인지 체크할 수 있습니다.</p> + +<p>A ping or pong is just a regular frame, but it's a <strong>control frame</strong>. Pings have an opcode of <code>0x9</code>, and pongs have an opcode of <code>0xA</code>. When you get a ping, send back a pong with the exact same Payload Data as the ping (for pings and pongs, the max payload length is 125). You might also get a pong without ever sending a ping; ignore this if it happens.</p> + +<div class="note"> +<p>If you have gotten more than one ping before you get the chance to send a pong, you only send one pong.</p> +</div> + +<h2 id="Step_4_Closing_the_connection">Step 4: Closing the connection</h2> + +<p>To close a connection either the client or server can send a control frame with data containing a specified control sequence to begin the closing handshake (detailed in <a href="http://tools.ietf.org/html/rfc6455#section-5.5.1">Section 5.5.1</a>). Upon receiving such a frame, the other peer sends a Close frame in response. The first peer then closes the connection. Any further data received after closing of connection is then discarded. </p> + +<h2 id="Miscellaneous_2"><a name="Miscellaneous">Miscellaneous</a></h2> + +<div class="note"> +<p>WebSocket codes, extensions, subprotocols, etc. are registered at the <a href="http://www.iana.org/assignments/websocket/websocket.xml">IANA WebSocket Protocol Registry</a>.</p> +</div> + +<p>WebSocket extensions and subprotocols are negotiated via headers during <a href="#Handshake">the handshake</a>. Sometimes extensions and subprotocols seem too similar to be different things, but there is a clear distinction. Extensions control the WebSocket <strong>frame</strong> and <strong>modify</strong> the payload, while subprotocols structure the WebSocket <strong>payload</strong> and <strong>never modify</strong> anything. Extensions are optional and generalized (like compression); subprotocols are mandatory and localized (like ones for chat and for MMORPG games).</p> + +<h3 id="Extensions">Extensions</h3> + +<div class="note"> +<p><strong>This section needs expansion. Please edit if you are equipped to do so.</strong></p> +</div> + +<p>Think of an extension as compressing a file before e-mailing it to someone. Whatever you do, you're sending the <em>same</em> data in different forms. The recipient will eventually be able to get the same data as your local copy, but it is sent differently. That's what an extension does. WebSockets defines a protocol and a simple way to send data, but an extension such as compression could allow sending the same data but in a shorter format.</p> + +<div class="note"> +<p>Extensions are explained in sections 5.8, 9, 11.3.2, and 11.4 of the spec.</p> +</div> + +<p><em>TODO</em></p> + +<h3 id="서브프로토콜">서브프로토콜</h3> + +<p>Think of a subprotocol as a custom <a href="https://en.wikipedia.org/wiki/XML_schema">XML schema</a> or <a href="https://en.wikipedia.org/wiki/Document_Type_Definition">doctype declaration</a>. You're still using XML and its syntax, but you're additionally restricted by a structure you agreed on. WebSocket subprotocols are just like that. They do not introduce anything fancy, they just establish structure. Like a doctype or schema, both parties must agree on the subprotocol; unlike a doctype or schema, the subprotocol is implemented on the server and cannot be externally refered to by the client.</p> + +<div class="note"> +<p>Subprotocols are explained in sections 1.9, 4.2, 11.3.4, and 11.5 of the spec.</p> +</div> + +<p>클라이언트는 핸드쉐이크 요청 시에 특정한 서브프로콜의 목록을 같이 보낼 수 있습니다.<strong> Sec-WebSocket-Protocol </strong>헤더에 사용하기를 원하는 서브프로토콜의 목록을 같이 보냅니다.</p> + +<pre class="notranslate">GET /chat HTTP/1.1 +... +Sec-WebSocket-Protocol: soap, wamp + +</pre> + +<p>또는 아래와 같이 보낼 수도 있습니다.:</p> + +<pre class="notranslate">... +Sec-WebSocket-Protocol: soap +Sec-WebSocket-Protocol: wamp + +</pre> + +<p>클라이언트로부터 서브프로토콜 요청을 받으면, 서버는 그 중에서 자신이 지원할 수 있는 서브프로토콜을 <strong>하나 </strong>골라야 합니다. 만약 클라이언트가 보낸 목록 중, 여러개를 지원할 수 있다면 지원하는 목록 중 가장 첫번째 서브프로토콜을 보내주세요. </p> + +<p>Imagine our server can use both <code>soap</code> and <code>wamp</code>. Then, in the response handshake, it'll send:</p> + +<pre class="notranslate">Sec-WebSocket-Protocol: soap + +</pre> + +<div class="warning"> +<p><code>서버는 반드시 하나의 Sec-Websocket-Protocol 헤더만을 송신해야 합니다.</code><br> + <code>만약 서버가 어떠한 서브프로토콜도 지원하고 싶지 않다면 Sec-Websocket-Protocol 헤더를 빼고 보내주세요. 빈 값을 넣어서 보내도 안됩니다.</code><br> + 서버가 아무 서브프로토콜을 지원하지 않겠다고 한다면 클라이언트는 연결을 닫아버릴수도 있습니다.</p> +</div> + +<p>If you want your server to obey certain subprotocols, then naturally you'll need extra code on the server. Let's imagine we're using a subprotocol <code>json</code>. In this subprotocol, all data is passed as <a href="https://en.wikipedia.org/wiki/JSON">JSON</a>. If the client solicits this protocol and the server wants to use it, the server will need to have a JSON parser. Practically speaking, this will be part of a library, but the server will need to pass the data around.</p> + +<div class="note"> +<p><strong>Tip:</strong> To avoid name conflict, it's recommended to make your subprotocol name part of a domain string. If you are building a custom chat app that uses a proprietary format exclusive to Example Inc., then you might use this: <code>Sec-WebSocket-Protocol: chat.example.com</code>. For different versions, a widely-used method is to add a <code>/</code> followed by the version number, like <code>chat.example.com/2.0</code>. Note that this isn't required, it's just an optional convention, and you can use any string you wish.</p> +</div> + +<h2 id="같이_보기">같이 보기</h2> + +<ul> + <li><a href="/en-US/docs/WebSockets/Writing_WebSocket_server" title="/en-US/docs/WebSockets/Writing_WebSocket_server">Tutorial: Websocket server in C#</a></li> + <li><a href="/en-US/docs/WebSockets/Writing_WebSocket_client_applications">Writing WebSocket client applications</a></li> + <li><a href="/en-US/docs/WebSockets/WebSocket_Server_Vb.NET">Tutorial: Websocket server in VB.NET</a></li> +</ul> diff --git a/files/ko/web/api/window/domcontentloaded_event/index.html b/files/ko/web/api/window/domcontentloaded_event/index.html new file mode 100644 index 0000000000..24db56aa91 --- /dev/null +++ b/files/ko/web/api/window/domcontentloaded_event/index.html @@ -0,0 +1,77 @@ +--- +title: DOMContentLoaded +slug: Web/Events/DOMContentLoaded +tags: + - Event + - Reference + - Web + - Window +translation_of: Web/API/Window/DOMContentLoaded_event +--- +<div>{{APIRef}}</div> + +<p><strong><code>DOMContentLoaded</code></strong> 이벤트는 초기 HTML 문서를 완전히 불러오고 분석했을 때 발생합니다. 스타일 시트, 이미지, 하위 프레임의 로딩은 기다리지 않습니다.</p> + +<table class="properties"> + <tbody> + <tr> + <th scope="row">확산</th> + <td>예</td> + </tr> + <tr> + <th scope="row">취소 가능</th> + <td>예 (although specified as a simple event that isn't cancelable)</td> + </tr> + <tr> + <th scope="row">인터페이스</th> + <td>{{domxref("Event")}}</td> + </tr> + <tr> + <th scope="row">이벤트 처리기 속성</th> + <td>아니오</td> + </tr> + </tbody> +</table> + +<p><code>DOMContentLoaded</code>의 원본 대상은 다 불러온 {{domxref("Document")}}입니다. You can listen for this event on the <code>Window</code> interface to handle it in the capture or bubbling phases. For full details on this event please see the page on the Document: {{domxref("Document/DOMContentLoaded_event", "DOMContentLoaded")}} event.</p> + +<p>A different event, {{domxref("Window/load_event", "load")}}, should be used only to detect a fully-loaded page. It is a common mistake to use <code>load</code> where <code>DOMContentLoaded</code> would be more appropriate.</p> + +<h2 id="예제">예제</h2> + +<h3 id="기본_용도">기본 용도</h3> + +<pre class="brush: js notranslate">window.addEventListener('DOMContentLoaded', (event) => { + console.log('DOM fully loaded and parsed'); +}); +</pre> + +<h2 id="사양">사양</h2> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">사양</th> + <th scope="col">상태</th> + </tr> + </thead> + <tbody> + <tr> + <td>{{SpecName('HTML WHATWG', 'indices.html#event-domcontentloaded')}}</td> + <td>{{Spec2('HTML WHATWG')}}</td> + </tr> + </tbody> +</table> + +<h2 id="브라우저_호환성">브라우저 호환성</h2> + + + +<p>{{Compat("api.Window.DOMContentLoaded_event")}}</p> + +<h2 id="같이_보기">같이 보기</h2> + +<ul> + <li>Related events: {{domxref("Window/load_event", "load")}}, {{domxref("Document/readystatechange_event", "readystatechange")}}, {{domxref("Window/beforeunload_event", "beforeunload")}}, {{domxref("Window/unload_event", "unload")}}</li> + <li>This event on {{domxref("Document")}} targets: {{domxref("Document/DOMContentLoaded_event", "DOMContentLoaded")}}</li> +</ul> diff --git a/files/ko/web/api/window/load_event/index.html b/files/ko/web/api/window/load_event/index.html new file mode 100644 index 0000000000..baef50af25 --- /dev/null +++ b/files/ko/web/api/window/load_event/index.html @@ -0,0 +1,128 @@ +--- +title: load +slug: Web/Events/load +tags: + - Event + - 이벤트 +translation_of: Web/API/Window/load_event +--- +<p><code>load</code> 이벤트는 리소스와 그것에 의존하는 리소스들의 로딩이 완료되면 실행됩니다.</p> + +<p> </p> + +<h2 id="예제">예제</h2> + +<h3 class="brush: html" id="Window">Window</h3> + +<pre class="brush: html"><script> + window.addEventListener("load", function(event) { + console.log("All resources finished loading!"); + }); +</script></pre> + +<h3 class="brush: html" id="script_엘리먼트"><code>script</code> 엘리먼트</h3> + +<pre class="brush: html"><script> + var script = document.createElement("script"); + script.addEventListener("load", function(event) { + console.log("Script finished loading and executing"); + }); + script.src = "http://example.com/example.js"; + script.async = true; + document.getElementsByTagName("script")[0].parentNode.appendChild(script); +</script></pre> + +<h2 id="일반_정보">일반 정보</h2> + +<dl> + <dt style="float: left; text-align: right; width: 120px;">스펙</dt> + <dd style="margin: 0 0 0 120px;"><a class="external" href="http://www.w3.org/TR/DOM-Level-3-Events/#event-type-load">DOM L3</a></dd> + <dt style="float: left; text-align: right; width: 120px;">인터페이스</dt> + <dd style="margin: 0 0 0 120px;">UIEvent</dd> + <dt style="float: left; text-align: right; width: 120px;">Bubbles</dt> + <dd style="margin: 0 0 0 120px;">No</dd> + <dt style="float: left; text-align: right; width: 120px;">취소가능 여부</dt> + <dd style="margin: 0 0 0 120px;">No</dd> + <dt style="float: left; text-align: right; width: 120px;">타겟</dt> + <dd style="margin: 0 0 0 120px;">Window,Document,Element</dd> + <dt style="float: left; text-align: right; width: 120px;">기본 동작</dt> + <dd style="margin: 0 0 0 120px;">None.</dd> +</dl> + +<h2 id="속성">속성</h2> + +<table class="standard-table"> + <thead> + <tr> + <th scope="col">속성</th> + <th scope="col">타입</th> + <th scope="col">설명</th> + </tr> + </thead> + <tbody> + <tr> + <td><code>target</code> {{readonlyInline}}</td> + <td><code>{{domxref("EventTarget")}}</code></td> + <td>The event target (the topmost target in the DOM tree).</td> + </tr> + <tr> + <td><code>type</code> {{readonlyInline}}</td> + <td><code>{{domxref("DOMString")}}</code></td> + <td>The type of event.</td> + </tr> + <tr> + <td><code>bubbles</code> {{readonlyInline}}</td> + <td><code>{{domxref("Boolean")}}</code></td> + <td>Whether the event normally bubbles or not.</td> + </tr> + <tr> + <td><code>cancelable</code> {{readonlyInline}}</td> + <td><code>{{domxref("Boolean")}}</code></td> + <td>Whether the event is cancellable or not.</td> + </tr> + <tr> + <td><code>view</code> {{readonlyInline}}</td> + <td><code>{{domxref("WindowProxy")}}</code></td> + <td><code>{{domxref("Document.defaultView", "document.defaultView")}}</code> (<code>window</code> of the document)</td> + </tr> + <tr> + <td><code>detail</code> {{readonlyInline}}</td> + <td><code>long</code> (<code>float</code>)</td> + <td>0.</td> + </tr> + </tbody> +</table> + +<h2 id="스펙_정보">스펙 정보</h2> + +<table class="standard-table"> + <tbody> + <tr> + <th scope="col">스펙</th> + <th scope="col">상태</th> + <th scope="col">코멘트</th> + </tr> + <tr> + <td>{{SpecName('UI Events', '#event-type-load', 'load')}}</td> + <td>{{Spec2('UI Events')}}</td> + <td> </td> + </tr> + <tr> + <td>{{SpecName('HTML WHATWG', 'parsing.html#the-end:event-load', 'Load event')}}</td> + <td>{{Spec2('HTML WHATWG')}}</td> + <td> + <p>이것은 문서 로딩이 끝날때 수행되는 단계와 연결되는 섹션과 연결됩니다. 'load' 이벤트는 많은 엘리먼트들에서도 발생합니다. 그리고 스펙 문서에서는 많은 곳에서 "<a href="https://html.spec.whatwg.org/multipage/parsing.html#delay-the-load-event">load이벤트를 지연할 수 있는</a>" 것들을 언급한다는 것을 주의하십시오.</p> + </td> + </tr> + </tbody> +</table> + +<h2 id="관련_이벤트">관련 이벤트</h2> + +<ul> + <li>{{event("DOMContentLoaded")}}</li> + <li>{{event("readystatechange")}}</li> + <li>{{event("load")}}</li> + <li>{{event("beforeunload")}}</li> + <li>{{event("unload")}}</li> +</ul> diff --git a/files/ko/web/api/windowtimers/settimeout/index.html b/files/ko/web/api/windoworworkerglobalscope/settimeout/index.html index 7b338a83fa..7b338a83fa 100644 --- a/files/ko/web/api/windowtimers/settimeout/index.html +++ b/files/ko/web/api/windoworworkerglobalscope/settimeout/index.html diff --git a/files/ko/web/api/xmlhttprequest/timeout/index.html b/files/ko/web/api/xmlhttprequest/timeout_event/index.html index 4ecc599f9d..4ecc599f9d 100644 --- a/files/ko/web/api/xmlhttprequest/timeout/index.html +++ b/files/ko/web/api/xmlhttprequest/timeout_event/index.html diff --git a/files/ko/web/api/xsltprocessor/basic_example/index.html b/files/ko/web/api/xsltprocessor/basic_example/index.html new file mode 100644 index 0000000000..cb96c52c55 --- /dev/null +++ b/files/ko/web/api/xsltprocessor/basic_example/index.html @@ -0,0 +1,49 @@ +--- +title: Basic Example +slug: XSLT_in_Gecko/Basic_Example +translation_of: Web/API/XSLTProcessor/Basic_Example +--- +<h2 id=".EA.B8.B0.EB.B3.B8_.EC.98.88"> 기본 예 </h2> +<p>이 첫 예는 브라우저에서 XSLT 변환 설정의 기본을 보여준다. 이 예는 Article에 대한 정보(Title, Author 목록과 Body 글)를 포함한 XML 문서를 얻어 그것을 사람이 읽을 수 있는 형식으로 나타낸다. +</p><p>그림1은 기본 XSLT예의 소스를 보여준다. XML문서(example.xml)은 글의 정보를 포함한다. ?xml-stylesheet? 처리명령을 써서, 그것의 href 속성을 통해 XSLT 스타일쉬트(example.xsl)에 연결한다. +</p><p>XSLT 스타일쉬트는 xsl:stylesheet 요소로 시작하는데, 이것은 최종 출력을 생성하는데 쓰이는 모든 템플리트를 포함한다. 그림1의 예는 템플리트 2개를 가진다 - 하나는 root 노드에 하나는 Author 노드에 대응한다. root 노드에 대응하는 템플리트는 글의 제목을 출력하고 Authors 노드의 자식노드인 Author 노드에 대응하는 모든 템플리트를 처리하기 위해 말한다. +</p><p>그림1 : 간단한 XSLT예 +</p><p>XML 문서 (example.xml) : +</p> +<pre> <?xml version="1.0"?> + <?xml-stylesheet type="text/xsl" href="example.xsl"?> + <Article> + <Title>My Article</Title> + <Authors> + <Author>Mr. Foo</Author> + <Author>Mr. Bar</Author> + </Authors> + <Body>This is my article text.</Body> + </Article> +</pre> +<p>XSL 스타일쉬트 (example.xsl) : +</p> +<pre> <?xml version="1.0"?> + <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> + + <xsl:output method="text"/> + + <xsl:template match="/"> + Article - <xsl:value-of select="/Article/Title"/> + Authors: <xsl:apply-templates select="/Article/Authors/Author"/> + </xsl:template> + + <xsl:template match="Author"> + - <xsl:value-of select="." /> + </xsl:template> + + </xsl:stylesheet> +</pre> +<p>브라우저 출력: +</p> +<pre> Article - My Article + Authors: + - Mr. Foo + - Mr. Bar +</pre> +{{ languages( { "en": "en/XSLT_in_Gecko/Basic_Example" } ) }} diff --git a/files/ko/web/api/xsltprocessor/browser_differences/index.html b/files/ko/web/api/xsltprocessor/browser_differences/index.html new file mode 100644 index 0000000000..0d22a5b825 --- /dev/null +++ b/files/ko/web/api/xsltprocessor/browser_differences/index.html @@ -0,0 +1,8 @@ +--- +title: Browser Differences +slug: XSLT_in_Gecko/Browser_Differences +translation_of: Web/API/XSLTProcessor/Browser_Differences +--- +<h2 id=".EB.B8.8C.EB.9D.BC.EC.9A.B0.EC.A0.80_.EC.B0.A8.EC.9D.B4"> 브라우저 차이</h2> +<p>Netscape 7.x (모든 플랫폼)과 Internet Explorer 6(윈도즈)는 W3C XSLT 1.0 표준( <a class=" external" href="http://www.w3.org/TR/xslt">http://www.w3.org/TR/xslt</a> )을 지원합니다. IE 5.0과 5.5 (둘 다 윈도즈)는 XSLT의 초안만 지원하므로 XSLT 1.0 스타일쉬트와는 호환하지 않습니다. Netscape 6.x는 XSLT 1.0을 부분적으로만 지원합니다. +</p>{{ languages( { "en": "en/XSLT_in_Gecko/Browser_Differences" } ) }} diff --git a/files/ko/web/api/xsltprocessor/generating_html/index.html b/files/ko/web/api/xsltprocessor/generating_html/index.html new file mode 100644 index 0000000000..5bb284bdb8 --- /dev/null +++ b/files/ko/web/api/xsltprocessor/generating_html/index.html @@ -0,0 +1,174 @@ +--- +title: Generating HTML +slug: XSLT_in_Gecko/Generating_HTML +translation_of: Web/API/XSLTProcessor/Generating_HTML +--- +<h2 id="HTML_.EC.83.9D.EC.84.B1.ED.95.98.EA.B8.B0"> HTML 생성하기</h2> +<p>브라우저에서 XSLT의 공통 응용은 XML을 클라이언트의 안에 변환해 넣는 것이다. 두번째 예는 입력문서(example2.xml)를 변환하는데, 이것은 또 글의 정보를 포함하고 HTML문서 안에 들어간다. +</p><p>Article의 <code><span><body></span></code> 요소는 지금 HTML의 요소 (<code><span><b></span></code> 와 <code><span><u></span></code> 태그, 그림 2)를 포함한다. XML 문서는 HTML요소와 XML 요소 모두 포함하지만, 단 하나의 namespace 즉 XML 요소만 필요하다. HTML namespace가 없으므로, 그리고 XHTML namespace를 사용하여 XSL에서 an XML document를 생성하고 그것은 HTML문서와 같은 양상은 아닐 것이고, XSL Stylesheet 의<code>xsl:output</code>는 결과문서는 HTML처럼 다루어질 것을 보장한다 . XML 요소에 대해, 우리 자신의 namespace <code><a class=" external" href="http://devedge.netscape.com/2002/de">http://devedge.netscape.com/2002/de</a></code> 는 필요하고, 그것은 접두어 myNS <code>(xmlns:myNS="<span>http://devedge.netscape.com/2002/de</span>)</code>에 주어진다. +</p><p><small><b>그림 2 XML 파일 (example2.xml)</b></small> +<span>XML Document (example2.xml):</span> +</p> +<pre><?xml version="1.0"?> +<?xml-stylesheet type="text/xsl" href="example2.xsl"?> +<myNS:Article xmlns:myNS="http://devedge.netscape.com/2002/de"> +<myNS:Title>My Article</myNS:Title> +<myNS:Authors> +<myNS:Author company="Foopy Corp.">Mr. Foo</myNS:Author> +<myNS:Author>Mr. Bar</myNS:Author> +</myNS:Authors> +<myNS:Body> +The <b>rain</b> in <u>Spain</u> stays mainly in the plains. +</myNS:Body> +</myNS:Article> +</pre> +<p>The XSL Stylesheet used will need to have two namespaces - one for the XSLT elements and one for our own XML elements used in the XML document. The output of the XSL Stylesheet is set to <code>HTML</code> by using the <code>xsl:output</code> element. By setting the output to be HTML and not having a namespace on the resulting elements (colored in blue), those elements will be treated as HTML elements. +</p><p><small><b>그림 3 : 두 namespaces를 가진 XSL Stylesheet (example2.xsl)</b></small> +<span>XSL Stylesheet (example2.xsl):</span> +</p> +<pre><?xml version="1.0"?> +<xsl:stylesheet version="1.0" +xmlns:xsl="http://www.w3.org/1999/XSL/Transform" +xmlns:myNS="http://devedge.netscape.com/2002/de"> + +<xsl:output method="html"/> +... +</xsl:stylesheet version="1.0"> +</pre> +<p>A template matching the root node of the XML document is created and used to create the basic structure of the HTML page. +</p><p><small><b>Figure 4 : Creating the basic HTML document</b></small> +<span>XSL Stylesheet (example2.xsl):</span> +</p> +<pre>... +<xsl:template match="/"> +<html> + +<head> + +<title> +<xsl:value-of select="/myNS:Article/myNS:Title"/> +</title> + +<style type="text/css"> +.myBox {margin:10px 155px 0 50px; border: 1px dotted #639ACE; padding:0 5px 0 5px;} +</style> + +</head> + +<body> +<p class="myBox"> +<span class="title"> +<xsl:value-of select="/myNS:Article/myNS:Title"/> +</span> </br> + +Authors: <br /> +<xsl:apply-templates select="/myNS:Article/myNS:Authors/myNS:Author"/> +</p> + +<p class="myBox"> +<xsl:apply-templates select="//myNS:Body"/> +</p> + +</body> + +</html> +</xsl:template> +... +</pre> +<p>Three more <code>xsl:template</code>'s are needed to complete the example. The first <code>xsl:template</code> is used for the author nodes, while the second one processes the body node. The third template has a general matching rule which will match any node and any attribute. It is needed in order to preserve the html elements in the XML document, since it matches all of them and copies them out into the HTML document the transformation creates. +</p><p><b><small>그림 5 : 최종 3개 템플리트</small></b> +<span>XSL Stylesheet(example2.xsl):</span> +</p> +<pre>... +<xsl:template match="myNS:Author"> +-- <xsl:value-of select="." /> + +<xsl:if test="@company"> +:: <b> <xsl:value-of select="@company" /> </b> +</xsl:if> + +<br /> +</xsl:template> + +<xsl:template match="myNS:Body"> +<xsl:copy> +<xsl:apply-templates select="@*|node()"/> +</xsl:copy> +</xsl:template> + +<xsl:template match="@*|node()"> +<xsl:copy> +<xsl:apply-templates select="@*|node()"/> +</xsl:copy> +</xsl:template> +... +</pre> +<p>The final XSLT stylesheet looks as follows: +</p><p><small><b>그림 6 : 최종 XSLT Stylesheet<span>view example | view source</span></b></small> +<span>XSL Stylesheet:</span> +</p> +<pre><?xml version="1.0"?> +<xsl:stylesheet version="1.0" +xmlns:xsl="http://www.w3.org/1999/XSL/Transform" +xmlns:myNS="http://devedge.netscape.com/2002/de"> + +<xsl:output method="html" /> + +<xsl:template match="/"> +<html> + +<head> + +<title> +<xsl:value-of select="/myNS:Article/myNS:Title"/> +</title> + +<style type="text/css"> +.myBox {margin:10px 155px 0 50px; border: 1px dotted #639ACE; padding:0 5px 0 5px;} +</style> + +</head> + +<body> +<p class="myBox"> +<span class="title"> +<xsl:value-of select="/myNS:Article/myNS:Title"/> +</span> <br /> + +Authors: <br /> +<xsl:apply-templates select="/myNS:Article/myNS:Authors/myNS:Author"/> +</p> + +<p class="myBox"> +<xsl:apply-templates select="//myNS:Body"/> +</p> + +</body> + +</html> +</xsl:template> + +<xsl:template match="myNS:Author"> +-- <xsl:value-of select="." /> + +<xsl:if test="@company"> +:: <b> <xsl:value-of select="@company" /> </b> +</xsl:if> + +<br /> +</xsl:template> + +<xsl:template match="myNS:Body"> +<xsl:copy> +<xsl:apply-templates select="@*|node()"/> +</xsl:copy> +</xsl:template> + +<xsl:template match="@*|node()"> +<xsl:copy> +<xsl:apply-templates select="@*|node()"/> +</xsl:copy> +</xsl:template> +</xsl:stylesheet> +</pre> +{{ languages( { "en": "en/XSLT_in_Gecko/Generating_HTML" } ) }} diff --git a/files/ko/web/api/xsltprocessor/index.html b/files/ko/web/api/xsltprocessor/index.html new file mode 100644 index 0000000000..84d5198c58 --- /dev/null +++ b/files/ko/web/api/xsltprocessor/index.html @@ -0,0 +1,15 @@ +--- +title: XSLT in Gecko +slug: XSLT_in_Gecko +tags: + - XSLT +translation_of: Web/API/XSLTProcessor +translation_of_original: XSLT_in_Gecko +--- +<ol><li> <a href="ko/XSLT_in_Gecko/Introduction">개요</a> +</li><li> <a href="ko/XSLT_in_Gecko/Basic_Example">기본 예제</a> +</li><li> <a href="ko/XSLT_in_Gecko/Generating_HTML">HTML 생성</a> +</li><li> <a href="ko/XSLT_in_Gecko/Browser_Differences">브라우저 차이</a> +</li><li> <a href="ko/XSLT_in_Gecko/Resources">자원</a> +</li></ol> +{{ languages( { "en": "en/XSLT_in_Gecko" } ) }} diff --git a/files/ko/web/api/xsltprocessor/introduction/index.html b/files/ko/web/api/xsltprocessor/introduction/index.html new file mode 100644 index 0000000000..bfb103b98f --- /dev/null +++ b/files/ko/web/api/xsltprocessor/introduction/index.html @@ -0,0 +1,13 @@ +--- +title: Introduction +slug: XSLT_in_Gecko/Introduction +translation_of: Web/API/XSLTProcessor/Introduction +--- +<h2 id=".EA.B0.9C.EC.9A.94">개요</h2> +<p>W3표준 안에서 주목할만한 하나의 흐름은 스타일로부터 내용을 분리하려는 노력이다. +</p><p>이것은 같은 스타일이 여러 내용에서 재사용되는 것을 허용할 뿐 아니라 유지보수를 쉽게 하고 (하나의 파일만 바꾸어서) 내용의 외관을 빠르게 바꾸는 방법을 허용한다. +</p><p>CSS (Cascade Style Sheets)는 W3C에서 제안된 첫번째 방법이다. CSS는 스타일규칙을 웹문서에 적용하는 간단한 방법이다. 이 스타일규칙은 어떻게 문서(내용)가 놓일지 정의한다. 그러나, 여러 제한이 있다. 프로그램 구조와 복잡한 레이아웃 모델을 만드는 가능성의 부족. CSS는 요소의 위치 변화제공에 제한된다. +</p><p>XSL (Extensible Stylesheet Language)변환은 두 부분으로 구성된다. XML트리를 다른 마크업 트리로 변환하는 XSL요소, 트리를 위한 선택언어 XPath. +XSLT는 XML문서를 얻어서 XSL스타일쉬트안의 규칙에 기반한 새 문서를 생성한다. 이것은 XSLT가 원 XML문서로부터 요소를 추가, 제거, 재구성하는 것을 허용하고 따라서 결과문서구조의 좀더 세분된 제어를 허용한다. +</p><p>XSLT의 변환은 template로 구성된 규칙에 기반한다. 각 template은 입력 XML문서의 조각에 대응하고 대응하는 부분을 새 결과문서에 적용한다. +</p>{{ languages( { "en": "en/XSLT_in_Gecko/Introduction" } ) }} diff --git a/files/ko/web/api/xsltprocessor/resources/index.html b/files/ko/web/api/xsltprocessor/resources/index.html new file mode 100644 index 0000000000..bcdb54116f --- /dev/null +++ b/files/ko/web/api/xsltprocessor/resources/index.html @@ -0,0 +1,14 @@ +--- +title: Resources +slug: XSLT_in_Gecko/Resources +translation_of: Web/API/XSLTProcessor/Resources +--- +<h2 id=".EC.9E.90.EC.9B.90" name=".EC.9E.90.EC.9B.90">자원</h2> +<ul> + <li><a class="external" href="http://devedge.netscape.com/library/manuals/2001/xslt/1.0/">Transforming XML: Netscape and XSLT</a></li> + <li><a class="external" href="http://www-106.ibm.com/developerworks/library/x-xslt/">What kind of language is XSLT?</a> at <a class="external" href="http://www-106.ibm.com/developerworks/">IBM developerWorks</a></li> + <li><a class="external" href="http://www.zvon.org/xxl/XSLTutorial/Books/Book1/index.html">XSLT Tutorial</a> at <a class="external" href="http://www.zvon.org/">zvon.org</a></li> + <li><a class="external" href="http://www.zvon.org/xxl/XPathTutorial/General/examples.html">XPath Tutorial</a> at <a class="external" href="http://www.zvon.org/">zvon.org</a></li> + <li><a href="ko/Using_the_Mozilla_JavaScript_interface_to_XSL_Transformations">Using the Mozilla JavaScript interface to XSL Transformations</a></li> + <li><a class="external" href="http://www.mozilla.org/projects/xslt/">Mozilla.org's XSLT Project Page</a>, which includes a frequently encountered issues section.</li> +</ul> |