Skip to content

Commit f2baf69

Browse files
committed
feat: fix bug of stackCornerRadius
1 parent 99da42a commit f2baf69

2 files changed

Lines changed: 110 additions & 2 deletions

File tree

packages/vrender-animate/__tests__/unit/animation-runtime-attribute.test.ts

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -882,6 +882,82 @@ describe('D3 pre-handoff animation runtime', () => {
882882
expect(rect.getFinalAttribute().width).toBe(resized.width);
883883
});
884884

885+
test('superseded executor update cannot commit stale layout when it ends late', () => {
886+
const { group, ticker, graphicService } = createStageHarness('executor-update-stale-end');
887+
const threeItemLayout = {
888+
x: 76.61875,
889+
y: 0,
890+
y1: 320,
891+
width: 41.5125,
892+
visible: true
893+
};
894+
const fourItemLayout = {
895+
x: 73.54375,
896+
y: 0,
897+
y1: 320,
898+
width: 32.2875,
899+
visible: true
900+
};
901+
const rect = createRect(threeItemLayout);
902+
bindGraphicService(rect as any, graphicService);
903+
rect.setFinalAttributes(threeItemLayout);
904+
group.appendChild(rect);
905+
906+
(rect as any).context = {
907+
animationState: 'update',
908+
data: [{ value: 10 }],
909+
diffAttrs: {
910+
x: fourItemLayout.x,
911+
width: fourItemLayout.width
912+
},
913+
finalAttrs: fourItemLayout
914+
};
915+
rect.setFinalAttributes(fourItemLayout);
916+
new AnimateExecutor(rect).execute({
917+
type: 'update',
918+
duration: 200,
919+
easing: 'linear'
920+
});
921+
922+
tick(ticker, 50);
923+
expect(rect.attribute.x).toBeLessThan(threeItemLayout.x);
924+
expect(rect.attribute.x).toBeGreaterThan(fourItemLayout.x);
925+
expect(rect.attribute.width).toBeLessThan(threeItemLayout.width);
926+
expect(rect.attribute.width).toBeGreaterThan(fourItemLayout.width);
927+
928+
(rect as any).context = {
929+
animationState: 'update',
930+
data: [{ value: 10 }],
931+
diffAttrs: {
932+
x: threeItemLayout.x,
933+
width: threeItemLayout.width
934+
},
935+
finalAttrs: threeItemLayout
936+
};
937+
rect.setFinalAttributes(threeItemLayout);
938+
new AnimateExecutor(rect).execute({
939+
type: 'update',
940+
duration: 100,
941+
easing: 'linear'
942+
});
943+
944+
tick(ticker, 100);
945+
expect(rect.attribute.x).toBeCloseTo(threeItemLayout.x, 5);
946+
expect(rect.attribute.width).toBeCloseTo(threeItemLayout.width, 5);
947+
expect((rect as any).baseAttributes.x).toBeCloseTo(threeItemLayout.x, 5);
948+
expect((rect as any).baseAttributes.width).toBeCloseTo(threeItemLayout.width, 5);
949+
expect(rect.getFinalAttribute().x).toBeCloseTo(threeItemLayout.x, 5);
950+
expect(rect.getFinalAttribute().width).toBeCloseTo(threeItemLayout.width, 5);
951+
952+
tick(ticker, 50);
953+
expect(rect.attribute.x).toBeCloseTo(threeItemLayout.x, 5);
954+
expect(rect.attribute.width).toBeCloseTo(threeItemLayout.width, 5);
955+
expect((rect as any).baseAttributes.x).toBeCloseTo(threeItemLayout.x, 5);
956+
expect((rect as any).baseAttributes.width).toBeCloseTo(threeItemLayout.width, 5);
957+
expect(rect.getFinalAttribute().x).toBeCloseTo(threeItemLayout.x, 5);
958+
expect(rect.getFinalAttribute().width).toBeCloseTo(threeItemLayout.width, 5);
959+
});
960+
885961
test('switching states mid-animation restores to the new static truth and blocks late writes', () => {
886962
const { group, ticker, graphicService } = createStageHarness('state-conflict');
887963
const rect = createAnimatedRect(graphicService);

packages/vrender-animate/src/custom/update.ts

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,46 @@ export class Update extends ACustomAnimate<Record<string, number>> {
3737
this.props = diffAttrs;
3838
}
3939

40+
private getStaticCommitAttrs(): Record<string, any> | null {
41+
if (!this.props) {
42+
return null;
43+
}
44+
45+
const target = this.target as any;
46+
const contextFinalAttrs = target.context?.finalAttrs as Record<string, any> | undefined;
47+
const finalAttribute = (
48+
typeof target.getFinalAttribute === 'function' ? target.getFinalAttribute() : target.finalAttribute
49+
) as Record<string, any> | undefined;
50+
const commitAttrs: Record<string, any> = {};
51+
52+
Object.keys(this.props).forEach(key => {
53+
if (contextFinalAttrs && Object.prototype.hasOwnProperty.call(contextFinalAttrs, key)) {
54+
commitAttrs[key] = contextFinalAttrs[key];
55+
return;
56+
}
57+
58+
if (finalAttribute && Object.prototype.hasOwnProperty.call(finalAttribute, key)) {
59+
commitAttrs[key] = finalAttribute[key];
60+
return;
61+
}
62+
63+
if (this.animate.validAttr(key)) {
64+
commitAttrs[key] = (this.props as Record<string, any>)[key];
65+
}
66+
});
67+
68+
return Object.keys(commitAttrs).length ? commitAttrs : null;
69+
}
70+
4071
onEnd(cb?: (animate: IAnimate, step: IStep) => void): void {
4172
if (cb) {
4273
super.onEnd(cb);
4374
return;
4475
}
4576

46-
if (this.props && Object.keys(this.props).length) {
47-
this.target.setAttributes(this.props, false, { type: AttributeUpdateType.ANIMATE_END });
77+
const commitAttrs = this.getStaticCommitAttrs();
78+
if (commitAttrs) {
79+
this.target.setAttributes(commitAttrs, false, { type: AttributeUpdateType.ANIMATE_END });
4880
}
4981
super.onEnd();
5082
}

0 commit comments

Comments
 (0)