You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
44 lines
1.5 KiB
44 lines
1.5 KiB
/**
|
|
* Line and area path generators. Inputs are already in pixel space (the caller
|
|
* maps data through scales first), so these are pure string builders.
|
|
*/
|
|
|
|
import type { AreaPoint, Curve, Point } from './types'
|
|
import { coord } from './path'
|
|
import { curveLinear } from './curve'
|
|
|
|
export interface LineOptions {
|
|
/** How to connect points. Default: straight segments. */
|
|
curve?: Curve
|
|
}
|
|
|
|
/**
|
|
* An open polyline through `points`. Returns an empty string for no points (a
|
|
* valid, invisible `d`), so binding it to a `<path>` is always safe.
|
|
*/
|
|
export function line(points: readonly Point[], options: LineOptions = {}): string {
|
|
if (points.length === 0) return ''
|
|
const link = options.curve ?? curveLinear
|
|
return `M${coord(points[0].x, points[0].y)}${link(points)}`
|
|
}
|
|
|
|
export interface AreaOptions {
|
|
curve?: Curve
|
|
}
|
|
|
|
/**
|
|
* A filled band between the `y0` (baseline) and `y1` (value) edges at each `x`.
|
|
* The outline runs along the top edge left→right, then back along the baseline
|
|
* right→left, and closes — so the same curve shapes both edges.
|
|
*/
|
|
export function area(points: readonly AreaPoint[], options: AreaOptions = {}): string {
|
|
if (points.length === 0) return ''
|
|
const link = options.curve ?? curveLinear
|
|
const tops: Point[] = points.map((p) => ({ x: p.x, y: p.y1 }))
|
|
const baseline: Point[] = points.map((p) => ({ x: p.x, y: p.y0 })).reverse()
|
|
return (
|
|
`M${coord(tops[0].x, tops[0].y)}${link(tops)}` +
|
|
`L${coord(baseline[0].x, baseline[0].y)}${link(baseline)}Z`
|
|
)
|
|
}
|