histogram 1.3.1

A collection of histogram data structures
Documentation
<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <style type="text/css">
      @import url("observable:styles/index.css");
      @import url("@fontsource/spline-sans-mono/400.css");
      @import url("@fontsource/spline-sans-mono/600.css");
      @import url("@fontsource/spline-sans-mono/700.css");
      @import url("@fontsource/spline-sans-mono/400-italic.css");
      @import url("@fontsource/spline-sans-mono/600-italic.css");
      @import url("@fontsource/spline-sans-mono/700-italic.css");
      @import url("@fontsource/source-serif-4/400.css");
      @import url("@fontsource/source-serif-4/700.css");
      @import url("@fontsource/source-serif-4/400-italic.css");
      @import url("@fontsource/source-serif-4/700-italic.css");
      @import url("@fontsource/inter/400.css");
      @import url("@fontsource/inter/500.css");
      @import url("@fontsource/inter/600.css");
      @import url("@fontsource/inter/700.css");
      @import url("@fontsource/inter/400-italic.css");
      @import url("@fontsource/inter/500-italic.css");
      @import url("@fontsource/inter/600-italic.css");
      @import url("@fontsource/inter/700-italic.css");
    </style>
    <style>
      body {
        display: grid;
        grid-template-columns: 1fr;
        column-gap: 2rem;
        align-items: start;
      }

      header.repo-header {
        grid-column: 1 / -1;
        padding: 0.75rem 1.5rem 0;
      }

      header.repo-header a {
        display: inline-flex;
        align-items: center;
        gap: 0.35rem;
        font: 12px/1 var(--sans-serif);
        color: var(--theme-foreground-muted);
        text-decoration: none;
      }

      header.repo-header a:hover {
        color: var(--theme-foreground);
      }

      header.repo-header svg {
        flex-shrink: 0;
      }

      main {
        min-width: 0;
        padding-left: 1.5rem;
      }

      aside.toc {
        display: none;
      }

      @media (min-width: 1080px) {
        body {
          max-width: calc(var(--max-width, 1100px) + 220px + 2rem);
          grid-template-columns: minmax(0, 1fr) 220px;
        }

        aside.toc {
          display: block;
          position: sticky;
          top: 1.25rem;
          align-self: start;
          max-height: calc(100vh - 2.5rem);
          overflow-y: auto;
          font: 14px/1.45 var(--sans-serif);
          color: var(--theme-foreground-muted);
          padding-right: 0.25rem;
        }

        aside.toc .toc-title {
          font-weight: 600;
          font-size: 12px;
          letter-spacing: 0.04em;
          text-transform: uppercase;
          color: var(--theme-foreground-muted);
          margin-bottom: 0.5rem;
        }

        aside.toc ol {
          list-style: none;
          padding: 0;
          margin: 0;
          border-left: 1px solid var(--theme-foreground-faintest);
        }

        aside.toc li { margin: 0; }
        aside.toc li.toc-h3 { padding-left: 1rem; }

        aside.toc a {
          display: block;
          padding: 0.2rem 0.75rem;
          margin-left: -1px;
          border-left: 1px solid transparent;
          color: var(--theme-foreground-muted);
          text-decoration: none;
          line-height: 1.35;
        }

        aside.toc a:hover {
          color: var(--theme-foreground);
        }

        aside.toc a.active {
          color: var(--theme-foreground);
          border-left-color: var(--theme-foreground-focus);
        }
      }
    </style>
  </head>
  <body>
    <header class="repo-header">
      <a href="https://github.com/iopsystems/histogram" target="_blank" rel="noopener noreferrer">
        <svg width="14" height="14" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true">
          <path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.012 8.012 0 0 0 16 8c0-4.42-3.58-8-8-8z"/>
        </svg>
        iopsystems/histogram
      </a>
    </header>
    <main></main>
    <aside class="toc" aria-label="On this page">
      <nav>
        <div class="toc-title">On this page</div>
        <ol id="toc-list"></ol>
      </nav>
    </aside>
    <script type="module">
      const main = document.querySelector("main");
      const list = document.getElementById("toc-list");
      let observer = null;
      let signature = "";

      function build() {
        const headings = main.querySelectorAll("h2[id], h3[id]");
        const sig = Array.from(headings, (h) => h.tagName + h.id + h.textContent).join("|");
        if (sig === signature) return;
        signature = sig;

        list.replaceChildren();
        const targets = [];
        for (const h of headings) {
          const li = document.createElement("li");
          li.className = "toc-" + h.tagName.toLowerCase();
          const a = document.createElement("a");
          a.href = "#" + h.id;
          a.textContent = h.textContent;
          li.appendChild(a);
          list.appendChild(li);
          targets.push({ el: h, link: a });
        }

        if (observer) observer.disconnect();
        if (!targets.length) return;

        const linkOf = new Map(targets.map((t) => [t.el, t.link]));
        const visible = new Set();
        observer = new IntersectionObserver(
          (entries) => {
            for (const e of entries) {
              if (e.isIntersecting) visible.add(e.target);
              else visible.delete(e.target);
            }
            const ordered = targets.filter((t) => visible.has(t.el));
            const active = ordered[0]?.link ?? null;
            for (const { link } of targets) link.classList.toggle("active", link === active);
          },
          { rootMargin: "0px 0px -65% 0px", threshold: 0 }
        );
        for (const { el } of targets) observer.observe(el);
      }

      const mo = new MutationObserver(() => build());
      mo.observe(main, { childList: true, subtree: true });
      build();
    </script>
  </body>
</html>