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/04/29 19:54:01 UTC

[incubator-echarts] 01/02: fix: (1) revert increamental render broken brought by a96d97191b28500d2a3dc4f44e53221d54fbe218 (2) add stream test tools.

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

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

commit 0802ef0a8ba2f7944fc1f1eca843bad3ecf328ca
Author: 100pah <su...@gmail.com>
AuthorDate: Wed Apr 29 23:26:04 2020 +0800

    fix:
    (1) revert increamental render broken brought by a96d97191b28500d2a3dc4f44e53221d54fbe218
    (2) add stream test tools.
---
 src/echarts.ts          |   4 +-
 test/-cases.js          |   1 +
 test/lib/reset.css      |  14 ++++
 test/lib/testHelper.js  | 219 +++++++++++++++++++++++++++++++++++++++---------
 test/stream-basic1.html | 163 +++++++++++++++++++++++++++++++++++
 5 files changed, 360 insertions(+), 41 deletions(-)

diff --git a/src/echarts.ts b/src/echarts.ts
index d60e366..bb85b18 100644
--- a/src/echarts.ts
+++ b/src/echarts.ts
@@ -1654,7 +1654,9 @@ class ECharts extends Eventful {
                 unfinished |= +renderTask.perform(scheduler.getPerformArgs(renderTask));
 
                 chartView.group.silent = !!seriesModel.get('silent');
-                chartView.group.markRedraw();
+                // Should not call markRedraw on group, because it will disable zrender
+                // increamental render (alway render from the __startIndex each frame)
+                // chartView.group.markRedraw();
 
                 updateZ(seriesModel, chartView);
 
diff --git a/test/-cases.js b/test/-cases.js
index 676b67f..9f5434f 100644
--- a/test/-cases.js
+++ b/test/-cases.js
@@ -53,6 +53,7 @@
     }, {
         name: 'stream-cases',
         whiteList: [
+            'stream-basic1.html',
             'lines-ny-appendData.html',
             'scatter-stream-large.html',
             'scatter-stream-not-large.html',
diff --git a/test/lib/reset.css b/test/lib/reset.css
index 67e7b0d..fd34ca6 100644
--- a/test/lib/reset.css
+++ b/test/lib/reset.css
@@ -122,3 +122,17 @@ td.test-data-table-key {
     width: 300px;
     height: 500px;
 }
+
+.control-frame-btn-panel {
+    position: fixed;
+    top: 10px;
+    left: 10px;
+    box-shadow: 0 0 3px #000;
+    background: green;
+    padding: 5px;
+}
+.control-frame-btn-panel .control-frame-info {
+    display: block;
+    color: #fff;
+    font-size: 10px;
+}
diff --git a/test/lib/testHelper.js b/test/lib/testHelper.js
index d6685d4..efbe103 100644
--- a/test/lib/testHelper.js
+++ b/test/lib/testHelper.js
@@ -147,44 +147,51 @@
             infoContainer.innerHTML = createObjectHTML(opt.info, opt.infoKey || 'option');
         }
 
-        if (opt.recordCanvas) {
-            recordCanvasContainer.innerHTML = ''
-                + '<button>Show Canvas Record</button>'
-                + '<button>Clear Canvas Record</button>'
-                + '<div class="content-area"><textarea></textarea><br><button>Close</button></div>';
-            var buttons = recordCanvasContainer.getElementsByTagName('button');
-            var canvasRecordButton = buttons[0];
-            var clearButton = buttons[1];
-            var closeButton = buttons[2];
-            var recordArea = recordCanvasContainer.getElementsByTagName('textarea')[0];
-            var contentAraa = recordArea.parentNode;
-            canvasRecordButton.addEventListener('click', function () {
-                var content = [];
-                eachCtx(function (zlevel, ctx) {
-                    content.push('Layer zlevel: ' + zlevel, '\n\n');
-                    if (typeof ctx.stack !== 'function') {
-                        alert('Missing: <script src="test/lib/canteen.js"></script>');
-                        return;
-                    }
-                    var stack = ctx.stack();
-                    for (var i = 0; i < stack.length; i++) {
-                        var line = stack[i];
-                        content.push(JSON.stringify(line), ',\n');
-                    }
-                });
-                contentAraa.style.display = 'block';
-                recordArea.value = content.join('');
-            });
-            clearButton.addEventListener('click', function () {
-                eachCtx(function (zlevel, ctx) {
-                    ctx.clear();
-                });
-                recordArea.value = 'Cleared.';
+        initRecordCanvas(opt, chart, recordCanvasContainer);
+
+        return chart;
+    };
+
+    function initRecordCanvas(opt, chart, recordCanvasContainer) {
+        if (!opt.recordCanvas) {
+            return;
+        }
+        recordCanvasContainer.innerHTML = ''
+            + '<button>Show Canvas Record</button>'
+            + '<button>Clear Canvas Record</button>'
+            + '<div class="content-area"><textarea></textarea><br><button>Close</button></div>';
+        var buttons = recordCanvasContainer.getElementsByTagName('button');
+        var canvasRecordButton = buttons[0];
+        var clearButton = buttons[1];
+        var closeButton = buttons[2];
+        var recordArea = recordCanvasContainer.getElementsByTagName('textarea')[0];
+        var contentAraa = recordArea.parentNode;
+        canvasRecordButton.addEventListener('click', function () {
+            var content = [];
+            eachCtx(function (zlevel, ctx) {
+                content.push('\nLayer zlevel: ' + zlevel, '\n\n');
+                if (typeof ctx.stack !== 'function') {
+                    alert('Missing: <script src="test/lib/canteen.js"></script>');
+                    return;
+                }
+                var stack = ctx.stack();
+                for (var i = 0; i < stack.length; i++) {
+                    var line = stack[i];
+                    content.push(JSON.stringify(line), ',\n');
+                }
             });
-            closeButton.addEventListener('click', function () {
-                contentAraa.style.display = 'none';
+            contentAraa.style.display = 'block';
+            recordArea.value = content.join('');
+        });
+        clearButton.addEventListener('click', function () {
+            eachCtx(function (zlevel, ctx) {
+                ctx.clear();
             });
-        }
+            recordArea.value = 'Cleared.';
+        });
+        closeButton.addEventListener('click', function () {
+            contentAraa.style.display = 'none';
+        });
 
         function eachCtx(cb) {
             var layers = chart.getZr().painter.getLayers();
@@ -197,9 +204,7 @@
                 }
             }
         }
-
-        return chart;
-    };
+    }
 
     /**
      * @param {ECharts} echarts
@@ -257,6 +262,95 @@
     };
 
 
+    var _dummyRequestAnimationFrameMounted = false;
+
+    /**
+     * Usage:
+     * ```js
+     * testHelper.controlFrame({pauseAt: 60});
+     * // Then load echarts.js (must after controlFrame called)
+     * ```
+     *
+     * @param {Object} [opt]
+     * @param {number} [opt.puaseAt] If specified `pauseAt`, auto pause at the frame.
+     * @param {Function} [opt.onFrame]
+     */
+    testHelper.controlFrame = function (opt) {
+        opt = opt || {};
+        var pauseAt = opt.pauseAt;
+        pauseAt == null && (pauseAt = 0);
+
+        var _running = true;
+        var _pendingCbList = [];
+        var _frameNumber = 0;
+        var _mounted = false;
+
+        var buttons = [{
+            text: 'run',
+            onclick: run
+        }, {
+            text: 'pause',
+            onclick: pause
+        }, {
+            text: 'next frame',
+            onclick: nextFrame
+        }];
+
+        var btnPanel = document.createElement('div');
+        btnPanel.className = 'control-frame-btn-panel'
+        var infoEl = document.createElement('div');
+        infoEl.className = 'control-frame-info';
+        btnPanel.appendChild(infoEl);
+        document.body.appendChild(btnPanel);
+        for (var i = 0; i < buttons.length; i++) {
+            var button = buttons[i];
+            var btnEl = document.createElement('button');
+            btnEl.innerHTML = button.text;
+            btnEl.addEventListener('click', button.onclick);
+            btnPanel.appendChild(btnEl);
+        }
+
+        if (_dummyRequestAnimationFrameMounted) {
+            throw new Error('Do not support `controlFrame` twice');
+        }
+        _dummyRequestAnimationFrameMounted = true;
+        var raf = window.requestAnimationFrame;
+        window.requestAnimationFrame = function (cb) {
+            _pendingCbList.push(cb);
+            if (_running && !_mounted) {
+                _mounted = true;
+                raf(nextFrame);
+            }
+        };
+
+        function run() {
+            _running = true;
+            nextFrame();
+        }
+
+        function pause() {
+            _running = false;
+        }
+
+        function nextFrame() {
+            opt.onFrame && opt.onFrame(_frameNumber);
+
+            infoEl.innerHTML = 'current frame: ' + _frameNumber;
+            if (pauseAt != null && _frameNumber === pauseAt) {
+                _running = false;
+                pauseAt = null;
+            }
+
+            _mounted = false;
+            var pending = _pendingCbList;
+            _pendingCbList = [];
+            for (var i = 0; i < pending.length; i++) {
+                pending[i]();
+            }
+            _frameNumber++;
+        }
+    }
+
     testHelper.resizable = function (chart) {
         var dom = chart.getDom();
         var width = dom.clientWidth;
@@ -505,7 +599,6 @@
      *        For example: 'z2' or ['z2', 'style.fill', 'style.stroke']
      * @param {function} [opt.filter] print a subtree only if any satisfied node exists.
      *        param: el, return: boolean
-     * @param {boolean} [opt.preventPrint]
      */
     testHelper.stringifyElements = function (chart, opt) {
         if (!chart) {
@@ -602,6 +695,52 @@
         console.log(elsStr);
     };
 
+    /**
+     * Usage:
+     * ```js
+     * // Print all elements that has `style.text`:
+     * testHelper.retrieveElements(chart, {
+     *     filter: el => el.style && el.style.text
+     * });
+     * ```
+     *
+     * @param {EChart} chart
+     * @param {Object} [opt]
+     * @param {function} [opt.filter] print a subtree only if any satisfied node exists.
+     *        param: el, return: boolean
+     * @return {Array.<Element>}
+     */
+    testHelper.retrieveElements = function (chart, opt) {
+        if (!chart) {
+            return;
+        }
+        opt = opt || {};
+        var attrNameList = opt.attr;
+        if (getType(attrNameList) !== 'array') {
+            attrNameList = attrNameList ? [attrNameList] : [];
+        }
+
+        var zr = chart.getZr();
+        var roots = zr.storage.getRoots();
+        var result = [];
+
+        retrieve(roots);
+
+        function retrieve(elList) {
+            for (var i = 0; i < elList.length; i++) {
+                var el = elList[i];
+                if (!opt.filter || opt.filter(el)) {
+                    result.push(el);
+                }
+                if (el.isGroup) {
+                    retrieve(el.childrenRef());
+                }
+            }
+        }
+
+        return result;
+    };
+
     // opt: {record: JSON, width: number, height: number}
     testHelper.reproduceCanteen = function (opt) {
         var canvas = document.createElement('canvas');
diff --git a/test/stream-basic1.html b/test/stream-basic1.html
new file mode 100644
index 0000000..bb74ee9
--- /dev/null
+++ b/test/stream-basic1.html
@@ -0,0 +1,163 @@
+<!DOCTYPE html>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied.  See the License for the
+specific language governing permissions and limitations
+under the License.
+-->
+
+
+<html>
+    <head>
+        <meta charset="utf-8">
+        <meta name="viewport" content="width=device-width, initial-scale=1" />
+        <script src="lib/esl.js"></script>
+        <script src="lib/config.js"></script>
+        <script src="lib/jquery.min.js"></script>
+        <script src="lib/facePrint.js"></script>
+        <script src="lib/testHelper.js"></script>
+        <script src="lib/canteen.js"></script>
+        <link rel="stylesheet" href="lib/reset.css" />
+    </head>
+    <body>
+        <style>
+            .record-title {
+                margin: 10px;
+                font-size: 18px;
+                font-weight: 700;
+            }
+            .record {
+                margin: 5px 20px;
+            }
+            .record-unit {
+                margin: 10px 10px;
+                font-size: 10px;
+            }
+            .record-unit .cmd-count {
+                color: red;
+                font-size: 12px;
+            }
+            .record-title .cmd-count {
+                color: red;
+            }
+        </style>
+
+
+
+        <div id="main0"></div>
+        <div class="record-title">
+            In incremental layer, each frame, <br>
+            new canvas command count (<span class="cmd-count">red number</span>) should be the same:</div>
+        <div id="record"></div>
+
+
+        <script>
+
+        window.Canteen.globals.STACK_SIZE = 100000000;
+
+        var recordContainer = document.getElementById('record');
+        var chart;
+        var layersInfoMap = {};
+
+        testHelper.controlFrame({
+            pauseAt: 120,
+            onFrame: function (frameNumber) {
+                if (chart) {
+                    var layers = chart.getZr().painter.getLayers();
+                    for (var zlevel in layers) {
+                        if (layers.hasOwnProperty(zlevel)) {
+                            printNewCmds(zlevel, layers[zlevel], frameNumber)
+                        }
+                    }
+                }
+            }
+        });
+
+        function printNewCmds(zlevel, layer, frameNumber) {
+            var layerInfo = layersInfoMap[zlevel];
+            if (!layerInfo) {
+                layerInfo = layersInfoMap[zlevel] = {
+                    lastStackLength: 0,
+                    recordDom: document.createElement('div')
+                };
+                layerInfo.recordDom.className = 'record-unit';
+                layerInfo.recordDom.innerHTML = 'layer ' + zlevel + ': <br>';
+                recordContainer.appendChild(layerInfo.recordDom);
+            }
+
+            var canvas = layer.dom;
+            var ctx = canvas.getContext('2d');
+            var stackLength = ctx.stack().length;
+            var span = document.createElement('span');
+            span.innerHTML = frameNumber + ':<span class="cmd-count">' + (stackLength - layerInfo.lastStackLength) + '</span> ';
+            layerInfo.recordDom.appendChild(span);
+            layerInfo.lastStackLength = stackLength;
+        }
+
+
+        require(['echarts'], function (echarts) {
+            var option;
+
+            var count = 5000;
+            var lineCount = 100;
+            var progressive = 50;
+            var data = [];
+            var yCurr = 5;
+            for (var i = 0; i < count; i++) {
+                var mod = i % lineCount;
+                if (mod === 0) {
+                    yCurr += 5;
+                }
+                data.push([mod, yCurr]);
+            }
+
+            option = {
+                color: ['red'],
+                grid: {top: 20, bottom: 30},
+                xAxis: {
+                    type: 'category',
+                    axisLabel: {fontSize: 9, interval: 0, rotate: 90, margin: 20},
+                    boundaryGap: false
+                },
+                yAxis: {
+                    type: 'category',
+                    axisLabel: {fontSize: 9, interval: 0},
+                    boundaryGap: false
+                },
+                progressive: progressive,
+                progressiveThreshold: 1,
+                largeThreshold: 1,
+                series: {
+                    type: 'scatter',
+                    symbolSize: 2,
+                    data: data
+                }
+            };
+
+            chart = testHelper.create(echarts, 'main0', {
+                title: [
+                    'Click **run** and check the printed records:',
+                ],
+                option: option,
+                height: 450,
+                recordCanvas: true
+            });
+        });
+        </script>
+
+
+    </body>
+</html>
+


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