30개의 프로젝트로 배우는 프론트엔드 with VanillaJS (7-3) 그림판

productuidev·2022년 10월 16일
0

FE Study

목록 보기
63/67
post-thumbnail

[fastcampus] 30개의 프로젝트로 배우는 프론트엔드 with VanillaJS (7-2)

(7) 그림판 구현

05) 지우개 기능

  • 지우개 요소 탐색
this.eraserEl = this.toolbarEl.querySelector('#eraser');
  • 지우개 기능의 경우, 캔버스와 동일한 색상의 브러시로 덮는 것과 같은 개념
  • 브러시 모드에서 브러시 색상을 통해 마우스로 지우는 개념
  • onClickEraser : 지우개를 눌렀을 때 상태 변경 (브러시 기능 응용)
  • 토글 눌렀을 때 active 클래스가 들어오는 코드 통일 (onClickBrush, onClickEraser, onClickNavigator)
event.currentTarget.classList.toggle('active')
  • initCanvasBackgroundColor : 초기화 시 캔버스 크기 만큼의 직사각형을 그리고 시작하는 것과 같은 개념 (캔버스와 동일한 색상으로)
  • fillRect(직사각형 그리기) : 캔버스 기준 0,0 좌표가 시작되는 지점, 캔버스의 너비, 캔버스 높이
  • 캔버스 배경색이 흰색이 아닌 경우도 있으므로(가령 다크모드) 지우개와 배경의 색상을 변수로 담아줌
class DrawingBoard {
  MODE = 'NONE'; // 브러시 모드 : NONE BRUSH ERASER
  IsMouseDown = false; // T/F
  eraserColor = '#FFFFFF'; // !지우개 변수
  backgroundColor = '#FFFFFF'; // !배경색 변수

  constructor() {
    this.assignElement();
    this.initContext();
    this.initCanvasBackgroundColor(); // !
    this.addEvent();
  }

  assignElement() {
    ...
    
    this.eraserEl = this.toolbarEl.querySelector('#eraser');
  }

  // 캔버스 초기화 (초기화 시 캔버스 크기만큼의 직사각형을 그리고 시작하는 개념)
  initCanvasBackgroundColor() {
    this.context.fillStyle = this.backgroundColor;
    this.context.fillRect(0, 0, this.canvasEl.width, this.canvasEl.height);
  }

  addEvent() {
	...
    
    this.eraserEl.addEventListener('click', this.onClickEraser.bind(this));
  }

  onMouseOut() {
	... 

    // 조건문으로 변경
    if (this.MODE === 'BRUSH') {
      this.context.strokeStyle = this.colorPickerEl.value; // 컬러피커의 값
      this.context.lineWidth = this.brushSliderEl.value; // 브러시슬라이더의 값
    } else if (this.MODE === 'ERASER') {
      // 지우개를 배경색(흰색)인 브러시로 덮는 개념이라고 보면 됨
      this.context.strokeStyle = this.eraserColor;
      this.context.lineWidth = 50;
    }
  }

  // 마우스를 움직일 때
    const IsActive = event.currentTarget.classList.contains('active'); // 반복 코드 정리
    this.MODE = IsActive ? 'NONE' : 'BRUSH';
    this.canvasEl.style.cursor = IsActive ? 'default' : 'crosshair';
    this.brushPanelEl.classList.toggle('hide'); // 브러시 패널 활성화
    event.currentTarget.classList.toggle('active'); // !
    // this.brushEl.classList.toggle('active');
    this.eraserEl.classList.remove('active');
  }

  // 지우개 기능 (브러시 기능 응용)
  // 지우개를 눌렀을 때 상태 변경
  onClickEraser() {
    const IsActive = event.currentTarget.classList.contains('active');
    this.MODE = IsActive ? 'NONE' : 'ERASER';
    this.canvasEl.style.cursor = IsActive ? 'default' : 'crosshair';
    this.brushPanelEl.classList.add('hide');
    event.currentTarget.classList.toggle('active'); // !
    // this.eraserEl.classList.toggle('active');
    this.brushEl.classList.remove('active');
  }
}

fillRect()

event target과 currentTarget의 차이

중간 결과1

06-1) 내비게이터 기능

  • 툴바에서 지도모양 아이콘을 누르면 오른쪽 하단에 캔버스에 그린 내용이 나타나는 네비게이터(미니맵) 구현
  • 툴바의 네비게이션 버튼, 하단의 표시되는 내비게이션(컨테이너)와 실제 캔버스의 이미지 요소 탐색
    this.navigatorEl = this.toolbarEl.querySelector('#navigator');
    this.navigatorImageContainerEl = this.containerEl.querySelector('#imgNav');
    this.navigatorImageEl = this.containerEl.querySelector('#canvasImg');
  • onClickNavigator : 아이콘 토글 시 보여주기/숨기기
  • updateNavigator : 현재 캔버스 상태를 이미지 형태로 변환하여 canvasImg에 src 형태로 업데이트하여 네비게이터(미니맵)으로 보여줄 수 있다
  • 단, 너무 자주 업데이트 시 버벅거리는 현상 > 마우스를 떼거나(onMouseUp) 밖으로 나갔을(onMouseOut) 때 업데이트되도록 updateNavigator() 추가
class DrawingBoard {

  ...
    
  assignElement() {
	...
    
    this.navigatorEl = this.toolbarEl.querySelector('#navigator');
    this.navigatorImageContainerEl = this.containerEl.querySelector('#imgNav');
    this.navigatorImageEl = this.containerEl.querySelector('#canvasImg');
  }
  
  addEvent() {
	...
    
    this.navigatorEl.addEventListener(
      'click',
      this.onClickNavigator.bind(this),
    );
  }
  
  onMouseOut() {
    if (this.MODE === 'NONE') return;
    this.IsMouseDown = false;
    this.updateNavigator(); // !
  }
  
  onMouseUp() {
    if (this.MODE === 'NONE') return;
    this.IsMouseDown = false;
    this.updateNavigator(); // !
  }
  
  // 네비게이터(미니맵)
  onClickNavigator(event) {
    event.currentTarget.classList.toggle('active');
    this.navigatorImageContainerEl.classList.toggle('hide');
    // console.log(this.canvasEl.toDataURL());
    this.updateNavigator();
  }

  updateNavigator() {
    this.navigatorImageEl.src = this.canvasEl.toDataURL();
  }
  
}

HTMLCanvasElement.toDataURL()

매개변수 에서 지정한 형식의 이미지 표현을 포함하는 데이터 URLtype 을 반환
캔버스에 그린 그림을 문자열 형태로 변환할 수 있는데, 이 문자열에는 이미지 MIME 타입과 인코딩 방법 그리고 인코딩 된 이미지 데이터 문자열이 포함된다
이미지의 컨텍스트 에서 데이터 URL 은 기본적 으로 ASCII 문자열로 표시되는 Base64 로 인코딩된 이미지 파일의 이진 데이터

중간 결과2


~ing

  • 30FE 강의 중에 Billy 강사님 강의스타일이 잘 맞는 거 같다 (로봇같은 말투가 인상적이다)
    클론코딩을 통해 이해하는 데 도움이 되는 거 같다 :)
profile
필요한 내용을 공부하고 저장합니다.

0개의 댓글