JavaScript와 캔버스(Canvas)를 사용하여 룰렛을 구현해보았습니다.
코드
코드 풀이
const $c = document.querySelector("canvas");
const ctx = $c.getContext(`2d`);
// 룰렛에 들어갈 항목
const product = [
"떡볶이", '돈가스', "초밥", "피자", "냉면", "치킨", '족발', "피자", "삼겹살",
];
// 각 항목에 해당하는 색상
const colors = [
"#dc0936", "#e6471d", "#f7a416",
"#efe61f ", "#60b236", "#209b6c",
"#169ed8", "#3f297e", "#87207b",
"#be107f", "#e7167b"
];
먼저 룰렛을 그려줄 Canvas 요소와 룰렛에 추가할 상품 목록과 해당하는 색상 배열을 정의해줍니다.
const newMake = () => {
const [cw, ch] = [$c.width / 2, $c.height / 2];
const arc = Math.PI / (product.length / 2);
// 룰렛 배경 그리기
for (let i = 0; i < product.length; i++) {
ctx.beginPath();
ctx.fillStyle = colors[i % (colors.length -1)];
ctx.moveTo(cw, ch);
ctx.arc(cw, ch, cw, arc * (i - 1), arc * i);
ctx.fill();
ctx.closePath();
}
...
newMake 함수를 정의해주고, 그려줄 캔버스의 중점 위치를 구해야 합니다. 그러기 위해서는 Canvas의 Width, Height 절반의 값을 통해서 얻을 수 있습니다.
그리고 룰렛에 그릴 항목의 수에 따른 항목의 크기 값을 구해줍니다. 해당 값을 통해 동그란 룰렛에 각 영역을 그리는 방법은 arc 메서드를 이용하는 방법입니다.
arc 메서드를 호출하기 전에, 색칠할 색상을 변경해주고, 그려줄 펜의 위치를 중점 위치로 옮겨주는 작업을 먼저 해줍니다.
// x, y -> 중점, radius -> 반지름(x와 같은 값)
ctx.arc(x, y, radius, startAngle, endAngle);
// ctx.arc(cw, ch, cw, arc * (i - 1), arc * i);
해당 메서드에서 핵심은 startAngle, endAngle 인자입니다. 항목 개수로 나눈 크기를 이용해서 (i - 1) ~ i 지점까지 만의 원을 그리는 코드를 작성해줍니다.
...
ctx.textAlign = "center"
// 그려진 배경 위에 텍스트 그리기
for (let i = 0; i < product.length; i++) {
const angle = (arc * i) + (arc / 2);
ctx.save();
ctx.translate(
cw + Math.cos(angle) * (cw - 50),
ch + Math.sin(angle) * (ch - 50),
);
ctx.rotate(angle + Math.PI / 2);
// 항목명에 띄어쓰기가 있을 시 줄바꿈
product[i].split(" ").forEach((text, j) => {
ctx.fillText(text, 0, 30 * j);
});
ctx.restore();
}
}
save, restore 메서드를 이용해서 속성 값이 적용된 캔버스의 설정 값(이미지 X)을 저장하고 가져올 수 있습니다. translate, rotate로 인해 변형된 콘텍스트 설정 값을 초기값으로 되돌려 주는 작업을 통해서 텍스트를 그려줍니다.
// 룰렛 돌리기
const rotate = () => {
// 룰렛 당첨 결정
const ran = Math.floor(Math.random() * product.length);
const arc = 360 / product.length;
const rotate = (ran * arc) + 3600 + (arc * 3);
$c.style.transform = `rotate(-${rotate}deg)`;
return ran;
};
// 함수 호출
const getResult = rotate();
setTimeout(() => alert(product[getResult]), 2000);
Math.random() 메서드를 통해서 랜덤 한 난수를 얻을 수 있습니다. 해당 수에 항목의 개수를 곱해주면 랜덤 한 당첨 결과를 얻을 수 있습니다.
랜덤 한 결과 값에 영역의 크기를 곱해서 룰렛의 위치를 맞추어주고, 360도를 10번 돌라는 의미의 3600을 추가로 더해줍니다. 추가로 오차범위를 조정하기 위해서 (arc * 3)의 수식을 추가로 사용하였습니다.
canvas {
transition: 2s;
}
마지막으로 CSS 코드로 canvas에 transition 속성을 2초 정도로 지정해주면, 완성입니다.
참고자료
https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/arc