初始化

This commit is contained in:
yuding
2025-12-26 17:08:02 +08:00
parent a754a5a511
commit cd1f8186d0
11 changed files with 361 additions and 53 deletions

View File

@@ -562,12 +562,314 @@ const dialog = engine.dialog.create({
| -------------- | ---------------------------- | ------------------------------ | ----------------------------- |
| `IconManager` | `src/utils/icon-manager.ts` | 统一管理所有 SVG 图标资源 | `docs/utils/icon-manager.md` |
**IconManager 说明**:
- 提供 `getIcon(name: string): string` 函数
- 所有组件通过该函数获取 SVG 图标字符串
- 支持默认图标回退机制
- 图标使用 `currentColor` 以支持主题颜色
- 详细说明见 `docs/utils/icon-manager.md`
---
## 4.4.1 IconManager 图标管理器使用指南
### 核心概念
**IconManager 是项目中所有 SVG 图标的统一管理工具,必须严格遵循以下规范:**
#### 强制要求
1. **禁止在代码中硬编码 SVG**: 所有图标必须通过 `getIcon()` 函数获取
2. **使用中文名称**: 图标名称使用清晰的中文描述,如 `'测量'`, `'地图'`, `'全屏'`
3. **支持主题颜色**: 所有图标使用 `fill="currentColor"` 以自动适配主题
### API 使用
#### 基本用法
```typescript
import { getIcon } from '../../utils/icon-manager';
// 获取图标 SVG 字符串
const icon = getIcon('测量');
// 在按钮配置中使用
const buttonConfig: ButtonConfig = {
id: 'measure',
icon: getIcon('测量'),
label: 'toolbar.measure'
};
// 在 DOM 中使用
button.innerHTML = getIcon('全屏');
```
#### 在组件中使用
```typescript
export class MyComponent implements IBimComponent {
private createButton(): HTMLButtonElement {
const btn = document.createElement('button');
// 直接使用 getIcon 获取图标
btn.innerHTML = getIcon('设置');
return btn;
}
}
```
### 图标分类
#### 1. 主要功能图标 (48x48)
用于 toolbar 和主要功能按钮:
- `测量`, `地图`, `框选放大`, `漫游`, `目录树`
- `剖切`, `剖切盒`, `全屏`, `设置`, `拾曲面剖切`
- `轴向剖切`, `主视角`, `文档`
#### 2. 测量工具图标 (32x32)
用于测量面板:
- `标高`, `距离`, `最小距离`, `激光边距`
- `角度`, `坡度`, `体积`, `空间体积`
#### 3. 通用 UI 图标 (24x24)
用于通用界面元素:
- `close`, `check`, `warning`, `error`, `success`
- `plus`, `minus`, `arrowUp`, `arrowDown`, `arrowLeft`, `arrowRight`
- `search`, `refresh`, `delete`, `edit`, `save`
- `expand`, `collapse`
### 图标尺寸规范
#### CSS 控制实际显示尺寸
虽然 SVG 有默认尺寸,但实际显示尺寸由 CSS 控制:
```css
/* Toolbar 按钮图标 - 底部工具栏 */
.bim-btn-group-root.is-bottom-toolbar .opt-btn-icon {
width: 32px;
height: 32px;
}
/* Walk 控制面板按钮图标 */
.walk-icon-btn svg {
width: 32px;
height: 32px;
}
/* 通用按钮图标 */
.opt-btn-icon {
width: 24px;
height: 24px;
}
```
**重要**: 确保不同组件的图标尺寸保持一致,推荐使用:
- **主按钮**: 32x32 (toolbar, walk-control-panel)
- **次要按钮**: 24x24 (menu, tree, dialog)
- **小图标**: 18x18 (下拉菜单项)
### 主题适配
#### currentColor 机制
所有图标使用 `fill="currentColor"`,会自动继承父元素的 `color` 属性:
```typescript
// icon-manager.ts 中的图标定义
测量: '<svg width="48" height="48" viewBox="0 0 48 48"><path fill="currentColor" d="..."/></svg>',
```
```css
/* CSS 中控制图标颜色 */
.opt-btn-icon {
color: var(--bim-icon-color, #ccc);
}
.opt-btn-icon svg {
fill: currentColor; /* 自动继承父元素的 color */
}
```
#### 主题变更自动适配
当主题切换时,只需更新 CSS 变量,所有图标自动更新颜色:
```typescript
// setTheme 方法中
element.style.setProperty('--bim-icon-color', theme.icon ?? '#ccc');
// 所有使用 currentColor 的图标自动适配新颜色
```
### 添加新图标
#### 流程步骤
1. **准备 SVG 文件**:
- 放到 `src/assets/` 目录
- 或直接获取 SVG 代码
2. **简化 SVG** (移除冗余):
```xml
<!-- 简化前 -->
<svg xmlns="..." xmlns:xlink="...">
<defs>...</defs>
<clipPath>...</clipPath>
<g clip-path="...">
<path d="..." fill="#000"/>
</g>
</svg>
<!-- 简化后 -->
<svg width="48" height="48" viewBox="0 0 48 48">
<path fill="currentColor" d="..."/>
</svg>
```
3. **添加到 icon-manager.ts**:
```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('新功能');
```
#### 命名规范
**✅ 推荐命名**:
- 使用清晰的中文描述功能
- 避免歧义和重复
- 示例: `测量`, `全屏`, `剖切盒`, `空间体积`
**❌ 不推荐命名**:
- 通用名称: `icon1`, `svg2`, `image`
- 英文缩写: `msr`, `cfg`, `btn_icon`
- 过长名称: `这是一个用于测量距离的图标`
### 错误处理
#### 自动回退机制
当请求的图标不存在时,自动返回默认图标:
```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;
}
```
**开发时的警告**:
```
[IconManager] Icon "不存在的图标" not found, using default icon
```
这帮助开发者快速发现图标名称错误。
### 最佳实践
#### ✅ 推荐做法
```typescript
// 1. 在组件顶部导入
import { getIcon } from '../../utils/icon-manager';
// 2. 在需要时调用
export const createButton = (): ButtonConfig => ({
id: 'home',
icon: getIcon('主视角'),
label: 'toolbar.home'
});
// 3. 在 DOM 中使用
const btn = document.createElement('button');
btn.innerHTML = getIcon('设置');
```
#### ❌ 避免做法
```typescript
// ❌ 不要硬编码 SVG
const icon = '<svg>...</svg>';
// ❌ 不要重复定义相同图标
const homeIcon = '<svg>...</svg>';
const anotherHomeIcon = '<svg>...</svg>';
// ❌ 不要使用未定义的图标名称
const icon = getIcon('ThisIconDoesNotExist'); // 会触发警告
```
### 性能说明
- **查找速度**: O(1) 字典查找,无性能问题
- **无需缓存**: 图标字符串很小,直接返回即可
- **按需使用**: 只在需要时调用 `getIcon()`,不需要预加载
### 维护建议
1. **定期清理**: 删除不再使用的图标
2. **统一风格**: 新增图标应与现有图标风格一致
3. **文档同步**: 添加新图标后更新 `docs/utils/icon-manager.md`
4. **测试验证**: 确保新图标在浅色/深色主题下都清晰可见
### 完整示例
#### 按钮配置中使用图标
```typescript
import { getIcon } from '../../../utils/icon-manager';
import type { ButtonConfig } from '../index.type';
import type { BimEngine } from '../../../bim-engine';
export const createMeasureButton = (engine: BimEngine): ButtonConfig => {
return {
id: 'measure',
groupId: 'group-1',
type: 'button',
label: 'toolbar.measure',
icon: getIcon('测量'), // 使用图标管理器
onClick: () => {
engine.measure?.show();
}
};
};
```
#### 组件中动态使用图标
```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] || getIcon('default');
}
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;
}
}
```
---
**相关文档**:
- 详细的图标清单和使用说明见 `docs/utils/icon-manager.md`
- SVG 简化规范和主题适配详见同一文档
### 4.5 事件总线定义