@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/README.md CHANGED
@@ -8,19 +8,19 @@ Supports both **Vue 2** and **Vue 3**.
8
8
 
9
9
  ### Vue 3 - Subtotal Table
10
10
 
11
- ![Vue 3 Example](docs/screenshot-vue3.png)
11
+ ![Vue 3 Example](examples/screenshot-vue3.png)
12
12
 
13
13
  ### Vue 3 - With UI
14
14
 
15
- ![Vue 3 UI Example](docs/screenshot-vue3-ui.png)
15
+ ![Vue 3 UI Example](examples/screenshot-vue3-ui.png)
16
16
 
17
17
  ### Vue 2 - Subtotal Table
18
18
 
19
- ![Vue 2 Example](docs/screenshot-vue2.png)
19
+ ![Vue 2 Example](examples/screenshot-vue2.png)
20
20
 
21
21
  ### Vue 2 - With UI
22
22
 
23
- ![Vue 2 UI Example](docs/screenshot-vue2-ui.png)
23
+ ![Vue 2 UI Example](examples/screenshot-vue2-ui.png)
24
24
 
25
25
  ## Features
26
26
 
@@ -275,12 +275,12 @@ cd vue3-pivottable/subtotal-renderer
275
275
  npm install
276
276
 
277
277
  # Run Vue 3 example
278
- cd example/vue3
278
+ cd examples/vue3
279
279
  npm install
280
280
  npm run dev
281
281
 
282
282
  # Run Vue 2 example (in another terminal)
283
- cd example/vue2
283
+ cd examples/vue2
284
284
  npm install
285
285
  npm run dev
286
286
  ```
package/dist/core.js CHANGED
@@ -22,19 +22,30 @@ function generateRowKeysWithSubtotals(rowKeys, rowAttrsCount, collapsedKeys = /*
22
22
  const subtotalKeyStr = JSON.stringify(subtotalKey);
23
23
  if (!addedSubtotals.has(subtotalKeyStr)) {
24
24
  addedSubtotals.add(subtotalKeyStr);
25
- const isCollapsed = collapsedKeys.has(subtotalKeyStr);
26
- result.push({
27
- key: subtotalKey,
28
- isSubtotal: true,
29
- level,
30
- isCollapsed
31
- });
25
+ let subtotalHidden = false;
26
+ for (let parentLevel = 1; parentLevel < level; parentLevel++) {
27
+ const parentKey = subtotalKey.slice(0, parentLevel);
28
+ if (collapsedKeys.has(JSON.stringify(parentKey))) {
29
+ subtotalHidden = true;
30
+ break;
31
+ }
32
+ }
33
+ if (!subtotalHidden) {
34
+ const isCollapsed = collapsedKeys.has(subtotalKeyStr);
35
+ result.push({
36
+ key: subtotalKey,
37
+ isSubtotal: true,
38
+ level,
39
+ isCollapsed
40
+ });
41
+ }
32
42
  }
33
43
  }
34
44
  let isHidden = false;
35
45
  for (let level = 1; level < rowKey.length; level++) {
36
46
  const parentKey = rowKey.slice(0, level);
37
- if (collapsedKeys.has(JSON.stringify(parentKey))) {
47
+ const parentKeyStr = JSON.stringify(parentKey);
48
+ if (collapsedKeys.has(parentKeyStr)) {
38
49
  isHidden = true;
39
50
  break;
40
51
  }
package/dist/core.mjs CHANGED
@@ -20,19 +20,30 @@ function generateRowKeysWithSubtotals(rowKeys, rowAttrsCount, collapsedKeys = /*
20
20
  const subtotalKeyStr = JSON.stringify(subtotalKey);
21
21
  if (!addedSubtotals.has(subtotalKeyStr)) {
22
22
  addedSubtotals.add(subtotalKeyStr);
23
- const isCollapsed = collapsedKeys.has(subtotalKeyStr);
24
- result.push({
25
- key: subtotalKey,
26
- isSubtotal: true,
27
- level,
28
- isCollapsed
29
- });
23
+ let subtotalHidden = false;
24
+ for (let parentLevel = 1; parentLevel < level; parentLevel++) {
25
+ const parentKey = subtotalKey.slice(0, parentLevel);
26
+ if (collapsedKeys.has(JSON.stringify(parentKey))) {
27
+ subtotalHidden = true;
28
+ break;
29
+ }
30
+ }
31
+ if (!subtotalHidden) {
32
+ const isCollapsed = collapsedKeys.has(subtotalKeyStr);
33
+ result.push({
34
+ key: subtotalKey,
35
+ isSubtotal: true,
36
+ level,
37
+ isCollapsed
38
+ });
39
+ }
30
40
  }
31
41
  }
32
42
  let isHidden = false;
33
43
  for (let level = 1; level < rowKey.length; level++) {
34
44
  const parentKey = rowKey.slice(0, level);
35
- if (collapsedKeys.has(JSON.stringify(parentKey))) {
45
+ const parentKeyStr = JSON.stringify(parentKey);
46
+ if (collapsedKeys.has(parentKeyStr)) {
36
47
  isHidden = true;
37
48
  break;
38
49
  }
package/dist/index.js CHANGED
@@ -17,28 +17,52 @@ function createSubtotalRenderers(PivotData) {
17
17
  "Subtotal Table": makeSubtotalRenderer({ name: "vue-subtotal-table" })
18
18
  };
19
19
  }
20
- function generateRowKeysWithSubtotals(rowKeys, depth) {
20
+ function generateRowKeysWithSubtotals(rowKeys, depth, collapsedKeys = /* @__PURE__ */ new Set()) {
21
21
  if (depth <= 1) {
22
22
  return rowKeys.map((key) => ({ key, isSubtotal: false, level: key.length }));
23
23
  }
24
24
  const result = [];
25
+ const addedSubtotals = /* @__PURE__ */ new Set();
25
26
  for (let i = 0; i < rowKeys.length; i++) {
26
27
  const rowKey = rowKeys[i];
27
- const nextRowKey = rowKeys[i + 1];
28
- result.push({ key: rowKey, isSubtotal: false, level: rowKey.length });
29
- for (let level = depth - 1; level >= 1; level--) {
30
- const currentPrefix = rowKey.slice(0, level);
31
- const nextPrefix = nextRowKey ? nextRowKey.slice(0, level) : null;
32
- const levelChanges = !nextPrefix || JSON.stringify(currentPrefix) !== JSON.stringify(nextPrefix);
33
- if (levelChanges) {
34
- result.push({
35
- key: currentPrefix,
36
- isSubtotal: true,
37
- level,
38
- subtotalLabel: `${currentPrefix[level - 1]} Subtotal`
39
- });
28
+ rowKeys[i + 1];
29
+ let isHidden = false;
30
+ for (let level = 1; level < rowKey.length; level++) {
31
+ const parentKey = rowKey.slice(0, level);
32
+ const parentKeyStr = JSON.stringify(parentKey);
33
+ if (collapsedKeys.has(parentKeyStr)) {
34
+ isHidden = true;
35
+ break;
36
+ }
37
+ }
38
+ for (let level = 1; level < rowKey.length; level++) {
39
+ const subtotalKey = rowKey.slice(0, level);
40
+ const subtotalKeyStr = JSON.stringify(subtotalKey);
41
+ if (!addedSubtotals.has(subtotalKeyStr)) {
42
+ addedSubtotals.add(subtotalKeyStr);
43
+ let subtotalHidden = false;
44
+ for (let parentLevel = 1; parentLevel < level; parentLevel++) {
45
+ const parentKey = subtotalKey.slice(0, parentLevel);
46
+ if (collapsedKeys.has(JSON.stringify(parentKey))) {
47
+ subtotalHidden = true;
48
+ break;
49
+ }
50
+ }
51
+ if (!subtotalHidden) {
52
+ const isCollapsed = collapsedKeys.has(subtotalKeyStr);
53
+ result.push({
54
+ key: subtotalKey,
55
+ isSubtotal: true,
56
+ level,
57
+ subtotalLabel: `${subtotalKey[level - 1]} Subtotal`,
58
+ isCollapsed
59
+ });
60
+ }
40
61
  }
41
62
  }
63
+ if (!isHidden) {
64
+ result.push({ key: rowKey, isSubtotal: false, level: rowKey.length });
65
+ }
42
66
  }
43
67
  return result;
44
68
  }
@@ -76,8 +100,60 @@ function spanSize(rowItems, i, j) {
76
100
  }
77
101
  return len;
78
102
  }
79
- function colSpanSize(arr, i, j) {
80
- if (i !== 0) {
103
+ function generateColKeysWithSubtotals(colKeys, depth, collapsedKeys = /* @__PURE__ */ new Set()) {
104
+ if (depth <= 1) {
105
+ return colKeys.map((key) => ({ key, isSubtotal: false, level: key.length }));
106
+ }
107
+ const result = [];
108
+ const addedSubtotals = /* @__PURE__ */ new Set();
109
+ for (let i = 0; i < colKeys.length; i++) {
110
+ const colKey = colKeys[i];
111
+ let isHidden = false;
112
+ for (let level = 1; level < colKey.length; level++) {
113
+ const parentKey = colKey.slice(0, level);
114
+ const parentKeyStr = JSON.stringify(parentKey);
115
+ if (collapsedKeys.has(parentKeyStr)) {
116
+ isHidden = true;
117
+ break;
118
+ }
119
+ }
120
+ for (let level = 1; level < colKey.length; level++) {
121
+ const subtotalKey = colKey.slice(0, level);
122
+ const subtotalKeyStr = JSON.stringify(subtotalKey);
123
+ if (!addedSubtotals.has(subtotalKeyStr)) {
124
+ addedSubtotals.add(subtotalKeyStr);
125
+ let subtotalHidden = false;
126
+ for (let parentLevel = 1; parentLevel < level; parentLevel++) {
127
+ const parentKey = subtotalKey.slice(0, parentLevel);
128
+ if (collapsedKeys.has(JSON.stringify(parentKey))) {
129
+ subtotalHidden = true;
130
+ break;
131
+ }
132
+ }
133
+ if (!subtotalHidden) {
134
+ const isCollapsed = collapsedKeys.has(subtotalKeyStr);
135
+ result.push({
136
+ key: subtotalKey,
137
+ isSubtotal: true,
138
+ level,
139
+ subtotalLabel: `${subtotalKey[level - 1]} Subtotal`,
140
+ isCollapsed
141
+ });
142
+ }
143
+ }
144
+ }
145
+ if (!isHidden) {
146
+ result.push({ key: colKey, isSubtotal: false, level: colKey.length });
147
+ }
148
+ }
149
+ return result;
150
+ }
151
+ function colSpanSizeWithSubtotals(colItems, i, j) {
152
+ if (colItems[i].isSubtotal) {
153
+ return 1;
154
+ }
155
+ const arr = colItems.map((item) => item.key);
156
+ if (i !== 0 && !colItems[i - 1].isSubtotal) {
81
157
  let asPrevious = true;
82
158
  for (let x = 0; x <= j; x++) {
83
159
  if (arr[i - 1][x] !== arr[i][x]) {
@@ -91,6 +167,8 @@ function colSpanSize(arr, i, j) {
91
167
  }
92
168
  let len = 0;
93
169
  while (i + len < arr.length) {
170
+ if (colItems[i + len].isSubtotal)
171
+ break;
94
172
  let same = true;
95
173
  for (let x = 0; x <= j; x++) {
96
174
  if (arr[i][x] !== arr[i + len][x]) {
@@ -242,10 +320,11 @@ function makeSubtotalRenderer(opts = {}) {
242
320
  const colKeys = pivotData.getColKeys();
243
321
  const grandTotalAggregator = pivotData.getAggregator([], []);
244
322
  const getAggregator = core.createSubtotalAggregatorGetter(pivotData);
245
- const rowKeysWithSubtotals = generateRowKeysWithSubtotals(rowKeys, rowAttrs.length);
323
+ const rowKeysWithSubtotals = generateRowKeysWithSubtotals(rowKeys, rowAttrs.length, state.collapsedRowKeys);
324
+ const colKeysWithSubtotals = generateColKeysWithSubtotals(colKeys, colAttrs.length, state.collapsedColKeys);
246
325
  const subtotalOpts = this.subtotalOptions;
247
- subtotalOpts.arrowCollapsed || "▶";
248
- subtotalOpts.arrowExpanded || "▼";
326
+ const arrowCollapsed = subtotalOpts.arrowCollapsed || "▶";
327
+ const arrowExpanded = subtotalOpts.arrowExpanded || "▼";
249
328
  const getClickHandler = (value, rowValues, colValues) => {
250
329
  var _a;
251
330
  if ((_a = this.tableOptions) == null ? void 0 : _a.clickCallback) {
@@ -271,23 +350,56 @@ function makeSubtotalRenderer(opts = {}) {
271
350
  if (j === 0 && rowAttrs.length !== 0) {
272
351
  cells.push(vue.h("th", {
273
352
  colSpan: rowAttrs.length,
274
- rowSpan: colAttrs.length,
275
- style: {
276
- backgroundColor: "#f5f5f5"
277
- }
353
+ rowSpan: colAttrs.length
278
354
  }));
279
355
  }
280
356
  cells.push(vue.h("th", { class: "pvtAxisLabel" }, c));
281
- colKeys.forEach((colKey, i) => {
282
- const colSpan = colSpanSize(colKeys, i, j);
283
- if (colSpan !== -1) {
284
- const label = applyLabel(colAttrs[j], colKey[j]);
285
- cells.push(vue.h("th", {
286
- class: "pvtColLabel",
287
- key: `colKey${i}-${j}`,
288
- colSpan,
289
- rowSpan: j === colAttrs.length - 1 && rowAttrs.length !== 0 ? 2 : 1
290
- }, label));
357
+ colKeysWithSubtotals.forEach((colItem, i) => {
358
+ const { key: colKey, isSubtotal, level } = colItem;
359
+ if (j < colKey.length) {
360
+ const colSpan = colSpanSizeWithSubtotals(colKeysWithSubtotals, i, j);
361
+ if (colSpan !== -1) {
362
+ const isLastAttrRow = j === colKey.length - 1;
363
+ if (isSubtotal && isLastAttrRow) {
364
+ const keyStr = JSON.stringify(colKey);
365
+ const isCollapsed = state.collapsedColKeys.has(keyStr);
366
+ const arrow = isCollapsed ? arrowCollapsed : arrowExpanded;
367
+ const label = `${colKey[j]} Subtotal`;
368
+ cells.push(vue.h("th", {
369
+ class: "pvtColLabel pvtColSubtotalLabel",
370
+ key: `colKey${i}-${j}`,
371
+ colSpan,
372
+ rowSpan: colAttrs.length - j + (rowAttrs.length !== 0 ? 1 : 0),
373
+ style: {
374
+ fontWeight: "bold",
375
+ backgroundColor: "#f0f0f0"
376
+ }
377
+ }, [
378
+ vue.h("span", {
379
+ class: "pvtColCollapseToggle",
380
+ style: {
381
+ cursor: "pointer",
382
+ marginRight: "4px",
383
+ userSelect: "none"
384
+ },
385
+ onClick: (e) => {
386
+ e.stopPropagation();
387
+ toggleColCollapse(keyStr);
388
+ }
389
+ }, arrow),
390
+ label
391
+ ]));
392
+ } else {
393
+ const label = applyLabel(colAttrs[j], colKey[j]);
394
+ const rowSpan = isLastAttrRow && rowAttrs.length !== 0 ? 2 : 1;
395
+ cells.push(vue.h("th", {
396
+ class: "pvtColLabel",
397
+ key: `colKey${i}-${j}`,
398
+ colSpan,
399
+ rowSpan
400
+ }, label));
401
+ }
402
+ }
291
403
  }
292
404
  });
293
405
  if (j === 0 && this.rowTotal) {
@@ -303,6 +415,9 @@ function makeSubtotalRenderer(opts = {}) {
303
415
  class: "pvtAxisLabel",
304
416
  key: `rowAttr${i}`
305
417
  }, r));
418
+ if (colAttrs.length !== 0) {
419
+ cells.push(vue.h("th"));
420
+ }
306
421
  if (colAttrs.length === 0 && this.rowTotal) {
307
422
  cells.push(vue.h("th", { class: "pvtTotalLabel" }, this.localeStrings.totals));
308
423
  }
@@ -316,6 +431,9 @@ function makeSubtotalRenderer(opts = {}) {
316
431
  const { key: rowKey, isSubtotal, level, subtotalLabel } = rowItem;
317
432
  const cells = [];
318
433
  if (isSubtotal) {
434
+ const keyStr = JSON.stringify(rowKey);
435
+ const isCollapsed = state.collapsedRowKeys.has(keyStr);
436
+ const arrow = isCollapsed ? arrowCollapsed : arrowExpanded;
319
437
  const subtotalText = subtotalLabel || `${rowKey[rowKey.length - 1]} Subtotal`;
320
438
  cells.push(vue.h("th", {
321
439
  class: "pvtRowLabel pvtSubtotalLabel",
@@ -324,18 +442,34 @@ function makeSubtotalRenderer(opts = {}) {
324
442
  fontWeight: "bold",
325
443
  backgroundColor: "#f0f0f0"
326
444
  }
327
- }, subtotalText));
328
- colKeys.forEach((colKey, j) => {
445
+ }, [
446
+ vue.h("span", {
447
+ class: "pvtCollapseToggle",
448
+ style: {
449
+ cursor: "pointer",
450
+ marginRight: "6px",
451
+ userSelect: "none"
452
+ },
453
+ onClick: (e) => {
454
+ e.stopPropagation();
455
+ toggleRowCollapse(keyStr);
456
+ }
457
+ }, arrow),
458
+ subtotalText
459
+ ]));
460
+ colKeysWithSubtotals.forEach((colItem, j) => {
461
+ const { key: colKey, isSubtotal: isColSubtotal } = colItem;
329
462
  const aggregator = getAggregator(rowKey, colKey);
330
463
  const val = aggregator.value();
331
464
  const formattedVal = aggregator.format ? aggregator.format(val) : val;
332
465
  const clickHandler = getClickHandler(val, rowKey, colKey);
466
+ const isDoubleSubtotal = isColSubtotal;
333
467
  cells.push(vue.h("td", {
334
- class: "pvtVal pvtSubtotalVal",
468
+ class: isColSubtotal ? "pvtVal pvtSubtotalVal pvtColSubtotalVal" : "pvtVal pvtSubtotalVal",
335
469
  key: `subtotal-val${i}-${j}`,
336
470
  style: {
337
471
  fontWeight: "bold",
338
- backgroundColor: "#f0f0f0"
472
+ backgroundColor: isDoubleSubtotal ? "#e0e0e0" : "#f0f0f0"
339
473
  },
340
474
  onClick: clickHandler || void 0
341
475
  }, formattedVal));
@@ -371,14 +505,19 @@ function makeSubtotalRenderer(opts = {}) {
371
505
  }, label));
372
506
  }
373
507
  });
374
- colKeys.forEach((colKey, j) => {
508
+ colKeysWithSubtotals.forEach((colItem, j) => {
509
+ const { key: colKey, isSubtotal: isColSubtotal } = colItem;
375
510
  const aggregator = getAggregator(rowKey, colKey);
376
511
  const val = aggregator.value();
377
512
  const formattedVal = aggregator.format ? aggregator.format(val) : val;
378
513
  const clickHandler = getClickHandler(val, rowKey, colKey);
379
514
  cells.push(vue.h("td", {
380
- class: "pvtVal",
515
+ class: isColSubtotal ? "pvtVal pvtColSubtotalVal" : "pvtVal",
381
516
  key: `val${i}-${j}`,
517
+ style: isColSubtotal ? {
518
+ fontWeight: "bold",
519
+ backgroundColor: "#f0f0f0"
520
+ } : void 0,
382
521
  onClick: clickHandler || void 0
383
522
  }, formattedVal));
384
523
  });
@@ -401,14 +540,19 @@ function makeSubtotalRenderer(opts = {}) {
401
540
  class: "pvtTotalLabel",
402
541
  colSpan: rowAttrs.length + (colAttrs.length === 0 ? 0 : 1)
403
542
  }, this.localeStrings.totals));
404
- colKeys.forEach((colKey, i) => {
543
+ colKeysWithSubtotals.forEach((colItem, i) => {
544
+ const { key: colKey, isSubtotal: isColSubtotal } = colItem;
405
545
  const totalAggregator = getAggregator([], colKey);
406
546
  const totalVal = totalAggregator.value();
407
547
  const formattedTotal = totalAggregator.format ? totalAggregator.format(totalVal) : totalVal;
408
548
  const clickHandler = getClickHandler(totalVal, [], colKey);
409
549
  cells.push(vue.h("td", {
410
- class: "pvtTotal",
550
+ class: isColSubtotal ? "pvtTotal pvtColSubtotalTotal" : "pvtTotal",
411
551
  key: `colTotal${i}`,
552
+ style: isColSubtotal ? {
553
+ fontWeight: "bold",
554
+ backgroundColor: "#e0e0e0"
555
+ } : void 0,
412
556
  onClick: clickHandler || void 0
413
557
  }, formattedTotal));
414
558
  });