Public
Edited
Oct 6, 2024
8 stars
Insert cell
Insert cell
Insert cell
Insert cell
{
randomize;
// input points for the curve to go through.
// note that we double the first and last point so that the curve goes through all of the control points.
const inputs = [randVec(), randVec(), randVec(), randVec(), randVec()];
const curve = new spline.CurveToQuadraticBeziers();
curve.init(
inputs[0], // use the first point twice
inputs[0], //
inputs[1]
);
const controlPoints = [];
let { q01, q02, q11, q12 } = curve.point(inputs[2]);
controlPoints.push(q01, q01, q02, q11, q12);

({ q01, q02, q11, q12 } = curve.point(inputs[3]));
controlPoints.push(q01, q02, q11, q12);

({ q01, q02, q11, q12 } = curve.point(inputs[4]));
controlPoints.push(q01, q02, q11, q12);

// use the last point twice
({ q01, q02, q11, q12 } = curve.point(inputs[4]));
controlPoints.push(q01, q02, q11, q12);
return Plot.plot({
marks: [
Plot.line(controlPoints, { x: "x", y: "y", stroke: "#f003" }),
,
new QuadraticCurves(controlPoints, { x: "x", y: "y" }),
Plot.dot(controlPoints, { x: "x", y: "y", fill: "#f66", r: 2 }),
Plot.dot(inputs, { x: "x", y: "y", fill: "#000", r: 4 })
],
axis: null,
margin: 10
});
}
Insert cell
Insert cell
Insert cell
{
randomize2;
const cubicControlPoints = [randVec(), randVec(), randVec(), randVec()];
let { q00, q01, q02, q11, q12 } = spline.cubicBezierToQuadraticBeziers(
...cubicControlPoints
);
const quadraticControlPoints = [q00, q01, q02, q11, q12];

return Plot.plot({
marks: [
Plot.line(cubicControlPoints, { x: "x", y: "y", stroke: "#f003" }),
new QuadraticCurves(quadraticControlPoints, { x: "x", y: "y" }),
Plot.dot(cubicControlPoints, { x: "x", y: "y", fill: "#f66", r: 2 }),
Plot.dot(
[
quadraticControlPoints[0],
quadraticControlPoints[2],
quadraticControlPoints[4]
],
{ x: "x", y: "y", fill: "#000", r: 4 }
)
],
axis: null,
margin: 10
});
}
Insert cell
Insert cell
randVec = () => ({ x: 10 * Math.random() - 5, y: 10 * Math.random() - 5 })
Insert cell
class QuadraticCurves extends Plot.Line {
render(index, scales, { x: X, y: Y }) {
let d = "";
for (let i = 1; i < X.length; i += 2)
d += `Q${X[i]},${Y[i]},${X[i + 1]},${Y[i + 1]}`;
return svg`<path d="M${X[0]},${Y[0]}${d}" stroke="black" fill="none">`;
}
}
Insert cell
// We need this to work around MIME-type issues with GitHub Gists (the response was being sent with text/plain, which `import` didn't like).
async function importScriptWithBlob(url) {
try {
const response = await fetch(url);
const scriptText = await response.text();
const blob = new Blob([scriptText], { type: "application/javascript" });
const blobUrl = URL.createObjectURL(blob);
return import(blobUrl);
} catch (error) {
console.error("Failed to import script:", error);
throw error;
}
}
Insert cell
spline = importScriptWithBlob(
"https://gist.githubusercontent.com/yurivish/02e1ec8d37b9fbd5dabe89f6869c4ff0/raw/6aa9a8dc6f75bdbc8d44dc9f3d710269e0781ebe/splines.mjs"
)
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