Skip to content

Commit c5e1697

Browse files
Revert performance improvements in this PR. Fix text measuring bugs.
1 parent d865d60 commit c5e1697

File tree

3 files changed

+46
-45
lines changed

3 files changed

+46
-45
lines changed

packages/x-charts/src/ChartsXAxis/ChartsXAxis.tsx

+28-41
Original file line numberDiff line numberDiff line change
@@ -37,80 +37,63 @@ type LabelExtraData = { width: number; height: number; skipLabel?: boolean };
3737
function addLabelDimension(
3838
xTicks: TickItemType[],
3939
{
40+
tickLabelClassName: className,
4041
tickLabelStyle: style,
4142
tickLabelInterval,
4243
// FIXME: Define the default value in the correct place
4344
minTickLabelGap = 8,
4445
reverse,
4546
isMounted,
46-
isPointInside,
4747
}: Pick<ChartsXAxisProps, 'tickLabelInterval' | 'tickLabelStyle'> &
4848
Pick<AxisDefaultized<ScaleName, any, ChartsXAxisProps>, 'reverse' | 'minTickLabelGap'> & {
49+
tickLabelClassName?: string;
4950
isMounted: boolean;
50-
isPointInside: (position: number) => boolean;
5151
},
5252
): (TickItemType & LabelExtraData)[] {
53-
const getTickLabelSize = (tick: TickItemType) => {
53+
const withDimension = xTicks.map((tick) => {
5454
if (!isMounted || tick.formattedValue === undefined) {
55-
return { width: 0, height: 0 };
55+
return { ...tick, width: 0, height: 0 };
5656
}
57-
58-
const tickSizes = getWordsByLines({ style, needsComputation: true, text: tick.formattedValue });
59-
57+
const tickSizes = getWordsByLines({
58+
className,
59+
style,
60+
needsComputation: true,
61+
text: tick.formattedValue,
62+
});
6063
return {
64+
...tick,
6165
width: Math.max(...tickSizes.map((size) => size.width)),
6266
height: Math.max(tickSizes.length * tickSizes[0].height),
6367
};
64-
};
68+
});
6569

6670
if (typeof tickLabelInterval === 'function') {
67-
return xTicks.map((item, index) => {
68-
const skipLabel = !tickLabelInterval(item.value, index);
69-
const size = skipLabel ? { width: 0, height: 0 } : getTickLabelSize(item);
70-
71-
return {
72-
...item,
73-
...size,
74-
skipLabel,
75-
};
76-
});
71+
return withDimension.map((item, index) => ({
72+
...item,
73+
skipLabel: !tickLabelInterval(item.value, index),
74+
}));
7775
}
7876

7977
// Filter label to avoid overlap
8078
let previousTextLimit = 0;
8179
const direction = reverse ? -1 : 1;
82-
83-
return xTicks.map((item, labelIndex) => {
84-
const { offset, labelOffset } = item;
85-
const textPosition = offset + labelOffset;
86-
87-
if (
88-
labelIndex > 0 &&
89-
direction * (textPosition - minTickLabelGap) < direction * previousTextLimit
90-
) {
91-
return { ...item, width: 0, height: 0, skipLabel: true };
92-
}
93-
94-
if (!isPointInside(textPosition)) {
95-
return { ...item, width: 0, height: 0, skipLabel: true };
96-
}
97-
98-
const { width, height } = getTickLabelSize(item);
80+
return withDimension.map((item, labelIndex) => {
81+
const { width, offset, labelOffset, height } = item;
9982

10083
const distance = getMinXTranslation(width, height, style?.angle);
84+
const textPosition = offset + labelOffset;
10185

10286
const currentTextLimit = textPosition - (direction * distance) / 2;
10387
if (
10488
labelIndex > 0 &&
105-
direction * (currentTextLimit - minTickLabelGap) < direction * previousTextLimit
89+
direction * currentTextLimit < direction * (previousTextLimit + minTickLabelGap)
10690
) {
10791
// Except for the first label, we skip all label that overlap with the last accepted.
10892
// Notice that the early return prevents `previousTextLimit` from being updated.
109-
return { ...item, width, height, skipLabel: true };
93+
return { ...item, skipLabel: true };
11094
}
111-
11295
previousTextLimit = textPosition + (direction * distance) / 2;
113-
return { ...item, width, height };
96+
return item;
11497
});
11598
}
11699

@@ -186,6 +169,11 @@ function ChartsXAxis(inProps: ChartsXAxisProps) {
186169
externalSlotProps: slotProps?.axisTickLabel,
187170
additionalProps: {
188171
style: {
172+
fontFamily: '"Roboto", "Helvetica", "Arial", sans-serif',
173+
fontWeight: 400,
174+
lineHeight: 1.66,
175+
letterSpacing: '0.03333em',
176+
fill: 'rgba(0, 0, 0, 0.87)',
189177
fontSize: 12,
190178
textAnchor: 'middle',
191179
dominantBaseline: position === 'bottom' ? 'hanging' : 'auto',
@@ -206,12 +194,11 @@ function ChartsXAxis(inProps: ChartsXAxisProps) {
206194
});
207195

208196
const xTicksWithDimension = addLabelDimension(xTicks, {
197+
tickLabelClassName: axisTickLabelProps.className,
209198
tickLabelStyle: axisTickLabelProps.style,
210199
tickLabelInterval,
211200
reverse,
212201
isMounted,
213-
isPointInside: (offset: number) =>
214-
instance.isPointInside({ x: offset, y: -1 }, { direction: 'x' }),
215202
});
216203

217204
const labelRefPoint = {

packages/x-charts/src/internals/domUtils.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -98,20 +98,24 @@ export const getStyleString = (style: React.CSSProperties) =>
9898
);
9999

100100
let domCleanTimeout: NodeJS.Timeout | undefined;
101-
102101
/**
103102
*
104103
* @param text The string to estimate
105104
* @param style The style applied
106105
* @returns width and height of the text
107106
*/
108-
export const getStringSize = (text: string | number, style: React.CSSProperties = {}) => {
107+
export const getStringSize = (
108+
text: string | number,
109+
{ className = '', style = {} }: { className?: string; style?: React.CSSProperties },
110+
) => {
109111
if (text === undefined || text === null || isSsr()) {
110112
return { width: 0, height: 0 };
111113
}
112114

113115
const str = `${text}`;
114116
const styleString = getStyleString(style);
117+
// FIXME: How to handle the className in cache? The class name be the same, but the style it's applying can change,
118+
// however this wouldn't cause the cache to be invalidated, resulting in wrong sizes.
115119
const cacheKey = `${str}-${styleString}`;
116120

117121
if (stringCache.widthCache[cacheKey]) {
@@ -130,6 +134,7 @@ export const getStringSize = (text: string | number, style: React.CSSProperties
130134
// https://en.wikipedia.org/wiki/Content_Security_Policy
131135
const measurementSpanStyle: Record<string, any> = { ...SPAN_STYLE, ...style };
132136

137+
measurementSpan.className = className;
133138
Object.keys(measurementSpanStyle).map((styleKey) => {
134139
(measurementSpan!.style as Record<string, any>)[camelToMiddleLine(styleKey)] =
135140
autoCompleteStyle(styleKey, measurementSpanStyle[styleKey]);

packages/x-charts/src/internals/getWordsByLines.ts

+11-2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ export interface ChartsTextStyle extends React.CSSProperties {
1212
}
1313

1414
export interface GetWordsByLinesParams {
15+
/**
16+
* CSS class applied to text elements.
17+
*/
18+
className?: string;
1519
/**
1620
* Text displayed.
1721
*/
@@ -27,9 +31,14 @@ export interface GetWordsByLinesParams {
2731
needsComputation?: boolean;
2832
}
2933

30-
export function getWordsByLines({ style, needsComputation, text }: GetWordsByLinesParams) {
34+
export function getWordsByLines({
35+
className,
36+
style,
37+
needsComputation,
38+
text,
39+
}: GetWordsByLinesParams) {
3140
return text.split('\n').map((subText) => ({
3241
text: subText,
33-
...(needsComputation ? getStringSize(subText, style) : { width: 0, height: 0 }),
42+
...(needsComputation ? getStringSize(subText, { className, style }) : { width: 0, height: 0 }),
3443
}));
3544
}

0 commit comments

Comments
 (0)