Move flow-fields code here
This commit is contained in:
parent
df621db3a2
commit
ef2f98ce53
15
README.md
15
README.md
@ -11,3 +11,18 @@ Or build with:
|
|||||||
```
|
```
|
||||||
$ pnpm run build
|
$ pnpm run build
|
||||||
```
|
```
|
||||||
|
|
||||||
|
# Individual Projects
|
||||||
|
|
||||||
|
## Flow Fields
|
||||||
|
|
||||||
|
Inspired by https://youtu.be/M_SUcX66SDA Low Byte Productions Flow Fields video
|
||||||
|
|
||||||
|
Uses code from:
|
||||||
|
* https://github.com/francisrstokes/vec-la-fp/tree/master
|
||||||
|
* https://github.com/francisrstokes/microcan
|
||||||
|
|
||||||
|
|
||||||
|
## Konva-ball
|
||||||
|
|
||||||
|
Experimenting with konva library
|
||||||
|
13
src/flow-fields/index.html
Normal file
13
src/flow-fields/index.html
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Flow Fields</title>
|
||||||
|
<script type="module" src="index.js"></script>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<canvas id="main"></canvas>
|
||||||
|
</body>
|
||||||
|
</html>
|
104
src/flow-fields/index.js
Normal file
104
src/flow-fields/index.js
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
// Inspired by https://youtu.be/M_SUcX66SDA Low Byte Productions Flow Fields video
|
||||||
|
|
||||||
|
import { vScale, vAdd, vAngle } from "./util.js";
|
||||||
|
|
||||||
|
//const vAngle = (a) => [Math.cos(a), Math.sin(a)];
|
||||||
|
|
||||||
|
const canvas = document.getElementById("main");
|
||||||
|
const ctx = canvas.getContext("2d");
|
||||||
|
|
||||||
|
const width = 800;
|
||||||
|
const height = 800;
|
||||||
|
|
||||||
|
// A 10x10 grid, transformed onto the canvas
|
||||||
|
const n = 25;
|
||||||
|
const fieldSize = width/n;
|
||||||
|
|
||||||
|
canvas.setAttribute("width", width);
|
||||||
|
canvas.setAttribute("height", height);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const fill = (ctx, r = 0, g = 0, b = 0, a = 255) => {
|
||||||
|
ctx.fillStyle = `rgba(${r}, ${g}, ${b}, ${a})`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const stroke = (ctx, r = 0, g = 0, b = 0, a = 255) => {
|
||||||
|
ctx.strokeStyle = `rgba(${r}, ${g}, ${b}, ${a})`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const line = (ctx, v, v2) => {
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(...v);
|
||||||
|
ctx.lineTo(...v2);
|
||||||
|
ctx.stroke();
|
||||||
|
ctx.closePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
const ellipse = (ctx, v, rx, ry = rx, oa = 0, sa = 0, ea = Math.PI * 2) => {
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.ellipse(...v, rx, ry, oa, sa, ea, false);
|
||||||
|
ctx.stroke();
|
||||||
|
ctx.fill();
|
||||||
|
ctx.closePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
const background = (ctx, r = 0, g = 0, b = 0, a = 255) => {
|
||||||
|
fill(ctx, r, g, b, a);
|
||||||
|
ctx.fillRect(0, 0, width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
fill(ctx, 0,0,0,0);
|
||||||
|
stroke(ctx, 255,255,255,1);
|
||||||
|
background(ctx, 0, 0, 255, width, height);
|
||||||
|
|
||||||
|
const vRandom = () => vAngle(Math.random() * Math.PI * 2);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
for (let y = 0; y < n; y++) {
|
||||||
|
for (let x = 0; x < n; x++) {
|
||||||
|
const sv = vAdd([fieldSize/2, fieldSize/2], vScale(fieldSize, [x, y]));
|
||||||
|
ellipse(ctx, sv, fieldSize/2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
let prevTimestamp;
|
||||||
|
|
||||||
|
const draw = (timestamp) => {
|
||||||
|
|
||||||
|
if (prevTimestamp === undefined) {
|
||||||
|
prevTimestamp = timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
const elapsed = timestamp - prevTimestamp;
|
||||||
|
|
||||||
|
if (elapsed > 500) {
|
||||||
|
prevTimestamp = timestamp;
|
||||||
|
|
||||||
|
const field = Array.from({length: n}, () => Array.from({length: n}, () => {
|
||||||
|
return vRandom();
|
||||||
|
}));
|
||||||
|
|
||||||
|
fill(ctx, 0,0,0,0);
|
||||||
|
stroke(ctx, 255,255,255,1);
|
||||||
|
background(ctx, 0, 0, 255, width, height);
|
||||||
|
|
||||||
|
field.forEach((row, y) => row.forEach((fv, x) => {
|
||||||
|
const sv = vAdd([fieldSize/2, fieldSize/2], vScale(fieldSize, [x, y]));
|
||||||
|
const upper = vAdd(sv, vScale(fieldSize/2, fv));
|
||||||
|
const lower = vAdd(sv, vScale(-fieldSize/2, fv));
|
||||||
|
line(ctx, upper, lower);
|
||||||
|
fill(ctx, 255,255,255,1);
|
||||||
|
ellipse(ctx, upper, 2);
|
||||||
|
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
window.requestAnimationFrame(draw);
|
||||||
|
};
|
||||||
|
|
||||||
|
draw();
|
8
src/flow-fields/util.js
Normal file
8
src/flow-fields/util.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
const vScale = (scale, vec) => vec.map(n => n * scale);
|
||||||
|
|
||||||
|
const vAdd = (v0, v1) => [v0[0] + v1[0], v0[1] + v1[1]];
|
||||||
|
|
||||||
|
const vAngle = (a) => [Math.cos(a), Math.sin(a)];
|
||||||
|
|
||||||
|
export { vAdd, vScale, vAngle };
|
@ -8,6 +8,7 @@
|
|||||||
<h1>Spazer</h1>
|
<h1>Spazer</h1>
|
||||||
<ul>
|
<ul>
|
||||||
<li> <a href="./konva-ball/index.html">Konva-ball</a>
|
<li> <a href="./konva-ball/index.html">Konva-ball</a>
|
||||||
|
<li> <a href="./flow-fields/index.html">Flow-fields</a>
|
||||||
</ul>
|
</ul>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
Loading…
Reference in New Issue
Block a user