1 minute read

들어가면서,

캔버스를 사용해서, 마우스로 interaction 이 가능한 텍스트를 그리려고 한다. 디테일한 구현 내용을, 전부 작성하기엔, 필요이상으로 내용이 길어지고, 글을 읽는데에 오히려 방해가 될 것 같아서, 핵심 아이디어 위주로 작성하려고 합니다.

코드를 완성된 시점에서 보는 것과, 코드가 짜여지는 과정을 옆에서 지켜보는 것은 많이 다릅니다. 완성된 코드만 봐서는, 구현된 함수들이 왜 필요한 지, 이해를 못할 수도 있습니다. 그것은 자연스러운 과정입니다.

그것을 이해하지 못했다고, 괴로워 하지 마시고, 구현에 굵직굵직한 아이디어에 집중하시면서, 시도해보시고, 다시 돌아오셔서, 시도해보신 코드와 맞춰보시는 과정으로 공부해보셨으면 좋겠습니다.

코드 전체는 아래 링크를 통해 공개되어 있습니다.

질문은 자유롭게 댓글을 통해서 해주시면 됩니다.

See the Pen pixelizing by jimmy jung (@idjjm92) on CodePen.

구현에 필요한 아이디어

  1. 캔버스 상의 텍스트를 픽셀로 변환시키기(Effect 클래스에서 다룸)
  2. 변환된 픽셀에 애니메이션, 마우스 인터렉션 추가하기

1. Effect 클래스

  • 각종 설정(줄간격, 색상, 정렬, 픽셀사이즈, 마우스위치 등)
  • 텍스트를 중앙으로 정렬해서 써주는 함수
  • 캔버스에 올라와 있는 내용을 픽셀로 변경해주는 함수
class Effect{

  생성자에서 각종 설정들은 해준다.(색상, 정렬, 픽셀사이즈, 마우스 위치 초기화 등)
  constructor(context, canvasWidth, canvasHeight){
    this.context = context;
    this.canvasWidth = canvasWidth;
    this.canvasHeight = canvasHeight;
    this.fontSize = 90;
    this.lineHeight = this.fontSize * 0.8;
    this.maxTextWidth = this.canvasWidth * 0.8;
    this.textX = this.canvasWidth/2;
    this.textY = this.canvasHeight/2;
    this.context.font = "90px Helvetica";
    this.context.fillStyle = "#fff";
    this.context.textAlign = "center";
    this.context.textBaseLine = "middle";
    this.gap = 3;
    this.mouse = {
      radius : 500,
      x: 0,
      y: 0
    }

  };

  캔버스 상의 텍스트를 픽셀로 변환해주는 함수
  compileToPixel(){
    const pixels = this.context.getImageData(0, 0, this.canvasWidth, this.canvasHeight).data;
    this.context.clearRect(0,0, this.canvasWidth, this.canvasHeight);
    for(let y = 0; y < this.canvasHeight; y+=this.gap){
      for(let x = 0; x < this.canvasWidth; x+= this.gap){
        const index = ((this.canvasWidth * y) + x) * 4;
        const alpha = pixels[index + 3];
        if(alpha > 0){
          const red = pixels[index];
          const green = pixels[index + 1];
          const blue = pixels[index + 2];
          const colour = `rgba(${red}, ${green}, ${blue}, ${alpha})`;
          this.context.fillStyle = colour;
          this.context.fillRect(x, y , this.gap, this.gap);
        }

      }
    }

  }

  텍스트 중앙정렬 함수
  wrapText(message){
    let words = message.split(" ");
    let lineArr = [];
    let line = "";
    let testLine = "";
    let lineNumb = 0;
    for(let i=0; i < words.length; i++){
      testLine += words[i] + " ";
      if(this.context.measureText(testLine).width > this.maxTextWidth){
        lineNumb++;
        testLine = words[i];
      };
      line = testLine;
      lineArr[lineNumb] = line;
    };

    const textBoxHeight = lineNumb * this.lineHeight;
    const coord_y = this.textY - textBoxHeight/2;
    lineArr.forEach((line, index)=>{
      this.context.fillText(line, this.textX, coord_y + index * this.lineHeight );
    });
    this.compileToPixel();
  }
}

구현내용: codepen
구현내용: https://github.com/jimyeong/animations

Leave a comment