-
Notifications
You must be signed in to change notification settings - Fork 35
Expand file tree
/
Copy pathArrayVisualizer.tsx
More file actions
99 lines (88 loc) · 3.1 KB
/
Copy pathArrayVisualizer.tsx
File metadata and controls
99 lines (88 loc) · 3.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
import type { Step } from '@lib/types'
import { highlightColors, DEFAULT_BAR_COLOR } from '@lib/highlight-colors'
interface ArrayVisualizerProps {
step: Step
}
export default function ArrayVisualizer({ step }: ArrayVisualizerProps) {
const { array = [], highlights = {}, sorted = [] } = step
if (array.length === 0) return null
const maxValue = Math.max(...array, 1)
const barGap = array.length > 12 ? 2 : 4
const activeHighlights = Object.entries(highlights)
.filter(([, type]) => type)
.map(([idx, type]) => `index ${idx}: ${type}`)
.join(', ')
return (
<div
className="flex-1 flex flex-col items-center justify-center gap-6 w-full"
role="img"
aria-label={`Array visualization: ${array.length} elements [${array.join(', ')}]${activeHighlights ? `. Active: ${activeHighlights}` : ''}`}
>
{/* Bar chart */}
<div
className="flex items-end w-full max-w-3xl"
style={{ height: 'clamp(180px, 40vw, 300px)', gap: `${barGap}px` }}
aria-hidden="true"
>
{array.map((value, index) => {
const highlight = highlights[index]
const isSorted = sorted.includes(index)
const color = highlight
? highlightColors[highlight]
: isSorted
? highlightColors.sorted
: DEFAULT_BAR_COLOR
const heightPercent = Math.max((value / maxValue) * 100, 2)
return (
<div
key={index}
className="flex-1 flex flex-col items-center justify-end h-full relative"
>
{/* Value label above bar */}
<span
className="text-[11px] font-mono font-semibold mb-2 transition-all duration-300"
style={{ color }}
>
{value}
</span>
{/* Bar */}
<div
className="w-full rounded-t-sm transition-all duration-300 ease-in-out relative"
style={{
height: `${heightPercent}%`,
backgroundColor: color,
opacity: !highlight && !isSorted ? 0.6 : 1,
}}
/>
</div>
)
})}
</div>
{/* Index row */}
<div className="flex w-full max-w-3xl" style={{ gap: `${barGap}px` }} aria-hidden="true">
{array.map((_, index) => {
const highlight = highlights[index]
const isSorted = sorted.includes(index)
const color = highlight
? highlightColors[highlight]
: isSorted
? highlightColors.sorted
: 'var(--viz-faint)'
return (
<div
key={index}
className="flex-1 text-center text-[10px] font-mono py-1 rounded-md transition-all duration-300"
style={{
backgroundColor: `${color}12`,
color: color,
borderBottom: highlight ? `2px solid ${color}40` : '2px solid transparent',
}}
>
{index}
</div>
)
})}
</div>
</div>
)
}