@vue-pivottable/multi-value-renderer 0.2.2 → 0.3.0-beta.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.
@@ -1,364 +0,0 @@
1
- "use strict";
2
- const vue = require("vue");
3
- const vuePivottable = require("vue-pivottable");
4
- const MultiValuePivotData = require("./MultiValuePivotData.js");
5
- const { PivotData } = vuePivottable.PivotUtilities;
6
- function redColorScaleGenerator(values) {
7
- const numericValues = values.filter((v) => typeof v === "number" && !isNaN(v));
8
- if (numericValues.length === 0) {
9
- return () => ({});
10
- }
11
- const min = Math.min(...numericValues);
12
- const max = Math.max(...numericValues);
13
- return (x) => {
14
- if (typeof x !== "number" || isNaN(x) || max === min) {
15
- return {};
16
- }
17
- const nonRed = 255 - Math.round(255 * (x - min) / (max - min));
18
- return { backgroundColor: `rgb(255,${nonRed},${nonRed})` };
19
- };
20
- }
21
- function makeMultiValueRenderer(opts = {}) {
22
- return vue.defineComponent({
23
- name: opts.name || "vue3-multi-value-table",
24
- props: {
25
- // Data props
26
- data: {
27
- type: [Array, Object, Function],
28
- required: true
29
- },
30
- rows: {
31
- type: Array,
32
- default: () => []
33
- },
34
- cols: {
35
- type: Array,
36
- default: () => []
37
- },
38
- vals: {
39
- type: Array,
40
- default: () => []
41
- },
42
- // Multi-value specific props
43
- aggregatorMap: {
44
- type: Object,
45
- default: () => ({})
46
- },
47
- aggregators: {
48
- type: Object,
49
- required: true
50
- },
51
- // Filter and sort props
52
- valueFilter: {
53
- type: Object,
54
- default: () => ({})
55
- },
56
- sorters: {
57
- type: [Object, Function],
58
- default: () => ({})
59
- },
60
- derivedAttributes: {
61
- type: [Object, Function],
62
- default: () => ({})
63
- },
64
- rowOrder: {
65
- type: String,
66
- default: "key_a_to_z"
67
- },
68
- colOrder: {
69
- type: String,
70
- default: "key_a_to_z"
71
- },
72
- // Display props
73
- rowTotal: {
74
- type: Boolean,
75
- default: true
76
- },
77
- colTotal: {
78
- type: Boolean,
79
- default: true
80
- },
81
- tableColorScaleGenerator: {
82
- type: Function,
83
- default: () => redColorScaleGenerator
84
- },
85
- tableOptions: {
86
- type: Object,
87
- default: () => ({})
88
- },
89
- localeStrings: {
90
- type: Object,
91
- default: () => ({ totals: "Totals" })
92
- },
93
- labels: {
94
- type: Object,
95
- default: () => ({})
96
- },
97
- // Multi-value display options
98
- cellLayout: {
99
- type: String,
100
- default: "vertical",
101
- validator: (v) => ["vertical", "horizontal", "compact"].includes(v)
102
- },
103
- showValueLabels: {
104
- type: Boolean,
105
- default: true
106
- },
107
- valueLabels: {
108
- type: Object,
109
- default: () => ({})
110
- }
111
- },
112
- setup(props) {
113
- const applyLabel = (attr, value) => {
114
- if (props.labels && typeof props.labels[attr] === "function") {
115
- return props.labels[attr](value);
116
- }
117
- return value;
118
- };
119
- const getValueLabel = (valName) => {
120
- if (props.valueLabels && props.valueLabels[valName]) {
121
- return props.valueLabels[valName];
122
- }
123
- return valName;
124
- };
125
- const spanSize = (arr, i, j) => {
126
- let x;
127
- if (i !== 0) {
128
- let noDraw = true;
129
- for (x = 0; x <= j; x++) {
130
- if (arr[i - 1][x] !== arr[i][x]) {
131
- noDraw = false;
132
- }
133
- }
134
- if (noDraw) return -1;
135
- }
136
- let len = 0;
137
- while (i + len < arr.length) {
138
- let stop = false;
139
- for (x = 0; x <= j; x++) {
140
- if (arr[i][x] !== arr[i + len][x]) {
141
- stop = true;
142
- }
143
- }
144
- if (stop) break;
145
- len++;
146
- }
147
- return len;
148
- };
149
- const formatValue = (valName, value) => {
150
- const aggName = props.aggregatorMap[valName] || "Sum";
151
- const agg = props.aggregators[aggName];
152
- if (agg) {
153
- try {
154
- const instance = agg([valName])();
155
- if (instance && instance.format) {
156
- return instance.format(value);
157
- }
158
- } catch (e) {
159
- }
160
- }
161
- if (value === null || value === void 0) return "";
162
- if (typeof value === "number") {
163
- return value.toLocaleString();
164
- }
165
- return String(value);
166
- };
167
- const renderMultiValueCell = (values) => {
168
- if (!values || typeof values !== "object") {
169
- return String(values || "");
170
- }
171
- const items = props.vals.map((val) => {
172
- const value = values[val];
173
- const formatted = formatValue(val, value);
174
- const label = getValueLabel(val);
175
- const aggName = props.aggregatorMap[val] || "Sum";
176
- if (props.cellLayout === "compact") {
177
- return formatted;
178
- }
179
- return vue.h("div", {
180
- class: "multi-value-item",
181
- key: val,
182
- "data-value": val,
183
- "data-aggregator": aggName
184
- }, [
185
- props.showValueLabels ? vue.h("span", { class: "multi-value-label" }, `${label}: `) : null,
186
- vue.h("span", { class: "multi-value-value" }, formatted)
187
- ]);
188
- });
189
- if (props.cellLayout === "compact") {
190
- return items.join(" / ");
191
- }
192
- return vue.h("div", {
193
- class: ["multi-value-cell", `layout-${props.cellLayout}`]
194
- }, items);
195
- };
196
- const createPivotData = () => {
197
- const multiValueAgg = MultiValuePivotData.createMultiValueAggregator(
198
- props.aggregatorMap,
199
- props.aggregators,
200
- props.vals
201
- );
202
- const modifiedAggregators = {
203
- ...props.aggregators,
204
- "Multi-Value": () => multiValueAgg
205
- };
206
- return new PivotData({
207
- data: props.data,
208
- rows: props.rows,
209
- cols: props.cols,
210
- vals: props.vals,
211
- aggregators: modifiedAggregators,
212
- aggregatorName: "Multi-Value",
213
- valueFilter: props.valueFilter,
214
- sorters: props.sorters,
215
- derivedAttributes: props.derivedAttributes,
216
- rowOrder: props.rowOrder,
217
- colOrder: props.colOrder
218
- });
219
- };
220
- return {
221
- applyLabel,
222
- getValueLabel,
223
- spanSize,
224
- formatValue,
225
- renderMultiValueCell,
226
- createPivotData
227
- };
228
- },
229
- render() {
230
- let pivotData;
231
- try {
232
- pivotData = this.createPivotData();
233
- } catch (error) {
234
- console.error("Multi-Value Renderer Error:", error);
235
- return vue.h("div", { class: "pvtError" }, `Error: ${error.message}`);
236
- }
237
- const colAttrs = pivotData.props.cols;
238
- const rowAttrs = pivotData.props.rows;
239
- const rowKeys = pivotData.getRowKeys();
240
- const colKeys = pivotData.getColKeys();
241
- const grandTotalAggregator = pivotData.getAggregator([], []);
242
- const getClickHandler = (value, rowValues, colValues) => {
243
- var _a;
244
- if ((_a = this.tableOptions) == null ? void 0 : _a.clickCallback) {
245
- const filters = {};
246
- colAttrs.forEach((attr, i) => {
247
- if (colValues[i] !== null) {
248
- filters[attr] = colValues[i];
249
- }
250
- });
251
- rowAttrs.forEach((attr, i) => {
252
- if (rowValues[i] !== null) {
253
- filters[attr] = rowValues[i];
254
- }
255
- });
256
- return (e) => this.tableOptions.clickCallback(e, value, filters, pivotData);
257
- }
258
- return null;
259
- };
260
- return vue.h("table", { class: ["pvtTable", "pvtMultiValueTable"] }, [
261
- // THEAD
262
- vue.h("thead", [
263
- // Column attribute headers
264
- ...colAttrs.map((c, j) => {
265
- return vue.h("tr", { key: `colAttrs${j}` }, [
266
- // Top-left corner cell
267
- j === 0 && rowAttrs.length !== 0 ? vue.h("th", { colSpan: rowAttrs.length, rowSpan: colAttrs.length }) : void 0,
268
- // Column attribute label
269
- vue.h("th", { class: "pvtAxisLabel" }, c),
270
- // Column keys
271
- ...colKeys.map((colKey, i) => {
272
- const x = this.spanSize(colKeys, i, j);
273
- if (x === -1) return null;
274
- return vue.h("th", {
275
- class: "pvtColLabel",
276
- key: `colKey${i}`,
277
- colSpan: x,
278
- rowSpan: j === colAttrs.length - 1 && rowAttrs.length !== 0 ? 2 : 1
279
- }, this.applyLabel(colAttrs[j], colKey[j]));
280
- }),
281
- // Totals header
282
- j === 0 && this.rowTotal ? vue.h("th", {
283
- class: "pvtTotalLabel",
284
- rowSpan: colAttrs.length + (rowAttrs.length === 0 ? 0 : 1)
285
- }, this.localeStrings.totals) : void 0
286
- ].filter(Boolean));
287
- }),
288
- // Row attribute labels row
289
- rowAttrs.length !== 0 ? vue.h("tr", [
290
- ...rowAttrs.map((r, i) => {
291
- return vue.h("th", { class: "pvtAxisLabel", key: `rowAttr${i}` }, r);
292
- }),
293
- this.rowTotal ? vue.h(
294
- "th",
295
- { class: "pvtTotalLabel" },
296
- colAttrs.length === 0 ? this.localeStrings.totals : null
297
- ) : colAttrs.length === 0 ? void 0 : vue.h("th")
298
- ].filter(Boolean)) : void 0
299
- ].filter(Boolean)),
300
- // TBODY
301
- vue.h("tbody", [
302
- // Data rows
303
- ...rowKeys.map((rowKey, i) => {
304
- const totalAggregator = pivotData.getAggregator(rowKey, []);
305
- return vue.h("tr", { key: `rowKeyRow${i}` }, [
306
- // Row labels
307
- ...rowKey.map((text, j) => {
308
- const x = this.spanSize(rowKeys, i, j);
309
- if (x === -1) return null;
310
- return vue.h("th", {
311
- class: "pvtRowLabel",
312
- key: `rowKeyLabel${i}-${j}`,
313
- rowSpan: x,
314
- colSpan: j === rowAttrs.length - 1 && colAttrs.length !== 0 ? 2 : 1
315
- }, this.applyLabel(rowAttrs[j], text));
316
- }),
317
- // Data cells
318
- ...colKeys.map((colKey, j) => {
319
- const aggregator = pivotData.getAggregator(rowKey, colKey);
320
- const value = aggregator.value();
321
- const clickHandler = getClickHandler(value, rowKey, colKey);
322
- return vue.h("td", {
323
- class: ["pvVal", "pvtMultiVal"],
324
- key: `pvtVal${i}-${j}`,
325
- onClick: clickHandler
326
- }, [this.renderMultiValueCell(value)]);
327
- }),
328
- // Row total
329
- this.rowTotal ? vue.h("td", {
330
- class: ["pvtTotal", "pvtMultiVal"],
331
- onClick: getClickHandler(totalAggregator.value(), rowKey, [])
332
- }, [this.renderMultiValueCell(totalAggregator.value())]) : void 0
333
- ].filter(Boolean));
334
- }),
335
- // Column totals row
336
- vue.h("tr", [
337
- this.colTotal ? vue.h("th", {
338
- class: "pvtTotalLabel",
339
- colSpan: rowAttrs.length + (colAttrs.length === 0 ? 0 : 1)
340
- }, this.localeStrings.totals) : void 0,
341
- ...this.colTotal ? colKeys.map((colKey, i) => {
342
- const totalAggregator = pivotData.getAggregator([], colKey);
343
- const clickHandler = getClickHandler(totalAggregator.value(), [], colKey);
344
- return vue.h("td", {
345
- class: ["pvtTotal", "pvtMultiVal"],
346
- key: `total${i}`,
347
- onClick: clickHandler
348
- }, [this.renderMultiValueCell(totalAggregator.value())]);
349
- }) : [],
350
- this.colTotal && this.rowTotal ? vue.h("td", {
351
- class: ["pvtGrandTotal", "pvtMultiVal"],
352
- onClick: getClickHandler(grandTotalAggregator.value(), [], [])
353
- }, [this.renderMultiValueCell(grandTotalAggregator.value())]) : void 0
354
- ].filter(Boolean))
355
- ])
356
- ]);
357
- }
358
- });
359
- }
360
- const MultiValueTableRenderer = vue.markRaw({
361
- "Multi-Value Table": makeMultiValueRenderer({ name: "vue3-multi-value-table" })
362
- });
363
- exports.MultiValueTableRenderer = MultiValueTableRenderer;
364
- exports.makeMultiValueRenderer = makeMultiValueRenderer;