feat: 增加 ECharts 渲染与预览交互增强
- 新增可复用的 markdown-echarts 工作区,支持安全的 YAML 围栏、默认值、语义校验、错误占位和 SVG 渲染 - 将 ECharts 接入统一 Markdown、快速预览、精确预览与 PDF 链路,并复用 Mermaid 的不可跨页和超高图单页适配策略 - 默认示例加入 ECharts,增加源文本折叠、顶部文档状态、页码输入跳转与滚动同步 - 快速预览改用外层容器滚动,使滚动条与精确预览统一贴在预览区域右侧,并兼容显示缩放 - 完善 Docker 工作区复制、可配置 Compose 镜像、测试覆盖和进度文档
This commit is contained in:
@@ -0,0 +1,179 @@
|
||||
# @md-to-pdf/markdown-echarts
|
||||
|
||||
为 Markdown 增加安全、可验证、可复用的 ECharts YAML 围栏,
|
||||
并在浏览器中渲染为 SVG。
|
||||
|
||||
该包不依赖 React、Paged.js 或特定 PDF 引擎。宿主可以将生成的
|
||||
HTML 用于网页预览,也可以在图表完成渲染后交给 Chromium 输出 PDF。
|
||||
|
||||
## 基本语法
|
||||
|
||||
````markdown
|
||||
```echarts
|
||||
height: 80mm
|
||||
caption: 年度收入
|
||||
option:
|
||||
xAxis:
|
||||
type: category
|
||||
data: [2023, 2024]
|
||||
yAxis:
|
||||
type: value
|
||||
series:
|
||||
- type: bar
|
||||
data: [120, 180]
|
||||
```
|
||||
````
|
||||
|
||||
围栏内容必须使用 YAML,并包含一个 ECharts `option` 对象。YAML
|
||||
会先转换为安全的纯数据对象,再交给 ECharts;不能使用函数、
|
||||
YAML 锚点、别名或自定义标签。
|
||||
|
||||
## 围栏字段
|
||||
|
||||
| 字段 | 类型 | 默认值 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `version` | `1` | `1` | 围栏协议版本 |
|
||||
| `height` | CSS 长度 | `80mm` | 支持 `mm`、`cm`、`in`、`px` |
|
||||
| `aspectRatio` | 正数 | 无 | 与 `height` 二选一;指定后不补默认高度 |
|
||||
| `theme` | `document`、`light`、`dark` | `document` | ECharts 主题 |
|
||||
| `caption` | 字符串 | 无 | 图表标题说明 |
|
||||
| `option` | 对象 | 必填 | 经过安全和语义验证的 ECharts 配置 |
|
||||
|
||||
## 数据来源
|
||||
|
||||
每个系列必须从以下任一位置获得有效数据:
|
||||
|
||||
- 非空的 `series[].data`;
|
||||
- 非空的 `dataset.source`;
|
||||
- 引用具有有效上游数据源的内置 `filter` 或 `sort` transform。
|
||||
|
||||
只有表头的二维数组、所有列均为空的对象以及空数组不属于有效
|
||||
数据。使用 `dataset` 时保留 ECharts 的默认维度映射,也可以通过
|
||||
`series.encode` 显式声明映射。
|
||||
|
||||
```yaml
|
||||
option:
|
||||
dataset:
|
||||
source:
|
||||
- [year, sales]
|
||||
- [2025, 120]
|
||||
- [2026, 180]
|
||||
series:
|
||||
- type: line
|
||||
encode:
|
||||
x: year
|
||||
y: sales
|
||||
```
|
||||
|
||||
## 系列验证规则
|
||||
|
||||
当前首版支持以下系列:
|
||||
|
||||
| 系列 | 主要规则 |
|
||||
| --- | --- |
|
||||
| `line` | 需要有效数据;支持直角坐标系和极坐标系 |
|
||||
| `bar` | 需要有效数据;支持直角坐标系和极坐标系 |
|
||||
| `scatter` | 直接数据至少包含两个坐标值 |
|
||||
| `pie` | 直接数据项的 `value` 必须是有限数值 |
|
||||
| `radar` | 必须提供非空 `radar.indicator`;数据维数不得少于指标数 |
|
||||
| `heatmap` | 直角坐标数据为 `[x, y, value]`;日历数据为 `[date, value]` |
|
||||
| `boxplot` | 直接数据为 `[min, Q1, median, Q3, max]` |
|
||||
| `candlestick` | 直接数据为 `[open, close, lowest, highest]` |
|
||||
|
||||
直角坐标系列缺少 `xAxis` 或 `yAxis` 时会补充空对象,让 ECharts
|
||||
使用自身的轴默认值。极坐标、雷达和日历坐标系表达了明确语义,
|
||||
因此不会猜测配置,缺少对应组件时会报告错误。
|
||||
|
||||
使用 `dataset` 时,验证器只验证数据源是否存在,不重复实现
|
||||
ECharts 的维度推断和 `encode` 映射规则。
|
||||
|
||||
## 错误行为
|
||||
|
||||
配置错误不会中断整篇 Markdown。对应围栏会变成局部错误占位:
|
||||
|
||||
```html
|
||||
<div class="md-echarts-error" role="alert">
|
||||
ECharts 图表配置无效:option.series.0.data 必须是非空数组……
|
||||
</div>
|
||||
```
|
||||
|
||||
错误消息包含配置路径,便于用户或 AI Agent 定位并修正 YAML。
|
||||
宿主还可以通过 `onError` 收集结构化错误。
|
||||
|
||||
```ts
|
||||
markdown.use(markdownItECharts, {
|
||||
onError(error, context) {
|
||||
console.warn(error.code, error.message, context.tokenIndex);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
## Markdown-it 接入
|
||||
|
||||
```ts
|
||||
import MarkdownIt from "markdown-it";
|
||||
import {
|
||||
markdownItECharts
|
||||
} from "@md-to-pdf/markdown-echarts";
|
||||
|
||||
const markdown = new MarkdownIt().use(markdownItECharts);
|
||||
const html = markdown.render(source);
|
||||
```
|
||||
|
||||
如果宿主还会对 HTML 做安全过滤,需要保留包生成的 `figure`、
|
||||
`figcaption`、隐藏配置节点及 `data-echarts-*` 属性。
|
||||
|
||||
## 浏览器渲染
|
||||
|
||||
```ts
|
||||
import {
|
||||
renderEChartsBlocks
|
||||
} from "@md-to-pdf/markdown-echarts/browser";
|
||||
import "@md-to-pdf/markdown-echarts/styles.css";
|
||||
|
||||
const outcomes = await renderEChartsBlocks(document, {
|
||||
outputMode: "inline-svg",
|
||||
animation: false,
|
||||
concurrency: 2,
|
||||
timeoutMs: 5000
|
||||
});
|
||||
```
|
||||
|
||||
输出模式:
|
||||
|
||||
- `interactive`:保留 ECharts 实例和响应式尺寸监听;
|
||||
- `inline-svg`:冻结为内联 SVG,适合打印和 PDF;
|
||||
- `svg-image`:冻结为 SVG Data URL 图片。
|
||||
|
||||
PDF 输出前应等待所有图表、字体和图片完成,再开始分页或调用
|
||||
Chromium `page.pdf()`。
|
||||
|
||||
## 安全边界
|
||||
|
||||
默认策略会拒绝:
|
||||
|
||||
- `custom` 系列及 `renderItem`;
|
||||
- JavaScript、HTTP、文件和 Data URL 外部资源;
|
||||
- HTML formatter;
|
||||
- 原型污染属性;
|
||||
- 未允许的 toolbox 功能;
|
||||
- 非内置数据转换;
|
||||
- 超过节点数、深度、字符串、数组和系列数量上限的配置。
|
||||
|
||||
这些限制适用于不受信任的 Markdown。宿主如需扩大能力,应在明确
|
||||
风险后扩展验证器,而不是直接执行 YAML 中的 JavaScript。
|
||||
|
||||
## 扩展系列验证
|
||||
|
||||
各系列规则注册在 `echartsSeriesValidators`。新增图形时需要同步:
|
||||
|
||||
1. 将系列类型加入协议支持列表;
|
||||
2. 在浏览器引擎中注册对应 ECharts Chart;
|
||||
3. 注册该系列的语义验证器;
|
||||
4. 增加有效、缺少数据、错误数据结构和真实 SVG 渲染测试。
|
||||
|
||||
参考:
|
||||
|
||||
- [ECharts 配置参考](https://echarts.apache.org/en/option.html)
|
||||
- [ECharts Dataset](https://echarts.apache.org/handbook/en/concepts/dataset/)
|
||||
- [ECharts Data Transform](https://echarts.apache.org/handbook/en/concepts/data-transform/)
|
||||
Reference in New Issue
Block a user