我有一个使用 d3.layout.force 的定向网络。适应this answer ,我已经设法让节点和链接在连接时淡出(连接方向无关紧要)。
我遇到的问题是,当标记所在的路径通过 mouseover
事件更改其不透明度时,能够更改标记的不透明度。
这是包含用于确定连接哪些节点的 isConnected
函数的脚本:
<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/