function PolarArea(data, {
value,
group = null,
levels = 5,
width = 800,
height = 800,
margin = 1,
marginTop = margin,
marginRight = margin,
marginBottom = margin,
marginLeft = margin,
padding = 50,
color = d3.schemeTableau10,
opacity = 0.6,
fill = "#f1f1f1",
stroke = "#cdcdcd",
} = {}) {
let groups = [];
const radius = Math.min(width - marginLeft - marginRight - padding, height - marginTop - marginBottom - padding) / 2;
if (group) {
groups = [...new Set(data.map(group))];
}
const layoutData = d3.pie().value(1)(data);
const arc = d3.arc()
.innerRadius(0)
.outerRadius(d => value(d.data) * (radius / levels));
const svg = d3.create("svg")
.attr("viewBox", [
marginRight - marginLeft - width / 2,
marginBottom - marginTop - height / 2,
width,
height
])
.attr("width", width)
.attr("height", height)
.attr("style", "max-width: 100%; height: auto; height: intrinsic;")
.attr("font-family", "sans-serif")
.attr("font-size", 12)
.attr("text-anchor", "middle");
//-------------------------------------
// Draw the grid
//-------------------------------------
// Wrapper for the grid & axes
var axisGrid = svg.append("g").attr("class", "axisWrapper");
// Draw the background circles
axisGrid.selectAll(".levels")
.data(d3.range(1, levels+1).reverse())
.enter()
.append("circle")
.attr("class", "gridCircle")
.attr("r", d => d * (radius / levels))
.style("fill", fill)
.style("stroke", stroke)
.style("fill-opacity", opacity);
// Create the straight lines radiating outward from the center
var axis = axisGrid.selectAll(".axis")
.data(layoutData)
.enter()
.append("g")
.attr("class", "axis");
axis.append("line")
.attr("x1", 0)
.attr("y1", 0)
.attr("x2", d => radius * Math.cos(d.startAngle - Math.PI/2))
.attr("y2", d => radius * Math.sin(d.startAngle - Math.PI/2))
.attr("class", "line")
.style("stroke", stroke);
//-------------------------------------
// Draw the data
//-------------------------------------
// Labels
axis.append("text")
.attr("class", "legend")
.attr("text-anchor", "middle")
.attr("dy", "-10")
.attr("x", d => radius * Math.cos((d.startAngle + d.endAngle)/2 - Math.PI/2))
.attr("y", d => radius * Math.sin((d.startAngle + d.endAngle)/2 - Math.PI/2))
.attr("transform", d => {
const x = radius * Math.cos((d.startAngle + d.endAngle)/2 - Math.PI/2);
const y = radius * Math.sin((d.startAngle + d.endAngle)/2 - Math.PI/2);
const degrees = (d.startAngle + d.endAngle)/2*180/Math.PI;
return `rotate(${degrees}, ${x}, ${y})`;
})
.text(d => d.data.name);
// Values
svg.selectAll("path")
.data(layoutData)
.enter()
.append("path")
.attr("d", arc)
.attr("fill", d => {
const idx = group ? groups.indexOf(group(d.data)) : d.index;
return color[idx];
})
.attr("fill-opacity", opacity);
return svg.node();
}