【问题标题】:Highlighting nodes and its neighbors not working in sync with another opacity filter突出显示节点及其邻居与另一个不透明度过滤器不同步
【发布时间】:2017-02-23 00:41:29
【问题描述】:

我有一个功能齐全的 d3.js 力有向图。有各种与图表相关的过滤器。

我现在正在尝试使用突出显示功能,即如果双击节点,那么与图表的其余部分相比,该节点及其所有邻居都处于更高的不透明度。再次双击任何节点,整个图表将变得可见。

这很好用:

 var toggle = 0;
//Create an array logging what is connected to what
var linkedByIndex = {};
for (i = 0; i < d3GraphData.nodes.length; i++) {
    linkedByIndex[i + "," + i] = 1;
};
d3GraphData.links.forEach(function (d) {
    linkedByIndex[d.source.index + "," + d.target.index] = 1;
});
//This function looks up whether a pair are neighbours
function neighboring(a, b) {
    return linkedByIndex[a.index + "," + b.index];
}
function connectedNodes() {
    if (toggle == 0) {
        //Reduce the opacity of all but the neighbouring nodes
        d = d3.select(this).node().__data__;

        node.style("opacity", function (o) {
            return neighboring(d, o) | neighboring(o, d) ? 1 : 0.1;
        });
        link.style("opacity", function (o) {
            return d.index==o.source.index | d.index==o.target.index ? 1 : 0.1;
        });
        //Reduce the op
        toggle = 1;
    } else {
        //Put them back to opacity=1
        node.style("opacity", 1);
        link.style("opacity", 1);
        toggle = 0;
    }
}

现在,我还有另一个通过复选框控制的不透明度过滤器。取消选中复选框会使未选中的节点不可见。

有4种节点类型:

 Agent,Customer,Phone,ID_Card

节点有一个属性

   d.visible:true

visible 属性的当前状态取决于选中/取消选中的框,保留在不透明度过滤器的代码中。

下面是复选框部分的代码:

var circles = svg.selectAll(".node");
var lines = svg.selectAll(".link");

lines.style("opacity", function(d) {
  return getOpacity(d.source) && getOpacity(d.target) ? 1 : 0;
})
var nodeTypes = ["Agent", "Customer", "Phone", "ID_Card"];
var checkBoxes = [];
for (let i = 0; i < nodeTypes.length; i++) {
  checkBoxes.push(document.querySelectorAll('input[value="' + nodeTypes[i] + '"]')[0])
  checkBoxes[i].checked = true;
  checkBoxes[i].addEventListener("click", function() {
    filterBy("type", checkBoxes[i].value, checkBoxes[i].checked);
  });
}

var toggleOpacity = function(attribute, value, visible) {
  circles.filter(function(d) { //filter circles by attribute value
            return d[attribute] == value;
          })
          .each(function(d) { //modify visible attribute
            d.visible = visible;
          })
          .style("opacity", function(d) { // get opacity
            return getOpacity(d);
          });
  lines.filter(function(d) { // get links for attribute-value
            return d.source[attribute] == value || d.target[attribute] == value;
          })
          .style("opacity", function(d) { // modify opacity
            return getOpacity(d.source) && getOpacity(d.target) ? 1 : 0;
          })
}

var filterBy = function(attribute, value, visible, highlightSelected) {

  if (highlightSelected) {
     circles.style("opacity", 0)
     lines.style("opacity", 0)

        toggleOpacity(attribute, value, visible)

    circles.filter(function(d){return d.visible;}).transition()
      .duration(2000)
      .style("opacity", 1);

    lines.filter(function(d){return d.source.visible && d.target.visible}).transition()
      .duration(2000)
      .style("opacity", 1);
  }
    else{
    toggleOpacity(attribute, value, visible)
  }

}

当某些复选框未选中时,节点的突出显示现在似乎不起作用。

例如当 CustomerPhone 被选中时,双击 Customer 节点应该只显示相邻的Customer电话 节点。

但即使是其他不可见的相邻节点也会出现。

connected nodes()函数中,我尝试使用节点的visible属性。

 node.style("opacity", function (o) {
        return neighboring(d.visible, o.visible) | neighboring(o.visible, d.visible) ? 1 : 0.1;
    });

但这种方法似乎行不通。

由于 visible 属性的当前状态已经被计算出来,它只是一个正确使用它的问题。但我正在努力做到这一点。仍然是我在 d3.js 中的第一个项目,因此感谢您的投入。

工作fiddle

【问题讨论】:

    标签: javascript d3.js


    【解决方案1】:

    当其他过滤器处于活动状态时,期望的行为是什么?例如。当客户单独处于活动状态(因此其他节点被隐藏)并且您双击客户时,是否要显示隐藏的邻居?

    看看这个小提琴:https://jsfiddle.net/g0dm4q3n/1/ 我修改了connectedNodes 函数,以便在单击 d 时调整相邻节点的不透明度,并根据 visible 属性恢复它们的不透明度 - 由其他过滤器设置。这样,当只有两个复选框被选中时,例如客户和电话,当你双击一个节点时,它会与它的邻居一起突出显示它(即使它们由于复选框而不可见),再次双击它会返回到之前的过滤状态。

    function connectedNodes() {
        d = d3.select(this).node().__data__;
        // use d.clicked to save toggle
        if (!d.clicked) {
            //Reduce the opacity of all but the neighbouring nodes
            d.clicked = true;
            node.style("opacity", function (o) {
                // if they are neighboring set opacity to 1 
                // else 0.1 and do not change visible attribute
                return neighboring(d, o) || neighboring(o, d) 
                                                        ? 1 
                                                        : 0.1;
            });
            // you might want to indicate the clicked node maybe with a different border
    
            link.style("opacity", function (o) {
                return d.index==o.source.index | d.index==o.target.index ? 1 : 0.1;
            });
        } else {
            d.clicked = !d.clicked;
            //Put them back to opacity=1
            node.style("opacity", function(o){
                return o.visible? 1 :  0;
            });
            link.style("opacity", function(o){
                return o.target.visible && o.source.visible? 1:0;
            });
        }
    }
    

    您可能想要指出一个节点被双击(看看这个:http://eutravel.clmsuk.com/semantics/graph - 它在点击时起作用。另外,给它一些时间来加载,因为那里有很多数据和很多事情: ) ) 以便用户知道该做什么。

    希望这会有所帮助!祝你好运!

    【讨论】:

    • 哇。万分感谢。主要的关键是考虑节点的 d.clicked 事件。我只是想不出那个方向。
    • 我很高兴它有帮助 :) 我发现使用元素本身来保存有关其状态的信息(视觉方面)在许多情况下非常有用。顺便说一句,您的项目正在变得不错!
    猜你喜欢
    • 1970-01-01
    • 2019-03-01
    • 2016-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-20
    • 2014-03-29
    • 1970-01-01
    相关资源
    最近更新 更多