# ice-chart-dsl
**Repository Path**: ice-render/ice-chart-dsl
## Basic Information
- **Project Name**: ice-chart-dsl
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: MIT
- **Default Branch**: main
- **Homepage**: https://ice-render.github.io/ice-render-doc/
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2026-09-13
- **Last Updated**: 2026-09-20
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# ice-chart-dsl
JSON-first DSL for AI agents to build charts with [`@damoqiongqiu/ice-chart`](https://www.npmjs.com/package/@damoqiongqiu/ice-chart).
ice-chart 的 `ChartOption` 本来就是纯 JSON(`toJSON()` / `fromJSONString()`),所以这个包**不是把 option 换个写法**。
它补的是 option 不做、而模型最容易写错的三件事:
| | ChartOption | ice-chart-dsl |
| --- | --- | --- |
| 输入 | 自己把数据拍成 `series[].data` | **一张表 + `encoding`**:`{ x: '月份', y: '销量', series: '渠道' }` |
| 默认值 | 逐项自己写 | 轴类型 / 图例显隐 / 提示框触发方式按类型自动定,显式写的优先 |
| 出错时 | 画出来是空的,只能自己猜 | **结构化诊断**:列不存在(带可用列名)、类型不匹配、空数据、公式错误(带字符位置) |
编译产物就是普通的 `ChartOption` —— 悬停、缩放、框选、序列化、跨图联动全部照旧。
## Install
```bash
npm install @damoqiongqiu/ice-chart-dsl @damoqiongqiu/ice-chart ice-render
```
## 30 秒
```json
{
"schemaVersion": 1,
"kind": "line",
"title": "月度销量",
"data": {
"columns": ["月份", "销量", "渠道"],
"rows": [["1月", 120, "线上"], ["1月", 86, "线下"], ["2月", 142, "线上"], ["2月", 92, "线下"]]
},
"encoding": { "x": "月份", "y": "销量", "series": "渠道" }
}
```
```ts
import { renderChartDsl, validateChartDsl, compileChartDsl } from '@damoqiongqiu/ice-chart-dsl';
const { chart, option, diagnostics } = renderChartDsl('canvas-id', dsl);
// 或者只要配置:编译出来的就是 ChartOption
const option = compileChartDsl(dsl);
// 或者只要诊断(validate 不抛异常,任何输入都能吃)
const result = validateChartDsl(dsl);
if (!result.valid) console.log(result.errors.map((e) => e.message).join('\n'));
```
浏览器直接用(UMD,注意顺序):
```html
```
## 数据集两种写法
```json
{ "columns": ["月份", "销量"], "rows": [["1月", 120], ["2月", 132]] }
```
```json
[{ "月份": "1月", "销量": 120 }, { "月份": "2月", "销量": 132 }]
```
对象数组是模型最常吐的形态,两种都收;`columns` 按对象 key 首次出现顺序推出来。
## kind 与覆盖范围
| kind | 需要的通道 | 说明 |
| --- | --- | --- |
| `line` / `area` | `x` + `y`(+ `series`) | 数值 x 自动用数值轴 + `[x, y]` 数据点 |
| `bar` | `x` + `y`(+ `series`) | 堆叠用 `options.stack` |
| `scatter` | `x` + `y`(+ `size`) | 绑 `size` 即气泡图 |
| `pie` | `name` + `value` | 负值会被警告(饼图不表达负值) |
| `radar` | `x`(指标)+ `y`(数值)+ `series` | 指标名从 x 列推,上限自动取整到好看的刻度 |
| `heatmap` | `x` + `y`(两个类目列)+ `value` | 二维矩阵表直接画 |
| `candlestick` | `x` + `y`=**四列** `[开, 收, 低, 高]` | 少给列会明确报错 |
| `waterfall` | `name` + `value`(+ `total`) | `total` 列非 0 的行当合计项 |
| `funnel` / `gauge` / `liquid` | `name` + `value` | 仪表盘/水位球只取第一行(多行会警告) |
| `sankey` | `source` + `target` + `value` | 一张「起点 / 终点 / 流量」的连线表 |
| `function` | `expression`(+ `domain` / `params`) | 不需要 data |
**直通**:`treemap` / `graph` / `parametric` / `boxplot` 等直接给 `series`(`options` 照常透传)。
**逃生舱**:`options` 里的键覆盖编译结果(`series` 除外),所以 DSL 跟不上核心演进时不会把人堵死。
## 标注:目标线 / 阈值线 / 异常点 / 目标区间
业务图上最高频的参考线不是「一种新图表」,而是一条配置 —— 顶层 `annotation`(与 `encoding` 平级):
```json
{
"schemaVersion": 1,
"kind": "line",
"title": "月度销量与目标",
"data": { "columns": ["月份", "销量"], "rows": [["1月", 120], ["2月", 132], ["3月", 101]] },
"encoding": { "x": "月份", "y": "销量" },
"annotation": {
"lines": [
{ "axis": "y", "value": 150, "text": "目标 150" },
{ "axis": "y", "value": 100, "text": "告警阈值", "color": "#dc3545" },
{ "axis": "x", "value": "2月", "text": "上线" }
],
"points": [{ "x": "3月", "y": 101, "text": "异常点", "symbol": "diamond" }],
"areas": [{ "axis": "y", "from": 0, "to": 100, "text": "达标区" }]
}
}
```
- `lines[].value` / `areas[].from`、`to` / `points[].x`、`y` 都是**数据值**(不是像素):
数值轴写数字、类目轴写类目名或下标、时间轴写时间戳或日期串。
- 它挂在坐标系上,所以**跟着缩放 / 平移走**,不进图例、不占数据下标、不抢命中测试;
越界的标注不画,原因由 ice-chart 的 `chart.annotationDiagnostics()` 给出。
- 只对直角坐标的 kind 有意义(`line` / `area` / `bar` / `scatter`);
给饼图 / 雷达 / 桑基等会被警告 `annotation-non-cartesian`。
- 编译期诊断:缺 `value` / 缺 `from`+`to` 是**错误**(带 `annotation.lines[0].value` 这样的路径),
类目不存在(`annotation-unknown-category`)、数值轴写了非数字(`annotation-value-type`)、
区间宽度为 0(`annotation-empty-area`)是**警告**。
- 逃生舱照常:`options.annotation` 能整体覆盖顶层 `annotation`。
## 主题:一条链路贯通图表与引擎
DSL 里的主题走图表的 `options.theme`(`'light'` / `'dark'` / `'auto'` / 部分主题片段),
**图表层再把它映射到引擎主题**(引擎 2.4 起):图表实例里那些「引擎自己画的东西」
(引擎默认样式、选中框 / 手柄 / 插槽这些交互外壳、应用后加的自定义图元)会跟着一起换。
```json
{
"kind": "line",
"data": { "columns": ["月份", "销量"], "rows": [["1月", 120], ["2月", 132]] },
"encoding": { "x": "月份", "y": "销量" },
"options": {
"theme": "dark"
}
}
```
- `theme: 'auto'` = 跟随**引擎实例主题**(按引擎主题背景色的亮度判定明暗)——
图表渲染在别人的暗色画布上时,写 `auto` 即可,不用自己判断。
- 需要品牌色就传片段:`"theme": { "colorPalette": ["#0d6efd", "#10b981"], "textColor": "#212529" }`
(浅合并到亮色主题),映射到引擎的那一份会自动跟着算。
- 完整的映射表见 `ice-chart` 仓库的 `src/theme/chartEngineBridge.ts`。
## 诊断:给 agent 的自修复反馈
`validateChartDsl()` **不抛异常**,返回结构化诊断(`{ severity, code, message, path }`):
```
[错误] 列「销售额」不存在。可用列:月份 / 销量 / 渠道。(encoding.y)
[错误] 列「渠道」不是数值列(数字占比 0%),不能当 y 用。(encoding.y)
[错误] 第 3 行有 2 个值,但列数是 3。(data.rows[2])
[警告] 饼图 / 玫瑰图不适合表达负值,检测到 2 行负数。(encoding.value)
[错误] 表达式错误:缺少右括号(位置 6)… (expression)
[警告] 参数「b」定义了但表达式没有用到。(expression)
[错误] annotation.lines[0] 缺少 value(数值轴写数字、类目轴写类目名或下标)。(annotation.lines[0].value)
[警告] annotation.lines[1].value 的类目名「13月」不在 x 列里(该列有 3 个类目),这条标注不会画出来。(annotation.lines[1].value)
```
公式类会**采样一遍再诊断**:静态检查抓语法错误,运行层抓「整段开不出来」「输出恒定」——
这两种恰恰是"公式写错了但没报错"最常见的表现。
## API
| 导出 | 说明 |
| --- | --- |
| `CHART_DSL_SCHEMA_VERSION` / `CHART_DSL_KINDS` | 版本与支持的 kind |
| `CHART_DSL_COMPILED_KINDS` | 走 data/encoding 编译的 kind 清单 |
| `validateChartDsl(dsl)` | 结构 + 语义校验,返回 `{ valid, errors, warnings }` |
| `formatDiagnostics(result)` | 诊断 → 多行文本 |
| `compileChartDsl(dsl)` | DSL → `ChartOption`(不合法时抛 `ChartDslCompileError`,`.diagnostics` 带原因) |
| `chartDslToJsonString(dsl)` | 直接拿编译产物的 JSON 字符串 |
| `renderChartDsl(target, dsl, chartOptions?)` | 编译并渲染,返回 `{ chart, option, diagnostics }` |
| `resolveDataset` / `columnIndex` / `numericRatio` | 数据集工具(自建通道映射时用得上) |
JSON Schema:[`src/schema/chart-dsl.schema.json`](./src/schema/chart-dsl.schema.json)。
## Example
```bash
npm install
npm run build
# 起一个静态服务打开 examples/chart-dsl.html
```
左边写 DSL,右边实时渲染,下面是诊断面板(含「错误示例」预设,可以直接看到列名纠错长什么样)。
## Agent discovery
- npm 包导出(`validateChartDsl` / `compileChartDsl` / `renderChartDsl`)
- [`skills/ice-chart-dsl/SKILL.md`](./skills/ice-chart-dsl/SKILL.md)
- [`prompts/agent-prompt.md`](./prompts/agent-prompt.md)
## License
MIT