GoJs实现切换上级节点

187 阅读3分钟

前言

在可视化图形的树形图或者流程图等图形中,不是靠中间的连线来表明两个节点之间的关系,而是通过上下级关系来表明两者之间的父子关系,因此在拓展整个图形的时候会出现新增下级节点,在新增下级节点的时候有的时候会出现信息录错位置的现象,如果节点的数据比较复杂。则删除重新新增的成本就比较大,因此本文从切换父级节点的功能进行一个实现。

准备工作

我们先准备一个基础的数据结构,然后在这个结构的基础上进行新增拓展。首先我们的数据如下

nodes: [
  { key: "1", text: "三国",parent:0  },
  { key: "1-1", text: "魏",parent:1  },
  { key: "1-2", text: "蜀",parent:1 },
  { key: "1-3", text: "吴",parent:1  },
],
links: [
  {
    from: "1",
    to: "1-1",
  },
  {
    from: "1",
    to: "1-2",
  },
  {
    from: "1",
    to: "1-3",
  },
],

let changeSVG = "M496 192h-480c0 0-0.001 0-0.001 0-8.836 0-15.999-7.163-15.999-16 0-4.418 1.791-8.418 4.686-11.314l128-128c2.895-2.896 6.895-4.686 11.314-4.686 8.837 0 16 7.163 16 16 0 4.418-1.791 8.418-4.686 11.313l-100.686 100.687h441.372c8.837 0 16 7.163 16 16s-7.163 16-16 16v0zM16 320h480c0 0 0 0 0 0 8.837 0 16 7.163 16 16 0 4.418-1.791 8.418-4.687 11.314l-128 128c-2.894 2.885-6.887 4.668-11.296 4.668-8.837 0-16-7.163-16-15.999 0-4.41 1.784-8.403 4.669-11.297l100.686-100.686h-441.373c-0.009 0-0.020 0-0.031 0-8.836 0-16-7.163-16-16s7.163-16 16-16c0.011 0 0.022 0 0.033 0h-0.002z"
let addSVG = "M464 272h-192v192c0 8.837-7.163 16-16 16s-16-7.163-16-16v0-192h-192c-8.837 0-16-7.163-16-16s7.163-16 16-16v0h192v-192c0-8.837 7.163-16 16-16s16 7.163 16 16v0 192h192c8.837 0 16 7.163 16 16s-7.163 16-16 16v0z"
let changeIcon = go.Geometry.parse(changeSVG, true);
let addIcon = go.Geometry.parse(addSVG, true);
this.myDiagram = $$(go.Diagram, "myDiagramDiv", {
  layout: $$(go.TreeLayout),
});
this.myDiagram.nodeTemplate = $$(
  go.Node,
  "Auto",
  $$(
    go.Shape,
    "Rectangle",
    { fill:"#0000FF" },
  ),
  $$(
    go.Panel,"Horizontal",{margin:new go.Margin(3,10)},
    $$(go.TextBlock,{stroke:"#FFF",margin:new go.Margin(3,10), font: "23px 微软雅黑,sans-serif ",editable: true,}, new go.Binding("text", "text")),
    $$(go.Panel,"Auto",$$(go.Shape, "Rectangle", {strokeWidth: 0,width: 50,height: 50,cursor: "pointer",click: this.changeNode,fill: "transparent",}),
    $$(go.Shape,{fill:"#FFF",width: 50,click: this.changeNode,margin:new go.Margin(3,10), height: 50,geometry:changeIcon}),),
    $$(go.Panel,"Auto",$$(go.Shape, "Rectangle", {strokeWidth: 0,width: 50,height: 50,cursor: "pointer",click: this.addNewNode,fill: "transparent",}),
    $$(go.Shape,{fill:"#FFF",width: 50,click: this.addNewNode,margin:new go.Margin(3,10), height: 50,geometry:addIcon}))
  ),
);

为了方便演示,我们修改了节点的显示样式,并且在每个节点增加了两个svg图标,分别是切换和添加的图标。在nodes的数据中,引入了parent字段是为了在新增节点的时候可以查询到父级节点的数据从而判断新增的节点的key值辅助。在布局上使用了层级更加明显的树形布局。并且在绘图模板上go.Shape使用SVG图形的时候,增加了透明的背景,以保证在点击的时候避免点击图标的空白处无法触发click事件的情况。

点击加号图标新增下级节点

由上面的准备代码可以看出,在加号图标的click事件绑定了一个方法为addNewNode方法。其内容如下

addNewNode(code,obj){
    let nodeData = obj.part.data
    let newNodeData = {text:"新增节点",parent:nodeData.key}
    let newLinkData = {}
    let newKey = JSON.parse(JSON.stringify(nodeData.key + "-" + this.getNewNum(nodeData.key)));
    newNodeData.key = newKey
    newLinkData.from = nodeData.key
    newLinkData.to = newKey
    this.myDiagram.model.addNodeData(newNodeData);
    this.myDiagram.model.addLinkData(newLinkData);
},

动画.gif

通过计算获取到新增的节点的key值,也可以根据自己的key值使用规则来定义,或者可以生成id来获取也可以。然后分别使用addNodeDataaddLinkData来实现对节点和连线的新增。在上面的nodeTemplate中对go.TextBlock文本增加了编辑功能,可以修改的新增节点的文本信息。

点击切换图标修改操作节点的父级节点

changeNode(code, obj) {
  this.changeParent = true;
  this.oldNodeData = obj;
},

this.myDiagram.addDiagramListener("ChangedSelection", function (e) {
    if (_this.changeParent) {
      var node = e.diagram.selection.first();
      var nodeOld = _this.myDiagram.findNodeForKey(
        _this.oldNodeData.part.data.key
      );
      nodeOld.findLinksInto().each(function (link) {
        _this.myDiagram.model.setDataProperty(
          link.data,
          "from",
          node.data.key
        );
      });
      _this.changeParent = false;
    }
});

动画.gif 通过addDiagramListener来监听ChangedSelection,也就是选择节点的变化事件。然后为了不一直切换父级节点,所以增加一个changeParent的标识。然后通过setDataProperty设置修改进入被切换节点的连线然后更改该连线的from值。

总结

切换上级节点是通过记录旧的选择节点和监听新的点击节点,然后切换更新对应的数据完成切换上级节点。