UNPKG

devexpress-reporting

Version:

DevExpress Reporting provides the capability to develop a reporting application to create and customize reports.

581 lines (580 loc) 27.9 kB
/** * DevExpress HTML/JS Reporting (designer\controls\crossTab\cellCreator.js) * Version: 24.2.6 * Build date: Mar 18, 2025 * Copyright (c) 2012 - 2025 Developer Express Inc. ALL RIGHTS RESERVED * License: https://www.devexpress.com/Support/EULAs/universal.xml */ import { SerializableModel } from '@devexpress/analytics-core/analytics-elements'; import { Disposable, ModelSerializer } from '@devexpress/analytics-core/analytics-utils'; import * as ko from 'knockout'; import { cellserializtionInfoBase } from '../metadata/crosstab/xrCrossTabCell'; import { CellKind, CornerHeaderDisplayMode, DataFieldLayout, TotalHeaderPosition, TotalsPosition } from './enums'; export class CrossTabCellInfo extends SerializableModel { constructor(model, serializer = new ModelSerializer()) { super(model, serializer, cellserializtionInfoBase); this.kind = ko.observable(CellKind.None); } } export class CellCreator extends Disposable { get rowFieldCount() { return this.crossTab.rowFields().length; } get columnFieldCount() { return this.crossTab.columnFields().length; } get dataFieldCount() { return this.crossTab.dataFields().length; } get rowDataCount() { return 1; } get columnDataCount() { return 1; } constructor(crossTab) { super(); this.crossTab = crossTab; } nextRowIndex(cell) { return cell._rowIndex() + cell._rowSpan(); } lastRowIndex(cell) { return this.nextRowIndex(cell) - 1; } nextColumnIndex(cell) { return cell._columnIndex() + cell._columnSpan(); } lastColumnIndex(cell) { return this.nextColumnIndex(cell) - 1; } setCellKind(cell, kind) { cell.kind(kind); } setLevel(cell, dataLevel, columnLevel, rowLevel) { if (dataLevel >= 0) this.setDataLevel(cell, dataLevel); if (columnLevel >= 0) this.setColumnLevel(cell, columnLevel); if (rowLevel >= 0) this.setRowLevel(cell, rowLevel); } setDataLevel(cell, level) { cell.dataLevel = level; } setColumnLevel(cell, level) { cell.columnLevel = level; } setRowLevel(cell, level) { cell.rowLevel = level; } indexToLevel(index, count) { return count - 1 - index; } setLayout(cell, columnIndex, rowIndex, columnSpan, rowSpan) { cell._columnIndex(columnIndex); cell._rowIndex(rowIndex); cell._columnSpan(columnSpan); cell._rowSpan(rowSpan); } static createInstance(crossTab) { return crossTab.dataFields().length <= 1 ? new CellCreator(crossTab) : crossTab.layoutOptions.dataFieldLayout() === DataFieldLayout[DataFieldLayout.InRow] ? new HorizontalCreator(crossTab) : new VerticalCreator(crossTab); } create() { const cells = []; const corners = this.createCorners(Math.max(1, this.columnFieldCount), Math.max(1, this.rowFieldCount)); cells.push(...corners); this.lastCorner = corners[corners.length - 1]; const dataHeaders = this.createDataHeaders(); cells.push(...dataHeaders); const dataCells = this.createData(); cells.push(...dataCells); const columnHeaders = this.createColumnHeaders(this.nextColumnIndex(this.lastCorner), this.columnFieldCount * this.columnDataCount, this.columnDataCount); cells.push(...columnHeaders); const rowHeaders = this.createRowHeaders(this.nextRowIndex(this.lastCorner), this.rowFieldCount * this.rowDataCount, this.rowDataCount); cells.push(...rowHeaders); const rowTotalHeaders = this.createRowTotalHeaders(rowHeaders[rowHeaders.length - 1]._columnIndex(), 1, this.nextRowIndex(rowHeaders[rowHeaders.length - 1]), this.rowDataCount); cells.push(...rowTotalHeaders); cells.push(...this.createRowTotals(dataCells[0]._columnIndex(), this.nextRowIndex(dataCells[0]), this.rowDataCount)); const columnTotalHeaders = this.createColumnTotalHeaders(this.nextColumnIndex(columnHeaders[columnHeaders.length - 1]), columnHeaders[columnHeaders.length - 1]._rowIndex(), 1, this.columnDataCount); cells.push(...columnTotalHeaders); cells.push(...this.createColumnTotals(this.nextColumnIndex(dataCells[0]), dataCells[0]._rowIndex(), this.columnDataCount)); cells.push(...this.createGrandTotals(dataCells, this.nextRowIndex(dataCells[dataCells.length - 1]), this.nextColumnIndex(dataCells[dataCells.length - 1]), dataCells.length, 1)); if (this.crossTab.layoutOptions.hierarchicalRowLayout() && this.rowFieldCount > 1) { cells.push(...this.createEmptyHeaders(this.columnFieldCount + 1)); cells.push(...this.createEmptyCells(1)); } return cells; } creator(cellKind) { const cell = new CrossTabCellInfo({}); this.setCellKind(cell, cellKind); return cell; } createCorners(columnCount, rowCount) { const mode = this.crossTab.layoutOptions.cornerHeaderDisplayMode(); const corners = []; let cell; if (CornerHeaderDisplayMode[mode] === CornerHeaderDisplayMode.RowFieldNames) { for (let i = 0; i < rowCount; i++) { cell = this.creator(CellKind.Corner); this.setLayout(cell, i, 0, 1, columnCount); this.setRowLevel(cell, i); cell.field = ko.observable(this.crossTab.rowFields()[i]); corners.push(cell); } } else if (CornerHeaderDisplayMode[mode] === CornerHeaderDisplayMode.ColumnFieldNames) { for (let i = 0; i < columnCount; i++) { cell = this.creator(CellKind.Corner); this.setLayout(cell, 0, i, rowCount, 1); this.setColumnLevel(cell, i); cell.field = ko.observable(this.crossTab.columnFields()[i]); corners.push(cell); } } else { if (this.crossTab.layoutOptions) cell = this.creator(CellKind.Corner); this.setLayout(cell, 0, 0, rowCount, columnCount); corners.push(cell); } return corners; } createDataHeaders() { return []; } createDataHeader(columnIndex, rowIndex, dataLevel, columnLevel = -1, rowLevel = -1) { const cell = this.creator(CellKind.DataHeader); this.setLevel(cell, dataLevel, columnLevel, rowLevel); this.setLayout(cell, columnIndex, rowIndex, 1, 1); cell.field = ko.observable(this.crossTab.dataFields()[dataLevel]); return cell; } createData() { let startRowIndex = this.nextRowIndex(this.lastCorner); if (this.crossTab.layoutOptions.hierarchicalRowLayout()) startRowIndex += this.rowFieldCount - 1; return [this.createDataCell(this.nextColumnIndex(this.lastCorner), startRowIndex, 0)]; } createDataCell(colIndex, rowIndex, level) { const cell = this.creator(CellKind.Data); cell.field = ko.observable(this.crossTab.dataFields()[level]); this.setDataLevel(cell, level); this.setLayout(cell, colIndex, rowIndex, 1, 1); return cell; } createColumnTotals(startColumnIndex, startRowIndex, dataCount) { if (this.columnFieldCount == 0) return []; const cells = []; let columnIndex = startColumnIndex; for (let i = 0; i < this.columnFieldCount; i++) { const level = this.indexToLevel(i, this.columnFieldCount) - 1; for (let j = 0; j < Math.max(1, this.dataFieldCount); j++) { cells.push(this.createColumnTotal(columnIndex, startRowIndex, j, level)); } columnIndex += dataCount; } return cells; } createColumnTotal(columnIndex, rowIndex, dataLevel, columnLevel) { const cell = this.creator(CellKind.ColumnTotal); this.setLevel(cell, dataLevel, columnLevel, -1); this.setLayout(cell, columnIndex, rowIndex, 1, 1); return cell; } createRowTotals(startColumnIndex, startRowIndex, dataCount) { if (this.rowFieldCount === 0) return []; const cells = []; let rowIndex = startRowIndex; for (let i = 0; i < this.rowFieldCount; i++) { const level = this.indexToLevel(i, this.rowFieldCount) - 1; for (let j = 0; j < Math.max(1, this.dataFieldCount); j++) { cells.push(this.createRowTotal(startColumnIndex, rowIndex, j, level)); } rowIndex += dataCount; } return cells; } createRowTotal(columnIndex, rowIndex, dataLevel, rowLevel) { const cell = this.creator(CellKind.RowTotal); this.setLevel(cell, dataLevel, -1, rowLevel); this.setLayout(cell, columnIndex, rowIndex, 1, 1); return cell; } createGrandTotals(dataItems, startRowIndex, startColumnIndex, columnInc, rowInc) { let columnIndex = startColumnIndex; const totals = []; for (let i = 0; i < this.columnFieldCount; i++) { const columnLevel = this.indexToLevel(i, this.columnFieldCount) - 1; let rowIndex = startRowIndex; for (let j = 0; j < this.rowFieldCount; j++) { const rowLevel = this.indexToLevel(j, this.rowFieldCount) - 1; for (let k = 0; k < dataItems.length; k++) { const cell = this.createGrandTotal(k, columnLevel, rowLevel); this.setGrandTotalLayout(cell, k, columnIndex, rowIndex); totals.push(cell); } rowIndex += rowInc; } columnIndex += columnInc; } return totals; } createGrandTotal(dataLevel, columnLevel, rowLevel) { const cell = this.creator(CellKind.GrandTotal); this.setLevel(cell, dataLevel, columnLevel, rowLevel); return cell; } setGrandTotalLayout(cells, inc, columnIndex, rowIndex) { this.setLayout(cells, columnIndex + inc, rowIndex, 1, 1); } createColumnHeaders(startColumnIndex, columnSpan, dataCount) { const cells = []; if (this.columnFieldCount === 0) { const columnHeader = this.creator(CellKind.ColumnHeader); this.setColumnLevel(columnHeader, 0); this.setLayout(columnHeader, startColumnIndex, 0, dataCount, 1); cells.push(columnHeader); } if (this.crossTab.layoutOptions.columnTotalHeaderPosition() === TotalHeaderPosition[TotalHeaderPosition.Outer]) columnSpan = Math.max(dataCount, columnSpan - dataCount); let rowIndex = 0; const isReversed = this.crossTab.layoutOptions.columnTotalsPosition() === TotalsPosition[TotalsPosition.BeforeData]; isReversed && (startColumnIndex += dataCount * (this.columnFieldCount + 1)); for (let i = 0; i < this.columnFieldCount; i++) { const columnHeader = this.creator(CellKind.ColumnHeader); columnHeader.field = ko.observable(this.crossTab.columnFields()[i]); this.setColumnLevel(columnHeader, i); this.setLayout(columnHeader, isReversed ? startColumnIndex - columnSpan : startColumnIndex, rowIndex, columnSpan, 1); cells.push(columnHeader); columnSpan = Math.max(dataCount, columnSpan - dataCount); rowIndex = this.nextRowIndex(columnHeader); } return cells; } createColumnTotalHeaders(startColumnIndex, startRowIndex, rowSpan, dataCount) { const cells = []; if (this.columnFieldCount === 0) return []; if (this.crossTab.layoutOptions.columnTotalHeaderPosition() === TotalHeaderPosition[TotalHeaderPosition.Outer] && startRowIndex > 0) { startRowIndex--; rowSpan++; } let rowIndex = startRowIndex; let columnIndex = startColumnIndex; let columnInc = dataCount; if (this.crossTab.layoutOptions.columnTotalsPosition() === TotalsPosition[TotalsPosition.BeforeData]) { columnIndex -= dataCount * 2; columnInc = -columnInc; } for (let i = 0; i < this.columnFieldCount; i++) { const level = this.indexToLevel(i, this.columnFieldCount); const columnTotalHeader = level === 0 ? this.createColumnGrandTotalHeader() : this.createColumnTotalHeader(level - 1); columnTotalHeader.field = ko.observable(this.crossTab.columnFields()[level - 1]); this.setLayout(columnTotalHeader, columnIndex, rowIndex, dataCount, rowSpan); cells.push(columnTotalHeader); if (rowIndex > 0) { rowIndex--; rowSpan++; } columnIndex += columnInc; } return cells; } createRowHeaders(startRowIndex, rowSpan, dataCount) { if (this.rowFieldCount === 0) { const rowHeader = this.creator(CellKind.RowHeader); this.setRowLevel(rowHeader, 0); this.setLayout(rowHeader, 0, startRowIndex, 1, dataCount); return [rowHeader]; } const cells = []; let columnShift = 0; if (this.crossTab.layoutOptions.hierarchicalRowLayout() && this.rowFieldCount > 1) { columnShift = 1; rowSpan = 1; } else if (this.crossTab.layoutOptions.rowTotalHeaderPosition() === TotalHeaderPosition[TotalHeaderPosition.Outer]) { rowSpan = Math.max(dataCount, rowSpan - dataCount); } let columnIndex = 0; let rowIndex = startRowIndex; const isReversed = this.crossTab.layoutOptions.rowTotalsPosition() === TotalsPosition[TotalsPosition.BeforeData]; isReversed && (rowIndex += dataCount * (this.rowFieldCount + 1)); let columnSpan = Math.max(1, this.rowFieldCount * columnShift); for (let i = 0; i < this.rowFieldCount; i++) { const rowHeader = this.creator(CellKind.RowHeader); rowHeader.field = ko.observable(this.crossTab.rowFields()[i]); this.setRowLevel(rowHeader, i); if (this.crossTab.layoutOptions.hierarchicalRowLayout() && this.rowFieldCount - 1 > i && this.crossTab.layoutOptions.dataFieldLayout() === DataFieldLayout[DataFieldLayout.InColumn]) { columnSpan += 1; } this.setLayout(rowHeader, columnIndex, isReversed ? rowIndex - rowSpan : rowIndex, columnSpan, rowSpan); cells.push(rowHeader); if (!this.crossTab.layoutOptions.hierarchicalRowLayout() || this.rowFieldCount - 2 == i) { rowSpan = Math.max(dataCount, rowSpan - dataCount); } columnSpan = Math.max(1, (this.rowFieldCount - i - 1) * columnShift); columnIndex = rowHeader._columnIndex() + 1; !isReversed && (rowIndex = rowHeader._rowIndex() + columnShift); } return cells; } createRowTotalHeaders(startColumnIndex, columnSpan, startRowIndex, dataCount) { if (this.rowFieldCount === 0) return []; if (this.crossTab.layoutOptions.rowTotalHeaderPosition() === TotalHeaderPosition[TotalHeaderPosition.Outer] && startColumnIndex > 0) { startColumnIndex--; columnSpan++; } let rowIndex = startRowIndex; let rowInc = dataCount; if (this.crossTab.layoutOptions.rowTotalsPosition() === TotalsPosition[TotalsPosition.BeforeData]) { rowIndex -= dataCount * 2; rowInc = -rowInc; } let columnIndex = startColumnIndex; const cells = []; for (let i = 0; i < this.rowFieldCount; i++) { const level = this.indexToLevel(i, this.rowFieldCount); const rowTotalHeader = level === 0 ? this.createRowGrandTotalHeader() : this.createRowTotalHeader(level - 1); rowTotalHeader.field = ko.observable(this.crossTab.rowFields()[level - 1]); this.setLayout(rowTotalHeader, columnIndex, rowIndex, columnSpan, dataCount); cells.push(rowTotalHeader); if (columnIndex > 0) { columnIndex--; columnSpan++; } rowIndex += rowInc; } return cells; } createEmptyHeaders(columnSpan) { let rowIndex = this.nextRowIndex(this.lastCorner); const columnIndex = this.nextColumnIndex(this.lastCorner); const cells = []; for (let i = 0; i < this.rowFieldCount - 1; i++) { const emptyHeader = this.createEmptyHeader(i); this.setLayout(emptyHeader, columnIndex, rowIndex, columnSpan, 1); cells.push(emptyHeader); rowIndex++; } return cells; } createEmptyCells(dataCount) { let rowIndex = this.nextRowIndex(this.lastCorner) + 1; let columnIndex = 0; let rowSpan = this.rowFieldCount * (dataCount + 1) - 2; if (this.crossTab.layoutOptions.rowTotalHeaderPosition() === TotalHeaderPosition[TotalHeaderPosition.Outer]) { rowSpan -= dataCount; } const cells = []; for (let i = 0; i < this.rowFieldCount - 1; i++) { const emptyCell = this.createEmptyCell(i); this.setLayout(emptyCell, columnIndex, rowIndex, 1, rowSpan); cells.push(emptyCell); rowIndex++; columnIndex++; rowSpan -= dataCount + 1; } return cells; } createEmptyHeader(level) { const emptyHeader = this.creator(CellKind.EmptyHeader); this.setRowLevel(emptyHeader, level); return emptyHeader; } createEmptyCell(level) { const emptyCell = this.creator(CellKind.Empty); this.setRowLevel(emptyCell, level); return emptyCell; } createColumnTotalHeader(level) { const columnHeaderTotal = this.creator(CellKind.ColumnTotalHeader); this.setColumnLevel(columnHeaderTotal, level); return columnHeaderTotal; } createColumnGrandTotalHeader() { const cell = this.creator(CellKind.ColumnTotalHeader); return cell; } createRowTotalHeader(level) { const rowHeaderTotal = this.creator(CellKind.RowTotalHeader); this.setRowLevel(rowHeaderTotal, level); return rowHeaderTotal; } createRowGrandTotalHeader() { const cell = this.creator(CellKind.RowTotalHeader); return cell; } } export class HorizontalCreator extends CellCreator { get columnDataCount() { return this.dataFieldCount; } createCorners(columnCount, rowCount) { const corners = super.createCorners(columnCount, rowCount); if (this.crossTab.layoutOptions.cornerHeaderDisplayMode() == CornerHeaderDisplayMode[CornerHeaderDisplayMode.ColumnFieldNames]) { const lastCorner = corners[corners.length - 1]; lastCorner._rowSpan(lastCorner._rowSpan() + 1); } else corners.forEach(corner => { corner._rowSpan(corner._rowSpan() + 1); }); return corners; } createDataHeaders() { const rowIndex = this.lastRowIndex(this.lastCorner); const isReversed = this.crossTab.layoutOptions.columnTotalsPosition() === TotalsPosition[TotalsPosition.BeforeData]; let columnIndex = !isReversed ? this.nextColumnIndex(this.lastCorner) : this.nextColumnIndex(this.lastCorner) + this.columnFieldCount * this.dataFieldCount; const cells = []; for (let i = 0; i < this.dataFieldCount; i++) { cells.push(this.createDataHeader(columnIndex, rowIndex, i)); columnIndex++; } const columnInc = Math.max(1, this.dataFieldCount); isReversed && (columnIndex -= 2 * columnInc); for (let i = 0; i < this.columnFieldCount; i++) { const columnLevel = this.indexToLevel(i, this.columnFieldCount); for (let j = 0; j < columnInc; j++) { const dataHeader = this.createDataHeader(columnIndex + j, rowIndex, j, columnLevel); this.setLevel(dataHeader, -1, columnLevel, -1); cells.push(dataHeader); } isReversed ? (columnIndex -= columnInc) : (columnIndex += columnInc); } return cells; } createData() { let startRowIndex = this.nextRowIndex(this.lastCorner); if (this.crossTab.layoutOptions.hierarchicalRowLayout()) startRowIndex += this.rowFieldCount - 1; const rowIndex = this.crossTab.layoutOptions.rowTotalsPosition() === TotalsPosition[TotalsPosition.AfterData] ? startRowIndex : startRowIndex + this.rowFieldCount; const columnIndex = this.crossTab.layoutOptions.columnTotalsPosition() === TotalsPosition[TotalsPosition.AfterData] ? this.nextColumnIndex(this.lastCorner) : this.nextColumnIndex(this.lastCorner) + this.columnFieldCount * this.dataFieldCount; const cells = []; for (let i = 0; i < this.dataFieldCount; i++) { cells.push(this.createDataCell(columnIndex + i, rowIndex, i)); } return cells; } createRowTotals(startColumnIndex, startRowIndex, dataCount) { if (this.crossTab.layoutOptions.rowTotalsPosition() === TotalsPosition[TotalsPosition.BeforeData]) { return super.createRowTotals(startColumnIndex, startRowIndex - 2, -dataCount); } return super.createRowTotals(startColumnIndex, startRowIndex, dataCount); } createColumnTotals(startColumnIndex, startRowIndex, dataCount) { if (this.crossTab.layoutOptions.columnTotalsPosition() === TotalsPosition[TotalsPosition.BeforeData]) { return super.createColumnTotals(startColumnIndex - dataCount - 1, startRowIndex, -dataCount); } return super.createColumnTotals(startColumnIndex + dataCount - 1, startRowIndex, dataCount); } createGrandTotals(dataItems, startRowIndex, startColumnIndex, columnIndex, rowIndex) { if (this.crossTab.layoutOptions.columnTotalsPosition() === TotalsPosition[TotalsPosition.BeforeData]) { startColumnIndex -= dataItems.length * 2; columnIndex = -dataItems.length; } if (this.crossTab.layoutOptions.rowTotalsPosition() === TotalsPosition[TotalsPosition.BeforeData]) { startRowIndex -= 2; rowIndex = -1; } return super.createGrandTotals(dataItems, startRowIndex, startColumnIndex, columnIndex, rowIndex); } createColumnTotal(columnIndex, rowIndex, dataLevel, columnLevel) { return super.createColumnTotal(columnIndex + dataLevel, rowIndex, dataLevel, columnLevel); } createRowTotal(columnIndex, rowIndex, dataLevel, rowLevel) { return super.createRowTotal(columnIndex + dataLevel, rowIndex, dataLevel, rowLevel); } createEmptyHeaders(columnSpan) { return super.createEmptyHeaders(columnSpan * this.dataFieldCount); } } export class VerticalCreator extends CellCreator { get rowDataCount() { return this.dataFieldCount; } createCorners(columnCount, rowCount) { const corners = super.createCorners(columnCount, rowCount); if (this.crossTab.layoutOptions.cornerHeaderDisplayMode() == CornerHeaderDisplayMode[CornerHeaderDisplayMode.RowFieldNames]) { const lastCorner = corners[corners.length - 1]; lastCorner._columnSpan(lastCorner._columnSpan() + 1); } else corners.forEach(corner => { corner._columnSpan(corner._columnSpan() + 1); }); return corners; } createDataHeaders() { let startRowIndex = this.nextRowIndex(this.lastCorner); if (this.crossTab.layoutOptions.hierarchicalRowLayout()) startRowIndex += this.rowFieldCount - 1; const isReversed = this.crossTab.layoutOptions.rowTotalsPosition() === TotalsPosition[TotalsPosition.BeforeData]; let rowIndex = !isReversed ? startRowIndex : startRowIndex + (this.rowFieldCount) * this.dataFieldCount; const columnIndex = this.lastColumnIndex(this.lastCorner); const cells = []; for (let i = 0; i < this.dataFieldCount; i++) { cells.push(this.createDataHeader(columnIndex, rowIndex, i)); rowIndex++; } const rowInc = Math.max(1, this.dataFieldCount); isReversed && (rowIndex -= 2 * rowInc); for (let i = 0; i < this.rowFieldCount; i++) { const rowLevel = this.indexToLevel(i, this.rowFieldCount); for (let j = 0; j < rowInc; j++) { const dataHeader = this.createDataHeader(columnIndex, rowIndex + j, j, undefined, rowLevel); this.setLevel(dataHeader, -1, -1, rowLevel); cells.push(dataHeader); } isReversed ? (rowIndex -= rowInc) : (rowIndex += rowInc); } return cells; } createData() { let startRowIndex = this.nextRowIndex(this.lastCorner); if (this.crossTab.layoutOptions.hierarchicalRowLayout()) startRowIndex += this.rowFieldCount - 1; const rowIndex = this.crossTab.layoutOptions.rowTotalsPosition() === TotalsPosition[TotalsPosition.AfterData] ? startRowIndex : startRowIndex + (this.rowFieldCount) * this.dataFieldCount; const columnIndex = this.crossTab.layoutOptions.columnTotalsPosition() === TotalsPosition[TotalsPosition.AfterData] ? this.nextColumnIndex(this.lastCorner) : this.nextColumnIndex(this.lastCorner) + this.columnFieldCount; const cells = []; for (let i = 0; i < this.dataFieldCount; i++) { cells.push(this.createDataCell(columnIndex, rowIndex + i, i)); } return cells; } createRowTotals(startColumnIndex, startRowIndex, dataCount) { if (this.crossTab.layoutOptions.rowTotalsPosition() === TotalsPosition[TotalsPosition.BeforeData]) { return super.createRowTotals(startColumnIndex, startRowIndex - 3, -dataCount); } return super.createRowTotals(startColumnIndex, startRowIndex + dataCount - 1, dataCount); } createColumnTotals(startColumnIndex, startRowIndex, dataCount) { if (this.crossTab.layoutOptions.columnTotalsPosition() === TotalsPosition[TotalsPosition.BeforeData]) { return super.createColumnTotals(startColumnIndex - 2, startRowIndex, -dataCount); } return super.createColumnTotals(startColumnIndex, startRowIndex, dataCount); } createColumnTotal(columnIndex, rowIndex, dataLevel, columnLevel) { return super.createColumnTotal(columnIndex, rowIndex + dataLevel, dataLevel, columnLevel); } createRowTotal(columnIndex, rowIndex, dataLevel, rowLevel) { return super.createRowTotal(columnIndex, rowIndex + dataLevel, dataLevel, rowLevel); } createGrandTotals(dataItems, startRowIndex, startColumnIndex, columnIndex, rowIndex) { columnIndex = 1; rowIndex = dataItems.length; if (this.crossTab.layoutOptions.columnTotalsPosition() === TotalsPosition[TotalsPosition.BeforeData]) { startColumnIndex -= 2; columnIndex = -1; } if (this.crossTab.layoutOptions.rowTotalsPosition() === TotalsPosition[TotalsPosition.BeforeData]) { startRowIndex -= this.dataFieldCount + 2; rowIndex = -dataItems.length; } return super.createGrandTotals(dataItems, startRowIndex, startColumnIndex, columnIndex, rowIndex); } setGrandTotalLayout(items, inc, columnIndex, rowIndex) { this.setLayout(items, columnIndex, rowIndex + inc, 1, 1); } createEmptyCells(dataCount) { return super.createEmptyCells(dataCount * this.dataFieldCount); } }