Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/johnfactotum/foliate-js/llms.txt

Use this file to discover all available pages before exploring further.

Overlayer is a class that places a full-size SVG element on top of a rendered page and draws annotation shapes — highlights, underlines, strikethroughs, squiggly lines, and outlines — from DOM Range objects. Renderers insert .element into the page and call .redraw() on resize; everything else is driven by your application code.

Import

import { Overlayer } from './foliate-js/overlayer.js'

Constructor

const overlayer = new Overlayer()
Creates a new Overlayer instance. The internal SVG element is configured with position: absolute, width: 100%, height: 100%, and pointer-events: none so it sits over the page without blocking input.

Properties

.element

The SVG DOM element. Insert it into the page container so the renderer can position it automatically.
container.append(overlayer.element)

Methods

.add(key, range, draw, options)

Adds an annotation. If an annotation with the same key already exists it is replaced.
key
any
required
A unique key used to identify and later remove this annotation. Can be any value usable as a Map key (string, number, object, etc.).
range
Range | function
required
A DOM Range covering the text to annotate. Alternatively, pass a function (rootNode) => Range that will be called with the SVG’s root node to produce the range lazily.
draw
function
required
A draw function with signature (rects: DOMRectList, options: object) => SVGElement. Use one of the built-in static methods or provide your own.
options
object
Options forwarded directly to the draw function (color, width, etc.).
overlayer.add('note-1', range, Overlayer.highlight, { color: 'yellow' })

// Lazy range resolved at draw time
overlayer.add('note-2', root => {
    const range = root.ownerDocument.createRange()
    // ... set range boundaries
    return range
}, Overlayer.underline, { color: 'blue' })

.remove(key)

Removes the annotation identified by key. Does nothing if key is not found.
key
any
required
The key passed to .add().
overlayer.remove('note-1')

.redraw()

Redraws all annotations by recomputing client rects from their stored ranges. Called automatically by the renderer on resize. Call this yourself if the page layout changes without a resize event.
window.addEventListener('resize', () => overlayer.redraw())

.hitTest({ x, y })

Returns the key and range of the topmost annotation at the given viewport coordinates. Iterates in reverse insertion order so more recently added annotations take priority.
x
number
required
Viewport x coordinate.
y
number
required
Viewport y coordinate.
Returns [key, Range] when a hit is found, or [] when no annotation is at that position.
document.addEventListener('click', e => {
    const hit = overlayer.hitTest({ x: e.clientX, y: e.clientY })
    if (hit.length) {
        const [key, range] = hit
        console.log('clicked annotation', key)
    }
})

Static draw functions

Each static method receives the DOMRectList from range.getClientRects() and an options object, and returns an SVGElement (a <g> group containing one or more shapes).

Overlayer.highlight(rects, options)

Draws filled rectangles over the text. Opacity and blend mode are controlled by CSS custom properties.
options.color
string
default:"'red'"
Fill color for the rectangles.
Opacity defaults to 0.3 via --overlayer-highlight-opacity and blend mode via --overlayer-highlight-blend-mode. Override these with CSS on a parent element.
overlayer.add(key, range, Overlayer.highlight, { color: '#ffeb3b' })

Overlayer.underline(rects, options)

Draws thin rectangles along the baseline of each line of text.
options.color
string
default:"'red'"
Fill color.
options.width
number
default:"2"
Stroke width in pixels.
options.writingMode
string
Set to 'vertical-rl' or 'vertical-lr' for vertical scripts; the underline is drawn on the right side of each rect instead of the bottom.

Overlayer.strikethrough(rects, options)

Draws a line through the vertical midpoint of each line of text. Accepts the same options as underline.
options.color
string
default:"'red'"
Fill color.
options.width
number
default:"2"
Stroke width in pixels.
options.writingMode
string
'vertical-rl' or 'vertical-lr' for vertical scripts.

Overlayer.squiggly(rects, options)

Draws a wavy SVG path under each line of text. Accepts the same options as underline.
options.color
string
default:"'red'"
Stroke color.
options.width
number
default:"2"
Stroke width in pixels; also controls the amplitude of the wave.
options.writingMode
string
'vertical-rl' or 'vertical-lr' for vertical scripts.

Overlayer.outline(rects, options)

Draws rounded-rectangle outlines around each rect. Used by view.js for search result highlights.
options.color
string
default:"'red'"
Stroke color.
options.width
number
default:"3"
Stroke width in pixels.
options.radius
number
default:"3"
Corner radius (rx) of each rectangle.
overlayer.add(key, range, Overlayer.outline, { color: '#4fc3f7', width: 2 })

Custom draw functions

You can pass any function that matches the draw signature. It receives the rects from range.getClientRects() and your options object, and must return a single SVGElement.
const myDraw = (rects, options = {}) => {
    const ns = 'http://www.w3.org/2000/svg'
    const g = document.createElementNS(ns, 'g')
    for (const { left, top, width, height } of rects) {
        const el = document.createElementNS(ns, 'rect')
        el.setAttribute('x', left)
        el.setAttribute('y', top)
        el.setAttribute('width', width)
        el.setAttribute('height', height)
        el.setAttribute('fill', options.color ?? 'blue')
        el.setAttribute('opacity', '0.4')
        g.append(el)
    }
    return g
}

overlayer.add('custom-1', range, myDraw, { color: 'green' })

Renderer interface

Renderer modules expect an overlayer object that exposes two members:
MemberTypeDescription
.elementSVGElementInserted into the page container and positioned automatically.
.redraw()functionCalled by the renderer whenever the layout changes.

Build docs developers (and LLMs) love