Monorepo for Tangled
tangled.org
1import type { Language } from "../../validation";
2
3interface LanguageCirclesProps {
4 languages: Language[];
5 width: number;
6}
7
8export function LanguageCircles({ languages, width }: LanguageCirclesProps) {
9 const MAX_RADIUS = width || 100;
10
11 const sortedLanguages = [...languages]
12 .sort((a, b) => b.percentage - a.percentage)
13 .slice(0, 5);
14
15 let cumulativePercentage = 0;
16 const circles: { color: string; radius: number }[] = [];
17
18 for (const lang of sortedLanguages) {
19 // Radius decreases as we go inward, but ring area is proportional to percentage
20 // Using sqrt to make area (πr²) proportional to remaining percentage
21 const radius = Math.max(
22 1,
23 Math.round(MAX_RADIUS * Math.sqrt(1 - cumulativePercentage / 100) * 100) /
24 100,
25 );
26 circles.push({ color: lang.color, radius });
27 cumulativePercentage += lang.percentage;
28 }
29
30 return (
31 <svg
32 width={MAX_RADIUS}
33 height={MAX_RADIUS}
34 viewBox={`0 0 ${MAX_RADIUS * 2} ${MAX_RADIUS * 2}`}>
35 {circles.map((circle, i) => (
36 <circle
37 key={i}
38 cx="50%"
39 cy="50%"
40 r={circle.radius}
41 fill={circle.color}
42 />
43 ))}
44 </svg>
45 );
46}