跳过 GoJS 图中 2 个节点之间路径上的所有节点

Skip all nodes on path between 2 nodes in GoJS diagram

我有一个 GoJS 图表,我想在其中 hide/unhide 任意 2 个选定节点之间的路径上的所有节点。

例如图中 A --> B --> C --> D

我想隐藏B和C节点所以变成这样 A --(2)--> D

其中(2)表示隐藏了2个节点。 当然图表可能要复杂得多,我想 hide/unhide 任意节点。

我尝试在 2 个节点之间对项目进行分组,这适用于某些情况,但由于可能存在要隐藏的节点已经是组的一部分 - 我被卡住了。

在 GoJS 中是否有开箱即用的(或明显的)解决方案?

感谢

以下代码假定您不想在模型中存储虚拟节点。隐藏节点不可见,并且虚拟节点通过虚拟链接与现在隐藏节点所连接的相同未选择节点连接。

<!DOCTYPE html>
<html>
<head>
<title>Simple Coalescing of Nodes without using Collapsed Groups</title>
<!-- Copyright 1998-2020 by Northwoods Software Corporation. -->
<meta charset="UTF-8">
<script src="https://unpkg.com/gojs"></script>
<script id="code">
  function init() {
    var $ = go.GraphObject.make;

    myDiagram =
      $(go.Diagram, "myDiagramDiv",
          {
            layout: $(go.ForceDirectedLayout,
                      { maxIterations: 500, isRealtime: false }),
            "InitialLayoutCompleted": function(e) {
              e.diagram.nodes.each(function(g) {
                if (g instanceof go.Group) g.layout = null;
              });
            },
            "undoManager.isEnabled": true
          });

    myDiagram.nodeTemplate =
      $(go.Node, "Auto",
        { width: 80, height: 50 },
        $(go.Shape,
          { fill: "white", portId: "", fromLinkable: true, toLinkable: true, cursor: "pointer" },
          new go.Binding("fill", "color")),
        $(go.TextBlock, { textAlign: "center" },
          new go.Binding("text"))
      );

    myDiagram.linkTemplate =
      $(go.Link,
        { relinkableFrom: true, relinkableTo: true },
        $(go.Shape),
        $(go.Shape, { toArrow: "OpenTriangle" })
      );

    myDiagram.groupTemplate =
      $(go.Group, "Auto",
        { layout: $(go.CircularLayout) },
        $(go.Shape, { fill: "#8882" }),
        $(go.Placeholder, { padding: 8 }),
        $(go.TextBlock, { font: "bold 12pt sans-serif" },
          new go.Binding("text", "key"))
      )

    myDiagram.model = new go.GraphLinksModel(
    [
      { key: 1, text: "Concept Maps" },
      { key: 2, text: "Organized Knowledge" },
      { key: 3, text: "Context Dependent" },
      { key: 4, text: "Concepts", group: "G1" },
      { key: 5, text: "Propositions", group: "G1" },
      { key: 6, text: "Associated Feelings or Affect", group: "G1" },
      { key: 7, text: "Perceived Regularities" },
      { key: 8, text: "Labeled" },
      { key: 9, text: "Hierarchically Structured" },
      { key: 10, text: "Effective Teaching", group: "G2" },
      { key: 11, text: "Crosslinks", group: "G2" },
      { key: 12, text: "Effective Learning" },
      { key: 13, text: "Events (Happenings)" },
      { key: 14, text: "Objects (Things)" },
      { key: 15, text: "Symbols", group: "G3" },
      { key: 16, text: "Words", group: "G3" },
      { key: 17, text: "Creativity", group: "G3" },
      { key: 18, text: "Interrelationships" },
      { key: 19, text: "Infants" },
      { key: 20, text: "Different Map Segments" },
      { key: "G1", isGroup: true },
      { key: "G2", isGroup: true },
      { key: "G3", isGroup: true }
    ],
    [
      { from: 1, to: 2, text: "represent" },
      { from: 2, to: 3, text: "is" },
      { from: 2, to: 4, text: "is" },
      { from: 2, to: 5, text: "is" },
      { from: 2, to: 6, text: "includes" },
      { from: 2, to: 10, text: "necessary\nfor" },
      { from: 2, to: 12, text: "necessary\nfor" },
      { from: 4, to: 5, text: "combine\nto form" },
      { from: 4, to: 6, text: "include" },
      { from: 4, to: 7, text: "are" },
      { from: 4, to: 8, text: "are" },
      { from: 4, to: 9, text: "are" },
      { from: 5, to: 9, text: "are" },
      { from: 5, to: 11, text: "may be" },
      { from: 7, to: 13, text: "in" },
      { from: 7, to: 14, text: "in" },
      { from: 7, to: 19, text: "begin\nwith" },
      { from: 8, to: 15, text: "with" },
      { from: 8, to: 16, text: "with" },
      { from: 9, to: 17, text: "aids" },
      { from: 11, to: 18, text: "show" },
      { from: 12, to: 19, text: "begins\nwith" },
      { from: 17, to: 18, text: "needed\nto see" },
      { from: 18, to: 20, text: "between" }
    ]);
  }

  function test() {
    if (myDiagram.selection.count === 0) return;
    if (myDiagram.selection.count === 1 && myDiagram.selection.first().hidden !== null) {
      // only expand a single coalesced node (dummy) at a time
      myDiagram.commit(function(diag) {
        var dummy = diag.selection.first();
        diag.remove(dummy);  // also removes connected links that are dummies
        dummy.hidden.each(function(n) {
          n.visible = true;
        });
        diag.selectCollection(dummy.hidden);
      }, "expanded");
    } else {
      myDiagram.commit(function(diag) {
        var $ = go.GraphObject.make;
        var dummy = $(go.Node, "Auto",
                      { locationSpot: go.Spot.Center },
                      $(go.Shape, "Circle", { fill: "yellow" }),
                      $(go.TextBlock, "hidden\nnodes", { textAlign: "center" })
                    );
        dummy.hidden = new go.Set();  // keep track of the nodes that it represents
        diag.selection.each(function(n) {
          if (n instanceof go.Node) {
            dummy.hidden.add(n);
            n.visible = false;
            new go.List(n.linksConnected).each(function(l) {
              if (!l.fromNode.isSelected || !l.toNode.isSelected) {
                var dum = $(go.Link,
                            $(go.Shape, { stroke: "brown" }),
                            $(go.Shape, { toArrow: "OpenTriangle", stroke: "brown" }));
                if (!l.fromNode.isSelected) dum.fromNode = l.fromNode;
                if (!l.toNode.isSelected) dum.toNode = l.toNode;
                if (!dum.fromNode) dum.fromNode = dummy;
                if (!dum.toNode) dum.toNode = dummy;
                diag.add(dum);
              }
            });
          }
        });
        dummy.location = diag.computePartsBounds(diag.selection).center;
        diag.add(dummy);
        diag.select(dummy);
      }, "coalesced nodes");
    }
  }
</script>
</head>
<body onload="init()">
  <div id="myDiagramDiv" style="border: solid 1px black; width:100%; height:600px"></div>
  <button onclick="test()">Test</button> to hide selected nodes,
  replaced by a temporary yellow node and temporary brown links that are not in the model
</body>
</html>