(worksheet, model)
| 3 | // TK(2023-10-10): turn this into a class constructor. |
| 4 | |
| 5 | function makePivotTable(worksheet, model) { |
| 6 | // Example `model`: |
| 7 | // { |
| 8 | // // Source of data: the entire sheet range is taken, |
| 9 | // // akin to `worksheet1.getSheetValues()`. |
| 10 | // sourceSheet: worksheet1, |
| 11 | // |
| 12 | // // Pivot table fields: values indicate field names; |
| 13 | // // they come from the first row in `worksheet1`. |
| 14 | // rows: ['A', 'B'], |
| 15 | // columns: ['C'], |
| 16 | // values: ['E'], // only 1 item possible for now |
| 17 | // metric: 'sum', // only 'sum' possible for now |
| 18 | // } |
| 19 | |
| 20 | validate(worksheet, model); |
| 21 | |
| 22 | const {sourceSheet} = model; |
| 23 | let {rows, columns, values} = model; |
| 24 | |
| 25 | const cacheFields = makeCacheFields(sourceSheet, [...rows, ...columns]); |
| 26 | |
| 27 | // let {rows, columns, values} use indices instead of names; |
| 28 | // names can then be accessed via `pivotTable.cacheFields[index].name`. |
| 29 | // *Note*: Using `reduce` as `Object.fromEntries` requires Node 12+; |
| 30 | // ExcelJS is >=8.3.0 (as of 2023-10-08). |
| 31 | const nameToIndex = cacheFields.reduce((result, cacheField, index) => { |
| 32 | result[cacheField.name] = index; |
| 33 | return result; |
| 34 | }, {}); |
| 35 | rows = rows.map(row => nameToIndex[row]); |
| 36 | columns = columns.map(column => nameToIndex[column]); |
| 37 | values = values.map(value => nameToIndex[value]); |
| 38 | |
| 39 | // form pivot table object |
| 40 | return { |
| 41 | sourceSheet, |
| 42 | rows, |
| 43 | columns, |
| 44 | values, |
| 45 | metric: 'sum', |
| 46 | cacheFields, |
| 47 | // defined in <pivotTableDefinition> of xl/pivotTables/pivotTable1.xml; |
| 48 | // also used in xl/workbook.xml |
| 49 | cacheId: '10', |
| 50 | }; |
| 51 | } |
| 52 | |
| 53 | function validate(worksheet, model) { |
| 54 | if (worksheet.workbook.pivotTables.length === 1) { |
no test coverage detected
searching dependent graphs…