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 KPI = [
{ name:'매즈', bands:[40,75,100] },
{ name:'신긌가입', bands:[30,60,100] },
{ name:'만족도', bands:[50,80,100] }
];
var cur = KPI.map(function(){ return { actual:50, target:70 }; });
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=64,padR=16,padT=10,padB=10;
var pw=W-padL-padR, ph=H-padT-padB;
var n=KPI.length;
var rowH=ph/n;
var barH=Math.min(14,rowH*0.34);
var fs=Math.max(8,Math.min(10,W/56));
var bandShades=[0.16,0.28,0.42];
KPI.forEach(function(k,i){
var y=padT+rowH*(i+0.5);
var lab=se('text');
sa(lab,{ x:padL-8, y:y+3, 'text-anchor':'end', fill:'var(--muted)', 'font-size':fs, 'font-weight':600 });
lab.textContent = k.name;
svg.appendChild(lab);
var prev=0;
k.bands.forEach(function(b,bi){
var x0=padL+(prev/100)*pw, x1=padL+(b/100)*pw;
var band=se('rect');
sa(band,{ x:x0, y:y-barH*1.15, width:x1-x0, height:barH*2.3, fill:'var(--muted)', 'fill-opacity':bandShades[bi] });
svg.appendChild(band);
prev=b;
});
var av=cur[i].actual;
var bar=se('rect');
sa(bar,{ x:padL, y:y-barH/2, width:(av/100)*pw, height:barH, fill:'var(--accent)' });
svg.appendChild(bar);
var tx=padL+(cur[i].target/100)*pw;
var tick=se('line');
sa(tick,{ x1:tx, y1:y-barH*1.3, x2:tx, y2:y+barH*1.3, stroke:'var(--fg)', 'stroke-width':2.4 });
svg.appendChild(tick);
});
}
function animate(target){
var from = cur.map(function(c){ return { actual:c.actual, target:c.target }; });
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(c,i){ return { actual:c.actual+(target[i].actual-c.actual)*e, target:c.target+(target[i].target-c.target)*e }; });
draw();
if (p<1) requestAnimationFrame(step);
}
requestAnimationFrame(step);
}
function nextTarget(){
return KPI.map(function(){ return { actual:R(15,98), target:R(55,92) }; });
}
new ResizeObserver(function(){ measure(); draw(); }).observe(svg);
measure();
draw();
animate(nextTarget());
setInterval(function(){ animate(nextTarget()); }, 3600);