Skip to content

Commit

Permalink
feat(theme): 新增度量值的主题配置, 修复小计总计主题配置不生效 close #1357 (#1364)
Browse files Browse the repository at this point in the history
* feat(theme): 新增度量值的主题配置, 修复小计总计主题配置不生效 close #1357

* test: 增加主题测试
  • Loading branch information
lijinke666 authored May 24, 2022
1 parent 50def10 commit 98d3387
Show file tree
Hide file tree
Showing 13 changed files with 282 additions and 47 deletions.
212 changes: 203 additions & 9 deletions packages/s2-core/__tests__/spreadsheet/theme-spec.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import { getContainer } from 'tests/util/helpers';
import { assembleDataCfg, assembleOptions } from 'tests/util';
/* eslint-disable jest/expect-expect */
import { createPivotSheet } from 'tests/util/helpers';
import { get } from 'lodash';
import { ShapeAttrs } from '@antv/g-canvas';
import { S2DataConfig } from './../../esm/common/interface/s2DataConfig.d';
import { TextTheme } from '@/common/interface/theme';
import { PivotSheet } from '@/sheet-type';
import { CellTypes, TextAlign } from '@/common';
import { CellTypes, EXTRA_FIELD, TextAlign } from '@/common';
import { RowCell } from '@/cell';
import { Node } from '@/facet/layout/node';

describe('SpreadSheet Theme Tests', () => {
let s2: PivotSheet;
const dataCfg = assembleDataCfg();

beforeAll(() => {
s2 = new PivotSheet(
getContainer(),
dataCfg,
assembleOptions({
s2 = createPivotSheet(
{
headerActionIcons: [
{
iconNames: ['DrillDownIcon'],
Expand All @@ -23,8 +23,11 @@ describe('SpreadSheet Theme Tests', () => {
action: () => {},
},
],
}),
},
{ useSimpleData: false },
);

s2.render();
});

afterAll(() => {
Expand Down Expand Up @@ -135,4 +138,195 @@ describe('SpreadSheet Theme Tests', () => {
},
);
});

describe('Measure Fields Theme Tests', () => {
const expectTextAlign = (options: {
textAlign: TextAlign;
fontWight: TextTheme['fontWeight'];
containsDataCells?: boolean;
customNodes?: Node[];
}) => {
const {
textAlign,
fontWight,
containsDataCells = false,
customNodes,
} = options;
const targetNodes = customNodes || s2.getColumnLeafNodes();
const dataCells = s2.interaction.getPanelGroupAllDataCells();

expect(targetNodes).not.toHaveLength(0);

if (!containsDataCells) {
expect(
targetNodes.every((node) => {
const nodeTextShape = node.belongsCell.getTextShape();
return (
nodeTextShape.attr('textAlign') === textAlign &&
nodeTextShape.attr('fontWeight') === fontWight
);
}),
).toBeTruthy();
return;
}

targetNodes.forEach((node) => {
const nodeTextShape = node.belongsCell.getTextShape();
const isEqualTextAlign = dataCells.every((cell) => {
return (
cell.getTextShape().attr('textAlign') ===
nodeTextShape.attr('textAlign')
);
});
expect(isEqualTextAlign).toBeTruthy();
expect(nodeTextShape.attr('fontWeight')).toStrictEqual(fontWight);
});
expect(dataCells[0].getTextShape().attr('textAlign')).toEqual(textAlign);
};

it('should default align column headers with data cells', () => {
expectTextAlign({
textAlign: 'right',
fontWight: 'normal',
containsDataCells: true,
});
});

it('should render normal font wight and left text align text with row cells', () => {
s2.setDataCfg({
fields: {
valueInCols: false,
},
} as S2DataConfig);

s2.render();

const rowMeasureFields = s2
.getRowNodes()
.filter((node) => node.field === EXTRA_FIELD);

expectTextAlign({
textAlign: 'left',
fontWight: 'normal',
containsDataCells: false,
customNodes: rowMeasureFields,
});
});

it('should render normal font wight and left text align text with col cell', () => {
s2.setDataCfg({
fields: {
valueInCols: true,
},
} as S2DataConfig);

s2.render();

const colMeasureFields = s2
.getColumnNodes()
.filter((node) => node.field === EXTRA_FIELD);

expectTextAlign({
textAlign: 'right',
fontWight: 'normal',
containsDataCells: false,
customNodes: colMeasureFields,
});
});

it.each(['left', 'center', 'right'] as TextAlign[])(
'should render %s text align for column nodes',
(textAlign) => {
s2.setThemeCfg({
theme: {
colCell: {
measureText: {
textAlign,
},
},
},
});

s2.render(true);

expectTextAlign({ textAlign, fontWight: 'normal' });
},
);

it.each([
{ isRowCell: true, textAlign: 'left' },
{ isRowCell: true, textAlign: 'center' },
{ isRowCell: true, textAlign: 'right' },
{ isRowCell: false, textAlign: 'left' },
{ isRowCell: false, textAlign: 'center' },
{ isRowCell: false, textAlign: 'right' },
] as Array<{ isRowCell: boolean; textAlign: TextAlign }>)(
'should render %s text align for totals nodes',
({ isRowCell, textAlign }) => {
s2.setOptions({
totals: {
col: {
showGrandTotals: true,
showSubTotals: true,
reverseLayout: true,
reverseSubLayout: false,
},
row: {
showGrandTotals: true,
showSubTotals: true,
reverseLayout: true,
reverseSubLayout: false,
},
},
});

s2.setThemeCfg({
theme: {
colCell: {
// 小计/总计是加粗字体
bolderText: {
textAlign,
},
},
rowCell: {
bolderText: {
textAlign,
},
},
},
});

s2.render();

const rowTotalNodes = s2.getRowNodes().filter((node) => node.isTotals);

const colTotalNodes = s2
.getColumnNodes()
.filter((node) => node.isTotals);

expectTextAlign({
textAlign,
fontWight: 520,
customNodes: isRowCell ? rowTotalNodes : colTotalNodes,
});
},
);

it('should not align column headers with data cells and render normal font wight leaf node text if hideMeasureColumn', () => {
s2.setOptions({
style: {
colCfg: {
hideMeasureColumn: true,
},
},
totals: null,
});
s2.render();

expectTextAlign({
textAlign: 'center',
fontWight: 'normal',
});
});
});
});
4 changes: 4 additions & 0 deletions packages/s2-core/src/cell/base-cell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -306,4 +306,8 @@ export abstract class BaseCell<T extends SimpleBBox> extends Group {
updateShapeAttr(this.textShape, SHAPE_STYLE_MAP.textOpacity, 1);
updateShapeAttr(this.linkFieldShape, SHAPE_STYLE_MAP.opacity, 1);
}

public getTextShape() {
return this.textShape;
}
}
41 changes: 16 additions & 25 deletions packages/s2-core/src/cell/col-cell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ import {
CellBorderPosition,
DefaultCellTheme,
IconTheme,
TextAlign,
TextBaseline,
TextTheme,
} from '@/common/interface';
import { AreaRange } from '@/common/interface/scroll';
Expand All @@ -26,7 +24,7 @@ import {
getTextAndFollowingIconPosition,
getTextAreaRange,
adjustColHeaderScrollingViewport,
adjustColHeaderScrollingTextPostion,
adjustColHeaderScrollingTextPosition,
} from '@/utils/cell/cell';
import { renderIcon, renderLine, renderRect } from '@/utils/g-renders';
import { isLastColumnAfterHidden } from '@/utils/hide-columns';
Expand Down Expand Up @@ -88,29 +86,19 @@ export class ColCell extends HeaderCell {
);
}

private getOriginalTextStyle(): TextTheme {
protected getTextStyle(): TextTheme {
const { isLeaf, isTotals } = this.meta;
const { text, bolderText } = this.getStyle();
return isLeaf && !isTotals ? text : bolderText;
}
const { text, bolderText, measureText } = this.getStyle();

protected getTextStyle(): TextTheme {
const { isLeaf } = this.meta;
const textStyle = this.getOriginalTextStyle();
const hideMeasureColumn =
this.spreadsheet.options.style.colCfg.hideMeasureColumn;
let textAlign: TextAlign;
let textBaseline: TextBaseline;
if (isLeaf && !hideMeasureColumn) {
textAlign = this.theme.dataCell.text.textAlign;
textBaseline = this.theme.dataCell.text.textBaseline;
} else {
// 为方便 getTextAreaRange 计算文字位置
// textAlign 固定为 center
textAlign = 'center';
textBaseline = 'middle';
if (this.isMeasureField()) {
return measureText || text;
}

if (isTotals || !isLeaf) {
return bolderText;
}
return { ...textStyle, textAlign, textBaseline };

return text;
}

protected getMaxTextWidth(): number {
Expand All @@ -121,16 +109,19 @@ export class ColCell extends HeaderCell {
protected getIconPosition(): Point {
const { isLeaf } = this.meta;
const iconStyle = this.getIconStyle();

if (isLeaf) {
return super.getIconPosition(this.getActionIconsCount());
}

const position = this.textAreaPosition;

const totalSpace =
this.actualTextWidth +
this.getActionIconsWidth() -
iconStyle.margin.right;
const startX = position.x - totalSpace / 2;

return {
x: startX + this.actualTextWidth + iconStyle.margin.left,
y: position.y - iconStyle.size / 2,
Expand Down Expand Up @@ -175,7 +166,7 @@ export class ColCell extends HeaderCell {
width: width + (scrollContainsRowHeader ? cornerWidth : 0),
};

const { textAlign } = this.getOriginalTextStyle();
const { textAlign } = this.getTextStyle();
const adjustedViewport = adjustColHeaderScrollingViewport(
viewport,
textAlign,
Expand All @@ -196,7 +187,7 @@ export class ColCell extends HeaderCell {

// textAreaRange.start 是以文字样式为 center 计算出的文字绘制点
// 此处按实际样式(left or right)调整
const startX = adjustColHeaderScrollingTextPostion(
const startX = adjustColHeaderScrollingTextPosition(
textAreaRange.start,
textAreaRange.width - textAndIconSpace,
textAlign,
Expand Down
7 changes: 5 additions & 2 deletions packages/s2-core/src/cell/header-cell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,10 @@ import {
import { BaseHeaderConfig } from '@/facet/header/base';
import { Node } from '@/facet/layout/node';
import { includeCell } from '@/utils/cell/data-cell';
import { S2Event } from '@/common/constant';
import { EXTRA_FIELD, S2Event } from '@/common/constant';
import { CellTypes } from '@/common/constant';
import { getSortTypeIcon } from '@/utils/sort-action';
import { SortParam } from '@/common/interface';
import { TableColCell } from '@/cell/table-col-cell';

export abstract class HeaderCell extends BaseCell<Node> {
protected headerConfig: BaseHeaderConfig;
Expand Down Expand Up @@ -300,4 +299,8 @@ export abstract class HeaderCell extends BaseCell<Node> {
public hideInteractionShape() {
super.hideInteractionShape();
}

public isMeasureField() {
return this.meta.field === EXTRA_FIELD;
}
}
16 changes: 10 additions & 6 deletions packages/s2-core/src/cell/row-cell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -359,13 +359,17 @@ export class RowCell extends HeaderCell {
}

protected getTextStyle(): TextTheme {
const { text, bolderText } = this.getStyle();
const style = this.isBolderText() ? bolderText : text;
const { text, bolderText, measureText } = this.getStyle();

return {
...style,
textBaseline: 'top',
};
if (this.isMeasureField()) {
return measureText || text;
}

if (this.isBolderText()) {
return bolderText;
}

return text;
}

protected getIconPosition() {
Expand Down
2 changes: 2 additions & 0 deletions packages/s2-core/src/common/interface/theme.ts
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,8 @@ export interface DefaultCellTheme extends GridAnalysisCellTheme {
bolderText?: TextTheme;
/* 文本样式 */
text?: TextTheme;
/* 度量值文本样式 */
measureText?: TextTheme;
/* 单元格样式 */
cell?: CellTheme;
/* 图标样式 */
Expand Down
Loading

0 comments on commit 98d3387

Please sign in to comment.