graphein 0.11.0 → 0.12.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 +244 -44
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -10159,7 +10159,7 @@ function buildTable(opts) {
|
|
|
10159
10159
|
overflow: "auto",
|
|
10160
10160
|
pointerEvents: "auto",
|
|
10161
10161
|
boxSizing: "border-box",
|
|
10162
|
-
border: `1px solid ${tokens.color.border}`,
|
|
10162
|
+
border: `1px solid ${opts.sketch ? "transparent" : tokens.color.border}`,
|
|
10163
10163
|
borderRadius: opts.sketch ? SKETCH_BORDER_RADIUS2 : `${tokens.radius.sm}px`,
|
|
10164
10164
|
background: tokens.color.background
|
|
10165
10165
|
});
|
|
@@ -10190,14 +10190,23 @@ function paintTableCanvas(opts) {
|
|
|
10190
10190
|
const available = Math.max(0, rect.width - 2);
|
|
10191
10191
|
const widths = computeFittedWidths(opts.columns, available);
|
|
10192
10192
|
opts.widths = widths;
|
|
10193
|
+
const pen = opts.sketch ? new RoughPen(ctx, opts.sketch) : null;
|
|
10194
|
+
const w = Math.max(0, rect.width);
|
|
10195
|
+
const h = Math.max(0, rect.height);
|
|
10193
10196
|
ctx.save();
|
|
10194
10197
|
ctx.beginPath();
|
|
10195
|
-
|
|
10196
|
-
|
|
10197
|
-
|
|
10198
|
-
|
|
10199
|
-
|
|
10200
|
-
|
|
10198
|
+
if (pen) {
|
|
10199
|
+
ctx.rect(rect.x, rect.y, w, h);
|
|
10200
|
+
ctx.fillStyle = tokens.color.background;
|
|
10201
|
+
ctx.fill();
|
|
10202
|
+
} else {
|
|
10203
|
+
roundedRect(ctx, rect.x, rect.y, w, h, tokens.radius.sm);
|
|
10204
|
+
ctx.fillStyle = tokens.color.background;
|
|
10205
|
+
ctx.fill();
|
|
10206
|
+
ctx.lineWidth = 1;
|
|
10207
|
+
ctx.strokeStyle = tokens.color.border;
|
|
10208
|
+
ctx.stroke();
|
|
10209
|
+
}
|
|
10201
10210
|
ctx.clip();
|
|
10202
10211
|
const headerRows = normalizedHeaderRows(opts);
|
|
10203
10212
|
const headerHeight = headerRows.length * metrics.headerHeight;
|
|
@@ -10209,17 +10218,18 @@ function paintTableCanvas(opts) {
|
|
|
10209
10218
|
const clipped = visibleRows < opts.rowCount;
|
|
10210
10219
|
const cueReserve = clipped && opts.clippedCue !== false && visibleRows > 0 ? metrics.rowHeight : 0;
|
|
10211
10220
|
const rowsToDraw = Math.max(0, visibleRows - (cueReserve > 0 ? 1 : 0));
|
|
10212
|
-
paintHeaderCanvas(opts, widths, headerRows, metrics);
|
|
10221
|
+
paintHeaderCanvas(opts, widths, headerRows, metrics, pen);
|
|
10213
10222
|
for (let rowIndex = 0; rowIndex < rowsToDraw; rowIndex += 1) {
|
|
10214
|
-
paintBodyRowCanvas(opts, widths, rowIndex, bodyTop + rowIndex * metrics.rowHeight, metrics);
|
|
10223
|
+
paintBodyRowCanvas(opts, widths, rowIndex, bodyTop + rowIndex * metrics.rowHeight, metrics, pen);
|
|
10215
10224
|
}
|
|
10216
10225
|
if (cueReserve > 0) {
|
|
10217
10226
|
paintClippedCueCanvas(opts, bodyTop + rowsToDraw * metrics.rowHeight, metrics, opts.rowCount - rowsToDraw);
|
|
10218
10227
|
}
|
|
10219
10228
|
if (opts.footerRow) {
|
|
10220
|
-
paintFooterCanvas(opts, widths, rect.y + rect.height - metrics.rowHeight, metrics);
|
|
10229
|
+
paintFooterCanvas(opts, widths, rect.y + rect.height - metrics.rowHeight, metrics, pen);
|
|
10221
10230
|
}
|
|
10222
10231
|
ctx.restore();
|
|
10232
|
+
if (pen) pen.rect(rect.x, rect.y, w, h, { stroke: tokens.color.border });
|
|
10223
10233
|
}
|
|
10224
10234
|
var FILL_EPS = 0.5;
|
|
10225
10235
|
var cachedScrollbarWidth = null;
|
|
@@ -10312,14 +10322,14 @@ function makeHeaderCell(opts, title2, colIndex, align, rowIndex = 0) {
|
|
|
10312
10322
|
th.textContent = title2;
|
|
10313
10323
|
const isSorted = colIndex != null && opts.sortState?.col === colIndex;
|
|
10314
10324
|
if (isSorted) th.setAttribute("aria-sort", opts.sortState?.dir === "desc" ? "descending" : "ascending");
|
|
10315
|
-
setCellBaseStyles(th, opts.tokens, align ?? "left", opts.stickyHeader !== false, metrics.padding);
|
|
10325
|
+
setCellBaseStyles(th, opts.tokens, align ?? "left", opts.stickyHeader !== false, metrics.padding, gridBorderColor(opts));
|
|
10316
10326
|
setStyles(th, {
|
|
10317
10327
|
top: `${rowIndex * metrics.headerHeight}px`,
|
|
10318
10328
|
zIndex: "4",
|
|
10319
10329
|
background: opts.tokens.color.surface,
|
|
10320
10330
|
color: opts.tokens.color.text,
|
|
10321
10331
|
fontWeight: String(opts.tokens.font.weight.bold),
|
|
10322
|
-
borderBottom: `1px solid ${opts
|
|
10332
|
+
borderBottom: `1px solid ${gridBorderColor(opts)}`,
|
|
10323
10333
|
userSelect: "none",
|
|
10324
10334
|
height: `${metrics.headerHeight}px`
|
|
10325
10335
|
});
|
|
@@ -10377,19 +10387,19 @@ function makeBodyRow(opts, rowIndex, rowHeight) {
|
|
|
10377
10387
|
const td = document.createElement("td");
|
|
10378
10388
|
const cell = opts.getCell(rowIndex, colIndex);
|
|
10379
10389
|
const rowBg = rowBackground(opts, rowIndex, cls);
|
|
10380
|
-
setCellBaseStyles(td, opts.tokens, column.align, false, metrics.padding);
|
|
10390
|
+
setCellBaseStyles(td, opts.tokens, column.align, false, metrics.padding, gridBorderColor(opts));
|
|
10381
10391
|
setStyles(td, {
|
|
10382
10392
|
position: colIndex < (opts.rowHeaderSpan ?? 0) ? "sticky" : "relative",
|
|
10383
10393
|
background: rowBg,
|
|
10384
10394
|
fontWeight: cls === "normal" ? String(opts.tokens.font.weight.normal) : String(opts.tokens.font.weight.bold),
|
|
10385
10395
|
color: opts.tokens.color.text,
|
|
10386
|
-
borderBottom: `1px solid ${opts
|
|
10396
|
+
borderBottom: `1px solid ${gridBorderColor(opts)}`,
|
|
10387
10397
|
height: rowHeight ? `${rowHeight}px` : `${metrics.rowHeight}px`,
|
|
10388
10398
|
whiteSpace: column.wrap === true ? "normal" : "nowrap"
|
|
10389
10399
|
});
|
|
10390
10400
|
const indent = opts.cellIndent?.(rowIndex, colIndex) ?? 0;
|
|
10391
10401
|
if (indent > 0) td.style.paddingLeft = `${metrics.paddingX + indent}px`;
|
|
10392
|
-
applyConditionalFormatting(td, opts, column, colIndex, cell, rowBg);
|
|
10402
|
+
applyConditionalFormatting(td, opts, column, colIndex, cell, rowBg, rowIndex);
|
|
10393
10403
|
if (td.childNodes.length === 0) {
|
|
10394
10404
|
td.textContent = formatDisplayValue(cell.value, column);
|
|
10395
10405
|
applyNegativeStyle(td, cell.value, column);
|
|
@@ -10407,7 +10417,7 @@ function buildFooter(opts) {
|
|
|
10407
10417
|
opts.columns.forEach((column, colIndex) => {
|
|
10408
10418
|
const td = document.createElement("td");
|
|
10409
10419
|
const cell = opts.footerRow?.cells[colIndex] ?? { value: null};
|
|
10410
|
-
setCellBaseStyles(td, opts.tokens, column.align, false, metrics.padding);
|
|
10420
|
+
setCellBaseStyles(td, opts.tokens, column.align, false, metrics.padding, gridBorderColor(opts));
|
|
10411
10421
|
setStyles(td, {
|
|
10412
10422
|
position: colIndex < (opts.rowHeaderSpan ?? 0) ? "sticky" : "sticky",
|
|
10413
10423
|
bottom: "0",
|
|
@@ -10415,8 +10425,8 @@ function buildFooter(opts) {
|
|
|
10415
10425
|
background: opts.tokens.color.surface,
|
|
10416
10426
|
color: opts.tokens.color.text,
|
|
10417
10427
|
fontWeight: String(opts.tokens.font.weight.bold),
|
|
10418
|
-
borderTop: `1px solid ${opts
|
|
10419
|
-
borderBottom: `1px solid ${opts
|
|
10428
|
+
borderTop: `1px solid ${gridBorderColor(opts)}`,
|
|
10429
|
+
borderBottom: `1px solid ${gridBorderColor(opts)}`,
|
|
10420
10430
|
height: `${metrics.rowHeight}px`,
|
|
10421
10431
|
whiteSpace: column.wrap === true ? "normal" : "nowrap"
|
|
10422
10432
|
});
|
|
@@ -10442,7 +10452,7 @@ function makeSpacerRow(opts, height) {
|
|
|
10442
10452
|
tr.appendChild(td);
|
|
10443
10453
|
return tr;
|
|
10444
10454
|
}
|
|
10445
|
-
function applyConditionalFormatting(td, opts, column, colIndex, cell, rowBg) {
|
|
10455
|
+
function applyConditionalFormatting(td, opts, column, colIndex, cell, rowBg, rowIndex = 0) {
|
|
10446
10456
|
const cf = column.conditionalFormat;
|
|
10447
10457
|
const raw = cell.raw;
|
|
10448
10458
|
const domain = opts.conditionalDomains?.[colIndex] ?? null;
|
|
@@ -10487,13 +10497,27 @@ function applyConditionalFormatting(td, opts, column, colIndex, cell, rowBg) {
|
|
|
10487
10497
|
}
|
|
10488
10498
|
if (!domain) return;
|
|
10489
10499
|
const ratio = normalized(numeric, domain);
|
|
10490
|
-
const bar = document.createElement("div");
|
|
10491
10500
|
const diverging2 = cf.negativeColor !== void 0 || cf.baseline === "zero";
|
|
10492
10501
|
const positive = numeric >= 0;
|
|
10493
10502
|
const barColor = alphaColor(positive ? cf.color ?? opts.tokens.color.accent : cf.negativeColor ?? opts.tokens.color.negative, 0.85);
|
|
10494
10503
|
const baseline = diverging2 ? normalized(0, domain) : 0;
|
|
10495
10504
|
const left = diverging2 ? Math.min(baseline, normalized(numeric, domain)) : 0;
|
|
10496
10505
|
const width = diverging2 ? Math.abs(normalized(numeric, domain) - baseline) : ratio;
|
|
10506
|
+
const text = document.createElement("span");
|
|
10507
|
+
text.textContent = cf.showValue === false ? "" : formatDisplayValue(cell.value, column);
|
|
10508
|
+
setStyles(text, overlayTextStyles(opts.tokens.color.text));
|
|
10509
|
+
td.style.background = rowBg;
|
|
10510
|
+
if (opts.sketch) {
|
|
10511
|
+
const colWidth = opts.widths?.[colIndex] ?? column.width ?? defaultColumnWidth(column);
|
|
10512
|
+
const rowHeight = densityMetrics(opts.density).rowHeight;
|
|
10513
|
+
const seed = (opts.sketch.seed ^ Math.imul(rowIndex + 1, 374761393) ^ Math.imul(colIndex + 1, 668265263)) >>> 0;
|
|
10514
|
+
const canvas = buildSketchDataBar(opts.sketch, barColor, colWidth, rowHeight, left, width, seed);
|
|
10515
|
+
if (canvas) td.appendChild(canvas);
|
|
10516
|
+
td.appendChild(text);
|
|
10517
|
+
applyNegativeStyle(text, cell.value, column);
|
|
10518
|
+
return;
|
|
10519
|
+
}
|
|
10520
|
+
const bar = document.createElement("div");
|
|
10497
10521
|
setStyles(bar, {
|
|
10498
10522
|
position: "absolute",
|
|
10499
10523
|
left: `calc(${Math.round(left * 1e3) / 10}% + 4px)`,
|
|
@@ -10505,14 +10529,38 @@ function applyConditionalFormatting(td, opts, column, colIndex, cell, rowBg) {
|
|
|
10505
10529
|
opacity: "0.9",
|
|
10506
10530
|
pointerEvents: "none"
|
|
10507
10531
|
});
|
|
10508
|
-
const text = document.createElement("span");
|
|
10509
|
-
text.textContent = cf.showValue === false ? "" : formatDisplayValue(cell.value, column);
|
|
10510
|
-
setStyles(text, overlayTextStyles(opts.tokens.color.text));
|
|
10511
|
-
td.style.background = rowBg;
|
|
10512
10532
|
td.append(bar, text);
|
|
10513
10533
|
applyNegativeStyle(text, cell.value, column);
|
|
10514
10534
|
}
|
|
10515
|
-
function
|
|
10535
|
+
function buildSketchDataBar(sketch, color, colWidth, rowHeight, leftRatio, widthRatio, seed) {
|
|
10536
|
+
const avail = Math.max(0, colWidth - 8);
|
|
10537
|
+
const barW = widthRatio * avail;
|
|
10538
|
+
const barH = Math.max(0, rowHeight - 10);
|
|
10539
|
+
if (barW <= 0.5 || barH <= 0) return null;
|
|
10540
|
+
const pad3 = 3;
|
|
10541
|
+
const leftPx = 4 + leftRatio * avail;
|
|
10542
|
+
const dpr = getDevicePixelRatio();
|
|
10543
|
+
const canvas = document.createElement("canvas");
|
|
10544
|
+
const cssW = barW + pad3 * 2;
|
|
10545
|
+
const cssH = barH + pad3 * 2;
|
|
10546
|
+
canvas.width = Math.max(1, Math.round(cssW * dpr));
|
|
10547
|
+
canvas.height = Math.max(1, Math.round(cssH * dpr));
|
|
10548
|
+
setStyles(canvas, {
|
|
10549
|
+
position: "absolute",
|
|
10550
|
+
left: `${leftPx - pad3}px`,
|
|
10551
|
+
top: `${5 - pad3}px`,
|
|
10552
|
+
width: `${cssW}px`,
|
|
10553
|
+
height: `${cssH}px`,
|
|
10554
|
+
pointerEvents: "none"
|
|
10555
|
+
});
|
|
10556
|
+
const ctx = canvas.getContext("2d");
|
|
10557
|
+
if (!ctx) return null;
|
|
10558
|
+
ctx.scale(dpr, dpr);
|
|
10559
|
+
const pen = new RoughPen(ctx, { ...sketch, seed });
|
|
10560
|
+
pen.rect(pad3, pad3, barW, barH, { stroke: color, fill: color, fillAlpha: 0.9, strokeAlpha: 0.9 });
|
|
10561
|
+
return canvas;
|
|
10562
|
+
}
|
|
10563
|
+
function setCellBaseStyles(cell, tokens, align, sticky, padding = "6px 10px", borderColor = tokens.color.border) {
|
|
10516
10564
|
setStyles(cell, {
|
|
10517
10565
|
boxSizing: "border-box",
|
|
10518
10566
|
padding,
|
|
@@ -10520,11 +10568,14 @@ function setCellBaseStyles(cell, tokens, align, sticky, padding = "6px 10px") {
|
|
|
10520
10568
|
whiteSpace: "nowrap",
|
|
10521
10569
|
overflow: "hidden",
|
|
10522
10570
|
textOverflow: "ellipsis",
|
|
10523
|
-
borderRight: `1px solid ${
|
|
10571
|
+
borderRight: `1px solid ${borderColor}`,
|
|
10524
10572
|
verticalAlign: "middle"
|
|
10525
10573
|
});
|
|
10526
10574
|
if (sticky) cell.style.position = "sticky";
|
|
10527
10575
|
}
|
|
10576
|
+
function gridBorderColor(opts) {
|
|
10577
|
+
return opts.sketch ? "transparent" : opts.tokens.color.border;
|
|
10578
|
+
}
|
|
10528
10579
|
function renderIconValue(td, icon, color, value, position) {
|
|
10529
10580
|
const iconSpan = document.createElement("span");
|
|
10530
10581
|
iconSpan.textContent = icon;
|
|
@@ -10578,7 +10629,7 @@ function normalizedHeaderRows(opts) {
|
|
|
10578
10629
|
}))
|
|
10579
10630
|
];
|
|
10580
10631
|
}
|
|
10581
|
-
function paintHeaderCanvas(opts, widths, rows, metrics) {
|
|
10632
|
+
function paintHeaderCanvas(opts, widths, rows, metrics, pen) {
|
|
10582
10633
|
rows.forEach((row, rowIndex) => {
|
|
10583
10634
|
let cursor = 0;
|
|
10584
10635
|
for (const cell of row) {
|
|
@@ -10589,7 +10640,7 @@ function paintHeaderCanvas(opts, widths, rows, metrics) {
|
|
|
10589
10640
|
const y = opts.rect.y + rowIndex * metrics.headerHeight;
|
|
10590
10641
|
const w = sumWidths(widths.slice(start, start + colSpan));
|
|
10591
10642
|
const h = metrics.headerHeight * rowSpan;
|
|
10592
|
-
paintCellBox(opts.ctx, x, y, w, h, opts.tokens.color.surface, opts.tokens.color.border);
|
|
10643
|
+
paintCellBox(opts.ctx, x, y, w, h, opts.tokens.color.surface, opts.tokens.color.border, false, pen);
|
|
10593
10644
|
paintCellText(opts, {
|
|
10594
10645
|
x,
|
|
10595
10646
|
y,
|
|
@@ -10605,7 +10656,7 @@ function paintHeaderCanvas(opts, widths, rows, metrics) {
|
|
|
10605
10656
|
}
|
|
10606
10657
|
});
|
|
10607
10658
|
}
|
|
10608
|
-
function paintBodyRowCanvas(opts, widths, rowIndex, y, metrics) {
|
|
10659
|
+
function paintBodyRowCanvas(opts, widths, rowIndex, y, metrics, pen) {
|
|
10609
10660
|
const cls = opts.rowClass?.(rowIndex) ?? "normal";
|
|
10610
10661
|
let x = opts.rect.x;
|
|
10611
10662
|
for (let colIndex = 0; colIndex < opts.columns.length; colIndex += 1) {
|
|
@@ -10615,8 +10666,8 @@ function paintBodyRowCanvas(opts, widths, rowIndex, y, metrics) {
|
|
|
10615
10666
|
const baseBg = canvasRowBackground(opts, rowIndex, cls);
|
|
10616
10667
|
const conditional = resolveCanvasConditional(opts, column, colIndex, cell, baseBg);
|
|
10617
10668
|
const bg = conditional.background ?? baseBg;
|
|
10618
|
-
paintCellBox(opts.ctx, x, y, width, metrics.rowHeight, bg, opts.tokens.color.border);
|
|
10619
|
-
if (conditional.bar) paintDataBar(opts, x, y, width, metrics.rowHeight, conditional.bar);
|
|
10669
|
+
paintCellBox(opts.ctx, x, y, width, metrics.rowHeight, bg, opts.tokens.color.border, false, pen);
|
|
10670
|
+
if (conditional.bar) paintDataBar(opts, x, y, width, metrics.rowHeight, conditional.bar, pen);
|
|
10620
10671
|
const indent = opts.cellIndent?.(rowIndex, colIndex) ?? 0;
|
|
10621
10672
|
const text = conditional.showValue === false ? "" : formatDisplayValue(cell.value, column);
|
|
10622
10673
|
const color = negativeTextColor(cell.value, column, conditional.color ?? opts.tokens.color.text);
|
|
@@ -10638,13 +10689,13 @@ function paintBodyRowCanvas(opts, widths, rowIndex, y, metrics) {
|
|
|
10638
10689
|
x += width;
|
|
10639
10690
|
}
|
|
10640
10691
|
}
|
|
10641
|
-
function paintFooterCanvas(opts, widths, y, metrics) {
|
|
10692
|
+
function paintFooterCanvas(opts, widths, y, metrics, pen) {
|
|
10642
10693
|
let x = opts.rect.x;
|
|
10643
10694
|
for (let colIndex = 0; colIndex < opts.columns.length; colIndex += 1) {
|
|
10644
10695
|
const column = opts.columns[colIndex];
|
|
10645
10696
|
const width = widths[colIndex] ?? 0;
|
|
10646
10697
|
const cell = opts.footerRow?.cells[colIndex] ?? { value: null};
|
|
10647
|
-
paintCellBox(opts.ctx, x, y, width, metrics.rowHeight, opts.tokens.color.surface, opts.tokens.color.border, true);
|
|
10698
|
+
paintCellBox(opts.ctx, x, y, width, metrics.rowHeight, opts.tokens.color.surface, opts.tokens.color.border, true, pen);
|
|
10648
10699
|
paintCellText(opts, {
|
|
10649
10700
|
x,
|
|
10650
10701
|
y,
|
|
@@ -10673,10 +10724,25 @@ function paintClippedCueCanvas(opts, y, metrics, remaining) {
|
|
|
10673
10724
|
paddingX: metrics.paddingX
|
|
10674
10725
|
});
|
|
10675
10726
|
}
|
|
10676
|
-
function paintCellBox(ctx, x, y, width, height, background, border, topBorder = false) {
|
|
10727
|
+
function paintCellBox(ctx, x, y, width, height, background, border, topBorder = false, pen) {
|
|
10677
10728
|
ctx.save();
|
|
10678
10729
|
ctx.fillStyle = background;
|
|
10679
10730
|
ctx.fillRect(x, y, width, height);
|
|
10731
|
+
if (pen) {
|
|
10732
|
+
pen.polyline(
|
|
10733
|
+
[
|
|
10734
|
+
{ x: x + width, y },
|
|
10735
|
+
{ x: x + width, y: y + height },
|
|
10736
|
+
{ x, y: y + height }
|
|
10737
|
+
],
|
|
10738
|
+
{ stroke: border, strokeWidth: 1 }
|
|
10739
|
+
);
|
|
10740
|
+
if (topBorder) {
|
|
10741
|
+
pen.polyline([{ x, y }, { x: x + width, y }], { stroke: border, strokeWidth: 1 });
|
|
10742
|
+
}
|
|
10743
|
+
ctx.restore();
|
|
10744
|
+
return;
|
|
10745
|
+
}
|
|
10680
10746
|
ctx.strokeStyle = border;
|
|
10681
10747
|
ctx.lineWidth = 1;
|
|
10682
10748
|
ctx.beginPath();
|
|
@@ -10787,9 +10853,18 @@ function resolveCanvasConditional(opts, column, colIndex, cell, rowBg) {
|
|
|
10787
10853
|
const color = alphaColor(positive ? cf.color ?? opts.tokens.color.accent : cf.negativeColor ?? opts.tokens.color.negative, 0.85);
|
|
10788
10854
|
return { background: rowBg, showValue: cf.showValue !== false, bar: { leftRatio, widthRatio, color } };
|
|
10789
10855
|
}
|
|
10790
|
-
function paintDataBar(opts, x, y, width, height, bar) {
|
|
10856
|
+
function paintDataBar(opts, x, y, width, height, bar, pen) {
|
|
10791
10857
|
const left = x + 4 + bar.leftRatio * Math.max(0, width - 8);
|
|
10792
10858
|
const barW = bar.widthRatio * Math.max(0, width - 8);
|
|
10859
|
+
if (pen) {
|
|
10860
|
+
pen.rect(left, y + 5, barW, Math.max(0, height - 10), {
|
|
10861
|
+
stroke: bar.color,
|
|
10862
|
+
fill: bar.color,
|
|
10863
|
+
fillAlpha: 0.9,
|
|
10864
|
+
strokeAlpha: 0.9
|
|
10865
|
+
});
|
|
10866
|
+
return;
|
|
10867
|
+
}
|
|
10793
10868
|
opts.ctx.save();
|
|
10794
10869
|
opts.ctx.globalAlpha *= 0.9;
|
|
10795
10870
|
opts.ctx.beginPath();
|
|
@@ -10798,6 +10873,72 @@ function paintDataBar(opts, x, y, width, height, bar) {
|
|
|
10798
10873
|
opts.ctx.fill();
|
|
10799
10874
|
opts.ctx.restore();
|
|
10800
10875
|
}
|
|
10876
|
+
function createSketchGridCanvas(rect) {
|
|
10877
|
+
const dpr = getDevicePixelRatio();
|
|
10878
|
+
const w = Math.max(0, rect.width);
|
|
10879
|
+
const h = Math.max(0, rect.height);
|
|
10880
|
+
const canvas = document.createElement("canvas");
|
|
10881
|
+
canvas.width = Math.max(1, Math.round(w * dpr));
|
|
10882
|
+
canvas.height = Math.max(1, Math.round(h * dpr));
|
|
10883
|
+
setStyles(canvas, {
|
|
10884
|
+
position: "absolute",
|
|
10885
|
+
left: `${rect.x}px`,
|
|
10886
|
+
top: `${rect.y}px`,
|
|
10887
|
+
width: `${w}px`,
|
|
10888
|
+
height: `${h}px`,
|
|
10889
|
+
pointerEvents: "none"
|
|
10890
|
+
});
|
|
10891
|
+
return { canvas, ctx: canvas.getContext("2d"), dpr };
|
|
10892
|
+
}
|
|
10893
|
+
function paintSketchGridOverlay(ctx, o) {
|
|
10894
|
+
const w = Math.max(0, o.rect.width);
|
|
10895
|
+
const h = Math.max(0, o.rect.height);
|
|
10896
|
+
ctx.save();
|
|
10897
|
+
ctx.setTransform(o.dpr, 0, 0, o.dpr, 0, 0);
|
|
10898
|
+
ctx.clearRect(0, 0, w, h);
|
|
10899
|
+
const metrics = densityMetrics(o.density);
|
|
10900
|
+
const headerHeight = o.headerRowCount * metrics.headerHeight;
|
|
10901
|
+
const footerHeight = o.hasFooter ? metrics.rowHeight : 0;
|
|
10902
|
+
const bodyTop = headerHeight;
|
|
10903
|
+
const bodyBottom = Math.max(bodyTop, h - footerHeight);
|
|
10904
|
+
const border = o.tokens.color.border;
|
|
10905
|
+
const base = o.sketch.seed >>> 0;
|
|
10906
|
+
const stroke = (x1, y1, x2, y2, seed) => {
|
|
10907
|
+
const pen = new RoughPen(ctx, { ...o.sketch, seed: seed >>> 0 });
|
|
10908
|
+
pen.polyline(
|
|
10909
|
+
[
|
|
10910
|
+
{ x: x1, y: y1 },
|
|
10911
|
+
{ x: x2, y: y2 }
|
|
10912
|
+
],
|
|
10913
|
+
{ stroke: border, strokeWidth: 1 }
|
|
10914
|
+
);
|
|
10915
|
+
};
|
|
10916
|
+
let cursor = 0;
|
|
10917
|
+
for (let i = 0; i < o.columns.length - 1; i += 1) {
|
|
10918
|
+
cursor += o.widths[i] ?? 0;
|
|
10919
|
+
const pinned = i < (o.rowHeaderSpan ?? 0);
|
|
10920
|
+
const x = pinned ? cursor : cursor - o.scrollLeft;
|
|
10921
|
+
if (x <= 0 || x >= w) continue;
|
|
10922
|
+
stroke(x, 0, x, h, base ^ Math.imul(i + 1, 2246822519));
|
|
10923
|
+
}
|
|
10924
|
+
ctx.save();
|
|
10925
|
+
ctx.beginPath();
|
|
10926
|
+
ctx.rect(0, bodyTop, w, Math.max(0, bodyBottom - bodyTop));
|
|
10927
|
+
ctx.clip();
|
|
10928
|
+
const firstRow = Math.max(0, Math.floor(o.scrollTop / metrics.rowHeight) - 1);
|
|
10929
|
+
for (let r = firstRow; r < o.rowCount; r += 1) {
|
|
10930
|
+
const y = bodyTop + (r + 1) * metrics.rowHeight - o.scrollTop;
|
|
10931
|
+
if (y <= bodyTop) continue;
|
|
10932
|
+
if (y >= bodyBottom) break;
|
|
10933
|
+
stroke(0, y, w, y, base ^ Math.imul(r + 1, 3266489917));
|
|
10934
|
+
}
|
|
10935
|
+
ctx.restore();
|
|
10936
|
+
if (headerHeight > 0 && headerHeight < h) stroke(0, headerHeight, w, headerHeight, (base ^ 2654435769) >>> 0);
|
|
10937
|
+
if (footerHeight > 0 && bodyBottom > bodyTop) stroke(0, bodyBottom, w, bodyBottom, (base ^ 2246822507) >>> 0);
|
|
10938
|
+
const framePen = new RoughPen(ctx, { ...o.sketch, seed: base });
|
|
10939
|
+
framePen.rect(1.5, 1.5, Math.max(0, w - 3), Math.max(0, h - 3), { stroke: border, strokeWidth: 1 });
|
|
10940
|
+
ctx.restore();
|
|
10941
|
+
}
|
|
10801
10942
|
function canvasRowBackground(opts, rowIndex, cls) {
|
|
10802
10943
|
if (cls !== "normal") return opts.tokens.color.surface;
|
|
10803
10944
|
if (opts.striped === true && rowIndex % 2 === 1) return subtleStripe(opts.tokens);
|
|
@@ -10900,7 +11041,7 @@ function drawTableCanvas(surface, spec, tokens, size) {
|
|
|
10900
11041
|
headerRows: buildTableHeaderRows(columns),
|
|
10901
11042
|
footerRow: buildTotalsRow(sortedRows, columns, read, spec),
|
|
10902
11043
|
density: spec.density,
|
|
10903
|
-
sketch: resolveSketch(spec)
|
|
11044
|
+
sketch: resolveSketch(spec)
|
|
10904
11045
|
});
|
|
10905
11046
|
}
|
|
10906
11047
|
function renderTable(surface, spec, tokens, size) {
|
|
@@ -10908,7 +11049,7 @@ function renderTable(surface, spec, tokens, size) {
|
|
|
10908
11049
|
const data = spec.data ?? [];
|
|
10909
11050
|
const columns = resolveColumns(data, spec);
|
|
10910
11051
|
const read = columns.map((column) => accessor(column.key));
|
|
10911
|
-
const sketch = resolveSketch(spec)
|
|
11052
|
+
const sketch = resolveSketch(spec);
|
|
10912
11053
|
let sortState = initialSortState(spec, columns);
|
|
10913
11054
|
let sortedRows = sortRows(data, columns, read, sortState);
|
|
10914
11055
|
const domains = columns.map(
|
|
@@ -10919,6 +11060,9 @@ function renderTable(surface, spec, tokens, size) {
|
|
|
10919
11060
|
);
|
|
10920
11061
|
const host = document.createElement("div");
|
|
10921
11062
|
surface.overlay.appendChild(host);
|
|
11063
|
+
const headerRowCount = buildTableHeaderRows(columns)?.length ?? 1;
|
|
11064
|
+
const overlay = sketch ? createSketchGridCanvas(rect) : null;
|
|
11065
|
+
if (overlay) surface.overlay.appendChild(overlay.canvas);
|
|
10922
11066
|
let frame = 0;
|
|
10923
11067
|
const renderWindow = () => {
|
|
10924
11068
|
const scrollTop = host.scrollTop || 0;
|
|
@@ -10926,7 +11070,8 @@ function renderTable(surface, spec, tokens, size) {
|
|
|
10926
11070
|
const start = Math.max(0, Math.floor(scrollTop / rowHeight) - BUFFER_ROWS);
|
|
10927
11071
|
const visible = Math.ceil(Math.max(rect.height, host.clientHeight || rect.height) / rowHeight) + BUFFER_ROWS * 2;
|
|
10928
11072
|
const end = Math.min(sortedRows.length, start + visible);
|
|
10929
|
-
|
|
11073
|
+
const footerRow = buildTotalsRow(sortedRows, columns, read, spec);
|
|
11074
|
+
const buildOpts = {
|
|
10930
11075
|
container: host,
|
|
10931
11076
|
tokens,
|
|
10932
11077
|
rect,
|
|
@@ -10947,11 +11092,28 @@ function renderTable(surface, spec, tokens, size) {
|
|
|
10947
11092
|
sortState: sortState ?? void 0,
|
|
10948
11093
|
conditionalDomains: domains,
|
|
10949
11094
|
headerRows: buildTableHeaderRows(columns),
|
|
10950
|
-
footerRow
|
|
11095
|
+
footerRow,
|
|
10951
11096
|
density: spec.density,
|
|
10952
11097
|
visibleRange: { start, end, rowHeight },
|
|
10953
11098
|
sketch
|
|
10954
|
-
}
|
|
11099
|
+
};
|
|
11100
|
+
buildTable(buildOpts);
|
|
11101
|
+
if (sketch && overlay?.ctx) {
|
|
11102
|
+
paintSketchGridOverlay(overlay.ctx, {
|
|
11103
|
+
sketch,
|
|
11104
|
+
tokens,
|
|
11105
|
+
rect,
|
|
11106
|
+
dpr: overlay.dpr,
|
|
11107
|
+
columns,
|
|
11108
|
+
widths: buildOpts.widths ?? [],
|
|
11109
|
+
rowCount: sortedRows.length,
|
|
11110
|
+
headerRowCount,
|
|
11111
|
+
hasFooter: Boolean(footerRow),
|
|
11112
|
+
density: spec.density,
|
|
11113
|
+
scrollLeft: host.scrollLeft || 0,
|
|
11114
|
+
scrollTop
|
|
11115
|
+
});
|
|
11116
|
+
}
|
|
10955
11117
|
};
|
|
10956
11118
|
host.addEventListener("scroll", () => {
|
|
10957
11119
|
if (frame !== 0) return;
|
|
@@ -11108,15 +11270,16 @@ function drawMatrixCanvas(surface, spec, tokens, size) {
|
|
|
11108
11270
|
conditionalDomains: prepared.bodyDomains,
|
|
11109
11271
|
headerRows: prepared.headerRows,
|
|
11110
11272
|
density: spec.density,
|
|
11111
|
-
sketch: resolveSketch(spec)
|
|
11273
|
+
sketch: resolveSketch(spec)
|
|
11112
11274
|
});
|
|
11113
11275
|
}
|
|
11114
11276
|
function renderMatrix(surface, spec, tokens, size) {
|
|
11115
11277
|
const rect = drawTitleBlock(surface, tokens, size, spec.title);
|
|
11116
11278
|
const prepared = prepareMatrix(spec);
|
|
11279
|
+
const sketch = resolveSketch(spec);
|
|
11117
11280
|
const host = document.createElement("div");
|
|
11118
11281
|
surface.overlay.appendChild(host);
|
|
11119
|
-
|
|
11282
|
+
const buildOpts = {
|
|
11120
11283
|
container: host,
|
|
11121
11284
|
tokens,
|
|
11122
11285
|
rect,
|
|
@@ -11143,8 +11306,45 @@ function renderMatrix(surface, spec, tokens, size) {
|
|
|
11143
11306
|
conditionalDomains: prepared.bodyDomains,
|
|
11144
11307
|
headerRows: prepared.headerRows,
|
|
11145
11308
|
density: spec.density,
|
|
11146
|
-
sketch
|
|
11147
|
-
}
|
|
11309
|
+
sketch
|
|
11310
|
+
};
|
|
11311
|
+
buildTable(buildOpts);
|
|
11312
|
+
if (sketch) {
|
|
11313
|
+
const overlay = createSketchGridCanvas(rect);
|
|
11314
|
+
if (overlay.ctx) {
|
|
11315
|
+
surface.overlay.appendChild(overlay.canvas);
|
|
11316
|
+
const ctx = overlay.ctx;
|
|
11317
|
+
const draw = () => {
|
|
11318
|
+
paintSketchGridOverlay(ctx, {
|
|
11319
|
+
sketch,
|
|
11320
|
+
tokens,
|
|
11321
|
+
rect,
|
|
11322
|
+
dpr: overlay.dpr,
|
|
11323
|
+
columns: prepared.columns,
|
|
11324
|
+
widths: buildOpts.widths ?? [],
|
|
11325
|
+
rowCount: prepared.rows.length,
|
|
11326
|
+
headerRowCount: prepared.headerRows.length,
|
|
11327
|
+
hasFooter: false,
|
|
11328
|
+
rowHeaderSpan: 1,
|
|
11329
|
+
density: spec.density,
|
|
11330
|
+
scrollLeft: host.scrollLeft || 0,
|
|
11331
|
+
scrollTop: host.scrollTop || 0
|
|
11332
|
+
});
|
|
11333
|
+
};
|
|
11334
|
+
draw();
|
|
11335
|
+
let frame = 0;
|
|
11336
|
+
host.addEventListener("scroll", () => {
|
|
11337
|
+
if (frame !== 0) return;
|
|
11338
|
+
frame = typeof requestAnimationFrame === "function" ? requestAnimationFrame(() => {
|
|
11339
|
+
frame = 0;
|
|
11340
|
+
draw();
|
|
11341
|
+
}) : window.setTimeout(() => {
|
|
11342
|
+
frame = 0;
|
|
11343
|
+
draw();
|
|
11344
|
+
}, 16);
|
|
11345
|
+
});
|
|
11346
|
+
}
|
|
11347
|
+
}
|
|
11148
11348
|
}
|
|
11149
11349
|
function prepareMatrix(spec) {
|
|
11150
11350
|
const data = spec.data ?? [];
|