본문 바로가기

Frontend/JavaScript

Canvas

반응형

The HTML <canvas> element provides various features such as drawing shapes and animations that can be used to create games and other applications. In this writing, we will see some of its attributes and how to use them and I will also introduce some useful tricks when working with the canvas such as dynamic sizing and the drawing application made with the canvas. 

List of Contents

The canvas element can be created either with HTML or JavaScript. However, we need the Canvas API to draw things on the canvas, so drawing can only be done with JavaScript.

 

Add the tag in the HTML to use the canvas

<body>
  <canvas width="1000" height="1000"></canvas>
</body>

Or, as mentioned above, create a canvas in JavaScript using the DOM

const canvasEl = document.createElement('canvas')
document.body.appendChild(canvasEl)

Initialization

One more thing we need to draw things on the canvas is the context. A context is the collection of the implementation methods we can choose from. To mention a few we have "2d", "webgl", "webgl2", and "bitmaprenderer". In this writing, we will use the "2d" context as it is simple and most heavily used. Note that each canvas can only have one context.

▶ getContext("context")

<!-- index.html -->

<body>
  <canvas width="800" height="600"></canvas>
</body>

width, height, mozOpaque, and mozPrintCallback are the only attributes a canvas can have other than the global attributes. For the width and height, 300px and 150px are default values. It is better to use the attribute rather than the CSS styles to set the size because there is a difference between the two values (I will elaborate on this subject below).


※ mozOpaque (deprecated) is the option to control the opacity of a canvas that can only be used for Mozilla-based browsers. This feature is not used often as there is an easier way to do the same thing with canvas configuration options.

 

※ mozPrintCallback is a callback function that is only supported by the Firefox browser Nightly (FF18) version. Its main feature is to run the code when all the pages are ready for printing not whenever a page is ready. It is in the experiment phase and not one of the standard features yet (Related: A New Way to Control Printing Output | Mozilla Labs).


/* index.js */

const canvas = document.querySelector('canvas')
const cv = canvas.getContext('2d')

// ※ shortcut
const cv = document.querySelector('canvas').getContext('2d')

Context configurations options:

  • alpha: controls the opacity
/* index.js */

const canvas = document.querySelector('canvas')
const cv = canvas.getContext('2d', {
  alpha: true
})
/* main.css */

canvas {
  border: 4px solid #000;
  margin: auto;
  display: block;
}

Sizing

It is recommended to set the size of a canvas in the element not with CSS. Because the units in the canvas attributes for the size are slightly different from the size attributes in the CSS. So images will be distorted if you set the size using CSS and try to draw something.

<!-- index.html -->

<body>
  <canvas width="300" height="300"></canvas>
  <canvas class="canvas-css"></canvas>
</body>
/* index.js */

const canvas = document.querySelector('canvas')
const canvasCSS = document.querySelector('.canvas-css')
const cv = canvas.getContext('2d')
const cv2 = canvasCSS.getContext('2d')

cv.beginPath()
cv.moveTo(0, 0)
cv.lineTo(100, 100)
cv.stroke()

cv2.beginPath()
cv2.moveTo(0, 0)
cv2.lineTo(100, 100)
cv2.stroke()
/* main.css */

body {
  display: flex;
}

canvas {
  border: 4px solid #000;
  margin: auto;
  display: block;
}

.canvas-css {
  height: 300px;
  width: 300px;  
}

Dynamic Sizing

 

Canvas - Dynamic Sizing

While the width and height of a canvas element are relevant to the pixel, the width and height of the CSS are relevant to the size of the element that the size is applied to. For this reason, it is not a good practice to set the size of a canvas element wi

jin-co.tistory.com

Using Canvas

Now, let's see how we can draw on the canvas

 

There are two basic syntaxes:

  • Canvas can use a shape and line to draw and 'fill' is used for the shapes and 'stroke' is used for the lines
  • The first two parameters represent the coordinate, x, and y (The measuring point of a shape is the top left corner of the shape).

Shapes

▶ fillRect(x, y, width, height)

Draws a rectangular

cv.fillStyle = 'yellow' // 색지정
cv.fillRect(60, 60, 200, 200)

▶ strokeRect(x, y, width, height)

Draws the border of a rectangular.

cv.strokeStyle = 'red'
cv.strokeRect(60, 60, 200, 200)

▶ clearRect(x, y, width, height)

Clears everything in the scope specified (like an eraser).

cv.fillStyle = 'yellow'
cv.fillRect(60, 60, 200, 200)

cv.clearRect(60, 60, 100, 100)

cv.strokeStyle = 'red'
cv.strokeRect(60, 60, 200, 200)


Lines

 

▶ stoke()

cv.lineTo(110, 110)
cv.lineTo(10, 110)
cv.lineTo(10, 10)
cv.stroke()

▶ fill()

cv.lineTo(110, 110)
cv.lineTo(10, 110)
cv.lineTo(10, 10)
cv.fill()

▶ beginPath()

Begins a new line

cv.beginPath()
cv.strokeStyle = 'red'
cv.moveTo(10, 10) // 시작점
cv.lineTo(110, 210)
cv.stroke()

cv.beginPath()
cv.strokeStyle = 'green'
cv.moveTo(10, 10) // 시작점
cv.lineTo(110, 110)
cv.stroke()

▶ arc(x, y, radius, startingAngle, endingAngle, countClockwise)

For the circle, unlike rectangular the measuring point for the coordinate of a circle is the center of the circle.

cv.beginPath()
cv.arc(150, 150, 100, 0, Math.PI / 3);
cv.stroke();

By default, it is drawn clockwise. Set the 'counterclockwise' parameter to 'true' to draw counter clock-wise.

cv.beginPath()
cv.arc(150, 150, 100, 0, Math.PI / 3, true);
cv.stroke();

Fonts

cv.font = "200px Sans-serif" //font = "<fontSize> <fontFamily>"
cv.strokeText("Font stroke", 60, 60) //strokeText("Text", x, y) / fillText("Text", x, y)

cv.font = "200px Sans-serif"
cv.fillText("Font fill", 30, 30)


Other Features

▶ toBlob(callbackFunction, "type", quality)

This converts the image to a Blob object. The second parameter is the format and the default value is "image/png". The third parameter is the quality of the image and the value can be set between 0 ~ 1.

<!-- index.html -->

<body>
  <canvas width="200" height="200"></canvas>
</body>
/* index.js */

const canvas = document.querySelector('canvas')
const cv = canvas.getContext('2d')

cv.beginPath()
cv.quadraticCurveTo(0, 10, 100, 100)
cv.stroke()

canvas.toBlob((blob) => {
  const newImg = document.createElement('img');
  const url = URL.createObjectURL(blob);

  newImg.onload = () => {
    URL.revokeObjectURL(url);
  };

  newImg.src = url;
  newImg.style.border = '1px solid red'; //구분을 위해 사용
  document.body.appendChild(newImg);
}, "image/jpg", 1);
/* main.css */

body {
  display: flex;
}

canvas {
  border: 4px solid #000;
  margin: auto;
  display: block;
}

.canvas-css {
  height: 300px;
  width: 300px;  
}

▶ toDataURL("type", quality)

This returns the image path and can be used for downloading the images. The first parameter is the format and the default value is "image/png". The second parameter is the quality of the image and the value can be set between 0 ~ 1.

<!-- index.html -->

<body>
  <canvas width="1000" height="1000"></canvas>
</body>
/* index.js */

console.log(canvas.toDataURL())


Styles

<p id="style-stroke" style="color: #333333; text-align: justify;" data-ke-size="size16"><b>▶ strokeStyle = "color"</b></p>
/* index.js */

cv.strokeStyle = "red"
cv.lineTo(110, 220)
cv.lineTo(210, 320)
cv.stroke()

▶ fillStyle = "color"

/* index.js */

cv.fillStyle = "yellow"
cv.fillRect(0, 0, 100, 100)

▶ lineWidth = size

/* index.js */

cv.lineWidth = 300
cv.lineTo(110, 220)
cv.lineTo(210, 320)
cv.stroke()

▶ lineCap = "type"

Defines the shape of the end of a line. Some of the options are "butt", "round", and "square"

/* index.js */

cv.strokeStyle = "red"
cv.lineWidth = 130
cv.beginPath()
cv.lineCap = "butt"
cv.moveTo(110, 220)
cv.lineTo(210, 320)
cv.stroke()

cv.beginPath()
cv.lineCap = "round"
cv.moveTo(410, 220)
cv.lineTo(510, 320)
cv.stroke()

cv.beginPath()
cv.lineCap = "square"
cv.moveTo(710, 220)
cv.lineTo(810, 320)
cv.stroke()

▶ lineJoin = "type"

Defines the shape of the point where lines meet. Some of the options are "round", "bevel", and "miter"

/* index.js */

cv.strokeStyle = "red"
cv.lineWidth = 30
cv.beginPath()
cv.lineJoin = "round"
cv.moveTo(110, 220)
cv.lineTo(210, 320)
cv.lineTo(210, 320)
cv.lineTo(300, 220)
cv.stroke()

cv.beginPath()
cv.lineJoin = "bevel"
cv.moveTo(410, 220)
cv.lineTo(510, 320)
cv.lineTo(510, 320)
cv.lineTo(600, 220)
cv.stroke()

cv.beginPath()
cv.lineJoin = "miter"
cv.moveTo(710, 220)
cv.lineTo(810, 320)
cv.lineTo(810, 320)
cv.lineTo(900, 220)
cv.stroke()

▶ setLineDash([lineWith, spaceWidth,...])

/* index.js */

cv.strokeStyle = "red"
cv.beginPath()
cv.setLineDash([10, 20, 5])
cv.moveTo(110, 220)
cv.lineTo(410, 220)
cv.stroke()

▶ lineDashOffset = offsetValue

Moves the dots by the numbers specified without changing the length of a line

/* index.js */

cv.strokeStyle = "red"
cv.beginPath()
cv.setLineDash([30, 20, 5, 10, 2, 22])
cv.moveTo(110, 220)
cv.lineTo(810, 220)
cv.stroke()

cv.strokeStyle = "green"
cv.beginPath()
cv.setLineDash([30, 20, 5, 10, 2, 22])
cv.lineDashOffset = 130
cv.moveTo(110, 250)
cv.lineTo(810, 250)
cv.stroke()

▶ createLinearGradient(xStart, yStart, xEnd, yEnd)

Sets the linear gradient. To use this, first set the coordinate and the size. Then use the 'addColorStop(location, color) to set the color and the location. The values for the first parameter for the 'addColorStop' is between 0 (start) and 1 (end).

/* index.js */

let grad = cv.createLinearGradient(0, 0, 200, 0)
grad.addColorStop(0, 'red')
grad.addColorStop(1, 'blue')

cv.fillStyle = grad
cv.fillRect(60, 60, 900, 200)

▶ createRadialGradient(xStart, yStart, radiusStart, xEnd, yEnd, radiusEnd)

Sets the radial gradient. To use this, first set the coordinate and the size. Then use the 'addColorStop(location, color) to set the color and the location. The values for the first parameter for the 'addColorStop' is between 0 (start) and 1 (end).

/* index.js */

let gradC = cv.createRadialGradient(150, 150, 10, 290, 160, 280)
gradC.addColorStop(0, 'red')
gradC.addColorStop(1, 'blue')

cv.fillStyle = gradC
cv.fillRect(60, 60, 900, 200)

▶ quadraticCurveTo(xCurve, yCurve, xEnd, yEnd)

/* index.js */

const canvas = document.querySelector('canvas')
const cv = canvas.getContext('2d')

cv.beginPath();
cv.moveTo(20, 110);
cv.quadraticCurveTo(230, 450, 650, 20);
cv.stroke();

Canvas Application - Drawing

 

프로젝트 - 그림판

그림판 애플리케이션 index.html 5 10 15 20 25 30 35 40 45 50 png jpg jpeg Save main.css @import url('https:fonts.googleapis.com/css?family=Poppins&display=swap'); * { margin: 0; padding: 0; box-sizing: border-box; } body { display: flex; flex-direc

jin-co.tistory.com

We explored the canvas in this writing and I hope it was helpful.


References

Canvas API - Web APIs | MDN (mozilla.org)

 

Canvas API - Web APIs | MDN

The Canvas API provides a means for drawing graphics via JavaScript and the HTML <canvas> element. Among other things, it can be used for animation, game graphics, data visualization, photo manipulation, and real-time video processing.

developer.mozilla.org

Bézier curve - MDN Web Docs Glossary: Definitions of Web-related terms | MDN (mozilla.org)

 

Bézier curve - MDN Web Docs Glossary: Definitions of Web-related terms | MDN

A Bézier curve (pronounced [bezje]) is a mathematically described curve used in computer graphics and animation. In vector images, they are used to model smooth curves that can be scaled indefinitely.

developer.mozilla.org

캔버스 동적크기

https://stackoverflow.com/questions/1664785/resize-html5-canvas-to-fit-window

 

Resize HTML5 canvas to fit window

How can I automatically scale the HTML5 <canvas> element to fit the page? For example, I can get a <div> to scale by setting the height and width properties to 100%, but a <canvas&g...

stackoverflow.com

https://stackoverflow.com/questions/26670810/why-we-cant-set-width-and-height-for-canvas-using-css

 

why we can't set width and height for canvas using css

Why the canvas appears as scaled one, when the height and width is specified in css instead of DOM? Html: <canvas></canvas> Css: canvas{ width:100px; height:100px...

stackoverflow.com

 

 

728x90
반응형

'Frontend > JavaScript' 카테고리의 다른 글

NPM - Nodemon  (0) 2023.12.15
Drag and Drop  (1) 2023.07.05
JavaScript Module - Button Ripple Effect  (1) 2023.07.03
NPM - JSON Server  (0) 2023.05.22
JavaScript Module - Text Wave Effect  (2) 2023.04.05