修复 d3 包布局中一个气泡的位置
Fix the position of one bubble in d3 pack layout
我正在使用 D3 js (v5) 构建气泡图,以显示一些研究结果。
基本上我有一个 JSON,总和作为根,子项作为每个结果。
其中一个结果必须突出显示并位于圆圈的顶部中心。
我设法在那里显示了这个结果,但其他气泡重叠(可能是因为我更改了 D3 层次结构算法提供的位置)。
是否可以通过编程方式固定一个气泡(在我的示例中为蓝色气泡)的位置并重新定位其他气泡,以免它们相互重叠?
const data = {
name: 'Total',
size: 1999999,
children: [{
name: 'Result A',
size: 69936,
},
{
name: 'Result b',
size: 45000,
},
{
name: 'Result C',
size: 250000,
},
{
name: 'Result D',
size: 426791,
},
{
name: 'Result E',
size: 56000,
},
{
name: 'Result F',
size: 61050,
},
{
name: 'Result G',
size: 30000,
},
],
};
// Fix this bubble at the top
const FIXED_BUBBLE_NAME = 'Result b';
const GREEN = '#90E0C2';
const BLUE = '#73A1FC';
const GRAPH_DIMENSIONS = {
WIDTH: 234,
HEIGHT: 234,
PADDING: 10,
};
const buildDataTree = () => {
const packLayout = d3
.pack()
.size([
GRAPH_DIMENSIONS.WIDTH,
GRAPH_DIMENSIONS.HEIGHT,
])
.padding(GRAPH_DIMENSIONS.PADDING);
const rootNode = d3
.hierarchy(data)
.sum((d) => d.size)
.sort((a, b) => {
return b.value - a.value;
})
return packLayout(rootNode);
};
const getSvgRoot = () => {
return d3
.select('#graph-container')
.append('svg')
.attr('id', 'graph-container-svg')
.attr('width', GRAPH_DIMENSIONS.WIDTH + GRAPH_DIMENSIONS.PADDING)
.attr('height', GRAPH_DIMENSIONS.HEIGHT + GRAPH_DIMENSIONS.PADDING)
.style('overflow', 'visible');
};
const rootNodeDataTree = buildDataTree();
const svgRoot = getSvgRoot();
const node = svgRoot
.selectAll('g')
.data(
d3
.nest()
.key((d) => d.id)
.entries(rootNodeDataTree.descendants()),
)
.join('g')
.selectAll('g')
.data(d => d.values)
.join('g');
node
.append('circle')
.attr('r', (d) => d.r)
.attr('cx', (d) => {
// if it is the selected bubble it must be at the center
if (d.data.name === FIXED_BUBBLE_NAME) {
return GRAPH_DIMENSIONS.WIDTH / 2 + d.r / 2;
}
return d.x + GRAPH_DIMENSIONS.PADDING;
})
.attr('cy', (d) => {
// if it is the selected bubble it must be at the center
if (d.data.name === FIXED_BUBBLE_NAME) {
return d.r + GRAPH_DIMENSIONS.PADDING * 2;
}
return d.y + GRAPH_DIMENSIONS.PADDING;
})
.attr('cursor', 'pointer')
.attr('stroke', (d) => (d.children ? GREEN : ''))
.attr('stroke-width', (d) => (d.children ? 2 : 0))
.attr('fill-opacity', (d) => (d.children ? 0.24 : 1))
.attr('fill', (d) => {
if (d.data.name === FIXED_BUBBLE_NAME) {
return BLUE;
} else {
return GREEN;
}
})
<script src="https://d3js.org/d3.v5.min.js"></script>
<div id="graph-container">
</div>
这是 fiddle 我的建议:https://jsfiddle.net/9r8kt1e0/1/
力模拟代码为:
const simulation = d3
.forceSimulation(allNodes.filter( (d) => d.depth !== 0))
.force("collide",d3.forceCollide(d => { return d.r;}))
.force("charge", d3.forceManyBody().strength(0))
.force("center", d3.forceCenter(GRAPH_DIMENSIONS.WIDTH/2+10, GRAPH_DIMENSIONS.HEIGHT/2))
.force("bound", (alpha) => {
for (let i = 0; i < allNodes.length; ++i) {
n = allNodes[i];
n.x = pythag(n.r, n.y, n.x);
n.y = pythag(n.r, n.x, n.y);
}
})
.stop();
for (var i = 0; i < 100; ++i) {
simulation.tick();
}
请注意,我们正在传递一个名为 bound
的自定义力,这个力应该负责将节点保持在父圆圈内。
这样就解决了重叠问题,你就得根据自己的需要稍微玩一下力了。
根据文档,力是一种修改节点位置的函数,您可以有多个力,因此希望稍微尝试一下力可以解决您的问题。
希望对您有所帮助。
我正在使用 D3 js (v5) 构建气泡图,以显示一些研究结果。
基本上我有一个 JSON,总和作为根,子项作为每个结果。
其中一个结果必须突出显示并位于圆圈的顶部中心。 我设法在那里显示了这个结果,但其他气泡重叠(可能是因为我更改了 D3 层次结构算法提供的位置)。
是否可以通过编程方式固定一个气泡(在我的示例中为蓝色气泡)的位置并重新定位其他气泡,以免它们相互重叠?
const data = {
name: 'Total',
size: 1999999,
children: [{
name: 'Result A',
size: 69936,
},
{
name: 'Result b',
size: 45000,
},
{
name: 'Result C',
size: 250000,
},
{
name: 'Result D',
size: 426791,
},
{
name: 'Result E',
size: 56000,
},
{
name: 'Result F',
size: 61050,
},
{
name: 'Result G',
size: 30000,
},
],
};
// Fix this bubble at the top
const FIXED_BUBBLE_NAME = 'Result b';
const GREEN = '#90E0C2';
const BLUE = '#73A1FC';
const GRAPH_DIMENSIONS = {
WIDTH: 234,
HEIGHT: 234,
PADDING: 10,
};
const buildDataTree = () => {
const packLayout = d3
.pack()
.size([
GRAPH_DIMENSIONS.WIDTH,
GRAPH_DIMENSIONS.HEIGHT,
])
.padding(GRAPH_DIMENSIONS.PADDING);
const rootNode = d3
.hierarchy(data)
.sum((d) => d.size)
.sort((a, b) => {
return b.value - a.value;
})
return packLayout(rootNode);
};
const getSvgRoot = () => {
return d3
.select('#graph-container')
.append('svg')
.attr('id', 'graph-container-svg')
.attr('width', GRAPH_DIMENSIONS.WIDTH + GRAPH_DIMENSIONS.PADDING)
.attr('height', GRAPH_DIMENSIONS.HEIGHT + GRAPH_DIMENSIONS.PADDING)
.style('overflow', 'visible');
};
const rootNodeDataTree = buildDataTree();
const svgRoot = getSvgRoot();
const node = svgRoot
.selectAll('g')
.data(
d3
.nest()
.key((d) => d.id)
.entries(rootNodeDataTree.descendants()),
)
.join('g')
.selectAll('g')
.data(d => d.values)
.join('g');
node
.append('circle')
.attr('r', (d) => d.r)
.attr('cx', (d) => {
// if it is the selected bubble it must be at the center
if (d.data.name === FIXED_BUBBLE_NAME) {
return GRAPH_DIMENSIONS.WIDTH / 2 + d.r / 2;
}
return d.x + GRAPH_DIMENSIONS.PADDING;
})
.attr('cy', (d) => {
// if it is the selected bubble it must be at the center
if (d.data.name === FIXED_BUBBLE_NAME) {
return d.r + GRAPH_DIMENSIONS.PADDING * 2;
}
return d.y + GRAPH_DIMENSIONS.PADDING;
})
.attr('cursor', 'pointer')
.attr('stroke', (d) => (d.children ? GREEN : ''))
.attr('stroke-width', (d) => (d.children ? 2 : 0))
.attr('fill-opacity', (d) => (d.children ? 0.24 : 1))
.attr('fill', (d) => {
if (d.data.name === FIXED_BUBBLE_NAME) {
return BLUE;
} else {
return GREEN;
}
})
<script src="https://d3js.org/d3.v5.min.js"></script>
<div id="graph-container">
</div>
这是 fiddle 我的建议:https://jsfiddle.net/9r8kt1e0/1/
力模拟代码为:
const simulation = d3
.forceSimulation(allNodes.filter( (d) => d.depth !== 0))
.force("collide",d3.forceCollide(d => { return d.r;}))
.force("charge", d3.forceManyBody().strength(0))
.force("center", d3.forceCenter(GRAPH_DIMENSIONS.WIDTH/2+10, GRAPH_DIMENSIONS.HEIGHT/2))
.force("bound", (alpha) => {
for (let i = 0; i < allNodes.length; ++i) {
n = allNodes[i];
n.x = pythag(n.r, n.y, n.x);
n.y = pythag(n.r, n.x, n.y);
}
})
.stop();
for (var i = 0; i < 100; ++i) {
simulation.tick();
}
请注意,我们正在传递一个名为 bound
的自定义力,这个力应该负责将节点保持在父圆圈内。
这样就解决了重叠问题,你就得根据自己的需要稍微玩一下力了。
根据文档,力是一种修改节点位置的函数,您可以有多个力,因此希望稍微尝试一下力可以解决您的问题。
希望对您有所帮助。