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:52 UTC
[echarts] 01/01: fix(dataZoom): not re-render shadow if not data not changed.
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