我已经用javascript中的d3.js实现了一个网络,我想根据收到的json将链接的颜色从灰色更改为红色。 JSON显示将要连接的源节点和目标节点。节点体系结构的架构如下:
现在,当接收到JSON时,我将解析数据,并使用以下代码添加新行,将源节点和目标节点连接到红色:
svg.selectAll()
.data(data.links)
.enter()
.append("line")
.attr("x1", function(d) { return nodes[source].x; })
.attr("y1", function(d) { return nodes[source].y; })
.attr("x2", function(d) { return nodes[target].x; })
.attr("y2", function(d) { return nodes[target].y; })
.attr("stroke","#b72b34")
.attr("stroke-width", 2)
然后,在2秒后,我使用相同的代码再次将线条的颜色更改为灰色。 还有另一种更简单的方法吗?
您可以看到,用户可以看到过去添加的行,尽管这不是所需的图像。我只想更改现有链接的颜色(如架构1所示)。
谢谢。
我的代码:
var nodes = [
{ x: width/2, y: height/4, id: 0, url: "http://icons.iconarchive.com/icons/icons-land/vista-hardware-devices/128/Computer-icon.png"},
{ x: 60, y: height-150, id: 1, url: "http://icons.iconarchive.com/icons/icons-land/vista-hardware-devices/128/Computer-icon.png"},
{ x: width-100, y: height-150, id: 2, url: "http://icons.iconarchive.com/icons/icons-land/vista-hardware-devices/128/Computer-icon.png"},
{ x: 60, y: height-50, id: 3, url: "http://icons.iconarchive.com/icons/icons-land/vista-hardware-devices/128/Computer-icon.png"},
{ x: width-100, y: height-50, id: 4, url: "http://icons.iconarchive.com/icons/icons-land/vista-hardware-devices/128/Inkjet-Printer-icon.png"}
];
var links = [
{ source: 1, target: 2 },
{ source: 1, target: 3 },
{ source: 1, target: 4 },
{ source: 1, target: 0 },
{ source: 2, target: 3 },
{ source: 2, target: 1 },
{ source: 2, target: 4 },
{ source: 2, target: 0 },
{ source: 3, target: 4 },
{ source: 3, target: 1 },
{ source: 3, target: 2 },
{ source: 3, target: 0 },
{ source: 4, target: 1 },
{ source: 4, target: 2 },
{ source: 4, target: 3 },
{ source: 4, target: 0 },
{ source: 0, target: 1 },
{ source: 0, target: 2 },
{ source: 0, target: 3 },
{ source: 0, target: 4 },
];
svg.selectAll()
.data(links)
.enter()
.append("line")
.attr("x1", function(d) { return nodes[d.source].x; })
.attr("y1", function(d) { return nodes[d.source].y; })
.attr("x2", function(d) { return nodes[d.target].x; })
.attr("y2", function(d) { return nodes[d.target].y; })
.attr("stroke-width", function (d) { return Math.sqrt(d.value); })
.attr("stroke","#f6f6f6")
svg.selectAll()
.data(nodes)
.enter()
.append("image")
.attr("x", function(d) { return d.x - 30/2; })
.attr("y", function(d) { return d.y - 30/2; })
.attr("width", 45)
.attr("height", 45)
.attr("xlink:href",function(d) { return d.url; })
setInterval(function(test){
var url = "http://..."
d3.json(url, function(error, data) {
for (var i = 0; i < data.links.length; i++) {
source = findNode(data.links[i].source);
target = findNode(data.links[i].target);
svg.selectAll()
.data(data.links)
.enter()
.append("line")
.attr("x1", function(d) { return nodes[source].x; })
.attr("y1", function(d) { return nodes[source].y; })
.attr("x2", function(d) { return nodes[target].x; })
.attr("y2", function(d) { return nodes[target].y; })
.attr("stroke","#b72b34")
.attr("stroke-width", function (d) { return Math.sqrt(d.value);
})
;
}
});
}, 5000);
答案 0 :(得分:2)
您当前每次更新图表时都会添加新行:
svg.selectAll()
.data(data.links)
.enter()
.append("line")
svg.selectAll()
是一个空选择,与svg.selectAll(null)
相同。因此,将在DOM中为数据数组中每项更新的项目创建一个项目。一段时间后,这会使速度变慢。
我们可以用svg.selectAll("circle")
选择圆以进行更新(或退出/输入旧行/新行),但是新数据数组将按照其索引顺序(而不是数据对)分配给现有行。我们可以使用.selectAll().data()
(the second argument for .data()
)为每个元素做一个键,但这必须是一个字符串。
我建议不要使用键,而是使用每行的ID(表示最初添加这些行)来代表其源和目标:
.attr("id", function(d) { return "link-"+d.source+"-"+d.target; })
然后,当我们处理json数据以更新图形时,我们选择适当的行。选择之后,我们将应用样式。使用转换时的延迟,我们可以确保两秒钟后完成返回正常状态的转换:
newData.links.forEach(function(d) {
d3.select("#link-"+d.source+"-"+d.target)
.attr("stroke","red")
.transition()
.delay(1500)
.duration(500)
.attr("stroke","#f6f6f6")
})
这部分代码适合您的超时功能:
var width = 600;
var height = 400;
var svg = d3.select("body").append("svg")
.attr("width",width)
.attr("height",height);
var nodes = [
{ x: width/2, y: height/4, id: 0, url: "http://icons.iconarchive.com/icons/icons-land/vista-hardware-devices/128/Computer-icon.png"},
{ x: 60, y: height-150, id: 1, url: "http://icons.iconarchive.com/icons/icons-land/vista-hardware-devices/128/Computer-icon.png"},
{ x: width-100, y: height-150, id: 2, url: "http://icons.iconarchive.com/icons/icons-land/vista-hardware-devices/128/Computer-icon.png"},
{ x: 60, y: height-50, id: 3, url: "http://icons.iconarchive.com/icons/icons-land/vista-hardware-devices/128/Computer-icon.png"},
{ x: width-100, y: height-50, id: 4, url: "http://icons.iconarchive.com/icons/icons-land/vista-hardware-devices/128/Inkjet-Printer-icon.png"}
];
var links = [
{ source: 1, target: 2 },
{ source: 1, target: 3 },
{ source: 1, target: 4 },
{ source: 1, target: 0 },
{ source: 2, target: 3 },
{ source: 2, target: 1 },
{ source: 2, target: 4 },
{ source: 2, target: 0 },
{ source: 3, target: 4 },
{ source: 3, target: 1 },
{ source: 3, target: 2 },
{ source: 3, target: 0 },
{ source: 4, target: 1 },
{ source: 4, target: 2 },
{ source: 4, target: 3 },
{ source: 4, target: 0 },
{ source: 0, target: 1 },
{ source: 0, target: 2 },
{ source: 0, target: 3 },
{ source: 0, target: 4 },
];
svg.selectAll()
.data(links)
.enter()
.append("line")
.attr("x1", function(d) { return nodes[d.source].x; })
.attr("y1", function(d) { return nodes[d.source].y; })
.attr("x2", function(d) { return nodes[d.target].x; })
.attr("y2", function(d) { return nodes[d.target].y; })
.attr("stroke-width", function (d) { return Math.sqrt(d.value); })
.attr("id", function(d) { return "link-"+d.source+"-"+d.target; })
.attr("stroke","#f6f6f6")
svg.selectAll()
.data(nodes)
.enter()
.append("image")
.attr("x", function(d) { return d.x - 45/2; })
.attr("y", function(d) { return d.y - 45/2; })
.attr("width", 45)
.attr("height", 45)
.attr("xlink:href",function(d) { return d.url; })
setInterval(function(){
// randomly links instead of calling external file:
var data = links.filter(function(d) { if (Math.random() < 0.5) return d; })
data.forEach(function(d) {
d3.select("#link-"+d.source+"-"+d.target)
.attr("stroke","red")
.transition()
.delay(1500)
.duration(500)
.attr("stroke","#f6f6f6")
})
}, 3000); // sped up for demonstration
<script src="https://d3js.org/d3.v3.min.js"></script>
为便于比较,以下是提供给.data()的密钥作为替代方法。为此,我们将目标和源转换为字符串,就像对id所做的一样,但是将其用作.data()中的键。这使我们可以跳过每个循环。这是更规范的d3方法:
var width = 600;
var height = 400;
var svg = d3.select("body").append("svg")
.attr("width",width)
.attr("height",height);
var nodes = [
{ x: width/2, y: height/4, id: 0, url: "http://icons.iconarchive.com/icons/icons-land/vista-hardware-devices/128/Computer-icon.png"},
{ x: 60, y: height-150, id: 1, url: "http://icons.iconarchive.com/icons/icons-land/vista-hardware-devices/128/Computer-icon.png"},
{ x: width-100, y: height-150, id: 2, url: "http://icons.iconarchive.com/icons/icons-land/vista-hardware-devices/128/Computer-icon.png"},
{ x: 60, y: height-50, id: 3, url: "http://icons.iconarchive.com/icons/icons-land/vista-hardware-devices/128/Computer-icon.png"},
{ x: width-100, y: height-50, id: 4, url: "http://icons.iconarchive.com/icons/icons-land/vista-hardware-devices/128/Inkjet-Printer-icon.png"}
];
var links = [
{ source: 1, target: 2 },
{ source: 1, target: 3 },
{ source: 1, target: 4 },
{ source: 1, target: 0 },
{ source: 2, target: 3 },
{ source: 2, target: 1 },
{ source: 2, target: 4 },
{ source: 2, target: 0 },
{ source: 3, target: 4 },
{ source: 3, target: 1 },
{ source: 3, target: 2 },
{ source: 3, target: 0 },
{ source: 4, target: 1 },
{ source: 4, target: 2 },
{ source: 4, target: 3 },
{ source: 4, target: 0 },
{ source: 0, target: 1 },
{ source: 0, target: 2 },
{ source: 0, target: 3 },
{ source: 0, target: 4 },
];
svg.selectAll()
.data(links, function(d) { return d.source+"-"+d.target })
.enter()
.append("line")
.attr("x1", function(d) { return nodes[d.source].x; })
.attr("y1", function(d) { return nodes[d.source].y; })
.attr("x2", function(d) { return nodes[d.target].x; })
.attr("y2", function(d) { return nodes[d.target].y; })
.attr("stroke-width", function (d) { return Math.sqrt(d.value); })
.attr("stroke","#f6f6f6")
svg.selectAll()
.data(nodes)
.enter()
.append("image")
.attr("x", function(d) { return d.x - 45/2; })
.attr("y", function(d) { return d.y - 45/2; })
.attr("width", 45)
.attr("height", 45)
.attr("xlink:href",function(d) { return d.url; })
setInterval(function(){
// randomly links instead of calling external file:
var data = links.filter(function(d) { if (Math.random() < 0.5) return d; })
d3.selectAll("line")
.data(data, function(d) { return d.source+"-"+d.target; })
.attr("stroke","red")
.transition()
.delay(1500)
.duration(500)
.attr("stroke","#f6f6f6")
}, 3000); // sped up for demonstration
<script src="https://d3js.org/d3.v3.min.js"></script>
答案 1 :(得分:0)
您可以将行选择缓存在变量中,以在超时时重新使用它。看看下面的代码。我还添加了一个可选的300ms过渡。
const redLine = svg.selectAll()
.data(data.links)
.enter()
.append("line")
.attr("x1", function(d) { return nodes[source].x; })
.attr("y1", function(d) { return nodes[source].y; })
.attr("x2", function(d) { return nodes[target].x; })
.attr("y2", function(d) { return nodes[target].y; })
.attr("stroke","#b72b34")
.attr("stroke-width", 2)
// drop this code inside setTimeout() instead of the whole block of code from
// above that you repeat
redLine
.transition(300)
.attr("stroke","grey")
.attr("stroke-width", 1)