@canvas-components/pivot-table 0.2.1 → 0.2.3

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,4 +1,4 @@
1
- import { stringifyDataIndex, getValueByDataIndex, clamp, serializeCsvRows, isPointInRect, copyTextSync, copyText } from '@canvas-components/utils';
1
+ import { stringifyDataIndex, getValueByDataIndex, dividePreciseNumber, addPreciseNumbers, clamp, serializeCsvRows, isPointInRect, copyTextSync, copyText, formatCustomNumberPattern, formatNumberValue, formatPercentValue, formatScientificValue, formatChineseNumber, parseChineseNumber, formatDateTimeValue } from '@canvas-components/utils';
2
2
  export { getValueByDataIndex, isSameDataIndex, stringifyDataIndex } from '@canvas-components/utils';
3
3
  import * as XLSX from 'xlsx';
4
4
 
@@ -309,8 +309,6 @@ function indexPivotNodes(root) {
309
309
  visit(root);
310
310
  return nodeMap;
311
311
  }
312
-
313
- // src/domain/aggregation/built-in-aggregators.ts
314
312
  function createBuiltInPivotAggregators() {
315
313
  return {
316
314
  sum: createNumericAggregator("sum"),
@@ -341,14 +339,14 @@ function createNumericAggregator(type) {
341
339
  return;
342
340
  }
343
341
  state.numericCount += 1;
344
- state.sum += numericValue;
342
+ state.sum = addPreciseNumbers(state.sum, numericValue) ?? state.sum;
345
343
  state.min = state.min == null ? numericValue : Math.min(state.min, numericValue);
346
344
  state.max = state.max == null ? numericValue : Math.max(state.max, numericValue);
347
345
  },
348
346
  merge(state, source) {
349
347
  state.count += source.count;
350
348
  state.numericCount += source.numericCount;
351
- state.sum += source.sum;
349
+ state.sum = addPreciseNumbers(state.sum, source.sum) ?? state.sum;
352
350
  state.min = mergeMinimum(state.min, source.min);
353
351
  state.max = mergeMaximum(state.max, source.max);
354
352
  source.distinctValues.forEach((value) => state.distinctValues.add(value));
@@ -356,9 +354,11 @@ function createNumericAggregator(type) {
356
354
  finalize(state) {
357
355
  if (type === "count") return state.count;
358
356
  if (type === "distinctCount") return state.distinctValues.size;
359
- if (type === "sum") return state.sum;
357
+ if (type === "sum") return Number(state.sum);
360
358
  if (type === "avg") {
361
- return state.numericCount === 0 ? null : state.sum / state.numericCount;
359
+ if (state.numericCount === 0) return null;
360
+ const average = dividePreciseNumber(state.sum, state.numericCount);
361
+ return average == null ? null : Number(average);
362
362
  }
363
363
  if (type === "min") return state.min;
364
364
  return state.max;
@@ -369,7 +369,7 @@ function createAccumulator() {
369
369
  return {
370
370
  count: 0,
371
371
  numericCount: 0,
372
- sum: 0,
372
+ sum: "0",
373
373
  min: null,
374
374
  max: null,
375
375
  distinctValues: /* @__PURE__ */ new Set()
@@ -411,6 +411,101 @@ function resolvePivotIndicatorAggregator(indicator, registry) {
411
411
  }
412
412
  return aggregator;
413
413
  }
414
+ var DATE_PATTERNS = {
415
+ dateSlash: "YYYY/MM/DD",
416
+ dateDash: "YYYY-MM-DD",
417
+ dateFullCN: "YYYY\u5E74M\u6708D\u65E5",
418
+ time: "HH:mm:ss",
419
+ timeShort: "HH:mm",
420
+ datetime: "YYYY/MM/DD HH:mm:ss",
421
+ datetime12: "YYYY/MM/DD Ah:mm"
422
+ };
423
+ function formatPivotIndicatorValue(value, dataFormat) {
424
+ if (typeof dataFormat === "object") {
425
+ if (dataFormat.type === "custom" && dataFormat.pattern) {
426
+ return formatCustomNumberPattern(value, dataFormat.pattern);
427
+ }
428
+ return formatPivotIndicatorValueWithOptions(value, dataFormat);
429
+ }
430
+ if (dataFormat === "default" || dataFormat === "text") {
431
+ return String(value ?? "");
432
+ }
433
+ if (dataFormat === "number") {
434
+ return formatNumberValue(value, {
435
+ decimalPlaces: "auto",
436
+ thousandsSeparator: false
437
+ });
438
+ }
439
+ if (dataFormat === "thousands") {
440
+ return formatNumberValue(value, {
441
+ decimalPlaces: "auto",
442
+ thousandsSeparator: true
443
+ });
444
+ }
445
+ if (dataFormat === "decimal") {
446
+ return formatNumberValue(value, {
447
+ decimalPlaces: 2,
448
+ thousandsSeparator: true
449
+ });
450
+ }
451
+ if (dataFormat === "percent" || dataFormat === "percentDecimal") {
452
+ return formatPercentValue(value, dataFormat === "percentDecimal" ? 2 : 0);
453
+ }
454
+ if (dataFormat === "scientific") return formatScientificValue(value);
455
+ if (dataFormat === "numberToChineseUpper") {
456
+ return formatChineseNumber(value, "financial") ?? String(value ?? "");
457
+ }
458
+ if (dataFormat === "chineseUpperToNumber") {
459
+ const parsed = parseChineseNumber(value);
460
+ return parsed == null ? String(value ?? "") : String(parsed);
461
+ }
462
+ if (dataFormat === "cny" || dataFormat === "cnyDecimal") {
463
+ return formatNumberValue(value, {
464
+ decimalPlaces: dataFormat === "cnyDecimal" ? 2 : 0,
465
+ thousandsSeparator: true,
466
+ symbol: "\xA5"
467
+ });
468
+ }
469
+ if (dataFormat === "usd" || dataFormat === "usdDecimal") {
470
+ return formatNumberValue(value, {
471
+ decimalPlaces: dataFormat === "usdDecimal" ? 2 : 0,
472
+ thousandsSeparator: true,
473
+ symbol: "$"
474
+ });
475
+ }
476
+ const pattern = DATE_PATTERNS[dataFormat];
477
+ return pattern ? formatDateTimeValue(value, pattern) ?? String(value ?? "") : String(value ?? "");
478
+ }
479
+ function formatPivotIndicatorValueWithOptions(value, dataFormat) {
480
+ if (dataFormat.pattern && dataFormat.type !== "custom") {
481
+ const formatted = formatDateTimeValue(value, dataFormat.pattern);
482
+ if (formatted != null) return formatted;
483
+ }
484
+ const decimalPlaces = Math.max(
485
+ 0,
486
+ Math.min(20, dataFormat.decimalPlaces ?? 2)
487
+ );
488
+ if (dataFormat.type === "percent" || dataFormat.type === "percentDecimal") {
489
+ return formatPercentValue(value, decimalPlaces);
490
+ }
491
+ if (dataFormat.type === "scientific") {
492
+ return formatScientificValue(value, decimalPlaces);
493
+ }
494
+ if (dataFormat.type === "cny" || dataFormat.type === "cnyDecimal" || dataFormat.type === "usd" || dataFormat.type === "usdDecimal") {
495
+ return formatNumberValue(value, {
496
+ decimalPlaces,
497
+ thousandsSeparator: dataFormat.useGrouping ?? true,
498
+ symbol: dataFormat.symbol ?? (dataFormat.type.startsWith("usd") ? "$" : "\xA5")
499
+ });
500
+ }
501
+ if (dataFormat.type === "number" || dataFormat.type === "thousands" || dataFormat.type === "decimal") {
502
+ return formatNumberValue(value, {
503
+ decimalPlaces,
504
+ thousandsSeparator: dataFormat.useGrouping ?? dataFormat.type !== "number"
505
+ });
506
+ }
507
+ return formatPivotIndicatorValue(value, dataFormat.type);
508
+ }
414
509
 
415
510
  // src/domain/aggregation/aggregate-records.ts
416
511
  function aggregatePivotRecords(params) {
@@ -475,7 +570,7 @@ function aggregatePivotRecords(params) {
475
570
  recordCount: item.recordIndexes.length,
476
571
  rowPathKey: item.rowPathKey,
477
572
  columnPathKey: item.columnPathKey
478
- }) ?? formatAggregateValue(value, item.indicator.precision),
573
+ }) ?? (item.indicator.dataFormat ? formatPivotIndicatorValue(value, item.indicator.dataFormat) : formatAggregateValue(value, item.indicator.precision)),
479
574
  recordCount: item.recordIndexes.length,
480
575
  recordIndexes: item.recordIndexes
481
576
  });
@@ -1025,7 +1120,6 @@ function resolveThumbOffset(scroll, maxScroll, track, thumb) {
1025
1120
  // src/domain/layout/pivot-layout.ts
1026
1121
  var DEFAULT_ROW_HEIGHT = 40;
1027
1122
  var DEFAULT_COLUMN_WIDTH = 120;
1028
- var DEFAULT_HEADER_SIZE = 40;
1029
1123
  var DEFAULT_ROW_DIMENSION_WIDTH2 = 140;
1030
1124
  var SCROLLBAR_THICKNESS2 = 10;
1031
1125
  function buildPivotLayoutSnapshot(params) {
@@ -1057,7 +1151,7 @@ function buildPivotLayoutSnapshot(params) {
1057
1151
  options.columns.length + (indicatorLayout === "columns" && hasIndicators ? 1 : 0),
1058
1152
  1
1059
1153
  );
1060
- const columnHeaderHeight = columnHeaderLevels * DEFAULT_HEADER_SIZE;
1154
+ const columnHeaderHeight = columnHeaderLevels * rowHeight;
1061
1155
  const reportFilterHeight = (options.filterDimensions?.length ?? 0) * rowHeight;
1062
1156
  const tableHeaderHeight = reportFilterHeight + columnHeaderHeight;
1063
1157
  const rawBodyWidth = Math.max(width - rowHeaderWidth, 0);
@@ -1191,6 +1285,7 @@ function buildPivotLayoutSnapshot(params) {
1191
1285
  rowHeaderWidth,
1192
1286
  scrollLeft: scroll.left,
1193
1287
  levels: columnHeaderLevels,
1288
+ headerSize: rowHeight,
1194
1289
  headerTop: reportFilterHeight,
1195
1290
  expandedNodeIds: params.expandedColumnNodeIds
1196
1291
  });
@@ -1591,7 +1686,7 @@ function buildColumnHeaderCells(params) {
1591
1686
  x,
1592
1687
  y: params.headerTop,
1593
1688
  width: columnWidth,
1594
- height: DEFAULT_HEADER_SIZE * (params.levels - (slot.indicatorKey ? 1 : 0))
1689
+ height: params.headerSize * (params.levels - (slot.indicatorKey ? 1 : 0))
1595
1690
  }
1596
1691
  });
1597
1692
  } else {
@@ -1631,9 +1726,9 @@ function buildColumnHeaderCells(params) {
1631
1726
  ),
1632
1727
  rect: {
1633
1728
  x,
1634
- y: params.headerTop + level * DEFAULT_HEADER_SIZE,
1729
+ y: params.headerTop + level * params.headerSize,
1635
1730
  width: columnWidth,
1636
- height: DEFAULT_HEADER_SIZE
1731
+ height: params.headerSize
1637
1732
  }
1638
1733
  });
1639
1734
  });
@@ -1660,9 +1755,9 @@ function buildColumnHeaderCells(params) {
1660
1755
  sortDirection: null,
1661
1756
  rect: {
1662
1757
  x,
1663
- y: params.headerTop + (params.levels - 1) * DEFAULT_HEADER_SIZE,
1758
+ y: params.headerTop + (params.levels - 1) * params.headerSize,
1664
1759
  width: columnWidth,
1665
- height: DEFAULT_HEADER_SIZE
1760
+ height: params.headerSize
1666
1761
  }
1667
1762
  });
1668
1763
  }
@@ -2699,6 +2794,15 @@ function resolvePivotSelectionRect(layout, selection) {
2699
2794
  const visibleStartY = Math.max(startY, clipRect.y);
2700
2795
  const visibleEndY = Math.min(endY, clipRect.y + clipRect.height);
2701
2796
  if (visibleStartX >= visibleEndX || visibleStartY >= visibleEndY) return null;
2797
+ const singleCell = kind === "cell" && indexes.startRowIndex === indexes.endRowIndex && indexes.startColumnIndex === indexes.endColumnIndex;
2798
+ if (singleCell) {
2799
+ return {
2800
+ x: startX,
2801
+ y: startY,
2802
+ width: endX - startX,
2803
+ height: endY - startY
2804
+ };
2805
+ }
2702
2806
  return {
2703
2807
  x: visibleStartX,
2704
2808
  y: visibleStartY,
@@ -2748,18 +2852,50 @@ function resolvePivotSelectionKind(selection) {
2748
2852
  }
2749
2853
  return selection?.activeNode?.axis ?? "cell";
2750
2854
  }
2751
- function drawPivotSelectionBorder(context, rect, color) {
2855
+ function drawPivotSelectionBorder(context, rect, color, options) {
2752
2856
  context.save();
2753
2857
  context.strokeStyle = color;
2754
2858
  context.lineWidth = 1;
2755
- context.strokeRect(
2756
- rect.x + 0.5,
2757
- rect.y + 0.5,
2758
- Math.max(rect.width - 1, 0),
2759
- Math.max(rect.height - 1, 0)
2760
- );
2859
+ const left = rect.x + 0.5;
2860
+ const top = rect.y + 0.5;
2861
+ const width = Math.max(rect.width - 1, 0);
2862
+ const height = Math.max(rect.height - 1, 0);
2863
+ const right = left + width;
2864
+ const bottom = top + height;
2865
+ const viewport = options?.viewportRect;
2866
+ const radius = Math.min(options?.radius ?? 8, width / 2, height / 2);
2867
+ const topLeft = viewport && isSameCoordinate(rect.x, viewport.x) && isSameCoordinate(rect.y, viewport.y) ? radius : 0;
2868
+ const topRight = viewport && isSameCoordinate(rect.x + rect.width, viewport.x + viewport.width) && isSameCoordinate(rect.y, viewport.y) ? radius : 0;
2869
+ const bottomRight = viewport && isSameCoordinate(rect.x + rect.width, viewport.x + viewport.width) && isSameCoordinate(rect.y + rect.height, viewport.y + viewport.height) ? radius : 0;
2870
+ const bottomLeft = viewport && isSameCoordinate(rect.x, viewport.x) && isSameCoordinate(rect.y + rect.height, viewport.y + viewport.height) ? radius : 0;
2871
+ if (!topLeft && !topRight && !bottomRight && !bottomLeft) {
2872
+ context.strokeRect(left, top, width, height);
2873
+ context.restore();
2874
+ return;
2875
+ }
2876
+ context.beginPath();
2877
+ context.moveTo(left + topLeft, top);
2878
+ context.lineTo(right - topRight, top);
2879
+ if (topRight) context.arcTo(right, top, right, top + topRight, topRight);
2880
+ else context.lineTo(right, top);
2881
+ context.lineTo(right, bottom - bottomRight);
2882
+ if (bottomRight) {
2883
+ context.arcTo(right, bottom, right - bottomRight, bottom, bottomRight);
2884
+ } else context.lineTo(right, bottom);
2885
+ context.lineTo(left + bottomLeft, bottom);
2886
+ if (bottomLeft) {
2887
+ context.arcTo(left, bottom, left, bottom - bottomLeft, bottomLeft);
2888
+ } else context.lineTo(left, bottom);
2889
+ context.lineTo(left, top + topLeft);
2890
+ if (topLeft) context.arcTo(left, top, left + topLeft, top, topLeft);
2891
+ else context.lineTo(left, top);
2892
+ context.closePath();
2893
+ context.stroke();
2761
2894
  context.restore();
2762
2895
  }
2896
+ function isSameCoordinate(first, second) {
2897
+ return Math.abs(first - second) < 0.01;
2898
+ }
2763
2899
  function resolveSelectionIndexes(layout, selection) {
2764
2900
  const range = selection?.ranges[0];
2765
2901
  if (range) {
@@ -3056,6 +3192,17 @@ function drawPivotGridRect(context, rect, color, options) {
3056
3192
  context.stroke();
3057
3193
  context.restore();
3058
3194
  }
3195
+ function drawPivotViewportRightBorder(context, rect, color) {
3196
+ const x = rect.x + rect.width - 0.5;
3197
+ context.save();
3198
+ context.strokeStyle = color;
3199
+ context.lineWidth = 1;
3200
+ context.beginPath();
3201
+ context.moveTo(x, rect.y);
3202
+ context.lineTo(x, rect.y + rect.height);
3203
+ context.stroke();
3204
+ context.restore();
3205
+ }
3059
3206
  function clipPivotViewport(context, rect, radius = 8) {
3060
3207
  appendRoundedRectPath(context, rect, radius);
3061
3208
  context.clip();
@@ -3141,6 +3288,12 @@ function renderPivotTable(params) {
3141
3288
  );
3142
3289
  const areaSelection = isPivotAreaSelection(layout, params.selection);
3143
3290
  const viewportWidth = resolvePivotViewportWidth(layout);
3291
+ const tableViewportRect = {
3292
+ x: 0,
3293
+ y: 0,
3294
+ width: layout.tableWidth,
3295
+ height: layout.height
3296
+ };
3144
3297
  context.clearRect(0, 0, layout.width, layout.height);
3145
3298
  context.save();
3146
3299
  clipPivotViewport(context, {
@@ -3181,7 +3334,7 @@ function renderPivotTable(params) {
3181
3334
  (cell) => drawPivotGridRect(context, cell.rect, theme.borderColor, {
3182
3335
  skipTop: true,
3183
3336
  skipLeft: cell.rect.x > 0,
3184
- skipRight: isSameCoordinate(
3337
+ skipRight: isSameCoordinate2(
3185
3338
  cell.rect.x + cell.rect.width,
3186
3339
  layout.rowHeaderRect.x + layout.rowHeaderRect.width
3187
3340
  )
@@ -3202,13 +3355,21 @@ function renderPivotTable(params) {
3202
3355
  );
3203
3356
  layout.columnHeaderCells.forEach(
3204
3357
  (cell) => drawPivotGridRect(context, cell.rect, theme.borderColor, {
3205
- skipTop: cell.rect.y > 0,
3206
- skipLeft: true,
3207
- skipRight: isSameCoordinate(
3358
+ skipTop: hasColumnHeaderCellAbove(
3359
+ layout.columnHeaderCells,
3360
+ cell,
3361
+ layout.columnHeaderRect.y
3362
+ ),
3363
+ skipLeft: hasColumnHeaderCellLeft(
3364
+ layout.columnHeaderCells,
3365
+ cell,
3366
+ layout.columnHeaderRect.x
3367
+ ),
3368
+ skipRight: isSameCoordinate2(
3208
3369
  cell.rect.x + cell.rect.width,
3209
3370
  layout.tableWidth
3210
3371
  ),
3211
- skipBottom: isSameCoordinate(
3372
+ skipBottom: isSameCoordinate2(
3212
3373
  cell.rect.y + cell.rect.height,
3213
3374
  layout.columnHeaderRect.y + layout.columnHeaderRect.height
3214
3375
  )
@@ -3240,7 +3401,7 @@ function renderPivotTable(params) {
3240
3401
  (cell) => drawPivotGridRect(context, cell.rect, theme.borderColor, {
3241
3402
  skipTop: true,
3242
3403
  skipLeft: true,
3243
- skipRight: isSameCoordinate(
3404
+ skipRight: isSameCoordinate2(
3244
3405
  cell.rect.x + cell.rect.width,
3245
3406
  layout.tableWidth
3246
3407
  )
@@ -3269,34 +3430,72 @@ function renderPivotTable(params) {
3269
3430
  headerBackgroundColor: theme.columnHeaderBackgroundColor,
3270
3431
  bodyBackgroundColor: theme.backgroundColor
3271
3432
  });
3433
+ if (params.resizeGuideX != null) {
3434
+ drawPivotResizeGuide(context, params.resizeGuideX, contentHeight);
3435
+ }
3436
+ context.restore();
3437
+ if (!layout.scrollbar.vertical) {
3438
+ context.save();
3439
+ clipPivotViewport(context, tableViewportRect);
3440
+ drawPivotViewportRightBorder(context, tableViewportRect, theme.borderColor);
3441
+ context.restore();
3442
+ }
3443
+ drawPivotViewportBorder(
3444
+ context,
3445
+ { x: 0, y: 0, width: viewportWidth, height: contentHeight },
3446
+ theme.borderColor
3447
+ );
3272
3448
  const selectionRect = resolvePivotSelectionRect(layout, params.selection);
3273
3449
  if (selectionRect) {
3274
3450
  const selectionClipRect = resolvePivotSelectionClipRect(
3275
3451
  layout,
3276
3452
  params.selection
3277
3453
  );
3454
+ context.save();
3455
+ clipPivotViewport(context, tableViewportRect);
3278
3456
  withClip(context, selectionClipRect, () => {
3279
3457
  drawPivotSelectionBorder(
3280
3458
  context,
3281
3459
  selectionRect,
3282
- theme.selectionBorderColor
3460
+ theme.selectionBorderColor,
3461
+ { viewportRect: tableViewportRect }
3283
3462
  );
3284
3463
  });
3464
+ context.restore();
3285
3465
  }
3286
- if (params.resizeGuideX != null) {
3287
- drawPivotResizeGuide(context, params.resizeGuideX, contentHeight);
3288
- }
3289
- context.restore();
3290
- drawPivotViewportBorder(
3291
- context,
3292
- { x: 0, y: 0, width: viewportWidth, height: contentHeight },
3293
- theme.borderColor
3294
- );
3295
3466
  return {
3296
3467
  headerCellCount: layout.reportFilterCells.length + layout.rowFieldHeaderCells.length + layout.rowHeaderCells.length + layout.columnHeaderCells.length,
3297
3468
  bodyCellCount: layout.bodyCells.length
3298
3469
  };
3299
3470
  }
3471
+ function hasColumnHeaderCellAbove(cells, cell, headerTop) {
3472
+ if (isSameCoordinate2(cell.rect.y, headerTop)) return headerTop > 0;
3473
+ const left = cell.rect.x;
3474
+ const right = left + cell.rect.width;
3475
+ return cells.some((candidate) => {
3476
+ if (candidate === cell) return false;
3477
+ const candidateBottom = candidate.rect.y + candidate.rect.height;
3478
+ if (!isSameCoordinate2(candidateBottom, cell.rect.y)) return false;
3479
+ const candidateLeft = candidate.rect.x;
3480
+ const candidateRight = candidateLeft + candidate.rect.width;
3481
+ return candidateLeft < right && candidateRight > left;
3482
+ });
3483
+ }
3484
+ function hasColumnHeaderCellLeft(cells, cell, headerLeft) {
3485
+ if (cell.rect.x <= headerLeft + 0.01) {
3486
+ return true;
3487
+ }
3488
+ const top = cell.rect.y;
3489
+ const bottom = top + cell.rect.height;
3490
+ return cells.some((candidate) => {
3491
+ if (candidate === cell) return false;
3492
+ const candidateRight = candidate.rect.x + candidate.rect.width;
3493
+ if (!isSameCoordinate2(candidateRight, cell.rect.x)) return false;
3494
+ const candidateTop = candidate.rect.y;
3495
+ const candidateBottom = candidateTop + candidate.rect.height;
3496
+ return candidateTop < bottom && candidateBottom > top;
3497
+ });
3498
+ }
3300
3499
  function resolvePivotViewportWidth(layout) {
3301
3500
  const horizontalRight = layout.scrollbar.horizontal ? layout.scrollbar.horizontal.increaseButton.x + layout.scrollbar.horizontal.increaseButton.width : 0;
3302
3501
  const verticalRight = layout.scrollbar.vertical ? layout.scrollbar.vertical.decreaseButton.x + layout.scrollbar.vertical.decreaseButton.width : 0;
@@ -3336,7 +3535,7 @@ function drawDebugOverlay(context, layout, theme) {
3336
3535
  layout.bodyRect
3337
3536
  ].forEach((rect) => strokeRect(context, rect, "#f04438"));
3338
3537
  context.setLineDash([]);
3339
- context.font = `12px ${theme.fontFamily}`;
3538
+ context.font = `${theme.fontSize}px ${theme.fontFamily}`;
3340
3539
  context.textAlign = "left";
3341
3540
  context.textBaseline = "top";
3342
3541
  context.fillStyle = "#f04438";
@@ -3595,11 +3794,11 @@ function resolveSlotPathKey(slots, nodeId, indicatorKey) {
3595
3794
  (slot) => (slot.nodeId ?? "") === nodeId && (!slot.indicatorKey || slot.indicatorKey === indicatorKey)
3596
3795
  )?.pathKey ?? null;
3597
3796
  }
3598
- function isSameCoordinate(first, second) {
3797
+ function isSameCoordinate2(first, second) {
3599
3798
  return Math.abs(first - second) < 0.01;
3600
3799
  }
3601
3800
  function resolveBodyDisplayText(cell, indicator) {
3602
- if (!indicator || indicator.formatter || typeof cell.value !== "number") {
3801
+ if (!indicator || indicator.formatter || indicator.dataFormat || typeof cell.value !== "number") {
3603
3802
  return cell.formattedValue;
3604
3803
  }
3605
3804
  if (indicator.cellType === "percent") {
@@ -3736,10 +3935,18 @@ function drawSortIcon(context, rect, direction, rightPadding) {
3736
3935
  function drawText(context, text, rect, color, padding, align) {
3737
3936
  const availableWidth = Math.max(rect.width - padding * 2, 0);
3738
3937
  const value = truncateText(context, text, availableWidth);
3938
+ context.textBaseline = "alphabetic";
3939
+ const metrics = context.measureText(value);
3940
+ const ascent = metrics.actualBoundingBoxAscent ?? 0;
3941
+ const descent = metrics.actualBoundingBoxDescent ?? 0;
3942
+ const hasGlyphBounds = ascent > 0 || descent > 0;
3943
+ const centerY = rect.y + rect.height / 2;
3739
3944
  context.fillStyle = color;
3740
3945
  context.textAlign = align;
3946
+ context.textBaseline = hasGlyphBounds ? "alphabetic" : "middle";
3741
3947
  const x = align === "right" ? rect.x + rect.width - padding : align === "center" ? rect.x + rect.width / 2 : rect.x + padding;
3742
- context.fillText(value, x, rect.y + rect.height / 2, availableWidth);
3948
+ const y = hasGlyphBounds ? centerY + (ascent - descent) / 2 : centerY;
3949
+ context.fillText(value, x, y, availableWidth);
3743
3950
  }
3744
3951
  function truncateText(context, text, maxWidth) {
3745
3952
  if (context.measureText(text).width <= maxWidth) return text;
@@ -3787,7 +3994,7 @@ function hitTestPivotLayout(layout, x, y) {
3787
3994
  onSortIcon: false
3788
3995
  };
3789
3996
  }
3790
- const bodyCell = findLastContaining(layout.bodyCells, x, y);
3997
+ const bodyCell = contains(layout.bodyRect, x, y) ? findLastContaining(layout.bodyCells, x, y) : void 0;
3791
3998
  if (bodyCell) {
3792
3999
  return {
3793
4000
  region: "body",
@@ -3797,7 +4004,7 @@ function hitTestPivotLayout(layout, x, y) {
3797
4004
  onSortIcon: false
3798
4005
  };
3799
4006
  }
3800
- const rowHeaderCell = findLastContaining(layout.rowHeaderCells, x, y);
4007
+ const rowHeaderCell = contains(layout.rowHeaderRect, x, y) ? findLastContaining(layout.rowHeaderCells, x, y) : void 0;
3801
4008
  if (rowHeaderCell) {
3802
4009
  return {
3803
4010
  region: "rowHeader",
@@ -3807,9 +4014,7 @@ function hitTestPivotLayout(layout, x, y) {
3807
4014
  onSortIcon: isSortIconHit(rowHeaderCell, x)
3808
4015
  };
3809
4016
  }
3810
- const columnHeaderCell = layout.columnHeaderCells.find(
3811
- (cell) => contains(cell.rect, x, y)
3812
- );
4017
+ const columnHeaderCell = contains(layout.columnHeaderRect, x, y) ? layout.columnHeaderCells.find((cell) => contains(cell.rect, x, y)) : void 0;
3813
4018
  if (columnHeaderCell) {
3814
4019
  return {
3815
4020
  region: "columnHeader",
@@ -4325,7 +4530,7 @@ var PivotTable = class {
4325
4530
  }
4326
4531
  if (hit.reportFilterCell) return;
4327
4532
  if (hit.bodyCell) {
4328
- this.selectCell(toCellAddress(hit.bodyCell), event.shiftKey);
4533
+ this.selectPointerCell(toCellAddress(hit.bodyCell), event.shiftKey);
4329
4534
  return;
4330
4535
  }
4331
4536
  const header = hit.headerCell;
@@ -4427,7 +4632,76 @@ var PivotTable = class {
4427
4632
  });
4428
4633
  __publicField(this, "handleContextMenu", (event) => {
4429
4634
  const hit = this.resolveHit(event);
4430
- if (!hit?.bodyCell || !this.core || !this.layout) return;
4635
+ if (!hit || !this.core || !this.layout) return;
4636
+ if (hit.reportFilterCell) {
4637
+ const cell = hit.reportFilterCell;
4638
+ event.preventDefault();
4639
+ this.options.ui?.onContextMenuRequest?.({
4640
+ x: event.clientX,
4641
+ y: event.clientY,
4642
+ target: "header",
4643
+ title: cell.label,
4644
+ axis: "filter",
4645
+ onCopy: () => this.copyPivotText(`${cell.label} ${cell.valueLabel}`),
4646
+ onOpenFilter: () => this.openReportFilterPanel(cell),
4647
+ ...this.createContextMenuSettings(),
4648
+ onExportCsv: () => downloadBlob(
4649
+ new Blob([this.exportCsv()], { type: "text/csv;charset=utf-8" }),
4650
+ "pivot-table.csv"
4651
+ ),
4652
+ onExportXlsx: () => downloadBlob(
4653
+ new Blob([toArrayBuffer(this.exportXlsx())], {
4654
+ type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
4655
+ }),
4656
+ "pivot-table.xlsx"
4657
+ ),
4658
+ onClose: () => this.options.ui?.onContextMenuRequest?.(null)
4659
+ });
4660
+ return;
4661
+ }
4662
+ if (hit.headerCell) {
4663
+ const header = hit.headerCell;
4664
+ const model2 = this.core.getPivotModel();
4665
+ const node = header.nodeId ? (header.axis === "row" ? model2?.rowNodes : model2?.columnNodes)?.get(
4666
+ header.nodeId
4667
+ ) : void 0;
4668
+ const dimensionKey = header.dimensionKey ?? node?.dimensionKey;
4669
+ event.preventDefault();
4670
+ this.options.ui?.onContextMenuRequest?.({
4671
+ x: event.clientX,
4672
+ y: event.clientY,
4673
+ target: "header",
4674
+ title: header.label,
4675
+ axis: header.axis,
4676
+ nodeKind: node?.kind ?? header.kind,
4677
+ indicatorKey: header.indicatorKey ?? void 0,
4678
+ onCopy: () => this.copyPivotText(header.label),
4679
+ sortDirection: header.sortDirection,
4680
+ onSortAsc: header.sortable && dimensionKey ? () => this.setDimensionSort(header.axis, dimensionKey, "asc") : void 0,
4681
+ onSortDesc: header.sortable && dimensionKey ? () => this.setDimensionSort(header.axis, dimensionKey, "desc") : void 0,
4682
+ onClearSort: header.sortable && dimensionKey ? () => this.setDimensionSort(header.axis, dimensionKey, null) : void 0,
4683
+ onOpenFilter: header.filterable ? () => this.openFilterPanel(hit) : void 0,
4684
+ expanded: header.expandable ? header.expanded : void 0,
4685
+ onExpand: header.expandable && header.nodeId ? () => header.axis === "row" ? this.expandRowNode(header.nodeId) : this.expandColumnNode(header.nodeId) : void 0,
4686
+ onCollapse: header.expandable && header.nodeId ? () => header.axis === "row" ? this.collapseRowNode(header.nodeId) : this.collapseColumnNode(header.nodeId) : void 0,
4687
+ onExpandAll: () => this.expandAll(header.axis),
4688
+ onCollapseAll: () => this.collapseAll(header.axis),
4689
+ ...this.createContextMenuSettings(header.indicatorKey ?? void 0),
4690
+ onExportCsv: () => downloadBlob(
4691
+ new Blob([this.exportCsv()], { type: "text/csv;charset=utf-8" }),
4692
+ "pivot-table.csv"
4693
+ ),
4694
+ onExportXlsx: () => downloadBlob(
4695
+ new Blob([toArrayBuffer(this.exportXlsx())], {
4696
+ type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
4697
+ }),
4698
+ "pivot-table.xlsx"
4699
+ ),
4700
+ onClose: () => this.options.ui?.onContextMenuRequest?.(null)
4701
+ });
4702
+ return;
4703
+ }
4704
+ if (!hit.bodyCell) return;
4431
4705
  event.preventDefault();
4432
4706
  const address = toCellAddress(hit.bodyCell);
4433
4707
  const currentRange = resolvePivotSelectionRange(
@@ -4437,7 +4711,7 @@ var PivotTable = class {
4437
4711
  const insideCurrentRange = Boolean(
4438
4712
  currentRange && hit.bodyCell.rowIndex >= currentRange.startRowIndex && hit.bodyCell.rowIndex <= currentRange.endRowIndex && hit.bodyCell.columnIndex >= currentRange.startColumnIndex && hit.bodyCell.columnIndex <= currentRange.endColumnIndex
4439
4713
  );
4440
- if (!insideCurrentRange) this.selectCell(address);
4714
+ if (!insideCurrentRange) this.selectPointerCell(address);
4441
4715
  const selectionRange = resolvePivotSelectionRange(
4442
4716
  this.layout,
4443
4717
  this.core.getSelection()
@@ -4447,15 +4721,28 @@ var PivotTable = class {
4447
4721
  columnPathKey: hit.bodyCell.columnPathKey,
4448
4722
  indicatorKey: hit.bodyCell.indicatorKey
4449
4723
  });
4724
+ const model = this.core.getPivotModel();
4725
+ const rowNode = hit.bodyCell.rowNodeId ? model?.rowNodes.get(hit.bodyCell.rowNodeId) : void 0;
4726
+ const summary = rowNode?.kind === "subtotal" || rowNode?.kind === "grandTotal";
4727
+ const indicator = this.options.indicators.find(
4728
+ (item) => item.key === hit.bodyCell?.indicatorKey
4729
+ );
4730
+ const summaryAggregator = typeof indicator?.aggregator === "string" && isBuiltInPivotAggregator(indicator.aggregator) ? indicator.aggregator : "sum";
4450
4731
  this.options.ui?.onContextMenuRequest?.({
4451
4732
  x: event.clientX,
4452
4733
  y: event.clientY,
4734
+ target: summary ? "summary" : "body",
4735
+ title: summary ? rowNode.label : void 0,
4736
+ nodeKind: rowNode?.kind,
4737
+ indicatorKey: hit.bodyCell.indicatorKey,
4453
4738
  recordCount: records.length,
4739
+ summaryAggregator: summary ? summaryAggregator : void 0,
4740
+ summaryPrecision: summary ? indicator?.precision : void 0,
4454
4741
  onCopy: () => {
4455
- const model = this.core?.getPivotModel();
4456
- const text = model ? createPivotRangeSelectionText({
4742
+ const model2 = this.core?.getPivotModel();
4743
+ const text = model2 ? createPivotRangeSelectionText({
4457
4744
  layout: this.layout,
4458
- model,
4745
+ model: model2,
4459
4746
  startRowIndex: hit.bodyCell.rowIndex,
4460
4747
  endRowIndex: hit.bodyCell.rowIndex,
4461
4748
  startColumnIndex: hit.bodyCell.columnIndex,
@@ -4480,11 +4767,11 @@ var PivotTable = class {
4480
4767
  columnCount: this.layout.columnSlots.length
4481
4768
  },
4482
4769
  onCopyCustomSelection: (range) => {
4483
- const model = this.core?.getPivotModel();
4484
- if (!model || !this.layout) return;
4770
+ const model2 = this.core?.getPivotModel();
4771
+ if (!model2 || !this.layout) return;
4485
4772
  const text = createPivotRangeSelectionText({
4486
4773
  layout: this.layout,
4487
- model,
4774
+ model: model2,
4488
4775
  startRowIndex: range.startRow - 1,
4489
4776
  endRowIndex: range.endRow - 1,
4490
4777
  startColumnIndex: range.startColumn - 1,
@@ -4494,6 +4781,7 @@ var PivotTable = class {
4494
4781
  this.copyPivotText(text);
4495
4782
  }
4496
4783
  },
4784
+ ...this.createContextMenuSettings(hit.bodyCell.indicatorKey),
4497
4785
  onExportCsv: () => downloadBlob(
4498
4786
  new Blob([this.exportCsv()], { type: "text/csv;charset=utf-8" }),
4499
4787
  "pivot-table.csv"
@@ -4509,9 +4797,9 @@ var PivotTable = class {
4509
4797
  });
4510
4798
  __publicField(this, "handlePointerDown", (event) => {
4511
4799
  if (!this.layout || !this.host) return;
4512
- this.stopWheelScrollSmoothing();
4513
4800
  const scrollbarHit = this.resolveScrollbarHit(event);
4514
4801
  if (scrollbarHit && event.button === 0) {
4802
+ this.stopWheelScrollSmoothing();
4515
4803
  this.beginScrollbarInteraction(event, scrollbarHit);
4516
4804
  return;
4517
4805
  }
@@ -4522,7 +4810,7 @@ var PivotTable = class {
4522
4810
  if (cellHit?.bodyCell) {
4523
4811
  const address = toCellAddress(cellHit.bodyCell);
4524
4812
  this.host.root.focus({ preventScroll: true });
4525
- const selection = this.selectCell(address, event.shiftKey);
4813
+ const selection = this.selectPointerCell(address, event.shiftKey);
4526
4814
  const text = this.resolveBodyText(cellHit.bodyCell);
4527
4815
  const textOriginX = this.resolveBodyTextOriginX(cellHit.bodyCell, text);
4528
4816
  const anchorOffset = text ? resolvePivotTextOffset({
@@ -4608,8 +4896,12 @@ var PivotTable = class {
4608
4896
  if (selection) this.setSelection(selection);
4609
4897
  this.host.root.setPointerCapture(event.pointerId);
4610
4898
  }
4899
+ if (cellHit?.headerCell || cellHit?.reportFilterCell) {
4900
+ event.preventDefault();
4901
+ }
4611
4902
  return;
4612
4903
  }
4904
+ this.stopWheelScrollSmoothing();
4613
4905
  event.preventDefault();
4614
4906
  const startWidth = hit.kind === "rowDimension" ? this.layout.rowDimensionWidths[hit.index] ?? 140 : this.layout.columnWidths[hit.index] ?? this.layout.columnWidth;
4615
4907
  this.resizeSession = {
@@ -4799,9 +5091,16 @@ var PivotTable = class {
4799
5091
  }
4800
5092
  /** 选中指定值单元格。 */
4801
5093
  selectCell(address, extend = false) {
5094
+ return this.commitCellSelection(address, extend, true);
5095
+ }
5096
+ /** 鼠标命中的单元格已在视口内,选中时不再校正滚动位置。 */
5097
+ selectPointerCell(address, extend = false) {
5098
+ return this.commitCellSelection(address, extend, false);
5099
+ }
5100
+ commitCellSelection(address, extend, reveal) {
4802
5101
  const selection = this.core?.selectCell(address, extend) ?? null;
4803
5102
  if (selection) {
4804
- this.scrollToCell(address);
5103
+ if (reveal) this.scrollToCell(address);
4805
5104
  this.scheduleRender();
4806
5105
  }
4807
5106
  return selection;
@@ -4959,6 +5258,27 @@ var PivotTable = class {
4959
5258
  this.advanceWheelScrollSmoothing(nextTime);
4960
5259
  });
4961
5260
  }
5261
+ createContextMenuSettings(indicatorKey) {
5262
+ const indicator = indicatorKey ? this.options.indicators.find((item) => item.key === indicatorKey) : void 0;
5263
+ return {
5264
+ density: resolvePivotTableDensity(this.options.rowHeight),
5265
+ onChangeDensity: (density) => {
5266
+ this.updateOptions({
5267
+ ...this.options,
5268
+ rowHeight: resolvePivotTableDensityRowHeight(density)
5269
+ });
5270
+ },
5271
+ dataFormat: indicator?.dataFormat ?? "default",
5272
+ onChangeDataFormat: indicator ? (dataFormat) => {
5273
+ this.updateOptions({
5274
+ ...this.options,
5275
+ indicators: this.options.indicators.map(
5276
+ (item) => item.key === indicator.key ? { ...item, dataFormat } : item
5277
+ )
5278
+ });
5279
+ } : void 0
5280
+ };
5281
+ }
4962
5282
  updateTooltip(hit, event) {
4963
5283
  if (!this.host) return;
4964
5284
  const cell = hit?.bodyCell ?? hit?.headerCell;
@@ -5164,7 +5484,7 @@ var PivotTable = class {
5164
5484
  const indicator = this.options.indicators.find(
5165
5485
  (item) => item.key === cell.indicatorKey
5166
5486
  );
5167
- if (!indicator || indicator.formatter || typeof cell.value !== "number")
5487
+ if (!indicator || indicator.formatter || indicator.dataFormat || typeof cell.value !== "number")
5168
5488
  return cell.formattedValue;
5169
5489
  if (indicator.cellType === "percent")
5170
5490
  return `${(cell.value * 100).toFixed(indicator.precision ?? 2)}%`;
@@ -5202,7 +5522,7 @@ var PivotTable = class {
5202
5522
  measurePivotText(text) {
5203
5523
  const context = this.host?.canvas.getContext("2d");
5204
5524
  if (!context) return text.length * 8;
5205
- context.font = `${this.options.theme?.fontSize ?? 13}px ${this.options.theme?.fontFamily ?? "sans-serif"}`;
5525
+ context.font = `${this.options.theme?.fontSize ?? 14}px ${this.options.theme?.fontFamily ?? "sans-serif"}`;
5206
5526
  return context.measureText(text).width;
5207
5527
  }
5208
5528
  updateRowHeaderSelectionDrag(event) {
@@ -5526,6 +5846,9 @@ function toCellAddress(cell) {
5526
5846
  indicatorKey: cell.indicatorKey
5527
5847
  };
5528
5848
  }
5849
+ function isBuiltInPivotAggregator(value) {
5850
+ return ["sum", "avg", "count", "distinctCount", "min", "max"].includes(value);
5851
+ }
5529
5852
  function isSameAddress(left, right) {
5530
5853
  return Boolean(
5531
5854
  left === right || left && right && left.rowNodeId === right.rowNodeId && left.columnNodeId === right.columnNodeId && left.indicatorKey === right.indicatorKey
@@ -5538,6 +5861,20 @@ function resolveNavigationDirection(key) {
5538
5861
  if (key === "ArrowRight") return { row: 0, column: 1 };
5539
5862
  return null;
5540
5863
  }
5864
+ function resolvePivotTableDensity(rowHeight) {
5865
+ if (rowHeight == null) return "auto";
5866
+ if (rowHeight <= 26) return "ultra-compact";
5867
+ if (rowHeight <= 32) return "compact";
5868
+ if (rowHeight >= 56) return "comfortable";
5869
+ return "middle";
5870
+ }
5871
+ function resolvePivotTableDensityRowHeight(density) {
5872
+ if (density === "comfortable") return 56;
5873
+ if (density === "middle") return 48;
5874
+ if (density === "compact") return 32;
5875
+ if (density === "ultra-compact") return 26;
5876
+ return void 0;
5877
+ }
5541
5878
  function resolveAdjacentAddress(layout, address, direction) {
5542
5879
  const indexes = resolveAddressIndexes3(layout, address);
5543
5880
  if (!indexes) return null;
@@ -5588,6 +5925,90 @@ function toArrayBuffer(value) {
5588
5925
  return buffer;
5589
5926
  }
5590
5927
 
5928
+ // src/adapters/storage/indexeddb-field-layout-storage.ts
5929
+ var DATABASE_NAME = "canvas_components_pivot_table_config";
5930
+ var STORE_NAME = "field_layout";
5931
+ var DB_VERSION = 1;
5932
+ var dbPromise = null;
5933
+ async function savePivotFieldLayout(key, layout) {
5934
+ try {
5935
+ const db = await openDatabase();
5936
+ await requestToPromise(
5937
+ db.transaction(STORE_NAME, "readwrite").objectStore(STORE_NAME).put(cloneLayout(layout), key)
5938
+ );
5939
+ } catch (error) {
5940
+ console.error("[PivotTable] \u5B57\u6BB5\u5E03\u5C40\u4FDD\u5B58\u5931\u8D25\uFF1A", error);
5941
+ }
5942
+ }
5943
+ async function loadPivotFieldLayout(key) {
5944
+ try {
5945
+ const db = await openDatabase();
5946
+ const value = await requestToPromise(
5947
+ db.transaction(STORE_NAME, "readonly").objectStore(STORE_NAME).get(key)
5948
+ );
5949
+ return isPivotFieldLayout(value) ? cloneLayout(value) : void 0;
5950
+ } catch (error) {
5951
+ console.error("[PivotTable] \u5B57\u6BB5\u5E03\u5C40\u8BFB\u53D6\u5931\u8D25\uFF1A", error);
5952
+ return void 0;
5953
+ }
5954
+ }
5955
+ async function clearPivotFieldLayout(key) {
5956
+ try {
5957
+ const db = await openDatabase();
5958
+ await requestToPromise(
5959
+ db.transaction(STORE_NAME, "readwrite").objectStore(STORE_NAME).delete(key)
5960
+ );
5961
+ } catch (error) {
5962
+ console.error("[PivotTable] \u5B57\u6BB5\u5E03\u5C40\u6E05\u9664\u5931\u8D25\uFF1A", error);
5963
+ }
5964
+ }
5965
+ function openDatabase() {
5966
+ if (dbPromise) return dbPromise;
5967
+ dbPromise = new Promise((resolve, reject) => {
5968
+ if (typeof indexedDB === "undefined") {
5969
+ reject(new Error("\u5F53\u524D\u73AF\u5883\u4E0D\u652F\u6301 IndexedDB"));
5970
+ return;
5971
+ }
5972
+ const request = indexedDB.open(DATABASE_NAME, DB_VERSION);
5973
+ request.onupgradeneeded = () => {
5974
+ const db = request.result;
5975
+ if (!db.objectStoreNames.contains(STORE_NAME)) {
5976
+ db.createObjectStore(STORE_NAME);
5977
+ }
5978
+ };
5979
+ request.onsuccess = () => resolve(request.result);
5980
+ request.onerror = () => reject(request.error);
5981
+ });
5982
+ dbPromise.catch(() => {
5983
+ dbPromise = null;
5984
+ });
5985
+ return dbPromise;
5986
+ }
5987
+ function requestToPromise(request) {
5988
+ return new Promise((resolve, reject) => {
5989
+ request.onsuccess = () => resolve(request.result);
5990
+ request.onerror = () => reject(request.error);
5991
+ });
5992
+ }
5993
+ function isPivotFieldLayout(value) {
5994
+ if (!value || typeof value !== "object") return false;
5995
+ const layout = value;
5996
+ return ["filters", "columns", "rows", "values"].every(
5997
+ (key) => isStringArray(layout[key])
5998
+ );
5999
+ }
6000
+ function isStringArray(value) {
6001
+ return Array.isArray(value) && value.every((item) => typeof item === "string");
6002
+ }
6003
+ function cloneLayout(layout) {
6004
+ return {
6005
+ filters: [...layout.filters],
6006
+ columns: [...layout.columns],
6007
+ rows: [...layout.rows],
6008
+ values: [...layout.values]
6009
+ };
6010
+ }
6011
+
5591
6012
  // src/domain/field/pivot-field-layout.ts
5592
6013
  function createEmptyPivotFieldLayout() {
5593
6014
  return { filters: [], columns: [], rows: [], values: [] };
@@ -5735,6 +6156,6 @@ function areaToLayoutKey(area) {
5735
6156
  return "values";
5736
6157
  }
5737
6158
 
5738
- export { PivotTable, aggregatePivotRecords, buildPivotDimensionTree, buildPivotLayoutSnapshot, computePivotScrollbarLayout, createBuiltInPivotAggregators, createEmptyPivotFieldLayout, createEmptyPivotFilterState, createPivotAggregatorRegistry, createPivotAxisSlots, createPivotCellKey, createPivotExportMatrix, createPivotFieldCatalog, createPivotFieldLayout, createPivotSelectionText, defaultPivotTableTheme, encodePivotDimensionValue, encodePivotPath, exportPivotMatrixToCsv, exportPivotMatrixToXlsx, filterPivotRecords, findPivotFieldArea, flattenVisiblePivotLeaves, getPivotDimensionFilterOptions, hitTestPivotLayout, hitTestPivotResize, hitTestPivotScrollbar, movePivotField, removePivotField, renderPivotTable, resolvePivotDefaultSorts, resolvePivotDimensionKey, resolvePivotDimensionTitle, resolvePivotDimensionValue, resolvePivotDimensionWidth, resolvePivotFieldLayoutOptions, resolvePivotIndicatorAggregator, resolvePivotValueFieldTitle };
6159
+ export { PivotTable, aggregatePivotRecords, buildPivotDimensionTree, buildPivotLayoutSnapshot, clearPivotFieldLayout, computePivotScrollbarLayout, createBuiltInPivotAggregators, createEmptyPivotFieldLayout, createEmptyPivotFilterState, createPivotAggregatorRegistry, createPivotAxisSlots, createPivotCellKey, createPivotExportMatrix, createPivotFieldCatalog, createPivotFieldLayout, createPivotSelectionText, defaultPivotTableTheme, encodePivotDimensionValue, encodePivotPath, exportPivotMatrixToCsv, exportPivotMatrixToXlsx, filterPivotRecords, findPivotFieldArea, flattenVisiblePivotLeaves, getPivotDimensionFilterOptions, hitTestPivotLayout, hitTestPivotResize, hitTestPivotScrollbar, loadPivotFieldLayout, movePivotField, removePivotField, renderPivotTable, resolvePivotDefaultSorts, resolvePivotDimensionKey, resolvePivotDimensionTitle, resolvePivotDimensionValue, resolvePivotDimensionWidth, resolvePivotFieldLayoutOptions, resolvePivotIndicatorAggregator, resolvePivotValueFieldTitle, savePivotFieldLayout };
5739
6160
  //# sourceMappingURL=index.js.map
5740
6161
  //# sourceMappingURL=index.js.map