이전 글 : 2024.11.18 - [개발/Canvas] - [Canvas-불꽃놀이-05] 화면 전환, 입력 이벤트 정의
파티클을 그릴때 필요한 데이터를 얻기 위해 TextData 클래스 생성
1. TextData class 생성
- 유저가 입력한 text를 캔버스에 그리고 픽셀 데이터를 가져오기 위해 TextData 클래스를 생성하였다.
- Canvas의 크기 설정과 관련된 속성을 사용하기 위해 CanvasOption을 상속하였다.
- strokeStyle을 black로 한 이유는 현재 배경색이 black이므로 혹시나 화면에 남아도 보여지지 않게 하기 위해서다.
// CanvasOption 상속
class TextData extends CanvasOption {
/**
* 사용자가 입력한 Text를 캔버스에 그리고 픽셀 데이터를 생성하기 위한 클래스
* @param {string} userInput
* @param {number} fontSize
*/
constructor(userInput, fontSize) {
super();
// 사용자가 입력한 text데이터와 설정할 폰트 사이즈
this.text = userInput;
this.fontSize = fontSize;
// ctx의 font관련 속성을 설정
this.ctx.font = this.setFontStyle(fontSize);
this.ctx.textAlign = "center";
this.ctx.textBaseline = "middle";
this.ctx.strokeStyle = "black";
// text를 그린 후 픽셀데이터를 저장하기 위한 멤버변수
this.textPixelData = {};
}
}
CanvasOption을 상속하여
- ctx의 font 속성을 설정할때 반복되는 코드를 줄이기 위해 CanvasOption 클래스에 폰트 스타일을 반환하는 메서드를 추가 하였다.
// CanvasOption.js에 추가
setFontStyle(fontSize) {
return `${fontSize}px ${FONT.FAMILY}`;
}
// constant.js FONT 객체에 추가
FAMILY: "Do Hyeon" // 구글에서 로드한 폰트 명
2. 캔버스에 텍스트 그리기
- 사용자가 입력한 텍스트를 캔버스에 그리고 불꽃놀이 파티클 생성을 위한 픽셀 데이터를 받아오는 메서드를 구현했다.
- ctx.measureText로 캔버스에 그린 이미지의 width와 fontBoundingBoxAscent, fontBoundingBoxDescent 데이터를 가져온 이유는 이미지 데이터를 가져올때 전체가 아닌 Text가 그려진 위치를 계산하기 위해서다.
- fontBoundingBoxAscent : 베이스 라인으로 부터 텍스트의 위쪽 끝까지의 거리
- fontBoundingBoxDescent : 베이스 라인으로 부터 텍스트 아래쪽 끝까지의 거리
- 아무리 ctx의 textBaseline을 middle로 해놓는다고 해도 영문, 한글 또는 글씨체에 따라 위로 올라갈수도 아래로 내려갈수 있으므로 안전 마진으로 더해주는 것이 정확한 데이터를 가져올 수 있다.
- ctx.getImageData로 텍스트 이미지의 픽셀 데이터를 가져올 때 x, y 좌표
- x좌표 : 텍스트가 화면 정중앙에 그려지므로 그려진 텍스트의 절반 길이를 빼줘야 시작점을 알 수 있다.
- y좌표 : 텍스트가 그려진 높이에 텍스트의 높이의 절반 길이를 빼줘야 시작점을 알 수 있다. 텍스트의 높이는 대체로 fontSize와 거의 유사하지만 좀 더 정확한 데이터를 가져오기 위해 fontBoundingBoxAscent를 빼줘 기준점을 높였다.
- ctx.getImageData로 텍스트 이미지의 픽셀 데이터를 가져올 때 dpr을 곱한 이유
- ctx.measureText를 통해 화면에 렌더링 되는 글자의 데이터는 캔버스 CSS 크기 기준이다.
- ctx.getImageData를 통해 가져오는 글자의 데이터는 캔버스 물리적 크기 기준이다. 고해상도 디스플레이에서도 정확한 데이터 추출을 위해 dpr 값을 곱해 물리적 크기로 변환해야 한다.
// TextData.js
drawText() {
// 다른 데이터가 섞이는 것을 방지하기 위해 캔버스 전체 화면을 지우고 시작한다.
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
// stroke 스타일로 x, y 좌표 위치에 사용자가 입력한 텍스트를 그린다.
this.text.strokeText(this.text, this.mainX, this.mainY);
// measureText 메서드를 통해 텍스트의 크기 데이터 값을 가져온다.
// (fontBoundingBoxAscent와 fontBoundingBoxDescent를 사용하여 텍스트 주위에 안전 마진을 추가)
const { width, fontBoundingBoxAscent = 0, fontBoundingBoxDescent = 0 }
= this.ctx.measureText(this.text);
// 이미지 데이터를 가져올때 필요한 좌표와 이미지 크기 정보
const x = (this.mainX - width / 2) * this.dpr;
const y = (this.mainY - this.fontSize / 2 - fontBoundingBoxAscent) * this.dpr;
const imgWidth = width * this.dpr;
const imgHeight = (this.fontSize + fontBoundingBoxDescent) * this.dpr;
// measureText를 통해 가져온 width값이 유효한 값일때만 이미지를 가져온다.
if (width) {
// 불러온 이미지 데이터 저장
this.textPixelData = this.ctx.getImageData(x, y, imgWidth, imgHeight);
// measureText를 통해 가져온
// text의 fontBoundingBoxAscent, fontBoundingBoxDescent 값을 textPixelData에 추가한다.
// 이미지 데이터를 가져올 시 y와 imgHeight에 위 값들을 포함하여 반영했기 때문에
// 추후 TextParticle 렌더링 시 파티클이 정확한 곳에 위치하도록 보정하기 위함이다.
this.textPixelData.fontBoundingBoxAscent = fontBoundingBoxAscent;
this.textPixelData.fontBoundingBoxDescent = fontBoundingBoxDescent;
}
}
Github 링크
'Canvas > 불꽃놀이 프로젝트' 카테고리의 다른 글
[Canvas-불꽃놀이-08] 애니메이션 기본 틀잡기 (0) | 2024.11.20 |
---|---|
[Canvas-불꽃놀이-07] 불꽃놀이 Particle들의 부모 클래스 (1) | 2024.11.18 |
[Canvas-불꽃놀이-05] index.js에서 중요 이벤트 정의 (1) | 2024.11.18 |
[Canvas-불꽃놀이-04] Canvas 설정 - 물리적 크기와 CSS 크기 (0) | 2024.11.17 |
[Canvas-불꽃놀이-03] Canvas 설정하기 (4) | 2024.11.16 |