본문 바로가기

프론트엔드/HTML

캔버스

반응형

HTML <canvas> 요소는 캔버스 에이피아이를 사용하여 단순한 도형부터 게임까지 만들 수 있게 해 주는 유용한 기능입니다. 이 글에서는 캔버스가 가지고 있는 속성들과 그 사용법, 동적으로 캔버스 크지 지정하기, 마지막으로 캔버스를 활용한 애플리케이션 제작방법소개로 구성하였습니다.

목차

 

캔버스는 요소는 HTML 또는 JavaScript로 생성 가능하지만 그림을 그리는 등 실제로 활용은 JavaScript를 통해서만 가능합니다. 

 

생성은 아래와 같이 HTML에서 추가

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

또는, 자바스크립트에서 생성하여 돔에 추가

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

캔버스 초기화

캔버스를 활용하기 위해서는 캔버스가 그려질 배경을 지정해 주어야 합니다. 사용가능한 배경들은 "2d", "webgl", "webgl2", "bitmaprenderer" 등이 있으며, 오늘 예시에서는 가장 많이 사용되는 "2d"로 지정해 보겠습니다 (참고로 하나의 캔버스는 하나의 콘텍스트만 가집니다).

▶ getContext("context")

<!-- index.html -->

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

width, height, mozOpaque, mozPrintCallback는 canvas가 가지는 유일한 속성(물론 전역속성은 제외)으로 지정하지 않을 시 기본값은 width 300px, height 150px입니다. CSS를 활용하지 않고 요소에 지접 크기를 지정하는 이유는 비율 때문인데요. 이 부분은 아래서 이어 가겠습니다.


※ mozOpaque (deprecated)는 캔버스를 불투명하게 하는 속성으로 Mozila기반의 브라우저에서만 사용가능하고 같은 기능을 콘텍스트 설정 시 옵션으로 추가가능하기 때문에 잘 사용되지 않습니다.

 

※ mozPrintCallback는 파이어폭스 브라우저 Nightly (FF18) 버전에서만 가능한 callback 기능으로 인쇄할 때 개별 페이지가 준비될 때마다 코드를 실행하기보다 모든 페이지가 준비되었을 때 코드를 실행하게 해 주는 기능으로 아직 실험 단계로 표준화된 기능은 아님 (관련: A New Way to Control Printing Output | Mozilla Labs).


/* index.js */

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

// ※ 아래와 같이 단축하여 사용도 가능합니다.
const cv = document.querySelector('canvas').getContext('2d')

콘텍스트 설정 시 추가 가능한 옵션들은 아래와 같음

  • alpha: 캔버스를 불투명하게 하는 옵션
/* 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;
}

캔버스 크기지정

캔버스의 크기는 CSS를 사용하는 것보다 요소에 직접지정 해 주어야 합니다. 이유는 CSS를 활용하는 경우 비율이 틀어져서 화면에 표시되는 이미지가 왜곡되기 때문입니다.

<!-- 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;  
}

캔버스 크기 동적으로 지정하기

 

캔버스 (Canvas) 동적 크기 지정 (dynamic size)

캔버스를 활용하여 그림판 애플리케이션을 만들 다 화면의 크기에 따라 동적으로 캔버스 크기를 조정하는 기능을 추가하기로 했습니다. 그냥 CSS를 활용하여 상대 단위를 적용하면 쉽게 구현될

jin-co.tistory.com

캔버스 사용하기

그럼, 생성된 캔버스를 사용해 볼까요?

 

먼저, 기본적인 문법을 보면

  • 캔버스는 사각형과 선만을 사용하여 표현하는데, fill으로 시작하는 기능은 도형을 stroke로 시작하는 기능은 선을 그립니다.
  • 처음에 오는 두 개의 매개변수는 x좌표와 y좌표를 의미합니다 (좌측 상단을 기준).

도형

▶ fillRect(x, y, width, height)

사각형을 그립니다.

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

▶ strokeRect(x, y, width, height)

사각형 외곽선을 그립니다.

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

▶ clearRect(x, y, width, height)

지정된 만큼 투명한 사각형을 만듭니다 (지우개 역할).

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

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

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


선 그리기

 

▶ 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()

새로운 선을 시작하는 명령어입니다. 

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)

좌표산정 시 좌측 상단을 기준으로 하는 HTML대부분의 요소와 달리 arc의 x, y는 원의 중심으로부터 산정합니다. 

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

원은 시계방향으로 그려지는데 countClockwise 매개변수를 'true'로 설정 시 시계반대방향으로 그려집니다.

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

글쓰기

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)


기타 기능들

▶ toBlob(callbackFunction, "type", quality)

캔버스에 그려진 이미지를 Blob객체로 생성하게 해 주는 기능으로 두 번째 매개변수는 이미지의 형식을 지정하는 값으로 지정하지 않을 시 "image/png"형식으로 저장됩니다. 세 번째 매개변수는 이미지의 질을 의미하며 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)

캔버스에 그려진 이미지경로를 반환기능으로 이미지 다운로드등에 사용가능합니다. 첫 번째 매개변수는 이미지의 형식을 지정하는 값으로 지정하지 않을 시 "image/png"형식으로 저장됩니다. 두 번째 매개변수는 이미지의 질을 의미하며 0 ~ 1의 값을 가집니다.

<!-- index.html -->

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

console.log(canvas.toDataURL())


스타일

<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"

라인 끝의 모양을 결정하는 속성으로 "butt", "round", "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"

라인이 만나는 지점의 모양을 결정하는 속성으로 "round", "bevel", "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

길이의 변화 없이 점선을 주어진 숫자만큼 이동시킵니다.

/* 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)

선형 그라데이션 스타일로 먼저 위치와 크기를 지정하고 addColorStop(위치, 색)를 색과 위치를 지정. addColorStop의 첫 번째 매개변수인 위치는 0 (시작) ~ 1 (끝) 사이의 값을 가집니다.

/* 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)

원형 그라데이션 스타일로 먼저 위치와 크기를 지정하고 addColorStop(위치, 색)를 색과 위치를 지정. addColorStop의 첫 번째 매개변수인 위치는 0 (시작) ~ 1 (끝) 사이의 값을 가집니다.

/* 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();

캔버스로 그림판 애플리케이션 만들기

 

프로젝트 - 그림판

그림판 애플리케이션 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

이상으로 캔버스에 대해서 알아보았습니다.


참고

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
반응형

'프론트엔드 > HTML' 카테고리의 다른 글

캔버스 동적 크기 지정  (0) 2023.01.18
전역속성 (global attribute)  (0) 2022.12.28
contenteditable  (0) 2022.12.28