Skip to content

Commit ef3f99e

Browse files
authored
feat(theme): 新增度量值的主题配置, 修复小计总计主题配置不生效 close #1357 (#1364)
* feat(theme): 新增度量值的主题配置, 修复小计总计主题配置不生效 close #1357 * test: 增加主题测试
1 parent 264a9e9 commit ef3f99e

File tree

13 files changed

+282
-47
lines changed

13 files changed

+282
-47
lines changed

packages/s2-core/__tests__/spreadsheet/theme-spec.ts

Lines changed: 203 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
1-
import { getContainer } from 'tests/util/helpers';
2-
import { assembleDataCfg, assembleOptions } from 'tests/util';
1+
/* eslint-disable jest/expect-expect */
2+
import { createPivotSheet } from 'tests/util/helpers';
33
import { get } from 'lodash';
44
import { ShapeAttrs } from '@antv/g-canvas';
5+
import { S2DataConfig } from './../../esm/common/interface/s2DataConfig.d';
6+
import { TextTheme } from '@/common/interface/theme';
57
import { PivotSheet } from '@/sheet-type';
6-
import { CellTypes, TextAlign } from '@/common';
8+
import { CellTypes, EXTRA_FIELD, TextAlign } from '@/common';
79
import { RowCell } from '@/cell';
10+
import { Node } from '@/facet/layout/node';
811

912
describe('SpreadSheet Theme Tests', () => {
1013
let s2: PivotSheet;
11-
const dataCfg = assembleDataCfg();
1214

1315
beforeAll(() => {
14-
s2 = new PivotSheet(
15-
getContainer(),
16-
dataCfg,
17-
assembleOptions({
16+
s2 = createPivotSheet(
17+
{
1818
headerActionIcons: [
1919
{
2020
iconNames: ['DrillDownIcon'],
@@ -23,8 +23,11 @@ describe('SpreadSheet Theme Tests', () => {
2323
action: () => {},
2424
},
2525
],
26-
}),
26+
},
27+
{ useSimpleData: false },
2728
);
29+
30+
s2.render();
2831
});
2932

3033
afterAll(() => {
@@ -135,4 +138,195 @@ describe('SpreadSheet Theme Tests', () => {
135138
},
136139
);
137140
});
141+
142+
describe('Measure Fields Theme Tests', () => {
143+
const expectTextAlign = (options: {
144+
textAlign: TextAlign;
145+
fontWight: TextTheme['fontWeight'];
146+
containsDataCells?: boolean;
147+
customNodes?: Node[];
148+
}) => {
149+
const {
150+
textAlign,
151+
fontWight,
152+
containsDataCells = false,
153+
customNodes,
154+
} = options;
155+
const targetNodes = customNodes || s2.getColumnLeafNodes();
156+
const dataCells = s2.interaction.getPanelGroupAllDataCells();
157+
158+
expect(targetNodes).not.toHaveLength(0);
159+
160+
if (!containsDataCells) {
161+
expect(
162+
targetNodes.every((node) => {
163+
const nodeTextShape = node.belongsCell.getTextShape();
164+
return (
165+
nodeTextShape.attr('textAlign') === textAlign &&
166+
nodeTextShape.attr('fontWeight') === fontWight
167+
);
168+
}),
169+
).toBeTruthy();
170+
return;
171+
}
172+
173+
targetNodes.forEach((node) => {
174+
const nodeTextShape = node.belongsCell.getTextShape();
175+
const isEqualTextAlign = dataCells.every((cell) => {
176+
return (
177+
cell.getTextShape().attr('textAlign') ===
178+
nodeTextShape.attr('textAlign')
179+
);
180+
});
181+
expect(isEqualTextAlign).toBeTruthy();
182+
expect(nodeTextShape.attr('fontWeight')).toStrictEqual(fontWight);
183+
});
184+
expect(dataCells[0].getTextShape().attr('textAlign')).toEqual(textAlign);
185+
};
186+
187+
it('should default align column headers with data cells', () => {
188+
expectTextAlign({
189+
textAlign: 'right',
190+
fontWight: 'normal',
191+
containsDataCells: true,
192+
});
193+
});
194+
195+
it('should render normal font wight and left text align text with row cells', () => {
196+
s2.setDataCfg({
197+
fields: {
198+
valueInCols: false,
199+
},
200+
} as S2DataConfig);
201+
202+
s2.render();
203+
204+
const rowMeasureFields = s2
205+
.getRowNodes()
206+
.filter((node) => node.field === EXTRA_FIELD);
207+
208+
expectTextAlign({
209+
textAlign: 'left',
210+
fontWight: 'normal',
211+
containsDataCells: false,
212+
customNodes: rowMeasureFields,
213+
});
214+
});
215+
216+
it('should render normal font wight and left text align text with col cell', () => {
217+
s2.setDataCfg({
218+
fields: {
219+
valueInCols: true,
220+
},
221+
} as S2DataConfig);
222+
223+
s2.render();
224+
225+
const colMeasureFields = s2
226+
.getColumnNodes()
227+
.filter((node) => node.field === EXTRA_FIELD);
228+
229+
expectTextAlign({
230+
textAlign: 'right',
231+
fontWight: 'normal',
232+
containsDataCells: false,
233+
customNodes: colMeasureFields,
234+
});
235+
});
236+
237+
it.each(['left', 'center', 'right'] as TextAlign[])(
238+
'should render %s text align for column nodes',
239+
(textAlign) => {
240+
s2.setThemeCfg({
241+
theme: {
242+
colCell: {
243+
measureText: {
244+
textAlign,
245+
},
246+
},
247+
},
248+
});
249+
250+
s2.render(true);
251+
252+
expectTextAlign({ textAlign, fontWight: 'normal' });
253+
},
254+
);
255+
256+
it.each([
257+
{ isRowCell: true, textAlign: 'left' },
258+
{ isRowCell: true, textAlign: 'center' },
259+
{ isRowCell: true, textAlign: 'right' },
260+
{ isRowCell: false, textAlign: 'left' },
261+
{ isRowCell: false, textAlign: 'center' },
262+
{ isRowCell: false, textAlign: 'right' },
263+
] as Array<{ isRowCell: boolean; textAlign: TextAlign }>)(
264+
'should render %s text align for totals nodes',
265+
({ isRowCell, textAlign }) => {
266+
s2.setOptions({
267+
totals: {
268+
col: {
269+
showGrandTotals: true,
270+
showSubTotals: true,
271+
reverseLayout: true,
272+
reverseSubLayout: false,
273+
},
274+
row: {
275+
showGrandTotals: true,
276+
showSubTotals: true,
277+
reverseLayout: true,
278+
reverseSubLayout: false,
279+
},
280+
},
281+
});
282+
283+
s2.setThemeCfg({
284+
theme: {
285+
colCell: {
286+
// 小计/总计是加粗字体
287+
bolderText: {
288+
textAlign,
289+
},
290+
},
291+
rowCell: {
292+
bolderText: {
293+
textAlign,
294+
},
295+
},
296+
},
297+
});
298+
299+
s2.render();
300+
301+
const rowTotalNodes = s2.getRowNodes().filter((node) => node.isTotals);
302+
303+
const colTotalNodes = s2
304+
.getColumnNodes()
305+
.filter((node) => node.isTotals);
306+
307+
expectTextAlign({
308+
textAlign,
309+
fontWight: 520,
310+
customNodes: isRowCell ? rowTotalNodes : colTotalNodes,
311+
});
312+
},
313+
);
314+
315+
it('should not align column headers with data cells and render normal font wight leaf node text if hideMeasureColumn', () => {
316+
s2.setOptions({
317+
style: {
318+
colCfg: {
319+
hideMeasureColumn: true,
320+
},
321+
},
322+
totals: null,
323+
});
324+
s2.render();
325+
326+
expectTextAlign({
327+
textAlign: 'center',
328+
fontWight: 'normal',
329+
});
330+
});
331+
});
138332
});

packages/s2-core/src/cell/base-cell.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,4 +306,8 @@ export abstract class BaseCell<T extends SimpleBBox> extends Group {
306306
updateShapeAttr(this.textShape, SHAPE_STYLE_MAP.textOpacity, 1);
307307
updateShapeAttr(this.linkFieldShape, SHAPE_STYLE_MAP.opacity, 1);
308308
}
309+
310+
public getTextShape() {
311+
return this.textShape;
312+
}
309313
}

packages/s2-core/src/cell/col-cell.ts

Lines changed: 16 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,6 @@ import {
1515
CellBorderPosition,
1616
DefaultCellTheme,
1717
IconTheme,
18-
TextAlign,
19-
TextBaseline,
2018
TextTheme,
2119
} from '@/common/interface';
2220
import { AreaRange } from '@/common/interface/scroll';
@@ -26,7 +24,7 @@ import {
2624
getTextAndFollowingIconPosition,
2725
getTextAreaRange,
2826
adjustColHeaderScrollingViewport,
29-
adjustColHeaderScrollingTextPostion,
27+
adjustColHeaderScrollingTextPosition,
3028
} from '@/utils/cell/cell';
3129
import { renderIcon, renderLine, renderRect } from '@/utils/g-renders';
3230
import { isLastColumnAfterHidden } from '@/utils/hide-columns';
@@ -88,29 +86,19 @@ export class ColCell extends HeaderCell {
8886
);
8987
}
9088

91-
private getOriginalTextStyle(): TextTheme {
89+
protected getTextStyle(): TextTheme {
9290
const { isLeaf, isTotals } = this.meta;
93-
const { text, bolderText } = this.getStyle();
94-
return isLeaf && !isTotals ? text : bolderText;
95-
}
91+
const { text, bolderText, measureText } = this.getStyle();
9692

97-
protected getTextStyle(): TextTheme {
98-
const { isLeaf } = this.meta;
99-
const textStyle = this.getOriginalTextStyle();
100-
const hideMeasureColumn =
101-
this.spreadsheet.options.style.colCfg.hideMeasureColumn;
102-
let textAlign: TextAlign;
103-
let textBaseline: TextBaseline;
104-
if (isLeaf && !hideMeasureColumn) {
105-
textAlign = this.theme.dataCell.text.textAlign;
106-
textBaseline = this.theme.dataCell.text.textBaseline;
107-
} else {
108-
// 为方便 getTextAreaRange 计算文字位置
109-
// textAlign 固定为 center
110-
textAlign = 'center';
111-
textBaseline = 'middle';
93+
if (this.isMeasureField()) {
94+
return measureText || text;
95+
}
96+
97+
if (isTotals || !isLeaf) {
98+
return bolderText;
11299
}
113-
return { ...textStyle, textAlign, textBaseline };
100+
101+
return text;
114102
}
115103

116104
protected getMaxTextWidth(): number {
@@ -121,16 +109,19 @@ export class ColCell extends HeaderCell {
121109
protected getIconPosition(): Point {
122110
const { isLeaf } = this.meta;
123111
const iconStyle = this.getIconStyle();
112+
124113
if (isLeaf) {
125114
return super.getIconPosition(this.getActionIconsCount());
126115
}
116+
127117
const position = this.textAreaPosition;
128118

129119
const totalSpace =
130120
this.actualTextWidth +
131121
this.getActionIconsWidth() -
132122
iconStyle.margin.right;
133123
const startX = position.x - totalSpace / 2;
124+
134125
return {
135126
x: startX + this.actualTextWidth + iconStyle.margin.left,
136127
y: position.y - iconStyle.size / 2,
@@ -175,7 +166,7 @@ export class ColCell extends HeaderCell {
175166
width: width + (scrollContainsRowHeader ? cornerWidth : 0),
176167
};
177168

178-
const { textAlign } = this.getOriginalTextStyle();
169+
const { textAlign } = this.getTextStyle();
179170
const adjustedViewport = adjustColHeaderScrollingViewport(
180171
viewport,
181172
textAlign,
@@ -196,7 +187,7 @@ export class ColCell extends HeaderCell {
196187

197188
// textAreaRange.start 是以文字样式为 center 计算出的文字绘制点
198189
// 此处按实际样式(left or right)调整
199-
const startX = adjustColHeaderScrollingTextPostion(
190+
const startX = adjustColHeaderScrollingTextPosition(
200191
textAreaRange.start,
201192
textAreaRange.width - textAndIconSpace,
202193
textAlign,

packages/s2-core/src/cell/header-cell.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,10 @@ import {
1313
import { BaseHeaderConfig } from '@/facet/header/base';
1414
import { Node } from '@/facet/layout/node';
1515
import { includeCell } from '@/utils/cell/data-cell';
16-
import { S2Event } from '@/common/constant';
16+
import { EXTRA_FIELD, S2Event } from '@/common/constant';
1717
import { CellTypes } from '@/common/constant';
1818
import { getSortTypeIcon } from '@/utils/sort-action';
1919
import { SortParam } from '@/common/interface';
20-
import { TableColCell } from '@/cell/table-col-cell';
2120

2221
export abstract class HeaderCell extends BaseCell<Node> {
2322
protected headerConfig: BaseHeaderConfig;
@@ -300,4 +299,8 @@ export abstract class HeaderCell extends BaseCell<Node> {
300299
public hideInteractionShape() {
301300
super.hideInteractionShape();
302301
}
302+
303+
public isMeasureField() {
304+
return this.meta.field === EXTRA_FIELD;
305+
}
303306
}

packages/s2-core/src/cell/row-cell.ts

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -359,13 +359,17 @@ export class RowCell extends HeaderCell {
359359
}
360360

361361
protected getTextStyle(): TextTheme {
362-
const { text, bolderText } = this.getStyle();
363-
const style = this.isBolderText() ? bolderText : text;
362+
const { text, bolderText, measureText } = this.getStyle();
364363

365-
return {
366-
...style,
367-
textBaseline: 'top',
368-
};
364+
if (this.isMeasureField()) {
365+
return measureText || text;
366+
}
367+
368+
if (this.isBolderText()) {
369+
return bolderText;
370+
}
371+
372+
return text;
369373
}
370374

371375
protected getIconPosition() {

packages/s2-core/src/common/interface/theme.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,8 @@ export interface DefaultCellTheme extends GridAnalysisCellTheme {
213213
bolderText?: TextTheme;
214214
/* 文本样式 */
215215
text?: TextTheme;
216+
/* 度量值文本样式 */
217+
measureText?: TextTheme;
216218
/* 单元格样式 */
217219
cell?: CellTheme;
218220
/* 图标样式 */

0 commit comments

Comments
 (0)