首先抱歉我的问题,因为我认为这是因为我不太了解D3库,特别是选择的工作。
这是我想做的事情:
在这里,我不想完全重绘图表;我希望现有节点和链接保持原样,新节点和链接将飞入场景。这就是为什么我将force布局的实例保留在drawGraph函数之外(作为全局变量)。
任务#1没有问题。
问题在于任务#2;我可以让新节点进入场景......但由于某种原因我无法拖动现有节点。我只能拖动新节点(Eduardo)。
我已经在Chrome中调试了它,看到了这个" var a"有9个元素(点击后)。所以,我想函数" force.layout"应该由D3为所有这9个元素调用。所以,如果我没有正确看待,我应该能够拖动所有9个圆圈。
但事实并非如此,所以我的代码出了问题。任何人都可以指出我弄错了吗?
这是代码。之后是JSON(两个独立的jsons,news.json和news3.json)。
其他问题:
我不太明白为什么这个块(关键函数)在第二次调用drawGraph函数时执行了17次(8 + 9)(当json更新为news3.json时)?我的期望是9次。
var lineSelections = svg.selectAll('line')
.data(dataset.edges, function(d){
console.log(d);
return d.source.index + '.' + d.target.index;
});
提前致谢!,
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>D3: Force layout</title>
<script type="text/javascript" src="../d3/d3.v3.js"></script>
<style type="text/css">
#tooltip {
position: absolute;
width: 200px;
height: auto;
padding: 10px;
background-color: white;
-webkit-border-radius: 10px;
-moz-border-radius: 10px;
border-radius: 10px;
-webkit-box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4);
-moz-box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4);
box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4);
pointer-events: none;
}
#tooltip.hidden {
display: none;
}
#tooltip p {
margin: 0;
font-family: sans-serif;
font-size: 16px;
line-height: 20px;
}
</style>
</head>
<body>
<div id="tooltip" class="hidden">
<p><span id="type"></span></p>
<p><span id="name"></span></p>
</div>
<p id="refresh">Click on this text to update the chart with new data values (once).</p>
<script type="text/javascript">
//Width and height
var w = 500;
var h = 300;
//http://stackoverflow.com/questions/16455194/how-to-store-a-json-object-loaded-from-a-file
var force = d3.layout.force()
.size([w, h])
.linkDistance([20])
.charge([-50]);
var svg = d3.select('body')
.append('svg')
.attr('width', w)
.attr('height', h);
drawGraph = function(dataset) {
force
.nodes(dataset.nodes)
.links(dataset.edges)
.start();
var lineSelections = svg.selectAll('line')
.data(dataset.edges, function(d){
console.log(d);
return d.source.index + '.' + d.target.index;
});
//Create edges as lines
var edges = lineSelections
.enter()
.append('line')
.style('stroke', function(d) {
if (d.target.type === 'publication') {
return 'red';
} else {
return 'blue';
}
})
.style('stroke-width', function(d) {
return d.weight;
});
var groups = svg.selectAll('g')
.data(dataset.nodes, function(d) {
console.log(d.name);
return d.name;
})
.enter()
.append('g');
var nodes = groups
.append('circle')
.attr('r', function(d) {
if (d.type === 'publication') {
var radius = d.weight / 6;
if (radius < 5) {
radius = 5;
}
return radius;
} else {
return d.weight * 3;
}
})
.style('fill', function(d, i) {
if (d.type === 'publication') {
return 'black';
} else {
return 'green';
}
});
var a = svg.selectAll('g circle');
a.call(force.drag);
//Create labels
var text = groups
.append('text')
.text(function(d) {
if (d.type === 'publication') {
return d.name;
} else {
return '';
}
})
.attr('x', function(d, i) {
d.x;
})
.attr('y', function(d) {
d.x;
})
.attr('font-family', 'sans-serif')
.attr('font-size', '24px')
.attr('fill', 'orange');
groups
.on("mouseover", function(d) {
//Get this bar's x/y values, then augment for the tooltip
//var hmm = d3.select(this).select('circle').attr('cx');
var xPosition = d3.select(this).select('circle').attr('cx');
var yPosition = d3.select(this).select('circle').attr('cy');
//Update the tooltip position and value
d3.select("#tooltip")
.style("left", xPosition + "px")
.style("top", yPosition + "px")
.select("#type")
.text(d.type);
d3.select("#tooltip")
.style("left", xPosition + "px")
.style("top", yPosition + "px")
.select("#name")
.text(d.name);
//Show the tooltip
//d3.select("#tooltip").classed("hidden", false);
})
.on("mouseout", function() {
//Hide the tooltip
d3.select("#tooltip").classed("hidden", true);
})
//Every time the simulation "ticks", this will be called
force.on('tick', function() {
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; });
nodes.attr('cx', function(d) { return d.x; })
.attr('cy', function(d) { return d.y; });
//Update all labels
svg.selectAll('text')
.data(dataset.nodes)
.attr('x', function(d, i) {
return d.x;
})
.attr('y', function(d) {
return d.y;
});
});
}
d3.json('news.json', function(dataset) {
drawGraph(dataset);
});
d3.select("p")
.on("click", function() {
});
d3.select("#refresh")
.on("click", function() {
d3.json('news3.json', function(dataset) {
console.log(dataset);
drawGraph(dataset);
});
});
</script>
</body>
</html>
news.json
{
"nodes": [
{ "name": "El Universal", "type": "publication", "weight": 10 },
{ "name": "Milenio", "type": "publication", "weight": 4},
{ "name": "Proceso", "type": "publication", "weight": 4},
{ "name": "Paco", "type": "person", "weight": 12},
{ "name": "Juan", "type": "person", "weight": 5},
{ "name": "Alberto", "type": "person", "weight": 5 },
{ "name": "Xochitl", "type": "person", "weight": 3 },
{ "name": "Reforma", "type": "publication", "weight": 2}
],
"edges": [
{ "source": 3, "target": 0, "weight": 9},
{ "source": 3, "target": 1, "weight": 3},
{ "source": 4, "target": 2, "weight": 4},
{ "source": 4, "target": 0, "weight": 1},
{ "source": 5, "target": 3, "weight": 5},
{ "source": 6, "target": 1, "weight": 1},
{ "source": 6, "target": 7, "weight": 2},
{ "source": 6, "target": 1, "weight": 1},
{ "source": 3, "target": 5, "weight": 4},
{ "source": 4, "target": 5, "weight": 1}
]
}
news3.json
{
"nodes": [
{ "name": "El Universal", "type": "publication", "weight": 10 },
{ "name": "Milenio", "type": "publication", "weight": 4},
{ "name": "Proceso", "type": "publication", "weight": 4},
{ "name": "Paco", "type": "person", "weight": 12},
{ "name": "Juan", "type": "person", "weight": 5},
{ "name": "Alberto", "type": "person", "weight": 5 },
{ "name": "Xochitl", "type": "person", "weight": 3 },
{ "name": "Reforma", "type": "publication", "weight": 2},
{ "name": "Eduardo", "type": "person", "weight": 2}
],
"edges": [
{ "source": 3, "target": 0, "weight": 9},
{ "source": 3, "target": 1, "weight": 3},
{ "source": 4, "target": 2, "weight": 4},
{ "source": 4, "target": 0, "weight": 1},
{ "source": 5, "target": 3, "weight": 5},
{ "source": 6, "target": 1, "weight": 1},
{ "source": 6, "target": 7, "weight": 2},
{ "source": 6, "target": 1, "weight": 1},
{ "source": 3, "target": 5, "weight": 4},
{ "source": 4, "target": 5, "weight": 1},
{ "source": 8, "target": 7, "weight": 2}
]
}
答案 0 :(得分:0)
我修改了分配给force.on('tick', ...);
上的tick事件的函数后,我得到了它。小修改:现在我使用groupSelection.selectAll('circle')
和groupSelection.selectAll('text')
而不是groupSelection.select('circle')
和groupSelection.select('text')
。
您可以看到有效的演示here。
以下是代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>D3: Force layout</title>
<script type="text/javascript" src="../d3/d3.v3.js"></script>
<style type="text/css">
#tooltip {
position: absolute;
width: 200px;
height: auto;
padding: 10px;
background-color: white;
-webkit-border-radius: 10px;
-moz-border-radius: 10px;
border-radius: 10px;
-webkit-box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4);
-moz-box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4);
box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4);
pointer-events: none;
}
#tooltip.hidden {
display: none;
}
#tooltip p {
margin: 0;
font-family: sans-serif;
font-size: 16px;
line-height: 20px;
}
</style>
</head>
<body>
<div id="tooltip" class="hidden">
<p><span id="type"></span></p>
<p><span id="name"></span></p>
</div>
<p id="refresh">Click on this text to update the chart with new data values (once).</p>
<script type="text/javascript">
//Width and height
var w = 300;
var h = 200;
//http://stackoverflow.com/questions/16455194/how-to-store-a-json-object-loaded-from-a-file
var force = d3.layout.force()
.size([w, h])
.linkDistance([20])
.charge([-50]);
var svg = d3.select('body')
.append('svg')
.attr('width', w)
.attr('height', h);
drawGraph = function(dataset) {
force.nodes(dataset.nodes);
force.links(dataset.edges);
force.start();
var lineSelections = svg.selectAll('line')
.data(dataset.edges, function(d){
return '.'.concat(d.source.name, '.', d.target.name);
});
lineSelections
.enter()
.append('line')
.style('stroke', function(d) {
if (d.target.type === 'publication') {
return 'red';
} else {
return 'blue';
}
})
.style('stroke-width', function(d) {
return d.weight;
});
var groupSelection = svg.selectAll('g')
.data(dataset.nodes, function(d) {
return d.name;
})
.call(force.drag);
var groups = groupSelection
.enter()
.append('g')
.call(force.drag);
groups
.append('circle')
.attr('r', function(d) {
if (d.type === 'publication') {
var radius = d.weight / 6;
if (radius < 5) {
radius = 5;
}
return radius;
} else {
return d.weight * 3;
}
})
.style('fill', function(d, i) {
if (d.type === 'publication') {
return 'black';
} else {
return 'green';
}
});
//Create labels
groups
.append('text')
.text(function(d) {
if (d.type === 'publication') {
return d.name;
} else {
return d.name;
}
})
.attr('x', function(d, i) {
d.x;
})
.attr('y', function(d) {
d.x;
})
.attr('font-family', 'sans-serif')
.attr('font-size', '14px')
.attr('fill', 'orange');
//Every time the simulation "ticks", this will be called
force.on('tick', function() {
lineSelections
.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;
});
groupSelection
.select('circle')
.attr('cx', function(d) {
return d.x;
})
.attr('cy', function(d) {
return d.y;
});
//Update all labels
groupSelection
.select('text')
.attr('x', function(d, i) {
return d.x;
})
.attr('y', function(d) {
return d.y;
});
});
}
d3.json('news.json', function(dataset) {
drawGraph(dataset);
});
d3.select("p")
.on("click", function() {
});
d3.select("#refresh")
.on("click", function() {
console.log('==================');
d3.json('news3.json', function(dataset) {
drawGraph(dataset);
});
});
</script>
</body>
</html>