我目前正在使用D3创建力导向图。 我一直在尝试使用HTML页面上的单选按钮创建年龄过滤器(使用年龄范围)。另外,我也在使用导入的JSON文件。
场景:我试图达到的预期结果是,当用户选择一个单选按钮时,应该看到具有特定年龄(从JSON文件创建)并且在范围内且符合条件的节点,而其他节点散焦。
到目前为止,每当我单击每个单选按钮时,都会连续出现一条错误消息,指出“未捕获的TypeError:无法读取未定义的属性'age'”。我确实查看了我的代码,看看它有什么问题。但是,我仍然不明白。在运行控制台时,错误出现在代码的此特定行“ if(d.age> = ageBracket [0] && d.age <= ageBracket [1])”。我的猜测是我是否必须为“ d.age”运行另一个循环?
**编辑:我添加了更多的JavaScript代码和HTML代码。
下面包含我的代码。
1。)Javascript代码:
(function(){
function sayHello(){
var name = "Hi John";
return
{
fullName: name
}
}
console.log(sayHello().fullName);
})();
2。)HTML代码
function createGraph() {
var svg = d3.select("svg"),
width = +svg.attr("width"),
height = +svg.attr("height");
var radius = 25;
/////////////////////////////////////////////////////////////////////////
d3.json("patient.json", function(error, d) {
if (error) throw error;
var dataset_nodes = d.nodes;
var dataset_links = d.links;
// console.log(dataset_nodes);
//console.log(dataset_links);
var simulation = d3.forceSimulation()
.nodes(dataset_nodes);
var link_force = d3.forceLink(dataset_links).id(function(d) { return d.id; })
.distance(function(d) { return d.value; })
.strength(1);
var charge_force = d3.forceManyBody()
.strength(-150); //initial value is 100
var center_force = d3.forceCenter(width / 2, height / 2);
simulation
.force("charge_force", charge_force)
.force("center_force", center_force)
.force("links", link_force)
//add tick instructions:
simulation.on("tick", tickActions);
//add encompassing group for the zoom
var g = svg.append("g")
.attr("class", "everything");
//draw lines for the links
var link = g.append("g")
.attr("class", "links")
.selectAll("line")
.data(dataset_links)
.enter().append("line")
.attr("stroke-width", 2)
.style("stroke", "#000000");
//draw circles for the nodes
var node = g.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(dataset_nodes)
.enter()
.append("circle")
.attr("r", radius)
.attr("fill", "#000000");
//add drag capabilities
var drag_handler = d3.drag()
.on("start", drag_start)
.on("drag", drag_drag)
.on("end", drag_end);
drag_handler(node);
//add zoom capabilities
var zoom_handler = d3.zoom()
.on("zoom", zoom_actions);
zoom_handler(svg);
function drag_start(d) {
if (!d3.event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
//make sure you can't drag the circle outside the box
function drag_drag(d) {
d.fx = d3.event.x;
d.fy = d3.event.y;
}
function drag_end(d) {
if (!d3.event.active) simulation.alphaTarget(0);
d.fx = null;
d.fy = null;
}
//Zoom functions
function zoom_actions() {
g.attr("transform", d3.event.transform)
}
function tickActions() {
//update circle positions each tick of the simulation
node.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
//update link positions
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; });
}
//Code for radio button filter on age range
d3.selectAll("input[name=radiob]").on("change", function(d) {
var age = document.getElementsByName("radiob");
var ageBracket;
node.style("opacity", 1);
link.style("opacity", 1);
for(var i=0; i < age.length; i++) {
if(age[i].checked) {
ageBracket = age[i].value.split("-");
if(d.age >= ageBracket[0] && d.age <= ageBracket[1])
{
node.filter(function(d) {
return d.age != ageBracket;
})
.style("opacity", "0.2");
link.filter(function(d) {
return d.source.age != ageBracket &&
d.target.age != ageBracket;
})
.style("opacity", "0.2");
link.filter(function(d) {
return d.source.age == ageBracket ||
d.target.age == ageBracket;
})
.style("opacity", "1");
}
}
}
});
}); //End of reading json file
}
3。)JSON文件的一小部分
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>D3 Visualization-Force Directed Graph</title>
<link href="style2.css" rel="stylesheet">
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="scripts2.js"></script>
<link href="https://fonts.googleapis.com/css?family=Ubuntu" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Oswald" rel="stylesheet">
</head>
<body>
<svg width="950" height="820"></svg>
<script>
createGraph();
</script>
<h3 id="title3">Age</h3>
<div class="radioButtonBoxMenu">
<label><input name="radiob" type="radio" value="0-20">0-20</label><br>
<label><input name="radiob" type="radio" value="20-30">20-30</label><br>
<label><input name="radiob" type="radio" value="30-40">30-40</label><br>
<label><input name="radiob" type="radio" value="40">40+</label><br>
</div>
答案 0 :(得分:1)
好的,所以您的代码无法正常工作的原因是因为您将包含数据的数组视为实际节点。您需要选择在“ createGraph”函数中创建的实际svg“节点”和“链接”。这是一个codepen:https://codepen.io/anon/pen/wxMmvm?editors=0011
要解决此问题,我选择了“节点”和“链接”,然后使用'.each'在这些对象中的每个对象上调用一个函数,以检查数据是否包含所选范围内的年龄值:>
//Code for radio button filter on age range
d3.selectAll("input[name=radiob]").on("change", function(d) {
var self = this;
var ageBracket = {
min : self.value.split('-')[0],
max : self.value.split('-')[1]
};
d3.selectAll('.nodes')
.selectAll('circle')
.each(function (d) {
if (d.age >= ageBracket.min && d.age <= ageBracket.max) {
d3.select(this).style('opacity', 1)
} else {
d3.select(this).style('opacity', 0.2)
}
})
d3.selectAll('.links')
.selectAll('line')
.each(function (d) {
if (d.target.age >= ageBracket.min && d.target.age <= ageBracket.max) {
d3.select(this).style('opacity', 1)
} else {
d3.select(this).style('opacity', 0.2)
}
})
});
注意:
答案 1 :(得分:1)
我将几家医院添加到json文件中
{
"nodes":[
{ "id": "1", "name": "John", "age": "31", "gender": "M"},
{ "id": "2", "name": "Emily", "age": "23", "gender": "F" },
{ "id": "3", "name": "Crystal", "age": "23", "gender": "F" },
{ "id": "4", "name": "Himiko", "age": "23", "gender": "F" },
{ "id": "hospital1", "name": "H1", "age": "31", "gender": "M"},
{ "id": "hospital2", "name": "H2", "age": "23", "gender": "F" },
{ "id": "hospital3", "name": "H3", "age": "23", "gender": "F" },
{ "id": "hospital4", "name": "H4", "age": "23", "gender": "F" }
],
"links": [
{ "source": "hospital1", "target": "1", "value": 200 },
{ "source": "hospital2", "target": "2", "value": 200 },
{ "source": "hospital3", "target": "3", "value": 200 },
{ "source": "hospital4", "target": "4", "value": 200 }]
}
它能够绘制节点和链接。
然后选择单选按钮显示了对d
的访问字段的违反。单选按钮更改回调没有参数。
要比较年龄,您需要构造一个年龄比较函数,并使用它来更新节点和链接的不透明度。
d3.selectAll("input[name=radiob]").on("change", function () {
var age = document.getElementsByName("radiob");
var ageBracket;
node.style("opacity", 1);
link.style("opacity", 1);
for(var i=0; i < age.length; i++) {
if(age[i].checked) {
ageBracket = age[i].value.split("-");
var testAgeBracket = function (d) { return (d >= ageBracket[0] && d <= ageBracket[1]) };
node.filter(function(d) { return testAgeBracket(d.age); })
.style("opacity", "0.2");
link.filter(function(d) {
return !testAgeBracket(d.source.age) &&
!testAgeBracket(d.target.age); })
.style("opacity", "0.2");
link.filter(function(d) {
return testAgeBracket(d.source.age) ||
testAgeBracket(d.target.age); })
.style("opacity", "1");
}
}
});