График не будет перезагружаться должным образом в раскладке D3.
Я играю с D3 и строю форсированные графики. Я хочу очистить и перезагрузить график в ответ на нажатия на кнопки. Однако, когда я перезагружаю уже загруженный график, он не форматируется должным образом. Это код, который я использую:
<!DOCTYPE html>
<meta charset="utf-8">
<script src="http://d3js.org/d3.v2.js?2.9.1"></script>
<style>
.link {
fill: none;
stroke: #666;
stroke-width: 1.5px;
}
.node circle {
fill: #ccc;
stroke: #fff;
stroke-width: 1.5px;
}
text {
font: 10px sans-serif;
pointer-events: none;
}
</style>
<body>
<script>
var all = [
{source: "Tockwotton", target: "List", type: "woodworking"},
{source: "Tockwotton", target: "Prince Lab", type: "woodworking"},
{source: "Prince Lab", target: "Prince Lab", type: "metalworking"},
{source: "Tockwotton", target: "List", type: "cnc"},
{source: "Granoff", target: "Prince Lab", type: "3d-printing"},
{source: "Tockwotton", target: "List", type: "drafting"},
{source: "List", target: "Prince Lab", type: "welding"},
{source: "Prince Lab", target: "Prince Lab", type: "sand-blaster"},
{source: "Tockwotton", target: "List", type: "finishing"},
{source: "Tockwotton", target: "Prince Lab", type: "finishing"},
{source: "Tockwotton", target: "Tockwotton", type: "laser-cutter"}
];
var wood = [
{source: "Tockwotton", target: "List", type: "woodworking"},
{source: "Tockwotton", target: "Prince Lab", type: "woodworking"}
];
var metal = [
{source: "Prince Lab", target: "Prince Lab", type: "metalworking"}
];
var cnc = [
{source: "Tockwotton", target: "List", type: "cnc"}
];
var print = [
{source: "Granoff", target: "Prince Lab", type: "3d-printing"}
];
var draft = [
{source: "Tockwotton", target: "List", type: "drafting"}
];
var weld = [
{source: "List", target: "Prince Lab", type: "welding"}
];
var sand = [
{source: "Prince Lab", target: "Prince Lab", type: "sand-blaster"}
];
var finishing = [
{source: "Tockwotton", target: "List", type: "finishing"},
{source: "Tockwotton", target: "Prince Lab", type: "finishing"}
];
var laser = [
{source: "Tockwotton", target: "Tockwotton", type: "laser-cutter"}
];
function render(linkdata){
d3.selectAll("svg").remove();
links = linkdata;
nodes = {};
// Compute the distinct nodes from the links.
links.forEach(function(link) {
link.source = nodes[link.source] || (nodes[link.source] = {name: link.source, type: link.type});
link.target = nodes[link.target] || (nodes[link.target] = {name: link.target, type: link.type});
});
width = 960,
height = 500;
force = d3.layout.force()
.nodes(d3.values(nodes))
.links(links)
.size([width, height])
.linkDistance(60)
.charge(-300)
.on("tick", tick)
.start();
svg = d3.select("body").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)
.call(force.drag);
node.append("circle")
.attr("r", 8);
node.append("text")
.attr("x", 12)
.attr("dy", ".35em")
.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", 8);
}
}
</script>
<div id="nav">
<div id="wood">
<a onclick="render(wood)">Woodworking</a>
</div>
<div id="metal">
<a onclick="render(metal)">Metalworking</a>
</div>
<div id="cnc">
<a onclick="render(cnc)">CNC</a>
</div>
<div id="print">
<a onclick="render(print)">3D Printing</a>
</div>
<div id="draft">
<a onclick="render(draft)">Drafting</a>
</div>
<div id="weld">
<a onclick="render(weld)">Welding</a>
</div>
<div id="sand">
<a onclick="render(sand)">Sand Blast</a>
</div>
<div id="finishing">
<a onclick="render(finishing)">Finishing</a>
</div>
<div id="laser">
<a onclick="render(laser)">Laser Cutting</a>
</div>
<div id="all">
<a onclick="render(all)">All</a>
</div>
</div>
</body>
Попробуйте и обратите внимание, что при первом нажатии на элемент он работает нормально, но если вы щелкнете по нему еще раз, вы получите только один узел с именем [object Object]
, Почему это и как я могу это исправить?
1 ответ
Когда вы используете links = linkdata
это, вероятно, не делает то, что вы ожидаете. Как и некоторые другие языки, это не копирует данные; вместо этого он просто делает links
указывают на то же место, что linkdata
указывает на. Когда вы проходите через links
модифицируя их так, чтобы они указывали друг на друга, вы модифицируете исходные объекты в массивах. Когда вы снова просматриваете их, они уже были изменены, что приводит к нежелательному поведению, которое вы испытываете.
Чтобы избежать этой участи, вам необходимо глубоко скопировать массив, прежде чем изменять его. Есть несколько способов сделать это, но вы должны убедиться, что любое используемое вами решение будет клонировать массив как массив, не превращая его в простой Object
,