The arithmetic of the charts, with no markup: where a value sits on an axis, the path of a line, an area, a column with a rounded top and a slice of a ring. Every function is pure, so the charts can be drawn on the server and tested without a browser.
Summary
Functions
The path of a ring slice between two radii, from angle a to b (degrees from the top, clockwise).
The path of the area under a line, closed down to baseline.
A column from baseline up to top, width wide, with the top corners rounded by radius.
A number as the least text that says it: 12, 12.5.
The path of a line through {x, y} points.
A round number at or above value, to end an axis on, that four grid lines divide without a mess: 1, 1.2, 1.6, 2, 2.4, 3, 4, 5, 6, 8 or 10 times a power of ten.
The point at angle degrees from the top, clockwise, on a circle.
A number rounded to two decimals, so paths stay short.
The y of value on an axis from 0 to max drawn between bottom and top.
Moves labels apart: ys are positions, the result keeps the order and leaves gap between neighbours.
The slices of a ring from values: {start, stop} angles in degrees, from the top, clockwise, each one
shortened by gap degrees so the slices do not touch. A value of 0 has no slice.
count positions from left to right; one position is the middle.
count + 1 evenly spaced values from 0 to max, for the grid lines.
Functions
The path of a ring slice between two radii, from angle a to b (degrees from the top, clockwise).
The path of the area under a line, closed down to baseline.
A column from baseline up to top, width wide, with the top corners rounded by radius.
A number as the least text that says it: 12, 12.5.
The path of a line through {x, y} points.
A round number at or above value, to end an axis on, that four grid lines divide without a mess: 1, 1.2, 1.6, 2, 2.4, 3, 4, 5, 6, 8 or 10 times a power of ten.
The point at angle degrees from the top, clockwise, on a circle.
A number rounded to two decimals, so paths stay short.
The y of value on an axis from 0 to max drawn between bottom and top.
Moves labels apart: ys are positions, the result keeps the order and leaves gap between neighbours.
The slices of a ring from values: {start, stop} angles in degrees, from the top, clockwise, each one
shortened by gap degrees so the slices do not touch. A value of 0 has no slice.
@spec spread(pos_integer(), number(), number()) :: [float()]
count positions from left to right; one position is the middle.
@spec ticks(number(), pos_integer()) :: [number()]
count + 1 evenly spaced values from 0 to max, for the grid lines.