Public
Edited
Oct 17, 2023
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
drawDensity = () => {
const d = data,
extentX = d3.extent(data, (d) => d.x),
extentY = d3.extent(data, (d) => d.y),
extentV = d3.extent(data, (d) => d.v);

return Plot.plot({
grid: true,
x: { nice: true, domain: extentX },
y: { nice: true, domain: extentY },
color: { nice: true, legend: true },
marks: [
Plot.density(d, { x: "x", y: "y", fill: "density", opacity: 0.2 }),
Plot.dot(d, {
x: "x",
y: "y",
r: 1,
fill: "white",
opacity: 0.1
}),
Plot.link(
[
{ x1: 0, y1: 0, x2: extentX[0], y2: Math.abs(extentX[0] * k) },
{ x1: 0, y1: 0, x2: extentX[1], y2: Math.abs(extentX[1] * k) }
],
{
x1: "x1",
y1: "y1",
x2: "x2",
y2: "y2",
stroke: "black"
}
)
]
});
}
Insert cell
draw = (t1 = 0, t2 = 1e10, r = 1) => {
const d = data.slice(t1, t2),
extentX = d3.extent(data, (d) => d.x),
extentY = d3.extent(data, (d) => d.y),
extentV = d3.extent(data, (d) => d.v);

return Plot.plot({
grid: true,
x: { nice: true, domain: extentX },
y: { nice: true, domain: extentY },
color: { nice: true, domain: extentV, legend: true, scheme: "Inferno" },
marks: [
Plot.dot(d, {
x: "x",
y: "y",
r: r,
fill: "v",
opacity: 0.2
}),
Plot.link(
[
{ x1: 0, y1: 0, x2: extentX[0], y2: Math.abs(extentX[0] * k) },
{ x1: 0, y1: 0, x2: extentX[1], y2: Math.abs(extentX[1] * k) }
],
{
x1: "x1",
y1: "y1",
x2: "x2",
y2: "y2",
stroke: "gray"
}
)
]
});
}
Insert cell
data = {
const data = [];

var x1, y1, vx1, vy1, pp;

// The start point
{
x1 = 0;
y1 = 1;
vx1 = initialVx;
vy1 = 0;

data.push({ i: 0, x: x1, y: y1, vx: vx1, vy: vy1 });
}

for (let i = 0; i < total; ++i) {
let { x, y, vx, vy } = data[i];

x += vx * dt;
y += vy * dt;
vy -= g * dt;

if (x > 0 && y < k * x) {
pp = pingpong(vx, vy, rightPanel);
vx = pp[0];
vy = pp[1];
// vx *= -1;
// vy *= -1;
}

if (x < 0 && y < -k * x) {
pp = pingpong(vx, vy, leftPanel);
vx = pp[0];
vy = pp[1];
// vx *= -1;
// vy *= -1;
}

data.push({ i: i + 1, x, y, vx, vy });
}

data.map((d) => {
const v = Math.sqrt(dot([d.vx, d.vy], [d.vx, d.vy]));
Object.assign(d, { v });
});

return data;
}
Insert cell
data
Type Table, then Shift-Enter. Ctrl-space for more options.

Insert cell
leftPanel = {
const pos = [-1, k],
panelDir = normalize(pos),
n = normalize([-k, -1]);

return { pos, panelDir, n };
}
Insert cell
rightPanel = {
const pos = [1, k],
panelDir = normalize(pos),
n = normalize([-k, 1]);

return { pos, panelDir, n };
}
Insert cell
Insert cell
pingpong(1, 2, leftPanel)
Insert cell
pingpong = (vx, vy, panel) => {
const { n, panelDir } = panel,
dotDir1 = dot([vx, vy], panelDir),
dotDir2 = dot([vx, vy], n),
lenDir1 = dotDir1, // < 0 ? -1 * Math.sqrt(-dotDir1) : Math.sqrt(dotDir1),
lenDir2 = dotDir2, // < 0 ? -1 * Math.sqrt(-dotDir2) : Math.sqrt(dotDir2),
u = add(mul(panelDir, lenDir1), mul(n, -1 * lenDir2));

return u;
}
Insert cell
normalize = (a) => {
const len = norm(a);
return a.map((e) => e / len);
}
Insert cell
norm = (a) => {
return Math.sqrt(dot(a, a));
}
Insert cell
add = (a, b) => {
return [a[0] + b[0], a[1] + b[1]];
}
Insert cell
mul = (a, m) => {
return [a[0] * m, a[1] * m];
}
Insert cell
dot = (a, b) => {
return a[0] * b[0] + a[1] * b[1];
}
Insert cell
scaleX = d3.scaleLinear().domain([-1.1, 1.1]).range([0, width]).nice()
Insert cell
scaleY = d3.scaleLinear().domain([1.1, -0.1]).range([0, height]).nice()
Insert cell
d3 = require("d3")
Insert cell
Insert cell
dt = 0.002
Insert cell
g = 9.8
Insert cell
height = width / 2
Insert cell
width = 800
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