글목록 보기

Fabric.js -> SVG.js 전환기

[작성일] 2024년 10월 2일

FromFabricToSVG썸네일이미지

이 게시글은 프론트엔드 개발자로 전향한 지 반년 차였던 2022년 가을에 겪은 경험을 담은 글이다. 실무 프로젝트의 Canvas 기반 핵심 모듈을 SVG 기술 기반으로 마이그레이션한 경험을 설명한다.


시작하며

우리 팀이 새롭게 맡게 된 프로젝트는 “인공지능 학습용 영상 데이터 가공 플랫폼” 개발이었다. 기존에 사내에서 사용되던 레거시 도구는 최소한의 기능만 제공하며, Bootstrap으로 구현된 단순한 내부 사용자용 도구로, 공개 서비스로는 부족한 상태였다.

특히, 끊임없이 늘어나는 기능 요구사항과 코드 관리의 부재로 기술적 부채가 심화되고 있었고, 이를 해결하기 위해 새롭게 플랫폼을 브랜딩하고 처음부터 개발하기로 결정했다.

머지 않아 기획과 화면 설계가 진행되었고, 주요 기능별로 담당자를 배정했다. 나는 HTML Canvas API를 개인 프로젝트에서 다뤄본 경험으로, 요구사항이 가장 많았던 “데이터 라벨링 작업공간” 화면을 전담하게 되었다.

마이그레이션을 결정

기존 레거시 도구에서는 “데이터 라벨링 작업공간” 화면이 HTML5 Canvas를 기반으로한 Fabric.js라이브러리로 구현 되어 있었다.

하지만, 기존 코드와 라이브러리를 익히던 중 HTML5 Canvas와 Fabric.js의 부족한 확장성, 많은 기능 요구사항 구현에 부적합함 등의 문제를 파악할 수 있었고 적합한 라이브러리를 찾아보기로 했다.

pixi.js, Ease1JS 등 다양한 웹 2D 그래픽 오픈소스 라이브러리를 리서치했고 경쟁사에서는 어떤 라이브러리를 사용하는지도 조사했다. 고심 끝에 SVG기반의 SVG.js라이브러리를 최종 채택하여 마이그레이션을 진행하기로 결정할 수 있었다.

후술할 내용들을 바탕으로 마이그레이션을 결정한 이유를 더 자세히 설명하도록 하겠다.


HTML5 Canvas와 SVG

Fabric.js는 HTML5 Canvas를 기반으로 한 라이브러리이고, SVG.js는 SVG를 다루기 위한 라이브러리이다. 두 라이브러리는 기반 기술이 다르기 때문에, 단순히 Fabric.js와 SVG.js를 비교하기보다는 Canvas와 SVG 각 그래픽 기술의 차이를 먼저 이해할 필요가 있었다.

Canvas

HTML5 Canvas API는 <canvas> 태그를 자바스크립트로 조작하여 픽셀 단위로 레스터화된 이미지를 생성하고 조작할 수 있는 기능을 제공하는 기술이다.

아래 코드는 canvas에서 왼쪽으로 10px, 위쪽으로 10px 떨어진 위치에 크기가 100 x 100 픽셀인 빨간 사각형을 그리는 예제 코드이다.

<canvas id="myCanvas" width="800" height="800"></canvas>

<script>
  const canvas = document.getElementById("myCanvas");
  const context = canvas.getContext("2d");
  context.fillStyle = "#c00";
  context.fillRect(10, 10, 100, 100);
</script>

위 예제 코드의 결과물은 이미지로 생성되며, 우클릭을 통해 이미지를 다운받을 수 있다. 이미지로 생성되기 때문에, JavaScript를 통한 사용자 이벤트 감지나 CSS로 스타일링을 적용하는 데 제약이 있다.

Canvas는 많은 상호작용이 있는 게임, 잦은 업데이트가 있는 실시간 데이터 시각화, 작은 영역에 많은 객체를 그려야 하는 시나리오에 강점을 보인다. 이는 Canvas가 즉시 그래픽 시스템으로, 픽셀이 한 번 그려지면 브라우저에 따로 보존하지 않고 정보를 없애기 때문이다. Canvas의 강점과 약점은 아래와 같다.

  • 강점
    • 게임, 실시간 데이터 연동처럼 자주 변경이 발생하는 경우에 적합
    • 많은 객체를 화면에 동시에 표시해야 할 때 유리
  • 약점
    • 객체를 크게 확대할 경우 품질 저하가 발생
    • 그래픽 상의 객체를 검색하거나 접근하는 데 제약이 있음

SVG

SVG는 Scalable Vector Graphics의 약자로, 2D 그래픽을 표현하는 XML 기반의 언어이다. 웹에서는 HTML5 문법을 사용하여 SVG를 다룬다. SVG로 작성된 그래픽은 CSS와 JavaScript를 사용하여 동적으로 제어할 수 있으며, 각 SVG 요소는 DOM 요소처럼 이벤트에 반응할 수 있다.

아래 코드는 위에서 본 예제와 동일한 결과물을 만드는 예제 코드이다.

<svg xmlns="https://www.w3.org/2000/svg" viewbox="0 0 800 800">
  <rect x="10" y="10" width="100" height="100" fill="#c00"  />
</svg>

SVG는 확장성이 중요한 경우에 적합하다. 예를 들어, 건축 및 공학 다이어그램, 생물학적 다이어그램, 조직도 등 복잡한 고해상도 그래픽을 다룰 때 유리하다. 또한, SVG는 사람이 읽을 수 있는 XML 기반 구조로 되어 있어 접근성 측면에서 유리하며, 사용자와의 상호작용을 쉽게 추가할 수 있다. SVG의 강점과 약점은 아래와 같다.

  • 강점
    • 확대 및 축소시 품질 저하가 없으므로 고해상도 디스플레이와 복잡한 그래픽에 적합
    • XML 기반 구조로 사람이 읽을 수 있으며, CSS와 JavaScript로 스타일링과 상호작용이 가능
  • 약점
    • 많은 노드를 포함한 복잡한 SVG는 렌더링 성능에 영향을 미침
    • 무거운 실시간 데이터 시각화나 애니메이션에는 부적합

고려 사항

성능

Canvas는 즉시 그래픽 시스템으로, 한 번 픽셀이 그려지면 그 정보는 사라진다. 반면, SVG는 객체를 브라우저의 내부 모델에 저장하는 보존 방식을 사용한다. 이는 개발자에게 친숙한 방법이지만, 성능에 영향을 미칠 수 있다.

정리하자면, SVG는 Canvas보다 개발자에게 더 친숙하고 확대 및 축소에 유리하지만, 객체가 많아질 경우 기하급수적인 성능 저하를 일으킬 수 있는 문제점이 있다.

Canvas_SVG_성능_벤치마킹_이미지

(출처 https://blog.logrocket.com/)

객체 수에 따른 렌더링 소요 시간 벤치마킹을 참고하면, 실제로 객체가 많아질 때 SVG는 성능 저하가 급격히 일어나는 것을 알 수 있다.

그렇지만, 플랫폼 스펙 상 최대 20,000개의 객체를 지원하면 되었고, 이는 지표에서 나타나는 심각한 성능 저하 수준에 도달하지 않음을 확인했다. 결국, 개발자 친화적이고 다양한 사용자 상호작용 요구사항을 충족하기 위해선 SVG를 채택하는 것이 납득 가능한 Trade-Off라는 결론을 내릴 수 있었다.

요구사항 충족

타이트한 일정 속에서 수많은 기능과 요구사항을 담아낸 “데이터 라벨링 작업공간” 화면을 개발해야 했다. 이러한 상황에서 SVGSVG.js는 가장 적합한 선택지로 떠올랐다. 아래에서 주요 요구사항을 중심으로 그 이유를 살펴보겠다

라벨링_데이터_예시_블러처리_이미지

예시 요구사항 데이터 이미지

1. 다양한 클래스를 지원

작업공간 화면에서는 바운딩 박스, 폴리곤, 랜드마크 클래스를 표현할 수 있어야 했다.

Fabric.js는 많은 기능과 편의를 제공하는 만큼 추상화 정도가 높았고, 확장성과 유연성이 비교적 부족한 라이브러리었다. 제공 된 기능 이외의 기능을 구현하거나 스타일 커스터마이징을 할때에 추가적인 리소스가 필요하게 되었다.

반면, SVG.js는 다양한 그래픽 요소를 쉽게 생성하고 조작할 수 있는 유틸리티 API를 제공하여 각 클래스를 직접 구현할 수 있었다.

2. 다양한 스타일, UI를 표현

각 객체는 상태에 따라 다양한 스타일을 표현해야 하며, 플로팅 라벨과 아이콘 같은 상호작용 요소를 화면에 표시할 수 있어야 했다.

SVG는 CSS와 JavaScript를 통해 스타일을 직접 제어할 수 있다는 점에서, 다양한 상태와 UI를 표현해야 하는 요구사항을 충족하기에 적합했다.

3. 매우 크거나 작은 해상도의 영상 데이터를 작업

작업공간에서는 매우 크거나 작은 해상도의 영상 데이터에서 세밀한 작업을 진행해야 하는 요구사항이 있었다.

이러한 영상 데이터에서는 높은 정밀도가 요구되었다. 정밀한 작업을 위해 이미지 품질이 유지되어야 했으며, Zoom 및 Panning 기능이 필수적이었다.

Canvas로도 이러한 작업을 구현할 수는 있지만, 픽셀 단위로 이미지를 다루는 기술적인 제약 때문에 품질 손생이 발생할 가능성이 높았다. 반면, SVG는 벡터 기반 구조를 사용하여 이미지 품질을 유지하면서도 viewbox 속성을 이용해 확대/축소 기능을 쉽게 구현할 수 있었다.


결과

개발결과물_프로토타입_동영상

최초 프로토타입 시연 영상

최종적으로 Canvas를 대체해 SVG기반의 SVG.js를 선택했고, 작업공간 화면을 기간 내에 성공적으로 완성할 수 있었다. 마이그레이션 작업으로 얻은 이점은 아래와 같다.

  1. 유연성과 확장성: SVG.js의 유틸리티 API를 통해 대부분의 기능 구현을 직접 진행했다. 이를 통해 차후 진행해야하는 신규 기능개발과 유지보수에 있어 이점을 가지게 되었다.

  2. 스타일링/UI 개발 리소스 감소: CSS와 Javascript를 활용한 간편한 스타일 제어가 가능했기 때문에 복잡한 상태와 UI를 처리하는 리소스를 줄일 수 있었다.

  3. 고해상도 작업 지원: 벡터 기반의 SVG는 확대/축소와 같은 정밀 작업에서 영상 품질 손실이 없어, 작업 환경의 요구사항에 잘 부합했다.

마치며

처음 작업 공간 화면을 개발할 때부터 2024년 하반기인 오늘까지, 수십 개의 추가 요구사항을 새롭게 개발하게 되었다.

최초 개발할 때 SVG 기반으로 마이그레이션을 결정하지 않았다면, 기능 개발이 어려웠거나 기한을 맞추지 못하는 상황이 발생했을 것이다.

과거에 이러한 결정을 내린 나에게 감사하며, 관성에 따라 기존 기술을 활용하는 것이 위험한 행위임을 깨닫게 되었다. 또한, 개발을 시작하기 전에 적합한 기술을 검토하는 일이 정말 중요하다는 것을 다시 한 번 되새기게 된다.


참고

https://www.sitepoint.com/canvas-vs-svg/

https://blog.logrocket.com/when-to-use-html5s-canvas-ce992b100ee8/

https://svgjs.dev/docs/3.2/

https://fabricjs.com/