@silverpoint/core 0.2.0 → 0.3.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/dist/index.js CHANGED
@@ -1,52 +1,8 @@
1
- import { scaleLinear, scaleBand } from 'd3-scale';
1
+ import { diagnose, circlePath, round2, DEFAULTS, readSeries, checkVolume, accessorName, read, formatCategory, formatValue, cartesianPlot, extent, seriesValues, valueAxis, categoryAxis, categoryLabels, formatNumber, finite, inset, rectPath, warnValue, toneOf, toneLevel, checkCount, linearScale, legend, AXIS_BAND, PLOT_INSET, horizontalValueAxis, pillPath, checkSectors, readSectors, polarFrame, ringTones, sectorPath, pointAt, sectorLegend, RIM_LABELS, rimLabels, arcPath, ringTone, polarLabel, TICK_CHAR, roundGeometry } from './chunk-I6BAZ7MJ.js';
2
+ export { DEFAULTS, FORCED_PRECISION_QUERY, SilverpointError, __setDiagnosticSink, bandScale, circlePath, deriveSeed, diagnose, expandDomain, extent, fnv1a32, instanceId, linearScale, max, min, resolveConfig, resolveSeed, round2, roundGeometry, roundPathData } from './chunk-I6BAZ7MJ.js';
2
3
  import { curveStepAfter, curveNatural, curveLinear, curveMonotoneX, line, curveStep, curveStepBefore, area } from 'd3-shape';
3
4
  import { chordDirected } from 'd3-chord';
4
5
 
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
6
  // src/render/serialize.ts
51
7
  function serializeGeometry(geometry) {
52
8
  return JSON.stringify(geometry);
@@ -64,47 +20,6 @@ function pathBytes(geometry) {
64
20
  }
65
21
  var PATH_BYTE_BUDGET = 4e4;
66
22
 
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
23
  // src/render/prng.ts
109
24
  function createPrng(seed) {
110
25
  let state = seed >>> 0;
@@ -135,137 +50,6 @@ function weekday(day) {
135
50
  return ((day + 4) % 7 + 7) % 7;
136
51
  }
137
52
 
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
53
  // src/render/heighten.ts
270
54
  function isOutlineOf(candidate, heightened) {
271
55
  return candidate.part === "ink" && (candidate.paint ?? "stroke") === "stroke" && candidate.d === heightened.d;
@@ -409,66 +193,6 @@ async function checkTypeface(fonts, chart, face = DISPLAY_FACE_PROBE) {
409
193
  return loaded;
410
194
  }
411
195
 
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
196
  // src/ink/null-inker.ts
473
197
  var NullInker = Object.freeze({
474
198
  name: "null",
@@ -491,72 +215,6 @@ function resolveInker(name, chart, builtins = []) {
491
215
  return NullInker;
492
216
  }
493
217
 
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
218
  // src/charts/shared/card.ts
561
219
  var CARD_PADDING = 16;
562
220
  var TITLE_ROW = 20;
@@ -624,162 +282,6 @@ function cardLayout(props, options) {
624
282
  return { viewBox: { x: 0, y: 0, width, height }, area: area5, strokes, labels };
625
283
  }
626
284
 
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
285
  // src/charts/shared/shell.ts
784
286
  function modelBase(chart, props, context, fallbackName, table) {
785
287
  const { id } = context;
@@ -1192,7 +694,7 @@ function buildBulletChart(props, context) {
1192
694
  }
1193
695
  const rowHeight = plot.height / rows.length;
1194
696
  const barHeight = Math.min(MAX_BAR, rowHeight * 0.35);
1195
- const at2 = (percent) => plot.x + percent / 100 * plot.width;
697
+ const at = (percent) => plot.x + percent / 100 * plot.width;
1196
698
  let met = 0;
1197
699
  for (const row of rows) {
1198
700
  const top = plot.y + row.index * rowHeight;
@@ -1204,16 +706,16 @@ function buildBulletChart(props, context) {
1204
706
  warnValue(CHART2, actualName, `Row ${row.index} has no finite value; its bar is omitted.`);
1205
707
  } else {
1206
708
  const actual = clampPercent(row.actual, actualName, row.index);
1207
- const bar = { x: plot.x, y: barY, width: at2(actual) - plot.x, height: barHeight };
709
+ const bar = { x: plot.x, y: barY, width: at(actual) - plot.x, height: barHeight };
1208
710
  if (bar.width > 0) strokes.push({ d: rectPath(bar), role: "encoding", part: "ink", tone: 2 });
1209
711
  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: at2(actual), y: barY + barHeight / 2, box: bar });
712
+ hitAreas.push({ seriesKey: actualName, index: row.index, datum: row.datum, value: row.actual, x: at(actual), y: barY + barHeight / 2, box: bar });
1211
713
  if (row.target !== void 0 && row.actual >= row.target) met += 1;
1212
714
  }
1213
715
  if (row.target === void 0) {
1214
716
  warnValue(CHART2, targetName, `Row ${row.index} has no finite target; its marker is omitted.`);
1215
717
  } else {
1216
- const x = at2(clampPercent(row.target, targetName, row.index));
718
+ const x = at(clampPercent(row.target, targetName, row.index));
1217
719
  strokes.push({ d: `M${x},${barY - MARKER_REACH}V${barY + barHeight + MARKER_REACH}`, role: "encoding", part: "ink", weight: 2 });
1218
720
  }
1219
721
  }
@@ -2495,109 +1997,6 @@ function buildFunnelChart(props, context) {
2495
1997
  }
2496
1998
  var funnelChart = /* @__PURE__ */ Object.freeze({ name: CHART15, build: buildFunnelChart });
2497
1999
 
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
2000
  // src/charts/donut-chart/demo.ts
2602
2001
  var DONUT_CHART_DEMO = /* @__PURE__ */ Object.freeze(
2603
2002
  /* @__PURE__ */ [
@@ -2824,8 +2223,8 @@ function buildPolarBarChart(props, context) {
2824
2223
  const tip = hole + b.value / largest * reach;
2825
2224
  const d = sectorPath(frame, { inner: hole, outer: tip, start, end });
2826
2225
  if (d && tip > hole) strokes.push({ d, role: "encoding", part: "ink", tone: 2 });
2827
- const at2 = pointAt(frame, (start + end) / 2, tip);
2828
- hitAreas.push({ seriesKey: valueName, index: b.index, datum: b.datum, value: b.value, x: at2.x, y: at2.y });
2226
+ const at = pointAt(frame, (start + end) / 2, tip);
2227
+ hitAreas.push({ seriesKey: valueName, index: b.index, datum: b.datum, value: b.value, x: at.x, y: at.y });
2829
2228
  });
2830
2229
  labels.push(...rimLabels(frame, bars.map((b, k) => ({ angle: (k + 0.5) * slot, text: b.name }))));
2831
2230
  const top = bars.reduce((a, b) => b.value > a.value ? b : a);
@@ -2887,8 +2286,8 @@ function buildCoxcombChart(props, context) {
2887
2286
  const r = frame.radius * Math.sqrt(s.value / largest);
2888
2287
  const d = sectorPath(frame, { inner: 0, outer: r, start: from, end: from + slot });
2889
2288
  if (d) strokes.push({ d, role: "encoding", part: "ink", tone: tones[k] });
2890
- const at2 = pointAt(frame, from + slot / 2, r * 0.6);
2891
- hitAreas.push({ seriesKey: valueName, index: s.index, datum: s.datum, value: s.value, x: at2.x, y: at2.y });
2289
+ const at = pointAt(frame, from + slot / 2, r * 0.6);
2290
+ hitAreas.push({ seriesKey: valueName, index: s.index, datum: s.datum, value: s.value, x: at.x, y: at.y });
2892
2291
  });
2893
2292
  labels.push(...rimLabels(frame, sectors.map((s, k) => ({ angle: start + (k + 0.5) * slot, text: s.name }))));
2894
2293
  const top = sectors.reduce((a, b) => b.value > a.value ? b : a);
@@ -3045,9 +2444,9 @@ function buildScalar(family, props, context) {
3045
2444
  const drawing = family.draw(frame, value);
3046
2445
  const strokes = [...card.strokes, ...drawing.strokes];
3047
2446
  const labels = [...card.labels, ...drawing.labels];
3048
- const at2 = family.readoutAt(frame);
3049
- labels.push({ x: frame.cx, y: at2.value, text: printed, kind: "value", part: "text", anchor: "middle" });
3050
- if (caption) labels.push({ x: frame.cx, y: at2.caption, text: caption, kind: "tick", part: "axis", anchor: "middle" });
2447
+ const at = family.readoutAt(frame);
2448
+ labels.push({ x: frame.cx, y: at.value, text: printed, kind: "value", part: "text", anchor: "middle" });
2449
+ if (caption) labels.push({ x: frame.cx, y: at.caption, text: caption, kind: "tick", part: "axis", anchor: "middle" });
3051
2450
  const hitAreas = [];
3052
2451
  if (value !== void 0 && drawing.tip) {
3053
2452
  hitAreas.push({ seriesKey: "value", index: 0, datum: { value }, value, x: drawing.tip.x, y: drawing.tip.y });
@@ -3944,8 +3343,8 @@ function buildWindRose(props, context) {
3944
3343
  if (r <= 0 || r > frame.radius + 0.01) continue;
3945
3344
  strokes.push({ d: arcPath(frame, r, 0, 2 * Math.PI), role: "ornament", part: "grid" });
3946
3345
  if (r > frame.radius - RIM_LABELS) continue;
3947
- const at2 = pointAt(frame, width / 2, r);
3948
- labels.push({ x: at2.x + 2, y: at2.y - 2, text: `${formatNumber(tick, locale, { maximumFractionDigits: 0 })}%`, kind: "tick", part: "axis", anchor: "start" });
3346
+ const at = pointAt(frame, width / 2, r);
3347
+ labels.push({ x: at.x + 2, y: at.y - 2, text: `${formatNumber(tick, locale, { maximumFractionDigits: 0 })}%`, kind: "tick", part: "axis", anchor: "start" });
3949
3348
  }
3950
3349
  tally.forEach((row, k) => {
3951
3350
  const start = k * width - width / 2 + width * SECTOR_GAP;
@@ -4204,13 +3603,13 @@ var POINTER = 7;
4204
3603
  var CHAR2 = 5.2;
4205
3604
  var CAP = 7;
4206
3605
  var AIR = 1;
4207
- function fits(frame, name, at2, inner, outer, start, end) {
3606
+ function fits(frame, name, at, inner, outer, start, end) {
4208
3607
  const width = name.length * CHAR2;
4209
3608
  const corners = [
4210
- [at2.x - width / 2, at2.y + 3 - CAP],
4211
- [at2.x + width / 2, at2.y + 3 - CAP],
4212
- [at2.x - width / 2, at2.y + 3],
4213
- [at2.x + width / 2, at2.y + 3]
3609
+ [at.x - width / 2, at.y + 3 - CAP],
3610
+ [at.x + width / 2, at.y + 3 - CAP],
3611
+ [at.x - width / 2, at.y + 3],
3612
+ [at.x + width / 2, at.y + 3]
4214
3613
  ];
4215
3614
  const middle = (start + end) / 2;
4216
3615
  return corners.every(([x, y]) => {
@@ -5011,6 +4410,6 @@ function linkedMarks(model, state) {
5011
4410
  return linkedItems(model, state.key, state.value).map((index) => readout(model, toActiveItem(model.geometry.hitAreas[index])).marker.d);
5012
4411
  }
5013
4412
 
5014
- export { DASHBOARD_DEFAULTS, DEFAULTS, DISPLAY_FACE_PROBE, FORCED_PRECISION_QUERY, LINE_CHART_DEMO, LINE_CHART_DEMO_KEYS, MIN_TOUCH_TARGET, NAVIGATION_KEYS, NullInker, PATH_BYTE_BUDGET, SilverpointError, __setDiagnosticSink, activityGrid, addDays, areaChart, bandScale, barChart, breakpointOf, bubbleChart, bulletChart, candlestickChart, cellChartBox, checkTypeface, chordRing, circlePath, composedChart, coxcombChart, createPrng, dashboardView, deriveSeed, diagnose, donutChart, enforceHeightening, expandDomain, extent, fnv1a32, funnelChart, gaugeArc, heatmapChart, inCell, instanceId, isoDate, kpiCard, lineChart, linearScale, linkFrom, linkedItems, linkedMarks, max, meterChart, min, orbitChart, parseGeometry, parseIsoDate, pathBytes, perBreakpoint, polarBarChart, pyramidChart, radarChart, radialArcGroup, radialRings, rangeBandChart, readout, reduceInteraction, registerInker, resolveActive, resolveConfig, resolveDashboard, resolveInker, resolveLayout, resolveSeed, round2, roundGeometry, roundPathData, sameActive, sankeyChart, scatterChart, serializeGeometry, sparklineRows, stackedBarChart, stepActive, stepChart, streamChart, svgString, toSvgPoint, toSvgView, treemapChart, volvelleChart, waterfallChart, weekday, windRose };
4413
+ export { DASHBOARD_DEFAULTS, DISPLAY_FACE_PROBE, LINE_CHART_DEMO, LINE_CHART_DEMO_KEYS, MIN_TOUCH_TARGET, NAVIGATION_KEYS, NullInker, PATH_BYTE_BUDGET, activityGrid, addDays, areaChart, barChart, breakpointOf, bubbleChart, bulletChart, candlestickChart, cellChartBox, checkTypeface, chordRing, composedChart, coxcombChart, createPrng, dashboardView, donutChart, enforceHeightening, funnelChart, gaugeArc, heatmapChart, inCell, isoDate, kpiCard, lineChart, linkFrom, linkedItems, linkedMarks, meterChart, orbitChart, parseGeometry, parseIsoDate, 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, weekday, windRose };
5015
4414
  //# sourceMappingURL=index.js.map
5016
4415
  //# sourceMappingURL=index.js.map