Public
Edited
Jul 9, 2024
1 fork
1 star
Insert cell
Insert cell
chart({ d: { w: 500, h: 500, r: 200 } })
Insert cell
chart = ({ d }) => {
const svg = d3.create("svg").attr("width", d.w).attr("height", d.h);
const center = { x: d.w / 2, y: d.h / 2 };

const gPlot = svg
.append("g")
.attr("class", "plot-container")
.attr("transform", `translate(${center.x}, ${center.y})`);

const gMonthLabel = gPlot
.append("g")
.attr("class", "month-labels")
.call((g) =>
arcLabel({
selection: g,
label: labels,
pathGenerator: arcGenerator({ angleScale, radius: d.r }),
format: d3.utcFormat("%B"),
className: "month"
})
);

// -----------------------Visual Helpers--------------------

const line = gPlot
.append("line")
.attr("x2", d.r)
.attr("y2", 0)
.attr("stroke", "black");

const angleText = svg.append("text");
const valueText = gPlot.append("text").attr("text-anchor", "middle");

svg.on("mousemove", (event) => {
const [x, y] = d3.pointer(event);
const [cx, cy] = [x - center.x, y - center.y];
const radAngle = atan2Scale(cy, cx);
const computerDegAngle = (radAngle * 180) / Math.PI;

const valueAtAngle = angleScale.invert(radAngle);
const valueFormat = valueAtAngle.toISOString();

angleText
.attr("x", x + 10)
.attr("y", y - 10)
.text(`${computerDegAngle}°`);

valueText.text(valueFormat);

line.attr("transform", `rotate(${computerDegAngle})`);
});

return svg.node();
}
Insert cell
Insert cell
Insert cell
startXYoffset = -Math.PI / 2
Insert cell
fullRoundAngle = 2 * Math.PI
Insert cell
Insert cell
// dataResolution = fullRoundAngle / 365
// angleScale = d3.scaleUtc()
// .domain([Date.UTC(2000, 0, 1), d3.utcDay.offset(Date.UTC(2001, 0, 1), -1)])
// .range([startXYoffset, startXYoffset + fullRoundAngle - dataResolution])
Insert cell
Insert cell
labels = {
const x = angleScale.ticks();
x.pop();
return x;
}
Insert cell
angleScale = d3
.scaleUtc()
.domain([Date.UTC(2019, 0, 1), Date.UTC(2020, 0, 1)])
.range([startXYoffset, startXYoffset + fullRoundAngle])
Insert cell
atan2Scale = (y, x) => {
const angle = Math.atan2(y, x);
return angle < startXYoffset ? angle + fullRoundAngle : angle;
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
pointRadialXY = (angle, radius) => d3.pointRadial(angle + Math.PI / 2, radius)
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