@tmagic/stage 1.0.0-beta.8 → 1.0.0-rc.10
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 +1 -0
- package/dist/tmagic-stage.es.js +609 -273
- package/dist/tmagic-stage.es.js.map +1 -1
- package/dist/tmagic-stage.umd.js +613 -279
- package/dist/tmagic-stage.umd.js.map +1 -1
- package/dist/types/src/StageCore.d.ts +14 -4
- package/dist/types/src/StageDragResize.d.ts +22 -7
- package/dist/types/src/StageHighlight.d.ts +27 -0
- package/dist/types/src/StageMask.d.ts +23 -0
- package/dist/types/src/TargetCalibrate.d.ts +20 -0
- package/dist/types/src/const.d.ts +28 -1
- package/dist/types/src/types.d.ts +25 -5
- package/dist/types/src/util.d.ts +4 -1
- package/package.json +13 -8
- package/src/Rule.ts +13 -5
- package/src/StageCore.ts +90 -24
- package/src/StageDragResize.ts +239 -99
- package/src/StageHighlight.ts +82 -0
- package/src/StageMask.ts +106 -26
- package/src/StageRender.ts +1 -0
- package/src/TargetCalibrate.ts +119 -0
- package/src/const.ts +31 -2
- package/src/types.ts +27 -5
- package/src/util.ts +53 -28
- package/LICENSE +0 -5432
- package/tsconfig.json +0 -9
- package/vite.config.ts +0 -27
package/src/StageDragResize.ts
CHANGED
|
@@ -21,15 +21,20 @@ import { EventEmitter } from 'events';
|
|
|
21
21
|
|
|
22
22
|
import type { MoveableOptions } from 'moveable';
|
|
23
23
|
import Moveable from 'moveable';
|
|
24
|
+
import MoveableHelper from 'moveable-helper';
|
|
24
25
|
|
|
25
|
-
import { GHOST_EL_ID_PREFIX, GuidesType, Mode } from './const';
|
|
26
|
+
import { DRAG_EL_ID_PREFIX, GHOST_EL_ID_PREFIX, GuidesType, Mode, ZIndex } from './const';
|
|
26
27
|
import StageCore from './StageCore';
|
|
27
28
|
import type { SortEventData, StageDragResizeConfig } from './types';
|
|
28
|
-
import { getAbsolutePosition, getMode, getOffset } from './util';
|
|
29
|
+
import { getAbsolutePosition, getGuideLineFromCache, getMode, getOffset } from './util';
|
|
29
30
|
|
|
31
|
+
/** 拖动状态 */
|
|
30
32
|
enum ActionStatus {
|
|
33
|
+
/** 开始拖动 */
|
|
31
34
|
START = 'start',
|
|
35
|
+
/** 拖动中 */
|
|
32
36
|
ING = 'ing',
|
|
37
|
+
/** 拖动结束 */
|
|
33
38
|
END = 'end',
|
|
34
39
|
}
|
|
35
40
|
|
|
@@ -38,23 +43,38 @@ enum ActionStatus {
|
|
|
38
43
|
*/
|
|
39
44
|
export default class StageDragResize extends EventEmitter {
|
|
40
45
|
public core: StageCore;
|
|
46
|
+
/** 画布容器 */
|
|
41
47
|
public container: HTMLElement;
|
|
48
|
+
/** 目标节点 */
|
|
42
49
|
public target?: HTMLElement;
|
|
43
|
-
|
|
50
|
+
/** 目标节点在蒙层中的占位节点 */
|
|
51
|
+
public dragEl: HTMLDivElement;
|
|
52
|
+
/** Moveable拖拽类实例 */
|
|
44
53
|
public moveable?: Moveable;
|
|
45
|
-
|
|
46
|
-
public
|
|
54
|
+
/** 水平参考线 */
|
|
55
|
+
public horizontalGuidelines: number[] = getGuideLineFromCache(GuidesType.HORIZONTAL);
|
|
56
|
+
/** 垂直参考线 */
|
|
57
|
+
public verticalGuidelines: number[] = getGuideLineFromCache(GuidesType.VERTICAL);
|
|
58
|
+
/** 对齐元素集合 */
|
|
59
|
+
public elementGuidelines: HTMLElement[] = [];
|
|
60
|
+
/** 布局方式:流式布局、绝对定位、固定定位 */
|
|
61
|
+
public mode: Mode = Mode.ABSOLUTE;
|
|
47
62
|
|
|
48
63
|
private moveableOptions: MoveableOptions = {};
|
|
64
|
+
/** 拖动状态 */
|
|
49
65
|
private dragStatus: ActionStatus = ActionStatus.END;
|
|
66
|
+
/** 流式布局下,目标节点的镜像节点 */
|
|
50
67
|
private ghostEl: HTMLElement | undefined;
|
|
51
|
-
private
|
|
68
|
+
private moveableHelper?: MoveableHelper;
|
|
52
69
|
|
|
53
70
|
constructor(config: StageDragResizeConfig) {
|
|
54
71
|
super();
|
|
55
72
|
|
|
56
73
|
this.core = config.core;
|
|
57
74
|
this.container = config.container;
|
|
75
|
+
|
|
76
|
+
this.dragEl = globalThis.document.createElement('div');
|
|
77
|
+
this.container.append(this.dragEl);
|
|
58
78
|
}
|
|
59
79
|
|
|
60
80
|
/**
|
|
@@ -63,23 +83,23 @@ export default class StageDragResize extends EventEmitter {
|
|
|
63
83
|
* @param el 选中组件的Dom节点元素
|
|
64
84
|
* @param event 鼠标事件
|
|
65
85
|
*/
|
|
66
|
-
public
|
|
86
|
+
public select(el: HTMLElement, event?: MouseEvent): void {
|
|
87
|
+
const oldTarget = this.target;
|
|
67
88
|
this.target = el;
|
|
68
|
-
// 如果有滚动条会导致resize时获取到width,height不准确
|
|
69
|
-
if (/(auto|scroll)/.test(this.target.style.overflow)) {
|
|
70
|
-
this.target.style.overflow = 'hidden';
|
|
71
|
-
}
|
|
72
|
-
this.mode = getMode(el);
|
|
73
|
-
this.destroyDragEl();
|
|
74
|
-
this.destroyGhostEl();
|
|
75
89
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
90
|
+
// 从不能拖动到能拖动的节点之间切换,要重新创建moveable,不然dragStart不生效
|
|
91
|
+
if (!this.moveable || this.target !== oldTarget) {
|
|
92
|
+
this.init(el);
|
|
93
|
+
this.moveableHelper = MoveableHelper.create({
|
|
94
|
+
useBeforeRender: true,
|
|
95
|
+
useRender: false,
|
|
96
|
+
createAuto: true,
|
|
97
|
+
});
|
|
81
98
|
|
|
82
|
-
|
|
99
|
+
this.initMoveable();
|
|
100
|
+
} else {
|
|
101
|
+
this.updateMoveable();
|
|
102
|
+
}
|
|
83
103
|
|
|
84
104
|
if (event) {
|
|
85
105
|
this.moveable?.dragStart(event);
|
|
@@ -89,11 +109,15 @@ export default class StageDragResize extends EventEmitter {
|
|
|
89
109
|
/**
|
|
90
110
|
* 初始化选中框并渲染出来
|
|
91
111
|
*/
|
|
92
|
-
public
|
|
112
|
+
public updateMoveable(el = this.target): void {
|
|
93
113
|
if (!this.moveable) throw new Error('未初始化moveable');
|
|
114
|
+
if (!el) throw new Error('为选中任何节点');
|
|
94
115
|
|
|
95
|
-
|
|
96
|
-
|
|
116
|
+
this.target = el;
|
|
117
|
+
|
|
118
|
+
this.init(el);
|
|
119
|
+
|
|
120
|
+
Object.entries(this.moveableOptions).forEach(([key, value]) => {
|
|
97
121
|
(this.moveable as any)[key] = value;
|
|
98
122
|
});
|
|
99
123
|
this.moveable.updateTarget();
|
|
@@ -102,17 +126,21 @@ export default class StageDragResize extends EventEmitter {
|
|
|
102
126
|
public setGuidelines(type: GuidesType, guidelines: number[]): void {
|
|
103
127
|
if (type === GuidesType.HORIZONTAL) {
|
|
104
128
|
this.horizontalGuidelines = guidelines;
|
|
129
|
+
this.moveableOptions.horizontalGuidelines = guidelines;
|
|
105
130
|
} else if (type === GuidesType.VERTICAL) {
|
|
106
131
|
this.verticalGuidelines = guidelines;
|
|
132
|
+
this.moveableOptions.verticalGuidelines = guidelines;
|
|
107
133
|
}
|
|
108
134
|
|
|
109
|
-
this.
|
|
135
|
+
this.updateMoveable();
|
|
110
136
|
}
|
|
111
137
|
|
|
112
138
|
public clearGuides() {
|
|
113
|
-
this.verticalGuidelines = [];
|
|
114
139
|
this.horizontalGuidelines = [];
|
|
115
|
-
this.
|
|
140
|
+
this.verticalGuidelines = [];
|
|
141
|
+
this.moveableOptions.horizontalGuidelines = [];
|
|
142
|
+
this.moveableOptions.verticalGuidelines = [];
|
|
143
|
+
this.updateMoveable();
|
|
116
144
|
}
|
|
117
145
|
|
|
118
146
|
/**
|
|
@@ -126,6 +154,45 @@ export default class StageDragResize extends EventEmitter {
|
|
|
126
154
|
this.removeAllListeners();
|
|
127
155
|
}
|
|
128
156
|
|
|
157
|
+
private init(el: HTMLElement): void {
|
|
158
|
+
// 如果有滚动条会导致resize时获取到width,height不准确
|
|
159
|
+
if (/(auto|scroll)/.test(el.style.overflow)) {
|
|
160
|
+
el.style.overflow = 'hidden';
|
|
161
|
+
}
|
|
162
|
+
this.mode = getMode(el);
|
|
163
|
+
|
|
164
|
+
this.destroyGhostEl();
|
|
165
|
+
|
|
166
|
+
this.updateDragEl(el);
|
|
167
|
+
|
|
168
|
+
this.moveableOptions = this.getOptions({
|
|
169
|
+
target: this.dragEl,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
private setElementGuidelines(nodes: HTMLElement[]) {
|
|
174
|
+
this.elementGuidelines.forEach((node) => {
|
|
175
|
+
node.remove();
|
|
176
|
+
});
|
|
177
|
+
this.elementGuidelines = [];
|
|
178
|
+
|
|
179
|
+
if (this.mode === Mode.ABSOLUTE) {
|
|
180
|
+
const frame = document.createDocumentFragment();
|
|
181
|
+
|
|
182
|
+
for (const node of nodes) {
|
|
183
|
+
const { width, height } = node.getBoundingClientRect();
|
|
184
|
+
if (node === this.target) continue;
|
|
185
|
+
const { left, top } = getOffset(node as HTMLElement);
|
|
186
|
+
const elementGuideline = document.createElement('div');
|
|
187
|
+
elementGuideline.style.cssText = `position: absolute;width: ${width}px;height: ${height}px;top: ${top}px;left: ${left}px`;
|
|
188
|
+
this.elementGuidelines.push(elementGuideline);
|
|
189
|
+
frame.append(elementGuideline);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
this.container.append(frame);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
129
196
|
private initMoveable() {
|
|
130
197
|
this.moveable?.destroy();
|
|
131
198
|
|
|
@@ -135,49 +202,47 @@ export default class StageDragResize extends EventEmitter {
|
|
|
135
202
|
|
|
136
203
|
this.bindResizeEvent();
|
|
137
204
|
this.bindDragEvent();
|
|
205
|
+
this.bindRotateEvent();
|
|
206
|
+
this.bindScaleEvent();
|
|
138
207
|
}
|
|
139
208
|
|
|
140
209
|
private bindResizeEvent(): void {
|
|
141
210
|
if (!this.moveable) throw new Error('moveable 为初始化');
|
|
142
211
|
|
|
143
212
|
const frame = {
|
|
144
|
-
|
|
213
|
+
left: 0,
|
|
214
|
+
top: 0,
|
|
145
215
|
};
|
|
146
216
|
|
|
147
217
|
this.moveable
|
|
148
218
|
.on('resizeStart', (e) => {
|
|
149
|
-
if (
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
219
|
+
if (!this.target) return;
|
|
220
|
+
|
|
221
|
+
this.dragStatus = ActionStatus.START;
|
|
222
|
+
this.moveableHelper?.onResizeStart(e);
|
|
223
|
+
|
|
224
|
+
frame.top = this.target.offsetTop;
|
|
225
|
+
frame.left = this.target.offsetLeft;
|
|
154
226
|
})
|
|
155
|
-
.on('resize', (
|
|
227
|
+
.on('resize', (e) => {
|
|
228
|
+
const { width, height, drag } = e;
|
|
156
229
|
if (!this.moveable || !this.target || !this.dragEl) return;
|
|
157
230
|
|
|
158
231
|
const { beforeTranslate } = drag;
|
|
159
|
-
frame.translate = beforeTranslate;
|
|
160
232
|
this.dragStatus = ActionStatus.ING;
|
|
161
233
|
|
|
162
|
-
this.
|
|
163
|
-
this.target.style.height = `${height}px`;
|
|
164
|
-
this.dragEl.style.width = `${width}px`;
|
|
165
|
-
this.dragEl.style.height = `${height}px`;
|
|
234
|
+
this.moveableHelper?.onResize(e);
|
|
166
235
|
|
|
167
236
|
// 流式布局
|
|
168
237
|
if (this.mode === Mode.SORTABLE) {
|
|
169
|
-
this.
|
|
170
|
-
|
|
171
|
-
|
|
238
|
+
this.target.style.top = '0px';
|
|
239
|
+
} else {
|
|
240
|
+
this.target.style.left = `${frame.left + beforeTranslate[0]}px`;
|
|
241
|
+
this.target.style.top = `${frame.top + beforeTranslate[1]}px`;
|
|
172
242
|
}
|
|
173
243
|
|
|
174
|
-
this.
|
|
175
|
-
this.
|
|
176
|
-
|
|
177
|
-
const offset = getAbsolutePosition(this.target, { left: beforeTranslate[0], top: beforeTranslate[1] });
|
|
178
|
-
|
|
179
|
-
this.target.style.left = `${offset.left}px`;
|
|
180
|
-
this.target.style.top = `${offset.top}px`;
|
|
244
|
+
this.target.style.width = `${width}px`;
|
|
245
|
+
this.target.style.height = `${height}px`;
|
|
181
246
|
})
|
|
182
247
|
.on('resizeEnd', () => {
|
|
183
248
|
this.dragStatus = ActionStatus.END;
|
|
@@ -188,34 +253,41 @@ export default class StageDragResize extends EventEmitter {
|
|
|
188
253
|
private bindDragEvent(): void {
|
|
189
254
|
if (!this.moveable) throw new Error('moveable 为初始化');
|
|
190
255
|
|
|
256
|
+
const frame = {
|
|
257
|
+
left: 0,
|
|
258
|
+
top: 0,
|
|
259
|
+
};
|
|
260
|
+
|
|
191
261
|
this.moveable
|
|
192
|
-
.on('dragStart', () => {
|
|
262
|
+
.on('dragStart', (e) => {
|
|
193
263
|
if (!this.target) throw new Error('未选中组件');
|
|
194
264
|
|
|
195
265
|
this.dragStatus = ActionStatus.START;
|
|
196
266
|
|
|
267
|
+
this.moveableHelper?.onDragStart(e);
|
|
268
|
+
|
|
197
269
|
if (this.mode === Mode.SORTABLE) {
|
|
198
270
|
this.ghostEl = this.generateGhostEl(this.target);
|
|
199
271
|
}
|
|
272
|
+
|
|
273
|
+
frame.top = this.target.offsetTop;
|
|
274
|
+
frame.left = this.target.offsetLeft;
|
|
200
275
|
})
|
|
201
|
-
.on('drag', (
|
|
276
|
+
.on('drag', (e) => {
|
|
202
277
|
if (!this.target || !this.dragEl) return;
|
|
203
|
-
this.dragStatus = ActionStatus.ING;
|
|
204
278
|
|
|
205
|
-
|
|
279
|
+
this.dragStatus = ActionStatus.ING;
|
|
206
280
|
|
|
207
281
|
// 流式布局
|
|
208
282
|
if (this.ghostEl) {
|
|
209
|
-
this.
|
|
210
|
-
this.ghostEl.style.top = `${offset.top}px`;
|
|
283
|
+
this.ghostEl.style.top = `${frame.top + e.beforeTranslate[1]}px`;
|
|
211
284
|
return;
|
|
212
285
|
}
|
|
213
286
|
|
|
214
|
-
this.
|
|
215
|
-
this.dragEl.style.top = `${top}px`;
|
|
287
|
+
this.moveableHelper?.onDrag(e);
|
|
216
288
|
|
|
217
|
-
this.target.style.left = `${
|
|
218
|
-
this.target.style.top = `${
|
|
289
|
+
this.target.style.left = `${frame.left + e.beforeTranslate[0]}px`;
|
|
290
|
+
this.target.style.top = `${frame.top + e.beforeTranslate[1]}px`;
|
|
219
291
|
})
|
|
220
292
|
.on('dragEnd', () => {
|
|
221
293
|
// 点击不拖动时会触发dragStart和dragEnd,但是不会有drag事件
|
|
@@ -234,19 +306,58 @@ export default class StageDragResize extends EventEmitter {
|
|
|
234
306
|
});
|
|
235
307
|
}
|
|
236
308
|
|
|
237
|
-
private
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
(() => {
|
|
242
|
-
|
|
243
|
-
|
|
309
|
+
private bindRotateEvent(): void {
|
|
310
|
+
if (!this.moveable) throw new Error('moveable 为初始化');
|
|
311
|
+
|
|
312
|
+
this.moveable
|
|
313
|
+
.on('rotateStart', (e) => {
|
|
314
|
+
this.dragStatus = ActionStatus.START;
|
|
315
|
+
this.moveableHelper?.onRotateStart(e);
|
|
316
|
+
})
|
|
317
|
+
.on('rotate', (e) => {
|
|
318
|
+
if (!this.target || !this.dragEl) return;
|
|
319
|
+
this.dragStatus = ActionStatus.ING;
|
|
320
|
+
this.moveableHelper?.onRotate(e);
|
|
321
|
+
const frame = this.moveableHelper?.getFrame(e.target);
|
|
322
|
+
this.target.style.transform = frame?.toCSSObject().transform || '';
|
|
323
|
+
})
|
|
324
|
+
.on('rotateEnd', (e) => {
|
|
325
|
+
this.dragStatus = ActionStatus.END;
|
|
326
|
+
const frame = this.moveableHelper?.getFrame(e.target);
|
|
327
|
+
this.emit('update', {
|
|
328
|
+
el: this.target,
|
|
329
|
+
style: {
|
|
330
|
+
transform: frame?.get('transform'),
|
|
331
|
+
},
|
|
332
|
+
});
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
private bindScaleEvent(): void {
|
|
337
|
+
if (!this.moveable) throw new Error('moveable 为初始化');
|
|
338
|
+
|
|
339
|
+
this.moveable
|
|
340
|
+
.on('scaleStart', (e) => {
|
|
341
|
+
this.dragStatus = ActionStatus.START;
|
|
342
|
+
this.moveableHelper?.onScaleStart(e);
|
|
343
|
+
})
|
|
344
|
+
.on('scale', (e) => {
|
|
345
|
+
if (!this.target || !this.dragEl) return;
|
|
346
|
+
this.dragStatus = ActionStatus.ING;
|
|
347
|
+
this.moveableHelper?.onScale(e);
|
|
348
|
+
const frame = this.moveableHelper?.getFrame(e.target);
|
|
349
|
+
this.target.style.transform = frame?.toCSSObject().transform || '';
|
|
350
|
+
})
|
|
351
|
+
.on('scaleEnd', (e) => {
|
|
352
|
+
this.dragStatus = ActionStatus.END;
|
|
353
|
+
const frame = this.moveableHelper?.getFrame(e.target);
|
|
354
|
+
this.emit('update', {
|
|
355
|
+
el: this.target,
|
|
356
|
+
style: {
|
|
357
|
+
transform: frame?.get('transform'),
|
|
358
|
+
},
|
|
359
|
+
});
|
|
244
360
|
});
|
|
245
|
-
return (
|
|
246
|
-
getSnapElements(el)
|
|
247
|
-
// 排除掉当前组件本身
|
|
248
|
-
.filter((element) => element !== this.target && !this.target?.contains(element))
|
|
249
|
-
);
|
|
250
361
|
}
|
|
251
362
|
|
|
252
363
|
private sort(): void {
|
|
@@ -269,14 +380,15 @@ export default class StageDragResize extends EventEmitter {
|
|
|
269
380
|
}
|
|
270
381
|
|
|
271
382
|
private update(isResize = false): void {
|
|
272
|
-
|
|
383
|
+
if (!this.target) return;
|
|
384
|
+
|
|
273
385
|
const offset =
|
|
274
|
-
this.mode === Mode.SORTABLE ? { left: 0, top: 0 } :
|
|
386
|
+
this.mode === Mode.SORTABLE ? { left: 0, top: 0 } : { left: this.target.offsetLeft, top: this.target.offsetTop };
|
|
275
387
|
|
|
276
388
|
const left = this.calcValueByFontsize(offset.left);
|
|
277
389
|
const top = this.calcValueByFontsize(offset.top);
|
|
278
|
-
const width = this.calcValueByFontsize(
|
|
279
|
-
const height = this.calcValueByFontsize(
|
|
390
|
+
const width = this.calcValueByFontsize(this.target.clientWidth);
|
|
391
|
+
const height = this.calcValueByFontsize(this.target.clientHeight);
|
|
280
392
|
|
|
281
393
|
this.emit('update', {
|
|
282
394
|
el: this.target,
|
|
@@ -291,8 +403,8 @@ export default class StageDragResize extends EventEmitter {
|
|
|
291
403
|
|
|
292
404
|
const ghostEl = el.cloneNode(true) as HTMLElement;
|
|
293
405
|
const { top, left } = getAbsolutePosition(el, getOffset(el));
|
|
294
|
-
ghostEl.id = `${GHOST_EL_ID_PREFIX}${
|
|
295
|
-
ghostEl.style.zIndex =
|
|
406
|
+
ghostEl.id = `${GHOST_EL_ID_PREFIX}${el.id}`;
|
|
407
|
+
ghostEl.style.zIndex = ZIndex.GHOST_EL;
|
|
296
408
|
ghostEl.style.opacity = '.5';
|
|
297
409
|
ghostEl.style.position = 'absolute';
|
|
298
410
|
ghostEl.style.left = `${left}px`;
|
|
@@ -306,34 +418,36 @@ export default class StageDragResize extends EventEmitter {
|
|
|
306
418
|
this.ghostEl = undefined;
|
|
307
419
|
}
|
|
308
420
|
|
|
309
|
-
private
|
|
310
|
-
if (this.dragEl) {
|
|
311
|
-
this.destroyDragEl();
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
const { width, height } = el.getBoundingClientRect();
|
|
421
|
+
private updateDragEl(el: HTMLElement) {
|
|
315
422
|
const offset = getOffset(el);
|
|
316
|
-
const
|
|
317
|
-
|
|
423
|
+
const { transform } = getComputedStyle(el);
|
|
424
|
+
|
|
425
|
+
this.dragEl.style.cssText = `
|
|
318
426
|
position: absolute;
|
|
427
|
+
transform: ${transform};
|
|
319
428
|
left: ${offset.left}px;
|
|
320
429
|
top: ${offset.top}px;
|
|
321
|
-
width: ${
|
|
322
|
-
height: ${
|
|
430
|
+
width: ${el.clientWidth}px;
|
|
431
|
+
height: ${el.clientHeight}px;
|
|
432
|
+
z-index: ${ZIndex.DRAG_EL};
|
|
323
433
|
`;
|
|
324
|
-
|
|
325
|
-
|
|
434
|
+
|
|
435
|
+
this.dragEl.id = `${DRAG_EL_ID_PREFIX}${el.id}`;
|
|
436
|
+
|
|
437
|
+
if (typeof this.core.config.updateDragEl === 'function') {
|
|
438
|
+
this.core.config.updateDragEl(this.dragEl, el);
|
|
439
|
+
}
|
|
326
440
|
}
|
|
327
441
|
|
|
328
442
|
private destroyDragEl(): void {
|
|
329
443
|
this.dragEl?.remove();
|
|
330
|
-
this.dragEl = undefined;
|
|
331
444
|
}
|
|
332
445
|
|
|
333
|
-
private
|
|
446
|
+
private getOptions(options: MoveableOptions = {}): MoveableOptions {
|
|
334
447
|
if (!this.target) return {};
|
|
335
448
|
|
|
336
449
|
const isAbsolute = this.mode === Mode.ABSOLUTE;
|
|
450
|
+
const isFixed = this.mode === Mode.FIXED;
|
|
337
451
|
|
|
338
452
|
let { moveableOptions = {} } = this.core.config;
|
|
339
453
|
|
|
@@ -341,21 +455,47 @@ export default class StageDragResize extends EventEmitter {
|
|
|
341
455
|
moveableOptions = moveableOptions(this.core);
|
|
342
456
|
}
|
|
343
457
|
|
|
458
|
+
const elementGuidelines: any = moveableOptions.elementGuidelines || this.target.parentElement?.children || [];
|
|
459
|
+
|
|
460
|
+
this.setElementGuidelines(elementGuidelines);
|
|
461
|
+
|
|
462
|
+
if (moveableOptions.elementGuidelines) {
|
|
463
|
+
delete moveableOptions.elementGuidelines;
|
|
464
|
+
}
|
|
465
|
+
|
|
344
466
|
return {
|
|
345
|
-
|
|
346
|
-
|
|
467
|
+
origin: false,
|
|
468
|
+
rootContainer: this.core.container,
|
|
347
469
|
zoom: 1,
|
|
348
|
-
dragArea:
|
|
470
|
+
dragArea: false,
|
|
349
471
|
draggable: true,
|
|
350
472
|
resizable: true,
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
473
|
+
scalable: false,
|
|
474
|
+
rotatable: false,
|
|
475
|
+
snappable: isAbsolute || isFixed,
|
|
476
|
+
snapGap: isAbsolute || isFixed,
|
|
477
|
+
snapThreshold: 5,
|
|
478
|
+
snapDigit: 0,
|
|
479
|
+
throttleDrag: 0,
|
|
480
|
+
isDisplaySnapDigit: isAbsolute,
|
|
481
|
+
snapDirections: {
|
|
482
|
+
top: isAbsolute,
|
|
483
|
+
right: isAbsolute,
|
|
484
|
+
bottom: isAbsolute,
|
|
485
|
+
left: isAbsolute,
|
|
486
|
+
center: isAbsolute,
|
|
487
|
+
middle: isAbsolute,
|
|
488
|
+
},
|
|
489
|
+
elementSnapDirections: {
|
|
490
|
+
top: isAbsolute,
|
|
491
|
+
right: isAbsolute,
|
|
492
|
+
bottom: isAbsolute,
|
|
493
|
+
left: isAbsolute,
|
|
494
|
+
},
|
|
495
|
+
isDisplayInnerSnapDigit: true,
|
|
357
496
|
horizontalGuidelines: this.horizontalGuidelines,
|
|
358
497
|
verticalGuidelines: this.verticalGuidelines,
|
|
498
|
+
elementGuidelines: this.elementGuidelines,
|
|
359
499
|
|
|
360
500
|
bounds: {
|
|
361
501
|
top: 0,
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
|
3
|
+
*
|
|
4
|
+
* Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved.
|
|
5
|
+
*
|
|
6
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
* you may not use this file except in compliance with the License.
|
|
8
|
+
* You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
* See the License for the specific language governing permissions and
|
|
16
|
+
* limitations under the License.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/* eslint-disable no-param-reassign */
|
|
20
|
+
import { EventEmitter } from 'events';
|
|
21
|
+
|
|
22
|
+
import Moveable from 'moveable';
|
|
23
|
+
|
|
24
|
+
import { HIGHLIGHT_EL_ID_PREFIX } from './const';
|
|
25
|
+
import StageCore from './StageCore';
|
|
26
|
+
import TargetCalibrate from './TargetCalibrate';
|
|
27
|
+
import type { StageHighlightConfig } from './types';
|
|
28
|
+
export default class StageHighlight extends EventEmitter {
|
|
29
|
+
public core: StageCore;
|
|
30
|
+
public container: HTMLElement;
|
|
31
|
+
public target?: HTMLElement;
|
|
32
|
+
public moveable?: Moveable;
|
|
33
|
+
public calibrationTarget: TargetCalibrate;
|
|
34
|
+
|
|
35
|
+
constructor(config: StageHighlightConfig) {
|
|
36
|
+
super();
|
|
37
|
+
|
|
38
|
+
this.core = config.core;
|
|
39
|
+
this.container = config.container;
|
|
40
|
+
this.calibrationTarget = new TargetCalibrate({
|
|
41
|
+
parent: this.core.mask.content,
|
|
42
|
+
mask: this.core.mask,
|
|
43
|
+
dr: this.core.dr,
|
|
44
|
+
core: this.core,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* 高亮鼠标悬停的组件
|
|
50
|
+
* @param el 选中组件的Dom节点元素
|
|
51
|
+
*/
|
|
52
|
+
public highlight(el: HTMLElement): void {
|
|
53
|
+
if (!el || el === this.target) return;
|
|
54
|
+
this.target = el;
|
|
55
|
+
this.moveable?.destroy();
|
|
56
|
+
|
|
57
|
+
this.moveable = new Moveable(this.container, {
|
|
58
|
+
target: this.calibrationTarget.update(el, HIGHLIGHT_EL_ID_PREFIX),
|
|
59
|
+
origin: false,
|
|
60
|
+
rootContainer: this.core.container,
|
|
61
|
+
zoom: 1,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* 清空高亮
|
|
67
|
+
*/
|
|
68
|
+
public clearHighlight(): void {
|
|
69
|
+
if (!this.moveable) return;
|
|
70
|
+
this.target = undefined;
|
|
71
|
+
this.moveable.target = null;
|
|
72
|
+
this.moveable.updateTarget();
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* 销毁实例
|
|
77
|
+
*/
|
|
78
|
+
public destroy(): void {
|
|
79
|
+
this.moveable?.destroy();
|
|
80
|
+
this.calibrationTarget.destroy();
|
|
81
|
+
}
|
|
82
|
+
}
|