본문 바로가기
블로그 이미지

방문해 주셔서 감사합니다! 항상 행복하세요!

  
   - 문의사항은 메일 또는 댓글로 언제든 연락주세요.
   - "해줘","답 내놔" 같은 질문은 답변드리지 않습니다.
   - 메일주소 : lts06069@naver.com


Html 캔버스/Html 캔버스 에니메이션

Html Canvas 도형 병합(merge figure, 다각형 만들기)

야근없는 행복한 삶을 위해 ~
by 마샤와 곰 2021. 8. 12.

 

* 게시글 하단의 제 깃허브 주소를 통해 실제 구현된 모습을 볼 수 있습니다

 

엑셀이나 한셀, 워드 및 한글등 이러한 프로그램에서 테이블을 병합하는 기능을 종종 사용하고는 합니다.

각각의 테이블의 셀이 이쁘장하게 병합되는 것을 보고나면 참 멋지지 않은 일이 아닐 수 없습니다.

이렇게 테이블 내부의 셀들이 이쁘게 합쳐지는 것을 볼 수 있습니다.

 

이러한 프로그램에서 병합 규칙은 무조건 사각형 모양만 된다는 점 입니다.

직사각형, 정사각형..사각형 모양 이외에는 병합 기능이 제공되지가 않습니다.

물론 표(table)라는 것은 데이터를 일정하게 정렬하고 정리하기 위한 기능이기 때문에 사각형 이외의 모양은 제공되지 않는 것이 맞습니다.

음...이렇게 사각형의 형태가 아니라 다각형 모양인 경우에는 합쳐지기가 안되네요..

 

그래서 웹에서 표(table) 이상의 병합이 가능한 기능을 한번 구현하여 보았습니다.

사각형을 모아서 다각형을 만들어 주는 기능이라 할 수 있겠네요.

먼저 도형을 그려주기 위해 사각형 모양의 테이블들을 그려 줍니다.

const canvas = document.getElementById('canvas')    
const ctx = canvas.getContext('2d')

let WIDTH = canvas.width
let HEIGHT = canvas.height

let pos = {
    row : 10,
    column : 10
}

for(let i=0; i < pos.row; i++){  //줄수
    for(let j=0; j < pos.column; j++){  //열수
        let data = {
            startTop : HEIGHT *  i/pos.row, 
            endTop : HEIGHT *  ( (i+1) / pos.row),
            startLeft : WIDTH *  j/pos.column, 
            endLeft : WIDTH *  ( (j+1) / pos.column)
        }    
    }
}

 

반복문을 통해서 데이터 배열을 만들어 줍니다.

start, end값에 각각의 x좌표와 y좌표의 시작 종료점을 넣어 줍니다.

그리고 나서 화면을 그려줍니다.

요렇게 그렸습니다.

 

사각형 모양의 판자를 그리는 방법은 매우 간단합니다.

moveTo 함수와 LineTo 함수를 이용하여 그려주거나 아니면 strokeRect 함수를 사용하면 됩니다.

여기서는 moveTo 함수와 LineTo 함수를 사용하였습니다.

 

다음으로 클릭 이벤트를 부여하여 선택된 도형에 색을 넣어 줍니다.

캔버스에 클릭 이벤트를 달아주고 선택된 영역의 x와 y좌표값을 데이터가 담긴 배열 안에 들어온 경우 색을 입히도록 하여 줍니다.

canvas.addEventListener('click', function (event) {
    let x1 = event.clientX - canvas.offsetLeft;
    let y1 = event.clientY - canvas.offsetTop;
    insideChecker(x1, y1)
})
function insideChecker(x1, y1){
    ctx.clearRect(0,0, WIDTH, HEIGHT)
    array = array.map( data => {
        if(x1 >= data.startLeft && x1 <= data.endLeft && y1 >= data.startTop && y1 <= data.endTop ){
            if(data.clicked){
                data.clicked = false
                data.background = 'white'
            } else {
                data.background = 'rgba(120, 220, 130, 0.4)'
                data.clicked = true
            }
        } 
        drawing(data)
        return data
    })
}

 

이제 클릭을 하면 색이 들어가는 멋진 배열이 완성 되었습니다.

실제 동작하는 모습을 살펴 봅니다.

색이 잘 들어 갑니다.

 

이제부터 고민해야 되는 부분입니다.

클릭 이벤트를 통해서 선택된 대상을 기록할 수 있습니다.

저렇게 선택된 대상에서 우리는 겹치는 선을 확인하여야 합니다.

겹치는 선을 제거해 주어야 아래 사진처럼 사각형 도형을 모아 다각형 형태로 만들 수 있기 때문 입니다.

이런모양!

먼저 데이터의 수정이 필요 합니다.

위에서 오른쪽 방향으로 선을 그려준다고 가정하여 봅니다.

그러면 이에 필요한 데이터를 아래 사진처럼 order 라는 작은 배열을 추가하여 from, to 라는 키 값으로 넣어줍니다.

order라는 배열을 추가합니다. order는 각각의 선을 의미 합니다.
인덱스는 0~3까지 총 4개 입니다.

 

이 상태에서 사각형을 그릴 때 선 그리는 방법을 바꾸어야 합니다.

먼저 fillRect 함수로 사각형을 채우고, 나머지 구간에서는 moveTo, LineTo 함수를 통해 선을 그려 주도록 합니다.

function drawing(data){
    ctx.save()
    ctx.beginPath() 

    if(data.background) {  //색 채우기
        ctx.moveTo(data.startLeft, data.startTop)
        ctx.fillStyle = data.background
        ctx.fillRect(data.startLeft, data.startTop, data.endLeft- data.startLeft, data.endTop -data.startTop )
    }      

    data.order.forEach( item => {  //선 그리기
        if(item.draw){
            ctx.moveTo(item.from[0], item.from[1])
            ctx.lineTo(item.to[0], item.to[1])
        } 
    })

    ctx.stroke()
    ctx.closePath()
    ctx.restore()    
}

 

이렇게 하고나서 선택된 도형에 대한 이벤트 입니다.

선택된 도형을 따로 배열(또는 맵) 객체에 담아 둡니다.

그리고 사용자가 도형 만들기를 확정 한 경우에 서로의 order 배열에서 겹치는 from과 to를 찾아 냅니다.

전부 찾아야 하기 때문에 N개에 대해서 N번 수행해야 합니다..ㅠ

만약 from과 to가 겹치는 겹선이 존재한 다면 해당 선을 그려주지 않도록 데이터를 수정하여 줍니다.

선택된 들을 자기 자신을 제외하고 전부 조사합니다. 시간복잡도가 상당하겠네요..

 

위에서 작업한 데이터를 통해 0~3번구간의 선 중 그려지지 않도록 하는 구간에 대해서는 moveTo, LineTo 함수가 동작하지 않도록 하여 줍니다.

즉, moveTo 함수와 lineTo 함수가 각각 개별로 동작 해야하는 이유가 바로 이것 때문 입니다.

그러므로 색깔을 입히는 fillRect 함수가 먼저 동작을 해야 선 내부가 채워지게 됩니다.

 

이를 통해 최종 완성된 모습 입니다!

잘 병합 되네요..ㅋ

 

해당 그리는 방식은 결국에는 각각의 채우기와 각각의 선 그리기 기능이 동작하는 것 입니다.

그렇지만 사람의 눈에는 1개의 도형으로 보이는 것 뿐이지요.

실제 동작하는 모습을 체험하려면 아래 깃헙에서 확인하여 주세요!

https://taeseungryu.github.io/sample/sampleView/mertFig/table.html

 

Table

 

taeseungryu.github.io

 

위 모든 내용이 웹(web)에서 동작하는 캔버스(canvas)로 이루어진 내용 입니다.

 * 플래쉬, 액션스크립트, 유니티 같은 응용 프로그램이 아닙니다~

이상으로 Html 캔버스를 활용한 도형 병합(merge figure, 다각형 만들기)에 대해서 정리하여 보았습니다.

 

해당 포스팅은 코드를 전부 공개하지 않고 개념만 정리한 내용입니다.

문의사항이나 궁금한 점은 언제든 댓글 또는 메일로 연락주세요~ 👻

반응형
* 위 에니메이션은 Html의 캔버스(canvas)기반으로 동작하는 기능 입니다. Html 캔버스 튜토리얼 도 한번 살펴보세요~ :)
* 직접 만든 Html 캔버스 애니메이션 도 한번 살펴보세요~ :)

댓글