// @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(); }