Published
Edited
Mar 18, 2022
8 stars
Insert cell
Insert cell
chart1 = {
const w = 500;
const h = 500;
const b = 10;

const iter = 7500;

const context = DOM.context2d(w, h);

const corners = [
[w / 2, h / 2 - ((Math.sqrt(3) * w) / 2 - b) / 2],
[b, h / 2 + ((Math.sqrt(3) * w) / 2 - b) / 2],
[w - b, h / 2 + ((Math.sqrt(3) * w) / 2 - b) / 2]
];

var pos = [0.5 * w, 0.5 * h];

var i = 0;

setTimeout(function () {
drawDots(pos);
}, 1000);

function drawDots(pos) {
setTimeout(function () {
for (var j = 0; j < 10; j++) {
var rv = corners[Math.floor(Math.random() * 3)];
pos = halfway(pos, rv);
context.beginPath();
context.rect(pos[0], pos[1], 1, 1);
context.fillStyle = "#000";
context.fill();
context.closePath();
}
i++;
if (i <= iter) {
drawDots(pos);
}
}, 1);
}

yield context.canvas;
}
Insert cell
Insert cell
chart2 = {
var w = 500;
var h = 500;
var b = 10;

var context = DOM.context2d(w, h);

// initial (largest) triangle
var triangles = [
[
[w / 2, h / 2 - ((Math.sqrt(3) * w) / 2 - b) / 2],
[b, h / 2 + ((Math.sqrt(3) * w) / 2 - b) / 2],
[w - b, h / 2 + ((Math.sqrt(3) * w) / 2 - b) / 2]
]
];

// draw initial triangle
context.beginPath();
context.moveTo(triangles[0][0][0], triangles[0][0][1]);
context.lineTo(triangles[0][1][0], triangles[0][1][1]);
context.lineTo(triangles[0][2][0], triangles[0][2][1]);
context.fillStyle = "#000";
context.fill();
context.closePath();

// set iterations
var iter = 9;
var i = 0;

setTimeout(function () {
removeTriangles(triangles);
}, 1000);

function removeTriangles(triangles) {
setTimeout(function () {
var newtriangles = [];
triangles.forEach(function (el, i) {
// "remove" triangle in the middle by painting over it
var nt = [
halfway(el[1], el[2]),
halfway(el[2], el[0]),
halfway(el[0], el[1])
];

context.beginPath();
context.moveTo(nt[0][0], nt[0][1]);
context.lineTo(nt[1][0], nt[1][1]);
context.lineTo(nt[2][0], nt[2][1]);
context.fillStyle = "#fff";
context.fill();
context.closePath();

// push new triangles to our array
newtriangles.push(
[nt[0], nt[1], el[2]],
[nt[0], el[1], nt[2]],
[el[0], nt[1], nt[2]]
);
});

i++;
if (i < iter) {
removeTriangles(newtriangles);
}
}, 750);
}

yield context.canvas;
}
Insert cell
Insert cell
chart3 = {
const w = 500;
const h = 500;
const b = 10;

const svg = d3.select(DOM.svg(w, h));

const points = [
[b, h / 2 + ((Math.sqrt(3) * w) / 2 - b) / 2],
[w - b, h / 2 + ((Math.sqrt(3) * w) / 2 - b) / 2]
];

svg
.append("path")
.attr("d", function () {
return makePath(points);
})
.style("stroke", "#000")
.style("stroke-width", "2px")
.style("fill", "none");

// set iterations
var iter = 8;
var i = 0;

var even = true; // the direction of the bend is toggled at every iteration

iterate(points);

function iterate(points) {
setTimeout(function () {
var newPoints = [points[0]];
for (var j = 0; j < points.length - 1; j++) {
newPoints.push(...bend(points[j], points[j + 1]));
}
svg
.select("path")
.transition()
.duration(2000)
.attrTween("d", pathTween(makePath(newPoints), 2));

i++;
if (i < iter) {
iterate(newPoints);
}
}, 2500);
}

function bend(a, d) {
even = !even;
var L = Math.sqrt(Math.pow(d[0] - a[0], 2) + Math.pow(d[1] - a[1], 2));
var alpha = Math.atan((d[1] - a[1]) / (d[0] - a[0]));
if (d[0] - a[0] < 0) {
alpha += Math.PI;
}
if (even) {
var b1 = a[0] + (L / 2) * Math.cos(alpha + Math.PI / 3);
var b2 = a[1] + (L / 2) * Math.sin(alpha + Math.PI / 3);
var c1 = a[0] + 0.5 * Math.sqrt(3) * L * Math.cos(alpha + Math.PI / 6);
var c2 = a[1] + 0.5 * Math.sqrt(3) * L * Math.sin(alpha + Math.PI / 6);
} else {
var b1 = a[0] + (L / 2) * Math.cos(alpha - Math.PI / 3);
var b2 = a[1] + (L / 2) * Math.sin(alpha - Math.PI / 3);
var c1 = a[0] + 0.5 * Math.sqrt(3) * L * Math.cos(alpha - Math.PI / 6);
var c2 = a[1] + 0.5 * Math.sqrt(3) * L * Math.sin(alpha - Math.PI / 6);
}
return [[b1, b2], [c1, c2], d];
}

function makePath(points) {
var p = "M" + points[0][0] + "," + points[0][1];
for (var i = 1; i < points.length; i++) {
p += "L" + points[i][0] + "," + points[i][1];
}
return p;
}
return svg.node();
}
Insert cell
Insert cell
halfway = function (a, b) {
return [(a[0] + b[0]) / 2, (a[1] + b[1]) / 2];
}
Insert cell
d3 = require("d3@5")
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