body{display:block}
.viz{position:relative;width:100%;height:100%}
svg{display:block;width:100%;height:100%;overflow:visible}
.tick{fill:var(--muted);font-weight:600}
.minor{display:none}
@media (min-width:460px){.minor{display:inline}}
.f0{fill:color-mix(in srgb, var(--accent) 42%, var(--surface))}
.f1{fill:color-mix(in srgb, var(--accent) 61%, var(--surface))}
.f2{fill:color-mix(in srgb, var(--accent) 80%, var(--surface))}
.f3{fill:var(--accent)}
var svg = document.getElementById('svg');
var NS = 'http://www.w3.org/2000/svg';
function se(t){ return document.createElementNS(NS,t); }
function sa(e,o){ for (var k in o) e.setAttribute(k,o[k]); }
function R(a,b){ return a + Math.random()*(b-a); }
var LABELS = ['방문','가입','장바구니','결제'];
function genVals(){
var v = [100];
for (var i=1;i<LABELS.length;i++) v.push(v[i-1]*R(0.46,0.82));
return v;
}
var cur = genVals();
var W=300, H=200;
function measure(){
var r = svg.getBoundingClientRect();
W = Math.max(r.width,10); H = Math.max(r.height,10);
sa(svg,{ viewBox: '0 0 ' + W + ' ' + H });
}
function draw(){
svg.innerHTML = '';
var padL=14, padR=14, padT=16, padB=6;
var pw=W-padL-padR, ph=H-padT-padB;
var n = cur.length;
var gap = ph*0.08;
var rowH = (ph-gap*(n-1))/n;
var fs = Math.max(8, Math.min(12, W/70));
var maxV = cur[0];
cur.forEach(function(v,i){
var bw = Math.max(14,(v/maxV)*pw);
var x = padL+(pw-bw)/2;
var y = padT+i*(rowH+gap);
var rect = se('rect');
sa(rect,{x:x,y:y,width:bw,height:rowH,rx:4,class:'f'+i});
svg.appendChild(rect);
var lab = se('text');
sa(lab,{x:W/2,y:y+rowH/2+fs*0.32,'text-anchor':'middle',fill:'var(--fg)','font-size':fs,'font-weight':700,stroke:'var(--surface)','stroke-width':3,'paint-order':'stroke'});
lab.textContent = LABELS[i]+' '+Math.round(v);
svg.appendChild(lab);
if (i>0){
var pct = se('text');
sa(pct,{x:W/2,y:y-4,'text-anchor':'middle',class:'tick minor','font-size':fs-1});
pct.textContent = Math.round(v/cur[i-1]*100)+'%';
svg.appendChild(pct);
}
});
}
function animate(target){
var from = cur.slice();
var t0 = performance.now();
function step(t){
var p = Math.min(1,(t-t0)/750);
var e = 1-Math.pow(1-p,3);
cur = from.map(function(v,i){ return v+(target[i]-v)*e; });
draw();
if (p<1) requestAnimationFrame(step);
}
requestAnimationFrame(step);
}
new ResizeObserver(function(){ measure(); draw(); }).observe(svg);
measure();
draw();
setInterval(function(){ animate(genVals()); }, 3700);