@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.cjs +175 -31
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +28 -21
- package/dist/index.d.ts +28 -21
- package/dist/index.js +174 -33
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -330,8 +330,6 @@ function indexPivotNodes(root) {
|
|
|
330
330
|
visit(root);
|
|
331
331
|
return nodeMap;
|
|
332
332
|
}
|
|
333
|
-
|
|
334
|
-
// src/domain/aggregation/built-in-aggregators.ts
|
|
335
333
|
function createBuiltInPivotAggregators() {
|
|
336
334
|
return {
|
|
337
335
|
sum: createNumericAggregator("sum"),
|
|
@@ -362,14 +360,14 @@ function createNumericAggregator(type) {
|
|
|
362
360
|
return;
|
|
363
361
|
}
|
|
364
362
|
state.numericCount += 1;
|
|
365
|
-
state.sum
|
|
363
|
+
state.sum = utils.addPreciseNumbers(state.sum, numericValue) ?? state.sum;
|
|
366
364
|
state.min = state.min == null ? numericValue : Math.min(state.min, numericValue);
|
|
367
365
|
state.max = state.max == null ? numericValue : Math.max(state.max, numericValue);
|
|
368
366
|
},
|
|
369
367
|
merge(state, source) {
|
|
370
368
|
state.count += source.count;
|
|
371
369
|
state.numericCount += source.numericCount;
|
|
372
|
-
state.sum
|
|
370
|
+
state.sum = utils.addPreciseNumbers(state.sum, source.sum) ?? state.sum;
|
|
373
371
|
state.min = mergeMinimum(state.min, source.min);
|
|
374
372
|
state.max = mergeMaximum(state.max, source.max);
|
|
375
373
|
source.distinctValues.forEach((value) => state.distinctValues.add(value));
|
|
@@ -377,9 +375,11 @@ function createNumericAggregator(type) {
|
|
|
377
375
|
finalize(state) {
|
|
378
376
|
if (type === "count") return state.count;
|
|
379
377
|
if (type === "distinctCount") return state.distinctValues.size;
|
|
380
|
-
if (type === "sum") return state.sum;
|
|
378
|
+
if (type === "sum") return Number(state.sum);
|
|
381
379
|
if (type === "avg") {
|
|
382
|
-
|
|
380
|
+
if (state.numericCount === 0) return null;
|
|
381
|
+
const average = utils.dividePreciseNumber(state.sum, state.numericCount);
|
|
382
|
+
return average == null ? null : Number(average);
|
|
383
383
|
}
|
|
384
384
|
if (type === "min") return state.min;
|
|
385
385
|
return state.max;
|
|
@@ -390,7 +390,7 @@ function createAccumulator() {
|
|
|
390
390
|
return {
|
|
391
391
|
count: 0,
|
|
392
392
|
numericCount: 0,
|
|
393
|
-
sum: 0,
|
|
393
|
+
sum: "0",
|
|
394
394
|
min: null,
|
|
395
395
|
max: null,
|
|
396
396
|
distinctValues: /* @__PURE__ */ new Set()
|
|
@@ -2769,18 +2769,50 @@ function resolvePivotSelectionKind(selection) {
|
|
|
2769
2769
|
}
|
|
2770
2770
|
return selection?.activeNode?.axis ?? "cell";
|
|
2771
2771
|
}
|
|
2772
|
-
function drawPivotSelectionBorder(context, rect, color) {
|
|
2772
|
+
function drawPivotSelectionBorder(context, rect, color, options) {
|
|
2773
2773
|
context.save();
|
|
2774
2774
|
context.strokeStyle = color;
|
|
2775
2775
|
context.lineWidth = 1;
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2776
|
+
const left = rect.x + 0.5;
|
|
2777
|
+
const top = rect.y + 0.5;
|
|
2778
|
+
const width = Math.max(rect.width - 1, 0);
|
|
2779
|
+
const height = Math.max(rect.height - 1, 0);
|
|
2780
|
+
const right = left + width;
|
|
2781
|
+
const bottom = top + height;
|
|
2782
|
+
const viewport = options?.viewportRect;
|
|
2783
|
+
const radius = Math.min(options?.radius ?? 8, width / 2, height / 2);
|
|
2784
|
+
const topLeft = viewport && isSameCoordinate(rect.x, viewport.x) && isSameCoordinate(rect.y, viewport.y) ? radius : 0;
|
|
2785
|
+
const topRight = viewport && isSameCoordinate(rect.x + rect.width, viewport.x + viewport.width) && isSameCoordinate(rect.y, viewport.y) ? radius : 0;
|
|
2786
|
+
const bottomRight = viewport && isSameCoordinate(rect.x + rect.width, viewport.x + viewport.width) && isSameCoordinate(rect.y + rect.height, viewport.y + viewport.height) ? radius : 0;
|
|
2787
|
+
const bottomLeft = viewport && isSameCoordinate(rect.x, viewport.x) && isSameCoordinate(rect.y + rect.height, viewport.y + viewport.height) ? radius : 0;
|
|
2788
|
+
if (!topLeft && !topRight && !bottomRight && !bottomLeft) {
|
|
2789
|
+
context.strokeRect(left, top, width, height);
|
|
2790
|
+
context.restore();
|
|
2791
|
+
return;
|
|
2792
|
+
}
|
|
2793
|
+
context.beginPath();
|
|
2794
|
+
context.moveTo(left + topLeft, top);
|
|
2795
|
+
context.lineTo(right - topRight, top);
|
|
2796
|
+
if (topRight) context.arcTo(right, top, right, top + topRight, topRight);
|
|
2797
|
+
else context.lineTo(right, top);
|
|
2798
|
+
context.lineTo(right, bottom - bottomRight);
|
|
2799
|
+
if (bottomRight) {
|
|
2800
|
+
context.arcTo(right, bottom, right - bottomRight, bottom, bottomRight);
|
|
2801
|
+
} else context.lineTo(right, bottom);
|
|
2802
|
+
context.lineTo(left + bottomLeft, bottom);
|
|
2803
|
+
if (bottomLeft) {
|
|
2804
|
+
context.arcTo(left, bottom, left, bottom - bottomLeft, bottomLeft);
|
|
2805
|
+
} else context.lineTo(left, bottom);
|
|
2806
|
+
context.lineTo(left, top + topLeft);
|
|
2807
|
+
if (topLeft) context.arcTo(left, top, left + topLeft, top, topLeft);
|
|
2808
|
+
else context.lineTo(left, top);
|
|
2809
|
+
context.closePath();
|
|
2810
|
+
context.stroke();
|
|
2782
2811
|
context.restore();
|
|
2783
2812
|
}
|
|
2813
|
+
function isSameCoordinate(first, second) {
|
|
2814
|
+
return Math.abs(first - second) < 0.01;
|
|
2815
|
+
}
|
|
2784
2816
|
function resolveSelectionIndexes(layout, selection) {
|
|
2785
2817
|
const range = selection?.ranges[0];
|
|
2786
2818
|
if (range) {
|
|
@@ -3077,6 +3109,17 @@ function drawPivotGridRect(context, rect, color, options) {
|
|
|
3077
3109
|
context.stroke();
|
|
3078
3110
|
context.restore();
|
|
3079
3111
|
}
|
|
3112
|
+
function drawPivotViewportRightBorder(context, rect, color) {
|
|
3113
|
+
const x = rect.x + rect.width - 0.5;
|
|
3114
|
+
context.save();
|
|
3115
|
+
context.strokeStyle = color;
|
|
3116
|
+
context.lineWidth = 1;
|
|
3117
|
+
context.beginPath();
|
|
3118
|
+
context.moveTo(x, rect.y);
|
|
3119
|
+
context.lineTo(x, rect.y + rect.height);
|
|
3120
|
+
context.stroke();
|
|
3121
|
+
context.restore();
|
|
3122
|
+
}
|
|
3080
3123
|
function clipPivotViewport(context, rect, radius = 8) {
|
|
3081
3124
|
appendRoundedRectPath(context, rect, radius);
|
|
3082
3125
|
context.clip();
|
|
@@ -3162,6 +3205,12 @@ function renderPivotTable(params) {
|
|
|
3162
3205
|
);
|
|
3163
3206
|
const areaSelection = isPivotAreaSelection(layout, params.selection);
|
|
3164
3207
|
const viewportWidth = resolvePivotViewportWidth(layout);
|
|
3208
|
+
const tableViewportRect = {
|
|
3209
|
+
x: 0,
|
|
3210
|
+
y: 0,
|
|
3211
|
+
width: layout.tableWidth,
|
|
3212
|
+
height: layout.height
|
|
3213
|
+
};
|
|
3165
3214
|
context.clearRect(0, 0, layout.width, layout.height);
|
|
3166
3215
|
context.save();
|
|
3167
3216
|
clipPivotViewport(context, {
|
|
@@ -3202,7 +3251,7 @@ function renderPivotTable(params) {
|
|
|
3202
3251
|
(cell) => drawPivotGridRect(context, cell.rect, theme.borderColor, {
|
|
3203
3252
|
skipTop: true,
|
|
3204
3253
|
skipLeft: cell.rect.x > 0,
|
|
3205
|
-
skipRight:
|
|
3254
|
+
skipRight: isSameCoordinate2(
|
|
3206
3255
|
cell.rect.x + cell.rect.width,
|
|
3207
3256
|
layout.rowHeaderRect.x + layout.rowHeaderRect.width
|
|
3208
3257
|
)
|
|
@@ -3225,11 +3274,11 @@ function renderPivotTable(params) {
|
|
|
3225
3274
|
(cell) => drawPivotGridRect(context, cell.rect, theme.borderColor, {
|
|
3226
3275
|
skipTop: cell.rect.y > 0,
|
|
3227
3276
|
skipLeft: true,
|
|
3228
|
-
skipRight:
|
|
3277
|
+
skipRight: isSameCoordinate2(
|
|
3229
3278
|
cell.rect.x + cell.rect.width,
|
|
3230
3279
|
layout.tableWidth
|
|
3231
3280
|
),
|
|
3232
|
-
skipBottom:
|
|
3281
|
+
skipBottom: isSameCoordinate2(
|
|
3233
3282
|
cell.rect.y + cell.rect.height,
|
|
3234
3283
|
layout.columnHeaderRect.y + layout.columnHeaderRect.height
|
|
3235
3284
|
)
|
|
@@ -3261,7 +3310,7 @@ function renderPivotTable(params) {
|
|
|
3261
3310
|
(cell) => drawPivotGridRect(context, cell.rect, theme.borderColor, {
|
|
3262
3311
|
skipTop: true,
|
|
3263
3312
|
skipLeft: true,
|
|
3264
|
-
skipRight:
|
|
3313
|
+
skipRight: isSameCoordinate2(
|
|
3265
3314
|
cell.rect.x + cell.rect.width,
|
|
3266
3315
|
layout.tableWidth
|
|
3267
3316
|
)
|
|
@@ -3290,29 +3339,37 @@ function renderPivotTable(params) {
|
|
|
3290
3339
|
headerBackgroundColor: theme.columnHeaderBackgroundColor,
|
|
3291
3340
|
bodyBackgroundColor: theme.backgroundColor
|
|
3292
3341
|
});
|
|
3342
|
+
if (params.resizeGuideX != null) {
|
|
3343
|
+
drawPivotResizeGuide(context, params.resizeGuideX, contentHeight);
|
|
3344
|
+
}
|
|
3345
|
+
context.restore();
|
|
3346
|
+
context.save();
|
|
3347
|
+
clipPivotViewport(context, tableViewportRect);
|
|
3348
|
+
drawPivotViewportRightBorder(context, tableViewportRect, theme.borderColor);
|
|
3349
|
+
context.restore();
|
|
3350
|
+
drawPivotViewportBorder(
|
|
3351
|
+
context,
|
|
3352
|
+
{ x: 0, y: 0, width: viewportWidth, height: contentHeight },
|
|
3353
|
+
theme.borderColor
|
|
3354
|
+
);
|
|
3293
3355
|
const selectionRect = resolvePivotSelectionRect(layout, params.selection);
|
|
3294
3356
|
if (selectionRect) {
|
|
3295
3357
|
const selectionClipRect = resolvePivotSelectionClipRect(
|
|
3296
3358
|
layout,
|
|
3297
3359
|
params.selection
|
|
3298
3360
|
);
|
|
3361
|
+
context.save();
|
|
3362
|
+
clipPivotViewport(context, tableViewportRect);
|
|
3299
3363
|
withClip(context, selectionClipRect, () => {
|
|
3300
3364
|
drawPivotSelectionBorder(
|
|
3301
3365
|
context,
|
|
3302
3366
|
selectionRect,
|
|
3303
|
-
theme.selectionBorderColor
|
|
3367
|
+
theme.selectionBorderColor,
|
|
3368
|
+
{ viewportRect: tableViewportRect }
|
|
3304
3369
|
);
|
|
3305
3370
|
});
|
|
3371
|
+
context.restore();
|
|
3306
3372
|
}
|
|
3307
|
-
if (params.resizeGuideX != null) {
|
|
3308
|
-
drawPivotResizeGuide(context, params.resizeGuideX, contentHeight);
|
|
3309
|
-
}
|
|
3310
|
-
context.restore();
|
|
3311
|
-
drawPivotViewportBorder(
|
|
3312
|
-
context,
|
|
3313
|
-
{ x: 0, y: 0, width: viewportWidth, height: contentHeight },
|
|
3314
|
-
theme.borderColor
|
|
3315
|
-
);
|
|
3316
3373
|
return {
|
|
3317
3374
|
headerCellCount: layout.reportFilterCells.length + layout.rowFieldHeaderCells.length + layout.rowHeaderCells.length + layout.columnHeaderCells.length,
|
|
3318
3375
|
bodyCellCount: layout.bodyCells.length
|
|
@@ -3357,7 +3414,7 @@ function drawDebugOverlay(context, layout, theme) {
|
|
|
3357
3414
|
layout.bodyRect
|
|
3358
3415
|
].forEach((rect) => strokeRect(context, rect, "#f04438"));
|
|
3359
3416
|
context.setLineDash([]);
|
|
3360
|
-
context.font =
|
|
3417
|
+
context.font = `${theme.fontSize}px ${theme.fontFamily}`;
|
|
3361
3418
|
context.textAlign = "left";
|
|
3362
3419
|
context.textBaseline = "top";
|
|
3363
3420
|
context.fillStyle = "#f04438";
|
|
@@ -3616,7 +3673,7 @@ function resolveSlotPathKey(slots, nodeId, indicatorKey) {
|
|
|
3616
3673
|
(slot) => (slot.nodeId ?? "") === nodeId && (!slot.indicatorKey || slot.indicatorKey === indicatorKey)
|
|
3617
3674
|
)?.pathKey ?? null;
|
|
3618
3675
|
}
|
|
3619
|
-
function
|
|
3676
|
+
function isSameCoordinate2(first, second) {
|
|
3620
3677
|
return Math.abs(first - second) < 0.01;
|
|
3621
3678
|
}
|
|
3622
3679
|
function resolveBodyDisplayText(cell, indicator) {
|
|
@@ -5223,7 +5280,7 @@ var PivotTable = class {
|
|
|
5223
5280
|
measurePivotText(text) {
|
|
5224
5281
|
const context = this.host?.canvas.getContext("2d");
|
|
5225
5282
|
if (!context) return text.length * 8;
|
|
5226
|
-
context.font = `${this.options.theme?.fontSize ??
|
|
5283
|
+
context.font = `${this.options.theme?.fontSize ?? 14}px ${this.options.theme?.fontFamily ?? "sans-serif"}`;
|
|
5227
5284
|
return context.measureText(text).width;
|
|
5228
5285
|
}
|
|
5229
5286
|
updateRowHeaderSelectionDrag(event) {
|
|
@@ -5609,6 +5666,90 @@ function toArrayBuffer(value) {
|
|
|
5609
5666
|
return buffer;
|
|
5610
5667
|
}
|
|
5611
5668
|
|
|
5669
|
+
// src/adapters/storage/indexeddb-field-layout-storage.ts
|
|
5670
|
+
var DATABASE_NAME = "canvas_components_pivot_table_config";
|
|
5671
|
+
var STORE_NAME = "field_layout";
|
|
5672
|
+
var DB_VERSION = 1;
|
|
5673
|
+
var dbPromise = null;
|
|
5674
|
+
async function savePivotFieldLayout(key, layout) {
|
|
5675
|
+
try {
|
|
5676
|
+
const db = await openDatabase();
|
|
5677
|
+
await requestToPromise(
|
|
5678
|
+
db.transaction(STORE_NAME, "readwrite").objectStore(STORE_NAME).put(cloneLayout(layout), key)
|
|
5679
|
+
);
|
|
5680
|
+
} catch (error) {
|
|
5681
|
+
console.error("[PivotTable] \u5B57\u6BB5\u5E03\u5C40\u4FDD\u5B58\u5931\u8D25\uFF1A", error);
|
|
5682
|
+
}
|
|
5683
|
+
}
|
|
5684
|
+
async function loadPivotFieldLayout(key) {
|
|
5685
|
+
try {
|
|
5686
|
+
const db = await openDatabase();
|
|
5687
|
+
const value = await requestToPromise(
|
|
5688
|
+
db.transaction(STORE_NAME, "readonly").objectStore(STORE_NAME).get(key)
|
|
5689
|
+
);
|
|
5690
|
+
return isPivotFieldLayout(value) ? cloneLayout(value) : void 0;
|
|
5691
|
+
} catch (error) {
|
|
5692
|
+
console.error("[PivotTable] \u5B57\u6BB5\u5E03\u5C40\u8BFB\u53D6\u5931\u8D25\uFF1A", error);
|
|
5693
|
+
return void 0;
|
|
5694
|
+
}
|
|
5695
|
+
}
|
|
5696
|
+
async function clearPivotFieldLayout(key) {
|
|
5697
|
+
try {
|
|
5698
|
+
const db = await openDatabase();
|
|
5699
|
+
await requestToPromise(
|
|
5700
|
+
db.transaction(STORE_NAME, "readwrite").objectStore(STORE_NAME).delete(key)
|
|
5701
|
+
);
|
|
5702
|
+
} catch (error) {
|
|
5703
|
+
console.error("[PivotTable] \u5B57\u6BB5\u5E03\u5C40\u6E05\u9664\u5931\u8D25\uFF1A", error);
|
|
5704
|
+
}
|
|
5705
|
+
}
|
|
5706
|
+
function openDatabase() {
|
|
5707
|
+
if (dbPromise) return dbPromise;
|
|
5708
|
+
dbPromise = new Promise((resolve, reject) => {
|
|
5709
|
+
if (typeof indexedDB === "undefined") {
|
|
5710
|
+
reject(new Error("\u5F53\u524D\u73AF\u5883\u4E0D\u652F\u6301 IndexedDB"));
|
|
5711
|
+
return;
|
|
5712
|
+
}
|
|
5713
|
+
const request = indexedDB.open(DATABASE_NAME, DB_VERSION);
|
|
5714
|
+
request.onupgradeneeded = () => {
|
|
5715
|
+
const db = request.result;
|
|
5716
|
+
if (!db.objectStoreNames.contains(STORE_NAME)) {
|
|
5717
|
+
db.createObjectStore(STORE_NAME);
|
|
5718
|
+
}
|
|
5719
|
+
};
|
|
5720
|
+
request.onsuccess = () => resolve(request.result);
|
|
5721
|
+
request.onerror = () => reject(request.error);
|
|
5722
|
+
});
|
|
5723
|
+
dbPromise.catch(() => {
|
|
5724
|
+
dbPromise = null;
|
|
5725
|
+
});
|
|
5726
|
+
return dbPromise;
|
|
5727
|
+
}
|
|
5728
|
+
function requestToPromise(request) {
|
|
5729
|
+
return new Promise((resolve, reject) => {
|
|
5730
|
+
request.onsuccess = () => resolve(request.result);
|
|
5731
|
+
request.onerror = () => reject(request.error);
|
|
5732
|
+
});
|
|
5733
|
+
}
|
|
5734
|
+
function isPivotFieldLayout(value) {
|
|
5735
|
+
if (!value || typeof value !== "object") return false;
|
|
5736
|
+
const layout = value;
|
|
5737
|
+
return ["filters", "columns", "rows", "values"].every(
|
|
5738
|
+
(key) => isStringArray(layout[key])
|
|
5739
|
+
);
|
|
5740
|
+
}
|
|
5741
|
+
function isStringArray(value) {
|
|
5742
|
+
return Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
5743
|
+
}
|
|
5744
|
+
function cloneLayout(layout) {
|
|
5745
|
+
return {
|
|
5746
|
+
filters: [...layout.filters],
|
|
5747
|
+
columns: [...layout.columns],
|
|
5748
|
+
rows: [...layout.rows],
|
|
5749
|
+
values: [...layout.values]
|
|
5750
|
+
};
|
|
5751
|
+
}
|
|
5752
|
+
|
|
5612
5753
|
// src/domain/field/pivot-field-layout.ts
|
|
5613
5754
|
function createEmptyPivotFieldLayout() {
|
|
5614
5755
|
return { filters: [], columns: [], rows: [], values: [] };
|
|
@@ -5772,6 +5913,7 @@ exports.PivotTable = PivotTable;
|
|
|
5772
5913
|
exports.aggregatePivotRecords = aggregatePivotRecords;
|
|
5773
5914
|
exports.buildPivotDimensionTree = buildPivotDimensionTree;
|
|
5774
5915
|
exports.buildPivotLayoutSnapshot = buildPivotLayoutSnapshot;
|
|
5916
|
+
exports.clearPivotFieldLayout = clearPivotFieldLayout;
|
|
5775
5917
|
exports.computePivotScrollbarLayout = computePivotScrollbarLayout;
|
|
5776
5918
|
exports.createBuiltInPivotAggregators = createBuiltInPivotAggregators;
|
|
5777
5919
|
exports.createEmptyPivotFieldLayout = createEmptyPivotFieldLayout;
|
|
@@ -5795,6 +5937,7 @@ exports.getPivotDimensionFilterOptions = getPivotDimensionFilterOptions;
|
|
|
5795
5937
|
exports.hitTestPivotLayout = hitTestPivotLayout;
|
|
5796
5938
|
exports.hitTestPivotResize = hitTestPivotResize;
|
|
5797
5939
|
exports.hitTestPivotScrollbar = hitTestPivotScrollbar;
|
|
5940
|
+
exports.loadPivotFieldLayout = loadPivotFieldLayout;
|
|
5798
5941
|
exports.movePivotField = movePivotField;
|
|
5799
5942
|
exports.removePivotField = removePivotField;
|
|
5800
5943
|
exports.renderPivotTable = renderPivotTable;
|
|
@@ -5806,5 +5949,6 @@ exports.resolvePivotDimensionWidth = resolvePivotDimensionWidth;
|
|
|
5806
5949
|
exports.resolvePivotFieldLayoutOptions = resolvePivotFieldLayoutOptions;
|
|
5807
5950
|
exports.resolvePivotIndicatorAggregator = resolvePivotIndicatorAggregator;
|
|
5808
5951
|
exports.resolvePivotValueFieldTitle = resolvePivotValueFieldTitle;
|
|
5952
|
+
exports.savePivotFieldLayout = savePivotFieldLayout;
|
|
5809
5953
|
//# sourceMappingURL=index.cjs.map
|
|
5810
5954
|
//# sourceMappingURL=index.cjs.map
|