dsh-drawai 0.2.6 → 0.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/lib/client.js +11 -10
- package/lib/index.js +18 -12
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -78,7 +78,7 @@ dsh plugin --profile web add github:fourzkw/dsh-drawai
|
|
|
78
78
|
| **图层** | 列出 / 新建 / 显示隐藏 / 锁定 / 重命名 / 删除(合并到邻层)/ 选中移层 / 设为当前层;隐藏与锁定写入文件 |
|
|
79
79
|
| **顺序** | 置顶 / 上移 / 下移 / 置底 —— 写回时**真的改动文件里单元的先后**(否则重新打开就变回去了) |
|
|
80
80
|
| **自定义数据** | 右键「编辑数据」,按 `key=value` 一行一项改单元属性;按 user object 存回文件,drawio 打开不会丢 |
|
|
81
|
-
| **导出** | SVG / PNG(
|
|
81
|
+
| **导出** | SVG / PNG(4×) / 透明 PNG(4×);「看一眼画布效果」走 DSH 附件服务,**不在工作区落文件** |
|
|
82
82
|
| **回退** | 「编辑 → 撤销 AI 改动」最多可以连着退 8 步 |
|
|
83
83
|
|
|
84
84
|
## 🤖 两个工具 / The two tools
|
|
@@ -211,7 +211,7 @@ id / layer / parent、选区能上报给模型、写回是逐单元的、画布
|
|
|
211
211
|
- **多页**:可切换编辑当前页(视图菜单);其它页保存时原样保留。AI 可用 `diagram_read` / `diagram_apply` 的 `page` 参数指定页。多页的**新建页**尚未实现。
|
|
212
212
|
- 独立 `edgeLabel` 单元只读;`entityRelation` 等其它 edgeStyle、箭头字形、旋转 / 翻转 / 透明、stencil 形状只保留、不渲染;`.drawio.svg` / `.png` / `.html` 内嵌载体不支持。
|
|
213
213
|
- **图片**:内嵌 SVG(`data:image/svg+xml,…`)与内嵌位图(PNG/JPEG/GIF/WebP data URI)都会画出来;**外链 / 相对路径**图片仍按矩形占位,单元原样保留(工作区磁盘上的图片文件画布直接读不到——要复刻请用 `traceImage`)。
|
|
214
|
-
- 导出只有 SVG、PNG(
|
|
214
|
+
- 导出只有 SVG、PNG(4×) 与透明 PNG(4×):没有 PDF。
|
|
215
215
|
- 交互细节:对齐辅助线只跟节点比(不与折点、端点对齐);单条选中的连线不能复制。
|
|
216
216
|
|
|
217
217
|
完整的取舍与实现细节在 [docs/design.md](docs/design.md)。
|
package/lib/client.js
CHANGED
|
@@ -7856,10 +7856,11 @@ window.__ModuleLoader__.load({
|
|
|
7856
7856
|
const url = URL.createObjectURL(new Blob([markup], { type: 'image/svg+xml;charset=utf-8' }))
|
|
7857
7857
|
const image = new Image()
|
|
7858
7858
|
image.onload = () => {
|
|
7859
|
-
// 默认
|
|
7860
|
-
let scale = opts !== undefined && opts !== null && typeof opts.scale === 'number' && opts.scale > 0 ? opts.scale :
|
|
7859
|
+
// 默认 4×(与透明高质量同档)。过大时压到浏览器常见 canvas 上限,避免整图失败。
|
|
7860
|
+
let scale = opts !== undefined && opts !== null && typeof opts.scale === 'number' && opts.scale > 0 ? opts.scale : 4
|
|
7861
7861
|
const transparent = opts !== undefined && opts !== null && opts.transparent === true
|
|
7862
|
-
|
|
7862
|
+
// Chromium / 多数桌面浏览器单边可到 16384;再高容易在部分环境创建失败。
|
|
7863
|
+
const maxEdge = 16384
|
|
7863
7864
|
while (scale > 1 && (width * scale > maxEdge || height * scale > maxEdge)) scale = scale / 2
|
|
7864
7865
|
const canvas = document.createElement('canvas')
|
|
7865
7866
|
canvas.width = Math.max(1, Math.round(width * scale))
|
|
@@ -9307,7 +9308,7 @@ window.__ModuleLoader__.load({
|
|
|
9307
9308
|
const askedName = fromObj && typeof request.name === 'string' && request.name.length > 0 ? request.name : null
|
|
9308
9309
|
const exportIds = fromObj && Array.isArray(request.ids) ? request.ids : null
|
|
9309
9310
|
const transparent = fromObj && request.transparent === true
|
|
9310
|
-
const scale = fromObj && typeof request.scale === 'number' && request.scale > 0 ? request.scale :
|
|
9311
|
+
const scale = fromObj && typeof request.scale === 'number' && request.scale > 0 ? request.scale : 4
|
|
9311
9312
|
const built = buildExportSvg(
|
|
9312
9313
|
exportIds !== null || transparent ? { ids: exportIds !== null ? exportIds : undefined, transparent: transparent } : undefined,
|
|
9313
9314
|
)
|
|
@@ -9359,7 +9360,7 @@ window.__ModuleLoader__.load({
|
|
|
9359
9360
|
return
|
|
9360
9361
|
}
|
|
9361
9362
|
setSaveNote('正在把画布渲成图片给 AI 看…')
|
|
9362
|
-
//
|
|
9363
|
+
// AI 看图用 2×(比手动导出的 4× 更轻);体量不再由客户端预检截断(宿主对 render-result 放开了 body 上限)。
|
|
9363
9364
|
// 部署附件服务若自带 maxImageBytes,仍会在那一侧拒收。
|
|
9364
9365
|
renderPngPayload(built.node, built.width, built.height, 2)
|
|
9365
9366
|
.then((payload) => {
|
|
@@ -11275,12 +11276,12 @@ window.__ModuleLoader__.load({
|
|
|
11275
11276
|
{ hint: '矢量,可再编辑', disabled: empty },
|
|
11276
11277
|
),
|
|
11277
11278
|
item(
|
|
11278
|
-
'导出 PNG(
|
|
11279
|
+
'导出 PNG(4×)',
|
|
11279
11280
|
() => {
|
|
11280
11281
|
setSelectedIds([])
|
|
11281
|
-
setExportRequest('png')
|
|
11282
|
+
setExportRequest({ format: 'png', scale: 4 })
|
|
11282
11283
|
},
|
|
11283
|
-
{ hint: '
|
|
11284
|
+
{ hint: '高质量位图,白/深色底,适合贴到文档里', disabled: empty },
|
|
11284
11285
|
),
|
|
11285
11286
|
item(
|
|
11286
11287
|
'导出透明 PNG(4×)',
|
|
@@ -11297,8 +11298,8 @@ window.__ModuleLoader__.load({
|
|
|
11297
11298
|
),
|
|
11298
11299
|
item(
|
|
11299
11300
|
'导出选中为 PNG',
|
|
11300
|
-
() => setExportRequest({ format: 'png', ids: selectedIds.slice() }),
|
|
11301
|
-
{ hint: '
|
|
11301
|
+
() => setExportRequest({ format: 'png', ids: selectedIds.slice(), scale: 4 }),
|
|
11302
|
+
{ hint: '只导出当前选区(白/深色底,4×)', disabled: empty || selectedIds.length === 0 },
|
|
11302
11303
|
),
|
|
11303
11304
|
item(
|
|
11304
11305
|
'导出选中为透明 PNG',
|
package/lib/index.js
CHANGED
|
@@ -944,15 +944,14 @@ async function applyOps(doc, ops, out, opctx) {
|
|
|
944
944
|
}
|
|
945
945
|
|
|
946
946
|
if (kind === 'addNode') {
|
|
947
|
-
// `
|
|
948
|
-
//
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
throw new Error('ops[' + i + '] addNode needs a non-empty string "label"(画图不带字的 svg 节点可以省 label,但要给 "svg" 内容)')
|
|
947
|
+
// 标签在 drawio 里是可选的(`value=""` = 没有文字的单元)。装饰面板 / 底框 /
|
|
948
|
+
// 内嵌 SVG 都可以省 label 或给 "";没给就当空串。给了就必须是 string。
|
|
949
|
+
let label = ''
|
|
950
|
+
if (has(op, 'label') && op.label !== null && op.label !== undefined) {
|
|
951
|
+
if (typeof op.label !== 'string') {
|
|
952
|
+
throw new Error('ops[' + i + '] addNode "label" must be a string(装饰面板可省或给 "")')
|
|
953
|
+
}
|
|
954
|
+
label = op.label
|
|
956
955
|
}
|
|
957
956
|
let id = typeof op.id === 'string' && op.id.length > 0 ? op.id : undefined
|
|
958
957
|
if (id !== undefined && findNode(id) >= 0) {
|
|
@@ -969,17 +968,22 @@ async function applyOps(doc, ops, out, opctx) {
|
|
|
969
968
|
// 形状/配色是糖,落盘只有 style 键;不给就是 drawio 缺省(空串 = 普通矩形 + 缺省配色)。
|
|
970
969
|
style: style,
|
|
971
970
|
// svg 节点缺省是**正方形**:按标签文字估宽(estimateWidth)对图没有意义。
|
|
971
|
+
// 空 label 的装饰面板也请显式给 w/h,否则会落到最短标签估宽(130)。
|
|
972
972
|
w: numberOr(op.w, svgNode ? DEFAULT_SVG_W : estimateWidth(label)),
|
|
973
973
|
h: numberOr(op.h, svgNode ? DEFAULT_SVG_H : DEFAULT_H),
|
|
974
974
|
}
|
|
975
975
|
if (typeof op.layer === 'string' && op.layer.length > 0) node.layer = resolveLayerRef(op.layer, 'ops[' + i + '] addNode layer')
|
|
976
|
-
//
|
|
976
|
+
// 位置:只有显式给了坐标才写入。缺省写 (0,0) 会让 placeMissing 以为"坐标齐全"而不补位,
|
|
977
977
|
// 新节点就会堆在原点压住别人。
|
|
978
978
|
if (has(op, 'x')) node.x = numberOr(op.x, 0)
|
|
979
979
|
if (has(op, 'y')) node.y = numberOr(op.y, 0)
|
|
980
980
|
doc.nodes.push(node)
|
|
981
981
|
recordCreated(id, 'node', label)
|
|
982
|
-
notes.push(
|
|
982
|
+
notes.push(
|
|
983
|
+
'+ node ' + id +
|
|
984
|
+
(svgNode ? ' [svg]' : label.length > 0 ? ' "' + label + '"' : ' (empty label)') +
|
|
985
|
+
(has(op, 'x') || has(op, 'y') ? ' at explicit coords' : ' (position pending)'),
|
|
986
|
+
)
|
|
983
987
|
continue
|
|
984
988
|
}
|
|
985
989
|
|
|
@@ -2018,6 +2022,8 @@ diagram_read —— 返回里的 path 就是它(这两条是一致的,同一
|
|
|
2018
2022
|
- **改一组用 ids**:{op:"setStyle", ids:["n1","n2","n5"], style:"green"} —— setStyle / setLabel /
|
|
2019
2023
|
move / remove 都收 ids,不要为了"把这几个改成绿色"发 12 个 op。批量 move 只收 dx/dy
|
|
2020
2024
|
(给一个绝对 x/y 等于把它们叠成一摞,宿主会直接拒绝)。
|
|
2025
|
+
- **addNode 的 label 可省或给 ""**:装饰面板 / 底框 / 纯色块不需要字时直接省掉;空 label 时请显式给 w/h
|
|
2026
|
+
(否则按最短标签估宽 130)。有字的节点照常写 label。
|
|
2021
2027
|
- **引用刚建的那个用 as**:{op:"addNode", label:"开始", as:"start"} 之后,同一个 ops 数组里
|
|
2022
2028
|
from/to/id 可以直接写 "start"。id 省略时是自动分配的(n 几/e 几),猜编号在非空画布上必错。
|
|
2023
2029
|
- **返回值里看 created/changed/removed**:新建单元的 id(含自动分配的)在这里,接着引用它们
|
|
@@ -2072,7 +2078,7 @@ diagram_read —— 返回里的 path 就是它(这两条是一致的,同一
|
|
|
2072
2078
|
浏览器按 XML 解析会直接丢弃这份图 —— 屏幕上什么都没有,也不报错)。
|
|
2073
2079
|
· 默认 **imageAspect=0 = 拉伸铺满**节点框;想让图形等比缩放居中就加 keys:{imageAspect:1}
|
|
2074
2080
|
(那就把 w/h 设成图形的比例,否则四周会留白)。
|
|
2075
|
-
· svg
|
|
2081
|
+
· svg 节点通常不带 label(画图不带字);要图上叠字就照常给 label。普通矩形/面板同样可以省 label。
|
|
2076
2082
|
· 颜色写在 SVG 自己身上(fill/stroke)—— 配色参数对它是无效的(图片不受 fillColor/strokeColor 影响)。
|
|
2077
2083
|
· 内容上限 250000 字符;**别放位图/base64**(那是图片不是图形,本画布画不出来)。
|
|
2078
2084
|
· 改内容只能整段替换(没有"改某一根线"的 op):先 read 拿回当前 svg,改完整段写回。
|