Renato Garcia

Hakyll diagram example

This is a usage example of the hakyll-diagrams library, which renders interactive diagrams. It is included here because GitHub has restrictions on adding inline SVG and JavaScript code to the project README file.

The code below creates an interactive figure that opens a link when clicking on each subpath. The links are embedded within the SVG itself and are created using the Haskell diagrams library. The interactive functionality is achieved by combining custom classes assigned to SVG elements in the Haskell code with JavaScript code that manipulates the SVG DOM.

diagram {
  figcaption="An interactive figure. It reacts to mouse hover and each part is a link."
  svg:width=400
}
let
  hydrogen =
    mconcat
      [ proton
      , electron # moveTo p0
      , orbit
      ]
    where
      orbit =
        circle 2
          # svgAttr "pointer-events" "stroke"
          # href "https://en.wikipedia.org/wiki/Atomic_orbital"
          # svgClass "svg_orbit"
      electron =
        circle 0.1
          # fc blue
          # lw 0
          # href "https://en.wikipedia.org/wiki/Electron"
          # svgClass "svg_electron"
      proton =
        circle 0.3
          # fc red
          # lw 0
          # href "https://en.wikipedia.org/wiki/Proton"
          # svgClass "svg_proton"
      p0 = fromJust $ maxTraceP origin (angleV $ 3/8 @@ turn) orbit

  background =
    roundedRect 5 5 0.1
      # lw 0
      # fc (sRGB24read "#808080")
      # opacity 0.15

in hydrogen <> background

Haskell

An interactive figure. It reacts to mouse hover and each part is a link.
Javascript code used to animate the figure above:
document.addEventListener("DOMContentLoaded", () => {
  const electrons = Array.from(document.querySelectorAll(".svg_electron"));
  const orbits    = Array.from(document.querySelectorAll(".svg_orbit"));
  const protons   = Array.from(document.querySelectorAll(".svg_proton"));

  const groups = [
    { name: "electron", elements: electrons },
    { name: "orbit",    elements: orbits },
    { name: "proton",   elements: protons }
  ];

  function fadeOut(list) {
    list.forEach(el => {
      el.style.transition = "opacity 0.3s ease";
      el.style.opacity = "0.2";
    });
  }

  function fadeIn(list) {
    list.forEach(el => {
      el.style.transition = "opacity 0.3s ease";
      el.style.opacity = "1";
    });
  }

  function attachHoverHandlers(group, others) {
    group.elements.forEach(el => {
      el.addEventListener("mouseenter", () => {
        others.forEach(g => fadeOut(g.elements));
      });
      el.addEventListener("mouseleave", () => {
        others.forEach(g => fadeIn(g.elements));
      });
    });
  }

  // Attach handlers for each group
  groups.forEach((group, _, all) => {
    const others = all.filter(g => g !== group);
    attachHoverHandlers(group, others);
  });
});

Javascript