From dfbe9e34ed5c9b47dd5ad1445fcc4e33e975a0db Mon Sep 17 00:00:00 2001 From: Ladd Hoffman Date: Sat, 22 Jun 2024 15:01:10 -0500 Subject: [PATCH] markdown drawings! --- draw.js | 63 ++++++++++++++++++++++++++--- reveal-override.css | 3 ++ reveal.html | 35 +---------------- test.html | 2 +- test.md | 96 ++++++++++++++++++++++++++++++++++++++++++--- 5 files changed, 153 insertions(+), 46 deletions(-) create mode 100644 reveal-override.css diff --git a/draw.js b/draw.js index 0ecc2e0..a9286ab 100644 --- a/draw.js +++ b/draw.js @@ -23,6 +23,7 @@ class Drawing { this.rt = 0; this.dt = 0; this.points = {}; + this.values = {}; this.stopped = true; this.frame = [[-10, -10], [110, 110]]; this.frameMargin = 10; @@ -180,6 +181,20 @@ class Drawing { return p; } } + + defineValue(name, fn) { + this.values[name] = fn; + } + + getValue(name) { + const fn = this.values[name]; + if (!fn) { + const e = new Error; + e.message = `Value '${name}' is not defined`; + throw e; + } + return fn(); + } line(p1, p2) { this.sequence.push(() => { @@ -280,7 +295,6 @@ class Drawing { } func(opts, fn) { - const origin = opts?.origin ?? [0, 0]; const domain = opts?.domain ?? [this.frame[0][0], this.frame[1][0]]; const step = opts?.step ?? 1; this.sequence.push(() => { @@ -306,6 +320,9 @@ class Drawing { const [cmd, ...args] = line.split(' '); // console.log({cmd, args}); switch (cmd) { + case 'start': { + d.start(); + } break; case 'title': { d.setTitle(args.join(' ')); } break; @@ -315,8 +332,12 @@ class Drawing { case 'buttons': { d.addButtons(); } break; + case 'scale': { + const [scale] = args; + d.setScale(scale); + } break; case 'frame': { - const [x1, y1, x2, y2] = args.map(x => parseInt(x)); + const [x1, y1, x2, y2] = args.map(x => eval(x)); d.setFrame([x1, y1], [x2, y2]); } break; case 'axes': { @@ -335,7 +356,7 @@ class Drawing { case 'point': { const [name, ...rest] = args; let body = rest.join(' '); - while (lines[i + 1].startsWith(' ')) { + while (i < lines.length - 1 && lines[i + 1].startsWith(' ')) { body += lines[i + 1]; i += 1; } @@ -345,14 +366,46 @@ class Drawing { })(d); }); } break; + case 'value': { + const [name, ...rest] = args; + let body = rest.join(' '); + while (i < lines.length - 1 && lines[i + 1].startsWith(' ')) { + body += lines[i + 1]; + i += 1; + } + d.defineValue(name, () => { + return (function(_) { + return eval(body); + })(d); + }); + } break; case 'circle': case 'square': { const p = args[0]; const traceAge = args[1] ? parseInt(args[1]) : 0; d[cmd](p, {trace: {age: traceAge}}); } break; - case 'start': { - d.start(); + case 'func': { + let body = args.join(' '); + while (i < lines.length - 1 && lines[i + 1].startsWith(' ')) { + body += lines[i + 1]; + i += 1; + } + d.func({step: 0.1}, (x) => { + return (function(_) { + return eval(body); + })(d); + }); + } break; + case 'eval': { + let body = args.join(' '); + while (i < lines.length - 1 && lines[i + 1].startsWith(' ')) { + body += lines[i + 1]; + i += 1; + } + (function(_) { + eval(body); + })(d); } break; } } diff --git a/reveal-override.css b/reveal-override.css new file mode 100644 index 0000000..5d18628 --- /dev/null +++ b/reveal-override.css @@ -0,0 +1,3 @@ +body { + --r-heading-text-transform: none; +} \ No newline at end of file diff --git a/reveal.html b/reveal.html index 98aec9a..58e1a59 100644 --- a/reveal.html +++ b/reveal.html @@ -11,6 +11,7 @@ + @@ -19,40 +20,6 @@
-
-

Slide 1

-

Content... `a = b / c`

-
- -
-
- -
-
diff --git a/test.html b/test.html index aa5f943..d12337b 100644 --- a/test.html +++ b/test.html @@ -109,7 +109,7 @@ d.setStroke('green', 1); d.line([0, 0], [v0x, v0y]); d.setFill('blue'); - const projectile = d.circle('p1', {trace: {age: -1}}) + const projectile = d.circle('p1', {trace: {age: -1}}); d.onStart(() => { if (d.t == 0) { projectile.reset(); diff --git a/test.md b/test.md index 278f5af..fc133e8 100644 --- a/test.md +++ b/test.md @@ -1,12 +1,9 @@ -## Slide 3 - -Testing - -
+## Slide 1 ```drawing title Test Drawing! caption This is a test +scale 2.0 buttons frame 0 0 200 100 axes 200 100 @@ -21,4 +18,91 @@ point p3 [ _.oscillatingValue(20, 80, 3000), fill green circle p3 1000 start -``` \ No newline at end of file +``` + +--- + +## Slide 2 + +```drawing +title Sine Wave +caption `y = sin(x)` +scale 64 +frame 0 -1 2*Math.PI 1 +stroke black 4 +eval _.line([0, -1], [0, 1]) +eval _.line([0, 0], [2*Math.PI, 0]) +stroke red 2 +func Math.sin(x) +``` + +--- + +## Slide 3 + +```drawing +title Oscillating Sine Wave +caption `y = sin(x) * sin(t)` +scale 64 +frame 0 -1 2*Math.PI 1 +stroke black 4 +eval _.line([0, -1], [0, 1]) +eval _.line([0, 0], [2*Math.PI, 0]) +stroke red 2 +func Math.sin(x) * _.oscillatingValue(-1, 1, 500) +start +``` + +--- + +## Slide 4 + +```drawing +title Travelling Sine Wave +caption `y = sin(x + t)` +scale 64 +frame 0 -1 2*Math.PI 1 +stroke black 4 +eval _.line([0, -1], [0, 1]) +eval _.line([0, 0], [2*Math.PI, 0]) +stroke red 2 +func Math.sin(x + 2*Math.PI*_.t / 1000) +start +``` + +--- + +## Slide 5 + +```drawing +title Projectile +caption `y = v_(0y) * t - g * t^2`
`x = v_(0x) * t` +scale 2 +frame 0 0 300 100 +stroke black 4 +eval _.polyline([0, 100], [0, 0], [300, 0]); +value v0 75 +value angle Math.PI / 4 +value v0x _.getValue('v0') * Math.cos(_.getValue('angle')) +value v0y _.getValue('v0') * Math.sin(_.getValue('angle')) +point p1 (function() { + const t = _.t / 1000; + const x = _.getValue('v0x') * t; + const y = _.getValue('v0y') * t - 9.81 * t**2; + if (t > 0 && (y <= 0 || x >= _.frame[1][0])) { + _.stop(); + _.t = 0; + } + return [x, y]; + })() +stroke green 1 +eval _.line([0, 0], [_.getValue('v0x'), _.getValue('v0y')]) +fill blue +eval const projectile = d.circle('p1', {trace: {age: -1}}); + d.onStart(() => { + if (d.t == 0) { + projectile.reset(); + } + }) +start +``` \ No newline at end of file