Skip to content

Commit 4a51ea6

Browse files
authored
Merge pull request #4680 from g1f9/refactor/wordcloud-shape-tap-member-callback
refactor: keep the word cloud shape tap as a stable member callback
2 parents 0461971 + 8ab5827 commit 4a51ea6

3 files changed

Lines changed: 35 additions & 35 deletions

File tree

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"changes": [
3+
{
4+
"packageName": "@visactor/vchart",
5+
"comment": "refactor: keep the word cloud shape afterRender tap as a stable member callback",
6+
"type": "none"
7+
}
8+
],
9+
"packageName": "@visactor/vchart",
10+
"email": "chendaxin.tk@bytedance.com"
11+
}

packages/vchart/__tests__/unit/series/word-cloud-shape-release.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { VChart } from '../../../src/vchart-all';
22
import { createDiv, removeDom } from '../../util/dom';
33

4-
type Tap = { name: string; fn: () => void };
4+
type Tap = { name: string; fn: (stage: unknown) => void };
55

66
const SVG_MASK =
77
'<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100"><circle cx="50" cy="50" r="50"/></svg>';
@@ -67,7 +67,7 @@ describe('word cloud shape afterRender tap', () => {
6767

6868
expect(getWordCloudTaps().length).toBe(0);
6969
// series 已经 release,_option 为空,这个 tap 即使被别处留住也不能再抛错
70-
expect(() => tap.fn()).not.toThrow();
70+
expect(() => tap.fn(vchart.getStage())).not.toThrow();
7171
});
7272

7373
it('should not be registered twice when the layout finishes more than once', () => {

packages/vchart/src/series/word-cloud/base.ts

Lines changed: 22 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ import { wordCloud } from '../../theme/builtin/common/series/word-cloud';
4646
import { LayoutZIndex } from '../../constant/layout';
4747
import { ChartEvent } from '../../core';
4848

49+
const AFTER_WORDCLOUD_SHAPE_DRAW_TAP = 'afterWordcloudShapeDraw';
50+
4951
export type IBaseWordCloudSeriesSpec = Omit<IWordCloudSeriesSpec, 'type'> & { type: string };
5052

5153
export class BaseWordCloudSeries<T extends IBaseWordCloudSeriesSpec = IBaseWordCloudSeriesSpec> extends BaseSeries<T> {
@@ -79,8 +81,18 @@ export class BaseWordCloudSeries<T extends IBaseWordCloudSeriesSpec = IBaseWordC
7981

8082
protected _maskShape?: string | WordCloudShapeType | TextShapeMask | GeometricMaskShape;
8183
protected _isWordCloudShape: boolean = false;
82-
/** 形状词云布局完成后挂到 stage 上的 afterRender tap,随 series 一起摘掉,避免 release 后再被触发 */
83-
protected _afterWordcloudShapeDrawTap?: { stage: IStage; fn: () => void };
84+
/** 形状词云布局完成后挂到 stage 上的 afterRender tap;引用稳定,便于 unTap 精确摘掉自己 */
85+
protected _afterWordcloudShapeDraw = (stage: IStage) => {
86+
stage.hooks.afterRender.unTap(AFTER_WORDCLOUD_SHAPE_DRAW_TAP, this._afterWordcloudShapeDraw);
87+
88+
// 布局是异步的,跑完之前 series 可能已经被 release,此时 _option 已置空
89+
const globalInstance = this._option?.globalInstance;
90+
if (!globalInstance) {
91+
return;
92+
}
93+
this._option.dispatchEvent?.(ChartEvent.afterWordcloudShapeDraw, { instance: globalInstance });
94+
globalInstance.getChart().getOption().performanceHook?.afterWordcloudShapeDraw?.(globalInstance);
95+
};
8496

8597
protected _wordCloudConfig?: WordCloudConfigType;
8698
protected _wordCloudShapeConfig?: WordCloudShapeConfigType;
@@ -397,29 +409,13 @@ export class BaseWordCloudSeries<T extends IBaseWordCloudSeriesSpec = IBaseWordC
397409
: this._maskShape,
398410
onUpdateMaskCanvas: this.handleMaskCanvasUpdate,
399411
onLayoutFinished: () => {
400-
// 布局是异步的,跑完时 series 可能已经被 release,此时 _option 已置空
401412
const stage = this._option?.globalInstance?.getStage();
402413
if (!stage) {
403414
return;
404415
}
405-
this._removeAfterWordcloudShapeDrawTap();
406-
407-
const afterWordcloudShapeDraw = () => {
408-
// 需要等到真正渲染完成
409-
this._removeAfterWordcloudShapeDrawTap();
410-
411-
const globalInstance = this._option?.globalInstance;
412-
if (!globalInstance) {
413-
return;
414-
}
415-
this._option.dispatchEvent?.(ChartEvent.afterWordcloudShapeDraw, {
416-
instance: globalInstance
417-
});
418-
globalInstance.getChart().getOption().performanceHook?.afterWordcloudShapeDraw?.(globalInstance);
419-
};
420-
421-
this._afterWordcloudShapeDrawTap = { stage, fn: afterWordcloudShapeDraw };
422-
stage.hooks.afterRender.tap('afterWordcloudShapeDraw', afterWordcloudShapeDraw);
416+
// 同一个 series 再次布局时,先摘掉上一轮还没被触发的那个
417+
stage.hooks.afterRender.unTap(AFTER_WORDCLOUD_SHAPE_DRAW_TAP, this._afterWordcloudShapeDraw);
418+
stage.hooks.afterRender.tap(AFTER_WORDCLOUD_SHAPE_DRAW_TAP, this._afterWordcloudShapeDraw);
423419
},
424420
dataIndexKey: DEFAULT_DATA_KEY,
425421
text: wordSpec.formatMethod
@@ -559,19 +555,12 @@ export class BaseWordCloudSeries<T extends IBaseWordCloudSeriesSpec = IBaseWordC
559555
this._wordMeasureCache?.clear();
560556
}
561557

562-
protected _removeAfterWordcloudShapeDrawTap() {
563-
const tap = this._afterWordcloudShapeDrawTap;
564-
if (!tap) {
565-
return;
566-
}
567-
this._afterWordcloudShapeDrawTap = undefined;
568-
569-
// 带上 fn:同一个 stage 上可能有多个词云系列,只按名字清会误删别人的回调
570-
tap.stage?.hooks?.afterRender?.unTap('afterWordcloudShapeDraw', tap.fn);
571-
}
572-
573558
release() {
574-
this._removeAfterWordcloudShapeDrawTap();
559+
// super.release() 会把 _option 置空,所以先摘钩子。带上 fn:同一个 stage 上可能有多个
560+
// 词云系列,只按名字清会误删别人的回调
561+
this._option?.globalInstance
562+
?.getStage()
563+
?.hooks.afterRender.unTap(AFTER_WORDCLOUD_SHAPE_DRAW_TAP, this._afterWordcloudShapeDraw);
575564
super.release();
576565
this._wordMeasureCache?.clear();
577566
this._wordMeasureCache = undefined;

0 commit comments

Comments
 (0)