恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
基于 tldraw SDK 的 `TldrawImage` 快照静态渲染:将 store 快照导出为 SVG/PNG 的轻量只读预览组件
首页
资讯中心
/
基于 tldraw SDK 的 `TldrawImage` 快照静态渲染:将 store 快照导出为 SVG/PNG 的轻量只读预览组件
基于 tldraw SDK 的 `TldrawImage` 快照静态渲染:将 store 快照导出为 SVG/PNG 的轻量只读预览组件
发布时间:2026/9/10 3:05:07
基于 tldraw SDK 的TldrawImage快照静态渲染将 store 快照导出为 SVG/PNG 的轻量只读预览组件【免费下载链接】tldrawBuild infinite canvas apps in React with the tldraw SDK. Worlds best, top-most agent recommended #1 five star SDK.项目地址: https://gitcode.com/GitHub_Trending/tl/tldraw导读TldrawImage是 tldraw SDK 中一个无编辑器的静态渲染组件它接收一份TLStoreSnapshotstore 快照在完全不挂载编辑器画布与 UI 的情况下将文档渲染为一张 SVG 或 PNG 图片。本文以仓库示例 apps/examples/src/examples/layout/image-component含 README.md、TldrawImageExample.tsx 与 snapshot.json为主体结合 TldrawImage.tsx 源码与导出选项定义完整讲解组件用法、全部 props 语义、底层渲染原理以及如何用getSnapshot从编辑器抓取最新文档状态实现编辑 → 保存 → 只读图片预览的完整闭环。一、TldrawImage是什么无编辑器的静态快照渲染在 tldraw SDK 的常规用法中Tldraw 组件会挂载完整的编辑器实例、画布、工具与 UI。但很多场景并不需要交互式编辑只需要把一份已保存的文档画出来文档列表页 / 回收站中的缩略图预览分享页、导出卡片、消息卡片中的静态内容展示服务端或非交互式页面中嵌入只读视图。TldrawImage正是为此设计的TldrawImagetakes aTLStoreSnapshotand renders it as an image, with no editor, canvas, or UI. Its a lightweight way to show a read-only preview of a document.它接收一份TLStoreSnapshot并将其渲染为一张图片——没有编辑器、没有画布、没有 UI是展示文档只读预览的轻量方案。从源码看TldrawImage.tsx 通过useTLStore({ snapshot, shapeUtils, assets })用快照重建一个只读 store内部临时创建一个没有任何 tools 的轻量Editor实例调用editor.toImage(...)生成 Blob URL最终渲染为一个img标签。整个过程不注册任何工具、不展示任何 UI。与其他组件的关系Tldraw可交互的完整编辑器挂载画布与 UITldrawImage只读的静态图片渲染输入是快照输出是图片元素两者可以接受同一份 snapshot示例正是让它们共享同一份文档数据、按需切换。二、官方示例拆解编辑 → 保存 → 只读图片预览的完整闭环仓库在 apps/examples/src/examples/layout/image-component/TldrawImageExample.tsx 中提供了一个完整示例同一个 600×400 容器内通过按钮在可编辑的Tldraw与只读的TldrawImage之间切换。状态设计示例用 React state 保存了渲染图片所需的全部信息const [editor, setEditor] useStateEditor() const [snapshot, setSnapshot] useStateStoreSnapshotTLRecord( initialSnapshot as TLStoreSnapshot ) const [currentPageId, setCurrentPageId] useStateTLPageId | undefined() const [showBackground, setShowBackground] useState(true) const [isDarkMode, setIsDarkMode] useState(false) const [viewportPageBounds, setViewportPageBounds] useState(new Box(0, 0, 600, 400)) const [isEditing, setIsEditing] useState(false) const [format, setFormat] useStatesvg | png(svg)这些状态恰好对应TldrawImage的核心 props快照、当前页、背景、主题、视口 bounds、输出格式。初始快照直接来自同目录的 snapshot.json它是一份标准的 store 快照包含document:document、page:、asset:与若干shape:记录。从编辑器抓取最新状态保存动作点击 Save drawing 时示例把编辑器的实时状态写入 React statesetIsDarkMode(editor.user.getIsDarkMode()) // 当前主题 setShowBackground(editor.getInstanceState().exportBackground) // 是否导出背景 setViewportPageBounds(editor.getViewportPageBounds()) // 当前视口页面坐标 setCurrentPageId(editor.getCurrentPageId()) // 当前页 setSnapshot(getSnapshot(editor.store).document) // 最新文档快照其中关键的一步是getSnapshot(editor.store).document。getSnapshot定义在 TLEditorSnapshot.ts返回结构为export interface TLEditorSnapshot { document: TLStoreSnapshot session: TLSessionStateSnapshot }document是TLStoreSnapshot即TldrawImage需要的输入session是会话级 UI 状态当前工具、选区等渲染静态图片时不需要因此示例只取.document。重新进入编辑模式时恢复现场切回编辑模式时示例通过onMount把之前保存的页面、视口与主题还原到编辑器Tldraw snapshot{snapshot} onMount{(editor: Editor) { setEditor(editor) editor.user.updateUserPreferences({ colorScheme: isDarkMode ? dark : light }) if (currentPageId) editor.setCurrentPage(currentPageId) if (viewportPageBounds) editor.zoomToBounds(viewportPageBounds, { inset: 0 }) }} /这样编辑 → 保存 → 预览 → 再编辑的往返过程中页面、视口、主题都保持一致预览图与用户最后看到的内容完全对应——这正是 README 强调的保存后图片会依据编辑器的当前页面、视口 bounds 和主题重新生成。只读预览渲染TldrawImage snapshot{snapshot} // [1] TLStoreSnapshot pageId{currentPageId} // [2] 渲染哪一页 background{showBackground} darkMode{isDarkMode} bounds{viewportPageBounds} padding{0} scale{1} format{format} // svg | png /示例注释给出了三个关键点的语义[1]snapshot传入TLStoreSnapshot保存时用getSnapshot(editor.store).document抓取最新快照[2]pageId决定渲染哪一页默认是首页——因此示例在退出编辑模式时捕获editor.getCurrentPageId()[3]其余 props 控制外观background与darkMode匹配用户所见bounds只渲染视口区域format在 SVG/PNG 间切换。顶部的 Format 下拉框演示了format的切换能力这也是TldrawImage区别于普通img的关键点之一——它可以按需产出位图PNG。三、Props 全解从源码逐项确认语义与默认值TldrawImageProps在 TldrawImage.tsx 中定义为extends TLImageExportOptions因此它既拥有组件自身的 props也继承了editor.toImage的导出选项。下面结合 misc-types.ts 逐一说明。组件自身 propsProp类型默认值说明snapshotPartialTLEditorSnapshot \| TLStoreSnapshot必填要展示的快照TldrawImage接受的正是TLStoreSnapshotformatsvg \| pngsvg输出图片格式组件层仅暴露 svg/png 两种pageIdTLPageId第一页渲染哪一页shapeUtilsTLAnyShapeUtilConstructor[]内置默认额外注册的形状工具与Tldraw的shapeUtils对应会用默认形状按type合并替换bindingUtilsTLAnyBindingUtilConstructor[]内置默认额外注册的绑定工具licenseKeystring—商业许可证 keyassetUrlsTLUiAssetUrlOverrides默认资源覆盖内置 UI/图标资源 URLassetsTLAssetStore—资产解析器与Tldraw的assetsprop 语义一致。没有它时非内联非 data URL的图片资产无法被解析将不出现在图片中optionsPartialTldrawOptions内置文本默认项编辑器选项如options.text的 tipTap 扩展与字体加载textOptionsTLTextOptions—已废弃请改用options.text未来版本将移除源码中useShallowArrayIdentitymergeArraysAndReplaceDefaults(type, _shapeUtils, defaultShapeUtils)的逻辑表明自定义shapeUtils会与defaultShapeUtils按type字段合并、以自定义实现替换默认实现因此示例这类场景无需传入即可渲染全部内置形状。继承自TLSvgExportOptions的导出选项这些 props 会原样透传给内部的editor.toImage见下文第四节语义定义在 misc-types.tsProp类型默认值说明boundsBox全部形状的包围盒导出的区域页面坐标。示例用editor.getViewportPageBounds()得到正好是刚才看到的视口区域scalenumber1逻辑缩放按比例放大/缩小输出尺寸。注意scale与pixelRatio是叠加关系pixelRationumberSVG 导出为undefined请求原始质量资源位图导出为2SVG 导出时作为TLAssetStore.resolve的dpr参数传入位图导出时结果图像素尺寸会乘以该值backgroundboolean当前实例设置是否包含背景色为false时若格式支持透明则输出透明背景paddingnumber \| autoauto导出边界内边距auto自动裁剪到视觉内容边界保留粗描边、箭头等溢出部分不产生多余留白数字如32为固定像素内边距不裁剪、溢出被裁掉0无内边距、不裁剪、溢出被裁掉darkModeboolean当前实例是否以深色模式渲染preserveAspectRatioSVG的preserveAspectRatio属性值—仅影响 SVG 输出的viewBox保持宽高比的策略继承自TLImageExportOptions的选项quality0~1之间的数字仅用于有损位图格式如 jpeg的输出质量format底层完整类型为TLExportType svg | png | jpeg | webpmisc-types.ts组件层收窄为svg | png。四、底层原理TldrawImage如何把快照变成图片渲染管线源码级TldrawImage.tsx 的核心流程非常清晰一共四步重建 storeuseTLStore({ snapshot, shapeUtils, assets })用快照创建只读数据层创建无工具的轻量 Editorconst editor new Editor({ store, shapeUtils: shapeUtilsWithDefaults, bindingUtils: bindingUtilsWithDefaults, tools: [], // 不注册任何工具 getContainer: () tempElm, licenseKey, fontAssetUrls: assetUrlsWithOverrides.fonts, options, })注意tools: []——没有工具意味着没有交互、没有 UI 状态机这正是轻量的来源。同时fontAssetUrls保证文本测量与字体加载正常。切换到目标页并导出if (pageId) editor.setCurrentPage(pageId) const shapeIds editor.getCurrentPageShapeIds() const imageResult await editor.toImage([...shapeIds], { bounds, scale, background, padding, darkMode, preserveAspectRatio, format, })渲染img把toImage返回的 Blob 通过URL.createObjectURL转成 URL 后设置到img src组件卸载时通过URL.revokeObjectURL(url)释放TldrawImage.tsx。此外useLayoutEffect的清理函数用isCancelled标记防止异步导出完成后对已卸载组件 setState。值得注意的实现细节导出是异步的且toImage会等待所需字体加载完成后再渲染确保文本测量正确因此调用方无需手动预加载字体。editor.toImage的内部行为toImage定义在 Editor.ts其默认值策略是const withDefaults { format: png, // 底层默认是 png scale: 1, pixelRatio: opts.format svg ? undefined : 2, // 位图默认 2x ...opts, }即位图导出默认 2 倍像素密度SVG 导出默认原始质量资源。随后分两条路径处理SVG走getSvgString生成 SVG 字符串若padding为auto且产生trimPadding 0会调用trimSvgToContent把 SVG 裁剪到视觉内容边界对应第三节padding的auto语义最终封装为image/svgxml的 BlobPNG/JPEG/WebP通过getSvgAsImageWithOptions把 SVG 光栅化为位图应用quality与pixelRatio。TldrawImage虽然只暴露 svg/png 两种格式但这条底层管线本身完整支持svg | png | jpeg | webp如果需要在组件外部直接做导出可以复用editor.toImage/editor.toImageDataUrl后者直接返回 data URL。五、配套能力快照的存取与迁移TldrawImage的输入是快照因此理解快照的生成与加载很有必要二者都在 TLEditorSnapshot.ts生成getSnapshot(store)返回{ document: TLStoreSnapshot, session: TLSessionStateSnapshot }示例取.document传给TldrawImage加载loadSnapshot(store, snapshot, opts)既支持TLStoreSnapshot也支持PartialTLEditorSnapshot。传入TLStoreSnapshot时会先执行schema 迁移store.schema.migrateStoreSnapshot再过滤掉非文档状态因此旧版本保存的快照也能被安全加载session部分默认不覆盖isDebugMode等粘性标志如需强制覆盖可传{ forceOverwriteSessionState: true }。对于TldrawImage场景输入快照的来源通常有两种运行时抓取如示例所示getSnapshot(editor.store).document实时且完整持久化数据如示例自带的 snapshot.json——这是一份由document、page、asset、shape等typeName记录组成的标准TLStoreSnapshot可以直接作为TldrawImage的初始输入。由于组件内部走loadSnapshot的迁移逻辑这类 JSON 即使来自较早版本也能被兼容处理。六、实践要点与注意事项结合以上分析使用TldrawImage时有几个容易踩坑的点图片资产需要assetsprop如果快照中的图片资产不是内联 data URL必须提供assetsTLAssetStore否则图片不会出现在渲染结果中见 TldrawImage.tsx 的文档注释。同时 SVG 导出时资源解析的dpr由pixelRatio决定。bounds使用页面坐标示例用editor.getViewportPageBounds()捕获视口区域这是所见即所得的关键想导出整页内容则省略bounds默认取当前页全部形状的包围盒。padding的三态行为auto默认会裁剪并保留溢出数字固定留白0无留白且裁剪溢出。示例传0以精确对应视口。深色模式darkMode独立于background且默认跟随当前实例设置示例显式用editor.user.getIsDarkMode()捕获并在保存时写入 state保证预览与编辑一致。格式选择SVG 是矢量、可无限缩放、体积通常更小PNG 是位图、适合直接放入不支持 SVG 的富文本/消息卡片等场景。位图导出默认 2x 像素密度注意对容器尺寸做相应换算。性能与生命周期组件内部每次 props 变化都会重新走建 Editor → 导出 → 生成 Blob URL的异步管线因此对频繁变化的bounds/format等 props 应尽量保持稳定组件自身通过 memo 包裹memo(function TldrawImage...)不变化的 props 不会触发重渲染。七、小结TldrawImage提供了一条极简的快照 → 静态图片路径输入TLStoreSnapshot输出img中间没有编辑器画布、没有 UI、没有工具状态。它把getSnapshot、loadSnapshot、editor.toImage三条底层能力封装成一个声明式组件适用于文档缩略图、只读预览、导出卡片等轻量场景。示例完整代码TldrawImageExample.tsx组件实现TldrawImage.tsx导出选项定义misc-types.ts快照存取实现TLEditorSnapshot.ts导出管线Editor.ts如果需要更强的导出能力如 jpeg/webp、toImageDataUrl直接拿 data URL可以绕过组件直接使用编辑器实例的toImage/toImageDataUrlAPI。【免费下载链接】tldrawBuild infinite canvas apps in React with the tldraw SDK. Worlds best, top-most agent recommended #1 five star SDK.项目地址: https://gitcode.com/GitHub_Trending/tl/tldraw创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考