根据边的数据和目标的数据选择边

Selecting edges based on both edge's data and target's data

我想要一个边缘匹配的选择器

edge[type="blocker"]

目标匹配

node[status="complete"]

换句话说,是否有一种有效的表达方式:

cytoscape({
   ...
   style: [
      ...
      {
         selector: '( node -> node[status="complete"] )[type="blocker"]',
         style: {
            display: 'none',
         },
      },
      ...
   ],
   ...
})

我在 documentation 中看不到这样做的方法。

显然,我可以将目标的数据复制到节点的数据中并使用以下命令:

edge[type="blocker"][target_status="complete"]

但是复制数据违背了我作为软件开发人员的每一个本能。

您可以为过滤方法提供功能:

cy.edges().filter(function(ele) {
    return ele.data('type') == 'blocker' &&
        ele.target().data('status') == 'complete';
})

这个怎么样 编辑:

var selectedEdges = cy.nodes("[status= 'complete']").connectedEdges("[type = 'blocker']);
var selectedEdges.addClass('specialSnowflake')

在您的样式表中,只需定义:

{
   "selector": "edge.specialSnowflake",
   "style": { 
      "display": "none"
   }
}

没有可以提供帮助的选择器。


但是,可以避免在数据更改时必须手动更新两个元素。

样式 sheet 每次匹配元素的数据更改时都会调用值函数。在其中一个函数中,可以因此在每次更新节点数据时更新传入边的数据,从而自动保持两者的数据同步。

var push_status = function(node) {
   node.incomers('edge').forEach( edge => edge.data('target_status', node.data('status')) );
   node.outgoers('edge').forEach( edge => edge.data('source_status', node.data('status')) );
};

cytoscape({
   ...
   style: [
      ...
      {
         selector: 'node',
         style: {
            label: node => { push_status(node); return node.data('id'); },
         },
      },
      {
         selector: 'edge[type="blocker"][target_status="complete"]',
         style: {
            display: 'none',
         },
      },
      ...
   ],
   ...
})

这可以算作黑客攻击,但效果很好。更新节点的数据会更新边的数据,这会导致根据需要应用或取消应用样式。


小心创建无限循环!特别是,修改节点父节点的数据将触发节点样式的计算。这个问题可以通过更换

来避免
ele.data('key', val)

// Making changes to a element's data triggers a style recalculation.
// This avoids needlessly triggering the style recalculation.
var set_data = function(node, key, new_val) {
   let old_val = node.data(key);
   if (new_val != old_val)
       node.data(key, new_val);
};

set_data(ele, 'key', val)

如果选择器不够用,那么您可以 (1) 建议一个新功能来增强边缘 -> 选择器,甚至可以为它创建一个 PR,或者 (2) 在样式上使用一个函数属性 而不是。

例如对于 (2):

{ selector: 'edge', style: { display: edgeIsDisplayed } }

函数可以是任何东西,比如edgeIsDisplayed(edge) => edge.data('foo') === 'bar' && edge.target().hasClass('baz')

http://js.cytoscape.org/#style/mappers