我遇到了位于此处的以下示例。
它基于这个问题。
我注意到的问题是它匹配第一个匹配节点并停止。这些关系基于每个条目的第一个匹配节点,而不是所有匹配节点。
我已经修改了代码,但我似乎无法弄清楚为什么图表不能正确呈现。
执行此操作的代码部分位于下面的第 64 行到第 128 行之间。完整的源代码在这里:http ://bl.ocks.org/hijonathan/raw/5793014/664407f1855a61250b30458b583fb59635bf3157/script.js
该脚本使用 underscore.js,我认为更正应该是使用 _.filter 而不是 _.find。关于修改此代码以包含所有关系的任何建议,而不是匹配第一个并停止?
可以在此处找到输出的实时示例。
var width = document.width,
height = document.height,
nodeRadius = 20,
subNodeRadius = nodeRadius / 2,
k = Math.sqrt(12 / (width * height));
var color = d3.scale.category20();
var force = d3.layout.force()
.linkDistance(function(d) {
if (d.type && d.type === 'property') {
return 10;
}
else {
return 100;
}
})
.charge(-10 / k)
.gravity(100 * k)
.size([width, height])
var svg = d3.select("body").append("svg:svg")
.attr("width", width)
.attr("height", height)
.attr("pointer-events", "all")
.append('svg:g')
.call(d3.behavior.zoom().on("zoom", redraw))
.append('svg:g');
svg.append('svg:rect')
.attr('width', width)
.attr('height', height)
.attr('fill', 'white');
function redraw() {
console.log("here", d3.event.translate, d3.event.scale);
svg.attr("transform",
"translate(" + d3.event.translate + ")" + " scale(" + d3.event.scale + ")");
}
d3.json("categories.json", function(error, graph) {
// Break out property nodes
var people = _.where(graph.nodes, {type: 'person'}),
nodes = people;
_.each(people, function(p) {
_.each(p, function(prop, _k) {
if (_k !== 'name' && _k !== 'Name' && _k !== 'id' && _k !== 'type') {
nodes.push({
target: p.id,
type: 'property',
name: _k,
value: prop
});
}
});
});
force.nodes(nodes);
// Dynamically build links based on shared attributes
var links = [];
var _nodes = nodes.slice(); // copy
_.each(nodes, function(n, i) {
if (n.type === "person") {
_nodes.shift();
var t = i,
matchKey,
matchValue;
//console.log(n);
for (var key in n) {
//console.log(n[key]+"THAT");
if (key === 'type' || key === 'target') {
continue;
}
var val = n[key];
//console.log(val + "THIS");
//should likely use _.filter() as opposed to _.find...
t = _.filter(_nodes, function(_n) {
//console.log(val);
return _n[key] === val;
});
if (t) {
//matchKey = key;
//matchValue = val;
//break;
}
}
console.log(t);
_.each(t, function(tv,tk) {//ITERATES OVER OBJECT COLLECTION
for(var tk2 in tv){ //ITERATES OVER EACH KEY VAL PAIR IN OBJECT.
if(tk2 ==='type' || tk2 ==='Likes Food'){
continue;
}
var val2 = tv[tk2];
at = _.find(t, function(_at){
return _at[tk2] === val2;
});
//console.log(at+"THIS IS AT");
if(at){
//console.log(tk2+":"+tv[tk2]);
var matchkey2 = tk2;
var matchval2 = val2;
console.log(matchkey2+":"+matchval2);
var uniqat = _.clone(at);
delete uniqat[matchkey2];
//delete uniqat.name;
//delete uniqat['Name'];
links.push(_.extend({
source: tk,
target: (at && at.id) || tk,
matchKey: matchkey2,
matchValue: matchval2
}, {props: uniqat}));
}
}
});
}
else {
links.push(_.extend(n, {
source: i
}));
}
});
force.links(links);
force.start();
var link = svg.selectAll(".link")
.data(links)
.enter().append("g")
.attr('class', function(d) {
if (d.props) {
return 'person link';
}
else return 'property link';
});
var line = link.append('line')
.style("stroke-width", 1);
var matchCirlce = svg.selectAll('.link.person')
.append('circle')
.attr('r', subNodeRadius)
.style('fill', '#000');
var text = svg.selectAll('.link.person')
.append("text")
.attr('dy', '.35em')
.attr('text-anchor', 'middle')
.text(function(d) {
if (d.matchValue === true || d.matchValue === false) {
return d.matchKey;
}
else {
return d.matchKey+ ": " + d.matchValue;
}
});
var node = svg.selectAll(".node")
.data(nodes)
.enter()
.append('g')
.attr("class", function(d) {
if (d.type && d.type === 'person') {
return 'node person'
}
else {
return 'node property';
}
})
.call(force.drag);
var circle = node.append("circle")
.attr("r", function(d) {
if (d.type && d.type === 'person') {
return nodeRadius;
}
else {
return subNodeRadius;
}
})
.style('fill', function(d) {
if (d.type && d.type === 'person') {
return color(d.id);
}
else {
return '#eee'
}
});
node.append("text")
.attr('dy', '.35em')
.attr('text-anchor', 'middle')
.text(function(d) {
if (d.type && d.type === 'person') {
return d.name;
}
else {
if (d.value === true || d.value === false) {
return d.name;
}
else return d.value;
}
});
force.on("tick", function() {
node.attr("transform", function(d) {
return "translate(" + d.x + "," + d.y + ")";
});
line.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; });
text.attr("transform", translateBetween);
matchCirlce.attr("transform", translateBetween);
});
});
function translateBetween(d) {
var x1 = d.source.x;
var y1 = d.source.y;
var x2 = d.target.x;
var y2 = d.target.y;
return "translate(" + (x1 + x2) / 2 + "," + (y1 + y2) / 2 + ")";
}