如何防止jointjs / rappid中的循环

时间:2018-03-03 21:32:56

标签: jointjs

我正在构建一个使用jointjs / rappid的应用程序,我希望能够避免在多个单元格中发生循环。

Jointjs已经有一些关于如何在单个单元中避免这种情况的例子(将“out”端口连接到同一单元的“in”端口),但没有关于如何检测和防止循环进一步发生的问题。链条。

为了帮助理解,想象一下论文中的每个单元格都是一个完成的步骤。每一步都应该只运行一次。如果最后一步有一个“out”端口连接到第一个单元的“in”端口,它将永远循环。这是我想要避免的。

非常感谢任何帮助。

2 个答案:

答案 0 :(得分:3)

我实际上为其他希望实现相同目标的人找到了一个非常简单的方法。只需包含graphlib依赖性并使用以下内容:

        paper.on("link:connect", function(linkView) {
            if(graphlib.alg.findCycles(graph.toGraphLib()).length > 0) {
                linkView.model.remove();
                // show some error message here
            }
        });

这一行:

graphlib.alg.findCycles(graph.toGraphLib())

返回包含任何循环的数组,因此通过检查长度,我们可以确定纸张是否包含任何循环,如果是,则删除用户尝试创建的链接。

注意:这不是完全完全证明的,因为如果论文已经包含一个循环(在用户添加链接之前),那么只删除用户正在创建的链接将不会删除任何存在的循环。对我来说这很好,因为我的所有论文都是从头开始创建的,只要这个逻辑始终存在,就不会创建循环。

答案 1 :(得分:2)

通过graphlib解决方案

基于Adam's graphlib solution,而不是findCycles来测试循环,graphlib文档建议使用isAcyclic function,其中:

  如果图表没有周期,则

返回true,如果图表没有,则返回false。该算法在检测到第一个周期后立即返回

因此这个条件:

if(graphlib.alg.findCycles(graph.toGraphLib()).length > 0)

可缩短为:

if(!graphlib.alg.isAcyclic(graph))

JointJS功能解决方案

查找新连接元素的ancestorssuccessor数组以及intersect个数组:

// invoke inside an event which tests if a specific `connectedElement` is part of a loop

function isElementPartOfLoop (graph, connectedElement) {
  var elemSuccessors = graph.getSuccessors(connectedElement, {deep: true});

  var elemAncestors = connectedElement.getAncestors();
  //       *** OR *** graph.getPredecessors(connectedElement, {deep: true});

  var commonElements = _.intersection(elemSuccessors, elemAncestors);

  // if an element is repeated (non-empty intersection), then it's part of a loop
  return !_.isEmpty(commonElements);
}

我没有对此进行测试,但您尝试完成的测试背后的理论应该是相似的。 此解决方案不如直接使用graphlib函数那样高效。

预防

阻止链接添加到图表的一种方法是在事件中处理它:

graph.on('add', _.bind(addCellOps, graph));

function addCellOps (cell, collection, opt) {
  if (cell.isLink()){
    // test link's target element: if it is part of a loop, remove the link
    var linkTarget = cell.getTargetElement();
    // `this` is the graph
    if(target && isElementPartOfLoop(this, linkTarget)){
      cell.remove();
    }
  }
  // other operations ....
}