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 GROUPS = [
{ name: '대조군', color: 'var(--viz-4)' },
{ name: '실험군', color: 'var(--accent)' }
];
var NP = 16;
var pts = [];
GROUPS.forEach(function(g,gi){
for (var i=0;i<NP;i++) pts.push({ g:gi, v:50 });
});
function sampleBell(mean,spread){
var s=0; for (var k=0;k<4;k++) s+=Math.random();
return Math.max(2,Math.min(98, mean + (s/4-0.5)*2*spread));
}
function nextValues(){
var out=[];
GROUPS.forEach(function(){
var mean = R(30,70), spread = R(24,46);
for (var i=0;i<NP;i++) out.push(sampleBell(mean,spread));
});
return out;
}
var OFFSETS = (function(){ var a=[0]; for (var k=1;k<=30;k++){ a.push(k); a.push(-k); } return a; })();
function layoutSwarm(items, r){
var order = items.slice().sort(function(a,b){ return a.px-b.px; });
var placed = [];
order.forEach(function(p){
var chosen = 0;
for (var oi=0; oi<OFFSETS.length; oi++){
var cand = OFFSETS[oi]*r*1.08;
var ok = true;
for (var j=0;j<placed.length;j++){
var q = placed[j];
var dx = p.px-q.px, dy = cand-q.py;
if (dx*dx+dy*dy < (r*2.02)*(r*2.02)){ ok=false; break; }
}
if (ok){ chosen=cand; break; }
}
p.py = chosen;
placed.push(p);
});
}
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=32,padR=14,padT=18,padB=16;
var pw=W-padL-padR, ph=H-padT-padB;
var rowY = [padT+ph*0.28, padT+ph*0.78];
var r = Math.max(2.2, Math.min(3.6, W/110));
GROUPS.forEach(function(g,gi){
var items = pts.filter(function(p){ return p.g===gi; });
items.forEach(function(p){ p.px = padL+(p.v/100)*pw; });
layoutSwarm(items, r);
items.forEach(function(p){ p.cx = p.px; p.cy = rowY[gi]+p.py; });
var lab = se('text');
sa(lab,{ x:padL-6, y:rowY[gi]+3, 'text-anchor':'end', fill:'var(--muted)', 'font-size':9, 'font-weight':700 });
lab.textContent = g.name;
svg.appendChild(lab);
});
var axis = se('line');
sa(axis,{ x1:padL, y1:H-4, x2:W-padR, y2:H-4, stroke:'var(--line)', 'stroke-width':1 });
svg.appendChild(axis);
pts.forEach(function(p){
var c = se('circle');
sa(c,{ cx:p.cx, cy:p.cy, r:r, fill:GROUPS[p.g].color, 'fill-opacity':0.85 });
svg.appendChild(c);
});
}
function animate(targetVals){
var from = pts.map(function(p){ return p.v; });
var t0=performance.now();
function step(t){
var pr=Math.min(1,(t-t0)/850);
var e=1-Math.pow(1-pr,3);
pts.forEach(function(p,i){ p.v = from[i]+(targetVals[i]-from[i])*e; });
draw();
if (pr<1) requestAnimationFrame(step);
}
requestAnimationFrame(step);
}
new ResizeObserver(function(){ measure(); draw(); }).observe(svg);
measure();
draw();
animate(nextValues());
setInterval(function(){ animate(nextValues()); }, 3800);