@tmagic/stage 1.2.0-beta.9 → 1.2.1
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.
- package/README.md +62 -1
- package/dist/{tmagic-stage.mjs → tmagic-stage.js} +1395 -1062
- package/dist/tmagic-stage.js.map +1 -0
- package/dist/{tmagic-stage.umd.js → tmagic-stage.umd.cjs} +1393 -1060
- package/dist/tmagic-stage.umd.cjs.map +1 -0
- package/package.json +9 -8
- package/src/ActionManager.ts +535 -0
- package/src/DragResizeHelper.ts +338 -0
- package/src/MoveableOptionsManager.ts +249 -0
- package/src/MoveableSelectParentAble.ts +3 -5
- package/src/Rule.ts +4 -4
- package/src/StageCore.ts +204 -276
- package/src/StageDragResize.ts +87 -349
- package/src/StageHighlight.ts +18 -17
- package/src/StageMask.ts +20 -103
- package/src/StageMultiDragResize.ts +98 -199
- package/src/StageRender.ts +86 -11
- package/src/TargetShadow.ts +120 -0
- package/src/const.ts +2 -2
- package/src/index.ts +1 -1
- package/src/logger.ts +1 -1
- package/src/types.ts +100 -20
- package/src/util.ts +19 -12
- package/types/ActionManager.d.ts +141 -0
- package/types/DragResizeHelper.d.ts +70 -0
- package/types/MoveableOptionsManager.d.ts +86 -0
- package/types/MoveableSelectParentAble.d.ts +1 -2
- package/types/StageCore.d.ts +58 -41
- package/types/StageDragResize.d.ts +12 -40
- package/types/StageHighlight.d.ts +3 -4
- package/types/StageMask.d.ts +0 -21
- package/types/StageMultiDragResize.d.ts +8 -24
- package/types/StageRender.d.ts +23 -4
- package/types/TargetShadow.d.ts +22 -0
- package/types/const.d.ts +1 -1
- package/types/types.d.ts +87 -18
- package/types/util.d.ts +8 -8
- package/dist/tmagic-stage.mjs.map +0 -1
- package/dist/tmagic-stage.umd.js.map +0 -1
- package/src/TargetCalibrate.ts +0 -119
- package/types/TargetCalibrate.d.ts +0 -20
package/src/StageHighlight.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
|
3
3
|
*
|
|
4
|
-
* Copyright (C)
|
|
4
|
+
* Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
|
|
5
5
|
*
|
|
6
6
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
7
|
* you may not use this file except in compliance with the License.
|
|
@@ -20,27 +20,28 @@ import { EventEmitter } from 'events';
|
|
|
20
20
|
|
|
21
21
|
import Moveable from 'moveable';
|
|
22
22
|
|
|
23
|
-
import { HIGHLIGHT_EL_ID_PREFIX } from './const';
|
|
24
|
-
import
|
|
25
|
-
import
|
|
26
|
-
|
|
23
|
+
import { HIGHLIGHT_EL_ID_PREFIX, ZIndex } from './const';
|
|
24
|
+
import TargetShadow from './TargetShadow';
|
|
25
|
+
import type { GetRootContainer, StageHighlightConfig } from './types';
|
|
26
|
+
|
|
27
27
|
export default class StageHighlight extends EventEmitter {
|
|
28
|
-
public core: StageCore;
|
|
29
28
|
public container: HTMLElement;
|
|
30
29
|
public target?: HTMLElement;
|
|
31
30
|
public moveable?: Moveable;
|
|
32
|
-
public
|
|
31
|
+
public targetShadow: TargetShadow;
|
|
32
|
+
private getRootContainer: GetRootContainer;
|
|
33
33
|
|
|
34
34
|
constructor(config: StageHighlightConfig) {
|
|
35
35
|
super();
|
|
36
36
|
|
|
37
|
-
this.core = config.core;
|
|
38
37
|
this.container = config.container;
|
|
39
|
-
this.
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
38
|
+
this.getRootContainer = config.getRootContainer;
|
|
39
|
+
|
|
40
|
+
this.targetShadow = new TargetShadow({
|
|
41
|
+
container: config.container,
|
|
42
|
+
updateDragEl: config.updateDragEl,
|
|
43
|
+
zIndex: ZIndex.HIGHLIGHT_EL,
|
|
44
|
+
idPrefix: HIGHLIGHT_EL_ID_PREFIX,
|
|
44
45
|
});
|
|
45
46
|
}
|
|
46
47
|
|
|
@@ -54,9 +55,9 @@ export default class StageHighlight extends EventEmitter {
|
|
|
54
55
|
this.moveable?.destroy();
|
|
55
56
|
|
|
56
57
|
this.moveable = new Moveable(this.container, {
|
|
57
|
-
target: this.
|
|
58
|
+
target: this.targetShadow.update(el),
|
|
58
59
|
origin: false,
|
|
59
|
-
rootContainer: this.
|
|
60
|
+
rootContainer: this.getRootContainer(),
|
|
60
61
|
zoom: 2,
|
|
61
62
|
});
|
|
62
63
|
}
|
|
@@ -65,7 +66,7 @@ export default class StageHighlight extends EventEmitter {
|
|
|
65
66
|
* 清空高亮
|
|
66
67
|
*/
|
|
67
68
|
public clearHighlight(): void {
|
|
68
|
-
if (!this.moveable) return;
|
|
69
|
+
if (!this.moveable || !this.target) return;
|
|
69
70
|
this.target = undefined;
|
|
70
71
|
this.moveable.target = null;
|
|
71
72
|
this.moveable.updateTarget();
|
|
@@ -76,6 +77,6 @@ export default class StageHighlight extends EventEmitter {
|
|
|
76
77
|
*/
|
|
77
78
|
public destroy(): void {
|
|
78
79
|
this.moveable?.destroy();
|
|
79
|
-
this.
|
|
80
|
+
this.targetShadow.destroy();
|
|
80
81
|
}
|
|
81
82
|
}
|
package/src/StageMask.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
|
3
3
|
*
|
|
4
|
-
* Copyright (C)
|
|
4
|
+
* Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
|
|
5
5
|
*
|
|
6
6
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
7
|
* you may not use this file except in compliance with the License.
|
|
@@ -16,20 +16,16 @@
|
|
|
16
16
|
* limitations under the License.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
import
|
|
20
|
-
import { throttle } from 'lodash-es';
|
|
19
|
+
import { createDiv, getDocument, injectStyle } from '@tmagic/utils';
|
|
21
20
|
|
|
22
|
-
import {
|
|
23
|
-
|
|
24
|
-
import { Mode, MouseButton, ZIndex } from './const';
|
|
21
|
+
import { Mode, ZIndex } from './const';
|
|
25
22
|
import Rule from './Rule';
|
|
26
|
-
import { getScrollParent, isFixedParent
|
|
23
|
+
import { getScrollParent, isFixedParent } from './util';
|
|
27
24
|
|
|
28
25
|
const wrapperClassName = 'editor-mask-wrapper';
|
|
29
|
-
const throttleTime = 100;
|
|
30
26
|
|
|
31
27
|
const hideScrollbar = () => {
|
|
32
|
-
injectStyle(
|
|
28
|
+
injectStyle(getDocument(), `.${wrapperClassName}::-webkit-scrollbar { width: 0 !important; display: none }`);
|
|
33
29
|
};
|
|
34
30
|
|
|
35
31
|
const createContent = (): HTMLDivElement =>
|
|
@@ -78,36 +74,28 @@ export default class StageMask extends Rule {
|
|
|
78
74
|
public wrapperWidth = 0;
|
|
79
75
|
public maxScrollTop = 0;
|
|
80
76
|
public maxScrollLeft = 0;
|
|
81
|
-
public isMultiSelectStatus: Boolean = false;
|
|
82
77
|
|
|
83
78
|
private mode: Mode = Mode.ABSOLUTE;
|
|
84
79
|
private pageScrollParent: HTMLElement | null = null;
|
|
85
80
|
private intersectionObserver: IntersectionObserver | null = null;
|
|
86
81
|
private wrapperResizeObserver: ResizeObserver | null = null;
|
|
87
82
|
|
|
88
|
-
/**
|
|
89
|
-
* 高亮事件处理函数
|
|
90
|
-
* @param event 事件对象
|
|
91
|
-
*/
|
|
92
|
-
private highlightHandler = throttle((event: MouseEvent): void => {
|
|
93
|
-
this.emit('highlight', event);
|
|
94
|
-
}, throttleTime);
|
|
95
|
-
|
|
96
83
|
constructor() {
|
|
97
84
|
const wrapper = createWrapper();
|
|
98
85
|
super(wrapper);
|
|
99
86
|
|
|
100
87
|
this.wrapper = wrapper;
|
|
101
88
|
|
|
102
|
-
this.
|
|
89
|
+
this.content.addEventListener('wheel', this.mouseWheelHandler);
|
|
103
90
|
this.wrapper.appendChild(this.content);
|
|
104
|
-
|
|
105
|
-
this.initMultiSelectEvent();
|
|
106
91
|
}
|
|
107
92
|
|
|
108
93
|
public setMode(mode: Mode) {
|
|
109
94
|
this.mode = mode;
|
|
110
95
|
this.scroll();
|
|
96
|
+
|
|
97
|
+
this.content.dataset.mode = mode;
|
|
98
|
+
|
|
111
99
|
if (mode === Mode.FIXED) {
|
|
112
100
|
this.content.style.width = `${this.wrapperWidth}px`;
|
|
113
101
|
this.content.style.height = `${this.wrapperHeight}px`;
|
|
@@ -182,42 +170,9 @@ export default class StageMask extends Rule {
|
|
|
182
170
|
this.pageScrollParent = null;
|
|
183
171
|
this.wrapperResizeObserver?.disconnect();
|
|
184
172
|
|
|
185
|
-
this.content.removeEventListener('mouseleave', this.mouseLeaveHandler);
|
|
186
173
|
super.destroy();
|
|
187
174
|
}
|
|
188
175
|
|
|
189
|
-
/**
|
|
190
|
-
* 初始化content的事件监听
|
|
191
|
-
*/
|
|
192
|
-
private initContentEventListener(): void {
|
|
193
|
-
this.content.addEventListener('mousedown', this.mouseDownHandler);
|
|
194
|
-
this.content.addEventListener('wheel', this.mouseWheelHandler);
|
|
195
|
-
this.content.addEventListener('mousemove', this.highlightHandler);
|
|
196
|
-
this.content.addEventListener('mouseleave', this.mouseLeaveHandler);
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* 初始化多选事件监听
|
|
201
|
-
*/
|
|
202
|
-
private initMultiSelectEvent(): void {
|
|
203
|
-
const isMac = /mac os x/.test(navigator.userAgent.toLowerCase());
|
|
204
|
-
|
|
205
|
-
const ctrl = isMac ? 'meta' : 'ctrl';
|
|
206
|
-
|
|
207
|
-
KeyController.global.keydown(ctrl, (e) => {
|
|
208
|
-
e.inputEvent.preventDefault();
|
|
209
|
-
this.isMultiSelectStatus = true;
|
|
210
|
-
});
|
|
211
|
-
// ctrl+tab切到其他窗口,需要将多选状态置为false
|
|
212
|
-
KeyController.global.on('blur', () => {
|
|
213
|
-
this.isMultiSelectStatus = false;
|
|
214
|
-
});
|
|
215
|
-
KeyController.global.keyup(ctrl, (e) => {
|
|
216
|
-
e.inputEvent.preventDefault();
|
|
217
|
-
this.isMultiSelectStatus = false;
|
|
218
|
-
});
|
|
219
|
-
}
|
|
220
|
-
|
|
221
176
|
/**
|
|
222
177
|
* 监听选中元素是否在画布可视区域内,如果目标元素不在可视区域内,通过滚动使该元素出现在可视区域
|
|
223
178
|
*/
|
|
@@ -286,6 +241,17 @@ export default class StageMask extends Rule {
|
|
|
286
241
|
|
|
287
242
|
private scrollTo(scrollLeft: number, scrollTop: number): void {
|
|
288
243
|
this.content.style.transform = `translate3d(${-scrollLeft}px, ${-scrollTop}px, 0)`;
|
|
244
|
+
|
|
245
|
+
const event = new CustomEvent<{
|
|
246
|
+
scrollLeft: number;
|
|
247
|
+
scrollTop: number;
|
|
248
|
+
}>('customScroll', {
|
|
249
|
+
detail: {
|
|
250
|
+
scrollLeft: this.scrollLeft,
|
|
251
|
+
scrollTop: this.scrollTop,
|
|
252
|
+
},
|
|
253
|
+
});
|
|
254
|
+
this.content.dispatchEvent(event);
|
|
289
255
|
}
|
|
290
256
|
|
|
291
257
|
/**
|
|
@@ -333,51 +299,7 @@ export default class StageMask extends Rule {
|
|
|
333
299
|
if (this.maxScrollLeft < this.scrollLeft) this.scrollLeft = this.maxScrollLeft;
|
|
334
300
|
}
|
|
335
301
|
|
|
336
|
-
/**
|
|
337
|
-
* 点击事件处理函数
|
|
338
|
-
* @param event 事件对象
|
|
339
|
-
*/
|
|
340
|
-
private mouseDownHandler = (event: MouseEvent): void => {
|
|
341
|
-
this.emit('clearHighlight');
|
|
342
|
-
event.stopImmediatePropagation();
|
|
343
|
-
event.stopPropagation();
|
|
344
|
-
|
|
345
|
-
if (event.button !== MouseButton.LEFT && event.button !== MouseButton.RIGHT) return;
|
|
346
|
-
if (!event.target) return;
|
|
347
|
-
|
|
348
|
-
const targetClassList = (event.target as HTMLDivElement).classList;
|
|
349
|
-
|
|
350
|
-
// 如果单击多选选中区域,则不需要再触发选中了,而可能是拖动行为
|
|
351
|
-
if (!this.isMultiSelectStatus && targetClassList.contains('moveable-area')) {
|
|
352
|
-
return;
|
|
353
|
-
}
|
|
354
|
-
// 点击对象如果是边框锚点,则可能是resize; 点击对象是功能按钮
|
|
355
|
-
if (targetClassList.contains('moveable-control') || isMoveableButton(event.target as Element)) {
|
|
356
|
-
return;
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
this.content.removeEventListener('mousemove', this.highlightHandler);
|
|
360
|
-
|
|
361
|
-
// 判断触发多选还是单选
|
|
362
|
-
if (this.isMultiSelectStatus) {
|
|
363
|
-
this.emit('beforeMultiSelect', event);
|
|
364
|
-
} else {
|
|
365
|
-
this.emit('beforeSelect', event);
|
|
366
|
-
}
|
|
367
|
-
// 如果是右键点击,这里的mouseup事件监听没有效果
|
|
368
|
-
globalThis.document.addEventListener('mouseup', this.mouseUpHandler);
|
|
369
|
-
};
|
|
370
|
-
|
|
371
|
-
private mouseUpHandler = (): void => {
|
|
372
|
-
globalThis.document.removeEventListener('mouseup', this.mouseUpHandler);
|
|
373
|
-
this.content.addEventListener('mousemove', this.highlightHandler);
|
|
374
|
-
if (!this.isMultiSelectStatus) {
|
|
375
|
-
this.emit('select');
|
|
376
|
-
}
|
|
377
|
-
};
|
|
378
|
-
|
|
379
302
|
private mouseWheelHandler = (event: WheelEvent) => {
|
|
380
|
-
this.emit('clearHighlight');
|
|
381
303
|
if (!this.page) throw new Error('page 未初始化');
|
|
382
304
|
|
|
383
305
|
const { deltaY, deltaX } = event;
|
|
@@ -394,11 +316,6 @@ export default class StageMask extends Rule {
|
|
|
394
316
|
}
|
|
395
317
|
|
|
396
318
|
this.scroll();
|
|
397
|
-
|
|
398
319
|
this.emit('scroll', event);
|
|
399
320
|
};
|
|
400
|
-
|
|
401
|
-
private mouseLeaveHandler = () => {
|
|
402
|
-
setTimeout(() => this.emit('clearHighlight'), throttleTime);
|
|
403
|
-
};
|
|
404
321
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
|
3
3
|
*
|
|
4
|
-
* Copyright (C)
|
|
4
|
+
* Copyright (C) 2023 THL A29 Limited, a Tencent company. All rights reserved.
|
|
5
5
|
*
|
|
6
6
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
7
|
* you may not use this file except in compliance with the License.
|
|
@@ -16,39 +16,46 @@
|
|
|
16
16
|
* limitations under the License.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
import { EventEmitter } from 'events';
|
|
20
|
-
|
|
21
|
-
import type { MoveableOptions, OnDragStart, OnResizeStart } from 'moveable';
|
|
22
19
|
import Moveable from 'moveable';
|
|
23
|
-
import MoveableHelper from 'moveable-helper';
|
|
24
20
|
|
|
25
|
-
import { DRAG_EL_ID_PREFIX,
|
|
26
|
-
import
|
|
27
|
-
import
|
|
28
|
-
import {
|
|
29
|
-
import { calcValueByFontsize, getMode
|
|
21
|
+
import { DRAG_EL_ID_PREFIX, Mode } from './const';
|
|
22
|
+
import DragResizeHelper from './DragResizeHelper';
|
|
23
|
+
import MoveableOptionsManager from './MoveableOptionsManager';
|
|
24
|
+
import { GetRenderDocument, MoveableOptionsManagerConfig, StageDragStatus, StageMultiDragResizeConfig } from './types';
|
|
25
|
+
import { calcValueByFontsize, getMode } from './util';
|
|
30
26
|
|
|
31
|
-
export default class StageMultiDragResize extends
|
|
32
|
-
public core: StageCore;
|
|
33
|
-
public mask: StageMask;
|
|
27
|
+
export default class StageMultiDragResize extends MoveableOptionsManager {
|
|
34
28
|
/** 画布容器 */
|
|
35
29
|
public container: HTMLElement;
|
|
36
30
|
/** 多选:目标节点组 */
|
|
37
31
|
public targetList: HTMLElement[] = [];
|
|
38
|
-
/** 多选:目标节点在蒙层中的占位节点组 */
|
|
39
|
-
public dragElList: HTMLDivElement[] = [];
|
|
40
32
|
/** Moveable多选拖拽类实例 */
|
|
41
33
|
public moveableForMulti?: Moveable;
|
|
42
|
-
/** 拖动状态 */
|
|
43
34
|
public dragStatus: StageDragStatus = StageDragStatus.END;
|
|
44
|
-
private
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
35
|
+
private dragResizeHelper: DragResizeHelper;
|
|
36
|
+
private getRenderDocument: GetRenderDocument;
|
|
37
|
+
|
|
38
|
+
constructor(config: StageMultiDragResizeConfig) {
|
|
39
|
+
const moveableOptionsManagerConfig: MoveableOptionsManagerConfig = {
|
|
40
|
+
container: config.container,
|
|
41
|
+
moveableOptions: config.multiMoveableOptions,
|
|
42
|
+
getRootContainer: config.getRootContainer,
|
|
43
|
+
};
|
|
44
|
+
super(moveableOptionsManagerConfig);
|
|
48
45
|
|
|
49
|
-
this.core = config.core;
|
|
50
46
|
this.container = config.container;
|
|
51
|
-
this.
|
|
47
|
+
this.getRenderDocument = config.getRenderDocument;
|
|
48
|
+
|
|
49
|
+
this.dragResizeHelper = new DragResizeHelper({
|
|
50
|
+
container: config.container,
|
|
51
|
+
updateDragEl: config.updateDragEl,
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
this.on('update-moveable', () => {
|
|
55
|
+
if (this.moveableForMulti) {
|
|
56
|
+
this.updateMoveable();
|
|
57
|
+
}
|
|
58
|
+
});
|
|
52
59
|
}
|
|
53
60
|
|
|
54
61
|
/**
|
|
@@ -56,168 +63,108 @@ export default class StageMultiDragResize extends EventEmitter {
|
|
|
56
63
|
* @param els
|
|
57
64
|
*/
|
|
58
65
|
public multiSelect(els: HTMLElement[]): void {
|
|
66
|
+
if (els.length === 0) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
this.mode = getMode(els[0]);
|
|
59
70
|
this.targetList = els;
|
|
60
|
-
|
|
61
|
-
this.
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
this.
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
// 业务方校准
|
|
69
|
-
if (typeof this.core.config.updateDragEl === 'function') {
|
|
70
|
-
this.core.config.updateDragEl(dragElDiv, elItem);
|
|
71
|
-
}
|
|
72
|
-
return dragElDiv;
|
|
73
|
-
});
|
|
71
|
+
|
|
72
|
+
this.dragResizeHelper.updateGroup(els);
|
|
73
|
+
|
|
74
|
+
// 设置周围元素,用于选中元素跟周围元素的对齐辅助
|
|
75
|
+
const elementGuidelines: HTMLElement[] =
|
|
76
|
+
Array.prototype.slice.call(this.targetList[0].parentElement?.children) || [];
|
|
77
|
+
this.setElementGuidelines(this.targetList, elementGuidelines);
|
|
78
|
+
|
|
74
79
|
this.moveableForMulti?.destroy();
|
|
75
|
-
this.
|
|
80
|
+
this.dragResizeHelper.clear();
|
|
76
81
|
this.moveableForMulti = new Moveable(
|
|
77
82
|
this.container,
|
|
78
|
-
this.getOptions({
|
|
79
|
-
target: this.
|
|
83
|
+
this.getOptions(true, {
|
|
84
|
+
target: this.dragResizeHelper.getShadowEls(),
|
|
80
85
|
}),
|
|
81
86
|
);
|
|
82
|
-
this.multiMoveableHelper = MoveableHelper.create({
|
|
83
|
-
useBeforeRender: true,
|
|
84
|
-
useRender: false,
|
|
85
|
-
createAuto: true,
|
|
86
|
-
});
|
|
87
|
-
const frames: { left: number; top: number; id: string }[] = [];
|
|
88
|
-
|
|
89
|
-
const setFrames = (events: OnDragStart[] | OnResizeStart[]) => {
|
|
90
|
-
// 记录拖动前快照
|
|
91
|
-
events.forEach((ev) => {
|
|
92
|
-
// 实际目标元素
|
|
93
|
-
const matchEventTarget = this.targetList.find(
|
|
94
|
-
(targetItem) => targetItem.id === ev.target.id.replace(DRAG_EL_ID_PREFIX, ''),
|
|
95
|
-
);
|
|
96
|
-
if (!matchEventTarget) return;
|
|
97
|
-
frames.push({
|
|
98
|
-
left: matchEventTarget.offsetLeft,
|
|
99
|
-
top: matchEventTarget.offsetTop,
|
|
100
|
-
id: matchEventTarget.id,
|
|
101
|
-
});
|
|
102
|
-
});
|
|
103
|
-
};
|
|
104
87
|
|
|
105
88
|
this.moveableForMulti
|
|
106
|
-
.on('resizeGroupStart', (
|
|
107
|
-
|
|
108
|
-
this.multiMoveableHelper?.onResizeGroupStart(params);
|
|
109
|
-
setFrames(events);
|
|
89
|
+
.on('resizeGroupStart', (e) => {
|
|
90
|
+
this.dragResizeHelper.onResizeGroupStart(e);
|
|
110
91
|
this.dragStatus = StageDragStatus.START;
|
|
111
92
|
})
|
|
112
|
-
.on('resizeGroup', (
|
|
113
|
-
|
|
114
|
-
// 拖动过程更新
|
|
115
|
-
events.forEach((ev) => {
|
|
116
|
-
const { width, height, beforeTranslate } = ev.drag;
|
|
117
|
-
const frameSnapShot = frames.find(
|
|
118
|
-
(frameItem) => frameItem.id === ev.target.id.replace(DRAG_EL_ID_PREFIX, ''),
|
|
119
|
-
);
|
|
120
|
-
if (!frameSnapShot) return;
|
|
121
|
-
const targeEl = this.targetList.find(
|
|
122
|
-
(targetItem) => targetItem.id === ev.target.id.replace(DRAG_EL_ID_PREFIX, ''),
|
|
123
|
-
);
|
|
124
|
-
if (!targeEl) return;
|
|
125
|
-
// 元素与其所属组同时加入多选列表时,只更新父元素
|
|
126
|
-
const isParentIncluded = this.targetList.find((targetItem) => targetItem.id === targeEl.parentElement?.id);
|
|
127
|
-
if (!isParentIncluded) {
|
|
128
|
-
// 更新页面元素位置
|
|
129
|
-
targeEl.style.left = `${frameSnapShot.left + beforeTranslate[0]}px`;
|
|
130
|
-
targeEl.style.top = `${frameSnapShot.top + beforeTranslate[1]}px`;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// 更新页面元素位置
|
|
134
|
-
targeEl.style.width = `${width}px`;
|
|
135
|
-
targeEl.style.height = `${height}px`;
|
|
136
|
-
});
|
|
137
|
-
this.multiMoveableHelper?.onResizeGroup(params);
|
|
93
|
+
.on('resizeGroup', (e) => {
|
|
94
|
+
this.dragResizeHelper.onResizeGroup(e);
|
|
138
95
|
this.dragStatus = StageDragStatus.ING;
|
|
139
96
|
})
|
|
140
97
|
.on('resizeGroupEnd', () => {
|
|
141
98
|
this.update(true);
|
|
142
99
|
this.dragStatus = StageDragStatus.END;
|
|
143
100
|
})
|
|
144
|
-
.on('dragGroupStart', (
|
|
145
|
-
|
|
146
|
-
this.multiMoveableHelper?.onDragGroupStart(params);
|
|
147
|
-
// 记录拖动前快照
|
|
148
|
-
setFrames(events);
|
|
101
|
+
.on('dragGroupStart', (e) => {
|
|
102
|
+
this.dragResizeHelper.onDragGroupStart(e);
|
|
149
103
|
this.dragStatus = StageDragStatus.START;
|
|
150
104
|
})
|
|
151
|
-
.on('dragGroup', (
|
|
152
|
-
|
|
153
|
-
// 拖动过程更新
|
|
154
|
-
events.forEach((ev) => {
|
|
155
|
-
const frameSnapShot = frames.find(
|
|
156
|
-
(frameItem) => frameItem.id === ev.target.id.replace(DRAG_EL_ID_PREFIX, ''),
|
|
157
|
-
);
|
|
158
|
-
if (!frameSnapShot) return;
|
|
159
|
-
const targeEl = this.targetList.find(
|
|
160
|
-
(targetItem) => targetItem.id === ev.target.id.replace(DRAG_EL_ID_PREFIX, ''),
|
|
161
|
-
);
|
|
162
|
-
if (!targeEl) return;
|
|
163
|
-
// 元素与其所属组同时加入多选列表时,只更新父元素
|
|
164
|
-
const isParentIncluded = this.targetList.find((targetItem) => targetItem.id === targeEl.parentElement?.id);
|
|
165
|
-
if (!isParentIncluded) {
|
|
166
|
-
// 更新页面元素位置
|
|
167
|
-
targeEl.style.left = `${frameSnapShot.left + ev.beforeTranslate[0]}px`;
|
|
168
|
-
targeEl.style.top = `${frameSnapShot.top + ev.beforeTranslate[1]}px`;
|
|
169
|
-
}
|
|
170
|
-
});
|
|
171
|
-
this.multiMoveableHelper?.onDragGroup(params);
|
|
105
|
+
.on('dragGroup', (e) => {
|
|
106
|
+
this.dragResizeHelper.onDragGroup(e);
|
|
172
107
|
this.dragStatus = StageDragStatus.ING;
|
|
173
108
|
})
|
|
174
109
|
.on('dragGroupEnd', () => {
|
|
175
110
|
this.update();
|
|
176
111
|
this.dragStatus = StageDragStatus.END;
|
|
177
112
|
})
|
|
178
|
-
.on('clickGroup', (
|
|
179
|
-
const { inputTarget, targets } =
|
|
180
|
-
//
|
|
181
|
-
if (
|
|
182
|
-
this.emit('select', inputTarget.id.replace(DRAG_EL_ID_PREFIX, ''));
|
|
113
|
+
.on('clickGroup', (e) => {
|
|
114
|
+
const { inputTarget, targets } = e;
|
|
115
|
+
// 如果有多个元素被选中,同时点击的元素在选中元素中的其中一项,可能是多选态切换为该元素的单选态,抛事件给上一层继续判断是否切换
|
|
116
|
+
if (targets.length > 1 && targets.includes(inputTarget)) {
|
|
117
|
+
this.emit('change-to-select', inputTarget.id.replace(DRAG_EL_ID_PREFIX, ''));
|
|
183
118
|
}
|
|
184
119
|
});
|
|
185
120
|
}
|
|
186
121
|
|
|
187
|
-
public canSelect(el: HTMLElement,
|
|
188
|
-
// 多选状态下不可以选中magic-ui-page,并停止继续向上层选中
|
|
189
|
-
if (el.className.includes(PAGE_CLASS)) {
|
|
190
|
-
this.core.highlightedDom = undefined;
|
|
191
|
-
this.core.highlightLayer.clearHighlight();
|
|
192
|
-
stop();
|
|
193
|
-
return false;
|
|
194
|
-
}
|
|
122
|
+
public canSelect(el: HTMLElement, selectedEl: HTMLElement | undefined): boolean {
|
|
195
123
|
const currentTargetMode = getMode(el);
|
|
196
|
-
let
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
124
|
+
let selectedElMode = '';
|
|
125
|
+
|
|
126
|
+
// 流式布局不支持多选
|
|
127
|
+
if (currentTargetMode === Mode.SORTABLE) {
|
|
128
|
+
return false;
|
|
200
129
|
}
|
|
201
|
-
|
|
130
|
+
|
|
131
|
+
if (this.targetList.length === 0 && selectedEl) {
|
|
202
132
|
// 单选后添加到多选的情况
|
|
203
|
-
|
|
133
|
+
selectedElMode = getMode(selectedEl);
|
|
204
134
|
} else if (this.targetList.length > 0) {
|
|
205
135
|
// 已加入多选列表的布局模式是一样的,取第一个判断
|
|
206
|
-
|
|
136
|
+
selectedElMode = getMode(this.targetList[0]);
|
|
207
137
|
}
|
|
208
138
|
// 定位模式不同,不可混选
|
|
209
|
-
if (currentTargetMode !==
|
|
139
|
+
if (currentTargetMode !== selectedElMode) {
|
|
210
140
|
return false;
|
|
211
141
|
}
|
|
212
142
|
return true;
|
|
213
143
|
}
|
|
214
144
|
|
|
145
|
+
public updateMoveable(eleList = this.targetList) {
|
|
146
|
+
if (!this.moveableForMulti) return;
|
|
147
|
+
if (!eleList) throw new Error('未选中任何节点');
|
|
148
|
+
|
|
149
|
+
this.targetList = eleList;
|
|
150
|
+
this.dragResizeHelper.setTargetList(eleList);
|
|
151
|
+
|
|
152
|
+
const options = this.getOptions(true, {
|
|
153
|
+
target: this.dragResizeHelper.getShadowEls(),
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
Object.entries(options).forEach(([key, value]) => {
|
|
157
|
+
(this.moveableForMulti as any)[key] = value;
|
|
158
|
+
});
|
|
159
|
+
this.moveableForMulti.updateTarget();
|
|
160
|
+
}
|
|
161
|
+
|
|
215
162
|
/**
|
|
216
163
|
* 清除多选状态
|
|
217
164
|
*/
|
|
218
165
|
public clearSelectStatus(): void {
|
|
219
166
|
if (!this.moveableForMulti) return;
|
|
220
|
-
this.
|
|
167
|
+
this.dragResizeHelper.clearMultiSelectStatus();
|
|
221
168
|
this.moveableForMulti.target = null;
|
|
222
169
|
this.moveableForMulti.updateTarget();
|
|
223
170
|
this.targetList = [];
|
|
@@ -228,14 +175,7 @@ export default class StageMultiDragResize extends EventEmitter {
|
|
|
228
175
|
*/
|
|
229
176
|
public destroy(): void {
|
|
230
177
|
this.moveableForMulti?.destroy();
|
|
231
|
-
this.
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
/**
|
|
235
|
-
* 清除蒙层占位节点
|
|
236
|
-
*/
|
|
237
|
-
public destroyDragElList(): void {
|
|
238
|
-
this.dragElList.forEach((dragElItem) => dragElItem?.remove());
|
|
178
|
+
this.dragResizeHelper.destroy();
|
|
239
179
|
}
|
|
240
180
|
|
|
241
181
|
/**
|
|
@@ -245,60 +185,19 @@ export default class StageMultiDragResize extends EventEmitter {
|
|
|
245
185
|
private update(isResize = false): void {
|
|
246
186
|
if (this.targetList.length === 0) return;
|
|
247
187
|
|
|
248
|
-
const
|
|
249
|
-
const doc = contentWindow?.document;
|
|
188
|
+
const doc = this.getRenderDocument();
|
|
250
189
|
if (!doc) return;
|
|
251
190
|
|
|
252
|
-
this.
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
style: isResize ? { left, top, width, height } : { left, top },
|
|
262
|
-
};
|
|
263
|
-
}),
|
|
264
|
-
parentEl: null,
|
|
191
|
+
const data = this.targetList.map((targetItem) => {
|
|
192
|
+
const left = calcValueByFontsize(doc, targetItem.offsetLeft);
|
|
193
|
+
const top = calcValueByFontsize(doc, targetItem.offsetTop);
|
|
194
|
+
const width = calcValueByFontsize(doc, targetItem.clientWidth);
|
|
195
|
+
const height = calcValueByFontsize(doc, targetItem.clientHeight);
|
|
196
|
+
return {
|
|
197
|
+
el: targetItem,
|
|
198
|
+
style: isResize ? { left, top, width, height } : { left, top },
|
|
199
|
+
};
|
|
265
200
|
});
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
/**
|
|
269
|
-
* 获取moveable options参数
|
|
270
|
-
* @param {MoveableOptions} options
|
|
271
|
-
* @return {MoveableOptions} moveable options参数
|
|
272
|
-
*/
|
|
273
|
-
private getOptions(options: MoveableOptions = {}): MoveableOptions {
|
|
274
|
-
let { multiMoveableOptions = {} } = this.core.config;
|
|
275
|
-
|
|
276
|
-
if (typeof multiMoveableOptions === 'function') {
|
|
277
|
-
multiMoveableOptions = multiMoveableOptions(this.core);
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
return {
|
|
281
|
-
defaultGroupRotate: 0,
|
|
282
|
-
defaultGroupOrigin: '50% 50%',
|
|
283
|
-
draggable: true,
|
|
284
|
-
resizable: true,
|
|
285
|
-
throttleDrag: 0,
|
|
286
|
-
startDragRotate: 0,
|
|
287
|
-
throttleDragRotate: 0,
|
|
288
|
-
zoom: 1,
|
|
289
|
-
origin: true,
|
|
290
|
-
padding: { left: 0, top: 0, right: 0, bottom: 0 },
|
|
291
|
-
snappable: true,
|
|
292
|
-
bounds: {
|
|
293
|
-
top: 0,
|
|
294
|
-
// 设置0的话无法移动到left为0,所以只能设置为-1
|
|
295
|
-
left: -1,
|
|
296
|
-
right: this.container.clientWidth - 1,
|
|
297
|
-
bottom: this.container.clientHeight,
|
|
298
|
-
...(multiMoveableOptions.bounds || {}),
|
|
299
|
-
},
|
|
300
|
-
...options,
|
|
301
|
-
...multiMoveableOptions,
|
|
302
|
-
};
|
|
201
|
+
this.emit('update', data, null);
|
|
303
202
|
}
|
|
304
203
|
}
|