@vue-pivottable/subtotal-renderer 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -16,28 +16,52 @@ function createSubtotalRenderers(PivotData) {
16
16
  "Subtotal Table": makeSubtotalRenderer({ name: "vue-subtotal-table" })
17
17
  };
18
18
  }
19
- function generateRowKeysWithSubtotals2(rowKeys, depth) {
19
+ function generateRowKeysWithSubtotals2(rowKeys, depth, collapsedKeys = /* @__PURE__ */ new Set()) {
20
20
  if (depth <= 1) {
21
21
  return rowKeys.map((key) => ({ key, isSubtotal: false, level: key.length }));
22
22
  }
23
23
  const result = [];
24
+ const addedSubtotals = /* @__PURE__ */ new Set();
24
25
  for (let i = 0; i < rowKeys.length; i++) {
25
26
  const rowKey = rowKeys[i];
26
- const nextRowKey = rowKeys[i + 1];
27
- result.push({ key: rowKey, isSubtotal: false, level: rowKey.length });
28
- for (let level = depth - 1; level >= 1; level--) {
29
- const currentPrefix = rowKey.slice(0, level);
30
- const nextPrefix = nextRowKey ? nextRowKey.slice(0, level) : null;
31
- const levelChanges = !nextPrefix || JSON.stringify(currentPrefix) !== JSON.stringify(nextPrefix);
32
- if (levelChanges) {
33
- result.push({
34
- key: currentPrefix,
35
- isSubtotal: true,
36
- level,
37
- subtotalLabel: `${currentPrefix[level - 1]} Subtotal`
38
- });
27
+ rowKeys[i + 1];
28
+ let isHidden = false;
29
+ for (let level = 1; level < rowKey.length; level++) {
30
+ const parentKey = rowKey.slice(0, level);
31
+ const parentKeyStr = JSON.stringify(parentKey);
32
+ if (collapsedKeys.has(parentKeyStr)) {
33
+ isHidden = true;
34
+ break;
35
+ }
36
+ }
37
+ for (let level = 1; level < rowKey.length; level++) {
38
+ const subtotalKey = rowKey.slice(0, level);
39
+ const subtotalKeyStr = JSON.stringify(subtotalKey);
40
+ if (!addedSubtotals.has(subtotalKeyStr)) {
41
+ addedSubtotals.add(subtotalKeyStr);
42
+ let subtotalHidden = false;
43
+ for (let parentLevel = 1; parentLevel < level; parentLevel++) {
44
+ const parentKey = subtotalKey.slice(0, parentLevel);
45
+ if (collapsedKeys.has(JSON.stringify(parentKey))) {
46
+ subtotalHidden = true;
47
+ break;
48
+ }
49
+ }
50
+ if (!subtotalHidden) {
51
+ const isCollapsed = collapsedKeys.has(subtotalKeyStr);
52
+ result.push({
53
+ key: subtotalKey,
54
+ isSubtotal: true,
55
+ level,
56
+ subtotalLabel: `${subtotalKey[level - 1]} Subtotal`,
57
+ isCollapsed
58
+ });
59
+ }
39
60
  }
40
61
  }
62
+ if (!isHidden) {
63
+ result.push({ key: rowKey, isSubtotal: false, level: rowKey.length });
64
+ }
41
65
  }
42
66
  return result;
43
67
  }
@@ -75,8 +99,60 @@ function spanSize(rowItems, i, j) {
75
99
  }
76
100
  return len;
77
101
  }
78
- function colSpanSize(arr, i, j) {
79
- if (i !== 0) {
102
+ function generateColKeysWithSubtotals2(colKeys, depth, collapsedKeys = /* @__PURE__ */ new Set()) {
103
+ if (depth <= 1) {
104
+ return colKeys.map((key) => ({ key, isSubtotal: false, level: key.length }));
105
+ }
106
+ const result = [];
107
+ const addedSubtotals = /* @__PURE__ */ new Set();
108
+ for (let i = 0; i < colKeys.length; i++) {
109
+ const colKey = colKeys[i];
110
+ let isHidden = false;
111
+ for (let level = 1; level < colKey.length; level++) {
112
+ const parentKey = colKey.slice(0, level);
113
+ const parentKeyStr = JSON.stringify(parentKey);
114
+ if (collapsedKeys.has(parentKeyStr)) {
115
+ isHidden = true;
116
+ break;
117
+ }
118
+ }
119
+ for (let level = 1; level < colKey.length; level++) {
120
+ const subtotalKey = colKey.slice(0, level);
121
+ const subtotalKeyStr = JSON.stringify(subtotalKey);
122
+ if (!addedSubtotals.has(subtotalKeyStr)) {
123
+ addedSubtotals.add(subtotalKeyStr);
124
+ let subtotalHidden = false;
125
+ for (let parentLevel = 1; parentLevel < level; parentLevel++) {
126
+ const parentKey = subtotalKey.slice(0, parentLevel);
127
+ if (collapsedKeys.has(JSON.stringify(parentKey))) {
128
+ subtotalHidden = true;
129
+ break;
130
+ }
131
+ }
132
+ if (!subtotalHidden) {
133
+ const isCollapsed = collapsedKeys.has(subtotalKeyStr);
134
+ result.push({
135
+ key: subtotalKey,
136
+ isSubtotal: true,
137
+ level,
138
+ subtotalLabel: `${subtotalKey[level - 1]} Subtotal`,
139
+ isCollapsed
140
+ });
141
+ }
142
+ }
143
+ }
144
+ if (!isHidden) {
145
+ result.push({ key: colKey, isSubtotal: false, level: colKey.length });
146
+ }
147
+ }
148
+ return result;
149
+ }
150
+ function colSpanSizeWithSubtotals(colItems, i, j) {
151
+ if (colItems[i].isSubtotal) {
152
+ return 1;
153
+ }
154
+ const arr = colItems.map((item) => item.key);
155
+ if (i !== 0 && !colItems[i - 1].isSubtotal) {
80
156
  let asPrevious = true;
81
157
  for (let x = 0; x <= j; x++) {
82
158
  if (arr[i - 1][x] !== arr[i][x]) {
@@ -90,6 +166,8 @@ function colSpanSize(arr, i, j) {
90
166
  }
91
167
  let len = 0;
92
168
  while (i + len < arr.length) {
169
+ if (colItems[i + len].isSubtotal)
170
+ break;
93
171
  let same = true;
94
172
  for (let x = 0; x <= j; x++) {
95
173
  if (arr[i][x] !== arr[i + len][x]) {
@@ -241,10 +319,11 @@ function makeSubtotalRenderer(opts = {}) {
241
319
  const colKeys = pivotData.getColKeys();
242
320
  const grandTotalAggregator = pivotData.getAggregator([], []);
243
321
  const getAggregator = createSubtotalAggregatorGetter(pivotData);
244
- const rowKeysWithSubtotals = generateRowKeysWithSubtotals2(rowKeys, rowAttrs.length);
322
+ const rowKeysWithSubtotals = generateRowKeysWithSubtotals2(rowKeys, rowAttrs.length, state.collapsedRowKeys);
323
+ const colKeysWithSubtotals = generateColKeysWithSubtotals2(colKeys, colAttrs.length, state.collapsedColKeys);
245
324
  const subtotalOpts = this.subtotalOptions;
246
- subtotalOpts.arrowCollapsed || "▶";
247
- subtotalOpts.arrowExpanded || "▼";
325
+ const arrowCollapsed = subtotalOpts.arrowCollapsed || "▶";
326
+ const arrowExpanded = subtotalOpts.arrowExpanded || "▼";
248
327
  const getClickHandler = (value, rowValues, colValues) => {
249
328
  var _a;
250
329
  if ((_a = this.tableOptions) == null ? void 0 : _a.clickCallback) {
@@ -270,23 +349,56 @@ function makeSubtotalRenderer(opts = {}) {
270
349
  if (j === 0 && rowAttrs.length !== 0) {
271
350
  cells.push(h("th", {
272
351
  colSpan: rowAttrs.length,
273
- rowSpan: colAttrs.length,
274
- style: {
275
- backgroundColor: "#f5f5f5"
276
- }
352
+ rowSpan: colAttrs.length
277
353
  }));
278
354
  }
279
355
  cells.push(h("th", { class: "pvtAxisLabel" }, c));
280
- colKeys.forEach((colKey, i) => {
281
- const colSpan = colSpanSize(colKeys, i, j);
282
- if (colSpan !== -1) {
283
- const label = applyLabel(colAttrs[j], colKey[j]);
284
- cells.push(h("th", {
285
- class: "pvtColLabel",
286
- key: `colKey${i}-${j}`,
287
- colSpan,
288
- rowSpan: j === colAttrs.length - 1 && rowAttrs.length !== 0 ? 2 : 1
289
- }, label));
356
+ colKeysWithSubtotals.forEach((colItem, i) => {
357
+ const { key: colKey, isSubtotal, level } = colItem;
358
+ if (j < colKey.length) {
359
+ const colSpan = colSpanSizeWithSubtotals(colKeysWithSubtotals, i, j);
360
+ if (colSpan !== -1) {
361
+ const isLastAttrRow = j === colKey.length - 1;
362
+ if (isSubtotal && isLastAttrRow) {
363
+ const keyStr = JSON.stringify(colKey);
364
+ const isCollapsed = state.collapsedColKeys.has(keyStr);
365
+ const arrow = isCollapsed ? arrowCollapsed : arrowExpanded;
366
+ const label = `${colKey[j]} Subtotal`;
367
+ cells.push(h("th", {
368
+ class: "pvtColLabel pvtColSubtotalLabel",
369
+ key: `colKey${i}-${j}`,
370
+ colSpan,
371
+ rowSpan: colAttrs.length - j + (rowAttrs.length !== 0 ? 1 : 0),
372
+ style: {
373
+ fontWeight: "bold",
374
+ backgroundColor: "#f0f0f0"
375
+ }
376
+ }, [
377
+ h("span", {
378
+ class: "pvtColCollapseToggle",
379
+ style: {
380
+ cursor: "pointer",
381
+ marginRight: "4px",
382
+ userSelect: "none"
383
+ },
384
+ onClick: (e) => {
385
+ e.stopPropagation();
386
+ toggleColCollapse(keyStr);
387
+ }
388
+ }, arrow),
389
+ label
390
+ ]));
391
+ } else {
392
+ const label = applyLabel(colAttrs[j], colKey[j]);
393
+ const rowSpan = isLastAttrRow && rowAttrs.length !== 0 ? 2 : 1;
394
+ cells.push(h("th", {
395
+ class: "pvtColLabel",
396
+ key: `colKey${i}-${j}`,
397
+ colSpan,
398
+ rowSpan
399
+ }, label));
400
+ }
401
+ }
290
402
  }
291
403
  });
292
404
  if (j === 0 && this.rowTotal) {
@@ -302,6 +414,9 @@ function makeSubtotalRenderer(opts = {}) {
302
414
  class: "pvtAxisLabel",
303
415
  key: `rowAttr${i}`
304
416
  }, r));
417
+ if (colAttrs.length !== 0) {
418
+ cells.push(h("th"));
419
+ }
305
420
  if (colAttrs.length === 0 && this.rowTotal) {
306
421
  cells.push(h("th", { class: "pvtTotalLabel" }, this.localeStrings.totals));
307
422
  }
@@ -315,6 +430,9 @@ function makeSubtotalRenderer(opts = {}) {
315
430
  const { key: rowKey, isSubtotal, level, subtotalLabel } = rowItem;
316
431
  const cells = [];
317
432
  if (isSubtotal) {
433
+ const keyStr = JSON.stringify(rowKey);
434
+ const isCollapsed = state.collapsedRowKeys.has(keyStr);
435
+ const arrow = isCollapsed ? arrowCollapsed : arrowExpanded;
318
436
  const subtotalText = subtotalLabel || `${rowKey[rowKey.length - 1]} Subtotal`;
319
437
  cells.push(h("th", {
320
438
  class: "pvtRowLabel pvtSubtotalLabel",
@@ -323,18 +441,34 @@ function makeSubtotalRenderer(opts = {}) {
323
441
  fontWeight: "bold",
324
442
  backgroundColor: "#f0f0f0"
325
443
  }
326
- }, subtotalText));
327
- colKeys.forEach((colKey, j) => {
444
+ }, [
445
+ h("span", {
446
+ class: "pvtCollapseToggle",
447
+ style: {
448
+ cursor: "pointer",
449
+ marginRight: "6px",
450
+ userSelect: "none"
451
+ },
452
+ onClick: (e) => {
453
+ e.stopPropagation();
454
+ toggleRowCollapse(keyStr);
455
+ }
456
+ }, arrow),
457
+ subtotalText
458
+ ]));
459
+ colKeysWithSubtotals.forEach((colItem, j) => {
460
+ const { key: colKey, isSubtotal: isColSubtotal } = colItem;
328
461
  const aggregator = getAggregator(rowKey, colKey);
329
462
  const val = aggregator.value();
330
463
  const formattedVal = aggregator.format ? aggregator.format(val) : val;
331
464
  const clickHandler = getClickHandler(val, rowKey, colKey);
465
+ const isDoubleSubtotal = isColSubtotal;
332
466
  cells.push(h("td", {
333
- class: "pvtVal pvtSubtotalVal",
467
+ class: isColSubtotal ? "pvtVal pvtSubtotalVal pvtColSubtotalVal" : "pvtVal pvtSubtotalVal",
334
468
  key: `subtotal-val${i}-${j}`,
335
469
  style: {
336
470
  fontWeight: "bold",
337
- backgroundColor: "#f0f0f0"
471
+ backgroundColor: isDoubleSubtotal ? "#e0e0e0" : "#f0f0f0"
338
472
  },
339
473
  onClick: clickHandler || void 0
340
474
  }, formattedVal));
@@ -370,14 +504,19 @@ function makeSubtotalRenderer(opts = {}) {
370
504
  }, label));
371
505
  }
372
506
  });
373
- colKeys.forEach((colKey, j) => {
507
+ colKeysWithSubtotals.forEach((colItem, j) => {
508
+ const { key: colKey, isSubtotal: isColSubtotal } = colItem;
374
509
  const aggregator = getAggregator(rowKey, colKey);
375
510
  const val = aggregator.value();
376
511
  const formattedVal = aggregator.format ? aggregator.format(val) : val;
377
512
  const clickHandler = getClickHandler(val, rowKey, colKey);
378
513
  cells.push(h("td", {
379
- class: "pvtVal",
514
+ class: isColSubtotal ? "pvtVal pvtColSubtotalVal" : "pvtVal",
380
515
  key: `val${i}-${j}`,
516
+ style: isColSubtotal ? {
517
+ fontWeight: "bold",
518
+ backgroundColor: "#f0f0f0"
519
+ } : void 0,
381
520
  onClick: clickHandler || void 0
382
521
  }, formattedVal));
383
522
  });
@@ -400,14 +539,19 @@ function makeSubtotalRenderer(opts = {}) {
400
539
  class: "pvtTotalLabel",
401
540
  colSpan: rowAttrs.length + (colAttrs.length === 0 ? 0 : 1)
402
541
  }, this.localeStrings.totals));
403
- colKeys.forEach((colKey, i) => {
542
+ colKeysWithSubtotals.forEach((colItem, i) => {
543
+ const { key: colKey, isSubtotal: isColSubtotal } = colItem;
404
544
  const totalAggregator = getAggregator([], colKey);
405
545
  const totalVal = totalAggregator.value();
406
546
  const formattedTotal = totalAggregator.format ? totalAggregator.format(totalVal) : totalVal;
407
547
  const clickHandler = getClickHandler(totalVal, [], colKey);
408
548
  cells.push(h("td", {
409
- class: "pvtTotal",
549
+ class: isColSubtotal ? "pvtTotal pvtColSubtotalTotal" : "pvtTotal",
410
550
  key: `colTotal${i}`,
551
+ style: isColSubtotal ? {
552
+ fontWeight: "bold",
553
+ backgroundColor: "#e0e0e0"
554
+ } : void 0,
411
555
  onClick: clickHandler || void 0
412
556
  }, formattedTotal));
413
557
  });
package/dist/vue2.js CHANGED
@@ -16,28 +16,51 @@ function createSubtotalRenderers(PivotData) {
16
16
  "Subtotal Table": makeSubtotalRenderer({ name: "vue-subtotal-table" })
17
17
  };
18
18
  }
19
- function generateRowKeysWithSubtotals(rowKeys, depth) {
19
+ function generateRowKeysWithSubtotals(rowKeys, depth, collapsedKeys = /* @__PURE__ */ new Set()) {
20
20
  if (depth <= 1) {
21
21
  return rowKeys.map((key) => ({ key, isSubtotal: false, level: key.length }));
22
22
  }
23
23
  const result = [];
24
+ const addedSubtotals = /* @__PURE__ */ new Set();
24
25
  for (let i = 0; i < rowKeys.length; i++) {
25
26
  const rowKey = rowKeys[i];
26
- const nextRowKey = rowKeys[i + 1];
27
- result.push({ key: rowKey, isSubtotal: false, level: rowKey.length });
28
- for (let level = depth - 1; level >= 1; level--) {
29
- const currentPrefix = rowKey.slice(0, level);
30
- const nextPrefix = nextRowKey ? nextRowKey.slice(0, level) : null;
31
- const levelChanges = !nextPrefix || JSON.stringify(currentPrefix) !== JSON.stringify(nextPrefix);
32
- if (levelChanges) {
33
- result.push({
34
- key: currentPrefix,
35
- isSubtotal: true,
36
- level,
37
- subtotalLabel: `${currentPrefix[level - 1]} Subtotal`
38
- });
27
+ let isHidden = false;
28
+ for (let level = 1; level < rowKey.length; level++) {
29
+ const parentKey = rowKey.slice(0, level);
30
+ const parentKeyStr = JSON.stringify(parentKey);
31
+ if (collapsedKeys.has(parentKeyStr)) {
32
+ isHidden = true;
33
+ break;
34
+ }
35
+ }
36
+ for (let level = 1; level < rowKey.length; level++) {
37
+ const subtotalKey = rowKey.slice(0, level);
38
+ const subtotalKeyStr = JSON.stringify(subtotalKey);
39
+ if (!addedSubtotals.has(subtotalKeyStr)) {
40
+ addedSubtotals.add(subtotalKeyStr);
41
+ let subtotalHidden = false;
42
+ for (let parentLevel = 1; parentLevel < level; parentLevel++) {
43
+ const parentKey = subtotalKey.slice(0, parentLevel);
44
+ if (collapsedKeys.has(JSON.stringify(parentKey))) {
45
+ subtotalHidden = true;
46
+ break;
47
+ }
48
+ }
49
+ if (!subtotalHidden) {
50
+ const isCollapsed = collapsedKeys.has(subtotalKeyStr);
51
+ result.push({
52
+ key: subtotalKey,
53
+ isSubtotal: true,
54
+ level,
55
+ subtotalLabel: `${subtotalKey[level - 1]} Subtotal`,
56
+ isCollapsed
57
+ });
58
+ }
39
59
  }
40
60
  }
61
+ if (!isHidden) {
62
+ result.push({ key: rowKey, isSubtotal: false, level: rowKey.length });
63
+ }
41
64
  }
42
65
  return result;
43
66
  }
@@ -75,8 +98,60 @@ function spanSize(rowItems, i, j) {
75
98
  }
76
99
  return len;
77
100
  }
78
- function colSpanSize(arr, i, j) {
79
- if (i !== 0) {
101
+ function generateColKeysWithSubtotals(colKeys, depth, collapsedKeys = /* @__PURE__ */ new Set()) {
102
+ if (depth <= 1) {
103
+ return colKeys.map((key) => ({ key, isSubtotal: false, level: key.length }));
104
+ }
105
+ const result = [];
106
+ const addedSubtotals = /* @__PURE__ */ new Set();
107
+ for (let i = 0; i < colKeys.length; i++) {
108
+ const colKey = colKeys[i];
109
+ let isHidden = false;
110
+ for (let level = 1; level < colKey.length; level++) {
111
+ const parentKey = colKey.slice(0, level);
112
+ const parentKeyStr = JSON.stringify(parentKey);
113
+ if (collapsedKeys.has(parentKeyStr)) {
114
+ isHidden = true;
115
+ break;
116
+ }
117
+ }
118
+ for (let level = 1; level < colKey.length; level++) {
119
+ const subtotalKey = colKey.slice(0, level);
120
+ const subtotalKeyStr = JSON.stringify(subtotalKey);
121
+ if (!addedSubtotals.has(subtotalKeyStr)) {
122
+ addedSubtotals.add(subtotalKeyStr);
123
+ let subtotalHidden = false;
124
+ for (let parentLevel = 1; parentLevel < level; parentLevel++) {
125
+ const parentKey = subtotalKey.slice(0, parentLevel);
126
+ if (collapsedKeys.has(JSON.stringify(parentKey))) {
127
+ subtotalHidden = true;
128
+ break;
129
+ }
130
+ }
131
+ if (!subtotalHidden) {
132
+ const isCollapsed = collapsedKeys.has(subtotalKeyStr);
133
+ result.push({
134
+ key: subtotalKey,
135
+ isSubtotal: true,
136
+ level,
137
+ subtotalLabel: `${subtotalKey[level - 1]} Subtotal`,
138
+ isCollapsed
139
+ });
140
+ }
141
+ }
142
+ }
143
+ if (!isHidden) {
144
+ result.push({ key: colKey, isSubtotal: false, level: colKey.length });
145
+ }
146
+ }
147
+ return result;
148
+ }
149
+ function colSpanSizeWithSubtotals(colItems, i, j) {
150
+ if (colItems[i].isSubtotal) {
151
+ return 1;
152
+ }
153
+ const arr = colItems.map((item) => item.key);
154
+ if (i !== 0 && !colItems[i - 1].isSubtotal) {
80
155
  let asPrevious = true;
81
156
  for (let x = 0; x <= j; x++) {
82
157
  if (arr[i - 1][x] !== arr[i][x]) {
@@ -90,6 +165,8 @@ function colSpanSize(arr, i, j) {
90
165
  }
91
166
  let len = 0;
92
167
  while (i + len < arr.length) {
168
+ if (colItems[i + len].isSubtotal)
169
+ break;
93
170
  let same = true;
94
171
  for (let x = 0; x <= j; x++) {
95
172
  if (arr[i][x] !== arr[i + len][x]) {
@@ -243,7 +320,11 @@ function makeSubtotalRenderer(opts = {}) {
243
320
  const colKeys = pivotData.getColKeys();
244
321
  const grandTotalAggregator = pivotData.getAggregator([], []);
245
322
  const getAggregator = core.createSubtotalAggregatorGetter(pivotData);
246
- const rowKeysWithSubtotals = generateRowKeysWithSubtotals(rowKeys, rowAttrs.length);
323
+ const rowKeysWithSubtotals = generateRowKeysWithSubtotals(rowKeys, rowAttrs.length, this.collapsedRowKeys);
324
+ const colKeysWithSubtotals = generateColKeysWithSubtotals(colKeys, colAttrs.length, this.collapsedColKeys);
325
+ const subtotalOpts = this.subtotalOptions;
326
+ const arrowCollapsed = subtotalOpts.arrowCollapsed || "▶";
327
+ const arrowExpanded = subtotalOpts.arrowExpanded || "▼";
247
328
  const getClickHandler = (value, rowValues, colValues) => {
248
329
  if (this.tableOptions && this.tableOptions.clickCallback) {
249
330
  const filters = {};
@@ -270,25 +351,62 @@ function makeSubtotalRenderer(opts = {}) {
270
351
  attrs: {
271
352
  colSpan: rowAttrs.length,
272
353
  rowSpan: colAttrs.length
273
- },
274
- style: {
275
- backgroundColor: "#f5f5f5"
276
354
  }
277
355
  }));
278
356
  }
279
357
  cells.push(h("th", { class: "pvtAxisLabel" }, c));
280
- colKeys.forEach((colKey, i) => {
281
- const colSpan = colSpanSize(colKeys, i, j);
282
- if (colSpan !== -1) {
283
- const label = this.applyLabel(colAttrs[j], colKey[j]);
284
- cells.push(h("th", {
285
- class: "pvtColLabel",
286
- key: `colKey${i}-${j}`,
287
- attrs: {
288
- colSpan,
289
- rowSpan: j === colAttrs.length - 1 && rowAttrs.length !== 0 ? 2 : 1
358
+ colKeysWithSubtotals.forEach((colItem, i) => {
359
+ const { key: colKey, isSubtotal, level } = colItem;
360
+ if (j < colKey.length) {
361
+ const colSpan = colSpanSizeWithSubtotals(colKeysWithSubtotals, i, j);
362
+ if (colSpan !== -1) {
363
+ const isLastAttrRow = j === colKey.length - 1;
364
+ if (isSubtotal && isLastAttrRow) {
365
+ const keyStr = JSON.stringify(colKey);
366
+ const isCollapsed = this.collapsedColKeys.has(keyStr);
367
+ const arrow = isCollapsed ? arrowCollapsed : arrowExpanded;
368
+ const label = `${colKey[j]} Subtotal`;
369
+ cells.push(h("th", {
370
+ class: "pvtColLabel pvtColSubtotalLabel",
371
+ key: `colKey${i}-${j}`,
372
+ attrs: {
373
+ colSpan,
374
+ rowSpan: colAttrs.length - j + (rowAttrs.length !== 0 ? 1 : 0)
375
+ },
376
+ style: {
377
+ fontWeight: "bold",
378
+ backgroundColor: "#f0f0f0"
379
+ }
380
+ }, [
381
+ h("span", {
382
+ class: "pvtColCollapseToggle",
383
+ style: {
384
+ cursor: "pointer",
385
+ marginRight: "4px",
386
+ userSelect: "none"
387
+ },
388
+ on: {
389
+ click: (e) => {
390
+ e.stopPropagation();
391
+ this.toggleColCollapse(keyStr);
392
+ }
393
+ }
394
+ }, arrow),
395
+ label
396
+ ]));
397
+ } else {
398
+ const label = this.applyLabel(colAttrs[j], colKey[j]);
399
+ const rowSpan = isLastAttrRow && rowAttrs.length !== 0 ? 2 : 1;
400
+ cells.push(h("th", {
401
+ class: "pvtColLabel",
402
+ key: `colKey${i}-${j}`,
403
+ attrs: {
404
+ colSpan,
405
+ rowSpan
406
+ }
407
+ }, label));
290
408
  }
291
- }, label));
409
+ }
292
410
  }
293
411
  });
294
412
  if (j === 0 && this.rowTotal) {
@@ -306,6 +424,9 @@ function makeSubtotalRenderer(opts = {}) {
306
424
  class: "pvtAxisLabel",
307
425
  key: `rowAttr${i}`
308
426
  }, r));
427
+ if (colAttrs.length !== 0) {
428
+ cells.push(h("th"));
429
+ }
309
430
  if (colAttrs.length === 0 && this.rowTotal) {
310
431
  cells.push(h("th", { class: "pvtTotalLabel" }, this.localeStrings.totals));
311
432
  }
@@ -319,6 +440,9 @@ function makeSubtotalRenderer(opts = {}) {
319
440
  const { key: rowKey, isSubtotal, level, subtotalLabel } = rowItem;
320
441
  const cells = [];
321
442
  if (isSubtotal) {
443
+ const keyStr = JSON.stringify(rowKey);
444
+ const isCollapsed = this.collapsedRowKeys.has(keyStr);
445
+ const arrow = isCollapsed ? arrowCollapsed : arrowExpanded;
322
446
  const subtotalText = subtotalLabel || `${rowKey[rowKey.length - 1]} Subtotal`;
323
447
  cells.push(h("th", {
324
448
  class: "pvtRowLabel pvtSubtotalLabel",
@@ -329,18 +453,36 @@ function makeSubtotalRenderer(opts = {}) {
329
453
  fontWeight: "bold",
330
454
  backgroundColor: "#f0f0f0"
331
455
  }
332
- }, subtotalText));
333
- colKeys.forEach((colKey, j) => {
456
+ }, [
457
+ h("span", {
458
+ class: "pvtCollapseToggle",
459
+ style: {
460
+ cursor: "pointer",
461
+ marginRight: "6px",
462
+ userSelect: "none"
463
+ },
464
+ on: {
465
+ click: (e) => {
466
+ e.stopPropagation();
467
+ this.toggleRowCollapse(keyStr);
468
+ }
469
+ }
470
+ }, arrow),
471
+ subtotalText
472
+ ]));
473
+ colKeysWithSubtotals.forEach((colItem, j) => {
474
+ const { key: colKey, isSubtotal: isColSubtotal } = colItem;
334
475
  const aggregator = getAggregator(rowKey, colKey);
335
476
  const val = aggregator.value();
336
477
  const formattedVal = aggregator.format ? aggregator.format(val) : val;
337
478
  const clickHandler = getClickHandler(val, rowKey, colKey);
479
+ const isDoubleSubtotal = isColSubtotal;
338
480
  cells.push(h("td", {
339
- class: "pvtVal pvtSubtotalVal",
481
+ class: isColSubtotal ? "pvtVal pvtSubtotalVal pvtColSubtotalVal" : "pvtVal pvtSubtotalVal",
340
482
  key: `subtotal-val${i}-${j}`,
341
483
  style: {
342
484
  fontWeight: "bold",
343
- backgroundColor: "#f0f0f0"
485
+ backgroundColor: isDoubleSubtotal ? "#e0e0e0" : "#f0f0f0"
344
486
  },
345
487
  on: clickHandler ? { click: clickHandler } : {}
346
488
  }, formattedVal));
@@ -378,14 +520,19 @@ function makeSubtotalRenderer(opts = {}) {
378
520
  }, label));
379
521
  }
380
522
  });
381
- colKeys.forEach((colKey, j) => {
523
+ colKeysWithSubtotals.forEach((colItem, j) => {
524
+ const { key: colKey, isSubtotal: isColSubtotal } = colItem;
382
525
  const aggregator = getAggregator(rowKey, colKey);
383
526
  const val = aggregator.value();
384
527
  const formattedVal = aggregator.format ? aggregator.format(val) : val;
385
528
  const clickHandler = getClickHandler(val, rowKey, colKey);
386
529
  cells.push(h("td", {
387
- class: "pvtVal",
530
+ class: isColSubtotal ? "pvtVal pvtColSubtotalVal" : "pvtVal",
388
531
  key: `val${i}-${j}`,
532
+ style: isColSubtotal ? {
533
+ fontWeight: "bold",
534
+ backgroundColor: "#f0f0f0"
535
+ } : void 0,
389
536
  on: clickHandler ? { click: clickHandler } : {}
390
537
  }, formattedVal));
391
538
  });
@@ -410,14 +557,19 @@ function makeSubtotalRenderer(opts = {}) {
410
557
  colSpan: rowAttrs.length + (colAttrs.length === 0 ? 0 : 1)
411
558
  }
412
559
  }, this.localeStrings.totals));
413
- colKeys.forEach((colKey, i) => {
560
+ colKeysWithSubtotals.forEach((colItem, i) => {
561
+ const { key: colKey, isSubtotal: isColSubtotal } = colItem;
414
562
  const totalAggregator = getAggregator([], colKey);
415
563
  const totalVal = totalAggregator.value();
416
564
  const formattedTotal = totalAggregator.format ? totalAggregator.format(totalVal) : totalVal;
417
565
  const clickHandler = getClickHandler(totalVal, [], colKey);
418
566
  cells.push(h("td", {
419
- class: "pvtTotal",
567
+ class: isColSubtotal ? "pvtTotal pvtColSubtotalTotal" : "pvtTotal",
420
568
  key: `colTotal${i}`,
569
+ style: isColSubtotal ? {
570
+ fontWeight: "bold",
571
+ backgroundColor: "#e0e0e0"
572
+ } : void 0,
421
573
  on: clickHandler ? { click: clickHandler } : {}
422
574
  }, formattedTotal));
423
575
  });