This is an automated email from the ASF dual-hosted git repository.

shenyi pushed a commit to branch graphic-animation
in repository https://gitbox.apache.org/repos/asf/echarts.git


The following commit(s) were added to refs/heads/graphic-animation by this push:
     new c46b928  feat(ani): support keyframe animation in custom series
c46b928 is described below

commit c46b92851782c562d7ffe510d0ee586f709a8f95
Author: pissang <[email protected]>
AuthorDate: Fri Dec 3 14:59:23 2021 +0800

    feat(ani): support keyframe animation in custom series
    
    support multiple keyframe animation
---
 src/animation/customGraphicKeyframeAnimation.ts | 19 ++++--
 src/chart/custom/CustomSeries.ts                | 10 +++
 src/chart/custom/CustomView.ts                  |  9 +++
 src/component/graphic/GraphicModel.ts           |  8 +--
 src/component/graphic/GraphicView.ts            |  3 +-
 test/graphic-animation.html                     | 87 +++++++++++++++++++++++--
 test/graphic-cases.html                         | 49 ++++++++++----
 7 files changed, 156 insertions(+), 29 deletions(-)

diff --git a/src/animation/customGraphicKeyframeAnimation.ts 
b/src/animation/customGraphicKeyframeAnimation.ts
index 20c9d7e..609efd3 100644
--- a/src/animation/customGraphicKeyframeAnimation.ts
+++ b/src/animation/customGraphicKeyframeAnimation.ts
@@ -19,7 +19,7 @@
 
 import { AnimationEasing } from 'zrender/src/animation/easing';
 import Element from 'zrender/src/Element';
-import { keys, filter, each } from 'zrender/src/core/util';
+import { keys, filter, each, isArray } from 'zrender/src/core/util';
 import { ELEMENT_ANIMATABLE_PROPS } from './customGraphicTransition';
 import { AnimationOption, AnimationOptionMixin, Dictionary } from 
'../util/types';
 import { Model } from '../echarts.all';
@@ -56,10 +56,17 @@ export function stopPreviousKeyframeAnimationAndRestore(el: 
Element) {
 
 export function applyKeyframeAnimation<T extends Record<string, any>>(
     el: Element,
-    animationOpts: ElementKeyframeAnimationOption<T>,
+    animationOpts: ElementKeyframeAnimationOption<T> | 
ElementKeyframeAnimationOption<T>[],
     animatableModel: Model<AnimationOptionMixin>
 ) {
-    if (!animatableModel.isAnimationEnabled()) {
+    if (!animatableModel.isAnimationEnabled() || !animationOpts) {
+        return;
+    }
+
+    if (isArray(animationOpts)) {
+        each(animationOpts, singleAnimationOpts => {
+            applyKeyframeAnimation(el, singleAnimationOpts, animatableModel);
+        });
         return;
     }
 
@@ -77,7 +84,7 @@ export function applyKeyframeAnimation<T extends 
Record<string, any>>(
 
     const stateToRestore: StateToRestore = getStateToRestore(el);
 
-    function applyKeyframeAnimationOnProp(targetPropName: typeof 
ELEMENT_ANIMATABLE_PROPS[number]) {
+    each(ELEMENT_ANIMATABLE_PROPS, (targetPropName) => {
         if (targetPropName && !(el as any)[targetPropName]) {
             return;
         }
@@ -144,7 +151,5 @@ export function applyKeyframeAnimation<T extends 
Record<string, any>>(
         animator
             .delay(animationOpts.delay || 0)
             .start(animationOpts.easing);
-    }
-
-    each(ELEMENT_ANIMATABLE_PROPS, applyKeyframeAnimationOnProp);
+    });
 }
\ No newline at end of file
diff --git a/src/chart/custom/CustomSeries.ts b/src/chart/custom/CustomSeries.ts
index 5a8e998..6477df2 100644
--- a/src/chart/custom/CustomSeries.ts
+++ b/src/chart/custom/CustomSeries.ts
@@ -72,6 +72,7 @@ import {
     TransitionDuringAPI
 } from '../../animation/customGraphicTransition';
 import { TransformProp } from 'zrender/src/core/Transformable';
+import { ElementKeyframeAnimationOption } from 
'../../animation/customGraphicKeyframeAnimation';
 
 export type CustomExtraElementInfo = Dictionary<unknown>;
 
@@ -154,6 +155,8 @@ export interface CustomGroupOption extends 
CustomBaseElementOption, TransitionOp
     diffChildrenByName?: boolean;
     children: CustomElementOption[];
     $mergeChildren?: false | 'byName' | 'byIndex';
+
+    keyframeAnimation?: ElementKeyframeAnimationOption<GroupProps> | 
ElementKeyframeAnimationOption<GroupProps>[]
 }
 export interface CustomBaseZRPathOption<T extends PathProps['shape'] = 
PathProps['shape']>
     extends CustomDisplayableOption, ShapeMorphingOption, 
TransitionOptionMixin<PathProps & {shape: T}> {
@@ -161,6 +164,9 @@ export interface CustomBaseZRPathOption<T extends 
PathProps['shape'] = PathProps
     shape?: T & TransitionOptionMixin<T>;
     style?: PathProps['style'] & TransitionOptionMixin<PathStyleProps>
     during?(params: TransitionDuringAPI<PathStyleProps, T>): void;
+
+    keyframeAnimation?: ElementKeyframeAnimationOption<PathProps & { shape: T 
}>
+        | ElementKeyframeAnimationOption<PathProps & { shape: T }>[]
 }
 
 interface BuiltinShapes {
@@ -211,6 +217,8 @@ export interface CustomImageOption extends 
CustomDisplayableOption, TransitionOp
     emphasis?: CustomImageOptionOnState;
     blur?: CustomImageOptionOnState;
     select?: CustomImageOptionOnState;
+
+    keyframeAnimation?: ElementKeyframeAnimationOption<ImageProps> | 
ElementKeyframeAnimationOption<ImageProps>[]
 }
 
 export interface CustomTextOptionOnState extends 
CustomDisplayableOptionOnState {
@@ -222,6 +230,8 @@ export interface CustomTextOption extends 
CustomDisplayableOption, TransitionOpt
     emphasis?: CustomTextOptionOnState;
     blur?: CustomTextOptionOnState;
     select?: CustomTextOptionOnState;
+
+    keyframeAnimation?: ElementKeyframeAnimationOption<TextProps> | 
ElementKeyframeAnimationOption<TextProps>[]
 }
 
 export type CustomElementOption = CustomPathOption
diff --git a/src/chart/custom/CustomView.ts b/src/chart/custom/CustomView.ts
index abfc4fa..32c0b99 100644
--- a/src/chart/custom/CustomView.ts
+++ b/src/chart/custom/CustomView.ts
@@ -95,6 +95,10 @@ import {
     applyUpdateTransition,
     ElementRootTransitionProp
 } from '../../animation/customGraphicTransition';
+import {
+    applyKeyframeAnimation,
+    stopPreviousKeyframeAnimationAndRestore
+} from '../../animation/customGraphicKeyframeAnimation';
 
 const EMPHASIS = 'emphasis' as const;
 const NORMAL = 'normal' as const;
@@ -442,6 +446,9 @@ function updateElNormal(
     isTextContent: boolean
 ): void {
 
+    // Stop and restore before update any other attributes.
+    stopPreviousKeyframeAnimationAndRestore(el);
+
     const txCfgOpt = attachedTxInfo && attachedTxInfo.normal.cfg;
     if (txCfgOpt) {
         // PENDING: whether use user object directly rather than clone?
@@ -494,6 +501,8 @@ function updateElNormal(
         clearStyle: true
     });
 
+    applyKeyframeAnimation(el, elOption.keyframeAnimation, seriesModel);
+
     if (!isTextContent) {
         // `elOption.info` enables user to mount some info on
         // elements and use them in event handlers.
diff --git a/src/component/graphic/GraphicModel.ts 
b/src/component/graphic/GraphicModel.ts
index eab5b9a..bf619a1 100644
--- a/src/component/graphic/GraphicModel.ts
+++ b/src/component/graphic/GraphicModel.ts
@@ -153,21 +153,21 @@ export interface GraphicComponentGroupOption
     // children: Omit<GraphicComponentElementOption, 'focus' | 'blurScope'>[];
     children: GraphicComponentElementOption[];
 
-    keyframeAnimation?: ElementKeyframeAnimationOption<GroupProps>
+    keyframeAnimation?: ElementKeyframeAnimationOption<GroupProps> | 
ElementKeyframeAnimationOption<GroupProps>[]
 };
 export interface GraphicComponentZRPathOption
     extends GraphicComponentDisplayableOption, 
TransitionOptionMixin<PathProps> {
     shape?: PathProps['shape'] & TransitionOptionMixin<PathProps['shape']>;
     style?: PathStyleProps & TransitionOptionMixin<PathStyleProps>
 
-    keyframeAnimation?: ElementKeyframeAnimationOption<PathProps>;
+    keyframeAnimation?: ElementKeyframeAnimationOption<PathProps> | 
ElementKeyframeAnimationOption<PathProps>[];
 }
 export interface GraphicComponentImageOption
     extends GraphicComponentDisplayableOption, 
TransitionOptionMixin<ImageProps> {
     type?: 'image';
     style?: ImageStyleProps & TransitionOptionMixin<ImageStyleProps>;
 
-    keyframeAnimation?: ElementKeyframeAnimationOption<ImageProps>;
+    keyframeAnimation?: ElementKeyframeAnimationOption<ImageProps> | 
ElementKeyframeAnimationOption<ImageProps>[];
 }
 // TODO: states?
 // interface GraphicComponentImageOptionOnState extends 
GraphicComponentDisplayableOptionOnState {
@@ -178,7 +178,7 @@ interface GraphicComponentTextOption
     type?: 'text';
     style?: TextStyleProps & TransitionOptionMixin<TextStyleProps>;
 
-    keyframeAnimation?: ElementKeyframeAnimationOption<TextProps>;
+    keyframeAnimation?: ElementKeyframeAnimationOption<TextProps> | 
ElementKeyframeAnimationOption<TextProps>[];
 }
 export type GraphicComponentElementOption =
     GraphicComponentGroupOption |
diff --git a/src/component/graphic/GraphicView.ts 
b/src/component/graphic/GraphicView.ts
index f790db8..131a223 100644
--- a/src/component/graphic/GraphicView.ts
+++ b/src/component/graphic/GraphicView.ts
@@ -222,7 +222,6 @@ export class GraphicComponentView extends ComponentView {
 
             if (el) {
                 const elInner = inner(el);
-                const keyframeAnimation = elOption.keyframeAnimation;
 
                 el.setTextConfig(textConfig);
 
@@ -236,7 +235,7 @@ export class GraphicComponentView extends ComponentView {
                     itemTooltipOption: elOption.tooltip
                 });
 
-                keyframeAnimation && applyKeyframeAnimation(el, 
keyframeAnimation, graphicModel);
+                applyKeyframeAnimation(el, elOption.keyframeAnimation, 
graphicModel);
             }
         });
     }
diff --git a/test/graphic-animation.html b/test/graphic-animation.html
index 4ebf2db..7ddea94 100644
--- a/test/graphic-animation.html
+++ b/test/graphic-animation.html
@@ -93,6 +93,79 @@ under the License.
 
         <script>
             require(['echarts'/*, 'map/js/china' */], function (echarts) {
+                let greenCirclePosition = 100;
+                var option = {
+                    graphic: {
+                        elements: [{
+                            type: 'circle',
+                            x: greenCirclePosition,
+                            y: 50,
+                            transition: 'all',
+                            shape: {
+                                cx: 0,
+                                cy: 0,
+                                r: 50
+                            },
+                            style: {
+                                fill: 'green'
+                            },
+                        }, {
+                            type: 'circle',
+                            x: 100,
+                            y: 200,
+                            shape: {
+                                cx: 0,
+                                cy: 0,
+                                r: 50
+                            },
+                            keyframeAnimation: {
+                                duration: 1000,
+                                loop: true,
+                                keyframes: [{
+                                    percent: 0,
+                                    x: 100
+                                }, {
+                                    percent: 0.5,
+                                    easing: 'sinusoidalInOut',
+                                    x: 500
+                                }, {
+                                    percent: 1,
+                                    easing: 'sinusoidalInOut',
+                                    x: 100
+                                }]
+                            },
+                            style: {
+                                fill: 'orange'
+                            }
+                        }]
+                    }
+                }
+
+                var chart = testHelper.create(echarts, 'main1', {
+                    title: [
+                        'Update on other elements should not affect the 
keyframe animation'
+                    ],
+                    buttons: [{
+                        text: 'Move Green Circle',
+                        onclick() {
+                            greenCirclePosition = 500 - greenCirclePosition;
+                            chart.setOption({
+                                graphic: {
+                                    elements: [{
+                                        x: greenCirclePosition
+                                    }]
+                                }
+                            });
+                        }
+                    }],
+                    option: option
+                });
+
+            });
+        </script>
+
+        <script>
+            require(['echarts'/*, 'map/js/china' */], function (echarts) {
                 var option = {
                     graphic: {
                         elements: [{
@@ -110,7 +183,7 @@ under the License.
                                 lineWidth: 1
                             },
                             keyframeAnimation: {
-                                duration: 4000,
+                                duration: 3000,
                                 loop: true,
                                 keyframes: [{
                                     percent: 0.7,
@@ -120,6 +193,12 @@ under the License.
                                         lineDash: [200, 0]
                                     }
                                 }, {
+                                    // Hold a bit.
+                                    percent: 0.8,
+                                    style: {
+                                        fill: 'transparent'
+                                    }
+                                }, {
                                     percent: 1,
                                     style: {
                                         fill: 'black'
@@ -130,15 +209,15 @@ under the License.
                     }
                 }
 
-                var chart = testHelper.create(echarts, 'main1', {
+                var chart = testHelper.create(echarts, 'main2', {
                     title: [
-                        'Text Stroke'
+                        'Text Stroke Animation'
                     ],
                     option: option
                 });
 
             });
-            </script>
+        </script>
     </body>
 </html>
 
diff --git a/test/graphic-cases.html b/test/graphic-cases.html
index 625a1c1..8b913ed 100644
--- a/test/graphic-cases.html
+++ b/test/graphic-cases.html
@@ -38,17 +38,18 @@ under the License.
 
 
         <div id="main0"></div>
-        <div id="main-legacy-style"></div>
+        <div id="main1"></div>
+        <div id="main2"></div>
 
 
 
 
         <script>
-        require(['echarts'/*, 'map/js/china' */], function (echarts) {
-            var option;
 
+        const imageURI = 
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANwAAADcCAYAAAAbWs+BAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4gIUARQAHY8+4wAAApBJREFUeNrt3cFqAjEUhlEjvv8rXzciiiBGk/He5JxdN2U649dY+KmnEwAAAAAv2uMXEeGOwERntwAEB4IDBAeCAwQHggPBAYIDwQGCA8GB4ADBgeAAwYHgAMGB4EBwgOCgpkuKq2it/r8Li2hbvGKqP6s/PycnHHv9YvSWEgQHCA4EBwgOBAeCAwQHggMEByXM+QRUE6D3suwuPafDn5MTDg50KXnVPSdxa54y/oYDwQGCA8EBggPBAYIDwYHggBE+X5rY3Y3Tey97Nn2eU+rnlGfaZa6Ft5SA4EBwgOBAcCA4QHAgOEBwIDjgZu60
 [...]
 
-            const imageURI = 
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANwAAADcCAYAAAAbWs+BAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4gIUARQAHY8+4wAAApBJREFUeNrt3cFqAjEUhlEjvv8rXzciiiBGk/He5JxdN2U649dY+KmnEwAAAAAv2uMXEeGOwERntwAEB4IDBAeCAwQHggPBAYIDwQGCA8GB4ADBgeAAwYHgAMGB4EBwgOCgpkuKq2it/r8Li2hbvGKqP6s/PycnHHv9YvSWEgQHCA4EBwgOBAeCAwQHggMEByXM+QRUE6D3suwuPafDn5MTDg50KXnVPSdxa54y/oYDwQGCA8EBggPBAYIDwYHggBE+X5rY3Y3Tey97Nn2eU+rnlGfaZa6Ft5SA4EBwgOBAcCA4QHAgOEBwIDjg
 [...]
+        require(['echarts'/*, 'map/js/china' */], function (echarts) {
+            var option;
 
 
             option = {
@@ -132,10 +133,6 @@ under the License.
         require(['echarts'/*, 'map/js/china' */], function (echarts) {
             var option;
 
-
-            const imageURI = 
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAANwAAADcCAYAAAAbWs+BAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4gIUARQAHY8+4wAAApBJREFUeNrt3cFqAjEUhlEjvv8rXzciiiBGk/He5JxdN2U649dY+KmnEwAAAAAv2uMXEeGOwERntwAEB4IDBAeCAwQHggPBAYIDwQGCA8GB4ADBgeAAwYHgAMGB4EBwgOCgpkuKq2it/r8Li2hbvGKqP6s/PycnHHv9YvSWEgQHCA4EBwgOBAeCAwQHggMEByXM+QRUE6D3suwuPafDn5MTDg50KXnVPSdxa54y/oYDwQGCA8EBggPBAYIDwYHggBE+X5rY3Y3Tey97Nn2eU+rnlGfaZa6Ft5SA4EBwgOBAcCA4QHAgOEBwIDjg
 [...]
-
-
             option = {
                 graphic: [{
                     type: 'circle',
@@ -176,14 +173,12 @@ under the License.
                     style: {
                         width: 50,
                         height: 100,
-                        image: imageURI,
-                        storke: 'blue',
-                        lineWidth: 5
+                        image: imageURI
                     }
                 }]
             };
 
-            var chart = testHelper.create(echarts, 'main-legacy-style', {
+            var chart = testHelper.create(echarts, 'main1', {
                 title: [
                     'Legacy API:',
                     'Should the same as new API'
@@ -194,6 +189,36 @@ under the License.
         });
         </script>
 
+        <script>
+            require(['echarts'/*, 'map/js/china' */], function (echarts) {
+                var option;
+                option = {
+                    graphic: {
+                        elements: [{
+                            type: 'text',
+                            x: 100,
+                            y: 100,
+                            style: {
+                                text: 'Apache ECharts',
+                                fill: 'none',
+                                fontSize: 50,
+                                fontWeight: 'bold',
+                                stroke: '#000',
+                                lineWidth: 1
+                            }
+                        }]
+                    }
+                };
+
+                var chart = testHelper.create(echarts, 'main2', {
+                    title: [
+                        'Stroke Only Text'
+                    ],
+                    option: option
+                });
+
+            });
+            </script>
 
     </body>
 </html>

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to