如何在Angular/JS/TypeScript中基于GoJS实现自定义拖拽决策树UI?
GoJS 自定义拖拽决策树UI实现示例
下面是覆盖你需求的完整可运行代码,包含节点增删、链接管理和节点选项功能,关键部分都加了注释:
<!DOCTYPE html> <html> <head> <script src="https://unpkg.com/gojs"></script> <style> #myDiagramDiv { width: 1000px; height: 600px; border: 1px solid #ccc; } .button { margin: 5px; padding: 8px; cursor: pointer; background: #eee; border: none; border-radius: 4px; } </style> </head> <body> <div id="myDiagramDiv"></div> <div> <button class="button" onclick="addNode()">添加节点</button> <button class="button" onclick="deleteSelected()">删除选中项</button> </div> <script> var $ = go.GraphObject.make; // 初始化画布配置 var myDiagram = $(go.Diagram, "myDiagramDiv", { initialContentAlignment: go.Spot.Center, undoManager: true, // 开启撤销/重做,方便操作 allowDrop: true, // 允许拖拽节点 // 开启拖拽创建链接功能 linkingTool: { isEnabled: true, direction: go.LinkingTool.ForwardsOnly, // 只允许从节点输出端发起链接 doActivate: function() { go.LinkingTool.prototype.doActivate.call(this); this.temporaryLink.routing = go.Link.AvoidsNodes; // 临时链接自动避开节点 } }, // 点击空白处快速创建节点 clickCreatingTool: { archetypeNodeData: { text: "新节点", options: [] } } }); // 节点模板定义 myDiagram.nodeTemplate = $(go.Node, "Auto", { movable: true, // 允许拖拽节点 deletable: true, // 按Delete键可删除节点 // 右键菜单:用于添加/管理选项 contextMenu: $(go.Adornment, "Vertical", $(go.TextBlock, "添加选项", { margin: 4, cursor: "pointer", click: addOption }), $(go.TextBlock, "删除选中选项", { margin: 4, cursor: "pointer", click: deleteSelectedOptions }) ) }, $(go.Shape, "RoundedRectangle", { fill: "#5BC0EB", strokeWidth: 2 }), $(go.Panel, "Vertical", // 节点标题 $(go.TextBlock, { margin: 8, font: "bold 14px sans-serif" }, new go.Binding("text", "text") ), // 选项列表容器 $(go.ListBox, { name: "OPTIONS_LIST", itemTemplate: $(go.Panel, "Horizontal", $(go.TextBlock, { margin: 4 }, new go.Binding("text")), $(go.Shape, "X", { width: 12, height: 12, fill: "#d9534f", margin: 4, cursor: "pointer", click: deleteSingleOption }) ), width: 180, height: 100, background: "#f8f9fa", selectionMode: go.ListBox.Single // 支持单选选项 }, new go.Binding("itemArray", "options") ) ) ); // 链接模板定义 myDiagram.linkTemplate = $(go.Link, { deletable: true, // 按Delete键可删除链接 routing: go.Link.AvoidsNodes, // 链接自动避开节点 corner: 5 // 链接转角圆角 }, $(go.Shape, { strokeWidth: 2 }), $(go.Shape, { toArrow: "Standard", stroke: null }) ); // 初始化决策树数据 myDiagram.model = new go.GraphLinksModel( [ { key: 1, text: "根节点", options: ["开始调研", "确认需求"] }, { key: 2, text: "执行方案A", options: [] }, { key: 3, text: "执行方案B", options: [] } ], [ { from: 1, to: 2 }, { from: 1, to: 3 } ] ); // 按钮触发添加节点 function addNode() { var newKey = myDiagram.model.nodeDataArray.length + 1; myDiagram.model.addNodeData({ key: newKey, text: "节点" + newKey, options: [] }); } // 删除选中的节点/链接 function deleteSelected() { var selection = myDiagram.selection; if (selection.count === 0) return; myDiagram.startTransaction("delete selection"); selection.each(function(part) { if (part instanceof go.Node) { myDiagram.model.removeNodeData(part.data); } else if (part instanceof go.Link) { myDiagram.model.removeLinkData(part.data); } }); myDiagram.commitTransaction("delete selection"); } // 右键菜单:给节点添加选项 function addOption(e, obj) { var node = obj.part.adornedPart; var input = prompt("请输入选项内容:"); if (!input) return; myDiagram.model.startTransaction("add option"); var updatedOptions = [...node.data.options, input]; myDiagram.model.setDataProperty(node.data, "options", updatedOptions); myDiagram.commitTransaction("add option"); } // 删除单个选项(点击选项旁的X) function deleteSingleOption(e, obj) { var item = obj.part; var listBox = item.panel; var node = listBox.part; var index = listBox.items.indexOf(item); if (index < 0) return; myDiagram.model.startTransaction("delete single option"); var updatedOptions = [...node.data.options]; updatedOptions.splice(index, 1); myDiagram.model.setDataProperty(node.data, "options", updatedOptions); myDiagram.commitTransaction("delete single option"); } // 右键菜单:删除选中的选项 function deleteSelectedOptions(e, obj) { var node = obj.part.adornedPart; var listBox = node.findObject("OPTIONS_LIST"); var selectedItems = listBox.selectedItems; if (selectedItems.count === 0) return; myDiagram.model.startTransaction("delete selected options"); var updatedOptions = [...node.data.options]; // 倒序删除,避免索引偏移 for (var i = selectedItems.count - 1; i >= 0; i--) { var item = selectedItems.elt(i); var idx = listBox.items.indexOf(item); if (idx >= 0) updatedOptions.splice(idx, 1); } myDiagram.model.setDataProperty(node.data, "options", updatedOptions); myDiagram.commitTransaction("delete selected options"); } </script> </body> </html>
功能说明
1. 节点与链接管理
- 创建链接:拖拽任意节点的边缘到另一个节点,即可自动生成链接;也可以通过点击空白处创建新节点后,拖拽链接到已有节点。
- 删除链接/节点:选中目标节点或链接,按
Delete键,或者点击页面上的「删除选中项」按钮即可删除。 - 添加节点:点击「添加节点」按钮快速创建,或直接点击画布空白处生成新节点。
2. 节点选项管理
- 添加选项:右键点击节点,选择「添加选项」,输入内容后确认即可添加到节点的选项列表。
- 删除选项:点击选项右侧的红色「X」删除单个选项;或右键节点选择「删除选中选项」,先在列表中选中要删除的选项再执行删除。
内容的提问来源于stack exchange,提问作者Margaret Nguyen
相关产品推荐
相关产品推荐

