{
const r = 200
const margin = { left: 30, top: 30, right: 30, bottom: 30 }
const svg = d3.select(DOM.svg(r * 2, r * 2))
.attr('viewBox',
`-${margin.left},
-${margin.top},
${r * 2 + margin.left + margin.right},
${r * 2 + margin.bottom + margin.top}`)
const dimensions = ['hp', 'attack', 'sp_attack', 'defense', 'sp_defense', 'speed']
const radialLine = d3.lineRadial()
const yScale = d3.scaleLinear()
.range([0, r])
.domain([0, 255])
const ticks = [50, 100, 150, 200, 255]
dimensions.forEach((dimension, i) => {
const g = svg.append('g')
.attr('transform', `translate(${r}, ${r}) rotate(${i * 60})`)
g.append('g')
.call(d3.axisLeft(yScale).tickFormat('').tickValues(ticks))
g.append('g')
.call(d3.axisRight(yScale).tickFormat('').tickValues(ticks))
// Add a text label for each axis, put it at the edge
// Again, this "text" element is inside the outer "g" element,
// and will be transformed to the right position with its parent element
g.append('text')
.text(dimension)
.attr('text-anchor', 'middle')
.attr('transform', `translate(0, -${r + 10})`)
})
// Line for the base stats of Snorlax
svg.append('g')
.selectAll('path')
.data([pokemonBaseStats[142]])
.enter()
.append('path')
.attr('d', d =>
radialLine([
d.hp,
d.attack,
d.sp_attack,
d.defense,
d.sp_defense,
d.speed,
d.hp // hp again to close the loop
].map((v, i) => [Math.PI * 2 * i / 6 /* radian */, yScale(v) /* distance from the origin */]))
)
// Move to the center
.attr('transform', `translate(${r}, ${r})`)
.attr('stroke', 'SteelBlue')
.attr('stroke-width', 5)
.attr('fill', 'rgba(70, 130, 180, 0.3)')
// Gird lines for references
svg.append('g')
.selectAll('path')
.data(ticks)
.enter()
.append('path')
.attr('d', d => radialLine(_.range(7).map((v, i) => [Math.PI * 2 * i / 6, yScale(d)])))
.attr('transform', `translate(${r}, ${r})`)
.attr('stroke', 'grey')
.attr('opacity', 0.5)
.attr('fill', 'none')
return svg.node()
}