Skip to content

Commit

Permalink
refactor: adjust animation logic (#5751)
Browse files Browse the repository at this point in the history
* refactor(transforms): transforms support receive draw context

* refactor(elements): edge update key when onframe

* refactor(elements): node/combo update key when onframe, adjust childrenNode type

* refactor(animation): adjust animation type definition

* feat(utils): add themeOf util

* feat(utils): add getElementAnimationOptions animationOf, remove unused utils

* refactor(runtime): extract animation logic into controller

* refactor(runtime): adapt new animation types

* refactor(animations): adjust animation executor

* refactor: adpat draw method

* chore: adjust toMatchSVGSnapshot

* refactor: adjust animations

* test: update test case and snapshots
  • Loading branch information
Aarebecca authored May 20, 2024
1 parent 66a8f5b commit 49e51bb
Show file tree
Hide file tree
Showing 40 changed files with 727 additions and 563 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,7 @@ export const transformProcessParallelEdges: TestCase = async (context) => {
.name('Mode')
.onChange((mode: string) => {
graph.updateTransform({ key: 'process-parallel-edges', mode });
graph.removeEdgeData(data.edges.map((edge) => edge.id));
graph.addEdgeData(data.edges);
graph.render();
graph.draw();
}),
panel
.add(
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion packages/g6/__tests__/unit/runtime/element.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ describe('ElementController', () => {

const comboStyle = elementController.getElementComputedStyle('combo', combo1);

expect(comboStyle.childrenNode[0].id).toEqual('node-3');
expect(comboStyle.childrenNode[0]).toEqual('node-3');

expect(omit(comboStyle, ['childrenNode', 'childrenData'])).toEqual({
...LIGHT_THEME.combo?.style,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { transformProcessParallelEdges } from '@/__tests__/demos';
import type { Graph } from '@/src';
import { getParallelEdges, groupByEndpoints, isParallelEdges } from '@/src/transforms/process-parallel-edges';
import data from '@@/dataset/parallel-edges.json';
import { createDemoGraph } from '@@/utils';

describe('transform-process-parallel-edges', () => {
Expand All @@ -18,9 +17,7 @@ describe('transform-process-parallel-edges', () => {
it('mode', async () => {
await expect(graph).toMatchSnapshot(__filename, 'merge-mode');
graph.updateTransform({ key: 'process-parallel-edges', mode: 'bundle' });
graph.removeEdgeData(data.edges.map((edge) => edge.id));
graph.addEdgeData(data.edges);
graph.render();
graph.draw();
await expect(graph).toMatchSnapshot(__filename, 'bundle-mode');

await expect(graph).toMatchSnapshot(__filename, 'bundle-add-orange-edge__before');
Expand Down
184 changes: 126 additions & 58 deletions packages/g6/__tests__/unit/utils/animation.spec.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { DEFAULT_ANIMATION_OPTIONS } from '@/src/constants';
import { AnimatableTask } from '@/src/types';
import type { GraphOptions } from '@/src';
import { AnimationEffectTiming } from '@/src';
import { STDAnimation } from '@/src/animations/types';
import { DEFAULT_ANIMATION_OPTIONS, DEFAULT_ELEMENTS_ANIMATION_OPTIONS } from '@/src/constants';
import { register } from '@/src/registry';
import {
createAnimationsProxy,
executeAnimatableTasks,
getAnimation,
getAnimationOptions,
getElementAnimationOptions,
inferDefaultValue,
preprocessKeyframes,
withAnimationCallbacks,
} from '@/src/utils/animation';
import type { IAnimation } from '@antv/g';

Expand Down Expand Up @@ -74,71 +76,137 @@ describe('animation', () => {
expect(inferDefaultValue('states')).toEqual([]);
});

it('withAnimationCallbacks', async () => {
const before = jest.fn();
const beforeAnimate = jest.fn();
const afterAnimate = jest.fn();
const after = jest.fn();

const callbacks = {
before: before,
beforeAnimate: beforeAnimate,
afterAnimate: afterAnimate,
after: after,
};

const animation = {
finished: Promise.resolve(),
} as unknown as IAnimation;

await withAnimationCallbacks(animation, callbacks)?.finished;
it('getAnimation', () => {
expect(getAnimationOptions({}, false)).toBe(false);
expect(getAnimationOptions({ animation: false }, true)).toBe(false);
expect(getAnimationOptions({}, true)).toEqual(DEFAULT_ANIMATION_OPTIONS);

expect(callbacks.before).toHaveBeenCalledTimes(1);
expect(callbacks.beforeAnimate).toHaveBeenCalledTimes(1);
expect(callbacks.afterAnimate).toHaveBeenCalledTimes(1);
expect(callbacks.after).toHaveBeenCalledTimes(1);
expect(getAnimationOptions({ animation: { duration: 1000 } }, true)).toEqual({
...DEFAULT_ANIMATION_OPTIONS,
duration: 1000,
});

await withAnimationCallbacks(null, callbacks)?.finished;
expect(getAnimationOptions({ animation: { duration: 1000 } }, { duration: 500, easing: 'linear' })).toEqual({
...DEFAULT_ANIMATION_OPTIONS,
duration: 500,
easing: 'linear',
});
});

expect(callbacks.before).toHaveBeenCalledTimes(2);
expect(callbacks.beforeAnimate).toHaveBeenCalledTimes(1);
expect(callbacks.afterAnimate).toHaveBeenCalledTimes(1);
expect(callbacks.after).toHaveBeenCalledTimes(2);
it('getElementAnimationOptions', () => {
// global, element, local => result
// total 2 * 3 * 3 = 18 cases
const animations: [
GraphOptions['animation'],
undefined | false | AnimationEffectTiming,
undefined | false | AnimationEffectTiming,
false | STDAnimation,
][] = [
[false, false, false, []],
[false, false, undefined, []],
[false, undefined, false, []],
[false, undefined, undefined, []],
[undefined, false, false, []],
[undefined, false, undefined, []],
[undefined, undefined, false, []],
[undefined, undefined, undefined, []],
[{ duration: 1000 }, undefined, undefined, []],
[false, undefined, undefined, []],
[undefined, { duration: 1000 }, undefined, [{ ...DEFAULT_ELEMENTS_ANIMATION_OPTIONS, fields: [] }]],
[
{ duration: 1000 },
{ duration: 500 },
undefined,
[{ ...DEFAULT_ELEMENTS_ANIMATION_OPTIONS, duration: 500, fields: [] }],
],
[
{ duration: 1000 },
{ duration: 500 },
{ duration: 200 },
[{ ...DEFAULT_ELEMENTS_ANIMATION_OPTIONS, duration: 200, fields: [] }],
],
[{ duration: 1000 }, { duration: 500 }, false, []],
[{ duration: 1000 }, false, { duration: 200 }, []],
[false, { duration: 500 }, { duration: 200 }, []],
[false, { duration: 500 }, false, []],
[{ duration: 1000 }, false, false, []],
[true, undefined, undefined, []],
[true, { duration: 500 }, undefined, [{ ...DEFAULT_ELEMENTS_ANIMATION_OPTIONS, duration: 500, fields: [] }]],
[
true,
{ duration: 500 },
{ duration: 200 },
[{ ...DEFAULT_ELEMENTS_ANIMATION_OPTIONS, duration: 200, fields: [] }],
],
[true, false, { duration: 200 }, []],
];

const stage = 'update' as const;
const elementType = 'node' as const;
for (const [global, element, local, result] of animations) {
expect(
getElementAnimationOptions(
{
animation: global,
[elementType]: {
animation: {
...(element === false
? { [stage]: false }
: element === undefined
? {}
: { [stage]: [{ ...element, fields: [] }] }),
},
},
},
elementType,
stage,
local,
),
).toEqual(result);
}
});

it('executeAnimatableTasks', async () => {
const before = jest.fn();
const after = jest.fn();
it('getElementAnimationOptions in theme', () => {
const stage = 'update' as const;

const task = jest.fn(() => () => {
return {
finished: Promise.resolve(),
} as unknown as IAnimation;
register('theme', 'test-element-animation', {
node: { animation: { [stage]: false } },
edge: { animation: false },
combo: {
animation: { [stage]: [{ fields: ['d', 'stroke'], shape: 'key', duration: 2000 }] },
},
});

const tasks: AnimatableTask[] = [task];

await executeAnimatableTasks(tasks, { before, after })?.finished;

expect(before).toHaveBeenCalledTimes(1);
expect(task).toHaveBeenCalledTimes(1);
expect(after).toHaveBeenCalledTimes(1);
expect(getElementAnimationOptions({ theme: 'test-element-animation' }, 'node', stage)).toEqual([]);
expect(getElementAnimationOptions({ theme: 'test-element-animation' }, 'edge', stage)).toEqual([]);
expect(getElementAnimationOptions({ theme: 'test-element-animation' }, 'combo', stage)).toEqual([
{ ...DEFAULT_ELEMENTS_ANIMATION_OPTIONS, fields: ['d', 'stroke'], shape: 'key', duration: 2000 },
]);
});

it('getAnimation', () => {
expect(getAnimation({ animation: true }, false)).toBe(false);
expect(getAnimation({ animation: false }, true)).toBe(false);
expect(getAnimation({ animation: true }, true)).toEqual(DEFAULT_ANIMATION_OPTIONS);
it('getElementAnimationOptions mixin', () => {
const stage = 'update' as const;

expect(getAnimation({ animation: { duration: 1000 } }, true)).toEqual({
...DEFAULT_ANIMATION_OPTIONS,
duration: 1000,
register('theme', 'test-element-animation-mixin', {
node: { animation: { [stage]: false } },
edge: { animation: false },
combo: {
animation: { [stage]: [{ fields: ['d', 'stroke'], shape: 'key', duration: 2000 }] },
},
});

expect(getAnimation({ animation: { duration: 1000 } }, { duration: 500, easing: 'linear' })).toEqual({
...DEFAULT_ANIMATION_OPTIONS,
duration: 500,
easing: 'linear',
});
const options = {
theme: 'test-element-animation-mixin',
node: {
animation: {
enter: [{ fields: ['x', 'y'], duration: 1000 }],
},
},
};

expect(getElementAnimationOptions(options, 'node', stage)).toEqual([]);
expect(getElementAnimationOptions(options, 'node', 'enter')).toEqual([
{ ...DEFAULT_ELEMENTS_ANIMATION_OPTIONS, fields: ['x', 'y'], duration: 1000 },
]);
});
});
14 changes: 14 additions & 0 deletions packages/g6/__tests__/unit/utils/theme.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { register } from '@/src/registry';
import { themeOf } from '@/src/utils/theme';

describe('theme', () => {
it('themeOf', () => {
expect(themeOf({})).toEqual({});
expect(themeOf({ theme: 'null' })).toEqual({});

const theme = { node: {} };
register('theme', 'light', theme);

expect(themeOf({ theme: 'light' })).toBe(theme);
});
});
Loading

0 comments on commit 49e51bb

Please sign in to comment.