@weasel-js/plot 1.15.0 → 1.15.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/README.md +40 -5
- package/dist/chunk-HA77BIQF.js +320 -0
- package/dist/chunk-HA77BIQF.js.map +1 -0
- package/dist/index.d.ts +1013 -235
- package/dist/index.js +3528 -500
- package/dist/index.js.map +1 -1
- package/dist/scales.d.ts +2 -0
- package/dist/scales.entry-BoLQpsxi.d.ts +275 -0
- package/dist/scales.js +3 -0
- package/dist/scales.js.map +1 -0
- package/package.json +9 -5
package/README.md
CHANGED
|
@@ -16,7 +16,15 @@ npm install @weasel-js/plot
|
|
|
16
16
|
|
|
17
17
|
**Scales, axes and marks.** A scale maps values onto a range and says which
|
|
18
18
|
values an axis marks and how they read: `linearScale`, `logScale`,
|
|
19
|
-
`bandScale`, `timeScale` (ticks on calendar units, in UTC)
|
|
19
|
+
`bandScale`, `timeScale` (ticks on calendar units, in UTC), `ordinalScale`, and
|
|
20
|
+
`polarScale` (a value along each of several spokes from a center).
|
|
21
|
+
A linear scale also places ticks by room rather than count: `spacedTicks({
|
|
22
|
+
minSpacing, inset })` takes the finest 1/2/5 step that keeps neighbors
|
|
23
|
+
`minSpacing` apart along the range, drops any within `inset` of an end, and
|
|
24
|
+
returns the step and the decimals the column shares, which `formatTick` writes
|
|
25
|
+
every label to. The scales import on their own, with no React, DOM or scene,
|
|
26
|
+
from `@weasel-js/plot/scales`; a control that places values along a track calls
|
|
27
|
+
one with a range of `[0, 1]`.
|
|
20
28
|
`axisMarks` draws an axis from any of the first four: a rule, ticks, labels
|
|
21
29
|
measured through `@weasel-js/text`, grid lines and a title. The mark builders
|
|
22
30
|
(`barMark`, `spanMark`, `lineMark`, `areaMark`, `pointMark`, `arcMark`,
|
|
@@ -24,14 +32,41 @@ measured through `@weasel-js/text`, grid lines and a title. The mark builders
|
|
|
24
32
|
and data the kit's own painters draw, with the datum under `plotMark`, so a
|
|
25
33
|
hit-test on a mark reaches its value.
|
|
26
34
|
|
|
27
|
-
**Chart specs.** `PlotData` is a union of chart specs on `kind
|
|
28
|
-
|
|
35
|
+
**Chart specs.** `PlotData` is a union of chart specs on `kind`:
|
|
36
|
+
|
|
37
|
+
| Kind | Spec | Edits |
|
|
38
|
+
| --- | --- | --- |
|
|
39
|
+
| `xychart` | bar and line series over a category band or a numeric range | drag a bar's end or a line's point |
|
|
40
|
+
| `gantt` | tasks in sections, each starting on a date, after other tasks, or after the one before, and ending on a date, after a duration, or when another starts; `dateFormat`, `axisFormat`, `excludes`, `todayMarker` | drag a task to move its start, or its end to change its length; tasks after it follow |
|
|
41
|
+
| `timeline` | periods in sections, each with its events | reorder periods by dragging a label; text |
|
|
42
|
+
| `pie` | labeled values; `showData` | a value, typed in the legend; labels |
|
|
43
|
+
| `quadrant` | points from 0 to 1 on both axes, axis and quadrant labels | drag a point; text |
|
|
44
|
+
| `journey` | tasks in sections, each scored 1 to 5, with its actors | drag a score; text |
|
|
45
|
+
| `gitgraph` | commits, branches, checkouts, merges and cherry-picks, replayed into a lane per branch | tags |
|
|
46
|
+
| `sankey` | flows from source to target | a flow's value; node names |
|
|
47
|
+
| `packet` | fields of bits laid in rows (a band scale of bits) | labels |
|
|
48
|
+
| `radar` | curves over axes (a `polarScale`), drawn as areas | drag a point along its axis; axis labels |
|
|
49
|
+
|
|
50
|
+
Each kind also has its title edited in place.
|
|
29
51
|
`plotSpecs(data, { box })` compiles one to scene node specs: a group root whose
|
|
30
52
|
data is `{ plot: { data, theme } }`, then every mark under it, in the root's
|
|
31
53
|
frame. `replacePlotData` swaps a root's spec and rebuilds its marks as one undo
|
|
32
54
|
entry. `plotEditing({ scene })` gives the handle layer and the contribution
|
|
33
|
-
that bind a drag on a bar's end
|
|
34
|
-
|
|
55
|
+
that bind a drag on a handle (a bar's end, a task's span) to `plot.dragValue`.
|
|
56
|
+
A text mark whose datum names an `edit` is the spec's text: `foldPlotText`
|
|
57
|
+
turns a text edit of it into one edit of the spec, and `usePlotTextEdit` gives
|
|
58
|
+
a `SceneCanvas` the options that do so. `PlotView` hosts one chart on a canvas
|
|
59
|
+
of its own with all of it wired.
|
|
60
|
+
|
|
61
|
+
Every collection a spec holds can be authored from nothing: each kind has
|
|
62
|
+
pure edits that insert, remove, and reorder its slices, series, rows, tasks,
|
|
63
|
+
commits, links, fields or axes (`insertPieSlice`, `removeGanttTask`,
|
|
64
|
+
`moveRadarAxis`, …), and set the fields a drag cannot reach. `plotSchemaOf`
|
|
65
|
+
describes a spec of any kind as fields and tables of rows, some holding tables
|
|
66
|
+
of their own under each row, every read and write going through those edits,
|
|
67
|
+
so a host builds a form or a grid with no knowledge of kinds.
|
|
68
|
+
`@weasel-js/ui`'s `PlotDataPanel` is that form. Commit what it proposes with
|
|
69
|
+
`replacePlotData`, one undo entry per edit.
|
|
35
70
|
|
|
36
71
|
Colors come from a `PlotTheme`, by role: `text`, `axis`, `grid`, and `series`,
|
|
37
72
|
which series take in turn. `plotThemeFrom` builds one from a resolved
|
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
// src/scales/linear.ts
|
|
2
|
+
var DEFAULT_TICKS = 5;
|
|
3
|
+
function tickStep(lo, hi, count = DEFAULT_TICKS) {
|
|
4
|
+
const span = Math.abs(hi - lo);
|
|
5
|
+
if (span === 0 || !Number.isFinite(span)) return 1;
|
|
6
|
+
const raw = span / Math.max(1, count);
|
|
7
|
+
const power = 10 ** Math.floor(Math.log10(raw));
|
|
8
|
+
const error = raw / power;
|
|
9
|
+
const factor = error >= Math.sqrt(50) ? 10 : error >= Math.sqrt(10) ? 5 : error >= Math.sqrt(2) ? 2 : 1;
|
|
10
|
+
return factor * power;
|
|
11
|
+
}
|
|
12
|
+
var MAX_DECIMALS = 20;
|
|
13
|
+
function decimalsOf(step) {
|
|
14
|
+
if (!(step > 0) || !Number.isFinite(step)) return 0;
|
|
15
|
+
return Math.min(MAX_DECIMALS, Math.max(0, -Math.floor(Math.log10(step) + 1e-9)));
|
|
16
|
+
}
|
|
17
|
+
function niceStep(rough) {
|
|
18
|
+
const mag = 10 ** Math.floor(Math.log10(rough));
|
|
19
|
+
const norm = rough / mag;
|
|
20
|
+
return (norm <= 1 ? 1 : norm <= 2 ? 2 : norm <= 5 ? 5 : 10) * mag;
|
|
21
|
+
}
|
|
22
|
+
var onGrid = (i, step) => Number((i * step).toFixed(decimalsOf(step)));
|
|
23
|
+
function stepTicks(lo, hi, step) {
|
|
24
|
+
const [a, b] = lo <= hi ? [lo, hi] : [hi, lo];
|
|
25
|
+
const out = [];
|
|
26
|
+
for (let i = Math.ceil(a / step - 1e-9); i <= Math.floor(b / step + 1e-9); i++) out.push(onGrid(i, step));
|
|
27
|
+
return lo <= hi ? out : out.reverse();
|
|
28
|
+
}
|
|
29
|
+
function spacedTicks(domain, length, options) {
|
|
30
|
+
const lo = Math.min(domain[0], domain[1]);
|
|
31
|
+
const hi = Math.max(domain[0], domain[1]);
|
|
32
|
+
const span = hi - lo;
|
|
33
|
+
const { minSpacing, inset = 0 } = options;
|
|
34
|
+
if (!(span > 0) || !Number.isFinite(span) || !(length > 0) || !(minSpacing > 0)) return { values: [], step: 0, decimals: 0 };
|
|
35
|
+
const perUnit = span / length;
|
|
36
|
+
const step = niceStep(minSpacing * perUnit);
|
|
37
|
+
const decimals = decimalsOf(step);
|
|
38
|
+
const first = Math.ceil((lo + inset * perUnit) / step - 1e-9);
|
|
39
|
+
const last = Math.floor((hi - inset * perUnit) / step + 1e-9);
|
|
40
|
+
const values = [];
|
|
41
|
+
for (let i = first; i <= last; i++) values.push(onGrid(i, step) + 0);
|
|
42
|
+
return { values, step, decimals };
|
|
43
|
+
}
|
|
44
|
+
function formatNumber(value, step) {
|
|
45
|
+
const fixed = value.toFixed(Math.min(20, decimalsOf(step)));
|
|
46
|
+
return fixed.includes(".") ? fixed.replace(/\.?0+$/, "") : fixed;
|
|
47
|
+
}
|
|
48
|
+
function niceDomain(domain, count = DEFAULT_TICKS) {
|
|
49
|
+
const [lo, hi] = domain;
|
|
50
|
+
if (lo === hi) return lo === 0 ? [0, 1] : [Math.min(0, lo), Math.max(0, hi)];
|
|
51
|
+
const step = tickStep(lo, hi, count);
|
|
52
|
+
const down = (v) => onGrid(Math.floor(v / step + 1e-9), step);
|
|
53
|
+
const up = (v) => onGrid(Math.ceil(v / step - 1e-9), step);
|
|
54
|
+
return lo < hi ? [down(lo), up(hi)] : [up(lo), down(hi)];
|
|
55
|
+
}
|
|
56
|
+
function linearScale(opts) {
|
|
57
|
+
const domain = opts.nice !== void 0 ? niceDomain(opts.domain, opts.nice) : [opts.domain[0], opts.domain[1]];
|
|
58
|
+
const range = [opts.range[0], opts.range[1]];
|
|
59
|
+
const [d0, d1] = domain;
|
|
60
|
+
const [r0, r1] = range;
|
|
61
|
+
const span = d1 - d0;
|
|
62
|
+
const map = (v) => span === 0 ? (r0 + r1) / 2 : r0 + (v - d0) / span * (r1 - r0);
|
|
63
|
+
const step = (count = DEFAULT_TICKS) => tickStep(d0, d1, count);
|
|
64
|
+
return {
|
|
65
|
+
kind: "linear",
|
|
66
|
+
domain,
|
|
67
|
+
range,
|
|
68
|
+
map,
|
|
69
|
+
position: map,
|
|
70
|
+
invert: (at) => r1 === r0 ? d0 : d0 + (at - r0) / (r1 - r0) * span,
|
|
71
|
+
tickStep: step,
|
|
72
|
+
spacedTicks: (options) => spacedTicks(domain, Math.abs(r1 - r0), options),
|
|
73
|
+
ticks: (count = DEFAULT_TICKS) => stepTicks(d0, d1, step(count)),
|
|
74
|
+
format: (v) => formatNumber(v, step())
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// src/scales/tickFormat.ts
|
|
79
|
+
var MAX_DECIMALS2 = 20;
|
|
80
|
+
function tickDecimals(values) {
|
|
81
|
+
let most = 0;
|
|
82
|
+
for (const v of values) {
|
|
83
|
+
if (!Number.isFinite(v)) continue;
|
|
84
|
+
let d = 0;
|
|
85
|
+
while (d < MAX_DECIMALS2 && Math.abs(Number(v.toFixed(d)) - v) > 1e-9 * Math.max(1, Math.abs(v))) d++;
|
|
86
|
+
most = Math.max(most, d);
|
|
87
|
+
}
|
|
88
|
+
return most;
|
|
89
|
+
}
|
|
90
|
+
function formatTick(value, ctx) {
|
|
91
|
+
const text = value.toFixed(ctx.decimals);
|
|
92
|
+
return /^-0(\.0*)?$/.test(text) ? text.slice(1) : text;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// src/scales/log.ts
|
|
96
|
+
function logScale(opts) {
|
|
97
|
+
const base = opts.base ?? 10;
|
|
98
|
+
const [d0, d1] = opts.domain;
|
|
99
|
+
if (!(d0 > 0 && d1 > 0)) throw new Error(`logScale: a domain of ${d0}..${d1} does not lie above zero`);
|
|
100
|
+
const [r0, r1] = opts.range;
|
|
101
|
+
const log = (v) => Math.log(v) / Math.log(base);
|
|
102
|
+
const l0 = log(d0);
|
|
103
|
+
const l1 = log(d1);
|
|
104
|
+
const map = (v) => l1 === l0 ? (r0 + r1) / 2 : r0 + (log(v) - l0) / (l1 - l0) * (r1 - r0);
|
|
105
|
+
const ticks = (count = 5) => {
|
|
106
|
+
const [lo, hi] = l0 <= l1 ? [l0, l1] : [l1, l0];
|
|
107
|
+
const first = Math.floor(lo + 1e-9);
|
|
108
|
+
const last = Math.ceil(hi - 1e-9);
|
|
109
|
+
const steps = last - first < count / 2 && base === 10 ? [1, 2, 5] : [1];
|
|
110
|
+
const out = [];
|
|
111
|
+
for (let p = first; p <= last; p++) {
|
|
112
|
+
for (const m of steps) {
|
|
113
|
+
const v = Number((m * base ** p).toPrecision(12));
|
|
114
|
+
if (log(v) >= lo - 1e-9 && log(v) <= hi + 1e-9) out.push(v);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return l0 <= l1 ? out : out.reverse();
|
|
118
|
+
};
|
|
119
|
+
return {
|
|
120
|
+
kind: "log",
|
|
121
|
+
base,
|
|
122
|
+
domain: [d0, d1],
|
|
123
|
+
range: [r0, r1],
|
|
124
|
+
map,
|
|
125
|
+
position: map,
|
|
126
|
+
invert: (at) => base ** (r1 === r0 ? l0 : l0 + (at - r0) / (r1 - r0) * (l1 - l0)),
|
|
127
|
+
ticks,
|
|
128
|
+
format: (v) => v >= 1 ? formatNumber(v, 1) : formatNumber(v, 10 ** Math.floor(Math.log10(v)))
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// src/scales/band.ts
|
|
133
|
+
function bandScale(opts) {
|
|
134
|
+
const domain = [...opts.domain];
|
|
135
|
+
const [r0, r1] = opts.range;
|
|
136
|
+
const inner = Math.min(1, Math.max(0, opts.paddingInner ?? 0.2));
|
|
137
|
+
const outer = Math.max(0, opts.paddingOuter ?? inner / 2);
|
|
138
|
+
const n = domain.length;
|
|
139
|
+
const step = n === 0 ? 0 : (r1 - r0) / Math.max(1e-9, n - inner + 2 * outer);
|
|
140
|
+
const bandwidth = Math.abs(step * (1 - inner));
|
|
141
|
+
const index = new Map(domain.map((key, i) => [key, i]));
|
|
142
|
+
const startAt = (i) => r0 + step * (outer + i) + (step < 0 ? step * (1 - inner) : 0);
|
|
143
|
+
const start = (key) => {
|
|
144
|
+
const i = index.get(key);
|
|
145
|
+
return i === void 0 ? Number.NaN : startAt(i);
|
|
146
|
+
};
|
|
147
|
+
return {
|
|
148
|
+
kind: "band",
|
|
149
|
+
domain,
|
|
150
|
+
range: [r0, r1],
|
|
151
|
+
bandwidth,
|
|
152
|
+
step: Math.abs(step),
|
|
153
|
+
start,
|
|
154
|
+
position: (key) => start(key) + bandwidth / 2,
|
|
155
|
+
invert: (at) => {
|
|
156
|
+
if (n === 0) return void 0;
|
|
157
|
+
const i = Math.round((at - r0) / step - outer - (1 - inner) / 2);
|
|
158
|
+
return domain[Math.min(n - 1, Math.max(0, i))];
|
|
159
|
+
},
|
|
160
|
+
ticks: () => [...domain],
|
|
161
|
+
format: (key) => key
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// src/scales/time.ts
|
|
166
|
+
var SECOND = 1e3;
|
|
167
|
+
var MINUTE = 60 * SECOND;
|
|
168
|
+
var HOUR = 60 * MINUTE;
|
|
169
|
+
var DAY = 24 * HOUR;
|
|
170
|
+
var INTERVALS = [
|
|
171
|
+
{ ms: SECOND, unit: "second" },
|
|
172
|
+
{ ms: 5 * SECOND, unit: "second" },
|
|
173
|
+
{ ms: 15 * SECOND, unit: "second" },
|
|
174
|
+
{ ms: 30 * SECOND, unit: "second" },
|
|
175
|
+
{ ms: MINUTE, unit: "minute" },
|
|
176
|
+
{ ms: 5 * MINUTE, unit: "minute" },
|
|
177
|
+
{ ms: 15 * MINUTE, unit: "minute" },
|
|
178
|
+
{ ms: 30 * MINUTE, unit: "minute" },
|
|
179
|
+
{ ms: HOUR, unit: "hour" },
|
|
180
|
+
{ ms: 3 * HOUR, unit: "hour" },
|
|
181
|
+
{ ms: 6 * HOUR, unit: "hour" },
|
|
182
|
+
{ ms: 12 * HOUR, unit: "hour" },
|
|
183
|
+
{ ms: DAY, unit: "day" },
|
|
184
|
+
{ ms: 2 * DAY, unit: "day" },
|
|
185
|
+
{ ms: 7 * DAY, unit: "day" },
|
|
186
|
+
{ months: 1, unit: "month" },
|
|
187
|
+
{ months: 3, unit: "month" },
|
|
188
|
+
{ months: 12, unit: "year" }
|
|
189
|
+
];
|
|
190
|
+
var MONTH_MS = 30 * DAY;
|
|
191
|
+
var spanOf = (i) => i.ms ?? i.months * MONTH_MS;
|
|
192
|
+
function intervalFor(span, count) {
|
|
193
|
+
const target = span / Math.max(1, count);
|
|
194
|
+
let best = INTERVALS[0];
|
|
195
|
+
for (const i of INTERVALS) if (Math.abs(Math.log(spanOf(i) / target)) < Math.abs(Math.log(spanOf(best) / target))) best = i;
|
|
196
|
+
if (best.unit === "year" && target > 12 * MONTH_MS) {
|
|
197
|
+
const years = 10 ** Math.floor(Math.log10(target / (12 * MONTH_MS)));
|
|
198
|
+
return { months: 12 * years, unit: "year" };
|
|
199
|
+
}
|
|
200
|
+
return best;
|
|
201
|
+
}
|
|
202
|
+
function gridTicks(lo, hi, interval) {
|
|
203
|
+
const out = [];
|
|
204
|
+
if (interval.ms !== void 0) {
|
|
205
|
+
for (let t = Math.ceil(lo / interval.ms) * interval.ms; t <= hi; t += interval.ms) out.push(t);
|
|
206
|
+
return out;
|
|
207
|
+
}
|
|
208
|
+
const at = new Date(lo);
|
|
209
|
+
let month = at.getUTCFullYear() * 12 + at.getUTCMonth();
|
|
210
|
+
month = Math.ceil(month / interval.months) * interval.months;
|
|
211
|
+
for (; ; month += interval.months) {
|
|
212
|
+
const t = Date.UTC(Math.floor(month / 12), month % 12, 1);
|
|
213
|
+
if (t < lo) continue;
|
|
214
|
+
if (t > hi) break;
|
|
215
|
+
out.push(t);
|
|
216
|
+
}
|
|
217
|
+
return out;
|
|
218
|
+
}
|
|
219
|
+
var pad = (n) => String(n).padStart(2, "0");
|
|
220
|
+
function formatInstant(t, unit) {
|
|
221
|
+
const d = new Date(t);
|
|
222
|
+
const date = `${d.getUTCFullYear()}-${pad(d.getUTCMonth() + 1)}-${pad(d.getUTCDate())}`;
|
|
223
|
+
const time = `${pad(d.getUTCHours())}:${pad(d.getUTCMinutes())}`;
|
|
224
|
+
switch (unit) {
|
|
225
|
+
case "year":
|
|
226
|
+
return String(d.getUTCFullYear());
|
|
227
|
+
case "month":
|
|
228
|
+
return date.slice(0, 7);
|
|
229
|
+
case "day":
|
|
230
|
+
return date;
|
|
231
|
+
case "hour":
|
|
232
|
+
case "minute":
|
|
233
|
+
return d.getUTCHours() === 0 && d.getUTCMinutes() === 0 ? date : time;
|
|
234
|
+
case "second":
|
|
235
|
+
return `${time}:${pad(d.getUTCSeconds())}`;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
function timeScale(opts) {
|
|
239
|
+
const [d0, d1] = opts.domain;
|
|
240
|
+
const [r0, r1] = opts.range;
|
|
241
|
+
const span = d1 - d0;
|
|
242
|
+
const map = (v) => span === 0 ? (r0 + r1) / 2 : r0 + (v - d0) / span * (r1 - r0);
|
|
243
|
+
const interval = (count = 5) => intervalFor(Math.abs(span), count);
|
|
244
|
+
return {
|
|
245
|
+
kind: "time",
|
|
246
|
+
domain: [d0, d1],
|
|
247
|
+
range: [r0, r1],
|
|
248
|
+
map,
|
|
249
|
+
position: map,
|
|
250
|
+
invert: (at) => r1 === r0 ? d0 : d0 + (at - r0) / (r1 - r0) * span,
|
|
251
|
+
ticks: (count = 5) => {
|
|
252
|
+
const out = gridTicks(Math.min(d0, d1), Math.max(d0, d1), interval(count));
|
|
253
|
+
return d0 <= d1 ? out : out.reverse();
|
|
254
|
+
},
|
|
255
|
+
format: (v) => formatInstant(v, interval().unit)
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// src/scales/ordinal.ts
|
|
260
|
+
function ordinalScale(opts) {
|
|
261
|
+
if (opts.range.length === 0) throw new Error("ordinalScale: an empty range");
|
|
262
|
+
const domain = [...opts.domain];
|
|
263
|
+
const index = new Map(domain.map((key, i) => [key, i]));
|
|
264
|
+
const range = [...opts.range];
|
|
265
|
+
return {
|
|
266
|
+
kind: "ordinal",
|
|
267
|
+
domain,
|
|
268
|
+
range,
|
|
269
|
+
map: (key) => {
|
|
270
|
+
let i = index.get(key);
|
|
271
|
+
if (i === void 0) {
|
|
272
|
+
i = domain.length;
|
|
273
|
+
domain.push(key);
|
|
274
|
+
index.set(key, i);
|
|
275
|
+
}
|
|
276
|
+
return range[i % range.length];
|
|
277
|
+
},
|
|
278
|
+
ticks: () => [...domain],
|
|
279
|
+
format: (key) => key
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// src/scales/polar.ts
|
|
284
|
+
function polarScale(opts) {
|
|
285
|
+
const center = { x: opts.center.x, y: opts.center.y };
|
|
286
|
+
const radius = [opts.radius[0], opts.radius[1]];
|
|
287
|
+
const domain = [opts.domain[0], opts.domain[1]];
|
|
288
|
+
const axes = Math.max(1, Math.floor(opts.axes));
|
|
289
|
+
const start = opts.startAngle ?? 0;
|
|
290
|
+
const linear = linearScale({ domain, range: radius });
|
|
291
|
+
const angle = (i) => start + 2 * Math.PI * i / axes;
|
|
292
|
+
const lo = Math.min(domain[0], domain[1]);
|
|
293
|
+
const hi = Math.max(domain[0], domain[1]);
|
|
294
|
+
return {
|
|
295
|
+
kind: "polar",
|
|
296
|
+
center,
|
|
297
|
+
radius,
|
|
298
|
+
domain,
|
|
299
|
+
axes,
|
|
300
|
+
angle,
|
|
301
|
+
radiusAt: linear.map,
|
|
302
|
+
point(i, value) {
|
|
303
|
+
const r = linear.map(value);
|
|
304
|
+
const a = angle(i);
|
|
305
|
+
return { x: center.x + r * Math.sin(a), y: center.y - r * Math.cos(a) };
|
|
306
|
+
},
|
|
307
|
+
valueAt(i, at) {
|
|
308
|
+
const a = angle(i);
|
|
309
|
+
const along = (at.x - center.x) * Math.sin(a) - (at.y - center.y) * Math.cos(a);
|
|
310
|
+
return Math.min(hi, Math.max(lo, linear.invert(along)));
|
|
311
|
+
},
|
|
312
|
+
tickStep: linear.tickStep,
|
|
313
|
+
ticks: linear.ticks,
|
|
314
|
+
format: linear.format
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
export { bandScale, decimalsOf, formatInstant, formatNumber, formatTick, linearScale, logScale, niceDomain, niceStep, ordinalScale, polarScale, stepTicks, tickDecimals, tickStep, timeScale };
|
|
319
|
+
//# sourceMappingURL=chunk-HA77BIQF.js.map
|
|
320
|
+
//# sourceMappingURL=chunk-HA77BIQF.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/scales/linear.ts","../src/scales/tickFormat.ts","../src/scales/log.ts","../src/scales/band.ts","../src/scales/time.ts","../src/scales/ordinal.ts","../src/scales/polar.ts"],"names":["MAX_DECIMALS"],"mappings":";AAsCA,IAAM,aAAA,GAAgB,CAAA;AAGf,SAAS,QAAA,CAAS,EAAA,EAAY,EAAA,EAAY,KAAA,GAAQ,aAAA,EAAuB;AAC9E,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,GAAA,CAAI,EAAA,GAAK,EAAE,CAAA;AAC7B,EAAA,IAAI,SAAS,CAAA,IAAK,CAAC,OAAO,QAAA,CAAS,IAAI,GAAG,OAAO,CAAA;AACjD,EAAA,MAAM,GAAA,GAAM,IAAA,GAAO,IAAA,CAAK,GAAA,CAAI,GAAG,KAAK,CAAA;AACpC,EAAA,MAAM,QAAQ,EAAA,IAAM,IAAA,CAAK,MAAM,IAAA,CAAK,KAAA,CAAM,GAAG,CAAC,CAAA;AAC9C,EAAA,MAAM,QAAQ,GAAA,GAAM,KAAA;AACpB,EAAA,MAAM,SAAS,KAAA,IAAS,IAAA,CAAK,KAAK,EAAE,CAAA,GAAI,KAAK,KAAA,IAAS,IAAA,CAAK,IAAA,CAAK,EAAE,IAAI,CAAA,GAAI,KAAA,IAAS,KAAK,IAAA,CAAK,CAAC,IAAI,CAAA,GAAI,CAAA;AACtG,EAAA,OAAO,MAAA,GAAS,KAAA;AAClB;AAEA,IAAM,YAAA,GAAe,EAAA;AAGd,SAAS,WAAW,IAAA,EAAsB;AAC/C,EAAA,IAAI,EAAE,OAAO,CAAA,CAAA,IAAM,CAAC,OAAO,QAAA,CAAS,IAAI,GAAG,OAAO,CAAA;AAClD,EAAA,OAAO,IAAA,CAAK,GAAA,CAAI,YAAA,EAAc,IAAA,CAAK,IAAI,CAAA,EAAG,CAAC,IAAA,CAAK,KAAA,CAAM,KAAK,KAAA,CAAM,IAAI,CAAA,GAAI,IAAI,CAAC,CAAC,CAAA;AACjF;AAIO,SAAS,SAAS,KAAA,EAAuB;AAC9C,EAAA,MAAM,MAAM,EAAA,IAAM,IAAA,CAAK,MAAM,IAAA,CAAK,KAAA,CAAM,KAAK,CAAC,CAAA;AAC9C,EAAA,MAAM,OAAO,KAAA,GAAQ,GAAA;AACrB,EAAA,OAAA,CAAQ,IAAA,IAAQ,IAAI,CAAA,GAAI,IAAA,IAAQ,IAAI,CAAA,GAAI,IAAA,IAAQ,CAAA,GAAI,CAAA,GAAI,EAAA,IAAM,GAAA;AAChE;AAGA,IAAM,MAAA,GAAS,CAAC,CAAA,EAAW,IAAA,KAAyB,MAAA,CAAA,CAAQ,CAAA,GAAI,IAAA,EAAM,OAAA,CAAQ,UAAA,CAAW,IAAI,CAAC,CAAC,CAAA;AAGxF,SAAS,SAAA,CAAU,EAAA,EAAY,EAAA,EAAY,IAAA,EAAwB;AACxE,EAAA,MAAM,CAAC,CAAA,EAAG,CAAC,CAAA,GAAI,EAAA,IAAM,EAAA,GAAK,CAAC,EAAA,EAAI,EAAE,CAAA,GAAI,CAAC,EAAA,EAAI,EAAE,CAAA;AAC5C,EAAA,MAAM,MAAgB,EAAC;AACvB,EAAA,KAAA,IAAS,CAAA,GAAI,KAAK,IAAA,CAAK,CAAA,GAAI,OAAO,IAAI,CAAA,EAAG,KAAK,IAAA,CAAK,KAAA,CAAM,IAAI,IAAA,GAAO,IAAI,GAAG,CAAA,EAAA,EAAK,GAAA,CAAI,KAAK,MAAA,CAAO,CAAA,EAAG,IAAI,CAAC,CAAA;AACxG,EAAA,OAAO,EAAA,IAAM,EAAA,GAAK,GAAA,GAAM,GAAA,CAAI,OAAA,EAAQ;AACtC;AAGA,SAAS,WAAA,CAAY,MAAA,EAAmC,MAAA,EAAgB,OAAA,EAAqC;AAC3G,EAAA,MAAM,EAAA,GAAK,KAAK,GAAA,CAAI,MAAA,CAAO,CAAC,CAAA,EAAG,MAAA,CAAO,CAAC,CAAC,CAAA;AACxC,EAAA,MAAM,EAAA,GAAK,KAAK,GAAA,CAAI,MAAA,CAAO,CAAC,CAAA,EAAG,MAAA,CAAO,CAAC,CAAC,CAAA;AACxC,EAAA,MAAM,OAAO,EAAA,GAAK,EAAA;AAClB,EAAA,MAAM,EAAE,UAAA,EAAY,KAAA,GAAQ,CAAA,EAAE,GAAI,OAAA;AAClC,EAAA,IAAI,EAAE,OAAO,CAAA,CAAA,IAAM,CAAC,OAAO,QAAA,CAAS,IAAI,CAAA,IAAK,EAAE,MAAA,GAAS,CAAA,CAAA,IAAM,EAAE,UAAA,GAAa,CAAA,CAAA,SAAW,EAAE,MAAA,EAAQ,EAAC,EAAG,IAAA,EAAM,CAAA,EAAG,QAAA,EAAU,CAAA,EAAE;AAC3H,EAAA,MAAM,UAAU,IAAA,GAAO,MAAA;AACvB,EAAA,MAAM,IAAA,GAAO,QAAA,CAAS,UAAA,GAAa,OAAO,CAAA;AAC1C,EAAA,MAAM,QAAA,GAAW,WAAW,IAAI,CAAA;AAChC,EAAA,MAAM,QAAQ,IAAA,CAAK,IAAA,CAAA,CAAM,KAAK,KAAA,GAAQ,OAAA,IAAW,OAAO,IAAI,CAAA;AAC5D,EAAA,MAAM,OAAO,IAAA,CAAK,KAAA,CAAA,CAAO,KAAK,KAAA,GAAQ,OAAA,IAAW,OAAO,IAAI,CAAA;AAC5D,EAAA,MAAM,SAAmB,EAAC;AAC1B,EAAA,KAAA,IAAS,CAAA,GAAI,KAAA,EAAO,CAAA,IAAK,IAAA,EAAM,CAAA,EAAA,EAAK,MAAA,CAAO,IAAA,CAAK,MAAA,CAAO,CAAA,EAAG,IAAI,CAAA,GAAI,CAAC,CAAA;AACnE,EAAA,OAAO,EAAE,MAAA,EAAQ,IAAA,EAAM,QAAA,EAAS;AAClC;AAGO,SAAS,YAAA,CAAa,OAAe,IAAA,EAAsB;AAChE,EAAA,MAAM,KAAA,GAAQ,MAAM,OAAA,CAAQ,IAAA,CAAK,IAAI,EAAA,EAAI,UAAA,CAAW,IAAI,CAAC,CAAC,CAAA;AAC1D,EAAA,OAAO,KAAA,CAAM,SAAS,GAAG,CAAA,GAAI,MAAM,OAAA,CAAQ,QAAA,EAAU,EAAE,CAAA,GAAI,KAAA;AAC7D;AAGO,SAAS,UAAA,CAAW,MAAA,EAAmC,KAAA,GAAQ,aAAA,EAAiC;AACrG,EAAA,MAAM,CAAC,EAAA,EAAI,EAAE,CAAA,GAAI,MAAA;AACjB,EAAA,IAAI,OAAO,EAAA,EAAI,OAAO,OAAO,CAAA,GAAI,CAAC,GAAG,CAAC,CAAA,GAAI,CAAC,IAAA,CAAK,GAAA,CAAI,GAAG,EAAE,CAAA,EAAG,KAAK,GAAA,CAAI,CAAA,EAAG,EAAE,CAAC,CAAA;AAC3E,EAAA,MAAM,IAAA,GAAO,QAAA,CAAS,EAAA,EAAI,EAAA,EAAI,KAAK,CAAA;AACnC,EAAA,MAAM,IAAA,GAAO,CAAC,CAAA,KAAc,MAAA,CAAO,IAAA,CAAK,MAAM,CAAA,GAAI,IAAA,GAAO,IAAI,CAAA,EAAG,IAAI,CAAA;AACpE,EAAA,MAAM,EAAA,GAAK,CAAC,CAAA,KAAc,MAAA,CAAO,IAAA,CAAK,KAAK,CAAA,GAAI,IAAA,GAAO,IAAI,CAAA,EAAG,IAAI,CAAA;AACjE,EAAA,OAAO,KAAK,EAAA,GAAK,CAAC,IAAA,CAAK,EAAE,GAAG,EAAA,CAAG,EAAE,CAAC,CAAA,GAAI,CAAC,EAAA,CAAG,EAAE,CAAA,EAAG,IAAA,CAAK,EAAE,CAAC,CAAA;AACzD;AAGO,SAAS,YAAY,IAAA,EAAuC;AACjE,EAAA,MAAM,SAAS,IAAA,CAAK,IAAA,KAAS,SAAY,UAAA,CAAW,IAAA,CAAK,QAAQ,IAAA,CAAK,IAAI,CAAA,GAAK,CAAC,KAAK,MAAA,CAAO,CAAC,GAAG,IAAA,CAAK,MAAA,CAAO,CAAC,CAAC,CAAA;AAC9G,EAAA,MAAM,KAAA,GAAQ,CAAC,IAAA,CAAK,KAAA,CAAM,CAAC,CAAA,EAAG,IAAA,CAAK,KAAA,CAAM,CAAC,CAAC,CAAA;AAC3C,EAAA,MAAM,CAAC,EAAA,EAAI,EAAE,CAAA,GAAI,MAAA;AACjB,EAAA,MAAM,CAAC,EAAA,EAAI,EAAE,CAAA,GAAI,KAAA;AACjB,EAAA,MAAM,OAAO,EAAA,GAAK,EAAA;AAClB,EAAA,MAAM,GAAA,GAAM,CAAC,CAAA,KAAe,IAAA,KAAS,CAAA,GAAA,CAAK,EAAA,GAAK,EAAA,IAAM,CAAA,GAAI,EAAA,GAAA,CAAO,CAAA,GAAI,EAAA,IAAM,IAAA,IAAS,EAAA,GAAK,EAAA,CAAA;AACxF,EAAA,MAAM,OAAO,CAAC,KAAA,GAAQ,kBAAkB,QAAA,CAAS,EAAA,EAAI,IAAI,KAAK,CAAA;AAC9D,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,QAAA;AAAA,IACN,MAAA;AAAA,IACA,KAAA;AAAA,IACA,GAAA;AAAA,IACA,QAAA,EAAU,GAAA;AAAA,IACV,MAAA,EAAQ,CAAC,EAAA,KAAQ,EAAA,KAAO,EAAA,GAAK,KAAK,EAAA,GAAA,CAAO,EAAA,GAAK,EAAA,KAAO,EAAA,GAAK,EAAA,CAAA,GAAO,IAAA;AAAA,IACjE,QAAA,EAAU,IAAA;AAAA,IACV,WAAA,EAAa,CAAC,OAAA,KAAY,WAAA,CAAY,MAAA,EAAQ,KAAK,GAAA,CAAI,EAAA,GAAK,EAAE,CAAA,EAAG,OAAO,CAAA;AAAA,IACxE,KAAA,EAAO,CAAC,KAAA,GAAQ,aAAA,KAAkB,UAAU,EAAA,EAAI,EAAA,EAAI,IAAA,CAAK,KAAK,CAAC,CAAA;AAAA,IAC/D,QAAQ,CAAC,CAAA,KAAM,YAAA,CAAa,CAAA,EAAG,MAAM;AAAA,GACvC;AACF;;;ACzHA,IAAMA,aAAAA,GAAe,EAAA;AAGd,SAAS,aAAa,MAAA,EAAmC;AAC9D,EAAA,IAAI,IAAA,GAAO,CAAA;AACX,EAAA,KAAA,MAAW,KAAK,MAAA,EAAQ;AACtB,IAAA,IAAI,CAAC,MAAA,CAAO,QAAA,CAAS,CAAC,CAAA,EAAG;AACzB,IAAA,IAAI,CAAA,GAAI,CAAA;AACR,IAAA,OAAO,CAAA,GAAIA,iBAAgB,IAAA,CAAK,GAAA,CAAI,OAAO,CAAA,CAAE,OAAA,CAAQ,CAAC,CAAC,CAAA,GAAI,CAAC,CAAA,GAAI,IAAA,GAAO,KAAK,GAAA,CAAI,CAAA,EAAG,KAAK,GAAA,CAAI,CAAC,CAAC,CAAA,EAAG,CAAA,EAAA;AACjG,IAAA,IAAA,GAAO,IAAA,CAAK,GAAA,CAAI,IAAA,EAAM,CAAC,CAAA;AAAA,EACzB;AACA,EAAA,OAAO,IAAA;AACT;AAGO,SAAS,UAAA,CAAW,OAAe,GAAA,EAA4B;AACpE,EAAA,MAAM,IAAA,GAAO,KAAA,CAAM,OAAA,CAAQ,GAAA,CAAI,QAAQ,CAAA;AACvC,EAAA,OAAO,cAAc,IAAA,CAAK,IAAI,IAAI,IAAA,CAAK,KAAA,CAAM,CAAC,CAAA,GAAI,IAAA;AACpD;;;ACVO,SAAS,SAAS,IAAA,EAAiC;AACxD,EAAA,MAAM,IAAA,GAAO,KAAK,IAAA,IAAQ,EAAA;AAC1B,EAAA,MAAM,CAAC,EAAA,EAAI,EAAE,CAAA,GAAI,IAAA,CAAK,MAAA;AACtB,EAAA,IAAI,EAAE,EAAA,GAAK,CAAA,IAAK,EAAA,GAAK,CAAA,CAAA,EAAI,MAAM,IAAI,KAAA,CAAM,CAAA,sBAAA,EAAyB,EAAE,CAAA,EAAA,EAAK,EAAE,CAAA,wBAAA,CAA0B,CAAA;AACrG,EAAA,MAAM,CAAC,EAAA,EAAI,EAAE,CAAA,GAAI,IAAA,CAAK,KAAA;AACtB,EAAA,MAAM,GAAA,GAAM,CAAC,CAAA,KAAc,IAAA,CAAK,IAAI,CAAC,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,IAAI,CAAA;AACtD,EAAA,MAAM,EAAA,GAAK,IAAI,EAAE,CAAA;AACjB,EAAA,MAAM,EAAA,GAAK,IAAI,EAAE,CAAA;AACjB,EAAA,MAAM,GAAA,GAAM,CAAC,CAAA,KAAe,EAAA,KAAO,MAAM,EAAA,GAAK,EAAA,IAAM,CAAA,GAAI,EAAA,GAAA,CAAO,IAAI,CAAC,CAAA,GAAI,EAAA,KAAO,EAAA,GAAK,OAAQ,EAAA,GAAK,EAAA,CAAA;AACjG,EAAA,MAAM,KAAA,GAAQ,CAAC,KAAA,GAAQ,CAAA,KAAgB;AACrC,IAAA,MAAM,CAAC,EAAA,EAAI,EAAE,CAAA,GAAI,EAAA,IAAM,EAAA,GAAK,CAAC,EAAA,EAAI,EAAE,CAAA,GAAI,CAAC,EAAA,EAAI,EAAE,CAAA;AAC9C,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,EAAA,GAAK,IAAI,CAAA;AAClC,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,IAAA,CAAK,EAAA,GAAK,IAAI,CAAA;AAEhC,IAAA,MAAM,KAAA,GAAQ,IAAA,GAAO,KAAA,GAAQ,KAAA,GAAQ,CAAA,IAAK,IAAA,KAAS,EAAA,GAAK,CAAC,CAAA,EAAG,CAAA,EAAG,CAAC,CAAA,GAAI,CAAC,CAAC,CAAA;AACtE,IAAA,MAAM,MAAgB,EAAC;AACvB,IAAA,KAAA,IAAS,CAAA,GAAI,KAAA,EAAO,CAAA,IAAK,IAAA,EAAM,CAAA,EAAA,EAAK;AAClC,MAAA,KAAA,MAAW,KAAK,KAAA,EAAO;AACrB,QAAA,MAAM,IAAI,MAAA,CAAA,CAAQ,CAAA,GAAI,QAAQ,CAAA,EAAG,WAAA,CAAY,EAAE,CAAC,CAAA;AAChD,QAAA,IAAI,GAAA,CAAI,CAAC,CAAA,IAAK,EAAA,GAAK,IAAA,IAAQ,GAAA,CAAI,CAAC,CAAA,IAAK,EAAA,GAAK,IAAA,EAAM,GAAA,CAAI,IAAA,CAAK,CAAC,CAAA;AAAA,MAC5D;AAAA,IACF;AACA,IAAA,OAAO,EAAA,IAAM,EAAA,GAAK,GAAA,GAAM,GAAA,CAAI,OAAA,EAAQ;AAAA,EACtC,CAAA;AACA,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,KAAA;AAAA,IACN,IAAA;AAAA,IACA,MAAA,EAAQ,CAAC,EAAA,EAAI,EAAE,CAAA;AAAA,IACf,KAAA,EAAO,CAAC,EAAA,EAAI,EAAE,CAAA;AAAA,IACd,GAAA;AAAA,IACA,QAAA,EAAU,GAAA;AAAA,IACV,MAAA,EAAQ,CAAC,EAAA,KAAO,IAAA,KAAS,EAAA,KAAO,EAAA,GAAK,EAAA,GAAK,EAAA,GAAA,CAAO,EAAA,GAAK,EAAA,KAAO,EAAA,GAAK,EAAA,CAAA,IAAQ,EAAA,GAAK,EAAA,CAAA,CAAA;AAAA,IAC/E,KAAA;AAAA,IACA,QAAQ,CAAC,CAAA,KAAO,KAAK,CAAA,GAAI,YAAA,CAAa,GAAG,CAAC,CAAA,GAAI,YAAA,CAAa,CAAA,EAAG,MAAM,IAAA,CAAK,KAAA,CAAM,KAAK,KAAA,CAAM,CAAC,CAAC,CAAC;AAAA,GAC/F;AACF;;;AC1BO,SAAS,UAAU,IAAA,EAAmC;AAC3D,EAAA,MAAM,MAAA,GAAS,CAAC,GAAG,IAAA,CAAK,MAAM,CAAA;AAC9B,EAAA,MAAM,CAAC,EAAA,EAAI,EAAE,CAAA,GAAI,IAAA,CAAK,KAAA;AACtB,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,IAAI,CAAA,EAAG,IAAA,CAAK,YAAA,IAAgB,GAAG,CAAC,CAAA;AAC/D,EAAA,MAAM,QAAQ,IAAA,CAAK,GAAA,CAAI,GAAG,IAAA,CAAK,YAAA,IAAgB,QAAQ,CAAC,CAAA;AACxD,EAAA,MAAM,IAAI,MAAA,CAAO,MAAA;AACjB,EAAA,MAAM,IAAA,GAAO,CAAA,KAAM,CAAA,GAAI,CAAA,GAAA,CAAK,EAAA,GAAK,EAAA,IAAM,IAAA,CAAK,GAAA,CAAI,IAAA,EAAM,CAAA,GAAI,KAAA,GAAQ,CAAA,GAAI,KAAK,CAAA;AAC3E,EAAA,MAAM,SAAA,GAAY,IAAA,CAAK,GAAA,CAAI,IAAA,IAAQ,IAAI,KAAA,CAAM,CAAA;AAC7C,EAAA,MAAM,KAAA,GAAQ,IAAI,GAAA,CAAI,MAAA,CAAO,GAAA,CAAI,CAAC,GAAA,EAAK,CAAA,KAAM,CAAC,GAAA,EAAK,CAAC,CAAC,CAAC,CAAA;AACtD,EAAA,MAAM,OAAA,GAAU,CAAC,CAAA,KAAc,EAAA,GAAK,IAAA,IAAQ,KAAA,GAAQ,CAAA,CAAA,IAAM,IAAA,GAAO,CAAA,GAAI,IAAA,IAAQ,CAAA,GAAI,KAAA,CAAA,GAAS,CAAA,CAAA;AAC1F,EAAA,MAAM,KAAA,GAAQ,CAAC,GAAA,KAAgB;AAC7B,IAAA,MAAM,CAAA,GAAI,KAAA,CAAM,GAAA,CAAI,GAAG,CAAA;AACvB,IAAA,OAAO,CAAA,KAAM,MAAA,GAAY,MAAA,CAAO,GAAA,GAAM,QAAQ,CAAC,CAAA;AAAA,EACjD,CAAA;AACA,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,MAAA;AAAA,IACN,MAAA;AAAA,IACA,KAAA,EAAO,CAAC,EAAA,EAAI,EAAE,CAAA;AAAA,IACd,SAAA;AAAA,IACA,IAAA,EAAM,IAAA,CAAK,GAAA,CAAI,IAAI,CAAA;AAAA,IACnB,KAAA;AAAA,IACA,UAAU,CAAC,GAAA,KAAQ,KAAA,CAAM,GAAG,IAAI,SAAA,GAAY,CAAA;AAAA,IAC5C,MAAA,EAAQ,CAAC,EAAA,KAAO;AACd,MAAA,IAAI,CAAA,KAAM,GAAG,OAAO,MAAA;AACpB,MAAA,MAAM,CAAA,GAAI,KAAK,KAAA,CAAA,CAAO,EAAA,GAAK,MAAM,IAAA,GAAO,KAAA,GAAA,CAAS,CAAA,GAAI,KAAA,IAAS,CAAC,CAAA;AAC/D,MAAA,OAAO,MAAA,CAAO,IAAA,CAAK,GAAA,CAAI,CAAA,GAAI,CAAA,EAAG,KAAK,GAAA,CAAI,CAAA,EAAG,CAAC,CAAC,CAAC,CAAA;AAAA,IAC/C,CAAA;AAAA,IACA,KAAA,EAAO,MAAM,CAAC,GAAG,MAAM,CAAA;AAAA,IACvB,MAAA,EAAQ,CAAC,GAAA,KAAQ;AAAA,GACnB;AACF;;;AC5CA,IAAM,MAAA,GAAS,GAAA;AACf,IAAM,SAAS,EAAA,GAAK,MAAA;AACpB,IAAM,OAAO,EAAA,GAAK,MAAA;AAClB,IAAM,MAAM,EAAA,GAAK,IAAA;AAMjB,IAAM,SAAA,GAAiC;AAAA,EACrC,EAAE,EAAA,EAAI,MAAA,EAAQ,IAAA,EAAM,QAAA,EAAS;AAAA,EAAG,EAAE,EAAA,EAAI,CAAA,GAAI,MAAA,EAAQ,MAAM,QAAA,EAAS;AAAA,EAAG,EAAE,EAAA,EAAI,EAAA,GAAK,MAAA,EAAQ,MAAM,QAAA,EAAS;AAAA,EAAG,EAAE,EAAA,EAAI,EAAA,GAAK,MAAA,EAAQ,MAAM,QAAA,EAAS;AAAA,EAC3I,EAAE,EAAA,EAAI,MAAA,EAAQ,IAAA,EAAM,QAAA,EAAS;AAAA,EAAG,EAAE,EAAA,EAAI,CAAA,GAAI,MAAA,EAAQ,MAAM,QAAA,EAAS;AAAA,EAAG,EAAE,EAAA,EAAI,EAAA,GAAK,MAAA,EAAQ,MAAM,QAAA,EAAS;AAAA,EAAG,EAAE,EAAA,EAAI,EAAA,GAAK,MAAA,EAAQ,MAAM,QAAA,EAAS;AAAA,EAC3I,EAAE,EAAA,EAAI,IAAA,EAAM,IAAA,EAAM,MAAA,EAAO;AAAA,EAAG,EAAE,EAAA,EAAI,CAAA,GAAI,IAAA,EAAM,MAAM,MAAA,EAAO;AAAA,EAAG,EAAE,EAAA,EAAI,CAAA,GAAI,IAAA,EAAM,MAAM,MAAA,EAAO;AAAA,EAAG,EAAE,EAAA,EAAI,EAAA,GAAK,IAAA,EAAM,MAAM,MAAA,EAAO;AAAA,EAC1H,EAAE,EAAA,EAAI,GAAA,EAAK,IAAA,EAAM,KAAA,EAAM;AAAA,EAAG,EAAE,EAAA,EAAI,CAAA,GAAI,GAAA,EAAK,MAAM,KAAA,EAAM;AAAA,EAAG,EAAE,EAAA,EAAI,CAAA,GAAI,GAAA,EAAK,MAAM,KAAA,EAAM;AAAA,EACnF,EAAE,MAAA,EAAQ,CAAA,EAAG,IAAA,EAAM,OAAA,EAAQ;AAAA,EAAG,EAAE,MAAA,EAAQ,CAAA,EAAG,IAAA,EAAM,OAAA,EAAQ;AAAA,EAAG,EAAE,MAAA,EAAQ,EAAA,EAAI,IAAA,EAAM,MAAA;AAClF,CAAA;AAEA,IAAM,WAAW,EAAA,GAAK,GAAA;AACtB,IAAM,SAAS,CAAC,CAAA,KAAwB,CAAA,CAAE,EAAA,IAAM,EAAE,MAAA,GAAS,QAAA;AAG3D,SAAS,WAAA,CAAY,MAAc,KAAA,EAAyB;AAC1D,EAAA,MAAM,MAAA,GAAS,IAAA,GAAO,IAAA,CAAK,GAAA,CAAI,GAAG,KAAK,CAAA;AACvC,EAAA,IAAI,IAAA,GAAO,UAAU,CAAC,CAAA;AACtB,EAAA,KAAA,MAAW,CAAA,IAAK,WAAW,IAAI,IAAA,CAAK,IAAI,IAAA,CAAK,GAAA,CAAI,MAAA,CAAO,CAAC,CAAA,GAAI,MAAM,CAAC,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,IAAA,CAAK,GAAA,CAAI,MAAA,CAAO,IAAI,CAAA,GAAI,MAAM,CAAC,CAAA,EAAG,IAAA,GAAO,CAAA;AAC1H,EAAA,IAAI,IAAA,CAAK,IAAA,KAAS,MAAA,IAAU,MAAA,GAAS,KAAK,QAAA,EAAU;AAClD,IAAA,MAAM,KAAA,GAAQ,MAAM,IAAA,CAAK,KAAA,CAAM,KAAK,KAAA,CAAM,MAAA,IAAU,EAAA,GAAK,QAAA,CAAS,CAAC,CAAA;AACnE,IAAA,OAAO,EAAE,MAAA,EAAQ,EAAA,GAAK,KAAA,EAAO,MAAM,MAAA,EAAO;AAAA,EAC5C;AACA,EAAA,OAAO,IAAA;AACT;AAGA,SAAS,SAAA,CAAU,EAAA,EAAY,EAAA,EAAY,QAAA,EAA8B;AACvE,EAAA,MAAM,MAAgB,EAAC;AACvB,EAAA,IAAI,QAAA,CAAS,OAAO,MAAA,EAAW;AAC7B,IAAA,KAAA,IAAS,IAAI,IAAA,CAAK,IAAA,CAAK,EAAA,GAAK,QAAA,CAAS,EAAE,CAAA,GAAI,QAAA,CAAS,EAAA,EAAI,CAAA,IAAK,IAAI,CAAA,IAAK,QAAA,CAAS,EAAA,EAAI,GAAA,CAAI,KAAK,CAAC,CAAA;AAC7F,IAAA,OAAO,GAAA;AAAA,EACT;AACA,EAAA,MAAM,EAAA,GAAK,IAAI,IAAA,CAAK,EAAE,CAAA;AACtB,EAAA,IAAI,QAAQ,EAAA,CAAG,cAAA,EAAe,GAAI,EAAA,GAAK,GAAG,WAAA,EAAY;AACtD,EAAA,KAAA,GAAQ,KAAK,IAAA,CAAK,KAAA,GAAQ,QAAA,CAAS,MAAM,IAAI,QAAA,CAAS,MAAA;AACtD,EAAA,SAAQ,KAAA,IAAS,SAAS,MAAA,EAAQ;AAChC,IAAA,MAAM,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,IAAA,CAAK,KAAA,CAAM,QAAQ,EAAE,CAAA,EAAG,KAAA,GAAQ,EAAA,EAAI,CAAC,CAAA;AACxD,IAAA,IAAI,IAAI,EAAA,EAAI;AACZ,IAAA,IAAI,IAAI,EAAA,EAAI;AACZ,IAAA,GAAA,CAAI,KAAK,CAAC,CAAA;AAAA,EACZ;AACA,EAAA,OAAO,GAAA;AACT;AAEA,IAAM,GAAA,GAAM,CAAC,CAAA,KAAc,MAAA,CAAO,CAAC,CAAA,CAAE,QAAA,CAAS,GAAG,GAAG,CAAA;AAG7C,SAAS,aAAA,CAAc,GAAW,IAAA,EAAoB;AAC3D,EAAA,MAAM,CAAA,GAAI,IAAI,IAAA,CAAK,CAAC,CAAA;AACpB,EAAA,MAAM,OAAO,CAAA,EAAG,CAAA,CAAE,cAAA,EAAgB,IAAI,GAAA,CAAI,CAAA,CAAE,WAAA,EAAY,GAAI,CAAC,CAAC,CAAA,CAAA,EAAI,IAAI,CAAA,CAAE,UAAA,EAAY,CAAC,CAAA,CAAA;AACrF,EAAA,MAAM,IAAA,GAAO,CAAA,EAAG,GAAA,CAAI,CAAA,CAAE,WAAA,EAAa,CAAC,CAAA,CAAA,EAAI,GAAA,CAAI,CAAA,CAAE,aAAA,EAAe,CAAC,CAAA,CAAA;AAC9D,EAAA,QAAQ,IAAA;AAAM,IACZ,KAAK,MAAA;AAAQ,MAAA,OAAO,MAAA,CAAO,CAAA,CAAE,cAAA,EAAgB,CAAA;AAAA,IAC7C,KAAK,OAAA;AAAS,MAAA,OAAO,IAAA,CAAK,KAAA,CAAM,CAAA,EAAG,CAAC,CAAA;AAAA,IACpC,KAAK,KAAA;AAAO,MAAA,OAAO,IAAA;AAAA,IACnB,KAAK,MAAA;AAAA,IACL,KAAK,QAAA;AAAU,MAAA,OAAO,CAAA,CAAE,aAAY,KAAM,CAAA,IAAK,EAAE,aAAA,EAAc,KAAM,IAAI,IAAA,GAAO,IAAA;AAAA,IAChF,KAAK,QAAA;AAAU,MAAA,OAAO,GAAG,IAAI,CAAA,CAAA,EAAI,IAAI,CAAA,CAAE,aAAA,EAAe,CAAC,CAAA,CAAA;AAAA;AAE3D;AAGO,SAAS,UAAU,IAAA,EAAmC;AAC3D,EAAA,MAAM,CAAC,EAAA,EAAI,EAAE,CAAA,GAAI,IAAA,CAAK,MAAA;AACtB,EAAA,MAAM,CAAC,EAAA,EAAI,EAAE,CAAA,GAAI,IAAA,CAAK,KAAA;AACtB,EAAA,MAAM,OAAO,EAAA,GAAK,EAAA;AAClB,EAAA,MAAM,GAAA,GAAM,CAAC,CAAA,KAAe,IAAA,KAAS,CAAA,GAAA,CAAK,EAAA,GAAK,EAAA,IAAM,CAAA,GAAI,EAAA,GAAA,CAAO,CAAA,GAAI,EAAA,IAAM,IAAA,IAAS,EAAA,GAAK,EAAA,CAAA;AACxF,EAAA,MAAM,QAAA,GAAW,CAAC,KAAA,GAAQ,CAAA,KAAM,YAAY,IAAA,CAAK,GAAA,CAAI,IAAI,CAAA,EAAG,KAAK,CAAA;AACjE,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,MAAA;AAAA,IACN,MAAA,EAAQ,CAAC,EAAA,EAAI,EAAE,CAAA;AAAA,IACf,KAAA,EAAO,CAAC,EAAA,EAAI,EAAE,CAAA;AAAA,IACd,GAAA;AAAA,IACA,QAAA,EAAU,GAAA;AAAA,IACV,MAAA,EAAQ,CAAC,EAAA,KAAQ,EAAA,KAAO,EAAA,GAAK,KAAK,EAAA,GAAA,CAAO,EAAA,GAAK,EAAA,KAAO,EAAA,GAAK,EAAA,CAAA,GAAO,IAAA;AAAA,IACjE,KAAA,EAAO,CAAC,KAAA,GAAQ,CAAA,KAAM;AACpB,MAAA,MAAM,GAAA,GAAM,SAAA,CAAU,IAAA,CAAK,GAAA,CAAI,IAAI,EAAE,CAAA,EAAG,IAAA,CAAK,GAAA,CAAI,EAAA,EAAI,EAAE,CAAA,EAAG,QAAA,CAAS,KAAK,CAAC,CAAA;AACzE,MAAA,OAAO,EAAA,IAAM,EAAA,GAAK,GAAA,GAAM,GAAA,CAAI,OAAA,EAAQ;AAAA,IACtC,CAAA;AAAA,IACA,QAAQ,CAAC,CAAA,KAAM,cAAc,CAAA,EAAG,QAAA,GAAW,IAAI;AAAA,GACjD;AACF;;;ACjFO,SAAS,aAAgB,IAAA,EAA+C;AAC7E,EAAA,IAAI,KAAK,KAAA,CAAM,MAAA,KAAW,GAAG,MAAM,IAAI,MAAM,8BAA8B,CAAA;AAC3E,EAAA,MAAM,MAAA,GAAS,CAAC,GAAG,IAAA,CAAK,MAAM,CAAA;AAC9B,EAAA,MAAM,KAAA,GAAQ,IAAI,GAAA,CAAI,MAAA,CAAO,GAAA,CAAI,CAAC,GAAA,EAAK,CAAA,KAAM,CAAC,GAAA,EAAK,CAAC,CAAC,CAAC,CAAA;AACtD,EAAA,MAAM,KAAA,GAAQ,CAAC,GAAG,IAAA,CAAK,KAAK,CAAA;AAC5B,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,SAAA;AAAA,IACN,MAAA;AAAA,IACA,KAAA;AAAA,IACA,GAAA,EAAK,CAAC,GAAA,KAAQ;AACZ,MAAA,IAAI,CAAA,GAAI,KAAA,CAAM,GAAA,CAAI,GAAG,CAAA;AACrB,MAAA,IAAI,MAAM,MAAA,EAAW;AACnB,QAAA,CAAA,GAAI,MAAA,CAAO,MAAA;AACX,QAAA,MAAA,CAAO,KAAK,GAAG,CAAA;AACf,QAAA,KAAA,CAAM,GAAA,CAAI,KAAK,CAAC,CAAA;AAAA,MAClB;AACA,MAAA,OAAO,KAAA,CAAM,CAAA,GAAI,KAAA,CAAM,MAAM,CAAA;AAAA,IAC/B,CAAA;AAAA,IACA,KAAA,EAAO,MAAM,CAAC,GAAG,MAAM,CAAA;AAAA,IACvB,MAAA,EAAQ,CAAC,GAAA,KAAQ;AAAA,GACnB;AACF;;;ACHO,SAAS,WAAW,IAAA,EAAqC;AAC9D,EAAA,MAAM,MAAA,GAAS,EAAE,CAAA,EAAG,IAAA,CAAK,OAAO,CAAA,EAAG,CAAA,EAAG,IAAA,CAAK,MAAA,CAAO,CAAA,EAAE;AACpD,EAAA,MAAM,MAAA,GAAS,CAAC,IAAA,CAAK,MAAA,CAAO,CAAC,CAAA,EAAG,IAAA,CAAK,MAAA,CAAO,CAAC,CAAC,CAAA;AAC9C,EAAA,MAAM,MAAA,GAAS,CAAC,IAAA,CAAK,MAAA,CAAO,CAAC,CAAA,EAAG,IAAA,CAAK,MAAA,CAAO,CAAC,CAAC,CAAA;AAC9C,EAAA,MAAM,IAAA,GAAO,KAAK,GAAA,CAAI,CAAA,EAAG,KAAK,KAAA,CAAM,IAAA,CAAK,IAAI,CAAC,CAAA;AAC9C,EAAA,MAAM,KAAA,GAAQ,KAAK,UAAA,IAAc,CAAA;AACjC,EAAA,MAAM,SAAS,WAAA,CAAY,EAAE,MAAA,EAAQ,KAAA,EAAO,QAAQ,CAAA;AACpD,EAAA,MAAM,QAAQ,CAAC,CAAA,KAAc,QAAS,CAAA,GAAI,IAAA,CAAK,KAAK,CAAA,GAAK,IAAA;AACzD,EAAA,MAAM,EAAA,GAAK,KAAK,GAAA,CAAI,MAAA,CAAO,CAAC,CAAA,EAAG,MAAA,CAAO,CAAC,CAAC,CAAA;AACxC,EAAA,MAAM,EAAA,GAAK,KAAK,GAAA,CAAI,MAAA,CAAO,CAAC,CAAA,EAAG,MAAA,CAAO,CAAC,CAAC,CAAA;AACxC,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,OAAA;AAAA,IACN,MAAA;AAAA,IACA,MAAA;AAAA,IACA,MAAA;AAAA,IACA,IAAA;AAAA,IACA,KAAA;AAAA,IACA,UAAU,MAAA,CAAO,GAAA;AAAA,IACjB,KAAA,CAAM,GAAG,KAAA,EAAO;AACd,MAAA,MAAM,CAAA,GAAI,MAAA,CAAO,GAAA,CAAI,KAAK,CAAA;AAC1B,MAAA,MAAM,CAAA,GAAI,MAAM,CAAC,CAAA;AACjB,MAAA,OAAO,EAAE,CAAA,EAAG,MAAA,CAAO,CAAA,GAAI,CAAA,GAAI,KAAK,GAAA,CAAI,CAAC,CAAA,EAAG,CAAA,EAAG,OAAO,CAAA,GAAI,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,EAAE;AAAA,IACxE,CAAA;AAAA,IACA,OAAA,CAAQ,GAAG,EAAA,EAAI;AACb,MAAA,MAAM,CAAA,GAAI,MAAM,CAAC,CAAA;AACjB,MAAA,MAAM,KAAA,GAAA,CAAS,EAAA,CAAG,CAAA,GAAI,MAAA,CAAO,KAAK,IAAA,CAAK,GAAA,CAAI,CAAC,CAAA,GAAA,CAAK,GAAG,CAAA,GAAI,MAAA,CAAO,CAAA,IAAK,IAAA,CAAK,IAAI,CAAC,CAAA;AAC9E,MAAA,OAAO,IAAA,CAAK,GAAA,CAAI,EAAA,EAAI,IAAA,CAAK,GAAA,CAAI,IAAI,MAAA,CAAO,MAAA,CAAO,KAAK,CAAC,CAAC,CAAA;AAAA,IACxD,CAAA;AAAA,IACA,UAAU,MAAA,CAAO,QAAA;AAAA,IACjB,OAAO,MAAA,CAAO,KAAA;AAAA,IACd,QAAQ,MAAA,CAAO;AAAA,GACjB;AACF","file":"chunk-HA77BIQF.js","sourcesContent":["import type { ContinuousScale } from './types';\n\n/** Options for {@link linearScale}. */\nexport interface LinearScaleOptions {\n domain: readonly [number, number];\n range: readonly [number, number];\n /** Widen the domain out to whole tick steps for about this many ticks. Default no widening. */\n nice?: number;\n}\n\n/** Options for {@link LinearScale.spacedTicks}. */\nexport interface SpacedTickOptions {\n /** Smallest gap between neighboring ticks, in range units (px, for a scale onto the screen). */\n minSpacing: number;\n /** Ticks closer than this to either end of the range are dropped, in range units. Default 0. */\n inset?: number;\n}\n\n/** A column of ticks and the facts its labels share. */\nexport interface TickSet {\n /** Ascending, whichever way the domain runs. */\n values: number[];\n /** Distance between neighboring ticks. */\n step: number;\n /** Places after the point every label in the column shares. */\n decimals: number;\n}\n\n/** A scale that maps numbers proportionally, as a value axis does. */\nexport interface LinearScale extends ContinuousScale {\n readonly kind: 'linear';\n /** The distance between ticks when about `count` are asked for. */\n tickStep(count?: number): number;\n /** Ticks on the finest 1/2/5 step that keeps neighbors `minSpacing` apart along the range, so a longer axis\n * gets more of them. Empty for an empty domain or range. */\n spacedTicks(options: SpacedTickOptions): TickSet;\n}\n\nconst DEFAULT_TICKS = 5;\n\n/** The round step, 1, 2 or 5 times a power of ten, that cuts `lo`..`hi` into about `count` pieces. */\nexport function tickStep(lo: number, hi: number, count = DEFAULT_TICKS): number {\n const span = Math.abs(hi - lo);\n if (span === 0 || !Number.isFinite(span)) return 1;\n const raw = span / Math.max(1, count);\n const power = 10 ** Math.floor(Math.log10(raw));\n const error = raw / power;\n const factor = error >= Math.sqrt(50) ? 10 : error >= Math.sqrt(10) ? 5 : error >= Math.sqrt(2) ? 2 : 1;\n return factor * power;\n}\n\nconst MAX_DECIMALS = 20;\n\n/** How many decimals a value on a grid of `step` needs; 0 for a step that is not a positive number. */\nexport function decimalsOf(step: number): number {\n if (!(step > 0) || !Number.isFinite(step)) return 0;\n return Math.min(MAX_DECIMALS, Math.max(0, -Math.floor(Math.log10(step) + 1e-9)));\n}\n\n/** The smallest of 1, 2 or 5 times a power of ten that is at least `rough`. Unlike {@link tickStep}, which\n * rounds to the nearest, this never goes under: a minimum spacing stays a minimum. */\nexport function niceStep(rough: number): number {\n const mag = 10 ** Math.floor(Math.log10(rough));\n const norm = rough / mag;\n return (norm <= 1 ? 1 : norm <= 2 ? 2 : norm <= 5 ? 5 : 10) * mag;\n}\n\n/** `i` steps of `step`, without the float noise a bare product carries. */\nconst onGrid = (i: number, step: number): number => Number((i * step).toFixed(decimalsOf(step)));\n\n/** Every multiple of `step` from `lo` to `hi`, inclusive. */\nexport function stepTicks(lo: number, hi: number, step: number): number[] {\n const [a, b] = lo <= hi ? [lo, hi] : [hi, lo];\n const out: number[] = [];\n for (let i = Math.ceil(a / step - 1e-9); i <= Math.floor(b / step + 1e-9); i++) out.push(onGrid(i, step));\n return lo <= hi ? out : out.reverse();\n}\n\n/** Ticks across `domain`, laid `length` range units long; see {@link LinearScale.spacedTicks}. */\nfunction spacedTicks(domain: readonly [number, number], length: number, options: SpacedTickOptions): TickSet {\n const lo = Math.min(domain[0], domain[1]);\n const hi = Math.max(domain[0], domain[1]);\n const span = hi - lo;\n const { minSpacing, inset = 0 } = options;\n if (!(span > 0) || !Number.isFinite(span) || !(length > 0) || !(minSpacing > 0)) return { values: [], step: 0, decimals: 0 };\n const perUnit = span / length;\n const step = niceStep(minSpacing * perUnit);\n const decimals = decimalsOf(step);\n const first = Math.ceil((lo + inset * perUnit) / step - 1e-9);\n const last = Math.floor((hi - inset * perUnit) / step + 1e-9);\n const values: number[] = [];\n for (let i = first; i <= last; i++) values.push(onGrid(i, step) + 0);\n return { values, step, decimals };\n}\n\n/** `value` written as plainly as a grid of `step` allows: no trailing zeros, no exponent. */\nexport function formatNumber(value: number, step: number): string {\n const fixed = value.toFixed(Math.min(20, decimalsOf(step)));\n return fixed.includes('.') ? fixed.replace(/\\.?0+$/, '') : fixed;\n}\n\n/** `domain` widened to whole steps of a tick grid of about `count` ticks. */\nexport function niceDomain(domain: readonly [number, number], count = DEFAULT_TICKS): [number, number] {\n const [lo, hi] = domain;\n if (lo === hi) return lo === 0 ? [0, 1] : [Math.min(0, lo), Math.max(0, hi)];\n const step = tickStep(lo, hi, count);\n const down = (v: number) => onGrid(Math.floor(v / step + 1e-9), step);\n const up = (v: number) => onGrid(Math.ceil(v / step - 1e-9), step);\n return lo < hi ? [down(lo), up(hi)] : [up(lo), down(hi)];\n}\n\n/** A linear scale from `domain` onto `range`. */\nexport function linearScale(opts: LinearScaleOptions): LinearScale {\n const domain = opts.nice !== undefined ? niceDomain(opts.domain, opts.nice) : ([opts.domain[0], opts.domain[1]] as const);\n const range = [opts.range[0], opts.range[1]] as const;\n const [d0, d1] = domain;\n const [r0, r1] = range;\n const span = d1 - d0;\n const map = (v: number) => (span === 0 ? (r0 + r1) / 2 : r0 + ((v - d0) / span) * (r1 - r0));\n const step = (count = DEFAULT_TICKS) => tickStep(d0, d1, count);\n return {\n kind: 'linear',\n domain,\n range,\n map,\n position: map,\n invert: (at) => (r1 === r0 ? d0 : d0 + ((at - r0) / (r1 - r0)) * span),\n tickStep: step,\n spacedTicks: (options) => spacedTicks(domain, Math.abs(r1 - r0), options),\n ticks: (count = DEFAULT_TICKS) => stepTicks(d0, d1, step(count)),\n format: (v) => formatNumber(v, step()),\n };\n}\n","/** What a tick label formatter knows about the column it is part of. */\nexport interface TickFormatCtx {\n /** Places after the point that every label in the column shares. */\n decimals: number;\n /** Distance between neighboring ticks, or 0 when the ticks were given explicitly and are not evenly spaced. */\n step: number;\n}\n\n/** Turns a tick value into its label. */\nexport type TickFormatter = (value: number, ctx: TickFormatCtx) => string;\n\nconst MAX_DECIMALS = 20;\n\n/** The most places after the point any of `values` needs, for a column of ticks given rather than generated. */\nexport function tickDecimals(values: readonly number[]): number {\n let most = 0;\n for (const v of values) {\n if (!Number.isFinite(v)) continue;\n let d = 0;\n while (d < MAX_DECIMALS && Math.abs(Number(v.toFixed(d)) - v) > 1e-9 * Math.max(1, Math.abs(v))) d++;\n most = Math.max(most, d);\n }\n return most;\n}\n\n/** `value` fixed to its column's shared decimals, with no negative zero, so a column of labels lines up. */\nexport function formatTick(value: number, ctx: TickFormatCtx): string {\n const text = value.toFixed(ctx.decimals);\n return /^-0(\\.0*)?$/.test(text) ? text.slice(1) : text;\n}\n","import { formatNumber } from './linear';\nimport type { ContinuousScale } from './types';\n\n/** Options for {@link logScale}. */\nexport interface LogScaleOptions {\n /** Both ends above zero. */\n domain: readonly [number, number];\n range: readonly [number, number];\n /** Default 10. */\n base?: number;\n}\n\n/** A scale that maps the logarithm of a value proportionally. */\nexport interface LogScale extends ContinuousScale {\n readonly kind: 'log';\n readonly base: number;\n}\n\n/** A logarithmic scale from `domain`, whose ends must both be above zero, onto `range`. */\nexport function logScale(opts: LogScaleOptions): LogScale {\n const base = opts.base ?? 10;\n const [d0, d1] = opts.domain;\n if (!(d0 > 0 && d1 > 0)) throw new Error(`logScale: a domain of ${d0}..${d1} does not lie above zero`);\n const [r0, r1] = opts.range;\n const log = (v: number) => Math.log(v) / Math.log(base);\n const l0 = log(d0);\n const l1 = log(d1);\n const map = (v: number) => (l1 === l0 ? (r0 + r1) / 2 : r0 + ((log(v) - l0) / (l1 - l0)) * (r1 - r0));\n const ticks = (count = 5): number[] => {\n const [lo, hi] = l0 <= l1 ? [l0, l1] : [l1, l0];\n const first = Math.floor(lo + 1e-9);\n const last = Math.ceil(hi - 1e-9);\n // Few decades get their 2s and 5s too, so a short axis still reads.\n const steps = last - first < count / 2 && base === 10 ? [1, 2, 5] : [1];\n const out: number[] = [];\n for (let p = first; p <= last; p++) {\n for (const m of steps) {\n const v = Number((m * base ** p).toPrecision(12));\n if (log(v) >= lo - 1e-9 && log(v) <= hi + 1e-9) out.push(v);\n }\n }\n return l0 <= l1 ? out : out.reverse();\n };\n return {\n kind: 'log',\n base,\n domain: [d0, d1],\n range: [r0, r1],\n map,\n position: map,\n invert: (at) => base ** (r1 === r0 ? l0 : l0 + ((at - r0) / (r1 - r0)) * (l1 - l0)),\n ticks,\n format: (v) => (v >= 1 ? formatNumber(v, 1) : formatNumber(v, 10 ** Math.floor(Math.log10(v)))),\n };\n}\n","import type { Scale } from './types';\n\n/** Options for {@link bandScale}. */\nexport interface BandScaleOptions {\n /** The categories, one band each, in order. */\n domain: readonly string[];\n range: readonly [number, number];\n /** The share of each step left empty between bands, 0 to 1. Default 0.2. */\n paddingInner?: number;\n /** The room before the first band and after the last, in steps. Default half of `paddingInner`. */\n paddingOuter?: number;\n}\n\n/** A scale that cuts its range into equal bands, one per category, as a bar chart's category axis does. */\nexport interface BandScale extends Scale<string> {\n readonly kind: 'band';\n readonly domain: readonly string[];\n /** The width of each band. */\n readonly bandwidth: number;\n /** From one band's start to the next's. */\n readonly step: number;\n /** Where `key`'s band starts, or `NaN` for a key not in the domain. */\n start(key: string): number;\n /** The key whose band is nearest `at`; `undefined` for an empty domain. */\n invert(at: number): string | undefined;\n}\n\n/** A band scale over `domain`. */\nexport function bandScale(opts: BandScaleOptions): BandScale {\n const domain = [...opts.domain];\n const [r0, r1] = opts.range;\n const inner = Math.min(1, Math.max(0, opts.paddingInner ?? 0.2));\n const outer = Math.max(0, opts.paddingOuter ?? inner / 2);\n const n = domain.length;\n const step = n === 0 ? 0 : (r1 - r0) / Math.max(1e-9, n - inner + 2 * outer);\n const bandwidth = Math.abs(step * (1 - inner));\n const index = new Map(domain.map((key, i) => [key, i]));\n const startAt = (i: number) => r0 + step * (outer + i) + (step < 0 ? step * (1 - inner) : 0);\n const start = (key: string) => {\n const i = index.get(key);\n return i === undefined ? Number.NaN : startAt(i);\n };\n return {\n kind: 'band',\n domain,\n range: [r0, r1],\n bandwidth,\n step: Math.abs(step),\n start,\n position: (key) => start(key) + bandwidth / 2,\n invert: (at) => {\n if (n === 0) return undefined;\n const i = Math.round((at - r0) / step - outer - (1 - inner) / 2);\n return domain[Math.min(n - 1, Math.max(0, i))];\n },\n ticks: () => [...domain],\n format: (key) => key,\n };\n}\n","import type { ContinuousScale } from './types';\n\n/** Options for {@link timeScale}. */\nexport interface TimeScaleOptions {\n /** Milliseconds since the epoch, as `Date.getTime` gives them. */\n domain: readonly [number, number];\n range: readonly [number, number];\n}\n\n/** A scale over instants, whose ticks fall on whole seconds, minutes, hours, days, months or years, in UTC. */\nexport interface TimeScale extends ContinuousScale {\n readonly kind: 'time';\n}\n\nconst SECOND = 1000;\nconst MINUTE = 60 * SECOND;\nconst HOUR = 60 * MINUTE;\nconst DAY = 24 * HOUR;\n\n/** A tick interval: a fixed span, or a count of calendar months. */\ntype Interval = { ms: number; months?: never; unit: Unit } | { months: number; ms?: never; unit: Unit };\ntype Unit = 'second' | 'minute' | 'hour' | 'day' | 'month' | 'year';\n\nconst INTERVALS: readonly Interval[] = [\n { ms: SECOND, unit: 'second' }, { ms: 5 * SECOND, unit: 'second' }, { ms: 15 * SECOND, unit: 'second' }, { ms: 30 * SECOND, unit: 'second' },\n { ms: MINUTE, unit: 'minute' }, { ms: 5 * MINUTE, unit: 'minute' }, { ms: 15 * MINUTE, unit: 'minute' }, { ms: 30 * MINUTE, unit: 'minute' },\n { ms: HOUR, unit: 'hour' }, { ms: 3 * HOUR, unit: 'hour' }, { ms: 6 * HOUR, unit: 'hour' }, { ms: 12 * HOUR, unit: 'hour' },\n { ms: DAY, unit: 'day' }, { ms: 2 * DAY, unit: 'day' }, { ms: 7 * DAY, unit: 'day' },\n { months: 1, unit: 'month' }, { months: 3, unit: 'month' }, { months: 12, unit: 'year' },\n];\n\nconst MONTH_MS = 30 * DAY;\nconst spanOf = (i: Interval): number => i.ms ?? i.months * MONTH_MS;\n\n/** The interval nearest a cut of `span` into `count` pieces; whole years past the table's end. */\nfunction intervalFor(span: number, count: number): Interval {\n const target = span / Math.max(1, count);\n let best = INTERVALS[0]!;\n for (const i of INTERVALS) if (Math.abs(Math.log(spanOf(i) / target)) < Math.abs(Math.log(spanOf(best) / target))) best = i;\n if (best.unit === 'year' && target > 12 * MONTH_MS) {\n const years = 10 ** Math.floor(Math.log10(target / (12 * MONTH_MS)));\n return { months: 12 * years, unit: 'year' };\n }\n return best;\n}\n\n/** Every instant on `interval`'s grid from `lo` to `hi`. */\nfunction gridTicks(lo: number, hi: number, interval: Interval): number[] {\n const out: number[] = [];\n if (interval.ms !== undefined) {\n for (let t = Math.ceil(lo / interval.ms) * interval.ms; t <= hi; t += interval.ms) out.push(t);\n return out;\n }\n const at = new Date(lo);\n let month = at.getUTCFullYear() * 12 + at.getUTCMonth();\n month = Math.ceil(month / interval.months) * interval.months;\n for (;; month += interval.months) {\n const t = Date.UTC(Math.floor(month / 12), month % 12, 1);\n if (t < lo) continue;\n if (t > hi) break;\n out.push(t);\n }\n return out;\n}\n\nconst pad = (n: number) => String(n).padStart(2, '0');\n\n/** `t` written to the precision of `unit`. */\nexport function formatInstant(t: number, unit: Unit): string {\n const d = new Date(t);\n const date = `${d.getUTCFullYear()}-${pad(d.getUTCMonth() + 1)}-${pad(d.getUTCDate())}`;\n const time = `${pad(d.getUTCHours())}:${pad(d.getUTCMinutes())}`;\n switch (unit) {\n case 'year': return String(d.getUTCFullYear());\n case 'month': return date.slice(0, 7);\n case 'day': return date;\n case 'hour':\n case 'minute': return d.getUTCHours() === 0 && d.getUTCMinutes() === 0 ? date : time;\n case 'second': return `${time}:${pad(d.getUTCSeconds())}`;\n }\n}\n\n/** A time scale from `domain`, in milliseconds since the epoch, onto `range`. */\nexport function timeScale(opts: TimeScaleOptions): TimeScale {\n const [d0, d1] = opts.domain;\n const [r0, r1] = opts.range;\n const span = d1 - d0;\n const map = (v: number) => (span === 0 ? (r0 + r1) / 2 : r0 + ((v - d0) / span) * (r1 - r0));\n const interval = (count = 5) => intervalFor(Math.abs(span), count);\n return {\n kind: 'time',\n domain: [d0, d1],\n range: [r0, r1],\n map,\n position: map,\n invert: (at) => (r1 === r0 ? d0 : d0 + ((at - r0) / (r1 - r0)) * span),\n ticks: (count = 5) => {\n const out = gridTicks(Math.min(d0, d1), Math.max(d0, d1), interval(count));\n return d0 <= d1 ? out : out.reverse();\n },\n format: (v) => formatInstant(v, interval().unit),\n };\n}\n","/** Options for {@link ordinalScale}. */\nexport interface OrdinalScaleOptions<T> {\n /** The keys, in order. */\n domain: readonly string[];\n /** What each key maps to, in domain order, wrapping when there are fewer than keys. */\n range: readonly T[];\n}\n\n/** A scale from keys to values in turn, as a series' colors are chosen. */\nexport interface OrdinalScale<T> {\n readonly kind: 'ordinal';\n readonly domain: readonly string[];\n readonly range: readonly T[];\n /** `key`'s value; a key not in the domain takes the next value after the last, and joins the domain. */\n map(key: string): T;\n /** The keys a legend lists. */\n ticks(): string[];\n format(key: string): string;\n}\n\n/** An ordinal scale from `domain` to `range`. Throws on an empty range. */\nexport function ordinalScale<T>(opts: OrdinalScaleOptions<T>): OrdinalScale<T> {\n if (opts.range.length === 0) throw new Error('ordinalScale: an empty range');\n const domain = [...opts.domain];\n const index = new Map(domain.map((key, i) => [key, i]));\n const range = [...opts.range];\n return {\n kind: 'ordinal',\n domain,\n range,\n map: (key) => {\n let i = index.get(key);\n if (i === undefined) {\n i = domain.length;\n domain.push(key);\n index.set(key, i);\n }\n return range[i % range.length]!;\n },\n ticks: () => [...domain],\n format: (key) => key,\n };\n}\n","import type { PlotPoint } from '../marks/types';\nimport { linearScale } from './linear';\n\n/** Options for {@link polarScale}. */\nexport interface PolarScaleOptions {\n center: PlotPoint;\n /** The radius the domain's ends sit at: inner, then outer. */\n radius: readonly [number, number];\n domain: readonly [number, number];\n /** How many spokes share the turn, evenly. */\n axes: number;\n /** Axis 0's angle, radians clockwise from twelve o'clock. Default 0. */\n startAngle?: number;\n}\n\n/** A scale over spokes from a center, as a radar chart's axes are: a value along each of `axes` evenly spaced spokes. */\nexport interface PolarScale {\n readonly kind: 'polar';\n readonly center: PlotPoint;\n readonly radius: readonly [number, number];\n readonly domain: readonly [number, number];\n readonly axes: number;\n /** Axis `i`'s angle, radians clockwise from twelve o'clock, as `arcMark`'s are. */\n angle(i: number): number;\n /** How far from the center `value` sits on every axis. */\n radiusAt(value: number): number;\n /** Where `value` sits on axis `i`. */\n point(i: number, value: number): PlotPoint;\n /** The value of the point on axis `i` nearest `at`, clamped to the domain. */\n valueAt(i: number, at: PlotPoint): number;\n /** The distance between ticks when about `count` are asked for. */\n tickStep(count?: number): number;\n /** Round values across the domain, about `count` of them. */\n ticks(count?: number): number[];\n /** `value` as a tick label reads it. */\n format(value: number): string;\n}\n\n/** A polar scale: values from `domain` out along `axes` spokes from `center`, `radius[0]` to `radius[1]` away. */\nexport function polarScale(opts: PolarScaleOptions): PolarScale {\n const center = { x: opts.center.x, y: opts.center.y };\n const radius = [opts.radius[0], opts.radius[1]] as const;\n const domain = [opts.domain[0], opts.domain[1]] as const;\n const axes = Math.max(1, Math.floor(opts.axes));\n const start = opts.startAngle ?? 0;\n const linear = linearScale({ domain, range: radius });\n const angle = (i: number) => start + (2 * Math.PI * i) / axes;\n const lo = Math.min(domain[0], domain[1]);\n const hi = Math.max(domain[0], domain[1]);\n return {\n kind: 'polar',\n center,\n radius,\n domain,\n axes,\n angle,\n radiusAt: linear.map,\n point(i, value) {\n const r = linear.map(value);\n const a = angle(i);\n return { x: center.x + r * Math.sin(a), y: center.y - r * Math.cos(a) };\n },\n valueAt(i, at) {\n const a = angle(i);\n const along = (at.x - center.x) * Math.sin(a) - (at.y - center.y) * Math.cos(a);\n return Math.min(hi, Math.max(lo, linear.invert(along)));\n },\n tickStep: linear.tickStep,\n ticks: linear.ticks,\n format: linear.format,\n };\n}\n"]}
|