Add projects and tutorials

This commit is contained in:
John Gatward
2026-03-16 18:03:17 +00:00
parent fc54c3bd4e
commit 4e94902f01
132 changed files with 19170 additions and 65 deletions

View File

@@ -0,0 +1,13 @@
class cLine{
constructor(p1, p2){
this.p1 = p1;
this.p2 = p2;
}
drawLine(){
stroke(255, 50);
strokeWeight(3);
line(this.p1.x, this.p1.y, this.p2.x, this.p2.y);
}
}

View File

@@ -0,0 +1,14 @@
class cPoint{
constructor(x,y) {this.x = x; this.y=y;}
drawPoint(){
strokeWeight(14);
stroke(255, 200);
point(this.x, this.y);
}
get getX(){return this.x;}
get getY(){return this.y;}
set changeX(_x){this.x = _x;}
set changeY(_y){this.y = _y;}
}

View File

@@ -0,0 +1,111 @@
let p = [], v=[];
let lines = [];
let theta=3/2 * Math.PI, t=0, clicks=0;
function setup(){
createCanvas(1000, 800);
initCubicCurve();
}
function draw(){
background(63);
for(let i = 0; i < p.length; i++){
p[i].drawPoint();
}
if(clicks > 3){
for(let i = 0; i < lines.length; i++){
lines[i].drawLine();
}
lerpCubicCurve();
drawCurve();
}
}
function drawCurve(){
if (v.length > 100*Math.PI){v=[];}
stroke(0, 255, 0, 200);
strokeWeight(5);
beginShape(LINES);
for (let i=0; i < v.length; i++){
vertex(v[i].x, v[i].y);
}
endShape();
}
function mouseClicked(){
if (clicks < 5) {
p[clicks].changeX = mouseX;
p[clicks].changeY = mouseY;
} else {
let c = clicks % 4;
p[c].changeX = mouseX;
p[c].changeY = mouseY;
}
v=[];
clicks ++;
t=0;
theta=3/2 * Math.PI;
}
function mouseDragged(){
p[0].changeX = mouseX;
p[0].changeY = mouseY;
return false;
}
function initCubicCurve(){
p[0] = new cPoint(0,0);
p[1] = new cPoint(0,0);
p[2] = new cPoint(0,0);
p[3] = new cPoint(0,0);
p[4] = new cPoint(0, 0);
p[5] = new cPoint(0, 0);
p[6] = new cPoint(0, 0);
p[7] = new cPoint(0, 0);
p[8] = new cPoint(0, 0);
p[9] = new cPoint(0, 0);
lines[0] = new cLine(p[0], p[1]);
lines[1] = new cLine(p[1], p[2]);
lines[2] = new cLine(p[2], p[3]);
lines[3] = new cLine(p[4], p[5]);
lines[4] = new cLine(p[5], p[6]);
lines[5] = new cLine(p[7], p[8]);
}
function lerpCubicCurve(){
p[4].changeX = (1-t)*p[0].x + t * p[1].x;
p[4].changeY = (1-t)*p[0].y + t * p[1].y;
p[5].changeX = (1-t)*p[1].x + t * p[2].x;
p[5].changeY = (1-t)*p[1].y + t * p[2].y;
p[6].changeX = (1-t)*p[2].x + t * p[3].x;
p[6].changeY = (1-t)*p[2].y + t * p[3].y;
p[7].changeX = (1-t)*p[4].x + t * p[5].x;
p[7].changeY = (1-t)*p[4].y + t * p[5].y;
p[8].changeX = (1-t)*p[5].x + t * p[6].x;
p[8].changeY = (1-t)*p[5].y + t * p[6].y;
p[9].changeX = (1-t)*p[7].x + t * p[8].x;
p[9].changeY = (1-t)*p[7].y + t * p[8].y;
v.push(new cPoint(p[9].x, p[9].y));
if (theta > 2*Math.PI){theta=0;}
theta += 0.01;
t = (Math.sin(theta) + 1) / 2;
}

View File

@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0>
<script src="https://cdn.jsdelivr.net/npm/p5@1.4.0/lib/p5.min.js"></script>
<script src="cPoint.js"></script>
<script src="cLine.js"></script>
<!-- <script src="quadCurve.js"></script> -->
<script src="cubicCurve.js"></script>
<!-- <script src="vectorForm.js"></script> -->
</head>
<body>
</body>
</html>

View File

@@ -0,0 +1,84 @@
let p = [], v=[];
let lines = [];
let theta=3/2 * Math.PI, t=0, clicks=0;
function setup(){
createCanvas(1000, 800);
initQuadCurve();
}
function draw(){
background(63);
for(let i = 0; i < p.length; i++){
p[i].drawPoint();
}
if(clicks > 2){
for(let i = 0; i < lines.length; i++){
lines[i].drawLine();
}
lerpQuadCurve();
drawCurve();
}
}
function drawCurve(){
if (v.length > 100*Math.PI){v=[];}
stroke(0, 255, 0, 200);
strokeWeight(5);
beginShape(LINES);
for (let i=0; i < v.length; i++){
vertex(v[i].x, v[i].y);
}
endShape();
}
function mouseClicked(){
if (clicks < 3){
p[clicks].changeX = mouseX;
p[clicks].changeY = mouseY;
} else {
let c = clicks % 3;
p[c].changeX = mouseX;
p[c].changeY = mouseY;
}
v=[];
clicks ++;
t=0;
theta=3/2 * Math.PI;
}
function initQuadCurve(){
p[0] = new cPoint(0,0);
p[1] = new cPoint(0,0);
p[2] = new cPoint(0,0);
p[3] = new cPoint(0, 0);
p[4] = new cPoint(0, 0);
p[5] = new cPoint(p[0].x, p[0].y);
lines[0] = new cLine(p[0], p[1]);
lines[1] = new cLine(p[1], p[2]);
lines[2] = new cLine(p[3], p[4]);
}
function lerpQuadCurve(){
p[3].changeX = (1-t)*p[0].x + t * p[1].x;
p[3].changeY = (1-t)*p[0].y + t * p[1].y;
p[4].changeX = (1-t)*p[1].x + t * p[2].x;
p[4].changeY = (1-t)*p[1].y + t * p[2].y;
p[5].changeX = (1-t)*p[3].x + t * p[4].x;
p[5].changeY = (1-t)*p[3].y + t * p[4].y;
v.push(new cPoint(p[5].x, p[5].y));
if (theta > 2*Math.PI){theta=0;}
theta += 0.01;
t = (Math.sin(theta) + 1) / 2;
}

View File

@@ -0,0 +1,37 @@
let t=0, theta=0;
let t1,t2,t3,t4;
function setup(){
createCanvas(1000, 1000);
}
function draw(){
background(15,26,38);
theta += 0.01;
t = (Math.sin(theta)+1)/2;
t1 = (-t)^3 + 3*t^2 - 3*t + 1;
strokeWeight(5);
textSize(40);
noFill();
stroke(217, 16, 75);
rect(50, 175, 750, 50);
text('1.00', 850, 215);
fill(217, 16, 75);
rect(50, 175, t1*325, 50);
noFill();
stroke(51, 185, 255);
rect(50, 375, 750, 50);
text('1.00', 850, 415);
stroke(16, 255, 171);
rect(50, 575, 750, 50);
text('1.00', 850, 615);
stroke(221, 192, 76);
rect(50, 775, 750, 50);
text('1.00', 850, 815);
}

View File

@@ -0,0 +1,184 @@
<DOCTYPE! html>
<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/p5@1.4.0/lib/p5.min.js"></script>
</head>
<style>
body {
font-family: Arial, sans-serif;
background: #fafafa;
margin: 20px;
text-align: center;
}
#container {
max-width: 900px;
margin: 0 auto;
}
h1,
h2,
p {
margin: 10px 0;
}
</style>
<div id="container">
<h1>Ellipse Construction</h1>
<p>
Inspired by a Richard Feyman's <a href="https://en.wikipedia.org/wiki/Feynman's_Lost_Lecture">lost
lecture</a> & <a href="https://www.youtube.com/watch?v=xdIjYBtnvZU">3blue1brown's video</a>.
</p>
<p>A geometric proof as to why planetary orbits are ellipitcal.</p>
<h2 id="PIbox"></h2>
<h3 id="percentage"></h3>
</div>
<script>
class dot {
constructor(x, y) {
this.x = x;
this.y = y;
}
}
var ux, uy;
var points = [];
var numericValue = 15;
function setup() {
createCanvas(800, 800);
background(41);
}
function draw() {
translate(width / 2, height / 2);
background(41);
stroke(75, 75, 215);
strokeWeight(3);
noFill();
ellipse(0, 0, width - (0.0625 * width), height - (0.0625 * height));
stroke(215, 215, 15);
strokeWeight(7);
point(0, 0);
if (mouseY > 0 && mouseY < height && mouseX > 0 && mouseX < width) {
if (mouseIsPressed == true && mouseButton == LEFT) {
ux = mouseX - width / 2;
uy = mouseY - height / 2;
point(ux, uy);
getCirclePoints();
drawLines(ux, uy);
drawTLines(ux, uy);
} else if (mouseIsPressed == true && mouseButton == RIGHT) {
ux = mouseX - width / 2;
uy = mouseY - height / 2;
point(ux, uy);
getCirclePoints();
drawTLines(ux, uy);
}
}
}
function getCirclePoints() {
var r = (width - (0.0625 * width)) / 2;
var step = 1 / numericValue;
var index = 0;
for (var i = 0; i < TWO_PI; i += step) {
var cx = r * Math.sin(i);
var cy = r * Math.cos(i);
points[index] = new dot(cx, cy);
index++;
}
}
function drawLines(startX, startY) {
strokeWeight(0.4);
stroke(255, 100);
for (var i = 0; i < points.length; i++) {
line(startX, startY, points[i].x, points[i].y);
//findMidpoint(startX, startY, points[i].x, points[i].y);
}
}
function drawTLines(startX, startY) {
strokeWeight(0.4);
stroke(255);
for (var i = 0; i < points.length; i++) {
findMidpoint(startX, startY, points[i].x, points[i].y);
}
}
function findMidpoint(x1, y1, x2, y2) {
//find center
var cx = (x1 + x2) / 2;
var cy = (y1 + y2) / 2;
//move line to the center on the origin
x1 -= cx; y1 -= cy;
x2 -= cx; y2 -= cy;
//rotate both points
xtemp = x1; ytemp = y1;
x1 = -ytemp; y1 = xtemp;
xtemp = x2; ytemp = y2;
x2 = -ytemp; y2 = xtemp;
//move the center point back to where it was
x1 += cx; y1 += cy;
x2 += cx; y2 += cy;
stroke(255, 0, 0);
line(x1, y1, x2, y2);
stroke(255);
}
function genLines() {
var pointOk = false;
do {
ux = random(width);
uy = random(height);
if (getDist(0, ux, 0, uy) <= (width - (0.0625 * width)) / 2) {
pointOk = true;
}
}
while (!pointOk);
point(ux, uy);
getCirclePoints();
drawLines(ux, uy);
drawTLines(ux, uy);
}
function genTLines() {
var pointOk = false;
do {
ux = random(width);
uy = random(height);
if (getDist(0, ux, 0, uy) <= (width - (0.0625 * width)) / 2) {
pointOk = true;
}
}
while (!pointOk);
point(ux, uy);
getCirclePoints();
drawTLines(ux, uy);
}
function getDist(x1, x2, y1, y2) {
return Math.sqrt((x1 - x2) ^ 2 + (y1 - y2) ^ 2);
}
</script>
</html>

122
projects/fourier_series.html Executable file
View File

@@ -0,0 +1,122 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Fourier Series — Epicycles (p5.js)</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<script src="https://cdn.jsdelivr.net/npm/p5@1.4.0/lib/p5.min.js"></script>
<style>
body {
font-family: Arial, sans-serif;
background: #fafafa;
margin: 20px;
text-align: center;
}
#container {
max-width: 900px;
margin: 0 auto;
}
h1,
h2,
p {
margin: 10px 0;
}
input[type="range"] {
display: block;
margin: 10px auto 0;
width: 260px;
}
</style>
</head>
<body>
<div id="container">
<h1>Fourier Series</h1>
<p>
This interactive sketch visualizes a Fourier series using epicycles. Each circle represents
an odd harmonic; as you add more epicycles with the slider, the path on the right converges toward a
square wave. The rotating vectors sum to a point whose vertical position is traced over time.
</p>
<div class="canvas-holder">
</div>
</div>
<script>
class dot {
constructor(x, y) {
this.x = x;
this.y = y;
}
}
class circle {
constructor(cx, cy, r, a) {
this.cx = cx;
this.cy = cy;
this.r = r;
this.a = a;
}
}
let time = 0;
let wave = [];
let slider;
function setup() {
createCanvas(900, 800);
slider = createSlider(1, 50, 5);
}
function draw() {
background(41);
translate(250, height / 2);
let x = 0;
let y = 0;
for (let i = 0; i < slider.value(); i++) {
let prevx = x;
let prevy = y;
let n = i * 2 + 1;
let radius = 100 * (4 / (n * PI));
x += radius * cos(n * time);
y += radius * sin(n * time);
stroke(255, 100);
noFill();
ellipse(prevx, prevy, radius * 2);
//fill(255);
stroke(255);
line(prevx, prevy, x, y);
//ellipse(x, y, 8);
}
wave.unshift(y);
translate(200, 0);
line(x - 200, y, 0, wave[0]);
beginShape();
noFill();
for (let i = 0; i < wave.length; i++) {
vertex(i, wave[i]);
}
endShape();
time += 0.02;
if (wave.length > 450) {
wave.pop();
}
}
</script>
</body>
</html>

112
projects/game_of_life.html Normal file
View File

@@ -0,0 +1,112 @@
<!DOCTYPE html>
<html>
<head>
<link rel="shortcut icon" type"image/ico" href"/Media/iconImage.ico">
<meta name="viewport" width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0>
<style>
body {
padding: 0;
margin: 0;
}
</style>
<script src="https://cdn.jsdelivr.net/npm/p5@1.4.0/lib/p5.min.js"></script>
<title>Game of Life</title>
<script>
function MakeArray(cols, rows) {
let arr = new Array(cols);
for (let i = 0; i < arr.length; i++) {
arr[i] = new Array(rows);
}
return arr;
}
let grid;
let cols;
let rows;
let resolution = 5;
function setup() {
createCanvas(800, 600);
//frameRate(3);
cols = floor(width / resolution);
rows = floor(height / resolution);
grid = MakeArray(cols, rows);
for (let i = 0; i < cols; i++) {
for (let j = 0; j < rows; j++) {
grid[i][j] = floor(random(2));
}
}
}
function draw() {
background(0);
for (let i = 0; i < cols; i++) {
for (let j = 0; j < rows; j++) {
//grid[i][j] = floor(random(2));
let x = i * resolution;
let y = j * resolution;
stroke(0);
if (grid[i][j] == 1) {
fill(255);
} else {
fill(0);
}
rect(x, y, resolution - 0.5, resolution - 0.5);
}
}
let next = MakeArray(cols, rows);
// Compute next based on grid
for (let i = 0; i < cols; i++) {
for (let j = 0; j < rows; j++) {
let state = grid[i][j];
// Count live neighbors!
let sum = 0;
let neighbors = CountNeighbors(grid, i, j);
if (state == 0 && neighbors == 3) {
next[i][j] = 1;
} else if (state == 1 && (neighbors < 2 || neighbors > 3)) {
next[i][j] = 0;
} else {
next[i][j] = state;
}
}
}
grid = next;
}
function CountNeighbors(grid, x, y) {
let sum = 0;
for (let i = -1; i < 2; i++) {
for (let j = -1; j < 2; j++) {
let col = (x + i + cols) % cols;
let row = (y + j + rows) % rows;
sum += grid[col][row];
}
}
sum -= grid[x][y];
return sum;
}
</script>
</head>
<body>
</body>
</html>

173
projects/marching_squares.html Executable file
View File

@@ -0,0 +1,173 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0>
<script src="https://cdn.jsdelivr.net/npm/p5@1.4.0/lib/p5.min.js"></script>
</head>
<script>
var reso = 50;
var cols, rows;
var field = [];
var draw_lines = true;
function setup() {
createCanvas(800, 600);
cols = width / reso + 1;
rows = height / reso + 1;
for (var i = 0; i < cols * rows; i++)
field[i] = Math.floor(random(2));
}
function draw() {
background(100);
const cBlue = color(55, 120, 232);
const cGreen = color(146, 232, 55);
for (var i = 0; i < cols * rows; i++){
let x = i % cols;
let y = Math.floor(i / cols);
let c = field[i] ? cBlue : cGreen;
fill(c);
rect(x*reso - reso*0.5, y*reso - reso*0.5, reso, reso);
}
for (var i = 0; i < cols * rows; i++) {
if (i + cols + 1 > cols * rows){break;}
var x = (i % cols) * reso;
var y = (Math.floor(i / cols)) * reso;
const a = [x + reso * 0.5, y ];
const b = [x + reso, y + reso * 0.5];
const c = [x + reso * 0.5, y + reso ];
const d = [x, y + reso * 0.5];
var s = getState(field[i], field[i+1], field[i+cols+1], field[i+cols]);
noStroke();
switch(s) {
case 1:
fill(cGreen);
triangle(x + reso*0.5, y + reso*0.5, c[0], c[1], d[0], d[1]);
break;
case 14:
fill(cBlue);
triangle(x + reso*0.5, y + reso*0.5, c[0], c[1], d[0], d[1]);
break;
case 2:
fill(cGreen);
triangle(x + reso*0.5, y + reso*0.5, b[0], b[1], c[0], c[1]);
break;
case 13:
fill(cBlue);
triangle(x + reso*0.5, y + reso*0.5, b[0], b[1], c[0], c[1]);
break;
case 3:
fill(cBlue);
rect(d[0], d[1], reso, reso*0.5);
break;
case 12:
fill(cGreen);
rect(d[0], d[1], reso, reso*0.5);
break;
case 4:
fill(cGreen);
triangle(x + reso*0.5, y + reso*0.5, a[0], a[1], b[0], b[1]);
break;
case 11:
fill(cBlue);
triangle(x + reso*0.5, y + reso*0.5, a[0], a[1], b[0], b[1]);
break;
case 5:
fill(cBlue);
triangle(x + reso*0.5, y + reso*0.5, a[0], a[1], d[0], d[1]);
triangle(x + reso*0.5, y + reso*0.5, b[0], b[1], c[0], c[1]);
break;
case 6:
fill(cBlue);
rect(a[0], a[1], reso*0.5, reso);
break;
case 9:
fill(cGreen);
rect(a[0], a[1], reso*0.5, reso);
break;
case 7:
fill(cBlue);
triangle(x + reso*0.5, y + reso*0.5, a[0], a[1], d[0], d[1]);
break;
case 8:
fill(cGreen);
triangle(x + reso*0.5, y + reso*0.5, a[0], a[1], d[0], d[1]);
break;
case 10:
fill(cBlue);
triangle(x + reso*0.5, y + reso*0.5, a[0], a[1], b[0], b[1]);
triangle(x + reso*0.5, y + reso*0.5, c[0], c[1], d[0], d[1]);
break;
default:
break;
};
if (draw_lines) { drawLines(s, a, b, c, d); }
}
}
function getState(a,b,c,d){
return d * 1 + c * 2 + b * 4 + a * 8;
}
function drawLines(s, a, b, c, d){
stroke(232,229,55);
strokeWeight(reso * 0.1);
switch(s) {
case 1: case 14:
line(c[0], c[1], d[0], d[1]);
break;
case 2: case 13:
line(b[0], b[1], c[0], c[1]);
break;
case 3: case 12:
line(b[0], b[1], d[0], d[1]);
break;
case 4: case 11:
line(a[0], a[1], b[0], b[1]);
break;
case 5:
line(a[0], a[1], d[0], d[1]);
line(b[0], b[1], c[0], c[1]);
break;
case 6: case 9:
line(a[0], a[1], c[0], c[1]);
break;
case 7: case 8:
line(a[0], a[1], d[0], d[1]);
break;
case 10:
line(a[0], a[1], b[0], b[1]);
line(c[0], c[1], d[0], d[1]);
break;
default:
break;
};
noStroke();
}
function mousePressed(){
if (mouseButton == LEFT){
var x = Math.floor((mouseX + 0.5*reso) / reso);
var y = Math.floor((mouseY + 0.5*reso) / reso);
var i = Math.floor(y * cols + x);
field[i] = (field[i] + 1) % 2;
} else if (mouseButton == RIGHT){
draw_lines = !draw_lines;
}
}
</script>
</html>

View File

@@ -0,0 +1,62 @@
<html>
<title>Oscilations in 3D</title>
<head>
<link rel="shortcut icon" type"image/ico" href"/Media/iconImage.ico">
<meta name="viewport" width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0>
<script src="https://cdn.jsdelivr.net/npm/p5@1.4.0/lib/p5.min.js"></script>
</head>
<script>
let angle = 0;
let w = 30; //amount of boxes
let ma;
let maxD
function setup() {
createCanvas(600, 600, WEBGL);
frameRate(24);
ma = atan(1 / sqrt(2)); //max angle
maxD = dist(0, 0, 200, 200); //max distance
}
function draw() {
background(100);
ortho(-400, 400, -400, 400, 0, 1000); //to set up ortho projection
directionalLight(255, 255, 255, 0, -1, 0);
rotateX(-QUARTER_PI);
rotateY(ma);
let offset = 0;
for (let z = 0; z < height; z += w) {
for (let x = 0; x < width; x += w) {
push()
let d = dist(x, z, width / 2, height / 2)
offset = map(d, 0, maxD, -PI, PI);
let a = angle + offset;
let h = floor(map(sin(a), -1, 1, 100, 350));
normalMaterial();
translate(x - width / 2, 0, z - width / 2);
box(w, h, w);
pop()
}
}
angle -= 0.1;
}
function mousePressed() {
if (w == 20) {
w = 25;
} else if (w == 25) {
w = 30;
} else {
w = 20;
}
redraw();
}
</script>
<style>
@import url('https://fonts.googleapis.com/css?family=Black+Han+Sans');
</style>
<p style="font-family: 'Black Han Sans', sans-serif;">Click me to change the number of boxes</p>
</html>

View File

@@ -0,0 +1,104 @@
<!DOCTYPE html>
<html>
<script src="https://cdn.jsdelivr.net/npm/p5@1.4.0/lib/p5.min.js"></script>
<h1 id="PIbox"></h1>
<h2 id="percentage"></h2>
<style>
body {
font-family: Arial, sans-serif;
background: #fafafa;
margin: 20px;
text-align: center;
}
#container {
max-width: 900px;
margin: 0 auto;
}
h1,
h2,
p {
margin: 10px 0;
}
</style>
<div id="container">
<h1>Monte Carlo π Estimator</h1>
<p>
A small demonstation on how the Monte Carlo method can approximate the value of π
by randomly placing points inside a square and checking how many fall within
the inner circle. The closer the ratio gets to π/4, the more accurate
the estimation becomes.
</p>
<h2 id="PIbox"></h2>
<h3 id="percentage"></h3>
</div>
<script>
const r = 400;
var circleCount, total;
var x, y;
var calcPI;
var DisplayPI = "a";
const PI = 3.1415926535;
var BestPI = 50;
function setup() {
createCanvas(r * 2, r * 2);
background(0);
stroke(255, 0, 0);
strokeWeight(3);
noFill()
translate(width / 2, height / 2);
rectMode(CENTER);
rect(0, 0, r * 2, r * 2);
ellipse(0, 0, r * 2, r * 2);
circleCount = 0;
total = 0;
}
function draw() {
translate(width / 2, height / 2);
x = random(-r, r)
y = random(-r, r)
stroke(0, 255, 0)
total += 1
var d = dist(x, y, 0, 0)
if (d < r) {
circleCount += 1
stroke(0, 0, 255)
}
point(x, y);
calcPI = 4 * (circleCount / total);
if (abs(PI - calcPI) < abs(PI - BestPI)) {
DisplayPI = calcPI;
BestPI = calcPI;
var PIDisplay = document.getElementById("PIbox");
PIDisplay.innerHTML = DisplayPI;
var ErrorDisplay = document.getElementById("percentage");
var DisplayError = "a";
var Perror = (calcPI - PI) / PI
Perror *= 100;
DisplayError = nfc(Perror, 10);
ErrorDisplay.innerHTML = DisplayError + '%';
}
}
</script>
</html>

110
projects/poissonDist.php Normal file
View File

@@ -0,0 +1,110 @@
<?php
if($_SERVER['HTTP_X_FORWARDED_PROTO'] !== 'https') {
header('Location: https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
die();
}
?>
<DOCTYPE! html>
<html>
<script src="https://cdn.jsdelivr.net/npm/p5@1.4.0/lib/p5.min.js"></script>
<script>
var r = 10; //circle size
var k = 30;
var grid = [];
var w = r / Math.sqrt(2);
var active = [];
var cols, rows;
var ordered = [];
function setup() {
createCanvas(900, 900);
background(0);
strokeWeight(4);
colorMode(HSB);
cols = floor(width / w);
rows = floor(height / w);
for (var i = 0; i < cols * rows; i++) {
grid[i] = undefined;
}
var x = width / 2;
var y = height / 2;
var i = floor(x / w);
var j = floor(y / w);
var pos = createVector(x, y);
grid[i + j * cols] = pos;
active.push(pos);
}
function draw() {
background(0);
for (var total = 0; total < 30; total++) {
if (active.length > 0) {
var randIndex = floor(random(active.length));
var pos = active[randIndex];
var found = false;
for (var n = 0; n < k; n++) {
var sample = p5.Vector.random2D();
var m = random(r, 2 * r);
sample.setMag(m);
sample.add(pos);
var col = floor(sample.x / w);
var row = floor(sample.y / w);
if (col > -1 && row > -1 && col < cols && row < rows && !grid[col + row * cols]) {
var flag = true;
for (var i = -1; i <= 1; i++) {
for (var j = -1; j <= 1; j++) {
var index = (col + i) + (row + j) * cols;
var neighbor = grid[index];
if (neighbor) {
var d = p5.Vector.dist(sample, neighbor);
if (d < r) {
flag = false;
}
}
}
}
if (flag) {
found = true;
grid[col + row * cols] = sample;
active.push(sample);
ordered.push(sample);
//break;
}
}
}
if (!found) {
active.splice(randIndex, 1);
}
}
}
for (var i = 0; i < ordered.length; i++) {
stroke(255, 0, 255);
strokeWeight(r * 0.5);
point(ordered[i].x, ordered[i].y);
}
for (var i = 0; i < active.length; i++) {
if (ordered[i]) {
stroke(i % 360, 100, 100);
strokeWeight(r * 0.5);
point(active[i].x, active[i].y);
}
}
}
</script>
</html>

69
projects/sorting_vis.html Executable file
View File

@@ -0,0 +1,69 @@
<!DOCTYPE html>
<html>
<script src="https://cdn.jsdelivr.net/npm/p5@1.4.0/lib/p5.min.js"></script>
<script>
var values = [];
let i = 0;
let j = 0;
function setup() {
createCanvas(windowWidth -20, windowHeight-20);
stroke(255);
background(0);
for (let i = 0; i < width; i++) {
values[i] = random(height);
line(i, height, i, height - values[i]);
}
}
function draw() {
stroke(243);
background(21);
for (let i = 0; i < width; i++) {
line(i, height, i, height - values[i]);
}
for (let n = 0; n < 50; n++) {
if (values[j] > values[j + 1]) {
tmp = values[j]
values[j] = values[j + 1];
values[j + 1] = tmp;
}
if (i < values.length) {
j += 1;
if (j >= values.length) {
j = 0;
i += 1;
}
} else {
stroke(0, 255, 0);
for (let i = 0; i < width; i++) {
line(i, height, i, height - values[i]);
}
noLoop();
}
}
}
function bSort() {
let tmp;
for (let i = 0; i < values.length; i++) {
for (let j = 0; j < values.length - i - 1; j++) {
if (values[j] > values[j + 1]) {
tmp = values[j]
values[j] = values[j + 1];
values[j + 1] = tmp;
}
}
}
}
</script>
</html>

133
projects/warp_lines.html Executable file
View File

@@ -0,0 +1,133 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0>
<script src="https://cdn.jsdelivr.net/npm/p5@1.4.0/lib/p5.min.js"></script>
<style>
body {
padding: 0;
margin: 0;
}
.slidecontainer {
width: 100%;
/* Width of the outside container */
}
/* The slider itself */
.slider {
-webkit-appearance: none;
/* Override default CSS styles */
appearance: none;
width: 100%;
/* Full-width */
height: 25px;
/* Specified height */
background: #d3d3d3;
/* Grey background */
outline: none;
/* Remove outline */
opacity: 1;
/* Set transparency (for mouse-over effects on hover) */
-webkit-transition: .2s;
/* 0.2 seconds transition on hover */
transition: opacity .2s;
}
.slider::-webkit-slider-thumb {
-webkit-appearance: none;
/* Override default look */
appearance: none;
width: 25px;
/* Set a specific slider handle width */
height: 25px;
/* Slider handle height */
background: #434343;
/* Grey background */
cursor: pointer;
/* Cursor on hover */
}
.slider::-moz-range-thumb {
width: 25px;
/* Set a specific slider handle width */
height: 25px;
/* Slider handle height */
background: #434343;
/* Grey background */
cursor: pointer;
/* Cursor on hover */
}
</style>
</head>
<div class="slidecontainer">
<input type="range" min="2" max="11" step="1" value="2" class="slider" id="myRange">
</div>
<script>
let vMargin, hMargin, arrowHeight, t, lineNum;
let lineMove = true;
function setup() {
createCanvas(windowWidth, windowHeight * 0.6);
hMargin = 12;
arrowHeight = 25;
t = 0;
lineNum = 1;
}
function windowResized() {
resizeCanvas(windowWidth, windowHeight * 0.6);
}
function draw() {
background(43);
angleMode(DEGREES);
lineNum = document.getElementById('myRange').value;
drawLine(hMargin, lineNum + 1);
if (lineMove) {
t++;
}
if (t == 360) {
t = 0;
}
}
function drawLine(hm, vm) {
//let changex = map(sin(t), -1, 1, -22, 22);
let changex = sin(t) * 18;
vm /= 10;
for (let j = 1; j < vm - 1; j++) {
stroke(255, 34, 63);
strokeWeight(4);
line(width / hm, j * height / vm, width / 2, j * height / vm); //red line
stroke(69, 98, 255);
line(width / 2, j * height / vm, (hm - 1) * width / hm, j * height / vm); //blue line
stroke(255);
line(width / hm, j * height / vm, width / hm + changex, (j * height / vm) - arrowHeight); //left top
line(width / hm + changex, (j * height / vm) + arrowHeight, width / hm, j * height / vm); //left bottom
line((hm - 1) * width / hm + changex, j * height / vm + arrowHeight, (hm - 1) * width / hm, j * height / vm); //right bottom
line(width / 2 - changex, j * height / vm + arrowHeight, width / 2, j * height / vm); //center bottom
line((hm - 1) * width / hm, j * height / vm, (hm - 1) * width / hm + changex, (j * height / vm) - arrowHeight); //right bottom
line(width / 2, j * height / vm, width / 2 - changex, (j * height / vm) - arrowHeight); //center top
}
}
function mouseClicked() {
lineMove = !lineMove;
}
</script>
</html>