gatepass / src /components /CompressionChart.tsx
rb125
Initial frontend deploy
4c62137
Raw
History Blame Contribute Delete
1.96 kB
"use client";
import { motion } from "framer-motion";
import type { CDCTPoint } from "@/lib/types";
export function CompressionChart({ data }: { data: CDCTPoint[] }) {
if (!data.length) return null;
const w = 400, h = 180, pad = 30;
const plotW = w - pad * 2, plotH = h - pad * 2;
const points = data.map((d, i) => ({
x: pad + (i / Math.max(data.length - 1, 1)) * plotW,
sa: pad + plotH - (d.sa_score / 10) * plotH,
label: `${(d.compression_level * 100).toFixed(0)}%`,
}));
const linePath = points.map((p) => `${p.x},${p.sa}`).join(" ");
return (
<div className="w-full">
<svg viewBox={`0 0 ${w} ${h}`} className="w-full overflow-visible">
{/* Minimal Grid */}
{[0, 5, 10].map((v) => {
const y = pad + plotH - (v / 10) * plotH;
return (
<line key={v} x1={pad} y1={y} x2={w - pad} y2={y} stroke="rgba(255,255,255,0.03)" strokeWidth="0.5" />
);
})}
{/* Signal Line */}
<motion.polyline
initial={{ pathLength: 0 }}
animate={{ pathLength: 1 }}
transition={{ duration: 1.5, ease: [0.4, 0, 0.2, 1] }}
points={linePath}
fill="none"
stroke="rgba(255, 255, 255, 0.3)"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
{/* Nodes */}
{points.map((p, i) => (
<circle key={i} cx={p.x} cy={p.sa} r="2" fill="white" />
))}
{/* X Labels */}
{points.map((p, i) => (
<text key={i} x={p.x} y={h - 10} textAnchor="middle" fill="var(--text-dim)" fontSize="7" fontWeight="500" className="opacity-40">
{p.label}
</text>
))}
</svg>
<div className="flex justify-center mt-2">
<span className="text-[9px] uppercase tracking-widest text-text-dim">Semantic Integrity Curve</span>
</div>
</div>
);
}