@silverpoint/core 0.2.0 → 0.6.0
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 +4 -0
- package/dist/catalog.d.ts +97 -0
- package/dist/catalog.js +8002 -0
- package/dist/catalog.js.map +1 -0
- package/dist/chunk-KFBSQH5G.js +34 -0
- package/dist/chunk-KFBSQH5G.js.map +1 -0
- package/dist/chunk-OLYKR5PS.js +632 -0
- package/dist/chunk-OLYKR5PS.js.map +1 -0
- package/dist/chunk-PD4MD7JU.js +170 -0
- package/dist/chunk-PD4MD7JU.js.map +1 -0
- package/dist/dashboard-demos.d.ts +2 -1
- package/dist/index.d.ts +10 -55
- package/dist/index.js +36 -793
- package/dist/index.js.map +1 -1
- package/dist/model-CLhtoG75.d.ts +53 -0
- package/dist/{types-D1hjElfL.d.ts → props-Dq8FC8GG.d.ts} +369 -143
- package/dist/types-B81k-s9_.d.ts +148 -0
- package/dist/ui-demos.d.ts +17 -0
- package/dist/ui-demos.js +129 -0
- package/dist/ui-demos.js.map +1 -0
- package/dist/ui.d.ts +545 -0
- package/dist/ui.js +716 -0
- package/dist/ui.js.map +1 -0
- package/package.json +19 -1
package/dist/index.js
CHANGED
|
@@ -1,52 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DEFAULTS } from './chunk-KFBSQH5G.js';
|
|
2
|
+
export { DEFAULTS, FORCED_PRECISION_QUERY, instanceId, resolveConfig } from './chunk-KFBSQH5G.js';
|
|
3
|
+
import { cardLayout, modelBase, measure, emptyModel, readyModel, parseIsoDate, isoDate, createPrng, weekday } from './chunk-PD4MD7JU.js';
|
|
4
|
+
export { addDays, createPrng, isoDate, parseIsoDate, weekday } from './chunk-PD4MD7JU.js';
|
|
5
|
+
import { diagnose, circlePath, round2, readSeries, checkVolume, accessorName, read, formatCategory, formatValue, cartesianPlot, extent, seriesValues, valueAxis, categoryAxis, categoryLabels, formatNumber, finite, inset, rectPath, warnValue, toneOf, toneLevel, TONE_SCALE, checkCount, linearScale, legend, AXIS_BAND, PLOT_INSET, horizontalValueAxis, pillPath, checkSectors, readSectors, polarFrame, ringTones, sectorPath, pointAt, sectorLegend, RIM_LABELS, rimLabels, arcPath, ringTone, polarLabel, TICK_CHAR } from './chunk-OLYKR5PS.js';
|
|
6
|
+
export { SilverpointError, __setDiagnosticSink, bandScale, circlePath, deriveSeed, diagnose, expandDomain, extent, fnv1a32, linearScale, max, min, resolveSeed, round2, roundGeometry, roundPathData } from './chunk-OLYKR5PS.js';
|
|
2
7
|
import { curveStepAfter, curveNatural, curveLinear, curveMonotoneX, line, curveStep, curveStepBefore, area } from 'd3-shape';
|
|
3
8
|
import { chordDirected } from 'd3-chord';
|
|
4
9
|
|
|
5
|
-
// src/render/round.ts
|
|
6
|
-
function round2(value) {
|
|
7
|
-
const rounded = Math.round(value * 100) / 100;
|
|
8
|
-
return Object.is(rounded, -0) ? 0 : rounded;
|
|
9
|
-
}
|
|
10
|
-
var NUMBER = /-?(?:\d+\.?\d*|\.\d+)(?:[eE][-+]?\d+)?/g;
|
|
11
|
-
function roundPathData(d) {
|
|
12
|
-
return d.replace(NUMBER, (token) => String(round2(Number(token))));
|
|
13
|
-
}
|
|
14
|
-
function roundRect(rect) {
|
|
15
|
-
return {
|
|
16
|
-
x: round2(rect.x),
|
|
17
|
-
y: round2(rect.y),
|
|
18
|
-
width: round2(rect.width),
|
|
19
|
-
height: round2(rect.height)
|
|
20
|
-
};
|
|
21
|
-
}
|
|
22
|
-
function roundStroke(stroke) {
|
|
23
|
-
return { ...stroke, d: roundPathData(stroke.d) };
|
|
24
|
-
}
|
|
25
|
-
function roundTile(tile) {
|
|
26
|
-
return {
|
|
27
|
-
...tile,
|
|
28
|
-
width: round2(tile.width),
|
|
29
|
-
height: round2(tile.height),
|
|
30
|
-
angle: round2(tile.angle),
|
|
31
|
-
strokes: tile.strokes.map(roundStroke)
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
function roundGeometry(geometry) {
|
|
35
|
-
return {
|
|
36
|
-
viewBox: roundRect(geometry.viewBox),
|
|
37
|
-
plot: roundRect(geometry.plot),
|
|
38
|
-
strokes: geometry.strokes.map(roundStroke),
|
|
39
|
-
labels: geometry.labels.map((label) => ({ ...label, x: round2(label.x), y: round2(label.y) })),
|
|
40
|
-
hitAreas: geometry.hitAreas.map((hit) => ({
|
|
41
|
-
...hit,
|
|
42
|
-
x: round2(hit.x),
|
|
43
|
-
y: round2(hit.y),
|
|
44
|
-
...hit.box ? { box: roundRect(hit.box) } : {}
|
|
45
|
-
})),
|
|
46
|
-
defs: geometry.defs.map(roundTile)
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
|
|
50
10
|
// src/render/serialize.ts
|
|
51
11
|
function serializeGeometry(geometry) {
|
|
52
12
|
return JSON.stringify(geometry);
|
|
@@ -64,208 +24,6 @@ function pathBytes(geometry) {
|
|
|
64
24
|
}
|
|
65
25
|
var PATH_BYTE_BUDGET = 4e4;
|
|
66
26
|
|
|
67
|
-
// src/render/seed.ts
|
|
68
|
-
var FNV_OFFSET_BASIS = 2166136261;
|
|
69
|
-
var FNV_PRIME = 16777619;
|
|
70
|
-
function utf8Bytes(input) {
|
|
71
|
-
const bytes = [];
|
|
72
|
-
for (const char of input) {
|
|
73
|
-
const code = char.codePointAt(0) ?? 0;
|
|
74
|
-
if (code < 128) {
|
|
75
|
-
bytes.push(code);
|
|
76
|
-
} else if (code < 2048) {
|
|
77
|
-
bytes.push(192 | code >> 6, 128 | code & 63);
|
|
78
|
-
} else if (code < 65536) {
|
|
79
|
-
bytes.push(224 | code >> 12, 128 | code >> 6 & 63, 128 | code & 63);
|
|
80
|
-
} else {
|
|
81
|
-
bytes.push(
|
|
82
|
-
240 | code >> 18,
|
|
83
|
-
128 | code >> 12 & 63,
|
|
84
|
-
128 | code >> 6 & 63,
|
|
85
|
-
128 | code & 63
|
|
86
|
-
);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
return bytes;
|
|
90
|
-
}
|
|
91
|
-
function fnv1a32(input) {
|
|
92
|
-
let hash = FNV_OFFSET_BASIS;
|
|
93
|
-
for (const byte of utf8Bytes(input)) {
|
|
94
|
-
hash ^= byte;
|
|
95
|
-
hash = Math.imul(hash, FNV_PRIME);
|
|
96
|
-
}
|
|
97
|
-
return hash >>> 0;
|
|
98
|
-
}
|
|
99
|
-
function deriveSeed(id) {
|
|
100
|
-
return fnv1a32(id);
|
|
101
|
-
}
|
|
102
|
-
function resolveSeed(seed, id) {
|
|
103
|
-
if (seed === void 0) return deriveSeed(id);
|
|
104
|
-
if (typeof seed === "string") return fnv1a32(seed);
|
|
105
|
-
return Number.isFinite(seed) ? Math.trunc(seed) >>> 0 : 0;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// src/render/prng.ts
|
|
109
|
-
function createPrng(seed) {
|
|
110
|
-
let state = seed >>> 0;
|
|
111
|
-
return () => {
|
|
112
|
-
state = state + 1831565813 >>> 0;
|
|
113
|
-
let t = state;
|
|
114
|
-
t = Math.imul(t ^ t >>> 15, t | 1);
|
|
115
|
-
t ^= t + Math.imul(t ^ t >>> 7, t | 61);
|
|
116
|
-
return ((t ^ t >>> 14) >>> 0) / 4294967296;
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// src/charts/shared/dates.ts
|
|
121
|
-
var DAY_MS = 864e5;
|
|
122
|
-
var ISO_DATE = /^(\d{4})-(\d{2})-(\d{2})$/;
|
|
123
|
-
function parseIsoDate(iso) {
|
|
124
|
-
const match = ISO_DATE.exec(iso);
|
|
125
|
-
if (!match) return Number.NaN;
|
|
126
|
-
return Date.UTC(Number(match[1]), Number(match[2]) - 1, Number(match[3])) / DAY_MS;
|
|
127
|
-
}
|
|
128
|
-
function isoDate(day) {
|
|
129
|
-
return new Date(day * DAY_MS).toISOString().slice(0, 10);
|
|
130
|
-
}
|
|
131
|
-
function addDays(day, days) {
|
|
132
|
-
return day + days;
|
|
133
|
-
}
|
|
134
|
-
function weekday(day) {
|
|
135
|
-
return ((day + 4) % 7 + 7) % 7;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// src/diagnostics/diagnose.ts
|
|
139
|
-
var SilverpointError = class extends Error {
|
|
140
|
-
code;
|
|
141
|
-
constructor(code, message) {
|
|
142
|
-
super(message);
|
|
143
|
-
this.name = "SilverpointError";
|
|
144
|
-
this.code = code;
|
|
145
|
-
}
|
|
146
|
-
};
|
|
147
|
-
var consoleSink = (_code, message) => {
|
|
148
|
-
console.warn(message);
|
|
149
|
-
};
|
|
150
|
-
var sink = consoleSink;
|
|
151
|
-
var reported = /* @__PURE__ */ new Set();
|
|
152
|
-
function __setDiagnosticSink(next) {
|
|
153
|
-
sink = next ?? consoleSink;
|
|
154
|
-
reported.clear();
|
|
155
|
-
return () => {
|
|
156
|
-
sink = consoleSink;
|
|
157
|
-
reported.clear();
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
function format(code, chart, detail, template) {
|
|
161
|
-
const specifics = detail.message ? ` ${detail.message}` : "";
|
|
162
|
-
return `[${code}] ${chart}: ${template.what} (\`${detail.property}\`).${specifics} ${template.todo}. (${template.req})`;
|
|
163
|
-
}
|
|
164
|
-
var ERRORS = {
|
|
165
|
-
SP009: {
|
|
166
|
-
req: "REQ-097",
|
|
167
|
-
what: "a scale bound cannot be derived from the data and was not supplied",
|
|
168
|
-
todo: "Pass the named property explicitly"
|
|
169
|
-
},
|
|
170
|
-
SP012: {
|
|
171
|
-
req: "REQ-127",
|
|
172
|
-
what: "the ground does not reach the minimum contrast",
|
|
173
|
-
todo: "Recompute the palette; colours are not chosen by eye"
|
|
174
|
-
}
|
|
175
|
-
};
|
|
176
|
-
function diagnose(code, chart, detail) {
|
|
177
|
-
const error = ERRORS[code];
|
|
178
|
-
if (error) {
|
|
179
|
-
throw new SilverpointError(code, format(code, chart, detail, error));
|
|
180
|
-
}
|
|
181
|
-
if (process.env.NODE_ENV !== "production") {
|
|
182
|
-
developmentDiagnose(code, chart, detail);
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
function developmentDiagnose(code, chart, detail) {
|
|
186
|
-
const template = WARNINGS[code];
|
|
187
|
-
if (!template) return;
|
|
188
|
-
const message = format(code, chart, detail, template);
|
|
189
|
-
if (code === "SP005") {
|
|
190
|
-
throw new SilverpointError(code, message);
|
|
191
|
-
}
|
|
192
|
-
if (reported.has(message)) return;
|
|
193
|
-
reported.add(message);
|
|
194
|
-
sink(code, message);
|
|
195
|
-
}
|
|
196
|
-
var WARNINGS = {
|
|
197
|
-
SP001: {
|
|
198
|
-
req: "REQ-007",
|
|
199
|
-
what: "the dataset is empty; the ground's empty state is drawn",
|
|
200
|
-
todo: "Pass at least one row, or omit `data` to see the demo dataset"
|
|
201
|
-
},
|
|
202
|
-
SP002: {
|
|
203
|
-
req: "REQ-008",
|
|
204
|
-
what: "a value cannot be drawn as given (null, not finite, or outside the data contract); it is corrected or omitted",
|
|
205
|
-
todo: "Check the value against the chart's data contract (Data Model \xA72)"
|
|
206
|
-
},
|
|
207
|
-
SP003: {
|
|
208
|
-
req: "REQ-009",
|
|
209
|
-
what: "the container measures 0 px; the render is deferred",
|
|
210
|
-
todo: "Give the container a size, or pin `width` and `height`"
|
|
211
|
-
},
|
|
212
|
-
SP004: {
|
|
213
|
-
req: "REQ-010",
|
|
214
|
-
what: "the scale domain has zero length; it is expanded with the ground's domainPadding",
|
|
215
|
-
todo: "Nothing to do if the data is constant; otherwise check the accessor"
|
|
216
|
-
},
|
|
217
|
-
SP005: {
|
|
218
|
-
req: "REQ-025",
|
|
219
|
-
what: "more than one element is marked with white heightening; only the first is applied",
|
|
220
|
-
todo: "Heighten a single element per chart"
|
|
221
|
-
},
|
|
222
|
-
SP006: {
|
|
223
|
-
req: "REQ-026",
|
|
224
|
-
what: "the inker is not registered; falling back to NullInker",
|
|
225
|
-
todo: "Register the inker or fix the ground's `inker` token"
|
|
226
|
-
},
|
|
227
|
-
SP007: {
|
|
228
|
-
req: "REQ-045",
|
|
229
|
-
what: "the ground is not registered; falling back to silverpoint",
|
|
230
|
-
todo: "Call registerGround() before rendering, or fix the name"
|
|
231
|
-
},
|
|
232
|
-
SP008: {
|
|
233
|
-
req: "REQ-096",
|
|
234
|
-
what: "the data volume is above the family's threshold",
|
|
235
|
-
todo: "Aggregate the data before charting it"
|
|
236
|
-
},
|
|
237
|
-
SP010: {
|
|
238
|
-
req: "REQ-091",
|
|
239
|
-
what: "the chord ring has more than 12 categories",
|
|
240
|
-
todo: "Group the smaller categories"
|
|
241
|
-
},
|
|
242
|
-
SP011: {
|
|
243
|
-
req: "NFR \xA77",
|
|
244
|
-
what: "the path byte budget of 40 KB is exceeded",
|
|
245
|
-
todo: "Use `hatchFill: 'tile'` or a larger hatch gap"
|
|
246
|
-
},
|
|
247
|
-
SP014: {
|
|
248
|
-
req: "REQ-204",
|
|
249
|
-
what: "a dashboard cell spans more columns than the breakpoint has; it is clamped",
|
|
250
|
-
todo: "Lower the span, or give that breakpoint more columns"
|
|
251
|
-
},
|
|
252
|
-
SP015: {
|
|
253
|
-
req: "REQ-205",
|
|
254
|
-
what: "the dashboard layout and its children disagree; unmatched children are placed in source order, span 1",
|
|
255
|
-
todo: "Give every child a `cell` the layout declares, once"
|
|
256
|
-
},
|
|
257
|
-
SP016: {
|
|
258
|
-
req: "REQ-217",
|
|
259
|
-
what: "a chart in a linked dashboard has no field named by `link.key`; it shows no linked mark",
|
|
260
|
-
todo: "Link on a field every linked chart carries, or leave this chart out of the link"
|
|
261
|
-
},
|
|
262
|
-
SP013: {
|
|
263
|
-
req: "REQ-032",
|
|
264
|
-
what: "the @silverpoint/fonts face failed to load; rendering fell back to the system stack",
|
|
265
|
-
todo: "Install @silverpoint/fonts and import its stylesheet; golden images will not match until then"
|
|
266
|
-
}
|
|
267
|
-
};
|
|
268
|
-
|
|
269
27
|
// src/render/heighten.ts
|
|
270
28
|
function isOutlineOf(candidate, heightened) {
|
|
271
29
|
return candidate.part === "ink" && (candidate.paint ?? "stroke") === "stroke" && candidate.d === heightened.d;
|
|
@@ -409,66 +167,6 @@ async function checkTypeface(fonts, chart, face = DISPLAY_FACE_PROBE) {
|
|
|
409
167
|
return loaded;
|
|
410
168
|
}
|
|
411
169
|
|
|
412
|
-
// src/scales/util.ts
|
|
413
|
-
function min(values) {
|
|
414
|
-
let result;
|
|
415
|
-
for (const value of values) {
|
|
416
|
-
if (Number.isFinite(value) && (result === void 0 || value < result)) result = value;
|
|
417
|
-
}
|
|
418
|
-
return result;
|
|
419
|
-
}
|
|
420
|
-
function max(values) {
|
|
421
|
-
let result;
|
|
422
|
-
for (const value of values) {
|
|
423
|
-
if (Number.isFinite(value) && (result === void 0 || value > result)) result = value;
|
|
424
|
-
}
|
|
425
|
-
return result;
|
|
426
|
-
}
|
|
427
|
-
function extent(values) {
|
|
428
|
-
const low = min(values);
|
|
429
|
-
const high = max(values);
|
|
430
|
-
return low === void 0 || high === void 0 ? void 0 : [low, high];
|
|
431
|
-
}
|
|
432
|
-
function expandDomain(domain, padding, site, fromZero = false) {
|
|
433
|
-
const [low, high] = domain;
|
|
434
|
-
if (low !== high) return [low, high];
|
|
435
|
-
const spread = low === 0 ? padding : Math.abs(low) * padding;
|
|
436
|
-
if (fromZero && low === 0) {
|
|
437
|
-
if (process.env.NODE_ENV !== "production") {
|
|
438
|
-
diagnose("SP004", site.chart, { property: site.property, message: `Domain [0, 0] became [0, ${2 * spread}].` });
|
|
439
|
-
}
|
|
440
|
-
return [0, 2 * spread];
|
|
441
|
-
}
|
|
442
|
-
if (process.env.NODE_ENV !== "production") {
|
|
443
|
-
diagnose("SP004", site.chart, {
|
|
444
|
-
property: site.property,
|
|
445
|
-
message: `Domain [${low}, ${high}] became [${low - spread}, ${high + spread}].`
|
|
446
|
-
});
|
|
447
|
-
}
|
|
448
|
-
return [low - spread, high + spread];
|
|
449
|
-
}
|
|
450
|
-
function linearScale(domain, range, options) {
|
|
451
|
-
const expanded = expandDomain(domain, options.padding, options, options.fromZero);
|
|
452
|
-
const scale = scaleLinear().domain(expanded).range(range);
|
|
453
|
-
if (options.nice) scale.nice(4);
|
|
454
|
-
const [low, high] = scale.domain();
|
|
455
|
-
const result = ((value) => scale(value));
|
|
456
|
-
Object.defineProperty(result, "domain", { value: [low, high] });
|
|
457
|
-
result.ticks = (count) => scale.ticks(count);
|
|
458
|
-
return result;
|
|
459
|
-
}
|
|
460
|
-
function bandScale(domain, range, options = {}) {
|
|
461
|
-
const scale = scaleBand().domain(domain).range(range).paddingInner(options.paddingInner ?? 0).paddingOuter(options.paddingOuter ?? 0);
|
|
462
|
-
const bandwidth = scale.bandwidth();
|
|
463
|
-
const result = ((value) => scale(value));
|
|
464
|
-
Object.defineProperty(result, "bandwidth", { value: bandwidth });
|
|
465
|
-
result.center = (value) => {
|
|
466
|
-
const start = scale(value);
|
|
467
|
-
return start === void 0 ? void 0 : start + bandwidth / 2;
|
|
468
|
-
};
|
|
469
|
-
return result;
|
|
470
|
-
}
|
|
471
|
-
|
|
472
170
|
// src/ink/null-inker.ts
|
|
473
171
|
var NullInker = Object.freeze({
|
|
474
172
|
name: "null",
|
|
@@ -491,363 +189,6 @@ function resolveInker(name, chart, builtins = []) {
|
|
|
491
189
|
return NullInker;
|
|
492
190
|
}
|
|
493
191
|
|
|
494
|
-
// src/config/resolve.ts
|
|
495
|
-
var DEFAULTS = Object.freeze({
|
|
496
|
-
ground: "silverpoint",
|
|
497
|
-
substrate: "cream",
|
|
498
|
-
mode: "ink",
|
|
499
|
-
chrome: "card",
|
|
500
|
-
hatchFill: "tile",
|
|
501
|
-
height: 160,
|
|
502
|
-
dataTable: "hidden",
|
|
503
|
-
locale: "en"
|
|
504
|
-
});
|
|
505
|
-
function resolveConfig(props, provider = {}, environment = {}) {
|
|
506
|
-
const mode = environment.forcedPrecision ? "precision" : props.mode ?? provider.mode ?? DEFAULTS.mode;
|
|
507
|
-
return {
|
|
508
|
-
ground: props.ground ?? provider.ground ?? DEFAULTS.ground,
|
|
509
|
-
substrate: props.substrate ?? provider.substrate ?? DEFAULTS.substrate,
|
|
510
|
-
mode,
|
|
511
|
-
chrome: props.chrome ?? DEFAULTS.chrome,
|
|
512
|
-
hatchFill: props.hatchFill ?? DEFAULTS.hatchFill,
|
|
513
|
-
height: props.height ?? DEFAULTS.height,
|
|
514
|
-
dataTable: props.dataTable ?? DEFAULTS.dataTable,
|
|
515
|
-
locale: props.locale ?? provider.locale ?? environment.locale ?? DEFAULTS.locale
|
|
516
|
-
};
|
|
517
|
-
}
|
|
518
|
-
var FORCED_PRECISION_QUERY = "(prefers-contrast: more), (forced-colors: active)";
|
|
519
|
-
function instanceId(chart, token) {
|
|
520
|
-
const slug = chart.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
|
|
521
|
-
const safe = String(token).replace(/[^A-Za-z0-9_-]/g, "");
|
|
522
|
-
return `sp-${slug}-${safe}`;
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
// src/charts/shared/format.ts
|
|
526
|
-
function read(accessor, datum, index) {
|
|
527
|
-
return typeof accessor === "function" ? accessor(datum, index) : datum[accessor];
|
|
528
|
-
}
|
|
529
|
-
function accessorName(accessor, fallback) {
|
|
530
|
-
return typeof accessor === "string" ? accessor : fallback;
|
|
531
|
-
}
|
|
532
|
-
var FORMATTERS = /* @__PURE__ */ new Map();
|
|
533
|
-
var MAX_FORMATTERS = 64;
|
|
534
|
-
function formatNumber(value, locale, options) {
|
|
535
|
-
const resolved = options ?? { maximumFractionDigits: 2 };
|
|
536
|
-
const read2 = [];
|
|
537
|
-
for (const name in resolved) read2.push(`${name}=${JSON.stringify(resolved[name])}`);
|
|
538
|
-
const key = `${locale}|${read2.sort().join("&")}`;
|
|
539
|
-
let formatter = FORMATTERS.get(key);
|
|
540
|
-
if (!formatter) {
|
|
541
|
-
if (FORMATTERS.size >= MAX_FORMATTERS) FORMATTERS.clear();
|
|
542
|
-
formatter = new Intl.NumberFormat(locale, resolved);
|
|
543
|
-
FORMATTERS.set(key, formatter);
|
|
544
|
-
}
|
|
545
|
-
return formatter.format(value);
|
|
546
|
-
}
|
|
547
|
-
function formatValue(value, locale, options) {
|
|
548
|
-
if (typeof value === "number") {
|
|
549
|
-
return Number.isFinite(value) ? formatNumber(value, locale, options) : "\u2014";
|
|
550
|
-
}
|
|
551
|
-
return value === null || value === void 0 ? "\u2014" : String(value);
|
|
552
|
-
}
|
|
553
|
-
function formatCategory(value, locale) {
|
|
554
|
-
return formatValue(value, locale, typeof value === "number" ? { useGrouping: false, maximumFractionDigits: 2 } : void 0);
|
|
555
|
-
}
|
|
556
|
-
function circlePath(cx, cy, r) {
|
|
557
|
-
return `M${cx - r},${cy}A${r},${r},0,1,0,${cx + r},${cy}A${r},${r},0,1,0,${cx - r},${cy}Z`;
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
// src/charts/shared/card.ts
|
|
561
|
-
var CARD_PADDING = 16;
|
|
562
|
-
var TITLE_ROW = 20;
|
|
563
|
-
var VALUE_ROW = 52;
|
|
564
|
-
var HEADER_GAP = 8;
|
|
565
|
-
var FOOTER_ROW = 30;
|
|
566
|
-
function cardLayout(props, options) {
|
|
567
|
-
const { width, areaHeight: areaHeight2, chrome, locale } = options;
|
|
568
|
-
if (chrome === "bare") {
|
|
569
|
-
const box = { x: 0, y: 0, width, height: areaHeight2 };
|
|
570
|
-
return { viewBox: box, area: box, strokes: [], labels: [] };
|
|
571
|
-
}
|
|
572
|
-
const labels = [];
|
|
573
|
-
const strokes = [];
|
|
574
|
-
const left = CARD_PADDING;
|
|
575
|
-
const right = width - CARD_PADDING;
|
|
576
|
-
let cursor = CARD_PADDING;
|
|
577
|
-
if (props.title !== void 0 || props.badge !== void 0) {
|
|
578
|
-
const baseline = cursor + 11;
|
|
579
|
-
if (props.title !== void 0) {
|
|
580
|
-
labels.push({ x: left, y: baseline, text: props.title, kind: "title", part: "text", anchor: "start" });
|
|
581
|
-
}
|
|
582
|
-
if (props.badge !== void 0) {
|
|
583
|
-
labels.push({ x: right, y: baseline, text: props.badge, kind: "badge", part: "axis", anchor: "end" });
|
|
584
|
-
}
|
|
585
|
-
cursor += TITLE_ROW;
|
|
586
|
-
}
|
|
587
|
-
if (props.value !== void 0 || props.unit !== void 0) {
|
|
588
|
-
if (props.value !== void 0) {
|
|
589
|
-
labels.push({
|
|
590
|
-
x: left,
|
|
591
|
-
y: cursor + 30,
|
|
592
|
-
text: formatValue(props.value, locale, props.numberFormat),
|
|
593
|
-
kind: "value",
|
|
594
|
-
part: "text",
|
|
595
|
-
anchor: "start"
|
|
596
|
-
});
|
|
597
|
-
}
|
|
598
|
-
if (props.unit !== void 0) {
|
|
599
|
-
labels.push({ x: left, y: cursor + 46, text: props.unit, kind: "unit", part: "axis", anchor: "start" });
|
|
600
|
-
}
|
|
601
|
-
cursor += VALUE_ROW;
|
|
602
|
-
}
|
|
603
|
-
if (cursor > CARD_PADDING) cursor += HEADER_GAP;
|
|
604
|
-
const area5 = { x: left, y: cursor, width: right - left, height: areaHeight2 };
|
|
605
|
-
cursor += areaHeight2;
|
|
606
|
-
if (props.footerLeft !== void 0 || props.footerRight !== void 0) {
|
|
607
|
-
const ruleY = cursor + 8;
|
|
608
|
-
strokes.push({ d: `M${left},${ruleY}H${right}`, role: "ornament", part: "rule" });
|
|
609
|
-
if (props.footerLeft !== void 0) {
|
|
610
|
-
labels.push({ x: left, y: ruleY + 18, text: props.footerLeft, kind: "footer", part: "axis", anchor: "start" });
|
|
611
|
-
}
|
|
612
|
-
if (props.footerRight !== void 0) {
|
|
613
|
-
labels.push({ x: right, y: ruleY + 18, text: props.footerRight, kind: "footer", part: "axis", anchor: "end" });
|
|
614
|
-
}
|
|
615
|
-
cursor += FOOTER_ROW;
|
|
616
|
-
}
|
|
617
|
-
const height = cursor + CARD_PADDING;
|
|
618
|
-
const inset2 = 0.5;
|
|
619
|
-
strokes.unshift({
|
|
620
|
-
d: `M${inset2},${inset2}H${width - inset2}V${height - inset2}H${inset2}Z`,
|
|
621
|
-
role: "ornament",
|
|
622
|
-
part: "rule"
|
|
623
|
-
});
|
|
624
|
-
return { viewBox: { x: 0, y: 0, width, height }, area: area5, strokes, labels };
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
// src/charts/shared/cells.ts
|
|
628
|
-
function rectPath(rect) {
|
|
629
|
-
const { x, y, width, height } = rect;
|
|
630
|
-
return `M${x},${y}H${x + width}V${y + height}H${x}Z`;
|
|
631
|
-
}
|
|
632
|
-
function inset(rect, by) {
|
|
633
|
-
return {
|
|
634
|
-
x: rect.x + by,
|
|
635
|
-
y: rect.y + by,
|
|
636
|
-
width: Math.max(rect.width - 2 * by, 0),
|
|
637
|
-
height: Math.max(rect.height - 2 * by, 0)
|
|
638
|
-
};
|
|
639
|
-
}
|
|
640
|
-
function finite(raw) {
|
|
641
|
-
return typeof raw === "number" && Number.isFinite(raw) ? raw : void 0;
|
|
642
|
-
}
|
|
643
|
-
function toneOf(ratio) {
|
|
644
|
-
if (!(ratio > 0)) return 0;
|
|
645
|
-
if (ratio <= 0.25) return 1;
|
|
646
|
-
if (ratio <= 0.5) return 2;
|
|
647
|
-
if (ratio <= 0.75) return 3;
|
|
648
|
-
return 4;
|
|
649
|
-
}
|
|
650
|
-
function toneLevel(raw) {
|
|
651
|
-
return Math.min(Math.max(Math.round(raw), 0), 4);
|
|
652
|
-
}
|
|
653
|
-
function warnValue(chart, property, message) {
|
|
654
|
-
if (process.env.NODE_ENV !== "production") diagnose("SP002", chart, { property, message });
|
|
655
|
-
}
|
|
656
|
-
|
|
657
|
-
// src/charts/shared/cartesian.ts
|
|
658
|
-
var AXIS_BAND = 20;
|
|
659
|
-
var PLOT_INSET = 6;
|
|
660
|
-
var LABEL_SPACING = 48;
|
|
661
|
-
function cartesianPlot(area5) {
|
|
662
|
-
return {
|
|
663
|
-
x: area5.x + PLOT_INSET,
|
|
664
|
-
y: area5.y + PLOT_INSET,
|
|
665
|
-
width: Math.max(area5.width - 2 * PLOT_INSET, 1),
|
|
666
|
-
height: Math.max(area5.height - AXIS_BAND - PLOT_INSET, 1)
|
|
667
|
-
};
|
|
668
|
-
}
|
|
669
|
-
function readSeries(data, accessor, fallbackName) {
|
|
670
|
-
let missing = 0;
|
|
671
|
-
const points = data.map((datum, index) => {
|
|
672
|
-
const raw = read(accessor, datum, index);
|
|
673
|
-
const value = typeof raw === "number" && Number.isFinite(raw) ? raw : void 0;
|
|
674
|
-
if (value === void 0) missing += 1;
|
|
675
|
-
return { index, datum, value };
|
|
676
|
-
});
|
|
677
|
-
return { key: accessorName(accessor, fallbackName), points, missing };
|
|
678
|
-
}
|
|
679
|
-
var POINTS_PER_SERIES = 500;
|
|
680
|
-
function checkVolume(chart, series) {
|
|
681
|
-
for (const s of series) checkCount(chart, s.key, s.points.length);
|
|
682
|
-
}
|
|
683
|
-
function checkCount(chart, property, count) {
|
|
684
|
-
if (process.env.NODE_ENV === "production" || count <= POINTS_PER_SERIES) return;
|
|
685
|
-
diagnose("SP008", chart, { property, message: `${count} points; the ceiling is ${POINTS_PER_SERIES} per series.` });
|
|
686
|
-
}
|
|
687
|
-
function seriesValues(series) {
|
|
688
|
-
return series.flatMap((s) => s.points.flatMap((p) => p.value === void 0 ? [] : [p.value]));
|
|
689
|
-
}
|
|
690
|
-
function valueAxis(plot, domain, options) {
|
|
691
|
-
const bottom = plot.y + plot.height;
|
|
692
|
-
const low = options.zero === false ? domain[0] : Math.min(0, domain[0]);
|
|
693
|
-
const high = options.zero === false ? domain[1] : Math.max(0, domain[1]);
|
|
694
|
-
const scale = linearScale([low, high], [bottom, plot.y], {
|
|
695
|
-
chart: options.chart,
|
|
696
|
-
property: options.property,
|
|
697
|
-
padding: options.padding,
|
|
698
|
-
nice: options.nice !== false,
|
|
699
|
-
fromZero: options.zero !== false
|
|
700
|
-
});
|
|
701
|
-
const strokes = [];
|
|
702
|
-
const labels = [];
|
|
703
|
-
for (const tick of scale.ticks(4)) {
|
|
704
|
-
const ty = scale(tick);
|
|
705
|
-
if (tick === scale.domain[0]) continue;
|
|
706
|
-
strokes.push({ d: `M${plot.x},${ty}H${plot.x + plot.width}`, role: "ornament", part: "grid" });
|
|
707
|
-
labels.push({ x: plot.x, y: ty - 3, text: formatNumber(tick, options.locale, options.numberFormat), kind: "tick", part: "axis", anchor: "start" });
|
|
708
|
-
}
|
|
709
|
-
strokes.push({ d: `M${plot.x},${bottom}H${plot.x + plot.width}`, role: "ornament", part: "rule" });
|
|
710
|
-
return { scale, strokes, labels };
|
|
711
|
-
}
|
|
712
|
-
function categoryAxis(xValues, plot, options) {
|
|
713
|
-
const numeric = options.numeric !== false && xValues.length > 0 && xValues.every((v) => typeof v === "number" && Number.isFinite(v));
|
|
714
|
-
if (numeric) {
|
|
715
|
-
const numbers = xValues;
|
|
716
|
-
const x = linearScale(extent(numbers) ?? [0, 0], [plot.x, plot.x + plot.width], {
|
|
717
|
-
chart: options.chart,
|
|
718
|
-
property: options.property,
|
|
719
|
-
padding: options.padding
|
|
720
|
-
});
|
|
721
|
-
return { at: (index) => x(numbers[index] ?? 0), bandwidth: 0 };
|
|
722
|
-
}
|
|
723
|
-
const keys = xValues.map((_, index) => String(index));
|
|
724
|
-
const band = bandScale(keys, [plot.x, plot.x + plot.width], { paddingInner: options.paddingInner, paddingOuter: options.paddingOuter });
|
|
725
|
-
return { at: (index) => band.center(String(index)) ?? plot.x, bandwidth: band.bandwidth };
|
|
726
|
-
}
|
|
727
|
-
function categoryLabels(texts, at2, area5, plot) {
|
|
728
|
-
const count = texts.length;
|
|
729
|
-
const step = Math.max(1, Math.ceil(count / Math.max(2, Math.floor(plot.width / LABEL_SPACING))));
|
|
730
|
-
const labels = [];
|
|
731
|
-
for (let index = 0; index < count; index += step) {
|
|
732
|
-
labels.push({
|
|
733
|
-
x: at2(index),
|
|
734
|
-
y: area5.y + area5.height - 5,
|
|
735
|
-
text: texts[index] ?? "",
|
|
736
|
-
kind: "tick",
|
|
737
|
-
part: "axis",
|
|
738
|
-
anchor: index === 0 ? "start" : "middle"
|
|
739
|
-
});
|
|
740
|
-
}
|
|
741
|
-
return labels;
|
|
742
|
-
}
|
|
743
|
-
var LEGEND_BAND = 22;
|
|
744
|
-
var TICK_CHAR = 5.2;
|
|
745
|
-
var LEGEND_CHAR = TICK_CHAR;
|
|
746
|
-
function legend(area5, entries) {
|
|
747
|
-
const strokes = [];
|
|
748
|
-
const labels = [];
|
|
749
|
-
let x = area5.x + PLOT_INSET;
|
|
750
|
-
for (const entry of entries) {
|
|
751
|
-
const swatch = { x, y: area5.y + 4, width: 12, height: 7 };
|
|
752
|
-
strokes.push({ d: rectPath(swatch), role: "ornament", part: entry.part, ...entry.tone ? { tone: entry.tone } : {}, ...entry.dash ? { dash: entry.dash } : {} });
|
|
753
|
-
labels.push({ x: x + 16, y: area5.y + 11, text: entry.name, kind: "tick", part: "axis", anchor: "start" });
|
|
754
|
-
x += 16 + entry.name.length * LEGEND_CHAR + 12;
|
|
755
|
-
}
|
|
756
|
-
return { area: { x: area5.x, y: area5.y + LEGEND_BAND, width: area5.width, height: Math.max(area5.height - LEGEND_BAND, 1) }, strokes, labels };
|
|
757
|
-
}
|
|
758
|
-
function pillPath(rect) {
|
|
759
|
-
const { x, y, width, height } = rect;
|
|
760
|
-
const r = Math.min(width, height) / 2;
|
|
761
|
-
if (r <= 0) return `M${x},${y}H${x + width}V${y + height}H${x}Z`;
|
|
762
|
-
return `M${x},${y + r}A${r},${r},0,0,1,${x + r},${y}H${x + width - r}A${r},${r},0,0,1,${x + width},${y + r}V${y + height - r}A${r},${r},0,0,1,${x + width - r},${y + height}H${x + r}A${r},${r},0,0,1,${x},${y + height - r}Z`;
|
|
763
|
-
}
|
|
764
|
-
function horizontalValueAxis(plot, area5, domain, options) {
|
|
765
|
-
const scale = linearScale([Math.min(0, domain[0]), Math.max(0, domain[1])], [plot.x, plot.x + plot.width], {
|
|
766
|
-
chart: options.chart,
|
|
767
|
-
property: options.property,
|
|
768
|
-
padding: options.padding,
|
|
769
|
-
nice: true,
|
|
770
|
-
fromZero: true
|
|
771
|
-
});
|
|
772
|
-
const strokes = [];
|
|
773
|
-
const labels = [];
|
|
774
|
-
for (const tick of scale.ticks(4)) {
|
|
775
|
-
const tx = scale(tick);
|
|
776
|
-
if (tick !== 0) strokes.push({ d: `M${tx},${plot.y}V${plot.y + plot.height}`, role: "ornament", part: "grid" });
|
|
777
|
-
labels.push({ x: tx, y: area5.y + area5.height - 5, text: formatNumber(tick, options.locale, options.numberFormat), kind: "tick", part: "axis", anchor: "middle" });
|
|
778
|
-
}
|
|
779
|
-
strokes.push({ d: `M${scale(0)},${plot.y}V${plot.y + plot.height}`, role: "ornament", part: "rule" });
|
|
780
|
-
return { scale, strokes, labels };
|
|
781
|
-
}
|
|
782
|
-
|
|
783
|
-
// src/charts/shared/shell.ts
|
|
784
|
-
function modelBase(chart, props, context, fallbackName, table) {
|
|
785
|
-
const { id } = context;
|
|
786
|
-
const name = props.label ?? props.title ?? fallbackName;
|
|
787
|
-
return {
|
|
788
|
-
chart,
|
|
789
|
-
id,
|
|
790
|
-
chrome: props.chrome ?? "card",
|
|
791
|
-
name,
|
|
792
|
-
ids: { title: `${id}-title`, desc: `${id}-desc`, table: `${id}-table` },
|
|
793
|
-
table: { caption: name, ...table },
|
|
794
|
-
dataTable: props.dataTable ?? "hidden"
|
|
795
|
-
};
|
|
796
|
-
}
|
|
797
|
-
function areaHeight(props) {
|
|
798
|
-
return props.height ?? 160;
|
|
799
|
-
}
|
|
800
|
-
function measure(base, props, context) {
|
|
801
|
-
const width = props.width ?? context.width;
|
|
802
|
-
const height = areaHeight(props);
|
|
803
|
-
if (width !== void 0 && width > 0 && height > 0) return { width, height };
|
|
804
|
-
if (width !== void 0 && process.env.NODE_ENV !== "production") {
|
|
805
|
-
diagnose("SP003", base.chart, {
|
|
806
|
-
property: width <= 0 ? "width" : "height",
|
|
807
|
-
message: `Measured ${width} \xD7 ${height} px.`
|
|
808
|
-
});
|
|
809
|
-
}
|
|
810
|
-
const box = { x: 0, y: 0, width: 0, height: 0 };
|
|
811
|
-
return {
|
|
812
|
-
deferred: {
|
|
813
|
-
...base,
|
|
814
|
-
status: "deferred",
|
|
815
|
-
geometry: { viewBox: box, plot: box, strokes: [], labels: [], hitAreas: [], defs: [] },
|
|
816
|
-
description: props.description ?? base.name
|
|
817
|
-
}
|
|
818
|
-
};
|
|
819
|
-
}
|
|
820
|
-
function emptyModel(base, props, context, frame, datasetEmpty) {
|
|
821
|
-
if (datasetEmpty && process.env.NODE_ENV !== "production") {
|
|
822
|
-
diagnose("SP001", base.chart, { property: "data" });
|
|
823
|
-
}
|
|
824
|
-
const { plot } = frame;
|
|
825
|
-
const strokes = [...frame.strokes];
|
|
826
|
-
if (context.emptyState.rule) {
|
|
827
|
-
strokes.push({ d: `M${plot.x},${plot.y + plot.height}H${plot.x + plot.width}`, role: "ornament", part: "rule" });
|
|
828
|
-
}
|
|
829
|
-
const labels = [
|
|
830
|
-
...frame.labels,
|
|
831
|
-
{
|
|
832
|
-
x: plot.x + plot.width / 2,
|
|
833
|
-
y: plot.y + plot.height / 2,
|
|
834
|
-
text: context.emptyState.text,
|
|
835
|
-
kind: "empty",
|
|
836
|
-
part: "axis",
|
|
837
|
-
anchor: "middle"
|
|
838
|
-
}
|
|
839
|
-
];
|
|
840
|
-
return {
|
|
841
|
-
...base,
|
|
842
|
-
status: "ready",
|
|
843
|
-
description: props.description ?? `${base.name}. ${context.emptyState.text}.`,
|
|
844
|
-
geometry: roundGeometry({ viewBox: frame.viewBox, plot, strokes, labels, hitAreas: [], defs: [] })
|
|
845
|
-
};
|
|
846
|
-
}
|
|
847
|
-
function readyModel(base, description, geometry) {
|
|
848
|
-
return { ...base, status: "ready", description, geometry: roundGeometry({ ...geometry, defs: [] }) };
|
|
849
|
-
}
|
|
850
|
-
|
|
851
192
|
// src/charts/line-chart/demo.ts
|
|
852
193
|
var LINE_CHART_DEMO = /* @__PURE__ */ Object.freeze(
|
|
853
194
|
/* @__PURE__ */ [
|
|
@@ -1043,6 +384,12 @@ var NAVIGATION_KEYS = ["ArrowRight", "ArrowDown", "ArrowLeft", "ArrowUp", "Home"
|
|
|
1043
384
|
function stepActive(geometry, current, key) {
|
|
1044
385
|
if (!NAVIGATION_KEYS.includes(key)) return void 0;
|
|
1045
386
|
if (key === "Escape") return null;
|
|
387
|
+
const hits = geometry.hitAreas;
|
|
388
|
+
if (hits[0]?.moves) {
|
|
389
|
+
const here = current ? hits.findIndex((hit) => hit.seriesKey === current.seriesKey && hit.index === current.index) : -1;
|
|
390
|
+
const to = here < 0 ? hits[0].moves[key === "End" ? "End" : "Home"] : hits[here]?.moves?.[key];
|
|
391
|
+
return toActiveItem(hits[to ?? Math.max(here, 0)]);
|
|
392
|
+
}
|
|
1046
393
|
const grid = geometry.hitAreas.length > 0 && geometry.hitAreas.every((hit) => hit.cell !== void 0);
|
|
1047
394
|
if (grid) return stepGrid(geometry.hitAreas, current, key);
|
|
1048
395
|
const seriesKey = current?.seriesKey ?? geometry.hitAreas[0]?.seriesKey;
|
|
@@ -1192,7 +539,7 @@ function buildBulletChart(props, context) {
|
|
|
1192
539
|
}
|
|
1193
540
|
const rowHeight = plot.height / rows.length;
|
|
1194
541
|
const barHeight = Math.min(MAX_BAR, rowHeight * 0.35);
|
|
1195
|
-
const
|
|
542
|
+
const at = (percent) => plot.x + percent / 100 * plot.width;
|
|
1196
543
|
let met = 0;
|
|
1197
544
|
for (const row of rows) {
|
|
1198
545
|
const top = plot.y + row.index * rowHeight;
|
|
@@ -1204,16 +551,16 @@ function buildBulletChart(props, context) {
|
|
|
1204
551
|
warnValue(CHART2, actualName, `Row ${row.index} has no finite value; its bar is omitted.`);
|
|
1205
552
|
} else {
|
|
1206
553
|
const actual = clampPercent(row.actual, actualName, row.index);
|
|
1207
|
-
const bar = { x: plot.x, y: barY, width:
|
|
554
|
+
const bar = { x: plot.x, y: barY, width: at(actual) - plot.x, height: barHeight };
|
|
1208
555
|
if (bar.width > 0) strokes.push({ d: rectPath(bar), role: "encoding", part: "ink", tone: 2 });
|
|
1209
556
|
labels.push({ x: plot.x + plot.width, y: baseline, text: formatNumber(row.actual, locale, numberFormat), kind: "tick", part: "axis", anchor: "end" });
|
|
1210
|
-
hitAreas.push({ seriesKey: actualName, index: row.index, datum: row.datum, value: row.actual, x:
|
|
557
|
+
hitAreas.push({ seriesKey: actualName, index: row.index, datum: row.datum, value: row.actual, x: at(actual), y: barY + barHeight / 2, box: bar });
|
|
1211
558
|
if (row.target !== void 0 && row.actual >= row.target) met += 1;
|
|
1212
559
|
}
|
|
1213
560
|
if (row.target === void 0) {
|
|
1214
561
|
warnValue(CHART2, targetName, `Row ${row.index} has no finite target; its marker is omitted.`);
|
|
1215
562
|
} else {
|
|
1216
|
-
const x =
|
|
563
|
+
const x = at(clampPercent(row.target, targetName, row.index));
|
|
1217
564
|
strokes.push({ d: `M${x},${barY - MARKER_REACH}V${barY + barHeight + MARKER_REACH}`, role: "encoding", part: "ink", weight: 2 });
|
|
1218
565
|
}
|
|
1219
566
|
}
|
|
@@ -1335,7 +682,6 @@ var CELL_GAP = 2;
|
|
|
1335
682
|
var HEADER_BAND = 14;
|
|
1336
683
|
var DIGIT_WIDTH = 5.5;
|
|
1337
684
|
var LINE_HEIGHT = 12;
|
|
1338
|
-
var CELL_SCALE = { 0: 0.4, 1: 0.55, 2: 0.7, 3: 0.85, 4: 1 };
|
|
1339
685
|
function buildHeatmapChart(props, context) {
|
|
1340
686
|
const usesDemo = props.data === void 0;
|
|
1341
687
|
const data = props.data ?? HEATMAP_CHART_DEMO;
|
|
@@ -1408,7 +754,7 @@ function buildHeatmapChart(props, context) {
|
|
|
1408
754
|
continue;
|
|
1409
755
|
}
|
|
1410
756
|
const tone = toneOf(value / scaleMax);
|
|
1411
|
-
const scale = printed ? 1 :
|
|
757
|
+
const scale = printed ? 1 : TONE_SCALE[tone];
|
|
1412
758
|
const drawn = { x: cx - cell.width * scale / 2, y: cy - cell.height * scale / 2, width: cell.width * scale, height: cell.height * scale };
|
|
1413
759
|
strokes.push({ d: rectPath(drawn), role: "encoding", part: "ink", ...tone > 0 ? { tone } : {} });
|
|
1414
760
|
if (printed) labels.push({ x: cx, y: cy + 4, text: formatNumber(value, locale, numberFormat), kind: "tick", part: "text", anchor: "middle" });
|
|
@@ -1719,8 +1065,8 @@ var CHART7 = "ActivityGrid";
|
|
|
1719
1065
|
var PLOT_INSET7 = 6;
|
|
1720
1066
|
var MONTH_BAND = 14;
|
|
1721
1067
|
var DEFAULT_WEEKS = 26;
|
|
1722
|
-
var
|
|
1723
|
-
var
|
|
1068
|
+
var DAY_MS = 864e5;
|
|
1069
|
+
var CELL_SCALE = { 0: 0.4, 1: 0.55, 2: 0.7, 3: 0.85, 4: 1 };
|
|
1724
1070
|
var CELL_FILL = 0.86;
|
|
1725
1071
|
var MONTH_GAP = 3;
|
|
1726
1072
|
function buildActivityGrid(props, context) {
|
|
@@ -1785,7 +1131,7 @@ function buildActivityGrid(props, context) {
|
|
|
1785
1131
|
const column = Math.floor(index / 7);
|
|
1786
1132
|
const row = index % 7;
|
|
1787
1133
|
if (row === 0) {
|
|
1788
|
-
const name = month.format(new Date(d.day *
|
|
1134
|
+
const name = month.format(new Date(d.day * DAY_MS));
|
|
1789
1135
|
const last = months.at(-1);
|
|
1790
1136
|
if (name !== last?.name) {
|
|
1791
1137
|
if (last && column - last.column < MONTH_GAP) {
|
|
@@ -1795,7 +1141,7 @@ function buildActivityGrid(props, context) {
|
|
|
1795
1141
|
}
|
|
1796
1142
|
}
|
|
1797
1143
|
}
|
|
1798
|
-
const side = slot * CELL_FILL *
|
|
1144
|
+
const side = slot * CELL_FILL * CELL_SCALE[d.level];
|
|
1799
1145
|
const cx = plot.x + column * slot + slot / 2;
|
|
1800
1146
|
const cy = top + row * slot + slot / 2;
|
|
1801
1147
|
const cell = { x: cx - side / 2, y: cy - side / 2, width: side, height: side };
|
|
@@ -2495,109 +1841,6 @@ function buildFunnelChart(props, context) {
|
|
|
2495
1841
|
}
|
|
2496
1842
|
var funnelChart = /* @__PURE__ */ Object.freeze({ name: CHART15, build: buildFunnelChart });
|
|
2497
1843
|
|
|
2498
|
-
// src/charts/shared/polar.ts
|
|
2499
|
-
function polarFrame(area5, labelRoom = 0) {
|
|
2500
|
-
return {
|
|
2501
|
-
cx: area5.x + area5.width / 2,
|
|
2502
|
-
cy: area5.y + area5.height / 2,
|
|
2503
|
-
radius: Math.max(Math.min(area5.width, area5.height) / 2 - PLOT_INSET - labelRoom, 1)
|
|
2504
|
-
};
|
|
2505
|
-
}
|
|
2506
|
-
var RIM_LABELS = 14;
|
|
2507
|
-
function rimLabels(frame, entries, most = 24) {
|
|
2508
|
-
const step = Math.max(1, Math.ceil(entries.length / most));
|
|
2509
|
-
return entries.filter((_, i) => i % step === 0).map((e) => polarLabel(frame, e.angle, frame.radius + 8, e.text));
|
|
2510
|
-
}
|
|
2511
|
-
function pointAt(frame, angle, r) {
|
|
2512
|
-
return { x: frame.cx + r * Math.sin(angle), y: frame.cy - r * Math.cos(angle) };
|
|
2513
|
-
}
|
|
2514
|
-
var EPSILON = 1e-9;
|
|
2515
|
-
var at = (frame, angle, r) => {
|
|
2516
|
-
const p = pointAt(frame, angle, r);
|
|
2517
|
-
return `${p.x},${p.y}`;
|
|
2518
|
-
};
|
|
2519
|
-
function arcTo(frame, r, end, clockwise) {
|
|
2520
|
-
return `A${r},${r},0,0,${clockwise ? 1 : 0},${at(frame, end, r)}`;
|
|
2521
|
-
}
|
|
2522
|
-
function sweep(frame, r, start, end, clockwise) {
|
|
2523
|
-
if (Math.abs(end - start) <= Math.PI) return arcTo(frame, r, end, clockwise);
|
|
2524
|
-
const middle = (start + end) / 2;
|
|
2525
|
-
return arcTo(frame, r, middle, clockwise) + arcTo(frame, r, end, clockwise);
|
|
2526
|
-
}
|
|
2527
|
-
function arcPath(frame, r, start, end) {
|
|
2528
|
-
if (Math.abs(end - start) < EPSILON || r <= 0) return "";
|
|
2529
|
-
return `M${at(frame, start, r)}${sweep(frame, r, start, end, end > start)}`;
|
|
2530
|
-
}
|
|
2531
|
-
function sectorPath(frame, shape) {
|
|
2532
|
-
const { inner, outer, start, end } = shape;
|
|
2533
|
-
if (Math.abs(end - start) < EPSILON || outer <= 0) return "";
|
|
2534
|
-
const clockwise = end > start;
|
|
2535
|
-
const outerArc = `M${at(frame, start, outer)}${sweep(frame, outer, start, end, clockwise)}`;
|
|
2536
|
-
if (inner <= 0) return `${outerArc}L${frame.cx},${frame.cy}Z`;
|
|
2537
|
-
return `${outerArc}L${at(frame, end, inner)}${sweep(frame, inner, end, start, !clockwise)}Z`;
|
|
2538
|
-
}
|
|
2539
|
-
var POLE = 0.1;
|
|
2540
|
-
function polarLabel(frame, angle, r, text, kind = "tick") {
|
|
2541
|
-
const p = pointAt(frame, angle, r);
|
|
2542
|
-
const side = Math.sin(angle);
|
|
2543
|
-
const anchor = side > POLE ? "start" : side < -POLE ? "end" : "middle";
|
|
2544
|
-
return { x: p.x, y: p.y + 3, text, kind, part: "axis", anchor };
|
|
2545
|
-
}
|
|
2546
|
-
function readSectors(data, nameKey, valueKey, chart, locale) {
|
|
2547
|
-
const valueName = accessorName(valueKey, "value");
|
|
2548
|
-
const seen = /* @__PURE__ */ new Map();
|
|
2549
|
-
const sectors = [];
|
|
2550
|
-
data.forEach((datum, index) => {
|
|
2551
|
-
const value = finite(read(valueKey, datum, index));
|
|
2552
|
-
if (value === void 0 || value < 0) {
|
|
2553
|
-
warnValue(chart, valueName, `Row ${index} has a ${valueName} of ${String(read(valueKey, datum, index))}; a sector needs a finite value \u2265 0, so it is omitted.`);
|
|
2554
|
-
return;
|
|
2555
|
-
}
|
|
2556
|
-
const given = read(nameKey, datum, index);
|
|
2557
|
-
if (given === void 0 || given === null || given === "") warnValue(chart, accessorName(nameKey, "name"), `Row ${index} has no name; it is shown as "\u2014".`);
|
|
2558
|
-
const raw = formatCategory(given, locale);
|
|
2559
|
-
const count = (seen.get(raw) ?? 0) + 1;
|
|
2560
|
-
seen.set(raw, count);
|
|
2561
|
-
if (count > 1) warnValue(chart, accessorName(nameKey, "name"), `The name "${raw}" repeats; row ${index} is shown as "${raw} (${count})".`);
|
|
2562
|
-
sectors.push({ index, datum, name: count > 1 ? `${raw} (${count})` : raw, value });
|
|
2563
|
-
});
|
|
2564
|
-
return sectors;
|
|
2565
|
-
}
|
|
2566
|
-
var SECTORS_PER_CHART = 60;
|
|
2567
|
-
function checkSectors(chart, property, count) {
|
|
2568
|
-
if (process.env.NODE_ENV === "production" || count <= SECTORS_PER_CHART) return;
|
|
2569
|
-
diagnose("SP008", chart, { property, message: `${count} sectors; the ceiling is ${SECTORS_PER_CHART}.` });
|
|
2570
|
-
}
|
|
2571
|
-
var RING_TONES = [1, 2, 3, 4];
|
|
2572
|
-
function ringTone(index, count) {
|
|
2573
|
-
const tone = RING_TONES[index % RING_TONES.length];
|
|
2574
|
-
if (count > 1 && index === count - 1 && tone === RING_TONES[0]) return RING_TONES[2];
|
|
2575
|
-
return tone;
|
|
2576
|
-
}
|
|
2577
|
-
function ringTones(values) {
|
|
2578
|
-
const drawn = values.filter((v) => v > 0).length;
|
|
2579
|
-
let k = 0;
|
|
2580
|
-
return values.map((v) => v > 0 ? ringTone(k++, drawn) : ringTone(Math.min(k, Math.max(drawn - 1, 0)), drawn));
|
|
2581
|
-
}
|
|
2582
|
-
var LEGEND_ROW = 14;
|
|
2583
|
-
function sectorLegend(area5, entries) {
|
|
2584
|
-
const strokes = [];
|
|
2585
|
-
const labels = [];
|
|
2586
|
-
const fits2 = Math.max(Math.floor(area5.height / LEGEND_ROW), 1);
|
|
2587
|
-
const shown = entries.length > fits2 ? fits2 - 1 : entries.length;
|
|
2588
|
-
const top = area5.y + (area5.height - Math.min(entries.length, fits2) * LEGEND_ROW) / 2;
|
|
2589
|
-
entries.slice(0, shown).forEach((entry, row) => {
|
|
2590
|
-
const y = top + row * LEGEND_ROW;
|
|
2591
|
-
strokes.push({ d: rectPath({ x: area5.x, y: y + 3, width: 9, height: 7 }), role: "ornament", part: "ink", tone: entry.tone });
|
|
2592
|
-
labels.push({ x: area5.x + 14, y: y + 10, text: entry.name, kind: "tick", part: "text", anchor: "start" });
|
|
2593
|
-
labels.push({ x: area5.x + area5.width, y: y + 10, text: entry.share, kind: "tick", part: "axis", anchor: "end" });
|
|
2594
|
-
});
|
|
2595
|
-
if (shown < entries.length) {
|
|
2596
|
-
labels.push({ x: area5.x + 14, y: top + shown * LEGEND_ROW + 10, text: `+${entries.length - shown} more`, kind: "tick", part: "axis", anchor: "start" });
|
|
2597
|
-
}
|
|
2598
|
-
return { strokes, labels };
|
|
2599
|
-
}
|
|
2600
|
-
|
|
2601
1844
|
// src/charts/donut-chart/demo.ts
|
|
2602
1845
|
var DONUT_CHART_DEMO = /* @__PURE__ */ Object.freeze(
|
|
2603
1846
|
/* @__PURE__ */ [
|
|
@@ -2824,8 +2067,8 @@ function buildPolarBarChart(props, context) {
|
|
|
2824
2067
|
const tip = hole + b.value / largest * reach;
|
|
2825
2068
|
const d = sectorPath(frame, { inner: hole, outer: tip, start, end });
|
|
2826
2069
|
if (d && tip > hole) strokes.push({ d, role: "encoding", part: "ink", tone: 2 });
|
|
2827
|
-
const
|
|
2828
|
-
hitAreas.push({ seriesKey: valueName, index: b.index, datum: b.datum, value: b.value, x:
|
|
2070
|
+
const at = pointAt(frame, (start + end) / 2, tip);
|
|
2071
|
+
hitAreas.push({ seriesKey: valueName, index: b.index, datum: b.datum, value: b.value, x: at.x, y: at.y });
|
|
2829
2072
|
});
|
|
2830
2073
|
labels.push(...rimLabels(frame, bars.map((b, k) => ({ angle: (k + 0.5) * slot, text: b.name }))));
|
|
2831
2074
|
const top = bars.reduce((a, b) => b.value > a.value ? b : a);
|
|
@@ -2887,8 +2130,8 @@ function buildCoxcombChart(props, context) {
|
|
|
2887
2130
|
const r = frame.radius * Math.sqrt(s.value / largest);
|
|
2888
2131
|
const d = sectorPath(frame, { inner: 0, outer: r, start: from, end: from + slot });
|
|
2889
2132
|
if (d) strokes.push({ d, role: "encoding", part: "ink", tone: tones[k] });
|
|
2890
|
-
const
|
|
2891
|
-
hitAreas.push({ seriesKey: valueName, index: s.index, datum: s.datum, value: s.value, x:
|
|
2133
|
+
const at = pointAt(frame, from + slot / 2, r * 0.6);
|
|
2134
|
+
hitAreas.push({ seriesKey: valueName, index: s.index, datum: s.datum, value: s.value, x: at.x, y: at.y });
|
|
2892
2135
|
});
|
|
2893
2136
|
labels.push(...rimLabels(frame, sectors.map((s, k) => ({ angle: start + (k + 0.5) * slot, text: s.name }))));
|
|
2894
2137
|
const top = sectors.reduce((a, b) => b.value > a.value ? b : a);
|
|
@@ -3045,9 +2288,9 @@ function buildScalar(family, props, context) {
|
|
|
3045
2288
|
const drawing = family.draw(frame, value);
|
|
3046
2289
|
const strokes = [...card.strokes, ...drawing.strokes];
|
|
3047
2290
|
const labels = [...card.labels, ...drawing.labels];
|
|
3048
|
-
const
|
|
3049
|
-
labels.push({ x: frame.cx, y:
|
|
3050
|
-
if (caption) labels.push({ x: frame.cx, y:
|
|
2291
|
+
const at = family.readoutAt(frame);
|
|
2292
|
+
labels.push({ x: frame.cx, y: at.value, text: printed, kind: "value", part: "text", anchor: "middle" });
|
|
2293
|
+
if (caption) labels.push({ x: frame.cx, y: at.caption, text: caption, kind: "tick", part: "axis", anchor: "middle" });
|
|
3051
2294
|
const hitAreas = [];
|
|
3052
2295
|
if (value !== void 0 && drawing.tip) {
|
|
3053
2296
|
hitAreas.push({ seriesKey: "value", index: 0, datum: { value }, value, x: drawing.tip.x, y: drawing.tip.y });
|
|
@@ -3944,8 +3187,8 @@ function buildWindRose(props, context) {
|
|
|
3944
3187
|
if (r <= 0 || r > frame.radius + 0.01) continue;
|
|
3945
3188
|
strokes.push({ d: arcPath(frame, r, 0, 2 * Math.PI), role: "ornament", part: "grid" });
|
|
3946
3189
|
if (r > frame.radius - RIM_LABELS) continue;
|
|
3947
|
-
const
|
|
3948
|
-
labels.push({ x:
|
|
3190
|
+
const at = pointAt(frame, width / 2, r);
|
|
3191
|
+
labels.push({ x: at.x + 2, y: at.y - 2, text: `${formatNumber(tick, locale, { maximumFractionDigits: 0 })}%`, kind: "tick", part: "axis", anchor: "start" });
|
|
3949
3192
|
}
|
|
3950
3193
|
tally.forEach((row, k) => {
|
|
3951
3194
|
const start = k * width - width / 2 + width * SECTOR_GAP;
|
|
@@ -4204,13 +3447,13 @@ var POINTER = 7;
|
|
|
4204
3447
|
var CHAR2 = 5.2;
|
|
4205
3448
|
var CAP = 7;
|
|
4206
3449
|
var AIR = 1;
|
|
4207
|
-
function fits(frame, name,
|
|
3450
|
+
function fits(frame, name, at, inner, outer, start, end) {
|
|
4208
3451
|
const width = name.length * CHAR2;
|
|
4209
3452
|
const corners = [
|
|
4210
|
-
[
|
|
4211
|
-
[
|
|
4212
|
-
[
|
|
4213
|
-
[
|
|
3453
|
+
[at.x - width / 2, at.y + 3 - CAP],
|
|
3454
|
+
[at.x + width / 2, at.y + 3 - CAP],
|
|
3455
|
+
[at.x - width / 2, at.y + 3],
|
|
3456
|
+
[at.x + width / 2, at.y + 3]
|
|
4214
3457
|
];
|
|
4215
3458
|
const middle = (start + end) / 2;
|
|
4216
3459
|
return corners.every(([x, y]) => {
|
|
@@ -5011,6 +4254,6 @@ function linkedMarks(model, state) {
|
|
|
5011
4254
|
return linkedItems(model, state.key, state.value).map((index) => readout(model, toActiveItem(model.geometry.hitAreas[index])).marker.d);
|
|
5012
4255
|
}
|
|
5013
4256
|
|
|
5014
|
-
export { DASHBOARD_DEFAULTS,
|
|
4257
|
+
export { DASHBOARD_DEFAULTS, DISPLAY_FACE_PROBE, LINE_CHART_DEMO, LINE_CHART_DEMO_KEYS, MIN_TOUCH_TARGET, NAVIGATION_KEYS, NullInker, PATH_BYTE_BUDGET, activityGrid, areaChart, barChart, breakpointOf, bubbleChart, bulletChart, candlestickChart, cellChartBox, checkTypeface, chordRing, composedChart, coxcombChart, dashboardView, donutChart, enforceHeightening, funnelChart, gaugeArc, heatmapChart, inCell, kpiCard, lineChart, linkFrom, linkedItems, linkedMarks, meterChart, orbitChart, parseGeometry, pathBytes, perBreakpoint, polarBarChart, pyramidChart, radarChart, radialArcGroup, radialRings, rangeBandChart, readout, reduceInteraction, registerInker, resolveActive, resolveDashboard, resolveInker, resolveLayout, sameActive, sankeyChart, scatterChart, serializeGeometry, sparklineRows, stackedBarChart, stepActive, stepChart, streamChart, svgString, toSvgPoint, toSvgView, treemapChart, volvelleChart, waterfallChart, windRose };
|
|
5015
4258
|
//# sourceMappingURL=index.js.map
|
|
5016
4259
|
//# sourceMappingURL=index.js.map
|