You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@echarts.apache.org by sh...@apache.org on 2020/09/13 08:02:51 UTC

[incubator-echarts] branch custom-shape-morphing created (now 69be972)

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

shenyi pushed a change to branch custom-shape-morphing
in repository https://gitbox.apache.org/repos/asf/incubator-echarts.git.


      at 69be972  feat(custom): add shapeMorphing option in renderItem returns.

This branch includes the following new commits:

     new 69be972  feat(custom): add shapeMorphing option in renderItem returns.

The 1 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.



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


[incubator-echarts] 01/01: feat(custom): add shapeMorphing option in renderItem returns.

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

shenyi pushed a commit to branch custom-shape-morphing
in repository https://gitbox.apache.org/repos/asf/incubator-echarts.git

commit 69be972c5ffca252e572fbee913418a1fc811429
Author: pissang <bm...@gmail.com>
AuthorDate: Sun Sep 13 16:01:55 2020 +0800

    feat(custom): add shapeMorphing option in renderItem returns.
---
 src/chart/custom.ts     |  42 +++++++++++++-
 test/custom-hexbin.html | 143 ++++++++++++++++++++++++++++++------------------
 2 files changed, 129 insertions(+), 56 deletions(-)

diff --git a/src/chart/custom.ts b/src/chart/custom.ts
index 5940580..dd60ba1 100644
--- a/src/chart/custom.ts
+++ b/src/chart/custom.ts
@@ -18,7 +18,7 @@
 */
 
 import {
-    hasOwn, assert, isString, retrieve2, retrieve3, defaults, each, keys, isArrayLike, bind
+    hasOwn, assert, isString, retrieve2, retrieve3, defaults, each, keys, isArrayLike, bind, logError, isFunction
 } from 'zrender/src/core/util';
 import * as graphicUtil from '../util/graphic';
 import { setDefaultStateProxy, enableHoverEmphasis } from '../util/states';
@@ -80,6 +80,7 @@ import {
 import Transformable from 'zrender/src/core/Transformable';
 import { ItemStyleProps } from '../model/mixin/itemStyle';
 import { cloneValue } from 'zrender/src/animation/Animator';
+import { morphPath } from 'zrender/src/tool/morphPath';
 
 
 const inner = makeInner<{
@@ -119,6 +120,13 @@ type TransitionTransformOption = {
     enterFrom?: Dictionary<unknown>;
     leaveTo?: Dictionary<unknown>;
 };
+type ShapeMorphingOption = {
+    /**
+     * If do shape morphing animation when type is changed.
+     * Only available on path.
+     */
+    shapeMorphing?: boolean
+};
 
 interface CustomBaseElementOption extends Partial<Pick<
     Element, TransformProps | 'silent' | 'ignore' | 'textConfig'
@@ -167,10 +175,10 @@ interface CustomGroupOption extends CustomBaseElementOption {
     children: Omit<CustomElementOption, 'focus' | 'blurScope'>[];
     $mergeChildren: false | 'byName' | 'byIndex';
 }
-interface CustomZRPathOption extends CustomDisplayableOption {
+interface CustomZRPathOption extends CustomDisplayableOption, ShapeMorphingOption {
     shape?: PathProps['shape'] & TransitionAnyOption;
 }
-interface CustomSVGPathOption extends CustomDisplayableOption {
+interface CustomSVGPathOption extends CustomDisplayableOption, ShapeMorphingOption {
     type: 'path';
     shape?: {
         // SVG Path, like 'M0,0 L0,-20 L70,-1 L70,0 Z'
@@ -1539,6 +1547,28 @@ function createOrUpdateItem(
     return el;
 }
 
+function applyShapeMorphingAnimation(oldEl: Element, el: Element, seriesModel: SeriesModel, dataIndex: number) {
+    if (!((oldEl instanceof graphicUtil.Path) && (el instanceof graphicUtil.Path))) {
+        if (__DEV__) {
+            logError('shapeMorphing can only be applied on two paths.');
+        }
+        return;
+    }
+    if (seriesModel.isAnimationEnabled()) {
+        const duration = seriesModel.get('animationDurationUpdate');
+        const delay = seriesModel.get('animationDelayUpdate');
+        const easing = seriesModel.get('animationEasingUpdate');
+        const durationNumber = isFunction(duration) ? duration(dataIndex) : duration;
+        if (durationNumber > 0) {
+            morphPath(oldEl, el, {
+                duration: durationNumber,
+                delay: isFunction(delay) ? delay(dataIndex) : delay,
+                easing: easing
+            });
+        }
+    }
+}
+
 function doCreateOrUpdateEl(
     el: Element,
     dataIndex: number,
@@ -1553,10 +1583,12 @@ function doCreateOrUpdateEl(
     }
 
     let toBeReplacedIdx = -1;
+    let oldEl: Element;
 
     if (el && doesElNeedRecreate(el, elOption)) {
         // Should keep at the original index, otherwise "merge by index" will be incorrect.
         toBeReplacedIdx = group.childrenRef().indexOf(el);
+        oldEl = el;
         el = null;
     }
 
@@ -1588,6 +1620,10 @@ function doCreateOrUpdateEl(
     );
 
     updateElNormal(el, dataIndex, elOption, elOption.style, attachedTxInfoTmp, seriesModel, isInit, false);
+    // Do shape morphing
+    if ((elOption as CustomZRPathOption).shapeMorphing && el && oldEl) {
+        applyShapeMorphingAnimation(oldEl, el, seriesModel, dataIndex);
+    }
 
     for (let i = 0; i < STATES.length; i++) {
         const stateName = STATES[i];
diff --git a/test/custom-hexbin.html b/test/custom-hexbin.html
index c9c42e2..7d69a93 100644
--- a/test/custom-hexbin.html
+++ b/test/custom-hexbin.html
@@ -38,7 +38,7 @@ under the License.
                 font-weight: bold;
                 font-size: 14px;
             }
-            .chart {
+            .test-chart {
                 height: 500px;
                 margin: 10px auto;
             }
@@ -156,56 +156,71 @@ under the License.
                             return [bin.x, bin.y, bin.points.length, (made / bin.points.length * 100).toFixed(2)];
                         });
 
-                        function renderItemHexBin(params, api) {
-                            var center = api.coord([api.value(0), api.value(1)]);
-                            var points = [];
-                            var pointsBG = [];
-
-                            var maxViewRadius = api.size([hexagonRadiusInGeo, 0])[0];
-                            var minViewRadius = Math.min(maxViewRadius, 4);
-                            var extentMax = Math.log(Math.sqrt(hexBinResult.maxBinLen));
-                            var viewRadius = echarts.number.linearMap(
-                                Math.log(Math.sqrt(api.value(2))),
-                                [0, extentMax],
-                                [minViewRadius, maxViewRadius]
-                            );
-
-                            var angle = Math.PI / 6;
-                            for (var i = 0; i < 6; i++, angle += Math.PI / 3) {
-                                points.push([
-                                    center[0] + viewRadius * Math.cos(angle),
-                                    center[1] + viewRadius * Math.sin(angle)
-                                ]);
-                                pointsBG.push([
-                                    center[0] + maxViewRadius * Math.cos(angle),
-                                    center[1] + maxViewRadius * Math.sin(angle)
-                                ]);
-                            }
+                        function createItemRenderer(type) {
+                            type = type || 'polygon';
+                            return function renderItemHexBin(params, api) {
+                                var center = api.coord([api.value(0), api.value(1)]);
+                                var points = [];
+                                var pointsBG = [];
+
+                                var maxViewRadius = api.size([hexagonRadiusInGeo, 0])[0];
+                                var minViewRadius = Math.min(maxViewRadius, 4);
+                                var extentMax = Math.log(Math.sqrt(hexBinResult.maxBinLen));
+                                var viewRadius = echarts.number.linearMap(
+                                    Math.log(Math.sqrt(api.value(2))),
+                                    [0, extentMax],
+                                    [minViewRadius, maxViewRadius]
+                                );
+
+                                var angle = Math.PI / 6;
+                                for (var i = 0; i < 6; i++, angle += Math.PI / 3) {
+                                    points.push([
+                                        center[0] + viewRadius * Math.cos(angle),
+                                        center[1] + viewRadius * Math.sin(angle)
+                                    ]);
+                                    pointsBG.push([
+                                        center[0] + maxViewRadius * Math.cos(angle),
+                                        center[1] + maxViewRadius * Math.sin(angle)
+                                    ]);
+                                }
 
-                            return {
-                                type: 'group',
-                                children: [{
-                                    type: 'polygon',
-                                    shape: {
-                                        points: points
-                                    },
-                                    style: {
-                                        stroke: '#ccc',
-                                        fill: api.visual('color'),
-                                        lineWidth: 0
-                                    }
-                                }, {
-                                    type: 'polygon',
-                                    shape: {
-                                        points: pointsBG
-                                    },
-                                    style: {
-                                        stroke: null,
-                                        fill: 'rgba(0,0,0,0.5)',
-                                        lineWidth: 0
-                                    },
-                                    z2: -19
-                                }]
+                                return {
+                                    type: 'group',
+                                    children: [{
+                                        type,
+                                        shapeMorphing: true,
+                                        shape: type === 'polygon' ? {
+                                            points: points
+                                        } : {
+                                            // Circle
+                                            cx: center[0],
+                                            cy: center[1],
+                                            r: viewRadius
+                                        },
+                                        style: {
+                                            stroke: '#ccc',
+                                            fill: api.visual('color'),
+                                            lineWidth: 0
+                                        }
+                                    }, {
+                                        type,
+                                        shapeMorphing: true,
+                                        shape: type === 'polygon' ? {
+                                            points: pointsBG
+                                        } : {
+                                            // Circle
+                                            cx: center[0],
+                                            cy: center[1],
+                                            r: maxViewRadius
+                                        },
+                                        style: {
+                                            stroke: null,
+                                            fill: 'rgba(0,0,0,0.5)',
+                                            lineWidth: 0
+                                        },
+                                        z2: -19
+                                    }]
+                                };
                             };
                         }
 
@@ -292,7 +307,7 @@ under the License.
                                 type: 'custom',
                                 coordinateSystem: 'geo',
                                 geoIndex: 0,
-                                renderItem: renderItemHexBin,
+                                renderItem: createItemRenderer(),
                                 dimensions: [null, null, 'Field Goals Attempted (hexagon size)', 'Field Goal Percentage (color)'],
                                 encode: {
                                     tooltip: [2, 3]
@@ -308,8 +323,30 @@ under the License.
                             }]
                         };
 
-                        var width = 700;
-                        testHelper.createChart(echarts, 'hexagonal-binning', option, {
+                        var width = 1000;
+                        const myChart = testHelper.create(echarts, 'hexagonal-binning', {
+                            option,
+                            buttons: [{
+                                text: 'Hexgon',
+                                onClick: function() {
+                                    myChart.setOption({
+                                        series: [{
+                                            type: 'custom',
+                                            renderItem: createItemRenderer('polygon')
+                                        }]
+                                    });
+                                }
+                            }, {
+                                text: 'Circle',
+                                onClick: function() {
+                                    myChart.setOption({
+                                        series: [{
+                                            type: 'custom',
+                                            renderItem: createItemRenderer('circle')
+                                        }]
+                                    });
+                                }
+                            }],
                             width: width,
                             height: width * nbaCourt.height / nbaCourt.width
                         });


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