javascript - 定向网络中的网络连接衰减 - d3js

标签 javascript d3.js

我有一个使用 d3.layout.force 的定向网络。适应this answer ,我已经设法让节点和链接在连接时淡出(连接方向无关紧要)。

我遇到的问题是,当标记所在的路径通过 mouseover 事件更改其不透明度时,能够更改标记的不透明度。

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

A live example is here.

<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>

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

最佳答案

由于标记实例的呈现方式,您的方法不可行。蚕食我自己的一个answers并引用 SVG 规范:

11.6.4 Details on how markers are rendered

[...]

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无法访问,因此无法单独设置样式。

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.

<小时/>

要规避这些限制,您可以使用两个定义 marker元素,第二个是第一个元素的克隆版本,但不透明度降低。

// 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:

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

看看下面的代码片段,了解一个有效的演示:

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>

关于javascript - 定向网络中的网络连接衰减 - d3js,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48731483/

相关文章:

javascript - 如何以 Angular 将 JSON 传递给@Input?

javascript - 如何在 D3 强制布局中添加复合节点?

javascript - d3.js 多重关系视觉/linkHorizo​​ntal()/纠结树

javascript - 安装 D3.js 失败

javascript - 使用 Neo4j Javascript 驱动程序 (node.js) 和 D3.js 在 HTML 页面上可视化 neo4j 数据

javascript - 属性或方法 "orgs"未在实例上定义,但被引用

javascript - 在 lodash.js 中,它会缓存 `.value()` 方法的结果吗?

javascript - 单击时将超链接替换为内联文本框

javascript - JQuery动态for循环问题

jquery - 缩放后 svg 过滤器在 mozilla firefox 中不起作用