I love the annotated geometry proof here. It doesn't take a lot of JavaScript to make. The main idea is to annotate the text and also the diagram, and then use the annotations plus CSS to drive the highlighting. I wanted to recreate a tiny bit of it to demonstrate how to make something like this. Live demo:

Let the straight line AB be divided into any two parts in C;
the square of AB is equal to
the squares of AC, CB,
and to twice the rectangle contained by AC, CB.

I also put the code up on jsfiddle for you to play with (try settings / bottom results). How does it work? The text contains annotations:

the square of <span data-key="A-ADEB">AB</span> is equal to
the squares of <span data-key="L-AC">AC</span>, <span data-key="L-CB">CB</span>,

The diagram also contains annotations:

  <path data-key="L-AB" d="M 0,0 l 100,0"/>
  <path data-key="A-ADEB" d="M 0,0 l 0,100 l 100,0 l 0,-100 Z"/>
  <text data-key="P-A" text-anchor="end" x="0" y="0">A</text>

Then this JavaScript ties it all together:

const highlightable = document.querySelectorAll("*[data-key]");
for (let el of highlightable) {
  el.addEventListener('pointerover', () => highlight(el.dataset.key));
  el.addEventListener('mouseout', () => highlight(null));
function highlight(key) {
  for (let el of highlightable) {
    el.classList.toggle("highlight", el.dataset.key === key);

When you mouse over (or touch) an element that has a data-key attribute, it will find all elements with that same key and add the highlight class to them. Then those elements are displayed differently using CSS:

  span[data-key^="L-"] { background: hsl(240, 75%, 95%); }
  span[data-key^="L-"].highlight { background: hsl(240, 50%, 80%); }
  path[data-key^="L-"] { stroke: black stroke-width: 0.75px; }
  path[data-key^="L-"].highlight { stroke: hsl(240, 100%, 60%); stroke-width: 2.5px; }

What is this funny ^= thing? It means the key must start with the pattern. I used L- to annotate line segments, A- to annotate areas, and P- to annotate points. So these rules will only apply to the line segments. Here's the CSS for areas:

  span[data-key^="A-"] { background: hsl(240, 40%, 75%); }
  span[data-key^="A-"].highlight { background: hsl(240, 50%, 60%); }
  path[data-key^="A-"] { fill: none; }
  path[data-key^="A-"].highlight { fill: hsla(240, 50%, 50%, 0.5); }

I implemented this example a little differently from @sliminality's original code at her site. Her page is more polished and avoids some of the little glitches in my version, but I think my version may be useful if you want to get started making things like this. It's only ten lines of JavaScript, and all the rest is done with HTML + SVG + CSS. It works with the simple example here but I don't know if it will work for more complex pages. Fortunately, most of my pages are simple!



Tyr wrote at June 28, 2021 11:15 AM

Nice! I like that.

Viewing this with my a11y hat on, you might want to also include focus/blur instead of just mouse events, and make the points have non-negative tabindex?

Though I'm not really sure what a screen reader is going to do with the diagram anyways.

Amit wrote at June 28, 2021 5:35 PM

Tyr: very good points, yes, focus/blur seems like it'd be useful here.