396 lines
11 KiB
Markdown
396 lines
11 KiB
Markdown
# OpenNodes V1 — 支持矩阵、富文本和样式
|
||
|
||
> 本文件是 DWS OpenNodes V1 协议的拆分章节。按需读取入口见
|
||
> [协议索引](../open-nodes-v1.md)。
|
||
|
||
## 7. 节点类型
|
||
|
||
### 7.1 支持矩阵
|
||
|
||
| `type` | query | update | 主要字段 |
|
||
| --- | --- | --- | --- |
|
||
| `shape` | 支持 | 支持 | `geometry`、`text?`、`style?` |
|
||
| `text` | 支持 | 支持 | `text`、`style?` |
|
||
| `connector` | 支持 | 支持 | `start`、`end`、`routing`、`waypoints?`、`style?` |
|
||
| `stickyNote` | 支持 | 支持 | `text?`、`style?` |
|
||
| `frame` | 支持 | 支持 | `title?`、`style?`、`presentationOrder?`、`resizeMode?` |
|
||
| `group` | 支持 | 支持 | 子关系通过 `parentId` 表达 |
|
||
| `image` | 支持 | 只读 | 仅公共字段 |
|
||
| `vector` | 支持 | 支持 | `resource` |
|
||
| `icon` | 支持 | 支持 | `catalogId` |
|
||
| `path` | 支持 | 支持 | `path`、`style?` |
|
||
| `pdf` | 支持 | 只读 | 仅公共字段 |
|
||
| `media` | 支持 | 只读 | 仅公共字段 |
|
||
| `webLink` | 支持 | 只读 | 仅公共字段 |
|
||
| `table` | 支持 | 只读 | 仅公共字段 |
|
||
| `chart` | 支持 | 只读 | 仅公共字段 |
|
||
| `uml` | 支持 | 只读 | 仅公共字段 |
|
||
| `swimlane` | 支持 | 只读 | 仅公共字段 |
|
||
| `mind` | 支持 | 只读 | 仅公共字段 |
|
||
| `timer` | 支持 | 只读 | 仅公共字段 |
|
||
| `placeholder` | 支持 | 只读 | 仅公共字段 |
|
||
| `unknown` | 支持 | 只读 | 未识别或尚未定义独立语义的节点统一映射到此类型 |
|
||
|
||
表中标记为只读的类型仍会完整返回公共几何、层级和顺序信息,但 update 提交会以
|
||
`nodeTypeUnsupported` 失败。
|
||
|
||
`timer`、`table`、`webLink` 不支持 V1 update。query 仅返回这些节点的公共几何、
|
||
层级、顺序和诊断字段,不承诺完整业务字段。文字 run 中的 `link` 是富文本能力,
|
||
不属于 `webLink` 节点,V1 支持读写。
|
||
|
||
`webLink` 只保留只读查询;OpenNodes V1 不支持创建或重建该节点。
|
||
|
||
### 7.2 Text
|
||
|
||
query 和 update 均支持普通段落、无序列表、有序列表、多 block、多 run 和文字
|
||
链接:
|
||
|
||
```ts
|
||
interface OpenTextRun {
|
||
text: string;
|
||
marks?: {
|
||
fontFamily?: string;
|
||
fontSize?: number;
|
||
bold?: boolean;
|
||
italic?: boolean;
|
||
underline?: boolean;
|
||
strike?: boolean;
|
||
color?: string;
|
||
highlight?: string;
|
||
};
|
||
link?: { url: string };
|
||
}
|
||
|
||
interface OpenTextBlock {
|
||
type: "paragraph" | "bulletList" | "orderedList";
|
||
horizontalAlign?: "left" | "center" | "right";
|
||
runs: OpenTextRun[];
|
||
}
|
||
|
||
interface OpenTextWrite {
|
||
blocks: OpenTextBlock[];
|
||
verticalAlign?: "top" | "center" | "bottom";
|
||
padding?: number | [number, number];
|
||
}
|
||
|
||
interface OpenText extends OpenTextWrite {
|
||
plainText: string;
|
||
writeSupport: "readWrite" | "readOnly";
|
||
unsupportedFeatures?: string[];
|
||
}
|
||
```
|
||
|
||
约束:
|
||
|
||
- `blocks.length >= 1`,每个 block 的 `type` 必须是 `paragraph`、
|
||
`bulletList` 或 `orderedList`。
|
||
- 每个 block 都必须满足 `runs.length >= 1`。
|
||
- run 的 `text` 不能包含 `\r`、`\n`、U+2028 或 U+2029。换行和列表项使用
|
||
独立 block 表达;每一段或每个列表项应写成一个 block,而不是把原始换行符
|
||
放进单个 run。
|
||
- 每个 `bulletList` / `orderedList` block 表示一个列表项;服务端会把连续且同类的
|
||
block 解释为同一个列表中的多个列表项。
|
||
- `link.url` 长度必须为 `1..2048`,不能包含控制字符、`<`、`>`。支持无 scheme
|
||
的相对/裸链接,以及 `http`、`https`、`mailto`、`tel`、`dingtalk` scheme;
|
||
`javascript:`、`data:` 等可执行或未知 scheme 会被拒绝。
|
||
- 相邻且 URL 相同的 linked run 会呈现为同一个链接,同时保留各 run 自己的 marks。
|
||
- `fontSize > 0`,padding 各项必须大于等于 `0`。
|
||
- `plainText`、文本级 `writeSupport` 和 `unsupportedFeatures` 是 query-only。
|
||
- text 节点必须提供 `text`;shape 和 stickyNote 的 `text` 可省略。
|
||
- 受支持的 paragraph、列表、链接、多 run 都保持
|
||
`writeSupport = "readWrite"`;未知 list style、非法链接、未支持的 block 或
|
||
run marks 会令文本和所属节点变为 `readOnly`。
|
||
|
||
下面的文本会显示为两个段落,第一段由两个不同样式的 run 组成:
|
||
|
||
```json
|
||
{
|
||
"blocks": [
|
||
{
|
||
"type": "paragraph",
|
||
"horizontalAlign": "left",
|
||
"runs": [
|
||
{
|
||
"text": "OpenNodes ",
|
||
"marks": { "fontSize": 18, "bold": true, "color": "#2563EB" }
|
||
},
|
||
{
|
||
"text": "rich text",
|
||
"marks": { "fontSize": 18, "italic": true, "color": "#0F172A" }
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"type": "paragraph",
|
||
"horizontalAlign": "right",
|
||
"runs": [
|
||
{
|
||
"text": "第二段",
|
||
"marks": { "fontSize": 16, "underline": true, "color": "#047857" }
|
||
}
|
||
]
|
||
}
|
||
],
|
||
"verticalAlign": "center",
|
||
"padding": [4, 8]
|
||
}
|
||
```
|
||
|
||
同一 `OpenTextWrite` 结构适用于独立 text 节点、shape 文本、stickyNote 文本和
|
||
frame title。
|
||
|
||
下面三个 block 会生成两个无序列表项,其中第二项包含文字链接:
|
||
|
||
```json
|
||
{
|
||
"blocks": [
|
||
{
|
||
"type": "bulletList",
|
||
"runs": [{ "text": "准备输入数据" }]
|
||
},
|
||
{
|
||
"type": "bulletList",
|
||
"runs": [
|
||
{
|
||
"text": "查看钉钉文档",
|
||
"marks": { "underline": true },
|
||
"link": { "url": "https://alidocs.dingtalk.com" }
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"type": "orderedList",
|
||
"runs": [{ "text": "执行生成" }]
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
颜色接受以下 CSS 形式:3/4/6/8 位十六进制、颜色名,以及
|
||
`rgb()`、`rgba()`、`hsl()`、`hsla()`、`oklch()`、`lab()`、`lch()`、
|
||
`color()`。字符串最长 128 字符,不能包含控制字符、`<`、`>` 或 `;`。
|
||
这里只接受可独立解析的字面量;依赖外部样式上下文的 `var()`、`calc()`、
|
||
`color-mix()` 等动态表达式不属于 V1。颜色名必须是标准 CSS named color,
|
||
任意字母串不会被当成颜色。
|
||
|
||
### 7.3 Style
|
||
|
||
query 可表达:
|
||
|
||
- `none`、`solid`、`theme`、线性渐变、径向渐变和图片 paint。
|
||
- shadow、blur 和 unknown effect。
|
||
|
||
V1 update 支持 `none`、`solid`、`theme`、线性渐变、九方向径向渐变,以及
|
||
单个自定义 shadow。主题明暗参数和渐变色标位置使用 `0~100` 的百分比,
|
||
不会归一化成 `0~1`:
|
||
|
||
```ts
|
||
type OpenRadialGradientPosition =
|
||
| "topLeft"
|
||
| "topCenter"
|
||
| "topRight"
|
||
| "centerLeft"
|
||
| "center"
|
||
| "centerRight"
|
||
| "bottomLeft"
|
||
| "bottomCenter"
|
||
| "bottomRight";
|
||
|
||
interface OpenColorStop {
|
||
offset: number;
|
||
color: string;
|
||
opacity?: number;
|
||
}
|
||
|
||
interface OpenImagePaint {
|
||
type: "image";
|
||
resource: {
|
||
kind: "managed" | "external" | "embedded" | "unresolved";
|
||
resourceId?: string;
|
||
};
|
||
intrinsicWidth: number;
|
||
intrinsicHeight: number;
|
||
}
|
||
|
||
type OpenPaint =
|
||
| { type: "none" }
|
||
| { type: "solid"; color: string; opacity?: number }
|
||
| {
|
||
type: "theme";
|
||
token: string;
|
||
lumMod?: number;
|
||
lumOff?: number;
|
||
resolvedColor?: string;
|
||
}
|
||
| {
|
||
type: "linearGradient";
|
||
angle: number;
|
||
stops: OpenColorStop[];
|
||
}
|
||
| {
|
||
type: "radialGradient";
|
||
position: OpenRadialGradientPosition | "custom";
|
||
stops: OpenColorStop[];
|
||
}
|
||
| OpenImagePaint;
|
||
|
||
type OpenEffect =
|
||
| {
|
||
type: "shadow";
|
||
offsetX: number;
|
||
offsetY: number;
|
||
blur: number;
|
||
color: string;
|
||
opacity: number;
|
||
}
|
||
| { type: "blur"; blur: number }
|
||
| { type: "unknown" };
|
||
|
||
interface OpenNodeStyle {
|
||
opacity?: number;
|
||
fill?: OpenPaint;
|
||
stroke?: {
|
||
paint: OpenPaint;
|
||
width?: number;
|
||
dash?: number[];
|
||
lineCap?: "butt" | "round" | "square";
|
||
lineJoin?: "miter" | "round" | "bevel";
|
||
};
|
||
effects?: OpenEffect[];
|
||
writeSupport: "readWrite" | "readOnly";
|
||
unsupportedFeatures?: string[];
|
||
}
|
||
|
||
interface OpenColorStopWrite {
|
||
offset: number; // [0, 100],百分比
|
||
color: string;
|
||
opacity?: number; // [0, 1]
|
||
}
|
||
|
||
type OpenPaintWrite =
|
||
| { type: "none" }
|
||
| { type: "solid"; color: string; opacity?: number }
|
||
| {
|
||
type: "theme";
|
||
token: string;
|
||
lumMod?: number; // [0, 100],默认 100
|
||
lumOff?: number; // [0, 100],默认 0
|
||
}
|
||
| {
|
||
type: "linearGradient";
|
||
angle: number;
|
||
stops: OpenColorStopWrite[];
|
||
}
|
||
| {
|
||
type: "radialGradient";
|
||
position: OpenRadialGradientPosition;
|
||
stops: OpenColorStopWrite[];
|
||
};
|
||
|
||
interface OpenShadowEffectWrite {
|
||
type: "shadow";
|
||
offsetX: number;
|
||
offsetY: number;
|
||
blur: number;
|
||
color: string;
|
||
opacity: number;
|
||
}
|
||
|
||
interface OpenNodeStyleWrite {
|
||
opacity?: number;
|
||
fill?: OpenPaintWrite;
|
||
stroke?: {
|
||
paint: OpenPaintWrite;
|
||
width?: number;
|
||
dash?: number[];
|
||
lineCap?: "butt" | "round" | "square";
|
||
lineJoin?: "miter" | "round" | "bevel";
|
||
};
|
||
effects?: OpenShadowEffectWrite[];
|
||
}
|
||
```
|
||
|
||
约束:
|
||
|
||
- opacity 范围为 `[0, 1]`。
|
||
- solid paint 的 `color` 与 `opacity` 在 query 后仍保持独立字段,不会合并为
|
||
动态 CSS 表达式。
|
||
- theme 的 `token` 必须能在当前白板主题中解析;
|
||
`lumMod`、`lumOff` 范围均为 `[0, 100]`。token 不存在时在
|
||
Request graph 阶段返回 `themeTokenNotFound`,不会写出部分节点。
|
||
token 长度为 `1~64`,首尾不能有空白,也不能包含空白、控制字符、
|
||
`<`、`>` 或 `;`。
|
||
- query 的 theme paint 还会返回按当前白板主题计算出的 query-only
|
||
`resolvedColor`。调用方写入时只传 `token/lumMod/lumOff`,不传
|
||
`resolvedColor`。
|
||
- 渐变必须至少有一个 stop;`offset` 范围为 `[0, 100]`,单位是百分比。
|
||
- 线性渐变 `angle` 范围为 `[0, 360]`。
|
||
- 径向渐变只接受上述九宫格位置。query 遇到九宫格以外的位置时返回
|
||
`position: "custom"` 并将该节点标为只读。
|
||
- `effects` 最多包含一个 `shadow`;`offsetX/offsetY` 必须是有限数,
|
||
`blur >= 0`,shadow opacity 范围为 `[0, 1]`。
|
||
- stroke width 和 dash 各项必须大于等于 `0`。
|
||
- 一旦提供 stroke,`stroke.paint` 必填。
|
||
- 样式级 `writeSupport` 和 `unsupportedFeatures` 是 query-only。
|
||
- 能在当前白板主题中解析且明暗参数合法的 theme paint 可写。无法解析的主题
|
||
token、越界的主题明暗参数、image paint、blur、unknown effect、叠加 effect
|
||
或自定义径向位置会令节点只读;受支持的 theme、渐变和单个 shadow 本身不会
|
||
令节点只读。
|
||
|
||
主题色示例:
|
||
|
||
```json
|
||
{
|
||
"fill": {
|
||
"type": "theme",
|
||
"token": "ac3",
|
||
"lumMod": 20,
|
||
"lumOff": 80
|
||
},
|
||
"stroke": {
|
||
"paint": {
|
||
"type": "theme",
|
||
"token": "sk1",
|
||
"lumMod": 80,
|
||
"lumOff": 20
|
||
},
|
||
"width": 2
|
||
}
|
||
}
|
||
```
|
||
|
||
示例中的 `ac3`、`sk1` 只是主题 token 示例,不是所有白板都可用的全局枚举。
|
||
调用方只能使用已确认可由当前白板主题解析的 token;无法确认时应改用
|
||
`solid` 颜色。
|
||
|
||
DWS 不提供新增、修改或切换主题的命令。当前白板没有有效主题时,应改用
|
||
`solid`。
|
||
|
||
示例:
|
||
|
||
```json
|
||
{
|
||
"fill": {
|
||
"type": "linearGradient",
|
||
"angle": 35,
|
||
"stops": [
|
||
{ "offset": 0, "color": "#1677ff", "opacity": 0.4 },
|
||
{ "offset": 100, "color": "#69b1ff" }
|
||
]
|
||
},
|
||
"effects": [
|
||
{
|
||
"type": "shadow",
|
||
"offsetX": 8,
|
||
"offsetY": 8,
|
||
"blur": 19,
|
||
"color": "rgba(93,190,172,1)",
|
||
"opacity": 0.5
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
未传 `style` 时使用节点类型的默认样式。调用方如需稳定的视觉结果,应显式传入
|
||
`fill` 和 `stroke`。
|