The <graphics-element>

For putting (interactive) graphics on a web page

And, if this made a difference in your dev life, consider (temporarily, even?) becoming a patron of my work over on my Patreon page, or send a one-time donatation to help keep this project, and others like it, funded. Any amount is appreciated!

Page sections

What is this?

Once up on a time I was involved in Processing.js, a JS port (as best as we could do at a time before ES6) of the Processing language, 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 P5.js 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.

My most graphics-intensive website is my Primer on Bezier curves, 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 "this.") and stick that on the web for anyone to use?

...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.

In fact, here's one right now: it shows the result of a PID controller 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.

example

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.

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.

example

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?)

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.

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.

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?

Sounds good to me, let's go:

example

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 matter without having to bother with all the code that we really don't want to have to care about.

In fact, let's take that one step further:

example

A point P at some angle on a circle has several trigonometric identities. The sine and cosine are the projection of P onto the y and x axes, respectively, and form two sides of a right angle triangle, with a hypotenuse that is equal to the circle's radius. We also see an "enclosing right triangle" with the circle's center as the right angle corner, the point's secant (which is just 1/cosine) as x-axis corner, and the point's cosecant (which is just 1/sine) as y-axis corner. Additionally, our point "splits" the enclosing right triangle's hypotenuse into two parts: one part, from P to the secant corner, has length tangent (which is just sine/cosine), and the other part, from P to the cosecant corner, has length cotangent (which is simply the inverse, cosine/sine).

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.

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 some folks to make some cool things that they otherwise wouldn't have. That's all we need: everything more is a bonus.

How do I use this?

<graphics-element> is conveniently available from cdn: simply visit the graphics-element page on cdnjs, and copy the JS and CSS links into your own webpage:

<!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>
    ...

Note that you must add the type="module" attribute and value, as the graphics-element is a modern ES module, and heavily relies on the functionality that comes with.

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!

Also, have a look at the general documentation to learn how to write code using this element (if you already know JavaScript, you're pretty much done already!) as well as the API documentation to learn which constants and functions you can use to create your own graphics (with loads of examples for you to learn from!)

And if you want to just try things to see what they do, you can head on over to the editor playground to see some more elaborate examples, as well as a blank project that you can use to experiment with!

How can I contribute?

Head on over to the code repository, which has all the information necessary to start contributing!

How do I contact you?

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 the issue tracker, or if you just want give me a shout you can message me on Mastodon, where I can be found as @TheRealPomax on mastodon.social.