배경
프론트엔드 작업은 화면 그리는일이 많다. 여러 프로젝트중 데이터 시각화를 구현하다보면 단순히 그리는 행위가 다가 아니라는것을 금방 깨닫게 된다. 데이터가 클수록 백엔드, 프론트엔드 전체를 생각하는 현명한 방법이 필요하다.
오늘은 브라우저단에서 대용량 데이터를 바탕으로 도형을 그릴때 어떤 방법이 효율적인지 비교를 해보도록 하겠다.
목표
해결해야할 목표는 다음과 같다.
500 x 500px 화면에 25만개의 1px 점(dot)을 그린다. 100 x 100px (1만개) / 1000 x 1000px (100만개) 에서도 동일하게 그려본다.
웹기반 UI를 그리기위해 세가지의 방법을 해보면서 비교해본다.
- HTML DOM
- SVG
- Canvas
편의상 25만개의 픽셀에 랜덤하게 색상을 입혀서 적용시켜보았다.
CPU/RAM/GPU등 하드웨어 성능과 브라우저 성능에 따라서 차이가 날 수 있으니 상대적인 비교를 보는것이 좋다. 테스트 환경은 i7/8GB/macOS/Chrome으로 테스트를 하였다.
1. HTML DOM
첫번째로 DOM으로 그리는 방식이다. 1px짜리 dom 25만개를 몰아서 그려넣엇을때 걸리는 시간은 얼마나 될까?
const area = document.getElementById('html');
console.time('Draw using HTML');
for(let i = 0; i < 500; i++) {
for(let j = 0; j < 500; j++) {
let dot = document.createElement("div");
dot.classList = 'dot';
dot.style.backgroundColor = getHex();
area.appendChild(dot)
}
}
console.timeEnd('Draw using HTML');
결과는?
Draw using HTML: 4356.2841796875ms
Draw using HTML: 3448.929931640625ms
Draw using HTML: 4671.57275390625ms
대략 3~4초 정도 걸린다.
그렇다면 메모리의 관점에서 본다면 얼마나 차지할지를 알아보자.
Google Chrome Helper: 796.3M
2. SVG
다음은 SVG를 이용하겠다. 1px짜리 rect를 그린다.
const area = document.getElementById('svg');
let dots = [];
console.time('Draw using SVG');
for(let i = 0; i < 500; i++) {
for(let j = 0; j < 500; j++) {
dots.push("<rect class='dot' style='fill:"+getHex()+"' width='1' height='1' x='"+(i)+"' y='"+(j)+"'></rect>");
}
}
area.innerHTML = area.innerHTML + dots.join("");
console.timeEnd('Draw using SVG');
Draw using SVG: 7799.06103515625ms
Draw using SVG: 6832.514892578125ms
Draw using SVG: 7336.588134765625ms
DOM방식보다 오래 걸리는것을 알 수 있다.
Google Chrome Helper:1.7G
메모리 측면에서도 과부하가 더 심하게 걸린다.
3.Canvas
마지막으로 Canvas에 마찬가지로 1px을 찍어본다.
const area = document.getElementById('canvas');
let ctx = area.getContext("2d");
console.time('Draw using Canvas');
for(let i = 0; i < 500; i++) {
for(let j = 0; j < 500; j++) {
ctx.fillStyle = getHex();
ctx.fillRect(i, j, 1, 1);
}
}
console.timeEnd('Draw using Canvas');
Draw using Canvas: 430.7109375ms
Draw using Canvas: 417.10888671875ms
Draw using Canvas: 388.585693359375ms
와우. 확연하게 빨라진 모습이다. 1,2번 방식은 화면이 나올때까지 시간이 상당히 걸리고 불러온뒤에도 과부하가 많이 발생한다. 하지만 Canvas로 그릴때는 시간뿐만 아니라 화면상 다른 동작을 할때도 전혀 부담이 없다.
Google Chrome Helper:217.6M
빠른 응답속도가 말해주듯 메모리 과부하고 가장 적다.
캔버스 사이즈 변경
이와 같은 방법으로 100 x 100 / 1000 x 1000 에서도 동일하게 테스트를 해보았다. 결과를 표로 정리해서 비교해보자.
1000 x 1000의 화면의 경우 HTML DOM / SVG는 테스트가 불가능할정도로 과부하가 심하게 걸렸다. 테스트를 할수록 RAM을 더 많이 잡아먹기때문에 더더욱 느려진다.
Canvas만이 1000 x 1000화면에서 쾌적한 성능을 보여준다.
결론
앞서 말했듯이 사용하는 컴퓨터의 성능에 따라 결과가 많이 달라진다. 그렇기 때문에 각 기법의 상대적인 비교를 보면 되겠다.
테스트에서 보듯이 Canvas를 이용하여 그리는것이 비교할수 없을만큼 빠르다는것을 알 수 있다.
다만 Canvas의 경우 DOM / SVG에서 가능한 개별 dot에 대한 이벤트 (click, mouseover등) 이 불가능하기 때문에 interaction이 필요한 작업이라면 다른 기법을 활용해야한다. 그렇기때문에 각 기법에 대한 이해를 높이고 작업의 목표에 따라서 자유자재로 적절한 기법을 사용하는것이 중요하겠다.