/* JewelLink admin — reusable SVG charts (on-brand, lightweight) */ /* Smooth area/line chart with gridlines + x labels */ function AreaChart({ data, labels, color = 'var(--blue-500)', height = 150, valueFmt = (v)=>v, yTicks = 4 }) { const w = 560, h = height, padL = 6, padR = 6, padT = 12, padB = 22; const iw = w - padL - padR, ih = h - padT - padB; const max = Math.max(...data), min = Math.min(...data, 0); const rng = max - min || 1; const X = i => padL + (i/(data.length-1))*iw; const Y = v => padT + ih - ((v-min)/rng)*ih; const pts = data.map((v,i)=>[X(i),Y(v)]); // smooth path (catmull-rom → bezier) let d = `M${pts[0][0]} ${pts[0][1]}`; for (let i=0;i min + (rng*i/yTicks)); return ( {ticks.map((t,i)=>( {valueFmt(Math.round(t))} ))} {pts.map((p,i)=> i===pts.length-1 && )} {labels && labels.map((l,i)=>( {l} ))} ); } /* Grouped/single vertical bars with gridlines */ function BarChart({ data, labels, color = 'var(--navy-600)', height = 160, valueFmt = (v)=>v, max: maxProp }) { const w = 560, h = height, padL = 6, padR = 6, padT = 14, padB = 24; const iw = w - padL - padR, ih = h - padT - padB; const max = maxProp || Math.max(...data) * 1.1; const bw = iw / data.length; const barW = Math.min(46, bw * 0.5); return ( {[0,0.25,0.5,0.75,1].map((f,i)=>{ const y = padT + ih - f*ih; return {valueFmt(Math.round(max*f))} ; })} {data.map((v,i)=>{ const x = padL + bw*i + bw/2; const bh = (v/max)*ih; const grad = 'bg'+i; return ( {valueFmt(v)} {labels && {labels[i]}} ); })} ); } /* Donut chart with center label + legend */ function DonutChart({ segments, size = 150, thickness = 22, centerTop, centerSub }) { const total = segments.reduce((s,x)=>s+x.value,0); const r = (size - thickness)/2, cx = size/2, cy = size/2, C = 2*Math.PI*r; let acc = 0; return (
{segments.map((s,i)=>{ const frac = s.value/total, len = frac*C; const el = ; acc += len; return el; })}
{centerTop}
{centerSub &&
{centerSub}
}
{segments.map((s,i)=>(
{s.label} {s.value}{s.suffix||''}
))}
); } Object.assign(window, { AreaChart, BarChart, DonutChart });