0

好的,我发现了一些资源试图使用 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 文件中包含的数据重绘(重新开始)可视化的功能。

4

0 回答 0