Published
Edited
May 14, 2021
Insert cell
md`# Concentric Arc Tweening`
Insert cell
{
const svg = d3.create("svg")
.attr("width", width)
.attr("height", height)
.style("background-color", svgBackgroundColor),
arcsContainer = svg.append("g")
.attr("transform", "translate(" + (width/2) + "," + (height/2) + ")"),
data = d3.range(numArcs).map(function(i) {
return {
id: i,
startAngle: Math.random() * tau,//random start and end angles for the arc
endAngle: Math.random() * tau

};
});
function update(arcsData){
const t = d3.transition()
.duration(1050);

let arcs = arcsContainer.selectAll("path")
.data(arcsData, d => d.id);
arcs
.join(
enter => enter.append("path")
.style("opacity", 0)
.call(e => e.transition(t)
.attr("d", concentricArc)
.attr("stroke", d => arcColor)
.attr("stroke-width", (d,i) => randomInteger(3,concentricScale.bandwidth(), d.id))
.style("opacity", (d,i) => 1)
.attr("fill", arcColor)
),
update => update
.call(e => {e.transition(t)
.attrTween("d", d => {
//tweening - interpolate from old arc to new arc
let oldStartAngle = d.startAngle;
let oldEndAngle = d.endAngle;
let randomNewStart = Math.random() * tau;
let randomNewEnd = Math.random() * tau;
let i = d3.interpolate(oldStartAngle, randomNewStart);
let u = d3.interpolate(oldEndAngle,randomNewEnd);
return t => {
d.endAngle = u(t);
d.startAngle = i(t);
return concentricArc(d);
};
}
)
//pick a new random stroke width and new random opacity
.attr("stroke-width", (d,i) => randomInteger(1,concentricScale.bandwidth(), d.id))
.style("opacity", (d,i) => randomInteger(5,9, d.id)/10)
}
)
)
}
yield svg.node();
update(data);
d3.interval(function() {
update(data)
}, 1200);
}
Insert cell
function randomInteger(min,max, index){
return Math.floor(Math.random() * (max - min) + min);
}
Insert cell
concentricScale = d3.scaleBand()
.range([10,innerRadius-10])
.domain(d3.range(0,numArcs))
Insert cell
concentricArc = d3.arc()
.innerRadius(d => concentricScale(d.id))
.outerRadius(d => concentricScale(d.id) + 2)
.startAngle(d => d.startAngle)
.endAngle(d => d.endAngle)
Insert cell
width = 500
Insert cell
height = 500
Insert cell
innerRadius = 250
Insert cell
tau = 2 * Math.PI
Insert cell
arcColor = "#d1ac00"
Insert cell
numArcs = 25
Insert cell
svgBackgroundColor = "#163C3C"
Insert cell
d3 = require("d3@6")
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