moving Python POC to JS

This commit is contained in:
James Turk 2024-07-06 14:17:10 -05:00
commit fc12f05e3a
8 changed files with 310 additions and 0 deletions

51
artworld/color.js Normal file
View File

@ -0,0 +1,51 @@
export class Color {
static defaultColorMode = "hsl";
constructor(p1, p2, p3, alpha = 1, mode = null) {
this.mode = mode || Color.defaultColorMode;
this.p1 = p1;
this.p2 = p2;
this.p3 = p3;
this.alpha = alpha;
}
toStr() {
return `${this.mode}(${this.p1} ${this.p2} ${this.p3} / ${this.alpha})`;
}
adjustHue(delta) {
this.p1 += delta;
}
adjustSat(delta) {
this.p2 += delta;
}
adjustLum(delta) {
this.p3 += delta;
}
adjustAlpha(delta) {
this.alpha += alpha;
}
}
// Palette Source: https://pico-8.fandom.com/wiki/Palette
export const Pico8 = {
BLACK: "rgb(0, 0, 0)",
DARK_BLUE: "rgb(29, 43, 83)",
PURPLE: "rgb(126, 37, 83)",
DARK_GREEN: "rgb(0, 135, 81)",
BROWN: "rgb(171, 82, 54)",
DARK_GREY: "rgb(95, 87, 79)",
LIGHT_GREY: "rgb(194, 195, 199)",
WHITE: "rgb(255, 241, 232)",
RED: "rgb(255, 0, 77)",
ORANGE: "rgb(255, 163, 0)",
YELLOW: "rgb(255, 236, 39)",
GREEN: "rgb(0, 228, 54)",
BLUE: "rgb(41, 173, 255)",
LAVENDER: "rgb(131, 118, 156)",
PINK: "rgb(255, 119, 168)",
LIGHT_PEACH: "rgb(255, 204, 170)",
};

101
artworld/drawable.js Normal file
View File

@ -0,0 +1,101 @@
import { Vector2 } from "./math.js";
import { artworld } from "./world.js";
export class Drawable {
constructor(parent) {
this._parent = parent;
this._updates = [];
this._fill = parent ? parent._fill : null;
this._stroke = parent ? parent._stroke : null;
this._strokeWeight = parent ? parent._strokeWeight : null;
this._z_index = parent ? parent._z_index : null;
this._posVec = new Vector2(0, 0);
this._register();
}
_register() {
if (this._parent) {
this._parent.push(this);
}
artworld.register(this);
}
copy() {
let obj = Object.assign({}, this);
obj._register();
return obj;
}
fill(color) {
this._fill = color;
return this;
}
stroke(color) {
this._stroke = color;
return this;
}
strokeWeight(scalar) {
this._strokeWeight = scalar;
return this;
}
pos(vec) {
this._posVec = vec;
return this;
}
x(scalar) {
this._posVec.x = scalar;
return this;
}
y(scalar) {
this._posVec.y = scalar;
return this;
}
z(scalar) {
this._z_index = scalar;
return this;
}
// Modifiers ///////////////////////////
move(byVec) {
this._posVec = this._posVec.add(byVec);
}
// TODO random()
// TODO draw() abstract
// getters /////////////////////////////
get worldPos() {
return this._parent ? this._parent.worldPos.add(this._pos) : this._pos;
}
}
export class Group extends Drawable {
constructor() {
super();
this._children = [];
}
copy() {
let newobj = super.copy();
for (let child of this._children) {
let ccopy = Object.assign({}, child);
ccopy._parent = newobj;
ccopy._register();
}
return newobj;
}
add(drawable) {
this._children.push(drawable);
drawable._parent = this;
return this;
}
}

4
artworld/index.js Normal file
View File

@ -0,0 +1,4 @@
export { artworld } from "./world.js";
export { Color } from "./color.js";
export { Vector2 } from "./math.js";
export { Line } from "./shapes.js";

37
artworld/math.js Normal file
View File

@ -0,0 +1,37 @@
export const TO_RADIANS = 180 / Math.PI;
export class Vector2 {
constructor(x, y) {
this.x = x;
this.y = y;
}
add(other) {
return Vector2(this.x + other.x, this.y + other.y);
}
sub(other) {
return Vector2(this.x - other.x, this.y - other.y);
}
scale(s) {
return Vector2(s * this.x, s * this.y);
}
static random(x, y) {
let theta = random() * 2 * Math.PI;
// if neither specified, use (1, 1)
if (x === undefined) {
x = 1;
}
// if only x specified, use (x, x)
if (y === undefined) {
y = x;
}
return Vector2(x * cos(theta), y * sin(theta));
}
static polar(mag, angle) {
return Vector2(mag * Math.cos(angle), mag * Math.sin(angle));
}
}

17
artworld/rect.js Normal file
View File

@ -0,0 +1,17 @@
class Rectangle {
constructor(x, y, width, height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
contains(x, y) {
return (
x > this.x &&
x < this.x + this.width &&
y > this.y &&
y < this.y + this.height
);
}
}

29
artworld/shapes.js Normal file
View File

@ -0,0 +1,29 @@
import { Vector2 } from "./math.js";
import { Drawable } from "./drawable.js";
export class Line extends Drawable {
constructor(parent) {
super(parent);
this._offsetVec = new Vector2(10, 0);
}
draw() {
artworld.setStrokeColor(this._stroke);
artworld.setStrokeWeight(this._strokeWeight);
artworld.drawLine(this._posVec, this._offsetVec);
}
to(vec) {
this._offsetVec = vec;
return this;
}
polar(mag, angle) {
return this.to(Vector2.polar(mag, angle));
}
angle(angle) {
let mag = this._offsetVec.magnitude;
return this.to(Vector2.polar(mag, angle));
}
}

52
artworld/world.js Normal file
View File

@ -0,0 +1,52 @@
export class World {
constructor() {
this.drawables = [];
this.ctx = null;
}
bindCanvas(id) {
this.ctx = document.getElementById(id).getContext("2d");
}
register(drawable) {
this.drawables.push(drawable);
}
draw() {
for (let d of this.drawables) {
d.draw();
}
}
// Canvas 2D /////////////////
setStrokeWeight(scalar) {
this.ctx.lineWidth = scalar;
}
setStrokeColor(color) {
this.ctx.strokeStyle = color.toStr();
}
setFillColor(color) {
this.ctx.fillStyle = color.toStr();
}
fillRect(rect) {
this.ctx.fillRect(rect.x, rect.y, rect.width, rect.height);
}
strokeRect(rect) {
this.ctx.fillRect(rect.x, rect.y, rect.width, rect.height);
}
drawLine(from, to) {
this.ctx.beginPath();
this.ctx.moveTo(from.x, from.y);
this.ctx.lineTo(to.x, to.y);
this.ctx.stroke();
}
}
// singleton (for now)
export const artworld = new World();

19
examples/lines.html Normal file
View File

@ -0,0 +1,19 @@
<html>
<head> </head>
<body>
<canvas id="mainCanvas" width="800" height="800"></canvas>
<script type="module">
import { artworld, Color, Line, Vector2 } from "../artworld/index.js";
artworld.bindCanvas("mainCanvas");
window.artworld = artworld;
for (let i = 0; i < 10; i++) {
new Line()
.pos(new Vector2(5 * i * 14, 5))
.to(new Vector2(5 * i * 14, 140))
.stroke(new Color(20 * i, 50, 50))
.strokeWeight(1 + i);
}
artworld.draw();
</script>
</body>
</html>