You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@echarts.apache.org by su...@apache.org on 2020/06/08 14:22:57 UTC

[incubator-echarts] branch custom-series-enhance updated (dfad53d -> 3a6ffe9)

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

sushuang pushed a change to branch custom-series-enhance
in repository https://gitbox.apache.org/repos/asf/incubator-echarts.git.


    from dfad53d  feature: enable "enterFrom" "leaveTo" "transition" animation setting in custom series.
     new 2f5de49  test: add test case for clip init.
     new 6c227d3  feature: custom series during callback params re-design.
     new 3a6ffe9  fix: fix custom series merge children strategy (force no empty children even thought merging children).

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 src/chart/custom.ts         | 196 ++++++++++++-----------
 src/util/graphic.ts         |   2 +-
 test/custom-feature.html    | 126 ++++++++++-----
 test/custom-transition.html | 383 +++++++++++++++++++++++++++++++++++---------
 4 files changed, 500 insertions(+), 207 deletions(-)


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@echarts.apache.org
For additional commands, e-mail: commits-help@echarts.apache.org


[incubator-echarts] 03/03: fix: fix custom series merge children strategy (force no empty children even thought merging children).

Posted by su...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sushuang pushed a commit to branch custom-series-enhance
in repository https://gitbox.apache.org/repos/asf/incubator-echarts.git

commit 3a6ffe9f5f9c390e3c28e2e819f085c5f14981a0
Author: 100pah <su...@gmail.com>
AuthorDate: Mon Jun 8 22:15:55 2020 +0800

    fix: fix custom series merge children strategy (force no empty children even thought merging children).
---
 src/chart/custom.ts         |  82 +++++++++++-----------
 src/util/graphic.ts         |   2 +-
 test/custom-transition.html | 164 ++++++++++++++++++++++++++++++++++++++++----
 3 files changed, 196 insertions(+), 52 deletions(-)

diff --git a/src/chart/custom.ts b/src/chart/custom.ts
index 9125b97..9485c0e 100644
--- a/src/chart/custom.ts
+++ b/src/chart/custom.ts
@@ -432,18 +432,18 @@ class CustomSeriesView extends ChartView {
         // roam or data zoom according to `actionType`.
         data.diff(oldData)
             .add(function (newIdx) {
-                createOrUpdateItemEl(
+                createOrUpdateItem(
                     null, newIdx, renderItem(newIdx, payload), customSeries, group, data
                 );
             })
             .update(function (newIdx, oldIdx) {
-                createOrUpdateItemEl(
+                createOrUpdateItem(
                     oldData.getItemGraphicEl(oldIdx),
                     newIdx, renderItem(newIdx, payload), customSeries, group, data
                 );
             })
             .remove(function (oldIdx) {
-                removeItemEl(oldData.getItemGraphicEl(oldIdx), customSeries, group);
+                doRemoveEl(oldData.getItemGraphicEl(oldIdx), customSeries, group);
             })
             .execute();
 
@@ -486,7 +486,7 @@ class CustomSeriesView extends ChartView {
             }
         }
         for (let idx = params.start; idx < params.end; idx++) {
-            const el = createOrUpdateItemEl(null, idx, renderItem(idx, payload), customSeries, this.group, data);
+            const el = createOrUpdateItem(null, idx, renderItem(idx, payload), customSeries, this.group, data);
             el.traverse(setIncrementalAndHoverLayer);
         }
     }
@@ -590,6 +590,13 @@ function createEl(elOption: CustomElementOption): Element {
  * Some "object-like" config like `textConfig`, `textContent`, `style` which are not needed for
  * every elment, so we replace them only when user specify them. And the that is a total replace.
  *
+ * TODO: there is no hint of 'isFirst' to users. So the performance enhancement can not be
+ * performed yet. Consider the case:
+ * (1) setOption to "mergeChildren" with a smaller children count
+ * (2) Use dataZoom to make an item disappear.
+ * (3) User dataZoom to make the item display again. At that time, renderItem need to return the
+ * full option rather than partial option to recreate the element.
+ *
  * ----------------------------------------------
  * [STRATEGY_NULL] `hasOwnProperty` or `== null`:
  *
@@ -1348,6 +1355,14 @@ function makeRenderItem(
         return itemStyle;
     }
 
+    function applyExtraAfter(itemStyle: ZRStyleProps, extra: ZRStyleProps): void {
+        for (const key in extra) {
+            if (hasOwn(extra, key)) {
+                (itemStyle as any)[key] = (extra as any)[key];
+            }
+        }
+    }
+
     function preFetchFromExtra(extra: ZRStyleProps, itemStyle: ItemStyleProps): void {
         // A trick to retrieve those props firstly, which are used to
         // apply auto inside fill/stroke in `convertToEC4StyleForCustomSerise`.
@@ -1425,7 +1440,7 @@ function wrapEncodeDef(data: List<CustomSeriesModel>): Dictionary<number[]> {
     return encodeDef;
 }
 
-function createOrUpdateItemEl(
+function createOrUpdateItem(
     el: Element,
     dataIndex: number,
     elOption: CustomElementOption,
@@ -1433,13 +1448,25 @@ function createOrUpdateItemEl(
     group: ViewRootGroup,
     data: List<CustomSeriesModel>
 ): Element {
-    el = doCreateOrUpdate(el, dataIndex, elOption, seriesModel, group, true);
+    // [Rule]
+    // If `renderItem` returns `null`/`undefined`/`false`, remove the previous el if existing.
+    //     (It seems that violate the "merge" principle, but most of users probably intuitively
+    //     regard "return;" as "show nothing element whatever", so make a exception to meet the
+    //     most cases.)
+    // The rule or "merge" see [STRATEGY_MERGE].
+
+    // If `elOption` is `null`/`undefined`/`false` (when `renderItem` returns nothing).
+    if (!elOption) {
+        el && group.remove(el);
+        return;
+    }
+    el = doCreateOrUpdateEl(el, dataIndex, elOption, seriesModel, group, true);
     el && data.setItemGraphicEl(dataIndex, el);
 
     return el;
 }
 
-function doCreateOrUpdate(
+function doCreateOrUpdateEl(
     el: Element,
     dataIndex: number,
     elOption: CustomElementOption,
@@ -1448,20 +1475,10 @@ function doCreateOrUpdate(
     isRoot: boolean
 ): Element {
 
-    // [Rule]
-    // If `renderItem` returns `null`/`undefined`/`false`, remove the previous el if existing.
-    //     (It seems that violate the "merge" principle, but most of users probably intuitively
-    //     regard "return;" as "show nothing element whatever", so make a exception to meet the
-    //     most cases.)
-    // The rule or "merge" see [STRATEGY_MERGE].
-
-    // If `elOption` is `null`/`undefined`/`false` (when `renderItem` returns nothing).
-    if (!elOption) {
-        el && group.remove(el);
-        return;
+    if (__DEV__) {
+        assert(elOption, 'should not have an null/undefined element setting');
     }
 
-    elOption = elOption || {} as CustomElementOption;
     let toBeReplacedIdx = -1;
 
     if (el && doesElNeedRecreate(el, elOption)) {
@@ -1525,7 +1542,6 @@ function doesElNeedRecreate(el: Element, elOption: CustomElementOption): boolean
     const elOptionShape = (elOption as CustomZRPathOption).shape;
     const elOptionStyle = elOption.style;
     return (
-        // || elOption.$merge === false
         // If `elOptionType` is `null`, follow the merge principle.
         (elOptionType != null
             && elOptionType !== elInner.customGraphicType
@@ -1729,8 +1745,7 @@ function retrieveStyleOptionOnState(
 //
 // For implementation simpleness, do not provide a direct way to remove sinlge
 // child (otherwise the total indicies of the children array have to be modified).
-// User can remove a single child by set its `ignore` as `true` or replace
-// it by another element, where its `$merge` can be set as `true` if necessary.
+// User can remove a single child by set its `ignore` as `true`.
 function mergeChildren(
     el: graphicUtil.Group,
     dataIndex: number,
@@ -1767,7 +1782,7 @@ function mergeChildren(
     // might be better performance.
     let index = 0;
     for (; index < newLen; index++) {
-        newChildren[index] && doCreateOrUpdate(
+        newChildren[index] && doCreateOrUpdateEl(
             el.childAt(index),
             dataIndex,
             newChildren[index],
@@ -1776,11 +1791,8 @@ function mergeChildren(
             false
         );
     }
-    if (__DEV__) {
-        assert(
-            !notMerge || el.childCount() === index,
-            'MUST NOT contain empty item in children array when `group.$mergeChildren` is `false`.'
-        );
+    for (let i = el.childCount() - 1; i >= index; i--) {
+        doRemoveEl(el.childAt(i), seriesModel, el);
     }
 }
 
@@ -1819,7 +1831,7 @@ function processAddUpdate(
     const childOption = newIndex != null ? context.newChildren[newIndex] : null;
     const child = oldIndex != null ? context.oldChildren[oldIndex] : null;
 
-    doCreateOrUpdate(
+    doCreateOrUpdateEl(
         child,
         context.dataIndex,
         childOption,
@@ -1829,21 +1841,13 @@ function processAddUpdate(
     );
 }
 
-function applyExtraAfter(itemStyle: ZRStyleProps, extra: ZRStyleProps): void {
-    for (const key in extra) {
-        if (hasOwn(extra, key)) {
-            (itemStyle as any)[key] = (extra as any)[key];
-        }
-    }
-}
-
 function processRemove(this: DataDiffer<DiffGroupContext>, oldIndex: number): void {
     const context = this.context;
     const child = context.oldChildren[oldIndex];
-    child && context.group.remove(child);
+    doRemoveEl(child, context.seriesModel, context.group);
 }
 
-function removeItemEl(
+function doRemoveEl(
     el: Element,
     seriesModel: CustomSeriesModel,
     group: ViewRootGroup
diff --git a/src/util/graphic.ts b/src/util/graphic.ts
index 21d6aa2..c97b438 100644
--- a/src/util/graphic.ts
+++ b/src/util/graphic.ts
@@ -1117,7 +1117,7 @@ function animateOrSetProps<Props>(
     }
     else {
         el.stopAnimation();
-        el.attr(props);
+        !isFrom && el.attr(props);
         cb && cb();
     }
 }
diff --git a/test/custom-transition.html b/test/custom-transition.html
index a51d31d..cd9c865 100644
--- a/test/custom-transition.html
+++ b/test/custom-transition.html
@@ -37,9 +37,11 @@ under the License.
 
 
         <!-- <div id="texture-bar-texture-maker"></div> -->
+
         <div id="spiral-fixed-extent"></div>
         <div id="spiral-dynamic-extent"></div>
         <div id="texture-bar-by-clipPath"></div>
+        <div id="no-animation"></div>
         <div id="enter-animation-and-merge"></div>
         <div id="enter-animation2"></div>
         <div id="enter-animation-clipPath"></div>
@@ -51,7 +53,6 @@ under the License.
 
 
 
-
 <!--
         <script>
             require(['echarts'], function (echarts) {
@@ -799,6 +800,133 @@ under the License.
 
 
 
+
+
+
+
+
+        <script>
+            require(['echarts'], function (echarts) {
+
+                var option = {
+                    animation: false,
+                    xAxis: {
+                        max: 600,
+                    },
+                    yAxis: {
+                    },
+                    dataZoom: [
+                        { type: 'slider', start: 10, end: 60 },
+                        { type: 'inside', start: 10, end: 60 }
+                    ],
+                    series: [{
+                        type: 'custom',
+                        renderItem: function (params, api) {
+                            var pos = api.coord([api.value(0), api.value(1)]);
+                            return {
+                                type: 'group',
+                                x: pos[0],
+                                y: pos[1],
+                                children: [{
+                                    type: 'rect',
+                                    shape: {
+                                        x: -50,
+                                        y: 50,
+                                        width: 100,
+                                        height: 50,
+                                        r: 10
+                                    },
+                                    style: {
+                                        fill: 'blue',
+                                    }
+                                }, {
+                                    type: 'circle',
+                                    shape: {
+                                        cx: -50,
+                                        cy: 50,
+                                        r: 30
+                                    },
+                                    style: {
+                                        fill: 'green',
+                                    },
+                                    textConfig: {
+                                        position: 'bottom'
+                                    },
+                                    textContent: {
+                                        style: {
+                                            text: 'xxxx',
+                                            fill: 'black',
+                                        }
+                                    }
+                                }]
+                            };
+                        },
+                        data: [[221, 333], [129, 312]]
+                    }]
+                };
+
+                var chart = testHelper.create(echarts, 'no-animation', {
+                    title: [
+                        'No-animation',
+                        '(1) Move dataZoom, position should have no transition animation but move normally.',
+                        '(2) Use dataZoom hide a data item, and then show it.',
+                        '(3) click button to setOption merge: ',
+                        '   circle **disappears** and rect become **red border black bg**',
+                        '(4) **Repeat (2)** after merged, should be correct.'
+                    ],
+                    height: 300,
+                    option: option,
+                    buttons: [{
+                        text: 'go',
+                        onclick: function () {
+                            chart.dispatchAction({type: 'dataZoom', start: 10, end: 60});
+                        }
+                    }, {
+                        text: 'click me to merge children',
+                        onclick: function () {
+                            chart.setOption({
+                                series: {
+                                    type: 'custom',
+                                    renderItem: function (params, api) {
+                                        var pos = api.coord([api.value(0), api.value(1)]);
+                                        return {
+                                            type: 'group',
+                                            x: pos[0],
+                                            y: pos[1],
+                                            children: [{
+                                                type: 'rect',
+                                                shape: {
+                                                    x: -50,
+                                                    y: 50,
+                                                    width: 100,
+                                                    height: 50,
+                                                    r: 10
+                                                },
+                                                style: {
+                                                    stroke: 'red',
+                                                    lineWidth: 5
+                                                }
+                                            }]
+                                        };
+                                    }
+                                }
+                            });
+                        }
+                    }]
+                });
+            });
+        </script>
+
+
+
+
+
+
+
+
+
+
+
         <script>
             require(['echarts'], function (echarts) {
 
@@ -808,12 +936,13 @@ under the License.
                     animationDuration: animationDuration,
                     animationDurationUpdate: animationDurationUpdate,
                     xAxis: {
+                        max: 600
                     },
                     yAxis: {
                     },
                     dataZoom: [
-                        { type: 'slider' },
-                        { type: 'inside' }
+                        { type: 'slider', start: 10, end: 60 },
+                        { type: 'inside', start: 10, end: 60 }
                     ],
                     series: [{
                         type: 'custom',
@@ -834,7 +963,7 @@ under the License.
                                     },
                                     style: {
                                         fill: 'blue',
-                                        $enterFrom: { opacity: 0 }
+                                        // $enterFrom: { opacity: 0 }
                                     }
                                 }, {
                                     type: 'circle',
@@ -845,7 +974,7 @@ under the License.
                                     },
                                     style: {
                                         fill: 'green',
-                                        $enterFrom: { opacity: 0 }
+                                        // $enterFrom: { opacity: 0 }
                                     },
                                     textConfig: {
                                         position: 'bottom'
@@ -854,44 +983,55 @@ under the License.
                                         style: {
                                             text: 'xxxx',
                                             fill: 'black',
-                                            $enterFrom: { opacity: 0 }
+                                            // $enterFrom: { opacity: 0 }
                                         }
                                     }
                                 }]
                             };
                         },
-                        data: [[121, 333], [29, 312]]
+                        data: [[221, 333], [129, 312]]
                     }]
                 };
 
                 var chart = testHelper.create(echarts, 'enter-animation-and-merge', {
                     title: [
+                        'Transition animation:',
                         '(1) Move dataZoom, position should have transition animation.',
                         '(2) Use dataZoom hide a data item, and then show it, ensure the **fade in** animation not be interupted.',
-                        '(3) click button to setOption merge.',
-                        '(4) Repeat (2), should be correct.'
+                        '(3) click button to setOption merge: ',
+                        '   circle **disappears** and rect become **red border black bg**',
+                        '(4) **Repeat (2)** after merged, should be correct.'
                     ],
                     height: 300,
                     option: option,
                     buttons: [{
-                        text: 'replace style: border become red, and background become black',
+                        text: 'click me to merge children',
                         onclick: function () {
                             chart.setOption({
                                 series: {
                                     type: 'custom',
                                     renderItem: function (params, api) {
+                                        var pos = api.coord([api.value(0), api.value(1)]);
                                         return {
                                             type: 'group',
+                                            x: pos[0],
+                                            y: pos[1],
                                             children: [{
                                                 type: 'rect',
+                                                shape: {
+                                                    x: -50,
+                                                    y: 50,
+                                                    width: 100,
+                                                    height: 50,
+                                                    r: 10
+                                                },
                                                 style: {
                                                     stroke: 'red',
                                                     lineWidth: 5
                                                 }
                                             }]
                                         };
-                                    },
-                                    data: [[121, 333], [29, 312]]
+                                    }
                                 }
                             });
                         }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@echarts.apache.org
For additional commands, e-mail: commits-help@echarts.apache.org


[incubator-echarts] 01/03: test: add test case for clip init.

Posted by su...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sushuang pushed a commit to branch custom-series-enhance
in repository https://gitbox.apache.org/repos/asf/incubator-echarts.git

commit 2f5de4916dd0652f6fe1b3d5f75853e14c33dd19
Author: 100pah <su...@gmail.com>
AuthorDate: Fri Jun 5 10:21:58 2020 +0800

    test: add test case for clip init.
---
 src/chart/custom.ts         |   4 +-
 test/custom-feature.html    | 126 ++++++++++++++++++++----------
 test/custom-transition.html | 184 ++++++++++++++++++++++++++++++++------------
 3 files changed, 221 insertions(+), 93 deletions(-)

diff --git a/src/chart/custom.ts b/src/chart/custom.ts
index cfd1a1f..b35f55b 100644
--- a/src/chart/custom.ts
+++ b/src/chart/custom.ts
@@ -221,13 +221,13 @@ interface CustomSeriesRenderItemCoordinateSystemAPI {
     ): number | number[];
 }
 interface CustomSeriesRenderItemParams {
-    context: {};
+    context: Dictionary<unknown>;
     seriesId: string;
     seriesName: string;
     seriesIndex: number;
     coordSys: CustomSeriesRenderItemParamsCoordSys;
     dataInsideLength: number;
-    encode: ReturnType<typeof wrapEncodeDef>
+    encode: ReturnType<typeof wrapEncodeDef>;
 }
 type CustomSeriesRenderItem = (
     params: CustomSeriesRenderItemParams,
diff --git a/test/custom-feature.html b/test/custom-feature.html
index cee7c53..be3f4e5 100644
--- a/test/custom-feature.html
+++ b/test/custom-feature.html
@@ -35,9 +35,10 @@ under the License.
         </style>
 
 
-        <div id="main0"></div>
-        <div id="main2"></div>
-        <div id="main3"></div>
+        <div id="main-eventful"></div>
+        <div id="main-clip-by-system"></div>
+        <div id="main-clip-by-self"></div>
+        <div id="main-SVG-Path"></div>
 
 
         <script>
@@ -107,7 +108,7 @@ under the License.
                     }]
                 };
 
-                var chart = testHelper.create(echarts, 'main0', {
+                var chart = testHelper.create(echarts, 'main-eventful', {
                     title: [
                         'Eventful: ',
                         'Only this el trigger events: **red circle** and **red rect** of **dataIndex: 1**',
@@ -138,8 +139,6 @@ under the License.
                 'echarts'/*, 'map/js/china' */
             ], function (echarts) {
 
-                // deprecated: this case would be wrong.
-
                 var option = {
                     xAxis: {
                         min: 90,
@@ -151,13 +150,11 @@ under the License.
                         max: 500,
                         scale: true
                     },
-                    dataZoom: [{
-                        type: 'inside',
-                        filterMode: 'none'
-                    }, {
-                        type: 'slider',
-                        filterMode: 'none'
-                    }],
+                    dataZoom: [
+                        {type: 'inside', filterMode: 'none'},
+                        {type: 'slider', filterMode: 'none'},
+                        {type: 'slider', filterMode: 'none', orient: 'vertical'},
+                    ],
                     series: [{
                         type: 'custom',
                         renderItem: function (params, api) {
@@ -173,24 +170,19 @@ under the License.
                                         [90, 50]
                                     ]
                                 },
-                                clip: {
-                                    x: params.coordSys.x,
-                                    y: params.coordSys.y,
-                                    width: params.coordSys.width,
-                                    height: params.coordSys.height
-                                },
                                 style: {
                                     fill: 'green'
                                 }
                             }
                         },
+                        clip: true,
                         data: [[100, 300]]
                     }]
                 };
 
-                var chart = testHelper.create(echarts, 'main2', {
+                var chart = testHelper.create(echarts, 'main-clip-by-system', {
                     title: [
-                        'The shape should be **clipped** by the grid. (TODO)',
+                        'The shape should be **clipped** by the grid (by series.clip).',
                     ],
                     option: option
                 });
@@ -204,13 +196,82 @@ under the License.
 
 
 
-
         <script>
 
             require([
                 'echarts'/*, 'map/js/china' */
             ], function (echarts) {
 
+                var option = {
+                    xAxis: {
+                        min: 90,
+                        max: 120,
+                        scale: true
+                    },
+                    yAxis: {
+                        min: 50,
+                        max: 500,
+                        scale: true
+                    },
+                    dataZoom: [
+                        {type: 'inside', filterMode: 'none'},
+                        {type: 'slider', filterMode: 'none'},
+                        {type: 'slider', filterMode: 'none', orient: 'vertical'},
+                    ],
+                    series: [{
+                        type: 'custom',
+                        renderItem: function (params, api) {
+                            return {
+                                type: 'group',
+                                children: [{
+                                    type: 'polygon',
+                                    position: api.coord([api.value(0), api.value(1)]),
+                                    shape: {
+                                        points: [
+                                            [0, 0],
+                                            [50, -50],
+                                            [90, -50],
+                                            [140, 0],
+                                            [90, 50]
+                                        ]
+                                    },
+                                    style: {
+                                        fill: 'blue'
+                                    }
+                                }],
+                                clipPath: {
+                                    type: 'rect',
+                                    shape: {
+                                        x: params.coordSys.x,
+                                        y: params.coordSys.y,
+                                        width: params.coordSys.width,
+                                        height: params.coordSys.height
+                                    }
+                                }
+                            }
+                        },
+                        data: [[100, 300]]
+                    }]
+                };
+
+                var chart = testHelper.create(echarts, 'main-clip-by-self', {
+                    title: [
+                        'The shape should be **clipped** by the grid (by custom clipPath).',
+                    ],
+                    option: option
+                });
+
+            });
+
+        </script>
+
+
+
+
+        <script>
+
+            require(['echarts'], function (echarts) {
+
                 // deprecated: this case would be wrong.
 
                 var data = [];
@@ -225,23 +286,6 @@ under the License.
                     },
                     dataZoom: [{
                         type: 'slider',
-                        xAxisIndex: 0,
-                        filterMode: 'weakFilter',
-                        height: 20,
-                        bottom: 0,
-                        start: -26,
-                        end: 26,
-                        showDetail: false
-                    }, {
-                        type: 'inside',
-                        xAxisIndex: 0,
-                        filterMode: 'weakFilter',
-                        start: -26,
-                        end: 26,
-                        zoomOnMouseWheel: false,
-                        moveOnMouseMove: true
-                    }, {
-                        type: 'slider',
                         yAxisIndex: 0,
                         zoomLock: true,
                         width: 10,
@@ -350,7 +394,7 @@ under the License.
                     };
                 }
 
-                var chart = testHelper.create(echarts, 'main3', {
+                var chart = testHelper.create(echarts, 'main-SVG-Path', {
                     title: [
                         'Test SVG path data auto fit to rect: ',
                         'the y axis label (made by custom series) should be center',
@@ -367,5 +411,7 @@ under the License.
 
 
 
+
+
     </body>
 </html>
\ No newline at end of file
diff --git a/test/custom-transition.html b/test/custom-transition.html
index e1a22ff..2d0f762 100644
--- a/test/custom-transition.html
+++ b/test/custom-transition.html
@@ -42,6 +42,7 @@ under the License.
         <div id="texture-bar-by-clipPath"></div>
         <div id="enter-animation"></div>
         <div id="enter-animation2"></div>
+        <div id="enter-animation-clipPath"></div>
         <div id="style-animation"></div>
         <div id="transform-animation"></div>
         <div id="transform-animation-disabled"></div>
@@ -51,6 +52,61 @@ under the License.
 
 
 
+<!--
+        <script>
+            require(['echarts'], function (echarts) {
+                var chart = testHelper.create(echarts, 'texture-bar-texture-maker', {
+                    title: [],
+                    width: 200,
+                    height: 200,
+                    option: {},
+                    buttons: [{
+                        text: 'dataURL',
+                        onclick: function () {
+                            console.log(chart.getDataURL({
+                                type: 'png',
+                                backgroundColor: 'rgba(0,0,0,0)'
+                            }));
+                        }
+                    }]
+                });
+                if (!chart) {
+                    return;
+                }
+
+                var zr = chart.getZr();
+                var eles = [];
+                var extent = [0.0, 0.95];
+                var count = 200;
+                var unit = (extent[1] - extent[0]) / count;
+                var baseColor = 'rgb(0,0,255)';
+                for (var i = 0; i < count; i++) {
+                    var oo = extent[0] + (count - i) * unit;
+                    var color = echarts.color.modifyHSL(baseColor, null, null, oo);
+                    var startAngle = 2 * Math.PI / count * i;
+                    var endAngle = Math.min((2 * Math.PI / count * (i + 1) + 0.05), Math.PI * 2);
+                    zr.add(new echarts.graphic.Sector({
+                        type: 'sector',
+                        shape: {
+                            cx: 100,
+                            cy: 100,
+                            r: 100,
+                            r0: 60,
+                            startAngle: startAngle,
+                            endAngle: endAngle
+                        },
+                        style: {
+                            fill: color
+                        }
+                    }));
+                }
+            });
+        </script> -->
+
+
+
+
+
         <script>
             require([
                 'echarts'
@@ -726,57 +782,6 @@ under the License.
         </script>
 
 
-        <script>
-            require(['echarts'], function (echarts) {
-                var chart = testHelper.create(echarts, 'texture-bar-texture-maker', {
-                    title: [],
-                    width: 200,
-                    height: 200,
-                    option: {},
-                    buttons: [{
-                        text: 'dataURL',
-                        onclick: function () {
-                            console.log(chart.getDataURL({
-                                type: 'png',
-                                backgroundColor: 'rgba(0,0,0,0)'
-                            }));
-                        }
-                    }]
-                });
-                if (!chart) {
-                    return;
-                }
-
-                var zr = chart.getZr();
-                var eles = [];
-                var extent = [0.0, 0.95];
-                var count = 200;
-                var unit = (extent[1] - extent[0]) / count;
-                var baseColor = 'rgb(0,0,255)';
-                for (var i = 0; i < count; i++) {
-                    var oo = extent[0] + (count - i) * unit;
-                    var color = echarts.color.modifyHSL(baseColor, null, null, oo);
-                    var startAngle = 2 * Math.PI / count * i;
-                    var endAngle = Math.min((2 * Math.PI / count * (i + 1) + 0.05), Math.PI * 2);
-                    zr.add(new echarts.graphic.Sector({
-                        type: 'sector',
-                        shape: {
-                            cx: 100,
-                            cy: 100,
-                            r: 100,
-                            r0: 60,
-                            startAngle: startAngle,
-                            endAngle: endAngle
-                        },
-                        style: {
-                            fill: color
-                        }
-                    }));
-                }
-            });
-        </script>
-
-
 
 
 
@@ -958,6 +963,83 @@ under the License.
 
 
 
+
+
+        <script>
+            require(['echarts'], function (echarts) {
+                var animationDuration = 1000;
+                var animationDurationUpdate = 1000;
+                var option = {
+                    animationDuration: animationDuration,
+                    animationDurationUpdate: animationDurationUpdate,
+                    animationEasing: 'linear',
+                    xAxis: {
+                        max: 500
+                    },
+                    yAxis: {
+                        max: 300
+                    },
+                    series: [{
+                        type: 'custom',
+                        renderItem: function (params, api) {
+                            var pos = api.coord([api.value(0), api.value(1)]);
+                            return {
+                                type: 'group',
+                                children: [{
+                                    type: 'rect',
+                                    shape: {x: 0, y: 0, width: 2000, height: 2000},
+                                    style: {fill: 'orange'}
+                                }, {
+                                    type: 'polygon',
+                                    x: pos[0],
+                                    y: pos[1],
+                                    shape: {
+                                        points: [
+                                            [0, 0],
+                                            [50, -50],
+                                            [90, -50],
+                                            [140, 0],
+                                            [90, 50]
+                                        ]
+                                    },
+                                    style: {
+                                        fill: 'green'
+                                    }
+                                }],
+                                clipPath: {
+                                    type: 'rect',
+                                    shape: {
+                                        x: params.coordSys.x,
+                                        y: params.coordSys.y,
+                                        width: params.coordSys.width,
+                                        height: params.coordSys.height,
+                                        $enterFrom: {width: 0}
+                                    }
+                                }
+                            };
+                        },
+                        data: [[71, 133], [159, 113]]
+                    }]
+                };
+
+                var chart = testHelper.create(echarts, 'enter-animation-clipPath', {
+                    title: [
+                        'Ensure enter animation by clipPath play normal (from left to right).'
+                    ],
+                    height: 300,
+                    option: option
+                });
+            });
+        </script>
+
+
+
+
+
+
+
+
+
         <script>
             require(['echarts'], function (echarts) {
                 var weatherIcons = {


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@echarts.apache.org
For additional commands, e-mail: commits-help@echarts.apache.org


[incubator-echarts] 02/03: feature: custom series during callback params re-design.

Posted by su...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

sushuang pushed a commit to branch custom-series-enhance
in repository https://gitbox.apache.org/repos/asf/incubator-echarts.git

commit 6c227d3ab5bc01a21d40b0827fbd623e80b85fc4
Author: 100pah <su...@gmail.com>
AuthorDate: Mon Jun 8 12:28:59 2020 +0800

    feature: custom series during callback params re-design.
---
 src/chart/custom.ts         | 110 ++++++++++++++++++++++++--------------------
 test/custom-transition.html |  63 +++++++++++++++----------
 2 files changed, 97 insertions(+), 76 deletions(-)

diff --git a/src/chart/custom.ts b/src/chart/custom.ts
index b35f55b..9125b97 100644
--- a/src/chart/custom.ts
+++ b/src/chart/custom.ts
@@ -103,6 +103,7 @@ const TRANSFORM_PROPS = {
     rotation: 1
 } as const;
 type TransformProps = keyof typeof TRANSFORM_PROPS;
+const transformPropNamesStr = keys(TRANSFORM_PROPS).join(', ');
 
 type TransitionAnyProps = string | string[];
 type TransitionTransformProps = TransformProps | TransformProps[];
@@ -134,7 +135,7 @@ interface CustomBaseElementOption extends Partial<Pick<
     // Shape can be set in any el option for custom prop for annimation duration.
     shape?: TransitionAnyOption;
     // updateDuringAnimation
-    during?(elProps: CustomDuringElProps): void;
+    during?(params: typeof customDuringAPI): void;
 };
 interface CustomDisplayableOption extends CustomBaseElementOption, Partial<Pick<
     Displayable, 'zlevel' | 'z' | 'z2' | 'invisible'
@@ -162,10 +163,6 @@ interface CustomGroupOption extends CustomBaseElementOption {
 interface CustomZRPathOption extends CustomDisplayableOption {
     shape?: PathProps['shape'] & TransitionAnyOption;
 }
-interface CustomDuringElProps extends Partial<Pick<Element, TransformProps>> {
-    shape?: PathProps['shape'];
-    style?: { text: string };
-}
 interface CustomSVGPathOption extends CustomDisplayableOption {
     type: 'path';
     shape?: {
@@ -319,9 +316,6 @@ const Z2_SPECIFIED_BIT = {
     emphasis: 1
 } as const;
 
-const tmpDuringStyle = {} as CustomDuringElProps['style'];
-const tmpDuringElProps = {} as CustomDuringElProps;
-
 const LEGACY_TRANSFORM_PROPS = {
     position: ['x', 'y'],
     scale: ['scaleX', 'scaleY'],
@@ -931,54 +925,68 @@ function getOrCreateLeaveToPropsFromEl(el: Element): LooseElementProps {
     return innerEl.leaveToProps || (innerEl.leaveToProps = {});
 }
 
+// Use it to avoid it be exposed to user.
+const tmpDuringScope = {} as {
+    el: Element;
+    isShapeDirty: boolean;
+    isStyleDirty: boolean;
+};
+const customDuringAPI = {
+    // Usually other props do not need to be changed in animation during.
+    setAttr(key: TransformProps, val: unknown): void {
+        assert(hasOwn(TRANSFORM_PROPS, key), 'Only ' + transformPropNamesStr + ' available in `setAttr`.');
+        tmpDuringScope.el[key] = val as number;
+    },
+    getAttr(key: TransformProps): unknown {
+        assert(hasOwn(TRANSFORM_PROPS, key), 'Only ' + transformPropNamesStr + ' available in `getAttr`.');
+        return tmpDuringScope.el[key];
+    },
+    setShape(key: string, val: unknown): void {
+        // In custom series, el other than Path can also has `shape` for intepolating props.
+        const shape = (tmpDuringScope.el as any).shape || ((tmpDuringScope.el as any).shape = {});
+        shape[key] = val;
+        tmpDuringScope.isShapeDirty = true;
+    },
+    getShape(key: string): unknown {
+        const shape = (tmpDuringScope.el as any).shape;
+        if (shape) {
+            return shape[key];
+        }
+    },
+    setStyle(key: string, val: unknown): void {
+        const style = (tmpDuringScope.el as Displayable).style;
+        if (style) {
+            style[key] = val;
+            tmpDuringScope.isStyleDirty = true;
+        }
+    },
+    getStyle(key: string): unknown {
+        const style = (tmpDuringScope.el as Displayable).style;
+        if (style) {
+            return style[key];
+        }
+    }
+};
+
 function elUpdateDuringAnimation(this: Element, key: string): void {
     const innerEl = inner(this);
     // FIXME `this.markRedraw();` directly ?
     innerEl.orginalDuring.call(this, key);
     const customDuring = innerEl.customDuring;
-    const thisPath = this as graphicUtil.Path;
-    const thisText = this as graphicUtil.Text;
-    let dirtyStyle = false;
-
-    // Only provide these props. Usually other props do not need to be
-    // changed in animation during.
-    // Do not give `this` to user util really needed in future.
-    // Props in `shape` can be modified directly in the during callback.
-    const shapeCurr = tmpDuringElProps.shape = thisPath.shape;
-    const xCurr = tmpDuringElProps.x = this.x;
-    const yCurr = tmpDuringElProps.y = this.y;
-    const scaleXCurr = tmpDuringElProps.scaleX = this.scaleX;
-    const scaleYCurr = tmpDuringElProps.scaleY = this.scaleY;
-    const originXCurr = tmpDuringElProps.originX = this.originX;
-    const originYCurr = tmpDuringElProps.originY = this.originY;
-    const rotationCurr = tmpDuringElProps.rotation = this.rotation;
-
-    // PENDING:
-    // Do not expose other style in case that is not stable.
-    const isText = this.type === 'text';
-    // Always assign in case that user modify `.style`.
-    tmpDuringElProps.style = tmpDuringStyle;
-    const textCurr = tmpDuringStyle.text = isText ? thisText.style.text : null;
-
-    customDuring(tmpDuringElProps);
-
-    tmpDuringElProps.shape !== shapeCurr && (thisPath.shape = tmpDuringElProps.shape);
-    // Consider prop on prototype.
-    tmpDuringElProps.x !== xCurr && (this.x = tmpDuringElProps.x);
-    tmpDuringElProps.y !== yCurr && (this.y = tmpDuringElProps.y);
-    tmpDuringElProps.scaleX !== scaleXCurr && (this.scaleX = tmpDuringElProps.scaleX);
-    tmpDuringElProps.scaleY !== scaleYCurr && (this.scaleY = tmpDuringElProps.scaleY);
-    tmpDuringElProps.originX !== originXCurr && (this.originX = tmpDuringElProps.originX);
-    tmpDuringElProps.originY !== originYCurr && (this.originY = tmpDuringElProps.originY);
-    tmpDuringElProps.rotation !== rotationCurr && (this.rotation = tmpDuringElProps.rotation);
-
-    if (isText) {
-        const currTmpStl = tmpDuringElProps.style; // Allow user modify `.style`.
-        currTmpStl && currTmpStl.text !== textCurr && (thisText.style.text = currTmpStl.text, dirtyStyle = true);
-    }
-
-    dirtyStyle && this.dirty();
-    // markRedraw() will be called by default.
+
+    tmpDuringScope.el = this;
+    tmpDuringScope.isShapeDirty = false;
+    tmpDuringScope.isStyleDirty = false;
+
+    customDuring(customDuringAPI);
+
+    if (tmpDuringScope.isShapeDirty && (this as graphicUtil.Path).dirtyShape) {
+        (this as graphicUtil.Path).dirtyShape();
+    }
+    if (tmpDuringScope.isStyleDirty && (this as Displayable).dirtyStyle) {
+        (this as Displayable).dirtyStyle();
+    }
+    // markRedraw() will be called by default in during.
 
     // FIXME: if in future meet the case that some prop will be both modified in `during` and `state`,
     // consider the issue that the prop might be incorrect when return to "normal" state.
diff --git a/test/custom-transition.html b/test/custom-transition.html
index 2d0f762..a51d31d 100644
--- a/test/custom-transition.html
+++ b/test/custom-transition.html
@@ -40,7 +40,7 @@ under the License.
         <div id="spiral-fixed-extent"></div>
         <div id="spiral-dynamic-extent"></div>
         <div id="texture-bar-by-clipPath"></div>
-        <div id="enter-animation"></div>
+        <div id="enter-animation-and-merge"></div>
         <div id="enter-animation2"></div>
         <div id="enter-animation-clipPath"></div>
         <div id="style-animation"></div>
@@ -185,10 +185,10 @@ under the License.
                             fill: color.inner,
                             stroke: color.border
                         },
-                        during: function (elProps) {
-                            elProps.shape.points = makeShapePoints(
-                                api, valOnRadius, elProps.shape.valOnAngle
-                            );
+                        during: function (apiDuring) {
+                            apiDuring.setShape('points', makeShapePoints(
+                                api, valOnRadius, apiDuring.getShape('valOnAngle')
+                            ));
                         }
                     });
                 }
@@ -230,12 +230,12 @@ under the License.
                             verticalAlign: 'middle'
                         },
                         z2: 50,
-                        during: function (elProps) {
-                            var iValOnAngle = elProps.shape.valOnAngle;
+                        during: function (apiDuring) {
+                            var iValOnAngle = apiDuring.getShape('valOnAngle');
                             var point = makeLabelPosition(api, valOnRadius, iValOnAngle);
-                            elProps.x = point[0];
-                            elProps.y = point[1];
-                            elProps.style.text = getText(iValOnAngle);
+                            apiDuring.setAttr('x', point[0]);
+                            apiDuring.setAttr('y', point[1]);
+                            apiDuring.setStyle('text', getText(iValOnAngle));
                         }
                     });
 
@@ -414,9 +414,13 @@ under the License.
                             fill: color.inner,
                             stroke: color.border
                         },
-                        during: function (elProps) {
-                            var shp = elProps.shape;
-                            shp.points = makeShapePoints(params, shp.widthRadius, shp.startRadius, shp.endRadian);
+                        during: function (apiDuring) {
+                            apiDuring.setShape('points', makeShapePoints(
+                                params,
+                                apiDuring.getShape('widthRadius'),
+                                apiDuring.getShape('startRadius'),
+                                apiDuring.getShape('endRadian')
+                            ));
                         }
                     });
                 }
@@ -476,12 +480,17 @@ under the License.
                             }
                         },
                         z2: 50,
-                        during: function (elProps) {
-                            var shp = elProps.shape;
-                            var point = makeLabelPosition(params, shp.widthRadius, shp.startRadius, shp.endRadian);
-                            elProps.x = point[0];
-                            elProps.y = point[1];
-                            elProps.style.text = makeText(shp.endRadian);
+                        during: function (apiDuring) {
+                            var endRadian = apiDuring.getShape('endRadian');
+                            var point = makeLabelPosition(
+                                params,
+                                apiDuring.getShape('widthRadius'),
+                                apiDuring.getShape('startRadius'),
+                                endRadian
+                            );
+                            apiDuring.setAttr('x', point[0]);
+                            apiDuring.setAttr('y', point[1]);
+                            apiDuring.setStyle('text', makeText(endRadian));
                         }
                     });
 
@@ -659,8 +668,11 @@ under the License.
                                     $transition: 'polarEndRadian',
                                     $enterFrom: { polarEndRadian: 0 }
                                 },
-                                during: function (elProps) {
-                                    elProps.shape.points = makePionterPoints(params, elProps.shape.polarEndRadian);
+                                during: function (apiDuring) {
+                                    apiDuring.setShape(
+                                        'points',
+                                        makePionterPoints(params, apiDuring.getShape('polarEndRadian'))
+                                    );
                                 }
                             },
                         }, {
@@ -694,8 +706,8 @@ under the License.
                                 verticalAlign: 'middle',
                                 $enterFrom: { opacity: 0 }
                             },
-                            during: function (elProps) {
-                                elProps.style.text = makeText(elProps.shape.valOnRadian);
+                            during: function (apiDuring) {
+                                apiDuring.setStyle('text', makeText(apiDuring.getShape('valOnRadian')));
                             }
                         }]
                     };
@@ -852,11 +864,12 @@ under the License.
                     }]
                 };
 
-                var chart = testHelper.create(echarts, 'enter-animation', {
+                var chart = testHelper.create(echarts, 'enter-animation-and-merge', {
                     title: [
                         '(1) Move dataZoom, position should have transition animation.',
                         '(2) Use dataZoom hide a data item, and then show it, ensure the **fade in** animation not be interupted.',
-                        '(3) click button to setOption merge.'
+                        '(3) click button to setOption merge.',
+                        '(4) Repeat (2), should be correct.'
                     ],
                     height: 300,
                     option: option,


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@echarts.apache.org
For additional commands, e-mail: commits-help@echarts.apache.org