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 2021/11/16 04:19:51 UTC

[echarts] branch throttle-inside-zoom created (now 94de106)

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

shenyi pushed a change to branch throttle-inside-zoom
in repository https://gitbox.apache.org/repos/asf/echarts.git.


      at 94de106  fix(dataZoom): not re-render shadow if not data not changed.

This branch includes the following new commits:

     new 94de106  fix(dataZoom): not re-render shadow if not data not changed.

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(dataZoom): not re-render shadow if not data not changed.

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

shenyi pushed a commit to branch throttle-inside-zoom
in repository https://gitbox.apache.org/repos/asf/echarts.git

commit 94de10642da2bd5fe6b24f0edea40fcdd19834fa
Author: pissang <bm...@gmail.com>
AuthorDate: Tue Nov 16 12:18:39 2021 +0800

    fix(dataZoom): not re-render shadow if not data not changed.
    
    Tighter throttle code
---
 src/component/axisPointer/BaseAxisPointer.ts | 54 +++++++++++-----------
 src/component/brush/visualEncoding.ts        | 29 +++++-------
 src/component/dataZoom/DataZoomModel.ts      |  5 +-
 src/component/dataZoom/SliderZoomView.ts     | 56 +++++++++++++----------
 src/component/dataZoom/roams.ts              | 32 ++++++-------
 src/component/parallel/ParallelView.ts       | 30 +++++++-----
 src/util/throttle.ts                         | 68 ----------------------------
 7 files changed, 106 insertions(+), 168 deletions(-)

diff --git a/src/component/axisPointer/BaseAxisPointer.ts b/src/component/axisPointer/BaseAxisPointer.ts
index 8b5ada4..64ae646 100644
--- a/src/component/axisPointer/BaseAxisPointer.ts
+++ b/src/component/axisPointer/BaseAxisPointer.ts
@@ -123,6 +123,11 @@ class BaseAxisPointer implements AxisPointer {
     protected animationThreshold = 15;
 
     /**
+     * Throttled method.
+     */
+     _doDispatchAxisPointer: (() => void) & throttleUtil.ThrottleController;
+
+    /**
      * @implement
      */
     render(axisModel: AxisBaseModel, axisPointerModel: AxisPointerModel, api: ExtensionAPI, forceRender?: boolean) {
@@ -387,12 +392,25 @@ class BaseAxisPointer implements AxisPointer {
         handle.scaleX = handleSize[0] / 2;
         handle.scaleY = handleSize[1] / 2;
 
-        throttleUtil.createOrUpdate(
-            this,
-            '_doDispatchAxisPointer',
-            handleModel.get('throttle') || 0,
-            'fixRate'
-        );
+        this._doDispatchAxisPointer = throttleUtil.throttle(() => {
+            const handle = this._handle;
+            if (!handle) {
+                return;
+            }
+
+            const payloadInfo = this._payloadInfo;
+            const axisModel = this._axisModel;
+            this._api.dispatchAction({
+                type: 'updateAxisPointer',
+                x: payloadInfo.cursorPoint[0],
+                y: payloadInfo.cursorPoint[1],
+                tooltipOption: payloadInfo.tooltipOption,
+                axesInfo: [{
+                    axisDim: axisModel.axis.dim,
+                    axisIndex: axisModel.componentIndex
+                }]
+            });
+        }, handleModel.get('throttle') || 0);
 
         this._moveHandleToValue(value, isInit);
     }
@@ -432,28 +450,6 @@ class BaseAxisPointer implements AxisPointer {
         this._doDispatchAxisPointer();
     }
 
-    /**
-     * Throttled method.
-     */
-    _doDispatchAxisPointer() {
-        const handle = this._handle;
-        if (!handle) {
-            return;
-        }
-
-        const payloadInfo = this._payloadInfo;
-        const axisModel = this._axisModel;
-        this._api.dispatchAction({
-            type: 'updateAxisPointer',
-            x: payloadInfo.cursorPoint[0],
-            y: payloadInfo.cursorPoint[1],
-            tooltipOption: payloadInfo.tooltipOption,
-            axesInfo: [{
-                axisDim: axisModel.axis.dim,
-                axisIndex: axisModel.componentIndex
-            }]
-        });
-    }
 
     private _onHandleDragEnd() {
         this._dragging = false;
@@ -493,6 +489,8 @@ class BaseAxisPointer implements AxisPointer {
             this._handle = null;
             this._payloadInfo = null;
         }
+
+        this._doDispatchAxisPointer && this._doDispatchAxisPointer.clear();
     }
 
     /**
diff --git a/src/component/brush/visualEncoding.ts b/src/component/brush/visualEncoding.ts
index 6a221eb..0517a28 100644
--- a/src/component/brush/visualEncoding.ts
+++ b/src/component/brush/visualEncoding.ts
@@ -32,17 +32,16 @@ import SeriesModel from '../../model/Series';
 import ParallelSeriesModel from '../../chart/parallel/ParallelSeries';
 import { ZRenderType } from 'zrender/src/zrender';
 import { BrushType, BrushDimensionMinMax } from '../helper/BrushController';
+import { makeInner } from '../../util/model';
 
 type BrushVisualState = 'inBrush' | 'outOfBrush';
 
 const STATE_LIST = ['inBrush', 'outOfBrush'] as const;
-const DISPATCH_METHOD = '__ecBrushSelect' as const;
-const DISPATCH_FLAG = '__ecInBrushSelectEvent' as const;
 
-interface BrushGlobalDispatcher extends ZRenderType {
-    [DISPATCH_FLAG]: boolean;
-    [DISPATCH_METHOD]: typeof doDispatch;
-}
+const getBrushSelectDispatcher = makeInner<{
+    brushSelect: typeof doDispatch
+    inBrush: boolean
+}, ZRenderType>();
 
 interface BrushSelectedItem {
     brushId: string;
@@ -254,29 +253,25 @@ function dispatchAction(
         return;
     }
 
-    const zr = api.getZr() as BrushGlobalDispatcher;
-    if (zr[DISPATCH_FLAG]) {
+    const dispatcher = getBrushSelectDispatcher(api.getZr());
+    if (dispatcher.inBrush) {
         return;
     }
 
-    if (!zr[DISPATCH_METHOD]) {
-        zr[DISPATCH_METHOD] = doDispatch;
-    }
-
-    const fn = throttleUtil.createOrUpdate(zr, DISPATCH_METHOD, throttleDelay, throttleType);
+    dispatcher.brushSelect = throttleUtil.throttle(doDispatch, throttleDelay, throttleType === 'debounce');
 
-    fn(api, brushSelected);
+    dispatcher.brushSelect(api, brushSelected);
 }
 
 function doDispatch(api: ExtensionAPI, brushSelected: BrushSelectedItem[]): void {
     if (!api.isDisposed()) {
-        const zr = api.getZr() as BrushGlobalDispatcher;
-        zr[DISPATCH_FLAG] = true;
+        const dispatcher = getBrushSelectDispatcher(api.getZr());
+        dispatcher.inBrush = true;
         api.dispatchAction({
             type: 'brushSelect',
             batch: brushSelected
         });
-        zr[DISPATCH_FLAG] = false;
+        dispatcher.inBrush = false;
     }
 }
 
diff --git a/src/component/dataZoom/DataZoomModel.ts b/src/component/dataZoom/DataZoomModel.ts
index 6ed6ccd..086c3d9 100644
--- a/src/component/dataZoom/DataZoomModel.ts
+++ b/src/component/dataZoom/DataZoomModel.ts
@@ -391,10 +391,7 @@ class DataZoomModel<Opts extends DataZoomOption = DataZoomOption> extends Compon
             this._autoThrottle = false;
         }
         if (this._autoThrottle) {
-            const globalOption = this.ecModel.option;
-            this.option.throttle = (
-                globalOption.animation && globalOption.animationDurationUpdate > 0
-            ) ? 100 : 20;
+            this.option.throttle = this.ecModel.isAnimationEnabled() ? 100 : 20;
         }
     }
 
diff --git a/src/component/dataZoom/SliderZoomView.ts b/src/component/dataZoom/SliderZoomView.ts
index b677224..0bcce48 100644
--- a/src/component/dataZoom/SliderZoomView.ts
+++ b/src/component/dataZoom/SliderZoomView.ts
@@ -42,6 +42,7 @@ import { deprecateLog } from '../../util/log';
 import { PointLike } from 'zrender/src/core/Point';
 import Displayable from 'zrender/src/graphic/Displayable';
 import {createTextStyle} from '../../label/labelStyle';
+import SeriesData from '../../data/SeriesData';
 
 const Rect = graphic.Rect;
 
@@ -124,6 +125,16 @@ class SliderZoomView extends DataZoomView {
         otherAxisInverse: boolean
     };
 
+    // Cached raw data. Avoid rendering data shadow multiple times.
+    private _shadowData: SeriesData;
+    private _shadowDim: string;
+
+
+    /**
+     * This action will be throttled.
+     */
+     _dispatchZoomAction: ((realtime: boolean) => void) & throttle.ThrottleController;
+
     init(ecModel: GlobalModel, api: ExtensionAPI) {
         this.api = api;
 
@@ -143,11 +154,20 @@ class SliderZoomView extends DataZoomView {
     ) {
         super.render.apply(this, arguments as any);
 
-        throttle.createOrUpdate(
-            this,
-            '_dispatchZoomAction',
-            dataZoomModel.get('throttle'),
-            'fixRate'
+        this._dispatchZoomAction = throttle.throttle(
+            (realtime: boolean) => {
+                const range = this._range;
+
+                this.api.dispatchAction({
+                    type: 'dataZoom',
+                    from: this.uid,
+                    dataZoomId: this.dataZoomModel.id,
+                    animation: realtime ? REALTIME_ANIMATION_CONFIG : null,
+                    start: range[0],
+                    end: range[1]
+                });
+            },
+            dataZoomModel.get('throttle')
         );
 
         this._orient = dataZoomModel.getOrient();
@@ -179,7 +199,7 @@ class SliderZoomView extends DataZoomView {
     }
 
     private _clear() {
-        throttle.clear(this, '_dispatchZoomAction');
+        this._dispatchZoomAction && this._dispatchZoomAction.clear();
 
         const zr = this.api.getZr();
         zr.off('mousemove', this._onBrush);
@@ -350,7 +370,6 @@ class SliderZoomView extends DataZoomView {
         const size = this._size;
         const seriesModel = info.series;
         const data = seriesModel.getRawData();
-
         const otherDim: string = seriesModel.getShadowDim
             ? seriesModel.getShadowDim() // @see candlestick
             : info.otherDim;
@@ -359,6 +378,13 @@ class SliderZoomView extends DataZoomView {
             return;
         }
 
+        // Not re-render if data doesn't change.
+        if (data === this._shadowData && otherDim === this._shadowDim) {
+            return;
+        }
+        this._shadowData = data;
+        this._shadowDim = otherDim;
+
         let otherDataExtent = data.getDataExtent(otherDim);
         // Nice extent.
         const otherOffset = (otherDataExtent[1] - otherDataExtent[0]) * 0.3;
@@ -1014,22 +1040,6 @@ class SliderZoomView extends DataZoomView {
         });
     }
 
-    /**
-     * This action will be throttled.
-     */
-    _dispatchZoomAction(realtime: boolean) {
-        const range = this._range;
-
-        this.api.dispatchAction({
-            type: 'dataZoom',
-            from: this.uid,
-            dataZoomId: this.dataZoomModel.id,
-            animation: realtime ? REALTIME_ANIMATION_CONFIG : null,
-            start: range[0],
-            end: range[1]
-        });
-    }
-
     private _findCoordRect() {
         // Find the grid coresponding to the first axis referred by dataZoom.
         let rect: RectLike;
diff --git a/src/component/dataZoom/roams.ts b/src/component/dataZoom/roams.ts
index 8624bb4..44afb27 100644
--- a/src/component/dataZoom/roams.ts
+++ b/src/component/dataZoom/roams.ts
@@ -54,7 +54,7 @@ interface CoordSysRecord {
     // coordId: string
     controller: RoamController;
     containsPoint: (e: ZRElementEvent, x: number, y: number) => boolean;
-    dispatchAction: Curry1<typeof dispatchAction, ExtensionAPI>;
+    dispatchAction: Curry1<typeof dispatchAction, ExtensionAPI> & throttleUtil.ThrottleController;
 }
 
 
@@ -112,10 +112,9 @@ function createCoordSysRecord(api: ExtensionAPI, coordSysModel: CoordinateSystem
     const coordSysRecord: CoordSysRecord = {
         model: coordSysModel,
         containsPoint: curry(containsPoint, coordSysModel),
-        dispatchAction: curry(dispatchAction, api),
         dataZoomInfoMap: null,
         controller: null
-    };
+    } as CoordSysRecord;
 
     // Must not do anything depends on coordSysRecord outside the event handler here,
     // because coordSysRecord not completed yet.
@@ -158,14 +157,16 @@ function createCoordSysRecord(api: ExtensionAPI, coordSysModel: CoordinateSystem
  * This action will be throttled.
  */
 function dispatchAction(api: ExtensionAPI, batch: DataZoomPayloadBatchItem[]) {
-    api.dispatchAction({
-        type: 'dataZoom',
-        animation: {
-            easing: 'cubicOut',
-            duration: 100
-        },
-        batch: batch
-    });
+    if (!api.isDisposed()) {
+        api.dispatchAction({
+            type: 'dataZoom',
+            animation: {
+                easing: 'cubicOut',
+                duration: 100
+            },
+            batch: batch
+        });
+    }
 }
 
 function containsPoint(
@@ -283,12 +284,9 @@ export function installDataZoomRoamProcessor(registers: EChartsExtensionInstallR
 
                 controller.setPointerChecker(coordSysRecord.containsPoint);
 
-                throttleUtil.createOrUpdate(
-                    coordSysRecord,
-                    'dispatchAction',
-                    firstDzInfo.model.get('throttle', true),
-                    'fixRate'
-                );
+                coordSysRecord.dispatchAction = throttleUtil.throttle((batch) => {
+                    dispatchAction(api, batch);
+                }, firstDzInfo.model.get('throttle', true));
             });
     });
 
diff --git a/src/component/parallel/ParallelView.ts b/src/component/parallel/ParallelView.ts
index 88f6693..bb270bb 100644
--- a/src/component/parallel/ParallelView.ts
+++ b/src/component/parallel/ParallelView.ts
@@ -25,7 +25,7 @@ import { ElementEventName } from 'zrender/src/core/types';
 import { ElementEvent } from 'zrender/src/Element';
 import { ParallelAxisExpandPayload } from '../axis/parallelAxisAction';
 import { each, bind, extend } from 'zrender/src/core/util';
-import { ThrottleController, createOrUpdate } from '../../util/throttle';
+import { ThrottleController, throttle } from '../../util/throttle';
 
 const CLICK_THRESHOLD = 5; // > 4
 
@@ -38,6 +38,14 @@ class ParallelView extends ComponentView {
     // @internal
     _mouseDownPoint: number[];
     private _handlers: Partial<Record<ElementEventName, ElementEventHandler>>;
+
+    /**
+     * @internal
+     * @param {Object} [opt] If null, cancle the last action triggering for debounce.
+     */
+    _throttledDispatchExpand: ((this: ParallelView, opt: Omit<ParallelAxisExpandPayload, 'type'>) => void)
+        & ThrottleController;
+
     render(parallelModel: ParallelModel, ecModel: GlobalModel, api: ExtensionAPI): void {
         this._model = parallelModel;
         this._api = api;
@@ -47,21 +55,22 @@ class ParallelView extends ComponentView {
                 api.getZr().on(eventName, this._handlers[eventName] = bind(handler, this) as ElementEventHandler);
             }, this);
         }
-        createOrUpdate(this, '_throttledDispatchExpand', parallelModel.get('axisExpandRate'), 'fixRate');
+
+        this._throttledDispatchExpand = throttle(
+            (opt: Omit<ParallelAxisExpandPayload, 'type'>) => {
+                this._dispatchExpand(opt);
+            },
+            parallelModel.get('axisExpandRate')
+        );
     }
     dispose(ecModel: GlobalModel, api: ExtensionAPI): void {
         each(this._handlers, function (handler: ElementEventHandler, eventName) {
             api.getZr().off(eventName, handler);
         });
         this._handlers = null;
+        this._throttledDispatchExpand && this._throttledDispatchExpand.clear();
     }
-    /**
-     * @internal
-     * @param {Object} [opt] If null, cancle the last action triggering for debounce.
-     */
-    _throttledDispatchExpand(this: ParallelView, opt: Omit<ParallelAxisExpandPayload, 'type'>): void {
-        this._dispatchExpand(opt);
-    }
+
     /**
      * @internal
      */
@@ -101,8 +110,7 @@ const handlers: Partial<Record<ElementEventName, ElementEventHandler>> = {
         const result = model.coordinateSystem.getSlidedAxisExpandWindow([e.offsetX, e.offsetY]);
         const behavior = result.behavior;
         behavior === 'jump'
-            && (this._throttledDispatchExpand as ParallelView['_throttledDispatchExpand'] & ThrottleController)
-                .debounceNextCall(model.get('axisExpandDebounce'));
+            && this._throttledDispatchExpand.debounceNextCall(model.get('axisExpandDebounce'));
         this._throttledDispatchExpand(behavior === 'none'
             ? null // Cancle the last trigger, in case that mouse slide out of the area quickly.
             : {
diff --git a/src/util/throttle.ts b/src/util/throttle.ts
index 6581773..04ac8e4 100755
--- a/src/util/throttle.ts
+++ b/src/util/throttle.ts
@@ -17,11 +17,6 @@
 * under the License.
 */
 
-
-const ORIGIN_METHOD = '\0__throttleOriginMethod' as const;
-const RATE = '\0__throttleRate' as const;
-const THROTTLE_TYPE = '\0__throttleType' as const;
-
 type ThrottleFunction = (this: unknown, ...args: unknown[]) => void;
 export type ThrottleType = 'fixRate' | 'debounce';
 
@@ -116,66 +111,3 @@ export function throttle<T extends ThrottleFunction>(
 
     return cb;
 }
-
-/**
- * Create throttle method or update throttle rate.
- *
- * @example
- * ComponentView.prototype.render = function () {
- *     ...
- *     throttle.createOrUpdate(
- *         this,
- *         '_dispatchAction',
- *         this.model.get('throttle'),
- *         'fixRate'
- *     );
- * };
- * ComponentView.prototype.remove = function () {
- *     throttle.clear(this, '_dispatchAction');
- * };
- * ComponentView.prototype.dispose = function () {
- *     throttle.clear(this, '_dispatchAction');
- * };
- *
- */
-export function createOrUpdate<T, S extends keyof T, P = T[S]>(
-    obj: T,
-    fnAttr: S,
-    rate: number,
-    throttleType: ThrottleType
-): P extends ThrottleFunction ? P & ThrottleController : never {
-    let fn = obj[fnAttr];
-
-    if (!fn) {
-        return;
-    }
-
-    const originFn = (fn as any)[ORIGIN_METHOD] || fn;
-    const lastThrottleType = (fn as any)[THROTTLE_TYPE];
-    const lastRate = (fn as any)[RATE];
-
-    if (lastRate !== rate || lastThrottleType !== throttleType) {
-        if (rate == null || !throttleType) {
-            return (obj[fnAttr] = originFn);
-        }
-
-        fn = obj[fnAttr] = throttle(
-            originFn, rate, throttleType === 'debounce'
-        );
-        (fn as any)[ORIGIN_METHOD] = originFn;
-        (fn as any)[THROTTLE_TYPE] = throttleType;
-        (fn as any)[RATE] = rate;
-    }
-
-    return fn as ReturnType<typeof createOrUpdate>;
-}
-
-/**
- * Clear throttle. Example see throttle.createOrUpdate.
- */
-export function clear<T, S extends keyof T>(obj: T, fnAttr: S): void {
-    const fn = obj[fnAttr];
-    if (fn && (fn as any)[ORIGIN_METHOD]) {
-        obj[fnAttr] = (fn as any)[ORIGIN_METHOD];
-    }
-}

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