| name | easyeda-draw-symbol |
| description | Create custom schematic symbols for EasyEDA Pro. Invoke when creating custom symbols, building devices from symbols, or when system library lacks required components. |
自定义符号创建
系统库中找不到所需器件符号时(如开发板模块、定制 IC),通过此流程创建自定义符号。
1. 什么时候需要自定义符号
- 系统库搜索不到(如
nice!nano v2、Pro Micro 等开发板模块)
- 有现成符号但引脚功能与设计不匹配
- 需要自定义引脚排列以优化原理图可读性
2. 创建流程
创建空符号 → 添加引脚/形状/文本 → 创建器件 → 在原理图中使用
Step 1: 创建空符号
const personalLib = await eda.lib_LibrariesList.getPersonalLibraryUuid();
const symbolUuid = await eda.lib_Symbol.create(personalLib, "nice!nano v2");
Step 2: 在符号编辑器中添加引脚和形状
打开符号编辑器,然后使用 SCH_Primitive* API 添加图元:
await eda.lib_Symbol.openInEditor(symbolUuid, personalLib);
await eda.sch_PrimitiveRectangle.create(-80, 130, 160, 260, 0, 0, null, null, null, null, null);
await eda.sch_PrimitivePin.create(-80, -110, "1", "D0", 0, 20, null, "None", "BI");
await eda.sch_PrimitivePin.create(80, -110, "13", "D10", 180, 20, null, "None", "BI");
await eda.sch_PrimitiveCircle.create(-70, 120, 5, null, null, null, null, null);
Step 3: 创建器件(绑定符号)
const deviceUuid = await eda.lib_Device.create(personalLib, "nice!nano v2", undefined, {
symbolType: "sch",
symbol: { uuid: symbolUuid, libraryUuid: personalLib },
});
Step 4: 在原理图中使用
const results = await eda.lib_Device.search("nice!nano v2", personalLib);
await eda.sch_PrimitiveComponent.create(
{ libraryUuid: personalLib, uuid: results[0].uuid },
x, y, "", 0, false, true, true
);
3. 引脚创建 API
参数说明
SCH_PrimitivePin.create(
x: number,
y: number,
pinNumber: string,
pinName?: string,
rotation?: number,
pinLength?: number,
pinColor?: string | null,
pinShape?: ESCH_PrimitivePinShape,
pinType?: ESCH_PrimitivePinType
)
⚠️ pinName 为空时的行为:pinName 传 undefined 或 null 时,引脚只显示编号不显示名称。传空字符串 "" 效果相同。如果符号中部分引脚不需要名称(如仅用于内部连接的 GND 引脚),可省略 pinName 参数。
⚠️ 重要:(x, y) 是引脚连接点(圆点)的位置,不是引脚端点。
引脚从连接点沿 rotation 方向延伸 pinLength 单位。
连接点应该放在矩形边缘上,这样引脚才能正确对齐。
错误示例:x=-100, rotation=0, 矩形边缘=-80 → 连接点和矩形之间有 20 单位间隙 ❌
正确示例:x=-80, rotation=0, 矩形边缘=-80 → 连接点正好在矩形边缘 ✅
引脚类型 (pinType)
| 类型 | 说明 | 适用场景 |
|---|
"BI" | 双向 | GPIO 引脚 |
"IN" | 输入 | RESET、中断输入 |
"OUT" | 输出 | TX、PWM 输出 |
"Power" | 电源 | VCC、VDD、RAW |
"Ground" | 地 | GND、VSS |
"Passive" | 无源 | 模拟引脚 |
"Undefined" | 未定义 | 不使用的引脚 |
引脚方向 (rotation)
⚠️ API 反转行为:sch_PrimitivePin.create() 传入的 rotation 值会被反转为存储值。
传 0 → 存储 180(向左)→ 引脚向左延伸
传 180 → 存储 0(向右)→ 引脚向右延伸
传 90 → 存储 270(向下)→ 引脚向下延伸
传 270 → 存储 90(向上)→ 引脚向上延伸
| 传入 rotation | 存储 rotation | 引脚方向 | 适用侧 |
|---|
0 | 180 | 向左 | 符号左侧引脚 |
90 | 270 | 向下 | 符号底部引脚 |
180 | 0 | 向右 | 符号右侧引脚 |
270 | 90 | 向上 | 符号顶部引脚 |
4. 矩形创建 API
SCH_PrimitiveRectangle.create(
topLeftX: number,
topLeftY: number,
width: number,
height: number,
cornerRadius?: number,
rotation?: number,
color?: string | null,
fillColor?: string | null,
lineWidth?: number | null,
lineType?: ESCH_PrimitiveLineType | null,
fillStyle?: ESCH_PrimitiveFillStyle | null
)
⚠️ 符号编辑器 Y 轴方向:与屏幕坐标不同,符号编辑器 Y 轴向上增长(数学坐标系)。
topLeftY 是矩形的最高点(Y 值最大的边),矩形从此点向下延伸 height。
例如:要让矩形覆盖 y=-130 到 y=130,应传 topLeftY=130, height=260(不是 topLeftY=-130)。
5. CLI 命令
./scripts/draw_cli.py create-symbol "器件名称"
./scripts/draw_cli.py open-symbol <symbolUuid> <libUuid>
./scripts/draw_cli.py create-device <名称> <symUuid> <libUuid>
./scripts/draw_cli.py build-symbol "器件名称"
./scripts/draw_cli.py search "nice!nano v2" 5 --lib <libraryUuid>
6. 参考示例
6.1 符号编辑器与原理图编辑器 API 差异
| 操作 | 原理图编辑器 | 符号编辑器 |
|---|
| 查询引脚 | sch_PrimitivePin.getAll() ✅ | sch_PrimitivePin.getAll() ✅ |
| 查询矩形 | sch_PrimitiveRectangle.getAll() ✅ | ❌ 返回空数组 |
| 查询圆 | sch_PrimitiveCircle.getAll() ✅ | ❌ 返回空数组 |
| 查询引脚 ID | sch_PrimitivePin.getAllPrimitiveId() ✅ | sch_PrimitivePin.getAllPrimitiveId() ✅ |
| 查询矩形 ID | sch_PrimitiveRectangle.getAllPrimitiveId() ✅ | ❌ 返回空数组 |
| 查询圆 ID | sch_PrimitiveCircle.getAllPrimitiveId() ✅ | ❌ 返回空数组 |
| 查询所有图元 | 各类型 getAll() 方法 | sch_SelectControl.getAllSelectedPrimitives() ✅(需先选中) |
| 获取图元类型 | sch_Primitive.getPrimitiveTypeByPrimitiveId(id) ✅ | ✅ 可用 |
| 获取图元属性 | sch_Primitive.getPrimitiveByPrimitiveId(id) ✅ | ✅ 可用 |
结论:在符号编辑器中,不要依赖 sch_PrimitiveRectangle.getAll() 和 sch_PrimitiveCircle.getAll() 等类型专属批量查询方法。 应使用 sch_PrimitivePin.getAllPrimitiveId() 获取所有引脚 ID,再通过 sch_Primitive.getPrimitiveByPrimitiveId(id) 逐个查询。或使用 sch_SelectControl.getAllSelectedPrimitives() 获取已选中图元(圆、矩形等均可用此方式查询)。
6.2 nice!nano v2 符号
符号参数:
- 24 个引脚(左 12 + 右 12)
- 引脚间距 20 单位
- 主体矩形 160×260(topLeftX=-80, topLeftY=130)
- 引脚长度 20
- 方向标识:圆点在矩形左上角内部 (-70, 120),半径 5,指示引脚 1 位置
- 引脚顺序(DIP 标准):
- 左列 Pin 1-12:从上到下,y = 110, 90, 70, 50, 30, 10, -10, -30, -50, -70, -90, -110
- 右列 Pin 13-24:从下到上,y = -110, -90, -70, -50, -30, -10, 10, 30, 50, 70, 90, 110
6.3 引脚布局规范
引脚名称在器件主体内部(推荐):
───┐ D0 GND ├───
───┤ D1 VCC ├───
───┤ D2 GND ├───
───┤ D3 ┌────────┐ RAW ├───
───┤ D4 │ 器件主体 │ VCC ├───
───┤ D5 │ 160×260 │ GND ├───
───┤ D6 └────────┘ RESET ├──
───┤ D7 连接点 D21 ├───
───┤ D8 x=-80/80 D20 ├───
───┤ D9 D19 ├───
───┤ D14 D18 ├───
───┘ D15 D16 └───
引脚连接点 (x,y) 在矩形边缘,引脚线在外侧
名称文本在矩形内部,编号在引脚线上方
左侧 (rotation=0): 名称在引脚线右侧(矩形内),偏移 +30
右侧 (rotation=180): 名称在引脚线左侧(矩形内),偏移 -30
7. 引脚名称位置调整(重要发现)
⚠️ 关键发现:引脚名称是 ATTR 图元(不是独立的 Text 图元),通过 parentPrimitiveId 精确关联到 PIN!
通过 sch_PrimitiveAttribute.getAllPrimitiveId() 可以获取所有 ATTR,包括 "Pin Name" 和 "Pin Number"。
7.1 问题现象
sch_PrimitivePin.create() 创建引脚时,EasyEDA 会自动生成 ATTR 图元作为名称和编号,但初始位置通常不正确:
PIN2 (正确): 引脚连接点(-80, 90), 名称ATTR(-50, 90) → 名称在矩形内部 ✅
PIN1 (异常): 引脚连接点(-80, 110), 名称ATTR(-103, 110) → 名称在矩形外部 ❌
7.2 原因
- 修改
rotation 只会旋转引脚线,不会同步调整已生成的 ATTR 图元位置
- ATTR 的
alignMode(对齐方式)和 x, y 坐标需要手动修正
- 同名引脚(如多个 GND)不能靠
value + y 匹配,必须用 parentPrimitiveId 精确匹配
7.3 解决方案
使用 set-pin-labels-position CLI 命令批量修正引脚名称位置:
./scripts/draw_cli.py set-pin-labels-position --side left --offset 30
./scripts/draw_cli.py set-pin-labels-position --side right --offset 30
实现原理(已固化到 fixPinLabels):
- 通过
sch_PrimitivePin.getAllPrimitiveId() 获取所有引脚
- 通过
sch_PrimitiveAttribute.getAllPrimitiveId() 获取所有 ATTR 图元
- 用
parentPrimitiveId 精确匹配 PIN 和 ATTR(避免同名引脚错乱)
- 设置正确的
alignMode 和 x, y 坐标
或手动用 sch_PrimitiveAttribute API 调整:
const attrIds = await eda.sch_PrimitiveAttribute.getAllPrimitiveId();
const attr = await eda.sch_PrimitiveAttribute.get([attrId]);
const at = attr[0].toAsync();
at.setState_AlignMode(2);
at.setState_X(-50);
at.setState_Y(-pin.y);
await at.done();
7.4 名称位置规律(已验证)
| 引脚侧 | rotation | alignMode 设置值 | alignMode 存储值 | 含义 | X 坐标 | Y 坐标 |
|---|
| 左侧 | 0 | 2 (左中) | 3 (左中) | 文字从锚点向右延伸,左对齐 | pin.x + offset | -pin.y |
| 右侧 | 180 | 8 (右中) | 5 (右中) | 文字从锚点向左延伸,右对齐 | pin.x - offset | -pin.y |
| 顶部 | 270 | 5 (正中) | 4 (正中) | 文字水平居中,在矩形内部 | pin.x | -pin.y + offset |
| 底部 | 90 | 5 (正中) | 4 (正中) | 文字水平居中,在矩形内部 | pin.x | -pin.y - offset |
⚠️ 关键规则(实测验证):
- Y 坐标 =
-pin.y:setState_Y(-pin.y) 后 EasyEDA 内部自动翻转为 pin.y 存储,显示位置正确
- alignMode 设置值与存储值不同:EasyEDA 内部使用列优先九宫格存储
- 设置值(
setState_AlignMode):1=左上 2=左中 3=左下 4=中上 5=正中 6=中下 7=右上 8=右中 9=右下
- 存储值(
alignMode 属性 / getState_AlignMode()):0=左上 1=中上 2=右上 3=左中 4=正中 5=右中 6=左下 7=中下 8=右下
- alignMode 必须用"中"锚点(设置值 2/8/5),不要用"上/下"锚点,否则 Y 位置会偏移
- X 坐标是文字锚点位置,不是文字中心:左中(2)时 X 是文字左边缘,右中(8)时 X 是文字右边缘,正中(5)时 X 是文字中心
- offset 推荐值 5~10:名称与矩形边缘的距离,默认 5
ATTR 属性说明:
key: "Pin Name" 或 "Pin Number"
value: 引脚名称或编号
x, y: ATTR 锚点位置(设置 -pin.y 或 -pin.y ± offset,存储为 pin.y 或 pin.y ∓ offset)
alignMode: 对齐方式存储值(左侧=3 左中,右侧=5 右中,上下=4 正中)
parentPrimitiveId: 精确关联的 PIN ID(匹配时必须使用)
7. 常见错误
| 错误 | 原因 | 解决 |
|---|
| "无法创建引脚图元" | pinShape 传了 null | 改为传 "None" |
| 搜索不到自定义器件 | 搜索的是系统库 | 传入个人库 UUID |
| 引脚不显示 | 符号编辑器未激活 | 先 openInEditor 再操作 |
| 引脚与矩形未对齐 | (x,y) 位置错误,放在矩形边缘 + 长度位置 | (x,y) 应放在矩形边缘上,不是边缘 + 长度 |
| 矩形查询不到 | sch_PrimitiveRectangle.getAll() 在符号编辑器中无效 | 改用 sch_SelectControl.getAllSelectedPrimitives() |