inkplot-scratch 0.0.0-stage → 1.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +60 -2
- package/bin.mjs +312 -0
- package/fonts/Inter-Bold.otf +0 -0
- package/fonts/Inter-Regular.otf +0 -0
- package/fonts/LICENSE.txt +133 -0
- package/package.json +14 -4
- package/skill/SKILL.md +61 -0
- package/skill/inkplot/SKILL.md +309 -0
- package/skill/inkplot/reference/exports.md +104 -0
- package/skill/inkplot/topics/axes.md +125 -0
- package/skill/inkplot/topics/data.md +141 -0
- package/skill/inkplot/topics/furniture.md +137 -0
- package/skill/inkplot/topics/interaction.md +169 -0
- package/skill/inkplot/topics/lines-bars.md +201 -0
- package/skill/inkplot/topics/markers-color.md +274 -0
- package/skill/inkplot/topics/planes.md +139 -0
- package/skill/inkplot/topics/statistics.md +365 -0
- package/skill/inkplot/topics/styling-output.md +75 -0
- package/skill/inkplot/topics/troubleshooting.md +24 -0
- package/src/app.ts +100 -0
- package/src/figures.ts +105 -0
- package/src/interact.ts +39 -0
- package/src/template.html +38 -0
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: inkplot
|
|
3
|
+
description: Write charts with the inkplot JavaScript/TypeScript chart library (a tree of elements drawn to SVG: Chart, CartesianPlane, Axis, DomainSeries, LinePath, BarPath…). Use when asked to make, change or debug an inkplot chart, in JSX, with `new`, in React, or as HTML tags.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# inkplot: how to write charts
|
|
7
|
+
|
|
8
|
+
inkplot draws a chart from a **tree of elements**. You build the tree, attach it to a page (or turn it into an SVG string), and change attributes to update it. There is no `render()` call and no options object: everything is an element with attributes and children.
|
|
9
|
+
|
|
10
|
+
**How to use this skill.** Read this file (it is short). It is enough for a plain line chart. For anything else, find the topic in **Topics** and read that topic file: it has worked examples and the attributes of its elements, and nothing else you need to open. Usually that is one or two files. Do not read topic files the chart does not need. Run the **Checklist** before you answer.
|
|
11
|
+
|
|
12
|
+
## Rules
|
|
13
|
+
|
|
14
|
+
1. **Write plain TypeScript: `new Element(attributes, ...children)`.** The attributes are one object, first; then the children, in order. Leave the attributes out only for an element with neither attributes nor children (`new LinearScale()`); with children and no attributes write `{}`. The expression *is* the element. Build the whole tree as one expression, inside out.
|
|
15
|
+
2. **Import every element you use by name** from `'inkplot'`: `import { Chart, CartesianPlane, … } from 'inkplot'`. Never `import *`.
|
|
16
|
+
3. **`Chart` needs a `theme`**: `theme: lightTheme` (or `darkTheme` for a dark chart; see the `styling-output` topic). Import it.
|
|
17
|
+
4. **A chart is `Chart` > plane > (`Axis` ×2, series)**. The plane is `CartesianPlane` (x and y), `PolarPlane` or `RadarPlane`. Every plane needs both axes.
|
|
18
|
+
5. **Child order matters, and `tsc` checks it.** `new Axis(attrs, scale)`: one scale (`new LinearScale()`, `new BandScale({ categories: […] })`, `new IntlTimeScale()`, `new LogScale()`). `new DomainSeries(attrs, data, ...renderers)`: the **data first**, then renderers. `new LinePath(attrs, curve)` and `new AreaPath(attrs, curve)`: one curve (`new LinearCurve()`). `new BarPath(attrs)` and the markers: no children.
|
|
19
|
+
6. **Data goes in a source, never in the series.** `FlatDataSource` (numbers), `ObjectDataSource` (rows), `CompositeDataSource` (columns), `SyntheticDataSource` (a function).
|
|
20
|
+
7. **Nested attributes are nested objects**: `{ regularDomain: { start: 0 } }`, `{ meta: { title: 'x' } }`, `{ style: { tickLabel: { size: 12 } } }`.
|
|
21
|
+
8. **A drawn title is an element with a `text` attribute**: `new ChartTitle({ text: 'Sales' })`. A drawn title or a legend is in the `furniture` topic; `meta: { title }` on the `Chart` is only its accessible name and is **not drawn**.
|
|
22
|
+
9. **Style through attributes, `style` and the theme, never CSS.** The output is SVG with presentation attributes. `style: { selector: { property: value } }`, e.g. `style: { gridline: { color: '#eee' } }`. Fill the page behind a chart with `style: { chart: { background: "#fff" } }` (none by default).
|
|
23
|
+
10. **Names make things appear.** A series with no `name` is not in the legend or the tooltip. Give every series a `name`.
|
|
24
|
+
11. **Charts need a size.** In a browser, give the container a height. For SVG text: `toSvgString(chart, { width, height })`.
|
|
25
|
+
12. **Update by setting attributes**: `source.setAttribute('data', next)`; `axis.setAttribute('max', 10)`. If you edit an array in place, call `source.invalidate()`. Setting `undefined` removes an attribute.
|
|
26
|
+
13. **Elements refer to each other by `id`**: `new ColorAxis({ id: 'heat' }, …)` and `bind: { fill: { axis: 'heat', channel: 'temp' } }`; `new Axis({ id: 'rain' }, …)` and `new DomainSeries({ valueAxis: 'rain' }, …)`.
|
|
27
|
+
14. **One element has one parent.** Do not put the same element object in two places; to use a source twice, make a function that returns a new one each time (`const source = () => new ObjectDataSource({ … })`).
|
|
28
|
+
15. **Do not invent API.** If an element or attribute is not in this file or in a topic file, it probably does not exist. See **Not in inkplot**.
|
|
29
|
+
|
|
30
|
+
## Template
|
|
31
|
+
|
|
32
|
+
Start from this and change it. It is a complete line chart.
|
|
33
|
+
|
|
34
|
+
```ts check title="Template: a line chart"
|
|
35
|
+
import {
|
|
36
|
+
Axis,
|
|
37
|
+
CartesianPlane,
|
|
38
|
+
Chart,
|
|
39
|
+
DomainSeries,
|
|
40
|
+
FlatDataSource,
|
|
41
|
+
LinePath,
|
|
42
|
+
LinearCurve,
|
|
43
|
+
LinearScale,
|
|
44
|
+
lightTheme,
|
|
45
|
+
} from 'inkplot';
|
|
46
|
+
|
|
47
|
+
export const chart = new Chart(
|
|
48
|
+
{ theme: lightTheme, meta: { title: 'Load over time' } },
|
|
49
|
+
new CartesianPlane(
|
|
50
|
+
{},
|
|
51
|
+
new Axis({ orientation: 'bottom', title: 'Hour', tickStep: 1 }, new LinearScale()),
|
|
52
|
+
new Axis({ orientation: 'left', title: 'Load' }, new LinearScale()),
|
|
53
|
+
new DomainSeries(
|
|
54
|
+
{ name: 'Load' },
|
|
55
|
+
new FlatDataSource({ data: [3, 5, 4, 8, 6, 9], regularDomain: { start: 0, step: 1 } }),
|
|
56
|
+
new LinePath({}, new LinearCurve()),
|
|
57
|
+
),
|
|
58
|
+
),
|
|
59
|
+
);
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Each `new Element(…)` has its own type, so `tsc` checks every element's arguments: attribute names and types (nested ones too), which children it takes, and in what order. `new Chart(…)` is a `Chart`, so nothing needs a cast. `AnyElement` is exported from `'inkplot'` for helper functions that take any element.
|
|
63
|
+
|
|
64
|
+
Show it (browser) or draw it (anywhere):
|
|
65
|
+
|
|
66
|
+
```ts check title="Attach to a page, or draw to a string"
|
|
67
|
+
import { DOMPlatform, toSvgString } from 'inkplot';
|
|
68
|
+
import type { Chart } from 'inkplot';
|
|
69
|
+
|
|
70
|
+
export function show(chart: Chart, container: HTMLElement): void {
|
|
71
|
+
chart.attach(new DOMPlatform(container)); // the container needs a height
|
|
72
|
+
}
|
|
73
|
+
export const svg = (chart: Chart): string => toSvgString(chart, { width: 640, height: 360 });
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
To run a file as a program that prints the SVG (a script, a build step, a server), put both in one file:
|
|
77
|
+
|
|
78
|
+
```ts check title="A whole program: print an SVG"
|
|
79
|
+
import {
|
|
80
|
+
Axis,
|
|
81
|
+
CartesianPlane,
|
|
82
|
+
Chart,
|
|
83
|
+
DomainSeries,
|
|
84
|
+
FlatDataSource,
|
|
85
|
+
LinePath,
|
|
86
|
+
LinearCurve,
|
|
87
|
+
LinearScale,
|
|
88
|
+
lightTheme,
|
|
89
|
+
toSvgString,
|
|
90
|
+
} from 'inkplot';
|
|
91
|
+
|
|
92
|
+
const chart = new Chart(
|
|
93
|
+
{ theme: lightTheme },
|
|
94
|
+
new CartesianPlane(
|
|
95
|
+
{},
|
|
96
|
+
new Axis({ orientation: 'bottom' }, new LinearScale()),
|
|
97
|
+
new Axis({ orientation: 'left' }, new LinearScale()),
|
|
98
|
+
new DomainSeries(
|
|
99
|
+
{ name: 'Load' },
|
|
100
|
+
new FlatDataSource({ data: [3, 5, 4, 8], regularDomain: { start: 0, step: 1 } }),
|
|
101
|
+
new LinePath({}, new LinearCurve()),
|
|
102
|
+
),
|
|
103
|
+
),
|
|
104
|
+
);
|
|
105
|
+
console.log(toSvgString(chart, { width: 640, height: 360 }));
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
## Elements used above
|
|
110
|
+
|
|
111
|
+
Attributes of the elements in the Template. An attribute followed by `(required)` must be given. Every element also takes `id`, `meta`, `visible` and `style`. Child order is in the Rules: `Axis` holds one scale, a series holds its data first and then its renderers.
|
|
112
|
+
|
|
113
|
+
<!-- api:start -->
|
|
114
|
+
### Chart
|
|
115
|
+
|
|
116
|
+
The root: a theme, a size, and what is drawn on it.
|
|
117
|
+
|
|
118
|
+
**In** none (the root) · **Holds** planes, ChartTitle, Legend, Cursor, ColorAxis, SizeAxis, ColorKey, SizeKey, ChartSummary
|
|
119
|
+
|
|
120
|
+
| Attribute | Type | |
|
|
121
|
+
|---|---|---|
|
|
122
|
+
| `theme` (required) | `BaseTheme` | Every default look: required, so a chart bundles exactly the theme it names (`lightTheme`, `darkTheme`, or your own). |
|
|
123
|
+
| `width` | `number` | Width of the drawing. Default: whatever the platform reports, followed as it changes. |
|
|
124
|
+
| `height` | `number` | Height of the drawing. Default: whatever the platform reports. |
|
|
125
|
+
| `padding` | `number \| Partial<Insets>` | Margin around everything, in pixels: one number for all sides, or any subset of the four. Default 10. |
|
|
126
|
+
| `measureText` | `TextMeasurer` | Replaces the platform's text measurement, e.g. to match a font the platform cannot see. |
|
|
127
|
+
| `locale` | `string` | A BCP 47 tag (`'de'`, `'fr-CA'`) for how numbers and dates are written: digit grouping, the decimal mark, month names. Default: numbers as plain digits with a point, and the runtime's own locale for dates. |
|
|
128
|
+
| `onFlush` | `(stats: FlushStats) => void` | Called after every flush with its statistics. |
|
|
129
|
+
|
|
130
|
+
### CartesianPlane
|
|
131
|
+
|
|
132
|
+
A rectangular plot (x and y).
|
|
133
|
+
|
|
134
|
+
**In** Chart · **Holds** Axis, series, Stack, LineAnnotation, CalloutAnnotation, PanZoom, BoxZoom, Brush, PointerListener
|
|
135
|
+
|
|
136
|
+
| Attribute | Type | |
|
|
137
|
+
|---|---|---|
|
|
138
|
+
| `gridlines` | `boolean` | Lines at the first horizontal and first vertical axis' ticks. Default true. |
|
|
139
|
+
| `frame` | `boolean` | Draw a border round the plot area, above the series. |
|
|
140
|
+
| `clip` | `boolean` | Clip series to the plot area. Default true. |
|
|
141
|
+
| `insets` | `Partial<Insets>` | Fixed margins round the plot (room for axes). |
|
|
142
|
+
|
|
143
|
+
### Axis
|
|
144
|
+
|
|
145
|
+
Positions data along one side of a plane, with ticks and labels.
|
|
146
|
+
|
|
147
|
+
**In** a plane · **Holds** 1 scale (required)
|
|
148
|
+
|
|
149
|
+
| Attribute | Type | |
|
|
150
|
+
|---|---|---|
|
|
151
|
+
| `orientation` | `AxisOrientation` | The side of the plot the axis sits on. Default: 'bottom' for the first axis in a plane, then 'left', 'top', 'right'. |
|
|
152
|
+
| `titlePosition` | `Side` | The edge of the plot the title sits at: past the axis' labels for an axis fixed to that side, otherwise at the middle of the edge, outside any axes there, which then take the room it needs. Default: the axis' own side. |
|
|
153
|
+
| `titleDirection` | `'horizontal' \| 'vertical'` | Whether the title runs along the horizontal or the vertical. Default: horizontal at the top and bottom, vertical at the left and right. |
|
|
154
|
+
| `crossesAt` | `number` | Float across the plot at this value of the crossing axis (the other one, or `crossAxis`), instead of sitting on a side. |
|
|
155
|
+
| `crossAxis` | `ElementRef<Axis>` | The axis `crossesAt` is a value of. Default: the plane's first axis on the other orientation. |
|
|
156
|
+
| `min` | `number` | Fix an end of the range. |
|
|
157
|
+
| `max` | `number` | Fix the top end of the range. |
|
|
158
|
+
| `include` | `readonly number[]` | Values the range must cover, e.g. `[0]` to anchor a bar-like axis at zero. |
|
|
159
|
+
| `padding` | `number` | Extra room at both ends as a fraction of the data's span. |
|
|
160
|
+
| `nice` | `boolean` | Round the ends outwards to tidy tick values. |
|
|
161
|
+
| `inverted` | `boolean` | Run from max to min along the axis. |
|
|
162
|
+
| `title` | `string` | The axis title (or, on a `ColorAxis` or `SizeAxis`, the default title of its key). Default: none. |
|
|
163
|
+
| `tickCount` | `number` | Ask for about this many ticks, whatever the length. |
|
|
164
|
+
| `ticks` | `readonly number[] \| ((range: Readonly<Extent>) => readonly …` | Put ticks exactly here (those inside the range are drawn), or at whatever a function of the range returns. |
|
|
165
|
+
| `tickStep` | `number` | Put ticks at every multiple of this step. |
|
|
166
|
+
| `format` | `(value: number) => string` | Turns a tick's number into its label, e.g. (v) => `${v}%`. Default: plain digits, grouped by `locale` if one is set. |
|
|
167
|
+
| `locale` | `string` | A BCP 47 tag for how this writes its numbers (grouping and decimal mark). Default: the chart's `locale`, else plain digits. |
|
|
168
|
+
| `onViewChange` | `(view: Readonly<Extent> \| null) => void` | Called when the view (what pan, zoom or a reset has set) changes: the new range, or null when it is back to the natural one. |
|
|
169
|
+
|
|
170
|
+
### LinearScale
|
|
171
|
+
|
|
172
|
+
Equal steps in the data are equal steps on the page.
|
|
173
|
+
|
|
174
|
+
**In** an axis · **Holds** none
|
|
175
|
+
|
|
176
|
+
No attributes of its own.
|
|
177
|
+
|
|
178
|
+
### DomainSeries
|
|
179
|
+
|
|
180
|
+
A value at each position along a domain.
|
|
181
|
+
|
|
182
|
+
**In** a plane or Stack · **Holds** 1 data (source or Decimator), then any renderers
|
|
183
|
+
|
|
184
|
+
| Attribute | Type | |
|
|
185
|
+
|---|---|---|
|
|
186
|
+
| `domainAxis` | `ElementRef<Axis>` | Default: the plane's first axis (a Cartesian plane's horizontal one, a polar plane's angle). |
|
|
187
|
+
| `valueAxis` | `ElementRef<Axis>` | Default: the plane's second axis (the vertical one, the radius). |
|
|
188
|
+
| `name` | `string` | What the series is called where it is named: a tooltip's heading. |
|
|
189
|
+
| `hit` | `false \| HitMode \| HitOptions` | How pointer hits find this series: a mode name, options, or `false` for a series that should never be hit (a selection overlay, a reference line). |
|
|
190
|
+
| `gaps` | `'break' \| 'connect' \| 'zero'` | What a missing value (NaN, or infinite) means. 'break' (default): nothing is there, so a line stops and starts again and an area splits. 'connect': the line goes straight across to the next value there is. 'zero': the value is 0 (and the axis reaches it). |
|
|
191
|
+
|
|
192
|
+
### FlatDataSource
|
|
193
|
+
|
|
194
|
+
Numbers in an array or typed array, read in place.
|
|
195
|
+
|
|
196
|
+
**In** a series · **Holds** none
|
|
197
|
+
|
|
198
|
+
| Attribute | Type | |
|
|
199
|
+
|---|---|---|
|
|
200
|
+
| `data` (required) | `ArrayLike<number>` | Float64Array, Float32Array, or any numeric array. |
|
|
201
|
+
| `stride` | `number` | Numbers per point. Default 2 (x, y pairs), or 1 when `regularDomain` is set. |
|
|
202
|
+
| `domainOffset` | `number` | Where the domain and the value sit within a point's `stride` numbers. Default 0 and 1 (0 when there is no stored domain). |
|
|
203
|
+
| `valueOffset` | `number` | Where the value sits within a point's `stride` numbers. Default 1 (0 when there is no stored domain). |
|
|
204
|
+
| `count` | `number` | Number of points. Default: `data.length / stride`. |
|
|
205
|
+
| `regularDomain` | `{ start: number; step: number }` | Evenly spaced domain with no stored x values: a y-only array. |
|
|
206
|
+
| `channels` | `Readonly<Record<Channel, number>>` | Extra columns that bindings can address by name, as offsets within a point's `stride` numbers. |
|
|
207
|
+
| `isSorted` | `boolean` | The stored points already ascend in the domain. Default false. |
|
|
208
|
+
| `wrap` | `number` | The domain repeats with this period, and the source delivers one more point: the first, again, one period on. |
|
|
209
|
+
|
|
210
|
+
### ObjectDataSource
|
|
211
|
+
|
|
212
|
+
Rows as objects, read by property name.
|
|
213
|
+
|
|
214
|
+
**In** a series · **Holds** none
|
|
215
|
+
|
|
216
|
+
| Attribute | Type | |
|
|
217
|
+
|---|---|---|
|
|
218
|
+
| `source` (required) | `readonly Row[]` | |
|
|
219
|
+
| `domain` | `Field<Row>` | Where each row is along the domain. |
|
|
220
|
+
| `value` (required) | `Field<Row>` | |
|
|
221
|
+
| `channels` | `Readonly<Record<Channel, Field<Row>>>` | Extra columns that bindings can address by name: a size, a colour, a category, the x of an XY plot. |
|
|
222
|
+
| `isSorted` | `boolean` | The stored points already ascend in the domain. Default false. |
|
|
223
|
+
| `wrap` | `number` | The domain repeats with this period, and the source delivers one more point: the first, again, one period on. |
|
|
224
|
+
|
|
225
|
+
### LinePath
|
|
226
|
+
|
|
227
|
+
A line through the points.
|
|
228
|
+
|
|
229
|
+
**In** a series · **Holds** 1 curve (required)
|
|
230
|
+
|
|
231
|
+
| Attribute | Type | |
|
|
232
|
+
|---|---|---|
|
|
233
|
+
| `stroke` | `string` | Outline colour (a CSS colour). Default: from the theme. |
|
|
234
|
+
| `strokeWidth` | `number` | Outline width in pixels. Default: from the theme. |
|
|
235
|
+
| `fill` | `string` | Fill colour (a CSS colour; 'none' for no fill). Default: from the theme. |
|
|
236
|
+
| `opacity` | `number` | Opacity from 0 to 1. Default 1. |
|
|
237
|
+
| `bind` | `Bindings<Bindable>` | Attributes fed from data instead of fixed. |
|
|
238
|
+
| `maxNodes` | `number` | Most paths this renderer may create. Default 1000. |
|
|
239
|
+
|
|
240
|
+
### LinearCurve
|
|
241
|
+
|
|
242
|
+
Straight lines.
|
|
243
|
+
|
|
244
|
+
**In** LinePath or AreaPath · **Holds** none
|
|
245
|
+
|
|
246
|
+
No attributes of its own.
|
|
247
|
+
<!-- api:end -->
|
|
248
|
+
|
|
249
|
+
Notes:
|
|
250
|
+
|
|
251
|
+
- `hit` on a series: `'point'`, `'line'`, `'area'`, `'shape'` or `false`. `gaps`: `'break'` (default), `'connect'`, `'zero'`.
|
|
252
|
+
- `ObjectDataSource`'s `domain` and `value` are a property name (`"x"`) or a function (`(row) => row.x`).
|
|
253
|
+
- Size: a `width` or `height` attribute on the `Chart` always wins. `toSvgString(chart, { width, height })` supplies what the chart leaves out; with neither it is 640 x 400. A chart attached to a page follows its container.
|
|
254
|
+
- Axes fit the data and tidy the ends, so a value axis does not start at 0 unless a bar needs it: use `include: [0]`, or `min`/`max`.
|
|
255
|
+
- A series may have more than one renderer (a line *and* markers). Every element used must be imported.
|
|
256
|
+
|
|
257
|
+
## Topics
|
|
258
|
+
|
|
259
|
+
Read the topic that matches the chart; each has examples and the attributes of the elements listed.
|
|
260
|
+
|
|
261
|
+
<!-- index:start -->
|
|
262
|
+
- **axes** (`topics/axes.md`): dates and times, categories, log and sqrt scales, tick labels and formats, axis limits, a second or reversed axis, number and date language. Elements: LogScale, SqrtScale, BandScale, IntlTimeScale, TemporalTimeScale.
|
|
263
|
+
- **lines-bars** (`topics/lines-bars.md`): bars (grouped, stacked), areas, smooth and stepped lines, curves, gaps in the data, several series sharing a plane. Elements: Stack, AreaPath, MonotoneCurve, NaturalCurve, CardinalCurve, CatmullRomCurve, BasisCurve, BumpCurve, QuadraticCurve, ArcCurve, StepCurve, BarPath, BarLinePath.
|
|
264
|
+
- **markers-color** (`topics/markers-color.md`): scatter and bubble charts, dots and crosses, colour or size taken from the data, colour and size keys. Elements: XYSeries, DotMarker, CrossMarker, PlusMarker, CircleMarker, SquareMarker, ColorAxis, SizeAxis, ColorKey, SizeKey.
|
|
265
|
+
- **statistics** (`topics/statistics.md`): histograms (a histogram is `Density` + `BarPath`), heat maps, density, box plots, trendlines (linear, polynomial, sinusoidal, loess), error bars and bands. Elements: BoxPath, BoxStats, Density, HeatMap, LinearTrend, PolynomialTrend, SinusoidalTrend, LoessTrend, ErrorBars, ErrorBand.
|
|
266
|
+
- **furniture** (`topics/furniture.md`): a chart title or caption, a legend, reference lines and callouts, an accessible name and summary. Elements: ChartTitle, Legend, ChartSummary, LineAnnotation, CalloutAnnotation.
|
|
267
|
+
- **interaction** (`topics/interaction.md`): tooltips, a crosshair, pan and zoom, drag-to-zoom, brushing a range, clicks and hovers, touch. Elements: ChartTooltip, Cursor, Crosshair, PanZoom, BoxZoom, Brush, PointerListener.
|
|
268
|
+
- **planes** (`topics/planes.md`): polar and radar charts. Elements: PolarPlane, RadarPlane.
|
|
269
|
+
- **data** (`topics/data.md`): a million points (decimation), data as columns or from a function, updating live data, reading a chart's data back as a table. Elements: CompositeDataSource, SyntheticDataSource, Decimator, MinMaxKernel, M4Kernel, LttbKernel, StrideKernel.
|
|
270
|
+
- **styling-output** (`topics/styling-output.md`): dark and custom themes, styling parts, React, a PNG, chart as JSON, your own element types.
|
|
271
|
+
- **troubleshooting** (`topics/troubleshooting.md`): an error message or a chart that draws nothing or draws wrongly.
|
|
272
|
+
<!-- index:end -->
|
|
273
|
+
|
|
274
|
+
Also: `reference/exports.md` lists every function and type exported from `'inkplot'` (read it only to find a name you do not have).
|
|
275
|
+
|
|
276
|
+
## Checklist
|
|
277
|
+
|
|
278
|
+
Before you answer, check each line against your code:
|
|
279
|
+
|
|
280
|
+
- [ ] Every element is made with `new Element(attributes, ...children)`, attributes first, and `tsc` reports no errors.
|
|
281
|
+
- [ ] Every element used is imported by name from `'inkplot'` (and `toSvgString`, when the file prints the SVG); none is imported and unused.
|
|
282
|
+
- [ ] `new Chart({ theme: … }, …)` has a theme.
|
|
283
|
+
- [ ] Every plane has two axes with an `orientation`; every `Axis` has exactly one scale child.
|
|
284
|
+
- [ ] Every series has a `name`, **data first** (a source or `Decimator`), then renderers; every `LinePath` and `AreaPath` has a curve.
|
|
285
|
+
- [ ] Data is in a source with the right attributes: `FlatDataSource` has `data` and (for y-only arrays, and for evenly spaced x including dates) `regularDomain: { start }` and `regularDomain: { step }`; `ObjectDataSource` has `source` and `value`; an `XYSeries` has `x` naming a channel.
|
|
286
|
+
- [ ] Bound channels are declared in the source's `channels` and the dimension has the `id` the `bind` names.
|
|
287
|
+
- [ ] `Cursor`, `Legend`, titles, `ColorAxis` and keys are children of the **chart**; axes, series, `PanZoom`, annotations and `PointerListener` are children of the **plane**.
|
|
288
|
+
- [ ] Dates are milliseconds; categories are `BandScale categories={[…]}` with domain 0, 1, 2…
|
|
289
|
+
- [ ] Nested attributes are objects (`regularDomain: { start, step }`, `meta: { title }`), spelled exactly; text is an attribute, not a child.
|
|
290
|
+
- [ ] A container height is set (browser) or a size is given (`toSvgString`).
|
|
291
|
+
- [ ] No element object is used in two places (make a function for a source you need twice).
|
|
292
|
+
- [ ] No invented names: every element and attribute is in this file or a topic file.
|
|
293
|
+
|
|
294
|
+
## Not in inkplot
|
|
295
|
+
|
|
296
|
+
These do **not** exist. Do not write them.
|
|
297
|
+
|
|
298
|
+
- `chart.render()`, `chart.update(options)`, `chart.destroy()`, `new Chart(container, options)`. Use `chart.attach(platform)`, `setAttribute`, `chart.detach()`.
|
|
299
|
+
- `series.data = …`, `chart.data`. Data lives in a source element.
|
|
300
|
+
- `new ChartTitle({}, 'Text')`, `new Axis({ label: '…' })` (use `title`), `new Legend({ position: '…' })` (use `side`).
|
|
301
|
+
- CSS classes or stylesheets for chart parts, or `d3`/`canvas` calls. Use `style`, attributes and themes.
|
|
302
|
+
- `LineSeries`, `BarSeries`, `ScatterSeries`: series are `DomainSeries` and `XYSeries`; the look comes from renderers (`LinePath`, `BarPath`, markers).
|
|
303
|
+
- `bind` on lines, areas and bars.
|
|
304
|
+
- A PNG export in the core or on a server. In the browser use `toPng`/`svgToPng`; on a server use `toSvgString` and a WASM rasterizer.
|
|
305
|
+
- Animation.
|
|
306
|
+
|
|
307
|
+
## More
|
|
308
|
+
|
|
309
|
+
`topics/*.md` (the topics above), `reference/exports.md`. The project's guide pages go deeper; they are not part of this skill and you do not need them for the charts described here.
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# Functions and other exports
|
|
2
|
+
|
|
3
|
+
The element classes (with every attribute) are in the attribute reference. This page lists everything else the package exports, grouped by what it is for. Names come from `import { … } from 'inkplot'`; the adapters are separate entry points (`inkplot/react`, `inkplot/web-components`, `inkplot/jsx-runtime`).
|
|
4
|
+
|
|
5
|
+
## Drawing
|
|
6
|
+
|
|
7
|
+
| Export | Is |
|
|
8
|
+
|---|---|
|
|
9
|
+
| `toSvgString(chart, { width, height, idPrefix })`, `SvgOptions` (type) | Draws a chart once to an SVG string, with no DOM. Ids inside it are `ink<hash>-<n>` unless `idPrefix` names them. Rendering |
|
|
10
|
+
| `AnyElement` (type) | The type of any element, and of every JSX expression: write `as Chart` where a `Chart` is needed. |
|
|
11
|
+
| `DOMPlatform` | A platform that draws a live `<svg>` in a container element: `new DOMPlatform(container, { size, preciseText, schedule })`. |
|
|
12
|
+
| `StringPlatform` | A platform that keeps the SVG in memory and prints it with `toString()`. |
|
|
13
|
+
| `estimateTextWidth` | The default text measure of a platform with no fonts (about 0.6 em per character). |
|
|
14
|
+
|
|
15
|
+
## Themes and style
|
|
16
|
+
|
|
17
|
+
| Export | Is |
|
|
18
|
+
|---|---|
|
|
19
|
+
| `lightTheme`, `darkTheme` | Complete base themes. Styling |
|
|
20
|
+
| `extendTheme(base, patch)` | A new theme: each selector in `patch` merged over the base's, property by property. |
|
|
21
|
+
| `resolveStyle(chain, scopes, theme, local?, accent?)` | The look for a selector chain; what `styleFor` calls. |
|
|
22
|
+
| `Selectors`, `Roots`, `Theme`, `BaseTheme`, `TextProps`, `LineProps`, `ShapeProps`, `AxisMetrics`, `MarkerMetrics` | Types. Augment `Selectors` to add a selector. |
|
|
23
|
+
|
|
24
|
+
## Data helpers
|
|
25
|
+
|
|
26
|
+
| Export | Is |
|
|
27
|
+
|---|---|
|
|
28
|
+
| `lineSeries(source, options?)` | A `DomainSeries` with a `LinePath` (and optionally a marker, a decimator and a curve) in one call. |
|
|
29
|
+
| `DataSource`, `DataTransform` | Bases for a source and a transform of your own. |
|
|
30
|
+
| `PointBuffer`, `PlanContext`, `FillPlan`, `FillResult` | Types of the data contract. |
|
|
31
|
+
|
|
32
|
+
## Serialization
|
|
33
|
+
|
|
34
|
+
| Export | Is |
|
|
35
|
+
|---|---|
|
|
36
|
+
| `toJSON`, `fromJSON`, `applyJSON` | A tree to JSON, JSON to a tree, and JSON applied to a live tree. Serialization |
|
|
37
|
+
| `Refs` | A table of names for functions and objects that JSON cannot hold. |
|
|
38
|
+
| `registry` | Every shipped class by name (pulls the whole library into a bundle). |
|
|
39
|
+
|
|
40
|
+
## Finding elements
|
|
41
|
+
|
|
42
|
+
| Export | Is |
|
|
43
|
+
|---|---|
|
|
44
|
+
| `findById(root, id)` | The element with that `id` under `root`, or `undefined`. |
|
|
45
|
+
| `descendantsOfType(root, Class)`, `childrenOfType`, `firstDescendantOfType`, `closestAncestorOfType` | Typed searches. |
|
|
46
|
+
| `walk(root, visit)` | Calls `visit(element, depth)` for an element and everything under it; returning `false` skips a subtree. |
|
|
47
|
+
| `resolveRef(ref, from, Class?)` | Turns an attribute that is an element or an id into the element. |
|
|
48
|
+
| `seriesOf(child)` | The series a plane child stands for: itself, a stack's members, or none. |
|
|
49
|
+
|
|
50
|
+
## Hit testing
|
|
51
|
+
|
|
52
|
+
Used by `Cursor`, `PointerListener` and your own interaction (Custom elements).
|
|
53
|
+
|
|
54
|
+
| Export | Is |
|
|
55
|
+
|---|---|
|
|
56
|
+
| `hitTest(series, x, y, maxDistance?)` | The series' point near (x, y) in plot pixels, as its `hit` mode measures it. A `NaN` coordinate leaves that direction out. |
|
|
57
|
+
| `hitPlane(plane, x, y)`, `hitAll(plane, x, y, radius?)` | The nearest hit over a plane's series; the nearest of each series, topmost first. |
|
|
58
|
+
| `hitAcross(plane, x, y)`, `interpolate(series, first)`, `interpolateAll(plane, x, y)` | Every series at a place along the first axis; a line read between its points, for one series or all. |
|
|
59
|
+
| `nearest`, `nearestPoint`, `nearestSegment`, `nearestShape`, `nearestTraced`, `insideArea`, `insideTrace`, `pointHit` | The measurements underneath. |
|
|
60
|
+
|
|
61
|
+
## Paths and text, for renderers
|
|
62
|
+
|
|
63
|
+
| Export | Is |
|
|
64
|
+
|---|---|
|
|
65
|
+
| `polyline(points, connect)`, `areaOutline(top, base, connect)` | Straight-line path text through placed points, and the closed shapes between a line and its baseline. |
|
|
66
|
+
| `lineTo`, `quadTo`, `cubicTo`, `arcTo`, `hermiteTo`, `smoothTo`, `StrokeCurve`, `Piece` | The pieces a curve is made of. |
|
|
67
|
+
| `stepLines`, `stemLines`, `barShapes` | The geometry of steps, stems and bars. |
|
|
68
|
+
| `applyText(surface, node, textProps, anchor?)` | Sets a text node's font attributes from a look. |
|
|
69
|
+
| `measureBlock`, `paintLines`, `LINE_HEIGHT` | Multi-line text. |
|
|
70
|
+
| `calloutSize`, `paintCallout`, `clearCallout` | The callout box, used by annotations and tooltips. |
|
|
71
|
+
| `paintSample` | A small picture of a series (for a legend). |
|
|
72
|
+
| `alignRows`, `layOut` | Stack arithmetic. |
|
|
73
|
+
|
|
74
|
+
## Accessibility and focus
|
|
75
|
+
|
|
76
|
+
| Export | Is |
|
|
77
|
+
|---|---|
|
|
78
|
+
| `writeAria(surface, node, meta, defaults?)` | Writes role, name, description and `meta.aria` on a node. |
|
|
79
|
+
| `hideFromAssistive(surface, node)` | Marks decoration `aria: { hidden }`. |
|
|
80
|
+
| `makeTabStop(surface, node)`, `drawFocusRing(surface, key, look, rect)`, `pressesButton(event)` | Keyboard focus building blocks. |
|
|
81
|
+
| `englishSummary(facts)` | The default `ChartSummary` wording. |
|
|
82
|
+
| `DEFAULT_CURSOR_KEYS`, `DEFAULT_PANZOOM_KEYS` | The default keys of those elements. |
|
|
83
|
+
|
|
84
|
+
## Elements and events
|
|
85
|
+
|
|
86
|
+
| Export | Is |
|
|
87
|
+
|---|---|
|
|
88
|
+
| `ChartElement` | The base class of everything. Custom elements |
|
|
89
|
+
| `Surface` | What an element draws with. |
|
|
90
|
+
| `EVENT_ATTACH`, `EVENT_MEASURE`, `EVENT_ARRANGE`, `EVENT_PAINT`, `EVENT_POINTER`, `EVENT_HOVER`, `EVENT_KEY`, `EVENT_FOCUS`, `EventBase` | Event types and the base of events. |
|
|
91
|
+
| `STRING`, `NUMBER`, `BOOLEAN`, `AUTO`, `AttrTypes`, `AttrTypesFor`, `Coerce` | How attribute text becomes values, for `static attrTypes`. |
|
|
92
|
+
| `expandAttributes(flat)` | Nests hyphenated names (`meta: { title }`) the way JSX and markup do. |
|
|
93
|
+
|
|
94
|
+
## Bases for your own classes
|
|
95
|
+
|
|
96
|
+
`Plane`, `RadialPlane`, `Series`, `SeriesRenderer`, `Marker`, `ShapeMarker`, `LineMarker`, `BarRenderer`, `Curve`, `StrokeCurve`, `Scale`, `TimeScale`, `Dimension`, `MappedDimension`, `Key`, `DecimationKernel`: see Custom elements, Custom renderers and Custom data and scales.
|
|
97
|
+
|
|
98
|
+
## Adapters
|
|
99
|
+
|
|
100
|
+
| Entry point | Export | Is |
|
|
101
|
+
|---|---|---|
|
|
102
|
+
| `inkplot/jsx-runtime` | `jsx`, `jsxs`, `Fragment`, `JSX` | The vanilla JSX runtime (set `jsxImportSource: "inkplot"`). |
|
|
103
|
+
| `inkplot/react` | a component per built-in element class (`Chart`, `Axis`, `LinePath`…), `reactWrapper(Class)`, `ChartView` | Components for React; one for a class of your own; showing a chart made another way. |
|
|
104
|
+
| `inkplot/web-components` | `defineElements(classes, { prefix, names?, registry? })` | Custom HTML elements for classes. |
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# inkplot topic: axes and scales
|
|
2
|
+
|
|
3
|
+
For: dates and times, categories, log and sqrt scales, tick labels and formats, axis limits, a second or reversed axis, number and date language.
|
|
4
|
+
|
|
5
|
+
Read `SKILL.md` first (rules, template, and the attributes of `Chart`, `CartesianPlane`, `Axis`, `LinearScale`, `DomainSeries`, `FlatDataSource`, `ObjectDataSource`, `LinePath`, `LinearCurve`). This file has the rest of what this topic needs: examples, notes, and the attributes of its elements. Everything here is exported from `'inkplot'`.
|
|
6
|
+
|
|
7
|
+
## Dates on x
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
```ts check title="Time series from objects"
|
|
11
|
+
import {
|
|
12
|
+
Axis,
|
|
13
|
+
CartesianPlane,
|
|
14
|
+
Chart,
|
|
15
|
+
DomainSeries,
|
|
16
|
+
IntlTimeScale,
|
|
17
|
+
Legend,
|
|
18
|
+
LinePath,
|
|
19
|
+
LinearCurve,
|
|
20
|
+
LinearScale,
|
|
21
|
+
ObjectDataSource,
|
|
22
|
+
lightTheme,
|
|
23
|
+
} from 'inkplot';
|
|
24
|
+
|
|
25
|
+
const rows = [
|
|
26
|
+
{ date: '2024-01-01', views: 120, signups: 12 },
|
|
27
|
+
{ date: '2024-01-02', views: 150, signups: 18 },
|
|
28
|
+
{ date: '2024-01-03', views: 140, signups: 15 },
|
|
29
|
+
];
|
|
30
|
+
const line = (name: string, field: 'views' | 'signups') =>
|
|
31
|
+
new DomainSeries(
|
|
32
|
+
{ name: name },
|
|
33
|
+
new ObjectDataSource({ source: rows, domain: (row) => Date.parse(row.date), value: field }),
|
|
34
|
+
new LinePath({}, new LinearCurve()),
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
export const chart = new Chart(
|
|
38
|
+
{ theme: lightTheme },
|
|
39
|
+
new CartesianPlane(
|
|
40
|
+
{},
|
|
41
|
+
new Axis({ orientation: 'bottom' }, new IntlTimeScale({ timeZone: 'UTC' })),
|
|
42
|
+
new Axis({ orientation: 'left' }, new LinearScale()),
|
|
43
|
+
line('Views', 'views'),
|
|
44
|
+
line('Signups', 'signups'),
|
|
45
|
+
),
|
|
46
|
+
new Legend({ side: 'bottom' }),
|
|
47
|
+
);
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Notes
|
|
51
|
+
|
|
52
|
+
- Time values are milliseconds since 1970 (`Date.UTC(…)`, `Date.parse(…)`). Daily values from 1 March 2024 in a `FlatDataSource`: `regularDomain: { start: Date.UTC(2024, 2, 1), step: 86400000 }`; any start works (`regularDomain: { start: 5 }` starts x at 5).
|
|
53
|
+
- `orientation` of an `Axis`: `'bottom'`, `'top'`, `'left'`, `'right'` for `CartesianPlane`; `'angle'`, `'radius'` for polar and radar.
|
|
54
|
+
|
|
55
|
+
| To… | Use |
|
|
56
|
+
|---|---|
|
|
57
|
+
| Set exact axis limits | `new Axis({ min: 0, max: 100 }, …)`; keep zero in range: `include: [0]`; headroom: `padding` |
|
|
58
|
+
| Label ticks yourself | ``format: (v) => `${v}%```, `ticks: [0, 50, 100]`, `tickStep: 1`, `tickCount: 5` |
|
|
59
|
+
| Reverse an axis | `inverted` |
|
|
60
|
+
| Second y axis | `new Axis({ id: 'b', orientation: 'right' }, …)` and `new DomainSeries({ valueAxis: 'b' }, …)` |
|
|
61
|
+
| Numbers and dates in a language | `new Chart({ locale: 'de' }, …)` (an axis or time scale can set its own); `format` beats it; the library's own words come from components that take yours |
|
|
62
|
+
|
|
63
|
+
`BandScale` puts categories at 0, 1, 2…: the data's domain is the category's index.
|
|
64
|
+
|
|
65
|
+
## Attributes of this topic's elements
|
|
66
|
+
|
|
67
|
+
An attribute followed by `(required)` must be given. Every element also takes `id`, `meta`, `visible` and `style`.
|
|
68
|
+
|
|
69
|
+
<!-- api:start -->
|
|
70
|
+
### LogScale
|
|
71
|
+
|
|
72
|
+
Logarithmic.
|
|
73
|
+
|
|
74
|
+
**In** an axis · **Holds** none
|
|
75
|
+
|
|
76
|
+
| Attribute | Type | |
|
|
77
|
+
|---|---|---|
|
|
78
|
+
| `base` | `number` | Default 10. |
|
|
79
|
+
|
|
80
|
+
### SqrtScale
|
|
81
|
+
|
|
82
|
+
Square root: gives zero a place.
|
|
83
|
+
|
|
84
|
+
**In** an axis · **Holds** none
|
|
85
|
+
|
|
86
|
+
No attributes of its own.
|
|
87
|
+
|
|
88
|
+
### BandScale
|
|
89
|
+
|
|
90
|
+
Categories in equal bands.
|
|
91
|
+
|
|
92
|
+
**In** an axis · **Holds** none
|
|
93
|
+
|
|
94
|
+
| Attribute | Type | |
|
|
95
|
+
|---|---|---|
|
|
96
|
+
| `categories` (required) | `readonly string[]` | Category labels in order; the domain values are indexes into this list. |
|
|
97
|
+
| `gap` | `number` | Fraction of each band left empty between neighbours, 0..1. Default 0.2. |
|
|
98
|
+
|
|
99
|
+
### IntlTimeScale
|
|
100
|
+
|
|
101
|
+
Timestamps on the calendar, with Date and Intl.
|
|
102
|
+
|
|
103
|
+
**In** an axis · **Holds** none
|
|
104
|
+
|
|
105
|
+
| Attribute | Type | |
|
|
106
|
+
|---|---|---|
|
|
107
|
+
| `locale` | `string` | The language the labels are written in (a BCP 47 tag). Default: the runtime's. |
|
|
108
|
+
| `timeZone` | `string` | An IANA time zone name, 'UTC' or 'local' (the runtime's). Default 'UTC'. |
|
|
109
|
+
| `weekStart` | `number` | The first day of a week, 0 for Sunday to 6. Default 1, Monday. |
|
|
110
|
+
| `formats` | `Partial<Record<TimeRank, Format>>` | Replaces the default format of a rank. |
|
|
111
|
+
|
|
112
|
+
### TemporalTimeScale
|
|
113
|
+
|
|
114
|
+
Timestamps on the calendar, with Temporal.
|
|
115
|
+
|
|
116
|
+
**In** an axis · **Holds** none
|
|
117
|
+
|
|
118
|
+
| Attribute | Type | |
|
|
119
|
+
|---|---|---|
|
|
120
|
+
| `locale` | `string` | The language the labels are written in (a BCP 47 tag). Default: the runtime's. |
|
|
121
|
+
| `temporal` | `Opaque<TemporalLike>` | Where `Temporal` comes from, when the runtime has none. |
|
|
122
|
+
| `timeZone` | `string` | An IANA time zone name, 'UTC' or 'local' (the runtime's). Default 'UTC'. |
|
|
123
|
+
| `weekStart` | `number` | The first day of a week, 0 for Sunday to 6. Default 1, Monday. |
|
|
124
|
+
| `formats` | `Partial<Record<TimeRank, Format>>` | Replaces the default format of a rank. |
|
|
125
|
+
<!-- api:end -->
|