@next-bricks/diagram 0.68.8 → 0.68.10

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.
Files changed (85) hide show
  1. package/dist/bricks.json +3 -3
  2. package/dist/chunks/1265.bf280e6d.js +3 -0
  3. package/dist/chunks/1265.bf280e6d.js.map +1 -0
  4. package/dist/chunks/1889.fa8b5dbe.js +2 -0
  5. package/dist/chunks/1889.fa8b5dbe.js.map +1 -0
  6. package/dist/chunks/3171.8057c0f4.js +2 -0
  7. package/dist/chunks/3171.8057c0f4.js.map +1 -0
  8. package/dist/chunks/{3654.59bd8992.js → 3654.6a028b09.js} +3 -3
  9. package/dist/chunks/{3654.59bd8992.js.map → 3654.6a028b09.js.map} +1 -1
  10. package/dist/chunks/{3746.591c50d8.js → 3746.7fad241d.js} +2 -2
  11. package/dist/chunks/{3746.591c50d8.js.map → 3746.7fad241d.js.map} +1 -1
  12. package/dist/chunks/515.23d8419d.js +2 -0
  13. package/dist/chunks/515.23d8419d.js.map +1 -0
  14. package/dist/chunks/5399.d786845a.js +2 -0
  15. package/dist/chunks/5399.d786845a.js.map +1 -0
  16. package/dist/chunks/5552.7718c4ca.js +2 -0
  17. package/dist/chunks/5552.7718c4ca.js.map +1 -0
  18. package/dist/chunks/577.c9c65352.js.map +1 -1
  19. package/dist/chunks/6376.a8716290.js +2 -0
  20. package/dist/chunks/6376.a8716290.js.map +1 -0
  21. package/dist/chunks/7920.367555e2.js +3 -0
  22. package/dist/chunks/7920.367555e2.js.map +1 -0
  23. package/dist/chunks/9118.8a9d6592.js +3 -0
  24. package/dist/chunks/9118.8a9d6592.js.LICENSE.txt +11 -0
  25. package/dist/chunks/9118.8a9d6592.js.map +1 -0
  26. package/dist/chunks/948.e308c274.js +3 -0
  27. package/dist/chunks/948.e308c274.js.map +1 -0
  28. package/dist/chunks/editable-label.667b04d5.js.map +1 -1
  29. package/dist/chunks/eo-diagram.78450578.js.map +1 -1
  30. package/dist/chunks/eo-display-canvas.2a43ce91.js.map +1 -1
  31. package/dist/chunks/eo-draw-canvas.e01342d6.js.map +1 -1
  32. package/dist/chunks/experimental-node.2f4d802a.js.map +1 -1
  33. package/dist/chunks/main.91a8e473.js +2 -0
  34. package/dist/chunks/main.91a8e473.js.map +1 -0
  35. package/dist/examples.json +10 -7
  36. package/dist/index.f358949f.js +2 -0
  37. package/dist/index.f358949f.js.map +1 -0
  38. package/dist/manifest.json +359 -220
  39. package/dist/types.json +5163 -5163
  40. package/dist-types/diagram/index.d.ts +48 -1
  41. package/dist-types/diagram/interfaces.d.ts +3 -3
  42. package/dist-types/display-canvas/index.d.ts +37 -3
  43. package/dist-types/draw-canvas/index.d.ts +75 -7
  44. package/dist-types/draw-canvas/interfaces.d.ts +3 -3
  45. package/dist-types/editable-label/index.d.ts +14 -1
  46. package/dist-types/experimental-node/index.d.ts +11 -1
  47. package/docs/editable-label.md +71 -1
  48. package/docs/editable-label.react.md +100 -0
  49. package/docs/eo-diagram.md +54 -87
  50. package/docs/eo-diagram.react.md +399 -0
  51. package/docs/eo-display-canvas.md +60 -21
  52. package/docs/eo-display-canvas.react.md +376 -0
  53. package/docs/eo-draw-canvas.md +95 -40
  54. package/docs/eo-draw-canvas.react.md +989 -0
  55. package/docs/experimental-node.md +156 -0
  56. package/docs/experimental-node.react.md +157 -0
  57. package/package.json +2 -2
  58. package/dist/chunks/1265.55a02b5a.js +0 -3
  59. package/dist/chunks/1265.55a02b5a.js.map +0 -1
  60. package/dist/chunks/1889.9e9ad16a.js +0 -2
  61. package/dist/chunks/1889.9e9ad16a.js.map +0 -1
  62. package/dist/chunks/3171.3bd2c8f0.js +0 -2
  63. package/dist/chunks/3171.3bd2c8f0.js.map +0 -1
  64. package/dist/chunks/4667.53203ccd.js +0 -2
  65. package/dist/chunks/4667.53203ccd.js.map +0 -1
  66. package/dist/chunks/4837.32dece7c.js +0 -2
  67. package/dist/chunks/4837.32dece7c.js.map +0 -1
  68. package/dist/chunks/5399.b1b4981d.js +0 -2
  69. package/dist/chunks/5399.b1b4981d.js.map +0 -1
  70. package/dist/chunks/5552.e3e728b7.js +0 -2
  71. package/dist/chunks/5552.e3e728b7.js.map +0 -1
  72. package/dist/chunks/7218.e0bf22af.js +0 -2
  73. package/dist/chunks/7218.e0bf22af.js.map +0 -1
  74. package/dist/chunks/7920.df65d810.js +0 -3
  75. package/dist/chunks/7920.df65d810.js.map +0 -1
  76. package/dist/chunks/948.83e23068.js +0 -3
  77. package/dist/chunks/948.83e23068.js.map +0 -1
  78. package/dist/chunks/main.4630d30e.js +0 -2
  79. package/dist/chunks/main.4630d30e.js.map +0 -1
  80. package/dist/index.c366c6da.js +0 -2
  81. package/dist/index.c366c6da.js.map +0 -1
  82. /package/dist/chunks/{1265.55a02b5a.js.LICENSE.txt → 1265.bf280e6d.js.LICENSE.txt} +0 -0
  83. /package/dist/chunks/{3654.59bd8992.js.LICENSE.txt → 3654.6a028b09.js.LICENSE.txt} +0 -0
  84. /package/dist/chunks/{7920.df65d810.js.LICENSE.txt → 7920.367555e2.js.LICENSE.txt} +0 -0
  85. /package/dist/chunks/{948.83e23068.js.LICENSE.txt → 948.e308c274.js.LICENSE.txt} +0 -0
@@ -1,14 +1,17 @@
1
1
  {
2
- "diagram.editable-label": {
3
- "doc": "构件 `diagram.editable-label`\n\n## Examples\n\n### Basic\n\n```yaml preview\nbrick: diagram.editable-label\nproperties:\n type: line\n label: Relation\nevents:\n label.change:\n action: message.success\n args:\n - \"<% `Label changed to: ${EVENT.detail}` %>\"\n# -- YAML DELIMITER (1nbbm8) --\n# <diagram.editable-label\n# type=\"line\"\n# label=\"Relation\"\n# id=\"brick-1\"\n# ></diagram.editable-label>\n# \n# <script>\n# const brick_1 = document.getElementById(\"brick-1\");\n# brick_1.addEventListener(\"label.change\", (e) => {\n# const message = document.createElement(\"basic.show-notification\");\n# message.resolve({\n# type: \"success\",\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# message: \"<% `Label changed to: ${EVENT.detail}` %>\",\n# });\n# });\n# </script>\n# \n```\n"
4
- },
5
2
  "eo-diagram": {
6
- "doc": "构件 `eo-diagram`\n\n## Examples\n\n### Basic\n\n```yaml preview minHeight=\"600px\"\nbrick: div\nproperties:\n style:\n position: fixed\n height: 100vh\n width: 100vw\n top: 0px\n left: 0px\ncontext:\n - name: activeTarget\n value: null\n - name: nodes\n value:\n - id: kspacey\n label: Kevin Spacey\n - id: swilliams\n label: Saul Williams\n - id: bpitt\n label: Brad Pitt\n # - id: hford\n # label: Harrison Ford\n - id: lwilson\n label: Luke Wilson\n - id: kbacon\n label: Kevin Bacon\n - name: edges\n value:\n - source: kspacey\n target: swilliams\n - source: swilliams\n target: kbacon\n - source: bpitt\n target: kbacon\n # - source: hford\n # target: lwilson\n - source: lwilson\n target: kbacon\nchildren:\n - brick: eo-button\n properties:\n textContent: Add Harrison Ford\n events:\n click:\n - action: context.replace\n args:\n - nodes\n - |\n <%\n CTX.nodes.concat({\n id: \"hford\",\n label: \"Harrison Ford\",\n })\n %>\n - action: context.replace\n args:\n - edges\n - |\n <%\n CTX.edges.concat({\n source: \"hford\",\n target: \"lwilson\",\n })\n %>\n - target: _self\n properties:\n style:\n visibility: hidden\n - brick: eo-button\n properties:\n textContent: Remove Kevin Spacey\n events:\n click:\n - action: context.replace\n args:\n - nodes\n - |\n <%\n CTX.nodes.filter(node => node.id !== \"kspacey\")\n %>\n - action: context.replace\n args:\n - edges\n - |\n <%\n CTX.edges.filter(({ source, target }) => source !== \"kspacey\" && target !== \"kspacey\")\n %>\n - target: _self\n properties:\n style:\n visibility: hidden\n - brick: eo-diagram\n properties:\n layout: dagre\n nodes: <%= CTX.nodes %>\n edges: <%= CTX.edges %>\n lines:\n - arrow: true\n activeTarget: <%= CTX.activeTarget %>\n nodeBricks:\n - useBrick:\n # if: <% DATA.node.id !== \"kbacon\" %>\n brick: div\n properties:\n style: |\n <%=\n {\n width: \"180px\",\n height: \"100px\",\n border: \"2px solid green\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n outline: CTX.activeTarget?.type === \"node\" && CTX.activeTarget.nodeId === DATA.node.id ? \"2px solid orange\" : \"none\",\n outlineOffset: \"2px\",\n }\n %>\n children:\n - brick: span\n properties:\n textContent: <% DATA.node.label %>\n events:\n click:\n action: context.replace\n args:\n - activeTarget\n - type: node\n nodeId: <% DATA.node.id %>\n events:\n activeTarget.change:\n action: context.replace\n args:\n - activeTarget\n - <% EVENT.detail %>\n# -- YAML DELIMITER (1nbbm8) --\n# <div style=\"position: fixed; height: 100vh; width: 100vw; top: 0px; left: 0px\">\n# <eo-button id=\"brick-1\">Add Harrison Ford</eo-button>\n# <eo-button id=\"brick-2\">Remove Kevin Spacey</eo-button>\n# <eo-diagram layout=\"dagre\" id=\"brick-3\"></eo-diagram>\n# </div>\n# \n# <script>\n# const brick_1 = document.getElementById(\"brick-1\");\n# brick_1.addEventListener(\"click\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_1.addEventListener(\"click\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_1.addEventListener(\"click\", (e) => {\n# const brick = e.target;\n# brick.style = {\n# visibility: \"hidden\",\n# };\n# });\n# \n# const brick_2 = document.getElementById(\"brick-2\");\n# brick_2.addEventListener(\"click\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_2.addEventListener(\"click\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_2.addEventListener(\"click\", (e) => {\n# const brick = e.target;\n# brick.style = {\n# visibility: \"hidden\",\n# };\n# });\n# \n# const brick_3 = document.getElementById(\"brick-3\");\n# brick_3.nodes = \"<%= CTX.nodes %>\";\n# brick_3.edges = \"<%= CTX.edges %>\";\n# brick_3.lines = [\n# {\n# arrow: true,\n# },\n# ];\n# brick_3.activeTarget = \"<%= CTX.activeTarget %>\";\n# brick_3.nodeBricks = [\n# {\n# useBrick: {\n# brick: \"div\",\n# properties: {\n# style:\n# '<%=\\n {\\n width: \"180px\",\\n height: \"100px\",\\n border: \"2px solid green\",\\n display: \"flex\",\\n alignItems: \"center\",\\n justifyContent: \"center\",\\n outline: CTX.activeTarget?.type === \"node\" && CTX.activeTarget.nodeId === DATA.node.id ? \"2px solid orange\" : \"none\",\\n outlineOffset: \"2px\",\\n }\\n%>\\n',\n# },\n# children: [\n# {\n# brick: \"span\",\n# properties: {\n# textContent: \"<% DATA.node.label %>\",\n# },\n# },\n# ],\n# events: {\n# click: {\n# action: \"context.replace\",\n# args: [\n# \"activeTarget\",\n# {\n# type: \"node\",\n# nodeId: \"<% DATA.node.id %>\",\n# },\n# ],\n# },\n# },\n# },\n# },\n# ];\n# brick_3.addEventListener(\"activeTarget.change\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# </script>\n# \n```\n\n### Page Architecture\n\n```yaml preview minHeight=\"600px\"\nbrick: div\nproperties:\n style:\n position: fixed\n height: 100vh\n width: 100vw\n top: 0px\n left: 0px\ncontext:\n - name: activeTarget\n value: null\n - name: tempNodeId\n - name: targetNode\n - name: editingLabelNodes\n value: []\n - name: editingLabelEdges\n value: []\n - name: nodes\n value:\n - type: board\n id: 60bf6078b095f\n name: Visual Builder\n depth: 0\n parentId:\n description: 某某产品\n - type: page\n id: 60bf60848d6d2\n name: 项目列表\n depth: 1\n parentId: 60bf6078b095f\n description: 列表页\n - type: page\n id: 60d533eba4ab2\n name: ccc\n depth: 1\n parentId: 60bf6078b095f\n description: cccc\n - type: link\n id: 60bf6091a1089\n name: 新建项目\n pageType: information:form:basic-form\n description: 新建页213\n to:\n \"@\":\n description: 无项目\n instanceId: 60c5fea301b32\n description: 新建页213\n instanceId: 60bf6091a1089\n module: []\n name: 新建项目\n pageType: information:form:basic-form\n depth: -1\n parentId:\n - type: link\n id: 60bf60a258613\n name: 项目首页-路由管理\n description: 路由管理\n to:\n description: 路由管理\n instanceId: 60bf60a258613\n module:\n - instanceId: 60bf609b26889\n name: Project\n name: 项目首页-路由管理\n depth: -1\n parentId:\n - type: link\n id: 60c5f39a2c2e1\n name: Launchpad 出厂配置\n description: Launchpad 出厂配置\n to:\n description: Launchpad 出厂配置\n instanceId: 60c5f39a2c2e1\n module: []\n name: Launchpad 出厂配置\n depth: -1\n parentId:\n - name: edges\n value:\n - type: menu\n source: 60bf6078b095f\n target: 60bf60848d6d2\n - type: menu\n source: 60bf6078b095f\n target: 60d533eba4ab2\n - type: link\n source: 60bf60848d6d2\n target: 60bf6091a1089\n description: 无项目\n - type: link\n source: 60bf60848d6d2\n target: 60bf60a258613\n - type: link\n source: 60bf60848d6d2\n target: 60c5f39a2c2e1\nchildren:\n - brick: eo-diagram\n properties:\n layout: dagre\n nodes: <%= CTX.nodes %>\n edges: <%= CTX.edges %>\n lines:\n - edgeType: link\n strokeColor: var(--theme-blue-color)\n arrow: true\n interactable: true\n label:\n useBrick:\n brick: diagram.editable-label\n properties:\n label: <% DATA.edge.description %>\n type: line\n events:\n label.change:\n if: <% (DATA.edge.description || \"\") !== (EVENT.detail || \"\") %>\n action: context.replace\n args:\n - edges\n - |-\n <%\n CTX.edges.map((edge) =>\n edge.source === DATA.edge.source &&\n edge.target === DATA.edge.target\n ? { ...edge, description: EVENT.detail }\n : edge\n )\n %>\n label.editing.change:\n action: context.replace\n args:\n - editingLabelEdges\n - |-\n <%\n EVENT.detail\n ? CTX.editingLabelEdges.concat(\n `${DATA.edge.source}-:-${DATA.edge.target}`\n )\n : CTX.editingLabelEdges.filter(\n (id) =>\n id !== `${DATA.edge.source}-:-${DATA.edge.target}`\n )\n %>\n click:\n action: context.replace\n args:\n - activeTarget\n - type: edge\n edge: <% DATA.edge %>\n - edgeType: menu\n strokeColor: var(--palette-gray-5)\n arrow: true\n interactable: true\n layoutOptions:\n nodePadding: [4, 10, 10]\n activeTarget: <%= CTX.activeTarget %>\n disableKeyboardAction: <%= CTX.editingLabelNodes.length > 0 || CTX.editingLabelEdges.length > 0 %>\n connectNodes:\n arrow: true\n strokeColor: |-\n <%\n DATA.source.type === \"board\"\n ? \"var(--palette-gray-5)\"\n : \"var(--theme-blue-color)\"\n %>\n nodeBricks:\n - useBrick:\n brick: visual-builder.page-arch-node\n properties:\n label: <% DATA.node.name %>\n type: <% DATA.node.type %>\n autoFocusOnce: |\n <% DATA.node.$temp ? DATA.node.id : undefined %>\n active: <%= CTX.activeTarget?.type === \"node\" && CTX.activeTarget.nodeId === DATA.node.id %>\n events:\n click:\n action: context.replace\n args:\n - activeTarget\n - type: node\n nodeId: <% DATA.node.id %>\n label.editing.change:\n action: context.replace\n args:\n - editingLabelNodes\n - |\n <%\n EVENT.detail\n ? CTX.editingLabelNodes.concat(DATA.node.id)\n : CTX.editingLabelNodes.filter(\n id => id !== DATA.node.id\n )\n %>\n label.change:\n - if: <% CTX.nodes.find(({id}) => id === DATA.node.id)?.$temp %>\n action: context.replace\n args:\n args:\n - nodes\n - |\n <%\n CTX.nodes.map((node) => (\n node.id === DATA.node.id\n ? { ...node, $temp: false, name: EVENT.detail }\n : node\n ))\n %>\n # Take reaction only if the label has been changed\n - if: <% CTX.nodes.find(({id}) => id === DATA.node.id)?.name !== EVENT.detail %>\n action: context.replace\n args:\n - nodes\n - |\n <%\n CTX.nodes.map((node) => (\n node.id === DATA.node.id\n ? { ...node, name: EVENT.detail }\n : node\n ))\n %>\n child.append:\n - action: context.replace\n args:\n - tempNodeId\n - <% _.uniqueId('$temp-') %>\n - action: context.replace\n args:\n - nodes\n - |\n <% CTX.nodes.concat({ id: CTX.tempNodeId, name: \"未命名\", $temp: true }) %>\n - action: context.replace\n args:\n - edges\n - |\n <% CTX.edges.concat({ source: DATA.node.id, target: CTX.tempNodeId, name: \"未命名\", type: \"link\", $temp: true }) %>\n - action: context.replace\n args:\n - activeTarget\n - type: node\n nodeId: <% CTX.tempNodeId %>\n events:\n activeTarget.change:\n action: context.replace\n args:\n - activeTarget\n - <% EVENT.detail %>\n node.delete:\n - action: context.replace\n args:\n - targetNode\n - <% EVENT.detail %>\n - useProvider: basic.show-dialog\n args:\n - type: delete\n title: Delete Confirm\n content: Please enter {{ expect }} to delete the node.\n expect: <% EVENT.detail.name || \"未命名\" %>\n callback:\n success:\n - action: context.replace\n args:\n - nodes\n - |-\n <%\n CTX.nodes.filter(\n ({ id }) => id !== CTX.targetNode.id\n )\n %>\n - action: context.replace\n args:\n - edges\n - |-\n <%\n CTX.edges.filter(\n ({ source, target }) =>\n source !== CTX.targetNode.id &&\n target !== CTX.targetNode.id\n )\n %>\n edge.delete:\n action: context.replace\n args:\n - edges\n - |-\n <%\n CTX.edges.filter(\n ({ source, target }) =>\n source !== EVENT.detail.source ||\n target !== EVENT.detail.target\n )\n %>\n line.click:\n action: context.replace\n args:\n - activeTarget\n - type: edge\n edge: <% EVENT.detail.edge %>\n line.dblclick:\n target: _self\n method: callOnLineLabel\n args:\n - <% `${EVENT.detail.id}-center` %>\n - enableEditing\n nodes.connect:\n if: |-\n <%\n EVENT.detail.target.type !== \"board\" &&\n !CTX.edges.some(\n (edge) =>\n edge.source === EVENT.detail.source.id &&\n edge.target === EVENT.detail.target.id\n )\n %>\n action: context.replace\n args:\n - edges\n - |-\n <%\n CTX.edges.concat({\n source: EVENT.detail.source.id,\n target: EVENT.detail.target.id,\n type:\n EVENT.detail.source.type === \"board\"\n ? \"menu\"\n : \"link\",\n })\n %>\n# -- YAML DELIMITER (1nbbm8) --\n# <div style=\"position: fixed; height: 100vh; width: 100vw; top: 0px; left: 0px\">\n# <eo-diagram layout=\"dagre\" disable-keyboard-action id=\"brick-1\"></eo-diagram>\n# </div>\n# \n# <script>\n# const brick_1 = document.getElementById(\"brick-1\");\n# brick_1.nodes = \"<%= CTX.nodes %>\";\n# brick_1.edges = \"<%= CTX.edges %>\";\n# brick_1.lines = [\n# {\n# edgeType: \"link\",\n# strokeColor: \"var(--theme-blue-color)\",\n# arrow: true,\n# interactable: true,\n# label: {\n# useBrick: {\n# brick: \"diagram.editable-label\",\n# properties: {\n# label: \"<% DATA.edge.description %>\",\n# type: \"line\",\n# },\n# events: {\n# \"label.change\": {\n# if: '<% (DATA.edge.description || \"\") !== (EVENT.detail || \"\") %>',\n# action: \"context.replace\",\n# args: [\n# \"edges\",\n# \"<%\\n CTX.edges.map((edge) =>\\n edge.source === DATA.edge.source &&\\n edge.target === DATA.edge.target\\n ? { ...edge, description: EVENT.detail }\\n : edge\\n )\\n%>\",\n# ],\n# },\n# \"label.editing.change\": {\n# action: \"context.replace\",\n# args: [\n# \"editingLabelEdges\",\n# \"<%\\n EVENT.detail\\n ? CTX.editingLabelEdges.concat(\\n `${DATA.edge.source}-:-${DATA.edge.target}`\\n )\\n : CTX.editingLabelEdges.filter(\\n (id) =>\\n id !== `${DATA.edge.source}-:-${DATA.edge.target}`\\n )\\n%>\",\n# ],\n# },\n# click: {\n# action: \"context.replace\",\n# args: [\n# \"activeTarget\",\n# {\n# type: \"edge\",\n# edge: \"<% DATA.edge %>\",\n# },\n# ],\n# },\n# },\n# },\n# },\n# },\n# {\n# edgeType: \"menu\",\n# strokeColor: \"var(--palette-gray-5)\",\n# arrow: true,\n# interactable: true,\n# },\n# ];\n# brick_1.layoutOptions = {\n# nodePadding: [4, 10, 10],\n# };\n# brick_1.activeTarget = \"<%= CTX.activeTarget %>\";\n# brick_1.connectNodes = {\n# arrow: true,\n# strokeColor:\n# '<%\\n DATA.source.type === \"board\"\\n ? \"var(--palette-gray-5)\"\\n : \"var(--theme-blue-color)\"\\n%>',\n# };\n# brick_1.nodeBricks = [\n# {\n# useBrick: {\n# brick: \"visual-builder.page-arch-node\",\n# properties: {\n# label: \"<% DATA.node.name %>\",\n# type: \"<% DATA.node.type %>\",\n# autoFocusOnce: \"<% DATA.node.$temp ? DATA.node.id : undefined %>\\n\",\n# active:\n# '<%= CTX.activeTarget?.type === \"node\" && CTX.activeTarget.nodeId === DATA.node.id %>',\n# },\n# events: {\n# click: {\n# action: \"context.replace\",\n# args: [\n# \"activeTarget\",\n# {\n# type: \"node\",\n# nodeId: \"<% DATA.node.id %>\",\n# },\n# ],\n# },\n# \"label.editing.change\": {\n# action: \"context.replace\",\n# args: [\n# \"editingLabelNodes\",\n# \"<%\\n EVENT.detail\\n ? CTX.editingLabelNodes.concat(DATA.node.id)\\n : CTX.editingLabelNodes.filter(\\n id => id !== DATA.node.id\\n )\\n%>\\n\",\n# ],\n# },\n# \"label.change\": [\n# {\n# if: \"<% CTX.nodes.find(({id}) => id === DATA.node.id)?.$temp %>\",\n# action: \"context.replace\",\n# args: [\n# \"nodes\",\n# \"<%\\n CTX.nodes.map((node) => (\\n node.id === DATA.node.id\\n ? { ...node, $temp: false, name: EVENT.detail }\\n : node\\n ))\\n%>\\n\",\n# ],\n# },\n# {\n# if: \"<% CTX.nodes.find(({id}) => id === DATA.node.id)?.name !== EVENT.detail %>\",\n# action: \"context.replace\",\n# args: [\n# \"nodes\",\n# \"<%\\n CTX.nodes.map((node) => (\\n node.id === DATA.node.id\\n ? { ...node, name: EVENT.detail }\\n : node\\n ))\\n%>\\n\",\n# ],\n# },\n# ],\n# \"child.append\": [\n# {\n# action: \"context.replace\",\n# args: [\"tempNodeId\", \"<% _.uniqueId('$temp-') %>\"],\n# },\n# {\n# action: \"context.replace\",\n# args: [\n# \"nodes\",\n# '<% CTX.nodes.concat({ id: CTX.tempNodeId, name: \"未命名\", $temp: true }) %>\\n',\n# ],\n# },\n# {\n# action: \"context.replace\",\n# args: [\n# \"edges\",\n# '<% CTX.edges.concat({ source: DATA.node.id, target: CTX.tempNodeId, name: \"未命名\", type: \"link\", $temp: true }) %>\\n',\n# ],\n# },\n# {\n# action: \"context.replace\",\n# args: [\n# \"activeTarget\",\n# {\n# type: \"node\",\n# nodeId: \"<% CTX.tempNodeId %>\",\n# },\n# ],\n# },\n# ],\n# },\n# },\n# },\n# ];\n# brick_1.addEventListener(\"activeTarget.change\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_1.addEventListener(\"node.delete\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_1.addEventListener(\"node.delete\", (e) => {\n# const provider = document.createElement(\"basic.show-dialog\");\n# const promise = Promise.resolve(\n# provider.resolve({\n# type: \"delete\",\n# title: \"Delete Confirm\",\n# content: \"Please enter {{ expect }} to delete the node.\",\n# expect: '<% EVENT.detail.name || \"未命名\" %>',\n# })\n# );\n# promise.then((r) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# promise.then((r) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# });\n# brick_1.addEventListener(\"edge.delete\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_1.addEventListener(\"line.click\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_1.addEventListener(\"line.dblclick\", (e) => {\n# const brick = e.target;\n# brick.callOnLineLabel(\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# \"<% `${EVENT.detail.id}-center` %>\",\n# \"enableEditing\"\n# );\n# });\n# brick_1.addEventListener(\"nodes.connect\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# </script>\n# \n```\n\n### Force\n\n```yaml preview minHeight=\"600px\"\nbrick: div\nproperties:\n style:\n position: fixed\n height: 100vh\n width: 100vw\n top: 0px\n left: 0px\ncontext:\n - name: activeTarget\n value: null\n - name: nodes\n value:\n - id: 产品评价\n - id: 产品线\n - id: 用户角色\n - id: 模型视图\n - id: 产品\n - id: 业务场景\n - id: 业务规则\n - id: 模型\n - id: 产品模块\n - id: 产品价值点\n - id: 工作流\n - id: 测试用例\n - id: 功能点\n # - id: 其他\n - name: edges\n value:\n - source: 产品\n target: 产品评价\n sourceName: 评价列表\n targetName: 所属产品\n sourceConstraints:\n required: true\n targetConstraints:\n multiple: true\n - source: 产品\n target: 产品线\n sourceName: 所属产品线\n targetName: 产品列表\n sourceConstraints:\n multiple: true\n targetConstraints:\n required: true\n - source: 产品\n target: 用户角色\n sourceName: 负责人\n targetName: 负责的产品\n sourceConstraints:\n multiple: true\n targetConstraints:\n multiple: true\n - source: 产品\n target: 模型视图\n sourceName: 模型视图列表\n targetName: 所属产品\n sourceConstraints:\n required: true\n targetConstraints:\n multiple: true\n - source: 产品\n target: 业务场景\n sourceName: 业务场景列表\n targetName: 所属产品\n sourceConstraints:\n required: true\n targetConstraints:\n multiple: true\n - source: 业务场景\n target: 业务场景\n - source: 业务场景\n target: 业务规则\n sourceName: 业务规则列表\n targetName: 所属业务场景\n sourceConstraints:\n required: true\n targetConstraints:\n multiple: true\n - source: 业务场景\n target: 用户角色\n sourceName: 负责人\n targetName: 负责的业务场景\n sourceConstraints:\n multiple: true\n targetConstraints:\n multiple: true\n - source: 产品\n target: 模型\n sourceName: 模型列表\n targetName: 关联的产品\n sourceConstraints:\n required: true\n targetConstraints:\n multiple: true\n - source: 产品\n target: 产品模块\n sourceName: 模块列表\n targetName: 所属产品\n sourceConstraints:\n required: true\n targetConstraints:\n multiple: true\n - source: 产品\n target: 产品价值点\n sourceName: 价值点列表\n targetName: 所属产品\n sourceConstraints:\n required: true\n targetConstraints:\n multiple: true\n - source: 业务场景\n target: 产品价值点\n sourceName: 价值点列表\n targetName: 关联的业务场景\n - source: 业务场景\n target: 工作流\n - source: 业务规则\n target: 工作流\n - source: 产品模块\n target: 产品模块\n - source: 产品模块\n target: 测试用例\n sourceName: 测试用例列表\n targetName: 所属产品模块\n sourceConstraints:\n multiple: true\n targetConstraints:\n multiple: true\n - source: 产品模块\n target: 功能点\n sourceName: 功能点列表\n targetName: 所属产品模块\n sourceConstraints:\n required: true\n targetConstraints:\n multiple: true\n - source: 测试用例\n target: 功能点\n sourceName: 关联的功能点\n targetName: 关联的测试用例\n sourceConstraints:\n multiple: true\n targetConstraints:\n multiple: true\n # - source: 产品线\n # target: 模型视图\nchildren:\n - brick: eo-diagram\n properties:\n layout: force\n dragNodes: {}\n nodes: <%= CTX.nodes %>\n edges: <%= CTX.edges %>\n activeTarget: <%= CTX.activeTarget %>\n layoutOptions:\n # nodePadding: 5\n dummyNodesOnEdges: 1\n collide:\n dummyRadius: 10\n radiusDiff: 40\n # rankdir: LR\n # acyclicer: greedy\n # align: DL\n lines:\n - label:\n - useBrick:\n brick: span\n properties:\n hidden: <%= CTX.activeTarget?.type !== \"node\" || (DATA.edge.source !== CTX.activeTarget.nodeId && DATA.edge.target !== CTX.activeTarget.nodeId) %>\n textContent: |\n <%= DATA.edge.source === CTX.activeTarget?.nodeId ? DATA.edge.sourceName : DATA.edge.target === CTX.activeTarget?.nodeId ? DATA.edge.targetName : \"\" %>\n style:\n color: var(--palette-gray-6)\n overrides:\n activeRelated:\n strokeColor: var(--palette-blue-4)\n nodeBricks:\n - useBrick:\n # if: <% DATA.node.id !== \"kbacon\" %>\n brick: div\n properties:\n style: |\n <%=\n {\n width: \"160px\",\n height: \"50px\",\n background: \"var(--palette-green-1)\",\n border: \"1px solid var(--palette-gray-4)\",\n borderRadius: \"8px\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n outline: CTX.activeTarget?.type === \"node\" && DATA.node.id === CTX.activeTarget.nodeId ? \"2px solid orange\" : \"none\",\n outlineOffset: \"2px\",\n cursor: \"pointer\",\n userSelect: \"none\",\n }\n %>\n children:\n - brick: span\n properties:\n textContent: <% DATA.node.id %>\n events:\n click:\n action: context.replace\n args:\n - activeTarget\n - type: node\n nodeId: <% DATA.node.id %>\n events:\n activeTarget.change:\n action: context.replace\n args:\n - activeTarget\n - <% EVENT.detail %>\n# -- YAML DELIMITER (1nbbm8) --\n# <div style=\"position: fixed; height: 100vh; width: 100vw; top: 0px; left: 0px\">\n# <eo-diagram layout=\"force\" id=\"brick-1\"></eo-diagram>\n# </div>\n# \n# <script>\n# const brick_1 = document.getElementById(\"brick-1\");\n# brick_1.dragNodes = {};\n# brick_1.nodes = \"<%= CTX.nodes %>\";\n# brick_1.edges = \"<%= CTX.edges %>\";\n# brick_1.activeTarget = \"<%= CTX.activeTarget %>\";\n# brick_1.layoutOptions = {\n# dummyNodesOnEdges: 1,\n# collide: {\n# dummyRadius: 10,\n# radiusDiff: 40,\n# },\n# };\n# brick_1.lines = [\n# {\n# label: [\n# {\n# useBrick: {\n# brick: \"span\",\n# properties: {\n# hidden:\n# '<%= CTX.activeTarget?.type !== \"node\" || (DATA.edge.source !== CTX.activeTarget.nodeId && DATA.edge.target !== CTX.activeTarget.nodeId) %>',\n# textContent:\n# '<%= DATA.edge.source === CTX.activeTarget?.nodeId ? DATA.edge.sourceName : DATA.edge.target === CTX.activeTarget?.nodeId ? DATA.edge.targetName : \"\" %>\\n',\n# style: {\n# color: \"var(--palette-gray-6)\",\n# },\n# },\n# },\n# },\n# ],\n# overrides: {\n# activeRelated: {\n# strokeColor: \"var(--palette-blue-4)\",\n# },\n# },\n# },\n# ];\n# brick_1.nodeBricks = [\n# {\n# useBrick: {\n# brick: \"div\",\n# properties: {\n# style:\n# '<%=\\n {\\n width: \"160px\",\\n height: \"50px\",\\n background: \"var(--palette-green-1)\",\\n border: \"1px solid var(--palette-gray-4)\",\\n borderRadius: \"8px\",\\n display: \"flex\",\\n alignItems: \"center\",\\n justifyContent: \"center\",\\n outline: CTX.activeTarget?.type === \"node\" && DATA.node.id === CTX.activeTarget.nodeId ? \"2px solid orange\" : \"none\",\\n outlineOffset: \"2px\",\\n cursor: \"pointer\",\\n userSelect: \"none\",\\n }\\n%>\\n',\n# },\n# children: [\n# {\n# brick: \"span\",\n# properties: {\n# textContent: \"<% DATA.node.id %>\",\n# },\n# },\n# ],\n# events: {\n# click: {\n# action: \"context.replace\",\n# args: [\n# \"activeTarget\",\n# {\n# type: \"node\",\n# nodeId: \"<% DATA.node.id %>\",\n# },\n# ],\n# },\n# },\n# },\n# },\n# ];\n# brick_1.addEventListener(\"activeTarget.change\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# </script>\n# \n```\n"
3
+ "doc": "---\ntagName: eo-diagram\ndisplayName: WrappedEoDiagram\ndescription: 图表构件,支持 dagre(有向无环图)和 force(力导向图)两种布局,可渲染节点和连线,支持缩放、平移、拖拽节点、连线交互等功能。\ncategory: diagram\nsource: \"@next-bricks/diagram\"\n---\n\n# eo-diagram\n\n> 图表构件,支持 dagre(有向无环图)和 force(力导向图)两种布局,可渲染节点和连线,支持缩放、平移、拖拽节点、连线交互等功能。\n\n## Props\n\n| 属性 | 类型 | 必填 | 默认值 | 说明 |\n| --------------------- | ----------------------------------- | ---- | ------ | ---------------------------------------------------------------------------------------------------------------- |\n| layout | `\"dagre\" \\| \"force\" \\| undefined` | - | - | 图表布局类型,支持 `dagre`(层次有向图)和 `force`(力导向图)。 |\n| nodes | `DiagramNode[] \\| undefined` | - | - | 节点数据列表,每个节点需包含唯一 `id` 字段。 |\n| edges | `DiagramEdge[] \\| undefined` | - | - | 边(连线)数据列表,每条边需包含 `source` 和 `target` 字段,指向节点 id。 |\n| nodeBricks | `NodeBrickConf[] \\| undefined` | - | - | 节点砖块配置,指定渲染节点使用的自定义构件,可按节点类型匹配不同配置。 |\n| lines | `LineConf[] \\| undefined` | - | - | 连线样式配置,支持箭头、颜色、标签、交互等多种选项。 |\n| layoutOptions | `LayoutOptions \\| undefined` | - | - | 布局算法选项,dagre 布局支持 rankdir、ranksep、nodesep 等,force 布局支持 dummyNodesOnEdges、collide 等。 |\n| activeTarget | `ActiveTarget \\| null \\| undefined` | - | - | 当前激活目标,可以是节点(`{ type: \"node\", nodeId }`) 或边(`{ type: \"edge\", edge }`),为 null 表示无激活目标。 |\n| disableKeyboardAction | `boolean \\| undefined` | - | - | 是否禁用键盘操作(删除节点/边、切换激活节点),当有标签正在编辑时可临时禁用以避免冲突。 |\n| connectNodes | `ConnectNodesOptions \\| undefined` | - | - | 连线交互配置,启用后支持从节点拖拽出新的连线,可配置连线样式和源节点过滤条件。 |\n| dragNodes | `DragNodesOptions \\| undefined` | - | - | 拖拽节点配置,启用后支持手动拖拽节点调整位置,可配置是否保存用户视图。 |\n| zoomable | `boolean \\| undefined` | - | `true` | 是否允许通过鼠标滚轮或触控板捏合手势缩放图表,默认为 true。 |\n| scrollable | `boolean \\| undefined` | - | `true` | 是否允许通过滚轮平移图表(非捏合手势),默认为 true。 |\n| pannable | `boolean \\| undefined` | - | `true` | 是否允许通过鼠标拖拽平移图表,默认为 true。 |\n| scaleRange | `RangeTuple \\| undefined` | - | - | 缩放比例范围,格式为 `[min, max]`,默认范围由内部常量决定。 |\n\n## Events\n\n| 事件 | detail | 说明 |\n| ------------------- | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ |\n| activeTarget.change | `ActiveTarget \\| null` — 当前激活目标,`{ type: \"node\", nodeId }` 或 `{ type: \"edge\", edge }` 或 null | 激活目标变化时触发,当用户点击节点或边使其激活,或点击空白处取消激活时触发。 |\n| node.delete | `DiagramNode` — 被删除的节点对象,包含节点 id 及其他自定义字段 | 用户按 Delete/Backspace 键且当前激活目标为节点时触发,需外部处理实际删除逻辑。 |\n| edge.delete | `DiagramEdge` — 被删除的边对象,包含 source、target 及其他自定义字段 | 用户按 Delete/Backspace 键且当前激活目标为边时触发,需外部处理实际删除逻辑。 |\n| line.click | `LineTarget` — 被点击的连线信息,包含 `{ id: 连线唯一标识, edge: 对应的边数据 }` | 用户点击可交互连线时触发。 |\n| line.dblclick | `LineTarget` — 被双击的连线信息,包含 `{ id: 连线唯一标识, edge: 对应的边数据 }` | 用户双击可交互连线时触发,常用于触发连线标签编辑。 |\n| nodes.connect | `ConnectLineDetail` — 连线详情,包含 `{ source: 起始节点, target: 目标节点 }` | 用户从一个节点拖拽连线到另一个节点并释放时触发,需外部处理实际建立连接的逻辑。 |\n\n## Methods\n\n| 方法 | 参数 | 返回值 | 说明 |\n| --------------- | ------------------------------------------------------- | ------ | ----------------------------------------------------------------------------------------------------- |\n| callOnLineLabel | `(id: string, method: string, args: unknown[]) => void` | `void` | 调用指定 id 的连线标签构件上的方法,常用于触发标签编辑(如 `callOnLineLabel(id, \"enableEditing\")`)。 |\n\n## Examples\n\n### Basic\n\n展示基本的 dagre 布局图表,包含节点和带箭头的连线,并支持动态添加/删除节点。\n\n```yaml preview minHeight=\"600px\"\nbrick: div\nproperties:\n style:\n position: fixed\n height: 100vh\n width: 100vw\n top: 0px\n left: 0px\ncontext:\n - name: activeTarget\n value: null\n - name: nodes\n value:\n - id: kspacey\n label: Kevin Spacey\n - id: swilliams\n label: Saul Williams\n - id: bpitt\n label: Brad Pitt\n # - id: hford\n # label: Harrison Ford\n - id: lwilson\n label: Luke Wilson\n - id: kbacon\n label: Kevin Bacon\n - name: edges\n value:\n - source: kspacey\n target: swilliams\n - source: swilliams\n target: kbacon\n - source: bpitt\n target: kbacon\n # - source: hford\n # target: lwilson\n - source: lwilson\n target: kbacon\nchildren:\n - brick: eo-button\n properties:\n textContent: Add Harrison Ford\n events:\n click:\n - action: context.replace\n args:\n - nodes\n - |\n <%\n CTX.nodes.concat({\n id: \"hford\",\n label: \"Harrison Ford\",\n })\n %>\n - action: context.replace\n args:\n - edges\n - |\n <%\n CTX.edges.concat({\n source: \"hford\",\n target: \"lwilson\",\n })\n %>\n - target: _self\n properties:\n style:\n visibility: hidden\n - brick: eo-button\n properties:\n textContent: Remove Kevin Spacey\n events:\n click:\n - action: context.replace\n args:\n - nodes\n - |\n <%\n CTX.nodes.filter(node => node.id !== \"kspacey\")\n %>\n - action: context.replace\n args:\n - edges\n - |\n <%\n CTX.edges.filter(({ source, target }) => source !== \"kspacey\" && target !== \"kspacey\")\n %>\n - target: _self\n properties:\n style:\n visibility: hidden\n - brick: eo-diagram\n properties:\n layout: dagre\n nodes: <%= CTX.nodes %>\n edges: <%= CTX.edges %>\n lines:\n - arrow: true\n activeTarget: <%= CTX.activeTarget %>\n nodeBricks:\n - useBrick:\n brick: div\n properties:\n style: |\n <%=\n {\n width: \"180px\",\n height: \"100px\",\n border: \"2px solid green\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n outline: CTX.activeTarget?.type === \"node\" && CTX.activeTarget.nodeId === DATA.node.id ? \"2px solid orange\" : \"none\",\n outlineOffset: \"2px\",\n }\n %>\n children:\n - brick: span\n properties:\n textContent: <% DATA.node.label %>\n events:\n click:\n action: context.replace\n args:\n - activeTarget\n - type: node\n nodeId: <% DATA.node.id %>\n events:\n activeTarget.change:\n action: context.replace\n args:\n - activeTarget\n - <% EVENT.detail %>\n# -- YAML DELIMITER (1nbbm8) --\n# <div style=\"position: fixed; height: 100vh; width: 100vw; top: 0px; left: 0px\">\n# <eo-button id=\"brick-1\">Add Harrison Ford</eo-button>\n# <eo-button id=\"brick-2\">Remove Kevin Spacey</eo-button>\n# <eo-diagram layout=\"dagre\" id=\"brick-3\"></eo-diagram>\n# </div>\n# \n# <script>\n# const brick_1 = document.getElementById(\"brick-1\");\n# brick_1.addEventListener(\"click\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_1.addEventListener(\"click\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_1.addEventListener(\"click\", (e) => {\n# const brick = e.target;\n# brick.style = {\n# visibility: \"hidden\",\n# };\n# });\n# \n# const brick_2 = document.getElementById(\"brick-2\");\n# brick_2.addEventListener(\"click\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_2.addEventListener(\"click\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_2.addEventListener(\"click\", (e) => {\n# const brick = e.target;\n# brick.style = {\n# visibility: \"hidden\",\n# };\n# });\n# \n# const brick_3 = document.getElementById(\"brick-3\");\n# brick_3.nodes = \"<%= CTX.nodes %>\";\n# brick_3.edges = \"<%= CTX.edges %>\";\n# brick_3.lines = [\n# {\n# arrow: true,\n# },\n# ];\n# brick_3.activeTarget = \"<%= CTX.activeTarget %>\";\n# brick_3.nodeBricks = [\n# {\n# useBrick: {\n# brick: \"div\",\n# properties: {\n# style:\n# '<%=\\n {\\n width: \"180px\",\\n height: \"100px\",\\n border: \"2px solid green\",\\n display: \"flex\",\\n alignItems: \"center\",\\n justifyContent: \"center\",\\n outline: CTX.activeTarget?.type === \"node\" && CTX.activeTarget.nodeId === DATA.node.id ? \"2px solid orange\" : \"none\",\\n outlineOffset: \"2px\",\\n }\\n%>\\n',\n# },\n# children: [\n# {\n# brick: \"span\",\n# properties: {\n# textContent: \"<% DATA.node.label %>\",\n# },\n# },\n# ],\n# events: {\n# click: {\n# action: \"context.replace\",\n# args: [\n# \"activeTarget\",\n# {\n# type: \"node\",\n# nodeId: \"<% DATA.node.id %>\",\n# },\n# ],\n# },\n# },\n# },\n# },\n# ];\n# brick_3.addEventListener(\"activeTarget.change\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# </script>\n# \n```\n\n### Page Architecture\n\n展示 dagre 布局图表用于页面架构可视化,包含节点标签编辑、连线标签、连线创建和节点删除交互。\n\n```yaml preview minHeight=\"600px\"\nbrick: div\nproperties:\n style:\n position: fixed\n height: 100vh\n width: 100vw\n top: 0px\n left: 0px\ncontext:\n - name: activeTarget\n value: null\n - name: tempNodeId\n - name: targetNode\n - name: editingLabelNodes\n value: []\n - name: editingLabelEdges\n value: []\n - name: nodes\n value:\n - type: board\n id: 60bf6078b095f\n name: Visual Builder\n depth: 0\n parentId:\n description: 某某产品\n - type: page\n id: 60bf60848d6d2\n name: 项目列表\n depth: 1\n parentId: 60bf6078b095f\n description: 列表页\n - type: page\n id: 60d533eba4ab2\n name: ccc\n depth: 1\n parentId: 60bf6078b095f\n description: cccc\n - type: link\n id: 60bf6091a1089\n name: 新建项目\n pageType: information:form:basic-form\n description: 新建页213\n to:\n \"@\":\n description: 无项目\n instanceId: 60c5fea301b32\n description: 新建页213\n instanceId: 60bf6091a1089\n module: []\n name: 新建项目\n pageType: information:form:basic-form\n depth: -1\n parentId:\n - type: link\n id: 60bf60a258613\n name: 项目首页-路由管理\n description: 路由管理\n to:\n description: 路由管理\n instanceId: 60bf60a258613\n module:\n - instanceId: 60bf609b26889\n name: Project\n name: 项目首页-路由管理\n depth: -1\n parentId:\n - type: link\n id: 60c5f39a2c2e1\n name: Launchpad 出厂配置\n description: Launchpad 出厂配置\n to:\n description: Launchpad 出厂配置\n instanceId: 60c5f39a2c2e1\n module: []\n name: Launchpad 出厂配置\n depth: -1\n parentId:\n - name: edges\n value:\n - type: menu\n source: 60bf6078b095f\n target: 60bf60848d6d2\n - type: menu\n source: 60bf6078b095f\n target: 60d533eba4ab2\n - type: link\n source: 60bf60848d6d2\n target: 60bf6091a1089\n description: 无项目\n - type: link\n source: 60bf60848d6d2\n target: 60bf60a258613\n - type: link\n source: 60bf60848d6d2\n target: 60c5f39a2c2e1\nchildren:\n - brick: eo-diagram\n properties:\n layout: dagre\n nodes: <%= CTX.nodes %>\n edges: <%= CTX.edges %>\n lines:\n - edgeType: link\n strokeColor: var(--theme-blue-color)\n arrow: true\n interactable: true\n label:\n useBrick:\n brick: diagram.editable-label\n properties:\n label: <% DATA.edge.description %>\n type: line\n events:\n label.change:\n if: <% (DATA.edge.description || \"\") !== (EVENT.detail || \"\") %>\n action: context.replace\n args:\n - edges\n - |-\n <%\n CTX.edges.map((edge) =>\n edge.source === DATA.edge.source &&\n edge.target === DATA.edge.target\n ? { ...edge, description: EVENT.detail }\n : edge\n )\n %>\n label.editing.change:\n action: context.replace\n args:\n - editingLabelEdges\n - |-\n <%\n EVENT.detail\n ? CTX.editingLabelEdges.concat(\n `${DATA.edge.source}-:-${DATA.edge.target}`\n )\n : CTX.editingLabelEdges.filter(\n (id) =>\n id !== `${DATA.edge.source}-:-${DATA.edge.target}`\n )\n %>\n click:\n action: context.replace\n args:\n - activeTarget\n - type: edge\n edge: <% DATA.edge %>\n - edgeType: menu\n strokeColor: var(--palette-gray-5)\n arrow: true\n interactable: true\n layoutOptions:\n nodePadding: [4, 10, 10]\n activeTarget: <%= CTX.activeTarget %>\n disableKeyboardAction: <%= CTX.editingLabelNodes.length > 0 || CTX.editingLabelEdges.length > 0 %>\n connectNodes:\n arrow: true\n strokeColor: |-\n <%\n DATA.source.type === \"board\"\n ? \"var(--palette-gray-5)\"\n : \"var(--theme-blue-color)\"\n %>\n nodeBricks:\n - useBrick:\n brick: visual-builder.page-arch-node\n properties:\n label: <% DATA.node.name %>\n type: <% DATA.node.type %>\n autoFocusOnce: |\n <% DATA.node.$temp ? DATA.node.id : undefined %>\n active: <%= CTX.activeTarget?.type === \"node\" && CTX.activeTarget.nodeId === DATA.node.id %>\n events:\n click:\n action: context.replace\n args:\n - activeTarget\n - type: node\n nodeId: <% DATA.node.id %>\n label.editing.change:\n action: context.replace\n args:\n - editingLabelNodes\n - |\n <%\n EVENT.detail\n ? CTX.editingLabelNodes.concat(DATA.node.id)\n : CTX.editingLabelNodes.filter(\n id => id !== DATA.node.id\n )\n %>\n label.change:\n - if: <% CTX.nodes.find(({id}) => id === DATA.node.id)?.$temp %>\n action: context.replace\n args:\n args:\n - nodes\n - |\n <%\n CTX.nodes.map((node) => (\n node.id === DATA.node.id\n ? { ...node, $temp: false, name: EVENT.detail }\n : node\n ))\n %>\n - if: <% CTX.nodes.find(({id}) => id === DATA.node.id)?.name !== EVENT.detail %>\n action: context.replace\n args:\n - nodes\n - |\n <%\n CTX.nodes.map((node) => (\n node.id === DATA.node.id\n ? { ...node, name: EVENT.detail }\n : node\n ))\n %>\n child.append:\n - action: context.replace\n args:\n - tempNodeId\n - <% _.uniqueId('$temp-') %>\n - action: context.replace\n args:\n - nodes\n - |\n <% CTX.nodes.concat({ id: CTX.tempNodeId, name: \"未命名\", $temp: true }) %>\n - action: context.replace\n args:\n - edges\n - |\n <% CTX.edges.concat({ source: DATA.node.id, target: CTX.tempNodeId, name: \"未命名\", type: \"link\", $temp: true }) %>\n - action: context.replace\n args:\n - activeTarget\n - type: node\n nodeId: <% CTX.tempNodeId %>\n events:\n activeTarget.change:\n action: context.replace\n args:\n - activeTarget\n - <% EVENT.detail %>\n node.delete:\n - action: context.replace\n args:\n - targetNode\n - <% EVENT.detail %>\n - useProvider: basic.show-dialog\n args:\n - type: delete\n title: Delete Confirm\n content: Please enter {{ expect }} to delete the node.\n expect: <% EVENT.detail.name || \"未命名\" %>\n callback:\n success:\n - action: context.replace\n args:\n - nodes\n - |-\n <%\n CTX.nodes.filter(\n ({ id }) => id !== CTX.targetNode.id\n )\n %>\n - action: context.replace\n args:\n - edges\n - |-\n <%\n CTX.edges.filter(\n ({ source, target }) =>\n source !== CTX.targetNode.id &&\n target !== CTX.targetNode.id\n )\n %>\n edge.delete:\n action: context.replace\n args:\n - edges\n - |-\n <%\n CTX.edges.filter(\n ({ source, target }) =>\n source !== EVENT.detail.source ||\n target !== EVENT.detail.target\n )\n %>\n line.click:\n action: context.replace\n args:\n - activeTarget\n - type: edge\n edge: <% EVENT.detail.edge %>\n line.dblclick:\n target: _self\n method: callOnLineLabel\n args:\n - <% `${EVENT.detail.id}-center` %>\n - enableEditing\n nodes.connect:\n if: |-\n <%\n EVENT.detail.target.type !== \"board\" &&\n !CTX.edges.some(\n (edge) =>\n edge.source === EVENT.detail.source.id &&\n edge.target === EVENT.detail.target.id\n )\n %>\n action: context.replace\n args:\n - edges\n - |-\n <%\n CTX.edges.concat({\n source: EVENT.detail.source.id,\n target: EVENT.detail.target.id,\n type:\n EVENT.detail.source.type === \"board\"\n ? \"menu\"\n : \"link\",\n })\n %>\n# -- YAML DELIMITER (1nbbm8) --\n# <div style=\"position: fixed; height: 100vh; width: 100vw; top: 0px; left: 0px\">\n# <eo-diagram layout=\"dagre\" disable-keyboard-action id=\"brick-1\"></eo-diagram>\n# </div>\n# \n# <script>\n# const brick_1 = document.getElementById(\"brick-1\");\n# brick_1.nodes = \"<%= CTX.nodes %>\";\n# brick_1.edges = \"<%= CTX.edges %>\";\n# brick_1.lines = [\n# {\n# edgeType: \"link\",\n# strokeColor: \"var(--theme-blue-color)\",\n# arrow: true,\n# interactable: true,\n# label: {\n# useBrick: {\n# brick: \"diagram.editable-label\",\n# properties: {\n# label: \"<% DATA.edge.description %>\",\n# type: \"line\",\n# },\n# events: {\n# \"label.change\": {\n# if: '<% (DATA.edge.description || \"\") !== (EVENT.detail || \"\") %>',\n# action: \"context.replace\",\n# args: [\n# \"edges\",\n# \"<%\\n CTX.edges.map((edge) =>\\n edge.source === DATA.edge.source &&\\n edge.target === DATA.edge.target\\n ? { ...edge, description: EVENT.detail }\\n : edge\\n )\\n%>\",\n# ],\n# },\n# \"label.editing.change\": {\n# action: \"context.replace\",\n# args: [\n# \"editingLabelEdges\",\n# \"<%\\n EVENT.detail\\n ? CTX.editingLabelEdges.concat(\\n `${DATA.edge.source}-:-${DATA.edge.target}`\\n )\\n : CTX.editingLabelEdges.filter(\\n (id) =>\\n id !== `${DATA.edge.source}-:-${DATA.edge.target}`\\n )\\n%>\",\n# ],\n# },\n# click: {\n# action: \"context.replace\",\n# args: [\n# \"activeTarget\",\n# {\n# type: \"edge\",\n# edge: \"<% DATA.edge %>\",\n# },\n# ],\n# },\n# },\n# },\n# },\n# },\n# {\n# edgeType: \"menu\",\n# strokeColor: \"var(--palette-gray-5)\",\n# arrow: true,\n# interactable: true,\n# },\n# ];\n# brick_1.layoutOptions = {\n# nodePadding: [4, 10, 10],\n# };\n# brick_1.activeTarget = \"<%= CTX.activeTarget %>\";\n# brick_1.connectNodes = {\n# arrow: true,\n# strokeColor:\n# '<%\\n DATA.source.type === \"board\"\\n ? \"var(--palette-gray-5)\"\\n : \"var(--theme-blue-color)\"\\n%>',\n# };\n# brick_1.nodeBricks = [\n# {\n# useBrick: {\n# brick: \"visual-builder.page-arch-node\",\n# properties: {\n# label: \"<% DATA.node.name %>\",\n# type: \"<% DATA.node.type %>\",\n# autoFocusOnce: \"<% DATA.node.$temp ? DATA.node.id : undefined %>\\n\",\n# active:\n# '<%= CTX.activeTarget?.type === \"node\" && CTX.activeTarget.nodeId === DATA.node.id %>',\n# },\n# events: {\n# click: {\n# action: \"context.replace\",\n# args: [\n# \"activeTarget\",\n# {\n# type: \"node\",\n# nodeId: \"<% DATA.node.id %>\",\n# },\n# ],\n# },\n# \"label.editing.change\": {\n# action: \"context.replace\",\n# args: [\n# \"editingLabelNodes\",\n# \"<%\\n EVENT.detail\\n ? CTX.editingLabelNodes.concat(DATA.node.id)\\n : CTX.editingLabelNodes.filter(\\n id => id !== DATA.node.id\\n )\\n%>\\n\",\n# ],\n# },\n# \"label.change\": [\n# {\n# if: \"<% CTX.nodes.find(({id}) => id === DATA.node.id)?.$temp %>\",\n# action: \"context.replace\",\n# args: [\n# \"nodes\",\n# \"<%\\n CTX.nodes.map((node) => (\\n node.id === DATA.node.id\\n ? { ...node, $temp: false, name: EVENT.detail }\\n : node\\n ))\\n%>\\n\",\n# ],\n# },\n# {\n# if: \"<% CTX.nodes.find(({id}) => id === DATA.node.id)?.name !== EVENT.detail %>\",\n# action: \"context.replace\",\n# args: [\n# \"nodes\",\n# \"<%\\n CTX.nodes.map((node) => (\\n node.id === DATA.node.id\\n ? { ...node, name: EVENT.detail }\\n : node\\n ))\\n%>\\n\",\n# ],\n# },\n# ],\n# \"child.append\": [\n# {\n# action: \"context.replace\",\n# args: [\"tempNodeId\", \"<% _.uniqueId('$temp-') %>\"],\n# },\n# {\n# action: \"context.replace\",\n# args: [\n# \"nodes\",\n# '<% CTX.nodes.concat({ id: CTX.tempNodeId, name: \"未命名\", $temp: true }) %>\\n',\n# ],\n# },\n# {\n# action: \"context.replace\",\n# args: [\n# \"edges\",\n# '<% CTX.edges.concat({ source: DATA.node.id, target: CTX.tempNodeId, name: \"未命名\", type: \"link\", $temp: true }) %>\\n',\n# ],\n# },\n# {\n# action: \"context.replace\",\n# args: [\n# \"activeTarget\",\n# {\n# type: \"node\",\n# nodeId: \"<% CTX.tempNodeId %>\",\n# },\n# ],\n# },\n# ],\n# },\n# },\n# },\n# ];\n# brick_1.addEventListener(\"activeTarget.change\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_1.addEventListener(\"node.delete\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_1.addEventListener(\"node.delete\", (e) => {\n# const provider = document.createElement(\"basic.show-dialog\");\n# const promise = Promise.resolve(\n# provider.resolve({\n# type: \"delete\",\n# title: \"Delete Confirm\",\n# content: \"Please enter {{ expect }} to delete the node.\",\n# expect: '<% EVENT.detail.name || \"未命名\" %>',\n# })\n# );\n# promise.then((r) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# promise.then((r) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# });\n# brick_1.addEventListener(\"edge.delete\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_1.addEventListener(\"line.click\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_1.addEventListener(\"line.dblclick\", (e) => {\n# const brick = e.target;\n# brick.callOnLineLabel(\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# \"<% `${EVENT.detail.id}-center` %>\",\n# \"enableEditing\"\n# );\n# });\n# brick_1.addEventListener(\"nodes.connect\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# </script>\n# \n```\n\n### Force\n\n展示 force 布局的力导向图,支持拖拽节点、连线标签显示,适合展示关系网络。\n\n```yaml preview minHeight=\"600px\"\nbrick: div\nproperties:\n style:\n position: fixed\n height: 100vh\n width: 100vw\n top: 0px\n left: 0px\ncontext:\n - name: activeTarget\n value: null\n - name: nodes\n value:\n - id: 产品评价\n - id: 产品线\n - id: 用户角色\n - id: 模型视图\n - id: 产品\n - id: 业务场景\n - id: 业务规则\n - id: 模型\n - id: 产品模块\n - id: 产品价值点\n - id: 工作流\n - id: 测试用例\n - id: 功能点\n - name: edges\n value:\n - source: 产品\n target: 产品评价\n sourceName: 评价列表\n targetName: 所属产品\n - source: 产品\n target: 产品线\n sourceName: 所属产品线\n targetName: 产品列表\n - source: 产品\n target: 用户角色\n sourceName: 负责人\n targetName: 负责的产品\n - source: 产品\n target: 模型视图\n sourceName: 模型视图列表\n targetName: 所属产品\n - source: 产品\n target: 业务场景\n sourceName: 业务场景列表\n targetName: 所属产品\n - source: 业务场景\n target: 业务规则\n sourceName: 业务规则列表\n targetName: 所属业务场景\n - source: 产品\n target: 模型\n sourceName: 模型列表\n targetName: 关联的产品\n - source: 产品\n target: 产品模块\n sourceName: 模块列表\n targetName: 所属产品\n - source: 产品模块\n target: 测试用例\n sourceName: 测试用例列表\n targetName: 所属产品模块\n - source: 产品模块\n target: 功能点\n sourceName: 功能点列表\n targetName: 所属产品模块\nchildren:\n - brick: eo-diagram\n properties:\n layout: force\n dragNodes: {}\n nodes: <%= CTX.nodes %>\n edges: <%= CTX.edges %>\n activeTarget: <%= CTX.activeTarget %>\n layoutOptions:\n dummyNodesOnEdges: 1\n collide:\n dummyRadius: 10\n radiusDiff: 40\n scaleRange: [0.5, 2]\n lines:\n - label:\n - useBrick:\n brick: span\n properties:\n hidden: <%= CTX.activeTarget?.type !== \"node\" || (DATA.edge.source !== CTX.activeTarget.nodeId && DATA.edge.target !== CTX.activeTarget.nodeId) %>\n textContent: |\n <%= DATA.edge.source === CTX.activeTarget?.nodeId ? DATA.edge.sourceName : DATA.edge.target === CTX.activeTarget?.nodeId ? DATA.edge.targetName : \"\" %>\n style:\n color: var(--palette-gray-6)\n overrides:\n activeRelated:\n strokeColor: var(--palette-blue-4)\n nodeBricks:\n - useBrick:\n brick: div\n properties:\n style: |\n <%=\n {\n width: \"160px\",\n height: \"50px\",\n background: \"var(--palette-green-1)\",\n border: \"1px solid var(--palette-gray-4)\",\n borderRadius: \"8px\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n outline: CTX.activeTarget?.type === \"node\" && DATA.node.id === CTX.activeTarget.nodeId ? \"2px solid orange\" : \"none\",\n outlineOffset: \"2px\",\n cursor: \"pointer\",\n userSelect: \"none\",\n }\n %>\n children:\n - brick: span\n properties:\n textContent: <% DATA.node.id %>\n events:\n click:\n action: context.replace\n args:\n - activeTarget\n - type: node\n nodeId: <% DATA.node.id %>\n events:\n activeTarget.change:\n action: context.replace\n args:\n - activeTarget\n - <% EVENT.detail %>\n# -- YAML DELIMITER (1nbbm8) --\n# <div style=\"position: fixed; height: 100vh; width: 100vw; top: 0px; left: 0px\">\n# <eo-diagram layout=\"force\" id=\"brick-1\"></eo-diagram>\n# </div>\n# \n# <script>\n# const brick_1 = document.getElementById(\"brick-1\");\n# brick_1.dragNodes = {};\n# brick_1.nodes = \"<%= CTX.nodes %>\";\n# brick_1.edges = \"<%= CTX.edges %>\";\n# brick_1.activeTarget = \"<%= CTX.activeTarget %>\";\n# brick_1.layoutOptions = {\n# dummyNodesOnEdges: 1,\n# collide: {\n# dummyRadius: 10,\n# radiusDiff: 40,\n# },\n# };\n# brick_1.scaleRange = [0.5, 2];\n# brick_1.lines = [\n# {\n# label: [\n# {\n# useBrick: {\n# brick: \"span\",\n# properties: {\n# hidden:\n# '<%= CTX.activeTarget?.type !== \"node\" || (DATA.edge.source !== CTX.activeTarget.nodeId && DATA.edge.target !== CTX.activeTarget.nodeId) %>',\n# textContent:\n# '<%= DATA.edge.source === CTX.activeTarget?.nodeId ? DATA.edge.sourceName : DATA.edge.target === CTX.activeTarget?.nodeId ? DATA.edge.targetName : \"\" %>\\n',\n# style: {\n# color: \"var(--palette-gray-6)\",\n# },\n# },\n# },\n# },\n# ],\n# overrides: {\n# activeRelated: {\n# strokeColor: \"var(--palette-blue-4)\",\n# },\n# },\n# },\n# ];\n# brick_1.nodeBricks = [\n# {\n# useBrick: {\n# brick: \"div\",\n# properties: {\n# style:\n# '<%=\\n {\\n width: \"160px\",\\n height: \"50px\",\\n background: \"var(--palette-green-1)\",\\n border: \"1px solid var(--palette-gray-4)\",\\n borderRadius: \"8px\",\\n display: \"flex\",\\n alignItems: \"center\",\\n justifyContent: \"center\",\\n outline: CTX.activeTarget?.type === \"node\" && DATA.node.id === CTX.activeTarget.nodeId ? \"2px solid orange\" : \"none\",\\n outlineOffset: \"2px\",\\n cursor: \"pointer\",\\n userSelect: \"none\",\\n }\\n%>\\n',\n# },\n# children: [\n# {\n# brick: \"span\",\n# properties: {\n# textContent: \"<% DATA.node.id %>\",\n# },\n# },\n# ],\n# events: {\n# click: {\n# action: \"context.replace\",\n# args: [\n# \"activeTarget\",\n# {\n# type: \"node\",\n# nodeId: \"<% DATA.node.id %>\",\n# },\n# ],\n# },\n# },\n# },\n# },\n# ];\n# brick_1.addEventListener(\"activeTarget.change\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# </script>\n# \n```\n"
7
4
  },
8
- "eo-display-canvas": {
9
- "doc": "用于展示查看的画布构件。\n\n## Examples\n\n### Basic\n\n```yaml preview minHeight=\"600px\"\n- brick: div\n properties:\n style:\n display: flex\n height: 600px\n gap: 1em\n context:\n - name: initialCells\n value: |\n <%\n [\n {\n type: \"decorator\",\n id: \"area-1\",\n decorator: \"area\",\n view: {\n x: 10,\n y: 20,\n width: 400,\n height: 300,\n },\n },\n {\n type: \"decorator\",\n id: \"container-1\",\n decorator: \"container\",\n view: {\n x: 50,\n y: 400,\n width: 280,\n height: 120,\n direction: \"top\",\n text: \" 上层服务\"\n },\n },\n {\n type: \"edge\",\n source: \"X\",\n target: \"Y\",\n data: {\n virtual: false,\n showStartArrow: false,\n strokeColor:\"red\",\n strokeWidth: 5,\n }\n },\n {\n type: \"edge\",\n source: \"X\",\n target: \"W\",\n data: {\n virtual: false,\n showStartArrow: true,\n strokeColor:\"pink\",\n animate:{\n useAnimate: true,\n duration: 4\n }\n }\n },\n {\n type: \"edge\",\n source: \"X\",\n target: \"Z\",\n data: {\n virtual: true,\n showStartArrow: true,\n strokeColor:\"blue\",\n animate:{\n useAnimate: true\n }\n }\n },\n {\n type: \"edge\",\n source: \"W\",\n target: \"Z\",\n view: {\n entryPosition: { x: 0, y: 0.5 },\n exitPosition: {x: 0.5, y: 0}\n }\n }\n ].concat(\n [\"X\", \"Y\", \"Z\", \"W\"].map((id) => ({\n type: \"node\",\n id,\n containerId: [\"X\",\"Y\",\"Z\"].includes(id)?\"container-1\":undefined,\n data: {\n name: `Node ${id}`,\n },\n view: {\n x: Math.round(\n id === \"X\"\n ? 200 + Math.random() * 200\n : id === \"Y\"\n ? Math.random() * 300\n : 300 + Math.random() * 300\n ),\n y: (id === \"X\" ? 0 : 300) + Math.round((Math.random() * 200)),\n width: 60,\n height: 60,\n }\n }))\n ).concat([\n {\n type: \"decorator\",\n id: \"text-1\",\n decorator: \"text\",\n view: {\n x: 100,\n y: 120,\n width: 100,\n height: 20,\n text: \"Hello!\"\n },\n },\n ])\n %>\n - name: activeTarget\n - name: targetCell\n children:\n - brick: div\n properties:\n style:\n flex: 1\n minWidth: 0\n children:\n - brick: eo-display-canvas\n properties:\n style:\n width: 100%\n height: 100%\n activeTarget: <%= CTX.activeTarget %>\n fadeUnrelatedCells: true\n # Initial nodes only\n defaultNodeSize: [60, 60]\n defaultNodeBricks:\n - useBrick:\n brick: diagram.experimental-node\n properties:\n textContent: <% `Node ${DATA.node.id}` %>\n status: |\n <%=\n CTX.activeTarget?.type === \"node\" && CTX.activeTarget.id === DATA.node.id\n ? \"highlighted\"\n // : CTX.unrelated.some(n =>\n // n.type === \"node\" && n.id === DATA.node.id\n // )\n // ? \"faded\"\n : \"default\"\n %>\n defaultEdgeLines:\n - if: true\n dashed: <% DATA.edge?.data?.virtual %>\n strokeColor: <% DATA.edge?.data?.strokeColor %>\n showStartArrow: <% DATA.edge?.data?.showStartArrow %>\n strokeWidth: <% DATA.edge?.data?.strokeWidth %>\n animate: <% DATA.edge?.data?.animate %>\n showStartArrow: true\n markers:\n - placement: end\n type: circle\n - placement: start\n type: arrow\n cells: <% CTX.initialCells %>\n events:\n activeTarget.change:\n action: context.replace\n args:\n - activeTarget\n - <% EVENT.detail %>\n cell.contextmenu:\n - target: eo-context-menu\n method: open\n args:\n - position:\n - <% EVENT.detail.clientX %>\n - <% EVENT.detail.clientY %>\n - action: context.replace\n args:\n - targetCell\n - <% EVENT.detail.cell %>\n- brick: eo-context-menu\n properties:\n actions: |\n <%=\n [\n {\n text: `Test ${CTX.targetCell?.type}`,\n event: `test-${CTX.targetCell?.type}`,\n }\n ]\n %>\n# -- YAML DELIMITER (1nbbm8) --\n# <div style=\"display: flex; height: 600px; gap: 1em\">\n# <div style=\"flex: 1; min-width: 0\">\n# <eo-display-canvas\n# style=\"width: 100%; height: 100%\"\n# fade-unrelated-cells\n# id=\"brick-1\"\n# ></eo-display-canvas>\n# </div>\n# </div>\n# <eo-context-menu\n# actions=\"&lt;%=\n# [\n# {\n# text: `Test ${CTX.targetCell?.type}`,\n# event: `test-${CTX.targetCell?.type}`,\n# }\n# ]\n# %&gt;\n# \"\n# ></eo-context-menu>\n# \n# <script>\n# const brick_1 = document.getElementById(\"brick-1\");\n# brick_1.activeTarget = \"<%= CTX.activeTarget %>\";\n# brick_1.defaultNodeSize = [60, 60];\n# brick_1.defaultNodeBricks = [\n# {\n# useBrick: {\n# brick: \"diagram.experimental-node\",\n# properties: {\n# textContent: \"<% `Node ${DATA.node.id}` %>\",\n# status:\n# '<%=\\n CTX.activeTarget?.type === \"node\" && CTX.activeTarget.id === DATA.node.id\\n ? \"highlighted\"\\n // : CTX.unrelated.some(n =>\\n // n.type === \"node\" && n.id === DATA.node.id\\n // )\\n // ? \"faded\"\\n : \"default\"\\n%>\\n',\n# },\n# },\n# },\n# ];\n# brick_1.defaultEdgeLines = [\n# {\n# if: true,\n# dashed: \"<% DATA.edge?.data?.virtual %>\",\n# strokeColor: \"<% DATA.edge?.data?.strokeColor %>\",\n# showStartArrow: true,\n# strokeWidth: \"<% DATA.edge?.data?.strokeWidth %>\",\n# animate: \"<% DATA.edge?.data?.animate %>\",\n# markers: [\n# {\n# placement: \"end\",\n# type: \"circle\",\n# },\n# {\n# placement: \"start\",\n# type: \"arrow\",\n# },\n# ],\n# },\n# ];\n# brick_1.cells = \"<% CTX.initialCells %>\";\n# brick_1.addEventListener(\"activeTarget.change\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_1.addEventListener(\"cell.contextmenu\", (e) => {\n# const brick = document.querySelector(\"eo-context-menu\");\n# brick.open({\n# position: [\"<% EVENT.detail.clientX %>\", \"<% EVENT.detail.clientY %>\"],\n# });\n# });\n# brick_1.addEventListener(\"cell.contextmenu\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# </script>\n# \n```\n\n### Force layout\n\n```yaml preview minHeight=\"600px\"\n- brick: div\n properties:\n style:\n display: flex\n height: 600px\n gap: 1em\n context:\n - name: initialCells\n value: |\n <%\n [\n {\n type: \"decorator\",\n id: \"area-1\",\n decorator: \"area\",\n view: {\n x: 10,\n y: 20,\n width: 400,\n height: 300,\n },\n },\n {\n type: \"edge\",\n source: \"X\",\n target: \"Y\",\n },\n {\n type: \"edge\",\n source: \"X\",\n target: \"Z\",\n data: {\n virtual: true,\n }\n },\n ].concat(\n [\"X\", \"Y\", \"Z\", \"W\"].map((id) => ({\n type: \"node\",\n id,\n data: {\n name: `Node ${id}`,\n },\n view: {\n width: 60,\n height: 60,\n }\n }))\n ).concat([\n {\n type: \"decorator\",\n id: \"text-1\",\n decorator: \"text\",\n view: {\n x: 100,\n y: 120,\n width: 100,\n height: 20,\n text: \"Hello!\"\n },\n },\n ])\n %>\n - name: activeTarget\n - name: targetCell\n children:\n - brick: div\n properties:\n style:\n flex: 1\n minWidth: 0\n children:\n - brick: eo-display-canvas\n properties:\n style:\n width: 100%\n height: 100%\n activeTarget: <%= CTX.activeTarget %>\n fadeUnrelatedCells: true\n layout: force\n # Initial nodes only\n defaultNodeSize: [60, 60]\n defaultNodeBricks:\n - useBrick:\n brick: diagram.experimental-node\n properties:\n textContent: <% `Node ${DATA.node.id}` %>\n status: |\n <%=\n CTX.activeTarget?.type === \"node\" && CTX.activeTarget.id === DATA.node.id\n ? \"highlighted\"\n // : CTX.unrelated.some(n =>\n // n.type === \"node\" && n.id === DATA.node.id\n // )\n // ? \"faded\"\n : \"default\"\n %>\n defaultEdgeLines:\n - if: <% DATA.edge.data?.virtual %>\n dashed: true\n cells: <% CTX.initialCells %>\n events:\n activeTarget.change:\n action: context.replace\n args:\n - activeTarget\n - <% EVENT.detail %>\n cell.contextmenu:\n - target: eo-context-menu\n method: open\n args:\n - position:\n - <% EVENT.detail.clientX %>\n - <% EVENT.detail.clientY %>\n - action: context.replace\n args:\n - targetCell\n - <% EVENT.detail.cell %>\n- brick: eo-context-menu\n properties:\n actions: |\n <%=\n [\n {\n text: `Test ${CTX.targetCell?.type}`,\n event: `test-${CTX.targetCell?.type}`,\n }\n ]\n %>\n# -- YAML DELIMITER (1nbbm8) --\n# <div style=\"display: flex; height: 600px; gap: 1em\">\n# <div style=\"flex: 1; min-width: 0\">\n# <eo-display-canvas\n# style=\"width: 100%; height: 100%\"\n# fade-unrelated-cells\n# layout=\"force\"\n# id=\"brick-1\"\n# ></eo-display-canvas>\n# </div>\n# </div>\n# <eo-context-menu\n# actions=\"&lt;%=\n# [\n# {\n# text: `Test ${CTX.targetCell?.type}`,\n# event: `test-${CTX.targetCell?.type}`,\n# }\n# ]\n# %&gt;\n# \"\n# ></eo-context-menu>\n# \n# <script>\n# const brick_1 = document.getElementById(\"brick-1\");\n# brick_1.activeTarget = \"<%= CTX.activeTarget %>\";\n# brick_1.defaultNodeSize = [60, 60];\n# brick_1.defaultNodeBricks = [\n# {\n# useBrick: {\n# brick: \"diagram.experimental-node\",\n# properties: {\n# textContent: \"<% `Node ${DATA.node.id}` %>\",\n# status:\n# '<%=\\n CTX.activeTarget?.type === \"node\" && CTX.activeTarget.id === DATA.node.id\\n ? \"highlighted\"\\n // : CTX.unrelated.some(n =>\\n // n.type === \"node\" && n.id === DATA.node.id\\n // )\\n // ? \"faded\"\\n : \"default\"\\n%>\\n',\n# },\n# },\n# },\n# ];\n# brick_1.defaultEdgeLines = [\n# {\n# if: \"<% DATA.edge.data?.virtual %>\",\n# dashed: true,\n# },\n# ];\n# brick_1.cells = \"<% CTX.initialCells %>\";\n# brick_1.addEventListener(\"activeTarget.change\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_1.addEventListener(\"cell.contextmenu\", (e) => {\n# const brick = document.querySelector(\"eo-context-menu\");\n# brick.open({\n# position: [\"<% EVENT.detail.clientX %>\", \"<% EVENT.detail.clientY %>\"],\n# });\n# });\n# brick_1.addEventListener(\"cell.contextmenu\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# </script>\n# \n```\n\n### Dagre layout\n\n```yaml preview minHeight=\"600px\"\n- brick: div\n properties:\n style:\n display: flex\n height: 600px\n gap: 1em\n context:\n - name: initialCells\n value: |\n <%\n [\n {\n type: \"decorator\",\n id: \"area-1\",\n decorator: \"area\",\n view: {\n x: 10,\n y: 20,\n width: 400,\n height: 300,\n },\n },\n {\n type: \"edge\",\n source: \"X\",\n target: \"Y\",\n view: {\n type: \"polyline\"\n }\n },\n {\n type: \"edge\",\n source: \"X\",\n target: \"Z\",\n data: {\n virtual: true,\n }\n },\n {\n type: \"edge\",\n source: \"Z\",\n target: \"W\",\n },\n ].concat(\n [\"X\", \"Y\", \"Z\", \"W\"].map((id) => ({\n type: \"node\",\n id,\n data: {\n name: `Node ${id}`,\n },\n view: {\n width: 60,\n height: 60,\n }\n }))\n )\n %>\n - name: activeTarget\n - name: targetCell\n children:\n - brick: div\n properties:\n style:\n flex: 1\n minWidth: 0\n children:\n - brick: eo-display-canvas\n properties:\n style:\n width: 100%\n height: 100%\n activeTarget: <%= CTX.activeTarget %>\n fadeUnrelatedCells: true\n layout: dagre\n layoutOptions:\n ranksep: 80\n nodesep: 80\n # Initial nodes only\n defaultNodeSize: [60, 60]\n defaultNodeBricks:\n - useBrick:\n brick: diagram.experimental-node\n properties:\n textContent: <% `Node ${DATA.node.id}` %>\n status: |\n <%=\n CTX.activeTarget?.type === \"node\" && CTX.activeTarget.id === DATA.node.id\n ? \"highlighted\"\n // : CTX.unrelated.some(n =>\n // n.type === \"node\" && n.id === DATA.node.id\n // )\n // ? \"faded\"\n : \"default\"\n %>\n defaultEdgeLines:\n - dashed: <% !!DATA.edge.data?.virtual %>\n strokeColor: var(--palette-blue-6)\n overrides:\n active:\n strokeWidth: <% 2 * (DATA.edge?.data?.strokeWidth ?? 1) %>\n strokeColor: cyan\n activeRelated:\n strokeWidth: <% 2 * (DATA.edge?.data?.strokeWidth ?? 1) %>\n motion:\n shape: '<% DATA.edge.data?.virtual ? \"dot\" : \"triangle\" %>'\n cells: <% CTX.initialCells %>\n events:\n activeTarget.change:\n action: context.replace\n args:\n - activeTarget\n - <% EVENT.detail %>\n cell.contextmenu:\n - target: eo-context-menu\n method: open\n args:\n - position:\n - <% EVENT.detail.clientX %>\n - <% EVENT.detail.clientY %>\n - action: context.replace\n args:\n - targetCell\n - <% EVENT.detail.cell %>\n- brick: eo-context-menu\n properties:\n actions: |\n <%=\n [\n {\n text: `Test ${CTX.targetCell?.type}`,\n event: `test-${CTX.targetCell?.type}`,\n }\n ]\n %>\n# -- YAML DELIMITER (1nbbm8) --\n# <div style=\"display: flex; height: 600px; gap: 1em\">\n# <div style=\"flex: 1; min-width: 0\">\n# <eo-display-canvas\n# style=\"width: 100%; height: 100%\"\n# fade-unrelated-cells\n# layout=\"dagre\"\n# id=\"brick-1\"\n# ></eo-display-canvas>\n# </div>\n# </div>\n# <eo-context-menu\n# actions=\"&lt;%=\n# [\n# {\n# text: `Test ${CTX.targetCell?.type}`,\n# event: `test-${CTX.targetCell?.type}`,\n# }\n# ]\n# %&gt;\n# \"\n# ></eo-context-menu>\n# \n# <script>\n# const brick_1 = document.getElementById(\"brick-1\");\n# brick_1.activeTarget = \"<%= CTX.activeTarget %>\";\n# brick_1.layoutOptions = {\n# ranksep: 80,\n# nodesep: 80,\n# };\n# brick_1.defaultNodeSize = [60, 60];\n# brick_1.defaultNodeBricks = [\n# {\n# useBrick: {\n# brick: \"diagram.experimental-node\",\n# properties: {\n# textContent: \"<% `Node ${DATA.node.id}` %>\",\n# status:\n# '<%=\\n CTX.activeTarget?.type === \"node\" && CTX.activeTarget.id === DATA.node.id\\n ? \"highlighted\"\\n // : CTX.unrelated.some(n =>\\n // n.type === \"node\" && n.id === DATA.node.id\\n // )\\n // ? \"faded\"\\n : \"default\"\\n%>\\n',\n# },\n# },\n# },\n# ];\n# brick_1.defaultEdgeLines = [\n# {\n# dashed: \"<% !!DATA.edge.data?.virtual %>\",\n# strokeColor: \"var(--palette-blue-6)\",\n# overrides: {\n# active: {\n# strokeWidth: \"<% 2 * (DATA.edge?.data?.strokeWidth ?? 1) %>\",\n# strokeColor: \"cyan\",\n# },\n# activeRelated: {\n# strokeWidth: \"<% 2 * (DATA.edge?.data?.strokeWidth ?? 1) %>\",\n# motion: {\n# shape: '<% DATA.edge.data?.virtual ? \"dot\" : \"triangle\" %>',\n# },\n# },\n# },\n# },\n# ];\n# brick_1.cells = \"<% CTX.initialCells %>\";\n# brick_1.addEventListener(\"activeTarget.change\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_1.addEventListener(\"cell.contextmenu\", (e) => {\n# const brick = document.querySelector(\"eo-context-menu\");\n# brick.open({\n# position: [\"<% EVENT.detail.clientX %>\", \"<% EVENT.detail.clientY %>\"],\n# });\n# });\n# brick_1.addEventListener(\"cell.contextmenu\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# </script>\n# \n```\n\n### Degraded diagram\n\n```yaml preview minHeight=\"600px\"\n- brick: div\n properties:\n style:\n display: flex\n height: 600px\n gap: 1em\n context:\n - name: initialCells\n value: |\n <%\n ((...seeds) => seeds.map((seed) => ({\n type: \"node\",\n id: seed,\n data: {\n name: seed,\n },\n })))(\n ...(\n new Array(500).fill(null).map((_, i) => String(i))\n )\n )\n %>\n - name: activeTarget\n - name: targetCell\n children:\n - brick: div\n properties:\n style:\n flex: 1\n minWidth: 0\n children:\n - brick: eo-display-canvas\n properties:\n style:\n width: 100%\n height: 100%\n activeTarget: <%= CTX.activeTarget %>\n fadeUnrelatedCells: true\n layout: force\n # Initial nodes only\n defaultNodeSize: [60, 60]\n defaultNodeBricks:\n - useBrick:\n brick: diagram.experimental-node\n properties:\n textContent: <% `Node ${DATA.node.id}` %>\n status: |\n <%=\n CTX.activeTarget?.type === \"node\" && CTX.activeTarget.id === DATA.node.id\n ? \"highlighted\"\n // : CTX.unrelated.some(n =>\n // n.type === \"node\" && n.id === DATA.node.id\n // )\n // ? \"faded\"\n : \"default\"\n %>\n defaultEdgeLines:\n - if: true\n dashed: <% DATA.edge?.data?.virtual %>\n strokeColor: <% DATA.edge?.data?.strokeColor %>\n showStartArrow: <% DATA.edge?.data?.showStartArrow %>\n strokeWidth: <% DATA.edge?.data?.strokeWidth %>\n animate: <% DATA.edge?.data?.animate %>\n cells: <% CTX.initialCells %>\n events:\n activeTarget.change:\n action: context.replace\n args:\n - activeTarget\n - <% EVENT.detail %>\n cell.contextmenu:\n - target: eo-context-menu\n method: open\n args:\n - position:\n - <% EVENT.detail.clientX %>\n - <% EVENT.detail.clientY %>\n - action: context.replace\n args:\n - targetCell\n - <% EVENT.detail.cell %>\n- brick: eo-context-menu\n properties:\n actions: |\n <%=\n [\n {\n text: `Test ${CTX.targetCell?.type}`,\n event: `test-${CTX.targetCell?.type}`,\n }\n ]\n %>\n# -- YAML DELIMITER (1nbbm8) --\n# <div style=\"display: flex; height: 600px; gap: 1em\">\n# <div style=\"flex: 1; min-width: 0\">\n# <eo-display-canvas\n# style=\"width: 100%; height: 100%\"\n# fade-unrelated-cells\n# layout=\"force\"\n# id=\"brick-1\"\n# ></eo-display-canvas>\n# </div>\n# </div>\n# <eo-context-menu\n# actions=\"&lt;%=\n# [\n# {\n# text: `Test ${CTX.targetCell?.type}`,\n# event: `test-${CTX.targetCell?.type}`,\n# }\n# ]\n# %&gt;\n# \"\n# ></eo-context-menu>\n# \n# <script>\n# const brick_1 = document.getElementById(\"brick-1\");\n# brick_1.activeTarget = \"<%= CTX.activeTarget %>\";\n# brick_1.defaultNodeSize = [60, 60];\n# brick_1.defaultNodeBricks = [\n# {\n# useBrick: {\n# brick: \"diagram.experimental-node\",\n# properties: {\n# textContent: \"<% `Node ${DATA.node.id}` %>\",\n# status:\n# '<%=\\n CTX.activeTarget?.type === \"node\" && CTX.activeTarget.id === DATA.node.id\\n ? \"highlighted\"\\n // : CTX.unrelated.some(n =>\\n // n.type === \"node\" && n.id === DATA.node.id\\n // )\\n // ? \"faded\"\\n : \"default\"\\n%>\\n',\n# },\n# },\n# },\n# ];\n# brick_1.defaultEdgeLines = [\n# {\n# if: true,\n# dashed: \"<% DATA.edge?.data?.virtual %>\",\n# strokeColor: \"<% DATA.edge?.data?.strokeColor %>\",\n# showStartArrow: \"<% DATA.edge?.data?.showStartArrow %>\",\n# strokeWidth: \"<% DATA.edge?.data?.strokeWidth %>\",\n# animate: \"<% DATA.edge?.data?.animate %>\",\n# },\n# ];\n# brick_1.cells = \"<% CTX.initialCells %>\";\n# brick_1.addEventListener(\"activeTarget.change\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_1.addEventListener(\"cell.contextmenu\", (e) => {\n# const brick = document.querySelector(\"eo-context-menu\");\n# brick.open({\n# position: [\"<% EVENT.detail.clientX %>\", \"<% EVENT.detail.clientY %>\"],\n# });\n# });\n# brick_1.addEventListener(\"cell.contextmenu\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# </script>\n# \n```\n"
5
+ "diagram.editable-label": {
6
+ "doc": "---\ntagName: diagram.editable-label\ndisplayName: WrappedDiagramEditableLabel\ndescription: 可编辑标签构件,用于在图表连线或节点上展示可双击编辑的文本标签,支持只读模式,常配合 `eo-draw-canvas` 和 `eo-diagram` 使用。\ncategory: diagram\nsource: \"@next-bricks/diagram\"\n---\n\n# diagram.editable-label\n\n> 可编辑标签构件,用于在图表连线或节点上展示可双击编辑的文本标签,支持只读模式,常配合 `eo-draw-canvas` 和 `eo-diagram` 使用。\n\n## Props\n\n| 属性 | 类型 | 必填 | 默认值 | 说明 |\n| -------- | ------------------------ | ---- | ------ | ------------------------------------------------------------------------------------------------------------------------------ |\n| label | `string \\| undefined` | - | - | 标签文本内容。 |\n| type | `LabelType \\| undefined` | - | - | 标签类型,`line` 用于连线标签样式,`default` 为默认节点标签样式,影响外观渲染(使用 `render: false` 仅更新属性不触发重渲染)。 |\n| readOnly | `boolean \\| undefined` | - | - | 是否为只读模式,启用后双击不会进入编辑状态,`enableEditing` 方法调用也不会生效。 |\n\n## Events\n\n| 事件 | detail | 说明 |\n| -------------------- | ----------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- |\n| label.editing.change | `boolean` — 当前是否处于编辑状态,true 表示正在编辑,false 表示结束编辑 | 标签编辑状态变化时触发,当用户开始编辑(双击或调用 `enableEditing`)或结束编辑(失焦/按 Enter)时触发。 |\n| label.change | `string` — 编辑完成后的新标签文本 | 标签编辑完成后触发(用户失焦或按 Enter 键),即使内容未变化也会触发,需自行判断是否发生实际变更。 |\n\n## Methods\n\n| 方法 | 参数 | 返回值 | 说明 |\n| ------------- | ------------ | ------ | ------------------------------------------------------------------ |\n| enableEditing | `() => void` | `void` | 以编程方式启用标签的编辑状态(相当于用户双击),只读模式下不生效。 |\n\n## Examples\n\n### Basic\n\n展示可编辑标签的基本用法,双击标签可进入编辑模式,失焦或按 Enter 键确认修改。\n\n```yaml preview\nbrick: diagram.editable-label\nproperties:\n type: line\n label: Relation\nevents:\n label.change:\n action: message.success\n args:\n - \"<% `Label changed to: ${EVENT.detail}` %>\"\n# -- YAML DELIMITER (1nbbm8) --\n# <diagram.editable-label\n# type=\"line\"\n# label=\"Relation\"\n# id=\"brick-1\"\n# ></diagram.editable-label>\n# \n# <script>\n# const brick_1 = document.getElementById(\"brick-1\");\n# brick_1.addEventListener(\"label.change\", (e) => {\n# const message = document.createElement(\"basic.show-notification\");\n# message.resolve({\n# type: \"success\",\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# message: \"<% `Label changed to: ${EVENT.detail}` %>\",\n# });\n# });\n# </script>\n# \n```\n\n### Read Only\n\n展示只读模式下的标签,双击不会进入编辑状态。\n\n```yaml preview\nbrick: diagram.editable-label\nproperties:\n type: line\n label: Read Only Label\n readOnly: true\nevents:\n label.change:\n action: message.success\n args:\n - \"<% `Label changed to: ${EVENT.detail}` %>\"\n# -- YAML DELIMITER (1nbbm8) --\n# <diagram.editable-label\n# type=\"line\"\n# label=\"Read Only Label\"\n# read-only\n# id=\"brick-1\"\n# ></diagram.editable-label>\n# \n# <script>\n# const brick_1 = document.getElementById(\"brick-1\");\n# brick_1.addEventListener(\"label.change\", (e) => {\n# const message = document.createElement(\"basic.show-notification\");\n# message.resolve({\n# type: \"success\",\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# message: \"<% `Label changed to: ${EVENT.detail}` %>\",\n# });\n# });\n# </script>\n# \n```\n\n### Editing State Change\n\n展示监听编辑状态变化事件,在用户开始/结束编辑时响应。\n\n```yaml preview\nbrick: diagram.editable-label\nproperties:\n type: default\n label: Click to edit\nevents:\n label.editing.change:\n action: message.info\n args:\n - \"<% EVENT.detail ? 'Editing started' : 'Editing ended' %>\"\n label.change:\n action: message.success\n args:\n - \"<% `New label: ${EVENT.detail}` %>\"\n# -- YAML DELIMITER (1nbbm8) --\n# <diagram.editable-label\n# type=\"default\"\n# label=\"Click to edit\"\n# id=\"brick-1\"\n# ></diagram.editable-label>\n# \n# <script>\n# const brick_1 = document.getElementById(\"brick-1\");\n# brick_1.addEventListener(\"label.editing.change\", (e) => {\n# const message = document.createElement(\"basic.show-notification\");\n# message.resolve({\n# type: \"info\",\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# message: \"<% EVENT.detail ? 'Editing started' : 'Editing ended' %>\",\n# });\n# });\n# brick_1.addEventListener(\"label.change\", (e) => {\n# const message = document.createElement(\"basic.show-notification\");\n# message.resolve({\n# type: \"success\",\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# message: \"<% `New label: ${EVENT.detail}` %>\",\n# });\n# });\n# </script>\n# \n```\n"
10
7
  },
11
8
  "eo-draw-canvas": {
12
- "doc": "用于手工绘图的画布。\n\n注意:将配套另外一个用于展示的画布构件。\n\n## Examples\n\n### Basic\n\n```yaml preview minHeight=\"600px\"\n- brick: div\n properties:\n style:\n display: flex\n height: 600px\n gap: 1em\n context:\n - name: initialCells\n value: |\n <%\n [\n {\n type: \"decorator\",\n id: \"container-1\",\n decorator: \"container\",\n view: {\n direction: \"left\",\n text: \"上层服务\" ,\n level: 1\n },\n },\n {\n type: \"decorator\",\n id: \"container-2\",\n decorator: \"container\",\n view: {\n direction: \"left\",\n text: \"应用\" ,\n level: 2\n },\n },\n {\n type: \"decorator\",\n id: \"group-1\",\n decorator: \"group\",\n containerId: \"container-2\",\n view: {\n usePlus: true, \n },\n },\n {\n type: \"node\",\n id: \"G\",\n groupId: \"group-1\",\n data: {\n name: `Node G`, \n }, \n view: {\n width: 60,\n height: 60,\n }\n },\n {\n type: \"edge\", \n source: \"X\",\n target: \"Y\",\n },\n {\n type: \"edge\",\n source: \"Z\", \n target: \"W\",\n },\n {\n type: \"edge\",\n source: \"X\",\n target: \"Z\",\n data: {\n virtual: true,\n }\n },\n ].concat(\n [\"A\",\"B\",\"C\",\"S\",\"D\",\"F\",\"X\", \"Y\", \"Z\", \"W\"].map((id) => ({\n type: \"node\",\n id,\n containerId: [\"W\",\"Z\",\"X\",\"Y\", \"W\"].includes(id)?\"container-1\":([\"A\",\"B\",].includes(id)?\"container-2\":null),\n groupId: [\"C\",\"S\",\"D\",\"F\",].includes(id)?\"group-1\":null,\n data: {\n name: `Node ${id}`,\n }, \n view: {\n x: [\"A\",\"B\",\"C\",\"S\",\"D\",\"F\",\"Z\",\"X\",\"Y\",].includes(id)?null:Math.round(\n id === \"X\"\n ? 200 + Math.random() * 200\n : id === \"Y\"\n ? Math.random() * 300\n : 300 + Math.random() * 300\n ),\n y: [\"A\",\"B\",\"C\",\"S\",\"D\",\"F\",\"Z\",\"X\",\"Y\"].includes(id)?null:(id === \"X\" ? 0 : 300) + Math.round((Math.random() * 200)),\n width: 60,\n height: 60,\n }\n }))\n ).concat([\n {\n type: \"decorator\",\n id: \"text-1\",\n decorator: \"text\", \n view: {\n x: 300,\n y: 120,\n width: 100,\n height: 20,\n text: \"Hello\\nWorld!\",\n style: {\n // 垂直书写(从右到左)\n writingMode: \"vertical-rl\",\n },\n },\n },\n ])\n %>\n - name: dragging\n - name: activeTarget\n - name: contextMenuDetail\n - name: scale\n value: 1\n children:\n - brick: div\n properties:\n style:\n width: 200px\n display: flex\n flexDirection: column\n gap: 1em\n border-right: \"1px solid var(--palette-gray-6)\"\n overflow: scroll\n children:\n - brick: eo-button\n properties:\n textContent: Add random nodes\n events:\n click:\n target: eo-draw-canvas\n method: addNodes\n args:\n - |\n <%\n ((...seeds) => seeds.map((seed) => ({\n id: seed,\n data: {\n name: String(seed),\n },\n })))(\n Math.round(Math.random() * 1e6),\n Math.round(Math.random() * 1e6),\n Math.round(Math.random() * 1e6),\n )\n %>\n callback:\n success:\n action: console.log\n args:\n - Added nodes\n - <% EVENT.detail %>\n - brick: eo-button\n properties:\n textContent: Add nodes to container-1\n events:\n click:\n target: eo-draw-canvas\n method: addNodes\n args:\n - |\n <%\n ((...seeds) => seeds.map((seed) => ({\n id: seed,\n containerId: \"container-1\",\n data: {\n name: String(seed),\n },\n })))(\n Math.round(Math.random() * 1e6),\n Math.round(Math.random() * 1e6),\n Math.round(Math.random() * 1e6),\n )\n %>\n callback:\n success:\n action: console.log\n args:\n - Added nodes\n - <% EVENT.detail %>\n - brick: eo-button\n properties:\n textContent: \"Add edge: Y => Z\"\n events:\n click:\n target: eo-draw-canvas\n method: addEdge\n args:\n - source: Y\n target: Z\n data:\n virtual: true\n - brick: :forEach\n dataSource:\n - X\n - Y\n children:\n - brick: eo-button\n properties:\n textContent: <% `Add nodes below ${ITEM}` %>\n events:\n click:\n target: eo-draw-canvas\n method: updateCells\n args:\n - |\n <%\n CTX.initialCells.concat([\n {\n type: \"edge\",\n source: ITEM,\n target: \"U\",\n },\n {\n type: \"edge\",\n source: ITEM,\n target: \"V\",\n },\n {\n type: \"node\",\n id: \"U\",\n data: {\n name: \"U\"\n }\n },\n {\n type: \"node\",\n id: \"V\",\n data: {\n name: \"V\"\n }\n },\n ])\n %>\n - reason: add-related-nodes\n parent: <% ITEM %>\n callback:\n success:\n action: console.log\n - brick: hr\n properties:\n style:\n width: 100%\n - brick: h3\n properties:\n textContent: Drag nodes below\n - brick: :forEach\n dataSource: |\n <%\n [\"A\", \"B\", \"C\"].map((id) => ({\n type: \"node\",\n id,\n data: {\n name: `Node ${id}`,\n },\n }))\n %>\n children:\n - brick: diagram.experimental-node\n properties:\n textContent: <% ITEM.data.name %>\n usage: library\n events:\n drag.move:\n action: context.replace\n args:\n - dragging\n - |\n <% {position: EVENT.detail, ...ITEM} %>\n drag.end:\n - action: context.replace\n args:\n - dragging\n - null\n - target: eo-draw-canvas\n method: dropNode\n args:\n - position: <% EVENT.detail %>\n id: <% ITEM.id %>\n data: <% ITEM.data %>\n callback:\n success:\n if: <% EVENT.detail %>\n then:\n action: message.success\n args:\n - <% JSON.stringify(EVENT.detail) %>\n else:\n action: message.warn\n args:\n - Unexpected drop position\n - brick: hr\n properties:\n style:\n width: 100%\n - brick: h3\n properties:\n textContent: Drag decorators below\n - brick: :forEach\n dataSource:\n - area\n - text\n - line\n - rect\n - container.top\n - container.right\n - container.bottom\n - container.left\n children:\n - brick: diagram.experimental-node\n properties:\n textContent: <% _.upperFirst(ITEM) %>\n usage: library\n events:\n drag.move:\n action: context.replace\n args:\n - dragging\n - |\n <% {position: EVENT.detail, type: \"decorator\", decorator: ITEM.split(\".\")[0]} %>\n drag.end:\n - action: context.replace\n args:\n - dragging\n - null\n - target: eo-draw-canvas\n method: dropDecorator\n args:\n - |\n <%\n ITEM === \"line\"\n ? {\n position: EVENT.detail,\n decorator: ITEM.split(\".\")[0],\n }\n : {\n position: EVENT.detail,\n decorator: ITEM.split(\".\")[0],\n text: _.upperFirst(ITEM),\n direction: ITEM.split(\".\").pop(),\n }\n %>\n callback:\n success:\n if: <% !EVENT.detail %>\n action: message.warn\n args:\n - Unexpected drop position\n - brick: div\n properties:\n style:\n flex: 1\n minWidth: 0\n children:\n - brick: eo-draw-canvas\n properties:\n style:\n width: 100%\n height: 100%\n activeTarget: <%= CTX.activeTarget %>\n fadeUnrelatedCells: true\n allowEdgeToArea: true\n dragBehavior: lasso\n layoutOptions:\n # initialLayout: layered-architecture\n initialLayout: layered-staggered\n snap:\n # grid: true\n object: true\n # Initial nodes only\n defaultNodeSize: [60, 60]\n defaultNodeBricks:\n - useBrick:\n brick: diagram.experimental-node\n properties:\n textContent: '<% `Node ${DATA.node.id}${DATA.node.locked ? \" (locked)\" : \"\"}` %>'\n status: |\n <%=\n (CTX.activeTarget?.type === \"multi\"\n ? CTX.activeTarget.targets\n : CTX.activeTarget\n ? [CTX.activeTarget]\n : []\n ).some((target) => (\n target.type === \"node\" && target.id === DATA.node.id\n ))\n ? \"highlighted\"\n : \"default\"\n %>\n defaultEdgeLines:\n - if: <% DATA.edge.data?.virtual %>\n dashed: true\n - if: <% !DATA.edge.data?.virtual %>\n dotted: true\n showStartArrow: true\n markers:\n - placement: start\n type: circle\n - placement: end\n type: arrow\n cells: <% CTX.initialCells %>\n lineConnector: true\n lineSettings:\n type: polyline\n events:\n activeTarget.change:\n action: context.replace\n args:\n - activeTarget\n - <% EVENT.detail %>\n cells.move:\n action: message.info\n args:\n - <% `You just moved ${EVENT.detail.length} cells` %>\n cell.resize:\n action: message.info\n args:\n - <% `You just resized ${EVENT.detail.type} ${EVENT.detail.id} to (${Math.round(EVENT.detail.width)}, ${Math.round(EVENT.detail.height)})` %>\n cells.delete:\n action: message.warn\n args:\n - |\n <% `You wanna delete ${EVENT.detail.length} cells?` %>\n cell.contextmenu:\n - target: eo-context-menu\n method: open\n args:\n - position:\n - <% EVENT.detail.clientX %>\n - <% EVENT.detail.clientY %>\n - action: context.replace\n args:\n - contextMenuDetail\n - <% EVENT.detail %>\n edge.add:\n action: message.info\n args:\n - |\n <% `Added an nice edge: ${JSON.stringify(EVENT.detail)}` %>\n edge.view.change:\n action: message.info\n args:\n - |\n <% `Edge view changed: ${JSON.stringify(EVENT.detail)}` %>\n decorator.view.change:\n action: message.info\n args:\n - |\n <% `Decorator view changed: ${JSON.stringify(EVENT.detail)}` %>\n decorator.text.change:\n action: message.info\n args:\n - <% JSON.stringify(EVENT.detail) %>\n node.container.change:\n action: message.info\n args:\n - <% JSON.stringify(EVENT.detail) %>\n scale.change:\n action: context.replace\n args:\n - scale\n - <% EVENT.detail %>\n- brick: diagram.experimental-node\n properties:\n usage: dragging\n textContent: |\n <%= CTX.dragging?.type === \"decorator\" ? (CTX.dragging.decorator === \"text\" ? \"Text\" : null) : CTX.dragging?.data.name %>\n decorator: |\n <%= CTX.dragging?.type === \"decorator\" ? CTX.dragging.decorator : null %>\n style: |\n <%=\n {\n left: `${CTX.dragging?.position[0]}px`,\n top: `${CTX.dragging?.position[1]}px`,\n transform: `scale(${CTX.scale})`,\n transformOrigin: \"0 0\",\n padding: CTX.dragging?.decorator === \"text\" ? \"0.5em\" : \"0\"\n }\n %>\n hidden: <%= !CTX.dragging %>\n- brick: eo-context-menu\n properties:\n actions: |\n <%=\n !CTX.contextMenuDetail\n ? []\n : CTX.contextMenuDetail.target?.type === \"multi\"\n ? [\n {\n text: \"锁定/取消锁定\",\n event: \"toggle-lock\",\n },\n ]\n : [\n ...(CTX.contextMenuDetail.locked ? [] : [{\n text: \"添加边\",\n event: \"add-edge\",\n },{\n text: \"移除\",\n event: \"remove\"\n }]),\n {\n text: \"锁定/取消锁定\",\n event: \"toggle-lock\",\n },\n ].filter((action) =>\n CTX.contextMenuDetail.cell.type === \"node\" || (\n CTX.contextMenuDetail.cell.type === \"decorator\" &&\n CTX.contextMenuDetail.cell.decorator === \"area\"\n ) || action.event !== \"add-edge\"\n )\n %>\n events:\n remove:\n target: eo-draw-canvas\n method: updateCells\n args:\n - |\n <%\n CTX.initialCells.filter((cell) =>\n !(\n CTX.contextMenuDetail.cell.type === \"edge\"\n ? cell.type === \"edge\" && CTX.contextMenuDetail.cell.source === cell.source && CTX.contextMenuDetail.cell.target === cell.target\n : cell.id === CTX.contextMenuDetail.cell.id ||\n (cell.type === \"edge\" && (\n CTX.contextMenuDetail.cell.id === cell.source ||\n CTX.contextMenuDetail.cell.id === cell.target))\n )\n )\n %>\n add-edge:\n target: eo-draw-canvas\n method: manuallyConnectNodes\n args:\n - <% CTX.contextMenuDetail.cell.id %>\n callback:\n success:\n - target: eo-draw-canvas\n method: addEdge\n args:\n - source: <% EVENT.detail.source.id %>\n target: <% EVENT.detail.target.id %>\n toggle-lock:\n target: eo-draw-canvas\n method: toggleLock\n args:\n - <% CTX.contextMenuDetail.target %>\n callback:\n success:\n action: console.log\n args:\n - \"Updated cells after toggle lock:\"\n - <% EVENT.detail %>\n# -- YAML DELIMITER (1nbbm8) --\n# <div style=\"display: flex; height: 600px; gap: 1em\">\n# <div\n# style=\"\n# width: 200px;\n# display: flex;\n# flex-direction: column;\n# gap: 1em;\n# border-right: 1px solid var(--palette-gray-6);\n# overflow: scroll;\n# \"\n# >\n# <eo-button id=\"brick-1\">Add random nodes</eo-button>\n# <eo-button id=\"brick-2\">Add nodes to container-1</eo-button>\n# <eo-button id=\"brick-3\">Add edge: Y =&gt; Z</eo-button>\n# <!-- WARN: \":forEach\" is not supported in HTML mode, please try YAML. -->\n# <hr style=\"width: 100%\" />\n# <h3>Drag nodes below</h3>\n# <!-- WARN: \":forEach\" is not supported in HTML mode, please try YAML. -->\n# <hr style=\"width: 100%\" />\n# <h3>Drag decorators below</h3>\n# <!-- WARN: \":forEach\" is not supported in HTML mode, please try YAML. -->\n# </div>\n# <div style=\"flex: 1; min-width: 0\">\n# <eo-draw-canvas\n# style=\"width: 100%; height: 100%\"\n# fade-unrelated-cells\n# allow-edge-to-area\n# drag-behavior=\"lasso\"\n# id=\"brick-7\"\n# ></eo-draw-canvas>\n# </div>\n# </div>\n# <diagram.experimental-node\n# usage=\"dragging\"\n# decorator='&lt;%= CTX.dragging?.type === \"decorator\" ? CTX.dragging.decorator : null %&gt;\n# '\n# hidden=\"&lt;%= !CTX.dragging %&gt;\"\n# >\n# &lt;%= CTX.dragging?.type === \"decorator\" ? (CTX.dragging.decorator === \"text\"\n# ? \"Text\" : null) : CTX.dragging?.data.name %&gt;\n# </diagram.experimental-node>\n# <eo-context-menu\n# actions='&lt;%=\n# !CTX.contextMenuDetail\n# ? []\n# : CTX.contextMenuDetail.target?.type === \"multi\"\n# ? [\n# {\n# text: \"锁定/取消锁定\",\n# event: \"toggle-lock\",\n# },\n# ]\n# : [\n# ...(CTX.contextMenuDetail.locked ? [] : [{\n# text: \"添加边\",\n# event: \"add-edge\",\n# },{\n# text: \"移除\",\n# event: \"remove\"\n# }]),\n# {\n# text: \"锁定/取消锁定\",\n# event: \"toggle-lock\",\n# },\n# ].filter((action) =&gt;\n# CTX.contextMenuDetail.cell.type === \"node\" || (\n# CTX.contextMenuDetail.cell.type === \"decorator\" &amp;&amp;\n# CTX.contextMenuDetail.cell.decorator === \"area\"\n# ) || action.event !== \"add-edge\"\n# )\n# %&gt;\n# '\n# id=\"brick-8\"\n# ></eo-context-menu>\n# \n# <script>\n# const brick_1 = document.getElementById(\"brick-1\");\n# brick_1.addEventListener(\"click\", (e) => {\n# const brick = document.querySelector(\"eo-draw-canvas\");\n# brick.addNodes(\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# \"<%\\n ((...seeds) => seeds.map((seed) => ({\\n id: seed,\\n data: {\\n name: String(seed),\\n },\\n })))(\\n Math.round(Math.random() * 1e6),\\n Math.round(Math.random() * 1e6),\\n Math.round(Math.random() * 1e6),\\n )\\n%>\\n\"\n# );\n# });\n# \n# const brick_2 = document.getElementById(\"brick-2\");\n# brick_2.addEventListener(\"click\", (e) => {\n# const brick = document.querySelector(\"eo-draw-canvas\");\n# brick.addNodes(\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# '<%\\n ((...seeds) => seeds.map((seed) => ({\\n id: seed,\\n containerId: \"container-1\",\\n data: {\\n name: String(seed),\\n },\\n })))(\\n Math.round(Math.random() * 1e6),\\n Math.round(Math.random() * 1e6),\\n Math.round(Math.random() * 1e6),\\n )\\n%>\\n'\n# );\n# });\n# \n# const brick_3 = document.getElementById(\"brick-3\");\n# brick_3.addEventListener(\"click\", (e) => {\n# const brick = document.querySelector(\"eo-draw-canvas\");\n# brick.addEdge({ source: \"Y\", target: \"Z\", data: { virtual: true } });\n# });\n# \n# const brick_4 = document.getElementById(\"brick-4\");\n# brick_4.addEventListener(\"click\", (e) => {\n# const brick = document.querySelector(\"eo-draw-canvas\");\n# brick.updateCells(\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# '<%\\n CTX.initialCells.concat([\\n {\\n type: \"edge\",\\n source: ITEM,\\n target: \"U\",\\n },\\n {\\n type: \"edge\",\\n source: ITEM,\\n target: \"V\",\\n },\\n {\\n type: \"node\",\\n id: \"U\",\\n data: {\\n name: \"U\"\\n }\\n },\\n {\\n type: \"node\",\\n id: \"V\",\\n data: {\\n name: \"V\"\\n }\\n },\\n ])\\n%>\\n',\n# { reason: \"add-related-nodes\", parent: \"<% ITEM %>\" }\n# );\n# });\n# \n# const brick_5 = document.getElementById(\"brick-5\");\n# brick_5.addEventListener(\"drag.move\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_5.addEventListener(\"drag.end\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_5.addEventListener(\"drag.end\", (e) => {\n# const brick = document.querySelector(\"eo-draw-canvas\");\n# brick.dropNode({\n# position: \"<% EVENT.detail %>\",\n# id: \"<% ITEM.id %>\",\n# data: \"<% ITEM.data %>\",\n# });\n# });\n# \n# const brick_6 = document.getElementById(\"brick-6\");\n# brick_6.addEventListener(\"drag.move\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_6.addEventListener(\"drag.end\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_6.addEventListener(\"drag.end\", (e) => {\n# const brick = document.querySelector(\"eo-draw-canvas\");\n# brick.dropDecorator(\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# '<%\\n ITEM === \"line\"\\n ? {\\n position: EVENT.detail,\\n decorator: ITEM.split(\".\")[0],\\n }\\n : {\\n position: EVENT.detail,\\n decorator: ITEM.split(\".\")[0],\\n text: _.upperFirst(ITEM),\\n direction: ITEM.split(\".\").pop(),\\n }\\n%>\\n'\n# );\n# });\n# \n# const brick_7 = document.getElementById(\"brick-7\");\n# brick_7.activeTarget = \"<%= CTX.activeTarget %>\";\n# brick_7.layoutOptions = {\n# initialLayout: \"layered-staggered\",\n# snap: {\n# object: true,\n# },\n# };\n# brick_7.defaultNodeSize = [60, 60];\n# brick_7.defaultNodeBricks = [\n# {\n# useBrick: {\n# brick: \"diagram.experimental-node\",\n# properties: {\n# textContent:\n# '<% `Node ${DATA.node.id}${DATA.node.locked ? \" (locked)\" : \"\"}` %>',\n# status:\n# '<%=\\n (CTX.activeTarget?.type === \"multi\"\\n ? CTX.activeTarget.targets\\n : CTX.activeTarget\\n ? [CTX.activeTarget]\\n : []\\n ).some((target) => (\\n target.type === \"node\" && target.id === DATA.node.id\\n ))\\n ? \"highlighted\"\\n : \"default\"\\n%>\\n',\n# },\n# },\n# },\n# ];\n# brick_7.defaultEdgeLines = [\n# {\n# if: \"<% DATA.edge.data?.virtual %>\",\n# dashed: true,\n# },\n# {\n# if: \"<% !DATA.edge.data?.virtual %>\",\n# dotted: true,\n# showStartArrow: true,\n# markers: [\n# {\n# placement: \"start\",\n# type: \"circle\",\n# },\n# {\n# placement: \"end\",\n# type: \"arrow\",\n# },\n# ],\n# },\n# ];\n# brick_7.cells = \"<% CTX.initialCells %>\";\n# brick_7.lineConnector = true;\n# brick_7.lineSettings = {\n# type: \"polyline\",\n# };\n# brick_7.addEventListener(\"activeTarget.change\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_7.addEventListener(\"cells.move\", (e) => {\n# const message = document.createElement(\"basic.show-notification\");\n# message.resolve({\n# type: \"info\",\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# message: \"<% `You just moved ${EVENT.detail.length} cells` %>\",\n# });\n# });\n# brick_7.addEventListener(\"cell.resize\", (e) => {\n# const message = document.createElement(\"basic.show-notification\");\n# message.resolve({\n# type: \"info\",\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# message:\n# \"<% `You just resized ${EVENT.detail.type} ${EVENT.detail.id} to (${Math.round(EVENT.detail.width)}, ${Math.round(EVENT.detail.height)})` %>\",\n# });\n# });\n# brick_7.addEventListener(\"cells.delete\", (e) => {\n# const message = document.createElement(\"basic.show-notification\");\n# message.resolve({\n# type: \"warn\",\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# message: \"<% `You wanna delete ${EVENT.detail.length} cells?` %>\\n\",\n# });\n# });\n# brick_7.addEventListener(\"cell.contextmenu\", (e) => {\n# const brick = document.querySelector(\"eo-context-menu\");\n# brick.open({\n# position: [\"<% EVENT.detail.clientX %>\", \"<% EVENT.detail.clientY %>\"],\n# });\n# });\n# brick_7.addEventListener(\"cell.contextmenu\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_7.addEventListener(\"edge.add\", (e) => {\n# const message = document.createElement(\"basic.show-notification\");\n# message.resolve({\n# type: \"info\",\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# message: \"<% `Added an nice edge: ${JSON.stringify(EVENT.detail)}` %>\\n\",\n# });\n# });\n# brick_7.addEventListener(\"edge.view.change\", (e) => {\n# const message = document.createElement(\"basic.show-notification\");\n# message.resolve({\n# type: \"info\",\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# message: \"<% `Edge view changed: ${JSON.stringify(EVENT.detail)}` %>\\n\",\n# });\n# });\n# brick_7.addEventListener(\"decorator.view.change\", (e) => {\n# const message = document.createElement(\"basic.show-notification\");\n# message.resolve({\n# type: \"info\",\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# message:\n# \"<% `Decorator view changed: ${JSON.stringify(EVENT.detail)}` %>\\n\",\n# });\n# });\n# brick_7.addEventListener(\"decorator.text.change\", (e) => {\n# const message = document.createElement(\"basic.show-notification\");\n# message.resolve({\n# type: \"info\",\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# message: \"<% JSON.stringify(EVENT.detail) %>\",\n# });\n# });\n# brick_7.addEventListener(\"node.container.change\", (e) => {\n# const message = document.createElement(\"basic.show-notification\");\n# message.resolve({\n# type: \"info\",\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# message: \"<% JSON.stringify(EVENT.detail) %>\",\n# });\n# });\n# brick_7.addEventListener(\"scale.change\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# \n# const brick_8 = document.getElementById(\"brick-8\");\n# brick_8.addEventListener(\"remove\", (e) => {\n# const brick = document.querySelector(\"eo-draw-canvas\");\n# brick.updateCells(\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# '<%\\n CTX.initialCells.filter((cell) =>\\n !(\\n CTX.contextMenuDetail.cell.type === \"edge\"\\n ? cell.type === \"edge\" && CTX.contextMenuDetail.cell.source === cell.source && CTX.contextMenuDetail.cell.target === cell.target\\n : cell.id === CTX.contextMenuDetail.cell.id ||\\n (cell.type === \"edge\" && (\\n CTX.contextMenuDetail.cell.id === cell.source ||\\n CTX.contextMenuDetail.cell.id === cell.target))\\n )\\n )\\n%>\\n'\n# );\n# });\n# brick_8.addEventListener(\"add-edge\", (e) => {\n# const brick = document.querySelector(\"eo-draw-canvas\");\n# brick.manuallyConnectNodes(\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# \"<% CTX.contextMenuDetail.cell.id %>\"\n# );\n# });\n# brick_8.addEventListener(\"toggle-lock\", (e) => {\n# const brick = document.querySelector(\"eo-draw-canvas\");\n# brick.toggleLock(\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# \"<% CTX.contextMenuDetail.target %>\"\n# );\n# });\n# </script>\n# \n```\n\n### Line labels\n\n设置连线文字。\n\n```yaml preview minHeight=\"600px\"\n- brick: div\n properties:\n style:\n display: flex\n flexDirection: column\n height: 600px\n gap: 1em\n context:\n - name: initialCells\n value: |\n <%\n [\n {\n type: \"edge\",\n source: \"X\",\n target: \"Y\",\n description: \"X->Y\",\n placement: \"end\",\n view: {\n type: \"polyline\"\n }\n },\n {\n type: \"edge\",\n source: \"X\",\n target: \"Z\"\n },\n {\n type: \"node\",\n id: \"X\",\n data: {\n name: \"Node X\",\n },\n view: {\n x: 100,\n y: 100,\n width: 60,\n height: 60,\n }\n },\n {\n type: \"node\",\n id: \"Y\",\n data: {\n name: \"Node Y\",\n },\n view: {\n x: 0,\n y: 300,\n width: 60,\n height: 60,\n }\n },\n {\n type: \"node\",\n id: \"Z\",\n data: {\n name: \"Node Z\",\n },\n view: {\n x: 300,\n y: 200,\n width: 60,\n height: 60,\n }\n },\n ]\n %>\n - name: activeTarget\n - name: scale\n value: 1\n children:\n - brick: eo-draw-canvas\n properties:\n style:\n width: 100%\n height: 100%\n activeTarget: <%= CTX.activeTarget %>\n fadeUnrelatedCells: true\n dragBehavior: lasso\n layoutOptions:\n snap:\n object: true\n defaultNodeSize: [60, 60]\n defaultNodeBricks:\n - useBrick:\n brick: diagram.experimental-node\n properties:\n textContent: <% `Node ${DATA.node.id}` %>\n status: |\n <%=\n (CTX.activeTarget?.type === \"multi\"\n ? CTX.activeTarget.targets\n : CTX.activeTarget\n ? [CTX.activeTarget]\n : []\n ).some((target) => (\n target.type === \"node\" && target.id === DATA.node.id\n ))\n ? \"highlighted\"\n : \"default\"\n %>\n cells: <% CTX.initialCells %>\n lineConnector: true\n defaultEdgeLines:\n - callLabelOnDoubleClick: enableEditing\n label:\n placement: <% DATA.edge.placement %>\n offset: 10\n useBrick:\n brick: diagram.editable-label\n properties:\n label: <% DATA.edge.description %>\n type: line\n # Set `readOnly: true` for eo-display-canvas\n # readOnly: true\n events:\n label.change:\n # Make sure only trigger update if label actually changed\n if: <% (DATA.edge.description || \"\") !== (EVENT.detail || \"\") %>\n action: context.replace\n args:\n - initialCells\n - |-\n <%\n CTX.initialCells.map((edge) =>\n edge.type === \"edge\" &&\n edge.source === DATA.edge.source &&\n edge.target === DATA.edge.target\n ? { ...edge, description: EVENT.detail }\n : edge\n )\n %>\n events:\n activeTarget.change:\n action: context.replace\n args:\n - activeTarget\n - <% EVENT.detail %>\n cell.delete:\n action: message.warn\n args:\n - |\n <% `You wanna delete ${EVENT.detail.type} ${EVENT.detail.type === \"edge\" ? `(${EVENT.detail.source} => ${EVENT.detail.target})` : EVENT.detail.id}?` %>\n scale.change:\n action: context.replace\n args:\n - scale\n - <% EVENT.detail %>\n# -- YAML DELIMITER (1nbbm8) --\n# <div style=\"display: flex; flex-direction: column; height: 600px; gap: 1em\">\n# <eo-draw-canvas\n# style=\"width: 100%; height: 100%\"\n# fade-unrelated-cells\n# drag-behavior=\"lasso\"\n# id=\"brick-1\"\n# ></eo-draw-canvas>\n# </div>\n# \n# <script>\n# const brick_1 = document.getElementById(\"brick-1\");\n# brick_1.activeTarget = \"<%= CTX.activeTarget %>\";\n# brick_1.layoutOptions = {\n# snap: {\n# object: true,\n# },\n# };\n# brick_1.defaultNodeSize = [60, 60];\n# brick_1.defaultNodeBricks = [\n# {\n# useBrick: {\n# brick: \"diagram.experimental-node\",\n# properties: {\n# textContent: \"<% `Node ${DATA.node.id}` %>\",\n# status:\n# '<%=\\n (CTX.activeTarget?.type === \"multi\"\\n ? CTX.activeTarget.targets\\n : CTX.activeTarget\\n ? [CTX.activeTarget]\\n : []\\n ).some((target) => (\\n target.type === \"node\" && target.id === DATA.node.id\\n ))\\n ? \"highlighted\"\\n : \"default\"\\n%>\\n',\n# },\n# },\n# },\n# ];\n# brick_1.cells = \"<% CTX.initialCells %>\";\n# brick_1.lineConnector = true;\n# brick_1.defaultEdgeLines = [\n# {\n# callLabelOnDoubleClick: \"enableEditing\",\n# label: {\n# placement: \"<% DATA.edge.placement %>\",\n# offset: 10,\n# useBrick: {\n# brick: \"diagram.editable-label\",\n# properties: {\n# label: \"<% DATA.edge.description %>\",\n# type: \"line\",\n# },\n# events: {\n# \"label.change\": {\n# if: '<% (DATA.edge.description || \"\") !== (EVENT.detail || \"\") %>',\n# action: \"context.replace\",\n# args: [\n# \"initialCells\",\n# '<%\\n CTX.initialCells.map((edge) =>\\n edge.type === \"edge\" &&\\n edge.source === DATA.edge.source &&\\n edge.target === DATA.edge.target\\n ? { ...edge, description: EVENT.detail }\\n : edge\\n )\\n%>',\n# ],\n# },\n# },\n# },\n# },\n# },\n# ];\n# brick_1.addEventListener(\"activeTarget.change\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_1.addEventListener(\"cell.delete\", (e) => {\n# const message = document.createElement(\"basic.show-notification\");\n# message.resolve({\n# type: \"warn\",\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# message:\n# '<% `You wanna delete ${EVENT.detail.type} ${EVENT.detail.type === \"edge\" ? `(${EVENT.detail.source} => ${EVENT.detail.target})` : EVENT.detail.id}?` %>\\n',\n# });\n# });\n# brick_1.addEventListener(\"scale.change\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# </script>\n# \n```\n\n### Line settings\n\n设置属性 `lineSettings` 来调整新的连线的样式,例如使用折线或直线。注意,该设置不影响已有的 edge 的连线样式。\n\n```yaml preview minHeight=\"600px\"\n- brick: div\n properties:\n style:\n display: flex\n flexDirection: column\n height: 600px\n gap: 1em\n context:\n - name: initialCells\n value: |\n <%\n [\n {\n type: \"decorator\",\n decorator: \"line\",\n id: \"line-1\",\n view: {\n source: {\n x: 200,\n y: 200,\n },\n target: {\n x: 250,\n y: 150,\n },\n // type: \"polyline\",\n vertices: [\n {\n x: 180,\n y: 125,\n },\n ],\n markers: [{\n placement: \"end\",\n type: \"arrow\",\n }],\n },\n },\n {\n type: \"edge\",\n source: \"X\",\n target: \"Y\",\n },\n {\n type: \"node\",\n id: \"X\",\n data: {\n name: \"Node X\",\n },\n view: {\n x: 100,\n y: 100,\n width: 60,\n height: 60,\n }\n },\n {\n type: \"node\",\n id: \"Y\",\n data: {\n name: \"Node Y\",\n },\n view: {\n x: 0,\n y: 300,\n width: 60,\n height: 60,\n }\n },\n {\n type: \"node\",\n id: \"Z\",\n data: {\n name: \"Node Z\",\n },\n view: {\n x: 300,\n y: 200,\n width: 60,\n height: 60,\n }\n },\n ]\n %>\n - name: dragging\n - name: activeTarget\n - name: targetCell\n - name: scale\n value: 1\n - name: lineType\n value: polyline\n children:\n - brick: div\n children:\n - brick: eo-radio\n properties:\n type: button\n value: polyline\n options:\n - polyline\n - curve\n - straight\n events:\n change:\n action: context.replace\n args:\n - lineType\n - <% EVENT.detail.value %>\n - brick: div\n properties:\n style:\n flex: 1\n minHeight: 0\n children:\n - brick: eo-draw-canvas\n properties:\n style:\n width: 100%\n height: 100%\n activeTarget: <%= CTX.activeTarget %>\n fadeUnrelatedCells: true\n dragBehavior: lasso\n layoutOptions:\n snap:\n object: true\n defaultNodeSize: [60, 60]\n defaultNodeBricks:\n - useBrick:\n brick: diagram.experimental-node\n properties:\n textContent: <% `Node ${DATA.node.id}` %>\n status: |\n <%=\n (CTX.activeTarget?.type === \"multi\"\n ? CTX.activeTarget.targets\n : CTX.activeTarget\n ? [CTX.activeTarget]\n : []\n ).some((target) => (\n target.type === \"node\" && target.id === DATA.node.id\n ))\n ? \"highlighted\"\n : \"default\"\n %>\n cells: <% CTX.initialCells %>\n defaultEdgeLines:\n - jumps: true\n lineConnector: true\n lineSettings: |\n <%= { type: CTX.lineType } %>\n events:\n activeTarget.change:\n action: context.replace\n args:\n - activeTarget\n - <% EVENT.detail %>\n cell.contextmenu:\n - target: eo-context-menu\n method: open\n args:\n - position:\n - <% EVENT.detail.clientX %>\n - <% EVENT.detail.clientY %>\n - action: context.replace\n args:\n - targetCell\n - <% EVENT.detail.cell %>\n edge.add:\n action: message.info\n args:\n - |\n <% `Added an nice edge: ${JSON.stringify(EVENT.detail)}` %>\n edge.view.change:\n action: message.info\n args:\n - |\n <% `Edge view changed: ${JSON.stringify(EVENT.detail)}` %>\n scale.change:\n action: context.replace\n args:\n - scale\n - <% EVENT.detail %>\n- brick: diagram.experimental-node\n properties:\n usage: dragging\n textContent: |\n <%= CTX.dragging?.type === \"decorator\" ? (CTX.dragging.decorator === \"text\" ? \"Text\" : null) : CTX.dragging?.data.name %>\n decorator: |\n <%= CTX.dragging?.type === \"decorator\" ? CTX.dragging.decorator : null %>\n style: |\n <%=\n {\n left: `${CTX.dragging?.position[0]}px`,\n top: `${CTX.dragging?.position[1]}px`,\n transform: `scale(${CTX.scale})`,\n transformOrigin: \"0 0\",\n padding: CTX.dragging?.decorator === \"text\" ? \"0.5em\" : \"0\"\n }\n %>\n hidden: <%= !CTX.dragging %>\n- brick: eo-context-menu\n properties:\n actions: |\n <%=\n ([\"node\"].includes(CTX.targetCell?.type )||CTX.targetCell?.decorator==\"area\") ? [\n {\n text: \"添加边\",\n event: \"add-edge\",\n }\n ] : [\n {\n text: `Test ${CTX.targetCell?.type}`,\n event: `test-${CTX.targetCell?.type}`,\n }\n ]\n %>\n events:\n add-edge:\n target: eo-draw-canvas\n method: manuallyConnectNodes\n args:\n - <% CTX.targetCell.id %>\n callback:\n success:\n - target: eo-draw-canvas\n method: addEdge\n args:\n - source: <% EVENT.detail.source.id %>\n target: <% EVENT.detail.target.id %>\n# -- YAML DELIMITER (1nbbm8) --\n# <div style=\"display: flex; flex-direction: column; height: 600px; gap: 1em\">\n# <div>\n# <eo-radio\n# type=\"button\"\n# value=\"polyline\"\n# options=\"polyline,curve,straight\"\n# id=\"brick-1\"\n# ></eo-radio>\n# </div>\n# <div style=\"flex: 1; min-height: 0\">\n# <eo-draw-canvas\n# style=\"width: 100%; height: 100%\"\n# fade-unrelated-cells\n# drag-behavior=\"lasso\"\n# id=\"brick-2\"\n# ></eo-draw-canvas>\n# </div>\n# </div>\n# <diagram.experimental-node\n# usage=\"dragging\"\n# decorator='&lt;%= CTX.dragging?.type === \"decorator\" ? CTX.dragging.decorator : null %&gt;\n# '\n# hidden=\"&lt;%= !CTX.dragging %&gt;\"\n# >\n# &lt;%= CTX.dragging?.type === \"decorator\" ? (CTX.dragging.decorator === \"text\"\n# ? \"Text\" : null) : CTX.dragging?.data.name %&gt;\n# </diagram.experimental-node>\n# <eo-context-menu\n# actions='&lt;%=\n# ([\"node\"].includes(CTX.targetCell?.type )||CTX.targetCell?.decorator==\"area\") ? [\n# {\n# text: \"添加边\",\n# event: \"add-edge\",\n# }\n# ] : [\n# {\n# text: `Test ${CTX.targetCell?.type}`,\n# event: `test-${CTX.targetCell?.type}`,\n# }\n# ]\n# %&gt;\n# '\n# id=\"brick-3\"\n# ></eo-context-menu>\n# \n# <script>\n# const brick_1 = document.getElementById(\"brick-1\");\n# brick_1.addEventListener(\"change\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# \n# const brick_2 = document.getElementById(\"brick-2\");\n# brick_2.activeTarget = \"<%= CTX.activeTarget %>\";\n# brick_2.layoutOptions = {\n# snap: {\n# object: true,\n# },\n# };\n# brick_2.defaultNodeSize = [60, 60];\n# brick_2.defaultNodeBricks = [\n# {\n# useBrick: {\n# brick: \"diagram.experimental-node\",\n# properties: {\n# textContent: \"<% `Node ${DATA.node.id}` %>\",\n# status:\n# '<%=\\n (CTX.activeTarget?.type === \"multi\"\\n ? CTX.activeTarget.targets\\n : CTX.activeTarget\\n ? [CTX.activeTarget]\\n : []\\n ).some((target) => (\\n target.type === \"node\" && target.id === DATA.node.id\\n ))\\n ? \"highlighted\"\\n : \"default\"\\n%>\\n',\n# },\n# },\n# },\n# ];\n# brick_2.cells = \"<% CTX.initialCells %>\";\n# brick_2.defaultEdgeLines = [\n# {\n# jumps: true,\n# },\n# ];\n# brick_2.lineConnector = true;\n# brick_2.lineSettings = \"<%= { type: CTX.lineType } %>\\n\";\n# brick_2.addEventListener(\"activeTarget.change\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_2.addEventListener(\"cell.contextmenu\", (e) => {\n# const brick = document.querySelector(\"eo-context-menu\");\n# brick.open({\n# position: [\"<% EVENT.detail.clientX %>\", \"<% EVENT.detail.clientY %>\"],\n# });\n# });\n# brick_2.addEventListener(\"cell.contextmenu\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_2.addEventListener(\"edge.add\", (e) => {\n# const message = document.createElement(\"basic.show-notification\");\n# message.resolve({\n# type: \"info\",\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# message: \"<% `Added an nice edge: ${JSON.stringify(EVENT.detail)}` %>\\n\",\n# });\n# });\n# brick_2.addEventListener(\"edge.view.change\", (e) => {\n# const message = document.createElement(\"basic.show-notification\");\n# message.resolve({\n# type: \"info\",\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# message: \"<% `Edge view changed: ${JSON.stringify(EVENT.detail)}` %>\\n\",\n# });\n# });\n# brick_2.addEventListener(\"scale.change\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# \n# const brick_3 = document.getElementById(\"brick-3\");\n# brick_3.addEventListener(\"add-edge\", (e) => {\n# const brick = document.querySelector(\"eo-draw-canvas\");\n# brick.manuallyConnectNodes(\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# \"<% CTX.targetCell.id %>\"\n# );\n# });\n# </script>\n# \n```\n\n### Force layout\n\n```yaml preview minHeight=\"600px\"\n- brick: div\n properties:\n style:\n display: flex\n height: 600px\n gap: 1em\n context:\n - name: initialCells\n value: |\n <%\n [\n {\n type: \"decorator\",\n id: \"area-1\",\n decorator: \"area\",\n view: {\n x: 10,\n y: 20,\n width: 400,\n height: 300,\n },\n },\n {\n type: \"decorator\",\n id: \"container-1\",\n decorator: \"container\",\n view: {\n x: 50,\n y: 400,\n width: 280,\n height: 120,\n direction: \"top\",\n text: \" 上层服务\"\n },\n },\n {\n type: \"edge\",\n source: \"X\",\n target: \"Y\",\n },\n {\n type: \"edge\",\n source: \"X\",\n target: \"Z\",\n data: {\n virtual: true,\n }\n },\n ].concat(\n [\"X\", \"Y\", \"Z\", \"W\"].map((id) => ({\n type: \"node\",\n id,\n containerId: [\"X\",\"Y\",\"Z\"].includes(id)?\"container-1\":undefined,\n data: {\n name: `Node ${id}`,\n },\n view: {\n width: 60,\n height: 60,\n }\n }))\n ).concat([\n {\n type: \"decorator\",\n id: \"text-1\",\n decorator: \"text\",\n view: {\n x: 100,\n y: 120,\n width: 100,\n height: 20,\n text: \"Hello!\"\n },\n },\n ])\n %>\n - name: dragging\n - name: activeTarget\n - name: targetCell\n - name: scale\n value: 1\n children:\n - brick: div\n properties:\n style:\n width: 180px\n display: flex\n flexDirection: column\n gap: 1em\n children:\n - brick: eo-button\n properties:\n textContent: Add random nodes\n events:\n click:\n target: eo-draw-canvas\n method: addNodes\n args:\n - |\n <%\n ((...seeds) => seeds.map((seed) => ({\n id: seed,\n data: {\n name: String(seed),\n },\n })))(\n Math.round(Math.random() * 1e6),\n Math.round(Math.random() * 1e6),\n Math.round(Math.random() * 1e6),\n )\n %>\n callback:\n success:\n action: console.log\n args:\n - Added nodes\n - <% EVENT.detail %>\n - brick: eo-button\n properties:\n textContent: \"Add edge: Y => Z\"\n events:\n click:\n target: eo-draw-canvas\n method: addEdge\n args:\n - source: Y\n target: Z\n data:\n virtual: true\n - brick: :forEach\n dataSource:\n - X\n - Y\n children:\n - brick: eo-button\n properties:\n textContent: <% `Add nodes below ${ITEM}` %>\n events:\n click:\n target: eo-draw-canvas\n method: updateCells\n args:\n - |\n <%\n CTX.initialCells.concat([\n {\n type: \"edge\",\n source: ITEM,\n target: \"U\",\n },\n {\n type: \"edge\",\n source: ITEM,\n target: \"V\",\n },\n {\n type: \"node\",\n id: \"U\",\n data: {\n name: \"U\"\n }\n },\n {\n type: \"node\",\n id: \"V\",\n data: {\n name: \"V\"\n }\n },\n ])\n %>\n - reason: add-related-nodes\n parent: <% ITEM %>\n callback:\n success:\n action: console.log\n - brick: hr\n properties:\n style:\n width: 100%\n - brick: h3\n properties:\n textContent: Drag nodes below\n - brick: :forEach\n dataSource: |\n <%\n [\"A\", \"B\", \"C\"].map((id) => ({\n type: \"node\",\n id,\n data: {\n name: `Node ${id}`,\n },\n }))\n %>\n children:\n - brick: diagram.experimental-node\n properties:\n textContent: <% ITEM.data.name %>\n usage: library\n events:\n drag.move:\n action: context.replace\n args:\n - dragging\n - |\n <% {position: EVENT.detail, ...ITEM} %>\n drag.end:\n - action: context.replace\n args:\n - dragging\n - null\n - target: eo-draw-canvas\n method: dropNode\n args:\n - position: <% EVENT.detail %>\n id: <% ITEM.id %>\n data: <% ITEM.data %>\n callback:\n success:\n if: <% EVENT.detail %>\n then:\n action: message.success\n args:\n - <% JSON.stringify(EVENT.detail) %>\n else:\n action: message.warn\n args:\n - Unexpected drop position\n - brick: hr\n properties:\n style:\n width: 100%\n - brick: h3\n properties:\n textContent: Drag decorators below\n - brick: :forEach\n dataSource:\n - area\n - text\n children:\n - brick: diagram.experimental-node\n properties:\n textContent: <% _.upperFirst(ITEM) %>\n usage: library\n events:\n drag.move:\n action: context.replace\n args:\n - dragging\n - |\n <% {position: EVENT.detail, type: \"decorator\", decorator: ITEM} %>\n drag.end:\n - action: context.replace\n args:\n - dragging\n - null\n - target: eo-draw-canvas\n method: dropDecorator\n args:\n - position: <% EVENT.detail %>\n decorator: <% ITEM %>\n text: '<% ITEM === \"text\" ? \"Text\" : undefined %>'\n callback:\n success:\n if: <% !EVENT.detail %>\n action: message.warn\n args:\n - Unexpected drop position\n - brick: div\n properties:\n style:\n flex: 1\n minWidth: 0\n children:\n - brick: eo-draw-canvas\n properties:\n style:\n width: 100%\n height: 100%\n activeTarget: <%= CTX.activeTarget %>\n fadeUnrelatedCells: true\n layout: force\n # Initial nodes only\n defaultNodeSize: [60, 60]\n defaultNodeBricks:\n - useBrick:\n brick: diagram.experimental-node\n properties:\n textContent: <% `Node ${DATA.node.id}` %>\n status: |\n <%=\n CTX.activeTarget?.type === \"node\" && CTX.activeTarget.id === DATA.node.id\n ? \"highlighted\"\n // : CTX.unrelated.some(n =>\n // n.type === \"node\" && n.id === DATA.node.id\n // )\n // ? \"faded\"\n : \"default\"\n %>\n defaultEdgeLines:\n - if: <% DATA.edge.data?.virtual %>\n dashed: true\n cells: <% CTX.initialCells %>\n events:\n activeTarget.change:\n action: context.replace\n args:\n - activeTarget\n - <% EVENT.detail %>\n cell.move:\n action: message.info\n args:\n - <% `You just moved ${EVENT.detail.type} ${EVENT.detail.id} to (${Math.round(EVENT.detail.x)}, ${Math.round(EVENT.detail.y)})` %>\n cell.resize:\n action: message.info\n args:\n - <% `You just resized ${EVENT.detail.type} ${EVENT.detail.id} to (${Math.round(EVENT.detail.width)}, ${Math.round(EVENT.detail.height)})` %>\n cell.delete:\n action: message.warn\n args:\n - |\n <% `You wanna delete ${EVENT.detail.type} ${EVENT.detail.type === \"edge\" ? `(${EVENT.detail.source} => ${EVENT.detail.target})` : EVENT.detail.id}?` %>\n cell.contextmenu:\n - target: eo-context-menu\n method: open\n args:\n - position:\n - <% EVENT.detail.clientX %>\n - <% EVENT.detail.clientY %>\n - action: context.replace\n args:\n - targetCell\n - <% EVENT.detail.cell %>\n decorator.text.change:\n action: message.info\n args:\n - <% JSON.stringify(EVENT.detail) %>\n scale.change:\n action: context.replace\n args:\n - scale\n - <% EVENT.detail %>\n- brick: diagram.experimental-node\n properties:\n usage: dragging\n textContent: |\n <%= CTX.dragging?.type === \"decorator\" ? (CTX.dragging.decorator === \"text\" ? \"Text\" : null) : CTX.dragging?.data.name %>\n decorator: |\n <%= CTX.dragging?.type === \"decorator\" ? CTX.dragging.decorator : null %>\n style: |\n <%=\n {\n left: `${CTX.dragging?.position[0]}px`,\n top: `${CTX.dragging?.position[1]}px`,\n transform: `scale(${CTX.scale})`,\n transformOrigin: \"0 0\",\n padding: CTX.dragging?.decorator === \"text\" ? \"0.5em\" : \"0\"\n }\n %>\n hidden: <%= !CTX.dragging %>\n- brick: eo-context-menu\n properties:\n actions: |\n <%=\n CTX.targetCell?.type === \"node\" ? [\n {\n text: \"添加边\",\n event: \"add-edge\",\n }\n ] : [\n {\n text: `Test ${CTX.targetCell?.type}`,\n event: `test-${CTX.targetCell?.type}`,\n }\n ]\n %>\n events:\n add-edge:\n target: eo-draw-canvas\n method: manuallyConnectNodes\n args:\n - <% CTX.targetCell.id %>\n callback:\n success:\n target: eo-draw-canvas\n method: addEdge\n args:\n - source: <% EVENT.detail.source.id %>\n target: <% EVENT.detail.target.id %>\n# -- YAML DELIMITER (1nbbm8) --\n# <div style=\"display: flex; height: 600px; gap: 1em\">\n# <div style=\"width: 180px; display: flex; flex-direction: column; gap: 1em\">\n# <eo-button id=\"brick-1\">Add random nodes</eo-button>\n# <eo-button id=\"brick-2\">Add edge: Y =&gt; Z</eo-button>\n# <!-- WARN: \":forEach\" is not supported in HTML mode, please try YAML. -->\n# <hr style=\"width: 100%\" />\n# <h3>Drag nodes below</h3>\n# <!-- WARN: \":forEach\" is not supported in HTML mode, please try YAML. -->\n# <hr style=\"width: 100%\" />\n# <h3>Drag decorators below</h3>\n# <!-- WARN: \":forEach\" is not supported in HTML mode, please try YAML. -->\n# </div>\n# <div style=\"flex: 1; min-width: 0\">\n# <eo-draw-canvas\n# style=\"width: 100%; height: 100%\"\n# fade-unrelated-cells\n# layout=\"force\"\n# id=\"brick-6\"\n# ></eo-draw-canvas>\n# </div>\n# </div>\n# <diagram.experimental-node\n# usage=\"dragging\"\n# decorator='&lt;%= CTX.dragging?.type === \"decorator\" ? CTX.dragging.decorator : null %&gt;\n# '\n# hidden=\"&lt;%= !CTX.dragging %&gt;\"\n# >\n# &lt;%= CTX.dragging?.type === \"decorator\" ? (CTX.dragging.decorator === \"text\"\n# ? \"Text\" : null) : CTX.dragging?.data.name %&gt;\n# </diagram.experimental-node>\n# <eo-context-menu\n# actions='&lt;%=\n# CTX.targetCell?.type === \"node\" ? [\n# {\n# text: \"添加边\",\n# event: \"add-edge\",\n# }\n# ] : [\n# {\n# text: `Test ${CTX.targetCell?.type}`,\n# event: `test-${CTX.targetCell?.type}`,\n# }\n# ]\n# %&gt;\n# '\n# id=\"brick-7\"\n# ></eo-context-menu>\n# \n# <script>\n# const brick_1 = document.getElementById(\"brick-1\");\n# brick_1.addEventListener(\"click\", (e) => {\n# const brick = document.querySelector(\"eo-draw-canvas\");\n# brick.addNodes(\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# \"<%\\n ((...seeds) => seeds.map((seed) => ({\\n id: seed,\\n data: {\\n name: String(seed),\\n },\\n })))(\\n Math.round(Math.random() * 1e6),\\n Math.round(Math.random() * 1e6),\\n Math.round(Math.random() * 1e6),\\n )\\n%>\\n\"\n# );\n# });\n# \n# const brick_2 = document.getElementById(\"brick-2\");\n# brick_2.addEventListener(\"click\", (e) => {\n# const brick = document.querySelector(\"eo-draw-canvas\");\n# brick.addEdge({ source: \"Y\", target: \"Z\", data: { virtual: true } });\n# });\n# \n# const brick_3 = document.getElementById(\"brick-3\");\n# brick_3.addEventListener(\"click\", (e) => {\n# const brick = document.querySelector(\"eo-draw-canvas\");\n# brick.updateCells(\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# '<%\\n CTX.initialCells.concat([\\n {\\n type: \"edge\",\\n source: ITEM,\\n target: \"U\",\\n },\\n {\\n type: \"edge\",\\n source: ITEM,\\n target: \"V\",\\n },\\n {\\n type: \"node\",\\n id: \"U\",\\n data: {\\n name: \"U\"\\n }\\n },\\n {\\n type: \"node\",\\n id: \"V\",\\n data: {\\n name: \"V\"\\n }\\n },\\n ])\\n%>\\n',\n# { reason: \"add-related-nodes\", parent: \"<% ITEM %>\" }\n# );\n# });\n# \n# const brick_4 = document.getElementById(\"brick-4\");\n# brick_4.addEventListener(\"drag.move\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_4.addEventListener(\"drag.end\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_4.addEventListener(\"drag.end\", (e) => {\n# const brick = document.querySelector(\"eo-draw-canvas\");\n# brick.dropNode({\n# position: \"<% EVENT.detail %>\",\n# id: \"<% ITEM.id %>\",\n# data: \"<% ITEM.data %>\",\n# });\n# });\n# \n# const brick_5 = document.getElementById(\"brick-5\");\n# brick_5.addEventListener(\"drag.move\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_5.addEventListener(\"drag.end\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_5.addEventListener(\"drag.end\", (e) => {\n# const brick = document.querySelector(\"eo-draw-canvas\");\n# brick.dropDecorator({\n# position: \"<% EVENT.detail %>\",\n# decorator: \"<% ITEM %>\",\n# text: '<% ITEM === \"text\" ? \"Text\" : undefined %>',\n# });\n# });\n# \n# const brick_6 = document.getElementById(\"brick-6\");\n# brick_6.activeTarget = \"<%= CTX.activeTarget %>\";\n# brick_6.defaultNodeSize = [60, 60];\n# brick_6.defaultNodeBricks = [\n# {\n# useBrick: {\n# brick: \"diagram.experimental-node\",\n# properties: {\n# textContent: \"<% `Node ${DATA.node.id}` %>\",\n# status:\n# '<%=\\n CTX.activeTarget?.type === \"node\" && CTX.activeTarget.id === DATA.node.id\\n ? \"highlighted\"\\n // : CTX.unrelated.some(n =>\\n // n.type === \"node\" && n.id === DATA.node.id\\n // )\\n // ? \"faded\"\\n : \"default\"\\n%>\\n',\n# },\n# },\n# },\n# ];\n# brick_6.defaultEdgeLines = [\n# {\n# if: \"<% DATA.edge.data?.virtual %>\",\n# dashed: true,\n# },\n# ];\n# brick_6.cells = \"<% CTX.initialCells %>\";\n# brick_6.addEventListener(\"activeTarget.change\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_6.addEventListener(\"cell.move\", (e) => {\n# const message = document.createElement(\"basic.show-notification\");\n# message.resolve({\n# type: \"info\",\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# message:\n# \"<% `You just moved ${EVENT.detail.type} ${EVENT.detail.id} to (${Math.round(EVENT.detail.x)}, ${Math.round(EVENT.detail.y)})` %>\",\n# });\n# });\n# brick_6.addEventListener(\"cell.resize\", (e) => {\n# const message = document.createElement(\"basic.show-notification\");\n# message.resolve({\n# type: \"info\",\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# message:\n# \"<% `You just resized ${EVENT.detail.type} ${EVENT.detail.id} to (${Math.round(EVENT.detail.width)}, ${Math.round(EVENT.detail.height)})` %>\",\n# });\n# });\n# brick_6.addEventListener(\"cell.delete\", (e) => {\n# const message = document.createElement(\"basic.show-notification\");\n# message.resolve({\n# type: \"warn\",\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# message:\n# '<% `You wanna delete ${EVENT.detail.type} ${EVENT.detail.type === \"edge\" ? `(${EVENT.detail.source} => ${EVENT.detail.target})` : EVENT.detail.id}?` %>\\n',\n# });\n# });\n# brick_6.addEventListener(\"cell.contextmenu\", (e) => {\n# const brick = document.querySelector(\"eo-context-menu\");\n# brick.open({\n# position: [\"<% EVENT.detail.clientX %>\", \"<% EVENT.detail.clientY %>\"],\n# });\n# });\n# brick_6.addEventListener(\"cell.contextmenu\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_6.addEventListener(\"decorator.text.change\", (e) => {\n# const message = document.createElement(\"basic.show-notification\");\n# message.resolve({\n# type: \"info\",\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# message: \"<% JSON.stringify(EVENT.detail) %>\",\n# });\n# });\n# brick_6.addEventListener(\"scale.change\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# \n# const brick_7 = document.getElementById(\"brick-7\");\n# brick_7.addEventListener(\"add-edge\", (e) => {\n# const brick = document.querySelector(\"eo-draw-canvas\");\n# brick.manuallyConnectNodes(\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# \"<% CTX.targetCell.id %>\"\n# );\n# });\n# </script>\n# \n```\n\n### Dagre layout\n\n```yaml preview minHeight=\"600px\"\n- brick: div\n properties:\n style:\n display: flex\n height: 600px\n gap: 1em\n context:\n - name: initialCells\n value: |\n <%\n [\n {\n type: \"decorator\",\n id: \"area-1\",\n decorator: \"area\",\n view: {\n x: 10,\n y: 20,\n width: 400,\n height: 300,\n },\n },\n {\n type: \"decorator\",\n id: \"container-1\",\n decorator: \"container\",\n view: {\n x: 50,\n y: 400,\n width: 280,\n height: 120,\n direction: \"top\",\n text: \" 上层服务\"\n },\n },\n {\n type: \"edge\",\n source: \"X\",\n target: \"Y\",\n },\n {\n type: \"edge\",\n source: \"X\",\n target: \"Z\",\n data: {\n virtual: true,\n }\n },\n {\n type: \"edge\",\n source: \"Z\",\n target: \"W\",\n },\n ].concat(\n [\"X\", \"Y\", \"Z\", \"W\"].map((id) => ({\n type: \"node\",\n id,\n containerId: [\"W\",\"Z\"].includes(id)?\"container-1\":undefined,\n data: {\n name: `Node ${id}`,\n },\n view: {\n width: 60,\n height: 60,\n }\n }))\n )\n %>\n - name: dragging\n - name: activeTarget\n - name: targetCell\n - name: scale\n value: 1\n children:\n - brick: div\n properties:\n style:\n width: 180px\n display: flex\n flexDirection: column\n gap: 1em\n children:\n - brick: eo-button\n properties:\n textContent: Add random nodes\n events:\n click:\n target: eo-draw-canvas\n method: addNodes\n args:\n - |\n <%\n ((...seeds) => seeds.map((seed) => ({\n id: seed,\n data: {\n name: String(seed),\n },\n })))(\n Math.round(Math.random() * 1e6),\n Math.round(Math.random() * 1e6),\n Math.round(Math.random() * 1e6),\n )\n %>\n callback:\n success:\n action: console.log\n args:\n - Added nodes\n - <% EVENT.detail %>\n - brick: eo-button\n properties:\n textContent: \"Add edge: Y => Z\"\n events:\n click:\n target: eo-draw-canvas\n method: addEdge\n args:\n - source: Y\n target: Z\n data:\n virtual: true\n - brick: :forEach\n dataSource:\n - X\n - Y\n children:\n - brick: eo-button\n properties:\n textContent: <% `Add nodes below ${ITEM}` %>\n events:\n click:\n target: eo-draw-canvas\n method: updateCells\n args:\n - |\n <%\n CTX.initialCells.concat([\n {\n type: \"edge\",\n source: ITEM,\n target: \"U\",\n },\n {\n type: \"edge\",\n source: ITEM,\n target: \"V\",\n },\n {\n type: \"node\",\n id: \"U\",\n data: {\n name: \"U\"\n }\n },\n {\n type: \"node\",\n id: \"V\",\n data: {\n name: \"V\"\n }\n },\n ])\n %>\n - reason: add-related-nodes\n parent: <% ITEM %>\n callback:\n success:\n action: console.log\n - brick: hr\n properties:\n style:\n width: 100%\n - brick: h3\n properties:\n textContent: Drag nodes below\n - brick: :forEach\n dataSource: |\n <%\n [\"A\", \"B\", \"C\"].map((id) => ({\n type: \"node\",\n id,\n data: {\n name: `Node ${id}`,\n },\n }))\n %>\n children:\n - brick: diagram.experimental-node\n properties:\n textContent: <% ITEM.data.name %>\n usage: library\n events:\n drag.move:\n action: context.replace\n args:\n - dragging\n - |\n <% {position: EVENT.detail, ...ITEM} %>\n drag.end:\n - action: context.replace\n args:\n - dragging\n - null\n - target: eo-draw-canvas\n method: dropNode\n args:\n - position: <% EVENT.detail %>\n id: <% ITEM.id %>\n data: <% ITEM.data %>\n callback:\n success:\n if: <% EVENT.detail %>\n then:\n action: message.success\n args:\n - <% JSON.stringify(EVENT.detail) %>\n else:\n action: message.warn\n args:\n - Unexpected drop position\n - brick: hr\n properties:\n style:\n width: 100%\n - brick: h3\n properties:\n textContent: Drag decorators below\n - brick: :forEach\n dataSource:\n - area\n - text\n children:\n - brick: diagram.experimental-node\n properties:\n textContent: <% _.upperFirst(ITEM) %>\n usage: library\n events:\n drag.move:\n action: context.replace\n args:\n - dragging\n - |\n <% {position: EVENT.detail, type: \"decorator\", decorator: ITEM} %>\n drag.end:\n - action: context.replace\n args:\n - dragging\n - null\n - target: eo-draw-canvas\n method: dropDecorator\n args:\n - position: <% EVENT.detail %>\n decorator: <% ITEM %>\n text: '<% ITEM === \"text\" ? \"Text\" : undefined %>'\n callback:\n success:\n if: <% !EVENT.detail %>\n action: message.warn\n args:\n - Unexpected drop position\n - brick: div\n properties:\n style:\n flex: 1\n minWidth: 0\n children:\n - brick: eo-draw-canvas\n properties:\n style:\n width: 100%\n height: 100%\n activeTarget: <%= CTX.activeTarget %>\n fadeUnrelatedCells: true\n layout: dagre\n # Initial nodes only\n defaultNodeSize: [60, 60]\n defaultNodeBricks:\n - useBrick:\n brick: diagram.experimental-node\n properties:\n textContent: <% `Node ${DATA.node.id}` %>\n status: |\n <%=\n CTX.activeTarget?.type === \"node\" && CTX.activeTarget.id === DATA.node.id\n ? \"highlighted\"\n // : CTX.unrelated.some(n =>\n // n.type === \"node\" && n.id === DATA.node.id\n // )\n // ? \"faded\"\n : \"default\"\n %>\n defaultEdgeLines:\n - dashed: <% !!DATA.edge.data?.virtual %>\n strokeColor: var(--palette-blue-6)\n overrides:\n active:\n strokeWidth: <% 2 * (DATA.edge?.data?.strokeWidth ?? 1) %>\n strokeColor: cyan\n cells: <% CTX.initialCells %>\n events:\n activeTarget.change:\n action: context.replace\n args:\n - activeTarget\n - <% EVENT.detail %>\n cell.move:\n action: message.info\n args:\n - <% `You just moved ${EVENT.detail.type} ${EVENT.detail.id} to (${Math.round(EVENT.detail.x)}, ${Math.round(EVENT.detail.y)})` %>\n cell.resize:\n action: message.info\n args:\n - <% `You just resized ${EVENT.detail.type} ${EVENT.detail.id} to (${Math.round(EVENT.detail.width)}, ${Math.round(EVENT.detail.height)})` %>\n cell.delete:\n action: message.warn\n args:\n - |\n <% `You wanna delete ${EVENT.detail.type} ${EVENT.detail.type === \"edge\" ? `(${EVENT.detail.source} => ${EVENT.detail.target})` : EVENT.detail.id}?` %>\n cell.contextmenu:\n - target: eo-context-menu\n method: open\n args:\n - position:\n - <% EVENT.detail.clientX %>\n - <% EVENT.detail.clientY %>\n - action: context.replace\n args:\n - targetCell\n - <% EVENT.detail.cell %>\n decorator.text.change:\n action: message.info\n args:\n - <% JSON.stringify(EVENT.detail) %>\n scale.change:\n action: context.replace\n args:\n - scale\n - <% EVENT.detail %>\n- brick: diagram.experimental-node\n properties:\n usage: dragging\n textContent: |\n <%= CTX.dragging?.type === \"decorator\" ? (CTX.dragging.decorator === \"text\" ? \"Text\" : null) : CTX.dragging?.data.name %>\n decorator: |\n <%= CTX.dragging?.type === \"decorator\" ? CTX.dragging.decorator : null %>\n style: |\n <%=\n {\n left: `${CTX.dragging?.position[0]}px`,\n top: `${CTX.dragging?.position[1]}px`,\n transform: `scale(${CTX.scale})`,\n transformOrigin: \"0 0\",\n padding: CTX.dragging?.decorator === \"text\" ? \"0.5em\" : \"0\"\n }\n %>\n hidden: <%= !CTX.dragging %>\n- brick: eo-context-menu\n properties:\n actions: |\n <%=\n CTX.targetCell?.type === \"node\" ? [\n {\n text: \"添加边\",\n event: \"add-edge\",\n }\n ] : [\n {\n text: `Test ${CTX.targetCell?.type}`,\n event: `test-${CTX.targetCell?.type}`,\n }\n ]\n %>\n events:\n add-edge:\n target: eo-draw-canvas\n method: manuallyConnectNodes\n args:\n - <% CTX.targetCell.id %>\n callback:\n success:\n target: eo-draw-canvas\n method: addEdge\n args:\n - source: <% EVENT.detail.source.id %>\n target: <% EVENT.detail.target.id %>\n# -- YAML DELIMITER (1nbbm8) --\n# <div style=\"display: flex; height: 600px; gap: 1em\">\n# <div style=\"width: 180px; display: flex; flex-direction: column; gap: 1em\">\n# <eo-button id=\"brick-1\">Add random nodes</eo-button>\n# <eo-button id=\"brick-2\">Add edge: Y =&gt; Z</eo-button>\n# <!-- WARN: \":forEach\" is not supported in HTML mode, please try YAML. -->\n# <hr style=\"width: 100%\" />\n# <h3>Drag nodes below</h3>\n# <!-- WARN: \":forEach\" is not supported in HTML mode, please try YAML. -->\n# <hr style=\"width: 100%\" />\n# <h3>Drag decorators below</h3>\n# <!-- WARN: \":forEach\" is not supported in HTML mode, please try YAML. -->\n# </div>\n# <div style=\"flex: 1; min-width: 0\">\n# <eo-draw-canvas\n# style=\"width: 100%; height: 100%\"\n# fade-unrelated-cells\n# layout=\"dagre\"\n# id=\"brick-6\"\n# ></eo-draw-canvas>\n# </div>\n# </div>\n# <diagram.experimental-node\n# usage=\"dragging\"\n# decorator='&lt;%= CTX.dragging?.type === \"decorator\" ? CTX.dragging.decorator : null %&gt;\n# '\n# hidden=\"&lt;%= !CTX.dragging %&gt;\"\n# >\n# &lt;%= CTX.dragging?.type === \"decorator\" ? (CTX.dragging.decorator === \"text\"\n# ? \"Text\" : null) : CTX.dragging?.data.name %&gt;\n# </diagram.experimental-node>\n# <eo-context-menu\n# actions='&lt;%=\n# CTX.targetCell?.type === \"node\" ? [\n# {\n# text: \"添加边\",\n# event: \"add-edge\",\n# }\n# ] : [\n# {\n# text: `Test ${CTX.targetCell?.type}`,\n# event: `test-${CTX.targetCell?.type}`,\n# }\n# ]\n# %&gt;\n# '\n# id=\"brick-7\"\n# ></eo-context-menu>\n# \n# <script>\n# const brick_1 = document.getElementById(\"brick-1\");\n# brick_1.addEventListener(\"click\", (e) => {\n# const brick = document.querySelector(\"eo-draw-canvas\");\n# brick.addNodes(\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# \"<%\\n ((...seeds) => seeds.map((seed) => ({\\n id: seed,\\n data: {\\n name: String(seed),\\n },\\n })))(\\n Math.round(Math.random() * 1e6),\\n Math.round(Math.random() * 1e6),\\n Math.round(Math.random() * 1e6),\\n )\\n%>\\n\"\n# );\n# });\n# \n# const brick_2 = document.getElementById(\"brick-2\");\n# brick_2.addEventListener(\"click\", (e) => {\n# const brick = document.querySelector(\"eo-draw-canvas\");\n# brick.addEdge({ source: \"Y\", target: \"Z\", data: { virtual: true } });\n# });\n# \n# const brick_3 = document.getElementById(\"brick-3\");\n# brick_3.addEventListener(\"click\", (e) => {\n# const brick = document.querySelector(\"eo-draw-canvas\");\n# brick.updateCells(\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# '<%\\n CTX.initialCells.concat([\\n {\\n type: \"edge\",\\n source: ITEM,\\n target: \"U\",\\n },\\n {\\n type: \"edge\",\\n source: ITEM,\\n target: \"V\",\\n },\\n {\\n type: \"node\",\\n id: \"U\",\\n data: {\\n name: \"U\"\\n }\\n },\\n {\\n type: \"node\",\\n id: \"V\",\\n data: {\\n name: \"V\"\\n }\\n },\\n ])\\n%>\\n',\n# { reason: \"add-related-nodes\", parent: \"<% ITEM %>\" }\n# );\n# });\n# \n# const brick_4 = document.getElementById(\"brick-4\");\n# brick_4.addEventListener(\"drag.move\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_4.addEventListener(\"drag.end\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_4.addEventListener(\"drag.end\", (e) => {\n# const brick = document.querySelector(\"eo-draw-canvas\");\n# brick.dropNode({\n# position: \"<% EVENT.detail %>\",\n# id: \"<% ITEM.id %>\",\n# data: \"<% ITEM.data %>\",\n# });\n# });\n# \n# const brick_5 = document.getElementById(\"brick-5\");\n# brick_5.addEventListener(\"drag.move\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_5.addEventListener(\"drag.end\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_5.addEventListener(\"drag.end\", (e) => {\n# const brick = document.querySelector(\"eo-draw-canvas\");\n# brick.dropDecorator({\n# position: \"<% EVENT.detail %>\",\n# decorator: \"<% ITEM %>\",\n# text: '<% ITEM === \"text\" ? \"Text\" : undefined %>',\n# });\n# });\n# \n# const brick_6 = document.getElementById(\"brick-6\");\n# brick_6.activeTarget = \"<%= CTX.activeTarget %>\";\n# brick_6.defaultNodeSize = [60, 60];\n# brick_6.defaultNodeBricks = [\n# {\n# useBrick: {\n# brick: \"diagram.experimental-node\",\n# properties: {\n# textContent: \"<% `Node ${DATA.node.id}` %>\",\n# status:\n# '<%=\\n CTX.activeTarget?.type === \"node\" && CTX.activeTarget.id === DATA.node.id\\n ? \"highlighted\"\\n // : CTX.unrelated.some(n =>\\n // n.type === \"node\" && n.id === DATA.node.id\\n // )\\n // ? \"faded\"\\n : \"default\"\\n%>\\n',\n# },\n# },\n# },\n# ];\n# brick_6.defaultEdgeLines = [\n# {\n# dashed: \"<% !!DATA.edge.data?.virtual %>\",\n# strokeColor: \"var(--palette-blue-6)\",\n# overrides: {\n# active: {\n# strokeWidth: \"<% 2 * (DATA.edge?.data?.strokeWidth ?? 1) %>\",\n# strokeColor: \"cyan\",\n# },\n# },\n# },\n# ];\n# brick_6.cells = \"<% CTX.initialCells %>\";\n# brick_6.addEventListener(\"activeTarget.change\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_6.addEventListener(\"cell.move\", (e) => {\n# const message = document.createElement(\"basic.show-notification\");\n# message.resolve({\n# type: \"info\",\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# message:\n# \"<% `You just moved ${EVENT.detail.type} ${EVENT.detail.id} to (${Math.round(EVENT.detail.x)}, ${Math.round(EVENT.detail.y)})` %>\",\n# });\n# });\n# brick_6.addEventListener(\"cell.resize\", (e) => {\n# const message = document.createElement(\"basic.show-notification\");\n# message.resolve({\n# type: \"info\",\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# message:\n# \"<% `You just resized ${EVENT.detail.type} ${EVENT.detail.id} to (${Math.round(EVENT.detail.width)}, ${Math.round(EVENT.detail.height)})` %>\",\n# });\n# });\n# brick_6.addEventListener(\"cell.delete\", (e) => {\n# const message = document.createElement(\"basic.show-notification\");\n# message.resolve({\n# type: \"warn\",\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# message:\n# '<% `You wanna delete ${EVENT.detail.type} ${EVENT.detail.type === \"edge\" ? `(${EVENT.detail.source} => ${EVENT.detail.target})` : EVENT.detail.id}?` %>\\n',\n# });\n# });\n# brick_6.addEventListener(\"cell.contextmenu\", (e) => {\n# const brick = document.querySelector(\"eo-context-menu\");\n# brick.open({\n# position: [\"<% EVENT.detail.clientX %>\", \"<% EVENT.detail.clientY %>\"],\n# });\n# });\n# brick_6.addEventListener(\"cell.contextmenu\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_6.addEventListener(\"decorator.text.change\", (e) => {\n# const message = document.createElement(\"basic.show-notification\");\n# message.resolve({\n# type: \"info\",\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# message: \"<% JSON.stringify(EVENT.detail) %>\",\n# });\n# });\n# brick_6.addEventListener(\"scale.change\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# \n# const brick_7 = document.getElementById(\"brick-7\");\n# brick_7.addEventListener(\"add-edge\", (e) => {\n# const brick = document.querySelector(\"eo-draw-canvas\");\n# brick.manuallyConnectNodes(\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# \"<% CTX.targetCell.id %>\"\n# );\n# });\n# </script>\n# \n```\n"
9
+ "doc": "---\ntagName: eo-draw-canvas\ndisplayName: WrappedEoDrawCanvas\ndescription: \"用于手工绘图的画布构件,支持节点拖放、连线绘制、元素移动/缩放/删除等交互操作,配合展示画布(eo-display-canvas)使用。\"\ncategory: diagram\nsource: \"@next-bricks/diagram\"\n---\n\n# eo-draw-canvas\n\n> 用于手工绘图的画布构件,支持节点拖放、连线绘制、元素移动/缩放/删除等交互操作,配合展示画布(eo-display-canvas)使用。\n\n## Props\n\n| 属性 | 类型 | 必填 | 默认值 | 说明 |\n| ----------------------------------- | ------------------------------ | ---- | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| cells | `InitialCell[]` | - | - | 初始化画布单元格数据,包含节点(node)、边(edge)和装饰器(decorator)。仅当初始化时使用,渲染后重新设置 `cells` 将无效,请使用 `updateCells` 方法代替。 |\n| layout | `LayoutType` | ✅ | - | 画布布局类型,支持 `manual`(手动定位)、`force`(力导向)、`dagre`(层次有向图)。 |\n| layoutOptions | `LayoutOptions` | - | - | 布局算法选项,根据 layout 类型不同,支持不同参数(如 dagre 的 ranksep/nodesep 等)。 |\n| defaultNodeSize | `SizeTuple` | - | `[20, 20]` | 节点默认尺寸,格式为 `[width, height]`,在节点未指定尺寸时使用。 |\n| defaultNodeBricks | `NodeBrickConf[]` | - | - | 节点默认砖块配置,指定渲染节点的自定义构件,可按节点类型匹配不同配置。 |\n| degradedThreshold | `number` | - | - | 当节点数量达到或超过 `degradedThreshold` 时,节点将被降级展示。 |\n| degradedNodeLabel | `string` | - | - | 设置节点将降级展示时显示的名称。 |\n| defaultEdgeLines | `EdgeLineConf[]` | - | - | 使用条件判断设置默认的边对应的连线。在 `if` 表达式中 `DATA` 为 `{ edge }`。 |\n| activeTarget | `ActiveTarget \\| null` | - | - | 当前激活目标,可以是节点、边或装饰器,为 null 表示无激活目标。 |\n| fadeUnrelatedCells | `boolean` | - | - | 当 `activeTarget` 不为 `null` 时,隐藏其他跟该 `activeTarget` 无关的元素,高亮相关节点和边。 |\n| zoomable | `boolean` | - | `true` | 是否允许通过鼠标滚轮或触控板捏合手势缩放画布,默认为 true。 |\n| scrollable | `boolean` | - | `true` | 是否允许通过滚轮平移画布(非捏合手势),默认为 true。 |\n| pannable | `boolean` | - | `true` | 是否允许通过鼠标拖拽平移画布,默认为 true。 |\n| allowEdgeToArea | `boolean` | - | `false` | 是否允许将边连接到区域(area)装饰器,默认为 false。 |\n| dragBehavior | `DragBehavior` | - | - | 按住鼠标拖动时的行为:`none`(无)、`lasso`(绘制选区)、`grab`(拖动画布)。 |\n| ctrlDragBehavior | `CtrlDragBehavior` | - | - | 按住 ctrl 键并按住鼠标拖动时的行为:`none`(无)、`grab`(拖动画布)。 |\n| scaleRange | `RangeTuple` | - | - | 缩放比例范围,格式为 `[min, max]`,默认范围由内部常量决定。 |\n| lineSettings | `LineSettings` | - | - | 连线设置,包含连线类型、箭头等属性,用于新建连线时的默认样式。 |\n| lineConnector | `LineConnecterConf \\| boolean` | - | - | 连线连接器配置,设置为 `true` 或配置对象以启用智能连线功能,允许从节点边缘拖出连线。 |\n| doNotResetActiveTargetForSelector | `string` | - | - | 选择器,点击该选择器对应的元素时不重置 `activeTarget`。 |\n| doNotResetActiveTargetOutsideCanvas | `boolean` | - | - | 在画布外点击时不重置 `activeTarget`。 |\n\n## Events\n\n| 事件 | detail | 说明 |\n| -------------------------- | -------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |\n| activeTarget.change | `ActiveTarget \\| null` — 当前激活目标,节点/边/装饰器对象或 null | 激活目标变化时触发,当用户点击节点、边或装饰器使其激活,或点击空白处取消激活时触发。 |\n| node.move | `MoveCellPayload` — 移动的节点信息,包含节点 id 和新位置 | 节点被拖拽移动后触发(已废弃,请使用 `cell.move`)。 |\n| cell.move | `MoveCellPayload` — 移动的单元格信息,包含单元格 id、类型和新位置 | 单个单元格(节点或装饰器)被拖拽移动后触发。 |\n| cells.move | `MoveCellPayload[]` — 移动的多个单元格信息列表 | 多个单元格(通过框选后拖拽)同时被移动后触发。 |\n| cell.resize | `ResizeCellPayload` — 调整大小的单元格信息,包含单元格 id 和新尺寸 | 单元格(节点或装饰器)被手动调整大小后触发。 |\n| node.delete | `Cell` — 被删除的节点 cell 对象 | 节点被删除时触发(已废弃,请使用 `cell.delete`)。 |\n| cell.delete | `Cell` — 被删除的单元格对象,包含节点、边或装饰器 | 单个单元格被删除时触发(用户按 Delete 键或通过菜单删除)。 |\n| cells.delete | `Cell[]` — 被批量删除的单元格对象列表 | 多个单元格被同时删除时触发(框选后批量删除)。 |\n| cell.contextmenu | `CellContextMenuDetail` — 右键菜单详情,包含 `{ cell: 对应的单元格, clientX: 鼠标X坐标, clientY: 鼠标Y坐标 }` | 用户右键点击节点、边或装饰器时触发,常用于弹出上下文菜单。 |\n| edge.add | `ConnectNodesDetail` — 新边详情,包含 `{ source: 起始节点 id, target: 目标节点 id }` | 通过画布绘图的方式添加边时触发(手动调用 `addEdge` 方法不会触发该事件)。 |\n| edge.view.change | `EdgeViewChangePayload` — 边视图变更详情,包含边 id 和新的视图属性 | 用户通过拖拽手柄修改连线路径或形状时触发。 |\n| decorator.view.change | `DecoratorViewChangePayload` — 装饰器视图变更详情,包含装饰器 id 和新的位置/尺寸 | 装饰器(area、container、text 等)被移动或调整大小时触发。 |\n| decorator.text.change | `DecoratorTextChangeDetail` — 文本变更详情,包含装饰器 id 和新的文本内容 | 装饰器文本(area/container/text 的文字)被编辑并确认后触发。 |\n| node.container.change | `MoveCellPayload[]` — 节点与容器关系变更详情列表,有 containerCell 则为新增关系,否则为删除关系 | 节点与容器组(container 装饰器)的包含关系发生变化时触发,包括拖入、拖出容器。 |\n| decorator.group.plus.click | `DecoratorCell` — 被点击加号按钮的分组容器 cell 对象 | 分组容器(group 装饰器)的加号按钮被点击时触发,用于触发在组内添加新节点的逻辑。 |\n| scale.change | `number` — 当前缩放比例值(如 1.0 表示 100%) | 画布缩放比例变化时触发,从素材库拖拽元素进画布时,拖拽图像应设置对应的缩放比例。 |\n| canvas.contextmenu | `CanvasContextMenuDetail` — 右键菜单详情,包含 `{ clientX: 鼠标X坐标, clientY: 鼠标Y坐标, view: 画布坐标 { x, y } }` | 用户在画布空白处右键点击时触发,常用于弹出画布级别的上下文菜单。 |\n| canvas.copy | `void` | 用户触发复制操作(Ctrl+C)时触发,外部需自行处理复制逻辑。 |\n| canvas.paste | `void` | 用户触发粘贴操作(Ctrl+V)时触发,外部需自行处理粘贴逻辑。 |\n| canvas.group | `void` | 用户触发分组操作(Ctrl+G)时触发,外部需自行处理分组逻辑。 |\n| canvas.ungroup | `void` | 用户触发取消分组操作(Ctrl+Shift+G)时触发,外部需自行处理解组逻辑。 |\n\n## Methods\n\n| 方法 | 参数 | 返回值 | 说明 |\n| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |\n| dropNode | <ul><li>`info: DropNodeInfo` - 拖放节点信息,包含节点 id、拖放位置(clientX/clientY)、尺寸和数据</li></ul> | `Promise<NodeCell \\| null>` | 将一个节点拖放到画布中指定位置。如果放置位置不在画布内,则返回 null。 |\n| dropDecorator | <ul><li>`info: DropDecoratorInfo` - 拖放装饰器信息,包含装饰器类型、拖放位置、文本和方向等</li></ul> | `Promise<DecoratorCell \\| null>` | 将一个装饰器(area、container、text、line 等)拖放到画布中指定位置。如果放置位置不在画布内,则返回 null。 |\n| addNodes | <ul><li>`nodes: AddNodeInfo[]` - 要添加的节点信息列表,每项包含 id、数据、尺寸等</li></ul> | `Promise<NodeCell[]>` | 批量添加节点到画布,节点位置由布局算法自动计算。 |\n| addEdge | <ul><li>`info: AddEdgeInfo` - 边信息,包含 source(起始节点 id)、target(目标节点 id)和可选的 data</li></ul> | `Promise<EdgeCell>` | 以编程方式添加一条边(连线)到画布。注意:此方法不会触发 `edge.add` 事件。 |\n| manuallyConnectNodes | <ul><li>`source: NodeId` - 起始节点的 id</li></ul> | `Promise<ConnectNodesDetail>` | 以编程方式启动从指定源节点到目标节点的手动连线流程,等待用户在画布上点击目标节点后返回连线详情。 |\n| updateCells | <ul><li>`cells: InitialCell[]` - 新的单元格数据列表</li><li>`ctx?: UpdateCellsContext` - 可选的更新上下文,用于指定更新原因和位置参考节点</li></ul> | `Promise<{ updated: Cell[] }>` | 更新画布中的单元格数据,支持增量更新(新增、修改),已渲染的画布使用此方法代替直接设置 `cells` 属性。 |\n| reCenter | - | `void` | 将画布视图重置并居中,使所有单元格重新显示在视口中央。 |\n| toggleLock | <ul><li>`target: ActiveTarget` - 当前选中的目标</li></ul> | `Promise<Cell[] \\| null>` | 切换锁定状态。如果目标中包含未锁定且可以锁定的元素,则将这些元素锁定;否则,如果目标中包含已锁定且可以解锁的元素,则将这些元素解锁。 |\n| lock | <ul><li>`target: ActiveTarget` - 当前选中的目标</li></ul> | `Promise<Cell[] \\| null>` | 锁定选中的目标。规则类似 `toggleLock`,但仅执行锁定操作。 |\n| unlock | <ul><li>`target: ActiveTarget` - 当前选中的目标</li></ul> | `Promise<Cell[] \\| null>` | 解锁选中的目标。规则类似 `toggleLock`,但仅执行解锁操作。 |\n\n## Examples\n\n### Basic\n\n基础绘图画布示例,展示手动布局(manual)下的节点拖放、连线绘制、装饰器(area/text/line/rect/container)添加、右键菜单(删除/添加边/锁定)等交互功能。\n\n```yaml preview minHeight=\"600px\"\n- brick: div\n properties:\n style:\n display: flex\n height: 600px\n gap: 1em\n context:\n - name: initialCells\n value: |\n <%\n [\n {\n type: \"decorator\",\n id: \"container-1\",\n decorator: \"container\",\n view: {\n direction: \"left\",\n text: \"上层服务\" ,\n level: 1\n },\n },\n {\n type: \"decorator\",\n id: \"container-2\",\n decorator: \"container\",\n view: {\n direction: \"left\",\n text: \"应用\" ,\n level: 2\n },\n },\n {\n type: \"decorator\",\n id: \"group-1\",\n decorator: \"group\",\n containerId: \"container-2\",\n view: {\n usePlus: true,\n },\n },\n {\n type: \"node\",\n id: \"G\",\n groupId: \"group-1\",\n data: {\n name: `Node G`,\n },\n view: {\n width: 60,\n height: 60,\n }\n },\n {\n type: \"edge\",\n source: \"X\",\n target: \"Y\",\n },\n {\n type: \"edge\",\n source: \"Z\",\n target: \"W\",\n },\n {\n type: \"edge\",\n source: \"X\",\n target: \"Z\",\n data: {\n virtual: true,\n }\n },\n ].concat(\n [\"A\",\"B\",\"C\",\"S\",\"D\",\"F\",\"X\", \"Y\", \"Z\", \"W\"].map((id) => ({\n type: \"node\",\n id,\n containerId: [\"W\",\"Z\",\"X\",\"Y\", \"W\"].includes(id)?\"container-1\":([\"A\",\"B\",].includes(id)?\"container-2\":null),\n groupId: [\"C\",\"S\",\"D\",\"F\",].includes(id)?\"group-1\":null,\n data: {\n name: `Node ${id}`,\n },\n view: {\n x: [\"A\",\"B\",\"C\",\"S\",\"D\",\"F\",\"Z\",\"X\",\"Y\",].includes(id)?null:Math.round(\n id === \"X\"\n ? 200 + Math.random() * 200\n : id === \"Y\"\n ? Math.random() * 300\n : 300 + Math.random() * 300\n ),\n y: [\"A\",\"B\",\"C\",\"S\",\"D\",\"F\",\"Z\",\"X\",\"Y\"].includes(id)?null:(id === \"X\" ? 0 : 300) + Math.round((Math.random() * 200)),\n width: 60,\n height: 60,\n }\n }))\n ).concat([\n {\n type: \"decorator\",\n id: \"text-1\",\n decorator: \"text\",\n view: {\n x: 300,\n y: 120,\n width: 100,\n height: 20,\n text: \"Hello\\nWorld!\",\n style: {\n // 垂直书写(从右到左)\n writingMode: \"vertical-rl\",\n },\n },\n },\n ])\n %>\n - name: dragging\n - name: activeTarget\n - name: contextMenuDetail\n - name: scale\n value: 1\n children:\n - brick: div\n properties:\n style:\n width: 200px\n display: flex\n flexDirection: column\n gap: 1em\n border-right: \"1px solid var(--palette-gray-6)\"\n overflow: scroll\n children:\n - brick: eo-button\n properties:\n textContent: Add random nodes\n events:\n click:\n target: eo-draw-canvas\n method: addNodes\n args:\n - |\n <%\n ((...seeds) => seeds.map((seed) => ({\n id: seed,\n data: {\n name: String(seed),\n },\n })))(\n Math.round(Math.random() * 1e6),\n Math.round(Math.random() * 1e6),\n Math.round(Math.random() * 1e6),\n )\n %>\n callback:\n success:\n action: console.log\n args:\n - Added nodes\n - <% EVENT.detail %>\n - brick: eo-button\n properties:\n textContent: Re-center\n events:\n click:\n target: eo-draw-canvas\n method: reCenter\n - brick: eo-button\n properties:\n textContent: \"Add edge: Y => Z\"\n events:\n click:\n target: eo-draw-canvas\n method: addEdge\n args:\n - source: Y\n target: Z\n data:\n virtual: true\n - brick: :forEach\n dataSource:\n - X\n - Y\n children:\n - brick: eo-button\n properties:\n textContent: <% `Add nodes below ${ITEM}` %>\n events:\n click:\n target: eo-draw-canvas\n method: updateCells\n args:\n - |\n <%\n CTX.initialCells.concat([\n {\n type: \"edge\",\n source: ITEM,\n target: \"U\",\n },\n {\n type: \"edge\",\n source: ITEM,\n target: \"V\",\n },\n {\n type: \"node\",\n id: \"U\",\n data: {\n name: \"U\"\n }\n },\n {\n type: \"node\",\n id: \"V\",\n data: {\n name: \"V\"\n }\n },\n ])\n %>\n - reason: add-related-nodes\n parent: <% ITEM %>\n callback:\n success:\n action: console.log\n - brick: hr\n properties:\n style:\n width: 100%\n - brick: h3\n properties:\n textContent: Drag nodes below\n - brick: :forEach\n dataSource: |\n <%\n [\"A\", \"B\", \"C\"].map((id) => ({\n type: \"node\",\n id,\n data: {\n name: `Node ${id}`,\n },\n }))\n %>\n children:\n - brick: diagram.experimental-node\n properties:\n textContent: <% ITEM.data.name %>\n usage: library\n events:\n drag.move:\n action: context.replace\n args:\n - dragging\n - |\n <% {position: EVENT.detail, ...ITEM} %>\n drag.end:\n - action: context.replace\n args:\n - dragging\n - null\n - target: eo-draw-canvas\n method: dropNode\n args:\n - position: <% EVENT.detail %>\n id: <% ITEM.id %>\n data: <% ITEM.data %>\n callback:\n success:\n if: <% EVENT.detail %>\n then:\n action: message.success\n args:\n - <% JSON.stringify(EVENT.detail) %>\n else:\n action: message.warn\n args:\n - Unexpected drop position\n - brick: hr\n properties:\n style:\n width: 100%\n - brick: h3\n properties:\n textContent: Drag decorators below\n - brick: :forEach\n dataSource:\n - area\n - text\n - line\n - rect\n - container.top\n - container.right\n - container.bottom\n - container.left\n children:\n - brick: diagram.experimental-node\n properties:\n textContent: <% _.upperFirst(ITEM) %>\n usage: library\n events:\n drag.move:\n action: context.replace\n args:\n - dragging\n - |\n <% {position: EVENT.detail, type: \"decorator\", decorator: ITEM.split(\".\")[0]} %>\n drag.end:\n - action: context.replace\n args:\n - dragging\n - null\n - target: eo-draw-canvas\n method: dropDecorator\n args:\n - |\n <%\n ITEM === \"line\"\n ? {\n position: EVENT.detail,\n decorator: ITEM.split(\".\")[0],\n }\n : {\n position: EVENT.detail,\n decorator: ITEM.split(\".\")[0],\n text: ITEM === \"text\" ? \"Text\" : undefined,\n direction: ITEM.split(\".\")[1],\n }\n %>\n callback:\n success:\n if: <% !EVENT.detail %>\n action: message.warn\n args:\n - Unexpected drop position\n - brick: div\n properties:\n style:\n flex: 1\n minWidth: 0\n children:\n - brick: eo-draw-canvas\n properties:\n style:\n width: 100%\n height: 100%\n activeTarget: <%= CTX.activeTarget %>\n fadeUnrelatedCells: true\n dragBehavior: lasso\n layoutOptions:\n snap:\n object: true\n defaultNodeSize: [60, 60]\n defaultNodeBricks:\n - useBrick:\n brick: diagram.experimental-node\n properties:\n textContent: <% `Node ${DATA.node.id}` %>\n status: |\n <%=\n (CTX.activeTarget?.type === \"multi\"\n ? CTX.activeTarget.targets\n : CTX.activeTarget\n ? [CTX.activeTarget]\n : []\n ).some((target) => (\n target.type === \"node\" && target.id === DATA.node.id\n ))\n ? \"highlighted\"\n : \"default\"\n %>\n defaultEdgeLines:\n - if: <% DATA.edge.data?.virtual %>\n dashed: true\n - if: <% !DATA.edge.data?.virtual %>\n dotted: true\n showStartArrow: true\n markers:\n - placement: start\n type: circle\n - placement: end\n type: arrow\n cells: <% CTX.initialCells %>\n lineConnector: true\n lineSettings:\n type: polyline\n events:\n activeTarget.change:\n action: context.replace\n args:\n - activeTarget\n - <% EVENT.detail %>\n cells.move:\n action: message.info\n args:\n - <% `You just moved ${EVENT.detail.length} cells` %>\n cell.resize:\n action: message.info\n args:\n - <% `You just resized ${EVENT.detail.type} ${EVENT.detail.id} to (${Math.round(EVENT.detail.width)}, ${Math.round(EVENT.detail.height)})` %>\n cells.delete:\n action: message.warn\n args:\n - |\n <% `You wanna delete ${EVENT.detail.length} cells?` %>\n cell.contextmenu:\n - target: eo-context-menu\n method: open\n args:\n - position:\n - <% EVENT.detail.clientX %>\n - <% EVENT.detail.clientY %>\n - action: context.replace\n args:\n - contextMenuDetail\n - <% EVENT.detail %>\n edge.add:\n action: message.info\n args:\n - |\n <% `Added an nice edge: ${JSON.stringify(EVENT.detail)}` %>\n edge.view.change:\n action: message.info\n args:\n - |\n <% `Edge view changed: ${JSON.stringify(EVENT.detail)}` %>\n decorator.view.change:\n action: message.info\n args:\n - |\n <% `Decorator view changed: ${JSON.stringify(EVENT.detail)}` %>\n decorator.text.change:\n action: message.info\n args:\n - <% JSON.stringify(EVENT.detail) %>\n node.container.change:\n action: message.info\n args:\n - <% JSON.stringify(EVENT.detail) %>\n scale.change:\n action: context.replace\n args:\n - scale\n - <% EVENT.detail %>\n- brick: diagram.experimental-node\n properties:\n usage: dragging\n textContent: |\n <%= CTX.dragging?.type === \"decorator\" ? (CTX.dragging.decorator === \"text\" ? \"Text\" : null) : CTX.dragging?.data.name %>\n decorator: |\n <%= CTX.dragging?.type === \"decorator\" ? CTX.dragging.decorator : null %>\n style: |\n <%=\n {\n left: `${CTX.dragging?.position[0]}px`,\n top: `${CTX.dragging?.position[1]}px`,\n transform: `scale(${CTX.scale})`,\n transformOrigin: \"0 0\",\n padding: CTX.dragging?.decorator === \"text\" ? \"0.5em\" : \"0\"\n }\n %>\n hidden: <%= !CTX.dragging %>\n- brick: eo-context-menu\n properties:\n actions: |\n <%=\n !CTX.contextMenuDetail\n ? []\n : CTX.contextMenuDetail.target?.type === \"multi\"\n ? [\n {\n text: \"锁定/取消锁定\",\n event: \"toggle-lock\",\n },\n ]\n : [\n ...(CTX.contextMenuDetail.locked ? [] : [{\n text: \"添加边\",\n event: \"add-edge\",\n },{\n text: \"移除\",\n event: \"remove\"\n }]),\n {\n text: \"锁定/取消锁定\",\n event: \"toggle-lock\",\n },\n ].filter((action) =>\n CTX.contextMenuDetail.cell.type === \"node\" || (\n CTX.contextMenuDetail.cell.type === \"decorator\" &&\n CTX.contextMenuDetail.cell.decorator === \"area\"\n ) || action.event !== \"add-edge\"\n )\n %>\n events:\n remove:\n target: eo-draw-canvas\n method: updateCells\n args:\n - |\n <%\n CTX.initialCells.filter((cell) =>\n !(\n CTX.contextMenuDetail.cell.type === \"edge\"\n ? cell.type === \"edge\" && CTX.contextMenuDetail.cell.source === cell.source && CTX.contextMenuDetail.cell.target === cell.target\n : cell.id === CTX.contextMenuDetail.cell.id ||\n (cell.type === \"edge\" && (\n CTX.contextMenuDetail.cell.id === cell.source ||\n CTX.contextMenuDetail.cell.id === cell.target))\n )\n )\n %>\n add-edge:\n target: eo-draw-canvas\n method: manuallyConnectNodes\n args:\n - <% CTX.contextMenuDetail.cell.id %>\n callback:\n success:\n - target: eo-draw-canvas\n method: addEdge\n args:\n - source: <% EVENT.detail.source.id %>\n target: <% EVENT.detail.target.id %>\n toggle-lock:\n target: eo-draw-canvas\n method: toggleLock\n args:\n - <% CTX.contextMenuDetail.target %>\n callback:\n success:\n action: console.log\n args:\n - \"Updated cells after toggle lock:\"\n - <% EVENT.detail %>\n# -- YAML DELIMITER (1nbbm8) --\n# <div style=\"display: flex; height: 600px; gap: 1em\">\n# <div\n# style=\"\n# width: 200px;\n# display: flex;\n# flex-direction: column;\n# gap: 1em;\n# border-right: 1px solid var(--palette-gray-6);\n# overflow: scroll;\n# \"\n# >\n# <eo-button id=\"brick-1\">Add random nodes</eo-button>\n# <eo-button id=\"brick-2\">Re-center</eo-button>\n# <eo-button id=\"brick-3\">Add edge: Y =&gt; Z</eo-button>\n# <!-- WARN: \":forEach\" is not supported in HTML mode, please try YAML. -->\n# <hr style=\"width: 100%\" />\n# <h3>Drag nodes below</h3>\n# <!-- WARN: \":forEach\" is not supported in HTML mode, please try YAML. -->\n# <hr style=\"width: 100%\" />\n# <h3>Drag decorators below</h3>\n# <!-- WARN: \":forEach\" is not supported in HTML mode, please try YAML. -->\n# </div>\n# <div style=\"flex: 1; min-width: 0\">\n# <eo-draw-canvas\n# style=\"width: 100%; height: 100%\"\n# fade-unrelated-cells\n# drag-behavior=\"lasso\"\n# id=\"brick-7\"\n# ></eo-draw-canvas>\n# </div>\n# </div>\n# <diagram.experimental-node\n# usage=\"dragging\"\n# decorator='&lt;%= CTX.dragging?.type === \"decorator\" ? CTX.dragging.decorator : null %&gt;\n# '\n# hidden=\"&lt;%= !CTX.dragging %&gt;\"\n# >\n# &lt;%= CTX.dragging?.type === \"decorator\" ? (CTX.dragging.decorator === \"text\"\n# ? \"Text\" : null) : CTX.dragging?.data.name %&gt;\n# </diagram.experimental-node>\n# <eo-context-menu\n# actions='&lt;%=\n# !CTX.contextMenuDetail\n# ? []\n# : CTX.contextMenuDetail.target?.type === \"multi\"\n# ? [\n# {\n# text: \"锁定/取消锁定\",\n# event: \"toggle-lock\",\n# },\n# ]\n# : [\n# ...(CTX.contextMenuDetail.locked ? [] : [{\n# text: \"添加边\",\n# event: \"add-edge\",\n# },{\n# text: \"移除\",\n# event: \"remove\"\n# }]),\n# {\n# text: \"锁定/取消锁定\",\n# event: \"toggle-lock\",\n# },\n# ].filter((action) =&gt;\n# CTX.contextMenuDetail.cell.type === \"node\" || (\n# CTX.contextMenuDetail.cell.type === \"decorator\" &amp;&amp;\n# CTX.contextMenuDetail.cell.decorator === \"area\"\n# ) || action.event !== \"add-edge\"\n# )\n# %&gt;\n# '\n# id=\"brick-8\"\n# ></eo-context-menu>\n# \n# <script>\n# const brick_1 = document.getElementById(\"brick-1\");\n# brick_1.addEventListener(\"click\", (e) => {\n# const brick = document.querySelector(\"eo-draw-canvas\");\n# brick.addNodes(\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# \"<%\\n ((...seeds) => seeds.map((seed) => ({\\n id: seed,\\n data: {\\n name: String(seed),\\n },\\n })))(\\n Math.round(Math.random() * 1e6),\\n Math.round(Math.random() * 1e6),\\n Math.round(Math.random() * 1e6),\\n )\\n%>\\n\"\n# );\n# });\n# \n# const brick_2 = document.getElementById(\"brick-2\");\n# brick_2.addEventListener(\"click\", (e) => {\n# const brick = document.querySelector(\"eo-draw-canvas\");\n# brick.reCenter();\n# });\n# \n# const brick_3 = document.getElementById(\"brick-3\");\n# brick_3.addEventListener(\"click\", (e) => {\n# const brick = document.querySelector(\"eo-draw-canvas\");\n# brick.addEdge({ source: \"Y\", target: \"Z\", data: { virtual: true } });\n# });\n# \n# const brick_4 = document.getElementById(\"brick-4\");\n# brick_4.addEventListener(\"click\", (e) => {\n# const brick = document.querySelector(\"eo-draw-canvas\");\n# brick.updateCells(\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# '<%\\n CTX.initialCells.concat([\\n {\\n type: \"edge\",\\n source: ITEM,\\n target: \"U\",\\n },\\n {\\n type: \"edge\",\\n source: ITEM,\\n target: \"V\",\\n },\\n {\\n type: \"node\",\\n id: \"U\",\\n data: {\\n name: \"U\"\\n }\\n },\\n {\\n type: \"node\",\\n id: \"V\",\\n data: {\\n name: \"V\"\\n }\\n },\\n ])\\n%>\\n',\n# { reason: \"add-related-nodes\", parent: \"<% ITEM %>\" }\n# );\n# });\n# \n# const brick_5 = document.getElementById(\"brick-5\");\n# brick_5.addEventListener(\"drag.move\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_5.addEventListener(\"drag.end\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_5.addEventListener(\"drag.end\", (e) => {\n# const brick = document.querySelector(\"eo-draw-canvas\");\n# brick.dropNode({\n# position: \"<% EVENT.detail %>\",\n# id: \"<% ITEM.id %>\",\n# data: \"<% ITEM.data %>\",\n# });\n# });\n# \n# const brick_6 = document.getElementById(\"brick-6\");\n# brick_6.addEventListener(\"drag.move\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_6.addEventListener(\"drag.end\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_6.addEventListener(\"drag.end\", (e) => {\n# const brick = document.querySelector(\"eo-draw-canvas\");\n# brick.dropDecorator(\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# '<%\\n ITEM === \"line\"\\n ? {\\n position: EVENT.detail,\\n decorator: ITEM.split(\".\")[0],\\n }\\n : {\\n position: EVENT.detail,\\n decorator: ITEM.split(\".\")[0],\\n text: ITEM === \"text\" ? \"Text\" : undefined,\\n direction: ITEM.split(\".\")[1],\\n }\\n%>\\n'\n# );\n# });\n# \n# const brick_7 = document.getElementById(\"brick-7\");\n# brick_7.activeTarget = \"<%= CTX.activeTarget %>\";\n# brick_7.layoutOptions = {\n# snap: {\n# object: true,\n# },\n# };\n# brick_7.defaultNodeSize = [60, 60];\n# brick_7.defaultNodeBricks = [\n# {\n# useBrick: {\n# brick: \"diagram.experimental-node\",\n# properties: {\n# textContent: \"<% `Node ${DATA.node.id}` %>\",\n# status:\n# '<%=\\n (CTX.activeTarget?.type === \"multi\"\\n ? CTX.activeTarget.targets\\n : CTX.activeTarget\\n ? [CTX.activeTarget]\\n : []\\n ).some((target) => (\\n target.type === \"node\" && target.id === DATA.node.id\\n ))\\n ? \"highlighted\"\\n : \"default\"\\n%>\\n',\n# },\n# },\n# },\n# ];\n# brick_7.defaultEdgeLines = [\n# {\n# if: \"<% DATA.edge.data?.virtual %>\",\n# dashed: true,\n# },\n# {\n# if: \"<% !DATA.edge.data?.virtual %>\",\n# dotted: true,\n# showStartArrow: true,\n# markers: [\n# {\n# placement: \"start\",\n# type: \"circle\",\n# },\n# {\n# placement: \"end\",\n# type: \"arrow\",\n# },\n# ],\n# },\n# ];\n# brick_7.cells = \"<% CTX.initialCells %>\";\n# brick_7.lineConnector = true;\n# brick_7.lineSettings = {\n# type: \"polyline\",\n# };\n# brick_7.addEventListener(\"activeTarget.change\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_7.addEventListener(\"cells.move\", (e) => {\n# const message = document.createElement(\"basic.show-notification\");\n# message.resolve({\n# type: \"info\",\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# message: \"<% `You just moved ${EVENT.detail.length} cells` %>\",\n# });\n# });\n# brick_7.addEventListener(\"cell.resize\", (e) => {\n# const message = document.createElement(\"basic.show-notification\");\n# message.resolve({\n# type: \"info\",\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# message:\n# \"<% `You just resized ${EVENT.detail.type} ${EVENT.detail.id} to (${Math.round(EVENT.detail.width)}, ${Math.round(EVENT.detail.height)})` %>\",\n# });\n# });\n# brick_7.addEventListener(\"cells.delete\", (e) => {\n# const message = document.createElement(\"basic.show-notification\");\n# message.resolve({\n# type: \"warn\",\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# message: \"<% `You wanna delete ${EVENT.detail.length} cells?` %>\\n\",\n# });\n# });\n# brick_7.addEventListener(\"cell.contextmenu\", (e) => {\n# const brick = document.querySelector(\"eo-context-menu\");\n# brick.open({\n# position: [\"<% EVENT.detail.clientX %>\", \"<% EVENT.detail.clientY %>\"],\n# });\n# });\n# brick_7.addEventListener(\"cell.contextmenu\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_7.addEventListener(\"edge.add\", (e) => {\n# const message = document.createElement(\"basic.show-notification\");\n# message.resolve({\n# type: \"info\",\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# message: \"<% `Added an nice edge: ${JSON.stringify(EVENT.detail)}` %>\\n\",\n# });\n# });\n# brick_7.addEventListener(\"edge.view.change\", (e) => {\n# const message = document.createElement(\"basic.show-notification\");\n# message.resolve({\n# type: \"info\",\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# message: \"<% `Edge view changed: ${JSON.stringify(EVENT.detail)}` %>\\n\",\n# });\n# });\n# brick_7.addEventListener(\"decorator.view.change\", (e) => {\n# const message = document.createElement(\"basic.show-notification\");\n# message.resolve({\n# type: \"info\",\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# message:\n# \"<% `Decorator view changed: ${JSON.stringify(EVENT.detail)}` %>\\n\",\n# });\n# });\n# brick_7.addEventListener(\"decorator.text.change\", (e) => {\n# const message = document.createElement(\"basic.show-notification\");\n# message.resolve({\n# type: \"info\",\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# message: \"<% JSON.stringify(EVENT.detail) %>\",\n# });\n# });\n# brick_7.addEventListener(\"node.container.change\", (e) => {\n# const message = document.createElement(\"basic.show-notification\");\n# message.resolve({\n# type: \"info\",\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# message: \"<% JSON.stringify(EVENT.detail) %>\",\n# });\n# });\n# brick_7.addEventListener(\"scale.change\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# \n# const brick_8 = document.getElementById(\"brick-8\");\n# brick_8.addEventListener(\"remove\", (e) => {\n# const brick = document.querySelector(\"eo-draw-canvas\");\n# brick.updateCells(\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# '<%\\n CTX.initialCells.filter((cell) =>\\n !(\\n CTX.contextMenuDetail.cell.type === \"edge\"\\n ? cell.type === \"edge\" && CTX.contextMenuDetail.cell.source === cell.source && CTX.contextMenuDetail.cell.target === cell.target\\n : cell.id === CTX.contextMenuDetail.cell.id ||\\n (cell.type === \"edge\" && (\\n CTX.contextMenuDetail.cell.id === cell.source ||\\n CTX.contextMenuDetail.cell.id === cell.target))\\n )\\n )\\n%>\\n'\n# );\n# });\n# brick_8.addEventListener(\"add-edge\", (e) => {\n# const brick = document.querySelector(\"eo-draw-canvas\");\n# brick.manuallyConnectNodes(\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# \"<% CTX.contextMenuDetail.cell.id %>\"\n# );\n# });\n# brick_8.addEventListener(\"toggle-lock\", (e) => {\n# const brick = document.querySelector(\"eo-draw-canvas\");\n# brick.toggleLock(\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# \"<% CTX.contextMenuDetail.target %>\"\n# );\n# });\n# </script>\n# \n```\n\n### Line labels\n\n设置连线文字。\n\n```yaml preview minHeight=\"600px\"\n- brick: div\n properties:\n style:\n display: flex\n flexDirection: column\n height: 600px\n gap: 1em\n context:\n - name: initialCells\n value: |\n <%\n [\n {\n type: \"edge\",\n source: \"X\",\n target: \"Y\",\n description: \"X->Y\",\n placement: \"end\",\n view: {\n type: \"polyline\"\n }\n },\n {\n type: \"edge\",\n source: \"X\",\n target: \"Z\"\n },\n {\n type: \"node\",\n id: \"X\",\n data: {\n name: \"Node X\",\n },\n view: {\n x: 100,\n y: 100,\n width: 60,\n height: 60,\n }\n },\n {\n type: \"node\",\n id: \"Y\",\n data: {\n name: \"Node Y\",\n },\n view: {\n x: 0,\n y: 300,\n width: 60,\n height: 60,\n }\n },\n {\n type: \"node\",\n id: \"Z\",\n data: {\n name: \"Node Z\",\n },\n view: {\n x: 300,\n y: 200,\n width: 60,\n height: 60,\n }\n },\n ]\n %>\n - name: activeTarget\n - name: scale\n value: 1\n children:\n - brick: eo-draw-canvas\n properties:\n style:\n width: 100%\n height: 100%\n activeTarget: <%= CTX.activeTarget %>\n fadeUnrelatedCells: true\n dragBehavior: lasso\n layoutOptions:\n snap:\n object: true\n defaultNodeSize: [60, 60]\n defaultNodeBricks:\n - useBrick:\n brick: diagram.experimental-node\n properties:\n textContent: <% `Node ${DATA.node.id}` %>\n status: |\n <%=\n (CTX.activeTarget?.type === \"multi\"\n ? CTX.activeTarget.targets\n : CTX.activeTarget\n ? [CTX.activeTarget]\n : []\n ).some((target) => (\n target.type === \"node\" && target.id === DATA.node.id\n ))\n ? \"highlighted\"\n : \"default\"\n %>\n cells: <% CTX.initialCells %>\n lineConnector: true\n defaultEdgeLines:\n - callLabelOnDoubleClick: enableEditing\n label:\n placement: <% DATA.edge.placement %>\n offset: 10\n useBrick:\n brick: diagram.editable-label\n properties:\n label: <% DATA.edge.description %>\n type: line\n # Set `readOnly: true` for eo-display-canvas\n # readOnly: true\n events:\n label.change:\n # Make sure only trigger update if label actually changed\n if: <% (DATA.edge.description || \"\") !== (EVENT.detail || \"\") %>\n action: context.replace\n args:\n - initialCells\n - |-\n <%\n CTX.initialCells.map((edge) =>\n edge.type === \"edge\" &&\n edge.source === DATA.edge.source &&\n edge.target === DATA.edge.target\n ? { ...edge, description: EVENT.detail }\n : edge\n )\n %>\n events:\n activeTarget.change:\n action: context.replace\n args:\n - activeTarget\n - <% EVENT.detail %>\n cell.delete:\n action: message.warn\n args:\n - |\n <% `You wanna delete ${EVENT.detail.type} ${EVENT.detail.type === \"edge\" ? `(${EVENT.detail.source} => ${EVENT.detail.target})` : EVENT.detail.id}?` %>\n scale.change:\n action: context.replace\n args:\n - scale\n - <% EVENT.detail %>\n# -- YAML DELIMITER (1nbbm8) --\n# <div style=\"display: flex; flex-direction: column; height: 600px; gap: 1em\">\n# <eo-draw-canvas\n# style=\"width: 100%; height: 100%\"\n# fade-unrelated-cells\n# drag-behavior=\"lasso\"\n# id=\"brick-1\"\n# ></eo-draw-canvas>\n# </div>\n# \n# <script>\n# const brick_1 = document.getElementById(\"brick-1\");\n# brick_1.activeTarget = \"<%= CTX.activeTarget %>\";\n# brick_1.layoutOptions = {\n# snap: {\n# object: true,\n# },\n# };\n# brick_1.defaultNodeSize = [60, 60];\n# brick_1.defaultNodeBricks = [\n# {\n# useBrick: {\n# brick: \"diagram.experimental-node\",\n# properties: {\n# textContent: \"<% `Node ${DATA.node.id}` %>\",\n# status:\n# '<%=\\n (CTX.activeTarget?.type === \"multi\"\\n ? CTX.activeTarget.targets\\n : CTX.activeTarget\\n ? [CTX.activeTarget]\\n : []\\n ).some((target) => (\\n target.type === \"node\" && target.id === DATA.node.id\\n ))\\n ? \"highlighted\"\\n : \"default\"\\n%>\\n',\n# },\n# },\n# },\n# ];\n# brick_1.cells = \"<% CTX.initialCells %>\";\n# brick_1.lineConnector = true;\n# brick_1.defaultEdgeLines = [\n# {\n# callLabelOnDoubleClick: \"enableEditing\",\n# label: {\n# placement: \"<% DATA.edge.placement %>\",\n# offset: 10,\n# useBrick: {\n# brick: \"diagram.editable-label\",\n# properties: {\n# label: \"<% DATA.edge.description %>\",\n# type: \"line\",\n# },\n# events: {\n# \"label.change\": {\n# if: '<% (DATA.edge.description || \"\") !== (EVENT.detail || \"\") %>',\n# action: \"context.replace\",\n# args: [\n# \"initialCells\",\n# '<%\\n CTX.initialCells.map((edge) =>\\n edge.type === \"edge\" &&\\n edge.source === DATA.edge.source &&\\n edge.target === DATA.edge.target\\n ? { ...edge, description: EVENT.detail }\\n : edge\\n )\\n%>',\n# ],\n# },\n# },\n# },\n# },\n# },\n# ];\n# brick_1.addEventListener(\"activeTarget.change\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_1.addEventListener(\"cell.delete\", (e) => {\n# const message = document.createElement(\"basic.show-notification\");\n# message.resolve({\n# type: \"warn\",\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# message:\n# '<% `You wanna delete ${EVENT.detail.type} ${EVENT.detail.type === \"edge\" ? `(${EVENT.detail.source} => ${EVENT.detail.target})` : EVENT.detail.id}?` %>\\n',\n# });\n# });\n# brick_1.addEventListener(\"scale.change\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# </script>\n# \n```\n\n### Line settings\n\n设置属性 `lineSettings` 来调整新的连线的样式,例如使用折线或直线。注意,该设置不影响已有的 edge 的连线样式。\n\n```yaml preview minHeight=\"600px\"\n- brick: div\n properties:\n style:\n display: flex\n flexDirection: column\n height: 600px\n gap: 1em\n context:\n - name: initialCells\n value: |\n <%\n [\n {\n type: \"decorator\",\n decorator: \"line\",\n id: \"line-1\",\n view: {\n source: {\n x: 200,\n y: 200,\n },\n target: {\n x: 250,\n y: 150,\n },\n // type: \"polyline\",\n vertices: [\n {\n x: 180,\n y: 125,\n },\n ],\n markers: [{\n placement: \"end\",\n type: \"arrow\",\n }],\n },\n },\n {\n type: \"edge\",\n source: \"X\",\n target: \"Y\",\n },\n {\n type: \"node\",\n id: \"X\",\n data: {\n name: \"Node X\",\n },\n view: {\n x: 100,\n y: 100,\n width: 60,\n height: 60,\n }\n },\n {\n type: \"node\",\n id: \"Y\",\n data: {\n name: \"Node Y\",\n },\n view: {\n x: 0,\n y: 300,\n width: 60,\n height: 60,\n }\n },\n {\n type: \"node\",\n id: \"Z\",\n data: {\n name: \"Node Z\",\n },\n view: {\n x: 300,\n y: 200,\n width: 60,\n height: 60,\n }\n },\n ]\n %>\n - name: dragging\n - name: activeTarget\n - name: targetCell\n - name: scale\n value: 1\n - name: lineType\n value: polyline\n children:\n - brick: div\n children:\n - brick: eo-radio\n properties:\n type: button\n value: polyline\n options:\n - polyline\n - curve\n - straight\n events:\n change:\n action: context.replace\n args:\n - lineType\n - <% EVENT.detail.value %>\n - brick: div\n properties:\n style:\n flex: 1\n minHeight: 0\n children:\n - brick: eo-draw-canvas\n properties:\n style:\n width: 100%\n height: 100%\n activeTarget: <%= CTX.activeTarget %>\n fadeUnrelatedCells: true\n dragBehavior: lasso\n layoutOptions:\n snap:\n object: true\n defaultNodeSize: [60, 60]\n defaultNodeBricks:\n - useBrick:\n brick: diagram.experimental-node\n properties:\n textContent: <% `Node ${DATA.node.id}` %>\n status: |\n <%=\n (CTX.activeTarget?.type === \"multi\"\n ? CTX.activeTarget.targets\n : CTX.activeTarget\n ? [CTX.activeTarget]\n : []\n ).some((target) => (\n target.type === \"node\" && target.id === DATA.node.id\n ))\n ? \"highlighted\"\n : \"default\"\n %>\n cells: <% CTX.initialCells %>\n defaultEdgeLines:\n - jumps: true\n lineConnector: true\n lineSettings: |\n <%= { type: CTX.lineType } %>\n events:\n activeTarget.change:\n action: context.replace\n args:\n - activeTarget\n - <% EVENT.detail %>\n cell.contextmenu:\n - target: eo-context-menu\n method: open\n args:\n - position:\n - <% EVENT.detail.clientX %>\n - <% EVENT.detail.clientY %>\n - action: context.replace\n args:\n - targetCell\n - <% EVENT.detail.cell %>\n edge.add:\n action: message.info\n args:\n - |\n <% `Added an nice edge: ${JSON.stringify(EVENT.detail)}` %>\n edge.view.change:\n action: message.info\n args:\n - |\n <% `Edge view changed: ${JSON.stringify(EVENT.detail)}` %>\n scale.change:\n action: context.replace\n args:\n - scale\n - <% EVENT.detail %>\n- brick: diagram.experimental-node\n properties:\n usage: dragging\n textContent: |\n <%= CTX.dragging?.type === \"decorator\" ? (CTX.dragging.decorator === \"text\" ? \"Text\" : null) : CTX.dragging?.data.name %>\n decorator: |\n <%= CTX.dragging?.type === \"decorator\" ? CTX.dragging.decorator : null %>\n style: |\n <%=\n {\n left: `${CTX.dragging?.position[0]}px`,\n top: `${CTX.dragging?.position[1]}px`,\n transform: `scale(${CTX.scale})`,\n transformOrigin: \"0 0\",\n padding: CTX.dragging?.decorator === \"text\" ? \"0.5em\" : \"0\"\n }\n %>\n hidden: <%= !CTX.dragging %>\n- brick: eo-context-menu\n properties:\n actions: |\n <%=\n ([\"node\"].includes(CTX.targetCell?.type )||CTX.targetCell?.decorator==\"area\") ? [\n {\n text: \"添加边\",\n event: \"add-edge\",\n }\n ] : [\n {\n text: `Test ${CTX.targetCell?.type}`,\n event: `test-${CTX.targetCell?.type}`,\n }\n ]\n %>\n events:\n add-edge:\n target: eo-draw-canvas\n method: manuallyConnectNodes\n args:\n - <% CTX.targetCell.id %>\n callback:\n success:\n - target: eo-draw-canvas\n method: addEdge\n args:\n - source: <% EVENT.detail.source.id %>\n target: <% EVENT.detail.target.id %>\n# -- YAML DELIMITER (1nbbm8) --\n# <div style=\"display: flex; flex-direction: column; height: 600px; gap: 1em\">\n# <div>\n# <eo-radio\n# type=\"button\"\n# value=\"polyline\"\n# options=\"polyline,curve,straight\"\n# id=\"brick-1\"\n# ></eo-radio>\n# </div>\n# <div style=\"flex: 1; min-height: 0\">\n# <eo-draw-canvas\n# style=\"width: 100%; height: 100%\"\n# fade-unrelated-cells\n# drag-behavior=\"lasso\"\n# id=\"brick-2\"\n# ></eo-draw-canvas>\n# </div>\n# </div>\n# <diagram.experimental-node\n# usage=\"dragging\"\n# decorator='&lt;%= CTX.dragging?.type === \"decorator\" ? CTX.dragging.decorator : null %&gt;\n# '\n# hidden=\"&lt;%= !CTX.dragging %&gt;\"\n# >\n# &lt;%= CTX.dragging?.type === \"decorator\" ? (CTX.dragging.decorator === \"text\"\n# ? \"Text\" : null) : CTX.dragging?.data.name %&gt;\n# </diagram.experimental-node>\n# <eo-context-menu\n# actions='&lt;%=\n# ([\"node\"].includes(CTX.targetCell?.type )||CTX.targetCell?.decorator==\"area\") ? [\n# {\n# text: \"添加边\",\n# event: \"add-edge\",\n# }\n# ] : [\n# {\n# text: `Test ${CTX.targetCell?.type}`,\n# event: `test-${CTX.targetCell?.type}`,\n# }\n# ]\n# %&gt;\n# '\n# id=\"brick-3\"\n# ></eo-context-menu>\n# \n# <script>\n# const brick_1 = document.getElementById(\"brick-1\");\n# brick_1.addEventListener(\"change\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# \n# const brick_2 = document.getElementById(\"brick-2\");\n# brick_2.activeTarget = \"<%= CTX.activeTarget %>\";\n# brick_2.layoutOptions = {\n# snap: {\n# object: true,\n# },\n# };\n# brick_2.defaultNodeSize = [60, 60];\n# brick_2.defaultNodeBricks = [\n# {\n# useBrick: {\n# brick: \"diagram.experimental-node\",\n# properties: {\n# textContent: \"<% `Node ${DATA.node.id}` %>\",\n# status:\n# '<%=\\n (CTX.activeTarget?.type === \"multi\"\\n ? CTX.activeTarget.targets\\n : CTX.activeTarget\\n ? [CTX.activeTarget]\\n : []\\n ).some((target) => (\\n target.type === \"node\" && target.id === DATA.node.id\\n ))\\n ? \"highlighted\"\\n : \"default\"\\n%>\\n',\n# },\n# },\n# },\n# ];\n# brick_2.cells = \"<% CTX.initialCells %>\";\n# brick_2.defaultEdgeLines = [\n# {\n# jumps: true,\n# },\n# ];\n# brick_2.lineConnector = true;\n# brick_2.lineSettings = \"<%= { type: CTX.lineType } %>\\n\";\n# brick_2.addEventListener(\"activeTarget.change\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_2.addEventListener(\"cell.contextmenu\", (e) => {\n# const brick = document.querySelector(\"eo-context-menu\");\n# brick.open({\n# position: [\"<% EVENT.detail.clientX %>\", \"<% EVENT.detail.clientY %>\"],\n# });\n# });\n# brick_2.addEventListener(\"cell.contextmenu\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_2.addEventListener(\"edge.add\", (e) => {\n# const message = document.createElement(\"basic.show-notification\");\n# message.resolve({\n# type: \"info\",\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# message: \"<% `Added an nice edge: ${JSON.stringify(EVENT.detail)}` %>\\n\",\n# });\n# });\n# brick_2.addEventListener(\"edge.view.change\", (e) => {\n# const message = document.createElement(\"basic.show-notification\");\n# message.resolve({\n# type: \"info\",\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# message: \"<% `Edge view changed: ${JSON.stringify(EVENT.detail)}` %>\\n\",\n# });\n# });\n# brick_2.addEventListener(\"scale.change\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# \n# const brick_3 = document.getElementById(\"brick-3\");\n# brick_3.addEventListener(\"add-edge\", (e) => {\n# const brick = document.querySelector(\"eo-draw-canvas\");\n# brick.manuallyConnectNodes(\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# \"<% CTX.targetCell.id %>\"\n# );\n# });\n# </script>\n# \n```\n\n### Force layout\n\n使用力导向(force)布局模式,节点位置由力导向算法自动计算。\n\n```yaml preview minHeight=\"600px\"\n- brick: div\n properties:\n style:\n display: flex\n height: 600px\n gap: 1em\n context:\n - name: initialCells\n value: |\n <%\n [\n {\n type: \"decorator\",\n id: \"area-1\",\n decorator: \"area\",\n view: {\n x: 10,\n y: 20,\n width: 400,\n height: 300,\n },\n },\n {\n type: \"decorator\",\n id: \"container-1\",\n decorator: \"container\",\n view: {\n x: 50,\n y: 400,\n width: 280,\n height: 120,\n direction: \"top\",\n text: \" 上层服务\"\n },\n },\n {\n type: \"edge\",\n source: \"X\",\n target: \"Y\",\n },\n {\n type: \"edge\",\n source: \"X\",\n target: \"Z\",\n data: {\n virtual: true,\n }\n },\n ].concat(\n [\"X\", \"Y\", \"Z\", \"W\"].map((id) => ({\n type: \"node\",\n id,\n containerId: [\"X\",\"Y\",\"Z\"].includes(id)?\"container-1\":undefined,\n data: {\n name: `Node ${id}`,\n },\n view: {\n width: 60,\n height: 60,\n }\n }))\n ).concat([\n {\n type: \"decorator\",\n id: \"text-1\",\n decorator: \"text\",\n view: {\n x: 100,\n y: 120,\n width: 100,\n height: 20,\n text: \"Hello!\"\n },\n },\n ])\n %>\n - name: dragging\n - name: activeTarget\n - name: targetCell\n - name: scale\n value: 1\n children:\n - brick: div\n properties:\n style:\n width: 180px\n display: flex\n flexDirection: column\n gap: 1em\n children:\n - brick: eo-button\n properties:\n textContent: Add random nodes\n events:\n click:\n target: eo-draw-canvas\n method: addNodes\n args:\n - |\n <%\n ((...seeds) => seeds.map((seed) => ({\n id: seed,\n data: {\n name: String(seed),\n },\n })))(\n Math.round(Math.random() * 1e6),\n Math.round(Math.random() * 1e6),\n Math.round(Math.random() * 1e6),\n )\n %>\n callback:\n success:\n action: console.log\n args:\n - Added nodes\n - <% EVENT.detail %>\n - brick: eo-button\n properties:\n textContent: \"Add edge: Y => Z\"\n events:\n click:\n target: eo-draw-canvas\n method: addEdge\n args:\n - source: Y\n target: Z\n data:\n virtual: true\n - brick: :forEach\n dataSource:\n - X\n - Y\n children:\n - brick: eo-button\n properties:\n textContent: <% `Add nodes below ${ITEM}` %>\n events:\n click:\n target: eo-draw-canvas\n method: updateCells\n args:\n - |\n <%\n CTX.initialCells.concat([\n {\n type: \"edge\",\n source: ITEM,\n target: \"U\",\n },\n {\n type: \"edge\",\n source: ITEM,\n target: \"V\",\n },\n {\n type: \"node\",\n id: \"U\",\n data: {\n name: \"U\"\n }\n },\n {\n type: \"node\",\n id: \"V\",\n data: {\n name: \"V\"\n }\n },\n ])\n %>\n - reason: add-related-nodes\n parent: <% ITEM %>\n callback:\n success:\n action: console.log\n - brick: hr\n properties:\n style:\n width: 100%\n - brick: h3\n properties:\n textContent: Drag nodes below\n - brick: :forEach\n dataSource: |\n <%\n [\"A\", \"B\", \"C\"].map((id) => ({\n type: \"node\",\n id,\n data: {\n name: `Node ${id}`,\n },\n }))\n %>\n children:\n - brick: diagram.experimental-node\n properties:\n textContent: <% ITEM.data.name %>\n usage: library\n events:\n drag.move:\n action: context.replace\n args:\n - dragging\n - |\n <% {position: EVENT.detail, ...ITEM} %>\n drag.end:\n - action: context.replace\n args:\n - dragging\n - null\n - target: eo-draw-canvas\n method: dropNode\n args:\n - position: <% EVENT.detail %>\n id: <% ITEM.id %>\n data: <% ITEM.data %>\n callback:\n success:\n if: <% EVENT.detail %>\n then:\n action: message.success\n args:\n - <% JSON.stringify(EVENT.detail) %>\n else:\n action: message.warn\n args:\n - Unexpected drop position\n - brick: hr\n properties:\n style:\n width: 100%\n - brick: h3\n properties:\n textContent: Drag decorators below\n - brick: :forEach\n dataSource:\n - area\n - text\n children:\n - brick: diagram.experimental-node\n properties:\n textContent: <% _.upperFirst(ITEM) %>\n usage: library\n events:\n drag.move:\n action: context.replace\n args:\n - dragging\n - |\n <% {position: EVENT.detail, type: \"decorator\", decorator: ITEM} %>\n drag.end:\n - action: context.replace\n args:\n - dragging\n - null\n - target: eo-draw-canvas\n method: dropDecorator\n args:\n - position: <% EVENT.detail %>\n decorator: <% ITEM %>\n text: '<% ITEM === \"text\" ? \"Text\" : undefined %>'\n callback:\n success:\n if: <% !EVENT.detail %>\n action: message.warn\n args:\n - Unexpected drop position\n - brick: div\n properties:\n style:\n flex: 1\n minWidth: 0\n children:\n - brick: eo-draw-canvas\n properties:\n style:\n width: 100%\n height: 100%\n activeTarget: <%= CTX.activeTarget %>\n fadeUnrelatedCells: true\n layout: force\n # Initial nodes only\n defaultNodeSize: [60, 60]\n defaultNodeBricks:\n - useBrick:\n brick: diagram.experimental-node\n properties:\n textContent: <% `Node ${DATA.node.id}` %>\n status: |\n <%=\n CTX.activeTarget?.type === \"node\" && CTX.activeTarget.id === DATA.node.id\n ? \"highlighted\"\n // : CTX.unrelated.some(n =>\n // n.type === \"node\" && n.id === DATA.node.id\n // )\n // ? \"faded\"\n : \"default\"\n %>\n defaultEdgeLines:\n - if: <% DATA.edge.data?.virtual %>\n dashed: true\n cells: <% CTX.initialCells %>\n events:\n activeTarget.change:\n action: context.replace\n args:\n - activeTarget\n - <% EVENT.detail %>\n cell.move:\n action: message.info\n args:\n - <% `You just moved ${EVENT.detail.type} ${EVENT.detail.id} to (${Math.round(EVENT.detail.x)}, ${Math.round(EVENT.detail.y)})` %>\n cell.resize:\n action: message.info\n args:\n - <% `You just resized ${EVENT.detail.type} ${EVENT.detail.id} to (${Math.round(EVENT.detail.width)}, ${Math.round(EVENT.detail.height)})` %>\n cell.delete:\n action: message.warn\n args:\n - |\n <% `You wanna delete ${EVENT.detail.type} ${EVENT.detail.type === \"edge\" ? `(${EVENT.detail.source} => ${EVENT.detail.target})` : EVENT.detail.id}?` %>\n cell.contextmenu:\n - target: eo-context-menu\n method: open\n args:\n - position:\n - <% EVENT.detail.clientX %>\n - <% EVENT.detail.clientY %>\n - action: context.replace\n args:\n - targetCell\n - <% EVENT.detail.cell %>\n decorator.text.change:\n action: message.info\n args:\n - <% JSON.stringify(EVENT.detail) %>\n scale.change:\n action: context.replace\n args:\n - scale\n - <% EVENT.detail %>\n- brick: diagram.experimental-node\n properties:\n usage: dragging\n textContent: |\n <%= CTX.dragging?.type === \"decorator\" ? (CTX.dragging.decorator === \"text\" ? \"Text\" : null) : CTX.dragging?.data.name %>\n decorator: |\n <%= CTX.dragging?.type === \"decorator\" ? CTX.dragging.decorator : null %>\n style: |\n <%=\n {\n left: `${CTX.dragging?.position[0]}px`,\n top: `${CTX.dragging?.position[1]}px`,\n transform: `scale(${CTX.scale})`,\n transformOrigin: \"0 0\",\n padding: CTX.dragging?.decorator === \"text\" ? \"0.5em\" : \"0\"\n }\n %>\n hidden: <%= !CTX.dragging %>\n- brick: eo-context-menu\n properties:\n actions: |\n <%=\n CTX.targetCell?.type === \"node\" ? [\n {\n text: \"添加边\",\n event: \"add-edge\",\n }\n ] : [\n {\n text: `Test ${CTX.targetCell?.type}`,\n event: `test-${CTX.targetCell?.type}`,\n }\n ]\n %>\n events:\n add-edge:\n target: eo-draw-canvas\n method: manuallyConnectNodes\n args:\n - <% CTX.targetCell.id %>\n callback:\n success:\n target: eo-draw-canvas\n method: addEdge\n args:\n - source: <% EVENT.detail.source.id %>\n target: <% EVENT.detail.target.id %>\n# -- YAML DELIMITER (1nbbm8) --\n# <div style=\"display: flex; height: 600px; gap: 1em\">\n# <div style=\"width: 180px; display: flex; flex-direction: column; gap: 1em\">\n# <eo-button id=\"brick-1\">Add random nodes</eo-button>\n# <eo-button id=\"brick-2\">Add edge: Y =&gt; Z</eo-button>\n# <!-- WARN: \":forEach\" is not supported in HTML mode, please try YAML. -->\n# <hr style=\"width: 100%\" />\n# <h3>Drag nodes below</h3>\n# <!-- WARN: \":forEach\" is not supported in HTML mode, please try YAML. -->\n# <hr style=\"width: 100%\" />\n# <h3>Drag decorators below</h3>\n# <!-- WARN: \":forEach\" is not supported in HTML mode, please try YAML. -->\n# </div>\n# <div style=\"flex: 1; min-width: 0\">\n# <eo-draw-canvas\n# style=\"width: 100%; height: 100%\"\n# fade-unrelated-cells\n# layout=\"force\"\n# id=\"brick-6\"\n# ></eo-draw-canvas>\n# </div>\n# </div>\n# <diagram.experimental-node\n# usage=\"dragging\"\n# decorator='&lt;%= CTX.dragging?.type === \"decorator\" ? CTX.dragging.decorator : null %&gt;\n# '\n# hidden=\"&lt;%= !CTX.dragging %&gt;\"\n# >\n# &lt;%= CTX.dragging?.type === \"decorator\" ? (CTX.dragging.decorator === \"text\"\n# ? \"Text\" : null) : CTX.dragging?.data.name %&gt;\n# </diagram.experimental-node>\n# <eo-context-menu\n# actions='&lt;%=\n# CTX.targetCell?.type === \"node\" ? [\n# {\n# text: \"添加边\",\n# event: \"add-edge\",\n# }\n# ] : [\n# {\n# text: `Test ${CTX.targetCell?.type}`,\n# event: `test-${CTX.targetCell?.type}`,\n# }\n# ]\n# %&gt;\n# '\n# id=\"brick-7\"\n# ></eo-context-menu>\n# \n# <script>\n# const brick_1 = document.getElementById(\"brick-1\");\n# brick_1.addEventListener(\"click\", (e) => {\n# const brick = document.querySelector(\"eo-draw-canvas\");\n# brick.addNodes(\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# \"<%\\n ((...seeds) => seeds.map((seed) => ({\\n id: seed,\\n data: {\\n name: String(seed),\\n },\\n })))(\\n Math.round(Math.random() * 1e6),\\n Math.round(Math.random() * 1e6),\\n Math.round(Math.random() * 1e6),\\n )\\n%>\\n\"\n# );\n# });\n# \n# const brick_2 = document.getElementById(\"brick-2\");\n# brick_2.addEventListener(\"click\", (e) => {\n# const brick = document.querySelector(\"eo-draw-canvas\");\n# brick.addEdge({ source: \"Y\", target: \"Z\", data: { virtual: true } });\n# });\n# \n# const brick_3 = document.getElementById(\"brick-3\");\n# brick_3.addEventListener(\"click\", (e) => {\n# const brick = document.querySelector(\"eo-draw-canvas\");\n# brick.updateCells(\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# '<%\\n CTX.initialCells.concat([\\n {\\n type: \"edge\",\\n source: ITEM,\\n target: \"U\",\\n },\\n {\\n type: \"edge\",\\n source: ITEM,\\n target: \"V\",\\n },\\n {\\n type: \"node\",\\n id: \"U\",\\n data: {\\n name: \"U\"\\n }\\n },\\n {\\n type: \"node\",\\n id: \"V\",\\n data: {\\n name: \"V\"\\n }\\n },\\n ])\\n%>\\n',\n# { reason: \"add-related-nodes\", parent: \"<% ITEM %>\" }\n# );\n# });\n# \n# const brick_4 = document.getElementById(\"brick-4\");\n# brick_4.addEventListener(\"drag.move\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_4.addEventListener(\"drag.end\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_4.addEventListener(\"drag.end\", (e) => {\n# const brick = document.querySelector(\"eo-draw-canvas\");\n# brick.dropNode({\n# position: \"<% EVENT.detail %>\",\n# id: \"<% ITEM.id %>\",\n# data: \"<% ITEM.data %>\",\n# });\n# });\n# \n# const brick_5 = document.getElementById(\"brick-5\");\n# brick_5.addEventListener(\"drag.move\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_5.addEventListener(\"drag.end\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_5.addEventListener(\"drag.end\", (e) => {\n# const brick = document.querySelector(\"eo-draw-canvas\");\n# brick.dropDecorator({\n# position: \"<% EVENT.detail %>\",\n# decorator: \"<% ITEM %>\",\n# text: '<% ITEM === \"text\" ? \"Text\" : undefined %>',\n# });\n# });\n# \n# const brick_6 = document.getElementById(\"brick-6\");\n# brick_6.activeTarget = \"<%= CTX.activeTarget %>\";\n# brick_6.defaultNodeSize = [60, 60];\n# brick_6.defaultNodeBricks = [\n# {\n# useBrick: {\n# brick: \"diagram.experimental-node\",\n# properties: {\n# textContent: \"<% `Node ${DATA.node.id}` %>\",\n# status:\n# '<%=\\n CTX.activeTarget?.type === \"node\" && CTX.activeTarget.id === DATA.node.id\\n ? \"highlighted\"\\n // : CTX.unrelated.some(n =>\\n // n.type === \"node\" && n.id === DATA.node.id\\n // )\\n // ? \"faded\"\\n : \"default\"\\n%>\\n',\n# },\n# },\n# },\n# ];\n# brick_6.defaultEdgeLines = [\n# {\n# if: \"<% DATA.edge.data?.virtual %>\",\n# dashed: true,\n# },\n# ];\n# brick_6.cells = \"<% CTX.initialCells %>\";\n# brick_6.addEventListener(\"activeTarget.change\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_6.addEventListener(\"cell.move\", (e) => {\n# const message = document.createElement(\"basic.show-notification\");\n# message.resolve({\n# type: \"info\",\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# message:\n# \"<% `You just moved ${EVENT.detail.type} ${EVENT.detail.id} to (${Math.round(EVENT.detail.x)}, ${Math.round(EVENT.detail.y)})` %>\",\n# });\n# });\n# brick_6.addEventListener(\"cell.resize\", (e) => {\n# const message = document.createElement(\"basic.show-notification\");\n# message.resolve({\n# type: \"info\",\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# message:\n# \"<% `You just resized ${EVENT.detail.type} ${EVENT.detail.id} to (${Math.round(EVENT.detail.width)}, ${Math.round(EVENT.detail.height)})` %>\",\n# });\n# });\n# brick_6.addEventListener(\"cell.delete\", (e) => {\n# const message = document.createElement(\"basic.show-notification\");\n# message.resolve({\n# type: \"warn\",\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# message:\n# '<% `You wanna delete ${EVENT.detail.type} ${EVENT.detail.type === \"edge\" ? `(${EVENT.detail.source} => ${EVENT.detail.target})` : EVENT.detail.id}?` %>\\n',\n# });\n# });\n# brick_6.addEventListener(\"cell.contextmenu\", (e) => {\n# const brick = document.querySelector(\"eo-context-menu\");\n# brick.open({\n# position: [\"<% EVENT.detail.clientX %>\", \"<% EVENT.detail.clientY %>\"],\n# });\n# });\n# brick_6.addEventListener(\"cell.contextmenu\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_6.addEventListener(\"decorator.text.change\", (e) => {\n# const message = document.createElement(\"basic.show-notification\");\n# message.resolve({\n# type: \"info\",\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# message: \"<% JSON.stringify(EVENT.detail) %>\",\n# });\n# });\n# brick_6.addEventListener(\"scale.change\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# \n# const brick_7 = document.getElementById(\"brick-7\");\n# brick_7.addEventListener(\"add-edge\", (e) => {\n# const brick = document.querySelector(\"eo-draw-canvas\");\n# brick.manuallyConnectNodes(\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# \"<% CTX.targetCell.id %>\"\n# );\n# });\n# </script>\n# \n```\n\n### Dagre layout\n\n使用层次有向图(dagre)布局模式,节点位置由 dagre 算法自动计算,适合展示有向依赖关系。\n\n```yaml preview minHeight=\"600px\"\n- brick: div\n properties:\n style:\n display: flex\n height: 600px\n gap: 1em\n context:\n - name: initialCells\n value: |\n <%\n [\n {\n type: \"decorator\",\n id: \"area-1\",\n decorator: \"area\",\n view: {\n x: 10,\n y: 20,\n width: 400,\n height: 300,\n },\n },\n {\n type: \"decorator\",\n id: \"container-1\",\n decorator: \"container\",\n view: {\n x: 50,\n y: 400,\n width: 280,\n height: 120,\n direction: \"top\",\n text: \" 上层服务\"\n },\n },\n {\n type: \"edge\",\n source: \"X\",\n target: \"Y\",\n },\n {\n type: \"edge\",\n source: \"X\",\n target: \"Z\",\n data: {\n virtual: true,\n }\n },\n {\n type: \"edge\",\n source: \"Z\",\n target: \"W\",\n },\n ].concat(\n [\"X\", \"Y\", \"Z\", \"W\"].map((id) => ({\n type: \"node\",\n id,\n containerId: [\"W\",\"Z\"].includes(id)?\"container-1\":undefined,\n data: {\n name: `Node ${id}`,\n },\n view: {\n width: 60,\n height: 60,\n }\n }))\n )\n %>\n - name: dragging\n - name: activeTarget\n - name: targetCell\n - name: scale\n value: 1\n children:\n - brick: div\n properties:\n style:\n width: 180px\n display: flex\n flexDirection: column\n gap: 1em\n children:\n - brick: eo-button\n properties:\n textContent: Add random nodes\n events:\n click:\n target: eo-draw-canvas\n method: addNodes\n args:\n - |\n <%\n ((...seeds) => seeds.map((seed) => ({\n id: seed,\n data: {\n name: String(seed),\n },\n })))(\n Math.round(Math.random() * 1e6),\n Math.round(Math.random() * 1e6),\n Math.round(Math.random() * 1e6),\n )\n %>\n callback:\n success:\n action: console.log\n args:\n - Added nodes\n - <% EVENT.detail %>\n - brick: eo-button\n properties:\n textContent: \"Add edge: Y => Z\"\n events:\n click:\n target: eo-draw-canvas\n method: addEdge\n args:\n - source: Y\n target: Z\n data:\n virtual: true\n - brick: :forEach\n dataSource:\n - X\n - Y\n children:\n - brick: eo-button\n properties:\n textContent: <% `Add nodes below ${ITEM}` %>\n events:\n click:\n target: eo-draw-canvas\n method: updateCells\n args:\n - |\n <%\n CTX.initialCells.concat([\n {\n type: \"edge\",\n source: ITEM,\n target: \"U\",\n },\n {\n type: \"edge\",\n source: ITEM,\n target: \"V\",\n },\n {\n type: \"node\",\n id: \"U\",\n data: {\n name: \"U\"\n }\n },\n {\n type: \"node\",\n id: \"V\",\n data: {\n name: \"V\"\n }\n },\n ])\n %>\n - reason: add-related-nodes\n parent: <% ITEM %>\n callback:\n success:\n action: console.log\n - brick: hr\n properties:\n style:\n width: 100%\n - brick: h3\n properties:\n textContent: Drag nodes below\n - brick: :forEach\n dataSource: |\n <%\n [\"A\", \"B\", \"C\"].map((id) => ({\n type: \"node\",\n id,\n data: {\n name: `Node ${id}`,\n },\n }))\n %>\n children:\n - brick: diagram.experimental-node\n properties:\n textContent: <% ITEM.data.name %>\n usage: library\n events:\n drag.move:\n action: context.replace\n args:\n - dragging\n - |\n <% {position: EVENT.detail, ...ITEM} %>\n drag.end:\n - action: context.replace\n args:\n - dragging\n - null\n - target: eo-draw-canvas\n method: dropNode\n args:\n - position: <% EVENT.detail %>\n id: <% ITEM.id %>\n data: <% ITEM.data %>\n callback:\n success:\n if: <% EVENT.detail %>\n then:\n action: message.success\n args:\n - <% JSON.stringify(EVENT.detail) %>\n else:\n action: message.warn\n args:\n - Unexpected drop position\n - brick: hr\n properties:\n style:\n width: 100%\n - brick: h3\n properties:\n textContent: Drag decorators below\n - brick: :forEach\n dataSource:\n - area\n - text\n children:\n - brick: diagram.experimental-node\n properties:\n textContent: <% _.upperFirst(ITEM) %>\n usage: library\n events:\n drag.move:\n action: context.replace\n args:\n - dragging\n - |\n <% {position: EVENT.detail, type: \"decorator\", decorator: ITEM} %>\n drag.end:\n - action: context.replace\n args:\n - dragging\n - null\n - target: eo-draw-canvas\n method: dropDecorator\n args:\n - position: <% EVENT.detail %>\n decorator: <% ITEM %>\n text: '<% ITEM === \"text\" ? \"Text\" : undefined %>'\n callback:\n success:\n if: <% !EVENT.detail %>\n action: message.warn\n args:\n - Unexpected drop position\n - brick: div\n properties:\n style:\n flex: 1\n minWidth: 0\n children:\n - brick: eo-draw-canvas\n properties:\n style:\n width: 100%\n height: 100%\n activeTarget: <%= CTX.activeTarget %>\n fadeUnrelatedCells: true\n layout: dagre\n # Initial nodes only\n defaultNodeSize: [60, 60]\n defaultNodeBricks:\n - useBrick:\n brick: diagram.experimental-node\n properties:\n textContent: <% `Node ${DATA.node.id}` %>\n status: |\n <%=\n CTX.activeTarget?.type === \"node\" && CTX.activeTarget.id === DATA.node.id\n ? \"highlighted\"\n // : CTX.unrelated.some(n =>\n // n.type === \"node\" && n.id === DATA.node.id\n // )\n // ? \"faded\"\n : \"default\"\n %>\n defaultEdgeLines:\n - dashed: <% !!DATA.edge.data?.virtual %>\n strokeColor: var(--palette-blue-6)\n overrides:\n active:\n strokeWidth: <% 2 * (DATA.edge?.data?.strokeWidth ?? 1) %>\n strokeColor: cyan\n cells: <% CTX.initialCells %>\n events:\n activeTarget.change:\n action: context.replace\n args:\n - activeTarget\n - <% EVENT.detail %>\n cell.move:\n action: message.info\n args:\n - <% `You just moved ${EVENT.detail.type} ${EVENT.detail.id} to (${Math.round(EVENT.detail.x)}, ${Math.round(EVENT.detail.y)})` %>\n cell.resize:\n action: message.info\n args:\n - <% `You just resized ${EVENT.detail.type} ${EVENT.detail.id} to (${Math.round(EVENT.detail.width)}, ${Math.round(EVENT.detail.height)})` %>\n cell.delete:\n action: message.warn\n args:\n - |\n <% `You wanna delete ${EVENT.detail.type} ${EVENT.detail.type === \"edge\" ? `(${EVENT.detail.source} => ${EVENT.detail.target})` : EVENT.detail.id}?` %>\n cell.contextmenu:\n - target: eo-context-menu\n method: open\n args:\n - position:\n - <% EVENT.detail.clientX %>\n - <% EVENT.detail.clientY %>\n - action: context.replace\n args:\n - targetCell\n - <% EVENT.detail.cell %>\n decorator.text.change:\n action: message.info\n args:\n - <% JSON.stringify(EVENT.detail) %>\n scale.change:\n action: context.replace\n args:\n - scale\n - <% EVENT.detail %>\n- brick: diagram.experimental-node\n properties:\n usage: dragging\n textContent: |\n <%= CTX.dragging?.type === \"decorator\" ? (CTX.dragging.decorator === \"text\" ? \"Text\" : null) : CTX.dragging?.data.name %>\n decorator: |\n <%= CTX.dragging?.type === \"decorator\" ? CTX.dragging.decorator : null %>\n style: |\n <%=\n {\n left: `${CTX.dragging?.position[0]}px`,\n top: `${CTX.dragging?.position[1]}px`,\n transform: `scale(${CTX.scale})`,\n transformOrigin: \"0 0\",\n padding: CTX.dragging?.decorator === \"text\" ? \"0.5em\" : \"0\"\n }\n %>\n hidden: <%= !CTX.dragging %>\n- brick: eo-context-menu\n properties:\n actions: |\n <%=\n CTX.targetCell?.type === \"node\" ? [\n {\n text: \"添加边\",\n event: \"add-edge\",\n }\n ] : [\n {\n text: `Test ${CTX.targetCell?.type}`,\n event: `test-${CTX.targetCell?.type}`,\n }\n ]\n %>\n events:\n add-edge:\n target: eo-draw-canvas\n method: manuallyConnectNodes\n args:\n - <% CTX.targetCell.id %>\n callback:\n success:\n target: eo-draw-canvas\n method: addEdge\n args:\n - source: <% EVENT.detail.source.id %>\n target: <% EVENT.detail.target.id %>\n# -- YAML DELIMITER (1nbbm8) --\n# <div style=\"display: flex; height: 600px; gap: 1em\">\n# <div style=\"width: 180px; display: flex; flex-direction: column; gap: 1em\">\n# <eo-button id=\"brick-1\">Add random nodes</eo-button>\n# <eo-button id=\"brick-2\">Add edge: Y =&gt; Z</eo-button>\n# <!-- WARN: \":forEach\" is not supported in HTML mode, please try YAML. -->\n# <hr style=\"width: 100%\" />\n# <h3>Drag nodes below</h3>\n# <!-- WARN: \":forEach\" is not supported in HTML mode, please try YAML. -->\n# <hr style=\"width: 100%\" />\n# <h3>Drag decorators below</h3>\n# <!-- WARN: \":forEach\" is not supported in HTML mode, please try YAML. -->\n# </div>\n# <div style=\"flex: 1; min-width: 0\">\n# <eo-draw-canvas\n# style=\"width: 100%; height: 100%\"\n# fade-unrelated-cells\n# layout=\"dagre\"\n# id=\"brick-6\"\n# ></eo-draw-canvas>\n# </div>\n# </div>\n# <diagram.experimental-node\n# usage=\"dragging\"\n# decorator='&lt;%= CTX.dragging?.type === \"decorator\" ? CTX.dragging.decorator : null %&gt;\n# '\n# hidden=\"&lt;%= !CTX.dragging %&gt;\"\n# >\n# &lt;%= CTX.dragging?.type === \"decorator\" ? (CTX.dragging.decorator === \"text\"\n# ? \"Text\" : null) : CTX.dragging?.data.name %&gt;\n# </diagram.experimental-node>\n# <eo-context-menu\n# actions='&lt;%=\n# CTX.targetCell?.type === \"node\" ? [\n# {\n# text: \"添加边\",\n# event: \"add-edge\",\n# }\n# ] : [\n# {\n# text: `Test ${CTX.targetCell?.type}`,\n# event: `test-${CTX.targetCell?.type}`,\n# }\n# ]\n# %&gt;\n# '\n# id=\"brick-7\"\n# ></eo-context-menu>\n# \n# <script>\n# const brick_1 = document.getElementById(\"brick-1\");\n# brick_1.addEventListener(\"click\", (e) => {\n# const brick = document.querySelector(\"eo-draw-canvas\");\n# brick.addNodes(\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# \"<%\\n ((...seeds) => seeds.map((seed) => ({\\n id: seed,\\n data: {\\n name: String(seed),\\n },\\n })))(\\n Math.round(Math.random() * 1e6),\\n Math.round(Math.random() * 1e6),\\n Math.round(Math.random() * 1e6),\\n )\\n%>\\n\"\n# );\n# });\n# \n# const brick_2 = document.getElementById(\"brick-2\");\n# brick_2.addEventListener(\"click\", (e) => {\n# const brick = document.querySelector(\"eo-draw-canvas\");\n# brick.addEdge({ source: \"Y\", target: \"Z\", data: { virtual: true } });\n# });\n# \n# const brick_3 = document.getElementById(\"brick-3\");\n# brick_3.addEventListener(\"click\", (e) => {\n# const brick = document.querySelector(\"eo-draw-canvas\");\n# brick.updateCells(\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# '<%\\n CTX.initialCells.concat([\\n {\\n type: \"edge\",\\n source: ITEM,\\n target: \"U\",\\n },\\n {\\n type: \"edge\",\\n source: ITEM,\\n target: \"V\",\\n },\\n {\\n type: \"node\",\\n id: \"U\",\\n data: {\\n name: \"U\"\\n }\\n },\\n {\\n type: \"node\",\\n id: \"V\",\\n data: {\\n name: \"V\"\\n }\\n },\\n ])\\n%>\\n',\n# { reason: \"add-related-nodes\", parent: \"<% ITEM %>\" }\n# );\n# });\n# \n# const brick_4 = document.getElementById(\"brick-4\");\n# brick_4.addEventListener(\"drag.move\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_4.addEventListener(\"drag.end\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_4.addEventListener(\"drag.end\", (e) => {\n# const brick = document.querySelector(\"eo-draw-canvas\");\n# brick.dropNode({\n# position: \"<% EVENT.detail %>\",\n# id: \"<% ITEM.id %>\",\n# data: \"<% ITEM.data %>\",\n# });\n# });\n# \n# const brick_5 = document.getElementById(\"brick-5\");\n# brick_5.addEventListener(\"drag.move\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_5.addEventListener(\"drag.end\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_5.addEventListener(\"drag.end\", (e) => {\n# const brick = document.querySelector(\"eo-draw-canvas\");\n# brick.dropDecorator({\n# position: \"<% EVENT.detail %>\",\n# decorator: \"<% ITEM %>\",\n# text: '<% ITEM === \"text\" ? \"Text\" : undefined %>',\n# });\n# });\n# \n# const brick_6 = document.getElementById(\"brick-6\");\n# brick_6.activeTarget = \"<%= CTX.activeTarget %>\";\n# brick_6.defaultNodeSize = [60, 60];\n# brick_6.defaultNodeBricks = [\n# {\n# useBrick: {\n# brick: \"diagram.experimental-node\",\n# properties: {\n# textContent: \"<% `Node ${DATA.node.id}` %>\",\n# status:\n# '<%=\\n CTX.activeTarget?.type === \"node\" && CTX.activeTarget.id === DATA.node.id\\n ? \"highlighted\"\\n // : CTX.unrelated.some(n =>\\n // n.type === \"node\" && n.id === DATA.node.id\\n // )\\n // ? \"faded\"\\n : \"default\"\\n%>\\n',\n# },\n# },\n# },\n# ];\n# brick_6.defaultEdgeLines = [\n# {\n# dashed: \"<% !!DATA.edge.data?.virtual %>\",\n# strokeColor: \"var(--palette-blue-6)\",\n# overrides: {\n# active: {\n# strokeWidth: \"<% 2 * (DATA.edge?.data?.strokeWidth ?? 1) %>\",\n# strokeColor: \"cyan\",\n# },\n# },\n# },\n# ];\n# brick_6.cells = \"<% CTX.initialCells %>\";\n# brick_6.addEventListener(\"activeTarget.change\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_6.addEventListener(\"cell.move\", (e) => {\n# const message = document.createElement(\"basic.show-notification\");\n# message.resolve({\n# type: \"info\",\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# message:\n# \"<% `You just moved ${EVENT.detail.type} ${EVENT.detail.id} to (${Math.round(EVENT.detail.x)}, ${Math.round(EVENT.detail.y)})` %>\",\n# });\n# });\n# brick_6.addEventListener(\"cell.resize\", (e) => {\n# const message = document.createElement(\"basic.show-notification\");\n# message.resolve({\n# type: \"info\",\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# message:\n# \"<% `You just resized ${EVENT.detail.type} ${EVENT.detail.id} to (${Math.round(EVENT.detail.width)}, ${Math.round(EVENT.detail.height)})` %>\",\n# });\n# });\n# brick_6.addEventListener(\"cell.delete\", (e) => {\n# const message = document.createElement(\"basic.show-notification\");\n# message.resolve({\n# type: \"warn\",\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# message:\n# '<% `You wanna delete ${EVENT.detail.type} ${EVENT.detail.type === \"edge\" ? `(${EVENT.detail.source} => ${EVENT.detail.target})` : EVENT.detail.id}?` %>\\n',\n# });\n# });\n# brick_6.addEventListener(\"cell.contextmenu\", (e) => {\n# const brick = document.querySelector(\"eo-context-menu\");\n# brick.open({\n# position: [\"<% EVENT.detail.clientX %>\", \"<% EVENT.detail.clientY %>\"],\n# });\n# });\n# brick_6.addEventListener(\"cell.contextmenu\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_6.addEventListener(\"decorator.text.change\", (e) => {\n# const message = document.createElement(\"basic.show-notification\");\n# message.resolve({\n# type: \"info\",\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# message: \"<% JSON.stringify(EVENT.detail) %>\",\n# });\n# });\n# brick_6.addEventListener(\"scale.change\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# \n# const brick_7 = document.getElementById(\"brick-7\");\n# brick_7.addEventListener(\"add-edge\", (e) => {\n# const brick = document.querySelector(\"eo-draw-canvas\");\n# brick.manuallyConnectNodes(\n# /* WARN: incompatible expressions in HTML, please try YAML: */\n# \"<% CTX.targetCell.id %>\"\n# );\n# });\n# </script>\n# \n```\n"
10
+ },
11
+ "diagram.experimental-node": {
12
+ "doc": "---\ntagName: diagram.experimental-node\ndisplayName: WrappedDiagramExperimentalNode\ndescription: 实验性图表节点构件,支持从素材库拖拽到画布(`usage: \"library\"`)和画布内节点渲染(`usage: \"default\"`),支持高亮、淡化等状态样式,常配合 `eo-draw-canvas` 和 `eo-display-canvas` 使用。\ncategory: diagram\nsource: \"@next-bricks/diagram\"\n---\n\n# diagram.experimental-node\n\n> 实验性图表节点构件,支持从素材库拖拽到画布(`usage: \"library\"`)和画布内节点渲染(`usage: \"default\"`),支持高亮、淡化等状态样式,常配合 `eo-draw-canvas` 和 `eo-display-canvas` 使用。\n\n## Props\n\n| 属性 | 类型 | 必填 | 默认值 | 说明 |\n| --------- | -------------------------------- | ---- | ------ | ------------------------------------------------------------------------------------------------------------------------- |\n| usage | `ExperimentalUsage \\| undefined` | - | - | 节点使用场景:`library` 表示素材库中的拖拽源,`dragging` 表示正在拖拽中的幽灵节点,`default` 表示画布内正常渲染的节点。 |\n| status | `NodeStatus \\| undefined` | - | - | 节点状态,影响外观样式:`highlighted` 高亮、`faded` 淡化、`default` 默认(使用 `render: false` 仅更新属性不触发重渲染)。 |\n| decorator | `DecoratorType \\| undefined` | - | - | 装饰器类型,用于渲染不同类型的装饰器外观(area、container、text 等),与 `usage: \"dragging\"` 配合使用。 |\n\n## Events\n\n| 事件 | detail | 说明 |\n| ---------- | --------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |\n| drag.start | `PositionTuple` — 拖拽开始时的鼠标坐标 `[clientX, clientY]` | 在 `usage: \"library\"` 模式下,用户开始拖拽节点时触发(移动距离超过阈值后才触发)。 |\n| drag.move | `PositionTuple` — 拖拽过程中的当前鼠标坐标 `[clientX, clientY]` | 在 `usage: \"library\"` 模式下,用户拖拽节点过程中持续触发,可用于更新幽灵节点位置。 |\n| drag.end | `PositionTuple` — 拖拽结束时的鼠标坐标 `[clientX, clientY]` | 在 `usage: \"library\"` 模式下,用户释放鼠标结束拖拽时触发,可通过 `dropNode` 或 `dropDecorator` 方法将节点添加到画布。 |\n\n## Examples\n\n### Basic\n\n展示节点在画布内渲染的基本用法,使用 `status` 属性控制节点高亮状态。\n\n```yaml preview\nbrick: diagram.experimental-node\nproperties:\n status: default\nchildren:\n - brick: span\n properties:\n textContent: Node A\n# -- YAML DELIMITER (1nbbm8) --\n# <diagram.experimental-node status=\"default\">\n# <span>Node A</span>\n# </diagram.experimental-node>\n# \n```\n\n### Library Usage\n\n展示素材库中的可拖拽节点,通过 `drag.start`、`drag.move`、`drag.end` 事件配合 `eo-draw-canvas` 实现拖拽放置。\n\n```yaml preview minHeight=\"400px\"\n- brick: div\n properties:\n style:\n display: flex\n gap: 1em\n context:\n - name: dragging\n children:\n - brick: div\n properties:\n style:\n width: 150px\n padding: 1em\n border-right: 1px solid var(--palette-gray-4)\n children:\n - brick: diagram.experimental-node\n properties:\n usage: library\n textContent: Node A\n events:\n drag.start:\n action: context.replace\n args:\n - dragging\n - position: <% EVENT.detail %>\n label: Node A\n drag.move:\n action: context.replace\n args:\n - dragging\n - position: <% EVENT.detail %>\n label: Node A\n drag.end:\n - action: context.replace\n args:\n - dragging\n - null\n - target: eo-draw-canvas\n method: dropNode\n args:\n - position: <% EVENT.detail %>\n id: node-a\n data:\n name: Node A\n - brick: eo-draw-canvas\n properties:\n style:\n flex: 1\n height: 400px\n layout: manual\n defaultNodeSize: [80, 40]\n defaultNodeBricks:\n - useBrick:\n brick: diagram.experimental-node\n properties:\n textContent: <% DATA.node.data.name %>\n status: default\n- brick: diagram.experimental-node\n properties:\n usage: dragging\n textContent: <% CTX.dragging?.label %>\n hidden: <% !CTX.dragging %>\n style: |\n <%=\n CTX.dragging ? {\n position: fixed,\n left: `${CTX.dragging.position[0]}px`,\n top: `${CTX.dragging.position[1]}px`,\n pointerEvents: none\n } : {}\n %>\n# -- YAML DELIMITER (1nbbm8) --\n# <div style=\"display: flex; gap: 1em\">\n# <div\n# style=\"\n# width: 150px;\n# padding: 1em;\n# border-right: 1px solid var(--palette-gray-4);\n# \"\n# >\n# <diagram.experimental-node usage=\"library\" id=\"brick-1\">\n# Node A\n# </diagram.experimental-node>\n# </div>\n# <eo-draw-canvas\n# style=\"flex: 1; height: 400px\"\n# layout=\"manual\"\n# id=\"brick-2\"\n# ></eo-draw-canvas>\n# </div>\n# <diagram.experimental-node usage=\"dragging\" hidden=\"&lt;% !CTX.dragging %&gt;\">\n# &lt;% CTX.dragging?.label %&gt;\n# </diagram.experimental-node>\n# \n# <script>\n# const brick_1 = document.getElementById(\"brick-1\");\n# brick_1.addEventListener(\"drag.start\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_1.addEventListener(\"drag.move\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_1.addEventListener(\"drag.end\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_1.addEventListener(\"drag.end\", (e) => {\n# const brick = document.querySelector(\"eo-draw-canvas\");\n# brick.dropNode({\n# position: \"<% EVENT.detail %>\",\n# id: \"node-a\",\n# data: { name: \"Node A\" },\n# });\n# });\n# \n# const brick_2 = document.getElementById(\"brick-2\");\n# brick_2.defaultNodeSize = [80, 40];\n# brick_2.defaultNodeBricks = [\n# {\n# useBrick: {\n# brick: \"diagram.experimental-node\",\n# properties: {\n# textContent: \"<% DATA.node.data.name %>\",\n# status: \"default\",\n# },\n# },\n# },\n# ];\n# </script>\n# \n```\n\n### Status States\n\n展示节点不同状态下的外观效果。\n\n```yaml preview\nbrick: div\nproperties:\n style:\n display: flex\n gap: 1em\n padding: 1em\nchildren:\n - brick: diagram.experimental-node\n properties:\n status: default\n children:\n - brick: span\n properties:\n textContent: Default\n - brick: diagram.experimental-node\n properties:\n status: highlighted\n children:\n - brick: span\n properties:\n textContent: Highlighted\n - brick: diagram.experimental-node\n properties:\n status: faded\n children:\n - brick: span\n properties:\n textContent: Faded\n# -- YAML DELIMITER (1nbbm8) --\n# <div style=\"display: flex; gap: 1em; padding: 1em\">\n# <diagram.experimental-node status=\"default\">\n# <span>Default</span>\n# </diagram.experimental-node>\n# <diagram.experimental-node status=\"highlighted\">\n# <span>Highlighted</span>\n# </diagram.experimental-node>\n# <diagram.experimental-node status=\"faded\">\n# <span>Faded</span>\n# </diagram.experimental-node>\n# </div>\n# \n```\n"
13
+ },
14
+ "eo-display-canvas": {
15
+ "doc": "---\ntagName: eo-display-canvas\ndisplayName: WrappedEoDisplayCanvas\ndescription: 用于展示查看的画布构件,支持 manual、force、dagre 多种布局,可展示节点、边和装饰器,支持缩放、平移、激活目标高亮、淡化无关元素等功能。\ncategory: diagram\nsource: \"@next-bricks/diagram\"\n---\n\n# eo-display-canvas\n\n> 用于展示查看的画布构件,支持 manual、force、dagre 多种布局,可展示节点、边和装饰器,支持缩放、平移、激活目标高亮、淡化无关元素等功能。\n\n## Props\n\n| 属性 | 类型 | 必填 | 默认值 | 说明 |\n| ----------------------------------- | ----------------------------------- | ---- | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------ |\n| cells | `InitialCell[] \\| undefined` | - | - | 画布中的单元格数据,包含节点(node)、边(edge)和装饰器(decorator)。 |\n| layout | `LayoutType` | 是 | - | 画布布局类型,支持 `manual`(手动定位)、`force`(力导向)、`dagre`(层次有向图)。 |\n| layoutOptions | `LayoutOptions \\| undefined` | - | - | 布局算法选项,根据 layout 类型不同,支持不同参数(如 dagre 的 ranksep/nodesep,force 的碰撞参数等)。 |\n| autoSize | `AutoSize \\| undefined` | - | - | 是否自动计算节点尺寸,启用后画布会根据节点内容自动调整节点大小。 |\n| defaultNodeSize | `SizeTuple` | 是 | `[DEFAULT_NODE_SIZE, DEFAULT_NODE_SIZE]` | 节点默认尺寸,格式为 `[width, height]`,在节点未指定尺寸时使用。 |\n| defaultNodeBricks | `NodeBrickConf[] \\| undefined` | - | - | 节点默认砖块配置,指定渲染节点的自定义构件,可按节点类型匹配不同配置。 |\n| degradedThreshold | `number \\| undefined` | - | `500` | 当节点数量达到或超过 `degradedThreshold` 时,节点将被降级展示。 |\n| degradedNodeLabel | `string \\| undefined` | - | `\"<% DATA.node.id %>\"` | 设置节点将降级展示时显示的名称。 |\n| defaultEdgeLines | `EdgeLineConf[] \\| undefined` | - | - | 使用条件判断设置默认的边对应的连线。在 `if` 表达式中 `DATA` 为 `{ edge }`。 |\n| activeTarget | `ActiveTarget \\| null \\| undefined` | - | - | 当前激活目标,可以是节点(`{ type: \"node\", id }`)或边(`{ type: \"edge\", id }`)等,为 null 表示无激活目标。 |\n| fadeUnrelatedCells | `boolean \\| undefined` | - | - | 当鼠标悬浮到某节点上时,隐藏其他跟该节点无关的元素,高亮相关节点和边。 |\n| zoomable | `boolean \\| undefined` | - | `true` | 是否允许通过鼠标滚轮或触控板捏合手势缩放画布,默认为 true。 |\n| scrollable | `boolean \\| undefined` | - | `true` | 是否允许通过滚轮平移画布(非捏合手势),默认为 true。 |\n| pannable | `boolean \\| undefined` | - | `true` | 是否允许通过鼠标拖拽平移画布,默认为 true。 |\n| scaleRange | `RangeTuple \\| undefined` | - | - | 缩放比例范围,格式为 `[min, max]`,默认范围由内部常量决定。 |\n| hideZoomBar | `boolean \\| undefined` | - | - | 隐藏右下角放大缩小的控制栏。 |\n| autoCenterWhenCellsChange | `boolean \\| undefined` | - | - | 每当 cells 改变时,重新自动居中。 |\n| doNotResetActiveTargetForSelector | `string \\| undefined` | - | - | 选择器,点击该选择器对应的元素时不重置 `activeTarget`。 |\n| doNotResetActiveTargetOutsideCanvas | `boolean \\| undefined` | - | - | 在画布外点击时不重置 `activeTarget`。 |\n| extraStyleTexts | `string[] \\| undefined` | - | - | 注入到 Shadow DOM 的额外 CSS 样式文本列表。 |\n\n## Events\n\n| 事件 | detail | 说明 |\n| ------------------- | ------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- |\n| activeTarget.change | `ActiveTarget \\| null` — 当前激活目标,节点/边对象或 null | 激活目标变化时触发,当用户点击节点或边使其激活,或点击空白处取消激活时触发。 |\n| cell.contextmenu | `CellContextMenuDetail` — 右键菜单详情,包含 `{ cell: 对应的单元格, clientX: 鼠标X坐标, clientY: 鼠标Y坐标 }` | 用户右键点击节点或边时触发,常用于弹出上下文菜单。 |\n| cell.click | `CellContextMenuDetail` — 点击详情,包含 `{ cell: 对应的单元格, clientX: 鼠标X坐标, clientY: 鼠标Y坐标 }` | 用户左键点击节点或边时触发。 |\n\n## Methods\n\n| 方法 | 参数 | 返回值 | 说明 |\n| ------ | ------------ | ------ | ------------------------------------------------------ |\n| center | `() => void` | `void` | 将画布视图重置并居中,使所有单元格重新显示在视口中央。 |\n\n## Examples\n\n### Basic\n\n展示基本的手动布局画布,包含节点、边、装饰器,并支持右键菜单和激活高亮。\n\n```yaml preview minHeight=\"600px\"\n- brick: div\n properties:\n style:\n display: flex\n height: 600px\n gap: 1em\n context:\n - name: initialCells\n value: |\n <%\n [\n {\n type: \"decorator\",\n id: \"area-1\",\n decorator: \"area\",\n view: {\n x: 10,\n y: 20,\n width: 400,\n height: 300,\n },\n },\n {\n type: \"decorator\",\n id: \"container-1\",\n decorator: \"container\",\n view: {\n x: 50,\n y: 400,\n width: 280,\n height: 120,\n direction: \"top\",\n text: \" 上层服务\"\n },\n },\n {\n type: \"edge\",\n source: \"X\",\n target: \"Y\",\n data: {\n virtual: false,\n showStartArrow: false,\n strokeColor:\"red\",\n strokeWidth: 5,\n }\n },\n {\n type: \"edge\",\n source: \"X\",\n target: \"W\",\n data: {\n virtual: false,\n showStartArrow: true,\n strokeColor:\"pink\",\n animate:{\n useAnimate: true,\n duration: 4\n }\n }\n },\n {\n type: \"edge\",\n source: \"X\",\n target: \"Z\",\n data: {\n virtual: true,\n showStartArrow: true,\n strokeColor:\"blue\",\n animate:{\n useAnimate: true\n }\n }\n },\n {\n type: \"edge\",\n source: \"W\",\n target: \"Z\",\n view: {\n entryPosition: { x: 0, y: 0.5 },\n exitPosition: {x: 0.5, y: 0}\n }\n }\n ].concat(\n [\"X\", \"Y\", \"Z\", \"W\"].map((id) => ({\n type: \"node\",\n id,\n containerId: [\"X\",\"Y\",\"Z\"].includes(id)?\"container-1\":undefined,\n data: {\n name: `Node ${id}`,\n },\n view: {\n x: Math.round(\n id === \"X\"\n ? 200 + Math.random() * 200\n : id === \"Y\"\n ? Math.random() * 300\n : 300 + Math.random() * 300\n ),\n y: (id === \"X\" ? 0 : 300) + Math.round((Math.random() * 200)),\n width: 60,\n height: 60,\n }\n }))\n ).concat([\n {\n type: \"decorator\",\n id: \"text-1\",\n decorator: \"text\",\n view: {\n x: 100,\n y: 120,\n width: 100,\n height: 20,\n text: \"Hello!\"\n },\n },\n ])\n %>\n - name: activeTarget\n - name: targetCell\n children:\n - brick: div\n properties:\n style:\n flex: 1\n minWidth: 0\n children:\n - brick: eo-display-canvas\n properties:\n style:\n width: 100%\n height: 100%\n activeTarget: <%= CTX.activeTarget %>\n fadeUnrelatedCells: true\n defaultNodeSize: [60, 60]\n defaultNodeBricks:\n - useBrick:\n brick: diagram.experimental-node\n properties:\n textContent: <% `Node ${DATA.node.id}` %>\n status: |\n <%=\n CTX.activeTarget?.type === \"node\" && CTX.activeTarget.id === DATA.node.id\n ? \"highlighted\"\n : \"default\"\n %>\n defaultEdgeLines:\n - if: true\n dashed: <% DATA.edge?.data?.virtual %>\n strokeColor: <% DATA.edge?.data?.strokeColor %>\n showStartArrow: <% DATA.edge?.data?.showStartArrow %>\n strokeWidth: <% DATA.edge?.data?.strokeWidth %>\n animate: <% DATA.edge?.data?.animate %>\n showStartArrow: true\n markers:\n - placement: end\n type: circle\n - placement: start\n type: arrow\n cells: <% CTX.initialCells %>\n events:\n activeTarget.change:\n action: context.replace\n args:\n - activeTarget\n - <% EVENT.detail %>\n cell.contextmenu:\n - target: eo-context-menu\n method: open\n args:\n - position:\n - <% EVENT.detail.clientX %>\n - <% EVENT.detail.clientY %>\n - action: context.replace\n args:\n - targetCell\n - <% EVENT.detail.cell %>\n- brick: eo-context-menu\n properties:\n actions: |\n <%=\n [\n {\n text: `Test ${CTX.targetCell?.type}`,\n event: `test-${CTX.targetCell?.type}`,\n }\n ]\n %>\n# -- YAML DELIMITER (1nbbm8) --\n# <div style=\"display: flex; height: 600px; gap: 1em\">\n# <div style=\"flex: 1; min-width: 0\">\n# <eo-display-canvas\n# style=\"width: 100%; height: 100%\"\n# fade-unrelated-cells\n# id=\"brick-1\"\n# ></eo-display-canvas>\n# </div>\n# </div>\n# <eo-context-menu\n# actions=\"&lt;%=\n# [\n# {\n# text: `Test ${CTX.targetCell?.type}`,\n# event: `test-${CTX.targetCell?.type}`,\n# }\n# ]\n# %&gt;\n# \"\n# ></eo-context-menu>\n# \n# <script>\n# const brick_1 = document.getElementById(\"brick-1\");\n# brick_1.activeTarget = \"<%= CTX.activeTarget %>\";\n# brick_1.defaultNodeSize = [60, 60];\n# brick_1.defaultNodeBricks = [\n# {\n# useBrick: {\n# brick: \"diagram.experimental-node\",\n# properties: {\n# textContent: \"<% `Node ${DATA.node.id}` %>\",\n# status:\n# '<%=\\n CTX.activeTarget?.type === \"node\" && CTX.activeTarget.id === DATA.node.id\\n ? \"highlighted\"\\n : \"default\"\\n%>\\n',\n# },\n# },\n# },\n# ];\n# brick_1.defaultEdgeLines = [\n# {\n# if: true,\n# dashed: \"<% DATA.edge?.data?.virtual %>\",\n# strokeColor: \"<% DATA.edge?.data?.strokeColor %>\",\n# showStartArrow: true,\n# strokeWidth: \"<% DATA.edge?.data?.strokeWidth %>\",\n# animate: \"<% DATA.edge?.data?.animate %>\",\n# markers: [\n# {\n# placement: \"end\",\n# type: \"circle\",\n# },\n# {\n# placement: \"start\",\n# type: \"arrow\",\n# },\n# ],\n# },\n# ];\n# brick_1.cells = \"<% CTX.initialCells %>\";\n# brick_1.addEventListener(\"activeTarget.change\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_1.addEventListener(\"cell.contextmenu\", (e) => {\n# const brick = document.querySelector(\"eo-context-menu\");\n# brick.open({\n# position: [\"<% EVENT.detail.clientX %>\", \"<% EVENT.detail.clientY %>\"],\n# });\n# });\n# brick_1.addEventListener(\"cell.contextmenu\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# </script>\n# \n```\n\n### Force layout\n\n展示 force(力导向)布局画布,节点位置由物理引擎自动计算。\n\n```yaml preview minHeight=\"600px\"\n- brick: div\n properties:\n style:\n display: flex\n height: 600px\n gap: 1em\n context:\n - name: initialCells\n value: |\n <%\n [\n {\n type: \"decorator\",\n id: \"area-1\",\n decorator: \"area\",\n view: {\n x: 10,\n y: 20,\n width: 400,\n height: 300,\n },\n },\n {\n type: \"edge\",\n source: \"X\",\n target: \"Y\",\n },\n {\n type: \"edge\",\n source: \"X\",\n target: \"Z\",\n data: {\n virtual: true,\n }\n },\n ].concat(\n [\"X\", \"Y\", \"Z\", \"W\"].map((id) => ({\n type: \"node\",\n id,\n data: {\n name: `Node ${id}`,\n },\n view: {\n width: 60,\n height: 60,\n }\n }))\n ).concat([\n {\n type: \"decorator\",\n id: \"text-1\",\n decorator: \"text\",\n view: {\n x: 100,\n y: 120,\n width: 100,\n height: 20,\n text: \"Hello!\"\n },\n },\n ])\n %>\n - name: activeTarget\n - name: targetCell\n children:\n - brick: div\n properties:\n style:\n flex: 1\n minWidth: 0\n children:\n - brick: eo-display-canvas\n properties:\n style:\n width: 100%\n height: 100%\n activeTarget: <%= CTX.activeTarget %>\n fadeUnrelatedCells: true\n layout: force\n defaultNodeSize: [60, 60]\n defaultNodeBricks:\n - useBrick:\n brick: diagram.experimental-node\n properties:\n textContent: <% `Node ${DATA.node.id}` %>\n status: |\n <%=\n CTX.activeTarget?.type === \"node\" && CTX.activeTarget.id === DATA.node.id\n ? \"highlighted\"\n : \"default\"\n %>\n defaultEdgeLines:\n - if: <% DATA.edge.data?.virtual %>\n dashed: true\n cells: <% CTX.initialCells %>\n events:\n activeTarget.change:\n action: context.replace\n args:\n - activeTarget\n - <% EVENT.detail %>\n cell.contextmenu:\n - target: eo-context-menu\n method: open\n args:\n - position:\n - <% EVENT.detail.clientX %>\n - <% EVENT.detail.clientY %>\n - action: context.replace\n args:\n - targetCell\n - <% EVENT.detail.cell %>\n- brick: eo-context-menu\n properties:\n actions: |\n <%=\n [\n {\n text: `Test ${CTX.targetCell?.type}`,\n event: `test-${CTX.targetCell?.type}`,\n }\n ]\n %>\n# -- YAML DELIMITER (1nbbm8) --\n# <div style=\"display: flex; height: 600px; gap: 1em\">\n# <div style=\"flex: 1; min-width: 0\">\n# <eo-display-canvas\n# style=\"width: 100%; height: 100%\"\n# fade-unrelated-cells\n# layout=\"force\"\n# id=\"brick-1\"\n# ></eo-display-canvas>\n# </div>\n# </div>\n# <eo-context-menu\n# actions=\"&lt;%=\n# [\n# {\n# text: `Test ${CTX.targetCell?.type}`,\n# event: `test-${CTX.targetCell?.type}`,\n# }\n# ]\n# %&gt;\n# \"\n# ></eo-context-menu>\n# \n# <script>\n# const brick_1 = document.getElementById(\"brick-1\");\n# brick_1.activeTarget = \"<%= CTX.activeTarget %>\";\n# brick_1.defaultNodeSize = [60, 60];\n# brick_1.defaultNodeBricks = [\n# {\n# useBrick: {\n# brick: \"diagram.experimental-node\",\n# properties: {\n# textContent: \"<% `Node ${DATA.node.id}` %>\",\n# status:\n# '<%=\\n CTX.activeTarget?.type === \"node\" && CTX.activeTarget.id === DATA.node.id\\n ? \"highlighted\"\\n : \"default\"\\n%>\\n',\n# },\n# },\n# },\n# ];\n# brick_1.defaultEdgeLines = [\n# {\n# if: \"<% DATA.edge.data?.virtual %>\",\n# dashed: true,\n# },\n# ];\n# brick_1.cells = \"<% CTX.initialCells %>\";\n# brick_1.addEventListener(\"activeTarget.change\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_1.addEventListener(\"cell.contextmenu\", (e) => {\n# const brick = document.querySelector(\"eo-context-menu\");\n# brick.open({\n# position: [\"<% EVENT.detail.clientX %>\", \"<% EVENT.detail.clientY %>\"],\n# });\n# });\n# brick_1.addEventListener(\"cell.contextmenu\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# </script>\n# \n```\n\n### Dagre layout\n\n展示 dagre(层次有向图)布局画布,节点按层级排列,支持折线连线和自定义连线样式。\n\n```yaml preview minHeight=\"600px\"\n- brick: div\n properties:\n style:\n display: flex\n height: 600px\n gap: 1em\n context:\n - name: initialCells\n value: |\n <%\n [\n {\n type: \"decorator\",\n id: \"area-1\",\n decorator: \"area\",\n view: {\n x: 10,\n y: 20,\n width: 400,\n height: 300,\n },\n },\n {\n type: \"edge\",\n source: \"X\",\n target: \"Y\",\n view: {\n type: \"polyline\"\n }\n },\n {\n type: \"edge\",\n source: \"X\",\n target: \"Z\",\n data: {\n virtual: true,\n }\n },\n {\n type: \"edge\",\n source: \"Z\",\n target: \"W\",\n },\n ].concat(\n [\"X\", \"Y\", \"Z\", \"W\"].map((id) => ({\n type: \"node\",\n id,\n data: {\n name: `Node ${id}`,\n },\n view: {\n width: 60,\n height: 60,\n }\n }))\n )\n %>\n - name: activeTarget\n - name: targetCell\n children:\n - brick: div\n properties:\n style:\n flex: 1\n minWidth: 0\n children:\n - brick: eo-display-canvas\n properties:\n style:\n width: 100%\n height: 100%\n activeTarget: <%= CTX.activeTarget %>\n fadeUnrelatedCells: true\n layout: dagre\n layoutOptions:\n ranksep: 80\n nodesep: 80\n defaultNodeSize: [60, 60]\n defaultNodeBricks:\n - useBrick:\n brick: diagram.experimental-node\n properties:\n textContent: <% `Node ${DATA.node.id}` %>\n status: |\n <%=\n CTX.activeTarget?.type === \"node\" && CTX.activeTarget.id === DATA.node.id\n ? \"highlighted\"\n : \"default\"\n %>\n defaultEdgeLines:\n - dashed: <% !!DATA.edge.data?.virtual %>\n strokeColor: var(--palette-blue-6)\n overrides:\n active:\n strokeWidth: <% 2 * (DATA.edge?.data?.strokeWidth ?? 1) %>\n strokeColor: cyan\n activeRelated:\n strokeWidth: <% 2 * (DATA.edge?.data?.strokeWidth ?? 1) %>\n motion:\n shape: '<% DATA.edge.data?.virtual ? \"dot\" : \"triangle\" %>'\n cells: <% CTX.initialCells %>\n events:\n activeTarget.change:\n action: context.replace\n args:\n - activeTarget\n - <% EVENT.detail %>\n cell.contextmenu:\n - target: eo-context-menu\n method: open\n args:\n - position:\n - <% EVENT.detail.clientX %>\n - <% EVENT.detail.clientY %>\n - action: context.replace\n args:\n - targetCell\n - <% EVENT.detail.cell %>\n- brick: eo-context-menu\n properties:\n actions: |\n <%=\n [\n {\n text: `Test ${CTX.targetCell?.type}`,\n event: `test-${CTX.targetCell?.type}`,\n }\n ]\n %>\n# -- YAML DELIMITER (1nbbm8) --\n# <div style=\"display: flex; height: 600px; gap: 1em\">\n# <div style=\"flex: 1; min-width: 0\">\n# <eo-display-canvas\n# style=\"width: 100%; height: 100%\"\n# fade-unrelated-cells\n# layout=\"dagre\"\n# id=\"brick-1\"\n# ></eo-display-canvas>\n# </div>\n# </div>\n# <eo-context-menu\n# actions=\"&lt;%=\n# [\n# {\n# text: `Test ${CTX.targetCell?.type}`,\n# event: `test-${CTX.targetCell?.type}`,\n# }\n# ]\n# %&gt;\n# \"\n# ></eo-context-menu>\n# \n# <script>\n# const brick_1 = document.getElementById(\"brick-1\");\n# brick_1.activeTarget = \"<%= CTX.activeTarget %>\";\n# brick_1.layoutOptions = {\n# ranksep: 80,\n# nodesep: 80,\n# };\n# brick_1.defaultNodeSize = [60, 60];\n# brick_1.defaultNodeBricks = [\n# {\n# useBrick: {\n# brick: \"diagram.experimental-node\",\n# properties: {\n# textContent: \"<% `Node ${DATA.node.id}` %>\",\n# status:\n# '<%=\\n CTX.activeTarget?.type === \"node\" && CTX.activeTarget.id === DATA.node.id\\n ? \"highlighted\"\\n : \"default\"\\n%>\\n',\n# },\n# },\n# },\n# ];\n# brick_1.defaultEdgeLines = [\n# {\n# dashed: \"<% !!DATA.edge.data?.virtual %>\",\n# strokeColor: \"var(--palette-blue-6)\",\n# overrides: {\n# active: {\n# strokeWidth: \"<% 2 * (DATA.edge?.data?.strokeWidth ?? 1) %>\",\n# strokeColor: \"cyan\",\n# },\n# activeRelated: {\n# strokeWidth: \"<% 2 * (DATA.edge?.data?.strokeWidth ?? 1) %>\",\n# motion: {\n# shape: '<% DATA.edge.data?.virtual ? \"dot\" : \"triangle\" %>',\n# },\n# },\n# },\n# },\n# ];\n# brick_1.cells = \"<% CTX.initialCells %>\";\n# brick_1.addEventListener(\"activeTarget.change\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_1.addEventListener(\"cell.contextmenu\", (e) => {\n# const brick = document.querySelector(\"eo-context-menu\");\n# brick.open({\n# position: [\"<% EVENT.detail.clientX %>\", \"<% EVENT.detail.clientY %>\"],\n# });\n# });\n# brick_1.addEventListener(\"cell.contextmenu\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# </script>\n# \n```\n\n### Degraded diagram\n\n展示节点数量超过降级阈值时的降级模式,节点以简单 SVG 形式渲染以提升性能。\n\n```yaml preview minHeight=\"600px\"\n- brick: div\n properties:\n style:\n display: flex\n height: 600px\n gap: 1em\n context:\n - name: initialCells\n value: |\n <%\n ((...seeds) => seeds.map((seed) => ({\n type: \"node\",\n id: seed,\n data: {\n name: seed,\n },\n })))(\n ...(\n new Array(500).fill(null).map((_, i) => String(i))\n )\n )\n %>\n - name: activeTarget\n - name: targetCell\n children:\n - brick: div\n properties:\n style:\n flex: 1\n minWidth: 0\n children:\n - brick: eo-display-canvas\n properties:\n style:\n width: 100%\n height: 100%\n activeTarget: <%= CTX.activeTarget %>\n fadeUnrelatedCells: true\n layout: force\n defaultNodeSize: [60, 60]\n degradedThreshold: 500\n degradedNodeLabel: <% DATA.node.id %>\n defaultNodeBricks:\n - useBrick:\n brick: diagram.experimental-node\n properties:\n textContent: <% `Node ${DATA.node.id}` %>\n status: |\n <%=\n CTX.activeTarget?.type === \"node\" && CTX.activeTarget.id === DATA.node.id\n ? \"highlighted\"\n : \"default\"\n %>\n defaultEdgeLines:\n - if: true\n dashed: <% DATA.edge?.data?.virtual %>\n strokeColor: <% DATA.edge?.data?.strokeColor %>\n showStartArrow: <% DATA.edge?.data?.showStartArrow %>\n strokeWidth: <% DATA.edge?.data?.strokeWidth %>\n animate: <% DATA.edge?.data?.animate %>\n cells: <% CTX.initialCells %>\n events:\n activeTarget.change:\n action: context.replace\n args:\n - activeTarget\n - <% EVENT.detail %>\n cell.contextmenu:\n - target: eo-context-menu\n method: open\n args:\n - position:\n - <% EVENT.detail.clientX %>\n - <% EVENT.detail.clientY %>\n - action: context.replace\n args:\n - targetCell\n - <% EVENT.detail.cell %>\n- brick: eo-context-menu\n properties:\n actions: |\n <%=\n [\n {\n text: `Test ${CTX.targetCell?.type}`,\n event: `test-${CTX.targetCell?.type}`,\n }\n ]\n %>\n# -- YAML DELIMITER (1nbbm8) --\n# <div style=\"display: flex; height: 600px; gap: 1em\">\n# <div style=\"flex: 1; min-width: 0\">\n# <eo-display-canvas\n# style=\"width: 100%; height: 100%\"\n# fade-unrelated-cells\n# layout=\"force\"\n# degraded-threshold=\"500\"\n# id=\"brick-1\"\n# ></eo-display-canvas>\n# </div>\n# </div>\n# <eo-context-menu\n# actions=\"&lt;%=\n# [\n# {\n# text: `Test ${CTX.targetCell?.type}`,\n# event: `test-${CTX.targetCell?.type}`,\n# }\n# ]\n# %&gt;\n# \"\n# ></eo-context-menu>\n# \n# <script>\n# const brick_1 = document.getElementById(\"brick-1\");\n# brick_1.activeTarget = \"<%= CTX.activeTarget %>\";\n# brick_1.defaultNodeSize = [60, 60];\n# brick_1.degradedNodeLabel = \"<% DATA.node.id %>\";\n# brick_1.defaultNodeBricks = [\n# {\n# useBrick: {\n# brick: \"diagram.experimental-node\",\n# properties: {\n# textContent: \"<% `Node ${DATA.node.id}` %>\",\n# status:\n# '<%=\\n CTX.activeTarget?.type === \"node\" && CTX.activeTarget.id === DATA.node.id\\n ? \"highlighted\"\\n : \"default\"\\n%>\\n',\n# },\n# },\n# },\n# ];\n# brick_1.defaultEdgeLines = [\n# {\n# if: true,\n# dashed: \"<% DATA.edge?.data?.virtual %>\",\n# strokeColor: \"<% DATA.edge?.data?.strokeColor %>\",\n# showStartArrow: \"<% DATA.edge?.data?.showStartArrow %>\",\n# strokeWidth: \"<% DATA.edge?.data?.strokeWidth %>\",\n# animate: \"<% DATA.edge?.data?.animate %>\",\n# },\n# ];\n# brick_1.cells = \"<% CTX.initialCells %>\";\n# brick_1.addEventListener(\"activeTarget.change\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# brick_1.addEventListener(\"cell.contextmenu\", (e) => {\n# const brick = document.querySelector(\"eo-context-menu\");\n# brick.open({\n# position: [\"<% EVENT.detail.clientX %>\", \"<% EVENT.detail.clientY %>\"],\n# });\n# });\n# brick_1.addEventListener(\"cell.contextmenu\", (e) => {\n# // WARN: encountered incompatible event handlers in HTML mode, please try YAML.\n# });\n# </script>\n# \n```\n"
13
16
  }
14
17
  }