Published
Edited
Jun 7, 2021
Importers
Insert cell
Insert cell
function* animatePlan(plan) {
const size=400;
const nominalArmLength=3;
const pad=10;
const c = DOM.context2d(size, size);
const scale=(size-2*pad)/(4*nominalArmLength);
const xy0 = size/2;
const to=(x,y)=>[xy0+x*scale,xy0-y*scale];
c.lineCap = "round";
c.font = `${Math.round(size/20)}px sanserif`;
c.textAlign = "right";
const twopi = 2*Math.PI;
const r0 = scale*nominalArmLength;
const [x0,y0]=to(0,0);
const period = plan.scheduleT.totalTime;
const t0 = Date.now();
while(true) {
const t = (Date.now()-t0)/1000 % period;
const {theta:[T,xT,yT],phi:[P,xP,yP]} = plan.getPosition(t);
let [x,y] = to(xT,yT);
c.globalAlpha=1, c.fillStyle="#fff", c.fillRect(0, 0, size, size);
c.strokeStyle="#aaa", c.lineWidth=1,
c.beginPath(), c.arc(x0, y0, r0, 0, twopi), c.stroke(),
c.beginPath(), c.arc(x0, y0, 2*r0, 0, twopi), c.stroke();
c.fillStyle="#000", c.textAlign="right", c.fillText(`t=${Number(t).toFixed(1)}s`, size-10, size-10);
c.textAlign="left", c.fillStyle="red", c.fillText(`θ=${Number(T).toFixed(0)}°`, 10, size-10);
c.fillStyle="blue", c.fillText(`ϕ=${Number(P).toFixed(0)}°`, 10, size-size/15-10);
c.strokeStyle="red", c.beginPath(), c.lineWidth = Math.round(0.5*scale),
c.moveTo(x0, y0), c.lineTo(x,y), c.stroke();
c.strokeStyle="blue", c.globalAlpha = 0.8, c.beginPath(), c.moveTo(x,y);
[x,y] = to(xP,yP);
c.lineTo(x,y), c.stroke();
yield c.canvas;
}
}
Insert cell
function plotPlan(plan, {omega=true, angle=true}={}) {
const alpha=0.4;
const marks=[Plot.frame()];
let xlabel="";
if(angle) {
marks.push(
Plot.line(plan.scheduleT.atime, {x:t=>t, y:(_,i)=>plan.scheduleT.angle[i],
stroke:"red", strokeWidth:2}),
Plot.line(plan.scheduleP.atime, {x:t=>t, y:(_,i)=>plan.scheduleP.angle[i],
stroke:"blue", strokeWidth:2})
);
xlabel = "Angle [deg]";
}
if(omega) {
marks.push(
Plot.areaY(plan.scheduleT.wtime, {x:t=>t, y1:0, y2:(_,i)=>plan.scheduleT.omega[i],
fill:"red", fillOpacity:alpha}),
Plot.areaY(plan.scheduleP.wtime, {x:t=>t, y1:0, y2:(_,i)=>plan.scheduleP.omega[i],
fill:"blue", fillOpacity:alpha}),
Plot.line(plan.scheduleT.wtime, {x:t=>t, y:(_,i)=>plan.scheduleT.omega[i],
stroke:"red", strokeWidth:1}),
Plot.line(plan.scheduleP.wtime, {x:t=>t, y:(_,i)=>plan.scheduleP.omega[i],
stroke:"blue", strokeWidth:1}),
);
if(angle) xlabel += ", ";
xlabel += "Angular Speed [deg/s]";
}
return Plot.plot({
grid:true,
x:{label:"Elapsed time [s]"},
y:{label:xlabel},
marks:marks,
});
}
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