Files
bim_engine/docs/utils/icon-manager.md

424 lines
11 KiB
Markdown
Raw Normal View History

2025-12-25 19:08:26 +08:00
# Icon Manager 图标管理器文档
> 本文档详细描述 Icon Manager 图标管理工具的实现细节,包括 API、使用方式、图标清单等,供 AI 根据文档重现功能。
---
## 1. 工具概述
### 1.1 基本信息
- **工具名称**: `IconManager`
- **文件路径**: `src/utils/icon-manager.ts`
- **导出函数**: `getIcon(name: string): string`
- **用途**: 统一管理所有 SVG 图标资源,提供通过名称获取图标的接口
- **特点**: 单一职责,简单易用,支持默认图标回退
### 1.2 设计目标
- **统一管理**: 所有图标集中在一个文件中管理,避免重复和不一致
- **简化使用**: 通过简单的函数调用获取图标,无需在各处重复 SVG 代码
- **类型安全**: SVG 作为字符串存储,可直接用于 innerHTML 或图标属性
- **容错机制**: 当请求的图标不存在时,返回默认图标而不是报错
---
## 2. API 文档
### 2.1 getIcon 函数
```typescript
function getIcon(name: string): string
```
**参数**:
- `name`: string - 图标名称(中文)
**返回值**:
- string - SVG 图标的完整字符串
**行为**:
1.`ICONS` 对象中查找对应名称的图标
2. 如果找到,返回该图标的 SVG 字符串
3. 如果未找到,在控制台输出警告并返回默认图标
**示例**:
```typescript
import { getIcon } from '../../utils/icon-manager';
// 获取测量图标
const measureIcon = getIcon('测量');
// 获取不存在的图标(会返回默认图标并警告)
const unknownIcon = getIcon('不存在的图标');
// 控制台输出: [IconManager] Icon "不存在的图标" not found, using default icon
```
---
## 3. 图标清单
### 3.1 来自 assets 的图标 (48x48)
这些图标从 `src/assets/` 目录中的 SVG 文件简化而来,用于 toolbar 和主要功能按钮:
| 图标名称 | 用途 | 原始文件 |
|---------|------|----------|
| 测量 | 测量工具 | 测量.svg |
| 地图 | 地图视图/平面图 | 地图.svg |
| 框选放大 | 框选缩放 | 框选放大.svg |
| 漫游 | 漫游模式 | 漫游.svg |
| 目录树 | 构件树 | 目录树.svg |
| 剖切 | 剖切菜单 | 剖切.svg |
| 剖切盒 | 剖切盒 | 剖切盒.svg |
| 全屏 | 全屏模式 | 全屏.svg |
| 设置 | 设置面板 | 设置.svg |
| 拾曲面剖切 | 拾取曲面剖切 | 拾曲面剖切.svg |
| 轴向剖切 | 轴向剖切 | 轴向剖切.svg |
| 主视角 | 主视角/首页 | 主视角.svg |
| 文档 | 文档/属性 | 地图 1.svg |
### 3.2 测量相关图标 (32x32)
用于测量面板的各种测量方式:
| 图标名称 | 用途 |
|---------|------|
| 标高 | 标高测量 |
| 距离 | 距离测量 |
| 最小距离 | 最小距离测量 |
| 激光边距 | 激光边距测量 |
| 角度 | 角度测量 |
| 坡度 | 坡度测量 |
| 体积 | 体积测量 |
| 空间体积 | 空间体积测量 |
### 3.3 通用图标 (24x24)
常用的 UI 图标:
| 图标名称 | 用途 |
|---------|------|
| close | 关闭 |
| check | 勾选/确认 |
| warning | 警告 |
| error | 错误 |
| success | 成功 |
| plus | 加号/新增 |
| minus | 减号/删除 |
| arrowUp | 向上箭头 |
| arrowDown | 向下箭头 |
| arrowLeft | 向左箭头 |
| arrowRight | 向右箭头 |
| search | 搜索 |
| refresh | 刷新 |
| delete | 删除 |
| edit | 编辑 |
| save | 保存 |
| expand | 展开 |
| collapse | 收起 |
### 3.4 默认图标
| 图标名称 | 用途 |
|---------|------|
| default | 当请求的图标不存在时返回 |
---
## 4. 使用场景
### 4.1 在按钮配置中使用
```typescript
import { getIcon } from '../../../utils/icon-manager';
export const createMeasureButton = (engine: BimEngine): ButtonConfig => {
return {
id: 'measure',
groupId: 'group-1',
type: 'button',
label: 'toolbar.measure',
icon: getIcon('测量'), // 使用图标管理器
onClick: () => {
engine.measure?.show();
}
};
};
```
### 4.2 在组件中使用
```typescript
import { getIcon } from '../../utils/icon-manager';
export class WalkControlPanel implements IBimComponent {
private getIconSVG(type: string): string {
const icons: Record<string, string> = {
'plan-view': getIcon('地图'),
'path': getIcon('地图'),
'walk': getIcon('漫游')
};
return icons[type] || '';
}
private createIconButton(type: string, onClick: () => void): HTMLButtonElement {
const btn = document.createElement('button');
btn.className = `walk-icon-btn walk-icon-btn-${type}`;
btn.innerHTML = this.getIconSVG(type);
btn.addEventListener('click', onClick);
return btn;
}
}
```
### 4.3 在树节点中使用
```typescript
import { getIcon } from '../../utils/icon-manager';
const treeData: TreeNodeConfig[] = [
{
id: 'level-1',
label: '一层',
icon: getIcon('目录树'),
children: [...]
}
];
```
---
## 5. SVG 简化规范
### 5.1 简化原则
从 assets 目录中的 SVG 文件简化时,遵循以下原则:
1. **保留核心路径**:只保留 `<path>` 元素及其 `d` 属性
2. **移除冗余属性**:删除 `<defs>`, `<clipPath>`, `<style>`, `<g>` 等非必要元素
3. **保持颜色属性**:保留 `fill="currentColor"` 以支持主题颜色
4. **统一尺寸**:根据用途设置合适的 `viewBox``width/height`
5. **简化变换**:如果有 `transform`,尽量简化或合并到路径中
### 5.2 简化示例
**原始 SVG (从 assets/测量.svg)**:
```xml
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="48" height="48" viewBox="0 0 48 48">
<defs>
<clipPath id="clip-path">
<rect width="48" height="48" fill="none"/>
</clipPath>
</defs>
<g id="测量" clip-path="url(#clip-path)">
<path d="M0,28.207H3.429v3.526H44.571V28.207H48v7.052H0ZM0,3.526v14.1a3.478,3.478,0,0,0,3.429,3.526H6.857V17.629h3.429v3.526h3.429V17.629h3.429v3.526h3.429V10.578H24V21.155h3.429V17.629h3.429v3.526h3.429V17.629h3.429v3.526h3.429V10.578h3.429V21.155A3.478,3.478,0,0,0,48,17.629V3.526A3.478,3.478,0,0,0,44.571,0H3.429A3.478,3.478,0,0,0,0,3.526Z" transform="translate(0 5.456)" fill="#000"/>
</g>
</svg>
```
**简化后 (在 icon-manager.ts 中)**:
```typescript
测量: '<svg width="48" height="48" viewBox="0 0 48 48"><path fill="currentColor" d="M0,28.207H3.429v3.526H44.571V28.207H48v7.052H0ZM0,3.526v14.1a3.478,3.478,0,0,0,3.429,3.526H6.857V17.629h3.429v3.526h3.429V17.629h3.429v3.526h3.429V10.578H24V21.155h3.429V17.629h3.429v3.526h3.429V17.629h3.429v3.526h3.429V10.578h3.429V21.155A3.478,3.478,0,0,0,48,17.629V3.526A3.478,3.478,0,0,0,44.571,0H3.429A3.478,3.478,0,0,0,0,3.526Z" transform="translate(0 5.456)"/></svg>',
```
**关键变化**:
- 移除了 `xmlns`, `xmlns:xlink`, `<defs>`, `<clipPath>`, `<g>`
-`fill="#000"` 改为 `fill="currentColor"` 以支持主题
- 保留了核心的 `<path>``viewBox`
---
## 6. 图标尺寸规范
### 6.1 尺寸分类
根据使用场景,图标分为三种尺寸:
1. **48x48**: 主要功能按钮(toolbar、工具栏)
2. **32x32**: 测量工具图标
3. **24x24**: 通用 UI 图标(关闭、展开等)
### 6.2 与 CSS 的配合
图标尺寸在 CSS 中可以被覆盖:
```css
/* Toolbar 按钮图标 */
.opt-btn-icon svg {
width: 100%;
height: 100%;
}
/* 漫游控制面板按钮图标 */
.walk-icon-btn svg {
width: 32px;
height: 32px;
}
```
实际显示尺寸由 CSS 控制,SVG 的 `width``height` 属性主要用于:
1. 定义默认尺寸
2. 计算宽高比
3. 作为 `viewBox` 的参考
---
## 7. 添加新图标
### 7.1 添加流程
1. **准备 SVG 文件**:
- 将新图标文件放到 `src/assets/` 目录
- 或直接获取 SVG 代码
2. **简化 SVG**:
- 按照 5.1 节的简化原则处理 SVG
- 确保 `fill="currentColor"` 以支持主题
- 设置合适的尺寸
3. **添加到 ICONS 对象**:
```typescript
const ICONS: Record<string, string> = {
// ... 现有图标
新图标名称: '<svg width="48" height="48" viewBox="0 0 48 48"><path fill="currentColor" d="..."/></svg>',
};
```
4. **使用新图标**:
```typescript
const icon = getIcon('新图标名称');
```
### 7.2 命名规范
- **使用中文名称**:便于理解和维护
- **描述功能**:名称应清晰描述图标用途
- **避免重复**:检查是否已存在类似图标
**推荐命名**:
- ✅ 好的命名: `测量`, `地图`, `全屏`, `剖切盒`
- ❌ 不好的命名: `icon1`, `svg2`, `btn_icon`
---
## 8. 实现细节(供 AI 重现)
### 8.1 核心数据结构
```typescript
const ICONS: Record<string, string> = {
// key: 图标名称(中文)
// value: SVG 字符串(完整的 <svg>...</svg>)
};
```
### 8.2 获取逻辑
```typescript
export function getIcon(name: string): string {
const icon = ICONS[name];
if (!icon) {
console.warn(`[IconManager] Icon "${name}" not found, using default icon`);
return ICONS.default;
}
return icon;
}
```
**关键点**:
1. 简单的字典查找
2. 未找到时返回默认图标而不是 `undefined`
3. 在控制台输出警告信息,便于调试
### 8.3 为什么不使用枚举?
设计选择:使用字符串而不是 TypeScript 枚举
**原因**:
1. **简化使用**:直接传中文字符串,更直观
2. **灵活性**:可以动态添加图标而不需要修改类型定义
3. **国际化友好**:中文名称与 UI 文案保持一致
4. **降低耦合**:使用方不需要导入枚举类型
---
## 9. 与主题系统的配合
### 9.1 currentColor 属性
所有图标使用 `fill="currentColor"`,这样图标颜色会继承父元素的 `color` 属性:
```typescript
测量: '<svg width="48" height="48" viewBox="0 0 48 48"><path fill="currentColor" d="..."/></svg>',
```
### 9.2 在 CSS 中控制颜色
```css
.opt-btn-icon {
color: var(--bim-icon-color, #ccc);
}
.opt-btn-icon svg {
fill: currentColor; /* 继承父元素的 color */
}
```
### 9.3 主题变更时的自动适配
当主题颜色变更时,只需更新 CSS 变量,所有图标会自动适配新颜色:
```typescript
// 在 setTheme 中
element.style.setProperty('--bim-icon-color', theme.icon ?? '#ccc');
// 所有使用 currentColor 的图标自动更新颜色
```
---
## 10. 最佳实践
### 10.1 使用建议
**✅ 推荐做法**:
```typescript
// 在组件顶部导入
import { getIcon } from '../../utils/icon-manager';
// 在需要时调用
const icon = getIcon('测量');
button.innerHTML = icon;
```
**❌ 避免做法**:
```typescript
// 不要在组件中硬编码 SVG
const icon = '<svg>...</svg>'; // 不推荐
// 不要重复定义相同的图标
const myIcon = '<svg>...</svg>'; // 应该使用 getIcon()
```
### 10.2 性能考虑
- **字符串查找很快**:`ICONS` 对象的查找是 O(1) 操作
- **无需缓存**:图标字符串很小,不需要额外的缓存机制
- **按需使用**:只在需要时调用 `getIcon()`,不需要预加载所有图标
### 10.3 维护建议
1. **定期整理**:删除不再使用的图标
2. **统一风格**:新增图标应与现有图标风格一致
3. **文档同步**:添加新图标时更新本文档的图标清单
4. **命名规范**:使用清晰、一致的中文命名
---
## 11. 更新记录
| 日期 | 修改内容 | 修改人 |
| ---------- | ----------------------------------------- | ------------ |
| 2025-12-25 | 创建图标管理器,整合所有 SVG 图标资源 | AI Assistant |
| 2025-12-25 | 添加"文档"图标,替换所有 toolbar 按钮图标 | AI Assistant |