Skip to content

Instantly share code, notes, and snippets.

@lablibertario
Forked from anonymous/index.html
Created February 20, 2018 01:06
Show Gist options
  • Save lablibertario/841fc2e526d0cdf967d25f3a93e141fb to your computer and use it in GitHub Desktop.
Save lablibertario/841fc2e526d0cdf967d25f3a93e141fb to your computer and use it in GitHub Desktop.
Lissajous
<canvas height="1600" width="1600"></canvas>
<canvas height="1600" width="1600"></canvas>
console.clear();
const PI = Math.PI,
PI2 = PI * 2,
RATE = 30,
CVS1 = document.querySelector('canvas:nth-child(1)'),
CVS2 = document.querySelector('canvas:nth-child(2)'),
CTX1 = CVS1.getContext('2d'),
CTX2 = CVS2.getContext('2d'),
CVS_DI = CVS1.width,
// How many cols/rows
COUNT = 8,
// Padding
PEN_PAD = CVS_DI * 0.025,
// Radius
PEN_RAD = CVS_DI / ((COUNT + 1) * 2),
// Stroke line width
STROKE = 2,
// Indicator radius
TIP_RAD = 6,
// Coloring
COLOR = '#FFF',
COLOR_OFF = '#333';
// An input "Pen", influences the x or y of a Group's output
class Pen {
constructor({ rate, x, y }) {
this.di = PEN_RAD * 2;
this.rad = PEN_RAD * 0.7;
this.x = x * this.di;
this.y = y * this.di;
this.cx = this.x + this.di * 0.5;
this.cy = this.y + this.di * 0.5;
this.rateName = rate;
this.rate = RATE * rate;
this.position = 0;
}
tick() {
this.progress = this.position / this.rate;
this._calc();
this.position++;
}
// Setting the coordinates for the tip of the pen
_calc() {
let deg = 360 * this.progress;
this.tipX = this.cx + this.rad * Math.cos(deg * PI / 180);
this.tipY = this.cy + this.rad * Math.sin(deg * PI / 180);
}
}
// Takes an x pen and y pen and produces an output
class Group {
constructor(penX, penY) {
this.penX = penX;
this.penY = penY;
this.tracker = {};
this.progress = 0;
}
tick() {
// setting the last coordinates for the output line
this.lastX = this.x;
this.lastY = this.y;
// Setting the current coordinates
this.x = this.penX.tipX + this.penY.x;
this.y = this.penY.tipY + this.penX.y;
// Storing the combination so we never redraw
let key = `${this.lastX}-${this.lastY}-${this.x}-${this.y}`;
// Setting draw to false if this has already been drawn
if (this.tracker[key]) this.draw = false;
// Setting draw to true then storing that this has been drawn
else { this.tracker[key] = true; this.draw = true };
// Draw the output and the Pens
this._draw();
this.progress++;
}
_draw() {
this._drawPen(this.penX);
this._drawPen(this.penY);
this._drawOutput();
}
// Take a pen and draw it, its rate, and an indicator of current position
_drawPen({ rad, di, x, y, cx, cy, tipX, tipY, rateName }) {
// the circle
CTX1.lineWidth = STROKE;
CTX1.strokeStyle = COLOR_OFF;
CTX1.beginPath();
CTX1.arc(cx, cy, rad, 0, PI2, false);
CTX1.stroke();
// The current position
CTX1.fillStyle = COLOR;
CTX1.strokeStyle = COLOR;
CTX1.beginPath();
CTX1.arc(tipX, tipY, TIP_RAD, 0, PI2, false);
CTX1.fill();
// the rate number
CTX1.fillStyle = COLOR_OFF;
CTX1.font = `lighter ${rad * 0.5}px Helvetica`;
CTX1.textAlign = 'center';
CTX1.textBaseline = 'middle';
CTX1.fillText(rateName, cx, cy);
}
// Draw the output of the two pens
_drawOutput() {
// If it hasnt already been drawn yet,
// draw the path on the canvas that isnt erased each frame
if (this.draw) {
CTX2.lineWidth = STROKE;
CTX2.strokeStyle = COLOR;
CTX2.beginPath();
CTX2.moveTo(this.lastX, this.lastY);
CTX2.lineTo(this.x, this.y);
CTX2.stroke();
}
// Draw the indicator on the refreshing canvas
CTX1.fillStyle = COLOR;
CTX1.beginPath();
CTX1.arc(this.x, this.y, TIP_RAD, 0, PI2, false);
CTX1.fill();
}
}
let pensX = [],
pensY = [],
groups = [];
// Generating the pens
for (let x = 0; x < COUNT; x++) {
let penX = new Pen({ rate: x + 1, x: x + 1, y: 0 }),
penY = new Pen({ rate: x + 1, x: 0, y: x + 1 });
pensX.push(penX);
pensY.push(penY);
}
// Generating the groups
for (let x = 0; x < pensY.length; x++)
for (let y = 0; y < pensX.length; y++)
groups.push(new Group(pensX[x], pensY[y]));
// Start running
run();
function run() {
// Clear the refreshing canvas
CTX1.clearRect(0, 0, CVS_DI, CVS_DI);
// For each pen
for (let i = 0; i < pensX.length; i++) {
// Tick them forward to get new coords
pensX[i].tick();
pensY[i].tick();
// Draw the axis
CTX1.lineWidth = STROKE;
CTX1.strokeStyle = COLOR_OFF;
CTX1.beginPath();
CTX1.moveTo(pensX[i].tipX, 0);
CTX1.lineTo(pensX[i].tipX, CVS_DI);
CTX1.stroke();
CTX1.beginPath();
CTX1.moveTo(0, pensY[i].tipY);
CTX1.lineTo(CVS_DI, pensY[i].tipY);
CTX1.stroke();
}
// Tick each group (draws them as well)
groups.forEach(group => group.tick());
// Run it again
requestAnimationFrame(run);
}
html, body {
height: 100%;
}
body {
background: #000;
}
canvas {
width: 800px;
height: auto;
max-width: 95%;
position: absolute;
display: block;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
&:first-child {
// background: white;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment