Skip to content

Commit b2c4352

Browse files
SociosarbisAarebeccahustcc
authored
fix: invisible axis labels after data changed (#328)
* fix: invisible axis labels after data changed * test: add test * fix: cancel eager handling --------- Co-authored-by: Aaron <yangtao.yangtao@antgroup.com> Co-authored-by: hustcc <i@hust.cc>
1 parent 2606484 commit b2c4352

3 files changed

Lines changed: 124 additions & 26 deletions

File tree

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import { IElement, Rect } from '@antv/g';
2+
import { Axis } from '../../src';
3+
import { onAnimatesFinished } from '../../src/animation';
4+
import { createCanvas } from '../utils/render';
5+
import { CLASS_NAMES } from '../../src/ui/axis/constant';
6+
7+
const isVisible = (item: IElement) => {
8+
return item.getAttribute('visibility') === 'visible';
9+
};
10+
11+
const canvas = createCanvas(523, 'svg');
12+
13+
describe('G2 6373', () => {
14+
it('basic', async () => {
15+
const data1 = [
16+
{ label: '2024-01', value: 0.2, id: '1' },
17+
{ label: '2024-02', value: 0.4, id: '2' },
18+
{ label: '2024-03', value: 0.8, id: '3' },
19+
];
20+
21+
const data2 = [
22+
{ label: '2024-01', value: 0.4, id: '1' },
23+
{ label: '2024-03', value: 0.7, id: '2' },
24+
];
25+
26+
const fontSize = 12;
27+
28+
const axis = new Axis({
29+
style: {
30+
animate: { duration: 300 },
31+
labelOverlap: [{ type: 'hide' }],
32+
labelFormatter: (d) => {
33+
const rect = new Rect({
34+
style: {
35+
x: 0,
36+
y: 0,
37+
opacity: 1,
38+
width: ((d.label?.toString() ?? '').length * fontSize) / 2,
39+
height: fontSize,
40+
},
41+
});
42+
return rect;
43+
},
44+
showLabel: true,
45+
showGrid: false,
46+
showTick: true,
47+
showLine: true,
48+
data: data1,
49+
endPos: [300, 50],
50+
labelAlign: 'horizontal',
51+
labelDirection: 'positive',
52+
labelFill: '#000',
53+
labelFillOpacity: 0.65,
54+
labelFontSize: fontSize,
55+
labelFontWeight: 'lighter',
56+
labelSpacing: 12,
57+
labelTransform: 'translate(-50%, 0)',
58+
lineArrow: undefined,
59+
lineLineWidth: 0.5,
60+
lineOpacity: 0,
61+
lineStroke: '#000',
62+
lineStrokeOpacity: 0.45,
63+
startPos: [45, 50],
64+
tickDirection: 'positive',
65+
tickLength: 4,
66+
tickLineWidth: 1,
67+
tickStroke: '#000',
68+
tickStrokeOpacity: 0.25,
69+
type: 'linear',
70+
},
71+
});
72+
73+
canvas.appendChild(axis);
74+
75+
let items = axis.querySelectorAll(CLASS_NAMES.labelItem.class);
76+
77+
expect(items.length).toBe(3);
78+
79+
expect(items.every(isVisible)).toBe(true);
80+
81+
const updateRes = axis.update({ data: data2 });
82+
83+
if (updateRes) {
84+
await new Promise<void>((res) => {
85+
onAnimatesFinished(updateRes, res);
86+
});
87+
}
88+
89+
items = axis.querySelectorAll(CLASS_NAMES.labelItem.class);
90+
91+
expect(items.length).toBe(2);
92+
93+
expect(items.every(isVisible)).toBe(true);
94+
});
95+
});

src/ui/axis/guides/labels.ts

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { IAnimation } from '@antv/g';
2-
import { get, isFunction } from '@antv/util';
2+
import { flatten, get, isFunction } from '@antv/util';
33
import type { StandardAnimationOption } from '../../../animation';
44
import { fadeOut, onAnimateFinished, onAnimatesFinished, transition, transitionShape } from '../../../animation';
55
import type { DisplayObject, TextStyleProps } from '../../../shapes';
@@ -223,7 +223,8 @@ export function renderLabels(
223223
) {
224224
const finalData = filterExec(data, attr.labelFilter);
225225
const style = subStyleProps<AxisLabelStyleProps>(attr, 'label');
226-
return container
226+
let _exit!: Selection<AxisDatum>;
227+
const transitions = container
227228
.selectAll(CLASS_NAMES.label.class)
228229
.data(finalData, (d, i) => i)
229230
.join(
@@ -237,33 +238,31 @@ export function renderLabels(
237238
// .axis-label
238239
this.style.transform = `translate(${x}, ${y})`;
239240
return null;
240-
})
241-
.call(() => {
242-
overlapHandler.call(container, attr);
243241
}),
244242
(update) =>
245-
update
246-
.transition(function (datum) {
247-
const prevLabel = this.querySelector(CLASS_NAMES.labelItem.class);
248-
const label = renderLabel(this, datum, data, style, attr);
249-
const shapeAnimation = transitionShape(prevLabel, label, animate.update);
250-
const { x, y } = getLabelPos(datum, data, attr);
251-
const animation = transition(this, { transform: `translate(${x}, ${y})` }, animate.update);
252-
return [...shapeAnimation, animation];
253-
// return [animation];
254-
})
255-
.call((selection) => {
256-
const transitions = get(selection, '_transitions').flat().filter(defined) as IAnimation[];
257-
onAnimatesFinished(transitions, () => {
258-
overlapHandler.call(container, attr);
259-
});
260-
}),
261-
(exit) =>
243+
update.transition(function (datum) {
244+
const prevLabel = this.querySelector(CLASS_NAMES.labelItem.class);
245+
const label = renderLabel(this, datum, data, style, attr);
246+
const shapeAnimation = transitionShape(prevLabel, label, animate.update);
247+
const { x, y } = getLabelPos(datum, data, attr);
248+
const animation = transition(this, { transform: `translate(${x}, ${y})` }, animate.update);
249+
return [...shapeAnimation, animation];
250+
// return [animation];
251+
}),
252+
(exit) => {
253+
_exit = exit;
262254
exit.transition(function () {
263255
const animation = fadeOut(this.childNodes[0], animate.exit);
264256
onAnimateFinished(animation, () => select(this).remove());
265257
return animation;
266-
})
258+
});
259+
return _exit;
260+
}
267261
)
268262
.transitions();
263+
// handle overlapping after transitions finished
264+
onAnimatesFinished(transitions, () => {
265+
overlapHandler.call(container, attr);
266+
});
267+
return transitions;
269268
}

src/util/selection.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// @ts-nocheck
22
import type { IAnimation, IDocument } from '@antv/g';
3+
import { flatten } from '@antv/util';
34
import type { AnimationResult } from '../animation';
45
import type { BaseStyleProps as BP, DisplayObject } from '../shapes';
56
import { Circle, Ellipse, Group, HTML, Image, Line, Path, Polygon, Polyline, Rect, Text } from '../shapes';
@@ -356,11 +357,14 @@ export class Selection<T = any> {
356357
});
357358
}
358359

359-
transition(callback?: (datum: T, index: number) => (null | IAnimation) | (null | IAnimation)[]): Selection<T> {
360+
transition(callback?: (datum: T, index: number) => AnimationResult | AnimationResult[]): Selection<T> {
360361
const { _transitions: T } = this;
361-
return this.each(function (d, i) {
362-
T[i] = callback.call(this, d, i);
362+
const newTransitions = new Array<ReturnType<Exclude<typeof callback, undefined>>>(this._elements.length);
363+
this.each(function (d, i) {
364+
newTransitions[i] = callback.call(this, d, i);
363365
});
366+
this._transitions = flatten(newTransitions);
367+
return this;
364368
}
365369

366370
on(event: string, handler: any) {

0 commit comments

Comments
 (0)