Public
Edited
Jan 19, 2023
Importers
Insert cell
Insert cell
function mod(n, m) {
// handle case of negative number
return ((n % m) + m) % m;
}
Insert cell
Insert cell
function lin(v0, v1, t) {
return v0 + (v1 - v0) * t;
}
Insert cell
function prop(v0, v1, v) {
return (v - v0) / (v1 - v0);
}
Insert cell
function interpolate(v0, v1, t) {
if (Array.isArray(v0)) {
return v0.map((_, i) => interpolate(v0[i], v1[i], t));
} else if (typeof v0 === 'number') {
return lin(v0, v1, t);
} else if (typeof v0 === 'boolean') {
return t >= 1 ? v1 : v0;
} else if (typeof v0 === 'string') {
return t >= 1 ? v1 : v0;
} else if (typeof v0 === 'object') {
return Object.fromEntries(Object.keys(v0).map(key => {
return [key, interpolate(v0[key], v1[key], t)];
}));
} else {
throw new Error(`Cannot interpolate ${typeof v0}`)
}
}
Insert cell
function clamp(t) {
return Math.max(0, Math.min(1, t));
}
Insert cell
function smooth(t) {
t = clamp(t);
return (1 - Math.cos(t * Math.PI)) / 2;
}
Insert cell
smoothTransition = function(v0, v1, t) {
return interpolate(v0, v1, smooth(t));
}
Insert cell
Insert cell
function degreesToRadians(degrees) {
return degrees / 180 * Math.PI;
}
Insert cell
function radiansToDegrees(radians) {
return radians / Math.PI * 180;
}
Insert cell
Insert cell
vec = ({
len([dx, dy]) {
return Math.sqrt(dx ** 2 + dy ** 2);
},
arg([dx, dy]) {
return radiansToDegrees(Math.atan2(dy, dx));
},
mul([dx, dy], s) {
return [s * dx, s * dy];
},
add([dx1, dy1], [dx2, dy2]) {
return [dx1 + dx2, dy1 + dy2];
},
sub([dx1, dy1], [dx2, dy2]) {
return [dx1 - dx2, dy1 - dy2];
},
vec([dx1, dy1], [dx2, dy2]) {
return [dx2 - dx1, dy2 - dy1];
},
inv([dx, dy]) {
return [-dx, -dy];
},
unit(vec, len=1) {
return this.mul(vec, len / this.len(vec));
},
rotate([dx, dy], degrees) {
const a = degreesToRadians(degrees);
const [c, s] = [Math.cos(a), Math.sin(a)];
return [c * dx - s * dy, c * dy + s * dx];
},
lin(source, target, prop) {
return this.add(source, this.mul(this.vec(source, target), prop));
},
pad(source, target, dist) {
return this.add(source, this.unit(this.vec(source, target), dist));
},
})
Insert cell
Insert cell
function randomSeed(seed) {
return d3.randomUniform.source(d3.randomLcg(seed))(0, 1);
}
Insert cell
Insert cell
utils = ({
mod,
lin,
prop,
interpolate,
clamp,
smooth,
smoothTransition,
degreesToRadians,
radiansToDegrees,
vec,
randomSeed,
})
Insert cell
Insert cell
d3 = require("d3@7")
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