# 仅渲染图形

从明确的语言与源码生成 SVG 和 PNG，管理取消、资源与失败。

只需要展示图形时，使用 `@quirekit/text-diagram/browser`。它不要求 Vue，也不会安装编辑器。语言由调用方明确传入，不从源码猜测。

## 1. 从源码生成 SVG

先提供语言、源码和取消信号。下面在浏览器中生成一张两节点流程图：

```ts [生成 SVG]
import { renderTextDiagram, rasterizeTextDiagram } from '@quirekit/text-diagram/browser'
const controller = new AbortController()
const vector = await renderTextDiagram('mermaid', 'flowchart LR; A-->B', {
  ownerDocument: document,
  signal: controller.signal,
})
```

`ownerDocument` 用于浏览器测量；`signal` 用于在切换源码或离开页面时取消请求。返回值保存这次渲染的源码与 SVG。

## 2. 从同一个结果生成 PNG

```ts [生成 PNG]
const raster = await rasterizeTextDiagram(vector, document, controller.signal)
```

`vector.svg` 是静态 SVG 字符串；`raster.dataUrl` 可作为图片 `src`。每个结果都携带实际渲染的 `language` 与 `source`。调用方显示结果前仍应确认请求未过期，不要把旧图片写进新源码对象。

## 并发与释放

连续输入时先取消上一个控制器，再为新源码创建控制器。取消意味着不接受迟到结果，不代表所有引擎都能立即停止计算；Mermaid 请求在共享队列中串行执行，PlantUML / DOT 使用独立 sandbox frame，取消后移除 frame。

如果把 SVG 包成 Blob URL，替换图片或销毁宿主时调用 `URL.revokeObjectURL`。自己创建的图片、容器和事件仍由宿主清理。PNG 是白色背景，按尺寸预算缩放，不保证与 SVG 一比一像素尺寸。

## 失败保留原文

空白或超限源码、语法错误、不受支持的外部资源、引擎超时都可能让 Promise 拒绝。取消旧请求通常无需显示错误；当前请求失败时展示简短提示、原文和重试入口，不用一张错误图片代替有效预览。

模型函数不验证 DSL 语法。工作台的语法着色也只是编辑辅助，是否可渲染以引擎结果为准。

## 服务器端

源码对象、模板和 Markdown 围栏函数可在 Node 中使用；本页渲染函数依赖 DOM、字体测量、iframe 和 Canvas，**不是 Node 渲染 API**。SSR 输出已有的 PNG，客户端再按需打开编辑器。详见[部署](/guide/deployment)和[浏览器 API](/api/browser)。

## 完整模块参考

`recipes/render.ts` 把上述两步组合成一个函数；`shared/types.ts` 定义返回的两种产物。需要复制完整函数时按文件查阅：

### recipes/render.ts

```ts
import type { TextDiagramLanguage } from "@quirekit/text-diagram";
import { renderTextDiagram, rasterizeTextDiagram } from "@quirekit/text-diagram/browser";
import type { DiagramFiles } from "../shared/types";

/**
 * Renders both formats in a browser without mounting the authoring UI.
 * @param language - Explicit supported grammar.
 * @param source - Exact source, kept alongside the generated files.
 * @param owner - Browser document used for measurement and rasterization.
 * @param signal - Abort on source replacement or host destruction.
 * @returns Sanitized SVG and PNG tied to the same immutable source snapshot.
 */
export async function createDiagramFiles(language: TextDiagramLanguage, source: string, owner: Document, signal: AbortSignal): Promise<DiagramFiles> {
  const vector = await renderTextDiagram(language, source, { ownerDocument: owner, signal });
  const raster = await rasterizeTextDiagram(vector, owner, signal);
  signal.throwIfAborted();
  return { vector, raster };
}

```

### shared/types.ts

```ts
import type { TextDiagramEditRequest, TextDiagramEmbed, TextDiagramSnapshot, TextDiagramRaster } from "@quirekit/text-diagram";

/** Minimal synchronous host; durable storage belongs to its caller. */
export interface DiagramSession {
  /** @returns The last accepted immutable object. */
  read(): TextDiagramEmbed;
  /** @returns A new edit request capturing the current baseline. */
  capture(): TextDiagramEditRequest;
}

/** Two output formats generated from exactly the same source. */
export interface DiagramFiles {
  /** Sanitized vector snapshot. */
  readonly vector: TextDiagramSnapshot;
  /** Bounded PNG projection. */
  readonly raster: TextDiagramRaster;
}

```
