【问题标题】:D3 Graph Won't Show dynamically created JSOND3 图表不会显示动态创建的 JSON
【发布时间】:2019-05-12 20:52:29
【问题描述】:

我有一个函数,在页面加载时,getVisualizer() 创建当前用户及其朋友的 JSON 文件。这里的目标是可视化用户网络。所以最终结果应该是当前用户节点,附加到标有朋友姓名的节点。

这里的 D3 设置为渲染称为“链接”的图形。我有一个可以渲染的示例图(标题为 previous_links),但是当我尝试创建自己的名为“links”的 JSON 文件时,它不再绘制。我在这里不知所措,因为我已经检查过是否将正确的数据添加到 JSON 文件对象中 - 所以我认为这可能是格式问题。

相关代码如下。

 <!doctype html>
    <html lang="en">
      <head>
        <style>....

        </style>
      </head>

    <body>     
      <div id = "trythis" class="container main-section">
      //...basic layout items here...//


    <script>

    var numRequests = 0;

    var links = [];

    //PROBLEM SOMEWHERE IN HERE.--------

    function getVisualizer() {
        $.getJSON('/visualizer', function(data) {
          var n = Object.keys(data).length;
          if (n !== numRequests) {
            for (var key in data) {
              var value = data[key];
              var myObj = {
             "source" : "MyName",    //Test Username variable
             "target" : value       //friends name variable
            };
            //push the object to JSON array
            console.log("The object added is" + JSON.stringify(myObj));
            links.push( myObj );
            }
            numRequests = n;
          }
          console.log("Reached end of function");
        });
      };

      function refresh() {
        getVisualizer();

        //test that item 1 is correct
        console.log(JSON.stringify(links[0]) + "is links 0");
      };


        refresh();


    //PARTIAL ISSUE HERE. THIS GRAPH DRAWS SUCCESSFULLY WHEN RENAMED "links"
    //As you can see, I tried to create the same data structure 
    //above when loading friends and calling "push" for each object.

    //---------SAMPLE GRAPH THAT DRAWS--------------------

    var previous_links = [{
        "source": "Analytics",
        "target": "Science"
    }, {
        "source": "Analytics",
        "target": "Software"
    }, {
        "source": "Analytics",
        "target": "Story"
    }, {
        "source": "Science",
        "target": "Math"
    }, {
        "source": "Science",
        "target": "Statistics"
    }, {
        "source": "Software",
        "target": "R"
    }, {
        "source": "Software",
        "target": "SAS"
    }, {
        "source": "Software",
        "target": "Other"
    }, {
        "source": "Story",
        "target": "Business Communication"
    }, {
        "source": "Story",
        "target": "Visualization"
    }];

    //----------------------------------  

    //Here, I set up the graph for JSON named "links". Question is, how come
    //my newly created version will not draw?

    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
        });
        link.value = +link.value;
    });

    var width = 900
    height = 300;

    var force = d3.layout.force()
        .nodes(d3.values(nodes))
        .links(links)
        .size([width, height])
        .linkDistance(50)
        .charge(-200)
        .on("tick", tick)
        .start();

    var svg = d3.select("#trythis").append("svg")
        .attr("width", width)
        .attr("height", height);

    var link = svg.selectAll(".link")
        .data(force.links())
        .enter().append("line")
        .attr("class", "link");

    var node = svg.selectAll(".node")
        .data(force.nodes())
        .enter().append("g")
        .attr("class", "node")
        .on("mouseover", mouseover)
        .on("mouseout", mouseout)
        .on("click", click)
        .on("dblclick", dblclick)
        .call(force.drag);

    node.append("circle")
        .attr("r", 12)
        .style("fill", "#C71585");

    node.append("text")
        .attr("x", 14)
        .attr("dy", ".35em")
        .style("fill", "#333")
        .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 + ")";
        });
    }

    function mouseover() {
        d3.select(this).select("circle").transition()
            .duration(750)
            .attr("r", 16);
    }

    function mouseout() {
        d3.select(this).select("circle").transition()
            .duration(750)
            .attr("r", 12);
    }
    // action to take on mouse click
    function click() {
        d3.select(this).select("text").transition()
            .duration(750)
            .attr("x", 22)
            .style("stroke-width", ".5px")
            .style("opacity", 1)
            .style("fill", "#E34A33")
            .style("font", "17.5px serif");
        d3.select(this).select("circle").transition()
            .duration(750)
            .style("fill", "#E34A33")
            .attr("r", 16)
    }

    // action to take on mouse double click
    function dblclick() {
        d3.select(this).select("circle").transition()
            .duration(750)
            .attr("r", 12)
            .style("fill", "#E34A33");
        d3.select(this).select("text").transition()
            .duration(750)
            .attr("x", 14)
            .style("stroke", "none")
            .style("fill", "#E34A33")
            .style("stroke", "none")
            .style("opacity", 0.6)
            .style("font", "14px serif");
    }





    </script>
    </div>
    </div>
    </div>
    </div>
    </div>

    </body>
    </html>

【问题讨论】:

    标签: javascript node.js json d3.js ejs


    【解决方案1】:

    如果没有要运行的示例项目,我很难验证这一点,但这是我认为发生的事情:

    links.forEach(function (link) { 运行时,links 的值仍然是[],因为$.getJSON('/visualizer', function(data) { 中的function 是异步运行的,并且可能会在运行其余代码之后发生。

    尝试模块化您的初始化代码并在异步代码之后调用它。像这样的:

    <script>
      let numRequests = 0
      let links = []
      let nodes = {}
      let link
      let node
    
      let testData = [{
        "source": "Analytics",
        "target": "Science"
      }, {
        "source": "Analytics",
        "target": "Software"
      }, {
        "source": "Analytics",
        "target": "Story"
      }, {
        "source": "Science",
        "target": "Math"
      }, {
        "source": "Science",
        "target": "Statistics"
      }, {
        "source": "Software",
        "target": "R"
      }, {
        "source": "Software",
        "target": "SAS"
      }, {
        "source": "Software",
        "target": "Other"
      }, {
        "source": "Story",
        "target": "Business Communication"
      }, {
        "source": "Story",
        "target": "Visualization"
      }]
    
    
      const addIfUnique = (list, item) => list.indexOf(item) === -1 ? list.concat(item) : list
      const byName = (links, {source, target}) => addIfUnique(addIfUnique(links, source), target)
      const toNode = (name, i) => ({name, index: i})
    
      function addLinks(data) {
        let names = data.reduce(byName, [])
        const toLink = ({source, target}) => ({
          source: names.indexOf(source),
          target: names.indexOf(target)
        })
        nodes = names.map(toNode)
        links = data.map(toLink)
      }
    
      function tick() {
        link.attr("x1", d => d.source.x)
          .attr("y1", d => d.source.y)
          .attr("x2", d => d.target.x)
          .attr("y2", d => d.target.y)
    
        node.attr("transform", d => `translate(${d.x},${d.y})`)
      }
    
      function mouseover() {
        d3.select(this).select("circle").transition()
          .duration(750)
          .attr("r", 16)
      }
    
      function mouseout() {
        d3.select(this).select("circle").transition()
          .duration(750)
          .attr("r", 12)
      }
    
      function click() {
        d3.select(this).select("text").transition()
          .duration(750)
          .attr("x", 22)
          .style("stroke-width", ".5px")
          .style("opacity", 1)
          .style("fill", "#E34A33")
          .style("font", "17.5px serif")
    
        d3.select(this).select("circle").transition()
          .duration(750)
          .style("fill", "#E34A33")
          .attr("r", 16)
      }
    
      function dblclick() {
        d3.select(this).select("circle").transition()
          .duration(750)
          .attr("r", 12)
          .style("fill", "#E34A33")
    
        d3.select(this).select("text").transition()
          .duration(750)
          .attr("x", 14)
          .style("stroke", "none")
          .style("fill", "#E34A33")
          .style("stroke", "none")
          .style("opacity", 0.6)
          .style("font", "14px serif")
      }
    
      function drawGraph() {
        const width = 900
        const height = 300
    
        const force = d3.layout.force()
          .nodes(d3.values(nodes))
          .links(links)
          .size([width, height])
          .linkDistance(50)
          .charge(-200)
          .on("tick", tick)
          .start()
    
        const svg = d3.select("#trythis").append("svg")
          .attr("width", width)
          .attr("height", height)
    
        link = svg.selectAll(".link")
          .data(force.links())
          .enter().append("line")
          .attr("class", "link")
    
        node = svg.selectAll(".node")
          .data(force.nodes())
          .enter().append("g")
          .attr("class", "node")
          .on("mouseover", mouseover)
          .on("mouseout", mouseout)
          .on("click", click)
          .on("dblclick", dblclick)
          .call(force.drag)
    
        node.append("circle")
          .attr("r", 12)
          .style("fill", "#C71585")
    
        node.append("text")
          .attr("x", 14)
          .attr("dy", ".35em")
          .style("fill", "#333")
          .text(d => d.name)
      }
    
      function verifyItem1IsCorrect() {
        const item1 = JSON.stringify(links[0])
        console.log(`${item1} is links 0`)
      }
    
      function setUpGraph(data) {
        addLinks(data)
        drawGraph()
        verifyItem1IsCorrect()
      }
    
      // $.getJSON('/visualizer', setUpGraph)
      setUpGraph(testData)
    </script>
    

    编辑:D3.js v3 API 具有linksnodes 所需的非常具体的布局。

    nodes 数组有一个简单的整数索引和一个字符串名称的对象,而 links 数组有带有源和目标属性的对象,但源和目标必须是:

    • 引用节点索引的整数;或
    • 对节点数组中实际节点的对象引用。

    【讨论】:

    • 是的,我绝对明白你在说什么——我得到的是 links[] 是空的。立即尝试,会通知您!
    • 所以,看起来正确的数据在那里 - 它只是卡在屏幕的角落。我得到 network:266 Uncaught ReferenceError: link is not defined。 (发生在tick()函数中)这可能是因为“链接”在被调用之前没有定义吗?
    • 是的,当然。事后我看到了。我会用新代码(ES6 的东西)更新这个答案。
    • 它是异步代码和作用域的结合:link 需要存在于tick() 可以访问它的作用域中,并且它还需要有一个可以引用的值。如果初始化代码在数据存在之前运行,那么它将创建一个没有数据的链接变量。
    • d3.v3.min.js:4 未捕获的类型错误:无法在 Object.l.start (d3.v3.min.js:4) 处读取未定义的属性“push”。 v3.min.js:4) at drawGraph (network:372) at Object.setUpGraph [as success] (network:412) at i (jquery.min.js:2) at Object.fireWith [as resolveWith] (jquery. min.js:2) at A (jquery.min.js:4) at XMLHttpRequest. (jquery.min.js:4) ----看来错误与未定义推送有关-不过对我来说没有意义......特别是因为我们现在已经在开始时初始化了 links[]
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-02
    • 1970-01-01
    • 2012-10-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多