Skip to content

Commit

Permalink
fix: invisible axis labels after data changed (#328)
Browse files Browse the repository at this point in the history
* fix: invisible axis labels after data changed

* test: add test

* fix: cancel eager handling

---------

Co-authored-by: Aaron <[email protected]>
Co-authored-by: hustcc <[email protected]>
  • Loading branch information
3 people authored Dec 9, 2024
1 parent 2606484 commit b2c4352
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 26 deletions.
95 changes: 95 additions & 0 deletions __tests__/bugs/issue-g2-6373.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { IElement, Rect } from '@antv/g';
import { Axis } from '../../src';
import { onAnimatesFinished } from '../../src/animation';
import { createCanvas } from '../utils/render';
import { CLASS_NAMES } from '../../src/ui/axis/constant';

const isVisible = (item: IElement) => {
return item.getAttribute('visibility') === 'visible';
};

const canvas = createCanvas(523, 'svg');

describe('G2 6373', () => {
it('basic', async () => {
const data1 = [
{ label: '2024-01', value: 0.2, id: '1' },
{ label: '2024-02', value: 0.4, id: '2' },
{ label: '2024-03', value: 0.8, id: '3' },
];

const data2 = [
{ label: '2024-01', value: 0.4, id: '1' },
{ label: '2024-03', value: 0.7, id: '2' },
];

const fontSize = 12;

const axis = new Axis({
style: {
animate: { duration: 300 },
labelOverlap: [{ type: 'hide' }],
labelFormatter: (d) => {
const rect = new Rect({
style: {
x: 0,
y: 0,
opacity: 1,
width: ((d.label?.toString() ?? '').length * fontSize) / 2,
height: fontSize,
},
});
return rect;
},
showLabel: true,
showGrid: false,
showTick: true,
showLine: true,
data: data1,
endPos: [300, 50],
labelAlign: 'horizontal',
labelDirection: 'positive',
labelFill: '#000',
labelFillOpacity: 0.65,
labelFontSize: fontSize,
labelFontWeight: 'lighter',
labelSpacing: 12,
labelTransform: 'translate(-50%, 0)',
lineArrow: undefined,
lineLineWidth: 0.5,
lineOpacity: 0,
lineStroke: '#000',
lineStrokeOpacity: 0.45,
startPos: [45, 50],
tickDirection: 'positive',
tickLength: 4,
tickLineWidth: 1,
tickStroke: '#000',
tickStrokeOpacity: 0.25,
type: 'linear',
},
});

canvas.appendChild(axis);

let items = axis.querySelectorAll(CLASS_NAMES.labelItem.class);

expect(items.length).toBe(3);

expect(items.every(isVisible)).toBe(true);

const updateRes = axis.update({ data: data2 });

if (updateRes) {
await new Promise<void>((res) => {
onAnimatesFinished(updateRes, res);
});
}

items = axis.querySelectorAll(CLASS_NAMES.labelItem.class);

expect(items.length).toBe(2);

expect(items.every(isVisible)).toBe(true);
});
});
45 changes: 22 additions & 23 deletions src/ui/axis/guides/labels.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { IAnimation } from '@antv/g';
import { get, isFunction } from '@antv/util';
import { flatten, get, isFunction } from '@antv/util';
import type { StandardAnimationOption } from '../../../animation';
import { fadeOut, onAnimateFinished, onAnimatesFinished, transition, transitionShape } from '../../../animation';
import type { DisplayObject, TextStyleProps } from '../../../shapes';
Expand Down Expand Up @@ -223,7 +223,8 @@ export function renderLabels(
) {
const finalData = filterExec(data, attr.labelFilter);
const style = subStyleProps<AxisLabelStyleProps>(attr, 'label');
return container
let _exit!: Selection<AxisDatum>;
const transitions = container
.selectAll(CLASS_NAMES.label.class)
.data(finalData, (d, i) => i)
.join(
Expand All @@ -237,33 +238,31 @@ export function renderLabels(
// .axis-label
this.style.transform = `translate(${x}, ${y})`;
return null;
})
.call(() => {
overlapHandler.call(container, attr);
}),
(update) =>
update
.transition(function (datum) {
const prevLabel = this.querySelector(CLASS_NAMES.labelItem.class);
const label = renderLabel(this, datum, data, style, attr);
const shapeAnimation = transitionShape(prevLabel, label, animate.update);
const { x, y } = getLabelPos(datum, data, attr);
const animation = transition(this, { transform: `translate(${x}, ${y})` }, animate.update);
return [...shapeAnimation, animation];
// return [animation];
})
.call((selection) => {
const transitions = get(selection, '_transitions').flat().filter(defined) as IAnimation[];
onAnimatesFinished(transitions, () => {
overlapHandler.call(container, attr);
});
}),
(exit) =>
update.transition(function (datum) {
const prevLabel = this.querySelector(CLASS_NAMES.labelItem.class);
const label = renderLabel(this, datum, data, style, attr);
const shapeAnimation = transitionShape(prevLabel, label, animate.update);
const { x, y } = getLabelPos(datum, data, attr);
const animation = transition(this, { transform: `translate(${x}, ${y})` }, animate.update);
return [...shapeAnimation, animation];
// return [animation];
}),
(exit) => {
_exit = exit;
exit.transition(function () {
const animation = fadeOut(this.childNodes[0], animate.exit);
onAnimateFinished(animation, () => select(this).remove());
return animation;
})
});
return _exit;
}
)
.transitions();
// handle overlapping after transitions finished
onAnimatesFinished(transitions, () => {
overlapHandler.call(container, attr);
});
return transitions;
}
10 changes: 7 additions & 3 deletions src/util/selection.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// @ts-nocheck
import type { IAnimation, IDocument } from '@antv/g';
import { flatten } from '@antv/util';
import type { AnimationResult } from '../animation';
import type { BaseStyleProps as BP, DisplayObject } from '../shapes';
import { Circle, Ellipse, Group, HTML, Image, Line, Path, Polygon, Polyline, Rect, Text } from '../shapes';
Expand Down Expand Up @@ -356,11 +357,14 @@ export class Selection<T = any> {
});
}

transition(callback?: (datum: T, index: number) => (null | IAnimation) | (null | IAnimation)[]): Selection<T> {
transition(callback?: (datum: T, index: number) => AnimationResult | AnimationResult[]): Selection<T> {
const { _transitions: T } = this;
return this.each(function (d, i) {
T[i] = callback.call(this, d, i);
const newTransitions = new Array<ReturnType<Exclude<typeof callback, undefined>>>(this._elements.length);
this.each(function (d, i) {
newTransitions[i] = callback.call(this, d, i);
});
this._transitions = flatten(newTransitions);
return this;
}

on(event: string, handler: any) {
Expand Down

0 comments on commit b2c4352

Please sign in to comment.