@malloydata/render 0.0.60-dev230718174455 → 0.0.60
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/html/table.d.ts +4 -3
- package/dist/html/table.js +76 -31
- package/package.json +2 -2
package/dist/html/table.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DataColumn, Field } from '@malloydata/malloy';
|
|
1
|
+
import { DataColumn, Field, SortableField } from '@malloydata/malloy';
|
|
2
2
|
import { StyleDefaults } from '../data_styles';
|
|
3
3
|
import { ContainerRenderer } from './container';
|
|
4
4
|
import { Renderer } from '../renderer';
|
|
@@ -6,12 +6,13 @@ export declare class HTMLTableRenderer extends ContainerRenderer {
|
|
|
6
6
|
protected childrenStyleDefaults: StyleDefaults;
|
|
7
7
|
render(table: DataColumn): Promise<HTMLElement>;
|
|
8
8
|
calculatePivotDimensions(table: DataColumn): {
|
|
9
|
-
dimensions:
|
|
10
|
-
nonDimensions:
|
|
9
|
+
dimensions: SortableField[];
|
|
10
|
+
nonDimensions: SortableField[];
|
|
11
11
|
};
|
|
12
12
|
generatePivotedCells(table: DataColumn, shouldTranspose: boolean): Promise<Map<string, Map<string, HTMLTableCellElement>>>;
|
|
13
13
|
generateNoValueCell(field: Field, shouldTranspose: boolean): HTMLTableCellElement;
|
|
14
14
|
createCellAndRender(childRenderer: Renderer, value: DataColumn, shouldTranspose: boolean): Promise<HTMLTableCellElement>;
|
|
15
|
+
createEmptyHeaderCell(): HTMLTableCellElement;
|
|
15
16
|
createHeaderCell(field: Field, shouldTranspose: boolean): HTMLTableCellElement;
|
|
16
17
|
createCell(childRenderer: Renderer, shouldTranspose: boolean): HTMLTableCellElement;
|
|
17
18
|
renderChild(value: DataColumn): Promise<HTMLElement>;
|
package/dist/html/table.js
CHANGED
|
@@ -29,13 +29,18 @@ const number_1 = require("./number");
|
|
|
29
29
|
const utils_1 = require("./utils");
|
|
30
30
|
const tags_utils_1 = require("../tags_utils");
|
|
31
31
|
class PivotedField {
|
|
32
|
-
constructor(parentField, values) {
|
|
32
|
+
constructor(parentField, values, span) {
|
|
33
33
|
this.parentField = parentField;
|
|
34
34
|
this.values = values;
|
|
35
|
+
this.span = span;
|
|
35
36
|
this.key = JSON.stringify({
|
|
36
37
|
parentField: this.parentField.name,
|
|
37
|
-
values: this.values.
|
|
38
|
+
values: this.values.map(v => (v.isScalar() ? v.key : '')),
|
|
38
39
|
});
|
|
40
|
+
this.fieldValueMap = new Map();
|
|
41
|
+
for (const value of this.values) {
|
|
42
|
+
this.fieldValueMap.set(value.field.name, value);
|
|
43
|
+
}
|
|
39
44
|
}
|
|
40
45
|
}
|
|
41
46
|
class PivotedColumnField {
|
|
@@ -56,6 +61,9 @@ class HTMLTableRenderer extends container_1.ContainerRenderer {
|
|
|
56
61
|
}
|
|
57
62
|
async render(table) {
|
|
58
63
|
var _a;
|
|
64
|
+
if (table.isNull()) {
|
|
65
|
+
return this.document.createElement('span');
|
|
66
|
+
}
|
|
59
67
|
if (!table.isArray() && !table.isRecord()) {
|
|
60
68
|
throw new Error('Invalid type for Table Renderer');
|
|
61
69
|
}
|
|
@@ -94,7 +102,7 @@ class HTMLTableRenderer extends container_1.ContainerRenderer {
|
|
|
94
102
|
nonDimensions = dimensionsResult.nonDimensions;
|
|
95
103
|
}
|
|
96
104
|
for (const innerRow of dc) {
|
|
97
|
-
const pivotedField = new PivotedField(field, dimensions.map(d => innerRow.cell(d)));
|
|
105
|
+
const pivotedField = new PivotedField(field, dimensions.map(d => innerRow.cell(d.field)), nonDimensions.length);
|
|
98
106
|
const pfKey = pivotedField.key;
|
|
99
107
|
if (!pivotedFields[pfKey]) {
|
|
100
108
|
pivotedFields.set(pfKey, pivotedField);
|
|
@@ -104,10 +112,26 @@ class HTMLTableRenderer extends container_1.ContainerRenderer {
|
|
|
104
112
|
if (!dimensions) {
|
|
105
113
|
throw new Error(`Could not pivot ${field.name}, no data found.`);
|
|
106
114
|
}
|
|
107
|
-
|
|
115
|
+
const sortedPivotedFields = Array.from(pivotedFields.values()).sort((a, b) => {
|
|
116
|
+
for (const d of dimensions) {
|
|
117
|
+
const aValue = a.fieldValueMap.get(d.field.name);
|
|
118
|
+
const bValue = b.fieldValueMap.get(d.field.name);
|
|
119
|
+
if ((aValue === null || aValue === void 0 ? void 0 : aValue.isScalar()) &&
|
|
120
|
+
(bValue === null || bValue === void 0 ? void 0 : bValue.isScalar()) &&
|
|
121
|
+
typeof aValue === typeof bValue) {
|
|
122
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
123
|
+
const compValue = aValue.compareTo(bValue);
|
|
124
|
+
if (compValue !== 0) {
|
|
125
|
+
return d.dir !== 'desc' ? compValue : -compValue;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return 0;
|
|
130
|
+
});
|
|
131
|
+
for (const pf of sortedPivotedFields) {
|
|
108
132
|
for (const nonDimension of nonDimensions) {
|
|
109
|
-
columnFields.push(new PivotedColumnField(pf
|
|
110
|
-
cells[rowIndex][columnIndex] = childRenderer.createHeaderCell(nonDimension, shouldTranspose);
|
|
133
|
+
columnFields.push(new PivotedColumnField(pf, nonDimension.field));
|
|
134
|
+
cells[rowIndex][columnIndex] = childRenderer.createHeaderCell(nonDimension.field, shouldTranspose);
|
|
111
135
|
columnIndex++;
|
|
112
136
|
}
|
|
113
137
|
}
|
|
@@ -140,29 +164,37 @@ class HTMLTableRenderer extends container_1.ContainerRenderer {
|
|
|
140
164
|
let lastPivotedColumnHash = null;
|
|
141
165
|
for (const field of columnFields) {
|
|
142
166
|
if (field instanceof PivotedColumnField) {
|
|
143
|
-
const headerCell = this.document.createElement('th');
|
|
144
|
-
headerCell.style.cssText = `
|
|
145
|
-
padding: 8px;
|
|
146
|
-
color: var(--malloy-title-color, #505050);
|
|
147
|
-
border-bottom: 1px solid var(--malloy-border-color, #eaeaea);
|
|
148
|
-
`;
|
|
149
167
|
const pfKey = field.pivotedField.key;
|
|
150
168
|
const valueIndex = field.pivotedField.values.length - pivotDepth + r;
|
|
151
|
-
if (
|
|
169
|
+
if (valueIndex < 0) {
|
|
170
|
+
row.push(this.createEmptyHeaderCell());
|
|
171
|
+
}
|
|
172
|
+
else if (lastPivotedColumnHash !== pfKey) {
|
|
173
|
+
const headerCell = this.document.createElement('th');
|
|
174
|
+
if (!shouldTranspose) {
|
|
175
|
+
headerCell.colSpan = field.pivotedField.span;
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
headerCell.rowSpan = field.pivotedField.span;
|
|
179
|
+
}
|
|
180
|
+
headerCell.style.cssText = `
|
|
181
|
+
padding: 8px;
|
|
182
|
+
color: var(--malloy-title-color, #505050);
|
|
183
|
+
border-bottom: 1px solid var(--malloy-border-color, #eaeaeb);
|
|
184
|
+
text-align: left;
|
|
185
|
+
`;
|
|
152
186
|
const value = field.pivotedField.values[valueIndex];
|
|
187
|
+
headerCell.appendChild(this.document.createTextNode(`${value.field.name}: `));
|
|
153
188
|
headerCell.appendChild(await this.childRenderers[field.pivotedField.parentField.name].renderChild(value));
|
|
154
189
|
lastPivotedColumnHash = pfKey;
|
|
190
|
+
row.push(headerCell);
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
row.push(undefined);
|
|
155
194
|
}
|
|
156
|
-
row.push(headerCell);
|
|
157
195
|
}
|
|
158
196
|
else {
|
|
159
|
-
|
|
160
|
-
headerCell.style.cssText = `
|
|
161
|
-
padding: 8px;
|
|
162
|
-
color: var(--malloy-title-color, #505050);
|
|
163
|
-
border-bottom: 1px solid var(--malloy-border-color, #eaeaea);
|
|
164
|
-
`;
|
|
165
|
-
row.push(headerCell);
|
|
197
|
+
row.push(this.createEmptyHeaderCell());
|
|
166
198
|
}
|
|
167
199
|
}
|
|
168
200
|
pivotHeaderCells.push(row);
|
|
@@ -215,7 +247,7 @@ class HTMLTableRenderer extends container_1.ContainerRenderer {
|
|
|
215
247
|
vertical-align: top;
|
|
216
248
|
border-bottom: 1px solid var(--malloy-border-color, #eaeaea);
|
|
217
249
|
width: 25px;
|
|
218
|
-
cursor: pointer
|
|
250
|
+
cursor: pointer;
|
|
219
251
|
`;
|
|
220
252
|
drillCell.onclick = () => {
|
|
221
253
|
if (this.options.onDrill) {
|
|
@@ -237,7 +269,10 @@ class HTMLTableRenderer extends container_1.ContainerRenderer {
|
|
|
237
269
|
}
|
|
238
270
|
const currentRow = this.document.createElement('tr');
|
|
239
271
|
for (let column = 0; column < (shouldTranspose ? rowIndex : columnIndex); column++) {
|
|
240
|
-
|
|
272
|
+
const cell = shouldTranspose ? cells[column][row] : cells[row][column];
|
|
273
|
+
if (cell) {
|
|
274
|
+
currentRow.appendChild(cell);
|
|
275
|
+
}
|
|
241
276
|
}
|
|
242
277
|
tableSection.appendChild(currentRow);
|
|
243
278
|
}
|
|
@@ -258,10 +293,11 @@ class HTMLTableRenderer extends container_1.ContainerRenderer {
|
|
|
258
293
|
let dimensions = undefined;
|
|
259
294
|
const userSpecifiedDimensions = (0, utils_1.parseCommaSeparatedParameterTagValue)(this.tags, 'pivot_dimensions');
|
|
260
295
|
if (userSpecifiedDimensions) {
|
|
261
|
-
dimensions = table.field.
|
|
296
|
+
dimensions = table.field.allFieldsWithOrder.filter(f => userSpecifiedDimensions.indexOf(f.field.name) >= 0);
|
|
262
297
|
if (dimensions.length !== userSpecifiedDimensions.length) {
|
|
263
298
|
for (const dim of userSpecifiedDimensions) {
|
|
264
|
-
if (table.field.
|
|
299
|
+
if (table.field.allFieldsWithOrder.filter(f => f.field.name === dim)
|
|
300
|
+
.length === 0) {
|
|
265
301
|
throw new Error(`Could not pivot ${table.field.name} since ${dim} is not a valid field.`);
|
|
266
302
|
}
|
|
267
303
|
}
|
|
@@ -270,7 +306,7 @@ class HTMLTableRenderer extends container_1.ContainerRenderer {
|
|
|
270
306
|
else {
|
|
271
307
|
dimensions = table.field.dimensions;
|
|
272
308
|
}
|
|
273
|
-
const nonDimensions = table.field.
|
|
309
|
+
const nonDimensions = table.field.allFieldsWithOrder.filter(f => dimensions.indexOf(f) < 0);
|
|
274
310
|
if (nonDimensions.length === 0) {
|
|
275
311
|
throw new Error(`Can not pivot ${table.field.name} since all of its fields are dimensions.`);
|
|
276
312
|
}
|
|
@@ -284,13 +320,13 @@ class HTMLTableRenderer extends container_1.ContainerRenderer {
|
|
|
284
320
|
if (!table.isArray() && !table.isRecord()) {
|
|
285
321
|
throw new Error(`Could not pivot ${table.field.name}`);
|
|
286
322
|
}
|
|
287
|
-
const { dimensions } = this.calculatePivotDimensions(table);
|
|
323
|
+
const { dimensions, nonDimensions } = this.calculatePivotDimensions(table);
|
|
288
324
|
for (const row of table) {
|
|
289
|
-
const pf = new PivotedField(table.field, dimensions.map(f => row.cell(f.name)));
|
|
325
|
+
const pf = new PivotedField(table.field, dimensions.map(f => row.cell(f.field.name)), nonDimensions.length);
|
|
290
326
|
const renderedCells = new Map();
|
|
291
|
-
for (const nonDimension of table.field.
|
|
292
|
-
const childRenderer = this.childRenderers[nonDimension.name];
|
|
293
|
-
renderedCells.set(nonDimension.name, await this.createCellAndRender(childRenderer, row.cell(nonDimension.name), shouldTranspose));
|
|
327
|
+
for (const nonDimension of table.field.allFieldsWithOrder.filter(f => dimensions.indexOf(f) < 0)) {
|
|
328
|
+
const childRenderer = this.childRenderers[nonDimension.field.name];
|
|
329
|
+
renderedCells.set(nonDimension.field.name, await this.createCellAndRender(childRenderer, row.cell(nonDimension.field.name), shouldTranspose));
|
|
294
330
|
}
|
|
295
331
|
if (result.has(pf.key)) {
|
|
296
332
|
throw new Error(`Can not pivot ${table.field.name} dimensions lead to non unique pivots.`);
|
|
@@ -309,6 +345,15 @@ class HTMLTableRenderer extends container_1.ContainerRenderer {
|
|
|
309
345
|
cell.appendChild(await childRenderer.render(value));
|
|
310
346
|
return cell;
|
|
311
347
|
}
|
|
348
|
+
createEmptyHeaderCell() {
|
|
349
|
+
const headerCell = this.document.createElement('th');
|
|
350
|
+
headerCell.style.cssText = `
|
|
351
|
+
padding: 8px;
|
|
352
|
+
color: var(--malloy-title-color, #505050);
|
|
353
|
+
border-bottom: 1px solid var(--malloy-border-color, #eaeaea);
|
|
354
|
+
`;
|
|
355
|
+
return headerCell;
|
|
356
|
+
}
|
|
312
357
|
createHeaderCell(field, shouldTranspose) {
|
|
313
358
|
let name = (0, utils_1.formatTitle)(this.options, field, this.options.dataStyles[field.name], field.parentExplore.queryTimezone);
|
|
314
359
|
const isNumeric = this.childRenderers[field.name] instanceof number_1.HTMLNumberRenderer;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@malloydata/render",
|
|
3
|
-
"version": "0.0.60
|
|
3
|
+
"version": "0.0.60",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"prepublishOnly": "npm run build"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@malloydata/malloy": "^0.0.60
|
|
21
|
+
"@malloydata/malloy": "^0.0.60",
|
|
22
22
|
"@types/luxon": "^2.4.0",
|
|
23
23
|
"lodash": "^4.17.20",
|
|
24
24
|
"luxon": "^2.4.0",
|