【发布时间】:2018-12-23 19:14:55
【问题描述】:
我有一个 d3 强制布局,它从 JSON 文件加载节点并从单独的 CSV 文件加载链接,但有几个(可能相关的)问题:
- 生成的结构间隔非常均匀,并且链接中有很多重叠,这使得很难看到哪些节点是连接的。我不知道为什么我会得到这样一个圆形的结构,以及为什么一些只有 1 个链接的节点被放置在与它们的连接节点相反的一侧
- 当我拖动一个节点时,没有一个连接节点随之移动。除了我正在移动的一个节点之外,一切似乎都保持静止,而且图表似乎在慢慢放大
您可以在下面的 sn-p 中看到这两个问题:
svg {
display: block;
margin: auto;
}
.links line {
stroke: #999;
stroke-opacity: 0.6;
pointer-events: none;
}
.nodes circle {
stroke: #fff;
stroke-width: 1.5px;
}
text {
font-family: sans-serif;
font-size: 14px;
font-weight: bold;
}
.primary {
color: #af0000;
}
.secondary {
color: #00a700;
}
div.tooltip {
position: absolute;
top: 10px;
right: 10px;
background-color: white;
max-width: 200px;
height: auto;
padding: 10px;
border-style: solid;
border-radius: 2px;
border-width: 1px;
box-shadow: 3px 3px 10px rgba(0, 0, 0, 0.5);
}
div.tooltip .Legendary {
color: #ff9b00;
}
div.tooltip .Epic {
color: #ac41c2;
}
div.tooltip .Elite {
color: #058cc3;
}
div.tooltip .Advanced {
color: #2d9830;
}
div.tooltip table {
border: 1px solid black;
border-collapse: collapse;
}
div.tooltip table td {
padding: 5px;
}
<svg width="960" height="700"></svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
const svg = d3.select('svg'),
width = +svg.attr('width'),
height = +svg.attr('height');
const color = d3
.scaleOrdinal()
.domain(['Legendary', 'Epic', 'Elite', 'Advanced'])
.range(['#ff9b00', '#ac41c2', '#058cc3', '#2d9830']);
const simulation = d3
.forceSimulation()
.force('link', d3.forceLink().id(d => d.id))
.force(
'charge',
d3
.forceManyBody()
.strength(-20)
.distanceMax([500])
)
.force('center', d3.forceCenter(width / 2, height / 2));
d3.queue()
.defer(d3.json, 'https://gist.githubusercontent.com/sho-87/bfe4d69be60454dccfd859b004262381/raw/ac259b468ae6f1140d5c10596f1663c743535b5a/commanders.json')
.defer(d3.csv, 'https://gist.githubusercontent.com/sho-87/89aa3c48baffc9c388bb98e613b9a5f4/raw/896e24a0187d555d395840d7def3b36b8fb28074/links.csv')
.await(function(error, commanders, links) {
const nodeByID = d3.map();
commanders.nodes.forEach(commander => {
nodeByID.set(commander.id, commander);
});
links.forEach(link => {
link.source = nodeByID.get(link.primary);
link.target = nodeByID.get(link.secondary);
});
const link = svg
.append('g')
.attr('class', 'links')
.selectAll('line')
.data(links)
.enter()
.append('line')
.attr('stroke-width', d => Math.sqrt(d.value * 1));
const node = svg
.selectAll('.node')
.data(commanders.nodes)
.enter()
.append('g')
.attr('class', 'nodes')
.call(
d3
.drag()
.on('start', dragstarted)
.on('drag', dragged)
.on('end', dragended)
)
.append('circle')
.attr('r', 8)
.attr('fill', d => color(d.group))
simulation.nodes(commanders.nodes).on('tick', ticked);
simulation.force('link').links(link);
function ticked() {
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 dragstarted(d) {
if (!d3.event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
function dragged(d) {
d.fx = d3.event.x;
d.fy = d3.event.y;
}
function dragended(d) {
if (!d3.event.active) simulation.alphaTarget(0);
d.fx = null;
d.fy = null;
}
</script>
我想要的是更不对称的东西,相关/连接的节点放置得更近。理想情况下,我想尽可能减少重叠链接的数量,所以更像这样:
【问题讨论】:
标签: javascript d3.js