有向网络中的衰落网络连接 - d3js [英] Fading network connections in directed network - d3js

查看:90
本文介绍了有向网络中的衰落网络连接 - d3js的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个使用 d3.layout.force 的定向网络。适应此答案,如果已连接(连接方向无关紧要),我已设法获取节点和链接淡出。

I have a directed network using the d3.layout.force . Adapting this answer, I have managed to get nodes and links to fade if connected (direction of connection doesn't matter).

我遇到的问题是能够在它们所在的路径使用 mouseover 事件改变其不透明度时更改标记的不透明度。

What I am having trouble with is to be able to change the opacity of markers when the path they are on is having its opacity altered with a mouseover event.

这是包含 isConnected 函数的脚本,用于确定连接的节点:

This is the script including the isConnected function for determining what nodes are connected:

这里有一个实例。

<script>


  function bar() {
  console.log("click");
  force.stop();
  force.start();
}



  var links = [
  {source: "A", target: "D", type: "high"},
  {source: "A", target: "K", type: "high"},
  {source: "B", target: "G", type: "high"},
  {source: "C", target: "A", type: "low"},
  {source: "D", target: "K", type: "low"},
  {source: "E", target: "A", type: "low"},
  {source: "F", target: "B", type: "low"},
  {source: "K", target: "J", type: "low"},
  {source: "F", target: "A", type: "low"},
  {source: "F", target: "I", type: "low"},
  {source: "G", target: "H", type: "low"},
  {source: "E", target: "K", type: "high"},
  {source: "E", target: "G", type: "low"},
  {source: "E", target: "F", type: "high"},
  {source: "D", target: "E", type: "high"}  
];

var nodes = {};

// Compute the distinct nodes from the links.
links.forEach(function(link) {
  link.source = nodes[link.source] || (nodes[link.source] = {name: link.source});
  link.target = nodes[link.target] || (nodes[link.target] = {name: link.target});
});

var width = 960,
    height = 700;

var force = d3.layout.force()
    .nodes(d3.values(nodes))
    .links(links)
    .size([width, height])
    .linkDistance(105)
    .charge(-775)
    .on("tick", tick)
    .start();



force.on("start", function () {
    console.log("start");
});
force.on("end", function () {
    console.log("end");
});

R=18



var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height);

// add defs-marker
svg.append('svg:defs')
    .append('svg:marker')
    .attr('id', 'end-arrow')
    .attr('viewBox', '0 0 10 10')
    .attr('refX', 2+R)
    .attr('refY', 5)
     .attr('markerWidth', 4)
     .attr('markerHeight', 4)
    .attr('orient', 'auto')
    .append('svg:path')
    .attr('d', 'M0,0 L0,10 L10,5 z');


var link = svg.selectAll(".link")
    .data(force.links())
    .enter()
    .append("line")
    .attr("class", "link")
    .attr('marker-end', 'url(#end-arrow)')
;  

var node = svg.selectAll(".node")
    .data(force.nodes())
    .enter().append("g")
    .attr("class", "node")
    .call(force.drag);

node.append("circle")
    .attr("r", R)
    .on("mouseover", fade(.1))
    .on("mouseout", fade(1))
;

node.append("text")
    .attr("x", 0)
    .attr("dy", ".35em")
    .text(function(d) { return d.name; });




function tick() {
  link
      .attr("x1", function(d) { return d.source.x; })
      .attr("y1", function(d) { return d.source.y; })
      .attr("x2", function(d) { return d.target.x; })
      .attr("y2", function(d) { return d.target.y; })      
    ;

  node
      .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
}



   var linkedByIndex = {};
    links.forEach(function(d) {
        linkedByIndex[d.source.index + "," + d.target.index] = 1;
    });

    function isConnected(a, b) {
        return linkedByIndex[a.index + "," + b.index] || linkedByIndex[b.index + "," + a.index] || a.index == b.index;
    }

 function fade(opacity) {
        return function(d) {
            node.style("stroke-opacity", function(o) {
                thisOpacity = isConnected(d, o) ? 1 : opacity;
                this.setAttribute('fill-opacity', thisOpacity);
                return thisOpacity;
            });

            link.style("stroke-opacity", function(o) {
                return o.source === d || o.target === d ? 1 : opacity;
            });

           marker.style("opacity", function(o) {
                return o.source === d || o.target === d ? 1 : opacity;
            });
        };
 }


</script>

一个切线相关的问题是如何缩短路径,以便当节点和链接的不透明度消失时,走到每个节点中间的线路不明显。

A tangentially related question would be how to shorten the path so that when the opacity of nodes and links fade, that the line going to the middle of each node is not noticeable.

推荐答案

由于标记方式,您的方法不可行实例被渲染。我自己的一个答案和引用SVG规范:

Your approach is not feasible because of the way marker instances are rendered. Cannibalizing one of my own answers and quoting the SVG spec:


11.6.4有关标记如何呈现的详细信息



[...]

a的渲染效果标记就好像引用的'marker'元素的内容被深深地克隆到标记的每个实例的单独的非暴露DOM树中。因为克隆的DOM树是非暴露的,所以SVG DOM不显示标记的克隆实例。

The rendering effect of a marker is as if the contents of the referenced ‘marker’ element were deeply cloned into a separate non-exposed DOM tree for each instance of the marker. Because the cloned DOM tree is non-exposed, the SVG DOM does not show the cloned instance of the marker.

仅原始标记元素,即声明< marker> 元素,可使用CSS设置样式,而通过属性引用的克隆实例 marker-start marker-mid marker-end 无法访问,因此无法单独设置样式。

Only the original marker elements, i.e. the declaring <marker> elements, are stylable using CSS, whereas the cloned instances referenced via properties marker-start, marker-mid, or marker-end are not accessible and therefore not individually stylable.


CSS2选择器可以应用于原始(即引用)元素,因为它们是正式文档结构的一部分。 CSS2选择器不能应用于(概念上)克隆的DOM树,因为它的内容不是正式文档结构的一部分。

CSS2 selectors can be applied to the original (i.e., referenced) elements because they are part of the formal document structure. CSS2 selectors cannot be applied to the (conceptually) cloned DOM tree because its contents are not part of the formal document structure.






为了规避这些约束,你可以使用两个定义的标记元素,第二个是第一个克隆版本,不透明度降低。


To circumvent these constraints you could use two defining marker elements, the second being a cloned version of the first with reduced opacity.

// add defs-markers
svg.append('svg:defs').selectAll("marker")
    .data([{id:"end-arrow", opacity:1}, {id:"end-arrow-fade", opacity:0.1}])
  .enter().append('marker')
    .attr('id', function(d) { return d.id; })
    .attr('viewBox', '0 0 10 10')
    .attr('refX', 2+R)
    .attr('refY', 5)
    .attr('markerWidth', 4)
    .attr('markerHeight', 4)
    .attr('orient', 'auto')
  .append('svg:path')
    .attr('d', 'M0,0 L0,10 L10,5 z')
    .style("opacity", function(d) { return d.opacity; });

在你的 fade()函数中,你是然后能够切换行' marker-end 属性以引用相应标记的ID:

Within your fade() function you are then able to switch the lines' marker-end properties to refer to the appropriate marker's id:

link.attr("marker-end", function(o) {
  return opacity === 1 || o.source === d || o.target === d
    ? 'url(#end-arrow)' : 'url(#end-arrow-fade)';
});          

查看以下代码片段以了解正常工作:

Have a look at the following snippet for a working demo:

function bar() {
  console.log("click");
  force.stop();
  force.start();
}
  
var links = [
  {source: "A", target: "D", type: "high"},
  {source: "A", target: "K", type: "high"},
  {source: "B", target: "G", type: "high"},
  {source: "C", target: "A", type: "low"},
  {source: "D", target: "K", type: "low"},
  {source: "E", target: "A", type: "low"},
  {source: "F", target: "B", type: "low"},
  {source: "K", target: "J", type: "low"},
  {source: "F", target: "A", type: "low"},
  {source: "F", target: "I", type: "low"},
  {source: "G", target: "H", type: "low"},
  {source: "E", target: "K", type: "high"},
  {source: "E", target: "G", type: "low"},
  {source: "E", target: "F", type: "high"},
  {source: "D", target: "E", type: "high"}  
];

var nodes = {};

// Compute the distinct nodes from the links.
links.forEach(function(link) {
  link.source = nodes[link.source] || (nodes[link.source] = {name: link.source});
  link.target = nodes[link.target] || (nodes[link.target] = {name: link.target});
});

var width = 600,
    height = 600;

var force = d3.layout.force()
    .nodes(d3.values(nodes))
    .links(links)
    .size([width, height])
    .linkDistance(105)
    .charge(-775)
    .on("tick", tick)
    .start();

force.on("start", function () {
    console.log("start");
});
force.on("end", function () {
    console.log("end");
});

R=18
 
var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height);

// add defs-markers
svg.append('svg:defs').selectAll("marker")
    .data([{id:"end-arrow", opacity:1}, {id:"end-arrow-fade", opacity:0.1}])
  .enter().append('marker')
    .attr('id', function(d) { return d.id; })
    .attr('viewBox', '0 0 10 10')
    .attr('refX', 2+R)
    .attr('refY', 5)
    .attr('markerWidth', 4)
    .attr('markerHeight', 4)
    .attr('orient', 'auto')
  .append('svg:path')
    .attr('d', 'M0,0 L0,10 L10,5 z')
    .style("opacity", function(d) { return d.opacity; });

var link = svg.selectAll(".link")
    .data(force.links())
    .enter()
    .append("line")
    .attr("class", "link")
    .attr('marker-end', 'url(#end-arrow)');  
 
var node = svg.selectAll(".node")
    .data(force.nodes())
    .enter().append("g")
    .attr("class", "node")
    .call(force.drag);

node.append("circle")
    .attr("r", R)
    .on("mouseover", fade(.1))
    .on("mouseout", fade(1))
;

node.append("text")
    .attr("x", 0)
    .attr("dy", ".35em")
    .text(function(d) { return d.name; });
  
function tick() {
  link.attr("x1", function(d) { return d.source.x; })
      .attr("y1", function(d) { return d.source.y; })
      .attr("x2", function(d) { return d.target.x; })
      .attr("y2", function(d) { return d.target.y; });

  node.attr("transform", function(d) {
    return "translate(" + d.x + "," + d.y + ")";
  });
}
  
var linkedByIndex = {};
links.forEach(function(d) {
  linkedByIndex[d.source.index + "," + d.target.index] = 1;
});

function isConnected(a, b) {
  return linkedByIndex[a.index + "," + b.index] || linkedByIndex[b.index +   "," + a.index] || a.index == b.index;
}
  
function fade(opacity) {
  return function(d) {
    node.style("stroke-opacity", function(o) {
      thisOpacity = isConnected(d, o) ? 1 : opacity;
      this.setAttribute('fill-opacity', thisOpacity);
      return thisOpacity;
    });

    link.style("stroke-opacity", function(o) {
      return o.source === d || o.target === d ? 1 : opacity;
    });

    link.attr("marker-end", function(o) {
      return opacity === 1 || o.source === d || o.target === d
        ? 'url(#end-arrow)' : 'url(#end-arrow-fade)';
    });          
  };
 }

.node circle {
  fill: #DDD;
  stroke: #777;
  stroke-width: 2px;
}
.node text {
  font-family: sans-serif;
  text-anchor: middle;
  pointer-events: none;
  user-select: none;
  -webkit-user-select: none;
}
.link {
  stroke: #88A;
  stroke-width: 4px;
}
text {
  font: 18px sans-serif;
  pointer-events: none;
}
#end-arrow {
  fill: #88A;
}

<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>

这篇关于有向网络中的衰落网络连接 - d3js的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆