본문 바로가기
자바스크립트&캔버스

자바스크립트와 캔바스 4번째 시간. 마우스의 파동을 느껴봐!

1. HTML 표준 CANVAS 기술 소개 / https://itadventure.tistory.com/130

2. 자바스크립트와 CANVAS 두번째시간. 캔바스에 눈을 내리자 / https://itadventure.tistory.com/131

3. 자바스크립트와 캔버스 3번째 시간, 공튀기기 놀이 / https://itadventure.tistory.com/132

◐ 4. 자바스크립트와 캔버스 3번째 시간, 공튀기기 놀이마우스의 파동을 느껴봐! ◑


HTML5 캔바스 4번째 시간입니다.
이번 시간에는 캔바스 내에서 마우스의 리액션에 대한 부분을 살펴볼텐데요.

그동안 3번째 시간까지는 오로지 보는 것에서 그쳤다면,
이번에는 드디어 마우스 클릭에 의해 반응하는 캔바스의 모습을 보실 수 있을 겁니다.

캔바스 내에서 마우스 버튼을 클릭하면 정확히 클릭한 위치를 알 수 있을까요?
물론 알아낼 수 있으니까 이런 질문을 하는 것이 아니겠습니까 ? :)

아래 페이지를 열어주신 다음에, 큰 사각형 안쪽 아무곳이나 마구 마구 클릭하시면 원의 파동을 구경하실수 있을겁니다.

http://dreamplan7.cafe24.com/canvas/cray04.php

 

캔바스 샘플#4. 마우스 이벤트

 

dreamplan7.cafe24.com

동그란 원은 마우스 클릭에 의해 발생합니다.

마우스를 클릭할때마다 그 위치에서 생겨난 동그란 원은 턴을 거듭할때마다 1.05배씩 점점 커집니다. 그리고 라이프타임, 즉 생명주기 100만큼 불타오르다가(?) 그 수명을 다하고 마쳐집니다.

우선 소스흐름은 지난 번과 거의 유사합니다.
반복된 설명을 피하기 위해, 전체 소스는 맨 마지막에 싣기로 하고 지난 시간과 다른 부분 위주로 언급하도록 하겠습니다.

우선 캔바스 내에서의 마우스 클릭을 인식하는 이벤트는 jQuery 로 처리하였습니다.
jQuery 의 문서 로딩 완료 이벤트 내부에 myCanvas 의 mousedown 이벤트를 아래와 같이 정의합니다.

$(document).ready(function(){
	Init();
	setInterval(Run, 20);
	$("#MyCanvas").mousedown(function(){
		var x=event.x - $("#MyCanvas").offset().left;
		var y=event.y - $("#MyCanvas").offset().top;
		onMouseDown(x, y);
	});
});

캔바스와 같은 특정 오브젝트 위에서 마우스 클릭을 감지할 때는 기본적으로 아래 이벤트를 정의해서 사용합니다.

$("#MyCanvas").mousedown(function(){
           :
});

그리고 event.x 와 event.y 라는 요소에 마우스로 클릭한 위치가 기본적으로 들어있는데

주의할 부분이 있습니다.

마우스로 클릭한 event.x 와 event.y 는 캔바스 내에서의 좌표가 아니라,

웹페이지의 왼쪽 상단을 기준으로 한 좌표이기 때문에,

event.x, event.y 값에서 캔바스의 상대 좌표만큼을 빼 주어야 합니다.

해당 부분을 반영한 소스가 바로 여기입니다.

		// 웹페이지에서 캔버스 시작 위치를 차감한 x, y좌표
		// 캔버스 내부의 좌표로 계산된다
		var x=event.x - $("#MyCanvas").offset().left;
		var y=event.y - $("#MyCanvas").offset().top;

그리고 이어서 onMouseDown(x, y); 라는 함수를 호출해줍니다.

		onMouseDown(x, y);

onMouseDown(x, y) 함수에서는 무슨 일을 할까요?

1개의 원 파동을 생성합니다.

제일 먼저 오브젝트를 생성한 다음,

// mousedown 이벤트 ( 캔바스 내 )
function onMouseDown(x, y)
{
	var obj=new Object();

마우스로 클릭한 캔바스내 지점 x, y 좌표를 오브젝트 속성으로 지정합니다.

	obj.x=x;
	obj.y=y;

그리고 초기 파동원의 크기와 생명주기를 정해줍니다.

	obj.size=5;
	obj.lifetime=100;

그런 다음 Circles 배열변수에 집어넣어 버립니다.

사실 이 배열변수는 전역변수로 이미 생성된 변수이지요.

두번 클릭하면 2개의 객체가, 세번 클릭하면 3개의 객체가 추가되겠지요

var Circles=new Array();

              :

	Circles.push(obj);

마우스 클릭에 따른 동작은 이걸로 끝입니다.

그 다음에는 시간이 흘러감에 따라 원의 파동이 점점 커지면서 생명주기만큼 작동하는 부분이 연출되는데요.

Run() 함수에서 그 부분을 담당합니다.

우선 생성된 모든 객체 갯수만큼 반복을 수행합니다.

지난 시간에는 갯수를 딱 정해놓았지만, 이번에는 갯수가 늘어났다 줄어들었다 하는 가변 배열입니다.

배열 변수의 크기는 배열변수.length 라는 속성으로 쉽게 판단이 가능하므로

0부터 Circles.length 바로 전까지 반복을 수행하는 for 루프를 구성합니다.

function Run()
{
	for(i=0;i<Circles.length;++i)
	{
               :
    }

그리고 원의 크기를 점점 키웁니다.

더하기보다는 곱하기가 더 확대되는 느낌이 부드러운데요.

여기서는 현재값에 1.05를 곱해줍니다.

이 공식은 시간이 지날수록 점점 그 확대폭이 커지기 때문에 매우 자연스럽습니다.

		Circles[i].size=Circles[i].size * 1.05;

아울러 생명주기를 하나 감소합니다.

		Circles[i].lifetime--;

이 생명주기가 점점 감소하는 과정에 마침내 0에 다다랐을때,

배열 객체에서 이 객체를 완전히 지워버립니다.

Circles.splice(i,1) 명령어는 Circles 배열객체에서 i번째부터 1개를 삭제하는 명령어입니다.

		if(Circles[i].lifetime<=0)
			Circles.splice(i,1);

반복문을 끝내고 마침내 onDraw() 함수를 호출합니다.

	onDraw();

onDraw 함수에서는 여지껏 상상의 나래(?) 속에서 변수 끼리만 논리적으로 연출했던 시뮬레이션을 실제 캔바스 위에 그리는 부분입니다.

테두리와 배경을 색칠하는 부분은 그냥 넘어간다 치고,

반복문을 통해, 파동원을 그려주는 부분입니다.

배열 객체의 반복문을 구성해주고

	for(i=0;i<Circles.length;++i)
	{
          :
	}

반복문 내에서 그리기 동작을 시작합니다.

지난번 눈내리기에서는 눈 내부를 채우기 위해 fillStyle을 사용했었지만,

이번에는 테두리를 그리는게 목적이기 때문에, strokeStyle 을 사용합니다.

아울러 생명주기에 따라 색상의 투명도를 점점 희미하게 주기 때문에 서서히 사라지는 효과도 있습니다.

	for(i=0;i<Circles.length;++i)
	{
		Context.beginPath();
		Context.strokeStyle=
			'rgba(0,0,0,' + Circles[i].lifetime/100 + ')';
		Context.lineWidth=1;

그리고 원을 그려줍니다. Circles[i].size 항목이 원의 크기이므로 원이 점점 커집니다.

		Context.arc(
			Circles[i].x,		// 가로좌표
			Circles[i].y,		// 세로좌표
			Circles[i].size,	// 원 크기
			0,				// 원호의 시작
			Math.PI * 2		// 원호의 끝
		);

그리기를 마무리하고 그린 요소에 선 그리기를 적용합니다.

		Context.closePath();
		Context.stroke();

여기까지가 대략적인 설명이지만,

아무래도 전체 소스를 보는 것이 더 도움이 될 수도 있을듯 하군요 :)

전체 소스 공개합니다.

<!DOCTYPE html>
<html lang="ko">
<head>
	<meta charset="UTF-8">
	<title>캔바스 샘플#4. 마우스 이벤트</title>
</head>
<body>
https://blog.naver.com/ephraimdrlee 
/ 크레이의 세컨드라이프 탐구생활 네이버 블로그<br/>
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script>
// 기본 초기화
var init=false;
var myCanvas;
var Context;
var Circles=new Array();

// 초기화
function Init()
{
	if(init==false)
	{
		myCanvas=document.getElementById("MyCanvas");
		Context=myCanvas.getContext("2d");
		
		init=true;
	}
}

function Run()
{
	for(i=0;i<Circles.length;++i)
	{
		Circles[i].size=Circles[i].size * 1.05;
		Circles[i].lifetime--;
		if(Circles[i].lifetime<=0)
			Circles.splice(i,1);
	}
	onDraw();
	$("#debug").text(Circles.length);
}

// mousedown 이벤트 ( 캔바스 내 )
function onMouseDown(x, y)
{
	var obj=new Object();
	obj.x=x;
	obj.y=y;
	obj.size=5;
	obj.lifetime=100;
	Circles.push(obj);
}

// draw 이벤트
function onDraw()
{
	if(init==false)return;
	Context.strokeStyle="#000";
	Context.lineWidth=1;
	Context.strokeRect(0, 0, myCanvas.width-1, myCanvas.height-1);
	Context.fillStyle="#fcfcfc";
	Context.fillRect(1, 1, myCanvas.width-2, myCanvas.height-2);
	for(i=0;i<Circles.length;++i)
	{
		Context.beginPath();
		Context.strokeStyle=
			'rgba(0,0,0,' + Circles[i].lifetime/100 + ')';
		Context.lineWidth=1;
		Context.arc(
			Circles[i].x,		// 가로좌표
			Circles[i].y,		// 세로좌표
			Circles[i].size,	// 원 크기
			0,				// 원호의 시작
			Math.PI * 2		// 원호의 끝
		);
		Context.closePath();
		Context.stroke();
	}
}

$(document).ready(function(){
	Init();
	setInterval(Run, 20);
	$("#MyCanvas").mousedown(function(){
		// 웹페이지에서 캔버스 시작 위치를 차감한 x, y좌표
		// 캔버스 내부의 좌표로 계산된다
		var x=event.x - $("#MyCanvas").offset().left;
		var y=event.y - $("#MyCanvas").offset().top;
		
		onMouseDown(x, y);
	});
});

</script>

<canvas id="MyCanvas" width=800 height=600>
Canvas is not supported.
</canvas>
<span id=debug></span>
</body>
</html>

아무쪼록 따라하시는 모든 분들은 꼭 성공하시기를 바랍니다.
리얼타임 프로그래밍에 익숙하지 않은 경우 입문자분에게는 초반에 좀 어려울 수 있으나 반복해서 읽어주시면 감이 오실 겁니다 :)
여기까지 읽어주셔서 감사합니다.

다음 강좌 보러가기 / https://itadventure.tistory.com/136

 

자바스크립트와 캔버스, 5번째 시간. 테트리스를 만들어봐-1

1. HTML 표준 CANVAS 기술 소개 / https://itadventure.tistory.com/130 2. 자바스크립트와 CANVAS 두번째시간. 캔바스에 눈을 내리자 / https://itadventure.tistory.com/131 3. 자바스크립트와 캔버스 3번째 시..

itadventure.tistory.com