好的,我发现了一些资源试图使用 d3js 加载两个数据源。不幸的是,他们似乎没有解决我遇到的问题。
本质上,我要做的是创建一个带有节点和链接的强制布局,并能够通过下拉菜单中的选择来更改数据源。
这是基础知识...我使用 d3.json 从外部文件中检索所有节点和链接。一切都很完美,我什至为可视化设置了动画,以循环遍历每个节点的不同日期。我的问题是,现在我正在尝试扩展此可视化的功能......我希望能够从下拉菜单中选择一个 .json 文件,然后使用新数据重新加载可视化。基本上为用户提供了查看完全不同数据的几种不同可视化。
除了当我使用新数据文件重新绘制可视化时,所有概念似乎都在起作用,一些节点出现并自行浮动,而不是链接到原始节点。我忘记了前 7 个节点,我将它们的 x、y 坐标硬编码到可视化的中间,之后的每个节点都使用强制功能根据它们链接到的内容来放置自己。
这是一些代码
$("#customer").change(function(){ // this is the dropdown menu
$("#customer option:selected").each(function () {
var line = d3.selectAll("line").remove(); // remove all links on screen
var g = d3.selectAll("g").remove(); // remove all nodes on screen
dataFile = this.innerHTML; // changes variable used in d3.json
change(); // calls function wrapper that contains d3.json
});
function change(){
d3.json(dataFile, function(fileData){
rtm = new Object(); // initialize dictionary object
dates = []; // initialize dates[] array to contain all dates in data
var node = {}; // node object
// traverse through data contained in file
for(var i = 0; i < fileData.nodes.length; i++){
node = fileData.nodes[i]; // assign current node to node object
node.date = new Date(node.date);
rtm[node.id] = node; // add node object to dictionary object
// check if date exists in dateArray
if(findDate(node.date, dates)){
dates.push(node.date); // add dates that don't exist
}
}
getNodes(fileData.nodes[0].date); // finds the nodes to be visualized and updates the array passed to force.nodes()
getLinks(fileData.nodes[0].date); // finds the nodes to be visualized and updates the array passed to force.links()
start(); // initiates visualization after d3.json() finishes
});
}
// function controls visualization. Uses d3.js framework to control visualization
// must be called from within d3.json for first initialization or nothing will render
function start(){
// stop force functionality to allow for removal and adding of new objects
force.stop();
// remove all elements inside visualization
var line = d3.selectAll("line").remove(); // remove all links on screen
var g = d3.selectAll("g").remove(); // remove all nodes on screen
// create any links needed, dependent on links contained links[] array
// selects links already created or adds new links.
link = svg.selectAll("line.link")
.data(force.links(), function(d){ return d.id;}) // 2nd parameter can be added to use as a comaparison for pairing existing links with identical same data
link.enter().append("line") // new data will be bound to a new line. 2nd parameter in .data() allows for element reuse
// instead of creation, otherwise data and line elements are matched on index. If those
// two don't match then a new element is created.
.attr("class", "link") // assigns .link class to link element to allow for css styling
//.style("stroke-opacity", .5)
.style("stroke-width", 8)
.style("stroke", function(d){
return d.target.id > 7 ? (d.target.fraud ? "Red" : "#35586C") : "Grey";
});
link.exit().remove(); // removes any links removed from links[] array
// create any nodes needed, dependent on data contained in .data()
// selects nodes already created or adds new nodes. matches nodes to data
node = svg.selectAll(".node")
.data(force.nodes(), function(d){ return d.id;}) // 2nd parameter can be added to use as a comaparison for pairing existing node with identical same data
node.enter().append("g") // new data will be bound to a new node. 2nd parameter in .data() allows for element reuse
// instead of creation, otherwise data and node elements are matched on index. If those
// two don't match, a new element is created.
.attr("class", "node") // assigns .node class to node element to allow for css styling
.call(force.drag); // allows for nodes to be dragged and moved. x,y coordinates will adjust to movement
//.transition().duration(10000).delay(10000); // transitions any new nodes into the visualization
node.exit().remove(); // removes any nodes removed from nodes[] array
node.append("image")
.attr("xlink:href", function(d){
// add path for image of each node
var path = "images/";
if(!d.fraud){ // check if fraudulent node
if(d.name == "Record"){
path += "record-G.gif";
return path;
}
if(d.id <= 7){
path += "Record/";
}else {
path += "Linked/";
}
if(d.name == "SSN"){
path += "SSN.png";
}else if(d.name == "Name"){
path += "Name.png";
}else if(d.name == "Address"){
path += "Address.png";
}else if(d.name == "Phone"){
path += "Phone.png";
}else if(d.name == "DOB"){
path += "DOB.png";
}else if(d.name == "Email"){
path += "Email.png";
}else if(d.name == "Record"){
path += "record-G.gif";
}else if(d.name == "App"){
path += "App.png";
}else {
path += "nan.gif";
}
}else {
path += "FraudApp.png"
}
return path;
})
.attr("class", "image")
.attr("x", function(d){ return d.name == "Record" ? -30 : -20})
.attr("y", function(d){ return d.name == "Record" ? -30 : -20})
.attr("height", function(d){ return d.name == "Record" ? 60 : 40})
.attr("width", function(d){ return d.name == "Record" ? 60 : 40});
force.start(); // restart force functionality
}
我不知道这是否有意义。简要概述:我想提供更改 .json 文件并使用该 .json 文件中包含的数据重绘(重新开始)可视化的功能。