文本间距属性 (letter/wordSpacing) 在测量层缺失且在业务组件层未透传,导致排版功能不可用
- Dominant language
- TypeScript
- Stars
- 6.6k
- Forks
- 543
- Avg merge
- 11h 33m
- Merged PRs (30d)
- 3
Description
## 问题描述
官方文档声明 `Text `原语([原语节点](https://infographic.antv.vision/reference/primitive-nodes#text))支持 letterSpacing 和 wordSpacing。但是该功能似乎不可用,问题贯穿了从底层的 测量算法 到中间的 样式解析 再到上层的 业务组件封装 的完整链路。
## 代码分析
### **1. 底层:测量函数忽略(measureText)**
- **`measureText` 实现忽略:** 在 `src/utils/measure-text.ts` 中,逻辑只解构了 `fontFamily`, `fontSize`, `fontWeight`, `lineHeight`,完全忽略了 `letterSpacing` 和 `wordSpacing`。
- **调用链路截断:** `src/utils/text.ts` 中的 `updateTextElement` 在调用 `measureText` 时,显式解构并过滤了样式属性,直接丢弃了这两个属性。
### **2.中间层: 样式解析不一致**
- **渲染属性白名单缺失**:在 `src/renderer/composites/text.ts` 的 `getTextAttributes` 函数中,使用了白名单机制提取 SVG 属性。
- **现状:** 该白名单包含 `'letter-spacing'`,但**漏掉了 `'word-spacing'`**。
- **后果:** 即使上层传入了 `wordSpacing`,它也会在最终生成 SVG `foreignObject` 内容时被剥离,无法渲染出视觉效果。
- 在`src/utils/text.ts`中的`getTextStyle`函数对`letterSpacing`做了处理,加上了`px`,但是没有对`wordSpacing`做处理。
### 3.**顶层:业务组件透传阻断**
虽然原子组件 `ItemLabel`/`ItemValue` /`ItemDes`支持透传 `TextProps`,但在 `SimpleItem`、`BadgeCard` 等业务组件中,**并没有开放接口**来配置内部文本的间距,也没有将`letterSpacing`和`wordSpacing`透传给文本节点。
### 4.总结:文本属性支持情况对比表
| **层级** | **问题** | **letterSpacing** | **wordSpacing** |
| ----------------------------------- | ---------------- | ----------------- | --------------- |
| **底层** (`measureText`) | 测量忽略间距属性 | ❌ 不支持 | ❌ 不支持 |
| **中间层** (`text.ts getTextStyle`) | px 后缀处理 | ✅ 有处理 | ❌ 无处理 |
| **中间层** (`composites/text.ts`) | 渲染白名单 | ✅ 已包含 | ❌ 缺失 |
| **原语层** (`jsx Text`) | 属性透传 | ✅ 正确 | ✅ 正确 |
| **业务组件层** | 接口暴露 | ❌ 未暴露 | ❌ 未暴露 |
## 建议方案
**Step 1: 修复核心渲染与测量 (Core Fix)**
- [ ] **Refactor `measureText`**: 升级函数签名,支持传入 `letterSpacing` 和 `wordSpacing`。
- [ ] **Fix `utils/text.ts`**: 在 `updateTextElement` 中正确透传这两个属性给测量函数。并且在`getTextStyle`函数中添加对`wordSpacing`的处理。
- [ ] **Fix `renderer/composites/text.ts`**: 在 `getTextAttributes` 的白名单数组中添加 `'word-spacing'`。
**Step 2: 修复组件层数据流 (Component Fix)**
- [ ] **Update Business Components**: 修改 `SimpleItem` 等组件,允许通过 props (如 `labelStyle`) 传入间距属性,并将其透传给内部的 `ItemLabel` / `ItemDesc`。
**Step 3:性能优化 (Performance Optimization - 可选)**
- [ ] **实现 LRU 缓存:** 我发现 `measureText` 在每次调用时都会触发 Canvas/DOM 测量,而没有任何缓存机制。我建议引入 **LRU (Least Recently Used)** 缓存机制(例如通过项目现有的 `flru` 库实现)。
> **备注:** 我已经准备好了一套本地实现LRU的方案。
**如果维护者同意,我愿意参与第一步(核心修复)和第三步(性能优化)。**
Contributor guide
No contributing guide indexed for this repository
Research direction
Read src/utils/measure-text.ts and src/utils/text.ts first, then trace the text attribute whitelist in src/renderer/composites/text.ts and the SimpleItem/BadgeCard component props. Confirm how spacing is measured, styled, rendered, and passed through; done means the named paths consistently support both spacing properties, with component behavior verified where applicable.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- frontend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100