본문 바로가기
블로그 이미지

방문해 주셔서 감사합니다! 항상 행복하세요!

  
   - 문의사항은 메일 또는 댓글로 언제든 연락주세요.
   - "해줘","답 내놔" 같은 질문은 답변드리지 않습니다.
   - 메일주소 : lts06069@naver.com


Html 캔버스/Html 캔버스 튜토리얼 (내가만든 차트!)

Html Canvas (Html 캔버스) 튜토리얼 (차트만들기!) - 7 : 좌표 심화

야근없는 행복한 삶을 위해 ~
by 마샤와 곰 2020. 2. 6.

translate 사전적 의미로는 번역을 뜻하며, 캔버스에서는 중앙점을 옮기는데 사용된다.

만약 x좌표가 0, y좌표가 0 인데 위 translate를 활용해서 x좌표를 50, y좌표를 50만큼 이동하면 0, 0의 실제 좌표값은 50,50이 되어버린다.

아래 코드를 실행하여보자.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>Canvas</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<style>
    body{padding: 5%;text-align: center;}
    canvas{border: 1px solid gray;border-radius: 3px;}
</style>
<body>
    <canvas width='400' height='400' id='canvas'></canvas>
</body>
</html>

<script>    
    const canvas = document.getElementById('canvas');
    const ctx = canvas.getContext('2d');
    ctx.fillStyle = 'green';
    ctx.fillRect(0, 0, 30, 30);  
    ctx.fillStyle = 'blue'; 
    ctx.translate(100,100);   //중앙점을 100,100 이동한다. 
    ctx.fillRect(0, 0, 30, 30);
</script>        

 

분명 같은 x좌표, y좌표를 가지고 있음에도 불구하고 서로위치가 다르게 나타났다.

그렇다면 해당 중앙점을 다시 원래대로 되돌리려면 어떻게 해야할까?

파랑색 사각형이 아래로 이동 하였다.

 

이론적으로는 내가 x좌표를 100만큼 y좌표를 100만큼 움직였으므로 다시 원래의 중심점으로 옮기려면 100만큼씩 빼 주면 가능하다.

실제로도 그렇게 적용하면 원하는 방향으로 잘 그려진다.

스크립트 코드를 변경하여보자.

    const canvas = document.getElementById('canvas');
    const ctx = canvas.getContext('2d');
    ctx.fillStyle = 'green';
    ctx.fillRect(0, 0, 30, 30);  
    ctx.fillStyle = 'blue'; 
    ctx.translate(100,100);    
    ctx.fillRect(0, 0, 30, 30);

    ctx.translate(-100,-100); //더한값 만큼을 다시 빼 주었다.   
    ctx.fillStyle = 'yellow'; 
    ctx.fillRect(0, 0, 30, 30);

 

문제없이 노랑색 사각형이 그려지는 것을 볼 수 있다.

그러나 위 방식대로 translate를 난발하여 사용하다보면 작은 차이지만 그림을 그리다 픽셀이 유실되는 경우가 생긴다고 한다.   * 내용 출처 :  https://developer.mozilla.org/ko/docs/Web/HTML

그러므로 translate는 save와 restore를 항상 달고 다녀야 한다.

노랑색 사각형이 원래의 0,0으로 이동했다.

 

위 코드를 수정하여보자.

최초 캔버스의 상태를 저장을 하여주고, 화면에 대한 변환 및 작업을 한 이후에 원래의 모양으로 돌아가려 할 때는 restore를 호출하는 방식으로 바꾸어주자.

    const canvas = document.getElementById('canvas');
    const ctx = canvas.getContext('2d');

    ctx.save();  //초기상태 저장

    ctx.fillStyle = 'green';
    ctx.fillRect(0, 0, 30, 30);  

    
    ctx.translate(100,100);    //변환
    ctx.fillStyle = 'blue'; 
    ctx.fillRect(0, 0, 30, 30);
    
    //ctx.translate(-100,-100);  기존 값을 빼주는 것을 주석  
    ctx.restore();  //예전상태로 복구

    ctx.fillStyle = 'yellow'; 
    ctx.fillRect(0, 0, 30, 30);

 

위 코드를 실행하면 중앙점이 다시 0, 0으로 돌아가는 것을 볼 수 있다.

 

 

 

다음으로 해볼 기능은 rotate이다. 회전!

rotate는 회전을 의미하며 내가 보고있는 화면을 돌리는 것을 의미한다.

스크립트 코드를 변경하여보자.

    const canvas = document.getElementById('canvas');
    const ctx = canvas.getContext('2d');
   
    ctx.rotate((Math.PI / 180) * 15);    //15도만큼 캔버스내부를 돌린다.
    ctx.fillStyle = 'green';
    ctx.fillRect(200, 200, 50, 30);  

 

rotate는 일반 도(degree)의 개념이 아니라 라디안(radian)을 사용하므로 라디안 값을 쓰기 어려우면 Math 함수를 통해서 사용자가 이해하기 쉬운 도를 사용하도록 하자.

위 소스코드는 15도 만큼 캔버스를 회전하라는 의미이다.  (캔버스 테그를 회전하라는게 아니라 안에 그릴 때 회전시키라는 뜻 이다.)

사각형이 뭔가 비스듬하게 회전했다.

 

rotate를 사용하면 캔버스의 중앙점(0, 0)을 기준으로 캔버스가 회전을 하기 때문에 많이들 햇갈려 한다.

사용자가 바라보는 캔버스의 최초 화면을 아래 사진이라고 하여보자.

녹색 부분이 사용자가 보는 화면이라고 하자.

 

그런데 위 캔버스를 회전하게되면 아래사진처럼 되어버린다.

사용자가 보는 곳은 그대로이지만 내부의 캔버스가 회전했다.

 

그러면 해당 내용을 가지고 rotate가 계속 이루어지는 애니메이션을 한번 만들어보자.

스크립트를 수정하여보자.

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
setInterval(() => {
    ctx.clearRect(0,0,400,400);
    ctx.fillRect(60, 60, 100, 100); 
    ctx.rotate((Math.PI / 180) * 1);    
}, 10);

 

실행하면 회전이 계속해서 이루어지는 화면을 만나게된다.

그런데..뭔가 좀 맘에들지는 않지만 말이다.

빙글빙글~

 

위 현상이 당연하게도 캔버스의 초기 중심점이 0, 0 이기 때문이다.

0, 0을 중심으로 캔버스를 회전시키기 때문에 위 사진과 같은 현상이 발생하는 것 이다.

중심점을 조금만 움직여주면 그나마 괜찮은 모양으로 출력이 된다.

아래 스크립트를 수정하여보자.

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
ctx.translate(150,150);  //중앙을 옮겨보자.
setInterval(() => {
    ctx.clearRect(0,0,400,400);
    ctx.fillRect(60, 60, 100, 100); 
    ctx.rotate((Math.PI / 180) * 1);    
}, 10);

 

중앙이 옮겨진 상태에서의 회전모양이 잘 나오게된다.

여기까지 하면 translate와 rotate에 대한 개념이 어느정도 잡히게 된다.  (아닌가요..?ㅠ)

조금 더 보기 편해졌다.ㅋ

 

그러면 머리를 조금만 더 써보면 사각형이 혼자서 빙글빙글 돌게 만들 수 있다.

작업하기 전 개념을 먼저 정리하여보자.

1. 초기 상태를 저장한다.

2. 캔버스를 초기화 한다.

3. 중앙점을 옮겨준다.

4. 회전시킨다.

5. 사각형을 그려준다.

6. 초기상태를 불러와준다.

 

여기서 눈여겨볼 것은 5번 사각형을 그려주는 부분인데..

시작점과 종료점을 사각형 크기의 절반만큼 뒤로 빼 주면 사각형이 제자리에서 빙글빙글 도는 효과를 나타낼 수 있다.

말이 어려우므로..코드를 직접 수정하여 확인하여보자.

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
var num = 1; //증가시킬 각도
setInterval(() => {
    ctx.save();  //초기상태 저장
    ctx.clearRect(0,0,460,460);    
    ctx.translate(100, 100);  // 중앙점 이동
    ctx.rotate((Math.PI / 180) * num);     //회전
    ctx.fillRect(-30,-30, 60, 60); // 사각형 그리기 (그리는 사각형의 절반 크기만큼을 빼준다.)
    ctx.restore();
    num++;
    if(num >=365){
        num = 1;
    }
}, 10);

 

단계를 이해하고 다시한번 코드를 살펴보아야 한다.

중앙점을 옮긴 것은 0,0 지점에서 사각형을 그리게 되면 잘려나가는 모습이 나오기 때문에 100, 100 만큼 이동 하였다.

그리고 회전을 시킨 뒤에 사각형의 절반 크기만큼씩 x좌표와 y좌표를 뒤로 이동하게 하였다.

만약 사각형의 x좌표와 y좌표가 절반값이 아니라면 두번째 움짤처럼 옮긴 중심을 기점으로 전체가 회전하는 모양이 나오게 될 것 이다.

중앙에서 빙글빙글~

 

여기까지 translate와 save, restore에 대해서 살펴 보았다.

만약 save와 restore를 쓰지 않았다면 translate를 할 때마다 값을 빼 주면서 동시에 발생 할 수 있는 픽셀 유실버그까지 해결해야되는 문제가 있었을 것 이다.

 

정리하여보자!

1. translate 함수는 캔버스의 중앙점을 옮기는 함수 이다.

2. save는 캔버스의 상태값을 저장한다. (만약 여러 효과를 준 상태에서 저장하면 해당 효과를 지닌 캔버스를 기억 한다)

3. restore는 save된 캔버스의 상태를 다시 불러온다.

4. rotate는 라디안 값을 기본적으로 사용하며, 사용자가 이해하기 쉬우려면 Math 함수를 사용해서 degree 값으로 변환해 주어야 한다.

5. rotate 함수는 캔버스를 회전시키는 행위를 의미 한다.

 

 

다음시간에는 원 그리기, scale 그리고 clip에 대해서 살펴보자.

 

반응형
* 위 에니메이션은 Html의 캔버스(canvas)기반으로 동작하는 기능 입니다. Html 캔버스 튜토리얼 도 한번 살펴보세요~ :)
* 직접 만든 Html 캔버스 애니메이션 도 한번 살펴보세요~ :)

댓글