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

productuidev·2022년 10월 18일
0

FE Study

목록 보기
64/67
post-thumbnail
post-custom-banner

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

(7) 그림판 구현

06-2) 내비게이터 기능 수정

  • 이전 구현 기능에서 네비게이터가 보이지 않는 경우에도 실시간으로 그린 상태가 업데이트되고 있음
  • onClickNavigator : 네비게이터가 보이지 않는 경우 그리는 상태가 업데이트되지 않도록 변경
  • IsNavigatorVisible : 네비게이터 활성 여부 (변수), currentTarget이 active를 포함하지 않은 상태인 경우에 onClickNavigator 실행
  • updateNavigator에도 켜두지 않은 상태일 경우 리턴 조건 추가
IsNavigatorVisible = false; // T/F

...

onClickNavigator(event) {
    this.IsNavigatorVisible = !event.currentTarget.classList.contains('active'); 
    event.currentTarget.classList.toggle('active');
    this.navigatorImageContainerEl.classList.toggle('hide');
    // console.log(this.canvasEl.toDataURL());

  updateNavigator() {
    if (!this.IsNavigatorVisible) return;
    this.navigatorImageEl.src = this.canvasEl.toDataURL();
  }

6-2) 결과

1

07) 실행 취소 기능

  • 실행 취소를 위해서는 현재 그린 상태와 이전 상태로 돌리기 위한 데이터가 필요함

undo 탐색/이벤트 바인딩

assignElement() {
	...
    
    this.undoEl = this.toolbarEl.querySelector('#undo');
  }
  
addEvent() {
    ...
    
    this.undoEl.addEventListener('click', this.onClickUndo.bind(this));
  }

실행 취소 배열

default는 빈 배열에서 시작

undoArray = [];

상태 저장/실행취소 실행

  • saveState : 현재 그린 상태 데이터를 배열(array)로 만들어서 저장, 저장은 최근 5개 상태까지만 저장 조건
  • onClickUndo : 실행취소한 데이터배열에서 이전 생성한 이미지 객체를 캔버스 메소드를 활용해 지우고/그려서 DataUrl로 가져옴
  onClickUndo() {
     // 최초인 경우 alert, return
    if (this.undoArray.length === 0) {
      alert('더 이상 실행취소는 불가합니다.');
      return;
    }

    let previousDataUrl = this.undoArray.pop(); // 배열의 마지막 요소 제거
    let previousImage = new Image(); // 이전 이미지 객체 생성
    
    previousImage.onload = () => {
      // clearRect : 캔버스의 특정 영역 지우는 메소드
      // clearRect(x, y, w, h)
      this.context.clearRect(0, 0, this.canvasEl.width, this.canvasEl.height);

      // drawImage : 캔버스에서 이미지를 그리는 메소드
      // drawImage(image, ix, iy, iw, ih, cx, cy, cw, ch)
      this.context.drawImage(
        previousImage,
        0,
        0,
        this.canvasEl.width,
        this.canvasEl.height,
        0,
        0,
        this.canvasEl.width,
        this.canvasEl.height,
      );
    };
    previousImage.src = previousDataUrl;
  }

  saveState() {
    if (this.undoArray.length > 4) {
      this.undoArray.shift(); // 배열의 첫번째 요소 제거
      this.undoArray.push(this.canvasEl.toDataURL()); // 배열의 끝에 추가
    } else {
      this.undoArray.push(this.canvasEl.toDataURL());
    }
    // console.log(this.undoArray);
  }

참고자료

07) 결과

2

08) 초기화 기능

캔버스 상태를 모두 초기화

clear 탐색/이벤트 바인딩

assignElement() {
	...
    
    this.clearEl = this.toolbarEl.querySelector('#clear');
  }
  
addEvent() {
    ...
    
    this.clearEl.addEventListener('click', this.onClickClear.bind(this));
  }

캔버스 지우기

  • 현재 상태에서 clearRect 메소드를 활용하여 지우기
  • 지운 후 undoArray는 default인 빈 배열인 상태
  • 캔버스를 지우고 네비게이터도 업데이트
  • 캔버스 배경색 초기화
  onClickClear() {
    this.context.clearRect(0, 0, this.canvasEl.width, this.canvasEl.height);
    this.undoArray = [];
    this.updateNavigator();
    this.initCanvasBackgroundColor();
  }

08) 결과

3-1

09) 다운로드 기능

캔버스에 그린 내용을 jpeg 확장자의 파일로 저장하는 기능

download 탐색/이벤트 바인딩

assignElement() {
	...
    
    this.donwloadLinkEl = this.toolbarEl.querySelector('#download');
  }
  
addEvent() {
    ...
    
    this.donwloadLinkEl.addEventListener(
      'click',
      this.onClickDonwload.bind(this),
    );
  }

다운로드

 onClickDonwload() {
    this.donwloadLinkEl.href = this.canvasEl.toDataURL('image/jpeg', 1);
    this.donwloadLinkEl.download = 'example.jpeg';
  }

마무리

class field쪽에 탐색 요소 코드 정리

class DrawingBoard {
  MODE = 'NONE'; // 브러시 모드 : NONE BRUSH ERASER
  IsMouseDown = false; // T/F
  eraserColor = '#FFFFFF'; // 지우개 변수
  backgroundColor = '#FFFFFF'; // 배경색 변수
  IsNavigatorVisible = false; // T/F
  undoArray = [];
  containerEl;
  canvasEl;
  toolbarEl;
  brushEl;
  colorPickerEl;
  brushPanelEl;
  brushSliderEl;
  brushSizePreviewEl;
  eraserEl;
  navigatorEl;
  navigatorImageContainerEl;
  navigatorImageEl;
  undoEl;
  clearEl;

   ......

}

09) 결과

4

gif 변환/업로드 에러가 있었지만 어쨌든 completed!!

profile
필요한 내용을 공부하고 저장합니다.
post-custom-banner

0개의 댓글