# core/observers/document.observer.ts

> 46 lines of code and 11 definitions.

Tree: Site tree
Language: typescript
Layer: application
Canonical: https://banes-lab.com/anatomy/tree#file-core-observers-document-observer-ts
Source text: https://banes-lab.com/assets/sources/source.236c0d0f09f8fe1ebdad7a65cd2bc47ed930375b4fd851ec4adf93c5b73a0231.generated.txt

## Definitions

- `observeSections` (lexical_declaration, line 26, exported)
- `track` (lexical_declaration, line 43, exported)
- `ROOT_MARGIN` (lexical_declaration, line 5)
- `THRESHOLD` (lexical_declaration, line 6)
- `markActive` (lexical_declaration, line 8)
- `bestEntry` (lexical_declaration, line 14)
- `best` (lexical_declaration, line 15)
- `bestRatio` (lexical_declaration, line 16)
- `ratios` (lexical_declaration, line 30, exported)
- `observer` (lexical_declaration, line 31, exported)
- `active` (lexical_declaration, line 36, exported)

## Used by

- [presentation/renderers/document.renderer.ts](https://banes-lab.com/source/tree/presentation/renderers/document.renderer.ts.md)

## Source

```typescript
import { ACTIVE_CLASS } from "#configuration/constants/element.constants";
import { ANCHOR_PREFIX } from "#configuration/constants/document.constants";
import type { Disposer } from "#types/base.types";

const ROOT_MARGIN = "-20% 0px -60% 0px";
const THRESHOLD = [0, 0.25, 0.5, 0.75, 1];

const markActive = function markActive(links: readonly HTMLAnchorElement[], id: string): void {
    for (const link of links) {
        link.classList.toggle(ACTIVE_CLASS, link.hash === ANCHOR_PREFIX + id);
    }
};

const bestEntry = function bestEntry(ratios: ReadonlyMap<string, number>): string | null {
    let best: string | null = null;
    let bestRatio = 0;
    for (const [id, ratio] of ratios) {
        if (ratio > bestRatio) {
            bestRatio = ratio;
            best = id;
        }
    }
    return best;
};

export const observeSections = function observeSections(
    sections: readonly Element[],
    links: readonly HTMLAnchorElement[],
): Disposer {
    const ratios = new Map<string, number>();
    const observer = new IntersectionObserver(
        (entries) => {
            for (const entry of entries) {
                ratios.set(entry.target.id, entry.isIntersecting ? entry.intersectionRatio : 0);
            }
            const active = bestEntry(ratios);
            if (active !== null) {
                markActive(links, active);
            }
        },
        { rootMargin: ROOT_MARGIN, threshold: THRESHOLD },
    );
    const track = observer.observe.bind(observer);
    for (const section of sections) {
        track(section);
    }
    return () => {
        observer.disconnect();
    };
};
```
