first commit
This commit is contained in:
@@ -0,0 +1,395 @@
|
||||
# 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`。
|
||||
Reference in New Issue
Block a user