From 6269b941fe1259d3e79c47cd097b2aa026ce5f47 Mon Sep 17 00:00:00 2001 From: Will Bamberg Date: Mon, 28 Nov 2022 10:20:30 -0800 Subject: [PATCH 1/5] Add 'Tutorial' to l10n strings --- files/jsondata/L10n-Common.json | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/files/jsondata/L10n-Common.json b/files/jsondata/L10n-Common.json index 8907f03c86f6c8a..8eccec73a6ee142 100644 --- a/files/jsondata/L10n-Common.json +++ b/files/jsondata/L10n-Common.json @@ -163,6 +163,13 @@ "ru": "[Перевести]", "zh-CN": "[我来译!]" }, + "Tutorial": { + "en-US": "Tutorial", + "fr": "Tutoriel", + "ja": "チュートリアル", + "ru": "Руководство", + "zh-CN": "教程" + }, "listSeparator": { "en-US": ", ", "es": ", ", From 16e05726c90a22c94397c4a258966b0a57cf831a Mon Sep 17 00:00:00 2001 From: Will Bamberg Date: Mon, 28 Nov 2022 10:23:57 -0800 Subject: [PATCH 2/5] Update groupdata with Canvas tutorial; Update Canvas API main page to use DefaultAPISidebar --- files/en-us/web/api/canvas_api/index.md | 2 +- files/jsondata/GroupData.json | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/files/en-us/web/api/canvas_api/index.md b/files/en-us/web/api/canvas_api/index.md index 83d0cd6405303ce..f8bc206abfd7261 100644 --- a/files/en-us/web/api/canvas_api/index.md +++ b/files/en-us/web/api/canvas_api/index.md @@ -12,7 +12,7 @@ tags: browser-compat: html.elements.canvas --- -{{CanvasSidebar}} +{{DefaultAPISidebar("Canvas API")}} The **Canvas API** provides a means for drawing graphics via [JavaScript](/en-US/docs/Web/JavaScript) and the [HTML](/en-US/docs/Web/HTML) {{HtmlElement("canvas")}} element. Among other things, it can be used for animation, game graphics, data visualization, photo manipulation, and real-time video processing. diff --git a/files/jsondata/GroupData.json b/files/jsondata/GroupData.json index 75a5b0af4bda62d..85a7afb2cc52d50 100644 --- a/files/jsondata/GroupData.json +++ b/files/jsondata/GroupData.json @@ -86,6 +86,21 @@ "/docs/Web/API/Canvas_API/A_basic_ray-caster", "/docs/Web/API/Canvas_API/Manipulating_video_using_canvas" ], + "tutorial": [ + "/docs/Web/API/Canvas_API/Tutorial", + "/docs/Web/API/Canvas_API/Tutorial/Basic_usage", + "/docs/Web/API/Canvas_API/Tutorial/Drawing_shapes", + "/docs/Web/API/Canvas_API/Tutorial/Applying_styles_and_colors", + "/docs/Web/API/Canvas_API/Tutorial/Drawing_text", + "/docs/Web/API/Canvas_API/Tutorial/Using_images", + "/docs/Web/API/Canvas_API/Tutorial/Transformations", + "/docs/Web/API/Canvas_API/Tutorial/Compositing", + "/docs/Web/API/Canvas_API/Tutorial/Basic_animations", + "/docs/Web/API/Canvas_API/Tutorial/Advanced_animations", + "/docs/Web/API/Canvas_API/Tutorial/Pixel_manipulation_with_canvas", + "/docs/Web/API/Canvas_API/Tutorial/Optimizing_canvas", + "/docs/Web/API/Canvas_API/Tutorial/Finale" + ], "interfaces": [ "CanvasGradient", "CanvasPattern", From bc58c970aed7b03c7050a419e2f524b88a2f0198 Mon Sep 17 00:00:00 2001 From: Will Bamberg Date: Mon, 28 Nov 2022 10:59:04 -0800 Subject: [PATCH 3/5] Trim a couple of guides --- files/jsondata/GroupData.json | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/files/jsondata/GroupData.json b/files/jsondata/GroupData.json index 85a7afb2cc52d50..fb4eeda5ba66115 100644 --- a/files/jsondata/GroupData.json +++ b/files/jsondata/GroupData.json @@ -81,11 +81,7 @@ }, "Canvas API": { "overview": ["Canvas API"], - "guides": [ - "/docs/Web/API/Canvas_API/Tutorial", - "/docs/Web/API/Canvas_API/A_basic_ray-caster", - "/docs/Web/API/Canvas_API/Manipulating_video_using_canvas" - ], + "guides": ["/docs/Web/API/Canvas_API/Manipulating_video_using_canvas"], "tutorial": [ "/docs/Web/API/Canvas_API/Tutorial", "/docs/Web/API/Canvas_API/Tutorial/Basic_usage", From ef677035c6cbdec31899bcb07e0560d364e4ee47 Mon Sep 17 00:00:00 2001 From: wbamberg Date: Mon, 28 Nov 2022 11:41:57 -0800 Subject: [PATCH 4/5] Add es string Co-authored-by: Alexander --- files/jsondata/L10n-Common.json | 1 + 1 file changed, 1 insertion(+) diff --git a/files/jsondata/L10n-Common.json b/files/jsondata/L10n-Common.json index 8eccec73a6ee142..13b44daf86b40c5 100644 --- a/files/jsondata/L10n-Common.json +++ b/files/jsondata/L10n-Common.json @@ -165,6 +165,7 @@ }, "Tutorial": { "en-US": "Tutorial", + "es": "Tutorial", "fr": "Tutoriel", "ja": "チュートリアル", "ru": "Руководство", From b6bf80fea4b2830a399fd3ad62d72f47160f5456 Mon Sep 17 00:00:00 2001 From: Will Bamberg Date: Mon, 5 Dec 2022 11:23:15 -0800 Subject: [PATCH 5/5] Update all Canvas pages to use standard sidebar --- .../manipulating_video_using_canvas/index.md | 88 ++-- .../tutorial/advanced_animations/index.md | 116 +++-- .../applying_styles_and_colors/index.md | 203 ++++---- .../tutorial/basic_animations/index.md | 71 +-- .../canvas_api/tutorial/basic_usage/index.md | 10 +- .../tutorial/compositing/example/index.md | 461 +++++++++--------- .../canvas_api/tutorial/compositing/index.md | 17 +- .../tutorial/drawing_shapes/index.md | 44 +- .../canvas_api/tutorial/drawing_text/index.md | 38 +- .../api/canvas_api/tutorial/finale/index.md | 2 +- .../web/api/canvas_api/tutorial/index.md | 2 +- .../tutorial/optimizing_canvas/index.md | 10 +- .../pixel_manipulation_with_canvas/index.md | 34 +- .../tutorial/transformations/index.md | 52 +- .../canvas_api/tutorial/using_images/index.md | 62 ++- 15 files changed, 641 insertions(+), 569 deletions(-) diff --git a/files/en-us/web/api/canvas_api/manipulating_video_using_canvas/index.md b/files/en-us/web/api/canvas_api/manipulating_video_using_canvas/index.md index 6fa371d63713013..32b3cc28f87d107 100644 --- a/files/en-us/web/api/canvas_api/manipulating_video_using_canvas/index.md +++ b/files/en-us/web/api/canvas_api/manipulating_video_using_canvas/index.md @@ -13,7 +13,7 @@ tags: - effects --- -{{CanvasSidebar}} +{{DefaultAPISidebar("Canvas API")}} By combining the capabilities of the [`video`](/en-US/docs/Web/HTML/Element/video) element with a [`canvas`](/en-US/docs/Web/HTML/Element/canvas), you can manipulate video data in real time to incorporate a variety of visual effects to the video being displayed. This tutorial demonstrates how to perform chroma-keying (also known as the "green screen effect") using JavaScript code. @@ -79,24 +79,28 @@ The JavaScript code in `processor.js` consists of three methods. The `doLoad()` method is called when the HTML document initially loads. This method's job is to prepare the variables needed by the chroma-key processing code, and to set up an event listener so we can detect when the user starts playing the video. ```js - const processor = {}; - - processor.doLoad = function doLoad() { - const video = document.getElementById('video'); - this.video = video; - - this.c1 = document.getElementById('c1'); - this.ctx1 = this.c1.getContext('2d'); - - this.c2 = document.getElementById('c2'); - this.ctx2 = this.c2.getContext('2d'); - - video.addEventListener('play', () => { - this.width = video.videoWidth / 2; - this.height = video.videoHeight / 2; - this.timerCallback(); - }, false); - }; +const processor = {}; + +processor.doLoad = function doLoad() { + const video = document.getElementById("video"); + this.video = video; + + this.c1 = document.getElementById("c1"); + this.ctx1 = this.c1.getContext("2d"); + + this.c2 = document.getElementById("c2"); + this.ctx2 = this.c2.getContext("2d"); + + video.addEventListener( + "play", + () => { + this.width = video.videoWidth / 2; + this.height = video.videoHeight / 2; + this.timerCallback(); + }, + false + ); +}; ``` This code grabs references to the elements in the HTML document that are of particular interest, namely the `video` element and the two `canvas` elements. It also fetches references to the graphics contexts for each of the two canvases. These will be used when we're actually doing the chroma-keying effect. @@ -108,15 +112,15 @@ Then `addEventListener()` is called to begin watching the `video` element so tha The timer callback is called initially when the video starts playing (when the "play" event occurs), then takes responsibility for establishing itself to be called periodically in order to launch the keying effect for each frame. ```js - processor.timerCallback = function timerCallback() { - if (this.video.paused || this.video.ended) { - return; - } - this.computeFrame(); - setTimeout(() => { - this.timerCallback(); - }, 0); - }; +processor.timerCallback = function timerCallback() { + if (this.video.paused || this.video.ended) { + return; + } + this.computeFrame(); + setTimeout(() => { + this.timerCallback(); + }, 0); +}; ``` The first thing the callback does is check to see if the video is even playing; if it's not, the callback returns immediately without doing anything. @@ -130,21 +134,21 @@ The last thing the callback does is call `setTimeout()` to schedule itself to be The `computeFrame()` method, shown below, is responsible for actually fetching a frame of data and performing the chroma-keying effect. ```js - processor.computeFrame = function () { - this.ctx1.drawImage(this.video, 0, 0, this.width, this.height); - const frame = this.ctx1.getImageData(0, 0, this.width, this.height); - const data = frame.data; - - for (let i = 0; i < data.length; i += 4) { - const red = data[i + 0]; - const green = data[i + 1]; - const blue = data[i + 2]; - if (green > 100 && red > 100 && blue < 43) { - data[i + 3] = 0; - } +processor.computeFrame = function () { + this.ctx1.drawImage(this.video, 0, 0, this.width, this.height); + const frame = this.ctx1.getImageData(0, 0, this.width, this.height); + const data = frame.data; + + for (let i = 0; i < data.length; i += 4) { + const red = data[i + 0]; + const green = data[i + 1]; + const blue = data[i + 2]; + if (green > 100 && red > 100 && blue < 43) { + data[i + 3] = 0; } - this.ctx2.putImageData(frame, 0, 0); - }; + } + this.ctx2.putImageData(frame, 0, 0); +}; ``` When this routine is called, the video element is displaying the most recent frame of video data, which looks like this: diff --git a/files/en-us/web/api/canvas_api/tutorial/advanced_animations/index.md b/files/en-us/web/api/canvas_api/tutorial/advanced_animations/index.md index 266f010dc4b0a20..f3b92a77aca1ed7 100644 --- a/files/en-us/web/api/canvas_api/tutorial/advanced_animations/index.md +++ b/files/en-us/web/api/canvas_api/tutorial/advanced_animations/index.md @@ -8,7 +8,7 @@ tags: - Tutorial --- -{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Basic_animations", "Web/API/Canvas_API/Tutorial/Pixel_manipulation_with_canvas")}} +{{DefaultAPISidebar("Canvas API")}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Basic_animations", "Web/API/Canvas_API/Tutorial/Pixel_manipulation_with_canvas")}} In the last chapter we made some [basic animations](/en-US/docs/Web/API/Canvas_API/Tutorial/Basic_animations) and got to know ways to get things moving. In this part we will have a closer look at the motion itself and are going to add some physics to make our animations more advanced. @@ -23,21 +23,21 @@ We are going to use a ball for our animation studies, so let's first draw that b As usual, we need a drawing context first. To draw the ball, we will create a `ball` object which contains properties and a `draw()` method to paint it on the canvas. ```js -const canvas = document.getElementById('canvas'); -const ctx = canvas.getContext('2d'); +const canvas = document.getElementById("canvas"); +const ctx = canvas.getContext("2d"); const ball = { x: 100, y: 100, radius: 25, - color: 'blue', + color: "blue", draw() { 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(); @@ -50,8 +50,8 @@ Nothing special here, the ball is actually a simple circle and gets drawn with t Now that we have a ball, we are ready to add a basic animation like we have learned in the [last chapter](/en-US/docs/Web/API/Canvas_API/Tutorial/Basic_animations) of this tutorial. Again, {{domxref("window.requestAnimationFrame()")}} helps us to control the animation. The ball gets moving by adding a velocity vector to the position. For each frame, we also {{domxref("CanvasRenderingContext2D.clearRect", "clear", "", 1)}} the canvas to remove old circles from prior frames. ```js -const canvas = document.getElementById('canvas'); -const ctx = canvas.getContext('2d'); +const canvas = document.getElementById("canvas"); +const ctx = canvas.getContext("2d"); let raf; const ball = { @@ -60,29 +60,29 @@ const ball = { vx: 5, vy: 2, radius: 25, - color: 'blue', + color: "blue", draw() { 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); + 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', (e) => { +canvas.addEventListener("mouseover", (e) => { raf = window.requestAnimationFrame(draw); }); -canvas.addEventListener('mouseout', (e) => { +canvas.addEventListener("mouseout", (e) => { window.cancelAnimationFrame(raf); }); @@ -115,8 +115,8 @@ Let's see how it looks in action so far. #### JavaScript ```js -const canvas = document.getElementById('canvas'); -const ctx = canvas.getContext('2d'); +const canvas = document.getElementById("canvas"); +const ctx = canvas.getContext("2d"); let raf; const ball = { @@ -125,39 +125,37 @@ const ball = { vx: 5, vy: 2, radius: 25, - color: 'blue', + color: "blue", draw() { 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); + 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) { + 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) { + if (ball.x + ball.vx > canvas.width || ball.x + ball.vx < 0) { ball.vx = -ball.vx; } raf = window.requestAnimationFrame(draw); } -canvas.addEventListener('mouseover', (e) => { +canvas.addEventListener("mouseover", (e) => { raf = window.requestAnimationFrame(draw); }); -canvas.addEventListener('mouseout', (e) => { +canvas.addEventListener("mouseout", (e) => { window.cancelAnimationFrame(raf); }); @@ -175,8 +173,8 @@ Move your mouse into the canvas to start the animation. To make the motion more real, you can play with the velocity like this, for example: ```js -ball.vy *= .99; -ball.vy += .25; +ball.vy *= 0.99; +ball.vy += 0.25; ``` This slows down the vertical velocity each frame, so that the ball will just bounce on the floor in the end. @@ -192,8 +190,8 @@ This slows down the vertical velocity each frame, so that the ball will just bou #### JavaScript ```js -const canvas = document.getElementById('canvas'); -const ctx = canvas.getContext('2d'); +const canvas = document.getElementById("canvas"); +const ctx = canvas.getContext("2d"); let raf; const ball = { @@ -202,41 +200,39 @@ const ball = { vx: 5, vy: 2, radius: 25, - color: 'blue', + color: "blue", draw() { 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); + ctx.clearRect(0, 0, canvas.width, canvas.height); ball.draw(); ball.x += ball.vx; ball.y += ball.vy; - ball.vy *= .99; - ball.vy += .25; + ball.vy *= 0.99; + ball.vy += 0.25; - if (ball.y + ball.vy > canvas.height || - ball.y + ball.vy < 0) { + 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) { + if (ball.x + ball.vx > canvas.width || ball.x + ball.vx < 0) { ball.vx = -ball.vx; } raf = window.requestAnimationFrame(draw); } -canvas.addEventListener('mouseover', (e) => { +canvas.addEventListener("mouseover", (e) => { raf = window.requestAnimationFrame(draw); }); -canvas.addEventListener('mouseout', (e) => { +canvas.addEventListener("mouseout", (e) => { window.cancelAnimationFrame(raf); }); @@ -252,7 +248,7 @@ ball.draw(); Until now we have made use of the {{domxref("CanvasRenderingContext2D.clearRect", "clearRect")}} method when clearing prior frames. If you replace this method with a semi-transparent {{domxref("CanvasRenderingContext2D.fillRect", "fillRect")}}, you can easily create a trailing effect. ```js -ctx.fillStyle = 'rgba(255, 255, 255, 0.3)'; +ctx.fillStyle = "rgba(255, 255, 255, 0.3)"; ctx.fillRect(0, 0, canvas.width, canvas.height); ``` @@ -267,8 +263,8 @@ ctx.fillRect(0, 0, canvas.width, canvas.height); #### JavaScript ```js -const canvas = document.getElementById('canvas'); -const ctx = canvas.getContext('2d'); +const canvas = document.getElementById("canvas"); +const ctx = canvas.getContext("2d"); let raf; const ball = { @@ -277,42 +273,40 @@ const ball = { vx: 5, vy: 2, radius: 25, - color: 'blue', + color: "blue", draw() { 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.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; + ball.vy *= 0.99; + ball.vy += 0.25; - if (ball.y + ball.vy > canvas.height || - ball.y + ball.vy < 0) { + 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) { + if (ball.x + ball.vx > canvas.width || ball.x + ball.vx < 0) { ball.vx = -ball.vx; } raf = window.requestAnimationFrame(draw); } -canvas.addEventListener('mouseover', (e) => { +canvas.addEventListener("mouseover", (e) => { raf = window.requestAnimationFrame(draw); }); -canvas.addEventListener('mouseout', (e) => { +canvas.addEventListener("mouseout", (e) => { window.cancelAnimationFrame(raf); }); @@ -338,8 +332,8 @@ To get some control over the ball, we can make it follow our mouse using the [`m #### JavaScript ```js -const canvas = document.getElementById('canvas'); -const ctx = canvas.getContext('2d'); +const canvas = document.getElementById("canvas"); +const ctx = canvas.getContext("2d"); let raf; let running = false; @@ -349,19 +343,19 @@ const ball = { vx: 5, vy: 1, radius: 25, - color: 'blue', + color: "blue", draw() { 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); + ctx.fillStyle = "rgba(255, 255, 255, 0.3)"; + ctx.fillRect(0, 0, canvas.width, canvas.height); } function draw() { @@ -380,7 +374,7 @@ function draw() { raf = window.requestAnimationFrame(draw); } -canvas.addEventListener('mousemove', (e) => { +canvas.addEventListener("mousemove", (e) => { if (!running) { clear(); ball.x = e.clientX; @@ -389,14 +383,14 @@ canvas.addEventListener('mousemove', (e) => { } }); -canvas.addEventListener('click', (e) => { +canvas.addEventListener("click", (e) => { if (!running) { raf = window.requestAnimationFrame(draw); running = true; } }); -canvas.addEventListener('mouseout', (e) => { +canvas.addEventListener("mouseout", (e) => { window.cancelAnimationFrame(raf); running = false; }); diff --git a/files/en-us/web/api/canvas_api/tutorial/applying_styles_and_colors/index.md b/files/en-us/web/api/canvas_api/tutorial/applying_styles_and_colors/index.md index c97615daa4deffb..3d632e10965fea2 100644 --- a/files/en-us/web/api/canvas_api/tutorial/applying_styles_and_colors/index.md +++ b/files/en-us/web/api/canvas_api/tutorial/applying_styles_and_colors/index.md @@ -10,7 +10,7 @@ tags: - Tutorial --- -{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Drawing_shapes", "Web/API/Canvas_API/Tutorial/Drawing_text")}} +{{DefaultAPISidebar("Canvas API")}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Drawing_shapes", "Web/API/Canvas_API/Tutorial/Drawing_text")}} In the chapter about [drawing shapes](/en-US/docs/Web/API/Canvas_API/Tutorial/Drawing_shapes), we used only the default line and fill styles. Here we will explore the canvas options we have at our disposal to make our drawings a little more attractive. You will learn how to add different colors, line styles, gradients, patterns and shadows to your drawings. @@ -34,10 +34,10 @@ The valid strings you can enter should, according to the specification, be CSS { ```js // these all set the fillStyle to 'orange' -ctx.fillStyle = 'orange'; -ctx.fillStyle = '#FFA500'; -ctx.fillStyle = 'rgb(255, 165, 0)'; -ctx.fillStyle = 'rgba(255, 165, 0, 1)'; +ctx.fillStyle = "orange"; +ctx.fillStyle = "#FFA500"; +ctx.fillStyle = "rgb(255, 165, 0)"; +ctx.fillStyle = "rgba(255, 165, 0, 1)"; ``` ### A `fillStyle` example @@ -46,10 +46,12 @@ In this example, we once again use two `for` loops to draw a grid of rectangles, ```js function draw() { - const ctx = document.getElementById('canvas').getContext('2d'); + const ctx = document.getElementById("canvas").getContext("2d"); for (let i = 0; i < 6; i++) { for (let j = 0; j < 6; j++) { - ctx.fillStyle = `rgb(${Math.floor(255 - 42.5 * i)}, ${Math.floor(255 - 42.5 * j)}, 0)`; + ctx.fillStyle = `rgb(${Math.floor(255 - 42.5 * i)}, ${Math.floor( + 255 - 42.5 * j + )}, 0)`; ctx.fillRect(j * 25, i * 25, 25, 25); } } @@ -57,7 +59,9 @@ function draw() { ``` ```html hidden -A 6 by 6 square grid displaying 36 different colors +A 6 by 6 square grid displaying 36 different colors ``` ```js hidden @@ -73,17 +77,19 @@ The result looks like this: This example is similar to the one above, but uses the `strokeStyle` property to change the colors of the shapes' outlines. We use the `arc()` method to draw circles instead of squares. ```js - function draw() { - const ctx = document.getElementById('canvas').getContext('2d'); - for (let i = 0; i < 6; i++) { - for (let 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, 2 * Math.PI, true); - ctx.stroke(); - } +function draw() { + const ctx = document.getElementById("canvas").getContext("2d"); + for (let i = 0; i < 6; i++) { + for (let 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, 2 * Math.PI, true); + ctx.stroke(); } } +} ``` ```html hidden @@ -112,8 +118,8 @@ Because the `strokeStyle` and `fillStyle` properties accept CSS rgba color value ```js // Assigning transparent colors to stroke and fill style -ctx.strokeStyle = 'rgba(255, 0, 0, 0.5)'; -ctx.fillStyle = 'rgba(255, 0, 0, 0.5)'; +ctx.strokeStyle = "rgba(255, 0, 0, 0.5)"; +ctx.fillStyle = "rgba(255, 0, 0, 0.5)"; ``` The `rgba()` function is similar to the `rgb()` function but it has one extra parameter. The last parameter sets the transparency value of this particular color. The valid range is again between 0.0 (fully transparent) and 1.0 (fully opaque). @@ -124,17 +130,17 @@ In this example, we'll draw a background of four different colored squares. On t ```js function draw() { - const ctx = document.getElementById('canvas').getContext('2d'); + const ctx = document.getElementById("canvas").getContext("2d"); // draw background - ctx.fillStyle = '#FD0'; + ctx.fillStyle = "#FD0"; ctx.fillRect(0, 0, 75, 75); - ctx.fillStyle = '#6C0'; + ctx.fillStyle = "#6C0"; ctx.fillRect(75, 0, 75, 75); - ctx.fillStyle = '#09F'; + ctx.fillStyle = "#09F"; ctx.fillRect(0, 75, 75, 75); - ctx.fillStyle = '#F30'; + ctx.fillStyle = "#F30"; ctx.fillRect(75, 75, 75, 75); - ctx.fillStyle = '#FFF'; + ctx.fillStyle = "#FFF"; // set transparency value ctx.globalAlpha = 0.2; @@ -164,16 +170,16 @@ In this second example, we do something similar to the one above, but instead of ```js function draw() { - const ctx = document.getElementById('canvas').getContext('2d'); + const ctx = document.getElementById("canvas").getContext("2d"); // Draw background - ctx.fillStyle = 'rgb(255, 221, 0)'; + ctx.fillStyle = "rgb(255, 221, 0)"; ctx.fillRect(0, 0, 150, 37.5); - ctx.fillStyle = 'rgb(102, 204, 0)'; + ctx.fillStyle = "rgb(102, 204, 0)"; ctx.fillRect(0, 37.5, 150, 37.5); - ctx.fillStyle = 'rgb(0, 153, 255)'; + ctx.fillStyle = "rgb(0, 153, 255)"; ctx.fillRect(0, 75, 150, 37.5); - ctx.fillStyle = 'rgb(255, 51, 0)'; + ctx.fillStyle = "rgb(255, 51, 0)"; ctx.fillRect(0, 112.5, 150, 37.5); // Draw semi transparent rectangles @@ -227,7 +233,7 @@ In the example below, 10 straight lines are drawn with increasing line widths. T ```js function draw() { - const ctx = document.getElementById('canvas').getContext('2d'); + const ctx = document.getElementById("canvas").getContext("2d"); for (let i = 0; i < 10; i++) { ctx.lineWidth = 1 + i; ctx.beginPath(); @@ -281,10 +287,10 @@ The line on the left uses the default `butt` option. You'll notice that it's dra ```js function draw() { - const ctx = document.getElementById('canvas').getContext('2d'); + const ctx = document.getElementById("canvas").getContext("2d"); // Draw guides - ctx.strokeStyle = '#09f'; + ctx.strokeStyle = "#09f"; ctx.beginPath(); ctx.moveTo(10, 10); ctx.lineTo(140, 10); @@ -293,8 +299,8 @@ function draw() { ctx.stroke(); // Draw lines - ctx.strokeStyle = 'black'; - ['butt', 'round', 'square'].forEach((lineCap, i) => { + ctx.strokeStyle = "black"; + ["butt", "round", "square"].forEach((lineCap, i) => { ctx.lineWidth = 15; ctx.lineCap = lineCap; ctx.beginPath(); @@ -332,9 +338,9 @@ The example below draws three different paths, demonstrating each of these three ```js function draw() { - const ctx = document.getElementById('canvas').getContext('2d'); + const ctx = document.getElementById("canvas").getContext("2d"); ctx.lineWidth = 10; - ['round', 'bevel', 'miter'].forEach((lineJoin, i) => { + ["round", "bevel", "miter"].forEach((lineJoin, i) => { ctx.lineJoin = lineJoin; ctx.beginPath(); ctx.moveTo(-5, 5 + i * 40); @@ -377,25 +383,25 @@ If you specify a `miterLimit` value below 4.2 in this demo, none of the visible ```js function draw() { - const ctx = document.getElementById('canvas').getContext('2d'); + const ctx = document.getElementById("canvas").getContext("2d"); // Clear canvas ctx.clearRect(0, 0, 150, 150); // Draw guides - ctx.strokeStyle = '#09f'; - ctx.lineWidth = 2; + ctx.strokeStyle = "#09f"; + ctx.lineWidth = 2; ctx.strokeRect(-5, 50, 160, 50); // Set line styles - ctx.strokeStyle = '#000'; + ctx.strokeStyle = "#000"; ctx.lineWidth = 10; // check input - if (document.getElementById('miterLimit').value.match(/\d+(\.\d+)?/)) { - ctx.miterLimit = parseFloat(document.getElementById('miterLimit').value); + if (document.getElementById("miterLimit").value.match(/\d+(\.\d+)?/)) { + ctx.miterLimit = parseFloat(document.getElementById("miterLimit").value); } else { - alert('Value must be a positive number'); + alert("Value must be a positive number"); } // Draw lines @@ -413,7 +419,9 @@ function draw() { ```html hidden - +
+ + Change the miterLimit by entering a new value below and clicking the redraw button.

@@ -428,7 +436,9 @@ function draw() { ``` ```js hidden -document.getElementById('miterLimit').value = document.getElementById('canvas').getContext('2d').miterLimit; +document.getElementById("miterLimit").value = document + .getElementById("canvas") + .getContext("2d").miterLimit; draw(); ``` @@ -445,7 +455,7 @@ In this example we are creating a marching ants effect. It is an animation techn ``` ```js -const ctx = document.getElementById('canvas').getContext('2d'); +const ctx = document.getElementById("canvas").getContext("2d"); let offset = 0; function draw() { @@ -496,8 +506,8 @@ You can add as many color stops to a gradient as you need. Below is a very simpl ```js const lineargradient = ctx.createLinearGradient(0, 0, 150, 150); -lineargradient.addColorStop(0, 'white'); -lineargradient.addColorStop(1, 'black'); +lineargradient.addColorStop(0, "white"); +lineargradient.addColorStop(1, "black"); ``` ### A `createLinearGradient` example @@ -506,18 +516,18 @@ In this example, we'll create two different gradients. As you can see here, both ```js function draw() { - const ctx = document.getElementById('canvas').getContext('2d'); + const ctx = document.getElementById("canvas").getContext("2d"); // Create gradients const 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'); + lingrad.addColorStop(0, "#00ABEB"); + lingrad.addColorStop(0.5, "#fff"); + lingrad.addColorStop(0.5, "#26C000"); + lingrad.addColorStop(1, "#fff"); const lingrad2 = ctx.createLinearGradient(0, 50, 0, 95); - lingrad2.addColorStop(0.5, '#000'); - lingrad2.addColorStop(1, 'rgba(0, 0, 0, 0)'); + lingrad2.addColorStop(0.5, "#000"); + lingrad2.addColorStop(1, "rgba(0, 0, 0, 0)"); // assign gradients to fill and stroke styles ctx.fillStyle = lingrad; @@ -526,7 +536,6 @@ function draw() { // draw shapes ctx.fillRect(10, 10, 130, 130); ctx.strokeRect(50, 50, 50, 50); - } ``` @@ -550,28 +559,28 @@ In this example, we'll define four different radial gradients. Because we have c ```js function draw() { - const ctx = document.getElementById('canvas').getContext('2d'); + const ctx = document.getElementById("canvas").getContext("2d"); // Create gradients const 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)'); + radgrad.addColorStop(0, "#A7D30C"); + radgrad.addColorStop(0.9, "#019F62"); + radgrad.addColorStop(1, "rgba(1, 159, 98, 0)"); const 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)'); + radgrad2.addColorStop(0, "#FF5F98"); + radgrad2.addColorStop(0.75, "#FF0188"); + radgrad2.addColorStop(1, "rgba(255, 1, 136, 0)"); const 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)'); + radgrad3.addColorStop(0, "#00C9FF"); + radgrad3.addColorStop(0.8, "#00B5E2"); + radgrad3.addColorStop(1, "rgba(0, 201, 255, 0)"); const 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)'); + radgrad4.addColorStop(0, "#F4F201"); + radgrad4.addColorStop(0.8, "#E4C700"); + radgrad4.addColorStop(1, "rgba(228, 199, 0, 0)"); // draw shapes ctx.fillStyle = radgrad4; @@ -605,23 +614,23 @@ In this example, we'll define two different conic gradients. A conic gradient di ```js function draw() { - const ctx = document.getElementById('canvas').getContext('2d'); + const ctx = document.getElementById("canvas").getContext("2d"); // Create gradients const conicGrad1 = ctx.createConicGradient(2, 62, 75); - conicGrad1.addColorStop(0, '#A7D30C'); - conicGrad1.addColorStop(1, '#fff'); + conicGrad1.addColorStop(0, "#A7D30C"); + conicGrad1.addColorStop(1, "#fff"); const conicGrad2 = ctx.createConicGradient(0, 187, 75); // we multiply our values by Math.PI/180 to convert degrees to radians - conicGrad2.addColorStop(0, 'black'); - conicGrad2.addColorStop(0.25, 'black'); - conicGrad2.addColorStop(0.25, 'white'); - conicGrad2.addColorStop(0.5, 'white'); - conicGrad2.addColorStop(0.5, 'black'); - conicGrad2.addColorStop(0.75, 'black'); - conicGrad2.addColorStop(0.75, 'white'); - conicGrad2.addColorStop(1, 'white'); + conicGrad2.addColorStop(0, "black"); + conicGrad2.addColorStop(0.25, "black"); + conicGrad2.addColorStop(0.25, "white"); + conicGrad2.addColorStop(0.5, "white"); + conicGrad2.addColorStop(0.5, "black"); + conicGrad2.addColorStop(0.75, "black"); + conicGrad2.addColorStop(0.75, "white"); + conicGrad2.addColorStop(1, "white"); // draw shapes ctx.fillStyle = conicGrad1; @@ -632,7 +641,9 @@ function draw() { ``` ```html hidden -A conic gradient +A conic gradient ``` ```js hidden @@ -667,8 +678,8 @@ We use this method to create a {{domxref("CanvasPattern")}} object which is very ```js const img = new Image(); -img.src = 'someimage.png'; -const ptrn = ctx.createPattern(img, 'repeat'); +img.src = "someimage.png"; +const ptrn = ctx.createPattern(img, "repeat"); ``` > **Note:** Like with the `drawImage()` method, you must make sure the image you use is loaded before calling this method or the pattern may be drawn incorrectly. @@ -679,19 +690,17 @@ In this last example, we'll create a pattern to assign to the `fillStyle` proper ```js function draw() { - const ctx = document.getElementById('canvas').getContext('2d'); + const ctx = document.getElementById("canvas").getContext("2d"); // create new image object to use as pattern const img = new Image(); - img.src = 'canvas_createpattern.png'; + img.src = "canvas_createpattern.png"; img.onload = () => { - // create pattern - const ptrn = ctx.createPattern(img, 'repeat'); + const ptrn = ctx.createPattern(img, "repeat"); ctx.fillStyle = ptrn; ctx.fillRect(0, 0, 150, 150); - - } + }; } ``` @@ -732,16 +741,16 @@ This example draws a text string with a shadowing effect. ```js function draw() { - const ctx = document.getElementById('canvas').getContext('2d'); + const ctx = document.getElementById("canvas").getContext("2d"); ctx.shadowOffsetX = 2; ctx.shadowOffsetY = 2; ctx.shadowBlur = 2; - ctx.shadowColor = 'rgba(0, 0, 0, 0.5)'; + ctx.shadowColor = "rgba(0, 0, 0, 0.5)"; - ctx.font = '20px Times New Roman'; - ctx.fillStyle = 'Black'; - ctx.fillText('Sample String', 5, 30); + ctx.font = "20px Times New Roman"; + ctx.fillStyle = "Black"; + ctx.fillText("Sample String", 5, 30); } ``` @@ -772,11 +781,11 @@ In this example we are using the `evenodd` rule. ```js function draw() { - const ctx = document.getElementById('canvas').getContext('2d'); + const 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'); + ctx.fill("evenodd"); } ``` diff --git a/files/en-us/web/api/canvas_api/tutorial/basic_animations/index.md b/files/en-us/web/api/canvas_api/tutorial/basic_animations/index.md index 845a10074d7efee..b8538a209f57c2d 100644 --- a/files/en-us/web/api/canvas_api/tutorial/basic_animations/index.md +++ b/files/en-us/web/api/canvas_api/tutorial/basic_animations/index.md @@ -10,7 +10,7 @@ tags: - Tutorial --- -{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Compositing", "Web/API/Canvas_API/Tutorial/Advanced_animations")}} +{{DefaultAPISidebar("Canvas API")}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Compositing", "Web/API/Canvas_API/Tutorial/Advanced_animations")}} Since we're using JavaScript to control {{HTMLElement("canvas")}} elements, it's also very easy to make (interactive) animations. In this chapter we will take a look at how to do some basic animations. @@ -67,33 +67,39 @@ const sun = new Image(); const moon = new Image(); const earth = new Image(); function init() { - sun.src = 'canvas_sun.png'; - moon.src = 'canvas_moon.png'; - earth.src = 'canvas_earth.png'; + sun.src = "canvas_sun.png"; + moon.src = "canvas_moon.png"; + earth.src = "canvas_earth.png"; window.requestAnimationFrame(draw); } function draw() { - const ctx = document.getElementById('canvas').getContext('2d'); + const ctx = document.getElementById("canvas").getContext("2d"); - ctx.globalCompositeOperation = 'destination-over'; + ctx.globalCompositeOperation = "destination-over"; ctx.clearRect(0, 0, 300, 300); // clear canvas - ctx.fillStyle = 'rgba(0, 0, 0, 0.4)'; - ctx.strokeStyle = 'rgba(0, 153, 255, 0.4)'; + ctx.fillStyle = "rgba(0, 0, 0, 0.4)"; + ctx.strokeStyle = "rgba(0, 153, 255, 0.4)"; ctx.save(); ctx.translate(150, 150); // Earth const time = new Date(); - ctx.rotate(((2 * Math.PI) / 60) * time.getSeconds() + ((2 * Math.PI) / 60000) * time.getMilliseconds()); + ctx.rotate( + ((2 * Math.PI) / 60) * time.getSeconds() + + ((2 * Math.PI) / 60000) * time.getMilliseconds() + ); ctx.translate(105, 0); ctx.fillRect(0, -12, 40, 24); // Shadow ctx.drawImage(earth, -12, -12); // Moon ctx.save(); - ctx.rotate(((2 * Math.PI) / 6) * time.getSeconds() + ((2 * Math.PI) / 6000) * time.getMilliseconds()); + 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(); @@ -131,17 +137,17 @@ This example draws an animated clock, showing your current time. ```js function clock() { const now = new Date(); - const canvas = document.getElementById('canvas'); - const ctx = canvas.getContext('2d'); + const canvas = document.getElementById("canvas"); + const ctx = 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.strokeStyle = "black"; + ctx.fillStyle = "white"; ctx.lineWidth = 8; - ctx.lineCap = 'round'; + ctx.lineCap = "round"; // Hour marks ctx.save(); @@ -170,16 +176,18 @@ function clock() { const sec = now.getSeconds(); const min = now.getMinutes(); - const hr = now.getHours() % 12; + const hr = now.getHours() % 12; - ctx.fillStyle = 'black'; + ctx.fillStyle = "black"; // Write image description - canvas.innerText = `The time is: ${hr}:${min}`; + canvas.innerText = `The time is: ${hr}:${min}`; // Write Hours ctx.save(); - ctx.rotate((Math.PI / 6) * hr + (Math.PI / 360) * min + (Math.PI / 21600) * sec); + ctx.rotate( + (Math.PI / 6) * hr + (Math.PI / 360) * min + (Math.PI / 21600) * sec + ); ctx.lineWidth = 14; ctx.beginPath(); ctx.moveTo(-20, 0); @@ -199,9 +207,9 @@ function clock() { // Write seconds ctx.save(); - ctx.rotate(sec * Math.PI / 30); - ctx.strokeStyle = '#D40000'; - ctx.fillStyle = '#D40000'; + ctx.rotate((sec * Math.PI) / 30); + ctx.strokeStyle = "#D40000"; + ctx.fillStyle = "#D40000"; ctx.lineWidth = 6; ctx.beginPath(); ctx.moveTo(-30, 0); @@ -213,14 +221,14 @@ function clock() { ctx.beginPath(); ctx.arc(95, 0, 10, 0, Math.PI * 2, true); ctx.stroke(); - ctx.fillStyle = 'rgba(0, 0, 0, 0)'; + 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.strokeStyle = "#325FA2"; ctx.arc(0, 0, 142, 0, Math.PI * 2, true); ctx.stroke(); @@ -245,7 +253,9 @@ In this example, a panorama is scrolled left-to-right. We're using [an image of The HTML includes the {{HTMLElement("canvas")}} in which the image is scrolled. Note that the width and height specified here must match the values of the `canvasXSize` and `canvasYSize` variables in the JavaScript code. ```html -Yosemite National Park, meadow at the base of El Capitan +Yosemite National Park, meadow at the base of El Capitan ``` ### JavaScript @@ -255,7 +265,7 @@ const img = new Image(); // User Variables - customize these to change the image being scrolled, its // direction, and the speed. -img.src = 'capitan_meadows_yosemite_national_park.jpg'; +img.src = "capitan_meadows_yosemite_national_park.jpg"; const canvasXSize = 800; const canvasYSize = 200; const speed = 30; // lower is faster @@ -285,11 +295,11 @@ img.onload = () => { clearY = Math.max(imgH, canvasYSize); // Get canvas context - ctx = document.getElementById('canvas').getContext('2d'); + ctx = document.getElementById("canvas").getContext("2d"); // Set refresh rate return setInterval(draw, speed); -} +}; function draw() { ctx.clearRect(0, 0, clearX, clearY); // clear the canvas @@ -340,7 +350,10 @@ function draw() { ### HTML ```html -Animation creating multi-colored disappearing stream of light that follow the cursor as it moves over the image +Animation creating multi-colored disappearing stream of light that follow the + cursor as it moves over the image + ``` ### CSS diff --git a/files/en-us/web/api/canvas_api/tutorial/basic_usage/index.md b/files/en-us/web/api/canvas_api/tutorial/basic_usage/index.md index 5e690b733a07afc..869716a6337247a 100644 --- a/files/en-us/web/api/canvas_api/tutorial/basic_usage/index.md +++ b/files/en-us/web/api/canvas_api/tutorial/basic_usage/index.md @@ -10,7 +10,7 @@ tags: - Tutorial --- -{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial", "Web/API/Canvas_API/Tutorial/Drawing_shapes")}} +{{DefaultAPISidebar("Canvas API")}} {{PreviousNext("Web/API/Canvas_API/Tutorial", "Web/API/Canvas_API/Tutorial/Drawing_shapes")}} Let's start this tutorial by looking at the {{HTMLElement("canvas")}} {{Glossary("HTML")}} element itself. At the end of this page, you will know how to set up a canvas 2D context and have drawn a first example in your browser. @@ -61,8 +61,8 @@ The {{HTMLElement("canvas")}} element creates a fixed-size drawing surface that The canvas is initially blank. To display something, a script first needs to access the rendering context and draw on it. The {{HTMLElement("canvas")}} element has a method called {{domxref("HTMLCanvasElement.getContext", "getContext()")}}, used to obtain the rendering context and its drawing functions. `getContext()` takes one parameter, the type of context. For 2D graphics, such as those covered by this tutorial, you specify `"2d"` to get a {{domxref("CanvasRenderingContext2D")}}. ```js -const canvas = document.getElementById('tutorial'); -const ctx = canvas.getContext('2d'); +const canvas = document.getElementById("tutorial"); +const ctx = canvas.getContext("2d"); ``` The first line in the script retrieves the node in the DOM representing the {{HTMLElement("canvas")}} element by calling the {{domxref("document.getElementById()")}} method. Once you have the element node, you can access the drawing context using its `getContext()` method. @@ -72,10 +72,10 @@ The first line in the script retrieves the node in the DOM representing the {{HT The fallback content is displayed in browsers which do not support {{HTMLElement("canvas")}}. Scripts can also check for support programmatically by testing for the presence of the `getContext()` method. Our code snippet from above becomes something like this: ```js -const canvas = document.getElementById('tutorial'); +const canvas = document.getElementById("tutorial"); if (canvas.getContext) { - const ctx = canvas.getContext('2d'); + const ctx = canvas.getContext("2d"); // drawing code here } else { // canvas-unsupported code here diff --git a/files/en-us/web/api/canvas_api/tutorial/compositing/example/index.md b/files/en-us/web/api/canvas_api/tutorial/compositing/example/index.md index 5611a329ed405e1..c60ff5093babead 100644 --- a/files/en-us/web/api/canvas_api/tutorial/compositing/example/index.md +++ b/files/en-us/web/api/canvas_api/tutorial/compositing/example/index.md @@ -10,7 +10,7 @@ tags: - Tutorial --- -{{CanvasSidebar}} +{{DefaultAPISidebar("Canvas API")}} This sample program demonstrates a number of [compositing operations](/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation). The output looks like this: @@ -23,40 +23,62 @@ This code sets up the global values used by the rest of the program. ```js const canvas1 = document.createElement("canvas"); const canvas2 = document.createElement("canvas"); -const 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(); +const 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(); const gcoText = [ -'This is the default setting and draws new shapes on top of the existing canvas content.', -'The new shape is drawn only where both the new shape and the destination canvas overlap. Everything else is made transparent.', -'The new shape is drawn where it doesn\'t overlap the existing canvas content.', -'The new shape is only drawn where it overlaps the existing canvas content.', -'New shapes are drawn behind the existing canvas content.', -'The existing canvas content is kept where both the new shape and existing canvas content overlap. Everything else is made transparent.', -'The existing content is kept where it doesn\'t overlap the new shape.', -'The existing canvas is only kept where it overlaps the new shape. The new shape is drawn behind the canvas content.', -'Where both shapes overlap the color is determined by adding color values.', -'Only the new shape is shown.', -'Shapes are made transparent where both overlap and drawn normal everywhere else.', -'The pixels of the top layer are multiplied with the corresponding pixel of the bottom layer. A darker picture is the result.', -'The pixels are inverted, multiplied, and inverted again. A lighter picture is the result (opposite of multiply)', -'A combination of multiply and screen. Dark parts on the base layer become darker, and light parts become lighter.', -'Retains the darkest pixels of both layers.', -'Retains the lightest pixels of both layers.', -'Divides the bottom layer by the inverted top layer.', -'Divides the inverted bottom layer by the top layer, and then inverts the result.', -'A combination of multiply and screen like overlay, but with top and bottom layer swapped.', -'A softer version of hard-light. Pure black or white does not result in pure black or white.', -'Subtracts the bottom layer from the top layer or the other way round to always get a positive value.', -'Like difference, but with lower contrast.', -'Preserves the luma and chroma of the bottom layer, while adopting the hue of the top layer.', -'Preserves the luma and hue of the bottom layer, while adopting the chroma of the top layer.', -'Preserves the luma of the bottom layer, while adopting the hue and chroma of the top layer.', -'Preserves the hue and chroma of the bottom layer, while adopting the luma of the top layer.' - ].reverse(); + "This is the default setting and draws new shapes on top of the existing canvas content.", + "The new shape is drawn only where both the new shape and the destination canvas overlap. Everything else is made transparent.", + "The new shape is drawn where it doesn't overlap the existing canvas content.", + "The new shape is only drawn where it overlaps the existing canvas content.", + "New shapes are drawn behind the existing canvas content.", + "The existing canvas content is kept where both the new shape and existing canvas content overlap. Everything else is made transparent.", + "The existing content is kept where it doesn't overlap the new shape.", + "The existing canvas is only kept where it overlaps the new shape. The new shape is drawn behind the canvas content.", + "Where both shapes overlap the color is determined by adding color values.", + "Only the new shape is shown.", + "Shapes are made transparent where both overlap and drawn normal everywhere else.", + "The pixels of the top layer are multiplied with the corresponding pixel of the bottom layer. A darker picture is the result.", + "The pixels are inverted, multiplied, and inverted again. A lighter picture is the result (opposite of multiply)", + "A combination of multiply and screen. Dark parts on the base layer become darker, and light parts become lighter.", + "Retains the darkest pixels of both layers.", + "Retains the lightest pixels of both layers.", + "Divides the bottom layer by the inverted top layer.", + "Divides the inverted bottom layer by the top layer, and then inverts the result.", + "A combination of multiply and screen like overlay, but with top and bottom layer swapped.", + "A softer version of hard-light. Pure black or white does not result in pure black or white.", + "Subtracts the bottom layer from the top layer or the other way round to always get a positive value.", + "Like difference, but with lower contrast.", + "Preserves the luma and chroma of the bottom layer, while adopting the hue of the top layer.", + "Preserves the luma and hue of the bottom layer, while adopting the chroma of the top layer.", + "Preserves the luma of the bottom layer, while adopting the hue and chroma of the top layer.", + "Preserves the hue and chroma of the bottom layer, while adopting the luma of the top layer.", +].reverse(); const width = 320; const height = 340; ``` @@ -67,21 +89,21 @@ When the page loads, this code runs to set up and run the example: ```js window.onload = () => { - // lum in sRGB - const lum = { - r: 0.33, - g: 0.33, - b: 0.33 - }; - // resize canvas - canvas1.width = width; - canvas1.height = height; - canvas2.width = width; - canvas2.height = height; - lightMix() - colorSphere(); - runComposite(); - return; + // lum in sRGB + const lum = { + r: 0.33, + g: 0.33, + b: 0.33, + }; + // resize canvas + canvas1.width = width; + canvas1.height = height; + canvas2.width = width; + canvas2.height = height; + lightMix(); + colorSphere(); + runComposite(); + return; }; ``` @@ -89,75 +111,75 @@ And this code, `runComposite()`, handles the bulk of the work, relying on a numb ```js function createCanvas() { - const 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; + const 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() { - const dl = document.createElement("dl"); - document.body.appendChild(dl); - while(gco.length) { - const pop = gco.pop(); - const dt = document.createElement("dt"); - dt.textContent = pop; - dl.appendChild(dt); - const dd = document.createElement("dd"); - const p = document.createElement("p"); - p.textContent = gcoText.pop(); - dd.appendChild(p); + const dl = document.createElement("dl"); + document.body.appendChild(dl); + while (gco.length) { + const pop = gco.pop(); + const dt = document.createElement("dt"); + dt.textContent = pop; + dl.appendChild(dt); + const dd = document.createElement("dd"); + const p = document.createElement("p"); + p.textContent = gcoText.pop(); + dd.appendChild(p); - const canvasToDrawOn = createCanvas(); - const canvasToDrawFrom = createCanvas(); - const canvasToDrawResult = createCanvas(); + const canvasToDrawOn = createCanvas(); + const canvasToDrawFrom = createCanvas(); + const canvasToDrawResult = createCanvas(); - let 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(); + let 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(); - 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('existing content', 5, height/2 - 5); - ctx.restore(); + 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("existing content", 5, height / 2 - 5); + ctx.restore(); - 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('new content', 5, height/2 - 5); - ctx.restore(); + 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("new content", 5, height / 2 - 5); + ctx.restore(); - dd.appendChild(canvasToDrawOn); - dd.appendChild(canvasToDrawFrom); - dd.appendChild(canvasToDrawResult); + dd.appendChild(canvasToDrawOn); + dd.appendChild(canvasToDrawFrom); + dd.appendChild(canvasToDrawResult); - dl.appendChild(dd); - } -}; + dl.appendChild(dd); + } +} ``` ### Utility functions @@ -166,59 +188,64 @@ The program relies on a number of utility functions. ```js const lightMix = () => { - const 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(); + const 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(); }; ``` ```js const colorSphere = (element) => { - const ctx = canvas1.getContext("2d"); - const width = 360; - const halfWidth = width / 2; - const rotate = (1 / 360) * Math.PI * 2; // per degree - const offset = 0; // scrollbar offset - const oleft = -20; - const otop = -20; - for (let n = 0; n <= 359; n ++) { - const gradient = ctx.createLinearGradient(oleft + halfWidth, otop, oleft + halfWidth, otop + halfWidth); - const 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)); - } + const ctx = canvas1.getContext("2d"); + const width = 360; + const halfWidth = width / 2; + const rotate = (1 / 360) * Math.PI * 2; // per degree + const offset = 0; // scrollbar offset + const oleft = -20; + const otop = -20; + for (let n = 0; n <= 359; n++) { + const gradient = ctx.createLinearGradient( + oleft + halfWidth, + otop, + oleft + halfWidth, + otop + halfWidth + ); + const 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.fillStyle = "#00f"; - ctx.fillRect(15,15,30,30) + ctx.moveTo(oleft + halfWidth, otop); + ctx.lineTo(oleft + halfWidth, otop + halfWidth); + ctx.lineTo(oleft + halfWidth + 6, otop); + ctx.fillStyle = gradient; ctx.fill(); - return ctx.canvas; + 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; }; ``` @@ -226,72 +253,72 @@ const colorSphere = (element) => { // HSV (1978) = H: Hue / S: Saturation / V: Value Color = {}; Color.HSV_RGB = (o) => { - const S = o.S / 100; - let H = o.H / 360, - V = o.V / 100; - let R, G; - let A, B, C, D; - if (S === 0) { - R = G = B = Math.round(V * 255); - } else { - if (H >= 1) H = 0; - H *= 6; - 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; - } + const S = o.S / 100; + let H = o.H / 360, + V = o.V / 100; + let R, G; + let A, B, C, D; + if (S === 0) { + R = G = B = Math.round(V * 255); + } else { + if (H >= 1) H = 0; + H *= 6; + 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, G, B }; + } + return { R, G, B }; }; const createInterlace = (size, color1, color2) => { - const 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); - const pattern = proto.createPattern(proto.canvas, "repeat"); - pattern.data = proto.canvas.toDataURL(); - return pattern; + const 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); + const pattern = proto.createPattern(proto.canvas, "repeat"); + pattern.data = proto.canvas.toDataURL(); + return pattern; }; const op_8x8 = createInterlace(8, "#FFF", "#eee"); diff --git a/files/en-us/web/api/canvas_api/tutorial/compositing/index.md b/files/en-us/web/api/canvas_api/tutorial/compositing/index.md index 069b659fca2b559..aa6383e2cbe0648 100644 --- a/files/en-us/web/api/canvas_api/tutorial/compositing/index.md +++ b/files/en-us/web/api/canvas_api/tutorial/compositing/index.md @@ -10,7 +10,7 @@ tags: - Tutorial --- -{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Transformations", "Web/API/Canvas_API/Tutorial/Basic_animations")}} +{{DefaultAPISidebar("Canvas API")}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Transformations", "Web/API/Canvas_API/Tutorial/Basic_animations")}} In all of our [previous examples](/en-US/docs/Web/API/Canvas_API/Tutorial/Transformations), shapes were always drawn one on top of the other. This is more than adequate for most situations, but it limits the order in which composite shapes are built. We can, however, change this behavior by setting the `globalCompositeOperation` property. In addition, the `clip` property allows us to hide unwanted parts of shapes. @@ -48,7 +48,7 @@ In this example, we'll use a circular clipping path to restrict the drawing of a ```js function draw() { - const ctx = document.getElementById('canvas').getContext('2d'); + const ctx = document.getElementById("canvas").getContext("2d"); ctx.fillRect(0, 0, 150, 150); ctx.translate(75, 75); @@ -59,8 +59,8 @@ function draw() { // draw background const lingrad = ctx.createLinearGradient(0, -75, 0, 75); - lingrad.addColorStop(0, '#232256'); - lingrad.addColorStop(1, '#143778'); + lingrad.addColorStop(0, "#232256"); + lingrad.addColorStop(1, "#143778"); ctx.fillStyle = lingrad; ctx.fillRect(-75, -75, 150, 150); @@ -68,13 +68,14 @@ function draw() { // draw stars for (let j = 1; j < 50; j++) { ctx.save(); - ctx.fillStyle = '#fff'; - ctx.translate(75 - Math.floor(Math.random() * 150), - 75 - Math.floor(Math.random() * 150)); + 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) { diff --git a/files/en-us/web/api/canvas_api/tutorial/drawing_shapes/index.md b/files/en-us/web/api/canvas_api/tutorial/drawing_shapes/index.md index 1b80f3813c0492e..8ce94cb095dc16f 100644 --- a/files/en-us/web/api/canvas_api/tutorial/drawing_shapes/index.md +++ b/files/en-us/web/api/canvas_api/tutorial/drawing_shapes/index.md @@ -11,7 +11,7 @@ tags: - Tutorial --- -{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Basic_usage", "Web/API/Canvas_API/Tutorial/Applying_styles_and_colors")}} +{{DefaultAPISidebar("Canvas API")}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Basic_usage", "Web/API/Canvas_API/Tutorial/Applying_styles_and_colors")}} Now that we have set up our [canvas environment](/en-US/docs/Web/API/Canvas_API/Tutorial/Basic_usage), we can get into the details of how to draw on the canvas. By the end of this article, you will have learned how to draw rectangles, triangles, lines, arcs and curves, providing familiarity with some of the basic shapes. Working with paths is essential when drawing objects onto the canvas and we will see how that can be done. @@ -52,9 +52,9 @@ Below is the `draw()` function from the previous page, but now it is making use ```js function draw() { - const canvas = document.getElementById('canvas'); + const canvas = document.getElementById("canvas"); if (canvas.getContext) { - const ctx = canvas.getContext('2d'); + const ctx = canvas.getContext("2d"); ctx.fillRect(25, 25, 100, 100); ctx.clearRect(45, 45, 60, 60); @@ -118,9 +118,9 @@ For example, the code for drawing a triangle would look something like this: ```js function draw() { - const canvas = document.getElementById('canvas'); + const canvas = document.getElementById("canvas"); if (canvas.getContext) { - const ctx = canvas.getContext('2d'); + const ctx = canvas.getContext("2d"); ctx.beginPath(); ctx.moveTo(75, 50); @@ -202,9 +202,9 @@ The example below draws two triangles, one filled and one outlined. ```js function draw() { - const canvas = document.getElementById('canvas'); + const canvas = document.getElementById("canvas"); if (canvas.getContext) { - const ctx = canvas.getContext('2d'); + const ctx = canvas.getContext("2d"); // Filled triangle ctx.beginPath(); @@ -263,9 +263,9 @@ The statement for the `clockwise` parameter results in the first and third row b ```js function draw() { - const canvas = document.getElementById('canvas'); + const canvas = document.getElementById("canvas"); if (canvas.getContext) { - const ctx = canvas.getContext('2d'); + const ctx = canvas.getContext("2d"); for (let i = 0; i < 4; i++) { for (let j = 0; j < 3; j++) { @@ -324,9 +324,9 @@ This example uses multiple quadratic Bézier curves to render a speech balloon. ```js function draw() { - const canvas = document.getElementById('canvas'); + const canvas = document.getElementById("canvas"); if (canvas.getContext) { - const ctx = canvas.getContext('2d'); + const ctx = canvas.getContext("2d"); // Quadratic curves example ctx.beginPath(); @@ -358,9 +358,9 @@ This example draws a heart using cubic Bézier curves. ```js function draw() { - const canvas = document.getElementById('canvas'); + const canvas = document.getElementById("canvas"); if (canvas.getContext) { - const ctx = canvas.getContext('2d'); + const ctx = canvas.getContext("2d"); // Cubic curves example ctx.beginPath(); @@ -401,9 +401,9 @@ So far, each example on this page has used only one type of path function per sh ```js function draw() { - const canvas = document.getElementById('canvas'); + const canvas = document.getElementById("canvas"); if (canvas.getContext) { - const ctx = canvas.getContext('2d'); + const ctx = canvas.getContext("2d"); roundedRect(ctx, 12, 12, 150, 150, 15); roundedRect(ctx, 19, 19, 150, 150, 9); @@ -443,7 +443,7 @@ function draw() { ctx.lineTo(83, 116); ctx.fill(); - ctx.fillStyle = 'white'; + ctx.fillStyle = "white"; ctx.beginPath(); ctx.moveTo(91, 96); ctx.bezierCurveTo(88, 96, 87, 99, 87, 101); @@ -457,7 +457,7 @@ function draw() { ctx.bezierCurveTo(107, 99, 106, 96, 103, 96); ctx.fill(); - ctx.fillStyle = 'black'; + ctx.fillStyle = "black"; ctx.beginPath(); ctx.arc(101, 102, 2, 0, Math.PI * 2, true); ctx.fill(); @@ -498,9 +498,9 @@ Let's see how we can construct a `Path2D` object: - : The **`Path2D()`** constructor returns a newly instantiated `Path2D` object, optionally with another path as an argument (creates a copy), or optionally with a string consisting of [SVG path](/en-US/docs/Web/SVG/Tutorial/Paths) data. ```js -new Path2D(); // empty path object +new Path2D(); // empty path object new Path2D(path); // copy from another Path2D object -new Path2D(d); // path from SVG path data +new Path2D(d); // path from SVG path data ``` All [path methods](/en-US/docs/Web/API/CanvasRenderingContext2D#paths) like `moveTo`, `rect`, `arc` or `quadraticCurveTo`, etc., which we got to know above, are available on `Path2D` objects. @@ -524,9 +524,9 @@ In this example, we are creating a rectangle and a circle. Both are stored as a ```js function draw() { - const canvas = document.getElementById('canvas'); + const canvas = document.getElementById("canvas"); if (canvas.getContext) { - const ctx = canvas.getContext('2d'); + const ctx = canvas.getContext("2d"); const rectangle = new Path2D(); rectangle.rect(10, 10, 50, 50); @@ -549,7 +549,7 @@ Another powerful feature of the new canvas `Path2D` API is using [SVG path data] The path will move to point (`M10 10`) and then move horizontally 80 points to the right (`h 80`), then 80 points down (`v 80`), then 80 points to the left (`h -80`), and then back to the start (`z`). You can see this example on the [`Path2D` constructor](/en-US/docs/Web/API/Path2D/Path2D#using_svg_paths) page. ```js -const p = new Path2D('M10 10 h 80 v 80 h -80 Z'); +const p = new Path2D("M10 10 h 80 v 80 h -80 Z"); ``` {{PreviousNext("Web/API/Canvas_API/Tutorial/Basic_usage", "Web/API/Canvas_API/Tutorial/Applying_styles_and_colors")}} diff --git a/files/en-us/web/api/canvas_api/tutorial/drawing_text/index.md b/files/en-us/web/api/canvas_api/tutorial/drawing_text/index.md index 240c549d22e4507..b217c28de9c56f2 100644 --- a/files/en-us/web/api/canvas_api/tutorial/drawing_text/index.md +++ b/files/en-us/web/api/canvas_api/tutorial/drawing_text/index.md @@ -9,7 +9,7 @@ tags: - Tutorial --- -{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Applying_styles_and_colors", "Web/API/Canvas_API/Tutorial/Using_images")}} +{{DefaultAPISidebar("Canvas API")}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Applying_styles_and_colors", "Web/API/Canvas_API/Tutorial/Using_images")}} After having seen how to [apply styles and colors](/en-US/docs/Web/API/Canvas_API/Tutorial/Applying_styles_and_colors) in the previous chapter, we will now have a look at how to draw text onto the canvas. @@ -28,9 +28,9 @@ The text is filled using the current `fillStyle`. ```js function draw() { - const ctx = document.getElementById('canvas').getContext('2d'); - ctx.font = '48px serif'; - ctx.fillText('Hello world', 10, 50); + const ctx = document.getElementById("canvas").getContext("2d"); + ctx.font = "48px serif"; + ctx.fillText("Hello world", 10, 50); } ``` @@ -50,9 +50,9 @@ The text is filled using the current `strokeStyle`. ```js function draw() { - const ctx = document.getElementById('canvas').getContext('2d'); - ctx.font = '48px serif'; - ctx.strokeText('Hello world', 10, 50); + const ctx = document.getElementById("canvas").getContext("2d"); + ctx.font = "48px serif"; + ctx.strokeText("Hello world", 10, 50); } ``` @@ -110,11 +110,11 @@ ctx.strokeText("Hello world", 0, 100); ``` ```js hidden -const canvas = document.getElementById('canvas'); -const ctx = canvas.getContext('2d'); -const textarea = document.getElementById('code'); -const reset = document.getElementById('reset'); -const edit = document.getElementById('edit'); +const canvas = document.getElementById("canvas"); +const ctx = canvas.getContext("2d"); +const textarea = document.getElementById("code"); +const reset = document.getElementById("reset"); +const edit = document.getElementById("edit"); const code = textarea.value; function drawCanvas() { @@ -122,17 +122,17 @@ function drawCanvas() { eval(textarea.value); } -reset.addEventListener('click', () => { +reset.addEventListener("click", () => { textarea.value = code; drawCanvas(); }); -edit.addEventListener('click', () => { +edit.addEventListener("click", () => { textarea.focus(); -}) +}); -textarea.addEventListener('input', drawCanvas); -window.addEventListener('load', drawCanvas); +textarea.addEventListener("input", drawCanvas); +window.addEventListener("load", drawCanvas); ``` {{ EmbedLiveSample('A_textBaseline_example', 700, 400) }} @@ -148,8 +148,8 @@ The following code snippet shows how you can measure a text and get its width. ```js function draw() { - const ctx = document.getElementById('canvas').getContext('2d'); - const text = ctx.measureText('foo'); // TextMetrics object + const ctx = document.getElementById("canvas").getContext("2d"); + const text = ctx.measureText("foo"); // TextMetrics object text.width; // 16; } ``` diff --git a/files/en-us/web/api/canvas_api/tutorial/finale/index.md b/files/en-us/web/api/canvas_api/tutorial/finale/index.md index b38045d2e6c7cd8..75b8fabfaffe385 100644 --- a/files/en-us/web/api/canvas_api/tutorial/finale/index.md +++ b/files/en-us/web/api/canvas_api/tutorial/finale/index.md @@ -8,7 +8,7 @@ tags: - Tutorial --- -{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Optimizing_canvas")}} +{{DefaultAPISidebar("Canvas API")}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Optimizing_canvas")}} Congratulations! You finished the [Canvas tutorial](/en-US/docs/Web/API/Canvas_API/Tutorial)! This knowledge will help you to make great 2D graphics on the web. diff --git a/files/en-us/web/api/canvas_api/tutorial/index.md b/files/en-us/web/api/canvas_api/tutorial/index.md index dbddb35213163f9..9ab31891c0b6646 100644 --- a/files/en-us/web/api/canvas_api/tutorial/index.md +++ b/files/en-us/web/api/canvas_api/tutorial/index.md @@ -11,7 +11,7 @@ tags: - Web --- -{{CanvasSidebar}} +{{DefaultAPISidebar("Canvas API")}} This tutorial describes how to use the [**``**](/en-US/docs/Web/HTML/Element/canvas) element to draw 2D graphics, starting with the basics. The examples provided should give you some clear ideas about what you can do with canvas, and will provide code snippets that may get you started in building your own content. diff --git a/files/en-us/web/api/canvas_api/tutorial/optimizing_canvas/index.md b/files/en-us/web/api/canvas_api/tutorial/optimizing_canvas/index.md index 317b5b59fb1414a..3dc8f50964d1031 100644 --- a/files/en-us/web/api/canvas_api/tutorial/optimizing_canvas/index.md +++ b/files/en-us/web/api/canvas_api/tutorial/optimizing_canvas/index.md @@ -10,7 +10,7 @@ tags: - Tutorial --- -{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Pixel_manipulation_with_canvas", "Web/API/Canvas_API/Tutorial/Finale")}} +{{DefaultAPISidebar("Canvas API")}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Pixel_manipulation_with_canvas", "Web/API/Canvas_API/Tutorial/Finale")}} The {{HTMLElement("canvas")}} element is one of the most widely used tools for rendering 2D graphics on the web. However, when websites and apps push the Canvas API to its limits, performance begins to suffer. This article provides suggestions for optimizing your use of the canvas element to ensure that your graphics perform well. @@ -23,11 +23,11 @@ The following is a collection of tips to improve canvas performance. If you find yourself repeating some of the same drawing operations on each animation frame, consider offloading them to an offscreen canvas. You can then render the offscreen image to your primary canvas as often as needed, without unnecessarily repeating the steps needed to generate it in the first place. ```js -myCanvas.offscreenCanvas = document.createElement('canvas'); +myCanvas.offscreenCanvas = document.createElement("canvas"); myCanvas.offscreenCanvas.width = myCanvas.width; myCanvas.offscreenCanvas.height = myCanvas.height; -myCanvas.getContext('2d').drawImage(myCanvas.offScreenCanvas, 0, 0); +myCanvas.getContext("2d").drawImage(myCanvas.offScreenCanvas, 0, 0); ``` ### Avoid floating-point coordinates and use integers instead @@ -95,7 +95,7 @@ const scaleY = window.innerHeight / canvas.height; const scaleToFit = Math.min(scaleX, scaleY); const scaleToCover = Math.max(scaleX, scaleY); -stage.style.transformOrigin = '0 0'; //scale from top left +stage.style.transformOrigin = "0 0"; //scale from top left stage.style.transform = `scale(${scaleToFit})`; ``` @@ -104,7 +104,7 @@ stage.style.transform = `scale(${scaleToFit})`; If your application uses canvas and doesn't need a transparent backdrop, set the `alpha` option to `false` when creating a drawing context with {{domxref("HTMLCanvasElement.getContext()")}}. This information can be used internally by the browser to optimize rendering. ```js -const ctx = canvas.getContext('2d', { alpha: false }); +const ctx = canvas.getContext("2d", { alpha: false }); ``` ### Scaling for high resolution displays diff --git a/files/en-us/web/api/canvas_api/tutorial/pixel_manipulation_with_canvas/index.md b/files/en-us/web/api/canvas_api/tutorial/pixel_manipulation_with_canvas/index.md index 933b2f264c1ea43..bea3067085c07d6 100644 --- a/files/en-us/web/api/canvas_api/tutorial/pixel_manipulation_with_canvas/index.md +++ b/files/en-us/web/api/canvas_api/tutorial/pixel_manipulation_with_canvas/index.md @@ -9,7 +9,7 @@ tags: - Tutorial --- -{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Advanced_animations", "Web/API/Canvas_API/Tutorial/Optimizing_canvas")}} +{{DefaultAPISidebar("Canvas API")}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Advanced_animations", "Web/API/Canvas_API/Tutorial/Optimizing_canvas")}} Until now we haven't looked at the actual pixels of our canvas. With the `ImageData` object you can directly read and write a data array to manipulate pixel data. We will also look into how image smoothing (anti-aliasing) can be controlled and how to save images from your canvas. @@ -217,10 +217,17 @@ With the help of the {{domxref("CanvasRenderingContext2D.drawImage", "drawImage( We get the position of the mouse and crop an image of 5 pixels left and above to 5 pixels right and below. Then we copy that one over to another canvas and resize the image to the size we want it to. In the zoom canvas we resize a 10×10 pixel crop of the original canvas to 200×200. ```js -zoomctx.drawImage(canvas, - Math.min(Math.max(0, x - 5), img.width - 10), - Math.min(Math.max(0, y - 5), img.height - 10), - 10, 10, 0, 0, 200, 200); +zoomctx.drawImage( + canvas, + Math.min(Math.max(0, x - 5), img.width - 10), + Math.min(Math.max(0, y - 5), img.height - 10), + 10, + 10, + 0, + 0, + 200, + 200 +); ``` Zoom example: @@ -255,12 +262,17 @@ function draw(img) { pixelatedZoomCtx.msImageSmoothingEnabled = false; const zoom = (ctx, x, y) => { - ctx.drawImage(canvas, - Math.min(Math.max(0, x - 5), img.width - 10), - Math.min(Math.max(0, y - 5), img.height - 10), - 10, 10, - 0, 0, - 200, 200); + ctx.drawImage( + canvas, + Math.min(Math.max(0, x - 5), img.width - 10), + Math.min(Math.max(0, y - 5), img.height - 10), + 10, + 10, + 0, + 0, + 200, + 200 + ); }; canvas.addEventListener("mousemove", (event) => { diff --git a/files/en-us/web/api/canvas_api/tutorial/transformations/index.md b/files/en-us/web/api/canvas_api/tutorial/transformations/index.md index d12d0f81e86a0ba..691f08cfadaaad5 100644 --- a/files/en-us/web/api/canvas_api/tutorial/transformations/index.md +++ b/files/en-us/web/api/canvas_api/tutorial/transformations/index.md @@ -11,7 +11,7 @@ tags: - Web --- -{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Using_images", "Web/API/Canvas_API/Tutorial/Compositing")}} +{{DefaultAPISidebar("Canvas API")}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Using_images", "Web/API/Canvas_API/Tutorial/Compositing")}} Earlier in this tutorial we've learned about the [canvas grid](/en-US/docs/Web/API/Canvas_API/Tutorial/Drawing_shapes) and the **coordinate space**. Until now, we only used the default grid and changed the size of the overall canvas for our needs. With transformations there are more powerful ways to translate the origin to a different position, rotate the grid and even scale it. @@ -56,24 +56,24 @@ This example tries to illustrate how the stack of drawing states functions by dr ```js function draw() { - const ctx = document.getElementById('canvas').getContext('2d'); + const ctx = document.getElementById("canvas").getContext("2d"); - ctx.fillRect(0, 0, 150, 150); // Draw a rectangle with default settings - ctx.save(); // Save the default state + ctx.fillRect(0, 0, 150, 150); // Draw a rectangle with default settings + ctx.save(); // Save the default state - ctx.fillStyle = '#09F'; // Make changes to the settings + ctx.fillStyle = "#09F"; // Make changes to the settings ctx.fillRect(15, 15, 120, 120); // Draw a rectangle with new settings - ctx.save(); // Save the current state - ctx.fillStyle = '#FFF'; // Make changes to the settings + ctx.save(); // Save the current state + ctx.fillStyle = "#FFF"; // Make changes to the settings ctx.globalAlpha = 0.5; - ctx.fillRect(30, 30, 90, 90); // Draw a rectangle with new settings + ctx.fillRect(30, 30, 90, 90); // Draw a rectangle with new settings - ctx.restore(); // Restore previous state - ctx.fillRect(45, 45, 60, 60); // Draw a rectangle with restored settings + ctx.restore(); // Restore previous state + ctx.fillRect(45, 45, 60, 60); // Draw a rectangle with restored settings - ctx.restore(); // Restore original state - ctx.fillRect(60, 60, 30, 30); // Draw a rectangle with restored settings + ctx.restore(); // Restore original state + ctx.fillRect(60, 60, 30, 30); // Draw a rectangle with restored settings } ``` @@ -112,7 +112,7 @@ In the `draw()` function, we call the `fillRect()` function nine times using two ```js function draw() { - const ctx = document.getElementById('canvas').getContext('2d'); + const ctx = document.getElementById("canvas").getContext("2d"); for (let i = 0; i < 3; i++) { for (let j = 0; j < 3; j++) { ctx.save(); @@ -154,32 +154,32 @@ In this example, we'll use the `rotate()` method to first rotate a rectangle fro ```js function draw() { - const ctx = document.getElementById('canvas').getContext('2d'); + const ctx = document.getElementById("canvas").getContext("2d"); // left rectangles, rotate from canvas origin ctx.save(); // blue rect - ctx.fillStyle = '#0095DD'; + ctx.fillStyle = "#0095DD"; ctx.fillRect(30, 30, 100, 100); ctx.rotate((Math.PI / 180) * 25); // grey rect - ctx.fillStyle = '#4D4E53'; + ctx.fillStyle = "#4D4E53"; ctx.fillRect(30, 30, 100, 100); ctx.restore(); // right rectangles, rotate from rectangle center // draw blue rect - ctx.fillStyle = '#0095DD'; + ctx.fillStyle = "#0095DD"; ctx.fillRect(150, 30, 100, 100); ctx.translate(200, 80); // translate to rectangle center - // x = x + 0.5 * width - // y = y + 0.5 * height + // x = x + 0.5 * width + // y = y + 0.5 * height ctx.rotate((Math.PI / 180) * 25); // rotate ctx.translate(-200, -80); // translate back // draw grey rect - ctx.fillStyle = '#4D4E53'; + ctx.fillStyle = "#4D4E53"; ctx.fillRect(150, 30, 100, 100); } ``` @@ -213,7 +213,7 @@ In this last example, we'll draw shapes with different scaling factors. ```js function draw() { - const ctx = document.getElementById('canvas').getContext('2d'); + const ctx = document.getElementById("canvas").getContext("2d"); // draw a simple rectangle, but scale it. ctx.save(); @@ -223,8 +223,8 @@ function draw() { // mirror horizontally ctx.scale(-1, 1); - ctx.font = '48px serif'; - ctx.fillText('MDN', -135, 120); + ctx.font = "48px serif"; + ctx.fillText("MDN", -135, 120); } ``` @@ -273,21 +273,21 @@ The parameters of this function are: ```js function draw() { - const ctx = document.getElementById('canvas').getContext('2d'); + const ctx = document.getElementById("canvas").getContext("2d"); const sin = Math.sin(Math.PI / 6); const cos = Math.cos(Math.PI / 6); ctx.translate(100, 100); let c = 0; for (let i = 0; i <= 12; i++) { - c = Math.floor(255 / 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.fillStyle = "rgba(255, 128, 255, 0.5)"; ctx.fillRect(0, 50, 100, 100); } ``` diff --git a/files/en-us/web/api/canvas_api/tutorial/using_images/index.md b/files/en-us/web/api/canvas_api/tutorial/using_images/index.md index 758046087a93d7a..e757d833cfc0c77 100644 --- a/files/en-us/web/api/canvas_api/tutorial/using_images/index.md +++ b/files/en-us/web/api/canvas_api/tutorial/using_images/index.md @@ -10,7 +10,7 @@ tags: - Tutorial --- -{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Drawing_text", "Web/API/Canvas_API/Tutorial/Transformations" )}} +{{DefaultAPISidebar("Canvas API")}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Drawing_text", "Web/API/Canvas_API/Tutorial/Transformations" )}} Until now we have created our own [shapes](/en-US/docs/Web/API/Canvas_API/Tutorial/Drawing_shapes) and [applied styles](/en-US/docs/Web/API/Canvas_API/Tutorial/Applying_styles_and_colors) to them. One of the more exciting features of {{HTMLElement("canvas")}} is the ability to use images. These can be used to do dynamic photo compositing or as backdrops of graphs, for sprites in games, and so forth. External images can be used in any format supported by the browser, such as PNG, GIF, or JPEG. You can even use the image produced by other canvas elements on the same page as the source! @@ -65,8 +65,8 @@ One of the more practical uses of this would be to use a second canvas element a Another option is to create new {{domxref("HTMLImageElement")}} objects in our script. To do this, you can use the convenient `Image()` constructor: ```js -const img = new Image(); // Create new img element -img.src = 'myImage.png'; // Set source path +const img = new Image(); // Create new img element +img.src = "myImage.png"; // Set source path ``` When this script gets executed, the image starts loading. @@ -74,11 +74,15 @@ When this script gets executed, the image starts loading. If you try to call `drawImage()` 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: ```js -const img = new Image(); // Create new img element -img.addEventListener('load', () => { - // execute drawImage statements here -}, false); -img.src = 'myImage.png'; // Set source path +const img = new Image(); // Create new img element +img.addEventListener( + "load", + () => { + // execute drawImage statements here + }, + false +); +img.src = "myImage.png"; // Set source path ``` 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. @@ -88,8 +92,9 @@ If you're only using one external image this can be a good approach, but once yo Another possible way to include images is via the [data: URL](/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs). Data URLs allow you to completely define an image as a Base64 encoded string of characters directly in your code. ```js -const img = new Image(); // Create new img element -img.src = 'data:image/gif;base64,R0lGODlhCwALAIAAAAAA3pn/ZiH5BAEAAAEALAAAAAALAAsAAAIUhA+hkcuO4lmNVindo7qyrIXiGBYAOw=='; +const img = new Image(); // Create new img element +img.src = + "data:image/gif;base64,R0lGODlhCwALAIAAAAAA3pn/ZiH5BAEAAAEALAAAAAALAAsAAAIUhA+hkcuO4lmNVindo7qyrIXiGBYAOw=="; ``` 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 [CSS](/en-US/docs/Web/CSS), [JavaScript](/en-US/docs/Web/JavaScript), [HTML](/en-US/docs/Web/HTML), and images, making it more portable to other locations. @@ -102,11 +107,11 @@ You can also use frames from a video being presented by a {{HTMLElement("video") ```js function getMyVideo() { - const canvas = document.getElementById('canvas'); + const canvas = document.getElementById("canvas"); if (canvas.getContext) { - const ctx = canvas.getContext('2d'); + const ctx = canvas.getContext("2d"); - return document.getElementById('myvideo'); + return document.getElementById("myvideo"); } } ``` @@ -136,7 +141,7 @@ In the following example, we will use an external image as the backdrop for a sm ```js function draw() { - const ctx = document.getElementById('canvas').getContext('2d'); + const ctx = document.getElementById("canvas").getContext("2d"); const img = new Image(); img.onload = () => { ctx.drawImage(img, 0, 0); @@ -147,7 +152,7 @@ function draw() { ctx.lineTo(170, 15); ctx.stroke(); }; - img.src = 'backdrop.png'; + img.src = "backdrop.png"; } ``` @@ -178,7 +183,7 @@ In this example, we'll use an image as a wallpaper and repeat it several times o ```js function draw() { - const ctx = document.getElementById('canvas').getContext('2d'); + const ctx = document.getElementById("canvas").getContext("2d"); const img = new Image(); img.onload = () => { for (let i = 0; i < 4; i++) { @@ -187,7 +192,7 @@ function draw() { } } }; - img.src = 'rhino.jpg'; + img.src = "rhino.jpg"; } ``` @@ -228,15 +233,24 @@ In this example, we'll use the same rhino as in the previous example, but we'll ```js function draw() { - const canvas = document.getElementById('canvas'); - const ctx = canvas.getContext('2d'); + const canvas = document.getElementById("canvas"); + const ctx = canvas.getContext("2d"); // Draw slice - ctx.drawImage(document.getElementById('source'), - 33, 71, 104, 124, 21, 20, 87, 104); + ctx.drawImage( + document.getElementById("source"), + 33, + 71, + 104, + 124, + 21, + 20, + 87, + 104 + ); // Draw frame - ctx.drawImage(document.getElementById('frame'), 0, 0); + ctx.drawImage(document.getElementById("frame"), 0, 0); } ``` @@ -304,9 +318,7 @@ function draw() { // Loop through all images for (const image of document.images) { // Don't add a canvas for the frame image - if (image.getAttribute('id') !== 'frame') { - - + if (image.getAttribute("id") !== "frame") { // Create canvas element const canvas = document.createElement("canvas"); canvas.setAttribute("width", 132);