• JavaScript canvas를 이용해서 드래그로 도형 그리기

    2022. 5. 26.

    by. 순일

    <canvas>html 요소 중 하나로서, 스크립트를 사용하여 그림을 그리는 데 사용된다.

     

    아래의 링크를 통해서 canvas의 예제 및 메서드의 설명이나 사용법을 알 수 있다.

     

    Canvas API - Web APIs | MDN

    The Canvas API provides a means for drawing graphics via JavaScript and the HTML <canvas> element. Among other things, it can be used for animation, game graphics, data visualization, photo manipulation, and real-time video processing.

    developer.mozilla.org

     

    나는 마우스를 드래그를 통해 그림을 그리는 프로젝트를 진행했고, 아래와 같은 방식으로 로직을 구현하였다.

    실제 코드는 아래의 깃허브에 올라가 있다.

     

     

    GitHub - BNOTY/BNOTY-CODE: OPEN SOURCE

    OPEN SOURCE. Contribute to BNOTY/BNOTY-CODE development by creating an account on GitHub.

    github.com

     

    [사각형]

    사각형의 같은 경우는 canvas에서 제공하는 메서드를 사용하면 된다.

    CanvasRenderingContext2D.strokeRect()
    strokeRect(x, y, width, height)
    x : 사각형 시작점의 x축 좌표입니다.
    y : 사각형 시작점의 y축 좌표입니다.
    width : 사각형의 너비입니다. 양수 값은 오른쪽이고 음수는 왼쪽입니다.
    height : 사각형의 높이입니다. 양수 값은 아래로, 음수 값은 위로 이동합니다.

    다만 마우스로 드래그를 하면서 그리는 것을 구현하기 위해선 네모가 드래그마다 계속 그려지는데 그걸 막기 위해서 그릴 때마다 그린 정보를 저장시키고 그릴때마다 저장된 이미지가 있다면 불러오는 방식으로 해결할 수 있었다.

     

    [삼각형]

    삼각형 같은 경우는 라인을 그리는 메서드를 이용하여 구현하였다.

    CanvasRenderingContext2D.moveTo()
    moveTo(x, y)
    x : 점의 x축(가로) 좌표입니다.
    y : 점의 y축(수직) 좌표입니다.
     
    CanvasRenderingContext2D.lineTo()
    lineTo(x, y)
    x : 선 끝점의 x축 좌표입니다.
    y : 선 끝점의 y축 좌표입니다.

     

    삼각형은 드래그 기준으로 상단 중간 위치를 계산하여 이동한 뒤 하단 왼쪽 끝과 오른쪽 끝으로 각각 moveTo()를 하고 lineTo()를 통해 선을 이어주면 된다. 다만 선 연결에 끝처리를 해줘야지 둥글게 끝맺음을 할 수 있다.

    lineCap 속성을 이용하여 "round"로 지정하면 끝 처리를 할 수 있다.

     

    [원]

    원의 경우 곡선을 그리는 메서드를 이용하여 구현하였다.

    CanvasRenderingContext2D.bezierCurveTo()
    bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)
    cp1x : 첫 번째 제어점의 x축 좌표입니다.
    cp1y : 첫 번째 제어점의 y축 좌표입니다.
    cp2x : 두 번째 제어점의 x축 좌표입니다.
    cp2y : 두 번째 제어점의 y축 좌표입니다.
    x : 끝점의 x축 좌표입니다.
    y : 끝점의 y축 좌표입니다.

    드래그할 때 생기는 사각형에서 계산을 통해 중간 위치를 구한 뒤 총 4개의 곡선으로 모두 이어주면 동그라미를 그릴 수 있다.

     

    [직선]

    직선은 라인을 그리는 메서드를 이용하여 구현하였다.

    CanvasRenderingContext2D.moveTo()
    moveTo(x, y)
    x : 점의 x축(가로) 좌표입니다.
    y : 점의 y축(수직) 좌표입니다.

    CanvasRenderingContext2D.lineTo()
    lineTo(x, y)
    x : 선 끝점의 x축 좌표입니다.
    y : 선 끝점의 y축 좌표입니다.

    마우스를 드래그하면 드래그가 시작하는 지점부터 끝나는 지점까지 선을 이어주면 된다.

     

    [곡선]

    곡선은 곡선을 그리는 메소드를 이용하여 구현하였다.

    CanvasRenderingContext2D.quadraticCurveTo()
    quadraticCurveTo(cpx, cpy, x, y)
    cpx : 제어점의 x축 좌표입니다.
    cpy : 제어점의 y축 좌표입니다.
    x : 끝점의 x축 좌표입니다.
    y : 끝점의 y축 좌표입니다.

    먼저 moveTo()를 이용해 시작 좌표로 이동한 뒤 드래그가 끝나는 지점을 cpx,cpycpx, cpy에 넣어준다 이후 마우스를 통해 곡선 범위를 지정하여 그 좌표를 x, y x, y로 넣어주면 원하는 곡선을 그릴 수 있다.

     

    [화살표]

    화살표는 구글링을 통해 사람들이 이미 만들어놓은 정보를 참고하여 제작하였다.

     

    캔버스 화살표 - Javascript 샘플 코드

    이 카테고리에서 인기 카테고리에 예제가 포함 된 인기있는 페이지

    ko.code-paper.com

    출처 : https://ko.code-paper.com/javascript/examples-canvas-arrow

     

    [지우개]

    지우개는 사각형 범위를 지워주는 메서드를 이용하여 구현할 수 있었다.

    CanvasRenderingContext2D.clearRect()
    clearRect(x, y, width, height)
    x : 사각형 시작점의 x축 좌표입니다.
    y : 사각형 시작점의 y축 좌표입니다.
    width : 사각형의 너비입니다. 양수 값은 오른쪽이고 음수는 왼쪽입니다.
    height : 사각형의 높이입니다. 양수 값은 아래로, 음수 값은 위로 이동합니다.

    해당 메서드를 통해 캔버스 전범위를 지정해주면 전체 지우기가 가능하며 마우스 위치를 기준으로 특정 값을 +- 해서 넣어주면 일부 지우기가 가능하다.

     

    [올가미]

    올가미는 특정 범위의 이미지를 저장하고 다시 그리는 메서드를 이용해서 구현하였다.

    CanvasRenderingContext2D.putImageData()
    putImageData(imageData, dx, dy)
    putImageData(imageData, dx, dy, dirtyX, dirtyY, dirtyWidth, dirtyHeight)
    imageData : ImageData픽셀 값의 배열을 포함하는 개체입니다.
    dx : 대상 캔버스에서 이미지 데이터를 배치할 수평 위치(x 좌표)입니다.
    dy : 대상 캔버스에서 이미지 데이터를 배치할 수직 위치(y 좌표)입니다.
    dirtyX 선택 과목 : 이미지 데이터가 추출될 왼쪽 상단 모서리의 수평 위치(x 좌표)입니다. 기본값은 0입니다.
    dirtyY 선택 과목 : 이미지 데이터가 추출될 왼쪽 상단 모서리의 수직 위치(y 좌표)입니다. 기본값은 0입니다.
    dirtyWidth 선택 과목 : 칠할 사각형의 너비입니다. 기본값은 이미지 데이터의 너비입니다.
    dirtyHeight 선택 과목 : 칠할 사각형의 높이입니다. 기본값은 이미지 데이터의 높이입니다.
     
    CanvasRenderingContext2D.getImageData()
    getImageData(sx, sy, sw, sh)
    sx : ImageData 추출할 사각형의 왼쪽 위 모서리의 x축 좌표입니다.
    sy : ImageData 추출할 사각형의 왼쪽 위 모서리의 y축 좌표입니다.
    sw : ImageData 추출할 사각형의 너비입니다. 양수 값은 오른쪽이고 음수는 왼쪽입니다.
    sh : ImageData추출할 사각형의 높이입니다. 양수 값은 아래로, 음수 값은 위로 이동합니다.

    먼저 드래그한 범위 내의 이미지를 getImageData를 통해 저장한 뒤 이동시키고 최종 이동 완료된 곳에 putImageData를 통해 이미지를 저장시켜준다.

     

    [이전, 다음]

    이전, 다음도 올가미와 마찬가지로 특정 범위의 이미지를 저장하고 다시 그리는 메서드를 이용해서 구현하였다.

    CanvasRenderingContext2D.putImageData()
    putImageData(imageData, dx, dy)
    putImageData(imageData, dx, dy, dirtyX, dirtyY, dirtyWidth, dirtyHeight)
    imageData : ImageData픽셀 값의 배열을 포함하는 개체입니다.
    dx : 대상 캔버스에서 이미지 데이터를 배치할 수평 위치(x 좌표)입니다.
    dy : 대상 캔버스에서 이미지 데이터를 배치할 수직 위치(y 좌표)입니다.
    dirtyX 선택 과목 : 이미지 데이터가 추출될 왼쪽 상단 모서리의 수평 위치(x 좌표)입니다. 기본값은 0입니다.
    dirtyY 선택 과목 : 이미지 데이터가 추출될 왼쪽 상단 모서리의 수직 위치(y 좌표)입니다. 기본값은 0입니다.
    dirtyWidth 선택 과목 : 칠할 사각형의 너비입니다. 기본값은 이미지 데이터의 너비입니다.
    dirtyHeight 선택 과목 : 칠할 사각형의 높이입니다. 기본값은 이미지 데이터의 높이입니다.
     
    CanvasRenderingContext2D.getImageData()
    getImageData(sx, sy, sw, sh)
    sx : ImageData 추출할 사각형의 왼쪽 위 모서리의 x축 좌표입니다.
    sy : ImageData 추출할 사각형의 왼쪽 위 모서리의 y축 좌표입니다.
    sw : ImageData 추출할 사각형의 너비입니다 . 양수 값은 오른쪽이고 음수는 왼쪽입니다.
    sh : ImageData추출할 사각형의 높이입니다. 양수 값은 아래로, 음수 값은 위로 이동합니다.

    작업이 끝날 때마다 캔버스 전체 이미지를 저장하여 배열에 추가하여주고 이전 이후 같은 경우 배열에 이전 값 혹은 이후 값이 있는지 인덱스로 비교를 하여 이동한 값을 캔버스에 다시 가져오는 방식으로 해결했다.

    728x90

    '공부 > FrontEnd' 카테고리의 다른 글

    Vue Router 특정 Component 비활성화 하기  (0) 2022.04.17
    Vue Web Socket 실시간 알림  (2) 2022.02.21

    댓글