Canvas를 사용하기 위해서는 html에서
<canvas id="draw" width="800" height="800"></canvas> 를 선언해 준 후
JS에서 기본 세팅을 시작한다
JS 베이스 세팅
// 캔버스 대지를 가져오고, 앞으로 context는 2d임을 canvas에 명시
const canvas = document.querySelector('#draw');
const ctx = canvas.getContext('2d');
// 기본 캔버스 사이즈를 window 크기 전체로 늘려 줌
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
// Base-setting
ctx.strokeStyle = '#BADA55';
ctx.lineJoin = 'round';
ctx.lineCap = 'round';
ctx.lineWidth = 100;
canvas에 대한 접근은 canvas.getContext 로 접근이 가능하고 canvas는 2d와 3d를 제공한다. 매번 getContext로 접근하기 번거로우므로 ctx(canvas context)라는 변수에 할당하고 접근 해줌
context는 다양한 속성이 있는데, 이 강의에서는 아래의 요소들을 사용 👇
- strokeStyle (선 색, RGB, hexcode, RGBA, 색상 이름)
- lineJoin (선과 선을 이을 때 마무리 스타일을 지정, round, butt, squere)
- lineCap (선 끝의 마무리 스타일을 지정 round , butt, squere)
선 그리기
ctx.beginPath(); // 선을 그리기 위해 호출
ctx.moveTo(lastX, lastY); // 선의 시작 점
ctx.lineTo(e.offsetX, e.offsetY); // 선의 마지막 지점
ctx.stroke(); // 그리기(호출 필수)
- e.offset 은 마우스의 위치를 반환한다. event를 mousemove에 걸어주었기 때문에 mousemove event의 offset 속성 즉 현재 마우스의 위치를 계속 가지고 있음
let direction = true;
function draw(e) {
if (!isDrawing) return; // 마우스 클릭 여부에 따라 그릴지 말지
ctx.strokeStyle = `hsl(${hue}, 100%, 50%)`;
ctx.beginPath();
ctx.moveTo(lastX, lastY);
ctx.lineTo(e.offsetX, e.offsetY);
ctx.stroke();
[lastX, lastY] = [e.offsetX, e.offsetY];
// 끝점을 시작점으로 바꿔줌
hue++;
if (hue >= 360) {
hue = 0;
}
if (ctx.lineWidth >= 100 || ctx.lineWidth <= 1) {
direction = !direction;
}
if (direction) {
ctx.lineWidth++;
} else {
ctx.lineWidth--;
}
}
- hue 선에 다양한 스타일을 넣어주기 위해 hue값을 지정하고 hue++로 계속 올라가게 해 놓음(무지개 색 선이 나옴) 360의 값이 최대이므로 최대 값을 넘으면 다시 0부터 시작하게 함 (설정하지 않아도 hue값은 계속 루프되지만 lineWidth와 연동할 것 이기 때문)
- lineWidth lineWidth를 hue값과 연동하여 선의 굵기도 조절되게 함 hue가 계속 늘어나면 선의 두께가 무한정 두꺼워지므로 2개의 if문으로 100이상 늘어나면(if 1) 다시 서서히 줄어들도록 함(if 2)
선 그리기 & 캔버스 초기화
// 오른쪽 마우스 클릭 시 나오는 메뉴 막기
canvas.addEventListener('contextmenu', (e) => {e.preventDefault(); return false});
// 마우스를 클릭하면 drawing을 시작하게 하는 함수에
// 왼, 오른 마우스를 구분하는 if를 넣어줌
canvas.addEventListener('mousedown', (e) => {
if (e.which === 1) {
isDrawing = true;
[lastX, lastY] = [e.offsetX, e.offsetY];
} else if (e.which === 3) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
});
canvas.addEventListener('mouseup', () => isDrawing = false);
canvas.addEventListener('mouseout', () => isDrawing = false);
- which는 마우스의 왼쪽 오른쪽에 해당하는 값을 반환해준다. 마우스 왼쪽은 1, 스크롤은 2, 마우스 오른쪽은 3의 값을 가짐
- 그려지는 순서
마우스 왼쪽 클릭 → mousedown함수 실행 → isDrawing 을 true로 바꿔 mousemove event의 draw함수를 실행 → 마우스를 떼거나(mouseup), 마우스가 화면 밖으로 나가면(mouseout) isDrawing이 false가 되어 draw함수에서 선 그리기를 멈춤
<body>
<canvas id="draw" width="800" height="800"></canvas>
<script>
// 캔버스 대지를 가져오고, 앞으로 context는 2d임을 canvas에 명시
const canvas = document.querySelector('#draw');
const ctx = canvas.getContext('2d');
// 기본 캔버스 사이즈를 window 크기 전체로 늘려 줌
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
// Base-setting
ctx.strokeStyle = '#BADA55';
ctx.lineJoin = 'round';
ctx.lineCap = 'round';
ctx.lineWidth = 100;
// drawing flag
let isDrawing = false;
// line 시작과 끝을 지정해 줄 변수
let lastX = 0;
let lastY = 0;
let hue = 0;
let direction = true;
function draw(e) {
if (!isDrawing) return; // isDraw가 true가 아닐때는 실행X
console.log(e);
ctx.strokeStyle = `hsl(${hue}, 100%, 50%)`;
// ctx.lineWidth = hue;
ctx.beginPath(); // 시작
ctx.moveTo(lastX, lastY); // 끝
ctx.lineTo(e.offsetX, e.offsetY);
ctx.stroke(); // 그리기
[lastX, lastY] = [e.offsetX, e.offsetY]; // 끝점을 시작점으로 바꿔줌
hue++;
if (hue >= 360) {
hue = 0;
}
if (ctx.lineWidth >= 100 || ctx.lineWidth <= 1) {
direction = !direction;
}
if (direction) {
ctx.lineWidth++;
} else {
ctx.lineWidth--;
}
}
// 마우스를 움직이는 것을 감지
canvas.addEventListener('mousemove', draw);
canvas.addEventListener('mousedown', (e) => {
if (e.which === 1) {
isDrawing = true;
[lastX, lastY] = [e.offsetX, e.offsetY];
} else if (e.which === 3) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
});
canvas.addEventListener('mouseup', () => isDrawing = false);
canvas.addEventListener('mouseout', () => isDrawing = false);
canvas.addEventListener('contextmenu', (e) => {e.preventDefault(); return false});
</script>
<style>
html, body {
margin: 0;
}
</style>
</body>
'DEV > JS30' 카테고리의 다른 글
[JS30] day 10 - Hold shift to check multiple checkboxes (0) | 2021.12.28 |
---|---|
[JS30] day 9 - 14 Must know dev tools tricks (0) | 2021.12.28 |
[JS30] day 7 - Array cardio day 2 (0) | 2021.12.12 |
[JS30] day 6 - Ajax type ahead (0) | 2021.12.12 |
[JS30] day 5 - Flex panels image gallery (0) | 2021.12.09 |