캔버스의 개념
캔버스의 개념
HTML5에 새롭게 등장한 요소인 캔버스. 캔버스는 이름처럼 코드를 이용해 그림을 그릴 수 있는 공간을 제공한다.
코드에 단순히 <canvas>라는 태그만 작성하게 되면 화면에 무언가 나타나거나 하지는 않는다. 캔버스라는 영역 위에 자바스크립트를 이용해 하나하나 그림을 그려가야 원하는 결과물을 볼 수 있다.
이런 기능을 활용해 애니메이션, 데이터 시각화 등의 다양한 그래픽 작업에 사용된다.
캔버스의 장점
이러한 캔버스 태그를 사용해 그래픽 작업을 하게 되면, 아래와 같은 장점이 있다.
- 브라우저 안에서 직접 렌더링하기 때문에 그래픽 성능이 뛰어나다.
- 또, 요즘의 모던 브라우저는 캔버스 태그를 지원하기 때문에 파이어폭스, 크롬, 엣지 가리지 않고 호환성에 유리하다.
- 그리고 다양한 그래픽 요소를 사용해 복잡한 화면을 만들 수 있기 때문에 유연성이 높다.
캔버스 사용시 주의사항
캔버스는 그래픽만 다루기 때문에 텍스트 콘텐츠를 포함하지 않는다.
예를 들어서, HTML의 이미지 태그 같은 경우는 alt 속성을 이용해서 해당 이미지가 로딩되지 않았을 때 이 이미지가 어떤 이미지인지 구체적인 대체 텍스트를 덧붙일 수 있다.
시각적으로 화면을 보기 어려운 유저들은 스크린 리더를 사용해 화면에 어떤 버튼이 있는지 귀로 들으며 브라우저를 이용할 수 있는데, 이러한 대체적 요소를 고려하는 것을 접근성이라고 한다.
이미지의 alt 속성 같은 경우, 화면을 보지 못하는 유저들은 alt 속성에 적어둔 글을 이용해 '아, 여기에는 웃고 있는 고양이 사진이 있구나.' 라는 것을 인지할 수 있다.
하지만 캔버스는 접근성을 고려할 수 있는 자체적인 요소가 없기 때문에, 개발자가 적절하게 대체 텍스트를 제공하거나 추가적인 접근성 기술을 사용해야 한다.
캔버스의 실제 사용 예시
현대자동차 캐스퍼 웹 플렛폼을 보면, [내 차 만들기] 페이지의 컨피규레이터에서 캔버스 요소가 사용되었다.
캔버스라는 공간 위해서 자바스크립트 코드로 자동차를 3D로 보여주고 있는데, 마우스를 이용해 상호작용하며 입체적인 요소를 느낄 수 있도록 구현되어있다.
이것을 코드로 구현하기 위해서는 현재 마우스 시각에서 바라보는 카메라 시점, 그리고 해당 차량의 위치 등을 수학적으로 계산해서 그려낸다고 한다.
캔버스의 기본 개념 정리
캔버스의 개념을 다시 정리해보자면 아래와 같다.
- 캔버스 태그는, 웹 페이지에 그래픽을 그릴 수 있는 강력한 도구이다.
- 자바스크립트와 결합해서 다양한 시각적 효과를 제공하고, 웹 애플리케이션의 대화형 요소를 강화하는데 유용하게 사용할 수 있다.
[참고] 웹 애플리케이션의 대화형 요소
보드게임 텔레스트레이션과 넷마블의 캐치마인드를 섞은 게임을 웹으로 구현한 갈틱폰이라는 웹사이트에서 대화형 요소라는 의미를 확인할 수 있다. 화면을 보면 그림판처럼 그림을 그릴 수 있는 부분이 있는데, 이 그림을 그리는 부분도 캔버스가 사용되었다.
마우스를 움직이는대로 사용자가 그림을 그릴 수 있는 부분뿐만 아니라 색상을 사용자가 선택해서 다양한 그림을 그릴 수 있도록 제공하는데, 이렇게 사용자와 상호작용할 수 있는 것들을 대화형 요소라고 한다.
또한 이런 드로잉앱뿐만 아니라 간단한 게임, 차트 등도 대화형 요소라고 할 수 있다. 캔버스가 그래픽 공간을 제공하기 때문에, 더 풍부한 대화형 요소를 만들어갈 수 있다.
캔버스의 사용 방법 및 예시
캔버스로 그림을 그려보자(1)
[니떡국 내떡국]이라는 프로젝트를 할 때 디자이너님이 위와 같이 룰렛을 그려주셨고, 캔버스를 이용해 직접 그림을 그릴 수 있다는 사실을 알고 나서 아래와 같이 코드를 구현했다.
// * 룰렛 회전 함수
const rotate = () => {
const image = imageRef.current
if (!image) return
setDisabled(true) // 버튼 1회만 클릭 가능하도록 state 설정
image.style.transition = 'initial'
image.style.transform = 'initial'
const TOTAL_ROTATION_TIME = 3000 // 룰렛 회전에 소요되는 시간
const totalDegrees = 3600 // 총 회전할 각도
const { randomGarnish, randomIdx } = getRandomGarnish()
if (randomGarnish === 'none') {
toast({
description:
'랜덤 고명 선택 중 오류가 발생했습니다. 팝업 종료 후 룰렛을 다시 클릭해주세요.',
})
}
// OptionGarnishes 배열의 weight을 기반으로 부채꼴(arcurate) 각도 계산
const arc = optionGarnishes.map((item) => (item.weight / 100) * 360)
// 랜덤 선택된 고명까지 회전시킬 각도 계산
let rotationAngle = 0
for (let i = 0; i <= randomIdx; i++) {
rotationAngle += arc[i] // 0번째 인덱스부터 randomIdx까지 해당 각도값 누적
}
rotationAngle += 83 // 룰렛 보정 각도
image.style.transition = `transform ${TOTAL_ROTATION_TIME}ms ease-out`
image.style.transform = `rotate(-${totalDegrees + rotationAngle}deg)`
// 회전 후 랜덤 선택된 고명 설정
setTimeout(() => {
setRouletteResult(randomGarnish)
}, TOTAL_ROTATION_TIME)
}
하지만 캔버스로 그림을 그리게 될 경우 테두리가 선명하지 않고 마치 그림판으로 그릴 때처럼 선이 뚝뚝 끊어져 있는걸 확인할 수 있었다. 그 이유는 캔버스는 위에 다른걸 결합해서 3D 그래픽을 만들 수는 있지만, 기본적으로 2D 그래픽만을 지원하기 때문에 매끄러운 3D를 구현할 수가 없었다.
이러한 UI적 단점 때문에 직접 구현한 코드는 접고 디자이너님과 상의 후 이미지를 통으로 돌려버리는 방식을 선택했었다.
캔버스로 그림을 그려보자(2)
다음은 회사 홈페이지에 있던 로봇 이미지를 캔버스 위에 그려보려고 했다. 이건 이미지상 표현할게 많아서 GPT에게 로봇 이미지를 건네주고, 캔버스 요소 위에 자바스크립트를 이용해 똑같은 그림을 그릴 수 있는 코드를 요청했다.
그 코드를 실행하면 과연 로봇과 얼마나 똑같은 모습이 완성될까?
결과물은 위와 같았다. 처음에 코드를 실행해보고 웃음이 났는데.. GPT가 똑똑해졌다더니 결과물이 왜 이럴까?
이유는 첫째, 이미지 자체에 블러효과가 들어가 있어서 이미지가 선명하지 않았다. 둘째, 가장 핵심적인 이유로 이전의 룰렛 그림이 매끄럽지 않았던 것과 같이, 캔버스 자체는 2D만 그릴 수 있기 때문에 GPT는 나름 최선을 다해서 2D로 로봇을 그려준 것이다.
자세히 보면 이미지와 얼굴, 팔, 다리의 위치가 비슷하고 나름 음영을 주려고 회색의 진함 정도가 다른 것을 알 수 있다. 3D 이미지를 그릴 수 없으니 어쩔 수 없던 것이다.
그렇다면 어떻게 해야 캔버스로 3D를 표현할 수 있을까?
관련 개념
WebGL
여기서 등장하는 개념이 WebGL이다. 캔버스는 원래 2D 그래픽만 렌더링할 수 있었는데, WebGL이 나온 후부터 고급 3D 애플리케이션을 만들 수 있게 되었다.
WebGL은 웹 브라우저에서 3D 그래픽을 렌더링할 수 있게 해주는 자바스크립트 API인데, 브라우저 엔진에 자체 내장되어 있어 따로 설치해줄 필요 없이 사용할 수 있다는 장점이 있다.
이러한 WebGL을 기반으로 만들어진 대표적인 3D 라이브러리로는 three.js가 있다.
단순히 canvas에 대해 알고 싶어 찾아 보기 시작했었는데, canvas와 WebGL을 순차대로 알아가면서 막연하게 느껴졌던 three.js까지 왜, 어떻게 구현하는것인지 배경 지식을 알 수 있어 좋았다.
이참에 내년엔 기회가 된다면 WebGL이나 three.js로 무언가를 구현해보는 것도...?!
'Front-End > HTML&CSS' 카테고리의 다른 글
[CSS] Align 알아보기 (0) | 2023.07.06 |
---|---|
[CSS] Float 알아보기 (1) | 2023.07.05 |
[CSS] Position 알아보기 (0) | 2023.07.05 |
[CSS] Display 알아보기 (0) | 2023.07.05 |
[CSS] CSS란? + Selectors (선택자) 알아보기 (0) | 2023.07.04 |