Public
Edited
Feb 26, 2024
Importers
3 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
class FirstMover extends Mover {
update() {
this.location.add(this.velocity)
}
}
Insert cell
Insert cell
Insert cell
class AccelMover extends Mover {
constructor({accFn, vMax, ...kwargs} = {}) {
super(kwargs)
this.maxVelocity = vMax
this.accelerationUpdate = accFn || (() => {})
}
update(opts) {
this.accelerationUpdate({
pos: this.location,
vel: this.velocity,
acc: this.acceleration,
...opts
})
this.velocity.add(this.acceleration)
this.maxVelocity && this.velocity.clampLength(0, this.maxVelocity)
this.location.add(this.velocity)
}
}
Insert cell
Insert cell
constantAcceleration = ({ acc }) => acc.set(-0.001, 0.01)
Insert cell
Insert cell
Insert cell
inputConstantAcceleration = ({ acc, mouse }) => {
if (mouse.down)
acc.set(-0.001, 0.01).multiplyScalar(mouse.pos.y < 100 ? -1 : 1);
else acc.set(0, 0);
}
Insert cell
Insert cell
Insert cell
randomAcceleration = ({ acc }) => acc.set(random() - 0.5, random() - 0.5)
Insert cell
Insert cell
Insert cell
getNoiseAcceleration = ({ t0 = 0, dt = 0.01 } = {}) => {
let t = t0;
return ({ acc }) => {
t += dt;
acc.set(simplex.noise2D(t, 0) * 0.5, simplex.noise2D(0, t) * 0.5);
};
}
Insert cell
Insert cell
Insert cell
accelerateTowardsMouse = ({ acc, pos, mouse }) => {
const dir = new THREE.Vector2();
if (mouse.pos) {
dir
.subVectors(mouse.pos, pos)
.normalize()
.multiplyScalar(0.5);
}
acc.copy(dir);
}
Insert cell
Insert cell
Insert cell
altAccelerateTowardsMouse = ({ acc, pos, vel, mouse }) => {
const dir = new THREE.Vector2();
if (mouse.pos) {
dir.subVectors(mouse.pos, pos);
let len = 1 / dir.length();
if (mouse.down) {
len = 1 - len;
}
dir.setLength(len);
} else {
dir
.copy(vel)
.negate()
.multiplyScalar(0.1);
if (dir.length() < 0.05) dir.copy(vel).negate();
}
acc.copy(dir);
}
Insert cell
Insert cell
Insert cell
Insert cell
class Mover {
constructor({ x = 0, y = 0, ax = 0, ay = 0, loc = {}, acc = {} } = {}) {
this.location = new THREE.Vector2(loc.x || x, loc.y || y);
this.velocity = new THREE.Vector2(0, 0);
this.acceleration = new THREE.Vector2(acc.x || ax, acc.y || ay);
}

update() {
this.velocity.add(this.acceleration);
this.location.add(this.velocity);
}

display(ctx) {
ctx.strokeStyle = '#000';
ctx.lineWidth = 2;
ctx.fillStyle = '#faa';
ctx.beginPath();
ctx.arc(this.x, this.y, 16, 0, 2 * PI);
ctx.fill();
ctx.stroke();
ctx.closePath();
}

get x() {
return this.location.x;
}
set x(xx) {
this.location.x = xx;
}
get y() {
return this.location.y;
}
set y(yy) {
this.location.y = yy;
}
}
Insert cell
Insert cell
renderMovers = function*(
{ visibility, height = 200, speed = 1, overflow = 'wrap', trace = false },
...movers
) {
const ctx = DOM.context2d(width, height);
let trailsCtx;
const srcDim = [0, 0, width * devicePixelRatio, height * devicePixelRatio];
const destDim = [0, 0, width, height];
if (trace) {
trailsCtx = DOM.context2d(width, height);
trailsCtx.strokeStyle = '#00f';
trailsCtx.lineWidth = 1;
trailsCtx.globalAlpha = 0.2;
}

const mouse = {
pos: null,
down: false,
shift: false
};

ctx.canvas.onmousemove = e => {
mouse.pos = new THREE.Vector2(e.offsetX, e.offsetY);
};
ctx.canvas.onmouseleave = e => {
mouse.pos = null;
mouse.down = false;
mouse.shift = false;
};
ctx.canvas.onmousedown = e => {
mouse.down = true;
mouse.shift = e.shiftKey;
};
ctx.canvas.onmouseup = e => {
mouse.down = false;
mouse.shift = false;
};

const update = mover => {
const start = [mover.x, mover.y];

mover.update({
mouse
});

const end = [mover.x, mover.y];

switch (overflow) {
case 'wrap':
mover.x = wrap(mover.x, 0, width);
mover.y = wrap(mover.y, 0, height);
break;
}

if (trace) {
trailsCtx.beginPath();
trailsCtx.moveTo(...start);
trailsCtx.lineTo(...end);
trailsCtx.stroke();
trailsCtx.closePath();
}
};

while (true) {
repeat(() => movers.forEach(update), speed);

ctx.clearRect(0, 0, width, height);

if (trace) {
ctx.drawImage(trailsCtx.canvas, ...srcDim, ...destDim);
}

movers.forEach(mover => mover.display(ctx));

yield visibility(ctx.canvas);
}
}
Insert cell
import { repeat, wrap } from '@ajur/the-nature-of-code-0-introduction'
Insert cell
import { THREE, threeScene } from "@ajur/threejs"
Insert cell
Insert cell
seedrandom = require("seedrandom/seedrandom.min.js")
Insert cell
random = seedrandom()
Insert cell
d3 = require("d3-random")
Insert cell
SimplexNoise = require('simplex-noise@2.4')
Insert cell
simplex = new SimplexNoise(random)
Insert cell
PI = Math.PI
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