Skip to content

Instantly share code, notes, and snippets.

@jameshenegan
Last active September 26, 2019 02:16
Show Gist options
  • Save jameshenegan/c7a2272ae8b7205e941778fbdceeff0d to your computer and use it in GitHub Desktop.
Save jameshenegan/c7a2272ae8b7205e941778fbdceeff0d to your computer and use it in GitHub Desktop.

Squiqqly Circle

Use d3's path generator to draw a circle. Over time, add jitter to the x and y coordinates of the circle to make it squirm.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="https://d3js.org/d3.v5.min.js"></script>
</head>
<p></p>
<script>
// Create Canvas
const width = 400
const height = 400
const margin = 100
const sd = 15
const svgContainer = d3.select("p").append("svg")
.attr("width", width)
.attr("height", height);
const xScale = d3.scaleLinear().domain([-1, 1]).range([margin, width - margin])
const yScale = d3.scaleLinear().domain([-1, 1]).range([height - margin, margin])
const lineFunction = d3.line()
.x(d => xScale(d.x))
.y(d => yScale(d.y))
.curve(d3.curveBasisClosed)
// Generate Initial Data
// Create a linear space from 0 to 2pi containing 50 points
const domain = []
const start = 0
const stop = 2 * Math.PI
const num_points = 20
const scaleFactor = (stop - start) / num_points
for (var i = 0; i <= num_points; i++) {
domain.push(scaleFactor * i)
}
const points = []
for (var i = 0; i <= num_points; i++) {
points.push({ "x": Math.cos(domain[i]), "y": Math.sin(domain[i]) })
}
// Draw First Circle
var lineGraph = svgContainer.append("path")
.attr("d", lineFunction(points))
.attr("stroke", "blue")
.attr("stroke-width", 2)
.attr("fill", "blue")
.attr("stroke", "gray")
.attr("stroke-width", 5);
// Make the circle wiggle
// Standard Normal variate using Box-Muller transform.
function randn_bm() {
var u = 0, v = 0;
while (u === 0) u = Math.random(); //Converting [0,1) to (0,1)
while (v === 0) v = Math.random();
return (
{
"x_jitter": Math.sqrt(-2.0 * Math.log(u)) * Math.cos(2.0 * Math.PI * v) / sd,
"y_jitter": Math.sqrt(-2.0 * Math.log(u)) * Math.sin(2.0 * Math.PI * v) / sd
})
;
}
d3.interval(() => {
const jitter = []
const new_points = []
for (var i = 0; i <= num_points; i++) {
const output = randn_bm()
jitter.push(
{
"x_jitter": output.x_jitter,
"y_jitter": output.y_jitter
})
new_points.push(
{
"x": points[i].x + jitter[i].x_jitter,
"y": points[i].y + jitter[i].y_jitter
}
)
}
svgContainer.selectAll("path").data(new_points).transition().duration(4000)
.attr("d", lineFunction(new_points))
}, 1500)
</script>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment