d3js强制布局:节点和链接位置的值为空

时间:2018-09-24 10:53:26

标签: javascript d3.js

我目前正在对此d3js force layout tutorial进行一些自定义修改。通常,我的兴趣是在后端和d3.js可视化之间引入一个抽象层,我正在使用JS类进行此操作。现在,我主要是丢弃我在模拟.json文件中拥有的某些属性,但是这种逻辑可能会变得更加复杂。

这是我似乎无法上班的MWE:

index.html

<!DOCTYPE html>
<html>
<meta charset="utf-8">

<head>
</head>

<body>
    <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
    <script src="http://d3js.org/d3.v3.min.js"></script>
    <script src="js/model.js"></script>
    <script src="js/viz.js"></script>
</body>

</html>

model.js

class Node {

    constructor(id, name) {
        this.id = id;
        this.name = name;
        this.outEdges = {};
        this.inEdges = {};
    }

}

class Edge {

    constructor(node1, node2) {
        this.source = node1;
        this.target = node2;
    }

}

class Graph {

    constructor(nodes, edges) {
        this.nodes = {}
        for (let node of nodes) {
            this.nodes[node.id] = node;
        }
        for (let edge of edges) {
            this.nodes[edge.source].outEdges[edge.target] = edge;
            this.nodes[edge.target].inEdges[edge.source] = edge;
        }
        this.edges = edges;
    }

}

viz.js

function loadJson() {
    path = "mockup2.json";
    $.getJSON(path, function(json) {
        var nodes = [];
        var edges = [];

        for (let node of json.nodes) {
            var temp = new Node(node.index, node.name);
            nodes.push(temp);
        }
        for (let edge of json.edges) {
            var temp = new Edge(edge.node1, edge.node2);
            edges.push(temp);
        }
        var graph = new Graph(nodes, edges);

        drawGraph(graph);
    });
}

function drawGraph(graph) {
    width = "90%";
    height = "90%";

    // set up svg and layout
    var svg = d3.select("body").append("svg")
                               .attr("width", width)
                               .attr("height", height);

    var force = d3.layout.force()
                  .gravity(.1)
                  .distance(20)
                  .charge(-30)
                  .size([width, height]);

    // prep nodes and links for d3 viz
    var d3nodes = [];
    var temp = {};
    for (var key in graph.nodes) {
        node = graph.nodes[key]
        temp = {}
        temp.x = Math.random() * 100;
        temp.y = Math.random() * 100;
        temp.index = node.id;
        d3nodes.push(temp);
    }

    d3edges = [];
    var temp = {}
    for (var key in graph.edges) {
        edge = graph.edges[key];
        temp = {}
        temp.source = edge.source;
        temp.target = edge.target;
        temp.timediff = edge.timediff;
        d3edges.push(temp);
    }

    // draw links and nodes
    var svglinks = svg.selectAll('.link')
                        .data(d3edges)
                        .enter().append('line')
                        .attr('class', 'link');

    var svgnodes = svg.selectAll('.node')
            .data(d3nodes)
            .enter().append('g')
            .attr('class', 'node')
            .call(force.drag);

    force.nodes(d3nodes)
         .links(d3edges)
         .linkDistance(width/3)
         .start();

    // test svglinks values
    svglinks.forEach(function(d) {
        console.log(JSON.stringify(d));
    });

    force.on("tick", function() {
        svglinks.attr("x1", function(d) {
                            console.log(JSON.stringify(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; });

        svgnodes.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });

        // avoid console spam
        force.stop();
    });

}


$(document).ready(function() {
    loadJson();
});

mockup2.json

{
  "nodes": [
    {"index": 0, "name": 0, "timestamp": 1, "group": 1},
    {"index": 1, "name": 0, "timestamp": 0, "group": 2},
    {"index": 2, "name": 0, "timestamp": 0, "group": 3},
    {"index": 3, "name": 0, "timestamp": 2, "group": 1},
    {"index": 4, "name": 0, "timestamp": 0, "group": 2},
    {"index": 5, "name": 0, "timestamp": 3, "group": 3},
    {"index": 6, "name": 0, "timestamp": 2, "group": 3},
    {"index": 7, "name": 0, "timestamp": 5, "group": 2},
    {"index": 8, "name": 0, "timestamp": 8, "group": 2},
    {"index": 9, "name": 0, "timestamp": 3, "group": 1}
  ],
  "edges": [
    {"node1": 1, "node2": 2},
    {"node1": 2, "node2": 4},
    {"node1": 4, "node2": 8},
    {"node1": 4, "node2": 8},
    {"node1": 8, "node2": 2},
    {"node1": 5, "node2": 9}
  ]
}

对我来说,最可恶的是,svglinks变量似乎在force.on('tick')之外之前还不错,它显示xy,{ {1}}和px-我也提供了一个py通话供您检查。但是,在该函数中打印相同的对象将为我显示所有这些属性的console.log()值,这使d3.js可以正确地绘制图形(至少以我的直觉)。

我还有一个更“标准”的示例,该示例使用更标准的null调用来加载.json文件,该文件已预先格式化为d3.json()source属性;这很完美。因此,我的直觉是我没有在上面正确构建targetd3nodes变量;但是,将它们与示例进行比较表明,它们看起来完全一样。我承认,我在这里有些傻眼了!

预先感谢所有愿意花时间去尝试的人。

0 个答案:

没有答案