Random Oscillator

Particle randomly moves from left to right

by wio_dude

HTML

<canvas id="canvas" width="600" height="600"></canvas>
<div id="config">
  <input id="trail" type="checkbox" checked><label for="trail">Show Trail</label><br />

  <input id="axes" type="checkbox" checked><label for="axes">Show Axes</label><br />
  <input id="polar" type="checkbox" checked><label for="polar">Show Polar</label><br />
  <input id="proj" type="checkbox"><label for="proj">Show Projection</label><br />
  <input id="avg" type="checkbox"><label for="avg">Show Averages</label><br />
  <input id="sound" type="checkbox"><label for="sound">Play Sound</label><br />
  <select id="movetype">
    <option value="basic" selected>Basic</option>
    <option value="bezier">Bezier</option>
    <option value="stop">Stop</option>
  </select>
</div>
<br />
<textarea id="debug" cols="50" rows="10"></textarea>

CSS

canvas {
  background-color: whitesmoke;
}

#config {
  float: right;
}

JavaScript

const TAU = 2 * Math.PI;
const X_AXIS = 0;
const Y_AXIS = 1;
const AXES = [X_AXIS, Y_AXIS];
const MAX_SPEED = 1;
const MAX_DISPLACEMENT = 200;
const ACCELERATION = 0.15;
const DEBUG_UPDATE_FRAME = 40;
const MAX_GAIN = 0.05;
const MAX_SOUND_FREQUENCY = 40;
const MIN_SOUND_FREQUENCY = 10000;
const HISTORY_SECONDS = 5 * 60
const HISTORY_FRAMES = HISTORY_SECONDS * 60;

const ELEM_IDS = [
  'canvas',
  'debug',
  'trail',
  'axes',
  'polar',
  'avg',
  'proj',
  'sound',
  'movetype',
];

const $e = {};
ELEM_IDS.forEach(id => {
  $e[id] = document.getElementById(id)
});


const basic = {
  init() {},
  update(p, v) {
    for (const axis of AXES) {
      const r = 2 * Math.random();
      const dir = r < 1 ? 1 : -1;
      if (r < 1) {
        v[axis] = Math.min(
          0.5 * (MAX_DISPLACEMENT - p[axis]),
          v[axis] + ACCELERATION);
      } else {
        v[axis] = Math.max(
          0.5 * (-MAX_DISPLACEMENT - p[axis]),
          v[axis] - ACCELERATION);
      }
      p[axis] += v[axis];
    }
  },
};


function random_point(xd, yd) {
	return [
  	(2 * Math.random() - 1) * xd,
  	(2 * Math.random() - 1) * yd
  ]
}

function bezier_period(points) {
	const [p0, p1, p2, p3] = points;
	const upper = Math.hypot(p3[0] - p2[0], p3[1] - p2[1]) + Math.hypot(p2[0] - p1[0], p2[1] - p1[1]) + Math.hypot(p1[0] - p0[0], p1[1] - p0[1]);
  const lower = Math.hypot(p3[0] - p0[0], p3[1] - p0[1]);
  return (upper + lower) / 2;
}

function next_random_bezier(b, xd, yd) {
	const [,, p2, p3] = b.points;
  let control1 = [
  	Math.max(-xd, Math.min(xd, 2 * p3[0] + p2[0])),
  	Math.max(-yd, Math.min(yd, 2 * p3[1] + p2[1])),
  ];
	const points = [
      p3,
      control1,
      random_point(xd, yd),
      random_point(xd, yd),
  ]
  const period = bezier_period(points);
  
	return {
  	points,
    t: 0,
    period,
  }
}

function random_bezier(start, xd, yd) {
	const points = [
      start,
      random_point(xd, yd),
      random_point(xd, yd),
      random_point(xd, yd),
  ];
 ...