mirror of
https://github.com/antvis/chart-visualization-skills.git
synced 2026-09-14 15:58:00 +08:00
5dc3e7c180
* feat(x6): add antv/x6 3.x skill docs and eval dataset * fix: gemini cr
546 lines
222 KiB
JSON
546 lines
222 KiB
JSON
[
|
||
{
|
||
"description": "使用 X6 创建一个最基础的画布,包含两个矩形节点(hello 和 world)和一条连接边,画布背景色为浅蓝色,节点带圆角边框。参考数据:[{\"id\": \"node1\", \"shape\": \"rect\", \"label\": \"hello\", \"x\": 40, \"y\": 40}, {\"id\": \"node2\", \"shape\": \"rect\", \"label\": \"world\", \"x\": 160, \"y\": 180}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: {\n color: '#F2F7FA',\n },\n});\n\ngraph.fromJSON({\n nodes: [\n {\n id: 'node1',\n shape: 'rect',\n x: 40,\n y: 40,\n width: 100,\n height: 40,\n label: 'hello',\n attrs: {\n body: {\n stroke: '#8f8f8f',\n strokeWidth: 1,\n fill: '#fff',\n rx: 6,\n ry: 6,\n },\n },\n },\n {\n id: 'node2',\n shape: 'rect',\n x: 160,\n y: 180,\n width: 100,\n height: 40,\n label: 'world',\n attrs: {\n body: {\n stroke: '#8f8f8f',\n strokeWidth: 1,\n fill: '#fff',\n rx: 6,\n ry: 6,\n },\n },\n },\n ],\n edges: [\n {\n shape: 'edge',\n source: 'node1',\n target: 'node2',\n label: 'x6',\n attrs: {\n line: {\n stroke: '#8f8f8f',\n strokeWidth: 1,\n },\n },\n },\n ],\n});\n\ngraph.centerContent();\n"
|
||
},
|
||
{
|
||
"description": "创建一个带有双层网格和浅蓝色背景的 X6 画布,主网格线为浅灰色,次网格线稍深,主次网格线间隔为4,并在画布中添加两个节点和一条边。参考数据:[{\"id\": \"node1\", \"shape\": \"rect\", \"label\": \"hello\", \"x\": 40, \"y\": 40}, {\"id\": \"node2\", \"shape\": \"rect\", \"label\": \"world\", \"x\": 160, \"y\": 180}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: {\n color: '#F2F7FA',\n },\n grid: {\n visible: true,\n type: 'doubleMesh',\n args: [\n {\n color: '#eee',\n thickness: 1,\n },\n {\n color: '#ddd',\n thickness: 1,\n factor: 4,\n },\n ],\n },\n});\n\ngraph.fromJSON({\n nodes: [\n {\n id: 'node1',\n shape: 'rect',\n x: 40,\n y: 40,\n width: 100,\n height: 40,\n label: 'hello',\n attrs: {\n body: {\n stroke: '#8f8f8f',\n strokeWidth: 1,\n fill: '#fff',\n rx: 6,\n ry: 6,\n },\n },\n },\n {\n id: 'node2',\n shape: 'rect',\n x: 160,\n y: 180,\n width: 100,\n height: 40,\n label: 'world',\n attrs: {\n body: {\n stroke: '#8f8f8f',\n strokeWidth: 1,\n fill: '#fff',\n rx: 6,\n ry: 6,\n },\n },\n },\n ],\n edges: [\n {\n shape: 'edge',\n source: 'node1',\n target: 'node2',\n label: 'x6',\n attrs: {\n line: {\n stroke: '#8f8f8f',\n strokeWidth: 1,\n },\n },\n },\n ],\n});\n\ngraph.centerContent();\n"
|
||
},
|
||
{
|
||
"description": "创建一个支持画布平移(拖拽)和按住 Ctrl 键滚轮缩放的 X6 画布,缩放范围为 0.2 到 4 倍,带网格背景。参考数据:[{\"id\": \"node1\", \"shape\": \"rect\", \"label\": \"hello\", \"x\": 40, \"y\": 40}, {\"id\": \"node2\", \"shape\": \"rect\", \"label\": \"world\", \"x\": 160, \"y\": 180}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: {\n color: '#F2F7FA',\n },\n grid: {\n visible: true,\n type: 'doubleMesh',\n args: [\n {\n color: '#eee',\n thickness: 1,\n },\n {\n color: '#ddd',\n thickness: 1,\n factor: 4,\n },\n ],\n },\n panning: true,\n mousewheel: {\n enabled: true,\n modifiers: 'Ctrl',\n maxScale: 4,\n minScale: 0.2,\n },\n});\n\ngraph.fromJSON({\n nodes: [\n {\n id: 'node1',\n shape: 'rect',\n x: 40,\n y: 40,\n width: 100,\n height: 40,\n label: 'hello',\n attrs: {\n body: {\n stroke: '#8f8f8f',\n strokeWidth: 1,\n fill: '#fff',\n rx: 6,\n ry: 6,\n },\n },\n },\n {\n id: 'node2',\n shape: 'rect',\n x: 160,\n y: 180,\n width: 100,\n height: 40,\n label: 'world',\n attrs: {\n body: {\n stroke: '#8f8f8f',\n strokeWidth: 1,\n fill: '#fff',\n rx: 6,\n ry: 6,\n },\n },\n },\n ],\n edges: [\n {\n source: 'node1',\n target: 'node2',\n attrs: {\n line: {\n stroke: '#8f8f8f',\n strokeWidth: 1,\n },\n },\n },\n ],\n});\n\ngraph.centerContent();\n"
|
||
},
|
||
{
|
||
"description": "创建一个 X6 画布,支持缩放和居中功能,初始化后将画布内容居中显示,画布支持 panning 和 mousewheel 缩放。参考数据:[{\"id\": \"source\", \"shape\": \"rect\", \"label\": \"Source\", \"x\": 40, \"y\": 40, \"width\": 100, \"height\": 40}, {\"id\": \"target\", \"shape\": \"rect\", \"label\": \"Target\", \"x\": 200, \"y\": 200, \"width\": 100, \"height\": 40}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: {\n color: '#F2F7FA',\n },\n grid: {\n visible: true,\n type: 'doubleMesh',\n args: [\n {\n color: '#eee',\n thickness: 1,\n },\n {\n color: '#ddd',\n thickness: 1,\n factor: 4,\n },\n ],\n },\n panning: true,\n mousewheel: {\n enabled: true,\n modifiers: 'Ctrl',\n maxScale: 4,\n minScale: 0.2,\n },\n});\n\nconst source = graph.addNode({\n shape: 'rect',\n x: 40,\n y: 40,\n width: 100,\n height: 40,\n label: 'Source',\n attrs: {\n body: {\n stroke: '#8f8f8f',\n strokeWidth: 1,\n fill: '#fff',\n rx: 6,\n ry: 6,\n },\n },\n});\n\nconst target = graph.addNode({\n shape: 'rect',\n x: 200,\n y: 200,\n width: 100,\n height: 40,\n label: 'Target',\n attrs: {\n body: {\n stroke: '#8f8f8f',\n strokeWidth: 1,\n fill: '#fff',\n rx: 6,\n ry: 6,\n },\n },\n});\n\ngraph.addEdge({\n source,\n target,\n attrs: {\n line: {\n stroke: '#8f8f8f',\n strokeWidth: 1,\n },\n },\n});\n\ngraph.zoomToFit();\ngraph.centerContent();\n"
|
||
},
|
||
{
|
||
"description": "在 X6 中注册一个自定义节点 shape,继承自 rect,包含一个矩形背景、一张图标图片和文字标签,然后用该自定义节点创建两个节点并连线。参考数据:[{\"id\": \"source\", \"shape\": \"custom-node\", \"label\": \"hello\", \"x\": 40, \"y\": 40}, {\"id\": \"target\", \"shape\": \"custom-node\", \"label\": \"world\", \"x\": 300, \"y\": 220}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nGraph.registerNode(\n 'custom-node',\n {\n inherit: 'rect',\n width: 100,\n height: 40,\n markup: [\n {\n tagName: 'rect',\n selector: 'body',\n },\n {\n tagName: 'image',\n selector: 'img',\n },\n {\n tagName: 'text',\n selector: 'label',\n },\n ],\n attrs: {\n body: {\n stroke: '#8f8f8f',\n strokeWidth: 1,\n fill: '#fff',\n rx: 6,\n ry: 6,\n },\n img: {\n 'xlink:href': 'https://gw.alipayobjects.com/zos/antfincdn/FLrTNDvlna/antv.png',\n width: 16,\n height: 16,\n x: 12,\n y: 12,\n },\n },\n },\n true,\n);\n\nconst graph = new Graph({\n container: 'container',\n background: {\n color: '#F2F7FA',\n },\n});\n\nconst source = graph.addNode({\n shape: 'custom-node',\n x: 40,\n y: 40,\n label: 'hello',\n});\n\nconst target = graph.addNode({\n shape: 'custom-node',\n x: 300,\n y: 220,\n label: 'world',\n});\n\ngraph.addEdge({\n source,\n target,\n attrs: {\n line: {\n stroke: '#8f8f8f',\n strokeWidth: 1,\n },\n },\n});\n"
|
||
},
|
||
{
|
||
"description": "创建一个 X6 画布,包含一个矩形节点,然后通过 node.attr() 方法动态修改节点的填充颜色和边框样式。参考数据:[{\"id\": \"node\", \"shape\": \"rect\", \"label\": \"Hello\", \"x\": 100, \"y\": 60, \"width\": 100, \"height\": 40}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: {\n color: '#F2F7FA',\n },\n});\n\nconst node = graph.addNode({\n shape: 'rect',\n x: 100,\n y: 60,\n width: 100,\n height: 40,\n label: 'Hello',\n attrs: {\n body: {\n stroke: '#8f8f8f',\n strokeWidth: 1,\n fill: '#fff',\n rx: 6,\n ry: 6,\n },\n },\n});\n\nnode.attr('body/fill', '#d9f7be');\nnode.attr('body/stroke', '#52c41a');\nnode.attr('label/fill', '#135200');\n"
|
||
},
|
||
{
|
||
"description": "创建三个不同大小的矩形节点,分别为小(60x30)、中(100x50)、大(140x60),水平排列,颜色分别为蓝色、绿色、橙色。参考数据:[{\"shape\": \"rect\", \"label\": \"Small\", \"x\": 40, \"y\": 80, \"width\": 60, \"height\": 30}, {\"shape\": \"rect\", \"label\": \"Medium\", \"x\": 140, \"y\": 70, \"width\": 100, \"height\": 50}, {\"shape\": \"rect\", \"label\": \"Large\", \"x\": 280, \"y\": 60, \"width\": 140, \"height\": 60}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: {\n color: '#F2F7FA',\n },\n});\n\ngraph.addNode({\n shape: 'rect',\n x: 40,\n y: 80,\n width: 60,\n height: 30,\n label: 'Small',\n attrs: {\n body: {\n stroke: '#1890ff',\n strokeWidth: 1,\n fill: '#e6f7ff',\n rx: 4,\n ry: 4,\n },\n },\n});\n\ngraph.addNode({\n shape: 'rect',\n x: 140,\n y: 70,\n width: 100,\n height: 50,\n label: 'Medium',\n attrs: {\n body: {\n stroke: '#52c41a',\n strokeWidth: 1,\n fill: '#f6ffed',\n rx: 4,\n ry: 4,\n },\n },\n});\n\ngraph.addNode({\n shape: 'rect',\n x: 280,\n y: 60,\n width: 140,\n height: 60,\n label: 'Large',\n attrs: {\n body: {\n stroke: '#fa8c16',\n strokeWidth: 1,\n fill: '#fff7e6',\n rx: 4,\n ry: 4,\n },\n },\n});\n"
|
||
},
|
||
{
|
||
"description": "创建一个包含圆形节点和椭圆节点的画布,圆形节点用于表示开始/结束状态,椭圆节点用于表示中间步骤,并用边连接它们。参考数据:[{\"id\": \"start\", \"shape\": \"circle\", \"label\": \"Start\", \"x\": 60, \"y\": 100, \"width\": 60, \"height\": 60}, {\"id\": \"process\", \"shape\": \"ellipse\", \"label\": \"Process\", \"x\": 200, \"y\": 90, \"width\": 120, \"height\": 60}, {\"id\": \"end\", \"shape\": \"circle\", \"label\": \"End\", \"x\": 400, \"y\": 100, \"width\": 60, \"height\": 60}, {\"source\": \"start\", \"target\": \"process\"}, {\"source\": \"process\", \"target\": \"end\"}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: {\n color: '#F2F7FA',\n },\n});\n\nconst start = graph.addNode({\n shape: 'circle',\n x: 60,\n y: 100,\n width: 60,\n height: 60,\n label: 'Start',\n attrs: {\n body: {\n stroke: '#52c41a',\n strokeWidth: 2,\n fill: '#f6ffed',\n },\n },\n});\n\nconst process = graph.addNode({\n shape: 'ellipse',\n x: 200,\n y: 90,\n width: 120,\n height: 60,\n label: 'Process',\n attrs: {\n body: {\n stroke: '#1890ff',\n strokeWidth: 2,\n fill: '#e6f7ff',\n },\n },\n});\n\nconst end = graph.addNode({\n shape: 'circle',\n x: 400,\n y: 100,\n width: 60,\n height: 60,\n label: 'End',\n attrs: {\n body: {\n stroke: '#f5222d',\n strokeWidth: 2,\n fill: '#fff1f0',\n },\n },\n});\n\ngraph.addEdge({\n source: start,\n target: process,\n attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1 } },\n});\n\ngraph.addEdge({\n source: process,\n target: end,\n attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1 } },\n});\n"
|
||
},
|
||
{
|
||
"description": "创建一个矩形节点,标签文字设置为多行显示效果,通过 attrs 配置文字的对齐方式和字体大小。参考数据:[{\"shape\": \"rect\", \"x\": 100, \"y\": 60, \"width\": 180, \"height\": 60}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: {\n color: '#F2F7FA',\n },\n});\n\ngraph.addNode({\n shape: 'rect',\n x: 100,\n y: 60,\n width: 180,\n height: 60,\n attrs: {\n body: {\n stroke: '#8f8f8f',\n strokeWidth: 1,\n fill: '#fff',\n rx: 6,\n ry: 6,\n },\n label: {\n text: 'Multi-line\\nText Node',\n fontSize: 14,\n fill: '#333',\n textAnchor: 'middle',\n textVerticalAnchor: 'middle',\n },\n },\n});\n"
|
||
},
|
||
{
|
||
"description": "创建一个带有图片图标的自定义节点,图标显示在节点左侧,文字标签显示在右侧。参考数据:[{\"shape\": \"icon-node\", \"label\": \"Node with Icon\", \"x\": 100, \"y\": 60}, {\"shape\": \"icon-node\", \"label\": \"Another Node\", \"x\": 100, \"y\": 140}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nGraph.registerNode(\n 'icon-node',\n {\n inherit: 'rect',\n width: 120,\n height: 40,\n markup: [\n { tagName: 'rect', selector: 'body' },\n { tagName: 'image', selector: 'icon' },\n { tagName: 'text', selector: 'label' },\n ],\n attrs: {\n body: {\n stroke: '#8f8f8f',\n strokeWidth: 1,\n fill: '#fff',\n rx: 6,\n ry: 6,\n },\n icon: {\n width: 20,\n height: 20,\n refX: 8,\n refY: 10,\n 'xlink:href': 'https://gw.alipayobjects.com/zos/antfincdn/FLrTNDvlna/antv.png',\n },\n label: {\n refX: 36,\n refY: 0.5,\n textAnchor: 'start',\n textVerticalAnchor: 'middle',\n fontSize: 13,\n },\n },\n },\n true,\n);\n\nconst graph = new Graph({\n container: 'container',\n background: {\n color: '#F2F7FA',\n },\n});\n\ngraph.addNode({\n shape: 'icon-node',\n x: 100,\n y: 60,\n label: 'Node with Icon',\n});\n\ngraph.addNode({\n shape: 'icon-node',\n x: 100,\n y: 140,\n label: 'Another Node',\n});\n"
|
||
},
|
||
{
|
||
"description": "创建三个部分重叠的矩形节点,通过不同的 zIndex 值控制它们的层级关系,演示节点的前后遮挡效果。参考数据:[{\"shape\": \"rect\", \"label\": \"Back (z=1)\", \"x\": 40, \"y\": 40, \"width\": 120, \"height\": 80}, {\"shape\": \"rect\", \"label\": \"Middle (z=2)\", \"x\": 80, \"y\": 70, \"width\": 120, \"height\": 80}, {\"shape\": \"rect\", \"label\": \"Front (z=3)\", \"x\": 120, \"y\": 100, \"width\": 120, \"height\": 80}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: {\n color: '#F2F7FA',\n },\n});\n\ngraph.addNode({\n shape: 'rect',\n x: 40,\n y: 40,\n width: 120,\n height: 80,\n label: 'Back (z=1)',\n zIndex: 1,\n attrs: {\n body: {\n stroke: '#8f8f8f',\n strokeWidth: 1,\n fill: '#e6f7ff',\n rx: 6,\n ry: 6,\n },\n },\n});\n\ngraph.addNode({\n shape: 'rect',\n x: 80,\n y: 70,\n width: 120,\n height: 80,\n label: 'Middle (z=2)',\n zIndex: 2,\n attrs: {\n body: {\n stroke: '#8f8f8f',\n strokeWidth: 1,\n fill: '#f6ffed',\n rx: 6,\n ry: 6,\n },\n },\n});\n\ngraph.addNode({\n shape: 'rect',\n x: 120,\n y: 100,\n width: 120,\n height: 80,\n label: 'Front (z=3)',\n zIndex: 3,\n attrs: {\n body: {\n stroke: '#8f8f8f',\n strokeWidth: 1,\n fill: '#fff7e6',\n rx: 6,\n ry: 6,\n },\n },\n});\n"
|
||
},
|
||
{
|
||
"description": "使用 graph.addNode 命令式方法逐个添加3个节点和2条边,形成线性连接结构 A -> B -> C。参考数据:[{\"id\": \"nodeA\", \"shape\": \"rect\", \"label\": \"A\", \"x\": 40, \"y\": 100, \"width\": 80, \"height\": 40}, {\"id\": \"nodeB\", \"shape\": \"rect\", \"label\": \"B\", \"x\": 200, \"y\": 100, \"width\": 80, \"height\": 40}, {\"id\": \"nodeC\", \"shape\": \"rect\", \"label\": \"C\", \"x\": 360, \"y\": 100, \"width\": 80, \"height\": 40}, {\"source\": \"nodeA\", \"target\": \"nodeB\"}, {\"source\": \"nodeB\", \"target\": \"nodeC\"}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: {\n color: '#F2F7FA',\n },\n});\n\nconst nodeA = graph.addNode({\n shape: 'rect',\n x: 40,\n y: 100,\n width: 80,\n height: 40,\n label: 'A',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\nconst nodeB = graph.addNode({\n shape: 'rect',\n x: 200,\n y: 100,\n width: 80,\n height: 40,\n label: 'B',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\nconst nodeC = graph.addNode({\n shape: 'rect',\n x: 360,\n y: 100,\n width: 80,\n height: 40,\n label: 'C',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\ngraph.addEdge({\n source: nodeA,\n target: nodeB,\n attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1 } },\n});\n\ngraph.addEdge({\n source: nodeB,\n target: nodeC,\n attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1 } },\n});\n"
|
||
},
|
||
{
|
||
"description": "创建一个指定宽度 800px、高度 400px 的 X6 画布,画布带网格背景,添加几个随机位置的节点。参考数据:[{\"shape\": \"rect\", \"label\": \"Node 1\", \"x\": 50, \"y\": 50, \"width\": 100, \"height\": 40}, {\"shape\": \"rect\", \"label\": \"Node 2\", \"x\": 300, \"y\": 150, \"width\": 100, \"height\": 40}, {\"shape\": \"circle\", \"label\": \"Node 3\", \"x\": 550, \"y\": 80, \"width\": 60, \"height\": 60}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n width: 800,\n height: 400,\n background: {\n color: '#F2F7FA',\n },\n grid: {\n visible: true,\n },\n});\n\ngraph.addNode({\n shape: 'rect',\n x: 50,\n y: 50,\n width: 100,\n height: 40,\n label: 'Node 1',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\ngraph.addNode({\n shape: 'rect',\n x: 300,\n y: 150,\n width: 100,\n height: 40,\n label: 'Node 2',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\ngraph.addNode({\n shape: 'circle',\n x: 550,\n y: 80,\n width: 60,\n height: 60,\n label: 'Node 3',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff' },\n },\n});\n"
|
||
},
|
||
{
|
||
"description": "创建画布并添加两个节点,然后通过 graph.removeNode 方法删除其中一个节点,演示节点的动态增删。参考数据:[{\"id\": \"node1\", \"shape\": \"rect\", \"label\": \"Keep\", \"x\": 40, \"y\": 40, \"width\": 100, \"height\": 40}, {\"id\": \"node2\", \"shape\": \"rect\", \"label\": \"Remove\", \"x\": 200, \"y\": 40, \"width\": 100, \"height\": 40}, {\"source\": \"node1\", \"target\": \"node2\"}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: {\n color: '#F2F7FA',\n },\n});\n\nconst node1 = graph.addNode({\n shape: 'rect',\n x: 40,\n y: 40,\n width: 100,\n height: 40,\n label: 'Keep',\n attrs: {\n body: { stroke: '#52c41a', strokeWidth: 2, fill: '#f6ffed', rx: 6, ry: 6 },\n },\n});\n\nconst node2 = graph.addNode({\n shape: 'rect',\n x: 200,\n y: 40,\n width: 100,\n height: 40,\n label: 'Remove',\n attrs: {\n body: { stroke: '#f5222d', strokeWidth: 2, fill: '#fff1f0', rx: 6, ry: 6 },\n },\n});\n\ngraph.addEdge({\n source: node1,\n target: node2,\n attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1 } },\n});\n\ngraph.removeNode(node2);\n"
|
||
},
|
||
{
|
||
"description": "创建两个节点并用 orth 路由器连接,边会自动绕开障碍物生成正交折线。参考数据:[{\"id\": \"source\", \"shape\": \"custom-node\", \"label\": \"hello\", \"x\": 40, \"y\": 40}, {\"id\": \"target\", \"shape\": \"custom-node\", \"label\": \"world\", \"x\": 300, \"y\": 220}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nGraph.registerNode(\n 'custom-node',\n {\n inherit: 'rect',\n width: 100,\n height: 40,\n markup: [\n { tagName: 'rect', selector: 'body' },\n { tagName: 'image', selector: 'img' },\n { tagName: 'text', selector: 'label' },\n ],\n attrs: {\n body: {\n stroke: '#8f8f8f',\n strokeWidth: 1,\n fill: '#fff',\n rx: 6,\n ry: 6,\n },\n img: {\n 'xlink:href': 'https://gw.alipayobjects.com/zos/antfincdn/FLrTNDvlna/antv.png',\n width: 16,\n height: 16,\n x: 12,\n y: 12,\n },\n },\n },\n true,\n);\n\nconst graph = new Graph({\n container: 'container',\n background: {\n color: '#F2F7FA',\n },\n});\n\nconst source = graph.addNode({\n shape: 'custom-node',\n x: 40,\n y: 40,\n label: 'hello',\n});\n\nconst target = graph.addNode({\n shape: 'custom-node',\n x: 300,\n y: 220,\n label: 'world',\n});\n\ngraph.addEdge({\n source,\n target,\n attrs: {\n line: {\n stroke: '#8f8f8f',\n strokeWidth: 1,\n },\n },\n vertices: [\n { x: 100, y: 200 },\n { x: 300, y: 120 },\n ],\n router: 'orth',\n});\n"
|
||
},
|
||
{
|
||
"description": "创建两个节点,用 rounded 连接器绘制圆角折线边,同时使用 orth 路由器。参考数据:[{\"id\": \"source\", \"shape\": \"rect\", \"label\": \"Source\", \"x\": 40, \"y\": 40, \"width\": 100, \"height\": 40}, {\"id\": \"target\", \"shape\": \"rect\", \"label\": \"Target\", \"x\": 300, \"y\": 220, \"width\": 100, \"height\": 40}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: {\n color: '#F2F7FA',\n },\n});\n\nconst source = graph.addNode({\n shape: 'rect',\n x: 40,\n y: 40,\n width: 100,\n height: 40,\n label: 'Source',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\nconst target = graph.addNode({\n shape: 'rect',\n x: 300,\n y: 220,\n width: 100,\n height: 40,\n label: 'Target',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\ngraph.addEdge({\n source,\n target,\n attrs: {\n line: {\n stroke: '#8f8f8f',\n strokeWidth: 1,\n },\n },\n vertices: [\n { x: 100, y: 200 },\n { x: 300, y: 120 },\n ],\n router: 'orth',\n connector: 'rounded',\n});\n"
|
||
},
|
||
{
|
||
"description": "创建一条带有两个中间顶点的边,使边形成折线路径,不使用路由器。参考数据:[{\"id\": \"source\", \"shape\": \"rect\", \"label\": \"hello\", \"x\": 40, \"y\": 40, \"width\": 100, \"height\": 40}, {\"id\": \"target\", \"shape\": \"rect\", \"label\": \"world\", \"x\": 300, \"y\": 220, \"width\": 100, \"height\": 40}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: {\n color: '#F2F7FA',\n },\n});\n\nconst source = graph.addNode({\n shape: 'rect',\n x: 40,\n y: 40,\n width: 100,\n height: 40,\n label: 'hello',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\nconst target = graph.addNode({\n shape: 'rect',\n x: 300,\n y: 220,\n width: 100,\n height: 40,\n label: 'world',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\ngraph.addEdge({\n source,\n target,\n attrs: {\n line: {\n stroke: '#8f8f8f',\n strokeWidth: 1,\n },\n },\n vertices: [\n { x: 100, y: 200 },\n { x: 300, y: 120 },\n ],\n});\n"
|
||
},
|
||
{
|
||
"description": "创建一条边,在边上添加两个标签,分别显示在边的 40% 和 60% 位置处。参考数据:[{\"id\": \"source\", \"shape\": \"rect\", \"label\": \"hello\", \"x\": 40, \"y\": 40, \"width\": 100, \"height\": 40}, {\"id\": \"target\", \"shape\": \"rect\", \"label\": \"world\", \"x\": 300, \"y\": 220, \"width\": 100, \"height\": 40}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: {\n color: '#F2F7FA',\n },\n});\n\nconst source = graph.addNode({\n shape: 'rect',\n x: 40,\n y: 40,\n width: 100,\n height: 40,\n label: 'hello',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\nconst target = graph.addNode({\n shape: 'rect',\n x: 300,\n y: 220,\n width: 100,\n height: 40,\n label: 'world',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\ngraph.addEdge({\n source,\n target,\n attrs: {\n line: {\n stroke: '#8f8f8f',\n strokeWidth: 1,\n },\n },\n labels: [\n {\n attrs: {\n label: {\n text: '40%',\n stroke: '#aaa',\n },\n },\n position: 0.4,\n },\n {\n attrs: {\n label: {\n text: '60%',\n stroke: '#aaa',\n },\n },\n position: 0.6,\n },\n ],\n});\n"
|
||
},
|
||
{
|
||
"description": "展示 X6 所有内置的边箭头标记类型,包括 block、classic、diamond、circle、circlePlus、ellipse、cross、async,每种类型一条水平边。参考数据:{\"edgeCount\": 1}",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: {\n color: '#F2F7FA',\n },\n});\n\nconst markers = ['block', 'classic', 'diamond', 'circle', 'circlePlus', 'ellipse', 'cross', 'async'];\n\nmarkers.forEach((marker, i) => {\n graph.addEdge({\n sourcePoint: [120, 20 + i * 40],\n targetPoint: [400, 20 + i * 40],\n label: marker,\n attrs: {\n line: {\n sourceMarker: marker,\n targetMarker: marker,\n stroke: '#8f8f8f',\n strokeWidth: 1,\n },\n },\n });\n});\n"
|
||
},
|
||
{
|
||
"description": "创建一条边,使用自定义 SVG path 作为箭头标记,源端为灰色默认箭头,目标端为红绿色自定义箭头。参考数据:[{\"label\": \"custom-marker\"}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: {\n color: '#F2F7FA',\n },\n});\n\ngraph.addEdge({\n source: [100, 140],\n target: [400, 140],\n label: 'custom-marker',\n attrs: {\n line: {\n sourceMarker: {\n tagName: 'path',\n d: 'M 20 -10 0 0 20 10 Z',\n },\n targetMarker: {\n tagName: 'path',\n stroke: '#D94111',\n strokeWidth: 2,\n fill: '#90C54C',\n d: 'M 20 -10 0 0 20 10 Z',\n },\n stroke: '#8f8f8f',\n strokeWidth: 1,\n },\n },\n});\n"
|
||
},
|
||
{
|
||
"description": "创建一条边后,通过 edge.attr() 和 edge.prop() 方法动态修改边的颜色和添加中间顶点。参考数据:[{\"id\": \"source\", \"shape\": \"rect\", \"label\": \"hello\", \"x\": 40, \"y\": 100, \"width\": 100, \"height\": 40}, {\"id\": \"target\", \"shape\": \"rect\", \"label\": \"world\", \"x\": 340, \"y\": 100, \"width\": 100, \"height\": 40}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: {\n color: '#F2F7FA',\n },\n});\n\nconst source = graph.addNode({\n shape: 'rect',\n x: 40,\n y: 100,\n width: 100,\n height: 40,\n label: 'hello',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\nconst target = graph.addNode({\n shape: 'rect',\n x: 340,\n y: 100,\n width: 100,\n height: 40,\n label: 'world',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\nconst edge = graph.addEdge({\n source,\n target,\n attrs: {\n line: {\n stroke: '#8f8f8f',\n strokeWidth: 1,\n },\n },\n});\n\nedge.attr('line/stroke', '#1890ff');\nedge.prop('vertices', [{ x: 200, y: 50 }]);\n"
|
||
},
|
||
{
|
||
"description": "使用 sourcePoint 和 targetPoint 坐标直接创建边,不连接到任何节点。参考数据:[{\"label\": \"Point to Point\"}, {\"label\": \"Dashed Line\"}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: {\n color: '#F2F7FA',\n },\n});\n\ngraph.addEdge({\n sourcePoint: [50, 50],\n targetPoint: [300, 50],\n label: 'Point to Point',\n attrs: {\n line: {\n stroke: '#1890ff',\n strokeWidth: 2,\n targetMarker: 'classic',\n },\n },\n});\n\ngraph.addEdge({\n sourcePoint: [50, 120],\n targetPoint: [300, 120],\n label: 'Dashed Line',\n attrs: {\n line: {\n stroke: '#52c41a',\n strokeWidth: 2,\n strokeDasharray: '5 5',\n targetMarker: 'block',\n },\n },\n});\n"
|
||
},
|
||
{
|
||
"description": "在同一画布中创建多条边,分别使用 normal、orth、manhattan 三种路由器展示不同的路由效果。参考数据:[{\"id\": \"source\", \"shape\": \"rect\", \"label\": \"Source\", \"x\": 40, \"y\": 120, \"width\": 80, \"height\": 40}, {\"id\": \"target1\", \"shape\": \"rect\", \"label\": \"normal\", \"x\": 320, \"y\": 40, \"width\": 80, \"height\": 40}, {\"id\": \"target2\", \"shape\": \"rect\", \"label\": \"orth\", \"x\": 320, \"y\": 120, \"width\": 80, \"height\": 40}, {\"id\": \"target3\", \"shape\": \"rect\", \"label\": \"manhattan\", \"x\": 320, \"y\": 200, \"width\": 80, \"height\": 40}, {\"target\": \"target1\", \"label\": \"normal\"}, {\"target\": \"target2\", \"label\": \"orth\"}, {\"target\": \"target3\", \"label\": \"manhattan\"}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: {\n color: '#F2F7FA',\n },\n});\n\nconst source = graph.addNode({\n shape: 'rect',\n x: 40,\n y: 120,\n width: 80,\n height: 40,\n label: 'Source',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\nconst target1 = graph.addNode({\n shape: 'rect',\n x: 320,\n y: 40,\n width: 80,\n height: 40,\n label: 'normal',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\nconst target2 = graph.addNode({\n shape: 'rect',\n x: 320,\n y: 120,\n width: 80,\n height: 40,\n label: 'orth',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\nconst target3 = graph.addNode({\n shape: 'rect',\n x: 320,\n y: 200,\n width: 80,\n height: 40,\n label: 'manhattan',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\ngraph.addEdge({\n source,\n target: target1,\n router: 'normal',\n attrs: { line: { stroke: '#1890ff', strokeWidth: 1 } },\n label: 'normal',\n});\n\ngraph.addEdge({\n source,\n target: target2,\n router: 'orth',\n attrs: { line: { stroke: '#52c41a', strokeWidth: 1 } },\n label: 'orth',\n});\n\ngraph.addEdge({\n source,\n target: target3,\n router: 'manhattan',\n attrs: { line: { stroke: '#fa8c16', strokeWidth: 1 } },\n label: 'manhattan',\n});\n"
|
||
},
|
||
{
|
||
"description": "注册一个带有上下连接桩的自定义节点,创建两个节点并通过连接桩连线。参考数据:[{\"id\": \"port_1\", \"shape\": \"custom-node-with-port\", \"label\": \"hello\", \"x\": 40, \"y\": 40}, {\"id\": \"port_3\", \"shape\": \"custom-node-with-port\", \"label\": \"world\", \"x\": 160, \"y\": 180}, {\"source\": \"source\", \"target\": \"target\"}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nGraph.registerNode(\n 'custom-node-with-port',\n {\n inherit: 'rect',\n width: 100,\n height: 40,\n attrs: {\n body: {\n stroke: '#8f8f8f',\n strokeWidth: 1,\n fill: '#fff',\n rx: 6,\n ry: 6,\n },\n },\n ports: {\n groups: {\n top: {\n position: 'top',\n attrs: {\n circle: {\n magnet: true,\n stroke: '#8f8f8f',\n r: 5,\n },\n },\n },\n bottom: {\n position: 'bottom',\n attrs: {\n circle: {\n magnet: true,\n stroke: '#8f8f8f',\n r: 5,\n },\n },\n },\n },\n },\n },\n true,\n);\n\nconst graph = new Graph({\n container: 'container',\n background: {\n color: '#F2F7FA',\n },\n});\n\nconst source = graph.addNode({\n shape: 'custom-node-with-port',\n x: 40,\n y: 40,\n label: 'hello',\n ports: {\n items: [\n { id: 'port_1', group: 'bottom' },\n { id: 'port_2', group: 'bottom' },\n ],\n },\n});\n\nconst target = graph.addNode({\n shape: 'custom-node-with-port',\n x: 160,\n y: 180,\n label: 'world',\n ports: {\n items: [\n { id: 'port_3', group: 'top' },\n { id: 'port_4', group: 'top' },\n ],\n },\n});\n\ngraph.addEdge({\n source: { cell: source, port: 'port_2' },\n target: { cell: target, port: 'port_3' },\n attrs: {\n line: {\n stroke: '#8f8f8f',\n strokeWidth: 1,\n },\n },\n});\n\ngraph.centerContent();\n"
|
||
},
|
||
{
|
||
"description": "创建一个节点,上下左右四个方向各有连接桩,连接桩使用 circle 样式并设置 magnet 属性。参考数据:[{\"id\": \"p1\", \"shape\": \"four-port-node\", \"label\": \"Node\", \"x\": 160, \"y\": 100}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nGraph.registerNode(\n 'four-port-node',\n {\n inherit: 'rect',\n width: 100,\n height: 60,\n attrs: {\n body: {\n stroke: '#8f8f8f',\n strokeWidth: 1,\n fill: '#fff',\n rx: 6,\n ry: 6,\n },\n },\n ports: {\n groups: {\n top: {\n position: 'top',\n attrs: { circle: { magnet: true, stroke: '#1890ff', r: 5, fill: '#fff' } },\n },\n bottom: {\n position: 'bottom',\n attrs: { circle: { magnet: true, stroke: '#1890ff', r: 5, fill: '#fff' } },\n },\n left: {\n position: 'left',\n attrs: { circle: { magnet: true, stroke: '#1890ff', r: 5, fill: '#fff' } },\n },\n right: {\n position: 'right',\n attrs: { circle: { magnet: true, stroke: '#1890ff', r: 5, fill: '#fff' } },\n },\n },\n },\n },\n true,\n);\n\nconst graph = new Graph({\n container: 'container',\n background: {\n color: '#F2F7FA',\n },\n});\n\ngraph.addNode({\n shape: 'four-port-node',\n x: 160,\n y: 100,\n label: 'Node',\n ports: {\n items: [\n { id: 'p1', group: 'top' },\n { id: 'p2', group: 'bottom' },\n { id: 'p3', group: 'left' },\n { id: 'p4', group: 'right' },\n ],\n },\n});\n"
|
||
},
|
||
{
|
||
"description": "创建一个节点后,通过 node.addPort() 方法动态添加连接桩。参考数据:[{\"id\": \"1\", \"shape\": \"dynamic-port-node\", \"label\": \"hello\", \"x\": 150, \"y\": 100}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nGraph.registerNode(\n 'dynamic-port-node',\n {\n inherit: 'rect',\n width: 100,\n height: 40,\n attrs: {\n body: {\n stroke: '#8f8f8f',\n strokeWidth: 1,\n fill: '#fff',\n rx: 6,\n ry: 6,\n },\n },\n ports: {\n groups: {\n top: {\n position: 'top',\n attrs: {\n circle: { magnet: true, stroke: '#8f8f8f', r: 5 },\n },\n label: { position: 'top' },\n },\n bottom: {\n position: 'bottom',\n attrs: {\n circle: { magnet: true, stroke: '#8f8f8f', r: 5 },\n },\n label: { position: 'top' },\n },\n },\n },\n },\n true,\n);\n\nconst graph = new Graph({\n container: 'container',\n background: {\n color: '#F2F7FA',\n },\n});\n\nconst node = graph.addNode({\n id: '1',\n shape: 'dynamic-port-node',\n x: 150,\n y: 100,\n label: 'hello',\n});\n\nnode.addPort({ group: 'top', attrs: { text: { text: '1' } } });\nnode.addPort({ group: 'top', attrs: { text: { text: '2' } } });\nnode.addPort({ group: 'bottom', attrs: { text: { text: '3' } } });\n\ngraph.centerContent();\n"
|
||
},
|
||
{
|
||
"description": "创建两个带有多个连接桩的节点,从源节点的不同输出端口连接到目标节点的不同输入端口。参考数据:[{\"id\": \"out1\", \"shape\": \"multi-port-node\", \"label\": \"Source\", \"x\": 100, \"y\": 40}, {\"id\": \"in1\", \"shape\": \"multi-port-node\", \"label\": \"Target\", \"x\": 100, \"y\": 200}, {\"source\": \"node1\", \"target\": \"node2\"}, {\"source\": \"node1\", \"target\": \"node2\"}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nGraph.registerNode(\n 'multi-port-node',\n {\n inherit: 'rect',\n width: 120,\n height: 50,\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n ports: {\n groups: {\n in: {\n position: 'top',\n attrs: { circle: { magnet: true, stroke: '#8f8f8f', r: 5 } },\n },\n out: {\n position: 'bottom',\n attrs: { circle: { magnet: true, stroke: '#8f8f8f', r: 5 } },\n },\n },\n },\n },\n true,\n);\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\nconst node1 = graph.addNode({\n shape: 'multi-port-node',\n x: 100,\n y: 40,\n label: 'Source',\n ports: {\n items: [\n { id: 'out1', group: 'out' },\n { id: 'out2', group: 'out' },\n { id: 'out3', group: 'out' },\n ],\n },\n});\n\nconst node2 = graph.addNode({\n shape: 'multi-port-node',\n x: 100,\n y: 200,\n label: 'Target',\n ports: {\n items: [\n { id: 'in1', group: 'in' },\n { id: 'in2', group: 'in' },\n { id: 'in3', group: 'in' },\n ],\n },\n});\n\ngraph.addEdge({\n source: { cell: node1, port: 'out1' },\n target: { cell: node2, port: 'in1' },\n attrs: { line: { stroke: '#1890ff', strokeWidth: 1 } },\n});\n\ngraph.addEdge({\n source: { cell: node1, port: 'out3' },\n target: { cell: node2, port: 'in3' },\n attrs: { line: { stroke: '#52c41a', strokeWidth: 1 } },\n});\n"
|
||
},
|
||
{
|
||
"description": "创建一个包含节点和边的画布,然后使用 graph.toJSON() 将画布内容序列化为 JSON 数据。参考数据:[{\"id\": \"source\", \"shape\": \"rect\", \"label\": \"Source\", \"x\": 40, \"y\": 40, \"width\": 100, \"height\": 40}, {\"id\": \"target\", \"shape\": \"rect\", \"label\": \"Target\", \"x\": 200, \"y\": 160, \"width\": 100, \"height\": 40}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: {\n color: '#F2F7FA',\n },\n});\n\nconst source = graph.addNode({\n shape: 'rect',\n x: 40,\n y: 40,\n width: 100,\n height: 40,\n label: 'Source',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\nconst target = graph.addNode({\n shape: 'rect',\n x: 200,\n y: 160,\n width: 100,\n height: 40,\n label: 'Target',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\ngraph.addEdge({\n source,\n target,\n attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1 } },\n});\n\nconst jsonData = graph.toJSON();\nconsole.log(JSON.stringify(jsonData, null, 2));\n"
|
||
},
|
||
{
|
||
"description": "创建多条不同样式的边:实线、虚线、点线,不同粗细和颜色,展示边的样式多样性。参考数据:[{\"label\": \"solid (1px)\"}, {\"label\": \"solid (3px)\"}, {\"label\": \"dashed\"}, {\"label\": \"dotted\"}, {\"label\": \"dash-dot\"}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: {\n color: '#F2F7FA',\n },\n});\n\ngraph.addEdge({\n sourcePoint: [50, 40],\n targetPoint: [400, 40],\n label: 'solid (1px)',\n attrs: {\n line: { stroke: '#333', strokeWidth: 1 },\n },\n});\n\ngraph.addEdge({\n sourcePoint: [50, 90],\n targetPoint: [400, 90],\n label: 'solid (3px)',\n attrs: {\n line: { stroke: '#1890ff', strokeWidth: 3 },\n },\n});\n\ngraph.addEdge({\n sourcePoint: [50, 140],\n targetPoint: [400, 140],\n label: 'dashed',\n attrs: {\n line: { stroke: '#52c41a', strokeWidth: 2, strokeDasharray: '10 5' },\n },\n});\n\ngraph.addEdge({\n sourcePoint: [50, 190],\n targetPoint: [400, 190],\n label: 'dotted',\n attrs: {\n line: { stroke: '#fa8c16', strokeWidth: 2, strokeDasharray: '2 4' },\n },\n});\n\ngraph.addEdge({\n sourcePoint: [50, 240],\n targetPoint: [400, 240],\n label: 'dash-dot',\n attrs: {\n line: { stroke: '#f5222d', strokeWidth: 2, strokeDasharray: '10 3 2 3' },\n },\n});\n"
|
||
},
|
||
{
|
||
"description": "创建三个节点形成三角形连接关系,边从节点边框出发而非中心点,使用 anchor 配置。参考数据:[{\"id\": \"node1\", \"shape\": \"rect\", \"label\": \"A\", \"x\": 200, \"y\": 40, \"width\": 80, \"height\": 40}, {\"id\": \"node2\", \"shape\": \"rect\", \"label\": \"B\", \"x\": 80, \"y\": 200, \"width\": 80, \"height\": 40}, {\"id\": \"node3\", \"shape\": \"rect\", \"label\": \"C\", \"x\": 320, \"y\": 200, \"width\": 80, \"height\": 40}, {\"source\": \"node1\", \"target\": \"node2\"}, {\"source\": \"node2\", \"target\": \"node3\"}, {\"source\": \"node3\", \"target\": \"node1\"}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: {\n color: '#F2F7FA',\n },\n});\n\nconst node1 = graph.addNode({\n shape: 'rect',\n x: 200,\n y: 40,\n width: 80,\n height: 40,\n label: 'A',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\nconst node2 = graph.addNode({\n shape: 'rect',\n x: 80,\n y: 200,\n width: 80,\n height: 40,\n label: 'B',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\nconst node3 = graph.addNode({\n shape: 'rect',\n x: 320,\n y: 200,\n width: 80,\n height: 40,\n label: 'C',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\ngraph.addEdge({\n source: node1,\n target: node2,\n attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1, targetMarker: 'classic' } },\n});\n\ngraph.addEdge({\n source: node2,\n target: node3,\n attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1, targetMarker: 'classic' } },\n});\n\ngraph.addEdge({\n source: node3,\n target: node1,\n attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1, targetMarker: 'classic' } },\n});\n"
|
||
},
|
||
{
|
||
"description": "创建一条边,在不同位置添加多个标签,包括起始位置、中间位置和结束位置,标签带有背景色。参考数据:[{\"id\": \"source\", \"shape\": \"rect\", \"label\": \"Start\", \"x\": 40, \"y\": 100, \"width\": 80, \"height\": 40}, {\"id\": \"target\", \"shape\": \"rect\", \"label\": \"End\", \"x\": 400, \"y\": 100, \"width\": 80, \"height\": 40}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: {\n color: '#F2F7FA',\n },\n});\n\nconst source = graph.addNode({\n shape: 'rect',\n x: 40,\n y: 100,\n width: 80,\n height: 40,\n label: 'Start',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\nconst target = graph.addNode({\n shape: 'rect',\n x: 400,\n y: 100,\n width: 80,\n height: 40,\n label: 'End',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\ngraph.addEdge({\n source,\n target,\n attrs: {\n line: { stroke: '#8f8f8f', strokeWidth: 1 },\n },\n labels: [\n {\n position: 0.1,\n attrs: { label: { text: 'Begin', fill: '#333' }, rect: { fill: '#f0f0f0', stroke: '#ddd' } },\n },\n {\n position: 0.5,\n attrs: { label: { text: 'Middle', fill: '#333' }, rect: { fill: '#e6f7ff', stroke: '#91d5ff' } },\n },\n {\n position: 0.9,\n attrs: { label: { text: 'End', fill: '#333' }, rect: { fill: '#f6ffed', stroke: '#b7eb8f' } },\n },\n ],\n});\n"
|
||
},
|
||
{
|
||
"description": "创建一个带有连接桩的节点,每个连接桩带有文字标签说明其用途。参考数据:[{\"id\": \"in1\", \"shape\": \"labeled-port-node\", \"label\": \"Processor\", \"x\": 150, \"y\": 80}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nGraph.registerNode(\n 'labeled-port-node',\n {\n inherit: 'rect',\n width: 140,\n height: 60,\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n ports: {\n groups: {\n in: {\n position: 'left',\n label: { position: 'left' },\n attrs: { circle: { magnet: true, stroke: '#52c41a', r: 5, fill: '#fff' } },\n },\n out: {\n position: 'right',\n label: { position: 'right' },\n attrs: { circle: { magnet: true, stroke: '#1890ff', r: 5, fill: '#fff' } },\n },\n },\n },\n },\n true,\n);\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\ngraph.addNode({\n shape: 'labeled-port-node',\n x: 150,\n y: 80,\n label: 'Processor',\n ports: {\n items: [\n { id: 'in1', group: 'in', attrs: { text: { text: 'input' } } },\n { id: 'in2', group: 'in', attrs: { text: { text: 'config' } } },\n { id: 'out1', group: 'out', attrs: { text: { text: 'output' } } },\n ],\n },\n});\n"
|
||
},
|
||
{
|
||
"description": "注册一个自定义边 shape(双线边),然后使用该自定义边连接两个节点。参考数据:[{\"id\": \"source\", \"shape\": \"rect\", \"label\": \"Source\", \"x\": 40, \"y\": 80, \"width\": 100, \"height\": 40}, {\"id\": \"target\", \"shape\": \"rect\", \"label\": \"Target\", \"x\": 300, \"y\": 80, \"width\": 100, \"height\": 40}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nGraph.registerEdge(\n 'double-edge',\n {\n inherit: 'edge',\n attrs: {\n line: {\n stroke: '#1890ff',\n strokeWidth: 3,\n targetMarker: 'classic',\n },\n outline: {\n stroke: '#73d13d',\n strokeWidth: 6,\n strokeLinecap: 'round',\n },\n },\n markup: [\n {\n tagName: 'path',\n selector: 'outline',\n attrs: { fill: 'none' },\n },\n {\n tagName: 'path',\n selector: 'line',\n attrs: { fill: 'none' },\n },\n ],\n },\n true,\n);\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\nconst source = graph.addNode({\n shape: 'rect',\n x: 40,\n y: 80,\n width: 100,\n height: 40,\n label: 'Source',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\nconst target = graph.addNode({\n shape: 'rect',\n x: 300,\n y: 80,\n width: 100,\n height: 40,\n label: 'Target',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\ngraph.addEdge({\n shape: 'double-edge',\n source,\n target,\n});\n"
|
||
},
|
||
{
|
||
"description": "先用 fromJSON 加载图数据,然后用 toJSON 导出,再用导出的数据重新创建图,演示数据持久化。参考数据:{\"nodes\": [{\"id\": \"node1\", \"shape\": \"rect\", \"label\": \"Node 1\", \"x\": 40, \"y\": 40, \"width\": 100, \"height\": 40}, {\"id\": \"node2\", \"shape\": \"rect\", \"label\": \"Node 2\", \"x\": 240, \"y\": 40, \"width\": 100, \"height\": 40}], \"edges\": [{\"source\": \"node1\", \"target\": \"node2\", \"label\": \"Edge\"}]}",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graphData = {\n nodes: [\n {\n id: 'node1',\n shape: 'rect',\n x: 40,\n y: 40,\n width: 100,\n height: 40,\n label: 'Node 1',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n },\n {\n id: 'node2',\n shape: 'rect',\n x: 240,\n y: 40,\n width: 100,\n height: 40,\n label: 'Node 2',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n },\n ],\n edges: [\n {\n source: 'node1',\n target: 'node2',\n label: 'Edge',\n attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1, targetMarker: 'classic' } },\n },\n ],\n};\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\ngraph.fromJSON(graphData);\ngraph.centerContent();\n\nconst exported = graph.toJSON();\nconsole.log('Exported:', JSON.stringify(exported));\n"
|
||
},
|
||
{
|
||
"description": "创建带有连接桩的节点,连接桩使用绝对位置配置,精确指定连接桩在节点上的位置。参考数据:[{\"id\": \"p1\", \"shape\": \"rect\", \"label\": \"Absolute Ports\", \"x\": 100, \"y\": 60, \"width\": 180, \"height\": 80}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\ngraph.addNode({\n shape: 'rect',\n x: 100,\n y: 60,\n width: 180,\n height: 80,\n label: 'Absolute Ports',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n ports: {\n groups: {\n absolute: {\n position: {\n name: 'absolute',\n },\n attrs: {\n circle: { magnet: true, stroke: '#1890ff', r: 5, fill: '#fff' },\n },\n },\n },\n items: [\n { id: 'p1', group: 'absolute', args: { x: 0, y: 20 } },\n { id: 'p2', group: 'absolute', args: { x: 0, y: 60 } },\n { id: 'p3', group: 'absolute', args: { x: 180, y: 20 } },\n { id: 'p4', group: 'absolute', args: { x: 180, y: 60 } },\n { id: 'p5', group: 'absolute', args: { x: 90, y: 0 } },\n { id: 'p6', group: 'absolute', args: { x: 90, y: 80 } },\n ],\n },\n});\n"
|
||
},
|
||
{
|
||
"description": "创建使用 smooth 曲线连接器的边,形成平滑的贝塞尔曲线连接。参考数据:[{\"id\": \"node1\", \"shape\": \"rect\", \"label\": \"Node 1\", \"x\": 40, \"y\": 40, \"width\": 80, \"height\": 40}, {\"id\": \"node2\", \"shape\": \"rect\", \"label\": \"Node 2\", \"x\": 300, \"y\": 40, \"width\": 80, \"height\": 40}, {\"id\": \"node3\", \"shape\": \"rect\", \"label\": \"Node 3\", \"x\": 300, \"y\": 200, \"width\": 80, \"height\": 40}, {\"source\": \"node1\", \"target\": \"node2\"}, {\"source\": \"node1\", \"target\": \"node3\"}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\nconst node1 = graph.addNode({\n shape: 'rect',\n x: 40,\n y: 40,\n width: 80,\n height: 40,\n label: 'Node 1',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\nconst node2 = graph.addNode({\n shape: 'rect',\n x: 300,\n y: 40,\n width: 80,\n height: 40,\n label: 'Node 2',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\nconst node3 = graph.addNode({\n shape: 'rect',\n x: 300,\n y: 200,\n width: 80,\n height: 40,\n label: 'Node 3',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\ngraph.addEdge({\n source: node1,\n target: node2,\n connector: 'smooth',\n attrs: { line: { stroke: '#1890ff', strokeWidth: 2, targetMarker: 'classic' } },\n});\n\ngraph.addEdge({\n source: node1,\n target: node3,\n connector: 'smooth',\n attrs: { line: { stroke: '#52c41a', strokeWidth: 2, targetMarker: 'classic' } },\n});\n"
|
||
},
|
||
{
|
||
"description": "创建带有连接桩的节点,默认隐藏连接桩,鼠标悬停节点时显示连接桩。参考数据:[{\"shape\": \"rect\", \"label\": \"Hover Me\", \"x\": 100, \"y\": 60, \"width\": 120, \"height\": 50}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\ngraph.addNode({\n shape: 'rect',\n x: 100,\n y: 60,\n width: 120,\n height: 50,\n label: 'Hover Me',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n ports: {\n groups: {\n top: {\n position: 'top',\n attrs: {\n circle: { magnet: true, stroke: '#1890ff', r: 5, fill: '#fff', style: { visibility: 'hidden' } },\n },\n },\n bottom: {\n position: 'bottom',\n attrs: {\n circle: { magnet: true, stroke: '#1890ff', r: 5, fill: '#fff', style: { visibility: 'hidden' } },\n },\n },\n },\n items: [\n { id: 'p1', group: 'top' },\n { id: 'p2', group: 'bottom' },\n ],\n },\n});\n\ngraph.on('node:mouseenter', ({ node }) => {\n const ports = node.getPorts();\n ports.forEach((port) => {\n node.portProp(port.id, 'attrs/circle/style/visibility', 'visible');\n });\n});\n\ngraph.on('node:mouseleave', ({ node }) => {\n const ports = node.getPorts();\n ports.forEach((port) => {\n node.portProp(port.id, 'attrs/circle/style/visibility', 'hidden');\n });\n});\n"
|
||
},
|
||
{
|
||
"description": "创建三个节点,其中一个作为障碍物放在中间,使用 manhattan 路由器让边自动绕开障碍物。参考数据:[{\"id\": \"source\", \"shape\": \"rect\", \"label\": \"Start\", \"x\": 40, \"y\": 100, \"width\": 80, \"height\": 40}, {\"shape\": \"rect\", \"label\": \"Obstacle\", \"x\": 200, \"y\": 80, \"width\": 80, \"height\": 80}, {\"id\": \"target\", \"shape\": \"rect\", \"label\": \"End\", \"x\": 380, \"y\": 100, \"width\": 80, \"height\": 40}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\nconst source = graph.addNode({\n shape: 'rect',\n x: 40,\n y: 100,\n width: 80,\n height: 40,\n label: 'Start',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\ngraph.addNode({\n shape: 'rect',\n x: 200,\n y: 80,\n width: 80,\n height: 80,\n label: 'Obstacle',\n attrs: {\n body: { stroke: '#f5222d', strokeWidth: 2, fill: '#fff1f0', rx: 6, ry: 6 },\n },\n});\n\nconst target = graph.addNode({\n shape: 'rect',\n x: 380,\n y: 100,\n width: 80,\n height: 40,\n label: 'End',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\ngraph.addEdge({\n source,\n target,\n router: 'manhattan',\n connector: 'rounded',\n attrs: {\n line: { stroke: '#1890ff', strokeWidth: 2, targetMarker: 'classic' },\n },\n});\n"
|
||
},
|
||
{
|
||
"description": "创建一个支持从连接桩拖拽连线的画布,配置 connecting 选项允许从空白处连线,并设置连线样式。参考数据:[{\"id\": \"port1\", \"x\": 60, \"y\": 50, \"width\": 100, \"height\": 40}, {\"id\": \"port1\", \"x\": 260, \"y\": 180, \"width\": 100, \"height\": 40}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n connecting: {\n allowBlank: true,\n allowMulti: true,\n allowLoop: true,\n allowNode: true,\n allowEdge: false,\n allowPort: true,\n createEdge() {\n return this.createEdge({\n attrs: {\n line: {\n stroke: '#8f8f8f',\n strokeWidth: 1,\n },\n },\n });\n },\n },\n});\n\ngraph.addNode({\n x: 60,\n y: 50,\n width: 100,\n height: 40,\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n ports: {\n groups: {\n in: {\n position: 'top',\n attrs: { circle: { magnet: true, stroke: '#8f8f8f', r: 5 } },\n },\n out: {\n position: 'bottom',\n attrs: { circle: { magnet: true, stroke: '#8f8f8f', r: 5 } },\n },\n },\n items: [\n { id: 'port1', group: 'in' },\n { id: 'port2', group: 'in' },\n { id: 'port3', group: 'out' },\n { id: 'port4', group: 'out' },\n ],\n },\n});\n\ngraph.addNode({\n x: 260,\n y: 180,\n width: 100,\n height: 40,\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n ports: {\n groups: {\n in: {\n position: 'top',\n attrs: { circle: { magnet: true, stroke: '#8f8f8f', r: 5 } },\n },\n out: {\n position: 'bottom',\n attrs: { circle: { magnet: true, stroke: '#8f8f8f', r: 5 } },\n },\n },\n items: [\n { id: 'port1', group: 'in' },\n { id: 'port2', group: 'in' },\n { id: 'port3', group: 'out' },\n ],\n },\n});\n"
|
||
},
|
||
{
|
||
"description": "配置连线验证规则,限制只能从输出端口连接到输入端口,并禁止自环连线。参考数据:[{\"id\": \"in1\", \"label\": \"Node A\", \"x\": 60, \"y\": 60, \"width\": 100, \"height\": 40}, {\"id\": \"in1\", \"label\": \"Node B\", \"x\": 260, \"y\": 180, \"width\": 100, \"height\": 40}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n connecting: {\n allowLoop: false,\n allowBlank: false,\n allowMulti: false,\n validateConnection({ sourcePort, targetPort }) {\n if (!sourcePort || !targetPort) return false;\n if (sourcePort.startsWith('in') && targetPort.startsWith('out')) return false;\n return true;\n },\n createEdge() {\n return this.createEdge({\n attrs: {\n line: { stroke: '#8f8f8f', strokeWidth: 1, targetMarker: 'classic' },\n },\n });\n },\n },\n});\n\ngraph.addNode({\n x: 60,\n y: 60,\n width: 100,\n height: 40,\n label: 'Node A',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n ports: {\n groups: {\n in: { position: 'top', attrs: { circle: { magnet: true, stroke: '#52c41a', r: 5 } } },\n out: { position: 'bottom', attrs: { circle: { magnet: true, stroke: '#1890ff', r: 5 } } },\n },\n items: [\n { id: 'in1', group: 'in' },\n { id: 'out1', group: 'out' },\n { id: 'out2', group: 'out' },\n ],\n },\n});\n\ngraph.addNode({\n x: 260,\n y: 180,\n width: 100,\n height: 40,\n label: 'Node B',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n ports: {\n groups: {\n in: { position: 'top', attrs: { circle: { magnet: true, stroke: '#52c41a', r: 5 } } },\n out: { position: 'bottom', attrs: { circle: { magnet: true, stroke: '#1890ff', r: 5 } } },\n },\n items: [\n { id: 'in1', group: 'in' },\n { id: 'in2', group: 'in' },\n { id: 'out1', group: 'out' },\n ],\n },\n});\n"
|
||
},
|
||
{
|
||
"description": "配置画布支持节点嵌入(embedding),拖拽子节点到父节点上时可以自动嵌入形成父子关系。参考数据:[{\"id\": \"parent\", \"shape\": \"rect\", \"label\": \"Parent\", \"x\": 40, \"y\": 40, \"width\": 360, \"height\": 160}, {\"id\": \"child1\", \"shape\": \"rect\", \"label\": \"Child 1\", \"x\": 80, \"y\": 100, \"width\": 80, \"height\": 40}, {\"id\": \"child2\", \"shape\": \"rect\", \"label\": \"Child 2\", \"x\": 280, \"y\": 100, \"width\": 80, \"height\": 40}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n embedding: {\n enabled: true,\n },\n});\n\nconst parent = graph.addNode({\n shape: 'rect',\n x: 40,\n y: 40,\n width: 360,\n height: 160,\n zIndex: 1,\n label: 'Parent',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#e6f7ff', rx: 6, ry: 6 },\n },\n});\n\nconst child1 = graph.addNode({\n shape: 'rect',\n x: 80,\n y: 100,\n width: 80,\n height: 40,\n label: 'Child 1',\n zIndex: 2,\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\nconst child2 = graph.addNode({\n shape: 'rect',\n x: 280,\n y: 100,\n width: 80,\n height: 40,\n label: 'Child 2',\n zIndex: 2,\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\nparent.addChild(child1);\nparent.addChild(child2);\n"
|
||
},
|
||
{
|
||
"description": "配置节点高亮效果,当鼠标移入节点或连接桩时显示高亮样式。参考数据:[{\"id\": \"out1\", \"label\": \"Source\", \"x\": 60, \"y\": 60, \"width\": 100, \"height\": 40}, {\"id\": \"in1\", \"label\": \"Target\", \"x\": 260, \"y\": 180, \"width\": 100, \"height\": 40}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n highlighting: {\n magnetAvailable: {\n name: 'stroke',\n args: {\n attrs: {\n fill: '#fff',\n stroke: '#47C769',\n },\n },\n },\n magnetAdsorbed: {\n name: 'stroke',\n args: {\n attrs: {\n fill: '#fff',\n stroke: '#31d0c6',\n },\n },\n },\n },\n connecting: {\n allowBlank: false,\n createEdge() {\n return this.createEdge({\n attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1 } },\n });\n },\n },\n});\n\ngraph.addNode({\n x: 60,\n y: 60,\n width: 100,\n height: 40,\n label: 'Source',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n ports: {\n groups: {\n out: { position: 'bottom', attrs: { circle: { magnet: true, stroke: '#8f8f8f', r: 5 } } },\n },\n items: [{ id: 'out1', group: 'out' }],\n },\n});\n\ngraph.addNode({\n x: 260,\n y: 180,\n width: 100,\n height: 40,\n label: 'Target',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n ports: {\n groups: {\n in: { position: 'top', attrs: { circle: { magnet: true, stroke: '#8f8f8f', r: 5 } } },\n },\n items: [{ id: 'in1', group: 'in' }],\n },\n});\n"
|
||
},
|
||
{
|
||
"description": "创建一个支持节点拖拽的画布,节点可自由移动位置,并监听节点位置变化事件。参考数据:[{\"shape\": \"rect\", \"label\": \"Drag Me\", \"x\": 100, \"y\": 60, \"width\": 120, \"height\": 50}, {\"shape\": \"circle\", \"label\": \"Also Me\", \"x\": 300, \"y\": 120, \"width\": 60, \"height\": 60}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n grid: { visible: true },\n});\n\ngraph.addNode({\n shape: 'rect',\n x: 100,\n y: 60,\n width: 120,\n height: 50,\n label: 'Drag Me',\n attrs: {\n body: { stroke: '#1890ff', strokeWidth: 2, fill: '#e6f7ff', rx: 6, ry: 6 },\n },\n});\n\ngraph.addNode({\n shape: 'circle',\n x: 300,\n y: 120,\n width: 60,\n height: 60,\n label: 'Also Me',\n attrs: {\n body: { stroke: '#52c41a', strokeWidth: 2, fill: '#f6ffed' },\n },\n});\n\ngraph.on('node:moved', ({ node }) => {\n const pos = node.getPosition();\n console.log(`Node ${node.id} moved to (${pos.x}, ${pos.y})`);\n});\n"
|
||
},
|
||
{
|
||
"description": "监听画布上节点和边的点击事件,点击节点时改变其填充颜色,点击边时改变线条颜色。参考数据:[{\"id\": \"source\", \"shape\": \"rect\", \"label\": \"Click Me\", \"x\": 40, \"y\": 40, \"width\": 100, \"height\": 40}, {\"id\": \"target\", \"shape\": \"rect\", \"label\": \"Click Me\", \"x\": 240, \"y\": 160, \"width\": 100, \"height\": 40}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\nconst source = graph.addNode({\n shape: 'rect',\n x: 40,\n y: 40,\n width: 100,\n height: 40,\n label: 'Click Me',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\nconst target = graph.addNode({\n shape: 'rect',\n x: 240,\n y: 160,\n width: 100,\n height: 40,\n label: 'Click Me',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\ngraph.addEdge({\n source,\n target,\n attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1 } },\n});\n\ngraph.on('node:click', ({ node }) => {\n node.attr('body/fill', '#d9f7be');\n});\n\ngraph.on('edge:click', ({ edge }) => {\n edge.attr('line/stroke', '#f5222d');\n edge.attr('line/strokeWidth', 2);\n});\n"
|
||
},
|
||
{
|
||
"description": "监听节点 node:dblclick 事件,双击节点时通过 node.attr(\"label/text\") 更新标签文本。参考数据:[{\"shape\": \"rect\", \"label\": \"Double Click Me\", \"x\": 100, \"y\": 60, \"width\": 140, \"height\": 50}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\ngraph.addNode({\n shape: 'rect',\n x: 100,\n y: 60,\n width: 140,\n height: 50,\n label: 'Double Click Me',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\ngraph.on('node:dblclick', ({ node }) => {\n node.attr('label/text', 'Edited');\n});\n"
|
||
},
|
||
{
|
||
"description": "配置连线的 snap 吸附功能,拖拽连线时自动吸附到最近的连接桩。参考数据:[{\"id\": \"out1\", \"label\": \"Source\", \"x\": 60, \"y\": 60, \"width\": 100, \"height\": 40}, {\"id\": \"in1\", \"label\": \"Target\", \"x\": 260, \"y\": 200, \"width\": 100, \"height\": 40}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n connecting: {\n snap: {\n radius: 30,\n },\n allowBlank: false,\n createEdge() {\n return this.createEdge({\n attrs: {\n line: { stroke: '#8f8f8f', strokeWidth: 1, targetMarker: 'classic' },\n },\n });\n },\n },\n});\n\ngraph.addNode({\n x: 60,\n y: 60,\n width: 100,\n height: 40,\n label: 'Source',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n ports: {\n groups: {\n out: { position: 'bottom', attrs: { circle: { magnet: true, stroke: '#8f8f8f', r: 5 } } },\n },\n items: [{ id: 'out1', group: 'out' }, { id: 'out2', group: 'out' }],\n },\n});\n\ngraph.addNode({\n x: 260,\n y: 200,\n width: 100,\n height: 40,\n label: 'Target',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n ports: {\n groups: {\n in: { position: 'top', attrs: { circle: { magnet: true, stroke: '#8f8f8f', r: 5 } } },\n },\n items: [{ id: 'in1', group: 'in' }, { id: 'in2', group: 'in' }],\n },\n});\n"
|
||
},
|
||
{
|
||
"description": "监听画布级别的事件:blank:click(点击空白)、cell:added(添加元素)、cell:removed(删除元素)。参考数据:[{\"shape\": \"rect\", \"label\": \"Node 1\", \"x\": 100, \"y\": 80, \"width\": 100, \"height\": 40}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n grid: { visible: true },\n});\n\ngraph.addNode({\n shape: 'rect',\n x: 100,\n y: 80,\n width: 100,\n height: 40,\n label: 'Node 1',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\ngraph.on('blank:click', ({ e }) => {\n console.log('Clicked on blank area');\n});\n\ngraph.on('cell:added', ({ cell }) => {\n console.log('Cell added:', cell.id);\n});\n\ngraph.on('cell:removed', ({ cell }) => {\n console.log('Cell removed:', cell.id);\n});\n\ngraph.on('node:mouseenter', ({ node }) => {\n node.attr('body/stroke', '#1890ff');\n node.attr('body/strokeWidth', 2);\n});\n\ngraph.on('node:mouseleave', ({ node }) => {\n node.attr('body/stroke', '#8f8f8f');\n node.attr('body/strokeWidth', 1);\n});\n"
|
||
},
|
||
{
|
||
"description": "配置节点只能在画布指定矩形范围内拖拽移动,超出边界自动回弹。参考数据:[{\"shape\": \"rect\", \"label\": \"Restricted\", \"x\": 200, \"y\": 150, \"width\": 120, \"height\": 50}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n width: 600,\n height: 400,\n background: { color: '#F2F7FA' },\n grid: { visible: true },\n translating: {\n restrict: {\n x: 0,\n y: 0,\n width: 600,\n height: 400,\n },\n },\n});\n\ngraph.addNode({\n shape: 'rect',\n x: 200,\n y: 150,\n width: 120,\n height: 50,\n label: 'Restricted',\n attrs: {\n body: { stroke: '#fa8c16', strokeWidth: 2, fill: '#fff7e6', rx: 6, ry: 6 },\n },\n});\n"
|
||
},
|
||
{
|
||
"description": "实现节点的选中/取消选中交互,点击节点时切换选中状态并改变样式。参考数据:[{\"id\": \"node1\", \"shape\": \"rect\", \"label\": \"Node 1\", \"x\": 60, \"y\": 60, \"width\": 100, \"height\": 40}, {\"id\": \"node2\", \"shape\": \"rect\", \"label\": \"Node 2\", \"x\": 240, \"y\": 60, \"width\": 100, \"height\": 40}, {\"id\": \"node3\", \"shape\": \"rect\", \"label\": \"Node 3\", \"x\": 150, \"y\": 180, \"width\": 100, \"height\": 40}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\ngraph.addNode({\n id: 'node1',\n shape: 'rect',\n x: 60,\n y: 60,\n width: 100,\n height: 40,\n label: 'Node 1',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\ngraph.addNode({\n id: 'node2',\n shape: 'rect',\n x: 240,\n y: 60,\n width: 100,\n height: 40,\n label: 'Node 2',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\ngraph.addNode({\n id: 'node3',\n shape: 'rect',\n x: 150,\n y: 180,\n width: 100,\n height: 40,\n label: 'Node 3',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\nlet selectedNode = null;\n\ngraph.on('node:click', ({ node }) => {\n if (selectedNode) {\n selectedNode.attr('body/stroke', '#8f8f8f');\n selectedNode.attr('body/strokeWidth', 1);\n }\n node.attr('body/stroke', '#1890ff');\n node.attr('body/strokeWidth', 3);\n selectedNode = node;\n});\n\ngraph.on('blank:click', () => {\n if (selectedNode) {\n selectedNode.attr('body/stroke', '#8f8f8f');\n selectedNode.attr('body/strokeWidth', 1);\n selectedNode = null;\n }\n});\n"
|
||
},
|
||
{
|
||
"description": "监听边的右键点击事件,用于实现上下文菜单功能,获取点击坐标和边信息。参考数据:[{\"id\": \"source\", \"shape\": \"rect\", \"label\": \"Source\", \"x\": 40, \"y\": 80, \"width\": 100, \"height\": 40}, {\"id\": \"target\", \"shape\": \"rect\", \"label\": \"Target\", \"x\": 300, \"y\": 80, \"width\": 100, \"height\": 40}, {\"label\": \"Right Click Me\"}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\nconst source = graph.addNode({\n shape: 'rect',\n x: 40,\n y: 80,\n width: 100,\n height: 40,\n label: 'Source',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\nconst target = graph.addNode({\n shape: 'rect',\n x: 300,\n y: 80,\n width: 100,\n height: 40,\n label: 'Target',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\ngraph.addEdge({\n source,\n target,\n label: 'Right Click Me',\n attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1 } },\n});\n\ngraph.on('edge:contextmenu', ({ e, edge }) => {\n e.preventDefault();\n console.log('Right clicked on edge:', edge.id);\n console.log('Position:', e.clientX, e.clientY);\n});\n\ngraph.on('node:contextmenu', ({ e, node }) => {\n e.preventDefault();\n console.log('Right clicked on node:', node.id);\n});\n"
|
||
},
|
||
{
|
||
"description": "配置节点支持通过拖拽边角调整大小,使用 transform 插件实现 resizing 功能。参考数据:[{\"shape\": \"rect\", \"label\": \"Resize Me\", \"x\": 100, \"y\": 60, \"width\": 150, \"height\": 80}, {\"shape\": \"rect\", \"label\": \"Me Too\", \"x\": 320, \"y\": 100, \"width\": 100, \"height\": 60}]",
|
||
"codeString": "import { Graph, Transform } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n grid: { visible: true },\n});\n\ngraph.use(\n new Transform({\n resizing: {\n enabled: true,\n minWidth: 40,\n minHeight: 40,\n },\n }),\n);\n\ngraph.addNode({\n shape: 'rect',\n x: 100,\n y: 60,\n width: 150,\n height: 80,\n label: 'Resize Me',\n attrs: {\n body: { stroke: '#1890ff', strokeWidth: 2, fill: '#e6f7ff', rx: 6, ry: 6 },\n },\n});\n\ngraph.addNode({\n shape: 'rect',\n x: 320,\n y: 100,\n width: 100,\n height: 60,\n label: 'Me Too',\n attrs: {\n body: { stroke: '#52c41a', strokeWidth: 2, fill: '#f6ffed', rx: 6, ry: 6 },\n },\n});\n"
|
||
},
|
||
{
|
||
"description": "配置节点支持旋转交互,使用 transform 插件启用 rotating 功能。参考数据:[{\"shape\": \"rect\", \"label\": \"Rotate Me\", \"x\": 150, \"y\": 80, \"width\": 120, \"height\": 60}]",
|
||
"codeString": "import { Graph, Transform } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n grid: { visible: true },\n});\n\ngraph.use(\n new Transform({\n rotating: {\n enabled: true,\n },\n }),\n);\n\ngraph.addNode({\n shape: 'rect',\n x: 150,\n y: 80,\n width: 120,\n height: 60,\n label: 'Rotate Me',\n attrs: {\n body: { stroke: '#722ed1', strokeWidth: 2, fill: '#f9f0ff', rx: 6, ry: 6 },\n },\n});\n"
|
||
},
|
||
{
|
||
"description": "配置连线验证,只允许从 source 类型节点连接到 target 类型节点,不允许相同类型之间连接。参考数据:[{\"id\": \"out1\", \"label\": \"Source A\", \"x\": 60, \"y\": 60, \"width\": 100, \"height\": 40}, {\"id\": \"out1\", \"label\": \"Source B\", \"x\": 60, \"y\": 180, \"width\": 100, \"height\": 40}, {\"id\": \"in1\", \"label\": \"Target\", \"x\": 300, \"y\": 120, \"width\": 100, \"height\": 40}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n connecting: {\n allowBlank: false,\n validateConnection({ sourceCell, targetCell }) {\n if (!sourceCell || !targetCell) return false;\n const sourceType = sourceCell.getData()?.type;\n const targetType = targetCell.getData()?.type;\n return sourceType === 'source' && targetType === 'target';\n },\n createEdge() {\n return this.createEdge({\n attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1, targetMarker: 'classic' } },\n });\n },\n },\n});\n\ngraph.addNode({\n x: 60,\n y: 60,\n width: 100,\n height: 40,\n label: 'Source A',\n data: { type: 'source' },\n attrs: {\n body: { stroke: '#1890ff', strokeWidth: 2, fill: '#e6f7ff', rx: 6, ry: 6 },\n },\n ports: {\n groups: {\n out: { position: 'bottom', attrs: { circle: { magnet: true, stroke: '#1890ff', r: 5 } } },\n },\n items: [{ id: 'out1', group: 'out' }],\n },\n});\n\ngraph.addNode({\n x: 60,\n y: 180,\n width: 100,\n height: 40,\n label: 'Source B',\n data: { type: 'source' },\n attrs: {\n body: { stroke: '#1890ff', strokeWidth: 2, fill: '#e6f7ff', rx: 6, ry: 6 },\n },\n ports: {\n groups: {\n out: { position: 'bottom', attrs: { circle: { magnet: true, stroke: '#1890ff', r: 5 } } },\n },\n items: [{ id: 'out1', group: 'out' }],\n },\n});\n\ngraph.addNode({\n x: 300,\n y: 120,\n width: 100,\n height: 40,\n label: 'Target',\n data: { type: 'target' },\n attrs: {\n body: { stroke: '#52c41a', strokeWidth: 2, fill: '#f6ffed', rx: 6, ry: 6 },\n },\n ports: {\n groups: {\n in: { position: 'left', attrs: { circle: { magnet: true, stroke: '#52c41a', r: 5 } } },\n },\n items: [{ id: 'in1', group: 'in' }, { id: 'in2', group: 'in' }],\n },\n});\n"
|
||
},
|
||
{
|
||
"description": "创建一个带网格的画布,节点拖拽移动时自动对齐到网格。参考数据:[{\"shape\": \"rect\", \"label\": \"Node A\", \"x\": 60, \"y\": 60, \"width\": 100, \"height\": 40}, {\"shape\": \"rect\", \"label\": \"Node B\", \"x\": 260, \"y\": 160, \"width\": 100, \"height\": 40}, {\"shape\": \"circle\", \"label\": \"Node C\", \"x\": 160, \"y\": 200, \"width\": 60, \"height\": 60}]",
|
||
"codeString": "import { Graph, Snapline } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n grid: {\n visible: true,\n size: 20,\n type: 'mesh',\n },\n});\n\ngraph.use(new Snapline({ enabled: true }));\n\ngraph.addNode({\n shape: 'rect',\n x: 60,\n y: 60,\n width: 100,\n height: 40,\n label: 'Node A',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\ngraph.addNode({\n shape: 'rect',\n x: 260,\n y: 160,\n width: 100,\n height: 40,\n label: 'Node B',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\ngraph.addNode({\n shape: 'circle',\n x: 160,\n y: 200,\n width: 60,\n height: 60,\n label: 'Node C',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff' },\n },\n});\n"
|
||
},
|
||
{
|
||
"description": "创建节点和边,监听 edge:mouseenter 事件在边上显示删除按钮工具,鼠标离开时移除。参考数据:[{\"id\": \"source\", \"shape\": \"rect\", \"label\": \"Source\", \"x\": 40, \"y\": 80, \"width\": 100, \"height\": 40}, {\"id\": \"target\", \"shape\": \"rect\", \"label\": \"Target\", \"x\": 300, \"y\": 80, \"width\": 100, \"height\": 40}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\nconst source = graph.addNode({\n shape: 'rect',\n x: 40,\n y: 80,\n width: 100,\n height: 40,\n label: 'Source',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\nconst target = graph.addNode({\n shape: 'rect',\n x: 300,\n y: 80,\n width: 100,\n height: 40,\n label: 'Target',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\ngraph.addEdge({\n source,\n target,\n attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1 } },\n});\n\ngraph.on('edge:mouseenter', ({ edge }) => {\n edge.addTools([\n {\n name: 'button-remove',\n args: { distance: '50%' },\n },\n ]);\n});\n\ngraph.on('edge:mouseleave', ({ edge }) => {\n edge.removeTools();\n});\n"
|
||
},
|
||
{
|
||
"description": "创建多个节点,通过代码批量选中指定节点并更改它们的样式。参考数据:[{\"id\": \"node\", \"shape\": \"rect\", \"x\": 40, \"y\": 40, \"width\": 100, \"height\": 40}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\nconst nodes = [];\nfor (let i = 0; i < 6; i++) {\n const node = graph.addNode({\n shape: 'rect',\n x: 40 + (i % 3) * 160,\n y: 40 + Math.floor(i / 3) * 100,\n width: 100,\n height: 40,\n label: `Node ${i + 1}`,\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n });\n nodes.push(node);\n}\n\nnodes.filter((_, i) => i % 2 === 0).forEach((node) => {\n node.attr('body/fill', '#e6f7ff');\n node.attr('body/stroke', '#1890ff');\n node.attr('body/strokeWidth', 2);\n});\n"
|
||
},
|
||
{
|
||
"description": "创建一个画布,添加散布各处的节点后,使用 zoomToFit 方法自动缩放画布使所有内容可见。参考数据:[{\"shape\": \"rect\", \"label\": \"Top-Left\", \"x\": 0, \"y\": 0, \"width\": 80, \"height\": 40}, {\"shape\": \"rect\", \"label\": \"Top-Right\", \"x\": 800, \"y\": 0, \"width\": 80, \"height\": 40}, {\"shape\": \"rect\", \"label\": \"Bottom\", \"x\": 400, \"y\": 500, \"width\": 80, \"height\": 40}, {\"shape\": \"rect\", \"label\": \"Center\", \"x\": 400, \"y\": 250, \"width\": 80, \"height\": 40}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n width: 600,\n height: 400,\n background: { color: '#F2F7FA' },\n});\n\ngraph.addNode({\n shape: 'rect', x: 0, y: 0, width: 80, height: 40, label: 'Top-Left',\n attrs: { body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 } },\n});\n\ngraph.addNode({\n shape: 'rect', x: 800, y: 0, width: 80, height: 40, label: 'Top-Right',\n attrs: { body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 } },\n});\n\ngraph.addNode({\n shape: 'rect', x: 400, y: 500, width: 80, height: 40, label: 'Bottom',\n attrs: { body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 } },\n});\n\ngraph.addNode({\n shape: 'rect', x: 400, y: 250, width: 80, height: 40, label: 'Center',\n attrs: { body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 } },\n});\n\ngraph.zoomToFit({ padding: 40 });\n"
|
||
},
|
||
{
|
||
"description": "创建节点和边,当鼠标移入边时高亮显示边,通过修改边样式实现强调效果。参考数据:[{\"id\": \"source\", \"shape\": \"rect\", \"label\": \"A\", \"x\": 40, \"y\": 100, \"width\": 100, \"height\": 40}, {\"id\": \"target\", \"shape\": \"rect\", \"label\": \"B\", \"x\": 340, \"y\": 100, \"width\": 100, \"height\": 40}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\nconst source = graph.addNode({\n shape: 'rect',\n x: 40,\n y: 100,\n width: 100,\n height: 40,\n label: 'A',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\nconst target = graph.addNode({\n shape: 'rect',\n x: 340,\n y: 100,\n width: 100,\n height: 40,\n label: 'B',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\ngraph.addEdge({\n source,\n target,\n attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1 } },\n});\n\ngraph.on('edge:mouseenter', ({ edge }) => {\n edge.attr('line/stroke', '#1890ff');\n edge.attr('line/strokeWidth', 3);\n});\n\ngraph.on('edge:mouseleave', ({ edge }) => {\n edge.attr('line/stroke', '#8f8f8f');\n edge.attr('line/strokeWidth', 1);\n});\n"
|
||
},
|
||
{
|
||
"description": "创建嵌套分组结构,外层为蓝色大组,内层为绿色小组,小组中包含子节点,演示多层嵌套。参考数据:[{\"id\": \"outerGroup\", \"shape\": \"rect\", \"label\": \"Outer Group\", \"x\": 40, \"y\": 40, \"width\": 400, \"height\": 240}, {\"id\": \"innerGroup\", \"shape\": \"rect\", \"label\": \"Inner Group\", \"x\": 80, \"y\": 100, \"width\": 200, \"height\": 140}, {\"id\": \"child1\", \"shape\": \"rect\", \"label\": \"Child 1\", \"x\": 100, \"y\": 160, \"width\": 80, \"height\": 40}, {\"id\": \"child2\", \"shape\": \"rect\", \"label\": \"Child 2\", \"x\": 320, \"y\": 160, \"width\": 80, \"height\": 40}, {\"source\": \"child1\", \"target\": \"child2\"}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\nconst outerGroup = graph.addNode({\n shape: 'rect',\n x: 40,\n y: 40,\n width: 400,\n height: 240,\n zIndex: 1,\n label: 'Outer Group',\n attrs: {\n body: { stroke: '#1890ff', strokeWidth: 2, fill: '#e6f7ff', rx: 6, ry: 6 },\n label: { refY: 16, textAnchor: 'middle', textVerticalAnchor: 'top' },\n },\n});\n\nconst innerGroup = graph.addNode({\n shape: 'rect',\n x: 80,\n y: 100,\n width: 200,\n height: 140,\n zIndex: 2,\n label: 'Inner Group',\n attrs: {\n body: { stroke: '#52c41a', strokeWidth: 2, fill: '#f6ffed', rx: 6, ry: 6 },\n label: { refY: 12, textAnchor: 'middle', textVerticalAnchor: 'top' },\n },\n});\n\nconst child1 = graph.addNode({\n shape: 'rect',\n x: 100,\n y: 160,\n width: 80,\n height: 40,\n zIndex: 3,\n label: 'Child 1',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\nconst child2 = graph.addNode({\n shape: 'rect',\n x: 320,\n y: 160,\n width: 80,\n height: 40,\n zIndex: 3,\n label: 'Child 2',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\nouterGroup.addChild(innerGroup);\ninnerGroup.addChild(child1);\nouterGroup.addChild(child2);\n\ngraph.addEdge({\n source: child1,\n target: child2,\n attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1 } },\n});\n"
|
||
},
|
||
{
|
||
"description": "创建一个可折叠的分组节点,点击折叠按钮时隐藏子节点,再次点击展开。参考数据:[{\"id\": \"group\", \"shape\": \"collapsable-group\", \"label\": \"Group (Click to collapse)\", \"x\": 60, \"y\": 40, \"width\": 300, \"height\": 200}, {\"id\": \"child1\", \"shape\": \"rect\", \"label\": \"Task A\", \"x\": 100, \"y\": 100, \"width\": 80, \"height\": 40}, {\"id\": \"child2\", \"shape\": \"rect\", \"label\": \"Task B\", \"x\": 240, \"y\": 100, \"width\": 80, \"height\": 40}, {\"source\": \"child1\", \"target\": \"child2\"}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nGraph.registerNode(\n 'collapsable-group',\n {\n inherit: 'rect',\n markup: [\n { tagName: 'rect', selector: 'body' },\n { tagName: 'text', selector: 'label' },\n {\n tagName: 'g',\n selector: 'buttonGroup',\n children: [\n { tagName: 'rect', selector: 'button', attrs: { width: 16, height: 16, rx: 2, ry: 2 } },\n { tagName: 'text', selector: 'buttonSign', attrs: { x: 8, y: 12, textAnchor: 'middle', fontSize: 12 } },\n ],\n },\n ],\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#e6f7ff', rx: 6, ry: 6 },\n label: { refY: 14, textAnchor: 'middle', textVerticalAnchor: 'top', fontSize: 13 },\n button: { fill: '#fff', stroke: '#8f8f8f', cursor: 'pointer', refX: 8, refY: 8 },\n buttonSign: { fill: '#333', cursor: 'pointer' },\n },\n },\n true,\n);\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\nconst group = graph.addNode({\n shape: 'collapsable-group',\n x: 60,\n y: 40,\n width: 300,\n height: 200,\n label: 'Group (Click to collapse)',\n attrs: {\n buttonSign: { text: '-' },\n },\n});\n\nconst child1 = graph.addNode({\n shape: 'rect',\n x: 100,\n y: 100,\n width: 80,\n height: 40,\n label: 'Task A',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\nconst child2 = graph.addNode({\n shape: 'rect',\n x: 240,\n y: 100,\n width: 80,\n height: 40,\n label: 'Task B',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\ngroup.addChild(child1);\ngroup.addChild(child2);\n\ngraph.addEdge({\n source: child1,\n target: child2,\n attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1 } },\n});\n\nlet collapsed = false;\ngraph.on('node:click', ({ node }) => {\n if (node === group) {\n collapsed = !collapsed;\n const children = group.getChildren();\n if (children) {\n children.forEach((child) => {\n collapsed ? child.hide() : child.show();\n });\n }\n node.attr('buttonSign/text', collapsed ? '+' : '-');\n if (collapsed) {\n node.resize(300, 50);\n } else {\n node.resize(300, 200);\n }\n }\n});\n"
|
||
},
|
||
{
|
||
"description": "为节点添加 button-remove 删除按钮工具,为边添加 vertices 和 segments 拖拽点工具。参考数据:[{\"id\": \"source\", \"shape\": \"rect\", \"label\": \"Source\", \"x\": 40, \"y\": 40, \"width\": 100, \"height\": 40}, {\"id\": \"target\", \"shape\": \"rect\", \"label\": \"Target\", \"x\": 160, \"y\": 240, \"width\": 100, \"height\": 40}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\nconst source = graph.addNode({\n shape: 'rect',\n x: 40,\n y: 40,\n width: 100,\n height: 40,\n label: 'Source',\n tools: ['button-remove'],\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\nconst target = graph.addNode({\n shape: 'rect',\n x: 160,\n y: 240,\n width: 100,\n height: 40,\n label: 'Target',\n tools: ['button-remove'],\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\ngraph.addEdge({\n source,\n target,\n vertices: [\n { x: 90, y: 160 },\n { x: 210, y: 160 },\n ],\n tools: ['vertices', 'segments'],\n attrs: {\n line: { stroke: '#8f8f8f', strokeWidth: 1 },\n },\n});\n"
|
||
},
|
||
{
|
||
"description": "鼠标悬停在节点上时动态显示节点工具(删除按钮),离开时隐藏工具。参考数据:[{\"shape\": \"rect\", \"label\": \"Hover to show tools\", \"x\": 60, \"y\": 60, \"width\": 120, \"height\": 50}, {\"shape\": \"rect\", \"label\": \"Another Node\", \"x\": 260, \"y\": 140, \"width\": 120, \"height\": 50}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\ngraph.addNode({\n shape: 'rect',\n x: 60,\n y: 60,\n width: 120,\n height: 50,\n label: 'Hover to show tools',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\ngraph.addNode({\n shape: 'rect',\n x: 260,\n y: 140,\n width: 120,\n height: 50,\n label: 'Another Node',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\ngraph.on('node:mouseenter', ({ node }) => {\n node.addTools([\n { name: 'button-remove', args: { x: 0, y: 0, offset: { x: -10, y: -10 } } },\n { name: 'boundary', args: { padding: 5 } },\n ]);\n});\n\ngraph.on('node:mouseleave', ({ node }) => {\n node.removeTools();\n});\n"
|
||
},
|
||
{
|
||
"description": "使用 HTML shape 创建包含 HTML 内容的自定义节点,节点内展示标题和描述文字。参考数据:[{\"shape\": \"html-node\", \"x\": 100, \"y\": 60}, {\"shape\": \"html-node\", \"x\": 320, \"y\": 160}]",
|
||
"codeString": "import { Graph, Shape } from '@antv/x6';\n\nShape.HTML.register({\n shape: 'html-node',\n width: 160,\n height: 80,\n html() {\n const div = document.createElement('div');\n div.style.width = '100%';\n div.style.height = '100%';\n div.style.background = '#fff';\n div.style.border = '1px solid #8f8f8f';\n div.style.borderRadius = '6px';\n div.style.display = 'flex';\n div.style.flexDirection = 'column';\n div.style.justifyContent = 'center';\n div.style.alignItems = 'center';\n div.style.padding = '8px';\n div.innerHTML = '<strong style=\"font-size:14px\">Task Node</strong><span style=\"font-size:12px;color:#666\">Processing...</span>';\n return div;\n },\n});\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\ngraph.addNode({\n shape: 'html-node',\n x: 100,\n y: 60,\n});\n\ngraph.addNode({\n shape: 'html-node',\n x: 320,\n y: 160,\n});\n"
|
||
},
|
||
{
|
||
"description": "创建 HTML 自定义节点,根据节点 data 动态渲染不同内容,修改 data 时自动更新视图。参考数据:[{\"id\": \"node1\", \"shape\": \"status-node\", \"x\": 60, \"y\": 60}, {\"id\": \"node2\", \"shape\": \"status-node\", \"x\": 60, \"y\": 160}, {\"id\": \"node3\", \"shape\": \"status-node\", \"x\": 280, \"y\": 110}, {\"source\": \"node1\", \"target\": \"node3\"}, {\"source\": \"node2\", \"target\": \"node3\"}]",
|
||
"codeString": "import { Graph, Shape } from '@antv/x6';\n\nShape.HTML.register({\n shape: 'status-node',\n width: 160,\n height: 60,\n effect: ['data'],\n html(cell) {\n const data = cell.getData() || {};\n const status = data.status || 'pending';\n const colors = { running: '#52c41a', pending: '#fa8c16', error: '#f5222d' };\n const color = colors[status] || '#8f8f8f';\n const div = document.createElement('div');\n div.style.cssText = 'width:100%;height:100%;background:#fff;border:2px solid ' + color + ';border-radius:6px;display:flex;align-items:center;justify-content:center;font-size:13px;';\n div.textContent = data.name + ' (' + status + ')';\n return div;\n },\n});\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\nconst node1 = graph.addNode({\n shape: 'status-node',\n x: 60,\n y: 60,\n data: { name: 'Task A', status: 'running' },\n});\n\nconst node2 = graph.addNode({\n shape: 'status-node',\n x: 60,\n y: 160,\n data: { name: 'Task B', status: 'pending' },\n});\n\nconst node3 = graph.addNode({\n shape: 'status-node',\n x: 280,\n y: 110,\n data: { name: 'Task C', status: 'error' },\n});\n\ngraph.addEdge({\n source: node1,\n target: node3,\n attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1 } },\n});\n\ngraph.addEdge({\n source: node2,\n target: node3,\n attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1 } },\n});\n"
|
||
},
|
||
{
|
||
"description": "创建一个分组,子节点只能在分组范围内拖拽移动,不能超出父节点边界。参考数据:[{\"id\": \"parent\", \"shape\": \"rect\", \"label\": \"Container (children restricted)\", \"x\": 40, \"y\": 40, \"width\": 400, \"height\": 200}, {\"id\": \"child\", \"shape\": \"rect\", \"label\": \"Drag Me\", \"x\": 100, \"y\": 120, \"width\": 80, \"height\": 40}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n embedding: {\n enabled: true,\n },\n translating: {\n restrict(cellView) {\n const cell = cellView.cell;\n const parent = cell.getParent();\n if (parent) {\n return parent.getBBox();\n }\n return null;\n },\n },\n});\n\nconst parent = graph.addNode({\n shape: 'rect',\n x: 40,\n y: 40,\n width: 400,\n height: 200,\n zIndex: 1,\n label: 'Container (children restricted)',\n attrs: {\n body: { stroke: '#1890ff', strokeWidth: 2, fill: '#e6f7ff', rx: 6, ry: 6 },\n label: { refY: 14, textAnchor: 'middle', textVerticalAnchor: 'top' },\n },\n});\n\nconst child = graph.addNode({\n shape: 'rect',\n x: 100,\n y: 120,\n width: 80,\n height: 40,\n zIndex: 2,\n label: 'Drag Me',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\nparent.addChild(child);\n"
|
||
},
|
||
{
|
||
"description": "配置边的连接点(connectionPoint),让边连接到节点边框上的精确位置而非中心点。参考数据:[{\"id\": \"node1\", \"shape\": \"rect\", \"label\": \"Rect\", \"x\": 60, \"y\": 100, \"width\": 80, \"height\": 80}, {\"id\": \"node2\", \"shape\": \"circle\", \"label\": \"Circle\", \"x\": 260, \"y\": 100, \"width\": 80, \"height\": 80}, {\"id\": \"node3\", \"shape\": \"ellipse\", \"label\": \"Ellipse\", \"x\": 160, \"y\": 240, \"width\": 120, \"height\": 60}, {\"source\": \"node1\", \"target\": \"node2\"}, {\"source\": \"node1\", \"target\": \"node3\"}, {\"source\": \"node2\", \"target\": \"node3\"}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n connecting: {\n connectionPoint: 'boundary',\n createEdge() {\n return this.createEdge({\n attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1, targetMarker: 'classic' } },\n });\n },\n },\n});\n\nconst node1 = graph.addNode({\n shape: 'rect',\n x: 60,\n y: 100,\n width: 80,\n height: 80,\n label: 'Rect',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\nconst node2 = graph.addNode({\n shape: 'circle',\n x: 260,\n y: 100,\n width: 80,\n height: 80,\n label: 'Circle',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff' },\n },\n});\n\nconst node3 = graph.addNode({\n shape: 'ellipse',\n x: 160,\n y: 240,\n width: 120,\n height: 60,\n label: 'Ellipse',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff' },\n },\n});\n\ngraph.addEdge({ source: node1, target: node2, attrs: { line: { stroke: '#1890ff', strokeWidth: 1, targetMarker: 'classic' } } });\ngraph.addEdge({ source: node1, target: node3, attrs: { line: { stroke: '#52c41a', strokeWidth: 1, targetMarker: 'classic' } } });\ngraph.addEdge({ source: node2, target: node3, attrs: { line: { stroke: '#fa8c16', strokeWidth: 1, targetMarker: 'classic' } } });\n"
|
||
},
|
||
{
|
||
"description": "创建一个自动扩展的分组节点,当子节点被拖到边界外时,分组自动扩大以容纳子节点。参考数据:[{\"id\": \"parent\", \"shape\": \"rect\", \"label\": \"Auto-expand Group\", \"x\": 60, \"y\": 40, \"width\": 300, \"height\": 160}, {\"id\": \"child1\", \"shape\": \"rect\", \"label\": \"Child 1\", \"x\": 100, \"y\": 100, \"width\": 80, \"height\": 40}, {\"id\": \"child2\", \"shape\": \"rect\", \"label\": \"Child 2\", \"x\": 240, \"y\": 100, \"width\": 80, \"height\": 40}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n embedding: {\n enabled: true,\n },\n});\n\nconst parent = graph.addNode({\n shape: 'rect',\n x: 60,\n y: 40,\n width: 300,\n height: 160,\n zIndex: 1,\n label: 'Auto-expand Group',\n attrs: {\n body: { stroke: '#1890ff', strokeWidth: 2, fill: '#e6f7ff', rx: 6, ry: 6 },\n label: { refY: 12, textAnchor: 'middle', textVerticalAnchor: 'top' },\n },\n});\n\nconst child1 = graph.addNode({\n shape: 'rect',\n x: 100,\n y: 100,\n width: 80,\n height: 40,\n zIndex: 2,\n label: 'Child 1',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\nconst child2 = graph.addNode({\n shape: 'rect',\n x: 240,\n y: 100,\n width: 80,\n height: 40,\n zIndex: 2,\n label: 'Child 2',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\nparent.addChild(child1);\nparent.addChild(child2);\n\nconst padding = 20;\n\ngraph.on('node:change:position', ({ node, options }) => {\n if (options.skipParentHandler) return;\n const nodeParent = node.getParent();\n if (nodeParent && nodeParent.isNode()) {\n let originSize = nodeParent.prop('originSize') || nodeParent.getSize();\n let originPosition = nodeParent.prop('originPosition') || nodeParent.getPosition();\n let x = originPosition.x;\n let y = originPosition.y;\n let cornerX = x + originSize.width;\n let cornerY = y + originSize.height;\n let hasChange = false;\n const children = nodeParent.getChildren();\n if (children) {\n children.forEach((child) => {\n const bbox = child.getBBox().inflate(padding);\n const corner = bbox.getCorner();\n if (bbox.x < x) { x = bbox.x; hasChange = true; }\n if (bbox.y < y) { y = bbox.y; hasChange = true; }\n if (corner.x > cornerX) { cornerX = corner.x; hasChange = true; }\n if (corner.y > cornerY) { cornerY = corner.y; hasChange = true; }\n });\n }\n if (hasChange) {\n nodeParent.prop({ position: { x, y }, size: { width: cornerX - x, height: cornerY - y } }, { skipParentHandler: true });\n }\n }\n});\n"
|
||
},
|
||
{
|
||
"description": "为边配置 vertices 工具和 segments 工具,允许用户拖拽添加/移动边的控制点。参考数据:[{\"id\": \"source\", \"shape\": \"rect\", \"label\": \"Source\", \"x\": 40, \"y\": 40, \"width\": 100, \"height\": 40}, {\"id\": \"target\", \"shape\": \"rect\", \"label\": \"Target\", \"x\": 320, \"y\": 240, \"width\": 100, \"height\": 40}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\nconst source = graph.addNode({\n shape: 'rect',\n x: 40,\n y: 40,\n width: 100,\n height: 40,\n label: 'Source',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\nconst target = graph.addNode({\n shape: 'rect',\n x: 320,\n y: 240,\n width: 100,\n height: 40,\n label: 'Target',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\ngraph.addEdge({\n source,\n target,\n router: 'orth',\n connector: 'rounded',\n attrs: { line: { stroke: '#1890ff', strokeWidth: 2 } },\n tools: [\n 'vertices',\n 'segments',\n { name: 'button-remove', args: { distance: '50%' } },\n ],\n});\n"
|
||
},
|
||
{
|
||
"description": "为边添加 source-arrowhead 和 target-arrowhead 工具,允许拖拽改变边的起点和终点。参考数据:[{\"id\": \"node1\", \"shape\": \"rect\", \"label\": \"Node 1\", \"x\": 40, \"y\": 40, \"width\": 100, \"height\": 40}, {\"id\": \"node2\", \"shape\": \"rect\", \"label\": \"Node 2\", \"x\": 300, \"y\": 40, \"width\": 100, \"height\": 40}, {\"id\": \"node3\", \"shape\": \"rect\", \"label\": \"Node 3\", \"x\": 170, \"y\": 200, \"width\": 100, \"height\": 40}, {\"source\": \"node1\", \"target\": \"node2\"}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\nconst node1 = graph.addNode({\n shape: 'rect',\n x: 40,\n y: 40,\n width: 100,\n height: 40,\n label: 'Node 1',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\nconst node2 = graph.addNode({\n shape: 'rect',\n x: 300,\n y: 40,\n width: 100,\n height: 40,\n label: 'Node 2',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\nconst node3 = graph.addNode({\n shape: 'rect',\n x: 170,\n y: 200,\n width: 100,\n height: 40,\n label: 'Node 3',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\ngraph.addEdge({\n source: node1,\n target: node2,\n attrs: { line: { stroke: '#1890ff', strokeWidth: 2 } },\n tools: ['source-arrowhead', 'target-arrowhead'],\n});\n"
|
||
},
|
||
{
|
||
"description": "在分组节点内部的子节点之间创建边,边也作为分组的子元素。参考数据:[{\"id\": \"group\", \"shape\": \"rect\", \"label\": \"Group\", \"x\": 40, \"y\": 40, \"width\": 360, \"height\": 200}, {\"id\": \"child1\", \"shape\": \"rect\", \"label\": \"A\", \"x\": 80, \"y\": 120, \"width\": 80, \"height\": 40}, {\"id\": \"child2\", \"shape\": \"rect\", \"label\": \"B\", \"x\": 280, \"y\": 120, \"width\": 80, \"height\": 40}, {\"source\": \"child1\", \"target\": \"child2\"}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\nconst group = graph.addNode({\n shape: 'rect',\n x: 40,\n y: 40,\n width: 360,\n height: 200,\n zIndex: 1,\n label: 'Group',\n attrs: {\n body: { stroke: '#1890ff', strokeWidth: 2, fill: '#e6f7ff', rx: 6, ry: 6 },\n label: { refY: 14, textAnchor: 'middle', textVerticalAnchor: 'top' },\n },\n});\n\nconst child1 = graph.addNode({\n shape: 'rect',\n x: 80,\n y: 120,\n width: 80,\n height: 40,\n zIndex: 2,\n label: 'A',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\nconst child2 = graph.addNode({\n shape: 'rect',\n x: 280,\n y: 120,\n width: 80,\n height: 40,\n zIndex: 2,\n label: 'B',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\nconst edge = graph.addEdge({\n source: child1,\n target: child2,\n attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1 } },\n});\n\ngroup.addChild(child1);\ngroup.addChild(child2);\ngroup.addChild(edge);\n"
|
||
},
|
||
{
|
||
"description": "同一对节点之间创建多条边,通过设置不同的 anchor 位置避免重叠。参考数据:[{\"id\": \"node1\", \"shape\": \"rect\", \"label\": \"Service A\", \"x\": 40, \"y\": 80, \"width\": 120, \"height\": 80}, {\"id\": \"node2\", \"shape\": \"rect\", \"label\": \"Service B\", \"x\": 340, \"y\": 80, \"width\": 120, \"height\": 80}, {\"source\": \"node1\", \"target\": \"node2\", \"label\": \"request\"}, {\"source\": \"node2\", \"target\": \"node1\", \"label\": \"response\"}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\nconst node1 = graph.addNode({\n shape: 'rect',\n x: 40,\n y: 80,\n width: 120,\n height: 80,\n label: 'Service A',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\nconst node2 = graph.addNode({\n shape: 'rect',\n x: 340,\n y: 80,\n width: 120,\n height: 80,\n label: 'Service B',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\ngraph.addEdge({\n source: { cell: node1, anchor: { name: 'right', args: { dy: -15 } } },\n target: { cell: node2, anchor: { name: 'left', args: { dy: -15 } } },\n label: 'request',\n attrs: { line: { stroke: '#1890ff', strokeWidth: 1, targetMarker: 'classic' } },\n});\n\ngraph.addEdge({\n source: { cell: node2, anchor: { name: 'left', args: { dy: 15 } } },\n target: { cell: node1, anchor: { name: 'right', args: { dy: 15 } } },\n label: 'response',\n attrs: { line: { stroke: '#52c41a', strokeWidth: 1, targetMarker: 'classic', strokeDasharray: '5 3' } },\n});\n"
|
||
},
|
||
{
|
||
"description": "创建多个节点,演示通过 node.hide() 和 node.show() 控制节点的可见性。参考数据:[{\"id\": \"node1\", \"shape\": \"rect\", \"label\": \"Visible\", \"x\": 60, \"y\": 60, \"width\": 100, \"height\": 40}, {\"id\": \"node2\", \"shape\": \"rect\", \"label\": \"Hidden\", \"x\": 60, \"y\": 140, \"width\": 100, \"height\": 40}, {\"id\": \"node3\", \"shape\": \"rect\", \"label\": \"Target\", \"x\": 240, \"y\": 100, \"width\": 100, \"height\": 40}, {\"source\": \"node1\", \"target\": \"node3\"}, {\"source\": \"node2\", \"target\": \"node3\"}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\nconst node1 = graph.addNode({\n shape: 'rect',\n x: 60,\n y: 60,\n width: 100,\n height: 40,\n label: 'Visible',\n attrs: {\n body: { stroke: '#52c41a', strokeWidth: 2, fill: '#f6ffed', rx: 6, ry: 6 },\n },\n});\n\nconst node2 = graph.addNode({\n shape: 'rect',\n x: 60,\n y: 140,\n width: 100,\n height: 40,\n label: 'Hidden',\n attrs: {\n body: { stroke: '#f5222d', strokeWidth: 2, fill: '#fff1f0', rx: 6, ry: 6 },\n },\n});\n\nconst node3 = graph.addNode({\n shape: 'rect',\n x: 240,\n y: 100,\n width: 100,\n height: 40,\n label: 'Target',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\ngraph.addEdge({ source: node1, target: node3, attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1 } } });\ngraph.addEdge({ source: node2, target: node3, attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1 } } });\n\nnode2.hide();\n"
|
||
},
|
||
{
|
||
"description": "为选中的节点添加 boundary 工具,显示虚线选择框边框效果。参考数据:[{\"id\": \"node1\", \"shape\": \"rect\", \"label\": \"Click Me\", \"x\": 60, \"y\": 60, \"width\": 100, \"height\": 50}, {\"id\": \"node2\", \"shape\": \"circle\", \"label\": \"Me Too\", \"x\": 260, \"y\": 60, \"width\": 60, \"height\": 60}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\nconst node1 = graph.addNode({\n shape: 'rect',\n x: 60,\n y: 60,\n width: 100,\n height: 50,\n label: 'Click Me',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\nconst node2 = graph.addNode({\n shape: 'circle',\n x: 260,\n y: 60,\n width: 60,\n height: 60,\n label: 'Me Too',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff' },\n },\n});\n\ngraph.on('node:click', ({ node }) => {\n graph.getNodes().forEach((n) => n.removeTools());\n node.addTools([\n {\n name: 'boundary',\n args: {\n padding: 6,\n attrs: {\n fill: 'none',\n stroke: '#1890ff',\n strokeWidth: 1,\n strokeDasharray: '5 3',\n },\n },\n },\n ]);\n});\n"
|
||
},
|
||
{
|
||
"description": "使用 Selection 插件实现节点框选功能,支持多选、橡皮筋框选和选中节点拖拽移动。参考数据:[{\"shape\": \"circle\", \"label\": \"Rect\", \"x\": 320, \"y\": 100, \"width\": 100, \"height\": 40}, {\"id\": \"source\", \"shape\": \"circle\", \"label\": \"Hello\", \"x\": 80, \"y\": 50, \"width\": 100, \"height\": 40}, {\"id\": \"target\", \"shape\": \"circle\", \"label\": \"World\", \"x\": 240, \"y\": 200, \"width\": 60, \"height\": 60}]",
|
||
"codeString": "import { Graph, Selection } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\ngraph.use(\n new Selection({\n enabled: true,\n multiple: true,\n rubberband: true,\n movable: true,\n showNodeSelectionBox: true,\n }),\n);\n\ngraph.addNode({\n x: 320,\n y: 100,\n width: 100,\n height: 40,\n label: 'Rect',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\nconst source = graph.addNode({\n x: 80,\n y: 50,\n width: 100,\n height: 40,\n label: 'Hello',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\nconst target = graph.addNode({\n shape: 'circle',\n x: 240,\n y: 200,\n width: 60,\n height: 60,\n label: 'World',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff' },\n },\n});\n\ngraph.addEdge({\n source,\n target,\n attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1 } },\n});\n"
|
||
},
|
||
{
|
||
"description": "使用 MiniMap 和 Scroller 插件为画布添加小地图导航功能,小地图显示在右下角。参考数据:[{\"shape\": \"circle\", \"label\": \"Rect\", \"x\": 200, \"y\": 100, \"width\": 100, \"height\": 40}, {\"id\": \"source\", \"shape\": \"circle\", \"label\": \"Hello\", \"x\": 32, \"y\": 32, \"width\": 100, \"height\": 40}, {\"id\": \"target\", \"shape\": \"circle\", \"label\": \"World\", \"x\": 160, \"y\": 180, \"width\": 60, \"height\": 60}]",
|
||
"codeString": "import { Graph, MiniMap, Scroller } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n width: 600,\n height: 320,\n panning: false,\n background: { color: '#F2F7FA' },\n});\n\ngraph.use(\n new Scroller({\n enabled: true,\n pageVisible: true,\n pageBreak: false,\n pannable: true,\n }),\n);\n\nconst minimapContainer = document.createElement('div');\nminimapContainer.style.position = 'absolute';\nminimapContainer.style.right = '10px';\nminimapContainer.style.bottom = '10px';\ndocument.getElementById('container').appendChild(minimapContainer);\n\ngraph.use(\n new MiniMap({\n container: minimapContainer,\n width: 200,\n height: 160,\n padding: 10,\n }),\n);\n\ngraph.addNode({\n x: 200,\n y: 100,\n width: 100,\n height: 40,\n label: 'Rect',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\nconst source = graph.addNode({\n x: 32,\n y: 32,\n width: 100,\n height: 40,\n label: 'Hello',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\nconst target = graph.addNode({\n shape: 'circle',\n x: 160,\n y: 180,\n width: 60,\n height: 60,\n label: 'World',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff' },\n },\n});\n\ngraph.addEdge({\n source,\n target,\n attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1 } },\n});\n"
|
||
},
|
||
{
|
||
"description": "使用 History 插件实现撤销和重做功能,监听 history:change 事件更新按钮状态。参考数据:[{\"label\": \"Drag Me\", \"x\": 100, \"y\": 60, \"width\": 100, \"height\": 40}]",
|
||
"codeString": "import { Graph, History } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\ngraph.use(\n new History({\n enabled: true,\n }),\n);\n\ngraph.addNode({\n x: 100,\n y: 60,\n width: 100,\n height: 40,\n label: 'Drag Me',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\ngraph.on('history:change', () => {\n console.log('Can Undo:', graph.canUndo());\n console.log('Can Redo:', graph.canRedo());\n});\n"
|
||
},
|
||
{
|
||
"description": "使用 Clipboard 和 Selection 插件实现节点的复制粘贴功能。参考数据:[{\"label\": \"Copy Me\", \"x\": 80, \"y\": 50, \"width\": 100, \"height\": 40}, {\"label\": \"Or Me\", \"x\": 280, \"y\": 150, \"width\": 100, \"height\": 40}]",
|
||
"codeString": "import { Graph, Clipboard, Selection } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\ngraph.use(\n new Clipboard({\n enabled: true,\n }),\n);\n\ngraph.use(\n new Selection({\n enabled: true,\n showNodeSelectionBox: true,\n }),\n);\n\ngraph.addNode({\n x: 80,\n y: 50,\n width: 100,\n height: 40,\n label: 'Copy Me',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\ngraph.addNode({\n x: 280,\n y: 150,\n width: 100,\n height: 40,\n label: 'Or Me',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n"
|
||
},
|
||
{
|
||
"description": "使用 Keyboard 插件绑定快捷键,实现 Ctrl+C 复制、Ctrl+V 粘贴、Delete 删除等功能。参考数据:[{\"shape\": \"circle\", \"label\": \"Hello\", \"x\": 80, \"y\": 50, \"width\": 100, \"height\": 40}, {\"shape\": \"circle\", \"label\": \"World\", \"x\": 240, \"y\": 160, \"width\": 60, \"height\": 60}]",
|
||
"codeString": "import { Graph, Clipboard, Keyboard, Selection } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\ngraph.use(new Clipboard({ enabled: true }));\ngraph.use(new Selection({ enabled: true, showNodeSelectionBox: true }));\ngraph.use(new Keyboard({ enabled: true, global: true }));\n\ngraph.addNode({\n x: 80,\n y: 50,\n width: 100,\n height: 40,\n label: 'Hello',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\ngraph.addNode({\n shape: 'circle',\n x: 240,\n y: 160,\n width: 60,\n height: 60,\n label: 'World',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff' },\n },\n});\n\ngraph.bindKey('ctrl+c', () => {\n const cells = graph.getSelectedCells();\n if (cells.length) {\n graph.copy(cells);\n }\n return false;\n});\n\ngraph.bindKey('ctrl+v', () => {\n if (!graph.isClipboardEmpty()) {\n const cells = graph.paste({ offset: 32 });\n graph.cleanSelection();\n graph.select(cells);\n }\n return false;\n});\n\ngraph.bindKey('delete', () => {\n const cells = graph.getSelectedCells();\n if (cells.length) {\n graph.removeCells(cells);\n }\n return false;\n});\n"
|
||
},
|
||
{
|
||
"description": "使用 Snapline 插件在拖拽节点时显示对齐辅助线,帮助精确对齐节点。参考数据:[{\"shape\": \"circle\", \"label\": \"Drag Me\", \"x\": 200, \"y\": 100, \"width\": 100, \"height\": 40}, {\"shape\": \"circle\", \"label\": \"Reference 1\", \"x\": 32, \"y\": 32, \"width\": 100, \"height\": 40}, {\"shape\": \"circle\", \"label\": \"Reference 2\", \"x\": 160, \"y\": 180, \"width\": 60, \"height\": 60}]",
|
||
"codeString": "import { Graph, Snapline } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\ngraph.use(\n new Snapline({\n enabled: true,\n clean: false,\n }),\n);\n\ngraph.addNode({\n x: 200,\n y: 100,\n width: 100,\n height: 40,\n label: 'Drag Me',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\ngraph.addNode({\n x: 32,\n y: 32,\n width: 100,\n height: 40,\n label: 'Reference 1',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\ngraph.addNode({\n shape: 'circle',\n x: 160,\n y: 180,\n width: 60,\n height: 60,\n label: 'Reference 2',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff' },\n },\n});\n"
|
||
},
|
||
{
|
||
"description": "使用 Stencil 插件创建拖拽面板,加载多种预设图形(矩形、圆形、椭圆)。Stencil 的 container 直接 append 到画布 container 中。参考数据:[{\"label\": \"Existing Node\", \"x\": 200, \"y\": 100, \"width\": 100, \"height\": 40}]",
|
||
"codeString": "import { Graph, Stencil } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\ngraph.addNode({\n x: 200,\n y: 100,\n width: 100,\n height: 40,\n label: 'Existing Node',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\nconst stencil = new Stencil({\n title: 'Components',\n target: graph,\n stencilGraphWidth: 180,\n stencilGraphHeight: 240,\n groups: [\n { name: 'basic', title: 'Basic Shapes' },\n ],\n});\ngraph.use(stencil);\n\nconst rect = graph.createNode({\n shape: 'rect',\n width: 80,\n height: 40,\n label: 'Rect',\n attrs: { body: { fill: '#fff', stroke: '#8f8f8f', strokeWidth: 1 } },\n});\n\nconst circle = graph.createNode({\n shape: 'circle',\n width: 40,\n height: 40,\n label: 'Circle',\n attrs: { body: { fill: '#fff', stroke: '#8f8f8f', strokeWidth: 1 } },\n});\n\nconst ellipse = graph.createNode({\n shape: 'ellipse',\n width: 80,\n height: 40,\n label: 'Ellipse',\n attrs: { body: { fill: '#fff', stroke: '#8f8f8f', strokeWidth: 1 } },\n});\n\nstencil.load([rect, circle, ellipse], 'basic');\n\ndocument.getElementById('container').appendChild(stencil.container);\n"
|
||
},
|
||
{
|
||
"description": "使用 Scroller 插件让画布支持滚动,当内容超出可视区域时可以通过滚动条查看。参考数据:[{\"shape\": \"rect\", \"label\": \"Node \", \"x\": 50, \"y\": 50, \"width\": 120, \"height\": 50}]",
|
||
"codeString": "import { Graph, Scroller } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n width: 600,\n height: 400,\n background: { color: '#F2F7FA' },\n});\n\ngraph.use(\n new Scroller({\n enabled: true,\n pannable: true,\n pageVisible: true,\n pageBreak: true,\n }),\n);\n\nfor (let i = 0; i < 8; i++) {\n graph.addNode({\n shape: 'rect',\n x: 50 + (i % 4) * 200,\n y: 50 + Math.floor(i / 4) * 200,\n width: 120,\n height: 50,\n label: 'Node ' + (i + 1),\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n });\n}\n"
|
||
},
|
||
{
|
||
"description": "使用 Transform 插件的 resizing 功能,允许节点通过拖拽边角改变大小,设置最小尺寸和保持比例。参考数据:[{\"shape\": \"rect\", \"label\": \"Resizable\", \"x\": 100, \"y\": 60, \"width\": 160, \"height\": 80}, {\"shape\": \"circle\", \"label\": \"Circle\", \"x\": 360, \"y\": 100, \"width\": 80, \"height\": 80}]",
|
||
"codeString": "import { Graph, Transform } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n grid: { visible: true },\n});\n\ngraph.use(\n new Transform({\n resizing: {\n enabled: true,\n minWidth: 60,\n minHeight: 40,\n maxWidth: 400,\n maxHeight: 300,\n orthogonal: false,\n restrict: false,\n preserveAspectRatio: false,\n },\n }),\n);\n\ngraph.addNode({\n shape: 'rect',\n x: 100,\n y: 60,\n width: 160,\n height: 80,\n label: 'Resizable',\n attrs: {\n body: { stroke: '#1890ff', strokeWidth: 2, fill: '#e6f7ff', rx: 6, ry: 6 },\n },\n});\n\ngraph.addNode({\n shape: 'circle',\n x: 360,\n y: 100,\n width: 80,\n height: 80,\n label: 'Circle',\n attrs: {\n body: { stroke: '#52c41a', strokeWidth: 2, fill: '#f6ffed' },\n },\n});\n"
|
||
},
|
||
{
|
||
"description": "使用 Transform 插件同时启用 resizing 和 rotating 功能,节点既可调整大小也可旋转。参考数据:[{\"shape\": \"rect\", \"label\": \"Resize & Rotate\", \"x\": 120, \"y\": 80, \"width\": 160, \"height\": 80}]",
|
||
"codeString": "import { Graph, Transform } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n grid: { visible: true },\n});\n\ngraph.use(\n new Transform({\n resizing: {\n enabled: true,\n },\n rotating: {\n enabled: true,\n grid: 15,\n },\n }),\n);\n\ngraph.addNode({\n shape: 'rect',\n x: 120,\n y: 80,\n width: 160,\n height: 80,\n label: 'Resize & Rotate',\n attrs: {\n body: { stroke: '#722ed1', strokeWidth: 2, fill: '#f9f0ff', rx: 6, ry: 6 },\n },\n});\n"
|
||
},
|
||
{
|
||
"description": "使用 Dnd 插件从外部拖拽创建新节点到画布中。参考数据:[{\"label\": \"Existing\", \"x\": 200, \"y\": 100, \"width\": 100, \"height\": 40}]",
|
||
"codeString": "import { Graph, Dnd } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n grid: { visible: true },\n});\n\nconst dnd = new Dnd({\n target: graph,\n getDragNode(sourceNode) {\n return sourceNode.clone();\n },\n getDropNode(draggingNode) {\n return draggingNode.clone();\n },\n});\n\ngraph.addNode({\n x: 200,\n y: 100,\n width: 100,\n height: 40,\n label: 'Existing',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\nconst dragSource = document.createElement('div');\ndragSource.style.cssText = 'width:80px;height:40px;border:1px solid #1890ff;background:#e6f7ff;text-align:center;line-height:40px;cursor:move;border-radius:4px;position:absolute;left:10px;top:10px;';\ndragSource.textContent = 'Drag Me';\ndocument.getElementById('container').parentElement.appendChild(dragSource);\n\ndragSource.addEventListener('mousedown', (e) => {\n const node = graph.createNode({\n shape: 'rect',\n width: 100,\n height: 40,\n label: 'New Node',\n attrs: {\n body: { stroke: '#1890ff', strokeWidth: 1, fill: '#e6f7ff', rx: 6, ry: 6 },\n },\n });\n dnd.start(node, e);\n});\n"
|
||
},
|
||
{
|
||
"description": "组合使用 Selection、Snapline、History、Keyboard、Clipboard 插件搭建一个基础的图编辑器。参考数据:[{\"id\": \"out1\", \"label\": \"Start\", \"x\": 60, \"y\": 60, \"width\": 100, \"height\": 40}, {\"id\": \"in1\", \"label\": \"End\", \"x\": 60, \"y\": 200, \"width\": 100, \"height\": 40}]",
|
||
"codeString": "import { Graph, Selection, Snapline, History, Keyboard, Clipboard } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n grid: { visible: true },\n connecting: {\n allowBlank: false,\n snap: { radius: 20 },\n createEdge() {\n return this.createEdge({\n attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1, targetMarker: 'classic' } },\n });\n },\n },\n});\n\ngraph.use(new Selection({ enabled: true, multiple: true, rubberband: true, showNodeSelectionBox: true }));\ngraph.use(new Snapline({ enabled: true }));\ngraph.use(new History({ enabled: true }));\ngraph.use(new Clipboard({ enabled: true }));\ngraph.use(new Keyboard({ enabled: true, global: true }));\n\ngraph.bindKey('ctrl+z', () => { graph.undo(); return false; });\ngraph.bindKey('ctrl+shift+z', () => { graph.redo(); return false; });\ngraph.bindKey('ctrl+c', () => { const cells = graph.getSelectedCells(); if (cells.length) graph.copy(cells); return false; });\ngraph.bindKey('ctrl+v', () => { if (!graph.isClipboardEmpty()) { const cells = graph.paste({ offset: 32 }); graph.cleanSelection(); graph.select(cells); } return false; });\ngraph.bindKey('delete', () => { const cells = graph.getSelectedCells(); if (cells.length) graph.removeCells(cells); return false; });\n\ngraph.addNode({\n x: 60, y: 60, width: 100, height: 40, label: 'Start',\n attrs: { body: { stroke: '#52c41a', strokeWidth: 2, fill: '#f6ffed', rx: 6, ry: 6 } },\n ports: {\n groups: { out: { position: 'bottom', attrs: { circle: { magnet: true, stroke: '#8f8f8f', r: 5 } } } },\n items: [{ id: 'out1', group: 'out' }],\n },\n});\n\ngraph.addNode({\n x: 60, y: 200, width: 100, height: 40, label: 'End',\n attrs: { body: { stroke: '#f5222d', strokeWidth: 2, fill: '#fff1f0', rx: 6, ry: 6 } },\n ports: {\n groups: { in: { position: 'top', attrs: { circle: { magnet: true, stroke: '#8f8f8f', r: 5 } } } },\n items: [{ id: 'in1', group: 'in' }],\n },\n});\n"
|
||
},
|
||
{
|
||
"description": "配置 Selection 插件的过滤功能,只允许选择特定类型的节点,圆形节点不可选。参考数据:[{\"shape\": \"rect\", \"label\": \"Selectable\", \"x\": 60, \"y\": 60, \"width\": 100, \"height\": 40}, {\"shape\": \"rect\", \"label\": \"Also Selectable\", \"x\": 260, \"y\": 60, \"width\": 100, \"height\": 40}, {\"shape\": \"circle\", \"label\": \"Not Selectable\", \"x\": 160, \"y\": 180, \"width\": 60, \"height\": 60}]",
|
||
"codeString": "import { Graph, Selection } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\ngraph.use(\n new Selection({\n enabled: true,\n multiple: true,\n rubberband: true,\n filter(cell) {\n return cell.shape !== 'circle';\n },\n }),\n);\n\ngraph.addNode({\n shape: 'rect',\n x: 60,\n y: 60,\n width: 100,\n height: 40,\n label: 'Selectable',\n attrs: {\n body: { stroke: '#1890ff', strokeWidth: 2, fill: '#e6f7ff', rx: 6, ry: 6 },\n },\n});\n\ngraph.addNode({\n shape: 'rect',\n x: 260,\n y: 60,\n width: 100,\n height: 40,\n label: 'Also Selectable',\n attrs: {\n body: { stroke: '#1890ff', strokeWidth: 2, fill: '#e6f7ff', rx: 6, ry: 6 },\n },\n});\n\ngraph.addNode({\n shape: 'circle',\n x: 160,\n y: 180,\n width: 60,\n height: 60,\n label: 'Not Selectable',\n attrs: {\n body: { stroke: '#f5222d', strokeWidth: 2, fill: '#fff1f0' },\n },\n});\n"
|
||
},
|
||
{
|
||
"description": "使用 History 插件的 batch 功能将多个操作合并为一次撤销步骤。参考数据:[{\"id\": \"node1\", \"shape\": \"rect\", \"label\": \"Node 1\", \"x\": 60, \"y\": 60, \"width\": 100, \"height\": 40}, {\"id\": \"node2\", \"shape\": \"rect\", \"label\": \"Node 2\", \"x\": 240, \"y\": 60, \"width\": 100, \"height\": 40}, {\"source\": \"node1\", \"target\": \"node2\"}]",
|
||
"codeString": "import { Graph, History } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\ngraph.use(new History({ enabled: true }));\n\nconst node1 = graph.addNode({\n shape: 'rect',\n x: 60,\n y: 60,\n width: 100,\n height: 40,\n label: 'Node 1',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\ngraph.startBatch('custom-batch');\n\nnode1.attr('body/fill', '#e6f7ff');\nnode1.attr('body/stroke', '#1890ff');\nnode1.prop('label', 'Updated');\n\nconst node2 = graph.addNode({\n shape: 'rect',\n x: 240,\n y: 60,\n width: 100,\n height: 40,\n label: 'Node 2',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\ngraph.addEdge({\n source: node1,\n target: node2,\n attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1 } },\n});\n\ngraph.stopBatch('custom-batch');\n"
|
||
},
|
||
{
|
||
"description": "配置 Snapline 插件的详细参数:吸附距离、是否显示尖锐线、是否在缩放时启用。参考数据:[{\"label\": \"Anchor 1\", \"x\": 80, \"y\": 60, \"width\": 100, \"height\": 40}, {\"label\": \"Anchor 2\", \"x\": 280, \"y\": 60, \"width\": 100, \"height\": 40}, {\"label\": \"Drag to align\", \"x\": 180, \"y\": 180, \"width\": 100, \"height\": 40}]",
|
||
"codeString": "import { Graph, Snapline } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n grid: { visible: true },\n});\n\ngraph.use(\n new Snapline({\n enabled: true,\n tolerance: 15,\n sharp: true,\n resizing: true,\n clean: 3000,\n }),\n);\n\ngraph.addNode({\n x: 80,\n y: 60,\n width: 100,\n height: 40,\n label: 'Anchor 1',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\ngraph.addNode({\n x: 280,\n y: 60,\n width: 100,\n height: 40,\n label: 'Anchor 2',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\ngraph.addNode({\n x: 180,\n y: 180,\n width: 100,\n height: 40,\n label: 'Drag to align',\n attrs: {\n body: { stroke: '#1890ff', strokeWidth: 2, fill: '#e6f7ff', rx: 6, ry: 6 },\n },\n});\n"
|
||
},
|
||
{
|
||
"description": "使用 Keyboard 和 Selection 插件实现快捷键删除选中节点、Ctrl+A 全选功能。参考数据:[{\"shape\": \"rect\", \"label\": \"Node \", \"x\": 40, \"y\": 40, \"width\": 100, \"height\": 40}]",
|
||
"codeString": "import { Graph, Keyboard, Selection } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\ngraph.use(new Selection({ enabled: true, multiple: true, rubberband: true, showNodeSelectionBox: true }));\ngraph.use(new Keyboard({ enabled: true, global: true }));\n\nfor (let i = 0; i < 4; i++) {\n graph.addNode({\n shape: 'rect',\n x: 40 + (i % 2) * 200,\n y: 40 + Math.floor(i / 2) * 120,\n width: 100,\n height: 40,\n label: 'Node ' + (i + 1),\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n });\n}\n\ngraph.bindKey('ctrl+a', () => {\n const nodes = graph.getNodes();\n graph.select(nodes);\n return false;\n});\n\ngraph.bindKey(['backspace', 'delete'], () => {\n const cells = graph.getSelectedCells();\n if (cells.length) {\n graph.removeCells(cells);\n }\n return false;\n});\n"
|
||
},
|
||
{
|
||
"description": "绑定多个组合快捷键:Ctrl+S 保存(toJSON)、Ctrl+D 复制选中节点、Ctrl+Shift+Z 重做。参考数据:[{\"label\": \"Try shortcuts\", \"x\": 100, \"y\": 60, \"width\": 120, \"height\": 50}]",
|
||
"codeString": "import { Graph, Keyboard, Selection, History } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\ngraph.use(new Selection({ enabled: true, showNodeSelectionBox: true }));\ngraph.use(new Keyboard({ enabled: true, global: true }));\ngraph.use(new History({ enabled: true }));\n\ngraph.addNode({\n x: 100,\n y: 60,\n width: 120,\n height: 50,\n label: 'Try shortcuts',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\ngraph.bindKey('ctrl+s', () => {\n const data = graph.toJSON();\n console.log('Saved:', JSON.stringify(data));\n return false;\n});\n\ngraph.bindKey('ctrl+d', () => {\n const cells = graph.getSelectedCells();\n if (cells.length) {\n const cloned = graph.cloneCells(cells);\n Object.values(cloned).forEach((cell) => {\n if (cell.isNode()) {\n cell.translate(30, 30);\n graph.addCell(cell);\n }\n });\n }\n return false;\n});\n\ngraph.bindKey('ctrl+z', () => { graph.undo(); return false; });\ngraph.bindKey('ctrl+shift+z', () => { graph.redo(); return false; });\n"
|
||
},
|
||
{
|
||
"description": "创建画布内容后,使用 graph.toPNG() 和 graph.toSVG() 方法将画布导出为图片。参考数据:[{\"id\": \"source\", \"shape\": \"rect\", \"label\": \"Export\", \"x\": 60, \"y\": 60, \"width\": 100, \"height\": 40}, {\"id\": \"target\", \"shape\": \"circle\", \"label\": \"Me\", \"x\": 260, \"y\": 100, \"width\": 60, \"height\": 60}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\nconst source = graph.addNode({\n shape: 'rect',\n x: 60,\n y: 60,\n width: 100,\n height: 40,\n label: 'Export',\n attrs: {\n body: { stroke: '#1890ff', strokeWidth: 2, fill: '#e6f7ff', rx: 6, ry: 6 },\n },\n});\n\nconst target = graph.addNode({\n shape: 'circle',\n x: 260,\n y: 100,\n width: 60,\n height: 60,\n label: 'Me',\n attrs: {\n body: { stroke: '#52c41a', strokeWidth: 2, fill: '#f6ffed' },\n },\n});\n\ngraph.addEdge({\n source,\n target,\n attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1, targetMarker: 'classic' } },\n});\n\ngraph.toPNG((dataUri) => {\n console.log('PNG exported:', dataUri.substring(0, 50) + '...');\n});\n"
|
||
},
|
||
{
|
||
"description": "演示如何动态启用和禁用插件功能,通过 disposePlugins 卸载插件后重新注册。参考数据:[{\"label\": \"Node A\", \"x\": 80, \"y\": 60, \"width\": 100, \"height\": 40}, {\"label\": \"Node B\", \"x\": 280, \"y\": 160, \"width\": 100, \"height\": 40}]",
|
||
"codeString": "import { Graph, Snapline, Selection } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\ngraph.use(new Snapline({ enabled: true }));\ngraph.use(new Selection({ enabled: true, rubberband: true, showNodeSelectionBox: true }));\n\ngraph.addNode({\n x: 80,\n y: 60,\n width: 100,\n height: 40,\n label: 'Node A',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\ngraph.addNode({\n x: 280,\n y: 160,\n width: 100,\n height: 40,\n label: 'Node B',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\ngraph.disableSnapline();\ngraph.disableSelection();\n\ngraph.enableSnapline();\ngraph.enableSelection();\n"
|
||
},
|
||
{
|
||
"description": "使用 X6 创建一个简单的审批流程图,包含开始、提交、判断(菱形)、通过、拒绝、结束六个节点,判断节点用 shape: \"polygon\" 配合 attrs.body.refPoints 绘制菱形,边带 targetMarker: \"classic\" 箭头。参考数据:[{\"id\": \"start\", \"shape\": \"circle\", \"label\": \"Start\", \"x\": 200, \"y\": 20, \"width\": 60, \"height\": 60}, {\"id\": \"apply\", \"shape\": \"rect\", \"label\": \"Submit\", \"x\": 185, \"y\": 120, \"width\": 100, \"height\": 40}, {\"id\": \"review\", \"shape\": \"polygon\", \"label\": \"Approve?\", \"x\": 190, \"y\": 200, \"width\": 80, \"height\": 80}, {\"id\": \"approved\", \"shape\": \"rect\", \"label\": \"Approved\", \"x\": 80, \"y\": 320, \"width\": 100, \"height\": 40}, {\"id\": \"rejected\", \"shape\": \"rect\", \"label\": \"Rejected\", \"x\": 290, \"y\": 320, \"width\": 100, \"height\": 40}, {\"id\": \"end\", \"shape\": \"circle\", \"label\": \"End\", \"x\": 200, \"y\": 420, \"width\": 60, \"height\": 60}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nGraph.registerNode(\n 'diamond',\n {\n inherit: 'polygon',\n width: 80,\n height: 80,\n attrs: {\n body: {\n refPoints: '0,10 10,0 20,10 10,20',\n fill: '#fff',\n stroke: '#8f8f8f',\n strokeWidth: 1,\n },\n label: {\n textAnchor: 'middle',\n textVerticalAnchor: 'middle',\n refX: '50%',\n refY: '50%',\n fontSize: 12,\n },\n },\n },\n true,\n);\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n grid: { visible: true },\n});\n\nconst start = graph.addNode({\n shape: 'circle',\n x: 200,\n y: 20,\n width: 60,\n height: 60,\n label: 'Start',\n attrs: { body: { stroke: '#52c41a', strokeWidth: 2, fill: '#f6ffed' } },\n});\n\nconst apply = graph.addNode({\n shape: 'rect',\n x: 185,\n y: 120,\n width: 100,\n height: 40,\n label: 'Submit',\n attrs: { body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 } },\n});\n\nconst review = graph.addNode({\n shape: 'diamond',\n x: 190,\n y: 200,\n width: 80,\n height: 80,\n label: 'Approve?',\n});\n\nconst approved = graph.addNode({\n shape: 'rect',\n x: 80,\n y: 320,\n width: 100,\n height: 40,\n label: 'Approved',\n attrs: { body: { stroke: '#52c41a', strokeWidth: 2, fill: '#f6ffed', rx: 6, ry: 6 } },\n});\n\nconst rejected = graph.addNode({\n shape: 'rect',\n x: 290,\n y: 320,\n width: 100,\n height: 40,\n label: 'Rejected',\n attrs: { body: { stroke: '#f5222d', strokeWidth: 2, fill: '#fff1f0', rx: 6, ry: 6 } },\n});\n\nconst end = graph.addNode({\n shape: 'circle',\n x: 200,\n y: 420,\n width: 60,\n height: 60,\n label: 'End',\n attrs: { body: { stroke: '#f5222d', strokeWidth: 2, fill: '#fff1f0' } },\n});\n\ngraph.addEdge({ source: start, target: apply, attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1, targetMarker: 'classic' } } });\ngraph.addEdge({ source: apply, target: review, attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1, targetMarker: 'classic' } } });\ngraph.addEdge({ source: review, target: approved, label: 'Yes', attrs: { line: { stroke: '#52c41a', strokeWidth: 1, targetMarker: 'classic' } } });\ngraph.addEdge({ source: review, target: rejected, label: 'No', attrs: { line: { stroke: '#f5222d', strokeWidth: 1, targetMarker: 'classic' } } });\ngraph.addEdge({ source: approved, target: end, attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1, targetMarker: 'classic' } } });\ngraph.addEdge({ source: rejected, target: end, attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1, targetMarker: 'classic' } } });\n\ngraph.centerContent();\n"
|
||
},
|
||
{
|
||
"description": "创建一个 DAG(有向无环图)数据管道,包含数据源、ETL处理、数据仓库、报表四个阶段,节点带有输入输出端口。参考数据:[{\"id\": \"out1\", \"shape\": \"dag-node\", \"label\": \"MySQL Source\", \"x\": 40, \"y\": 40}, {\"id\": \"out1\", \"shape\": \"dag-node\", \"label\": \"Kafka Source\", \"x\": 40, \"y\": 140}, {\"id\": \"in1\", \"shape\": \"dag-node\", \"label\": \"ETL Transform\", \"x\": 260, \"y\": 90}, {\"id\": \"in1\", \"shape\": \"dag-node\", \"label\": \"Data Warehouse\", \"x\": 480, \"y\": 90}, {\"id\": \"in1\", \"shape\": \"dag-node\", \"label\": \"Report Dashboard\", \"x\": 700, \"y\": 90}, {\"source\": \"source1\", \"target\": \"etl\"}, {\"source\": \"source2\", \"target\": \"etl\"}, {\"source\": \"etl\", \"target\": \"warehouse\"}, {\"source\": \"warehouse\", \"target\": \"report\"}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nGraph.registerNode(\n 'dag-node',\n {\n inherit: 'rect',\n width: 140,\n height: 50,\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n ports: {\n groups: {\n in: { position: 'left', attrs: { circle: { magnet: true, stroke: '#1890ff', r: 5, fill: '#fff' } } },\n out: { position: 'right', attrs: { circle: { magnet: true, stroke: '#1890ff', r: 5, fill: '#fff' } } },\n },\n },\n },\n true,\n);\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n grid: { visible: true },\n panning: true,\n connecting: {\n allowBlank: false,\n connector: 'rounded',\n router: 'orth',\n },\n});\n\nconst source1 = graph.addNode({\n shape: 'dag-node', x: 40, y: 40, label: 'MySQL Source',\n ports: { items: [{ id: 'out1', group: 'out' }] },\n});\n\nconst source2 = graph.addNode({\n shape: 'dag-node', x: 40, y: 140, label: 'Kafka Source',\n ports: { items: [{ id: 'out1', group: 'out' }] },\n});\n\nconst etl = graph.addNode({\n shape: 'dag-node', x: 260, y: 90, label: 'ETL Transform',\n ports: { items: [{ id: 'in1', group: 'in' }, { id: 'in2', group: 'in' }, { id: 'out1', group: 'out' }] },\n});\n\nconst warehouse = graph.addNode({\n shape: 'dag-node', x: 480, y: 90, label: 'Data Warehouse',\n ports: { items: [{ id: 'in1', group: 'in' }, { id: 'out1', group: 'out' }] },\n});\n\nconst report = graph.addNode({\n shape: 'dag-node', x: 700, y: 90, label: 'Report Dashboard',\n ports: { items: [{ id: 'in1', group: 'in' }] },\n});\n\ngraph.addEdge({ source: { cell: source1, port: 'out1' }, target: { cell: etl, port: 'in1' }, attrs: { line: { stroke: '#1890ff', strokeWidth: 1, targetMarker: 'classic' } } });\ngraph.addEdge({ source: { cell: source2, port: 'out1' }, target: { cell: etl, port: 'in2' }, attrs: { line: { stroke: '#1890ff', strokeWidth: 1, targetMarker: 'classic' } } });\ngraph.addEdge({ source: { cell: etl, port: 'out1' }, target: { cell: warehouse, port: 'in1' }, attrs: { line: { stroke: '#1890ff', strokeWidth: 1, targetMarker: 'classic' } } });\ngraph.addEdge({ source: { cell: warehouse, port: 'out1' }, target: { cell: report, port: 'in1' }, attrs: { line: { stroke: '#1890ff', strokeWidth: 1, targetMarker: 'classic' } } });\n"
|
||
},
|
||
{
|
||
"description": "创建一个简单的 ER 实体关系图,包含 User、Order、Product 三个实体表,每个表显示字段名和类型。参考数据:[{\"id\": \"user\", \"shape\": \"er-entity\", \"x\": 40, \"y\": 60}, {\"id\": \"order\", \"shape\": \"er-entity\", \"x\": 300, \"y\": 40}, {\"id\": \"product\", \"shape\": \"er-entity\", \"label\": \"1:N\", \"x\": 300, \"y\": 220}, {\"source\": \"user\", \"target\": \"order\", \"label\": \"1:N\"}, {\"source\": \"product\", \"target\": \"order\", \"label\": \"1:N\"}]",
|
||
"codeString": "import { Graph, Shape } from '@antv/x6';\n\nShape.HTML.register({\n shape: 'er-entity',\n width: 180,\n height: 120,\n effect: ['data'],\n html(cell) {\n const data = cell.getData() || {};\n const div = document.createElement('div');\n div.style.cssText = 'width:100%;height:100%;border:1px solid #8f8f8f;border-radius:4px;overflow:hidden;font-size:12px;background:#fff;';\n const header = '<div style=\"background:#1890ff;color:#fff;padding:6px 8px;font-weight:bold;\">' + (data.name || 'Entity') + '</div>';\n const fields = (data.fields || []).map(f => '<div style=\"padding:4px 8px;border-top:1px solid #eee;\">' + f.name + ' <span style=\"color:#999\">' + f.type + '</span></div>').join('');\n div.innerHTML = header + fields;\n return div;\n },\n});\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n panning: true,\n});\n\nconst user = graph.addNode({\n shape: 'er-entity',\n x: 40,\n y: 60,\n data: {\n name: 'User',\n fields: [\n { name: 'id', type: 'INT PK' },\n { name: 'name', type: 'VARCHAR' },\n { name: 'email', type: 'VARCHAR' },\n ],\n },\n});\n\nconst order = graph.addNode({\n shape: 'er-entity',\n x: 300,\n y: 40,\n data: {\n name: 'Order',\n fields: [\n { name: 'id', type: 'INT PK' },\n { name: 'user_id', type: 'INT FK' },\n { name: 'product_id', type: 'INT FK' },\n { name: 'amount', type: 'DECIMAL' },\n ],\n },\n});\n\nconst product = graph.addNode({\n shape: 'er-entity',\n x: 300,\n y: 220,\n data: {\n name: 'Product',\n fields: [\n { name: 'id', type: 'INT PK' },\n { name: 'name', type: 'VARCHAR' },\n { name: 'price', type: 'DECIMAL' },\n ],\n },\n});\n\ngraph.addEdge({\n source: user,\n target: order,\n label: '1:N',\n router: 'orth',\n connector: 'rounded',\n attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1, targetMarker: 'classic' } },\n});\n\ngraph.addEdge({\n source: product,\n target: order,\n label: '1:N',\n router: 'orth',\n connector: 'rounded',\n attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1, targetMarker: 'classic' } },\n});\n"
|
||
},
|
||
{
|
||
"description": "创建一个数据血缘图,展示数据从源表经过多层加工到最终报表的流转关系,使用左右布局。参考数据:[{\"id\": \"out1\", \"shape\": \"lineage-node\", \"label\": \"ods_user\", \"x\": 40, \"y\": 40}, {\"id\": \"out1\", \"shape\": \"lineage-node\", \"label\": \"ods_order\", \"x\": 40, \"y\": 120}, {\"id\": \"out1\", \"shape\": \"lineage-node\", \"label\": \"ods_product\", \"x\": 40, \"y\": 200}, {\"id\": \"in1\", \"shape\": \"lineage-node\", \"label\": \"dwd_order_detail\", \"x\": 260, \"y\": 80}, {\"id\": \"in1\", \"shape\": \"lineage-node\", \"label\": \"dwd_user_profile\", \"x\": 260, \"y\": 160}, {\"id\": \"in1\", \"shape\": \"lineage-node\", \"label\": \"dws_sales_summary\", \"x\": 480, \"y\": 120}, {\"id\": \"in1\", \"shape\": \"lineage-node\", \"label\": \"ads_dashboard\", \"x\": 700, \"y\": 120}, {\"source\": \"srcA\", \"target\": \"dwd2\"}, {\"source\": \"srcB\", \"target\": \"dwd1\"}, {\"source\": \"srcC\", \"target\": \"dwd1\"}, {\"source\": \"dwd1\", \"target\": \"dws\"}, {\"source\": \"dwd2\", \"target\": \"dws\"}, {\"source\": \"dws\", \"target\": \"ads\"}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nGraph.registerNode(\n 'lineage-node',\n {\n inherit: 'rect',\n width: 140,\n height: 40,\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 4, ry: 4 },\n },\n ports: {\n groups: {\n in: { position: 'left', attrs: { circle: { magnet: true, stroke: '#8f8f8f', r: 4, fill: '#fff' } } },\n out: { position: 'right', attrs: { circle: { magnet: true, stroke: '#8f8f8f', r: 4, fill: '#fff' } } },\n },\n },\n },\n true,\n);\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n panning: true,\n});\n\nconst srcA = graph.addNode({ shape: 'lineage-node', x: 40, y: 40, label: 'ods_user', ports: { items: [{ id: 'out1', group: 'out' }] } });\nconst srcB = graph.addNode({ shape: 'lineage-node', x: 40, y: 120, label: 'ods_order', ports: { items: [{ id: 'out1', group: 'out' }] } });\nconst srcC = graph.addNode({ shape: 'lineage-node', x: 40, y: 200, label: 'ods_product', ports: { items: [{ id: 'out1', group: 'out' }] } });\n\nconst dwd1 = graph.addNode({ shape: 'lineage-node', x: 260, y: 80, label: 'dwd_order_detail', attrs: { body: { fill: '#e6f7ff' } }, ports: { items: [{ id: 'in1', group: 'in' }, { id: 'in2', group: 'in' }, { id: 'out1', group: 'out' }] } });\nconst dwd2 = graph.addNode({ shape: 'lineage-node', x: 260, y: 160, label: 'dwd_user_profile', attrs: { body: { fill: '#e6f7ff' } }, ports: { items: [{ id: 'in1', group: 'in' }, { id: 'out1', group: 'out' }] } });\n\nconst dws = graph.addNode({ shape: 'lineage-node', x: 480, y: 120, label: 'dws_sales_summary', attrs: { body: { fill: '#f6ffed' } }, ports: { items: [{ id: 'in1', group: 'in' }, { id: 'in2', group: 'in' }, { id: 'out1', group: 'out' }] } });\n\nconst ads = graph.addNode({ shape: 'lineage-node', x: 700, y: 120, label: 'ads_dashboard', attrs: { body: { fill: '#fff7e6' } }, ports: { items: [{ id: 'in1', group: 'in' }] } });\n\ngraph.addEdge({ source: { cell: srcA, port: 'out1' }, target: { cell: dwd2, port: 'in1' }, connector: 'smooth', attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1 } } });\ngraph.addEdge({ source: { cell: srcB, port: 'out1' }, target: { cell: dwd1, port: 'in1' }, connector: 'smooth', attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1 } } });\ngraph.addEdge({ source: { cell: srcC, port: 'out1' }, target: { cell: dwd1, port: 'in2' }, connector: 'smooth', attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1 } } });\ngraph.addEdge({ source: { cell: dwd1, port: 'out1' }, target: { cell: dws, port: 'in1' }, connector: 'smooth', attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1 } } });\ngraph.addEdge({ source: { cell: dwd2, port: 'out1' }, target: { cell: dws, port: 'in2' }, connector: 'smooth', attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1 } } });\ngraph.addEdge({ source: { cell: dws, port: 'out1' }, target: { cell: ads, port: 'in1' }, connector: 'smooth', attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1 } } });\n"
|
||
},
|
||
{
|
||
"description": "创建一个订单状态机图,包含待支付、已支付、发货中、已完成、已取消五个状态及其转换关系。参考数据:[{\"id\": \"pending\", \"shape\": \"circle\", \"label\": \"Pending\", \"x\": 60, \"y\": 120, \"width\": 70, \"height\": 70}, {\"id\": \"paid\", \"shape\": \"circle\", \"label\": \"Paid\", \"x\": 200, \"y\": 120, \"width\": 70, \"height\": 70}, {\"id\": \"shipping\", \"shape\": \"circle\", \"label\": \"Shipping\", \"x\": 340, \"y\": 120, \"width\": 70, \"height\": 70}, {\"id\": \"completed\", \"shape\": \"circle\", \"label\": \"Done\", \"x\": 480, \"y\": 120, \"width\": 70, \"height\": 70}, {\"id\": \"cancelled\", \"shape\": \"circle\", \"label\": \"Cancel\", \"x\": 200, \"y\": 260, \"width\": 70, \"height\": 70}, {\"source\": \"pending\", \"target\": \"paid\", \"label\": \"pay\"}, {\"source\": \"paid\", \"target\": \"shipping\", \"label\": \"ship\"}, {\"source\": \"shipping\", \"target\": \"completed\", \"label\": \"confirm\"}, {\"source\": \"pending\", \"target\": \"cancelled\", \"label\": \"cancel\"}, {\"source\": \"paid\", \"target\": \"cancelled\", \"label\": \"refund\"}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n grid: { visible: true },\n});\n\nconst pending = graph.addNode({\n shape: 'circle', x: 60, y: 120, width: 70, height: 70, label: 'Pending',\n attrs: { body: { stroke: '#fa8c16', strokeWidth: 2, fill: '#fff7e6' } },\n});\n\nconst paid = graph.addNode({\n shape: 'circle', x: 200, y: 120, width: 70, height: 70, label: 'Paid',\n attrs: { body: { stroke: '#1890ff', strokeWidth: 2, fill: '#e6f7ff' } },\n});\n\nconst shipping = graph.addNode({\n shape: 'circle', x: 340, y: 120, width: 70, height: 70, label: 'Shipping',\n attrs: { body: { stroke: '#722ed1', strokeWidth: 2, fill: '#f9f0ff' } },\n});\n\nconst completed = graph.addNode({\n shape: 'circle', x: 480, y: 120, width: 70, height: 70, label: 'Done',\n attrs: { body: { stroke: '#52c41a', strokeWidth: 2, fill: '#f6ffed' } },\n});\n\nconst cancelled = graph.addNode({\n shape: 'circle', x: 200, y: 260, width: 70, height: 70, label: 'Cancel',\n attrs: { body: { stroke: '#f5222d', strokeWidth: 2, fill: '#fff1f0' } },\n});\n\ngraph.addEdge({ source: pending, target: paid, label: 'pay', attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1, targetMarker: 'classic' } } });\ngraph.addEdge({ source: paid, target: shipping, label: 'ship', attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1, targetMarker: 'classic' } } });\ngraph.addEdge({ source: shipping, target: completed, label: 'confirm', attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1, targetMarker: 'classic' } } });\ngraph.addEdge({ source: pending, target: cancelled, label: 'cancel', attrs: { line: { stroke: '#f5222d', strokeWidth: 1, targetMarker: 'classic' } } });\ngraph.addEdge({ source: paid, target: cancelled, label: 'refund', attrs: { line: { stroke: '#f5222d', strokeWidth: 1, targetMarker: 'classic' } } });\n"
|
||
},
|
||
{
|
||
"description": "创建一个简单的组织架构图,CEO 在顶部,下设 CTO、CFO 两个副总,CTO 下有两个团队 Leader。参考数据:[{\"id\": \"ceo\", \"shape\": \"rect\", \"label\": \"CEO\", \"x\": 220, \"y\": 20, \"width\": 120, \"height\": 40}, {\"id\": \"cto\", \"shape\": \"rect\", \"label\": \"CTO\", \"x\": 100, \"y\": 120, \"width\": 120, \"height\": 40}, {\"id\": \"cfo\", \"shape\": \"rect\", \"label\": \"CFO\", \"x\": 340, \"y\": 120, \"width\": 120, \"height\": 40}, {\"id\": \"leader1\", \"shape\": \"rect\", \"label\": \"FE Leader\", \"x\": 40, \"y\": 220, \"width\": 120, \"height\": 40}, {\"id\": \"leader2\", \"shape\": \"rect\", \"label\": \"BE Leader\", \"x\": 200, \"y\": 220, \"width\": 120, \"height\": 40}, {\"source\": \"ceo\", \"target\": \"cto\"}, {\"source\": \"ceo\", \"target\": \"cfo\"}, {\"source\": \"cto\", \"target\": \"leader1\"}, {\"source\": \"cto\", \"target\": \"leader2\"}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\nconst ceo = graph.addNode({\n shape: 'rect', x: 220, y: 20, width: 120, height: 40, label: 'CEO',\n attrs: { body: { stroke: '#722ed1', strokeWidth: 2, fill: '#f9f0ff', rx: 20, ry: 20 } },\n});\n\nconst cto = graph.addNode({\n shape: 'rect', x: 100, y: 120, width: 120, height: 40, label: 'CTO',\n attrs: { body: { stroke: '#1890ff', strokeWidth: 2, fill: '#e6f7ff', rx: 20, ry: 20 } },\n});\n\nconst cfo = graph.addNode({\n shape: 'rect', x: 340, y: 120, width: 120, height: 40, label: 'CFO',\n attrs: { body: { stroke: '#52c41a', strokeWidth: 2, fill: '#f6ffed', rx: 20, ry: 20 } },\n});\n\nconst leader1 = graph.addNode({\n shape: 'rect', x: 40, y: 220, width: 120, height: 40, label: 'FE Leader',\n attrs: { body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 } },\n});\n\nconst leader2 = graph.addNode({\n shape: 'rect', x: 200, y: 220, width: 120, height: 40, label: 'BE Leader',\n attrs: { body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 } },\n});\n\ngraph.addEdge({ source: ceo, target: cto, router: 'orth', attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1, targetMarker: 'classic' } } });\ngraph.addEdge({ source: ceo, target: cfo, router: 'orth', attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1, targetMarker: 'classic' } } });\ngraph.addEdge({ source: cto, target: leader1, router: 'orth', attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1, targetMarker: 'classic' } } });\ngraph.addEdge({ source: cto, target: leader2, router: 'orth', attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1, targetMarker: 'classic' } } });\n\ngraph.centerContent();\n"
|
||
},
|
||
{
|
||
"description": "创建一个微服务架构图,展示 Gateway、User Service、Order Service、Payment Service 之间的调用关系。参考数据:[{\"id\": \"gateway\", \"shape\": \"rect\", \"label\": \"API Gateway\", \"x\": 220, \"y\": 20, \"width\": 140, \"height\": 50}, {\"id\": \"userSvc\", \"shape\": \"rect\", \"label\": \"User Service\", \"x\": 60, \"y\": 140, \"width\": 140, \"height\": 50}, {\"id\": \"orderSvc\", \"shape\": \"rect\", \"label\": \"Order Service\", \"x\": 260, \"y\": 140, \"width\": 140, \"height\": 50}, {\"id\": \"paymentSvc\", \"shape\": \"rect\", \"label\": \"Payment Service\", \"x\": 460, \"y\": 140, \"width\": 140, \"height\": 50}, {\"id\": \"db\", \"shape\": \"rect\", \"label\": \"Database\", \"x\": 180, \"y\": 280, \"width\": 120, \"height\": 40}, {\"id\": \"cache\", \"shape\": \"rect\", \"label\": \"Redis Cache\", \"x\": 380, \"y\": 280, \"width\": 120, \"height\": 40}, {\"source\": \"gateway\", \"target\": \"userSvc\"}, {\"source\": \"gateway\", \"target\": \"orderSvc\", \"label\": \"query user\"}, {\"source\": \"gateway\", \"target\": \"paymentSvc\", \"label\": \"query user\"}, {\"source\": \"orderSvc\", \"target\": \"userSvc\", \"label\": \"query user\"}, {\"source\": \"orderSvc\", \"target\": \"paymentSvc\", \"label\": \"create payment\"}, {\"source\": \"userSvc\", \"target\": \"db\"}, {\"source\": \"orderSvc\", \"target\": \"db\"}, {\"source\": \"paymentSvc\", \"target\": \"cache\"}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n grid: { visible: true },\n});\n\nconst gateway = graph.addNode({\n shape: 'rect', x: 220, y: 20, width: 140, height: 50, label: 'API Gateway',\n attrs: { body: { stroke: '#722ed1', strokeWidth: 2, fill: '#f9f0ff', rx: 6, ry: 6 } },\n});\n\nconst userSvc = graph.addNode({\n shape: 'rect', x: 60, y: 140, width: 140, height: 50, label: 'User Service',\n attrs: { body: { stroke: '#1890ff', strokeWidth: 2, fill: '#e6f7ff', rx: 6, ry: 6 } },\n});\n\nconst orderSvc = graph.addNode({\n shape: 'rect', x: 260, y: 140, width: 140, height: 50, label: 'Order Service',\n attrs: { body: { stroke: '#52c41a', strokeWidth: 2, fill: '#f6ffed', rx: 6, ry: 6 } },\n});\n\nconst paymentSvc = graph.addNode({\n shape: 'rect', x: 460, y: 140, width: 140, height: 50, label: 'Payment Service',\n attrs: { body: { stroke: '#fa8c16', strokeWidth: 2, fill: '#fff7e6', rx: 6, ry: 6 } },\n});\n\nconst db = graph.addNode({\n shape: 'rect', x: 180, y: 280, width: 120, height: 40, label: 'Database',\n attrs: { body: { stroke: '#8f8f8f', strokeWidth: 2, fill: '#f0f0f0', rx: 6, ry: 6 } },\n});\n\nconst cache = graph.addNode({\n shape: 'rect', x: 380, y: 280, width: 120, height: 40, label: 'Redis Cache',\n attrs: { body: { stroke: '#f5222d', strokeWidth: 2, fill: '#fff1f0', rx: 6, ry: 6 } },\n});\n\ngraph.addEdge({ source: gateway, target: userSvc, attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1, targetMarker: 'classic' } } });\ngraph.addEdge({ source: gateway, target: orderSvc, attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1, targetMarker: 'classic' } } });\ngraph.addEdge({ source: gateway, target: paymentSvc, attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1, targetMarker: 'classic' } } });\ngraph.addEdge({ source: orderSvc, target: userSvc, label: 'query user', attrs: { line: { stroke: '#aaa', strokeWidth: 1, strokeDasharray: '5 3', targetMarker: 'classic' } } });\ngraph.addEdge({ source: orderSvc, target: paymentSvc, label: 'create payment', attrs: { line: { stroke: '#aaa', strokeWidth: 1, strokeDasharray: '5 3', targetMarker: 'classic' } } });\ngraph.addEdge({ source: userSvc, target: db, attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1, targetMarker: 'classic' } } });\ngraph.addEdge({ source: orderSvc, target: db, attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1, targetMarker: 'classic' } } });\ngraph.addEdge({ source: paymentSvc, target: cache, attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1, targetMarker: 'classic' } } });\n"
|
||
},
|
||
{
|
||
"description": "创建一个泳道图:用三个大矩形(背景色淡蓝/淡绿/淡黄)作为部门泳道,在泳道上叠加流程节点展示跨部门协作。泳道节点设置较小 zIndex 让流程节点显示在上层。参考数据:[{\"id\": \"lane1\", \"shape\": \"rect\", \"label\": \"Sales Dept\", \"x\": 20, \"y\": 20, \"width\": 560, \"height\": 100}, {\"id\": \"lane2\", \"shape\": \"rect\", \"label\": \"Tech Dept\", \"x\": 20, \"y\": 130, \"width\": 560, \"height\": 100}, {\"id\": \"lane3\", \"shape\": \"rect\", \"label\": \"Finance Dept\", \"x\": 20, \"y\": 240, \"width\": 560, \"height\": 100}, {\"id\": \"task1\", \"shape\": \"rect\", \"label\": \"Receive Order\", \"x\": 140, \"y\": 50, \"width\": 100, \"height\": 36}, {\"id\": \"task2\", \"shape\": \"rect\", \"label\": \"Develop\", \"x\": 300, \"y\": 160, \"width\": 100, \"height\": 36}, {\"id\": \"task3\", \"shape\": \"rect\", \"label\": \"Invoice\", \"x\": 460, \"y\": 270, \"width\": 100, \"height\": 36}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\nconst lane1 = graph.addNode({\n shape: 'rect', x: 20, y: 20, width: 560, height: 100, zIndex: 0,\n label: 'Sales Dept', attrs: { body: { fill: '#e6f7ff', stroke: '#91d5ff', rx: 6, ry: 6 }, label: { refX: 30, refY: 0.5, textAnchor: 'start' } },\n});\n\nconst lane2 = graph.addNode({\n shape: 'rect', x: 20, y: 130, width: 560, height: 100, zIndex: 0,\n label: 'Tech Dept', attrs: { body: { fill: '#f6ffed', stroke: '#b7eb8f', rx: 6, ry: 6 }, label: { refX: 30, refY: 0.5, textAnchor: 'start' } },\n});\n\nconst lane3 = graph.addNode({\n shape: 'rect', x: 20, y: 240, width: 560, height: 100, zIndex: 0,\n label: 'Finance Dept', attrs: { body: { fill: '#fff7e6', stroke: '#ffd591', rx: 6, ry: 6 }, label: { refX: 30, refY: 0.5, textAnchor: 'start' } },\n});\n\nconst task1 = graph.addNode({\n shape: 'rect', x: 140, y: 50, width: 100, height: 36, zIndex: 2, label: 'Receive Order',\n attrs: { body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 4, ry: 4 } },\n});\n\nconst task2 = graph.addNode({\n shape: 'rect', x: 300, y: 160, width: 100, height: 36, zIndex: 2, label: 'Develop',\n attrs: { body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 4, ry: 4 } },\n});\n\nconst task3 = graph.addNode({\n shape: 'rect', x: 460, y: 270, width: 100, height: 36, zIndex: 2, label: 'Invoice',\n attrs: { body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 4, ry: 4 } },\n});\n\ngraph.addEdge({ source: task1, target: task2, router: 'orth', connector: 'rounded', attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1, targetMarker: 'classic' } } });\ngraph.addEdge({ source: task2, target: task3, router: 'orth', connector: 'rounded', attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1, targetMarker: 'classic' } } });\n"
|
||
},
|
||
{
|
||
"description": "创建一个 CI/CD 流水线的 DAG 图,包含 Build、Test、Deploy 等阶段,支持并行任务。参考数据:[{\"id\": \"build\", \"shape\": \"rect\", \"label\": \"Build\", \"x\": 60, \"y\": 100, \"width\": 100, \"height\": 40}, {\"id\": \"unitTest\", \"shape\": \"rect\", \"label\": \"Unit Test\", \"x\": 220, \"y\": 50, \"width\": 100, \"height\": 40}, {\"id\": \"lint\", \"shape\": \"rect\", \"label\": \"Lint\", \"x\": 220, \"y\": 150, \"width\": 100, \"height\": 40}, {\"id\": \"integTest\", \"shape\": \"rect\", \"label\": \"Integration Test\", \"x\": 380, \"y\": 100, \"width\": 120, \"height\": 40}, {\"id\": \"deploy\", \"shape\": \"rect\", \"label\": \"Deploy\", \"x\": 560, \"y\": 100, \"width\": 100, \"height\": 40}, {\"source\": \"build\", \"target\": \"unitTest\"}, {\"source\": \"build\", \"target\": \"lint\"}, {\"source\": \"unitTest\", \"target\": \"integTest\"}, {\"source\": \"lint\", \"target\": \"integTest\"}, {\"source\": \"integTest\", \"target\": \"deploy\"}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n grid: { visible: true },\n});\n\nconst build = graph.addNode({\n shape: 'rect', x: 60, y: 100, width: 100, height: 40, label: 'Build',\n attrs: { body: { stroke: '#1890ff', strokeWidth: 2, fill: '#e6f7ff', rx: 6, ry: 6 } },\n});\n\nconst unitTest = graph.addNode({\n shape: 'rect', x: 220, y: 50, width: 100, height: 40, label: 'Unit Test',\n attrs: { body: { stroke: '#52c41a', strokeWidth: 2, fill: '#f6ffed', rx: 6, ry: 6 } },\n});\n\nconst lint = graph.addNode({\n shape: 'rect', x: 220, y: 150, width: 100, height: 40, label: 'Lint',\n attrs: { body: { stroke: '#52c41a', strokeWidth: 2, fill: '#f6ffed', rx: 6, ry: 6 } },\n});\n\nconst integTest = graph.addNode({\n shape: 'rect', x: 380, y: 100, width: 120, height: 40, label: 'Integration Test',\n attrs: { body: { stroke: '#fa8c16', strokeWidth: 2, fill: '#fff7e6', rx: 6, ry: 6 } },\n});\n\nconst deploy = graph.addNode({\n shape: 'rect', x: 560, y: 100, width: 100, height: 40, label: 'Deploy',\n attrs: { body: { stroke: '#722ed1', strokeWidth: 2, fill: '#f9f0ff', rx: 6, ry: 6 } },\n});\n\ngraph.addEdge({ source: build, target: unitTest, attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1, targetMarker: 'classic' } } });\ngraph.addEdge({ source: build, target: lint, attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1, targetMarker: 'classic' } } });\ngraph.addEdge({ source: unitTest, target: integTest, attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1, targetMarker: 'classic' } } });\ngraph.addEdge({ source: lint, target: integTest, attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1, targetMarker: 'classic' } } });\ngraph.addEdge({ source: integTest, target: deploy, attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1, targetMarker: 'classic' } } });\n"
|
||
},
|
||
{
|
||
"description": "创建一个简单的网络拓扑图,包含路由器、交换机和多台终端设备,呈星型拓扑结构。参考数据:[{\"id\": \"router\", \"shape\": \"circle\", \"label\": \"Router\", \"x\": 240, \"y\": 20, \"width\": 70, \"height\": 70}, {\"id\": \"switch1\", \"shape\": \"rect\", \"label\": \"Switch A\", \"x\": 120, \"y\": 140, \"width\": 100, \"height\": 40}, {\"id\": \"switch2\", \"shape\": \"rect\", \"label\": \"Switch B\", \"x\": 340, \"y\": 140, \"width\": 100, \"height\": 40}, {\"id\": \"pc1\", \"shape\": \"rect\", \"label\": \"PC-1\", \"x\": 40, \"y\": 260, \"width\": 80, \"height\": 36}, {\"id\": \"pc2\", \"shape\": \"rect\", \"label\": \"PC-2\", \"x\": 140, \"y\": 260, \"width\": 80, \"height\": 36}, {\"id\": \"pc3\", \"shape\": \"rect\", \"label\": \"Server-1\", \"x\": 300, \"y\": 260, \"width\": 80, \"height\": 36}, {\"id\": \"pc4\", \"shape\": \"rect\", \"label\": \"Server-2\", \"x\": 400, \"y\": 260, \"width\": 80, \"height\": 36}, {\"source\": \"router\", \"target\": \"switch1\"}, {\"source\": \"router\", \"target\": \"switch2\"}, {\"source\": \"switch1\", \"target\": \"pc1\"}, {\"source\": \"switch1\", \"target\": \"pc2\"}, {\"source\": \"switch2\", \"target\": \"pc3\"}, {\"source\": \"switch2\", \"target\": \"pc4\"}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\nconst router = graph.addNode({\n shape: 'circle', x: 240, y: 20, width: 70, height: 70, label: 'Router',\n attrs: { body: { stroke: '#722ed1', strokeWidth: 2, fill: '#f9f0ff' } },\n});\n\nconst switch1 = graph.addNode({\n shape: 'rect', x: 120, y: 140, width: 100, height: 40, label: 'Switch A',\n attrs: { body: { stroke: '#1890ff', strokeWidth: 2, fill: '#e6f7ff', rx: 6, ry: 6 } },\n});\n\nconst switch2 = graph.addNode({\n shape: 'rect', x: 340, y: 140, width: 100, height: 40, label: 'Switch B',\n attrs: { body: { stroke: '#1890ff', strokeWidth: 2, fill: '#e6f7ff', rx: 6, ry: 6 } },\n});\n\nconst pc1 = graph.addNode({ shape: 'rect', x: 40, y: 260, width: 80, height: 36, label: 'PC-1', attrs: { body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 4, ry: 4 } } });\nconst pc2 = graph.addNode({ shape: 'rect', x: 140, y: 260, width: 80, height: 36, label: 'PC-2', attrs: { body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 4, ry: 4 } } });\nconst pc3 = graph.addNode({ shape: 'rect', x: 300, y: 260, width: 80, height: 36, label: 'Server-1', attrs: { body: { stroke: '#52c41a', strokeWidth: 1, fill: '#f6ffed', rx: 4, ry: 4 } } });\nconst pc4 = graph.addNode({ shape: 'rect', x: 400, y: 260, width: 80, height: 36, label: 'Server-2', attrs: { body: { stroke: '#52c41a', strokeWidth: 1, fill: '#f6ffed', rx: 4, ry: 4 } } });\n\ngraph.addEdge({ source: router, target: switch1, attrs: { line: { stroke: '#8f8f8f', strokeWidth: 2 } } });\ngraph.addEdge({ source: router, target: switch2, attrs: { line: { stroke: '#8f8f8f', strokeWidth: 2 } } });\ngraph.addEdge({ source: switch1, target: pc1, attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1 } } });\ngraph.addEdge({ source: switch1, target: pc2, attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1 } } });\ngraph.addEdge({ source: switch2, target: pc3, attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1 } } });\ngraph.addEdge({ source: switch2, target: pc4, attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1 } } });\n\ngraph.centerContent();\n"
|
||
},
|
||
{
|
||
"description": "创建一个简单的决策树图,从根节点开始通过条件分支达到不同的叶子结果节点。参考数据:[{\"id\": \"root\", \"shape\": \"rect\", \"label\": \"Age > 30?\", \"x\": 220, \"y\": 20, \"width\": 120, \"height\": 40}, {\"id\": \"leftChild\", \"shape\": \"rect\", \"label\": \"Income > 50k?\", \"x\": 80, \"y\": 120, \"width\": 120, \"height\": 40}, {\"id\": \"rightChild\", \"shape\": \"rect\", \"label\": \"Student?\", \"x\": 360, \"y\": 120, \"width\": 120, \"height\": 40}, {\"id\": \"leaf1\", \"shape\": \"rect\", \"label\": \"Approve ✓\", \"x\": 20, \"y\": 220, \"width\": 100, \"height\": 36}, {\"id\": \"leaf2\", \"shape\": \"rect\", \"label\": \"Reject ✗\", \"x\": 160, \"y\": 220, \"width\": 100, \"height\": 36}, {\"id\": \"leaf3\", \"shape\": \"rect\", \"label\": \"Reject ✗\", \"x\": 320, \"y\": 220, \"width\": 100, \"height\": 36}, {\"id\": \"leaf4\", \"shape\": \"rect\", \"label\": \"Approve ✓\", \"x\": 460, \"y\": 220, \"width\": 100, \"height\": 36}, {\"source\": \"root\", \"target\": \"leftChild\", \"label\": \"Yes\"}, {\"source\": \"root\", \"target\": \"rightChild\", \"label\": \"No\"}, {\"source\": \"leftChild\", \"target\": \"leaf1\", \"label\": \"Yes\"}, {\"source\": \"leftChild\", \"target\": \"leaf2\", \"label\": \"No\"}, {\"source\": \"rightChild\", \"target\": \"leaf3\", \"label\": \"No\"}, {\"source\": \"rightChild\", \"target\": \"leaf4\", \"label\": \"Yes\"}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\nconst root = graph.addNode({\n shape: 'rect', x: 220, y: 20, width: 120, height: 40, label: 'Age > 30?',\n attrs: { body: { stroke: '#1890ff', strokeWidth: 2, fill: '#e6f7ff', rx: 6, ry: 6 } },\n});\n\nconst leftChild = graph.addNode({\n shape: 'rect', x: 80, y: 120, width: 120, height: 40, label: 'Income > 50k?',\n attrs: { body: { stroke: '#fa8c16', strokeWidth: 2, fill: '#fff7e6', rx: 6, ry: 6 } },\n});\n\nconst rightChild = graph.addNode({\n shape: 'rect', x: 360, y: 120, width: 120, height: 40, label: 'Student?',\n attrs: { body: { stroke: '#fa8c16', strokeWidth: 2, fill: '#fff7e6', rx: 6, ry: 6 } },\n});\n\nconst leaf1 = graph.addNode({\n shape: 'rect', x: 20, y: 220, width: 100, height: 36, label: 'Approve ✓',\n attrs: { body: { stroke: '#52c41a', strokeWidth: 2, fill: '#f6ffed', rx: 4, ry: 4 } },\n});\n\nconst leaf2 = graph.addNode({\n shape: 'rect', x: 160, y: 220, width: 100, height: 36, label: 'Reject ✗',\n attrs: { body: { stroke: '#f5222d', strokeWidth: 2, fill: '#fff1f0', rx: 4, ry: 4 } },\n});\n\nconst leaf3 = graph.addNode({\n shape: 'rect', x: 320, y: 220, width: 100, height: 36, label: 'Reject ✗',\n attrs: { body: { stroke: '#f5222d', strokeWidth: 2, fill: '#fff1f0', rx: 4, ry: 4 } },\n});\n\nconst leaf4 = graph.addNode({\n shape: 'rect', x: 460, y: 220, width: 100, height: 36, label: 'Approve ✓',\n attrs: { body: { stroke: '#52c41a', strokeWidth: 2, fill: '#f6ffed', rx: 4, ry: 4 } },\n});\n\ngraph.addEdge({ source: root, target: leftChild, label: 'Yes', attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1, targetMarker: 'classic' } } });\ngraph.addEdge({ source: root, target: rightChild, label: 'No', attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1, targetMarker: 'classic' } } });\ngraph.addEdge({ source: leftChild, target: leaf1, label: 'Yes', attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1, targetMarker: 'classic' } } });\ngraph.addEdge({ source: leftChild, target: leaf2, label: 'No', attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1, targetMarker: 'classic' } } });\ngraph.addEdge({ source: rightChild, target: leaf3, label: 'No', attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1, targetMarker: 'classic' } } });\ngraph.addEdge({ source: rightChild, target: leaf4, label: 'Yes', attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1, targetMarker: 'classic' } } });\n\ngraph.centerContent();\n"
|
||
},
|
||
{
|
||
"description": "创建画布后演示 graph.clearCells() 清空所有元素,然后重新加载新数据。参考数据:[{\"shape\": \"rect\", \"label\": \"Old Node 1\", \"x\": 60, \"y\": 60, \"width\": 100, \"height\": 40}, {\"shape\": \"rect\", \"label\": \"Old Node 2\", \"x\": 240, \"y\": 60, \"width\": 100, \"height\": 40}, {\"id\": \"newSource\", \"shape\": \"rect\", \"label\": \"New Node A\", \"x\": 60, \"y\": 80, \"width\": 100, \"height\": 40}, {\"id\": \"newTarget\", \"shape\": \"rect\", \"label\": \"New Node B\", \"x\": 260, \"y\": 80, \"width\": 100, \"height\": 40}, {\"source\": \"newSource\", \"target\": \"newTarget\"}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\ngraph.addNode({\n shape: 'rect', x: 60, y: 60, width: 100, height: 40, label: 'Old Node 1',\n attrs: { body: { stroke: '#f5222d', strokeWidth: 1, fill: '#fff1f0', rx: 6, ry: 6 } },\n});\n\ngraph.addNode({\n shape: 'rect', x: 240, y: 60, width: 100, height: 40, label: 'Old Node 2',\n attrs: { body: { stroke: '#f5222d', strokeWidth: 1, fill: '#fff1f0', rx: 6, ry: 6 } },\n});\n\ngraph.clearCells();\n\nconst newSource = graph.addNode({\n shape: 'rect', x: 60, y: 80, width: 100, height: 40, label: 'New Node A',\n attrs: { body: { stroke: '#52c41a', strokeWidth: 2, fill: '#f6ffed', rx: 6, ry: 6 } },\n});\n\nconst newTarget = graph.addNode({\n shape: 'rect', x: 260, y: 80, width: 100, height: 40, label: 'New Node B',\n attrs: { body: { stroke: '#52c41a', strokeWidth: 2, fill: '#f6ffed', rx: 6, ry: 6 } },\n});\n\ngraph.addEdge({\n source: newSource,\n target: newTarget,\n attrs: { line: { stroke: '#52c41a', strokeWidth: 2, targetMarker: 'classic' } },\n});\n"
|
||
},
|
||
{
|
||
"description": "创建多个任务节点,通过点击切换节点的运行状态(待执行→执行中→完成),根据状态改变节点颜色。参考数据:[{\"shape\": \"rect\", \"x\": 40, \"y\": 40, \"width\": 120, \"height\": 45}, {\"source\": \"nodes\", \"target\": \"nodes\"}, {\"source\": \"nodes\", \"target\": \"nodes\"}, {\"source\": \"nodes\", \"target\": \"nodes\"}, {\"source\": \"nodes\", \"target\": \"nodes\"}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst statusColors = {\n pending: { stroke: '#8f8f8f', fill: '#fff' },\n running: { stroke: '#1890ff', fill: '#e6f7ff' },\n success: { stroke: '#52c41a', fill: '#f6ffed' },\n failed: { stroke: '#f5222d', fill: '#fff1f0' },\n};\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\nconst nodes = ['Task 1', 'Task 2', 'Task 3', 'Task 4'].map((label, i) => {\n return graph.addNode({\n shape: 'rect',\n x: 40 + (i % 2) * 200,\n y: 40 + Math.floor(i / 2) * 100,\n width: 120,\n height: 45,\n label: label,\n data: { status: 'pending' },\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 2, fill: '#fff', rx: 6, ry: 6 },\n },\n });\n});\n\ngraph.addEdge({ source: nodes[0], target: nodes[1], attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1, targetMarker: 'classic' } } });\ngraph.addEdge({ source: nodes[0], target: nodes[2], attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1, targetMarker: 'classic' } } });\ngraph.addEdge({ source: nodes[1], target: nodes[3], attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1, targetMarker: 'classic' } } });\ngraph.addEdge({ source: nodes[2], target: nodes[3], attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1, targetMarker: 'classic' } } });\n\nconst statusOrder = ['pending', 'running', 'success'];\n\ngraph.on('node:click', ({ node }) => {\n const data = node.getData() || {};\n const currentIdx = statusOrder.indexOf(data.status || 'pending');\n const nextStatus = statusOrder[(currentIdx + 1) % statusOrder.length];\n node.setData({ status: nextStatus });\n const colors = statusColors[nextStatus];\n node.attr('body/stroke', colors.stroke);\n node.attr('body/fill', colors.fill);\n});\n"
|
||
},
|
||
{
|
||
"description": "创建一组垂直排列的节点,模拟可拖拽排序的列表,节点只能在垂直方向移动。参考数据:[{\"shape\": \"rect\", \"x\": 100, \"y\": 20, \"width\": 200, \"height\": 44}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n translating: {\n restrict(cellView) {\n const cell = cellView.cell;\n const bbox = cell.getBBox();\n return { x: 100, y: 0, width: 1, height: 400 };\n },\n },\n});\n\nconst items = ['Item A', 'Item B', 'Item C', 'Item D', 'Item E'];\n\nitems.forEach((label, i) => {\n graph.addNode({\n shape: 'rect',\n x: 100,\n y: 20 + i * 60,\n width: 200,\n height: 44,\n label: label,\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n });\n});\n"
|
||
},
|
||
{
|
||
"description": "创建一个较大的画布,包含多个分散的节点,使用 graph.scrollToCell() 滚动到指定节点位置。参考数据:[{\"id\": \"far-away\", \"shape\": \"rect\", \"label\": \"Far Away Node\", \"x\": 1000, \"y\": 800, \"width\": 120, \"height\": 50}, {\"shape\": \"rect\", \"label\": \"Near Node\", \"x\": 50, \"y\": 50, \"width\": 100, \"height\": 40}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n width: 600,\n height: 400,\n background: { color: '#F2F7FA' },\n panning: true,\n mousewheel: { enabled: true, modifiers: 'ctrl' },\n});\n\ngraph.addNode({\n id: 'far-away',\n shape: 'rect',\n x: 1000,\n y: 800,\n width: 120,\n height: 50,\n label: 'Far Away Node',\n attrs: {\n body: { stroke: '#f5222d', strokeWidth: 2, fill: '#fff1f0', rx: 6, ry: 6 },\n },\n});\n\ngraph.addNode({\n shape: 'rect',\n x: 50,\n y: 50,\n width: 100,\n height: 40,\n label: 'Near Node',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\nconst targetNode = graph.getCellById('far-away');\ngraph.centerCell(targetNode);\n"
|
||
},
|
||
{
|
||
"description": "创建一个带有渐变填充色的矩形节点,使用 SVG 线性渐变从蓝色过渡到绿色。参考数据:[{\"shape\": \"rect\", \"label\": \"Gradient Node\", \"x\": 100, \"y\": 60, \"width\": 160, \"height\": 80}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\ngraph.addNode({\n shape: 'rect',\n x: 100,\n y: 60,\n width: 160,\n height: 80,\n label: 'Gradient Node',\n attrs: {\n body: {\n fill: {\n type: 'linearGradient',\n stops: [\n { offset: '0%', color: '#1890ff' },\n { offset: '100%', color: '#52c41a' },\n ],\n },\n stroke: '#8f8f8f',\n strokeWidth: 1,\n rx: 6,\n ry: 6,\n },\n label: {\n fill: '#fff',\n fontSize: 14,\n },\n },\n});\n"
|
||
},
|
||
{
|
||
"description": "使用 graph.getCells() 获取画布中所有元素,并通过 graph.getNodes() 和 graph.getEdges() 分别获取节点和边。参考数据:[{\"id\": \"node1\", \"shape\": \"rect\", \"label\": \"A\", \"x\": 40, \"y\": 40, \"width\": 100, \"height\": 40}, {\"id\": \"node2\", \"shape\": \"rect\", \"label\": \"B\", \"x\": 240, \"y\": 40, \"width\": 100, \"height\": 40}, {\"id\": \"node3\", \"shape\": \"circle\", \"label\": \"C\", \"x\": 140, \"y\": 160, \"width\": 60, \"height\": 60}, {\"source\": \"node1\", \"target\": \"node3\"}, {\"source\": \"node2\", \"target\": \"node3\"}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\nconst node1 = graph.addNode({\n shape: 'rect', x: 40, y: 40, width: 100, height: 40, label: 'A',\n attrs: { body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 } },\n});\n\nconst node2 = graph.addNode({\n shape: 'rect', x: 240, y: 40, width: 100, height: 40, label: 'B',\n attrs: { body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 } },\n});\n\nconst node3 = graph.addNode({\n shape: 'circle', x: 140, y: 160, width: 60, height: 60, label: 'C',\n attrs: { body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff' } },\n});\n\ngraph.addEdge({ source: node1, target: node3, attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1 } } });\ngraph.addEdge({ source: node2, target: node3, attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1 } } });\n\nconst allCells = graph.getCells();\nconst allNodes = graph.getNodes();\nconst allEdges = graph.getEdges();\nconsole.log('Total cells:', allCells.length);\nconsole.log('Nodes:', allNodes.length);\nconsole.log('Edges:', allEdges.length);\n"
|
||
},
|
||
{
|
||
"description": "创建节点并使用 node.setPosition() 和 node.setSize() 方法动态修改节点的位置和大小。参考数据:[{\"id\": \"node\", \"shape\": \"rect\", \"label\": \"Original\", \"x\": 40, \"y\": 40, \"width\": 100, \"height\": 40}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n grid: { visible: true },\n});\n\nconst node = graph.addNode({\n shape: 'rect',\n x: 40,\n y: 40,\n width: 100,\n height: 40,\n label: 'Original',\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 },\n },\n});\n\nnode.setPosition(200, 100);\nnode.setSize(160, 60);\nnode.attr('label/text', 'Moved & Resized');\nnode.attr('body/fill', '#e6f7ff');\n"
|
||
},
|
||
{
|
||
"description": "使用 graph.batchUpdate() 实现批量操作时的性能优化,将多次操作合并为一次渲染更新。参考数据:[{\"shape\": \"rect\", \"label\": \"Node \", \"x\": 20, \"y\": 20, \"width\": 90, \"height\": 36}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\ngraph.batchUpdate('add-nodes', () => {\n for (let i = 0; i < 20; i++) {\n graph.addNode({\n shape: 'rect',\n x: 20 + (i % 5) * 120,\n y: 20 + Math.floor(i / 5) * 80,\n width: 90,\n height: 36,\n label: 'Node ' + (i + 1),\n attrs: {\n body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 4, ry: 4 },\n },\n });\n }\n});\n\ngraph.centerContent();\n"
|
||
},
|
||
{
|
||
"description": "创建一条带有动画效果的边,使用 strokeDasharray 和 strokeDashoffset 模拟流动动画。参考数据:[{\"id\": \"source\", \"shape\": \"rect\", \"label\": \"Source\", \"x\": 40, \"y\": 100, \"width\": 100, \"height\": 40}, {\"id\": \"target\", \"shape\": \"rect\", \"label\": \"Target\", \"x\": 340, \"y\": 100, \"width\": 100, \"height\": 40}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\nconst source = graph.addNode({\n shape: 'rect', x: 40, y: 100, width: 100, height: 40, label: 'Source',\n attrs: { body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 } },\n});\n\nconst target = graph.addNode({\n shape: 'rect', x: 340, y: 100, width: 100, height: 40, label: 'Target',\n attrs: { body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 } },\n});\n\nconst edge = graph.addEdge({\n source,\n target,\n attrs: {\n line: {\n stroke: '#1890ff',\n strokeWidth: 2,\n strokeDasharray: '5 5',\n targetMarker: 'classic',\n style: {\n animation: 'ant-line 30s infinite linear',\n },\n },\n },\n});\n"
|
||
},
|
||
{
|
||
"description": "创建一个画布,配置全局的默认边样式,所有后续添加的边都继承该默认样式。参考数据:[{\"id\": \"out1\", \"shape\": \"rect\", \"label\": \"Node 1\", \"x\": 40, \"y\": 40, \"width\": 100, \"height\": 40}, {\"id\": \"in1\", \"shape\": \"rect\", \"label\": \"Node 2\", \"x\": 40, \"y\": 200, \"width\": 100, \"height\": 40}, {\"id\": \"in1\", \"shape\": \"rect\", \"label\": \"Node 3\", \"x\": 260, \"y\": 120, \"width\": 100, \"height\": 40}, {\"source\": \"node1\", \"target\": \"node2\"}, {\"source\": \"node1\", \"target\": \"node3\"}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n connecting: {\n createEdge() {\n return this.createEdge({\n attrs: {\n line: { stroke: '#1890ff', strokeWidth: 2, targetMarker: 'classic' },\n },\n router: 'orth',\n connector: 'rounded',\n });\n },\n },\n});\n\nconst node1 = graph.addNode({\n shape: 'rect', x: 40, y: 40, width: 100, height: 40, label: 'Node 1',\n attrs: { body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 } },\n ports: {\n groups: { out: { position: 'bottom', attrs: { circle: { magnet: true, stroke: '#8f8f8f', r: 5 } } } },\n items: [{ id: 'out1', group: 'out' }],\n },\n});\n\nconst node2 = graph.addNode({\n shape: 'rect', x: 40, y: 200, width: 100, height: 40, label: 'Node 2',\n attrs: { body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 } },\n ports: {\n groups: { in: { position: 'top', attrs: { circle: { magnet: true, stroke: '#8f8f8f', r: 5 } } } },\n items: [{ id: 'in1', group: 'in' }],\n },\n});\n\nconst node3 = graph.addNode({\n shape: 'rect', x: 260, y: 120, width: 100, height: 40, label: 'Node 3',\n attrs: { body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 } },\n ports: {\n groups: { in: { position: 'left', attrs: { circle: { magnet: true, stroke: '#8f8f8f', r: 5 } } } },\n items: [{ id: 'in1', group: 'in' }],\n },\n});\n\ngraph.addEdge({ source: { cell: node1, port: 'out1' }, target: { cell: node2, port: 'in1' } });\ngraph.addEdge({ source: { cell: node1, port: 'out1' }, target: { cell: node3, port: 'in1' } });\n"
|
||
},
|
||
{
|
||
"description": "使用 graph.getNeighbors() 获取指定节点的相邻节点,并高亮显示所有相邻节点。参考数据:[{\"id\": \"center\", \"shape\": \"circle\", \"label\": \"Center\", \"x\": 200, \"y\": 120, \"width\": 70, \"height\": 70}, {\"shape\": \"rect\", \"label\": \"N\", \"width\": 80, \"height\": 40}, {\"source\": \"center\", \"target\": \"node\"}]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\nconst center = graph.addNode({\n id: 'center',\n shape: 'circle', x: 200, y: 120, width: 70, height: 70, label: 'Center',\n attrs: { body: { stroke: '#1890ff', strokeWidth: 2, fill: '#e6f7ff' } },\n});\n\nconst positions = [[80, 40], [320, 40], [80, 220], [320, 220]];\nconst neighbors = positions.map((pos, i) => {\n return graph.addNode({\n shape: 'rect', x: pos[0], y: pos[1], width: 80, height: 40, label: 'N' + (i + 1),\n attrs: { body: { stroke: '#8f8f8f', strokeWidth: 1, fill: '#fff', rx: 6, ry: 6 } },\n });\n});\n\nneighbors.forEach((node) => {\n graph.addEdge({\n source: center,\n target: node,\n attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1 } },\n });\n});\n\nconst connectedNodes = graph.getNeighbors(center);\nconnectedNodes.forEach((node) => {\n node.attr('body/fill', '#d9f7be');\n node.attr('body/stroke', '#52c41a');\n});\n"
|
||
},
|
||
{
|
||
"description": "使用 HTML shape 创建一个包含头像、姓名和职位信息的用户卡片节点",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nGraph.registerHTMLComponent('user-card', (node) => {\n const data = node.getData() || {};\n const div = document.createElement('div');\n div.style.cssText = 'width:100%;height:100%;display:flex;align-items:center;padding:8px;box-sizing:border-box;border:1px solid #e8e8e8;border-radius:8px;background:#fff;';\n div.innerHTML = `\n <div style=\"width:36px;height:36px;border-radius:50%;background:#1890ff;display:flex;align-items:center;justify-content:center;color:#fff;font-weight:bold;margin-right:10px;\">\n ${(data.name || 'U')[0]}\n </div>\n <div>\n <div style=\"font-size:14px;font-weight:500;\">${data.name || 'User'}</div>\n <div style=\"font-size:12px;color:#999;\">${data.role || 'Engineer'}</div>\n </div>\n `;\n return div;\n});\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\ngraph.addNode({\n shape: 'html',\n x: 80,\n y: 60,\n width: 200,\n height: 60,\n html: 'user-card',\n data: { name: 'Alice', role: 'Frontend Engineer' },\n});\n\ngraph.addNode({\n shape: 'html',\n x: 80,\n y: 160,\n width: 200,\n height: 60,\n html: 'user-card',\n data: { name: 'Bob', role: 'Backend Engineer' },\n});\n"
|
||
},
|
||
{
|
||
"description": "创建一个 HTML 自定义节点作为任务卡片,显示任务标题、进度条和状态标签",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nGraph.registerHTMLComponent('task-card', (node) => {\n const data = node.getData() || {};\n const progress = data.progress || 0;\n const status = data.status || 'todo';\n const statusColors = { todo: '#d9d9d9', doing: '#1890ff', done: '#52c41a' };\n const div = document.createElement('div');\n div.style.cssText = 'width:100%;height:100%;padding:12px;box-sizing:border-box;border:1px solid #e8e8e8;border-radius:8px;background:#fff;font-family:sans-serif;';\n div.innerHTML = `\n <div style=\"display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;\">\n <span style=\"font-size:13px;font-weight:500;\">${data.title || 'Task'}</span>\n <span style=\"font-size:11px;padding:2px 6px;border-radius:4px;background:${statusColors[status]};color:#fff;\">${status}</span>\n </div>\n <div style=\"height:6px;background:#f0f0f0;border-radius:3px;overflow:hidden;\">\n <div style=\"height:100%;width:${progress}%;background:${statusColors[status]};border-radius:3px;\"></div>\n </div>\n <div style=\"font-size:11px;color:#999;margin-top:6px;\">${progress}% complete</div>\n `;\n return div;\n});\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\ngraph.addNode({\n shape: 'html',\n x: 60,\n y: 40,\n width: 220,\n height: 90,\n html: 'task-card',\n data: { title: 'Design Review', status: 'done', progress: 100 },\n});\n\ngraph.addNode({\n shape: 'html',\n x: 60,\n y: 160,\n width: 220,\n height: 90,\n html: 'task-card',\n data: { title: 'API Development', status: 'doing', progress: 65 },\n});\n\ngraph.addNode({\n shape: 'html',\n x: 60,\n y: 280,\n width: 220,\n height: 90,\n html: 'task-card',\n data: { title: 'Unit Testing', status: 'todo', progress: 0 },\n});\n"
|
||
},
|
||
{
|
||
"description": "用 HTML shape 实现一个带有输入输出端口的数据处理节点,节点内显示处理类型和配置参数",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nGraph.registerHTMLComponent('processor-node', (node) => {\n const data = node.getData() || {};\n const div = document.createElement('div');\n div.style.cssText = 'width:100%;height:100%;box-sizing:border-box;border:1px solid #d9d9d9;border-radius:6px;background:#fff;overflow:hidden;';\n div.innerHTML = `\n <div style=\"padding:4px 10px;background:#1890ff;color:#fff;font-size:12px;font-weight:500;\">${data.type || 'Processor'}</div>\n <div style=\"padding:8px 10px;font-size:11px;color:#666;\">\n <div>Input: ${data.input || 'any'}</div>\n <div>Output: ${data.output || 'any'}</div>\n </div>\n `;\n return div;\n});\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n connecting: {\n allowBlank: false,\n router: 'orth',\n connector: 'rounded',\n },\n});\n\nconst filterNode = graph.addNode({\n shape: 'html',\n x: 60,\n y: 80,\n width: 160,\n height: 80,\n html: 'processor-node',\n data: { type: 'Filter', input: 'DataFrame', output: 'DataFrame' },\n ports: {\n groups: {\n in: { position: 'left', attrs: { circle: { r: 5, magnet: true, stroke: '#1890ff', fill: '#fff' } } },\n out: { position: 'right', attrs: { circle: { r: 5, magnet: true, stroke: '#52c41a', fill: '#fff' } } },\n },\n items: [\n { id: 'in-1', group: 'in' },\n { id: 'out-1', group: 'out' },\n ],\n },\n});\n\nconst mapNode = graph.addNode({\n shape: 'html',\n x: 320,\n y: 80,\n width: 160,\n height: 80,\n html: 'processor-node',\n data: { type: 'Map', input: 'DataFrame', output: 'Series' },\n ports: {\n groups: {\n in: { position: 'left', attrs: { circle: { r: 5, magnet: true, stroke: '#1890ff', fill: '#fff' } } },\n out: { position: 'right', attrs: { circle: { r: 5, magnet: true, stroke: '#52c41a', fill: '#fff' } } },\n },\n items: [\n { id: 'in-1', group: 'in' },\n { id: 'out-1', group: 'out' },\n ],\n },\n});\n\ngraph.addEdge({\n source: { cell: filterNode, port: 'out-1' },\n target: { cell: mapNode, port: 'in-1' },\n attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1, targetMarker: 'classic' } },\n});\n"
|
||
},
|
||
{
|
||
"description": "使用 HTML shape 和 effect 配置创建一个状态可变节点,修改 data 后自动重新渲染 HTML 内容",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nGraph.registerHTMLComponent('status-badge', (node) => {\n const data = node.getData() || {};\n const colors = { online: '#52c41a', offline: '#ff4d4f', idle: '#faad14' };\n const color = colors[data.status] || '#d9d9d9';\n const div = document.createElement('div');\n div.style.cssText = 'width:100%;height:100%;display:flex;align-items:center;justify-content:center;border-radius:8px;border:2px solid ' + color + ';background:#fff;font-family:sans-serif;';\n div.innerHTML = `\n <div style=\"width:8px;height:8px;border-radius:50%;background:${color};margin-right:8px;\"></div>\n <span style=\"font-size:13px;color:#333;\">${data.name || 'Service'}</span>\n <span style=\"font-size:11px;color:${color};margin-left:8px;\">${data.status || 'unknown'}</span>\n `;\n return div;\n});\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\nconst node1 = graph.addNode({\n shape: 'html',\n x: 80,\n y: 60,\n width: 200,\n height: 50,\n html: 'status-badge',\n data: { name: 'API Server', status: 'online' },\n});\n\nconst node2 = graph.addNode({\n shape: 'html',\n x: 80,\n y: 140,\n width: 200,\n height: 50,\n html: 'status-badge',\n data: { name: 'Database', status: 'idle' },\n});\n\nconst node3 = graph.addNode({\n shape: 'html',\n x: 80,\n y: 220,\n width: 200,\n height: 50,\n html: 'status-badge',\n data: { name: 'Worker', status: 'offline' },\n});\n\n// Simulate status change\nsetTimeout(() => {\n node3.setData({ name: 'Worker', status: 'online' });\n}, 1000);\n"
|
||
},
|
||
{
|
||
"description": "用 HTML shape 创建一个可编辑的表单节点,内含输入框和下拉选择框",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nGraph.registerHTMLComponent('form-node', (node) => {\n const data = node.getData() || {};\n const div = document.createElement('div');\n div.style.cssText = 'width:100%;height:100%;padding:12px;box-sizing:border-box;border:1px solid #d9d9d9;border-radius:8px;background:#fff;font-family:sans-serif;';\n div.innerHTML = `\n <div style=\"font-size:13px;font-weight:500;margin-bottom:8px;color:#333;\">${data.title || 'Config'}</div>\n <div style=\"margin-bottom:6px;\">\n <label style=\"font-size:11px;color:#666;\">Name:</label>\n <input style=\"width:100%;padding:3px 6px;border:1px solid #d9d9d9;border-radius:4px;font-size:12px;box-sizing:border-box;\" value=\"${data.name || ''}\" />\n </div>\n <div>\n <label style=\"font-size:11px;color:#666;\">Type:</label>\n <select style=\"width:100%;padding:3px 6px;border:1px solid #d9d9d9;border-radius:4px;font-size:12px;\">\n <option ${data.type === 'string' ? 'selected' : ''}>string</option>\n <option ${data.type === 'number' ? 'selected' : ''}>number</option>\n <option ${data.type === 'boolean' ? 'selected' : ''}>boolean</option>\n </select>\n </div>\n `;\n return div;\n});\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\ngraph.addNode({\n shape: 'html',\n x: 80,\n y: 40,\n width: 200,\n height: 130,\n html: 'form-node',\n data: { title: 'Variable Config', name: 'userName', type: 'string' },\n});\n\ngraph.addNode({\n shape: 'html',\n x: 80,\n y: 200,\n width: 200,\n height: 130,\n html: 'form-node',\n data: { title: 'Parameter Config', name: 'maxRetry', type: 'number' },\n});\n"
|
||
},
|
||
{
|
||
"description": "用 HTML shape 实现一个数据表格节点,展示字段名、类型、是否主键等列信息,适用于 ER 图场景",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nGraph.registerHTMLComponent('table-node', (node) => {\n const data = node.getData() || {};\n const fields = data.fields || [];\n const div = document.createElement('div');\n div.style.cssText = 'width:100%;height:100%;box-sizing:border-box;border:1px solid #d9d9d9;border-radius:6px;background:#fff;overflow:hidden;font-family:sans-serif;';\n const fieldsHtml = fields.map(f => `\n <tr style=\"border-top:1px solid #f0f0f0;\">\n <td style=\"padding:4px 8px;font-size:11px;\">${f.pk ? '🔑 ' : ''}${f.name}</td>\n <td style=\"padding:4px 8px;font-size:11px;color:#999;\">${f.type}</td>\n </tr>\n `).join('');\n div.innerHTML = `\n <div style=\"padding:6px 10px;background:#722ed1;color:#fff;font-size:12px;font-weight:500;\">${data.tableName || 'Table'}</div>\n <table style=\"width:100%;border-collapse:collapse;\">${fieldsHtml}</table>\n `;\n return div;\n});\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n connecting: { router: 'orth', connector: 'rounded' },\n});\n\nconst userTable = graph.addNode({\n shape: 'html',\n x: 60,\n y: 40,\n width: 180,\n height: 130,\n html: 'table-node',\n data: {\n tableName: 'users',\n fields: [\n { name: 'id', type: 'int', pk: true },\n { name: 'name', type: 'varchar' },\n { name: 'email', type: 'varchar' },\n ],\n },\n ports: {\n groups: { out: { position: 'right', attrs: { circle: { r: 4, magnet: true, stroke: '#722ed1', fill: '#fff' } } } },\n items: [{ id: 'out-1', group: 'out' }],\n },\n});\n\nconst orderTable = graph.addNode({\n shape: 'html',\n x: 360,\n y: 40,\n width: 180,\n height: 130,\n html: 'table-node',\n data: {\n tableName: 'orders',\n fields: [\n { name: 'id', type: 'int', pk: true },\n { name: 'user_id', type: 'int' },\n { name: 'amount', type: 'decimal' },\n ],\n },\n ports: {\n groups: { in: { position: 'left', attrs: { circle: { r: 4, magnet: true, stroke: '#722ed1', fill: '#fff' } } } },\n items: [{ id: 'in-1', group: 'in' }],\n },\n});\n\ngraph.addEdge({\n source: { cell: userTable, port: 'out-1' },\n target: { cell: orderTable, port: 'in-1' },\n label: '1:N',\n attrs: { line: { stroke: '#722ed1', strokeWidth: 1, targetMarker: 'classic' } },\n});\n"
|
||
},
|
||
{
|
||
"description": "创建画布后使用 graph.centerContent() 将所有内容居中显示,再使用 graph.zoom(0.8) 缩小视图",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n width: 600,\n height: 400,\n background: { color: '#F2F7FA' },\n panning: true,\n mousewheel: { enabled: true, modifiers: 'ctrl' },\n});\n\ngraph.addNode({ shape: 'rect', x: 50, y: 50, width: 100, height: 40, label: 'Node A', attrs: { body: { fill: '#fff', stroke: '#8f8f8f', rx: 6, ry: 6 } } });\ngraph.addNode({ shape: 'rect', x: 400, y: 300, width: 100, height: 40, label: 'Node B', attrs: { body: { fill: '#fff', stroke: '#8f8f8f', rx: 6, ry: 6 } } });\ngraph.addNode({ shape: 'rect', x: 200, y: 150, width: 100, height: 40, label: 'Node C', attrs: { body: { fill: '#fff', stroke: '#8f8f8f', rx: 6, ry: 6 } } });\n\ngraph.centerContent();\ngraph.zoom(-0.2);\n"
|
||
},
|
||
{
|
||
"description": "使用 graph.localToGraph 和 graph.graphToLocal 进行坐标转换,将画布坐标和本地坐标互转",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n panning: true,\n mousewheel: { enabled: true, modifiers: 'ctrl' },\n});\n\nconst node = graph.addNode({\n shape: 'rect',\n x: 100,\n y: 80,\n width: 120,\n height: 50,\n label: 'Click canvas',\n attrs: { body: { fill: '#fff', stroke: '#1890ff', strokeWidth: 2, rx: 6, ry: 6 } },\n});\n\ngraph.on('blank:click', ({ e }) => {\n const localPoint = graph.clientToLocal(e.clientX, e.clientY);\n console.log('Local coordinates:', localPoint.x, localPoint.y);\n\n graph.addNode({\n shape: 'circle',\n x: localPoint.x - 15,\n y: localPoint.y - 15,\n width: 30,\n height: 30,\n attrs: { body: { fill: '#1890ff', stroke: 'none' } },\n });\n});\n"
|
||
},
|
||
{
|
||
"description": "配置画布支持 panning 拖拽平移和 mousewheel 缩放,限制缩放范围为 0.5 到 3 倍",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n grid: { visible: true, size: 10 },\n panning: {\n enabled: true,\n modifiers: 'shift',\n },\n mousewheel: {\n enabled: true,\n modifiers: 'ctrl',\n minScale: 0.5,\n maxScale: 3,\n },\n});\n\ngraph.addNode({ shape: 'rect', x: 60, y: 60, width: 120, height: 50, label: 'Shift+Drag to pan', attrs: { body: { fill: '#e6f7ff', stroke: '#1890ff', rx: 6, ry: 6 } } });\ngraph.addNode({ shape: 'rect', x: 260, y: 160, width: 120, height: 50, label: 'Ctrl+Wheel to zoom', attrs: { body: { fill: '#f6ffed', stroke: '#52c41a', rx: 6, ry: 6 } } });\n\ngraph.addEdge({\n source: { x: 180, y: 85 },\n target: { x: 260, y: 185 },\n attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1, targetMarker: 'classic' } },\n});\n"
|
||
},
|
||
{
|
||
"description": "创建画布并添加 10 个随机位置的矩形节点,使用 graph.zoomToRect 将视口缩放到指定矩形区域,实现局部放大功能。参考数据:[{\"shape\": \"rect\", \"width\": 80, \"height\": 40}(共 10 个节点,x/y 随机)]",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n width: 600,\n height: 400,\n background: { color: '#F2F7FA' },\n panning: true,\n mousewheel: { enabled: true },\n});\n\nfor (let i = 0; i < 10; i++) {\n graph.addNode({\n shape: 'rect',\n x: Math.random() * 800,\n y: Math.random() * 600,\n width: 80,\n height: 40,\n label: `Node ${i + 1}`,\n attrs: { body: { fill: '#fff', stroke: '#8f8f8f', rx: 4, ry: 4 } },\n });\n}\n\ngraph.zoomToRect({\n x: 0,\n y: 0,\n width: 400,\n height: 300,\n});\n"
|
||
},
|
||
{
|
||
"description": "为节点添加过渡动画,通过 transition 方法实现节点位置从当前位置平滑移动到目标位置",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\nconst node = graph.addNode({\n shape: 'rect',\n x: 40,\n y: 80,\n width: 100,\n height: 40,\n label: 'Animate Me',\n attrs: { body: { fill: '#e6f7ff', stroke: '#1890ff', strokeWidth: 2, rx: 6, ry: 6 } },\n});\n\nnode.transition('position', { x: 350, y: 200 }, {\n duration: 1000,\n timing: 'ease-in-out',\n});\n"
|
||
},
|
||
{
|
||
"description": "创建边后使用 edge.attr 配合 strokeDasharray 和 CSS animation 实现流动虚线动画效果",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\nconst source = graph.addNode({\n shape: 'rect',\n x: 40,\n y: 100,\n width: 100,\n height: 40,\n label: 'Source',\n attrs: { body: { fill: '#fff', stroke: '#1890ff', strokeWidth: 2, rx: 6, ry: 6 } },\n});\n\nconst target = graph.addNode({\n shape: 'rect',\n x: 350,\n y: 100,\n width: 100,\n height: 40,\n label: 'Target',\n attrs: { body: { fill: '#fff', stroke: '#52c41a', strokeWidth: 2, rx: 6, ry: 6 } },\n});\n\nconst edge = graph.addEdge({\n source,\n target,\n attrs: {\n line: {\n stroke: '#1890ff',\n strokeWidth: 2,\n strokeDasharray: '5 5',\n style: {\n animation: 'ant-line 30s infinite linear',\n },\n },\n },\n});\n"
|
||
},
|
||
{
|
||
"description": "为节点的多个属性同时添加动画,包括位置移动、大小变化和透明度渐变",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\nconst node = graph.addNode({\n shape: 'rect',\n x: 60,\n y: 60,\n width: 80,\n height: 40,\n label: 'Animate',\n attrs: {\n body: { fill: '#1890ff', stroke: 'none', rx: 6, ry: 6, opacity: 1 },\n label: { fill: '#fff' },\n },\n});\n\nnode.transition('position', { x: 300, y: 180 }, {\n duration: 1500,\n timing: 'ease-out',\n});\n\nnode.transition('size', { width: 140, height: 60 }, {\n duration: 1500,\n timing: 'ease-out',\n});\n\nnode.transition('attrs/body/opacity', 0.6, {\n duration: 1500,\n timing: 'ease-out',\n});\n"
|
||
},
|
||
{
|
||
"description": "为边添加 button 工具,点击按钮可以删除该边,按钮显示在边的中间位置",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\nconst source = graph.addNode({\n shape: 'rect',\n x: 40,\n y: 100,\n width: 100,\n height: 40,\n label: 'Source',\n attrs: { body: { fill: '#fff', stroke: '#8f8f8f', rx: 6, ry: 6 } },\n});\n\nconst target = graph.addNode({\n shape: 'rect',\n x: 340,\n y: 100,\n width: 100,\n height: 40,\n label: 'Target',\n attrs: { body: { fill: '#fff', stroke: '#8f8f8f', rx: 6, ry: 6 } },\n});\n\nconst edge = graph.addEdge({\n source,\n target,\n attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1, targetMarker: 'classic' } },\n tools: [\n {\n name: 'button-remove',\n args: { distance: 0.5 },\n },\n ],\n});\n"
|
||
},
|
||
{
|
||
"description": "为节点添加 boundary 工具显示选中边框,并在鼠标悬停时动态添加/移除节点工具",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n background: { color: '#F2F7FA' },\n});\n\ngraph.addNode({\n shape: 'rect',\n x: 80,\n y: 60,\n width: 120,\n height: 50,\n label: 'Hover me',\n attrs: { body: { fill: '#fff', stroke: '#8f8f8f', rx: 6, ry: 6 } },\n});\n\ngraph.addNode({\n shape: 'rect',\n x: 280,\n y: 60,\n width: 120,\n height: 50,\n label: 'Hover me too',\n attrs: { body: { fill: '#fff', stroke: '#8f8f8f', rx: 6, ry: 6 } },\n});\n\ngraph.on('node:mouseenter', ({ node }) => {\n node.addTools([\n { name: 'boundary', args: { attrs: { fill: '#1890ff', fillOpacity: 0.1, stroke: '#1890ff', strokeWidth: 1 } } },\n { name: 'button-remove', args: { x: 0, y: 0, offset: { x: -6, y: -6 } } },\n ]);\n});\n\ngraph.on('node:mouseleave', ({ node }) => {\n node.removeTools();\n});\n"
|
||
},
|
||
{
|
||
"description": "使用 virtual render 虚拟渲染模式创建包含 1000 个节点的大规模画布,仅渲染可视区域内的节点提升性能",
|
||
"codeString": "import { Graph, Scroller } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n width: 600,\n height: 400,\n virtual: true,\n async: true,\n background: { color: '#F2F7FA' },\n});\n\ngraph.use(new Scroller({ enabled: true }));\n\nconst cols = 30;\nconst rows = 34;\nconst nodeWidth = 80;\nconst nodeHeight = 36;\nconst gapX = 40;\nconst gapY = 30;\n\nfor (let i = 0; i < rows; i++) {\n for (let j = 0; j < cols; j++) {\n const index = i * cols + j;\n graph.addNode({\n shape: 'rect',\n x: j * (nodeWidth + gapX) + 20,\n y: i * (nodeHeight + gapY) + 20,\n width: nodeWidth,\n height: nodeHeight,\n label: `Node ${index}`,\n attrs: { body: { fill: '#fff', stroke: '#d9d9d9', rx: 4, ry: 4 }, label: { fontSize: 10 } },\n });\n }\n}\n\ngraph.centerContent();\n"
|
||
},
|
||
{
|
||
"description": "构建一个完整的 BPMN 审批流程编辑器,包含开始事件(圆形)、用户任务(圆角矩形)、排他网关(菱形)和结束事件,支持连线交互",
|
||
"codeString": "import { Graph, Selection, Snapline, History } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n width: 800,\n height: 500,\n background: { color: '#F2F7FA' },\n grid: { visible: true, size: 10 },\n connecting: {\n allowBlank: false,\n router: 'orth',\n connector: 'rounded',\n createEdge() {\n return this.createEdge({\n attrs: { line: { stroke: '#5F95FF', strokeWidth: 1, targetMarker: 'classic' } },\n });\n },\n },\n});\n\ngraph.use(new Selection({ enabled: true, rubberband: true }));\ngraph.use(new Snapline({ enabled: true }));\ngraph.use(new History({ enabled: true }));\n\nconst start = graph.addNode({\n shape: 'circle',\n x: 80,\n y: 200,\n width: 40,\n height: 40,\n attrs: { body: { fill: '#52c41a', stroke: '#389e0d' }, label: { text: 'Start', fill: '#fff', fontSize: 11 } },\n ports: { groups: { out: { position: 'right', attrs: { circle: { r: 4, magnet: true, stroke: '#52c41a', fill: '#fff' } } } }, items: [{ id: 'out', group: 'out' }] },\n});\n\nconst submit = graph.addNode({\n shape: 'rect',\n x: 200,\n y: 190,\n width: 120,\n height: 60,\n label: 'Submit Request',\n attrs: { body: { fill: '#e6f7ff', stroke: '#1890ff', rx: 8, ry: 8 } },\n ports: { groups: { in: { position: 'left', attrs: { circle: { r: 4, magnet: true, stroke: '#1890ff', fill: '#fff' } } }, out: { position: 'right', attrs: { circle: { r: 4, magnet: true, stroke: '#1890ff', fill: '#fff' } } } }, items: [{ id: 'in', group: 'in' }, { id: 'out', group: 'out' }] },\n});\n\nconst gateway = graph.addNode({\n shape: 'polygon',\n x: 400,\n y: 195,\n width: 50,\n height: 50,\n attrs: { body: { fill: '#fffbe6', stroke: '#faad14', refPoints: '0,10 10,0 20,10 10,20' }, label: { text: '?', fontSize: 16 } },\n ports: { groups: { in: { position: 'left', attrs: { circle: { r: 4, magnet: true, stroke: '#faad14', fill: '#fff' } } }, out: { position: 'right', attrs: { circle: { r: 4, magnet: true, stroke: '#faad14', fill: '#fff' } } }, bottom: { position: 'bottom', attrs: { circle: { r: 4, magnet: true, stroke: '#faad14', fill: '#fff' } } } }, items: [{ id: 'in', group: 'in' }, { id: 'out', group: 'out' }, { id: 'bottom', group: 'bottom' }] },\n});\n\nconst approve = graph.addNode({\n shape: 'rect',\n x: 540,\n y: 190,\n width: 120,\n height: 60,\n label: 'Approve',\n attrs: { body: { fill: '#f6ffed', stroke: '#52c41a', rx: 8, ry: 8 } },\n ports: { groups: { in: { position: 'left', attrs: { circle: { r: 4, magnet: true, stroke: '#52c41a', fill: '#fff' } } }, out: { position: 'right', attrs: { circle: { r: 4, magnet: true, stroke: '#52c41a', fill: '#fff' } } } }, items: [{ id: 'in', group: 'in' }, { id: 'out', group: 'out' }] },\n});\n\nconst end = graph.addNode({\n shape: 'circle',\n x: 720,\n y: 200,\n width: 40,\n height: 40,\n attrs: { body: { fill: '#ff4d4f', stroke: '#cf1322' }, label: { text: 'End', fill: '#fff', fontSize: 11 } },\n ports: { groups: { in: { position: 'left', attrs: { circle: { r: 4, magnet: true, stroke: '#ff4d4f', fill: '#fff' } } } }, items: [{ id: 'in', group: 'in' }] },\n});\n\ngraph.addEdge({ source: { cell: start, port: 'out' }, target: { cell: submit, port: 'in' }, attrs: { line: { stroke: '#5F95FF', strokeWidth: 1, targetMarker: 'classic' } } });\ngraph.addEdge({ source: { cell: submit, port: 'out' }, target: { cell: gateway, port: 'in' }, attrs: { line: { stroke: '#5F95FF', strokeWidth: 1, targetMarker: 'classic' } } });\ngraph.addEdge({ source: { cell: gateway, port: 'out' }, target: { cell: approve, port: 'in' }, label: 'Yes', attrs: { line: { stroke: '#52c41a', strokeWidth: 1, targetMarker: 'classic' } } });\ngraph.addEdge({ source: { cell: approve, port: 'out' }, target: { cell: end, port: 'in' }, attrs: { line: { stroke: '#5F95FF', strokeWidth: 1, targetMarker: 'classic' } } });\n"
|
||
},
|
||
{
|
||
"description": "创建一个数据管道的 DAG 编辑器,支持从端口拖出连线、正交路由、节点缩放,展示数据 ETL 流程",
|
||
"codeString": "import { Graph, Transform, Snapline } from '@antv/x6';\n\nGraph.registerNode('dag-node', {\n inherit: 'rect',\n width: 140,\n height: 48,\n attrs: {\n body: { fill: '#fff', stroke: '#5F95FF', strokeWidth: 1, rx: 6, ry: 6 },\n label: { fontSize: 13, fill: '#333' },\n },\n ports: {\n groups: {\n in: { position: 'left', attrs: { circle: { r: 5, magnet: true, stroke: '#5F95FF', fill: '#fff', strokeWidth: 1 } } },\n out: { position: 'right', attrs: { circle: { r: 5, magnet: true, stroke: '#5F95FF', fill: '#fff', strokeWidth: 1 } } },\n },\n },\n}, true);\n\nconst graph = new Graph({\n container: 'container',\n width: 800,\n height: 500,\n background: { color: '#F2F7FA' },\n grid: { visible: true, size: 10 },\n connecting: {\n allowBlank: false,\n allowLoop: false,\n allowMulti: false,\n router: 'orth',\n connector: 'rounded',\n createEdge() {\n return this.createEdge({\n attrs: { line: { stroke: '#5F95FF', strokeWidth: 1, targetMarker: 'classic' } },\n });\n },\n validateConnection({ sourcePort, targetPort }) {\n return sourcePort !== targetPort;\n },\n },\n});\n\ngraph.use(new Transform({ resizing: { enabled: true, minWidth: 100, minHeight: 40 } }));\ngraph.use(new Snapline({ enabled: true }));\n\nconst extract = graph.addNode({ shape: 'dag-node', x: 40, y: 100, label: 'MySQL Source', ports: { items: [{ id: 'out-1', group: 'out' }] } });\nconst transform = graph.addNode({ shape: 'dag-node', x: 260, y: 60, label: 'Data Clean', ports: { items: [{ id: 'in-1', group: 'in' }, { id: 'out-1', group: 'out' }] } });\nconst aggregate = graph.addNode({ shape: 'dag-node', x: 260, y: 160, label: 'Aggregate', ports: { items: [{ id: 'in-1', group: 'in' }, { id: 'out-1', group: 'out' }] } });\nconst load = graph.addNode({ shape: 'dag-node', x: 500, y: 120, label: 'Write to DW', ports: { items: [{ id: 'in-1', group: 'in' }, { id: 'in-2', group: 'in' }] } });\n\ngraph.addEdge({ source: { cell: extract, port: 'out-1' }, target: { cell: transform, port: 'in-1' }, attrs: { line: { stroke: '#5F95FF', strokeWidth: 1, targetMarker: 'classic' } } });\ngraph.addEdge({ source: { cell: extract, port: 'out-1' }, target: { cell: aggregate, port: 'in-1' }, attrs: { line: { stroke: '#5F95FF', strokeWidth: 1, targetMarker: 'classic' } } });\ngraph.addEdge({ source: { cell: transform, port: 'out-1' }, target: { cell: load, port: 'in-1' }, attrs: { line: { stroke: '#5F95FF', strokeWidth: 1, targetMarker: 'classic' } } });\ngraph.addEdge({ source: { cell: aggregate, port: 'out-1' }, target: { cell: load, port: 'in-2' }, attrs: { line: { stroke: '#5F95FF', strokeWidth: 1, targetMarker: 'classic' } } });\n"
|
||
},
|
||
{
|
||
"description": "创建一个组织架构图,从 CEO 开始向下展开,使用分组和嵌套表示部门层级,边使用正交路由",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n width: 800,\n height: 500,\n background: { color: '#F2F7FA' },\n});\n\nconst createPerson = (x, y, name, title, color) => {\n return graph.addNode({\n shape: 'rect',\n x,\n y,\n width: 130,\n height: 50,\n attrs: {\n body: { fill: '#fff', stroke: color, strokeWidth: 2, rx: 6, ry: 6 },\n label: { text: `${name}\\n${title}`, fontSize: 11, lineHeight: 16 },\n },\n });\n};\n\nconst ceo = createPerson(310, 30, 'John', 'CEO', '#722ed1');\nconst cto = createPerson(120, 140, 'Alice', 'CTO', '#1890ff');\nconst cfo = createPerson(490, 140, 'Bob', 'CFO', '#faad14');\nconst lead1 = createPerson(40, 260, 'Carol', 'FE Lead', '#1890ff');\nconst lead2 = createPerson(200, 260, 'Dave', 'BE Lead', '#1890ff');\nconst acc = createPerson(430, 260, 'Eve', 'Accounting', '#faad14');\nconst fin = createPerson(570, 260, 'Frank', 'Finance', '#faad14');\n\nconst edgeStyle = { attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1, targetMarker: null } }, router: 'orth', connector: 'rounded' };\n\ngraph.addEdge({ source: ceo, target: cto, ...edgeStyle });\ngraph.addEdge({ source: ceo, target: cfo, ...edgeStyle });\ngraph.addEdge({ source: cto, target: lead1, ...edgeStyle });\ngraph.addEdge({ source: cto, target: lead2, ...edgeStyle });\ngraph.addEdge({ source: cfo, target: acc, ...edgeStyle });\ngraph.addEdge({ source: cfo, target: fin, ...edgeStyle });\n"
|
||
},
|
||
{
|
||
"description": "使用 fromJSON 批量加载一个完整的微服务调用关系图,展示多个服务节点之间的 HTTP/gRPC 调用链路",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n width: 800,\n height: 500,\n background: { color: '#F2F7FA' },\n grid: { visible: true, size: 10 },\n panning: true,\n mousewheel: { enabled: true, modifiers: 'ctrl' },\n});\n\ngraph.fromJSON({\n nodes: [\n { id: 'gateway', shape: 'rect', x: 60, y: 180, width: 100, height: 44, label: 'API Gateway', attrs: { body: { fill: '#e6f7ff', stroke: '#1890ff', rx: 6, ry: 6 } } },\n { id: 'user-svc', shape: 'rect', x: 240, y: 80, width: 120, height: 44, label: 'User Service', attrs: { body: { fill: '#f6ffed', stroke: '#52c41a', rx: 6, ry: 6 } } },\n { id: 'order-svc', shape: 'rect', x: 240, y: 180, width: 120, height: 44, label: 'Order Service', attrs: { body: { fill: '#f6ffed', stroke: '#52c41a', rx: 6, ry: 6 } } },\n { id: 'pay-svc', shape: 'rect', x: 240, y: 280, width: 120, height: 44, label: 'Payment Service', attrs: { body: { fill: '#f6ffed', stroke: '#52c41a', rx: 6, ry: 6 } } },\n { id: 'mysql', shape: 'rect', x: 480, y: 80, width: 100, height: 44, label: 'MySQL', attrs: { body: { fill: '#fff2e8', stroke: '#fa8c16', rx: 6, ry: 6 } } },\n { id: 'redis', shape: 'rect', x: 480, y: 180, width: 100, height: 44, label: 'Redis', attrs: { body: { fill: '#fff2e8', stroke: '#fa8c16', rx: 6, ry: 6 } } },\n { id: 'mq', shape: 'rect', x: 480, y: 280, width: 100, height: 44, label: 'RocketMQ', attrs: { body: { fill: '#fff2e8', stroke: '#fa8c16', rx: 6, ry: 6 } } },\n ],\n edges: [\n { source: 'gateway', target: 'user-svc', label: 'HTTP', attrs: { line: { stroke: '#1890ff', strokeWidth: 1, targetMarker: 'classic' } }, router: 'orth' },\n { source: 'gateway', target: 'order-svc', label: 'HTTP', attrs: { line: { stroke: '#1890ff', strokeWidth: 1, targetMarker: 'classic' } }, router: 'orth' },\n { source: 'gateway', target: 'pay-svc', label: 'HTTP', attrs: { line: { stroke: '#1890ff', strokeWidth: 1, targetMarker: 'classic' } }, router: 'orth' },\n { source: 'user-svc', target: 'mysql', label: 'TCP', attrs: { line: { stroke: '#52c41a', strokeWidth: 1, targetMarker: 'classic' } } },\n { source: 'order-svc', target: 'redis', label: 'TCP', attrs: { line: { stroke: '#52c41a', strokeWidth: 1, targetMarker: 'classic' } } },\n { source: 'order-svc', target: 'mq', label: 'gRPC', attrs: { line: { stroke: '#52c41a', strokeWidth: 1, targetMarker: 'classic' } } },\n { source: 'pay-svc', target: 'mq', label: 'Pub', attrs: { line: { stroke: '#52c41a', strokeWidth: 1, targetMarker: 'classic' } } },\n ],\n});\n"
|
||
},
|
||
{
|
||
"description": "搭建一个完整的流程图编辑器,集成 Selection、Snapline、History、Keyboard 插件,支持框选、撤销重做、快捷键删除",
|
||
"codeString": "import { Graph, Selection, Snapline, History, Keyboard, Clipboard } from '@antv/x6';\n\nconst graph = new Graph({\n container: 'container',\n width: 800,\n height: 500,\n background: { color: '#F2F7FA' },\n grid: { visible: true, size: 10 },\n panning: { enabled: true, modifiers: 'shift' },\n mousewheel: { enabled: true, modifiers: 'ctrl' },\n connecting: {\n allowBlank: false,\n router: 'manhattan',\n connector: 'rounded',\n createEdge() {\n return this.createEdge({\n attrs: { line: { stroke: '#5F95FF', strokeWidth: 1, targetMarker: 'classic' } },\n });\n },\n },\n});\n\ngraph.use(new Selection({ enabled: true, rubberband: true, multiple: true }));\ngraph.use(new Snapline({ enabled: true }));\ngraph.use(new History({ enabled: true }));\ngraph.use(new Keyboard({ enabled: true }));\ngraph.use(new Clipboard({ enabled: true }));\n\ngraph.bindKey('backspace', () => {\n const cells = graph.getSelectedCells();\n if (cells.length) graph.removeCells(cells);\n});\ngraph.bindKey(['ctrl+z', 'meta+z'], () => graph.undo());\ngraph.bindKey(['ctrl+shift+z', 'meta+shift+z'], () => graph.redo());\ngraph.bindKey(['ctrl+c', 'meta+c'], () => graph.copy(graph.getSelectedCells()));\ngraph.bindKey(['ctrl+v', 'meta+v'], () => graph.paste());\n\nGraph.registerNode('flow-node', {\n inherit: 'rect',\n width: 120,\n height: 48,\n attrs: { body: { fill: '#fff', stroke: '#5F95FF', strokeWidth: 1, rx: 6, ry: 6 }, label: { fontSize: 13 } },\n ports: {\n groups: {\n top: { position: 'top', attrs: { circle: { r: 4, magnet: true, stroke: '#5F95FF', fill: '#fff' } } },\n bottom: { position: 'bottom', attrs: { circle: { r: 4, magnet: true, stroke: '#5F95FF', fill: '#fff' } } },\n left: { position: 'left', attrs: { circle: { r: 4, magnet: true, stroke: '#5F95FF', fill: '#fff' } } },\n right: { position: 'right', attrs: { circle: { r: 4, magnet: true, stroke: '#5F95FF', fill: '#fff' } } },\n },\n items: [{ group: 'top' }, { group: 'bottom' }, { group: 'left' }, { group: 'right' }],\n },\n}, true);\n\nconst start = graph.addNode({ shape: 'flow-node', x: 320, y: 40, label: 'Start', attrs: { body: { fill: '#d9f7be', stroke: '#52c41a' } }, ports: { items: [{ group: 'bottom' }] } });\nconst process1 = graph.addNode({ shape: 'flow-node', x: 320, y: 140, label: 'Process Data' });\nconst decision = graph.addNode({ shape: 'polygon', x: 345, y: 250, width: 50, height: 50, attrs: { body: { fill: '#fffbe6', stroke: '#faad14', refPoints: '0,10 10,0 20,10 10,20' }, label: { text: 'OK?' } }, ports: { groups: { right: { position: 'right', attrs: { circle: { r: 4, magnet: true, stroke: '#faad14', fill: '#fff' } } }, bottom: { position: 'bottom', attrs: { circle: { r: 4, magnet: true, stroke: '#faad14', fill: '#fff' } } }, top: { position: 'top', attrs: { circle: { r: 4, magnet: true, stroke: '#faad14', fill: '#fff' } } } }, items: [{ group: 'top' }, { group: 'right' }, { group: 'bottom' }] } });\nconst end = graph.addNode({ shape: 'flow-node', x: 320, y: 360, label: 'End', attrs: { body: { fill: '#fff1f0', stroke: '#ff4d4f' } }, ports: { items: [{ group: 'top' }] } });\n\ngraph.addEdge({ source: start, target: process1, attrs: { line: { stroke: '#5F95FF', strokeWidth: 1, targetMarker: 'classic' } } });\ngraph.addEdge({ source: process1, target: decision, attrs: { line: { stroke: '#5F95FF', strokeWidth: 1, targetMarker: 'classic' } } });\ngraph.addEdge({ source: decision, target: end, label: 'Yes', attrs: { line: { stroke: '#52c41a', strokeWidth: 1, targetMarker: 'classic' } } });\n"
|
||
},
|
||
{
|
||
"description": "创建一个数据血缘追踪图,展示源表通过多层 ETL 转换生成目标宽表的完整链路,节点按层级从左到右排列",
|
||
"codeString": "import { Graph } from '@antv/x6';\n\nGraph.registerNode('lineage-node', {\n inherit: 'rect',\n width: 130,\n height: 40,\n attrs: {\n body: { fill: '#fff', stroke: '#d9d9d9', strokeWidth: 1, rx: 4, ry: 4 },\n label: { fontSize: 12 },\n },\n ports: {\n groups: {\n in: { position: 'left', attrs: { circle: { r: 4, magnet: true, stroke: '#8f8f8f', fill: '#fff' } } },\n out: { position: 'right', attrs: { circle: { r: 4, magnet: true, stroke: '#8f8f8f', fill: '#fff' } } },\n },\n },\n}, true);\n\nconst graph = new Graph({\n container: 'container',\n width: 800,\n height: 450,\n background: { color: '#F2F7FA' },\n panning: true,\n mousewheel: { enabled: true, modifiers: 'ctrl' },\n});\n\n// Source layer\nconst src1 = graph.addNode({ shape: 'lineage-node', x: 30, y: 80, label: 'ods_user', attrs: { body: { stroke: '#1890ff' } }, ports: { items: [{ id: 'out', group: 'out' }] } });\nconst src2 = graph.addNode({ shape: 'lineage-node', x: 30, y: 160, label: 'ods_order', attrs: { body: { stroke: '#1890ff' } }, ports: { items: [{ id: 'out', group: 'out' }] } });\nconst src3 = graph.addNode({ shape: 'lineage-node', x: 30, y: 240, label: 'ods_payment', attrs: { body: { stroke: '#1890ff' } }, ports: { items: [{ id: 'out', group: 'out' }] } });\n\n// DWD layer\nconst dwd1 = graph.addNode({ shape: 'lineage-node', x: 240, y: 120, label: 'dwd_user_order', attrs: { body: { stroke: '#722ed1' } }, ports: { items: [{ id: 'in1', group: 'in' }, { id: 'in2', group: 'in' }, { id: 'out', group: 'out' }] } });\nconst dwd2 = graph.addNode({ shape: 'lineage-node', x: 240, y: 220, label: 'dwd_order_pay', attrs: { body: { stroke: '#722ed1' } }, ports: { items: [{ id: 'in1', group: 'in' }, { id: 'in2', group: 'in' }, { id: 'out', group: 'out' }] } });\n\n// DWS layer\nconst dws = graph.addNode({ shape: 'lineage-node', x: 460, y: 160, label: 'dws_user_summary', attrs: { body: { stroke: '#fa8c16' } }, ports: { items: [{ id: 'in1', group: 'in' }, { id: 'in2', group: 'in' }, { id: 'out', group: 'out' }] } });\n\n// ADS layer\nconst ads = graph.addNode({ shape: 'lineage-node', x: 660, y: 160, label: 'ads_dashboard', attrs: { body: { stroke: '#52c41a', strokeWidth: 2 } }, ports: { items: [{ id: 'in', group: 'in' }] } });\n\nconst edgeAttrs = { attrs: { line: { stroke: '#8f8f8f', strokeWidth: 1, targetMarker: 'classic' } }, router: 'orth', connector: 'rounded' };\ngraph.addEdge({ source: { cell: src1, port: 'out' }, target: { cell: dwd1, port: 'in1' }, ...edgeAttrs });\ngraph.addEdge({ source: { cell: src2, port: 'out' }, target: { cell: dwd1, port: 'in2' }, ...edgeAttrs });\ngraph.addEdge({ source: { cell: src2, port: 'out' }, target: { cell: dwd2, port: 'in1' }, ...edgeAttrs });\ngraph.addEdge({ source: { cell: src3, port: 'out' }, target: { cell: dwd2, port: 'in2' }, ...edgeAttrs });\ngraph.addEdge({ source: { cell: dwd1, port: 'out' }, target: { cell: dws, port: 'in1' }, ...edgeAttrs });\ngraph.addEdge({ source: { cell: dwd2, port: 'out' }, target: { cell: dws, port: 'in2' }, ...edgeAttrs });\ngraph.addEdge({ source: { cell: dws, port: 'out' }, target: { cell: ads, port: 'in' }, ...edgeAttrs });\n"
|
||
}
|
||
] |