canvas를 활용한 웹 인터랙션
그림판 만들 때 처음 접한 canvas :)
미니게임 강의들을 때에 간혹 접하고는 했었는데, 웹에서 canvas를 활용한 UI가 있길래 강의 토대로 만들어보고 정리해봄
일단 심플하게 마크업을 해주고...
<div class="video-wrap">
<video autoplay muted loop id="heroVideo">
<source src="./video.mp4" type="video/mp4">
</video>
</div>
<div class="container">
<div>
<h1>
<a href="#">HelloCoding</a>
</h1>
<div class="nav-list">
<a href="#">Projects</a>
<a href="#">About Us</a>
<a href="#">Contact</a>
<a href="#">Careers</a>
</div>
</div>
</div>
<div class="visual-copy">
<strong>Hello Coding</strong>
<p>Welcome to the coding world.</p>
</div>
.
<!-- 그 외 생략 -->
.
<canvas id="draw"></canvas>
js로 canvas를 불러와 기본 세팅부터 해줌
const canvas = document.querySelector('canvas');
const ctx = canvas.getContext('2d');
canvas.width = innerWidth; //캔버스 너비
canvas.height = innerHeight; //캔버스 높이
ctx.lineJoin = 'round'; //선 모서리 둥글게
ctx.lineCap = 'round'; //선 끝 둥글게
ctx.lineWidth = 100; //선 두께
간단한 작업 step👇
검은 배경은 fillRect로 캔버스 크기만큼 덮어주고
ctx.fillStyle = 'black';
ctx.fillRect(0, 0, canvas.width, canvas.height);
마우스가 움직일 때 그려지도록 draw라는 함수를 만들어줌.
이때 마우스 위치값을 담을 변수가 필요함
let lastX = 0;
let lastY = 0;
function draw(e){
ctx.beginPath();
ctx.moveTo(lastX, lastY);
ctx.lineTo(e.offsetX, e.offsetY);
ctx.stroke();
[lastX, lastY] = [e.offsetX, e.offsetY];
}
canvas.addEventListener('mousemove', draw);
mousemove 될 때 마우스 위치값을 시작으로 e.offsetX, e.offsetY 현재 움직이는 위치값까지 라인이 그려지게끔 해주고,
[lastX, lastY] = [e.offsetX, e.offsetY]
마우스 위치값에 움직인 위치값을 할당해줌
그럼 마우스 움직일 때마다 위치값이 변경되며 라인이 마우스 움직임대로 따라오게 됨
but 마우스가 움직일 때마다 그려지면 안 됨;
누른 상태에서 움직일 때 그려지고 떼면 그려지지 않도록 해줘야 하기때문에 현재 그리고있는지 아닌지를 판단할 수 있는 변수가 필요함
let isDrawing = false; //현재 drawing X
canvas.addEventListener('mousedown', () => {isDrawing = true;})
canvas.addEventListener('mouseup', () => {isDrawing = false;})
canvas.addEventListener('mouseout', () => {isDrawing = false;})
mousedown 하면 isDrawing이 true로 바뀌고 mouseup 하면 다시 false가 되도록 함, 마찬가지로 마우스가 벗어나면 그려지지 않도록 mouseout 도 똑같이 해줌
마지막으로 draw() 에 isDrawing 조건문을 넣어줌
function draw(e){
if(!isDrawing) return [lastX, lastY] = [window.offsetX, window.offsetY];
ctx.beginPath();
ctx.moveTo(lastX, lastY);
ctx.lineTo(e.offsetX, e.offsetY);
ctx.stroke();
[lastX, lastY] = [e.offsetX, e.offsetY];
}
isDrawing이 false 면 [lastX, lastY] = [window.offsetX, window.offsetY] 을 리턴하도록 해줌
누르지않아도 마우스 움직임을 읽어주도록해야 잘 그려짐, [lastX, lastY] = [window.offsetX, window.offsetY] 값 빼버리면 선이 뚝뚝 끊어지는 오류가 생김
선이 그려지기는 하지만 strokeStyle 기본값인 검정으로 그려지고 있음, 이를 투명으로 지우개 역할을 하듯 바꿔줘야 함
✨Canvas 2D API에서 제공하는 속성을 사용하면 됨🫢
globalCompositeOperation
: Canvas 2D API에서 제공되는 속성으로, 전역 복합(compositing) 연산을 설정하여 이미지의 그리는 방식을 제어한다.
설명들으니 무슨 소리인가 싶지만, 간단하게
캔버스에 그리려는 색이 그려져 있던 색과 겹쳐질때 어떤식으로 조합할지 정하는 기능이라 함
(포토샵의 블렌딩모드 느낌이라 생각하면 좋을 듯)
여기서 필요한 속성값은 destination-out.
ctx.globalCompositeOperation = 'destination-out';
현재 그림이 이미 그려진 내용을 삭제, 즉 투명하게 만들어줘서 '지우개로 이미 그려진 그림을 지우는' 듯한 효과를 줌
👍그럼 끝👍
✍️globalCompositeOperation 속성값 살펴보기
source-over: 새로운 그림이 기존 그림 위에 그려진다.
source-in: 새로운 그림과 기존 그림이 겹치는 부분만 남는다.
source-out: 새로운 그림과 기존 그림이 겹치지 않는 부분만 남는다.
source-atop: 새로운 그림은 기존 그림 위에 그려지지만, 겹치지 않는 부분만 기존 그림이 남는다.
destination-over: 새로운 그림이 기존 그림 뒤에 그려진다.
destination-in: 기존 그림과 새로운 그림이 겹치는 부분만 남는다.
destination-out: 기존 그림과 새로운 그림이 겹치지 않는 부분만 남는다.
destination-atop: 기존 그림은 새로운 그림 위에 그려지지만, 겹치지 않는 부분만 새로운 그림이 남는다.
lighter: 새로운 그림이 기존 그림과 합성되어 겹쳐진다.
copy: 새로운 그림으로 기존 그림을 완전히 대체한다.
xor: 새로운 그림과 기존 그림이 겹치지 않는 부분만 남는다.
