【问题标题】:D3 JSON file with source and index as strings rather than indicesD3 JSON 文件,源和索引为字符串而不是索引
【发布时间】:2023-03-15 16:09:04
【问题描述】:

此代码与源和索引均采用索引形式的 JSON 文件完美配合。但是,当我切换到源和目标为字符串的格式时,它会抛出 TypeError: e[u.source.index] is undefined。我该如何克服这个问题?

<!DOCTYPE html>
<meta charset="utf-8">
<body>
<script src="https://d3js.org/d3.v3.min.js"></script>
<script>

var width = 960,
    height = 500,
    active = d3.select(null);

var zoom = d3.behavior.zoom()
    .scaleExtent([1, 8])
    .on("zoom", zoomed);    

var force = d3.layout.force()
    .size([width, height])
    .charge(-400)
    .linkDistance(40)
    .on("tick", tick);

var drag = force.drag()
    .on("dragstart", dragstart);

var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height)
   // .on("click", reset);

var g = svg.append("g");

var link = g.selectAll(".link"),
    node = g.selectAll(".node");

svg
    .call(zoom) // delete this line to disable free zooming
    .call(zoom.event);

d3.json("data/miserables.json", function(error, graph) {
  if (error) throw error;

  force
      .nodes(graph.nodes)
      .links(graph.links)
      .start();

  link = link.data(graph.links)
    .enter().append("line")
      .attr("class", "links")
      .style("stroke", "#999");

  node = node.data(graph.nodes)
    .enter().append("circle")
      .attr("class", "node")
      .attr("r", 12)
      .on("click", clicked)
      //.call(drag);
});

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("cx", function(d) { return d.x; })
      .attr("cy", function(d) { return d.y; });
}

function clicked(d){
  if (active.node() === this) return reset();
  active.classed("active", false);
  active = d3.select(this).classed("active", true);

  var bbox = active.node().getBBox(),
      bounds = [[bbox.x, bbox.y],[bbox.x + bbox.width, bbox.y + bbox.height]];

  var dx = bounds[1][0] - bounds[0][0],
      dy = bounds[1][1] - bounds[0][1],
      x = (bounds[0][0] + bounds[1][0]) / 2,
      y = (bounds[0][1] + bounds[1][1]) / 2,
      scale = Math.max(1, Math.min(8, 0.9 / Math.max(dx / width, dy / height))),
      translate = [width / 2 - scale * x, height / 2 - scale * y];

  svg.transition()
      .duration(750)
      .call(zoom.translate(translate).scale(scale).event);
} 

function reset() {
  active.classed("active", false);
  active = d3.select(null);

  svg.transition()
      .duration(750)
      .call(zoom.translate([0, 0]).scale(1).event);
}    


function dragstart(d) {
  d3.select(this).classed("fixed", d.fixed = true);
}

function zoomed() {
  console.log(d3.event)
  g.style("stroke-width", 1.5 / d3.event.scale + "px");
  g.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
}    

</script>

【问题讨论】:

    标签: javascript json d3.js


    【解决方案1】:

    您使用的是 D3 v3.x。虽然在 D3 v4.x 中按名称链接是一件容易的事,但在 D3 v3.x 中似乎不可能。请参阅 D3 v3.x 中的 this issue,以及 API 中的说明:

    注意:源和目标属性的值最初可以指定为节点数组的索引;这些将在调用开始后被引用替换。

    这样,下面的sn-p就不行了(代码不是我的,我只是在网上找到的,把links数组从索引改成了名字):

    var nodes = [{
        name: "node1"
    }, {
        name: "node2"
    }, {
        name: "node3"
    }, {
        name: "node4"
    }, {
        name: "node5"
    }, {
        name: "node6"
    }, {
        name: "node7"
    }];
    
    var edges = [{
        source: "node1",
        target: "node3"
    }, {
        source: "node1",
        target: "node2"
    }, {
        source: "node1",
        target: "node4"
    }, {
        source: "node2",
        target: "node3"
    }, {
        source: "node2",
        target: "node5"
    }, {
        source: "node2",
        target: "node6"
    }, {
        source: "node3",
        target: "node"
    }];
    
    var width = 400;
    var height = 400;
    var svg = d3.select("body")
        .append("svg")
        .attr("width", width)
        .attr("height", height);
    
    var force = d3.layout.force()
        .nodes(nodes)
        .links(edges)
        .size([width, height])
        .linkDistance(150)
        .charge(-400);
    
    force.start();
    var svg_edges = svg.selectAll("line")
        .data(edges)
        .enter()
        .append("line")
        .style("stroke", "#ccc")
        .style("stroke-width", 1);
    
    var color = d3.scale.category20();
    var svg_nodes = svg.selectAll("circle")
        .data(nodes)
        .enter()
        .append("circle")
        .attr("r", 20)
        .style("fill", function(d, i) {
            return color(i);
        })
        .call(force.drag);
    var svg_texts = svg.selectAll("text")
        .data(nodes)
        .enter()
        .append("text")
        .style("fill", "black")
        .attr("dx", 20)
        .attr("dy", 8)
        .text(function(d) {
            return d.name;
        });
    
    force.on("tick", function() {
        svg_edges.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;
            });
    
        svg_nodes.attr("cx", function(d) {
                return d.x;
            })
            .attr("cy", function(d) {
                return d.y;
            });
    
        svg_texts.attr("x", function(d) {
                return d.x;
            })
            .attr("y", function(d) {
                return d.y;
            });
    });
    &lt;script src="https://d3js.org/d3.v4.min.js"&gt;&lt;/script&gt;

    如果你点击“run sn-p”,你只会看到一个错误:

    未捕获的类型错误:无法读取未定义的属性“强制”

    解决方案:使用索引保持链接数组。但是,如果您已经拥有/接收了一个带有名称的数组,则可以将其更改为索引:

    var nodeByName = d3.map(nodes, function(d) {
        return d.name;
    });
    
    edges.forEach(function(d) {
        d.source = nodeByName.get(d.source);
        d.target = nodeByName.get(d.target);
    });
    

    这里是第一个sn-p的相同代码,但有上述更改。现在可以了:

    var nodes = [{
        name: "node1"
    }, {
        name: "node2"
    }, {
        name: "node3"
    }, {
        name: "node4"
    }, {
        name: "node5"
    }, {
        name: "node6"
    }, {
        name: "node7"
    }];
    
    var edges = [{
        source: "node1",
        target: "node3"
    }, {
        source: "node1",
        target: "node2"
    }, {
        source: "node1",
        target: "node4"
    }, {
        source: "node2",
        target: "node3"
    }, {
        source: "node2",
        target: "node5"
    }, {
        source: "node2",
        target: "node6"
    }, {
        source: "node2",
        target: "node7"
    }];
    
    var nodeByName = d3.map(nodes, function(d) {
        return d.name;
    });
    
    edges.forEach(function(d) {
        d.source = nodeByName.get(d.source);
        d.target = nodeByName.get(d.target);
    });
    
    var width = 400;
    var height = 400;
    var svg = d3.select("body")
        .append("svg")
        .attr("width", width)
        .attr("height", height);
    
    var force = d3.layout.force()
        .nodes(nodes)
        .links(edges)
        .size([width, height])
        .linkDistance(150)
        .charge(-400);
    
    force.start();
    var svg_edges = svg.selectAll("line")
        .data(edges)
        .enter()
        .append("line")
        .style("stroke", "#ccc")
        .style("stroke-width", 1);
    
    var color = d3.scale.category20();
    var svg_nodes = svg.selectAll("circle")
        .data(nodes)
        .enter()
        .append("circle")
        .attr("r", 20)
        .style("fill", function(d, i) {
            return color(i);
        })
        .call(force.drag);
    var svg_texts = svg.selectAll("text")
        .data(nodes)
        .enter()
        .append("text")
        .style("fill", "black")
        .attr("dx", 20)
        .attr("dy", 8)
        .text(function(d) {
            return d.name;
        });
    
    force.on("tick", function() {
        svg_edges.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;
            });
    
        svg_nodes.attr("cx", function(d) {
                return d.x;
            })
            .attr("cy", function(d) {
                return d.y;
            });
    
        svg_texts.attr("x", function(d) {
                return d.x;
            })
            .attr("y", function(d) {
                return d.y;
            });
    });
    &lt;script src="https://d3js.org/d3.v3.min.js"&gt;&lt;/script&gt;

    【讨论】:

      猜你喜欢
      • 2012-05-10
      • 2022-01-14
      • 1970-01-01
      • 1970-01-01
      • 2014-12-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多