From a2eae95e5bcfe4b9eb88de73e15856e058999f8d Mon Sep 17 00:00:00 2001 From: "F.W. Dekker" Date: Sun, 31 Oct 2021 15:12:56 +0100 Subject: [PATCH] Separate model from view --- src/main/js/Main.ts | 181 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 139 insertions(+), 42 deletions(-) diff --git a/src/main/js/Main.ts b/src/main/js/Main.ts index 46c46bb..5cc5b0d 100644 --- a/src/main/js/Main.ts +++ b/src/main/js/Main.ts @@ -2,61 +2,158 @@ 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(() => { - $("main").classList.remove("hidden"); - - // State - const startTime = Math.floor(Date.now() / 100); - let lastDrawTime = 0; - const linePartAngles: number[] = []; - - // Draw const canvas = $("#art"); const ctx = canvas.getContext("2d"); - const draw = () => { - ctx.fillStyle = "#000000"; - ctx.fillRect(0, 0, canvas.width, canvas.height); - const center = [canvas.width / 2, canvas.height / 2]; + // 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); - // Center dot - ctx.beginPath(); - ctx.fillStyle = "#ffffff"; - ctx.arc(center[0] - 5, center[1] - 5, 10, 0, 2 * Math.PI); - ctx.fill(); - - // Lines - ctx.beginPath(); - ctx.strokeStyle = "#ffffff"; - ctx.moveTo(center[0], center[1]); - let lastPos = [center[0], center[1]]; - let totalAngle = 0; - for (const linePartAngle of linePartAngles) { - totalAngle += linePartAngle; - lastPos = [lastPos[0] + Math.cos(totalAngle) * 25, lastPos[1] + Math.sin(totalAngle) * 25]; - ctx.lineTo(lastPos[0], lastPos[1]); - } - ctx.stroke(); - - const secondsSinceStart = Math.floor(Date.now() / 100) - startTime; - if (secondsSinceStart > lastDrawTime) { - lastDrawTime = secondsSinceStart; - linePartAngles.push((random_normal() - 0.5) * Math.PI * 2); - } - - window.requestAnimationFrame(draw); - }; - window.requestAnimationFrame(draw); - - // Listen to resize + // 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;