@canvas-components/pivot-table 0.2.1 → 0.2.2

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.cts CHANGED
@@ -941,6 +941,33 @@ declare class PivotTable<RecordType = Record<string, unknown>> {
941
941
  private render;
942
942
  }
943
943
 
944
+ /** 自定义字段可放置的透视区域。 */
945
+ type PivotFieldArea = "filter" | "column" | "row" | "value";
946
+ /** 自定义面板中的字段定义。 */
947
+ interface PivotField<RecordType = Record<string, unknown>> extends PivotDimension<RecordType> {
948
+ /** 勾选未使用字段时进入的默认区域。 */
949
+ defaultArea?: PivotFieldArea;
950
+ /** 字段进入值区域时使用的指标配置。 */
951
+ indicator?: Omit<PivotIndicator<RecordType>, "key" | "title" | "dataIndex"> & {
952
+ title?: string;
953
+ dataIndex?: PivotIndicator<RecordType>["dataIndex"];
954
+ };
955
+ }
956
+ /** 自定义面板四个区域内的有序字段键。 */
957
+ interface PivotFieldLayout {
958
+ filters: string[];
959
+ columns: string[];
960
+ rows: string[];
961
+ values: string[];
962
+ }
963
+
964
+ /** 将字段布局保存到 IndexedDB。 */
965
+ declare function savePivotFieldLayout(key: string, layout: PivotFieldLayout): Promise<void>;
966
+ /** 从 IndexedDB 读取字段布局;缓存内容无效时返回 undefined。 */
967
+ declare function loadPivotFieldLayout(key: string): Promise<PivotFieldLayout | undefined>;
968
+ /** 清除 IndexedDB 中指定键的字段布局。 */
969
+ declare function clearPivotFieldLayout(key: string): Promise<void>;
970
+
944
971
  /** 将原始记录聚合成第一版稀疏 PivotModel。 */
945
972
  declare function aggregatePivotRecords<RecordType>(params: {
946
973
  records: RecordType[];
@@ -1008,26 +1035,6 @@ declare function getPivotDimensionFilterOptions<RecordType>(params: {
1008
1035
  dimensionKey: string;
1009
1036
  }): PivotFilterOptionItem[];
1010
1037
 
1011
- /** 自定义字段可放置的透视区域。 */
1012
- type PivotFieldArea = "filter" | "column" | "row" | "value";
1013
- /** 自定义面板中的字段定义。 */
1014
- interface PivotField<RecordType = Record<string, unknown>> extends PivotDimension<RecordType> {
1015
- /** 勾选未使用字段时进入的默认区域。 */
1016
- defaultArea?: PivotFieldArea;
1017
- /** 字段进入值区域时使用的指标配置。 */
1018
- indicator?: Omit<PivotIndicator<RecordType>, "key" | "title" | "dataIndex"> & {
1019
- title?: string;
1020
- dataIndex?: PivotIndicator<RecordType>["dataIndex"];
1021
- };
1022
- }
1023
- /** 自定义面板四个区域内的有序字段键。 */
1024
- interface PivotFieldLayout {
1025
- filters: string[];
1026
- columns: string[];
1027
- rows: string[];
1028
- values: string[];
1029
- }
1030
-
1031
1038
  /** 创建四个区域均为空的字段布局。 */
1032
1039
  declare function createEmptyPivotFieldLayout(): PivotFieldLayout;
1033
1040
  /** 根据当前透视配置创建字段区域布局。 */
@@ -1222,4 +1229,4 @@ declare function flattenVisiblePivotLeaves(params: {
1222
1229
  defaultExpandDepth?: number;
1223
1230
  }): PivotNode[];
1224
1231
 
1225
- export { type BuiltInPivotAggregatorName, type PivotAggregateCell, type PivotAggregator, type PivotAggregatorContext, type PivotAggregatorRegistry, type PivotAxis, type PivotAxisScrollbarLayout, type PivotAxisSlot, type PivotBodyCellLayout, type PivotCellAddress, type PivotCellStyle, type PivotContextMenuRequest, type PivotDataIndex, type PivotDimension, type PivotDimensionFilter, type PivotDimensionFilterOption, type PivotDimensionFilterPanelRequest, type PivotDimensionHeaderContent, type PivotDimensionHeaderImageContent, type PivotDimensionHeaderTextContent, type PivotDimensionTitle, type PivotDimensionValue, type PivotExpansionChangeEvent, type PivotExportMatrix, type PivotExportOptions, type PivotField, type PivotFieldArea, type PivotFieldLayout, type PivotFilterAxis, type PivotFilterChangeEvent, type PivotFilterCondition, type PivotFilterConditionOperator, type PivotFilterOptionItem, type PivotFilterState, type PivotGrandTotalPosition, type PivotHeaderCellLayout, type PivotHighlightMode, type PivotHitRegion, type PivotHitTestResult, type PivotIndicator, type PivotIndicatorFormatContext, type PivotLayoutSnapshot, type PivotLoadingRequest, type PivotModel, type PivotNode, type PivotNodeKind, type PivotRect, type PivotRenderStats, type PivotReportFilterCellLayout, type PivotResizeHit, type PivotResolvedPath, type PivotScrollState, type PivotScrollbarAxis, type PivotScrollbarLayout, type PivotScrollbarRect, type PivotScrollbarRole, type PivotSelectionChangeEvent, type PivotSelectionRange, type PivotSelectionState, type PivotSortChangeEvent, type PivotSortRule, type PivotSubtotalPosition, PivotTable, type PivotTableOptions, type PivotTableStateSnapshot, type PivotTableTheme, type PivotTableUiOptions, type PivotTextAlign, type PivotTooltipRequest, type PivotTotalsOptions, type ResolvedPivotDimensionValue, 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 };
1232
+ export { type BuiltInPivotAggregatorName, type PivotAggregateCell, type PivotAggregator, type PivotAggregatorContext, type PivotAggregatorRegistry, type PivotAxis, type PivotAxisScrollbarLayout, type PivotAxisSlot, type PivotBodyCellLayout, type PivotCellAddress, type PivotCellStyle, type PivotContextMenuRequest, type PivotDataIndex, type PivotDimension, type PivotDimensionFilter, type PivotDimensionFilterOption, type PivotDimensionFilterPanelRequest, type PivotDimensionHeaderContent, type PivotDimensionHeaderImageContent, type PivotDimensionHeaderTextContent, type PivotDimensionTitle, type PivotDimensionValue, type PivotExpansionChangeEvent, type PivotExportMatrix, type PivotExportOptions, type PivotField, type PivotFieldArea, type PivotFieldLayout, type PivotFilterAxis, type PivotFilterChangeEvent, type PivotFilterCondition, type PivotFilterConditionOperator, type PivotFilterOptionItem, type PivotFilterState, type PivotGrandTotalPosition, type PivotHeaderCellLayout, type PivotHighlightMode, type PivotHitRegion, type PivotHitTestResult, type PivotIndicator, type PivotIndicatorFormatContext, type PivotLayoutSnapshot, type PivotLoadingRequest, type PivotModel, type PivotNode, type PivotNodeKind, type PivotRect, type PivotRenderStats, type PivotReportFilterCellLayout, type PivotResizeHit, type PivotResolvedPath, type PivotScrollState, type PivotScrollbarAxis, type PivotScrollbarLayout, type PivotScrollbarRect, type PivotScrollbarRole, type PivotSelectionChangeEvent, type PivotSelectionRange, type PivotSelectionState, type PivotSortChangeEvent, type PivotSortRule, type PivotSubtotalPosition, PivotTable, type PivotTableOptions, type PivotTableStateSnapshot, type PivotTableTheme, type PivotTableUiOptions, type PivotTextAlign, type PivotTooltipRequest, type PivotTotalsOptions, type ResolvedPivotDimensionValue, 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 };
package/dist/index.d.ts CHANGED
@@ -941,6 +941,33 @@ declare class PivotTable<RecordType = Record<string, unknown>> {
941
941
  private render;
942
942
  }
943
943
 
944
+ /** 自定义字段可放置的透视区域。 */
945
+ type PivotFieldArea = "filter" | "column" | "row" | "value";
946
+ /** 自定义面板中的字段定义。 */
947
+ interface PivotField<RecordType = Record<string, unknown>> extends PivotDimension<RecordType> {
948
+ /** 勾选未使用字段时进入的默认区域。 */
949
+ defaultArea?: PivotFieldArea;
950
+ /** 字段进入值区域时使用的指标配置。 */
951
+ indicator?: Omit<PivotIndicator<RecordType>, "key" | "title" | "dataIndex"> & {
952
+ title?: string;
953
+ dataIndex?: PivotIndicator<RecordType>["dataIndex"];
954
+ };
955
+ }
956
+ /** 自定义面板四个区域内的有序字段键。 */
957
+ interface PivotFieldLayout {
958
+ filters: string[];
959
+ columns: string[];
960
+ rows: string[];
961
+ values: string[];
962
+ }
963
+
964
+ /** 将字段布局保存到 IndexedDB。 */
965
+ declare function savePivotFieldLayout(key: string, layout: PivotFieldLayout): Promise<void>;
966
+ /** 从 IndexedDB 读取字段布局;缓存内容无效时返回 undefined。 */
967
+ declare function loadPivotFieldLayout(key: string): Promise<PivotFieldLayout | undefined>;
968
+ /** 清除 IndexedDB 中指定键的字段布局。 */
969
+ declare function clearPivotFieldLayout(key: string): Promise<void>;
970
+
944
971
  /** 将原始记录聚合成第一版稀疏 PivotModel。 */
945
972
  declare function aggregatePivotRecords<RecordType>(params: {
946
973
  records: RecordType[];
@@ -1008,26 +1035,6 @@ declare function getPivotDimensionFilterOptions<RecordType>(params: {
1008
1035
  dimensionKey: string;
1009
1036
  }): PivotFilterOptionItem[];
1010
1037
 
1011
- /** 自定义字段可放置的透视区域。 */
1012
- type PivotFieldArea = "filter" | "column" | "row" | "value";
1013
- /** 自定义面板中的字段定义。 */
1014
- interface PivotField<RecordType = Record<string, unknown>> extends PivotDimension<RecordType> {
1015
- /** 勾选未使用字段时进入的默认区域。 */
1016
- defaultArea?: PivotFieldArea;
1017
- /** 字段进入值区域时使用的指标配置。 */
1018
- indicator?: Omit<PivotIndicator<RecordType>, "key" | "title" | "dataIndex"> & {
1019
- title?: string;
1020
- dataIndex?: PivotIndicator<RecordType>["dataIndex"];
1021
- };
1022
- }
1023
- /** 自定义面板四个区域内的有序字段键。 */
1024
- interface PivotFieldLayout {
1025
- filters: string[];
1026
- columns: string[];
1027
- rows: string[];
1028
- values: string[];
1029
- }
1030
-
1031
1038
  /** 创建四个区域均为空的字段布局。 */
1032
1039
  declare function createEmptyPivotFieldLayout(): PivotFieldLayout;
1033
1040
  /** 根据当前透视配置创建字段区域布局。 */
@@ -1222,4 +1229,4 @@ declare function flattenVisiblePivotLeaves(params: {
1222
1229
  defaultExpandDepth?: number;
1223
1230
  }): PivotNode[];
1224
1231
 
1225
- export { type BuiltInPivotAggregatorName, type PivotAggregateCell, type PivotAggregator, type PivotAggregatorContext, type PivotAggregatorRegistry, type PivotAxis, type PivotAxisScrollbarLayout, type PivotAxisSlot, type PivotBodyCellLayout, type PivotCellAddress, type PivotCellStyle, type PivotContextMenuRequest, type PivotDataIndex, type PivotDimension, type PivotDimensionFilter, type PivotDimensionFilterOption, type PivotDimensionFilterPanelRequest, type PivotDimensionHeaderContent, type PivotDimensionHeaderImageContent, type PivotDimensionHeaderTextContent, type PivotDimensionTitle, type PivotDimensionValue, type PivotExpansionChangeEvent, type PivotExportMatrix, type PivotExportOptions, type PivotField, type PivotFieldArea, type PivotFieldLayout, type PivotFilterAxis, type PivotFilterChangeEvent, type PivotFilterCondition, type PivotFilterConditionOperator, type PivotFilterOptionItem, type PivotFilterState, type PivotGrandTotalPosition, type PivotHeaderCellLayout, type PivotHighlightMode, type PivotHitRegion, type PivotHitTestResult, type PivotIndicator, type PivotIndicatorFormatContext, type PivotLayoutSnapshot, type PivotLoadingRequest, type PivotModel, type PivotNode, type PivotNodeKind, type PivotRect, type PivotRenderStats, type PivotReportFilterCellLayout, type PivotResizeHit, type PivotResolvedPath, type PivotScrollState, type PivotScrollbarAxis, type PivotScrollbarLayout, type PivotScrollbarRect, type PivotScrollbarRole, type PivotSelectionChangeEvent, type PivotSelectionRange, type PivotSelectionState, type PivotSortChangeEvent, type PivotSortRule, type PivotSubtotalPosition, PivotTable, type PivotTableOptions, type PivotTableStateSnapshot, type PivotTableTheme, type PivotTableUiOptions, type PivotTextAlign, type PivotTooltipRequest, type PivotTotalsOptions, type ResolvedPivotDimensionValue, 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 };
1232
+ export { type BuiltInPivotAggregatorName, type PivotAggregateCell, type PivotAggregator, type PivotAggregatorContext, type PivotAggregatorRegistry, type PivotAxis, type PivotAxisScrollbarLayout, type PivotAxisSlot, type PivotBodyCellLayout, type PivotCellAddress, type PivotCellStyle, type PivotContextMenuRequest, type PivotDataIndex, type PivotDimension, type PivotDimensionFilter, type PivotDimensionFilterOption, type PivotDimensionFilterPanelRequest, type PivotDimensionHeaderContent, type PivotDimensionHeaderImageContent, type PivotDimensionHeaderTextContent, type PivotDimensionTitle, type PivotDimensionValue, type PivotExpansionChangeEvent, type PivotExportMatrix, type PivotExportOptions, type PivotField, type PivotFieldArea, type PivotFieldLayout, type PivotFilterAxis, type PivotFilterChangeEvent, type PivotFilterCondition, type PivotFilterConditionOperator, type PivotFilterOptionItem, type PivotFilterState, type PivotGrandTotalPosition, type PivotHeaderCellLayout, type PivotHighlightMode, type PivotHitRegion, type PivotHitTestResult, type PivotIndicator, type PivotIndicatorFormatContext, type PivotLayoutSnapshot, type PivotLoadingRequest, type PivotModel, type PivotNode, type PivotNodeKind, type PivotRect, type PivotRenderStats, type PivotReportFilterCellLayout, type PivotResizeHit, type PivotResolvedPath, type PivotScrollState, type PivotScrollbarAxis, type PivotScrollbarLayout, type PivotScrollbarRect, type PivotScrollbarRole, type PivotSelectionChangeEvent, type PivotSelectionRange, type PivotSelectionState, type PivotSortChangeEvent, type PivotSortRule, type PivotSubtotalPosition, PivotTable, type PivotTableOptions, type PivotTableStateSnapshot, type PivotTableTheme, type PivotTableUiOptions, type PivotTextAlign, type PivotTooltipRequest, type PivotTotalsOptions, type ResolvedPivotDimensionValue, 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 };
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 } 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()
@@ -2748,18 +2748,50 @@ function resolvePivotSelectionKind(selection) {
2748
2748
  }
2749
2749
  return selection?.activeNode?.axis ?? "cell";
2750
2750
  }
2751
- function drawPivotSelectionBorder(context, rect, color) {
2751
+ function drawPivotSelectionBorder(context, rect, color, options) {
2752
2752
  context.save();
2753
2753
  context.strokeStyle = color;
2754
2754
  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
- );
2755
+ const left = rect.x + 0.5;
2756
+ const top = rect.y + 0.5;
2757
+ const width = Math.max(rect.width - 1, 0);
2758
+ const height = Math.max(rect.height - 1, 0);
2759
+ const right = left + width;
2760
+ const bottom = top + height;
2761
+ const viewport = options?.viewportRect;
2762
+ const radius = Math.min(options?.radius ?? 8, width / 2, height / 2);
2763
+ const topLeft = viewport && isSameCoordinate(rect.x, viewport.x) && isSameCoordinate(rect.y, viewport.y) ? radius : 0;
2764
+ const topRight = viewport && isSameCoordinate(rect.x + rect.width, viewport.x + viewport.width) && isSameCoordinate(rect.y, viewport.y) ? radius : 0;
2765
+ const bottomRight = viewport && isSameCoordinate(rect.x + rect.width, viewport.x + viewport.width) && isSameCoordinate(rect.y + rect.height, viewport.y + viewport.height) ? radius : 0;
2766
+ const bottomLeft = viewport && isSameCoordinate(rect.x, viewport.x) && isSameCoordinate(rect.y + rect.height, viewport.y + viewport.height) ? radius : 0;
2767
+ if (!topLeft && !topRight && !bottomRight && !bottomLeft) {
2768
+ context.strokeRect(left, top, width, height);
2769
+ context.restore();
2770
+ return;
2771
+ }
2772
+ context.beginPath();
2773
+ context.moveTo(left + topLeft, top);
2774
+ context.lineTo(right - topRight, top);
2775
+ if (topRight) context.arcTo(right, top, right, top + topRight, topRight);
2776
+ else context.lineTo(right, top);
2777
+ context.lineTo(right, bottom - bottomRight);
2778
+ if (bottomRight) {
2779
+ context.arcTo(right, bottom, right - bottomRight, bottom, bottomRight);
2780
+ } else context.lineTo(right, bottom);
2781
+ context.lineTo(left + bottomLeft, bottom);
2782
+ if (bottomLeft) {
2783
+ context.arcTo(left, bottom, left, bottom - bottomLeft, bottomLeft);
2784
+ } else context.lineTo(left, bottom);
2785
+ context.lineTo(left, top + topLeft);
2786
+ if (topLeft) context.arcTo(left, top, left + topLeft, top, topLeft);
2787
+ else context.lineTo(left, top);
2788
+ context.closePath();
2789
+ context.stroke();
2761
2790
  context.restore();
2762
2791
  }
2792
+ function isSameCoordinate(first, second) {
2793
+ return Math.abs(first - second) < 0.01;
2794
+ }
2763
2795
  function resolveSelectionIndexes(layout, selection) {
2764
2796
  const range = selection?.ranges[0];
2765
2797
  if (range) {
@@ -3056,6 +3088,17 @@ function drawPivotGridRect(context, rect, color, options) {
3056
3088
  context.stroke();
3057
3089
  context.restore();
3058
3090
  }
3091
+ function drawPivotViewportRightBorder(context, rect, color) {
3092
+ const x = rect.x + rect.width - 0.5;
3093
+ context.save();
3094
+ context.strokeStyle = color;
3095
+ context.lineWidth = 1;
3096
+ context.beginPath();
3097
+ context.moveTo(x, rect.y);
3098
+ context.lineTo(x, rect.y + rect.height);
3099
+ context.stroke();
3100
+ context.restore();
3101
+ }
3059
3102
  function clipPivotViewport(context, rect, radius = 8) {
3060
3103
  appendRoundedRectPath(context, rect, radius);
3061
3104
  context.clip();
@@ -3141,6 +3184,12 @@ function renderPivotTable(params) {
3141
3184
  );
3142
3185
  const areaSelection = isPivotAreaSelection(layout, params.selection);
3143
3186
  const viewportWidth = resolvePivotViewportWidth(layout);
3187
+ const tableViewportRect = {
3188
+ x: 0,
3189
+ y: 0,
3190
+ width: layout.tableWidth,
3191
+ height: layout.height
3192
+ };
3144
3193
  context.clearRect(0, 0, layout.width, layout.height);
3145
3194
  context.save();
3146
3195
  clipPivotViewport(context, {
@@ -3181,7 +3230,7 @@ function renderPivotTable(params) {
3181
3230
  (cell) => drawPivotGridRect(context, cell.rect, theme.borderColor, {
3182
3231
  skipTop: true,
3183
3232
  skipLeft: cell.rect.x > 0,
3184
- skipRight: isSameCoordinate(
3233
+ skipRight: isSameCoordinate2(
3185
3234
  cell.rect.x + cell.rect.width,
3186
3235
  layout.rowHeaderRect.x + layout.rowHeaderRect.width
3187
3236
  )
@@ -3204,11 +3253,11 @@ function renderPivotTable(params) {
3204
3253
  (cell) => drawPivotGridRect(context, cell.rect, theme.borderColor, {
3205
3254
  skipTop: cell.rect.y > 0,
3206
3255
  skipLeft: true,
3207
- skipRight: isSameCoordinate(
3256
+ skipRight: isSameCoordinate2(
3208
3257
  cell.rect.x + cell.rect.width,
3209
3258
  layout.tableWidth
3210
3259
  ),
3211
- skipBottom: isSameCoordinate(
3260
+ skipBottom: isSameCoordinate2(
3212
3261
  cell.rect.y + cell.rect.height,
3213
3262
  layout.columnHeaderRect.y + layout.columnHeaderRect.height
3214
3263
  )
@@ -3240,7 +3289,7 @@ function renderPivotTable(params) {
3240
3289
  (cell) => drawPivotGridRect(context, cell.rect, theme.borderColor, {
3241
3290
  skipTop: true,
3242
3291
  skipLeft: true,
3243
- skipRight: isSameCoordinate(
3292
+ skipRight: isSameCoordinate2(
3244
3293
  cell.rect.x + cell.rect.width,
3245
3294
  layout.tableWidth
3246
3295
  )
@@ -3269,29 +3318,37 @@ function renderPivotTable(params) {
3269
3318
  headerBackgroundColor: theme.columnHeaderBackgroundColor,
3270
3319
  bodyBackgroundColor: theme.backgroundColor
3271
3320
  });
3321
+ if (params.resizeGuideX != null) {
3322
+ drawPivotResizeGuide(context, params.resizeGuideX, contentHeight);
3323
+ }
3324
+ context.restore();
3325
+ context.save();
3326
+ clipPivotViewport(context, tableViewportRect);
3327
+ drawPivotViewportRightBorder(context, tableViewportRect, theme.borderColor);
3328
+ context.restore();
3329
+ drawPivotViewportBorder(
3330
+ context,
3331
+ { x: 0, y: 0, width: viewportWidth, height: contentHeight },
3332
+ theme.borderColor
3333
+ );
3272
3334
  const selectionRect = resolvePivotSelectionRect(layout, params.selection);
3273
3335
  if (selectionRect) {
3274
3336
  const selectionClipRect = resolvePivotSelectionClipRect(
3275
3337
  layout,
3276
3338
  params.selection
3277
3339
  );
3340
+ context.save();
3341
+ clipPivotViewport(context, tableViewportRect);
3278
3342
  withClip(context, selectionClipRect, () => {
3279
3343
  drawPivotSelectionBorder(
3280
3344
  context,
3281
3345
  selectionRect,
3282
- theme.selectionBorderColor
3346
+ theme.selectionBorderColor,
3347
+ { viewportRect: tableViewportRect }
3283
3348
  );
3284
3349
  });
3350
+ context.restore();
3285
3351
  }
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
3352
  return {
3296
3353
  headerCellCount: layout.reportFilterCells.length + layout.rowFieldHeaderCells.length + layout.rowHeaderCells.length + layout.columnHeaderCells.length,
3297
3354
  bodyCellCount: layout.bodyCells.length
@@ -3336,7 +3393,7 @@ function drawDebugOverlay(context, layout, theme) {
3336
3393
  layout.bodyRect
3337
3394
  ].forEach((rect) => strokeRect(context, rect, "#f04438"));
3338
3395
  context.setLineDash([]);
3339
- context.font = `12px ${theme.fontFamily}`;
3396
+ context.font = `${theme.fontSize}px ${theme.fontFamily}`;
3340
3397
  context.textAlign = "left";
3341
3398
  context.textBaseline = "top";
3342
3399
  context.fillStyle = "#f04438";
@@ -3595,7 +3652,7 @@ function resolveSlotPathKey(slots, nodeId, indicatorKey) {
3595
3652
  (slot) => (slot.nodeId ?? "") === nodeId && (!slot.indicatorKey || slot.indicatorKey === indicatorKey)
3596
3653
  )?.pathKey ?? null;
3597
3654
  }
3598
- function isSameCoordinate(first, second) {
3655
+ function isSameCoordinate2(first, second) {
3599
3656
  return Math.abs(first - second) < 0.01;
3600
3657
  }
3601
3658
  function resolveBodyDisplayText(cell, indicator) {
@@ -5202,7 +5259,7 @@ var PivotTable = class {
5202
5259
  measurePivotText(text) {
5203
5260
  const context = this.host?.canvas.getContext("2d");
5204
5261
  if (!context) return text.length * 8;
5205
- context.font = `${this.options.theme?.fontSize ?? 13}px ${this.options.theme?.fontFamily ?? "sans-serif"}`;
5262
+ context.font = `${this.options.theme?.fontSize ?? 14}px ${this.options.theme?.fontFamily ?? "sans-serif"}`;
5206
5263
  return context.measureText(text).width;
5207
5264
  }
5208
5265
  updateRowHeaderSelectionDrag(event) {
@@ -5588,6 +5645,90 @@ function toArrayBuffer(value) {
5588
5645
  return buffer;
5589
5646
  }
5590
5647
 
5648
+ // src/adapters/storage/indexeddb-field-layout-storage.ts
5649
+ var DATABASE_NAME = "canvas_components_pivot_table_config";
5650
+ var STORE_NAME = "field_layout";
5651
+ var DB_VERSION = 1;
5652
+ var dbPromise = null;
5653
+ async function savePivotFieldLayout(key, layout) {
5654
+ try {
5655
+ const db = await openDatabase();
5656
+ await requestToPromise(
5657
+ db.transaction(STORE_NAME, "readwrite").objectStore(STORE_NAME).put(cloneLayout(layout), key)
5658
+ );
5659
+ } catch (error) {
5660
+ console.error("[PivotTable] \u5B57\u6BB5\u5E03\u5C40\u4FDD\u5B58\u5931\u8D25\uFF1A", error);
5661
+ }
5662
+ }
5663
+ async function loadPivotFieldLayout(key) {
5664
+ try {
5665
+ const db = await openDatabase();
5666
+ const value = await requestToPromise(
5667
+ db.transaction(STORE_NAME, "readonly").objectStore(STORE_NAME).get(key)
5668
+ );
5669
+ return isPivotFieldLayout(value) ? cloneLayout(value) : void 0;
5670
+ } catch (error) {
5671
+ console.error("[PivotTable] \u5B57\u6BB5\u5E03\u5C40\u8BFB\u53D6\u5931\u8D25\uFF1A", error);
5672
+ return void 0;
5673
+ }
5674
+ }
5675
+ async function clearPivotFieldLayout(key) {
5676
+ try {
5677
+ const db = await openDatabase();
5678
+ await requestToPromise(
5679
+ db.transaction(STORE_NAME, "readwrite").objectStore(STORE_NAME).delete(key)
5680
+ );
5681
+ } catch (error) {
5682
+ console.error("[PivotTable] \u5B57\u6BB5\u5E03\u5C40\u6E05\u9664\u5931\u8D25\uFF1A", error);
5683
+ }
5684
+ }
5685
+ function openDatabase() {
5686
+ if (dbPromise) return dbPromise;
5687
+ dbPromise = new Promise((resolve, reject) => {
5688
+ if (typeof indexedDB === "undefined") {
5689
+ reject(new Error("\u5F53\u524D\u73AF\u5883\u4E0D\u652F\u6301 IndexedDB"));
5690
+ return;
5691
+ }
5692
+ const request = indexedDB.open(DATABASE_NAME, DB_VERSION);
5693
+ request.onupgradeneeded = () => {
5694
+ const db = request.result;
5695
+ if (!db.objectStoreNames.contains(STORE_NAME)) {
5696
+ db.createObjectStore(STORE_NAME);
5697
+ }
5698
+ };
5699
+ request.onsuccess = () => resolve(request.result);
5700
+ request.onerror = () => reject(request.error);
5701
+ });
5702
+ dbPromise.catch(() => {
5703
+ dbPromise = null;
5704
+ });
5705
+ return dbPromise;
5706
+ }
5707
+ function requestToPromise(request) {
5708
+ return new Promise((resolve, reject) => {
5709
+ request.onsuccess = () => resolve(request.result);
5710
+ request.onerror = () => reject(request.error);
5711
+ });
5712
+ }
5713
+ function isPivotFieldLayout(value) {
5714
+ if (!value || typeof value !== "object") return false;
5715
+ const layout = value;
5716
+ return ["filters", "columns", "rows", "values"].every(
5717
+ (key) => isStringArray(layout[key])
5718
+ );
5719
+ }
5720
+ function isStringArray(value) {
5721
+ return Array.isArray(value) && value.every((item) => typeof item === "string");
5722
+ }
5723
+ function cloneLayout(layout) {
5724
+ return {
5725
+ filters: [...layout.filters],
5726
+ columns: [...layout.columns],
5727
+ rows: [...layout.rows],
5728
+ values: [...layout.values]
5729
+ };
5730
+ }
5731
+
5591
5732
  // src/domain/field/pivot-field-layout.ts
5592
5733
  function createEmptyPivotFieldLayout() {
5593
5734
  return { filters: [], columns: [], rows: [], values: [] };
@@ -5735,6 +5876,6 @@ function areaToLayoutKey(area) {
5735
5876
  return "values";
5736
5877
  }
5737
5878
 
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 };
5879
+ 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
5880
  //# sourceMappingURL=index.js.map
5740
5881
  //# sourceMappingURL=index.js.map