이전글 : [Canvas-불꽃놀이-02] UI 구성
캔버스 기본 세팅
1. 캔버스 설정하기
대략적인 UI 구성이 완료되어 canvas를 설정하고자 한다.
- Canvas Class : 캔버스에 그림을 그리는 로직, 애니메이션, 파티클 생성을 담당해 화면에 실제로 그리는 핵심 로직을 담당
- CanvasOption Class : 캔버스의 ctx, 크기, 색상, 폰트, 해상도 등 기본 옵션을 정의하고 관리
이렇게 옵션 설정과 그리기를 분리하여 한 클래스에 모든 로직이 집중되지 않게 하고 모듈화를 통해 재사용성과 유지보수를 용이하게 만들었다. 프로젝트의 확장이 필요할 때도 비교적 유연하게 대응할 수 있다.
2. CanvasOption 클래스
2-1. 캔버스 객체를 불러오고 애니메이션 기본 설정 해주기
- 캔버스 객체를 생성하고 만약 실패시 에러를 던진다.
- 상수값 관리를 편하게 하기 위해 상수 파일을 생성해 사용하였다.
- interval : 설정된 fps 기반으로 각 프레임 사이의 시간 간격을 계산한다. 예를 들어 1초에 60 프레임을 렌더 하면 대략 16.67 밀리초 간격으로 프레임이 업데이트된다.
class CanvasOption {
constructor() {
this.canvas = document.getElementById("canvas");
if (!this.canvas) {
throw new Error("캔버스 객체를 발견하지 못했습니다. 다시 확인해주세요.");
}
// 2d 컨텍스트를 불러오고 이미지를 그릴 때 성능 최적화를 위해 willReadFrequently 설정 추가
this.ctx = this.canvas.getContext("2d", { willReadFrequently: true });
// 초당 렌더링할 프레임 수
this.fps = ANIMATION.FPS;
// 프레임간 간격을 계산하여 각 프레임이 그려지는 시간 간격을 설정 (밀리초 단위)
this.interval = 1000 / this.fps;
}
}
2-2. 캔버스 멤버 변수 초기화
- 리사이즈 이벤트가 일어나면 변경된 크기에 맞춰 캔버스의 설정을 변경해야 하므로 캔버스 사이즈 크기에 영향을 받는 멤버변수들은 따로 멤버변수 초기화 함수함수를 통해 설정
// CanvasOption.js
initCanvasOptionVars() {
// 최대 3으로 설정하여 성능저하 방지
this.dpr = Math.min(Math.round(window.devicePixelRatio), SCREEN.MAX_DPR) || 1;
// 캔버스 태그 자체의 width, height
this.canvasCssWidth = window.innerWidth;
this.canvasCssHeight = window.innerHeight;
// 모바일 화면 여부 판별
this.isSmallScreen = window.matchMedia(`(max-width: ${SCREEN.SMALL_WIDTH}px)`).matches;
// 메인 텍스트 기본 좌표값
this.mainX = this.canvasCssWidth / POS.MAIN_X_DIVISOR;
this.mainY = Math.floor(this.canvasCssHeight * POS.MAIN_Y_RATIO);
// 텍스트별 폰트 사이즈
this.mainFontSize = this.setMainFontSize();
this.subFontSize = this.setSubFontSize();
}
/**
* @param {number} fontSize
* @returns {number} 메인 폰트 사이즈 반환 (작은 화면일 경우 별도의 비율 적용)
*/
setMainFontSize(fontSize) {
if (!fontSize) {
// 캔버스 font에는 반응형 적용이 안되니 화면 크기에 따라 폰트 사이즈를 설정해 반응형같은 효과를 만듬
const ratio = this.isSmallScreen ? FONT.MAIN_RATIO_SMALL : FONT.MAIN_RATIO_GENERAL;
fontSize = ((this.canvasCssWidth + this.canvasCssHeight) / 2) * ratio;
}
return Math.round(fontSize);
}
/**
* @returns {number} 서브 폰트 사이즈 반환
*/
setSubFontSize() {
return Math.round(this.mainFontSize) * FONT.SUB_RATIO;
}
2-3. 설정 초기화를 위한 init 함수 생성
- 클래스 인스턴스 생성할 때 초기화하고, 화면 사이즈 변경 시에도 영향을 받는 멤버 변수의 값을 업데이트하기 위해 초기화를 위한 init 메서드를 만들고 initCanvasOptionVars() 메서드를 실행시킨다.
class CanvasOption {
constructor() {
this.canvas = document.getElementById("canvas");
if (!this.canvas) {
throw new Error("캔버스 객체를 발견하지 못했습니다. 다시 확인해주세요.");
}
this.ctx = this.canvas.getContext("2d", { willReadFrequently: true });
this.fps = ANIMATION.FPS;
this.interval = 1000 / this.fps;
// 멤버변수 초기화
this.initCanvasOptionVars();
}
init() {
this.initCanvasOptionVars();
}
// 생략 ......
}
3. Canvas 클래스
- CanvasOption 클래스에서 설정한 캔버스 옵션을 사용하기 위해 Canvas 클래스는 CanvasOption 클래스를 상속받는다.
- 불꽃놀이 화면(canvas)에 진입 시 init 함수를 실행하여 캔버스 객체 멤버변수의 초기화를 진행한다.
- 캔버스 화면에서 선명한 이미지 구현을 위해 캔버스의 크기를 물리적 크기와 CSS 크기를 같이 사용한다. dpr(Device Pixel Ratio)를 활용하여 캔버스의 픽셀 밀도를 높여 선명한 이미지를 렌더 할 수 있게 한다.
- 캔버스 물리적 크기 설정 : 캔버스 CSS크기에 dpr을 곱해 물리적 크기를 증가시킨다.
- 컨텍스트 스케일 조정 : 캔버스 렌더링 단위를 dpr만큼 확대하여 고해상도를 반영하도록 설정한다
- dpr을 곱해서 캔버스 물리적 크기를 키우면 물리적인 픽셀 수는 늘어나나 캔버스의 렌더링 스케일은 물리적 크기를 키우기 전 사이즈다
- 그래서 물리적 크기가 늘어난 만큼 캔버스 렌더링 스케일을 dpr 크기만큼 키우면 (픽셀 크기 == 렌더링 스케일)이 되니 고화질로 렌더링 할 수 있게 된다.
- 예를 들어 캔버스 물리적 크기가 500px인데 dpr(2)를 곱하면 캔버스의 물리적 크기는 1000px이 된다. 이때 렌더링 스케일도 dpr에 맞춰 같이 확대하지 않으면 500px 기준으로 그려진 이미지를 1000px로 맞춰서 그려야 하니 이미지가 흐려지게 된다.
- 캔버스 CSS 크기 설정 : 캔버스 태그의 스타일을 현재 창크기에 맞춰 확대된 픽셀 밀도에도 화면에 현재 창의 크기대로 보일 수 있게 유지한다.
class Canvas extends CanvasOption {
consturctor() {
super();
}
init() {
// 리사이즈시 CanvasOption도 수정해야 하므로 부모클래스의 init 메서드도 실행한다.
super.init();
// 고해상도를 위한 캔버스 물리적 크기 설정
this.canvas.width = this.canvasCssWidth * this.dpr;
this.canvas.height = this.canvasCssHeight * this.dpr;
this.ctx.scale(this.dpr, this.dpr);
// 캔버스 CSS 크기는 선명한 이미지를 유지할 수 있도록 현재 창 크기로 설정
this.canvas.style.width = `${this.canvasCssWidth}px`;
this.canvas.style.height = `${this.canvasCssHeight}px`;
}
}
Github 링크
'Canvas > 불꽃놀이 프로젝트' 카테고리의 다른 글
[Canvas-불꽃놀이-06] TextData 클래스 (2) | 2024.11.18 |
---|---|
[Canvas-불꽃놀이-05] index.js에서 중요 이벤트 정의 (1) | 2024.11.18 |
[Canvas-불꽃놀이-04] Canvas 설정 - 물리적 크기와 CSS 크기 (0) | 2024.11.17 |
[Canvas-불꽃놀이-02] UI 구성 (3) | 2024.11.16 |
[Canvas-불꽃놀이-01] 프로젝트 초기화 (1) | 2024.11.15 |