我有一个函数,该函数会在页面加载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>
答案 0 :(得分:0)
我很难在没有示例项目运行的情况下进行验证,但这是我认为已发生的事情:
在links.forEach(function (link) {
运行时,links
仍具有值[]
,因为function
中的$.getJSON('/visualizer', function(data) {
异步运行,并且很可能在运行后发生您其余的代码。
尝试模块化您的初始化代码,并在异步代码之后调用它。像这样:
<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具有links和nodes所需的非常特定的布局。
nodes数组中的对象带有一个简单的整数索引和一个字符串名称,links数组中的对象具有源和目标属性,但源和目标必须是: