Published
Edited
Aug 15, 2019
6 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function* draw() {
const context = DOM.context2d(width, height);
context.translate(width / 2, width / 3);
let t = 0;

let points = [];
for (let i = 0; i < n; ++i) {
const p = new Point([0, 0, 3], i);
points.push(p);
}

let trace = [];
let play = true;

while (play) {
yield Promises.delay(20).then(() => {
t += 1;
context.clearRect(-width / 2, -width / 2, width, width);

context.beginPath();
context.rect(-width / 2, 5, width, -width / 2);
context.clip();
line([-width / 2, 5], [width / 2, 5], context, {
color: "rgba(150,150,150,0.9)"
});

points.forEach(p => p.draw(context));
const nextPoints = updatePointsPosition(points, t, context);
trace.push(nextPoints);

drawTrace(trace, context);

if (t > tMax) {
play = false;
let maxPoints = findMax(trace);
maxPoints.forEach(p => p.draw(context, { color: "red" }));
}
return context.canvas;
});
}
}
Insert cell
function findMax(trace) {
let res = [];

for (let i = 0; i < trace.length; ++i) {
for (let j = 0; j < trace[i].length; ++j) {
const y = trace[i][j].position[1];
if (!res[j] || y < res[j].position[1]) {
res[j] = trace[i][j];
}
}
}

return res;
}
Insert cell
function updatePointsPosition(points, t) {
const nextPoints = [];

for (let [i, p] of enumerate(points)) {
nextPoints.push(p.clone());
p.update();
p.applyForce([0, 0.5]);
}

return nextPoints;
}
Insert cell
function addVec([ax, ay], [fx, fy]) {
return [ax + fx, ay + fy];
}
Insert cell
function enumerate(arr) {
const res = [];
for (let i = 0; i < arr.length; ++i) {
res.push([i, arr[i]]);
}
return res;
}
Insert cell
function drawTrace(trace, context) {
for (let i = 0; i < trace.length - 1; ++i) {
for (let j = 0; j < trace[i].length; ++j) {
line(trace[i][j].position, trace[i + 1][j].position, context, {
color: "rgba(150,150,150,0.9)"
});
}
}
}
Insert cell
class Point {
constructor([x, y], i) {
this.acceleration = [0, 0];
this.ind = i;
this.velocity = coordsFromDeg((360 / n) * i, 15, [x, y]);
this.position = [x, y];
}

draw(context, opts) {
circle([...this.position, 3], context, opts);
}

update() {
const { velocity, acceleration, position } = this;
this.velocity = addVec(velocity, acceleration);
this.position = addVec(position, velocity);
this.acceleration = [0, 0];
}

applyForce(force) {
const { acceleration } = this;
this.acceleration = addVec(acceleration, force);
}

clone() {
return new Point(this.position, this.ind);
}
}
Insert cell
Insert cell
Insert cell
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