graphein 0.16.1 → 0.17.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.d.ts +68 -1
- package/dist/index.js +427 -25
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -219,35 +219,43 @@ function fixedDuration(interval) {
|
|
|
219
219
|
}
|
|
220
220
|
}
|
|
221
221
|
function floorFixed(value, interval) {
|
|
222
|
-
const duration = fixedDuration(interval);
|
|
223
|
-
if (interval.unit !== "week") {
|
|
224
|
-
return Math.floor(value / duration) * duration;
|
|
225
|
-
}
|
|
226
222
|
const date = new Date(value);
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
223
|
+
if (interval.unit === "day") {
|
|
224
|
+
return new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime();
|
|
225
|
+
}
|
|
226
|
+
if (interval.unit === "week") {
|
|
227
|
+
const day = date.getDay();
|
|
228
|
+
return new Date(date.getFullYear(), date.getMonth(), date.getDate() - day).getTime();
|
|
229
|
+
}
|
|
230
|
+
const duration = fixedDuration(interval);
|
|
231
|
+
return Math.floor(value / duration) * duration;
|
|
231
232
|
}
|
|
232
233
|
function addFixed(value, interval) {
|
|
234
|
+
const date = new Date(value);
|
|
235
|
+
if (interval.unit === "day") {
|
|
236
|
+
return new Date(date.getFullYear(), date.getMonth(), date.getDate() + interval.step).getTime();
|
|
237
|
+
}
|
|
238
|
+
if (interval.unit === "week") {
|
|
239
|
+
return new Date(date.getFullYear(), date.getMonth(), date.getDate() + 7 * interval.step).getTime();
|
|
240
|
+
}
|
|
233
241
|
return value + fixedDuration(interval);
|
|
234
242
|
}
|
|
235
243
|
function floorMonth(value, step) {
|
|
236
244
|
const date = new Date(value);
|
|
237
|
-
const month = Math.floor(date.
|
|
238
|
-
return Date
|
|
245
|
+
const month = Math.floor(date.getMonth() / step) * step;
|
|
246
|
+
return new Date(date.getFullYear(), month, 1).getTime();
|
|
239
247
|
}
|
|
240
248
|
function floorYear(value, step) {
|
|
241
249
|
const date = new Date(value);
|
|
242
|
-
const year = Math.floor(date.
|
|
243
|
-
return Date
|
|
250
|
+
const year = Math.floor(date.getFullYear() / step) * step;
|
|
251
|
+
return new Date(year, 0, 1).getTime();
|
|
244
252
|
}
|
|
245
253
|
function addCalendar(value, interval) {
|
|
246
254
|
const date = new Date(value);
|
|
247
255
|
if (interval.unit === "month") {
|
|
248
|
-
return Date
|
|
256
|
+
return new Date(date.getFullYear(), date.getMonth() + interval.step, 1).getTime();
|
|
249
257
|
}
|
|
250
|
-
return Date
|
|
258
|
+
return new Date(date.getFullYear() + interval.step, 0, 1).getTime();
|
|
251
259
|
}
|
|
252
260
|
function floorTime(value, interval) {
|
|
253
261
|
if (interval.unit === "month") {
|
|
@@ -295,17 +303,17 @@ function timeTickFormat(values) {
|
|
|
295
303
|
const span = ordered.length > 1 ? Math.abs(ordered[1] - ordered[0]) : 0;
|
|
296
304
|
return (time) => {
|
|
297
305
|
const date = new Date(time);
|
|
298
|
-
const year = date.
|
|
299
|
-
const month = MONTH_NAMES[date.
|
|
300
|
-
const day = date.
|
|
301
|
-
const hours = pad2(date.
|
|
302
|
-
const minutes = pad2(date.
|
|
303
|
-
const seconds = pad2(date.
|
|
306
|
+
const year = date.getFullYear();
|
|
307
|
+
const month = MONTH_NAMES[date.getMonth()];
|
|
308
|
+
const day = date.getDate();
|
|
309
|
+
const hours = pad2(date.getHours());
|
|
310
|
+
const minutes = pad2(date.getMinutes());
|
|
311
|
+
const seconds = pad2(date.getSeconds());
|
|
304
312
|
if (span >= YEAR * 0.8) {
|
|
305
313
|
return String(year);
|
|
306
314
|
}
|
|
307
315
|
if (span >= MONTH * 0.8) {
|
|
308
|
-
return ordered.some((tick) => new Date(tick).
|
|
316
|
+
return ordered.some((tick) => new Date(tick).getFullYear() !== year) ? `${month} ${year}` : month;
|
|
309
317
|
}
|
|
310
318
|
if (span >= DAY * 0.8) {
|
|
311
319
|
return `${month} ${day}`;
|
|
@@ -4173,6 +4181,7 @@ var COMBO_MARKS = ["line", "bar", "area", "scatter"];
|
|
|
4173
4181
|
var COMBO_AXES = ["left", "right"];
|
|
4174
4182
|
var NEGATIVE_STYLES = ["sign", "parens", "red", "parens-red"];
|
|
4175
4183
|
var SHOW_AS = ["value", "percentOfRow", "percentOfColumn", "percentOfTotal"];
|
|
4184
|
+
var DEBUG_SECTIONS = ["preview", "spec", "data", "validation", "report", "summary"];
|
|
4176
4185
|
function isObject3(v) {
|
|
4177
4186
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
4178
4187
|
}
|
|
@@ -4658,6 +4667,32 @@ function validateSpec(spec) {
|
|
|
4658
4667
|
}
|
|
4659
4668
|
}
|
|
4660
4669
|
}
|
|
4670
|
+
const debug = spec.debug;
|
|
4671
|
+
if (debug !== void 0 && typeof debug !== "boolean") {
|
|
4672
|
+
if (!isObject3(debug)) {
|
|
4673
|
+
err("debug", '"debug" must be a boolean or a DebugConfig object.');
|
|
4674
|
+
} else {
|
|
4675
|
+
const sections = debug.sections;
|
|
4676
|
+
if (sections !== void 0) {
|
|
4677
|
+
if (!Array.isArray(sections)) {
|
|
4678
|
+
err("debug.sections", '"sections" must be an array of section names.');
|
|
4679
|
+
} else {
|
|
4680
|
+
for (const s of sections) {
|
|
4681
|
+
if (!DEBUG_SECTIONS.includes(s)) {
|
|
4682
|
+
err(
|
|
4683
|
+
"debug.sections",
|
|
4684
|
+
`Unknown debug section "${String(s)}". Expected one of: ${DEBUG_SECTIONS.join(", ")}.`
|
|
4685
|
+
);
|
|
4686
|
+
}
|
|
4687
|
+
}
|
|
4688
|
+
}
|
|
4689
|
+
}
|
|
4690
|
+
const rows = debug.rows;
|
|
4691
|
+
if (rows !== void 0 && (typeof rows !== "number" || !Number.isFinite(rows) || rows < 0)) {
|
|
4692
|
+
err("debug.rows", '"rows" must be a non-negative number.');
|
|
4693
|
+
}
|
|
4694
|
+
}
|
|
4695
|
+
}
|
|
4661
4696
|
try {
|
|
4662
4697
|
for (const finding of lintSpec(spec)) warnings.push(finding);
|
|
4663
4698
|
} catch {
|
|
@@ -17448,6 +17483,356 @@ function facetReport(spec, layout2, tokens, size) {
|
|
|
17448
17483
|
};
|
|
17449
17484
|
}
|
|
17450
17485
|
|
|
17486
|
+
// src/runtime/debug.ts
|
|
17487
|
+
var DEFAULT_SECTIONS = ["preview", "summary", "validation", "report", "spec", "data"];
|
|
17488
|
+
var DEFAULT_ROW_CAP = 50;
|
|
17489
|
+
function resolveConfig(debug) {
|
|
17490
|
+
const cfg = typeof debug === "object" && debug != null ? debug : {};
|
|
17491
|
+
const sections = cfg.sections && cfg.sections.length ? cfg.sections : DEFAULT_SECTIONS;
|
|
17492
|
+
const rowCap = cfg.rows != null && Number.isFinite(cfg.rows) ? Math.max(0, Math.floor(cfg.rows)) : DEFAULT_ROW_CAP;
|
|
17493
|
+
return { sections, rowCap };
|
|
17494
|
+
}
|
|
17495
|
+
function specTitle(spec) {
|
|
17496
|
+
const t = spec.title;
|
|
17497
|
+
if (typeof t === "string") return t;
|
|
17498
|
+
if (t && typeof t === "object") return t.text;
|
|
17499
|
+
return void 0;
|
|
17500
|
+
}
|
|
17501
|
+
function cellText2(v) {
|
|
17502
|
+
if (v == null) return "";
|
|
17503
|
+
if (v instanceof Date) return v.toISOString();
|
|
17504
|
+
if (typeof v === "object") return JSON.stringify(v);
|
|
17505
|
+
return String(v);
|
|
17506
|
+
}
|
|
17507
|
+
function highlightJson(json, tokens) {
|
|
17508
|
+
const esc = json.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
17509
|
+
const syn = tokens.dark ? { key: "#7dd3fc", string: "#86efac", number: "#fca5a5", keyword: "#c4b5fd" } : { key: "#0369a1", string: "#15803d", number: "#b91c1c", keyword: "#7c3aed" };
|
|
17510
|
+
return esc.replace(
|
|
17511
|
+
/("(?:\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(?:true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+-]?\d+)?)/g,
|
|
17512
|
+
(match) => {
|
|
17513
|
+
let color = syn.number;
|
|
17514
|
+
if (match[0] === '"') color = /:\s*$/.test(match) ? syn.key : syn.string;
|
|
17515
|
+
else if (match === "true" || match === "false" || match === "null") color = syn.keyword;
|
|
17516
|
+
return `<span style="color:${color}">${match}</span>`;
|
|
17517
|
+
}
|
|
17518
|
+
);
|
|
17519
|
+
}
|
|
17520
|
+
function specForDisplay(spec) {
|
|
17521
|
+
const copy = { ...spec };
|
|
17522
|
+
if (Array.isArray(spec.data)) copy.data = `[\u2026 ${spec.data.length} rows \u2014 see the Data panel]`;
|
|
17523
|
+
return copy;
|
|
17524
|
+
}
|
|
17525
|
+
function makePanel(title2, tokens) {
|
|
17526
|
+
const card = createDiv("graphein-debug-panel", {
|
|
17527
|
+
border: `1px solid ${tokens.color.border}`,
|
|
17528
|
+
borderRadius: `${tokens.radius.md}px`,
|
|
17529
|
+
background: tokens.color.surface,
|
|
17530
|
+
overflow: "hidden",
|
|
17531
|
+
marginBottom: `${tokens.spacing.sm}px`
|
|
17532
|
+
});
|
|
17533
|
+
const header = createDiv("graphein-debug-panel-header", {
|
|
17534
|
+
display: "flex",
|
|
17535
|
+
alignItems: "center",
|
|
17536
|
+
gap: `${tokens.spacing.xs}px`,
|
|
17537
|
+
padding: `${tokens.spacing.xs}px ${tokens.spacing.sm}px`,
|
|
17538
|
+
font: fontString(tokens.font.size.small, tokens.font.family, tokens.font.weight.bold),
|
|
17539
|
+
color: tokens.color.textMuted,
|
|
17540
|
+
cursor: "pointer",
|
|
17541
|
+
userSelect: "none",
|
|
17542
|
+
borderBottom: `1px solid ${tokens.color.border}`
|
|
17543
|
+
});
|
|
17544
|
+
const caret = document.createElement("span");
|
|
17545
|
+
caret.textContent = "\u25BE";
|
|
17546
|
+
const label = document.createElement("span");
|
|
17547
|
+
label.textContent = title2;
|
|
17548
|
+
header.append(caret, label);
|
|
17549
|
+
const body = createDiv("graphein-debug-panel-body", {
|
|
17550
|
+
padding: `${tokens.spacing.sm}px`,
|
|
17551
|
+
color: tokens.color.text,
|
|
17552
|
+
font: fontString(tokens.font.size.small, tokens.font.family, tokens.font.weight.normal)
|
|
17553
|
+
});
|
|
17554
|
+
header.addEventListener("click", () => {
|
|
17555
|
+
const collapsed = body.style.display === "none";
|
|
17556
|
+
body.style.display = collapsed ? "" : "none";
|
|
17557
|
+
caret.textContent = collapsed ? "\u25BE" : "\u25B8";
|
|
17558
|
+
});
|
|
17559
|
+
card.append(header, body);
|
|
17560
|
+
return { card, body };
|
|
17561
|
+
}
|
|
17562
|
+
function monoStyle(tokens) {
|
|
17563
|
+
return {
|
|
17564
|
+
margin: "0",
|
|
17565
|
+
whiteSpace: "pre",
|
|
17566
|
+
overflow: "auto",
|
|
17567
|
+
maxHeight: "320px",
|
|
17568
|
+
fontFamily: "ui-monospace, SFMono-Regular, Menlo, Consolas, monospace",
|
|
17569
|
+
fontSize: `${tokens.font.size.small}px`,
|
|
17570
|
+
lineHeight: "1.5"
|
|
17571
|
+
};
|
|
17572
|
+
}
|
|
17573
|
+
function buildPreviewPanel(spec, tokens, deps) {
|
|
17574
|
+
const { card, body } = makePanel("Live preview", tokens);
|
|
17575
|
+
const host = createDiv("graphein-debug-preview", { position: "relative", width: "100%", height: "260px" });
|
|
17576
|
+
body.appendChild(host);
|
|
17577
|
+
let preview = null;
|
|
17578
|
+
let report = null;
|
|
17579
|
+
try {
|
|
17580
|
+
preview = deps.renderPreview(host, { ...spec, debug: false, animation: false });
|
|
17581
|
+
report = preview.report();
|
|
17582
|
+
} catch (e) {
|
|
17583
|
+
body.replaceChildren();
|
|
17584
|
+
const msg = createDiv(void 0, { color: tokens.color.negative, whiteSpace: "pre-wrap" });
|
|
17585
|
+
msg.textContent = `Preview failed to render:
|
|
17586
|
+
${e instanceof Error ? e.message : String(e)}`;
|
|
17587
|
+
body.appendChild(msg);
|
|
17588
|
+
}
|
|
17589
|
+
return { card, preview, report };
|
|
17590
|
+
}
|
|
17591
|
+
function buildSummaryPanel(spec, tokens) {
|
|
17592
|
+
const { card, body } = makePanel("Summary", tokens);
|
|
17593
|
+
let text = "";
|
|
17594
|
+
try {
|
|
17595
|
+
text = summarize(spec);
|
|
17596
|
+
} catch {
|
|
17597
|
+
text = "";
|
|
17598
|
+
}
|
|
17599
|
+
body.textContent = text || "\u2014 (no summary for this chart type)";
|
|
17600
|
+
if (!text) setStyle(body, { color: tokens.color.textMuted });
|
|
17601
|
+
return card;
|
|
17602
|
+
}
|
|
17603
|
+
function diagnosticRow(path, message, color, tokens) {
|
|
17604
|
+
const row = createDiv(void 0, { display: "flex", gap: `${tokens.spacing.xs}px`, padding: "2px 0" });
|
|
17605
|
+
const key = document.createElement("code");
|
|
17606
|
+
key.textContent = path;
|
|
17607
|
+
setStyle(key, { color, fontWeight: String(tokens.font.weight.bold), flex: "0 0 auto" });
|
|
17608
|
+
const msg = document.createElement("span");
|
|
17609
|
+
msg.textContent = message;
|
|
17610
|
+
setStyle(msg, { color: tokens.color.text });
|
|
17611
|
+
row.append(key, msg);
|
|
17612
|
+
return row;
|
|
17613
|
+
}
|
|
17614
|
+
function buildValidationPanel(spec, tokens) {
|
|
17615
|
+
const { card, body } = makePanel("Validation", tokens);
|
|
17616
|
+
const result = validateSpec(spec);
|
|
17617
|
+
if (result.valid && result.warnings.length === 0) {
|
|
17618
|
+
body.textContent = "\u2713 Valid \u2014 no errors or warnings";
|
|
17619
|
+
setStyle(body, { color: tokens.color.positive });
|
|
17620
|
+
return card;
|
|
17621
|
+
}
|
|
17622
|
+
const add = (items, color, prefix) => {
|
|
17623
|
+
for (const item of items) {
|
|
17624
|
+
const tag = item.rule ? `${prefix} ${item.rule}` : prefix;
|
|
17625
|
+
body.appendChild(diagnosticRow(item.path ? `${tag} @ ${item.path}` : tag, item.message, color, tokens));
|
|
17626
|
+
}
|
|
17627
|
+
};
|
|
17628
|
+
add(result.errors, tokens.color.negative, "error");
|
|
17629
|
+
add(result.warnings, tokens.dark ? "#fbbf24" : "#b45309", "warn");
|
|
17630
|
+
return card;
|
|
17631
|
+
}
|
|
17632
|
+
function buildReportPanel(report, tokens) {
|
|
17633
|
+
const { card, body } = makePanel("Render report", tokens);
|
|
17634
|
+
if (!report) {
|
|
17635
|
+
body.textContent = "\u2014 (no report available)";
|
|
17636
|
+
setStyle(body, { color: tokens.color.textMuted });
|
|
17637
|
+
return card;
|
|
17638
|
+
}
|
|
17639
|
+
const stats = createDiv(void 0, { marginBottom: `${tokens.spacing.xs}px` });
|
|
17640
|
+
const ok = report.ok ? "\u2713 ok" : "\u2717 issues";
|
|
17641
|
+
stats.textContent = `${ok} \xB7 ${report.type} \xB7 ${Math.round(report.size.width)}\xD7${Math.round(report.size.height)}px \xB7 marks ${report.markCount} \xB7 series ${report.seriesCount} \xB7 colors ${report.colorCount}`;
|
|
17642
|
+
setStyle(stats, { color: report.ok ? tokens.color.positive : tokens.color.negative });
|
|
17643
|
+
body.appendChild(stats);
|
|
17644
|
+
for (const d of report.diagnostics) {
|
|
17645
|
+
const color = d.severity === "error" ? tokens.color.negative : d.severity === "warning" ? tokens.dark ? "#fbbf24" : "#b45309" : tokens.color.textMuted;
|
|
17646
|
+
body.appendChild(diagnosticRow(d.code, d.message, color, tokens));
|
|
17647
|
+
}
|
|
17648
|
+
return card;
|
|
17649
|
+
}
|
|
17650
|
+
function buildSpecPanel(spec, tokens) {
|
|
17651
|
+
const { card, body } = makePanel("Spec", tokens);
|
|
17652
|
+
const pre = document.createElement("pre");
|
|
17653
|
+
setStyle(pre, monoStyle(tokens));
|
|
17654
|
+
pre.innerHTML = highlightJson(JSON.stringify(specForDisplay(spec), null, 2), tokens);
|
|
17655
|
+
body.appendChild(pre);
|
|
17656
|
+
return card;
|
|
17657
|
+
}
|
|
17658
|
+
function buildDataPanel(spec, tokens, rowCap) {
|
|
17659
|
+
const { card, body } = makePanel("Data", tokens);
|
|
17660
|
+
const data = Array.isArray(spec.data) ? spec.data : [];
|
|
17661
|
+
if (data.length === 0) {
|
|
17662
|
+
body.textContent = "\u2014 (no data)";
|
|
17663
|
+
setStyle(body, { color: tokens.color.textMuted });
|
|
17664
|
+
return card;
|
|
17665
|
+
}
|
|
17666
|
+
const columns = Object.keys(data[0] ?? {});
|
|
17667
|
+
const types = new Map(columns.map((c) => [c, inferType(data, c)]));
|
|
17668
|
+
const reads = new Map(columns.map((c) => [c, accessor(c)]));
|
|
17669
|
+
const scroll = createDiv(void 0, { overflow: "auto", maxHeight: "320px" });
|
|
17670
|
+
const table = document.createElement("table");
|
|
17671
|
+
setStyle(table, {
|
|
17672
|
+
borderCollapse: "collapse",
|
|
17673
|
+
width: "100%",
|
|
17674
|
+
fontFamily: "ui-monospace, SFMono-Regular, Menlo, Consolas, monospace",
|
|
17675
|
+
fontSize: `${tokens.font.size.small}px`
|
|
17676
|
+
});
|
|
17677
|
+
const thead = document.createElement("thead");
|
|
17678
|
+
const htr = document.createElement("tr");
|
|
17679
|
+
for (const c of columns) {
|
|
17680
|
+
const th = document.createElement("th");
|
|
17681
|
+
setStyle(th, {
|
|
17682
|
+
textAlign: "left",
|
|
17683
|
+
padding: "3px 8px",
|
|
17684
|
+
borderBottom: `1px solid ${tokens.color.border}`,
|
|
17685
|
+
color: tokens.color.text,
|
|
17686
|
+
whiteSpace: "nowrap",
|
|
17687
|
+
position: "sticky",
|
|
17688
|
+
top: "0",
|
|
17689
|
+
background: tokens.color.surface
|
|
17690
|
+
});
|
|
17691
|
+
const name = document.createElement("div");
|
|
17692
|
+
name.textContent = c;
|
|
17693
|
+
const type = document.createElement("div");
|
|
17694
|
+
type.textContent = types.get(c) ?? "nominal";
|
|
17695
|
+
setStyle(type, { color: tokens.color.textMuted, fontWeight: "400", fontSize: `${tokens.font.size.tiny}px` });
|
|
17696
|
+
th.append(name, type);
|
|
17697
|
+
htr.appendChild(th);
|
|
17698
|
+
}
|
|
17699
|
+
thead.appendChild(htr);
|
|
17700
|
+
table.appendChild(thead);
|
|
17701
|
+
const tbody = document.createElement("tbody");
|
|
17702
|
+
const shown = Math.min(data.length, rowCap);
|
|
17703
|
+
for (let i = 0; i < shown; i++) {
|
|
17704
|
+
const tr = document.createElement("tr");
|
|
17705
|
+
for (const c of columns) {
|
|
17706
|
+
const td = document.createElement("td");
|
|
17707
|
+
setStyle(td, { padding: "3px 8px", borderBottom: `1px solid ${tokens.color.border}`, color: tokens.color.text, whiteSpace: "nowrap" });
|
|
17708
|
+
td.textContent = cellText2(reads.get(c)(data[i]));
|
|
17709
|
+
tr.appendChild(td);
|
|
17710
|
+
}
|
|
17711
|
+
tbody.appendChild(tr);
|
|
17712
|
+
}
|
|
17713
|
+
table.appendChild(tbody);
|
|
17714
|
+
scroll.appendChild(table);
|
|
17715
|
+
body.appendChild(scroll);
|
|
17716
|
+
const footer = createDiv(void 0, { marginTop: `${tokens.spacing.xs}px`, color: tokens.color.textMuted });
|
|
17717
|
+
footer.textContent = `${data.length} row${data.length === 1 ? "" : "s"} \xD7 ${columns.length} column${columns.length === 1 ? "" : "s"}` + (shown < data.length ? ` (showing first ${shown})` : "");
|
|
17718
|
+
body.appendChild(footer);
|
|
17719
|
+
return card;
|
|
17720
|
+
}
|
|
17721
|
+
function renderDebugView(surface, spec, tokens, size, deps) {
|
|
17722
|
+
const { sections, rowCap } = resolveConfig(spec.debug);
|
|
17723
|
+
const want = (s) => sections.includes(s);
|
|
17724
|
+
const host = createDiv("graphein-debug", {
|
|
17725
|
+
position: "absolute",
|
|
17726
|
+
inset: "0",
|
|
17727
|
+
width: "100%",
|
|
17728
|
+
height: "100%",
|
|
17729
|
+
boxSizing: "border-box",
|
|
17730
|
+
overflow: "auto",
|
|
17731
|
+
padding: `${tokens.spacing.md}px`,
|
|
17732
|
+
background: tokens.color.background,
|
|
17733
|
+
color: tokens.color.text,
|
|
17734
|
+
font: fontString(tokens.font.size.base, tokens.font.family, tokens.font.weight.normal),
|
|
17735
|
+
pointerEvents: "auto"
|
|
17736
|
+
});
|
|
17737
|
+
const header = createDiv(void 0, {
|
|
17738
|
+
display: "flex",
|
|
17739
|
+
alignItems: "center",
|
|
17740
|
+
gap: `${tokens.spacing.sm}px`,
|
|
17741
|
+
marginBottom: `${tokens.spacing.sm}px`
|
|
17742
|
+
});
|
|
17743
|
+
const badge = document.createElement("span");
|
|
17744
|
+
badge.textContent = "DEBUG";
|
|
17745
|
+
setStyle(badge, {
|
|
17746
|
+
background: tokens.color.accent,
|
|
17747
|
+
color: "#ffffff",
|
|
17748
|
+
borderRadius: `${tokens.radius.sm}px`,
|
|
17749
|
+
padding: "2px 6px",
|
|
17750
|
+
font: fontString(tokens.font.size.tiny, tokens.font.family, tokens.font.weight.bold),
|
|
17751
|
+
letterSpacing: "0.06em"
|
|
17752
|
+
});
|
|
17753
|
+
const typeLabel = document.createElement("span");
|
|
17754
|
+
typeLabel.textContent = spec.type;
|
|
17755
|
+
setStyle(typeLabel, { fontWeight: String(tokens.font.weight.bold) });
|
|
17756
|
+
header.append(badge, typeLabel);
|
|
17757
|
+
const title2 = specTitle(spec);
|
|
17758
|
+
if (title2) {
|
|
17759
|
+
const t = document.createElement("span");
|
|
17760
|
+
t.textContent = title2;
|
|
17761
|
+
setStyle(t, { color: tokens.color.textMuted });
|
|
17762
|
+
header.appendChild(t);
|
|
17763
|
+
}
|
|
17764
|
+
host.appendChild(header);
|
|
17765
|
+
const body = createDiv(void 0, { display: "flex", flexWrap: "wrap", gap: `${tokens.spacing.md}px`, alignItems: "flex-start" });
|
|
17766
|
+
const left = createDiv(void 0, { flex: "1 1 320px", minWidth: "0" });
|
|
17767
|
+
const right = createDiv(void 0, { flex: "1 1 320px", minWidth: "0" });
|
|
17768
|
+
body.append(left, right);
|
|
17769
|
+
host.appendChild(body);
|
|
17770
|
+
let preview = null;
|
|
17771
|
+
let previewReport = null;
|
|
17772
|
+
if (want("preview")) {
|
|
17773
|
+
const p = buildPreviewPanel(spec, tokens, deps);
|
|
17774
|
+
left.appendChild(p.card);
|
|
17775
|
+
preview = p.preview;
|
|
17776
|
+
previewReport = p.report;
|
|
17777
|
+
}
|
|
17778
|
+
if (want("summary")) left.appendChild(buildSummaryPanel(spec, tokens));
|
|
17779
|
+
if (want("validation")) left.appendChild(buildValidationPanel(spec, tokens));
|
|
17780
|
+
if (want("report")) left.appendChild(buildReportPanel(previewReport, tokens));
|
|
17781
|
+
if (want("spec")) right.appendChild(buildSpecPanel(spec, tokens));
|
|
17782
|
+
if (want("data")) right.appendChild(buildDataPanel(spec, tokens, rowCap));
|
|
17783
|
+
surface.overlay.appendChild(host);
|
|
17784
|
+
const report = previewReport ?? {
|
|
17785
|
+
type: spec.type,
|
|
17786
|
+
size,
|
|
17787
|
+
markCount: 0,
|
|
17788
|
+
seriesCount: 0,
|
|
17789
|
+
colorCount: 0,
|
|
17790
|
+
ok: true,
|
|
17791
|
+
diagnostics: []
|
|
17792
|
+
};
|
|
17793
|
+
return { preview, report };
|
|
17794
|
+
}
|
|
17795
|
+
function drawDebugCanvas(surface, spec, tokens, size) {
|
|
17796
|
+
const ctx = surface.marks.ctx;
|
|
17797
|
+
const pad3 = tokens.spacing.md;
|
|
17798
|
+
const lineH = tokens.font.size.small * 1.5;
|
|
17799
|
+
let y = pad3 + tokens.font.size.large;
|
|
17800
|
+
ctx.save();
|
|
17801
|
+
ctx.textBaseline = "alphabetic";
|
|
17802
|
+
ctx.fillStyle = tokens.color.text;
|
|
17803
|
+
ctx.font = fontString(tokens.font.size.large, tokens.font.family, tokens.font.weight.bold);
|
|
17804
|
+
ctx.fillText(`DEBUG \xB7 ${spec.type}`, pad3, y);
|
|
17805
|
+
y += lineH * 1.5;
|
|
17806
|
+
const result = validateSpec(spec);
|
|
17807
|
+
const rowCount = Array.isArray(spec.data) ? spec.data.length : 0;
|
|
17808
|
+
const header = [
|
|
17809
|
+
`rows: ${rowCount}`,
|
|
17810
|
+
`errors: ${result.errors.length}`,
|
|
17811
|
+
`warnings: ${result.warnings.length}`
|
|
17812
|
+
].join(" ");
|
|
17813
|
+
ctx.fillStyle = result.valid ? tokens.color.textMuted : tokens.color.negative;
|
|
17814
|
+
ctx.font = fontString(tokens.font.size.small, tokens.font.family, tokens.font.weight.normal);
|
|
17815
|
+
ctx.fillText(header, pad3, y);
|
|
17816
|
+
y += lineH * 1.5;
|
|
17817
|
+
ctx.fillStyle = tokens.color.text;
|
|
17818
|
+
ctx.font = fontString(
|
|
17819
|
+
tokens.font.size.small,
|
|
17820
|
+
"ui-monospace, SFMono-Regular, Menlo, Consolas, monospace",
|
|
17821
|
+
tokens.font.weight.normal
|
|
17822
|
+
);
|
|
17823
|
+
const json = JSON.stringify(specForDisplay(spec), null, 2);
|
|
17824
|
+
for (const line2 of json.split("\n")) {
|
|
17825
|
+
if (y > size.height - pad3) {
|
|
17826
|
+
ctx.fillStyle = tokens.color.textMuted;
|
|
17827
|
+
ctx.fillText("\u2026", pad3, y);
|
|
17828
|
+
break;
|
|
17829
|
+
}
|
|
17830
|
+
ctx.fillText(line2, pad3, y);
|
|
17831
|
+
y += lineH;
|
|
17832
|
+
}
|
|
17833
|
+
ctx.restore();
|
|
17834
|
+
}
|
|
17835
|
+
|
|
17451
17836
|
// src/render/fonts.ts
|
|
17452
17837
|
function fontFaceSet() {
|
|
17453
17838
|
try {
|
|
@@ -17635,6 +18020,7 @@ function render(target, spec, options) {
|
|
|
17635
18020
|
let interaction;
|
|
17636
18021
|
let entrance;
|
|
17637
18022
|
let updateTransition;
|
|
18023
|
+
let preview;
|
|
17638
18024
|
let lastValue = null;
|
|
17639
18025
|
let lastCompare = null;
|
|
17640
18026
|
let lastSparkline = null;
|
|
@@ -17670,6 +18056,8 @@ function render(target, spec, options) {
|
|
|
17670
18056
|
entrance = void 0;
|
|
17671
18057
|
updateTransition?.cancel();
|
|
17672
18058
|
updateTransition = void 0;
|
|
18059
|
+
preview?.destroy();
|
|
18060
|
+
preview = void 0;
|
|
17673
18061
|
const tokens = resolveSketchTokens(currentSpec);
|
|
17674
18062
|
const size = resolveSize(container, currentSpec);
|
|
17675
18063
|
lastDrawnW = size.width;
|
|
@@ -17693,6 +18081,7 @@ function render(target, spec, options) {
|
|
|
17693
18081
|
let interactionModel = null;
|
|
17694
18082
|
let reportModel;
|
|
17695
18083
|
let facetRpt;
|
|
18084
|
+
let debugReport;
|
|
17696
18085
|
let legendSelect = null;
|
|
17697
18086
|
const type = currentSpec.type;
|
|
17698
18087
|
if (COUNT_UP_TYPES.has(type) || SWEEP_TYPES.has(type)) {
|
|
@@ -17700,8 +18089,15 @@ function render(target, spec, options) {
|
|
|
17700
18089
|
lastCompare = SWEEP_TYPES.has(type) ? resolveValueRef(effectiveSpec.compare, effectiveSpec.data ?? EMPTY_DATA) : null;
|
|
17701
18090
|
lastSparkline = type === "kpi" ? kpiSparklineSeries(effectiveSpec, effectiveSpec.data ?? EMPTY_DATA) : null;
|
|
17702
18091
|
}
|
|
17703
|
-
const facetLayout = isFaceted(effectiveSpec) ? buildFacetModels(effectiveSpec, tokens, size) : null;
|
|
17704
|
-
if (
|
|
18092
|
+
const facetLayout = !currentSpec.debug && isFaceted(effectiveSpec) ? buildFacetModels(effectiveSpec, tokens, size) : null;
|
|
18093
|
+
if (currentSpec.debug) {
|
|
18094
|
+
const result = renderDebugView(surface, effectiveSpec, tokens, size, {
|
|
18095
|
+
renderPreview: (host, previewSpec) => render(host, previewSpec, { inspect: false })
|
|
18096
|
+
});
|
|
18097
|
+
preview = result.preview ?? void 0;
|
|
18098
|
+
debugReport = result.report;
|
|
18099
|
+
interactionModel = null;
|
|
18100
|
+
} else if (facetLayout) {
|
|
17705
18101
|
drawFacet(surface, effectiveSpec, facetLayout, tokens);
|
|
17706
18102
|
facetRpt = facetReport(effectiveSpec, facetLayout, tokens, size);
|
|
17707
18103
|
} else if (CARTESIAN_TYPES.has(type)) {
|
|
@@ -17804,7 +18200,7 @@ function render(target, spec, options) {
|
|
|
17804
18200
|
}
|
|
17805
18201
|
applyA11y(surface, currentSpec);
|
|
17806
18202
|
inspector?.write(currentSpec);
|
|
17807
|
-
lastReport = facetRpt ?? buildRenderReport({
|
|
18203
|
+
lastReport = debugReport ?? facetRpt ?? buildRenderReport({
|
|
17808
18204
|
type,
|
|
17809
18205
|
spec: currentSpec,
|
|
17810
18206
|
data: filtered,
|
|
@@ -17946,6 +18342,7 @@ function render(target, spec, options) {
|
|
|
17946
18342
|
hostListeners.clear();
|
|
17947
18343
|
entrance?.cancel();
|
|
17948
18344
|
updateTransition?.cancel();
|
|
18345
|
+
preview?.destroy();
|
|
17949
18346
|
observer?.disconnect();
|
|
17950
18347
|
inspector?.destroy();
|
|
17951
18348
|
interaction?.destroy();
|
|
@@ -19011,6 +19408,11 @@ function renderToContext(target, spec) {
|
|
|
19011
19408
|
const src = spec.data ?? [];
|
|
19012
19409
|
const data = spec.transform?.length ? applyTransforms(spec.transform, src) : src;
|
|
19013
19410
|
const effectiveSpec = data === src ? spec : { ...spec, data };
|
|
19411
|
+
if (spec.debug) {
|
|
19412
|
+
drawDebugCanvas(surface, effectiveSpec, tokens, size);
|
|
19413
|
+
const model = CARTESIAN_TYPES.has(type) ? buildCartesianModel(effectiveSpec, tokens, size) : void 0;
|
|
19414
|
+
return buildRenderReport({ type, spec, data, tokens, size, model });
|
|
19415
|
+
}
|
|
19014
19416
|
if (isFaceted(effectiveSpec)) {
|
|
19015
19417
|
const layout2 = buildFacetModels(effectiveSpec, tokens, size);
|
|
19016
19418
|
if (layout2) {
|
|
@@ -19053,6 +19455,6 @@ function renderToContext(target, spec) {
|
|
|
19053
19455
|
// src/index.ts
|
|
19054
19456
|
var VERSION = "0.1.0";
|
|
19055
19457
|
|
|
19056
|
-
export { CARTESIAN_TYPES, CHART_TYPES, CanvasLayer, DEFAULT_ENTRANCE_DURATION, DEFAULT_ROUGH_STYLE, DEFAULT_UPDATE_DURATION, DIM_ALPHA, ExpressionError, FACETABLE_TYPES2 as FACETABLE_TYPES, FUNCTION_NAMES, InteractionController, NO_PADDING, RoughPen, SKETCH_FONT_FAMILY, SKETCH_FONT_NAME, SLICER_TYPES, SPEC_ATTR, SR_ONLY_STYLE, Surface, TICK_SIZE, TIME_UNITS, TRANSFORM_KINDS, TYPE_ATTR, Tooltip, VERSION, aggregateValues, analyzeChart, animate, applyA11y, applyAggregate, applyBin, applyCalculate, applyFilter, applyFold, applyPatch, applyPick, applyTimeUnit, applyTransform, applyTransforms, arc, area, assertValidSpec, autoInsightAnnotations, backOut, bandScale, bounceOut, buildCartesianInteraction, buildCartesianModel, buildComboModel, buildDataTableFallback, buildFacetModels, buildHistogramModel, buildRenderReport, cartesianInteractionBuilders, cartesianRenderers, categorical, categoricalSchemes, chartTitleText, chartTypeLabel, checkExpression, clamp012 as clamp01, clamp255, compileExpression, compilePredicate, computeBackingSize, computeBins, computeFrame, computeSeriesInsights, contrastRatio, createDiv, createInspector, createRoughPen, createSelectionStore, cubicIn, cubicInOut, cubicOut, curveCatmullRom, curveLinear, curveMonotoneX, curveStep, curveStepAfter, curveStepBefore, customRenderers, darkTheme, decimate, defaultSpan, dependentParams, diverging, divergingColorScale, divergingSchemes, drawAnnotationLabels, drawAnnotations, drawAxesUnderlay, drawFacet, drawLegend, drawOverlay, drawTitle, drawTrendlineLabels, drawTrendlines, easings, elasticOut, ellipsize, ensureSketchFont, expoInOut, expoOut, facetReport, fillParentStyle, filterRows, fontString, formatCountUp, formatDate, formatNumber2 as formatNumber, formatValue, getDevicePixelRatio, groupBy, hashString, inferFieldType, inferFieldTypes, inferValueType, inheritInto, interpolateArray, interpolateNumber, interpolateNumberArray, interpolateObject, interpolateOklab, interpolateRgb, isBrowser, isEmptyValue, isFaceted, isParamClause, isSlicerType, keyFields, legendSwatchWidth, lightTheme, line, linear, linearRegression, linearScale, linearToSrgb, lintSpec, literalToValue, logScale, lttbRun, makeMatcher, matchesValue, measureText, monotoneXTangents, mulberry32, niceDomain, oklabToOklch, oklabToRgb, oklchToOklab, ordinalColorScale, overlayTextToCanvasCmd, paintCanvasText, paintLegendSwatch, parseColor, parseNumberFormat, pivot, placeViews, pointScale, polygonHachureLines, prefersReducedMotion, prettyDate, profileColumns, quadIn, quadInOut, quadOut, rampFromStops, readableTextColor, recommendChart, relativeLuminance, render, renderDashboard, renderToContext, repairReport, repairSpec, resolveCurve, resolveDashboardLayout, resolveDashboardSections, resolveEmphasis, resolveEntrance, resolveFilterValues, resolveInsightOptions, resolveSketch, resolveTheme, resolveUpdate, resolveValueRef, rgbToOklab, rgbaToCss, rotatePoint, roundedRect, sampleArc, sequential, sequentialColorScale, sequentialSchemes, serializeSpec, setMeasureContext, setStyle, sinInOut, slicerParamName, smartDate, specFields, srgbToLinear, stripData, summarize, summarizeChart, themes, tickIncrement, tickStep, ticks, timeScale, timeTickFormat, timeTicks, toHex, toPointer, tooltipEnabled, truncateTo, validateDashboard, validateSpec, wireViews, withAlpha, withSketchFont };
|
|
19458
|
+
export { CARTESIAN_TYPES, CHART_TYPES, CanvasLayer, DEFAULT_ENTRANCE_DURATION, DEFAULT_ROUGH_STYLE, DEFAULT_UPDATE_DURATION, DIM_ALPHA, ExpressionError, FACETABLE_TYPES2 as FACETABLE_TYPES, FUNCTION_NAMES, InteractionController, NO_PADDING, RoughPen, SKETCH_FONT_FAMILY, SKETCH_FONT_NAME, SLICER_TYPES, SPEC_ATTR, SR_ONLY_STYLE, Surface, TICK_SIZE, TIME_UNITS, TRANSFORM_KINDS, TYPE_ATTR, Tooltip, VERSION, aggregateValues, analyzeChart, animate, applyA11y, applyAggregate, applyBin, applyCalculate, applyFilter, applyFold, applyPatch, applyPick, applyTimeUnit, applyTransform, applyTransforms, arc, area, assertValidSpec, autoInsightAnnotations, backOut, bandScale, bounceOut, buildCartesianInteraction, buildCartesianModel, buildComboModel, buildDataTableFallback, buildFacetModels, buildHistogramModel, buildRenderReport, cartesianInteractionBuilders, cartesianRenderers, categorical, categoricalSchemes, chartTitleText, chartTypeLabel, checkExpression, clamp012 as clamp01, clamp255, compileExpression, compilePredicate, computeBackingSize, computeBins, computeFrame, computeSeriesInsights, contrastRatio, createDiv, createInspector, createRoughPen, createSelectionStore, cubicIn, cubicInOut, cubicOut, curveCatmullRom, curveLinear, curveMonotoneX, curveStep, curveStepAfter, curveStepBefore, customRenderers, darkTheme, decimate, defaultSpan, dependentParams, diverging, divergingColorScale, divergingSchemes, drawAnnotationLabels, drawAnnotations, drawAxesUnderlay, drawDebugCanvas, drawFacet, drawLegend, drawOverlay, drawTitle, drawTrendlineLabels, drawTrendlines, easings, elasticOut, ellipsize, ensureSketchFont, expoInOut, expoOut, facetReport, fillParentStyle, filterRows, fontString, formatCountUp, formatDate, formatNumber2 as formatNumber, formatValue, getDevicePixelRatio, groupBy, hashString, inferFieldType, inferFieldTypes, inferValueType, inheritInto, interpolateArray, interpolateNumber, interpolateNumberArray, interpolateObject, interpolateOklab, interpolateRgb, isBrowser, isEmptyValue, isFaceted, isParamClause, isSlicerType, keyFields, legendSwatchWidth, lightTheme, line, linear, linearRegression, linearScale, linearToSrgb, lintSpec, literalToValue, logScale, lttbRun, makeMatcher, matchesValue, measureText, monotoneXTangents, mulberry32, niceDomain, oklabToOklch, oklabToRgb, oklchToOklab, ordinalColorScale, overlayTextToCanvasCmd, paintCanvasText, paintLegendSwatch, parseColor, parseNumberFormat, pivot, placeViews, pointScale, polygonHachureLines, prefersReducedMotion, prettyDate, profileColumns, quadIn, quadInOut, quadOut, rampFromStops, readableTextColor, recommendChart, relativeLuminance, render, renderDashboard, renderDebugView, renderToContext, repairReport, repairSpec, resolveCurve, resolveDashboardLayout, resolveDashboardSections, resolveEmphasis, resolveEntrance, resolveFilterValues, resolveInsightOptions, resolveSketch, resolveTheme, resolveUpdate, resolveValueRef, rgbToOklab, rgbaToCss, rotatePoint, roundedRect, sampleArc, sequential, sequentialColorScale, sequentialSchemes, serializeSpec, setMeasureContext, setStyle, sinInOut, slicerParamName, smartDate, specFields, srgbToLinear, stripData, summarize, summarizeChart, themes, tickIncrement, tickStep, ticks, timeScale, timeTickFormat, timeTicks, toHex, toPointer, tooltipEnabled, truncateTo, validateDashboard, validateSpec, wireViews, withAlpha, withSketchFont };
|
|
19057
19459
|
//# sourceMappingURL=index.js.map
|
|
19058
19460
|
//# sourceMappingURL=index.js.map
|