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/12/10 13:44:15 UTC

[incubator-echarts] 05/05: fix: when label animation is not finished, start a new label animation, the label should not jump the the last final value.

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

sushuang pushed a commit to branch fix/label-valueAnimation
in repository https://gitbox.apache.org/repos/asf/incubator-echarts.git

commit ab9aa43e7b0f782c9c6febc12c9c7ecc11847d11
Author: 100pah <su...@gmail.com>
AuthorDate: Thu Dec 10 21:43:08 2020 +0800

    fix: when label animation is not finished, start a new label animation, the label should not jump the the last final value.
---
 src/label/labelStyle.ts                   |  17 +-
 test/label-animation.html                 | 329 ++++++++++++++++++++----------
 test/lib/testHelper.js                    |  25 ++-
 test/line-endLabel.html                   |  87 +++++++-
 test/runTest/actions/__meta__.json        |   2 +
 test/runTest/actions/label-animation.json |   1 +
 test/runTest/actions/line-endLabel.json   |   1 +
 7 files changed, 344 insertions(+), 118 deletions(-)

diff --git a/src/label/labelStyle.ts b/src/label/labelStyle.ts
index 7934fe5..2a8caed 100644
--- a/src/label/labelStyle.ts
+++ b/src/label/labelStyle.ts
@@ -620,10 +620,14 @@ export const labelInner = makeInner<{
      */
     prevValue?: ParsedValue | ParsedValue[]
     /**
-     * Current value stored used for label.
+     * Target value stored used for label.
      */
     value?: ParsedValue | ParsedValue[]
     /**
+     * Current value in text animation.
+     */
+    interpolatedValue?: ParsedValue | ParsedValue[]
+    /**
      * If enable value animation
      */
     valueAnimation?: boolean
@@ -657,7 +661,9 @@ export function setLabelValueAnimation(
     }
 
     const obj = labelInner(label);
-    obj.prevValue = obj.value;
+    // Consider the case that being animating, do not use the `obj.value`,
+    // Otherwise it will jump to the `obj.value` when this new animation started.
+    obj.prevValue = retrieve2(obj.interpolatedValue, obj.value);
     obj.value = value;
 
     const normalLabelModel = labelStatesModels.normal;
@@ -693,6 +699,7 @@ export function animateLabelValue(
             currentValue,
             percent
         );
+        labelInnerStore.interpolatedValue = percent === 1 ? null : interpolated;
 
         const labelText = getLabelText({
             labelDataIndex: dataIndex,
@@ -705,6 +712,8 @@ export function animateLabelValue(
         setLabelText(textEl, labelText);
     }
 
-    (prevValue == null ? initProps
-        : updateProps)(textEl, {}, seriesModel, dataIndex, null, during);
+    (prevValue == null
+        ? initProps
+        : updateProps
+    )(textEl, {}, seriesModel, dataIndex, null, during);
 }
\ No newline at end of file
diff --git a/test/label-animation.html b/test/label-animation.html
index e9940e9..5a534d8 100644
--- a/test/label-animation.html
+++ b/test/label-animation.html
@@ -39,11 +39,13 @@ under the License.
 
         <div id="main0"></div>
         <div id="main1"></div>
+        <div id="main2"></div>
+
 
 
 
         <script>
-            function makeSource1() {
+            function makeSource0() {
                 return [
                     [ 'Int','Country', 'Float', 'Num'],
                     [900, 'Germany', 90.55, 0],
@@ -56,6 +58,17 @@ under the License.
                     [1200, 'France', 120.55, 3],
                 ];
             }
+            function makeSource1() {
+                return {
+                    category: ['Germany', 'France'],
+                    dataList: [
+                        [900, 1900],
+                        [300, 1300],
+                        [800, 1800],
+                        [200, 1200]
+                    ]
+                };
+            }
         </script>
 
 
@@ -67,6 +80,42 @@ under the License.
             var option;
             var currNum = 0;
 
+            var formatterConfigs = [
+                {
+                    text: 'formatter: {c} 元',
+                    formatter: '{c} 元'
+                },
+                {
+                    text: 'formatter: {@[1]} {@[0]} 元',
+                    formatter: '{@[1]} {@[0]} 元'
+                },
+                {
+                    text: 'formatter: {@Country} {@Int} 元',
+                    formatter: '{@Country} {@Int} 元'
+                },
+                {
+                    text: 'formatter: callback',
+                    formatter: function (params) {
+                        return params.value.join(',') + ' 元';
+                    }
+                }
+            ];
+            var formatterSwitchButtons = [];
+            for (var i = 0; i < formatterConfigs.length; i++) {
+                var config = formatterConfigs[i];
+                formatterSwitchButtons.push({
+                    text: config.text,
+                    onclick: (function (cfg) {
+                        return function () {
+                            currNum = 0;
+                            var option = makeOption(cfg.formatter);
+                            chart.__testHelper.updateInfo(cfg.formatter.toString(), 'formatter');
+                            chart.setOption(option, { notMerge: true } );
+                        };
+                    })(config)
+                });
+            }
+
             function makeTransformDataset() {
                 return {
                     id: 'singleA',
@@ -88,68 +137,57 @@ under the License.
                 };
             }
 
-            option = {
-                animationDuration: 5000,
-                animationDurationUpdate: 5000,
-                dataset: [{
-                    source: makeSource1(),
-                },
-                    makeTransformDataset()
-                ],
-                xAxis: {},
-                yAxis: { type: 'category' },
-                grid: {
-                    right: 160
-                },
-                series: [{
-                    type: 'bar',
-                    datasetId: 'singleA',
-                    encode: {
-                        x: 'Int',
-                        y: 'Country'
+            function makeOption(labelFormatter) {
+                return {
+                    animationDuration: 3000,
+                    animationDurationUpdate: 3000,
+                    dataset: [{
+                        source: makeSource0(),
                     },
-                    label: {
-                        show: true,
-                        position: 'right',
-                        fontSize: 16,
-                        formatter: '(StrFmt) {c} 元',
-                        valueAnimation: true
-                    }
-                }, {
-                    type: 'bar',
-                    datasetId: 'singleA',
-                    encode: {
-                        x: 'Int',
-                        y: 'Country'
+                        makeTransformDataset()
+                    ],
+                    xAxis: {},
+                    yAxis: { type: 'category' },
+                    grid: {
+                        right: 160
                     },
-                    label: {
-                        show: true,
-                        position: 'right',
-                        fontSize: 16,
-                        formatter: function (params) {
-                            console.log(params);
-                            return '(CbFmt) ' + params.value.join(',') + ' 元';
+                    series: [{
+                        id: Math.random(),
+                        type: 'bar',
+                        datasetId: 'singleA',
+                        encode: {
+                            x: 'Int',
+                            y: 'Country'
                         },
-                        valueAnimation: true
-                    }
-                }]
-            };
+                        label: {
+                            show: true,
+                            position: 'right',
+                            fontSize: 16,
+                            formatter: labelFormatter,
+                            valueAnimation: true
+                        }
+                    }]
+                };
+            }
 
             var chart = testHelper.create(echarts, 'main0', {
                 title: [
-                    'Check init and **click next once**',
-                    'label text anmiation should OK. **except Country**',
-                    'label should display like : "910,France,617.52,0 元"',
+                    'Check **init** valueAnimation should be OK',
+                    'Swithch formatter, for each formatter **click next once**',
+                    'label text anmiation should OK. **except Country**'
                 ],
-                option: option,
+                option: makeOption(formatterConfigs[0].formatter),
+                info: formatterConfigs[0].formatter.toString(),
+                infoKey: 'formatter',
                 buttons: [{
-                    text: 'next', onclick: function () {
+                    text: 'next',
+                    onclick: function () {
                         currNum++;
                         chart.setOption({
                             dataset: makeTransformDataset()
                         });
                     }
-                }],
+                }].concat(formatterSwitchButtons)
             });
         });
         </script>
@@ -162,92 +200,171 @@ under the License.
 
 
 
+
+
+
+
+
+
         <script>
         require(['echarts'/*, 'map/js/china' */], function (echarts) {
             var option;
             var currNum = 0;
 
-            function makeTransformDataset() {
+            var formatterConfigs = [
+                {
+                    text: 'formatter: {c} 元',
+                    formatter: '{c} 元'
+                },
+                // { // not supportted in this case
+                //     text: 'formatter: {@[1]} {@[0]} 元',
+                //     formatter: '{@[1]} {@[0]} 元'
+                // },
+                {
+                    text: 'formatter: callback',
+                    formatter: function (params) {
+                        return params.value + ' 元';
+                    }
+                }
+            ];
+            var formatterSwitchButtons = [];
+            for (var i = 0; i < formatterConfigs.length; i++) {
+                var config = formatterConfigs[i];
+                formatterSwitchButtons.push({
+                    text: config.text,
+                    onclick: (function (cfg) {
+                        return function () {
+                            currNum = 0;
+                            var option = makeOption(cfg.formatter);
+                            chart.__testHelper.updateInfo(cfg.formatter.toString(), 'formatter');
+                            chart.setOption(option, { notMerge: true } );
+                        };
+                    })(config)
+                });
+            }
+
+            var source1 = makeSource1();
+
+            function makeOption(labelFormatter) {
                 return {
-                    id: 'singleA',
-                    transform: {
-                        type: 'filter',
-                        print: true,
-                        config: {
-                            and: [{
-                                or: [{
-                                    dimension: 'Country', eq: 'Germany'
-                                }, {
-                                    dimension: 'Country', eq: 'France'
-                                }]
-                            }, {
-                                dimension: 'Num', eq: currNum
-                            }]
+                    animationDuration: 3000,
+                    animationDurationUpdate: 3000,
+                    xAxis: {},
+                    yAxis: {
+                        type: 'category',
+                        data: source1.category
+                    },
+                    grid: {
+                        right: 160
+                    },
+                    series: [{
+                        id: Math.random(),
+                        type: 'bar',
+                        data: source1.dataList[currNum],
+                        label: {
+                            show: true,
+                            position: 'right',
+                            fontSize: 16,
+                            formatter: labelFormatter,
+                            valueAnimation: true
                         }
-                    }
+                    }]
                 };
             }
 
-            option = {
+            var chart = testHelper.create(echarts, 'main1', {
+                title: [
+                    'Check **init** valueAnimation should be OK',
+                    'Swithch formatter, for each formatter **click next once**',
+                    'label text anmiation should OK. **except Country**'
+                ],
+                option: makeOption(formatterConfigs[0].formatter),
+                info: formatterConfigs[0].formatter.toString(),
+                infoKey: 'formatter',
+                buttons: [{
+                    text: 'next',
+                    onclick: function () {
+                        currNum++;
+                        chart.setOption({
+                            series: {
+                                data: source1.dataList[currNum]
+                            }
+                        });
+                    }
+                }].concat(formatterSwitchButtons)
+            });
+        });
+        </script>
+
+
+
+
+
+
+
+
+
+        <script>
+        require(['echarts'/*, 'map/js/china' */], function (echarts) {
+            var valueA = 100;
+            var valueB = 200;
+
+            var option = {
                 animationDuration: 5000,
                 animationDurationUpdate: 5000,
-                dataset: [{
-                    source: makeSource1(),
-                },
-                    makeTransformDataset()
-                ],
+                animationEasing: 'linear',
+                animationEasingUpdate: 'linear',
                 xAxis: {},
-                yAxis: { type: 'category' },
+                yAxis: {
+                    type: 'category',
+                    data: ['A', 'B']
+                },
                 grid: {
                     right: 160
                 },
                 series: [{
                     type: 'bar',
-                    datasetId: 'singleA',
-                    encode: {
-                        x: 'Int',
-                        y: 'Country'
-                    },
-                    label: {
-                        show: true,
-                        position: 'right',
-                        fontSize: 16,
-                        formatter: '(StrFmt1) {@Country} {@Int} 元',
-                        valueAnimation: true
-                    }
-                }, {
-                    type: 'bar',
-                    datasetId: 'singleA',
-                    encode: {
-                        x: 'Int',
-                        y: 'Country'
-                    },
+                    data: [valueA, valueB],
                     label: {
                         show: true,
                         position: 'right',
                         fontSize: 16,
-                        formatter: '(StrFmt2) {@[1]} {@[0]} 元',
+                        formatter: '{c} ton',
                         valueAnimation: true
                     }
                 }]
             };
 
-            var chart = testHelper.create(echarts, 'main1', {
+            function updateChart() {
+                chart.setOption({
+                    series: [{
+                        data: [valueA, valueB]
+                    }]
+                });
+            }
+
+            var chart = testHelper.create(echarts, 'main2', {
                 title: [
-                    'Check init and **click next once**',
-                    'label text anmiation should OK. **except Country**',
-                    'label should display like : "France 910 元"',
+                    'Check A++ **before value animation finished**.',
+                    'B should keep on label animation, rather than jump to the final label.',
+                    'B should finally reach at 200. A should finally reach at 600'
                 ],
                 option: option,
                 buttons: [{
-                    text: 'next', onclick: function () {
-                        currNum++;
-                        chart.setOption({
-                            dataset: makeTransformDataset()
-                        });
+                    text: 'A++',
+                    onclick: function () {
+                        valueA += 500;
+                        updateChart();
+                    }
+                }, {
+                    text: 'B++',
+                    onclick: function () {
+                        valueB += 500;
+                        updateChart();
                     }
-                }],
+                }]
             });
+
         });
         </script>
 
@@ -256,12 +373,6 @@ under the License.
 
 
 
-
-
-
-
-
-
     </body>
 </html>
 
diff --git a/test/lib/testHelper.js b/test/lib/testHelper.js
index 88dc879..be1d491 100644
--- a/test/lib/testHelper.js
+++ b/test/lib/testHelper.js
@@ -144,11 +144,19 @@
         }
 
         if (opt.info) {
-            infoContainer.innerHTML = createObjectHTML(opt.info, opt.infoKey || 'option');
+            updateInfo(opt.info, opt.infoKey);
+        }
+
+        function updateInfo(info, infoKey) {
+            infoContainer.innerHTML = createObjectHTML(info, infoKey || 'option');
         }
 
         initRecordCanvas(opt, chart, recordCanvasContainer);
 
+        chart.__testHelper = {
+            updateInfo: updateInfo
+        };
+
         return chart;
     };
 
@@ -932,9 +940,15 @@
     }
 
     function createObjectHTML(obj, key) {
+        var html = isObject(obj)
+            ? testHelper.encodeHTML(printObject(obj, key))
+            : obj
+            ? obj.toString()
+            : '';
+
         return [
             '<pre class="test-print-object">',
-            testHelper.encodeHTML(printObject(obj, key)),
+            html,
             '</pre>'
         ].join('');
     }
@@ -977,6 +991,13 @@
         return params ? params.split('&') : [];
     }
 
+    function isObject(value) {
+        // Avoid a V8 JIT bug in Chrome 19-20.
+        // See https://code.google.com/p/v8/issues/detail?id=2291 for more details.
+        const type = typeof value;
+        return type === 'function' || (!!value && type === 'object');
+    }
+
     context.testHelper = testHelper;
 
 })(window);
\ No newline at end of file
diff --git a/test/line-endLabel.html b/test/line-endLabel.html
index b5826cb..3fcbd04 100644
--- a/test/line-endLabel.html
+++ b/test/line-endLabel.html
@@ -36,7 +36,90 @@ under the License.
                 height: 1000px;
                 margin-bottom: 30px;
             }
+            #formatterSwitchButtons {
+                margin: 10px;
+                padding: 10px;
+            }
+            #currentFormatter {
+                margin: 10px;
+                padding: 10px;
+                border: 1px solid #aaa;
+            }
         </style>
+
+        <div id="formatterSwitchButtons">
+        </div>
+        <div>
+            Current formatter:
+            <pre id="currentFormatter"></pre>
+        </div>
+
+        <script>
+            var _endLabelFormatter;
+
+            // Init formatter switch buttons.
+            (function () {
+
+                var formatterConfigs = [
+                    {
+                        text: 'formatter string {c}',
+                        formatter: '$ {c}'
+                    },
+                    {
+                        text: 'formatter string {@[dimIndex]}',
+                        formatter: '$ {@[1]}'
+                    },
+                    {
+                        text: 'formatter callback',
+                        formatter: function (param) {
+                            return '$ ' + param.value;
+                        }
+                    }
+                ];
+                var END_LABEL_FORMATTER = '__EC_TEST_line-endLabel.html_FOMRATTER___';
+
+                function setLocalStorage(formatterKey) {
+                    window.localStorage.setItem(END_LABEL_FORMATTER, formatterKey);
+                }
+                function getLocalStorage() {
+                    return window.localStorage.getItem(END_LABEL_FORMATTER);
+                }
+
+                var currFormatterKey = getLocalStorage();
+                var fmtBtnBox = document.getElementById('formatterSwitchButtons');
+                for (var i = 0; i < formatterConfigs.length; i++) {
+                    var config = formatterConfigs[i];
+
+                    if (_endLabelFormatter == null
+                        && (
+                            currFormatterKey == null
+                            || currFormatterKey === config.text
+                        )
+                    ) {
+                        _endLabelFormatter = config.formatter;
+                    }
+
+                    var btn = document.createElement('button');
+                    btn.innerHTML = config.text;
+                    btn.onclick = (function (cfg) {
+                        return function () {
+                            setLocalStorage(cfg.text);
+                            location.reload();
+                        };
+                    })(config);
+                    fmtBtnBox.appendChild(btn);
+                }
+
+                if (!_endLabelFormatter) {
+                    throw new Error();
+                }
+                var formatterDisplayBox = document.getElementById('currentFormatter');
+                formatterDisplayBox.innerHTML = _endLabelFormatter.toString();
+            })();
+
+        </script>
+
+
         <div id="main0"></div>
         <div id="main1"></div>
         <script>
@@ -200,9 +283,7 @@ under the License.
                                         },
                                         endLabel: {
                                             show: true,
-                                            formatter: function (param) {
-                                                return '$' + param.value;
-                                            },
+                                            formatter: _endLabelFormatter,
                                             fontSize: 14
                                         },
                                         emphasis: {
diff --git a/test/runTest/actions/__meta__.json b/test/runTest/actions/__meta__.json
index 663ac84..f6eb460 100644
--- a/test/runTest/actions/__meta__.json
+++ b/test/runTest/actions/__meta__.json
@@ -91,6 +91,7 @@
   "hoverFocus2": 2,
   "hoverStyle": 14,
   "hoverStyle2": 1,
+  "label-animation": 3,
   "label-layout": 1,
   "label-position": 1,
   "largeLine-tooltip": 1,
@@ -100,6 +101,7 @@
   "line-animation": 1,
   "line-boldWhenHover": 1,
   "line-crash": 1,
+  "line-endLabel": 1,
   "map": 3,
   "map-contour": 2,
   "map-default": 1,
diff --git a/test/runTest/actions/label-animation.json b/test/runTest/actions/label-animation.json
new file mode 100644
index 0000000..045bf8a
--- /dev/null
+++ b/test/runTest/actions/label-animation.json
@@ -0,0 +1 @@
+[{"name":"Action 1","ops":[{"type":"mousemove","time":476,"x":107,"y":131},{"type":"mousemove","time":676,"x":107,"y":118},{"type":"mousedown","time":820,"x":108,"y":115},{"type":"mousemove","time":885,"x":108,"y":115},{"type":"mouseup","time":952,"x":108,"y":115},{"time":953,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":3025,"x":105,"y":115},{"type":"mousemove","time":3225,"x":31,"y":128},{"type":"mousemove","time":3425,"x":20,"y":126},{"type":"mousemove","time":3633, [...]
\ No newline at end of file
diff --git a/test/runTest/actions/line-endLabel.json b/test/runTest/actions/line-endLabel.json
new file mode 100644
index 0000000..712dc3e
--- /dev/null
+++ b/test/runTest/actions/line-endLabel.json
@@ -0,0 +1 @@
+[{"name":"Action 1","ops":[{"type":"mousemove","time":732,"x":86,"y":167},{"type":"mousemove","time":932,"x":85,"y":126},{"type":"mousemove","time":1132,"x":85,"y":63},{"type":"mousemove","time":1339,"x":94,"y":30},{"type":"mousemove","time":1556,"x":95,"y":28},{"type":"mousedown","time":1764,"x":95,"y":28},{"type":"mouseup","time":1928,"x":95,"y":28},{"time":1929,"delay":400,"type":"screenshot-auto"},{"type":"mousemove","time":4451,"x":96,"y":28},{"type":"mousemove","time":4667,"x":135, [...]
\ 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