Skip to content

Fills

A fill covers the inside of a polygon. Pass the polygon the stroke was drawn through, so the fill follows the drawn line. For a smooth outline, that is the base that roughCurve returns. For a straight-edged outline, it is the outline itself, because roughEdges keeps the vertices in place below roughness 2.

Hachure

hachureFill(base, options) returns the Path of parallel lines that fill the polygon, the look of a hand-shaded area.

type HachureOptions = {
readonly cross: boolean;
readonly gap: number;
readonly roughness: number;
readonly seed: Seed;
};
Option Meaning
cross false draws one set of lines. true adds a second set at right angles (cross-hatch)
gap Distance between two neighbouring lines, in local units. The paint layer uses 4 × stroke
roughness Scales the wobble of each line. 0 draws exact straight lines
seed Fixes every random choice

How it draws:

  1. Scanlines. The lines run at -49 degrees, which rises to the right on a screen whose y axis points down. This is the direction roughjs draws for its default hachureAngle of -41 degrees. The first line sits half a gap inside the polygon, and the next ones follow one gap apart.
  2. Intersection. Each polygon edge is cut against only the scanlines it spans, and its crossings land in a bucket per scanline, so the cost grows with the edges plus the crossings, not their product. The crossings, sorted along the line, pair up into the inside spans. A concave polygon gives a scanline more than one span, so the lines skip its notches.
  3. Roughening. Each span is drawn twice, like a rough edge, but its two ends never move, at any roughness. The lines wobble inside the polygon and never poke out of the outline.

Each set holds at most 10000 lines. When the polygon would need more at the requested gap, the gap widens until the set has exactly 10000 lines, spread evenly over the polygon. Shapes under about 1e4 units across, at any normal gap, never reach the cap, so their output does not change. The cap keeps the cost of a fill bounded on absurdly large shapes.

Cross-hatch draws the first set, then a second set at +41 degrees, with the same generator. The cross-hatch path starts with exactly the lines of the plain hachure.

Solid

solidFill(base) returns the polygon as one closed path: a move to the first point, a line to each other point and a line back to the first. A canvas fills it with fill().

Degenerate input

Both functions return an empty path for fewer than three points. hachureFill also returns an empty path for a polygon of zero area, such as three points on one line, and for a gap that is 0, negative or NaN. No input produces NaN in the output.