Published
Edited
Mar 14, 2019
1 fork
Importers
21 stars
Insert cell
Insert cell
Insert cell
Insert cell
canvas = {
const context = DOM.context2d(width, height);

function update() {
mutable points = mutable points;
const curve = new Bezier(mutable points.flat());
const outline = curve.outline(offset1, offset1, offset2, offset2);
context.clearRect(0, 0, width, height);
drawSkeleton(context, curve);
drawCurve(context, curve);
context.strokeStyle = "red";
outline.curves.forEach(c => drawCurve(context, c));
}

return d3.select(context.canvas)
.call(drag, {radius: 20, points: mutable points, update})
.call(update)
.node();
}
Insert cell
mutable points = [
[0.75 * Math.min(640, width), 80],
[0.40 * Math.min(640, width), 20],
[0.15 * Math.min(640, width), 150]
]
Insert cell
function drag(selection, {points, radius, update}) {

function dragsubject() {
let S = null;
let R = radius;
for (const p of points) {
let r = Math.hypot(d3.event.x - p[0], d3.event.y - p[1]);
if (r < R) R = r, S = p;
}
return {x: S[0], y: S[1], point: S};
}

function dragged() {
d3.event.subject.point[0] = d3.event.x;
d3.event.subject.point[1] = d3.event.y;
}

selection.call(d3.drag()
.subject(dragsubject)
.on("drag", dragged)
.on("start.update drag.update end.update", update));
}
Insert cell
function drawLine(ctx, p1, p2, offset) {
offset = offset || { x:0, y:0 };
var ox = offset.x;
var oy = offset.y;
ctx.beginPath();
ctx.moveTo(p1.x + ox,p1.y + oy);
ctx.lineTo(p2.x + ox,p2.y + oy);
ctx.stroke();
}
Insert cell
function drawPoint(ctx, p, offset) {
offset = offset || { x:0, y:0 };
var ox = offset.x;
var oy = offset.y;
ctx.beginPath();
ctx.arc(p.x + ox, p.y + oy, 5, 0, 2*Math.PI);
ctx.stroke();
}
Insert cell
function drawCircle(ctx, p, r, offset) {
offset = offset || { x:0, y:0 };
var ox = offset.x;
var oy = offset.y;
ctx.beginPath();
ctx.arc(p.x + ox, p.y + oy, r, 0, 2*Math.PI);
ctx.stroke();
}
Insert cell
function drawPoints(ctx, points, offset) {
offset = offset || { x:0, y:0 };
points.forEach(p => drawCircle(ctx, p, 3, offset));
}
Insert cell
function drawSkeleton(ctx, curve, offset = {x: 0, y: 0}, nocoords) {
var pts = curve.points;
ctx.strokeStyle = "lightgrey";
drawLine(ctx, pts[0], pts[1], offset);
if (pts.length === 3) drawLine(ctx, pts[1], pts[2], offset);
else drawLine(ctx, pts[2], pts[3], offset);
ctx.strokeStyle = "black";
if(!nocoords) drawPoints(ctx, pts, offset);
}
Insert cell
function drawCurve(ctx, curve, offset) {
offset = offset || { x:0, y:0 };
var ox = offset.x;
var oy = offset.y;
ctx.beginPath();
var p = curve.points, i;
ctx.moveTo(p[0].x + ox, p[0].y + oy);
if (p.length === 3) {
ctx.quadraticCurveTo(
p[1].x + ox, p[1].y + oy,
p[2].x + ox, p[2].y + oy
);
}
if (p.length === 4) {
ctx.bezierCurveTo(
p[1].x + ox, p[1].y + oy,
p[2].x + ox, p[2].y + oy,
p[3].x + ox, p[3].y + oy
);
}
ctx.stroke();
ctx.closePath();
}
Insert cell
height = 200
Insert cell
Bezier = require("bezier-js@2/bezier.js").catch(() => window.Bezier)
Insert cell
d3 = require("d3-selection@1", "d3-drag@1")
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