Public
Edited
Feb 23, 2024
2 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function renderTeam (data, {
imageSize = 80, //square
columnLength = null,
strokeWidth = 4,
textBoxheight = 30,
stroke = '#efefef',
} = {}) {

const dataLength = data.length
const size = (imageSize + (strokeWidth * 2))
const columns = (columnLength !== null && columnLength > 1 ) ? columnLength : Math.floor(width / size)
const rows = Math.ceil((dataLength / columns))
const height = rows * (size + textBoxheight)

const svg = d3.create('svg')
.attr('width', width)
.attr('height', height + strokeWidth)

renderDefs(data)

function renderDefs (data) {
const defs = svg.append('defs')
.selectAll('pattern')
.data(data)
.join('pattern')
.attr('id', d => `p-${d.id}`)
.attr('width', 1)
.attr('height', 1)
.append('image')
.attr('xlink:href', d => `https://api.dicebear.com/7.x/avataaars/svg?seed=${d.name}`)
.attr('x', 5)
.attr('y', 0)
.attr('width', size)
.attr('height', size)
}

const scaleColumn = d3.scaleLinear()
.domain([0, columns])
.range([strokeWidth/2, columns * size])

const scaleRow = d3.scaleLinear()
.domain([0, rows])
.range([strokeWidth/2, height + strokeWidth/2])
const g = svg
.selectAll('g')
.data(data)
.join('g')
.attr('class', 'item')
// .attr('transform', (d, i) => `translate(${i * size + 3}, ${size})`)
.attr('transform', (d, i) => {
const x = i % columns
const y = Math.floor(i / columns)
return `translate(${scaleColumn(x)}, ${scaleRow(y)})`
})


g.append('rect')
.attr('width', size)
.attr('height', size + textBoxheight)
.attr('stroke', stroke)
.attr('stroke-width', strokeWidth)
.attr('class', 'item-bgd')
.attr('fill', d => d.bgdCol)

g.append('rect')
.attr('width', size)
.attr('height', size)
.attr('class', 'item-img')
.attr('fill', d => {
const id = `p-${d.id}`
return `url(#${id})`
})

g.append('text')
.attr('x', size/2)
.attr('y', size)
.attr('dy', '20px')
.text(d => d.name)

return svg.node()
}
Insert cell
Insert cell
Insert cell
teamData = {

const teamSizes = [20, 15, 10, 10, 8, 6, 3, 3, 2]
const teamNames = teamSizes.map((d, i) => `t-0${i + 1}`)

const teamColours = ['#f5f5b8', '#bcd382', '#ffbf6e', '#29bdad', '#d1b0b3', '#888d2a', '#f2ff26', '#bdf226', '#abf5ed']

let teamIndex = 0 // use as a refernce to change team
let teamChange = teamSizes[teamIndex]
const members = d3.range(_.sum(teamSizes)).map((d, i) => {
if (i >= teamChange) {
teamIndex++
teamChange = teamChange + teamSizes[teamIndex]
}
return {
name: names[_.random(0, 328)],
team: teamNames[teamIndex],
los_months: _.sample([_.random(1, 30), _.random(1, 30), _.random(0, 50), _.random(1, 200)]),
id: i,
img: `${i}.svg`, // return a unique id!
bgdCol: teamColours[teamIndex]
}
})

return members
}
Insert cell
Insert cell
teams = _.uniqBy(teamData, 'team').map(d => d.team)
Insert cell
Insert cell
Insert cell
<hr>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=PT+Sans&display=swap" rel="stylesheet">

<style>
text {
font-family: 'PT Sans', sans-serif;
font-weight: 400;
font-size: 9px;
letter-spacing: 2px;
text-anchor: middle;
}


</style>

Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more