Canvas API란?
Canvas API는 Javascript와 HTML을 이용해서 그래픽을 처리를 할 수 있게 도와줍니다. 이 API를 이용해서 애니메이션, 그림, 비디오등을 처리 할 수 있고, 이번에 소개해 드릴 2D 및 3D 그래픽을 그립니다.
Canvas API 기본적인 예시
Canvas API를 이용한 간단한 예시를 보여드리겠습니다.
<canvas id="scene"></canvas>
//html id가 scene인 값을 참조 합니다.
const canvas = document.getElementById("scene");
//렌더링이 될 수 있는 대상을 얻는 메소드를 얻습니다.
//HTMLCanvasElement.getContext() => 캔버스의 드로잉 컨텍스트를 반환 합니다. 지원이 되지 않는 다면
//null를 반환
const ctx = canvas.getContext("2d");
// 캔버스 전체를 green으로 채우기
ctx.fillStyle = "green";
//처음 부터 x,y, width, height을 주는 메소드 이므로
// 상단 좌즉 10, 10인 곳에 배치하고 높이와 넓이를 150으로 지정
ctx.fillRect(10, 10, 150, 100);
이렇게 하면 저희는 아래의 사진처럼 상단 좌측의 초록색의 150, 100의 contents를 얻을 수 있습니다.
3D 그래픽 만들기
<canvas id="scene"></canvas>
console.clear();
// Get the canvas element from the DOM
const canvas = document.querySelector("#scene");
canvas.width = canvas.clientWidth;
canvas.height = canvas.clientHeight;
// Store the 2D context
const ctx = canvas.getContext("2d");
if (window.devicePixelRatio > 1) {
canvas.width = canvas.clientWidth * 2;
canvas.height = canvas.clientHeight * 2;
ctx.scale(2, 2);
}
/* ====================== */
/* ====== VARIABLES ===== */
/* ====================== */
let width = canvas.clientWidth; // Width of the canvas
let height = canvas.clientHeight; // Height of the canvas
let rotation = 0; // Rotation of the globe
let dots = []; // Every dots in an array
/* ====================== */
/* ====== CONSTANTS ===== */
/* ====================== */
/* Some of those constants may change if the user resizes their screen but I still strongly believe they belong to the Constants part of the variables */
const DOTS_AMOUNT = 1000; // Amount of dots on the screen
const DOT_RADIUS = 4; // Radius of the dots
let GLOBE_RADIUS = width * 0.7; // Radius of the globe
let GLOBE_CENTER_Z = -GLOBE_RADIUS; // Z value of the globe center
let PROJECTION_CENTER_X = width / 2; // X center of the canvas HTML
let PROJECTION_CENTER_Y = height / 2; // Y center of the canvas HTML
let FIELD_OF_VIEW = width * 0.8;
//canvas 스크린에 보이는 점들을 표시해 주는 함수
// y좌표 x좌표 z좌표 설정 후 에 sin값과 cos값을 이용해서 Dot위치를 설정해 준다.
class Dot {
constructor(x, y, z) {
this.x = x;
this.y = y;
this.z = z;
this.xProject = 0;
this.yProject = 0;
this.sizeProjection = 0;
}
// Do some math to project the 3D position into the 2D canvas
project(sin, cos) {
const rotX = cos * this.x + sin * (this.z - GLOBE_CENTER_Z);
const rotZ =
-sin * this.x + cos * (this.z - GLOBE_CENTER_Z) + GLOBE_CENTER_Z;
this.sizeProjection = FIELD_OF_VIEW / (FIELD_OF_VIEW - rotZ);
this.xProject = rotX * this.sizeProjection + PROJECTION_CENTER_X;
this.yProject = this.y * this.sizeProjection + PROJECTION_CENTER_Y;
}
// Draw the dot on the canvas
draw(sin, cos) {
this.project(sin, cos);
// ctx.fillRect(this.xProject - DOT_RADIUS, this.yProject - DOT_RADIUS, DOT_RADIUS * 2 * this.sizeProjection, DOT_RADIUS * 2 * this.sizeProjection);
ctx.beginPath();
ctx.arc(
this.xProject,
this.yProject,
DOT_RADIUS * this.sizeProjection,
0,
Math.PI * 2
);
ctx.closePath();
ctx.fill();
}
}
//Dot 생성 후 Array로 저장한다
// 이부분의 저장이 실제 구 에서 보여지는 값
function createDots() {
// Empty the array of dots
dots.length = 0;
// Create a new dot based on the amount needed
for (let i = 0; i < DOTS_AMOUNT; i++) {
const theta = Math.random() * 2 * Math.PI; // Random value between [0, 2PI]
const phi = Math.acos(Math.random() * 2 - 1); // Random value between [-1, 1]
// Calculate the [x, y, z] coordinates of the dot along the globe
const x = GLOBE_RADIUS * Math.sin(phi) * Math.cos(theta);
const y = GLOBE_RADIUS * Math.sin(phi) * Math.sin(theta);
const z = GLOBE_RADIUS * Math.cos(phi) + GLOBE_CENTER_Z;
dots.push(new Dot(x, y, z));
}
}
/* ====================== */
/* ======== RENDER ====== */
/* ====================== */
function render(a) {
// Clear the scene
ctx.clearRect(0, 0, width, height);
// Increase the globe rotation
rotation = a * 0.0004;
const sineRotation = Math.sin(rotation); // Sine of the rotation
const cosineRotation = Math.cos(rotation); // Cosine of the rotation
//Dot 찍기 시작
// Loop through the dots array and draw every dot
for (var i = 0; i < dots.length; i++) {
dots[i].draw(sineRotation, cosineRotation);
}
window.requestAnimationFrame(render);
}
// Function called after the user resized its screen
function afterResize() {
width = canvas.offsetWidth;
height = canvas.offsetHeight;
if (window.devicePixelRatio > 1) {
canvas.width = canvas.clientWidth * 2;
canvas.height = canvas.clientHeight * 2;
ctx.scale(2, 2);
} else {
canvas.width = width;
canvas.height = height;
}
GLOBE_RADIUS = width * 0.7;
GLOBE_CENTER_Z = -GLOBE_RADIUS;
PROJECTION_CENTER_X = width / 2;
PROJECTION_CENTER_Y = height / 2;
FIELD_OF_VIEW = width * 0.8;
createDots(); // Reset all dots
}
// Variable used to store a timeout when user resized its screen
let resizeTimeout;
// Function called right after user resized its screen
function onResize() {
// Clear the timeout variable
resizeTimeout = window.clearTimeout(resizeTimeout);
// Store a new timeout to avoid calling afterResize for every resize event
// resizeTimeout = window.setTimeout(afterResize, 500);
}
window.addEventListener("resize", onResize);
// Populate the dots array with random dots
createDots();
// Render the scene
// canvas에 렌더 되는 함수 (중요)
window.requestAnimationFrame(render);
위에 처럼 코드르 짠 후 렌더된 html을 보게 되면 아래 사진처럼 보이게 될 것이다(실제로는 회전함…)
주의
좌표값을 구할 때 일반적인 평면이 아닌 입체여서 좌표값이 3개로 나와해서 힘들 수 있다.
참조
https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer https://wsss.tistory.com/25 https://www.basedesign.com/blog/how-to-render-3d-in-2d-canvas