Skip to content

line-scale

Terminal window
$ npx shadcn@latest add https://lacodda.github.io/dowel/r/line-scale.json
See it liveThe numbers, printed rather than drawn: a series with a hole in it, and the ticks a range asks for.→

Split out of LineChart like track-segments and activity-weeks: a product labelling its own points, or checking its own domain sums, should not import a component to get at the numbers.

import { boundsOf, runs, ticksFor } from '@/components/ui/line-scale'
const bounds = boundsOf(points, { min: 0 })
runs(points, bounds) // the drawable stretches, split at every hole
ticksFor(bounds, 4) // [0, 10, 20, 30] for a range of 0..37

runs breaks the series at every hole, and that is the whole point. Interpolating across invents a reading nobody took; dropping the point closes the gap and shifts every later reading left, so the axis stops matching the data. Breaking leaves the gap visible and moves nothing. A run of one point survives: it has no line, but it is a measurement.

boundsOf does not force the floor to zero. A line’s subject is change, and a balance between 4,900 and 5,100 flattens on a zero-based axis. State min: 0 for a count, where zero is the truth rather than a flattening. A flat series gets a band around its value instead of a range of zero to divide by.

ticksFor answers “what reads as a round number”, not “how do I cut this range into four”. The step is the nearest 1, 2, 5 or 10 above what the range needs, and the ticks are its multiples inside the range — so a range of 0 to 37 gives 0, 10, 20, 30 rather than 9.25 and its friends. Decimals are trimmed to what the step makes real, or a tick reads 0.30000000000000004.

Values are clamped into the plot, but a point keeps its own reading, so a label beside it can say the real figure even where the line sits on the ceiling.

Export
boundsOf(points, stated?) The box to draw against, or null when nothing was measured
runs(points, bounds) The drawable stretches, split at every hole
pathOf(run) One stretch as an SVG path, in percentages
ticksFor(bounds, wanted?) Round-number ticks inside the range
yOf(value, bounds) A percentage from the top, or null outside the plot

Accessibility

The examples on the stand, through axe 4.14.0 in a browser, in both themes, against WCAG 2.2 A and AA and axe's best practices: 4 rules applied and passed, and none failed. The accessibility report has every item.

History

Each release that changed ui/line-scale.tsx - the file a product copies - newest first.

  1. v0.34.1
    • fix keep a module's description through shadcn add a2182f9
  2. v0.24.0
    • feat a level between the readings, with a hole drawn as a hole 24fee8f