캔버스에 대한 기초 사용법은 모질라 web docs에서 볼 수 있습니다.

 

원 그리기

(arc) 명령을 이용해서 원을 그릴 수 있습니다.

arc(x, y, radius, startAngle, endAngle, anticlockwise)

(x, y) 위치에 원점을 두면서, 반지름 r을 가지고,  startAngle 에서 시작하여 endAngle 에서 끝나며 주어진 anticlockwise 방향으로 향하는 (기본값 false – 시계방향 회전) 호를 그리게 됩니다.

예제 코드를 살펴보겠습니다. HTML 기본 토대는 다음과 같습니다.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>

<body onload="draw();">
    <canvas width="500" height="500" id="canvas"></canvas>

    <script>
        ............
    </script>
</body>
</html>

body 요소의 로드가 완료되면 스크립트 부분의 draw() 함수를 실행합니다.

 

const geom = {
    x: 100,
    y: 100,
    radius: 90,
    statrAngle: 0,
    endAngle: 360,
    anticlockwise: false
}

function degToRad(deg) {
    return (Math.PI / 180) * deg
}
//

function draw() {
    const canvas = document.getElementById("canvas")
    const ctx = canvas.getContext("2d")

    ctx.beginPath()
    // arc(x, y, radius, startAngle, endAngle, anticlockwise)
    ctx.arc(geom.x, geom.y, geom.radius, degToRad(geom.statrAngle), degToRad(geom.endAngle), geom.anticlockwise)
    console.log(degToRad(geom.statrAngle), degToRad(geom.endAngle))
    ctx.stroke()

}

변수 geom은 설정 정보를 모아놓은 객체 변수입니다. 함수 degToRad는 각도(degree)를 라디언(radian)으로 변환하여 리턴합니다. 제가 사실 문과 출신이라 라디언이 뭔지 잘 몰라서 이하 내용에서는 전부 각도를 사용한 뒤 degToRad 를 이용해 변환하겠습니다. 함수 draw는 캔버스에 그림을 그리는 부분입니다.

ctx는 컨텍스트 정보를 담고 있는 변수로 컨텍스트는 지금 단계에서는 ‘캔버스에 그림을 그리는 방법‘이라고 생각하면 될 것 같습니다. 2D, 또는 3D 등이 있는데 여기에서 사용할 것은 2차원으로 그림을 그리는 것이므로 canvas.getContext("2d") 라고 작성하여 2차원 컨텍스트를 가져옵니다.

ctx.beginPath()경로(path)를 시작하는 명령입니다. 경로는 사각형 이외의 모든 도형에서 사용하는 점들의 집합(선)입니다. 경로를 끝내는 명령은 ctx.closePath() 입니다. arc는 호(arc)를 그리는데 이 호들이 모이면 원이 될 수 있습니다. ctx.stroke()는 작성된 경로를 바탕으로 시각적으로 보이는 외곽선을 그립니다.

arc 명령에서 x, y중심점의 위치입니다. radius반지름입니다. 단위는 캔버스에서 사용하는 고유 단위입니다. (픽셀과 비슷하나 1:1 대응하지는 않습니다.) startAngle, endAngle시작 각끝 각인데 사용 단위는 라디언(radian)입니다. anticlockwise는 회전 방향을 지정하는 것으로 기본값은 false입니다. (반시계방향 설정인데 false이므로 시계 방향 회전합니다.)

startAngle이 0인 경우 3시 방향을 가리키는 것이니 주의하시기 바랍니다.

 

startAngle, endAngle 값의 변화에 따른 그림들

 

원을 n등분하여 그리기

function draw(){
    const canvas = document.getElementById("canvas")
    const ctx = canvas.getContext("2d")
    const geom = {
        x: 120,
        y: 120,
        radius: 100,
        statrAngle: 0,
        endAngle: 360,
        anticlockwise: false
    }
    
    let part = 6
    let eachDeg = 360 / part

//
    
    ctx.beginPath()
    for(let i = 0; i <= part; i++){
        // arc(x, y, radius, startAngle, endAngle, anticlockwise)
        ctx.arc(geom.x, geom.y, geom.radius, degToRad(i * eachDeg), degToRad(i * eachDeg + eachDeg), geom.anticlockwise)
        ctx.lineTo(geom.x, geom.y)
    }

    ctx.stroke()

    
}

원을 으로 나눠 그리는 예제입니다. 피자 나누는 그림을 생각하면 될 것 같습니다. part의 숫자에 따라 나누는데, lineTo()은 현재 경로의 위치에서 특정 좌표까지 선을 그리면서 이동하는 명령입니다. 360도를 n으로 나누면 각 등분한 도형 당 필요한 각도가 계산되고, for문을 돌리면서 필요한 각도를 곱하는 식으로 원을 그리게 됩니다.

6등분

11등분

 

예제: 피자를 n등분으로 나누기

여기에 이미지를 입히고 입력값을 받아 피자를 n등분하는 예제 프로그램을 만들어보도록 하겠습니다. (jsfiddle에서 보기)


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Pizza</title>
</head>
<body onload="draw();">
<canvas width="300" height="300" id="canvas"></canvas>
<input type="number" min="1" max="360" id="input-part" value="5">
<script>
// 설정 변수
const geom = {
x: 150,
y: 150,
radius: 110,
statrAngle: 0,
endAngle: 360,
anticlockwise: false
}
// 각도(degree)를 라디안(radian)으로 변환
function degToRad(deg) {
return (Math.PI / 180) * deg
}
// 2d 컨텍스트에 원을 n등분하여 그림
function divCircle(ctx, part) {
const eachDeg = 360 / part // n등분 할 경우 각 부분의 각도
const lineWidth = part <= 8 ? 6 : part <= 16 ? 3 : 1
if (part == 1) {
// 1등분인 경우 원을 나눌 필요가 없으므로 단일의 원을 그리고 종료
ctx.beginPath()
ctx.arc(geom.x, geom.y, geom.radius, degToRad(0), degToRad(360), geom.anticlockwise)
ctx.closePath()
ctx.fillStyle = `rgba(${Math.random() * 255}, ${Math.random() * 255}, ${Math.random() * 255}, 0)`
ctx.fill()
} else {
for (let i = 0; i <= part; i++) {
ctx.beginPath() // 경로 시작
ctx.lineWidth = lineWidth
ctx.strokeStyle = "rgba(0, 0, 0, 1)"
// arc(x, y, radius, startAngle, endAngle, anticlockwise)
ctx.arc(geom.x, geom.y, geom.radius, degToRad(i * eachDeg), degToRad(i * eachDeg + eachDeg), geom.anticlockwise)
ctx.lineTo(geom.x, geom.y) // 특정 좌표 위치로 선을 그림
ctx.closePath() // 경로 종료
ctx.fillStyle = `rgba(${Math.random() * 255}, ${Math.random() * 255}, ${Math.random() * 255}, 0)`
ctx.fill() // 채우기
ctx.stroke() // 윤곽선 그리기
}
}
}
// 캔버스를 초기화
function resetCanvas(canvas, cbFunc) {
const ctx = canvas.getContext("2d")
ctx.clearRect(0, 0, canvas.width, canvas.height) // 캔버스를 지우고 초기화
const image = new Image() // 이미지 객체 생성
image.src = getPizzaBase64()
image.onload = _ => {
ctx.drawImage(image, 0, 0) // 이미지 파일 내용을 캔버스 컨텍스트에 배치
cbFunc()
}
}
// canvas가 로딩되면 실행되는 함수
function draw() {
const canvas = document.getElementById("canvas")
const ctx = canvas.getContext("2d")
const numField = document.getElementById("input-part")
const cbFunc = _ => {
divCircle(ctx, numField.value)
}
resetCanvas(canvas, cbFunc)
numField.onchange = e => {
resetCanvas(canvas, cbFunc)
}
}
// 피자 그림 (Base64)
function getPizzaBase64() {
return "./pizza.png"
}
</script>
</body></html>

view raw

pizza.html

hosted with ❤ by GitHub

 

new Image()로 인스턴스를 만들어 이미지를 불러오고, 그 이미지를 ctx.drawImage(image객체, 시작점x, 시작점y)로 그린 다음 n등분한 원의 외곽선을 검은색으로 그려 피자를 칼로 자른것 같은 이미지를 보여줍니다.

Pizza GIF - Find & Share on GIPHY

 

문의 | 코멘트 또는 yoonbumtae@gmail.com




0개의 댓글

답글 남기기

Avatar placeholder

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다