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/02 17:54:35 UTC

[incubator-echarts] 05/10: feature: add duration animation for custom series.

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 c56e2dcd1e553780b91c6a004c1a06b770f082bf
Author: 100pah <su...@gmail.com>
AuthorDate: Wed May 13 04:08:33 2020 +0800

    feature: add duration animation for custom series.
---
 src/chart/custom.ts      |  54 +++++-
 test/custom-feature.html | 442 ++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 494 insertions(+), 2 deletions(-)

diff --git a/src/chart/custom.ts b/src/chart/custom.ts
index 3ed15b9..a58633d 100644
--- a/src/chart/custom.ts
+++ b/src/chart/custom.ts
@@ -84,6 +84,8 @@ const inner = makeInner<{
     customImagePath: CustomImageOption['style']['image'];
     customText: string;
     txConZ2Set: number;
+    orginalDuring: Element['updateDuringAnimation'];
+    customDuring: CustomZRPathOption['during'];
 }, Element>();
 
 type CustomExtraElementInfo = Dictionary<unknown>;
@@ -103,6 +105,8 @@ interface CustomBaseElementOption extends Partial<Pick<
     info?: CustomExtraElementInfo;
     // `false` means remove the textContent.
     textContent?: CustomTextOption | false;
+    // updateDuringAnimation
+    during?(elProps: CustomDuringElProps): void;
 };
 interface CustomDisplayableOption extends CustomBaseElementOption, Partial<Pick<
     Displayable, 'zlevel' | 'z' | 'z2' | 'invisible'
@@ -128,6 +132,9 @@ interface CustomGroupOption extends CustomBaseElementOption {
 }
 interface CustomZRPathOption extends CustomDisplayableOption, Pick<PathProps, 'shape'> {
 }
+interface CustomDuringElProps extends Partial<Pick<Element, TransformProps>> {
+    shape?: PathProps['shape'];
+}
 interface CustomSVGPathOption extends CustomDisplayableOption {
     type: 'path';
     shape?: {
@@ -277,7 +284,7 @@ const Z2_SPECIFIED_BIT = {
     emphasis: 1
 } as const;
 
-
+const tmpDuringElProps = {} as CustomDuringElProps;
 
 
 export type PrepareCustomInfo = (coordSys: CoordinateSystem) => {
@@ -640,6 +647,19 @@ function updateElNormal(
     zrUtil.hasOwn(elOption, 'silent') && (el.silent = elOption.silent);
     zrUtil.hasOwn(elOption, 'ignore') && (el.ignore = elOption.ignore);
 
+    const customDuringMounted = el.updateDuringAnimation === elUpdateDuringAnimation;
+    if (elOption.during) {
+        const innerEl = inner(el);
+        if (!customDuringMounted) {
+            innerEl.orginalDuring = el.updateDuringAnimation;
+            el.updateDuringAnimation = elUpdateDuringAnimation;
+        }
+        innerEl.customDuring = elOption.during;
+    }
+    else if (customDuringMounted) {
+        el.updateDuringAnimation = inner(el).orginalDuring;
+    }
+
     if (!isTextContent) {
         // `elOption.info` enables user to mount some info on
         // elements and use them in event handlers.
@@ -650,6 +670,38 @@ function updateElNormal(
     el.markRedraw();
 }
 
+function elUpdateDuringAnimation(this: graphicUtil.Path, key: string): void {
+    const innerEl = inner(this);
+    // FIXME `this.markRedraw();` directly ?
+    innerEl.orginalDuring.call(this, key);
+    const customDuring = innerEl.customDuring;
+
+    // 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.
+    tmpDuringElProps.shape = this.shape;
+    tmpDuringElProps.x = this.x;
+    tmpDuringElProps.y = this.y;
+    tmpDuringElProps.scaleX = this.scaleX;
+    tmpDuringElProps.scaleX = this.scaleY;
+    tmpDuringElProps.originX = this.originX;
+    tmpDuringElProps.originY = this.originY;
+    tmpDuringElProps.rotation = this.rotation;
+
+    customDuring(tmpDuringElProps);
+
+    tmpDuringElProps.shape !== this.shape && (this.shape = tmpDuringElProps.shape);
+    // Consider prop on prototype.
+    tmpDuringElProps.x !== this.x && (this.x = tmpDuringElProps.x);
+    tmpDuringElProps.y !== this.y && (this.y = tmpDuringElProps.y);
+    tmpDuringElProps.scaleX !== this.scaleX && (this.scaleX = tmpDuringElProps.scaleX);
+    tmpDuringElProps.scaleY !== this.scaleY && (this.scaleY = tmpDuringElProps.scaleY);
+    tmpDuringElProps.originX !== this.originX && (this.originX = tmpDuringElProps.originX);
+    tmpDuringElProps.originY !== this.originY && (this.originY = tmpDuringElProps.originY);
+    tmpDuringElProps.rotation !== this.rotation && (this.rotation = tmpDuringElProps.rotation);
+}
+
 function updateElOnState(
     state: DisplayStateNonNormal,
     el: Element,
diff --git a/test/custom-feature.html b/test/custom-feature.html
index 03457ed..56e106e 100644
--- a/test/custom-feature.html
+++ b/test/custom-feature.html
@@ -38,7 +38,10 @@ under the License.
         <div id="main0"></div>
         <div id="main2"></div>
         <div id="main3"></div>
-        <!-- <div id="main1"></div> -->
+        <div id="init-animation-additive"></div>
+        <!-- <div id="spiral"></div> -->
+        <div id="spiral2"></div>
+        <div id="texture-bar"></div>
 
 
         <script>
@@ -365,6 +368,443 @@ under the License.
 
 
 
+        <script>
+
+            require(['echarts'], function (echarts) {
+
+                var animationDuration = 5000;
+                var animationDurationUpdate = 4000;
+                var option = {
+                    xAxis: {},
+                    yAxis: {},
+                    dataZoom: [
+                        { type: 'slider' },
+                        { type: 'inside' }
+                    ],
+                    animationDuration: animationDuration,
+                    animationDurationUpdate: animationDurationUpdate,
+                    series: [{
+                        type: 'custom',
+                        renderItem: function (params, api) {
+                            return {
+                                type: 'group',
+                                position: api.coord([api.value(0), api.value(1)]),
+                                children: [{
+                                    type: 'rect',
+                                    shape: {
+                                        x: -50,
+                                        y: 50,
+                                        width: 100,
+                                        height: 150,
+                                        r: 10
+                                    },
+                                    style: {
+                                        fill: 'rgba(102,241,98,0.9)'
+                                    }
+                                }, {
+                                    type: 'circle',
+                                    shape: {
+                                        cx: -50,
+                                        cy: 50,
+                                        r: 30
+                                    },
+                                    style: {
+                                        fill: 'blue'
+                                    },
+                                    textContent: {
+                                        text: 'data',
+                                        style: {
+                                            fill: '#fff'
+                                        }
+                                    }
+                                }]
+                            };
+                        },
+                        data: [[121, 333], [29, 312]]
+                    }]
+                };
+
+                var chart = testHelper.create(echarts, 'init-animation-additive', {
+                    title: [
+                        'Style merge:',
+                        '(1) dataZoom hide a data item, and then show it, ensure the fade in animation normal.',
+                        '(2) click button to setOption merge.'
+                    ],
+                    option: option,
+                    info: {
+                        animationDuration: animationDuration,
+                        animationDurationUpdate: animationDurationUpdate
+                    },
+                    buttons: [{
+                        text: 'merge style: border become blue, but background not changed',
+                        onclick: function () {
+                            chart.setOption({
+                                type: 'custom',
+                                renderItem: function (params, api) {
+                                    return {
+                                        type: 'group',
+                                        children: [{
+                                            type: 'rect',
+                                            style: {
+                                                stroke: 'red',
+                                                lineWidth: 5
+                                            }
+                                        }]
+                                    };
+                                }
+                            });
+                        }
+                    }]
+                });
+            });
+
+        </script>
+
+
+
+
+<!--
+
+        <script>
+            require([
+                'echarts'/*, 'map/js/china' */
+            ], function (echarts) {
+                var animationDuration = 5000;
+                var animationDurationUpdate = 4000;
+                var angleLabel = ['Aries', 'Taurus', 'Gemini', 'Cancer', 'Leo', 'Virgo', 'Libra', 'Scorpius', 'Sagittarius', 'Capricornus', 'Aquarius', 'Pisces'];
+                var angleRoundValue = angleLabel.length;
+                var radiusOffset = 10;
+                var angleStep = angleRoundValue / 90;
+                var barWidthValue = 0.4;
+                var radiusStep = 4;
+                var colors = {
+                    'A': { stroke: 'green', fill: 'rgba(0,152,0,0.6)' },
+                    'B': { stroke: 'red', fill: 'rgba(152,0,0,0.6)' },
+                    'C': { stroke: 'blue', fill: 'rgba(0,0, 152,0.6)' },
+                };
+                var allData = [[
+                    [[1, 3, 'A']],
+                    [[2, 6, 'B']],
+                    [[3, 9, 'C']],
+                ], [
+                    [[1, 12, 'A']],
+                    [[2, 16, 'B']],
+                    [[3, 14, 'C']],
+                ], [
+                    [[1, 17, 'A']],
+                    [[2, 22, 'B']],
+                    [[3, 19, 'C']],
+                ]];
+                var currentDataIndex = 0;
+
+                function getMaxRadius() {
+                    var radius = 0;
+                    for (var j = 0; j < allData.length; j++) {
+                        var data = allData[j];
+                        for (var i = 0; i < data.length; i++) {
+                            radius = Math.max(radius, getSpiralValueRadius(data[i][0][0], data[i][0][1]));
+                        }
+                    }
+                    return Math.ceil(radius * 1.2);
+                }
+
+                function getSpiralValueRadius(valRadius, valAngle) {
+                    return valRadius + radiusStep * (valAngle / angleRoundValue);
+                }
+
+                function renderItem(params, api) {
+                    var valueRadius = api.value(0);
+                    var valueAngle = api.value(1);
+                    var points = [];
+                    for (var iAngleVal = 0, end = valueAngle + angleStep; iAngleVal < end; iAngleVal += angleStep) {
+                        iAngleVal > valueAngle && (iAngleVal = valueAngle);
+                        var iRadiusVal = getSpiralValueRadius(valueRadius - barWidthValue, iAngleVal);
+                        var point = api.coord([iRadiusVal, iAngleVal]).slice(0, 2);
+                        points.push(point);
+                    }
+                    for (var iAngleVal = valueAngle; iAngleVal > -angleStep; iAngleVal -= angleStep) {
+                        iAngleVal < 0 && (iAngleVal = 0);
+                        var iRadiusVal = getSpiralValueRadius(valueRadius + barWidthValue, iAngleVal);
+                        var point = api.coord([iRadiusVal, iAngleVal]).slice(0, 2);
+                        points.push(point);
+                    }
+                    var name = api.value(2);
+                    return {
+                        type: 'polygon',
+                        shape: { points: points },
+                        style: {
+                            lineWidth: 1,
+                            fill: colors[name].fill,
+                            stroke: colors[name].stroke
+                        }
+                    };
+                }
+
+                var option = {
+                    animationDuration: animationDuration,
+                    animationDurationUpdate: animationDurationUpdate,
+                    angleAxis: {
+                        type: 'value',
+                        // splitLine: { show: false },
+                        splitArea: {show: true},
+                        axisLabel: {
+                            formatter: function(val) {
+                                return angleLabel[val];
+                            },
+                            color: 'rgba(0,0,0,0.2)'
+                        },
+                        axisLine: { lineStyle: { color: 'rgba(0,0,0,0.2)' } },
+                        min: 0,
+                        max: angleRoundValue
+                    },
+                    radiusAxis: {
+                        type: 'value',
+                        splitLine: { show: false },
+                        axisLabel: { color: 'rgba(0,0,0,0.2)' },
+                        axisLine: { lineStyle: { color: 'rgba(0,0,0,0.2)' } },
+                        min: 0,
+                        max: getMaxRadius()
+                    },
+                    polar: {
+                    },
+                    tooltip: {},
+                    series: [{
+                        type: 'custom',
+                        name: 'A',
+                        coordinateSystem: 'polar',
+                        renderItem: renderItem,
+                        data: allData[currentDataIndex][0]
+                    }, {
+                        type: 'custom',
+                        name: 'B',
+                        coordinateSystem: 'polar',
+                        renderItem: renderItem,
+                        data: allData[currentDataIndex][1]
+                    }, {
+                        type: 'custom',
+                        name: 'C',
+                        coordinateSystem: 'polar',
+                        renderItem: renderItem,
+                        data: allData[currentDataIndex][2]
+                    }]
+                };
+
+                var chart = testHelper.create(echarts, 'spiral', {
+                    title: [
+                        'animation: ',
+                    ],
+                    option: option,
+                    buttons: [{
+                        text: 'next',
+                        onclick: function () {
+                            currentDataIndex++;
+                            currentDataIndex >= allData.length && (currentDataIndex = 0);
+                            chart.setOption({
+                                series: [{
+                                    data: allData[currentDataIndex][0]
+                                }, {
+                                    data: allData[currentDataIndex][1]
+                                }, {
+                                    data: allData[currentDataIndex][2]
+                                }]
+                            })
+                        }
+                    }, {
+                        text: 'enable animation',
+                        onclick: function () {
+                            chart.setOption({ animation: true });
+                        }
+                    }, {
+                        text: 'disable animation',
+                        onclick: function () {
+                            chart.setOption({ animation: false });
+                        }
+                    }]
+                });
+            });
+        </script>
+ -->
+
+
+
+
+
+
+
+        <script>
+            require([
+                'echarts'/*, 'map/js/china' */
+            ], function (echarts) {
+                var animationDuration = 5000;
+                var animationDurationUpdate = 4000;
+                var animationEasingUpdate = 'elasticOut';
+                var angleLabel = ['Aries', 'Taurus', 'Gemini', 'Cancer', 'Leo', 'Virgo', 'Libra', 'Scorpius', 'Sagittarius', 'Capricornus', 'Aquarius', 'Pisces'];
+                var angleRoundValue = angleLabel.length;
+                var radiusOffset = 10;
+                var angleStep = angleRoundValue / 90;
+                var barWidthValue = 0.4;
+                var radiusStep = 4;
+                var colors = {
+                    'A': { stroke: 'green', fill: 'rgba(0,152,0,0.6)' },
+                    'B': { stroke: 'red', fill: 'rgba(152,0,0,0.6)' },
+                    'C': { stroke: 'blue', fill: 'rgba(0,0, 152,0.6)' },
+                };
+                var allData = [[
+                    [[1, 3, 'A']],
+                    [[2, 6, 'B']],
+                    [[3, 9, 'C']],
+                ], [
+                    [[1, 12, 'A']],
+                    [[2, 16, 'B']],
+                    [[3, 14, 'C']],
+                ], [
+                    [[1, 17, 'A']],
+                    [[2, 22, 'B']],
+                    [[3, 19, 'C']],
+                ]];
+                var currentDataIndex = 0;
+
+                function getMaxRadius() {
+                    var radius = 0;
+                    for (var j = 0; j < allData.length; j++) {
+                        var data = allData[j];
+                        for (var i = 0; i < data.length; i++) {
+                            radius = Math.max(radius, getSpiralValueRadius(data[i][0][0], data[i][0][1]));
+                        }
+                    }
+                    return Math.ceil(radius * 1.2);
+                }
+
+                function getSpiralValueRadius(valRadius, valAngle) {
+                    return valRadius + radiusStep * (valAngle / angleRoundValue);
+                }
+
+                function makeShapePoints(api, valueRadius, valueAngle) {
+                    var points = [];
+                    for (var iAngleVal = 0, end = valueAngle + angleStep; iAngleVal < end; iAngleVal += angleStep) {
+                        iAngleVal > valueAngle && (iAngleVal = valueAngle);
+                        var iRadiusVal = getSpiralValueRadius(valueRadius - barWidthValue, iAngleVal);
+                        var point = api.coord([iRadiusVal, iAngleVal]).slice(0, 2);
+                        points.push(point);
+                    }
+                    for (var iAngleVal = valueAngle; iAngleVal > -angleStep; iAngleVal -= angleStep) {
+                        iAngleVal < 0 && (iAngleVal = 0);
+                        var iRadiusVal = getSpiralValueRadius(valueRadius + barWidthValue, iAngleVal);
+                        var point = api.coord([iRadiusVal, iAngleVal]).slice(0, 2);
+                        points.push(point);
+                    }
+                    return points;
+                }
+
+                function renderItem(params, api) {
+                    var valueRadius = api.value(0);
+                    var valueAngle = api.value(1);
+                    var name = api.value(2);
+                    return {
+                        type: 'polygon',
+                        shape: {
+                            points: makeShapePoints(api, valueRadius, valueAngle),
+                            valueAngle: valueAngle
+                        },
+                        style: {
+                            lineWidth: 1,
+                            fill: colors[name].fill,
+                            stroke: colors[name].stroke
+                        },
+                        during: function (elProps) {
+                            elProps.shape.points = makeShapePoints(
+                                api, valueRadius, elProps.shape.valueAngle
+                            );
+                        }
+                    };
+                }
+
+                var option = {
+                    animationDuration: animationDuration,
+                    animationDurationUpdate: animationDurationUpdate,
+                    animationEasingUpdate: animationEasingUpdate,
+                    angleAxis: {
+                        type: 'value',
+                        // splitLine: { show: false },
+                        splitArea: {show: true},
+                        axisLabel: {
+                            formatter: function(val) {
+                                return angleLabel[val];
+                            },
+                            color: 'rgba(0,0,0,0.2)'
+                        },
+                        axisLine: { lineStyle: { color: 'rgba(0,0,0,0.2)' } },
+                        min: 0,
+                        max: angleRoundValue
+                    },
+                    radiusAxis: {
+                        type: 'value',
+                        splitLine: { show: false },
+                        axisLabel: { color: 'rgba(0,0,0,0.2)' },
+                        axisLine: { lineStyle: { color: 'rgba(0,0,0,0.2)' } },
+                        min: 0,
+                        max: getMaxRadius()
+                    },
+                    polar: {
+                    },
+                    tooltip: {},
+                    series: [{
+                        type: 'custom',
+                        name: 'A',
+                        coordinateSystem: 'polar',
+                        renderItem: renderItem,
+                        data: allData[currentDataIndex][0]
+                    }, {
+                        type: 'custom',
+                        name: 'B',
+                        coordinateSystem: 'polar',
+                        renderItem: renderItem,
+                        data: allData[currentDataIndex][1]
+                    }, {
+                        type: 'custom',
+                        name: 'C',
+                        coordinateSystem: 'polar',
+                        renderItem: renderItem,
+                        data: allData[currentDataIndex][2]
+                    }]
+                };
+
+                var chart = testHelper.create(echarts, 'spiral2', {
+                    title: [
+                        'animation: ',
+                    ],
+                    option: option,
+                    buttons: [{
+                        text: 'next',
+                        onclick: function () {
+                            currentDataIndex++;
+                            currentDataIndex >= allData.length && (currentDataIndex = 0);
+                            chart.setOption({
+                                series: [{
+                                    data: allData[currentDataIndex][0]
+                                }, {
+                                    data: allData[currentDataIndex][1]
+                                }, {
+                                    data: allData[currentDataIndex][2]
+                                }]
+                            })
+                        }
+                    }, {
+                        text: 'enable animation',
+                        onclick: function () {
+                            chart.setOption({ animation: true });
+                        }
+                    }, {
+                        text: 'disable animation',
+                        onclick: function () {
+                            chart.setOption({ animation: false });
+                        }
+                    }]
+                });
+            });
+        </script>
+
+
 
     </body>
 </html>
\ No newline at end of file


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