【问题标题】:D3 Dynamic hierarchical edge bundling - 2 way importD3 动态分层边缘捆绑 - 2 路导入
【发布时间】:2014-10-02 16:01:00
【问题描述】:

我正在尝试创建基于 M Bostock (http://bl.ocks.org/mbostock/7607999) 实现的动态分层边缘捆绑:

我的数据集的 bl.ocks 版本在这里:http://bl.ocks.org/ratnakarv/91ace0b5f77fff5ef0ab

与原来的不同,节点 1 和节点 2 之间的关系是一种方式(即节点 1 可以导入节点 2 或其他方式),在我的数据集中,节点 1 和节点 2 可以有两种方式的导入关系.这在业务流程中经常发生,这就是我的应用程序。

  • 当前挑战:

在此示例中,“评估”导入“创建 QOS 降级报告”,“创建 QOS...”也导入“评估”。但是当鼠标悬停时,'Assess', node - 'Create..' 显示为红色,但线为绿色。当鼠标悬停在节点“创建...”上时,导入行以及“评估”显示为红色。

  • 所需的要求:

我的要求是,如果存在双向导入,那么 - 1. 线以及其他节点以第三种颜色(红色或绿色除外)或 2. 线以及其他节点显示显示为红色。

任何指向此的指针都会有所帮助。我有 D3 的基本知识,但我不是数据可视化专家,只是尝试在我的工作领域中使用可视化来更好地沟通。

【问题讨论】:

    标签: javascript json svg d3.js bundle-layout


    【解决方案1】:

    有几种方法可以解决这个问题,但这是我目前能想到的最简单的方法。

    请注意,在您的 bl.ock 中,AssessCreate QoS Degradation Report 之间有 两条 路径,它们的值相等但相反(因为它们都是源 彼此的目标)。其中一个恰好放在另一个之上,使它们看起来像是一条路径。这就是为什么这两个节点之间的链接有些参差不齐,而其他节点却是平滑的。也许我们可以利用这一点。

    如果您在 CSS 中调整 link--sourcelink--target 的定义以使其不透明度值小于 1,则部分透明的源链接将与部分透明的目标链接重叠,从而呈现“新”的外观,不同的颜色。

    对于节点颜色,使用“新”颜色创建一个新的 CSS 类 node--both,如果 mousovered 函数中的 n.sourcen.target 都为 true,则将其应用于节点。

    node
        .classed("node--both", function(n) { return n.source && n.target; })
        .classed("node--target", function(n) { return n.target; })
        .classed("node--source", function(n) { return n.source; });
    

    这并不完美,但这里有一个小提琴证明了这一点:http://jsfiddle.net/w2rfwokx/

    关键是要适当地选择源链接和目标链接的颜色和不透明度值(我没有这样做),以便获得与源链接和目标链接足够不同的新颜色,并且无论是否源或目标链接在“顶部”。在当前的 fiddle 版本中,您可以看到颜色略有不同,具体取决于哪个节点处于活动状态。 This thread 或类似的东西可能会有所帮助。

    您还可以尝试操作links 数组以将两个相同的路径合并为一个,并添加一个属性以指示这是一个源和目标链接,并在稍后处理时使用此属性。

    更新:您在评论中的想法是正确的。无论如何,颜色技巧更像是一种技巧。

    links 数组包含两个项目,用于双向导入节点之间的一条路径。让我们删除其中一个,并在另一个中设置一个属性以指示这是双向导入。

    var unique_links = links.reduce(function(p,c) {
        var index=p.map(function(d,i) { if(d.source===c.target && d.target===c.source) return i;}).shift();
        if(!isNaN(index)) p[index].both=true; else p.push(c);
        return p;
     },[]);
    

    现在unique_links 每条边只有一个元素,而那个元素有both=true。让我们也将both 属性传递给捆绑布局。

    link = link
          .data(bundle(unique_links))
        .enter().append("path")
          .each(function(d) {
            d.source = d[0], 
            d.target = d[d.length - 1],
            d.both = unique_links.filter(function(v) { if (v.source===d.source && v.target===d.target) return v.both; }).shift();
          })
          .attr("class", "link")
          .attr("d", line);
    

    最后一步是更改 mouseovered 函数以使用 both 设置具有不同颜色的新 CSS 类:

    function mouseovered(d) {
      node
          .each(function(n) { n.target = n.source = false; });
    
      link
          .classed("link--both", function(l) { if((l.target===d || l.source===d) && l.both) return l.source.source = l.source.target = l.target.source = l.target.target = true;})
          .classed("link--target", function(l) { if (l.target === d && !l.both) return l.source.source = true; })
          .classed("link--source", function(l) { if (l.source === d && !l.both) return l.target.target = true; })
        .filter(function(l) { return l.target === d || l.source === d; })
          .each(function() { this.parentNode.appendChild(this); });
    
      node
          .classed("node--both", function(n) { return n.target && n.source; })
          .classed("node--target", function(n) { return n.target; })
          .classed("node--source", function(n) { return n.source; });
    }
    

    并重置mouseouted中的类:

    function mouseouted(d) {
      link
          .classed("link--both", false)
          .classed("link--target", false)
          .classed("link--source", false);
    
      node
          .classed("node--both", false)
          .classed("node--target", false)
          .classed("node--source", false);
    }
    

    记得在 CSS 中定义新的类:

    .link--both {
      stroke: orange;
    }
    
    .node--both {
      fill: orange;
    }
    

    这是完整代码的更新小提琴:http://jsfiddle.net/w2rfwokx/1/

    【讨论】:

    • 非常感谢 OrionMelt。我尝试使用颜色混合。虽然它非常聪明并且节点颜色得到了照顾,但链接颜色仍然是一个挑战。仅从一种方式导入的颜色存在对比,当节点 1 和节点 2 被鼠标悬停时显示的颜色不同(在这种情况下,节点 1 和节点 2 具有 2 方式导入)。我尝试了几种颜色和不透明度的组合,但这似乎仍然存在。我正在尝试探索您的其他想法 - 使用 links 数组。关于目标位置的任何指示/建议会有帮助吗?再次感谢
    • 我的理解是这段代码在哪里构建链接数组是需要进行更改的地方。目前,如果节点 1 和节点 2 具有 2 路链接,则在此数组中创建两个数组项(排列)。可能需要做的是:在构造数组后,检查冗余,删除其中一个重复项并标记另一个以说明它是双向链接。这个标签可以在着色时使用。请告知这是否是这样做的方法。在这种情况下,你能帮我处理代码部分吗?
    • 有点令人费解的是,当我尝试使用更大且不同的数据集进行操作时,在link 中运行良好的相同代码有一个小问题。更大和不同数据集的小提琴在这里link。虽然其他一切正常,但 2 路链接不是橙色的(应该是橙色的)。鉴别诊断可能指向数据集,但 json 格式的数据集看起来不错....任何指针都会有所帮助
    • 看起来我们构造 unique_links 数组的方式存在错误。错误的假设是 map 函数将始终包含匹配的索引作为第一个元素,而 shift 将返回这个第一个元素。但是,如果第一个元素恰好未定义,则 shift 将返回未定义。在移动之前过滤数组以查找未定义可解决此问题。在此处查看更新的小提琴:jsfiddle.net/w2rfwokx/4