radialOrderedChart = {
const width = 700, height = 700
const svg = d3.create("svg")
.attr("width", width)
.attr("height", height)
.attr("viewBox", [0, 0, width, height])
.attr("style", "max-width: 100%; height: auto; height: intrinsic;")
.attr('font-family', 'Helvetica')
const sizeVar = 'affected_per_mil'
const padding = 20,
innerRadius = 50,
maxRadius = width / 2 - padding,
maxCircleRadius = ((maxRadius - innerRadius) / (maxInOneYear * 2)) + overlap;
const theta = 2 * Math.PI / years.length;
const rings = [20, 80, 100]
const rScale = d3.scaleLinear()
.domain([0, maxInOneYear])
.range([innerRadius, maxRadius])
const sizeScale = d3.scaleSqrt()
.domain(d3.extent(chartData, d => d[sizeVar]))
.range([1, maxCircleRadius])
const arcScale = d3.scaleLinear()
.domain([0, d3.max(yearTotals, d => d[1] )])
.range([0, theta])
const polarToX = (r, i) => r * Math.cos(i * theta - Math.PI/2 ) + width / 2
const polarToY = (r, i) => r * Math.sin(i * theta - Math.PI/2 ) + height / 2
function findIndex(data) {
return chartData.filter(d => d.year === data.year).indexOf(data)
}
// Define the arrowhead marker
svg.append("defs").append("marker")
.attr("id", "arrowhead")
.attr("markerWidth", 8)
.attr("markerHeight", 5)
.attr("refX", 0)
.attr("refY", 2.5)
.attr("orient", "auto")
.append("path")
.attr("d", "M 0 0 L 8 2.5 L 0 5 z")
.attr("fill", "darkgrey");
const yearSel = svg.selectAll('line')
.data(years)
.enter()
yearSel
.append('line')
.attr('x1', (d, i) => polarToX(innerRadius, i ) )
.attr('y1', (d, i) => polarToY(innerRadius, i ) )
.attr('x2', (d, i) => polarToX(maxRadius, i ) )
.attr('y2', (d, i) => polarToY(maxRadius, i ) )
.attr('stroke', d => d % 10 === 0 ? 'lightgrey' : '#F5F5F5')
.attr('stroke-width', d => d % 10 === 0 ? 1.5 : 1)
.attr('stroke-dasharray', '3 3')
const ringSel = svg.selectAll('ring')
.data(rings)
.enter()
ringSel
.append('circle')
.attr('cx', width / 2)
.attr('cy', height / 2)
.attr('r', d => rScale(d) )
.attr('fill', "none")
.attr('stroke', 'grey')
.attr('stroke-dasharray', '2 2')
ringSel
.append('text')
.attr('x', d => width / 2 + rScale(d) )
.attr('y', (d, i) => height / 2)
.attr('font-size', 12)
.attr('text-anchor', 'middle')
.attr('font-weight', 'bold')
.text(d =>d.toLocaleString('en') )
const arcGenerator = d3.arc()
.innerRadius(rScale(200))
.outerRadius(rScale(200) + 15)
.startAngle((d) => years.indexOf(d[0]) * theta )
.endAngle((d) => years.indexOf(d[0]) * theta + arcScale(d[1]) );
// paths
svg.selectAll('path')
.data(yearTotals)
.enter()
.append('path')
.attr('d', arcGenerator )
.attr('fill', 'lightgrey')
.attr('stroke', '#FFF')
.attr('transform', `translate(${width / 2},${height / 2})`)
const selected = (type) => dataFilter === 'All' || dataFilter === type
// circles
svg.selectAll('circle')
.data(chartData)
.enter()
.append("circle")
.attr('cx', (d, i) => polarToX(rScale(findIndex(d) ), years.indexOf(d.year) ) )
.attr('cy', (d, i) => polarToY(rScale(findIndex(d) ), years.indexOf(d.year) ) )
.attr('r', d => sizeScale(d[sizeVar]))
.attr('fill', d => selected(d.type) ? colorScale(d.type) : 'lightgrey')
.attr('stroke', d => selected(d.type) ? colorScale(d.type) : 'lightgrey')
.attr('fill-opacity', d => selected(d.type) ? .5 : .1)
.attr('stroke-width', .5)
yearSel
.append('text')
.attr('x', (d, i) => polarToX(maxRadius, i ))
.attr('y', (d, i) => polarToY(maxRadius + 5, i ))
.attr('text-anchor', 'middle')
.attr('font-size', d => d % 10 === 0 ? 14 : 10)
.attr('font-weight',d => d % 10 === 0 ? 600 : d % 5 === 0 ? 600 : 400)
.attr('opacity',d => countPerYear[d] >= 1 ? 1 : .2 )
.text(d =>d )
svg.append("line")
.attr("x1", width / 2)
.attr("y1", height / 2 - maxRadius + 120 )
.attr("x2", width / 2)
.attr("y2", height / 2 - maxRadius + 80 )
.attr("stroke", "darkgrey")
.attr("stroke-width", 2)
.attr("marker-end", "url(#arrowhead)");
svg.append('text')
.attr('x', width / 2)
.attr('y', height / 2 - maxRadius + 52)
.attr('text-anchor', 'middle')
.attr('stroke', '#FFF')
.attr('paint-order', 'stroke fill')
.attr('font-size', 12)
.text('Time')
return svg.node()
}