[Canvas-불꽃놀이-12] text 픽셀 데이터 생성

이전 글 : [Canvas-불꽃놀이-11] 불꽃놀이 꼬리 완성

 

[Canvas-불꽃놀이-11] 불꽃놀이 꼬리 완성

이전 글 : [Canvas-불꽃놀이-10] 불꽃놀이 꼬리의 위치와 속도 구현 [Canvas-불꽃놀이-10] 불꽃놀이 꼬리의 위치와 속도 구현이전 글 : [Canvas-불꽃놀이-09] 파티클 관리와 객체 폴링 [Canvas-불꽃놀이-09]

jinsk-joy.tistory.com

 

사용자가 입력한 문자열의 TextData 생성하기

1.  문자열의 textData 생성하기

앞에서 만들었던 TextData 클래스를 활용하여 파티클을 화면에 그릴 때 필요한 픽셀 데이터를 가져오도록 하겠다.

 

1-1. textData 가져오기

  • fontSize를 인자를 받아 텍스트를 화면에 그리고 픽셀 데이터를 반환하는 메서드를 생성한다.
// Canvas.js
getTextData(fontSize) {
    // fontSize크기의 TextData 인스턴스를 생성한다.
    const textData = new TextData(this.text, fontSize);
    
    // 화면에 text를 그리고 픽셀 데이터를 추출한다.
    textData.drawText();

    // 픽셀 데이터를 반환한다.
    return textData.textPixelData;
}

 

1-2. 불꽃놀이에 필요한 textData 생성하기

  • 이 프로젝트에서는 총 2가지의 폰트 사이즈가 존재한다. 
    -. mainFontSize : 중앙에서 생성되는 불꽃일때 보여줄 사이즈
    -. subFontSize : 중앙 이외 범위에서 생성되는 불꽃일때 보여줄 사이즈
  • 각 사이즈에 맞춰 데이터를 담을 멤버 변수를 생성한다.
  • 텍스트를 화면에 그리기 전 정확한 텍스트의 width를 가늠하기 어렵다. 글자수가 많은 경우 텍스트가 화면 범위 밖으로 벗어날 가능성이 있기때문에 텍스트 데이터를 생성하기 전 미리 width를 확인하고 폰트 사이즈를 조절하도록 한다.

 

  • 데이터를 담을 멤버 변수 추가
// Canvas.js
initCanvasVars() {
    this.animationId = undefined;

    this.text = "";
    this.textLength = 0;
    
    // 텍스트 데이터를 저장할 변수
    this.mainTextData = {};
    this.subTextData = {};

    // 생략...
}

 

  • 텍스트를 화면에 그리기 전 미리 width를 확인할 수 있는 메서드 구현
// Canvas.js
getTextWidth(fontSize) {
    // measureText를 하기 전 font 스타일을 적용해주어야 제대로된 결과를 얻을 수 있다.
    // font의 weight, family, size 등
    this.ctx.font = this.setFontStyle(fontSize);
    
    // 측정된 텍스트 데이터중에서 텍스트의 width를 반환한다.
    return this.ctx.measureText(this.text).width;
}

 

  • 폰트 사이즈를 조절할 수 있는 메서드 구현
    -. 텍스트의 width가 허용가능한 범위를 초과하면 반복문을 통해 허용 범위 안으로 들어올 때까지 폰트 사이즈를 조절한다.
    -. 반복문 조건으로 최소 폰트 크기 비교를 추가해 무한 루프 가능성을 방지한다.
// constants.js
export const SCREEN = {
    // 생략...
    MAX_WIDTH_RATIO: 0.9,
    MIN_SIZE_RATIO: 0.7,
};

export const FONT = {
    // 생략...
    ADJUST_RATIO: 0.95,
};
// Canvas.js
adjustFontSize() {
    // 최대 허용 범위
    const maxWidth = this.canvasCssWidth * SCREEN.MAX_WIDTH_RATIO;
    
    // 실제 텍스트의 width
    let textWidth = this.getTextWidth(this.mainFontSize);

    // 실제 텍스트의 width가 최대 허용 범위 안이면 조정할 필요가 없으므로 종료
    if (textWidth < maxWidth) return;

    // 무한 루프 방지를 위해 최소 폰트 사이즈를 설정
    const minFontSize = this.mainFontSize * FONT.MIN_SIZE_RATIO;
    // 테스트할 임시 폰트 사이즈
    let tempSize = this.mainFontSize;

    // textWidth가 maxWidth보다 작아지거나
    // 조절된 폰트 사이즈인 tempSize가 최소 기준인 minFontSize보다 작아질 경우 반복문을 종료한다.
    while (textWidth > maxWidth && tempSize > minFontSize) {
    
        // 조절된 폰트 사이즈를 계산하여 다시 textWidth를 구한다.
        tempSize *= FONT.ADJUST_RATIO;
        textWidth = this.getTextWidth(tempSize);
    }

    // 만약 조절된 폰트 사이즈가 최소 폰트 사이즈 미만이면 메인 폰트 사이즈를 최소 폰트 사이즈로 설정한다.
    if (tempSize < minFontSize) tempSize = minFontSize;

    // 새로운 폰트 사이즈를 적용한다.
    this.mainFontSize = this.setMainFontSize(tempSize);
    this.subFontSize = this.setSubFontSize();
}

텍스트가 화면 밖을 벗어난 예시 이미지

최대 입력 가능글자인 10글자를 입력했을때 폰트 사이즈를 조절해주지 않으면 화면을 벗어나는 결과를 초래할 수 있다.

  • 위의 메서드를 활용하여 실제 화면에 구현할 텍스트 데이터 생성 하기
// Canvas.js
createTextDatas() {
    // 폰트 크기 조절이 필요한지 확인
    this.adjustFontSize();

    // 텍스트를 그린 다음 반환받은 픽셀 데이터를 대입한다.
    this.mainTextData = this.getTextData(this.mainFontSize);
    this.subTextData = this.getTextData(this.subFontSize);
}

 

2.  textData 생성 함수 실행하기

  • 위에서 만든 텍스트 데이터는 애니메이션 실행 전 미리 생성해놓는게 효율적이다. 
  • 매번 불꽃놀이를 생성할때마다 텍스트를 그리고 데이터를 업데이트 하기엔 불필요한 리소스가 많이 들기 때문에 애니메이션 시작 전 한번만 생성하도록 한다.
  • 미리 생성한 좌표 데이터를 바탕으로 TextParticle을 그릴때 그 위치에 맞춰 좌표를 재계산해서 그리면 된다. 
  • 계산을 좀 더 쉽게 하기 위해 텍스트는 mainX, mainY 위치에 그리도록 TextData 클래스에서 미리 설정하였다.

 

// Canvas.js
render() {
    if (this.text !== "") {
        // 애니메이션 시작 전 미리 텍스트 데이터를 생성해놓는다.
        this.createTextDatas();
        this.animateFireworks();
    }
}

 

애니메이션 실행 전 잘 생성된 모습을 볼 수 있다. (예시를 보여주기 위해 글자색은 흰색으로 설정)

 

Github 주소