dataclock, another take on the clock with Var() instead of animate() to keep w/ declarative mode

This commit is contained in:
James Turk 2025-03-09 20:52:32 -05:00
parent d42774ad1f
commit c44252a14c
5 changed files with 118 additions and 13 deletions

View File

@ -4,3 +4,4 @@ export { Vector2, degToRad, radToDeg } from "./math.js";
export { Line, Rect, Circle, Arc, Polygon } from "./shapes.js";
export { Group } from "./drawable.js";
export { Random } from "./random.js";
export { Var } from "./variables.js";

View File

@ -1,6 +1,7 @@
import { Vector2 } from "./math.js";
import { Drawable } from "./drawable.js";
import { Random } from "./random.js";
import { getVal } from "./variables.js";
function makeCopy(Cls, obj, override) {
// make new object, will be registered with world, but no _parent yet
@ -32,7 +33,10 @@ export class Line extends Drawable {
draw() {
artworld.prepareDraw(this);
artworld.drawLine(this.worldPos, this.worldPos.add(this._offsetVec));
artworld.drawLine(
this.worldPos,
this.worldPos.add(getVal(this._offsetVec)),
);
}
to(vec) {

32
artworld/variables.js Normal file
View File

@ -0,0 +1,32 @@
import { artworld } from "./world.js";
export function getVal(x) {
return x && x.getValue ? x.getValue() : x;
}
export class Var {
constructor(value) {
if (typeof value === "function") {
this._updateFunc = value;
this._value = this._updateFunc(0);
} else {
this._value = value;
this._updateFunc = null;
}
artworld.register(this);
}
updateFunc(func) {
this._updateFunc = func;
}
update(t) {
if (this._updateFunc) {
this._value = this._updateFunc(t);
}
}
getValue() {
return this._value;
}
}

View File

@ -1,9 +1,11 @@
import { Timer } from "./timer.js";
import { getVal, Var } from "./variables.js";
export class World {
constructor() {
this.ctx = null;
this.drawables = [];
this.variables = [];
this.backgroundColor = "white";
this.timer = new Timer();
this.targetFrameRate = 60;
@ -25,8 +27,13 @@ export class World {
}
// TODO rename
register(drawable) {
this.drawables.push(drawable);
register(thing) {
if (thing instanceof Var) {
this.variables.push(thing);
} else {
// TODO: check drawable?
this.drawables.push(thing);
}
}
draw() {
@ -44,6 +51,9 @@ export class World {
for (let d of this.drawables) {
d.update(this.numTicks);
}
for (let v of this.variables) {
v.update(this.numTicks);
}
}
get updatesPerSecond() {
@ -67,21 +77,21 @@ export class World {
prepareDraw(drawable) {
this._stroke = false;
this._fill = false;
if (drawable._stroke) {
this.ctx.lineWidth = drawable._strokeWeight;
this.ctx.strokeStyle = drawable._stroke.toStr
? drawable._stroke.toStr()
: drawable._stroke;
let stroke = getVal(drawable._stroke);
let fill = getVal(drawable._fill);
if (stroke) {
this.ctx.lineWidth = getVal(drawable._strokeWeight);
this.ctx.strokeStyle = stroke.toStr ? stroke.toStr() : stroke;
this._stroke = true;
} else if (drawable._fill) {
this.ctx.fillStyle = drawable._fill.toStr
? drawable._fill.toStr()
: drawable._fill;
} else if (fill) {
this.ctx.fillStyle = fill.toStr ? fill.toStr() : fill;
this._fill = true;
}
}
drawLine(from, to) {
from = getVal(from);
to = getVal(to);
this.ctx.beginPath();
this.ctx.moveTo(from.x, from.y);
this.ctx.lineTo(to.x, to.y);
@ -89,13 +99,23 @@ export class World {
}
drawArc(center, radius, fromAngle, toAngle) {
center = getVal(center);
this.ctx.beginPath();
this.ctx.arc(center.x, center.y, radius, fromAngle, toAngle);
this.ctx.arc(
center.x,
center.y,
getVal(radius),
getVal(fromAngle),
getVal(toAngle),
);
if (this._stroke) this.ctx.stroke();
if (this._fill) this.ctx.fill();
}
drawRect(center, width, height) {
center = getVal(center);
width = getVal(width);
height = getVal(height);
this.ctx.beginPath();
this.ctx.rect(center.x - width / 2, center.y - height / 2, width, height);
if (this._stroke) this.ctx.stroke();
@ -103,6 +123,7 @@ export class World {
}
drawPolygon(center, points) {
center = getVal(center);
this.ctx.beginPath();
this.ctx.moveTo(center.x + points[0].x, center.y + points[0].y);
for (let i = 1; i < points.length; i++) {

47
examples/dataclock.html Normal file
View File

@ -0,0 +1,47 @@
<html>
<head> </head>
<body>
<canvas id="mainCanvas" width="500" height="500"></canvas>
<script type="module">
import {
artworld,
Color,
Pico8,
Group,
Rect,
Random,
Vector2,
Line,
Circle,
Var,
degToRad,
} from "../artworld/index.js";
artworld.bindCanvas("mainCanvas");
window.artworld = artworld;
// declare some time-fluctuation variables
let color = new Var(
(t) =>
[Pico8.RED, Pico8.ORANGE, Pico8.GREEN, Pico8.BLUE][
Math.floor(t / 60) % 4
],
);
let outerR = new Var((t) => Math.sin(t / 100) * 50 + 200);
// simple dependency
let innerR = new Var(() => outerR.getValue() - 10);
// example of a more complex Var that uses other vars
let lineTo = new Var((t) => {
let angle = (t / 6000) * Math.PI * 2;
return Vector2.polar(innerR.getValue(), angle);
});
let g = new Group().pos(new Vector2(250, 250));
new Circle(g).fill(Pico8.BLACK).z(1).radius(outerR);
new Circle(g).z(10).fill(color).radius(innerR);
new Circle(g).radius(20).fill(Pico8.BLACK).z(50);
new Line(g).to(lineTo).z(100);
artworld.loopStep();
</script>
</body>
</html>