Published
Edited
Jan 20, 2022
Insert cell
Insert cell
Insert cell
{


const svgBackgroundColor = "#152c33",
height = 400,
width = 400,
numPoints = 16,

svg = d3.create("svg")
.attr("width", width)
.attr("height", height)
.style("background-color", svgBackgroundColor),
container = svg.append("g")
.attr("transform", `translate(${100},${100})`),
radius1 = 80,
radius2 = 81;
let points = getCirclePoints({x: 100, y: 100}, radius1, numPoints);

function drawZigZag(points){
let t = d3.transition()
.duration(3000);

let t2 = d3.transition()
.duration(2000)
.delay(2000);
points.push(points[0])

let zigs = container.selectAll("path")
.data([points], d => d);
zigs
.join(
enter => enter.append("path")
.attr("d", d => d3.line()
.x(d => d.x)
.y(d => d.y)(d))
.attr("stroke", "#f72585")
.attr("fill", "#560bad")
.attr("stroke-width", 5)
.style("opacity", 0.7)
.call(e => e.transition(t)
.attr("d", d => {
if(!points[0].x2){
//calculate second set of points
let pts2 = updatePoints(points, width);
return d3.line().x(d => d.x2).y(d => d.y2)(pts2);
}else{
return d3.line().x(d => d.x2).y(d => d.y2)(d);
}
})
.attr("fill", "#f72585")
)
.call(e => e.transition(t2)
.attr("d", d => d3.line()
.x(d => d.x)
.y(d => d.y)(d))
.attr("stroke", "#f72585")
.attr("fill", "#560bad")
.attr("stroke-width", 5)
.style("opacity", 0.7)
)
)
}





function reRun(){
d3.selectAll("path").remove();
drawZigZag(points);
}

d3.select("button#runAnimation").on("click", reRun);

yield svg.node();

drawZigZag(points);
}
Insert cell
Insert cell
function getCirclePoints(center,radius,numPoints){
let points = [];
let angleDist = (Math.PI*2) / numPoints;
for(let i in d3.range(numPoints)){
let radiusOffset = getRandomBetween(.5,.2);
let newRadius = i%2===0 ? radius - (radius*radiusOffset) : radius + (radius * radiusOffset);
let theta = i * angleDist;
const x = center.x + newRadius * Math.cos(theta);
const y = center.y + newRadius * Math.sin(theta);
const originalX = center.x + radius * Math.cos(theta);
const originalY = center.y + radius * Math.sin(theta);
points.push({
x: x,
y: y,
originalX: originalX,
originalY: originalY,
offset: radiusOffset
})
}
return points;
}
Insert cell
function getRandomBetween(max,min){
return Math.random() * (max - min) + min;
}
Insert cell
function updatePoints(pts,newRadius){
let points = [];
let angleDist = (Math.PI*2) / pts.length;
for(let i in pts){
let point = pts[i];
let radiusOffset = point.offset;
let updatedRadius = i%2===0 ? newRadius - (newRadius*radiusOffset) : newRadius + (newRadius * radiusOffset);
let theta = i * angleDist;
point.x2 = point.originalX + updatedRadius * Math.cos(theta);
point.y2 = point.originalY + updatedRadius * Math.sin(theta);
points.push(point);
}
return points;
}
Insert cell
render = () => {

return t => {

return svg.node();
}
}
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