You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@echarts.apache.org by wa...@apache.org on 2021/12/11 23:40:38 UTC

[echarts] branch fix-tooltip-lag created (now e546f19)

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

wangzx pushed a change to branch fix-tooltip-lag
in repository https://gitbox.apache.org/repos/asf/echarts.git.


      at e546f19  fix(tooltip): only throttle `updatePosition` function when transition is enabled, resolves #16101.

This branch includes the following new commits:

     new e546f19  fix(tooltip): only throttle `updatePosition` function when transition is enabled, resolves #16101.

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


[echarts] 01/01: fix(tooltip): only throttle `updatePosition` function when transition is enabled, resolves #16101.

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

wangzx pushed a commit to branch fix-tooltip-lag
in repository https://gitbox.apache.org/repos/asf/echarts.git

commit e546f193dc4f0c47883a6d290c5d4b3d21c25dbc
Author: plainheart <yh...@all-my-life.cn>
AuthorDate: Sun Dec 12 07:40:01 2021 +0800

    fix(tooltip): only throttle `updatePosition` function when transition is enabled, resolves #16101.
---
 src/component/tooltip/TooltipHTMLContent.ts |  1 -
 src/component/tooltip/TooltipView.ts        | 79 ++++++++++++++++-------------
 test/tooltip-lag-glitch.html                | 26 +++++++++-
 3 files changed, 67 insertions(+), 39 deletions(-)

diff --git a/src/component/tooltip/TooltipHTMLContent.ts b/src/component/tooltip/TooltipHTMLContent.ts
index b324d6a..baca229 100644
--- a/src/component/tooltip/TooltipHTMLContent.ts
+++ b/src/component/tooltip/TooltipHTMLContent.ts
@@ -18,7 +18,6 @@
 */
 
 import { isString, indexOf, each, bind, isArray, isDom } from 'zrender/src/core/util';
-import { toHex } from 'zrender/src/tool/color';
 import { normalizeEvent } from 'zrender/src/core/event';
 import { transformLocalCoord } from 'zrender/src/core/dom';
 import env from 'zrender/src/core/env';
diff --git a/src/component/tooltip/TooltipView.ts b/src/component/tooltip/TooltipView.ts
index 1523a18..a317363 100644
--- a/src/component/tooltip/TooltipView.ts
+++ b/src/component/tooltip/TooltipView.ts
@@ -16,12 +16,12 @@
 * specific language governing permissions and limitations
 * under the License.
 */
-import * as zrUtil from 'zrender/src/core/util';
+import { bind, each, clone, trim, isString, isFunction, isArray, isObject } from 'zrender/src/core/util';
 import env from 'zrender/src/core/env';
 import TooltipHTMLContent from './TooltipHTMLContent';
 import TooltipRichContent from './TooltipRichContent';
 import * as formatUtil from '../../util/format';
-import * as numberUtil from '../../util/number';
+import { parsePercent } from '../../util/number';
 import * as graphic from '../../util/graphic';
 import findPointFromSeries from '../axisPointer/findPointFromSeries';
 import * as layoutUtil from '../../util/layout';
@@ -57,11 +57,7 @@ import { DataByCoordSys, DataByAxis } from '../axisPointer/axisTrigger';
 import { normalizeTooltipFormatResult } from '../../model/mixin/dataFormat';
 import { createTooltipMarkup, buildTooltipMarkup, TooltipMarkupStyleCreator } from './tooltipMarkup';
 import { findEventDispatcher } from '../../util/event';
-import { throttle } from '../../util/throttle';
-
-const bind = zrUtil.bind;
-const each = zrUtil.each;
-const parsePercent = numberUtil.parsePercent;
+import { throttle, ThrottleController } from '../../util/throttle';
 
 const proxyRect = new graphic.Rect({
     shape: { x: -1, y: -1, width: 2, height: 2 }
@@ -168,7 +164,8 @@ class TooltipView extends ComponentView {
     private _lastDataByCoordSys: DataByCoordSys[];
     private _cbParamsList: TooltipCallbackDataParams[];
 
-    private _updatePosition: ReturnType<typeof throttle> | TooltipView['_doUpdatePosition'];
+    private _updatePosition: TooltipView['_doUpdatePosition'];
+    private _throttledUpdatePosition: TooltipView['_doUpdatePosition'] & ThrottleController;
 
     init(ecModel: GlobalModel, api: ExtensionAPI) {
         if (env.node || !api.getDom()) {
@@ -176,14 +173,19 @@ class TooltipView extends ComponentView {
         }
 
         const tooltipModel = ecModel.getComponent('tooltip') as TooltipModel;
-        const renderMode = tooltipModel.get('renderMode');
-        this._renderMode = getTooltipRenderMode(renderMode);
+        const renderMode = this._renderMode = getTooltipRenderMode(tooltipModel.get('renderMode'));
+
+        const isRichTextMode = renderMode === 'richText';
 
-        this._tooltipContent = this._renderMode === 'richText'
+        this._tooltipContent = isRichTextMode
             ? new TooltipRichContent(api)
             : new TooltipHTMLContent(api.getDom(), api, {
                 appendToBody: tooltipModel.get('appendToBody', true)
             });
+
+        if (!isRichTextMode) {
+            this._throttledUpdatePosition = throttle(bind(this._doUpdatePosition, this), 50);
+        }
     }
 
     render(
@@ -220,14 +222,17 @@ class TooltipView extends ComponentView {
 
         // PENDING
         // `mousemove` event will be triggered very frequently when the mouse moves fast,
-        // which causes that the updatePosition was also called very frequently.
-        // In Chrome with devtools open and Firefox, tooltip looks lagged and shaked around. See #14695.
-        // To avoid the frequent triggering,
-        // consider throttling it in 50ms. (the tested result may need to validate)
-        this._updatePosition =
-            this._renderMode === 'html'
-                ? throttle(bind(this._doUpdatePosition, this), 50)
-                : this._doUpdatePosition;
+        // which causes that the `updatePosition` function was also called frequently.
+        // In Chrome with devtools open and Firefox, tooltip looks laggy and shakes. See #14695 #16101
+        // To avoid frequent triggering,
+        // consider throttling it in 50ms when transition is enabled
+        this._updatePosition = (...args: any[]) => {
+            const ctx = this;
+            const updateFn = tooltipModel.get('transitionDuration')
+                ? ctx._throttledUpdatePosition
+                : ctx._doUpdatePosition;
+            return updateFn.apply(ctx, args);
+        };
     }
 
     private _initGlobalListener() {
@@ -517,7 +522,7 @@ class TooltipView extends ComponentView {
         // something. `showDelay` makes it easier to enter the content
         // but tooltip do not move immediately.
         const delay = tooltipModel.get('showDelay');
-        cb = zrUtil.bind(cb, this);
+        cb = bind(cb, this);
         clearTimeout(this._showTimout);
         delay > 0
             ? (this._showTimout = setTimeout(cb, delay) as any)
@@ -559,13 +564,13 @@ class TooltipView extends ComponentView {
                 );
                 const axisSectionMarkup = createTooltipMarkup('section', {
                     header: axisValueLabel,
-                    noHeader: !zrUtil.trim(axisValueLabel),
+                    noHeader: !trim(axisValueLabel),
                     sortBlocks: true,
                     blocks: []
                 });
                 articleMarkup.blocks.push(axisSectionMarkup);
 
-                zrUtil.each(axisItem.seriesDataIndices, function (idxItem) {
+                each(axisItem.seriesDataIndices, function (idxItem) {
                     const series = ecModel.getSeriesByIndex(idxItem.seriesIndex);
                     const dataIndex = idxItem.dataIndexInside;
                     const cbParams = series.getDataParams(dataIndex) as TooltipCallbackDataParams;
@@ -728,7 +733,7 @@ class TooltipView extends ComponentView {
         const ecData = getECData(el);
         const tooltipConfig = ecData.tooltipConfig;
         let tooltipOpt = tooltipConfig.option || {};
-        if (zrUtil.isString(tooltipOpt)) {
+        if (isString(tooltipOpt)) {
             const content = tooltipOpt;
             tooltipOpt = {
                 content: content,
@@ -766,7 +771,7 @@ class TooltipView extends ComponentView {
         this._showOrMove(subTooltipModel, function (this: TooltipView) {
             // Use formatterParams from element defined in component
             // Avoid users modify it.
-            const formatterParams = zrUtil.clone(subTooltipModel.get('formatterParams') as any || {});
+            const formatterParams = clone(subTooltipModel.get('formatterParams') as any || {});
             this._showTooltipContent(
                 subTooltipModel, defaultHtml, formatterParams,
                 asyncTicket, e.offsetX, e.offsetY, e.position, el, markupStyleCreator
@@ -814,9 +819,9 @@ class TooltipView extends ComponentView {
         const nearPointColor = nearPoint.color;
 
         if (formatter) {
-            if (zrUtil.isString(formatter)) {
+            if (isString(formatter)) {
                 const useUTC = tooltipModel.ecModel.get('useUTC');
-                const params0 = zrUtil.isArray(params) ? params[0] : params;
+                const params0 = isArray(params) ? params[0] : params;
                 const isTimeAxis = params0 && params0.axisType && params0.axisType.indexOf('time') >= 0;
                 html = formatter;
                 if (isTimeAxis) {
@@ -824,7 +829,7 @@ class TooltipView extends ComponentView {
                 }
                 html = formatUtil.formatTpl(html, params, true);
             }
-            else if (zrUtil.isFunction(formatter)) {
+            else if (isFunction(formatter)) {
                 const callback = bind(function (cbTicket: string, html: string | HTMLElement | HTMLElement[]) {
                     if (cbTicket === this._ticket) {
                         tooltipContent.setContent(html, markupStyleCreator, tooltipModel, nearPointColor, positionExpr);
@@ -857,13 +862,13 @@ class TooltipView extends ComponentView {
     ): {
         color: ZRColor;
     } {
-        if (trigger === 'axis' || zrUtil.isArray(tooltipDataParams)) {
+        if (trigger === 'axis' || isArray(tooltipDataParams)) {
             return {
                 color: borderColor || (this._renderMode === 'html' ? '#fff' : 'none')
             };
         }
 
-        if (!zrUtil.isArray(tooltipDataParams)) {
+        if (!isArray(tooltipDataParams)) {
             return {
                 color: borderColor || tooltipDataParams.color || tooltipDataParams.borderColor
             };
@@ -890,7 +895,7 @@ class TooltipView extends ComponentView {
         const rect = el && el.getBoundingRect().clone();
         el && rect.applyTransform(el.transform);
 
-        if (zrUtil.isFunction(positionExpr)) {
+        if (isFunction(positionExpr)) {
             // Callback of position can be an array or a string specify the position
             positionExpr = positionExpr([x, y], params, content.el, rect, {
                 viewSize: [viewWidth, viewHeight],
@@ -898,11 +903,11 @@ class TooltipView extends ComponentView {
             });
         }
 
-        if (zrUtil.isArray(positionExpr)) {
+        if (isArray(positionExpr)) {
             x = parsePercent(positionExpr[0], viewWidth);
             y = parsePercent(positionExpr[1], viewHeight);
         }
-        else if (zrUtil.isObject(positionExpr)) {
+        else if (isObject(positionExpr)) {
             const boxLayoutPosition = positionExpr as BoxLayoutOptionMixin;
             boxLayoutPosition.width = contentSize[0];
             boxLayoutPosition.height = contentSize[1];
@@ -917,7 +922,7 @@ class TooltipView extends ComponentView {
             vAlign = null;
         }
         // Specify tooltip position by string 'top' 'bottom' 'left' 'right' around graphic element
-        else if (zrUtil.isString(positionExpr) && el) {
+        else if (isString(positionExpr) && el) {
             const pos = calcTooltipPosition(
                 positionExpr, rect, contentSize, tooltipModel.get('borderWidth')
             );
@@ -982,7 +987,7 @@ class TooltipView extends ComponentView {
                 });
 
                 // check is cbParams data value changed
-                lastCbParamsList && zrUtil.each(lastItem.seriesDataIndices, (idxItem) => {
+                lastCbParamsList && each(lastItem.seriesDataIndices, (idxItem) => {
                     const seriesIdx = idxItem.seriesIndex;
                     const cbParams = cbParamsList[seriesIdx];
                     const lastCbParams = lastCbParamsList[seriesIdx];
@@ -1016,6 +1021,8 @@ class TooltipView extends ComponentView {
         if (env.node || !api.getDom()) {
             return;
         }
+        const throttledUpdatePosition = this._throttledUpdatePosition;
+        throttledUpdatePosition && throttledUpdatePosition.clear();
         this._tooltipContent.dispose();
         globalListener.unregister('itemTooltip', api);
     }
@@ -1057,7 +1064,7 @@ function buildTooltipModel(
             //  value: 10,
             //  tooltip: 'Something you need to know'
             // }
-            if (zrUtil.isString(tooltipOpt)) {
+            if (isString(tooltipOpt)) {
                 tooltipOpt = {
                     formatter: tooltipOpt
                 };
@@ -1072,7 +1079,7 @@ function buildTooltipModel(
 }
 
 function makeDispatchAction(payload: ShowTipPayload | HideTipPayload, api: ExtensionAPI) {
-    return payload.dispatchAction || zrUtil.bind(api.dispatchAction, api);
+    return payload.dispatchAction || bind(api.dispatchAction, api);
 }
 
 function refixTooltipPosition(
diff --git a/test/tooltip-lag-glitch.html b/test/tooltip-lag-glitch.html
index d5cf6a0..a125785 100644
--- a/test/tooltip-lag-glitch.html
+++ b/test/tooltip-lag-glitch.html
@@ -40,6 +40,7 @@ under the License.
 
         <div id="main0"></div>
         <div id="main1"></div>
+        <div id="main2"></div>
 
 
         <script>
@@ -97,7 +98,7 @@ under the License.
 
                 var chart1 = testHelper.create(echarts, 'main0', {
                     title: [
-                        'Tooltip shouldn\'t shake or lag',
+                        'Tooltip shouldn\'t shake or be laggy',
                         '1) Chrome with the devtools open',
                         '2) Firefox'
                     ],
@@ -106,13 +107,34 @@ under the License.
 
                 var chart2 = testHelper.create(echarts, 'main1', {
                     title: [
-                        'Tooltip shouldn\'t shake or lag',
+                        'Tooltip shouldn\'t shake or be laggy',
                         '1) Chrome with the devtools open',
                         '2) Firefox'
                     ],
                     option: option
                 });
 
+                var chart3 = testHelper.create(echarts, 'main2', {
+                    title: [
+                        'Tooltip shouldn\'t be laggy when transition is disabled',
+                        'https://github.com/apache/echarts/issues/16101'
+                    ],
+                    option: option,
+                    buttons: [{
+                        text: 'Disable transition',
+                        onclick: function () {
+                            var enabled = chart3._transitionEnabled;
+                            chart3.setOption({
+                                tooltip: {
+                                    transitionDuration: enabled && .4
+                                }
+                            });
+                            chart3._transitionEnabled = !enabled;
+                            this.innerText = (enabled ? 'Disable' : 'Enable') + ' transition';
+                        }
+                    }]
+                });
+
                 echarts.connect([chart1, chart2]);
             });
 

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