{
const svg = DOM.svg(width, height)
const sel = d3.select(svg)
const packLayout = d3.pack()
.size([width, height])
.radius(() => 40)
.padding(padding)
const rootNode = d3.hierarchy(data)
rootNode.sum(() => 1)
packLayout(rootNode)
renderDefs(rootNode.descendants())
renderCircles(rootNode.descendants())
renderLabels(rootNode.descendants())
function renderDefs (nodes) {
const defs = sel.append('defs')
.selectAll('pattern')
.data(nodes, d => d.data.id)
defs.join('pattern')
.attr('id', (d, i) => `p-${i}`)
.attr('width', 1)
.attr('height', 1)
.append('image')
.attr('xlink:href', d => {
const obj = d.data.data
return `https://api.dicebear.com/7.x/avataaars/svg?seed=${obj.img}`
})
.attr('x', 5)
.attr('y', 0)
.attr('width', 70)
.attr('height', 70)
}
function renderCircles (nodes) {
const circles = sel
.selectAll('circle')
.data(nodes, d => d.data.id)
circles.join('circle')
.attr('class', d => {
if (d.depth === 0) {
return 'root'
} else if (d.depth === 1) {
return 'cluster'
} else {
return 'item'
}
})
.attr('cx', d => d.x)
.attr('cy', d => d.y)
.attr('r', d => d.r)
.attr('fill', (d, i) => {
const obj = d.data.data
const id = `p-${i}`
return `url(#${id})`
})
}
function renderLabels (nodes) {
const labels = sel
.selectAll('text')
.data(nodes, d => d.data.id)
labels.join('text')
.attr('x', d => d.x)
.attr('y', d => d.y)
.attr('dy', '40px')
.text(d => {
if (d.depth === 0 || d.depth === 1) {
return ''
} else {
return d.data.data.first_name
}
})
}
return svg
}