3.9 KiB
PPT Frame 素材插入经验
更新日期:2026-04-27
背景
用户在画布中选中 PPT 页面(底层为 Frame)后,从素材库或生成结果插入图片/视频,预期素材进入当前 PPT 页面并自适应页面尺寸。旧逻辑只把素材插入到选中元素下方,导致素材落在页面外,需要用户手动拖入和执行「素材自适应PPT」。
经验
1. 先复用 Frame 内部插入能力
insertMediaIntoFrame 已经覆盖 Frame 查找、contain/stretch 适配、居中放置和 frameId 绑定。新需求不要再在素材库、任务队列、AI 预览等入口各写一套几何逻辑,只在通用插入链路前置识别「单选 Frame」即可。
2. 单选 Frame 才改变插入语义
只有当前 selection 或 appState.lastSelectedElementIds 是单个 Frame 时,才插入到 Frame 内。多选、选中普通元素、拖拽指定坐标、显式传入 startPoint/referenceDimensions 时,应继续沿用原插入位置,避免破坏批量排列和拖拽语义。
3. PPT 自适应要用 contain,不要默认拉伸
插入到 PPT 页面内的图片/视频应保持媒体比例并居中适配 Frame。只有明确传 { fit: 'stretch' } 时才铺满页面,避免素材变形。视频没有真实尺寸时可用 16:9 兜底,但如果上层已传媒体尺寸,必须尊重该尺寸计算适配。
4. 插入后必须绑定 frameId
PPT 导出、Frame 移动、预览缩略图和「素材自适应PPT」都依赖 frameId 或几何相交关系。插入时直接绑定 frameId,比后续靠最大相交面积补救更稳定。
5. 底层修复优先于入口补丁
素材插入入口很多:素材库、任务队列、AI 预览、MCP/工作流、快捷工具栏。修在 insertImageFromUrl、insertVideoFromUrl 和 executeCanvasInsertion 这类公共层,能覆盖更多路径,也减少后续漏改风险。
实现要点
- 新增
getSelectedInsertionFrame:优先读当前 selection,selection 为空时回退lastSelectedElementIds。 - 新增
insertMediaIntoSelectedFrame:把选中 Frame 的points转为目标尺寸,再调用insertMediaIntoFrame。 - 图片/视频通用插入函数在没有显式坐标和尺寸时,先尝试插入选中 Frame。
executeCanvasInsertion对单个图片/视频内容做同样前置处理,覆盖quickInsert、任务队列和 AI 预览。- 视频插入新增
lockReferenceDimensions,避免 Frame 适配后的尺寸再次被默认 16:9 逻辑改写。
注意事项
- 不要为了「当前 PPT」新增实体或全局状态;当前画布 selection 已经足够表达目标 Frame。
- 不要在插入前完整下载视频元数据;高并发文件处理场景下应保持轻量,必要时使用传入尺寸或默认比例。
- 不要让
startPoint场景自动吸附 Frame;拖拽和批量排版需要尊重调用方坐标。 - 不要只改素材库按钮;生成结果、工作流和预览器也会走插入链路。
验证建议
- 指定文件测试:
pnpm --dir packages/drawnix exec vitest run src/utils/__tests__/frame-insertion-utils.test.ts src/utils/__tests__/ppt-media-fit.test.ts
- 类型检查:
pnpm nx run drawnix:typecheck
- 注意测试命令:
pnpm --filter @aitu/drawnix test -- frame-insertion-utils.test.ts
该写法会被当前包脚本吞成更大范围测试,可能暴露仓库既有 unrelated 失败。需要精确验证单文件时,优先使用 pnpm --dir packages/drawnix exec vitest run ...。
检查清单
- 单选 PPT 页面后插入图片,图片出现在页面内部并保持比例。
- 单选 PPT 页面后插入视频,视频出现在页面内部并保持比例。
- 插入后的媒体元素带有目标页面
frameId。 - 未选中 Frame 时,素材仍插入到原来的默认位置。
- 传入显式
startPoint的批量插入不被 Frame 逻辑劫持。