@tmagic/stage 1.2.0-beta.9 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +62 -1
  2. package/dist/{tmagic-stage.mjs → tmagic-stage.js} +1395 -1062
  3. package/dist/tmagic-stage.js.map +1 -0
  4. package/dist/{tmagic-stage.umd.js → tmagic-stage.umd.cjs} +1393 -1060
  5. package/dist/tmagic-stage.umd.cjs.map +1 -0
  6. package/package.json +9 -8
  7. package/src/ActionManager.ts +535 -0
  8. package/src/DragResizeHelper.ts +338 -0
  9. package/src/MoveableOptionsManager.ts +249 -0
  10. package/src/MoveableSelectParentAble.ts +3 -5
  11. package/src/Rule.ts +4 -4
  12. package/src/StageCore.ts +203 -275
  13. package/src/StageDragResize.ts +86 -348
  14. package/src/StageHighlight.ts +17 -16
  15. package/src/StageMask.ts +19 -102
  16. package/src/StageMultiDragResize.ts +97 -198
  17. package/src/StageRender.ts +85 -10
  18. package/src/TargetShadow.ts +120 -0
  19. package/src/const.ts +1 -1
  20. package/src/types.ts +99 -19
  21. package/src/util.ts +18 -11
  22. package/types/ActionManager.d.ts +141 -0
  23. package/types/DragResizeHelper.d.ts +70 -0
  24. package/types/MoveableOptionsManager.d.ts +86 -0
  25. package/types/MoveableSelectParentAble.d.ts +1 -2
  26. package/types/StageCore.d.ts +58 -41
  27. package/types/StageDragResize.d.ts +12 -40
  28. package/types/StageHighlight.d.ts +3 -4
  29. package/types/StageMask.d.ts +0 -21
  30. package/types/StageMultiDragResize.d.ts +8 -24
  31. package/types/StageRender.d.ts +23 -4
  32. package/types/TargetShadow.d.ts +22 -0
  33. package/types/const.d.ts +1 -1
  34. package/types/types.d.ts +87 -18
  35. package/types/util.d.ts +8 -8
  36. package/dist/tmagic-stage.mjs.map +0 -1
  37. package/dist/tmagic-stage.umd.js.map +0 -1
  38. package/src/TargetCalibrate.ts +0 -119
  39. package/types/TargetCalibrate.d.ts +0 -20
package/src/StageCore.ts CHANGED
@@ -18,303 +18,149 @@
18
18
 
19
19
  import { EventEmitter } from 'events';
20
20
 
21
- import type { Id } from '@tmagic/schema';
22
- import { addClassName } from '@tmagic/utils';
21
+ import { Id } from '@tmagic/schema';
23
22
 
24
- import { CONTAINER_HIGHLIGHT_CLASS, DEFAULT_ZOOM, GHOST_EL_ID_PREFIX, PAGE_CLASS } from './const';
25
- import StageDragResize from './StageDragResize';
26
- import StageHighlight from './StageHighlight';
23
+ import ActionManager from './ActionManager';
24
+ import { DEFAULT_ZOOM } from './const';
27
25
  import StageMask from './StageMask';
28
- import StageMultiDragResize from './StageMultiDragResize';
29
26
  import StageRender from './StageRender';
30
27
  import {
31
- CanSelect,
32
- ContainerHighlightType,
28
+ ActionManagerConfig,
29
+ CustomizeRender,
33
30
  GuidesEventData,
34
- IsContainer,
31
+ Point,
35
32
  RemoveData,
36
33
  Runtime,
37
- SortEventData,
38
34
  StageCoreConfig,
39
- StageDragStatus,
40
35
  UpdateData,
41
36
  UpdateEventData,
42
37
  } from './types';
43
- import { addSelectedClassName, removeSelectedClassName } from './util';
44
38
 
39
+ /**
40
+ * 负责管理画布,管理renderer、mask、actionManager三个核心类,并负责统一对外通信,包括提供接口和抛事件
41
+ */
45
42
  export default class StageCore extends EventEmitter {
46
43
  public container?: HTMLDivElement;
47
- // 当前选中的节点
48
- public selectedDom: HTMLElement | undefined;
49
- // 多选选中的节点组
50
- public selectedDomList: HTMLElement[] = [];
51
- public highlightedDom: Element | undefined;
52
44
  public renderer: StageRender;
53
45
  public mask: StageMask;
54
- public dr: StageDragResize;
55
- public multiDr: StageMultiDragResize;
56
- public highlightLayer: StageHighlight;
57
- public config: StageCoreConfig;
58
- public zoom = DEFAULT_ZOOM;
59
- public containerHighlightClassName: string;
60
- public containerHighlightDuration: number;
61
- public containerHighlightType?: ContainerHighlightType;
62
- public isContainer: IsContainer;
63
-
64
- private canSelect: CanSelect;
46
+
47
+ private actionManager: ActionManager;
65
48
  private pageResizeObserver: ResizeObserver | null = null;
49
+ private autoScrollIntoView: boolean | undefined;
50
+ private customizedRender?: CustomizeRender;
66
51
 
67
52
  constructor(config: StageCoreConfig) {
68
53
  super();
69
54
 
70
- this.config = config;
71
-
72
- this.setZoom(config.zoom);
73
- this.canSelect = config.canSelect || ((el: HTMLElement) => !!el.id);
74
- this.isContainer = config.isContainer;
75
- this.containerHighlightClassName = config.containerHighlightClassName || CONTAINER_HIGHLIGHT_CLASS;
76
- this.containerHighlightDuration = config.containerHighlightDuration || 800;
77
- this.containerHighlightType = config.containerHighlightType;
78
-
79
- this.renderer = new StageRender({ runtimeUrl: config.runtimeUrl, render: this.render.bind(this) });
80
- this.mask = new StageMask();
81
- this.dr = new StageDragResize({ core: this, container: this.mask.content, mask: this.mask });
82
- this.multiDr = new StageMultiDragResize({ core: this, container: this.mask.content, mask: this.mask });
83
- this.highlightLayer = new StageHighlight({ core: this, container: this.mask.wrapper });
84
-
85
- this.renderer.on('runtime-ready', (runtime: Runtime) => {
86
- this.emit('runtime-ready', runtime);
87
- });
88
- this.renderer.on('page-el-update', (el: HTMLElement) => {
89
- this.mask?.observe(el);
90
- this.observePageResize(el);
91
- });
55
+ this.autoScrollIntoView = config.autoScrollIntoView;
56
+ this.customizedRender = config.render;
92
57
 
93
- this.mask
94
- .on('beforeSelect', async (event: MouseEvent) => {
95
- this.clearSelectStatus('multiSelect');
96
- const el = await this.getElementFromPoint(event);
97
- if (!el) return;
98
- this.select(el, event);
99
- })
100
- .on('select', () => {
101
- this.emit('select', this.selectedDom);
102
- })
103
- .on('changeGuides', (data: GuidesEventData) => {
104
- this.dr.setGuidelines(data.type, data.guides);
105
- this.emit('changeGuides', data);
106
- })
107
- .on('highlight', async (event: MouseEvent) => {
108
- const el = await this.getElementFromPoint(event);
109
- if (!el) return;
110
- // 如果多选组件处于拖拽状态时不进行组件高亮
111
- if (this.multiDr.dragStatus === StageDragStatus.ING) return;
112
- await this.highlight(el);
113
- if (this.highlightedDom === this.selectedDom) {
114
- this.highlightLayer.clearHighlight();
115
- return;
58
+ this.renderer = new StageRender({
59
+ runtimeUrl: config.runtimeUrl,
60
+ zoom: config.zoom,
61
+ customizedRender: async (): Promise<HTMLElement | null> => {
62
+ if (this?.customizedRender) {
63
+ return await this.customizedRender(this);
116
64
  }
117
- this.emit('highlight', this.highlightedDom);
118
- })
119
- .on('clearHighlight', async () => {
120
- this.highlightLayer.clearHighlight();
121
- })
122
- .on('beforeMultiSelect', async (event: MouseEvent) => {
123
- const el = await this.getElementFromPoint(event);
124
- if (!el) return;
125
- // 如果已有单选选中元素,不是magic-ui-page就可以加入多选列表
126
- if (this.selectedDom && !this.selectedDom.className.includes(PAGE_CLASS)) {
127
- this.selectedDomList.push(this.selectedDom as HTMLElement);
128
- this.selectedDom = undefined;
129
- }
130
- // 判断元素是否已在多选列表
131
- const existIndex = this.selectedDomList.findIndex((selectedDom) => selectedDom.id === el.id);
132
- if (existIndex !== -1) {
133
- // 再次点击取消选中
134
- this.selectedDomList.splice(existIndex, 1);
135
- } else {
136
- this.selectedDomList.push(el);
137
- }
138
- this.multiSelect(this.selectedDomList);
139
- this.emit('multiSelect', this.selectedDomList);
140
- });
141
-
142
- // 要先触发select,在触发update
143
- this.dr
144
- .on('update', (data: UpdateEventData) => {
145
- setTimeout(() => this.emit('update', data));
146
- })
147
- .on('sort', (data: UpdateEventData) => {
148
- setTimeout(() => this.emit('sort', data));
149
- })
150
- .on('select-parent', () => {
151
- this.emit('select-parent');
152
- });
65
+ return null;
66
+ },
67
+ });
68
+ this.mask = new StageMask();
69
+ this.actionManager = new ActionManager(this.getActionManagerConfig(config));
153
70
 
154
- this.multiDr
155
- .on('update', (data: UpdateEventData) => {
156
- setTimeout(() => this.emit('update', data));
157
- })
158
- .on('select', async (id: Id) => {
159
- const el = await this.getTargetElement(id);
160
- this.select(el); // 选中
161
- setTimeout(() => this.emit('select', el)); // set node
162
- });
71
+ this.initRenderEvent();
72
+ this.initActionEvent();
73
+ this.initMaskEvent();
163
74
  }
164
75
 
165
- public getElementsFromPoint(event: MouseEvent) {
166
- const { renderer, zoom } = this;
167
-
168
- let x = event.clientX;
169
- let y = event.clientY;
76
+ /**
77
+ * 单选选中元素
78
+ * @param idOrEl 选中的id或者元素
79
+ */
80
+ public async select(idOrEl: Id | HTMLElement, event?: MouseEvent): Promise<void> {
81
+ const el = this.renderer.getTargetElement(idOrEl);
82
+ if (el === this.actionManager.getSelectedEl()) return;
170
83
 
171
- if (renderer.iframe) {
172
- const rect = renderer.iframe.getClientRects()[0];
173
- if (rect) {
174
- x = x - rect.left;
175
- y = y - rect.top;
176
- }
177
- }
84
+ await this.renderer.select([el]);
178
85
 
179
- return renderer.getDocument()?.elementsFromPoint(x / zoom, y / zoom) as HTMLElement[];
180
- }
86
+ this.mask.setLayout(el);
181
87
 
182
- public async getElementFromPoint(event: MouseEvent) {
183
- const els = this.getElementsFromPoint(event);
184
- let stopped = false;
185
- const stop = () => (stopped = true);
186
- for (const el of els) {
187
- if (!el.id.startsWith(GHOST_EL_ID_PREFIX) && (await this.isElCanSelect(el, event, stop))) {
188
- if (stopped) break;
189
- return el;
190
- }
191
- }
192
- }
88
+ this.actionManager.select(el, event);
193
89
 
194
- public async isElCanSelect(el: HTMLElement, event: MouseEvent, stop: () => boolean): Promise<Boolean> {
195
- // 执行业务方传入的判断逻辑
196
- const canSelectByProp = await this.canSelect(el, event, stop);
197
- if (!canSelectByProp) return false;
198
- // 多选规则
199
- if (this.mask.isMultiSelectStatus) {
200
- return this.multiDr.canSelect(el, stop);
90
+ if (this.autoScrollIntoView || el.dataset.autoScrollIntoView) {
91
+ this.mask.observerIntersection(el);
201
92
  }
202
- return true;
203
93
  }
204
94
 
205
95
  /**
206
- * 选中组件
207
- * @param idOrEl 组件Dom节点的id属性,或者Dom节点
96
+ * 多选选中多个元素
97
+ * @param idOrElList 选中元素的id或元素列表
208
98
  */
209
- public async select(idOrEl: Id | HTMLElement, event?: MouseEvent): Promise<void> {
210
- this.clearSelectStatus('multiSelect');
211
- const el = await this.getTargetElement(idOrEl);
212
-
213
- if (el === this.selectedDom) return;
214
-
215
- const runtime = await this.renderer.getRuntime();
99
+ public async multiSelect(idOrElList: HTMLElement[] | Id[]): Promise<void> {
100
+ const els = idOrElList.map((idOrEl) => this.renderer.getTargetElement(idOrEl));
101
+ if (els.length === 0) return;
216
102
 
217
- await runtime?.select?.(el.id);
103
+ const lastEl = els[els.length - 1];
104
+ // 是否减少了组件选择
105
+ const isReduceSelect = els.length < this.actionManager.getSelectedElList().length;
106
+ await this.renderer.select(els);
218
107
 
219
- if (runtime?.beforeSelect) {
220
- await runtime.beforeSelect(el);
221
- }
108
+ this.mask.setLayout(lastEl);
222
109
 
223
- this.mask.setLayout(el);
224
- this.dr.select(el, event);
110
+ this.actionManager.multiSelect(idOrElList);
225
111
 
226
- if (this.config.autoScrollIntoView || el.dataset.autoScrollIntoView) {
227
- this.mask.observerIntersection(el);
228
- }
229
-
230
- this.selectedDom = el;
231
-
232
- const doc = this.renderer.getDocument();
233
- if (doc) {
234
- removeSelectedClassName(doc);
235
- if (this.selectedDom) {
236
- addSelectedClassName(this.selectedDom, doc);
237
- }
112
+ if ((this.autoScrollIntoView || lastEl.dataset.autoScrollIntoView) && !isReduceSelect) {
113
+ this.mask.observerIntersection(lastEl);
238
114
  }
239
115
  }
240
116
 
241
117
  /**
242
- * 多选
243
- * @param domList 多选节点
118
+ * 高亮选中元素
119
+ * @param el 要高亮的元素
244
120
  */
245
- public async multiSelect(idOrElList: HTMLElement[] | Id[]): Promise<void> {
246
- this.clearSelectStatus('select');
247
- this.selectedDomList = await Promise.all(idOrElList.map(async (idOrEl) => await this.getTargetElement(idOrEl)));
248
- this.multiDr.multiSelect(this.selectedDomList);
121
+ public highlight(idOrEl: Id | HTMLElement): void {
122
+ this.actionManager.highlight(idOrEl);
249
123
  }
250
124
 
251
125
  /**
252
- * 更新选中的节点
253
- * @param data 更新的数据
126
+ * 更新组件
127
+ * @param data 更新组件的数据
254
128
  */
255
- public update(data: UpdateData): Promise<void> {
129
+ public async update(data: UpdateData): Promise<void> {
256
130
  const { config } = data;
257
131
 
258
- return this.renderer?.getRuntime().then((runtime) => {
259
- runtime?.update?.(data);
260
- // 更新配置后,需要等组件渲染更新
261
- setTimeout(() => {
262
- const el = this.renderer.getDocument()?.getElementById(`${config.id}`);
263
- // 有可能dom已经重新渲染,不再是原来的dom了,所以这里判断id,而不是判断el === this.selectedDom
264
- if (el && el.id === this.selectedDom?.id) {
265
- this.selectedDom = el;
266
- // 更新了组件的布局,需要重新设置mask是否可以滚动
267
- this.mask.setLayout(el);
268
- this.dr.updateMoveable(el);
269
- }
270
- }, 0);
132
+ await this.renderer.update(data);
133
+ // 通过setTimeout等画布中组件完成渲染更新
134
+ setTimeout(() => {
135
+ const el = this.renderer.getTargetElement(`${config.id}`);
136
+ if (el && this.actionManager.isSelectedEl(el)) {
137
+ // 更新了组件的布局,需要重新设置mask是否可以滚动
138
+ this.mask.setLayout(el);
139
+ // 组件有更新,需要set
140
+ this.actionManager.setSelectedEl(el);
141
+ this.actionManager.updateMoveable(el);
142
+ }
271
143
  });
272
144
  }
273
145
 
274
146
  /**
275
- * 高亮选中组件
276
- * @param el 页面Dom节点
147
+ * 往画布增加一个组件
148
+ * @param data 组件信息数据
277
149
  */
278
- public async highlight(idOrEl: HTMLElement | Id): Promise<void> {
279
- let el;
280
- try {
281
- el = await this.getTargetElement(idOrEl);
282
- } catch (error) {
283
- this.highlightLayer.clearHighlight();
284
- return;
285
- }
286
- if (el === this.highlightedDom || !el) return;
287
- this.highlightLayer.highlight(el);
288
- this.highlightedDom = el;
289
- }
290
-
291
- public sortNode(data: SortEventData): Promise<void> {
292
- return this.renderer?.getRuntime().then((runtime) => runtime?.sortNode?.(data));
150
+ public async add(data: UpdateData): Promise<void> {
151
+ return await this.renderer.add(data);
293
152
  }
294
153
 
295
- public add(data: UpdateData): Promise<void> {
296
- return this.renderer?.getRuntime().then((runtime) => runtime?.add?.(data));
297
- }
298
-
299
- public remove(data: RemoveData): Promise<void> {
300
- return this.renderer?.getRuntime().then((runtime) => runtime?.remove?.(data));
154
+ /**
155
+ * 从画布删除一个组件
156
+ * @param data 组件信息数据
157
+ */
158
+ public async remove(data: RemoveData): Promise<void> {
159
+ return await this.renderer.remove(data);
301
160
  }
302
161
 
303
162
  public setZoom(zoom: number = DEFAULT_ZOOM): void {
304
- this.zoom = zoom;
305
- }
306
-
307
- /**
308
- * 用于在切换选择模式时清除上一次的状态
309
- * @param selectType 需要清理的选择模式 多选:multiSelect,单选:select
310
- */
311
- public clearSelectStatus(selectType: String) {
312
- if (selectType === 'multiSelect') {
313
- this.multiDr.clearSelectStatus();
314
- this.selectedDomList = [];
315
- } else {
316
- this.dr.clearSelectStatus();
317
- }
163
+ this.renderer.setZoom(zoom);
318
164
  }
319
165
 
320
166
  /**
@@ -336,40 +182,36 @@ export default class StageCore extends EventEmitter {
336
182
  */
337
183
  public clearGuides() {
338
184
  this.mask.clearGuides();
339
- this.dr.clearGuides();
185
+ this.actionManager.clearGuides();
340
186
  }
341
187
 
342
- public async addContainerHighlightClassName(event: MouseEvent, exclude: Element[]) {
343
- const els = this.getElementsFromPoint(event);
344
- const { renderer } = this;
345
- const doc = renderer.getDocument();
346
-
347
- if (!doc) return;
348
-
349
- for (const el of els) {
350
- if (!el.id.startsWith(GHOST_EL_ID_PREFIX) && (await this.isContainer(el)) && !exclude.includes(el)) {
351
- addClassName(el, doc, this.containerHighlightClassName);
352
- break;
353
- }
354
- }
188
+ /**
189
+ * @deprecated 废弃接口,建议用delayedMarkContainer代替
190
+ */
191
+ public getAddContainerHighlightClassNameTimeout(event: MouseEvent, excludeElList: Element[] = []): NodeJS.Timeout {
192
+ return this.delayedMarkContainer(event, excludeElList);
355
193
  }
356
194
 
357
- public getAddContainerHighlightClassNameTimeout(event: MouseEvent, exclude: Element[] = []): NodeJS.Timeout {
358
- return globalThis.setTimeout(() => {
359
- this.addContainerHighlightClassName(event, exclude);
360
- }, this.containerHighlightDuration);
195
+ /**
196
+ * 鼠标拖拽着元素,在容器上方悬停,延迟一段时间后,对容器进行标记,如果悬停时间够长将标记成功,悬停时间短,调用方通过返回的timeoutId取消标记
197
+ * 标记的作用:1、高亮容器,给用户一个加入容器的交互感知;2、释放鼠标后,通过标记的标志找到要加入的容器
198
+ * @param event 鼠标事件
199
+ * @param excludeElList 计算鼠标所在容器时要排除的元素列表
200
+ * @returns timeoutId,调用方在鼠标移走时要取消该timeout,阻止标记
201
+ */
202
+ public delayedMarkContainer(event: MouseEvent, excludeElList: Element[] = []): NodeJS.Timeout {
203
+ return this.actionManager.delayedMarkContainer(event, excludeElList);
361
204
  }
362
205
 
363
206
  /**
364
207
  * 销毁实例
365
208
  */
366
209
  public destroy(): void {
367
- const { mask, renderer, dr, highlightLayer, pageResizeObserver } = this;
210
+ const { mask, renderer, actionManager, pageResizeObserver } = this;
368
211
 
369
212
  renderer.destroy();
370
213
  mask.destroy();
371
- dr.destroy();
372
- highlightLayer.destroy();
214
+ actionManager.destroy();
373
215
  pageResizeObserver?.disconnect();
374
216
 
375
217
  this.removeAllListeners();
@@ -384,32 +226,118 @@ export default class StageCore extends EventEmitter {
384
226
  if (typeof ResizeObserver !== 'undefined') {
385
227
  this.pageResizeObserver = new ResizeObserver((entries) => {
386
228
  this.mask.pageResize(entries);
387
-
388
- if (this.dr.moveable) {
389
- this.dr.updateMoveable();
390
- }
229
+ this.actionManager.updateMoveable();
391
230
  });
392
231
 
393
232
  this.pageResizeObserver.observe(page);
394
233
  }
395
234
  }
396
235
 
236
+ private getActionManagerConfig(config: StageCoreConfig): ActionManagerConfig {
237
+ const actionManagerConfig: ActionManagerConfig = {
238
+ containerHighlightClassName: config.containerHighlightClassName,
239
+ containerHighlightDuration: config.containerHighlightDuration,
240
+ containerHighlightType: config.containerHighlightType,
241
+ moveableOptions: config.moveableOptions,
242
+ multiMoveableOptions: config.multiMoveableOptions,
243
+ container: this.mask.content,
244
+ disabledDragStart: config.disabledDragStart,
245
+ canSelect: config.canSelect,
246
+ isContainer: config.isContainer,
247
+ updateDragEl: config.updateDragEl,
248
+ getRootContainer: () => this.container,
249
+ getRenderDocument: () => this.renderer.getDocument(),
250
+ getTargetElement: (idOrEl: Id | HTMLElement) => this.renderer.getTargetElement(idOrEl),
251
+ getElementsFromPoint: (point: Point) => this.renderer.getElementsFromPoint(point),
252
+ };
253
+
254
+ return actionManagerConfig;
255
+ }
256
+
257
+ private initRenderEvent(): void {
258
+ this.renderer.on('runtime-ready', (runtime: Runtime) => {
259
+ this.emit('runtime-ready', runtime);
260
+ });
261
+ this.renderer.on('page-el-update', (el: HTMLElement) => {
262
+ this.mask?.observe(el);
263
+ this.observePageResize(el);
264
+ });
265
+ }
266
+
267
+ private initMaskEvent(): void {
268
+ this.mask.on('change-guides', (data: GuidesEventData) => {
269
+ this.actionManager.setGuidelines(data.type, data.guides);
270
+ this.emit('change-guides', data);
271
+ });
272
+ }
273
+
397
274
  /**
398
- * 传入stageRender供其回调,获取业务方自定义渲染画布页面渲染结果
275
+ * 初始化操作相关事件监听
399
276
  */
400
- private async render(): Promise<HTMLElement | null> {
401
- if (this.config?.render) {
402
- return await this.config.render(this);
403
- }
404
- return null;
277
+ private initActionEvent(): void {
278
+ this.initActionManagerEvent();
279
+ this.initDrEvent();
280
+ this.initMulDrEvent();
281
+ this.initHighlightEvent();
405
282
  }
406
283
 
407
- private async getTargetElement(idOrEl: Id | HTMLElement): Promise<HTMLElement> {
408
- if (typeof idOrEl === 'string' || typeof idOrEl === 'number') {
409
- const el = this.renderer.getDocument()?.getElementById(`${idOrEl}`);
410
- if (!el) throw new Error(`不存在ID为${idOrEl}的元素`);
411
- return el;
412
- }
413
- return idOrEl;
284
+ /**
285
+ * 初始化ActionManager类本身抛出来的事件监听
286
+ */
287
+ private initActionManagerEvent(): void {
288
+ this.actionManager
289
+ .on('before-select', (idOrEl: Id | HTMLElement, event?: MouseEvent) => {
290
+ this.select(idOrEl, event);
291
+ })
292
+ .on('select', (selectedEl: HTMLElement) => {
293
+ this.emit('select', selectedEl);
294
+ })
295
+ .on('before-multi-select', (idOrElList: HTMLElement[] | Id[]) => {
296
+ this.multiSelect(idOrElList);
297
+ })
298
+ .on('multi-select', (selectedElList: HTMLElement[]) => {
299
+ this.emit('multi-select', selectedElList);
300
+ });
301
+ }
302
+
303
+ /**
304
+ * 初始化DragResize类通过ActionManager抛出来的事件监听
305
+ */
306
+ private initDrEvent(): void {
307
+ this.actionManager
308
+ .on('update', (data: UpdateEventData) => {
309
+ this.emit('update', data);
310
+ })
311
+ .on('sort', (data: UpdateEventData) => {
312
+ this.emit('sort', data);
313
+ })
314
+ .on('select-parent', () => {
315
+ this.emit('select-parent');
316
+ });
317
+ }
318
+
319
+ /**
320
+ * 初始化MultiDragResize类通过ActionManager抛出来的事件监听
321
+ */
322
+ private initMulDrEvent(): void {
323
+ this.actionManager
324
+ // 多选切换到单选
325
+ .on('change-to-select', (el: HTMLElement) => {
326
+ this.select(el);
327
+ // 先保证画布内完成渲染,再通知外部更新
328
+ setTimeout(() => this.emit('select', el));
329
+ })
330
+ .on('multi-update', (data: UpdateEventData, parentEl: HTMLElement | null) => {
331
+ this.emit('update', { data, parentEl });
332
+ });
333
+ }
334
+
335
+ /**
336
+ * 初始化Highlight类通过ActionManager抛出来的事件监听
337
+ */
338
+ private initHighlightEvent(): void {
339
+ this.actionManager.on('highlight', async (highlightEl: HTMLElement) => {
340
+ this.emit('highlight', highlightEl);
341
+ });
414
342
  }
415
343
  }