psychotherapy/src/main/js/Main.ts

168 lines
4.1 KiB
TypeScript

// @ts-ignore
const {$, doAfterLoad} = window.fwdekker;
/**
* A two-dimensional point.
*/
class Point {
x: number;
y: number;
/**
* Constructs a new `Point`.
*
* @param x the X coordinate of the `Point`
* @param y the Y coordinate of the `Point`
*/
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
/**
* Returns `true` if and only if this `Point` is exactly the same as `other`.
*
* @param other the `Point` to check equality against
* @return `true` if and only if this `Point` is exactly the same as `other`
*/
equals(other: Point): boolean {
return this.x === other.x && this.y === other.y;
}
}
/**
* A segment that is part of a [Line].
*/
class LineSegment {
x: number;
y: number;
/**
* Constructs a new [LineSegment].
*
* @param x the relative horizontal translation of this `LineSegment`
* @param y the relative vertical translation of this `LineSegment`
*/
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
/**
* Returns `true` if and only if this `LineSegment` is exactly the same as `other`.
*
* @param other the `LineSegment` to check equality against
* @return `true` if and only if this `LineSegment` is exactly the same as `other`
*/
equals(other: LineSegment): boolean {
return this.x === other.x && this.y === other.y;
}
}
/**
* A line that is made up of [LineSegment]s.
*/
class Line {
segments: LineSegment[];
thickness: number;
/**
* Constructs a new `Line`.
*
* @param thickness the relative thickness of the line
*/
constructor(thickness: number) {
this.segments = [];
this.thickness = thickness;
}
/**
* Returns `true` if and only if this `Line` is exactly the same as `other`.
*
* @param other the `Line` to check equality against
* @return `true` if and only if this `Line` is exactly the same as `other`
*/
equals(other: Line): boolean {
return this.segments.every((_, i) => this.segments[i].equals(other.segments[i]))
&& this.thickness === other.thickness;
}
}
doAfterLoad(() => $("main").classList.remove("hidden"));
doAfterLoad(() => {
const canvas = $("#art");
const ctx = canvas.getContext("2d");
// State
const lines: Line[] = [];
lines.push(new Line(10));
setInterval(() => {
const angle = (random_normal() - 0.5) * Math.PI * 2;
lines[0].segments.push(new LineSegment(Math.cos(angle) * 25, Math.sin(angle) * 25));
}, 1000);
// Resize
const resize = () => {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
};
window.addEventListener("resize", resize, false);
resize();
// Draw
const draw = () => {
const center = new Point(canvas.width / 2, canvas.height / 2);
// Background
ctx.fillStyle = "#000000";
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Center dot
ctx.beginPath();
ctx.fillStyle = "#ffffff";
ctx.arc(center.x - 5, center.y - 5, 10, 0, 2 * Math.PI);
ctx.fill();
// Lines
ctx.strokeStyle = "#ffffff";
for (const line of lines) {
ctx.beginPath();
ctx.moveTo(center.x, center.y);
let lastPos = new Point(center.x, center.y);
for (const segment of line.segments) {
lastPos = new Point(lastPos.x + segment.x, lastPos.y + segment.y);
ctx.lineTo(lastPos.x, lastPos.y);
}
ctx.stroke();
}
window.requestAnimationFrame(draw);
};
window.requestAnimationFrame(draw);
});
// Taken from https://stackoverflow.com/a/49434653/
function random_normal(): number {
let u = 0;
while (u === 0) u = Math.random();
let v = 0;
while (v === 0) v = Math.random();
const num = Math.sqrt(-2.0 * Math.log(u)) * Math.cos(2.0 * Math.PI * v) / 10.0 + 0.5;
if (num >= 0 && num < 1) return num;
return random_normal();
}