我正在尝试制作一个力有向图,其中子节点和孙节点正在环绕/环绕父节点。同时父节点连接到它的子节点,每个子节点连接到它们的每个孙节点。
在视觉上,它看起来像这样:
我已经尝试干预默认的力有向图(在这里和那里),但似乎没有办法像我试图制作的视觉效果那样将它们整齐地排列成圆形/轨道。
我尝试查找轨道代码,但似乎需要一种完全不同的方法。
这是我的小提琴和代码:https ://jsfiddle.net/znqkcLhs/
function getNeighbors(node) {
return links.reduce(function (neighbors, link) {
if (link.target.id === node.id) {
neighbors.push(link.source.id)
} else if (link.source.id === node.id) {
neighbors.push(link.target.id)
}
return neighbors
},
[node.id]
)
}
function isNeighborLink(node, link) {
return link.target.id === node.id || link.source.id === node.id
}
function getNodeColor(node, neighbors) {
if (Array.isArray(neighbors) && neighbors.indexOf(node.id) > -1) {
return node.level === 1 ? 'blue' : 'green'
}
return node.level === 1 ? 'red' : 'gray'
}
function getLinkColor(node, link) {
return isNeighborLink(node, link) ? 'green' : '#E5E5E5'
}
function getTextColor(node, neighbors) {
return Array.isArray(neighbors) && neighbors.indexOf(node.id) > -1 ? 'green' : 'black'
}
var width = window.innerWidth
var height = window.innerHeight
var svg = d3.select('svg')
svg.attr('width', width).attr('height', height)
// simulation setup with all forces
var linkForce = d3
.forceLink()
.id(function (link) { return link.id })
.strength(function (link) { return link.strength })
var simulation = d3
.forceSimulation()
.force('link', linkForce)
.force('charge', d3.forceManyBody().strength(-120))
.force('center', d3.forceCenter(width / 2, height / 2))
var dragDrop = d3.drag().on('start', function (node) {
node.fx = node.x
node.fy = node.y
}).on('drag', function (node) {
simulation.alphaTarget(0.7).restart()
node.fx = d3.event.x
node.fy = d3.event.y
}).on('end', function (node) {
if (!d3.event.active) {
simulation.alphaTarget(0)
}
node.fx = null
node.fy = null
})
function selectNode(selectedNode) {
var neighbors = getNeighbors(selectedNode)
// we modify the styles to highlight selected nodes
nodeElements.attr('fill', function (node) { return getNodeColor(node, neighbors) })
textElements.attr('fill', function (node) { return getTextColor(node, neighbors) })
linkElements.attr('stroke', function (link) { return getLinkColor(selectedNode, link) })
}
var linkElements = svg.append("g")
.attr("class", "links")
.selectAll("line")
.data(links)
.enter().append("line")
.attr("stroke-width", function(link) { return link.value; })
.attr("stroke", "rgba(50, 50, 50, 0.2)")
var nodeElements = svg.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(nodes)
.enter().append("circle")
.attr("r", 10)
.attr("fill", getNodeColor)
.call(dragDrop)
.on('click', selectNode)
var textElements = svg.append("g")
.attr("class", "texts")
.selectAll("text")
.data(nodes)
.enter().append("text")
.text(function (node) { return node.label })
.attr("font-size", 15)
.attr("dx", 15)
.attr("dy", 4)
simulation.nodes(nodes).on('tick', () => {
nodeElements
.attr('cx', function (node) { return node.x })
.attr('cy', function (node) { return node.y })
textElements
.attr('x', function (node) { return node.x })
.attr('y', function (node) { return node.y })
linkElements
.attr('x1', function (link) { return link.source.x })
.attr('y1', function (link) { return link.source.y })
.attr('x2', function (link) { return link.target.x })
.attr('y2', function (link) { return link.target.y })
})
simulation.force("link").links(links)
有任何想法吗?