Skip to content

Commit c266d77

Browse files
committed
优化代码显示组件的变量值展示
1. 增强变量监视面板: - 按类型分组显示变量(节点、值、结果、其他) - 添加步骤类型标签显示当前执行阶段 - 为不同类型变量添加颜色编码和图标 2. 改进代码行内变量标注: - 根据步骤类型智能选择显示的变量 - 添加高亮脉冲动画效果 - 为布尔值添加图标(✓/✗) 3. 优化样式: - 增强debug效果的视觉呈现 - 改进变量标签的悬停效果 - 优化响应式布局 4. 修复编译错误: - 导出预留功能函数 - 清理未使用的导入和变量
1 parent 9abed43 commit c266d77

27 files changed

+7181
-333
lines changed
Lines changed: 367 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,367 @@
1+
# Design Document: Algorithm Visualization Platform
2+
3+
## Overview
4+
5+
本设计文档描述一个以教学为目的的 LeetCode 算法可视化演示平台。平台使用 TypeScript + React + D3.js 技术栈,以单屏幕形式展示算法的分步骤执行过程。核心目标是通过交互式画布、代码同步高亮、数据流可视化等功能,帮助用户直观理解算法执行过程。
6+
7+
## Architecture
8+
9+
### 整体架构
10+
11+
```
12+
┌─────────────────────────────────────────────────────────────────┐
13+
│ Header │
14+
│ [GitHub ⭐] [101. 对称二叉树 →] │
15+
├─────────────────────────────────────────────────────────────────┤
16+
│ [输入框] [样例1] [样例2] [样例3] [🎲随机] │
17+
├─────────────────────────────────────────────────────────────────┤
18+
│ │
19+
│ ┌─────────────────────────────┐ ┌──────────────────────────┐ │
20+
│ │ │ │ Code Display │ │
21+
│ │ Canvas (D3.js) │ │ ┌────────────────────┐ │ │
22+
│ │ │ │ │ Java Python Go JS │ │ │
23+
│ │ [Tree Visualization] │ │ ├────────────────────┤ │ │
24+
│ │ [Data Flow Arrows] │ │ │ 1│ public boolean │ │ │
25+
│ │ [Annotations] │ │ │►2│ if (root == │ │ │
26+
│ │ [Recursion Stack] │ │ │ 3│ return isMir │ │ │
27+
│ │ │ │ │ │ left=1 ✓ │ │ │
28+
│ │ │ │ └────────────────────┘ │ │
29+
│ └─────────────────────────────┘ └──────────────────────────┘ │
30+
│ │
31+
├─────────────────────────────────────────────────────────────────┤
32+
│ [⏮ R] [⏪ ←] [▶ 空格] [→ ⏩] [⏭] 速度: [0.5x][1x][2x][4x] │
33+
│ ████████████░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░ │
34+
└─────────────────────────────────────────────────────────────────┘
35+
[💬 交流群]
36+
```
37+
38+
### 组件层次结构
39+
40+
```
41+
App
42+
├── Header
43+
│ ├── GitHubBadge (Star count with IndexedDB cache)
44+
│ └── LeetCodeTitle (Clickable link)
45+
├── DataInputBar
46+
│ ├── TextInput
47+
│ ├── PresetExamples
48+
│ └── RandomGenerator
49+
├── MainContent
50+
│ ├── CanvasPanel
51+
│ │ ├── TreeVisualization (D3.js)
52+
│ │ ├── DataFlowArrows
53+
│ │ ├── AnnotationSystem
54+
│ │ └── RecursionStackOverlay
55+
│ └── CodePanel
56+
│ ├── LanguageTabs
57+
│ ├── CodeLines (with line numbers)
58+
│ ├── ExecutionHighlight
59+
│ └── VariableWatch
60+
├── BottomControlBar
61+
│ ├── PlaybackControls
62+
│ ├── SpeedSelector
63+
│ └── ProgressBar
64+
└── WeChatFloat
65+
```
66+
67+
## Components and Interfaces
68+
69+
### 1. Header 组件
70+
71+
```typescript
72+
interface HeaderProps {
73+
title: string; // "101. 对称二叉树"
74+
leetcodeUrl: string; // LeetCode 题目链接
75+
githubUrl: string; // GitHub 仓库链接
76+
githubRepo: string; // "owner/repo" 格式
77+
}
78+
79+
interface GitHubStarCache {
80+
stars: number;
81+
timestamp: number; // 缓存时间戳
82+
}
83+
```
84+
85+
### 2. DataInputBar 组件
86+
87+
```typescript
88+
interface DataInputBarProps {
89+
onDataChange: (data: TreeData) => void;
90+
onError: (error: string) => void;
91+
}
92+
93+
interface PresetExample {
94+
label: string;
95+
value: string;
96+
description?: string;
97+
}
98+
99+
// 数据验证函数
100+
function validateTreeInput(input: string): ValidationResult;
101+
function generateRandomTree(constraints: TreeConstraints): TreeData;
102+
```
103+
104+
### 3. CodeDisplay 组件
105+
106+
```typescript
107+
type Language = 'java' | 'python' | 'golang' | 'javascript';
108+
109+
interface CodeDisplayProps {
110+
method: 'recursive' | 'iterative';
111+
currentStep: number;
112+
variables: VariableMap;
113+
}
114+
115+
interface CodeLine {
116+
lineNumber: number;
117+
content: string;
118+
isHighlighted: boolean;
119+
isExecuting: boolean;
120+
variables?: VariableAnnotation[];
121+
}
122+
123+
interface VariableAnnotation {
124+
name: string;
125+
value: string | number | boolean | null;
126+
type: 'node' | 'value' | 'result' | 'size';
127+
}
128+
```
129+
130+
### 4. Canvas 组件
131+
132+
```typescript
133+
interface CanvasProps {
134+
root: TreeNode | null;
135+
currentStep: AlgorithmStep;
136+
animationEnabled: boolean;
137+
}
138+
139+
interface DataFlowArrow {
140+
from: Position;
141+
to: Position;
142+
label: string;
143+
type: 'value-transfer' | 'comparison' | 'return';
144+
}
145+
146+
interface Annotation {
147+
nodeId: string;
148+
text: string;
149+
position: 'top' | 'bottom' | 'left' | 'right';
150+
type: 'compare' | 'result' | 'info';
151+
}
152+
```
153+
154+
### 5. BottomControlBar 组件
155+
156+
```typescript
157+
interface BottomControlBarProps {
158+
currentStep: number;
159+
totalSteps: number;
160+
isPlaying: boolean;
161+
playSpeed: number;
162+
onStepChange: (step: number) => void;
163+
onPlayToggle: () => void;
164+
onSpeedChange: (speed: number) => void;
165+
onReset: () => void;
166+
}
167+
168+
// IndexedDB 存储接口
169+
interface PlaybackSettings {
170+
speed: number;
171+
lastUpdated: number;
172+
}
173+
```
174+
175+
### 6. WeChatFloat 组件
176+
177+
```typescript
178+
interface WeChatFloatProps {
179+
qrCodeUrl: string;
180+
instructions: string;
181+
}
182+
```
183+
184+
## Data Models
185+
186+
### TreeNode
187+
188+
```typescript
189+
interface TreeNode {
190+
val: number;
191+
left: TreeNode | null;
192+
right: TreeNode | null;
193+
}
194+
```
195+
196+
### AlgorithmStep
197+
198+
```typescript
199+
interface AlgorithmStep {
200+
stepIndex: number;
201+
type: 'initial' | 'compare' | 'check-null' | 'check-value' | 'check-subtree' | 'return' | 'final';
202+
message: string;
203+
detailedMessage?: string;
204+
leftNodeId?: string;
205+
rightNodeId?: string;
206+
result?: boolean;
207+
codeLineNumber: number;
208+
variables: VariableMap;
209+
annotations: Annotation[];
210+
dataFlowArrows: DataFlowArrow[];
211+
}
212+
```
213+
214+
### IndexedDB Schema
215+
216+
```typescript
217+
// Database: leetcode-symmetric-tree-db
218+
// Stores:
219+
// 1. github-cache: { key: string, stars: number, timestamp: number }
220+
// 2. settings: { key: string, value: any }
221+
```
222+
223+
## Correctness Properties
224+
225+
*A property is a characteristic or behavior that should hold true across all valid executions of a system-essentially, a formal statement about what the system should do. Properties serve as the bridge between human-readable specifications and machine-verifiable correctness guarantees.*
226+
227+
### Property 1: GitHub Star Cache Validity
228+
*For any* star count fetched from the GitHub API, the system SHALL store it in IndexedDB with a timestamp, and subsequent fetches within one hour SHALL return the cached value without making an API call.
229+
**Validates: Requirements 2.4**
230+
231+
### Property 2: Random Tree Generation Validity
232+
*For any* randomly generated tree data, the output SHALL conform to the problem constraints (valid array format, root not null, all values are numbers or null).
233+
**Validates: Requirements 3.6**
234+
235+
### Property 3: Input Validation Correctness
236+
*For any* user input string, the validation function SHALL correctly identify whether it represents a valid tree array according to the problem constraints.
237+
**Validates: Requirements 3.7**
238+
239+
### Property 4: Code-Step Synchronization
240+
*For any* algorithm step, the code display SHALL highlight the corresponding code line that matches the step's execution point.
241+
**Validates: Requirements 4.3**
242+
243+
### Property 5: Variable Display Accuracy
244+
*For any* variable value change during algorithm execution, the displayed value SHALL match the actual value at that step.
245+
**Validates: Requirements 4.4**
246+
247+
### Property 6: Keyboard Shortcut Consistency
248+
*For any* keyboard shortcut press (←, →, Space, R), the system SHALL execute the corresponding action (previous step, next step, play/pause, reset).
249+
**Validates: Requirements 7.5, 7.6, 7.7, 7.8**
250+
251+
### Property 7: Playback Speed Persistence
252+
*For any* playback speed change, the new speed SHALL be persisted to IndexedDB and restored on page reload.
253+
**Validates: Requirements 7.10**
254+
255+
### Property 8: No Purple Colors
256+
*For any* rendered element on the page, its color values SHALL NOT contain purple hues (hue values between 270-330 degrees in HSL color space).
257+
**Validates: Requirements 10.2**
258+
259+
### Property 9: Comparison Visualization
260+
*For any* comparison step in the algorithm, the canvas SHALL display visual indicators (arrows, highlights, labels) showing the two values being compared.
261+
**Validates: Requirements 6.4**
262+
263+
### Property 10: Auto-fit Large Trees
264+
*For any* tree with more than 7 nodes, the canvas SHALL automatically adjust the zoom level so that all nodes are visible within the viewport.
265+
**Validates: Requirements 5.4**
266+
267+
## Error Handling
268+
269+
1. **GitHub API 失败**: 使用 IndexedDB 缓存的值,如果无缓存则显示 0
270+
2. **输入验证失败**: 显示具体错误信息,阻止可视化
271+
3. **随机生成失败**: 显示错误提示,允许重试
272+
4. **IndexedDB 不可用**: 降级为内存存储,功能正常但不持久化
273+
5. **D3.js 渲染错误**: 显示错误边界,提供重置选项
274+
275+
## Testing Strategy
276+
277+
### 单元测试
278+
279+
使用 Vitest 进行单元测试:
280+
281+
1. 测试 `validateTreeInput` 函数正确验证各种输入
282+
2. 测试 `generateRandomTree` 函数生成有效数据
283+
3. 测试 `getCodeLineForStep` 函数返回正确的行号
284+
4. 测试 IndexedDB 缓存读写功能
285+
5. 测试颜色验证函数排除紫色
286+
287+
### 属性测试
288+
289+
使用 fast-check 进行属性测试:
290+
291+
1. **Property 1 测试**: 生成随机 star 数和时间戳,验证缓存行为
292+
2. **Property 2 测试**: 多次调用随机生成,验证所有输出都有效
293+
3. **Property 3 测试**: 生成随机字符串输入,验证验证函数正确分类
294+
4. **Property 4 测试**: 生成随机步骤序列,验证代码行高亮正确
295+
5. **Property 5 测试**: 生成随机变量值,验证显示值匹配
296+
6. **Property 6 测试**: 模拟随机键盘事件,验证动作正确
297+
7. **Property 7 测试**: 生成随机速度值,验证持久化和恢复
298+
8. **Property 8 测试**: 检查所有 CSS 颜色值,验证无紫色
299+
9. **Property 9 测试**: 生成随机比较步骤,验证可视化元素存在
300+
10. **Property 10 测试**: 生成不同大小的树,验证自动缩放
301+
302+
每个属性测试配置运行至少 100 次迭代。
303+
304+
测试文件命名规范:`*.test.ts`
305+
306+
测试标注格式:
307+
```typescript
308+
// **Feature: algorithm-visualization-platform, Property 1: GitHub Star Cache Validity**
309+
```
310+
311+
## 技术实现细节
312+
313+
### IndexedDB 缓存策略
314+
315+
```typescript
316+
const CACHE_DURATION = 60 * 60 * 1000; // 1小时
317+
318+
async function getStarCount(repo: string): Promise<number> {
319+
const cached = await getCachedStars();
320+
if (cached && Date.now() - cached.timestamp < CACHE_DURATION) {
321+
return cached.stars;
322+
}
323+
try {
324+
const stars = await fetchFromGitHub(repo);
325+
await setCachedStars(stars);
326+
return stars;
327+
} catch {
328+
return cached?.stars ?? 0;
329+
}
330+
}
331+
```
332+
333+
### 代码-步骤同步映射
334+
335+
```typescript
336+
// 每种语言、每种方法的步骤类型到代码行的映射
337+
const stepToLineMap: Record<Language, Record<Method, Record<StepType, number>>> = {
338+
java: {
339+
recursive: {
340+
'initial': 1,
341+
'check-null': 6,
342+
'check-value': 8,
343+
'compare': 9,
344+
'check-subtree': 10,
345+
'return': 10,
346+
'final': 3
347+
},
348+
// ... 其他方法
349+
},
350+
// ... 其他语言
351+
};
352+
```
353+
354+
### 颜色验证
355+
356+
```typescript
357+
function isPurple(color: string): boolean {
358+
const hsl = colorToHSL(color);
359+
return hsl.h >= 270 && hsl.h <= 330;
360+
}
361+
362+
function validateNoP urple(element: HTMLElement): boolean {
363+
const styles = getComputedStyle(element);
364+
const colorProps = ['color', 'backgroundColor', 'borderColor', 'fill', 'stroke'];
365+
return colorProps.every(prop => !isPurple(styles[prop]));
366+
}
367+
```

0 commit comments

Comments
 (0)