-
-
Notifications
You must be signed in to change notification settings - Fork 1
/
index.html
418 lines (376 loc) · 17.7 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>The <graphics-element> HTML element</title>
<link
href="https://fonts.googleapis.com/css2?family=Inter&display=swap"
rel="stylesheet"
/>
<!-- the only HTML code we need to make sweet graphics work: -->
<script type="module" src="dist/graphics-element.js" async></script>
<link rel="stylesheet" href="dist/graphics-element.css" async />
<link rel="stylesheet" href="index.css" async />
<style>
graphics-element table.slider-wrapper {
background: #ececec;
margin-bottom: 0.25em;
}
</style>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/vs.min.css"
async
/>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/lioshi.min.css"
media="(prefers-color-scheme: dark)"
async
/>
</head>
<body>
<header>
<h1 id="top" style="text-align: center; font-size: 2.5em">
The
<a href="."><span><</span>graphics-element<span>></span></a>
</h1>
<h3>For putting (interactive) graphics on a web page</h3>
</header>
<ul>
<li>Visit <a href=".">the main page</a> (wait, you're already here!)</li>
<li>Read <a href="docs.html">the documentation</a></li>
<li>Check out the <a href="api.html">API</a></li>
<li>Try the <a href="edit/">editor playground</a></li>
<li>
View the project
<a href="https://github.com/Pomax/custom-graphics-element">on GitHub</a>
</li>
</ul>
<p>
And, if this made a difference in your dev life, consider (temporarily,
even?) becoming a patron of my work over on
<a href="https://www.patreon.com/bezierinfo">my Patreon page</a>, or send
a one-time donatation to
<a
href="https://www.paypal.com/donate/?cmd=_s-xclick&hosted_button_id=QPRDLNGDANJSW"
>help keep this project, and others like it, funded</a
>. Any amount is appreciated!
</p>
<h2>Page sections</h2>
<ul>
<li><a href="#what-is-this">What is this?</a></li>
<li><a href="#how-do-I-use-this">How do I use this?</a></li>
<li><a href="#how-can-I-contribute">How can I contribute?</a></li>
<li><a href="#how-do-I-contact-you">How do I contact you?</a></li>
</ul>
<h2 id="what-is-this"><a href="#what-is-this">What is this?</a></h2>
<p>
Once up on a time I was involved in
<a href="http://processingjs.org">Processing.js</a>, a JS port (as best as
we could do at a time before ES6) of the
<a href="https://processing.org">Processing language</a>, a visual
programming language that, to this day, I will whip out whenever I need to
do some quick trig. And as much as I know why Processing.js is now an
archived project on github (because I was the one who archived it), I
still miss it, and I frequently write web pages that would seriously
benefit from having some interactive graphics on the page. Sure, there's
<a href="https://p5js.org">P5.js</a> which answers the question "what if
the web was what it is today, back when the idea of Processing was born",
but it's not the same. For me, at least. It's a completely different API,
with a very different "feel", if that makes sense.
</p>
<p>
My most graphics-intensive website is my
<a href="https://pomax.github.io/bezierinfo">Primer on Bezier curves</a>,
and that ended up being enough work that I wrote a special graphics
element for it, which allowed me to write "Processing-ish" code that could
render the first frame serverside, as a placeholder image, and would then
PWA-style load the real graphic on top of it if JS is enabled, for
interactive goodness. So what if I just... turn that into a web component
that anyone can use? Just something you stick on a page as a
<graphics-element src="..."></graphics-element> and then you
just write your visual thing using a Processing-like flavour of JS (with
some magic sprinkled in so you're not prefixing every single function call
with "<em>this.</em>") and stick that on the web for anyone to use?
</p>
<p>
...so, yeah, this is that. Let's put some interactive graphics right onto
the page, using the magic of a custom element! In fact, right click on
this page and pick "view source": you'll just see a few
<graphics-element> entries, with normal "src" attributes for the
graphics that need to be shown.
</p>
<p>
In fact, here's one right now: it shows the result of a
<a
href="https://en.wikipedia.org/wiki/Proportional%E2%80%93integral%E2%80%93derivative_controller"
>PID controller</a
>
trying to get a signal (in red) starting at 0 to reach the intended target
value 100 (in blue), and then a while later, a target value of 50. The way
it does that is by checking the "current signal value", seeing how far off
it is from the "desired target value", and then generating an output that
gets used to update whatever generates the signal. This means that on the
very first run, it doesn't need to do anything, but the moment the target
value jumps to 100, it'll see a signal that's at 0, a target that's at
100, and so it finds a discrepancy of 100. As a result, it will go "I
think you should add 100". However, real world signals generally don't
immediately change by large amounts (good luck getting your car from 0 to
100 in no seconds =D), so in order to apply that change we can only add a
small amount to our signal, and then on the next iteration the PID
controller gets to check how far off we are now, and what its recommended
new change is. Say that by the next iteration our input only managed to
rise to around 10, instead of all the way to 100. In that case, the PID
controller will go "okay, well, I think you should update by 90 now that
I'm seeing 10 and the target is 100". And we keep running that feedback
loop forever (or in this case, for as wide as our graphics panel is) to
ensure that "eventually" the signal matches the desired output.
</p>
<h4 class="example">example</h4>
<graphics-element
title="an example using a PID controller"
src="./graphics/pid-example.js"
width="650"
height="300"
centered="centered"
><img
class="fallback"
src="./graphics/fallback/cbe8c7e5e2723775d915b4120a4ad146.png"
width="700px"
height="552px"
title="This is a placeholder image because JavaScript is disabled"
/></graphics-element>
<p>
The "neat" thing about this is that it'll oscillate: by the time the input
value actually reaches 100, it's applying such large updates that it's
going to "overshoot" the target, and now the PID controller is going to
try to bring the value back down to 100: we see the green PID
recommendation curve having maxima where the input is at its lowest and
its highest, and a recommendation of "no change" when the input is at 100,
but because of how the update feedback works, we'll never stabilize...
unless we take either the accumulated error over time (the "I" in PID),
the "speed at which the input changes" (the "D" in PID), or both into
account. If you slide the P, I, or D sliders around, you'll see what
effect that might have on how a signal changes over time. With a bit of
sliding, you might find something like P=0.5, I=0.4, and D=17, and now
we're in business.
</p>
<p>
Of course, this graphic is only "interactive" in the sense that you get to
move HTML sliders, so how about some actual interaction? The library that
backs the graphics element doesn't require you to write your own
mouse/touch handling for things like "this point should be
click-draggable", you instead say which points can be moved around, and
done: they can now be moved around. So let's look at an example of that.
</p>
<h4 class="example">example</h4>
<graphics-element
title="an example with interactive points"
src="./graphics/point-example.js"
><img
class="fallback"
src="./graphics/fallback/3c182ba57ae0b249d29c2afa682692d7.png"
width="550px"
height="464px"
title="This is a placeholder image because JavaScript is disabled"
/>
<source src="./graphics/add-points.js" />
<p>
Click-drag (or touch-slide) points to move them around in our graphics
pane, to reveal a bunch of curves that have been fit to the collection
of points (there's a polygon, two Bezier curves, a cardinal spline, and
even a B-spline. Can you identify each?)
</p>
</graphics-element>
<p>
And click that "view source" link, as well as the "[+1]" link. I want you
to be able to see the source code that makes cool things be cool. Because
I want you to be able to make cool things, too. Let's make the web cool
again. In fact, I want you to be able to not just view source, but
comfortably work with "lots of code", so you can add more than one source
file: if you view the page source for the above element, you'll see that
it has a <source> element in addition to the main "src" attribute:
this allows you to write graphics in a modular way, where you have have
one file that's just "the basics" that lets you add additional files for
extra bits that are relevant to "this specific graphic". In this case, we
have some general code for drawing points, and then an extra bit of code
that specifies a bunch of points and adds Bezier and B-spline drawing.
</p>
<p>
And that "view source" link is baked into the graphics element itself, so
that you can always see what code generated the graphics you're looking
at. No pretending that something you put on the web is somehow super
secret: everything you put on the web is public. That's the very nature of
the web. It's what makes it so great: anyone can learn from anyone by
looking at how they did something.
</p>
<p>
So how about we take things a step further, and actually write a real
animation? Say, for example, visualising the trigonometric identities of a
point on a circle (its sine, cosine, tangent, secant, and cosecant values)
as we move points around, and then mirror that a few times so we get a
kaleidoscope going?
</p>
<p>Sounds good to me, let's go:</p>
<h4 class="example">example</h4>
<graphics-element
title="an example with a play button as well as tap-to-play"
src="./graphics/animated-example.js"
><img
class="fallback"
src="./graphics/fallback/352e4463373b32ae1416baecaca324f5.png"
width="800px"
height="382px"
title="This is a placeholder image because JavaScript is disabled"
/></graphics-element>
<p>
And again, if you click "view source" link you'll see that most of the
code is things that draw lines and set colors: we get to focus on the
parts that <em>matter</em> without having to bother with all the code that
we really don't want to have to care about.
</p>
<p>In fact, let's take that one step further:</p>
<h4 class="example">example</h4>
<graphics-element
src="./graphics/trigonometry.js"
title="A trigonometric identity visualisation"
width="500"
height="200"
><img
class="fallback"
src="./graphics/fallback/2aa43cc230dedba5b1ceba67e3c05423.png"
width="550px"
height="557px"
title="This is a placeholder image because JavaScript is disabled"
/>
<p>
A point <b>P</b> at some <darkgreen>angle</darkgreen> on a circle has
several trigonometric identities. The <red>sine</red> and
<blue>cosine</blue> are the projection of <b>P</b> onto the y and x
axes, respectively, and form two sides of
<lavender>a right angle triangle</lavender>, with a
<midnightblue>hypotenuse</midnightblue> that is equal to the circle's
radius. We also see an
<mistyrose>"enclosing right triangle"</mistyrose> with the circle's
center as the right angle corner, the point's
<darkblue>secant</darkblue> (which is just <blue>1/cosine</blue>) as
x-axis corner, and the point's <brown>cosecant</brown> (which is just
<red>1/sine</red>) as y-axis corner. Additionally, our point "splits"
the enclosing right triangle's hypotenuse into two parts: one part, from
<b>P</b> to the secant corner, has length
<orange>tangent</orange> (which is just
<red>sine</red>/<blue>cosine</blue>), and the other part, from
<b>P</b> to the cosecant corner, has length
<purple>cotangent</purple> (which is simply the inverse,
<blue>cosine</blue>/<red>sine</red>).
</p>
</graphics-element>
<p>
See all those coloured terms in the text? Mouse-over or tap-and-hold them:
you'll notice that the correspondingly colored part of the graphic gets
highlighted in the loudest shade of mint. And don't want all those
colours? Click the remove button so you can more easily read the text, and
click "reset" to get the colours back! How does it work? "More HTML!",
view this page's source and have a look at the HTML that is used for the
above graphic. Each term is decorated with a tag that uses a CSS color
name like <black> or <gold> and the graphics-element knows to
cross-link those into the graphics API's fill and stroke logic. No work on
your part, just mark a bunch of text with with the same color you use in
your graphics source code, and done, that's all the highlighting code
written.
</p>
<p>
This is the kind of thing I wish I had available back when I had to
archive Processing.js due to a lack of devs, and frankly, interest. The
need to make cool graphics hasn't gone away. Only the tools to let you
just easily put those on a page have. So hopefully this tool enables at
least <em>some</em> folks to make <em>some</em> cool things that they
otherwise wouldn't have. That's all we need: everything more is a bonus.
</p>
<h2 id="how-do-I-use-this">
<a href="#how-do-I-use-this">How do I use this?</a>
</h2>
<p>
<graphics-element> is conveniently available from cdn: simply
<a href="https://cdnjs.com/libraries/graphics-element"
>visit the graphics-element page on <code>cdnjs</code></a
>, and copy the JS and CSS links into your own webpage:
</p>
<pre><code class="language-js"><!doctype html>
<html>
<head>
...
<script
type="module"
src="https://cdnjs.cloudflare.com/.../graphics-element.js"
integrity="..."
crossorigin="anonymous"
referrerpolicy="no-referrer"></script>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/.../graphics-element.css"
integrity="..."
crossorigin="anonymous"
referrerpolicy="no-referrer" />
...
</head>
<body>
...</code></pre>
<p>
Note that you <strong>must add</strong> the
<code>type="module"</code> attribute and value, as the graphics-element is
a modern ES module, and heavily relies on the functionality that comes
with.
</p>
<p>
But with that, that's all you need: you can now add
<graphics-element> to your page in the exact same way as you're
already adding any other content!
</p>
<p>
Also, have a look at the <a href="docs">general documentation</a> to learn
how to write code using this element (if you already know JavaScript,
you're <em>pretty</em> much done already!) as well as the
<a href="api">API documentation</a> to learn which constants and functions
you can use to create your own graphics (with <em>loads</em> of examples
for you to learn from!)
</p>
<p>
And if you want to just try things to see what they do, you can head on
over to the
<a href="edit/">editor playground</a> to see some more elaborate examples,
as well as a blank project that you can use to experiment with!
</p>
<h2 id="how-can-I-contribute">
<a href="#how-can-I-contribute">How can I contribute?</a>
</h2>
<p>
Head on over to the
<a
href="https://github.com/Pomax/custom-graphics-element?tab=readme-ov-file#working-on-the-code"
>code repository</a
>, which has all the information necessary to start contributing!
</p>
<h2 id="how-do-I-contact-you">
<a href="#how-do-I-contact-you">How do I contact you?</a>
</h2>
<p>
If you think you've found a bug, or you think something's missing, or you
have an idea that you think might work well for the
<graphics-element>, please file an issue over on
<a href="https://github.com/Pomax/custom-graphics-element/issues"
>the issue tracker</a
>, or if you just want give me a shout you can message me on Mastodon,
where I can be found as
<a href="https://mastodon.social/@TheRealPomax"
>@TheRealPomax on mastodon.social</a
>.
</p>
<!-- ===================code syntax highlighting====================== -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
<script>
hljs.highlightAll({ language: "javascript" });
</script>
</body>
</html>