javascript - D3 Collapse Tree 渲染数千个节点
问题描述
我正在使用 D3 来渲染包含数千个节点的可折叠树。第一个深度只有大约 20 个节点;扩展这些节点后会出现问题。深度 2 中的一些节点包含数百个子节点,因此它们开始消失。我似乎无法弄清楚如何解决这个问题。一般来说,我对使用 D3 和 SVG 还是很陌生,任何资源都会有所帮助。
我的问题是:
- 如何使包裹我的树的 svg 更加动态,以便它随着我的树的扩展而扩展?
- 我的树在初始加载时的位置非常低,我怎样才能将它居中?
任何调整树的位置以适应许多节点的建议将不胜感激。
onLoad()
async function onLoad() {
const width = 960
const height = document.body.clientHeight
const dx = 10
const dy = 156
const metrics = getData()
const root = d3.hierarchy(metrics)
console.log(root)
const margin = {
top: 10,
right: 120,
bottom: 10,
left: 40
}
const diagonal = d3.linkHorizontal().x(d => d.y).y(d => d.x)
root.x0 = dy / 2
root.y0 = 0
root.descendants().forEach((d, i) => {
d.id = i
d._children = d.children
// collapse(d)
if (d.depth && d.depth <= 1) d.children = null
})
const svg = d3.select('svg')
// .attr('viewbox', [-margin.left, -margin.top, width, dx])
.style('user-select', 'none')
const gNode = svg.append('g')
.attr('cursor', 'pointer')
.attr('pointer-events', ' all')
.attr('width', width)
.attr('height', height)
const tree = d3.tree().nodeSize([dx, dy])
function update(source) {
const duration = d3.event && d3.eventaltKey ? 2500 : 250
const nodes = root.descendants().reverse()
const links = root.links()
console.log('updating tree...')
tree(root) // compute new tree
let left = root
let right = root
root.eachBefore(n => {
if (n.x < left.x) left = n
if (n.x > right.x) right = n
})
const height = right.x - left.x + margin.top + margin.bottom
console.log(left.x)
const transition = svg.transition()
.duration(duration)
.attr('viewBox', [-margin.left, left.x - margin.top, width / 2, height / 2])
.tween('resize', window.ResizeObserver ? null : () => () => svg.dispatch('toggle'))
// Update the nodes…
const node = gNode.selectAll('g')
.data(nodes, d => d.id)
// Enter any new nodes at the parent's previous position.
const nodeEnter = node.enter().append('g')
.attr('transform', d => `translate(${source.y0},${source.x0})`)
.attr('fill-opacity', 0)
.attr('stroke-opacity', 0)
.on('click', d => {
d.children = d.children ? null : d._children
update(d)
})
nodeEnter.append('circle')
.attr('r', d => d._children ? 2.5 : 1)
.attr('fill', d => d._children ? '#555' : '#999')
.attr('stroke-width', 2)
nodeEnter.append('text')
.attr('dy', '0.31em')
.attr('x', d => d._children ? -10 : 10)
.attr('text-anchor', d => d._children ? 'end' : 'start')
.attr('font-size', d => d.depth === 0 ? 5 : 10 / (d.depth * 1.3))
.text(d => {
console.log(d)
return d.data.title
})
.clone(true).lower()
.attr('stroke-linejoin', 'round')
.attr('stroke-width', 3)
.attr('stroke', 'white')
// Transition nodes to their new position.
const nodeUpdate = node.merge(nodeEnter).transition(transition)
.attr('transform', d => `translate(${d.y},${d.x})`)
.attr('fill-opacity', 1)
.attr('stroke-opacity', 1)
// Transition exiting nodes to the parent's new position.
const nodeExit = node.exit().transition(transition).remove()
.attr('transform', d => `translate(${source.y},${source.x})`)
.attr('fill-opacity', 0)
.attr('stroke-opacity', 0)
// Update the links…
const link = gNode.selectAll('path')
.data(links, d => d.target.id)
// Enter any new links at the parent's previous position.
const linkEnter = link.enter().append('path')
.attr('d', d => {
const o = {
x: source.x0,
y: source.y0
}
return diagonal({
source: o,
target: o
})
})
// Transition links to their new position.
link.merge(linkEnter).transition(transition)
.attr('d', diagonal)
// Transition exiting nodes to the parent's new position.
link.exit().transition(transition).remove()
.attr('d', d => {
const o = {
x: source.x,
y: source.y
}
return diagonal({
source: o,
target: o
})
})
// Stash the old positions for transition.
root.eachBefore(d => {
d.x0 = d.x
d.y0 = d.y
})
}
update(root)
}
编辑
在插入和更新时使用 getBBox,我不确定如何处理这个问题。
const svg = d3.select('svg')
// .attr('viewbox', [-margin.left, -margin.top, width, dx])
.style('user-select', 'none')
const gNode = svg.append('g')
.attr('cursor', 'pointer')
.attr('pointer-events', ' all')
/* .attr('width', width)
.attr('height', height) */
const tree = d3.tree().nodeSize([dx, dy])
const { x, y, w, h } = gNode.getBBox()
svg.attr('viewbox', [x, y, width, height])
解决方案
推荐阅读
- java - Android Studio VerifyError 拒绝来自 JavaMail API 的类 text_plain
- android - 带有自定义字体和后退箭头的操作栏
- c# - 从 Soap Envelop 请求中解析数据
- r - 单击搜索结果后,R传单搜索不会缩放到正确的位置
- javascript - 使用 Javascript document.body.className 添加正文类而不是 document.body.setAttribute
- c - 如何构建用户友好的界面以允许检测无效输入?
- python-3.x - 如何将具有对象数据类型的时间纳秒列转换为日期时间?
- javascript - Javascript仅在循环中第一次工作
- javascript - 在用户键入时更改标签中单词的每个字母。我可以使用 JS 或 CSS 来实现吗?
- c# - Microsoft.Win32.TaskScheduler AllTasks 无法正常工作