@leafer-in/editor 1.7.0 → 1.8.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.
- package/dist/editor.cjs +164 -111
- package/dist/editor.esm.js +164 -111
- package/dist/editor.esm.min.js +1 -1
- package/dist/editor.esm.min.js.map +1 -1
- package/dist/editor.js +164 -111
- package/dist/editor.min.cjs +1 -1
- package/dist/editor.min.cjs.map +1 -1
- package/dist/editor.min.js +1 -1
- package/dist/editor.min.js.map +1 -1
- package/package.json +6 -6
- package/src/Editor.ts +31 -23
- package/src/decorator/data.ts +4 -2
- package/src/display/EditBox.ts +103 -45
- package/src/display/EditSelect.ts +4 -4
- package/src/display/Stroker.ts +4 -3
- package/src/editor/cursor.ts +9 -6
- package/src/editor/target.ts +2 -1
- package/src/helper/EditDataHelper.ts +12 -8
- package/src/index.ts +1 -1
- package/src/tool/TransformTool.ts +12 -24
- package/types/index.d.ts +40 -26
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@leafer-in/editor",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.0",
|
|
4
4
|
"description": "@leafer-in/editor",
|
|
5
5
|
"author": "Chao (Leafer) Wan",
|
|
6
6
|
"license": "MIT",
|
|
@@ -34,10 +34,10 @@
|
|
|
34
34
|
"leaferjs"
|
|
35
35
|
],
|
|
36
36
|
"peerDependencies": {
|
|
37
|
-
"@leafer-ui/draw": "^1.
|
|
38
|
-
"@leafer-ui/core": "^1.
|
|
39
|
-
"@leafer-in/resize": "^1.
|
|
40
|
-
"@leafer-ui/interface": "^1.
|
|
41
|
-
"@leafer-in/interface": "^1.
|
|
37
|
+
"@leafer-ui/draw": "^1.8.0",
|
|
38
|
+
"@leafer-ui/core": "^1.8.0",
|
|
39
|
+
"@leafer-in/resize": "^1.8.0",
|
|
40
|
+
"@leafer-ui/interface": "^1.8.0",
|
|
41
|
+
"@leafer-in/interface": "^1.8.0"
|
|
42
42
|
}
|
|
43
43
|
}
|
package/src/Editor.ts
CHANGED
|
@@ -52,9 +52,15 @@ export class Editor extends Group implements IEditor {
|
|
|
52
52
|
public get multiple(): boolean { return this.list.length > 1 }
|
|
53
53
|
public get single(): boolean { return this.list.length === 1 }
|
|
54
54
|
|
|
55
|
+
public get dragPoint(): IEditPoint { return this.editBox.dragPoint }
|
|
56
|
+
|
|
55
57
|
public get dragging(): boolean { return this.editBox.dragging }
|
|
58
|
+
public get gesturing(): boolean { return this.editBox.gesturing } // 手势操作元素中
|
|
59
|
+
|
|
56
60
|
public get moving(): boolean { return this.editBox.moving }
|
|
57
|
-
public get
|
|
61
|
+
public get resizing(): boolean { return this.editBox.resizing }
|
|
62
|
+
public get rotating(): boolean { return this.editBox.rotating }
|
|
63
|
+
public get skewing(): boolean { return this.editBox.skewing }
|
|
58
64
|
|
|
59
65
|
// 组件
|
|
60
66
|
|
|
@@ -131,22 +137,26 @@ export class Editor extends Group implements IEditor {
|
|
|
131
137
|
}
|
|
132
138
|
|
|
133
139
|
public updateEditTool(): void {
|
|
134
|
-
|
|
135
|
-
if (tool) {
|
|
136
|
-
this.editBox.unload()
|
|
137
|
-
tool.unload()
|
|
138
|
-
this.editTool = null
|
|
139
|
-
}
|
|
140
|
+
this.unloadEditTool()
|
|
140
141
|
|
|
141
142
|
if (this.editing) {
|
|
142
|
-
const
|
|
143
|
-
tool = this.editTool = this.editToolList[
|
|
143
|
+
const name = this.element.editOuter || 'EditTool'
|
|
144
|
+
const tool = this.editTool = this.editToolList[name] = this.editToolList[name] || EditToolCreator.get(name, this)
|
|
144
145
|
this.editBox.load()
|
|
145
146
|
tool.load()
|
|
146
147
|
this.update()
|
|
147
148
|
}
|
|
148
149
|
}
|
|
149
150
|
|
|
151
|
+
public unloadEditTool(): void {
|
|
152
|
+
let tool = this.editTool
|
|
153
|
+
if (tool) {
|
|
154
|
+
this.editBox.unload()
|
|
155
|
+
tool.unload()
|
|
156
|
+
this.editTool = null
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
150
160
|
|
|
151
161
|
// get
|
|
152
162
|
|
|
@@ -255,15 +265,20 @@ export class Editor extends Group implements IEditor {
|
|
|
255
265
|
|
|
256
266
|
// inner
|
|
257
267
|
|
|
258
|
-
public openInnerEditor(target?: IUI, select?: boolean): void {
|
|
268
|
+
public openInnerEditor(target?: IUI, nameOrSelect?: string | boolean, select?: boolean): void {
|
|
269
|
+
let name: string
|
|
270
|
+
if (typeof nameOrSelect === 'string') name = nameOrSelect
|
|
271
|
+
else if (!select) select = nameOrSelect
|
|
272
|
+
|
|
259
273
|
if (target && select) this.target = target
|
|
274
|
+
|
|
260
275
|
if (this.single) {
|
|
261
276
|
const editTarget = target || this.element
|
|
262
|
-
|
|
263
|
-
if (
|
|
277
|
+
name || (name = editTarget.editInner)
|
|
278
|
+
if (name && EditToolCreator.list[name]) {
|
|
264
279
|
this.editTool.unload()
|
|
265
280
|
this.innerEditing = true
|
|
266
|
-
this.innerEditor = this.editToolList[
|
|
281
|
+
this.innerEditor = this.editToolList[name] = this.editToolList[name] || EditToolCreator.get(name, this)
|
|
267
282
|
this.innerEditor.editTarget = editTarget
|
|
268
283
|
|
|
269
284
|
this.emitInnerEvent(InnerEditorEvent.BEFORE_OPEN)
|
|
@@ -273,7 +288,7 @@ export class Editor extends Group implements IEditor {
|
|
|
273
288
|
}
|
|
274
289
|
}
|
|
275
290
|
|
|
276
|
-
public closeInnerEditor(): void {
|
|
291
|
+
public closeInnerEditor(onlyInnerEditor?: boolean): void {
|
|
277
292
|
if (this.innerEditing) {
|
|
278
293
|
this.innerEditing = false
|
|
279
294
|
|
|
@@ -281,7 +296,7 @@ export class Editor extends Group implements IEditor {
|
|
|
281
296
|
this.innerEditor.unload()
|
|
282
297
|
this.emitInnerEvent(InnerEditorEvent.CLOSE)
|
|
283
298
|
|
|
284
|
-
this.
|
|
299
|
+
if (!onlyInnerEditor) this.updateEditTool()
|
|
285
300
|
this.innerEditor = null
|
|
286
301
|
}
|
|
287
302
|
}
|
|
@@ -337,14 +352,7 @@ export class Editor extends Group implements IEditor {
|
|
|
337
352
|
const { app, leafer, editMask } = this
|
|
338
353
|
this.targetEventIds = [
|
|
339
354
|
leafer.on_(RenderEvent.START, this.onRenderStart, this),
|
|
340
|
-
|
|
341
|
-
app.on_([
|
|
342
|
-
[RenderEvent.CHILD_START, this.onAppRenderStart, this],
|
|
343
|
-
|
|
344
|
-
[MoveEvent.BEFORE_MOVE, this.onMove, this, true],
|
|
345
|
-
[ZoomEvent.BEFORE_ZOOM, this.onScale, this, true],
|
|
346
|
-
[RotateEvent.BEFORE_ROTATE, this.onRotate, this, true],
|
|
347
|
-
])
|
|
355
|
+
app.on_(RenderEvent.CHILD_START, this.onAppRenderStart, this)
|
|
348
356
|
]
|
|
349
357
|
if (editMask.visible) editMask.forceRender()
|
|
350
358
|
}
|
package/src/decorator/data.ts
CHANGED
|
@@ -19,6 +19,7 @@ export function targetAttr(fn: IFunction) {
|
|
|
19
19
|
const isSelect = key === 'target'
|
|
20
20
|
if (isSelect) {
|
|
21
21
|
if (value instanceof Array && value.length > 1 && value[0].locked) value.splice(0, 1) // fix: 单个锁定 + shift多选
|
|
22
|
+
if ((this as IEditor).single) (this as IEditor).element.syncEventer = null // 重置 EditBox.load() 设置
|
|
22
23
|
|
|
23
24
|
const { beforeSelect } = (this as IEditor).config
|
|
24
25
|
if (beforeSelect) {
|
|
@@ -44,8 +45,9 @@ export function mergeConfigAttr() {
|
|
|
44
45
|
return (target: IEditor, key: string) => {
|
|
45
46
|
defineKey(target, key, {
|
|
46
47
|
get() {
|
|
47
|
-
const { config, element, dragPoint } = this, mergeConfig = { ...config } // 实时合并,后期可优化
|
|
48
|
-
if (element && element.editConfig) Object.assign(mergeConfig, element.editConfig)
|
|
48
|
+
const { config, element, dragPoint, editBox } = this, mergeConfig = { ...config } // 实时合并,后期可优化
|
|
49
|
+
if (element && element.editConfig) Object.assign(mergeConfig, element.editConfig) // 元素上的配置
|
|
50
|
+
if (editBox.config) Object.assign(mergeConfig, editBox.config) // EditBox 上的配置
|
|
49
51
|
if (dragPoint) {
|
|
50
52
|
if (dragPoint.editConfig) Object.assign(mergeConfig, dragPoint.editConfig)
|
|
51
53
|
if (mergeConfig.editSize === 'font-size') mergeConfig.lockRatio = true // 强制锁定比例
|
package/src/display/EditBox.ts
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { IRect, IEventListenerId, IBoundsData, IPointData, IKeyEvent, IGroup, IBox, IBoxInputData, IAlign, IUI, IEditorConfig, IEditorDragStartData, IEventParams, ITransformTool } from '@leafer-ui/interface'
|
|
2
|
-
import { Group, Box, Text, AroundHelper, Direction9, ResizeEvent } from '@leafer-ui/draw'
|
|
3
|
-
import { DragEvent, PointerEvent, KeyEvent } from '@leafer-ui/core'
|
|
2
|
+
import { Group, Box, Text, AroundHelper, Direction9, ResizeEvent, BoundsHelper } from '@leafer-ui/draw'
|
|
3
|
+
import { DragEvent, PointerEvent, KeyEvent, RotateEvent, ZoomEvent, MoveEvent } from '@leafer-ui/core'
|
|
4
4
|
|
|
5
5
|
import { IEditBox, IEditor, IEditPoint, IEditPointType } from '@leafer-in/interface'
|
|
6
6
|
|
|
7
|
-
import {
|
|
8
|
-
import { EditorEvent } from '../event/EditorEvent'
|
|
7
|
+
import { updatePointCursor, updateMoveCursor } from '../editor/cursor'
|
|
9
8
|
import { EditPoint } from './EditPoint'
|
|
10
9
|
import { EditDataHelper } from '../helper/EditDataHelper'
|
|
11
10
|
|
|
@@ -17,7 +16,12 @@ export class EditBox extends Group implements IEditBox {
|
|
|
17
16
|
public editor: IEditor
|
|
18
17
|
|
|
19
18
|
public dragging: boolean
|
|
19
|
+
public gesturing: boolean
|
|
20
|
+
|
|
20
21
|
public moving: boolean
|
|
22
|
+
public resizing: boolean
|
|
23
|
+
public rotating: boolean
|
|
24
|
+
public skewing: boolean
|
|
21
25
|
|
|
22
26
|
public view: IGroup = new Group() // 放置默认编辑工具控制点
|
|
23
27
|
|
|
@@ -38,8 +42,8 @@ export class EditBox extends Group implements IEditBox {
|
|
|
38
42
|
public mergedConfig: IEditorConfig
|
|
39
43
|
|
|
40
44
|
public get mergeConfig(): IEditorConfig {
|
|
41
|
-
const { config } = this, { mergeConfig } = this.editor
|
|
42
|
-
return this.mergedConfig = config ? { ...mergeConfig, ...config } : mergeConfig
|
|
45
|
+
const { config } = this, { mergeConfig, editBox } = this.editor
|
|
46
|
+
return this.mergedConfig = config && (editBox !== this) ? { ...mergeConfig, ...config } : mergeConfig // 可能会出现多个editBox的情况
|
|
43
47
|
}
|
|
44
48
|
|
|
45
49
|
protected _target: IUI
|
|
@@ -58,6 +62,13 @@ export class EditBox extends Group implements IEditBox {
|
|
|
58
62
|
public get flippedY(): boolean { return this.scaleY < 0 }
|
|
59
63
|
public get flippedOne(): boolean { return this.scaleX * this.scaleY < 0 }
|
|
60
64
|
|
|
65
|
+
public get canUse(): boolean { return (this.visible && this.view.visible) as boolean } // 编辑框是否处于激活状态
|
|
66
|
+
public get canGesture(): boolean { // 是否支持手势
|
|
67
|
+
if (!this.canUse) return false
|
|
68
|
+
const { moveable, resizeable, rotateable } = this.mergeConfig
|
|
69
|
+
return typeof moveable === 'string' || typeof resizeable === 'string' || typeof rotateable === 'string'
|
|
70
|
+
}
|
|
71
|
+
|
|
61
72
|
protected __eventIds: IEventListenerId[] = []
|
|
62
73
|
|
|
63
74
|
constructor(editor: IEditor) {
|
|
@@ -95,6 +106,7 @@ export class EditBox extends Group implements IEditBox {
|
|
|
95
106
|
this.add(view)
|
|
96
107
|
}
|
|
97
108
|
|
|
109
|
+
|
|
98
110
|
public load(): void {
|
|
99
111
|
const { target, mergeConfig, single, rect, circle, resizePoints } = this
|
|
100
112
|
const { stroke, strokeWidth } = mergeConfig
|
|
@@ -107,7 +119,7 @@ export class EditBox extends Group implements IEditBox {
|
|
|
107
119
|
for (let i = 0; i < 8; i++) {
|
|
108
120
|
resizeP = resizePoints[i]
|
|
109
121
|
resizeP.set(this.getPointStyle((i % 2) ? middlePointsStyle[((i - 1) / 2) % middlePointsStyle.length] : pointsStyle[(i / 2) % pointsStyle.length]))
|
|
110
|
-
|
|
122
|
+
resizeP.rotation = ((i - (i % 2 ? 1 : 0)) / 2) * 90
|
|
111
123
|
}
|
|
112
124
|
|
|
113
125
|
// rotate
|
|
@@ -118,12 +130,12 @@ export class EditBox extends Group implements IEditBox {
|
|
|
118
130
|
|
|
119
131
|
const syncEventer = single && this.transformTool.editTool
|
|
120
132
|
|
|
133
|
+
// 编辑框作为底部虚拟元素, 在 unload() 中重置
|
|
121
134
|
rect.hittable = !syncEventer
|
|
122
135
|
rect.syncEventer = syncEventer && this.editor // 单选下 rect 的事件不会冒泡,需要手动传递给editor
|
|
123
136
|
|
|
124
|
-
// 编辑框作为底部虚拟元素, 在 onSelect 方法移除
|
|
125
137
|
if (syncEventer) {
|
|
126
|
-
target.syncEventer = rect
|
|
138
|
+
target.syncEventer = rect // 在 target 属性装饰中重置
|
|
127
139
|
this.app.interaction.bottomList = [{ target: rect, proxy: target }]
|
|
128
140
|
}
|
|
129
141
|
|
|
@@ -137,14 +149,22 @@ export class EditBox extends Group implements IEditBox {
|
|
|
137
149
|
this.updateBounds({ x: 0, y: 0, width, height })
|
|
138
150
|
}
|
|
139
151
|
|
|
152
|
+
public unload(): void {
|
|
153
|
+
this.visible = false
|
|
154
|
+
if (this.app) this.rect.syncEventer = this.app.interaction.bottomList = null
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
|
|
140
158
|
public updateBounds(bounds: IBoundsData): void {
|
|
141
159
|
const { editMask } = this.editor
|
|
142
160
|
const { mergeConfig, single, rect, circle, buttons, resizePoints, rotatePoints, resizeLines } = this
|
|
143
|
-
const { middlePoint, resizeable, rotateable, hideOnSmall, editBox, mask } = mergeConfig
|
|
161
|
+
const { middlePoint, resizeable, rotateable, hideOnSmall, editBox, mask, spread } = mergeConfig
|
|
144
162
|
|
|
145
163
|
this.visible = !this.target.locked
|
|
146
164
|
editMask.visible = mask ? true : 0
|
|
147
165
|
|
|
166
|
+
if (spread) BoundsHelper.spread(bounds, spread)
|
|
167
|
+
|
|
148
168
|
if (this.view.worldOpacity) {
|
|
149
169
|
const { width, height } = bounds
|
|
150
170
|
const smallSize = typeof hideOnSmall === 'number' ? hideOnSmall : 10
|
|
@@ -175,7 +195,6 @@ export class EditBox extends Group implements IEditBox {
|
|
|
175
195
|
if (hideOnSmall && resizeP.width * 2 > width) resizeP.visible = false
|
|
176
196
|
} else {
|
|
177
197
|
resizeL.height = height
|
|
178
|
-
resizeP.rotation = 90
|
|
179
198
|
if (hideOnSmall && resizeP.width * 2 > height) resizeP.visible = false
|
|
180
199
|
}
|
|
181
200
|
}
|
|
@@ -238,11 +257,6 @@ export class EditBox extends Group implements IEditBox {
|
|
|
238
257
|
}
|
|
239
258
|
|
|
240
259
|
|
|
241
|
-
public unload(): void {
|
|
242
|
-
this.visible = false
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
|
|
246
260
|
public getPointStyle(userStyle?: IBoxInputData): IBoxInputData {
|
|
247
261
|
const { stroke, strokeWidth, pointFill, pointSize, pointRadius } = this.mergedConfig
|
|
248
262
|
const defaultStyle = { fill: pointFill, stroke, strokeWidth, around: 'center', strokeAlign: 'center', width: pointSize, height: pointSize, cornerRadius: pointRadius, offsetX: 0, offsetY: 0, editConfig } as IBoxInputData
|
|
@@ -259,23 +273,27 @@ export class EditBox extends Group implements IEditBox {
|
|
|
259
273
|
return middlePoint instanceof Array ? middlePoint : (middlePoint ? [middlePoint] : this.getPointsStyle())
|
|
260
274
|
}
|
|
261
275
|
|
|
262
|
-
protected onSelect(e: EditorEvent): void {
|
|
263
|
-
if (e.oldList.length === 1) {
|
|
264
|
-
e.oldList[0].syncEventer = null
|
|
265
|
-
if (this.app) this.app.interaction.bottomList = null
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
276
|
|
|
269
277
|
// drag
|
|
270
278
|
|
|
271
279
|
protected onDragStart(e: DragEvent): void {
|
|
272
280
|
this.dragging = true
|
|
273
281
|
const point = this.dragPoint = e.current as IEditPoint, { pointType } = point
|
|
274
|
-
const { editor, dragStartData } = this, { target } = this
|
|
282
|
+
const { editor, dragStartData } = this, { target } = this, { moveable, resizeable, rotateable, skewable, hideOnMove } = this.mergeConfig
|
|
283
|
+
|
|
284
|
+
// 确定模式
|
|
275
285
|
if (point.name === 'rect') {
|
|
276
|
-
this.moving = true
|
|
277
|
-
editor.opacity =
|
|
286
|
+
moveable && (this.moving = true)
|
|
287
|
+
editor.opacity = hideOnMove ? 0 : 1 // move
|
|
288
|
+
} else {
|
|
289
|
+
if (pointType.includes('rotate') || e.metaKey || e.ctrlKey || !resizeable) {
|
|
290
|
+
rotateable && (this.rotating = true)
|
|
291
|
+
if (pointType === 'resize-rotate') resizeable && (this.resizing = true)
|
|
292
|
+
else if (point.name === 'resize-line') skewable && (this.skewing = true), this.rotating = false
|
|
293
|
+
} else if (pointType === 'resize') resizeable && (this.resizing = true)
|
|
294
|
+
if (pointType === 'skew') skewable && (this.skewing = true)
|
|
278
295
|
}
|
|
296
|
+
|
|
279
297
|
dragStartData.x = e.x
|
|
280
298
|
dragStartData.y = e.y
|
|
281
299
|
dragStartData.point = { x: target.x, y: target.y } // 用于移动
|
|
@@ -285,37 +303,73 @@ export class EditBox extends Group implements IEditBox {
|
|
|
285
303
|
}
|
|
286
304
|
|
|
287
305
|
protected onDragEnd(e: DragEvent): void {
|
|
288
|
-
this.dragging = false
|
|
289
306
|
this.dragPoint = null
|
|
290
|
-
this.
|
|
307
|
+
this.resetDoing()
|
|
291
308
|
const { name, pointType } = e.current as IEditPoint
|
|
292
309
|
if (name === 'rect') this.editor.opacity = 1 // move
|
|
293
310
|
if (pointType && pointType.includes('resize')) ResizeEvent.resizingKeys = null
|
|
294
311
|
}
|
|
295
312
|
|
|
296
313
|
protected onDrag(e: DragEvent): void {
|
|
297
|
-
const { transformTool
|
|
298
|
-
if (
|
|
314
|
+
const { transformTool, moving, resizing, rotating, skewing } = this
|
|
315
|
+
if (moving) {
|
|
299
316
|
transformTool.onMove(e)
|
|
300
317
|
updateMoveCursor(this)
|
|
301
|
-
} else {
|
|
302
|
-
const
|
|
303
|
-
if (pointType
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
318
|
+
} else if (resizing || rotating || skewing) {
|
|
319
|
+
const point = e.current as IEditPoint
|
|
320
|
+
if (point.pointType) this.enterPoint = point// 防止变化
|
|
321
|
+
if (rotating) transformTool.onRotate(e)
|
|
322
|
+
if (resizing) transformTool.onScale(e)
|
|
323
|
+
if (skewing) transformTool.onSkew(e)
|
|
324
|
+
updatePointCursor(this, e)
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
protected resetDoing(): void {
|
|
329
|
+
if (this.canUse) this.dragging = this.gesturing = this.moving = this.resizing = this.rotating = this.skewing = false
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// 手势控制元素
|
|
333
|
+
|
|
334
|
+
public onMove(e: MoveEvent): void {
|
|
335
|
+
if (this.canGesture && e.moveType !== 'drag') {
|
|
336
|
+
e.stop()
|
|
337
|
+
if (typeof this.mergeConfig.moveable === 'string') {
|
|
338
|
+
this.gesturing = this.moving = true
|
|
339
|
+
this.transformTool.onMove(e)
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
public onScale(e: ZoomEvent): void {
|
|
345
|
+
if (this.canGesture) {
|
|
346
|
+
e.stop()
|
|
347
|
+
if (typeof this.mergeConfig.resizeable === 'string') {
|
|
348
|
+
this.gesturing = this.resizing = true
|
|
349
|
+
this.transformTool.onScale(e)
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
public onRotate(e: RotateEvent): void {
|
|
355
|
+
if (this.canGesture) {
|
|
356
|
+
e.stop()
|
|
357
|
+
if (typeof this.mergeConfig.rotateable === 'string') {
|
|
358
|
+
this.gesturing = this.rotating = true
|
|
359
|
+
this.transformTool.onRotate(e)
|
|
360
|
+
}
|
|
309
361
|
}
|
|
310
362
|
}
|
|
311
363
|
|
|
364
|
+
// 键盘
|
|
365
|
+
|
|
312
366
|
protected onKey(e: KeyEvent): void {
|
|
313
|
-
|
|
367
|
+
updatePointCursor(this, e)
|
|
314
368
|
}
|
|
315
369
|
|
|
316
370
|
public onArrow(e: IKeyEvent): void {
|
|
317
|
-
const { editor } = this
|
|
318
|
-
if (editor.editing && this.mergeConfig.keyEvent) {
|
|
371
|
+
const { editor, transformTool } = this
|
|
372
|
+
if (this.canUse && editor.editing && this.mergeConfig.keyEvent) {
|
|
319
373
|
let x = 0, y = 0
|
|
320
374
|
const distance = e.shiftKey ? 10 : 1
|
|
321
375
|
switch (e.code) {
|
|
@@ -331,7 +385,7 @@ export class EditBox extends Group implements IEditBox {
|
|
|
331
385
|
case 'ArrowRight':
|
|
332
386
|
x = distance
|
|
333
387
|
}
|
|
334
|
-
if (x || y)
|
|
388
|
+
if (x || y) transformTool.move(x, y)
|
|
335
389
|
}
|
|
336
390
|
}
|
|
337
391
|
|
|
@@ -376,7 +430,7 @@ export class EditBox extends Group implements IEditBox {
|
|
|
376
430
|
[DragEvent.END, this.onDragEnd, this],
|
|
377
431
|
[PointerEvent.LEAVE, () => { this.enterPoint = null }],
|
|
378
432
|
]
|
|
379
|
-
if (point.name !== 'circle') events.push([PointerEvent.ENTER, (e: PointerEvent) => { this.enterPoint = point,
|
|
433
|
+
if (point.name !== 'circle') events.push([PointerEvent.ENTER, (e: PointerEvent) => { this.enterPoint = point, updatePointCursor(this, e) }])
|
|
380
434
|
this.__eventIds.push(point.on_(events))
|
|
381
435
|
}
|
|
382
436
|
|
|
@@ -384,8 +438,6 @@ export class EditBox extends Group implements IEditBox {
|
|
|
384
438
|
const { rect, editor, __eventIds: events } = this
|
|
385
439
|
|
|
386
440
|
events.push(
|
|
387
|
-
editor.on_(EditorEvent.SELECT, this.onSelect, this),
|
|
388
|
-
|
|
389
441
|
rect.on_([
|
|
390
442
|
[DragEvent.START, this.onDragStart, this],
|
|
391
443
|
[DragEvent.DRAG, this.onDrag, this],
|
|
@@ -401,7 +453,13 @@ export class EditBox extends Group implements IEditBox {
|
|
|
401
453
|
events.push(
|
|
402
454
|
editor.app.on_([
|
|
403
455
|
[[KeyEvent.HOLD, KeyEvent.UP], this.onKey, this],
|
|
404
|
-
[KeyEvent.DOWN, this.onArrow, this]
|
|
456
|
+
[KeyEvent.DOWN, this.onArrow, this],
|
|
457
|
+
[MoveEvent.BEFORE_MOVE, this.onMove, this, true],
|
|
458
|
+
[ZoomEvent.BEFORE_ZOOM, this.onScale, this, true],
|
|
459
|
+
[RotateEvent.BEFORE_ROTATE, this.onRotate, this, true],
|
|
460
|
+
[MoveEvent.END, this.resetDoing, this],
|
|
461
|
+
[ZoomEvent.END, this.resetDoing, this],
|
|
462
|
+
[RotateEvent.END, this.resetDoing, this],
|
|
405
463
|
])
|
|
406
464
|
)
|
|
407
465
|
})
|
|
@@ -54,16 +54,16 @@ export class EditSelect extends Group implements IEditSelect {
|
|
|
54
54
|
|
|
55
55
|
protected onSelect(): void {
|
|
56
56
|
if (this.running) {
|
|
57
|
-
|
|
58
|
-
const { stroke, strokeWidth, selectedStyle } = mergeConfig
|
|
59
|
-
this.targetStroker.setTarget(list, { stroke, strokeWidth: Math.max(1, strokeWidth / 2), ...(selectedStyle || {}) })
|
|
57
|
+
this.targetStroker.setTarget(this.editor.list)
|
|
60
58
|
this.hoverStroker.target = null
|
|
61
59
|
}
|
|
62
60
|
}
|
|
63
61
|
|
|
64
62
|
public update(): void {
|
|
65
63
|
this.hoverStroker.update()
|
|
66
|
-
|
|
64
|
+
|
|
65
|
+
const { stroke, strokeWidth, selectedStyle } = this.editor.mergedConfig
|
|
66
|
+
this.targetStroker.update({ stroke, strokeWidth: strokeWidth && Math.max(1, strokeWidth / 2), ...(selectedStyle || {}) })
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
// move / down
|
package/src/display/Stroker.ts
CHANGED
|
@@ -27,16 +27,17 @@ export class Stroker extends UI implements IStroker {
|
|
|
27
27
|
this.strokeAlign = 'center'
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
public setTarget(target: IUI | IUI[], style
|
|
31
|
-
this.set(style)
|
|
30
|
+
public setTarget(target: IUI | IUI[], style?: IRectInputData): void {
|
|
31
|
+
if (style) this.set(style)
|
|
32
32
|
this.target = target
|
|
33
33
|
this.update()
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
public update(): void {
|
|
36
|
+
public update(style?: IRectInputData): void {
|
|
37
37
|
const { list } = this
|
|
38
38
|
if (list.length) {
|
|
39
39
|
setListWithFn(bounds, list, worldBounds)
|
|
40
|
+
if (style) this.set(style)
|
|
40
41
|
this.set(bounds)
|
|
41
42
|
this.visible = true
|
|
42
43
|
} else this.visible = 0
|
package/src/editor/cursor.ts
CHANGED
|
@@ -8,23 +8,26 @@ import { EditDataHelper } from '../helper/EditDataHelper'
|
|
|
8
8
|
|
|
9
9
|
const cacheCursors: IObject = {}
|
|
10
10
|
|
|
11
|
-
export function
|
|
12
|
-
const { enterPoint: point } = editBox
|
|
13
|
-
if (!point || !editBox.editor.editing || !editBox.
|
|
11
|
+
export function updatePointCursor(editBox: IEditBox, e: IUIEvent): void {
|
|
12
|
+
const { enterPoint: point, dragging, skewing, resizing, flippedX, flippedY } = editBox
|
|
13
|
+
if (!point || !editBox.editor.editing || !editBox.canUse) return
|
|
14
14
|
if (point.name === 'circle') return // 独立旋转按钮
|
|
15
15
|
if (point.pointType === 'button') { // 普通按钮
|
|
16
16
|
if (!point.cursor) point.cursor = 'pointer'
|
|
17
17
|
return
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
let { rotation
|
|
20
|
+
let { rotation } = editBox
|
|
21
21
|
const { pointType } = point, { resizeCursor, rotateCursor, skewCursor, resizeable, rotateable, skewable } = editBox.mergeConfig
|
|
22
22
|
|
|
23
23
|
let showResize = pointType.includes('resize')
|
|
24
24
|
if (showResize && rotateable && (e.metaKey || e.ctrlKey || !resizeable)) showResize = false
|
|
25
25
|
const showSkew = skewable && !showResize && (point.name === 'resize-line' || pointType === 'skew')
|
|
26
26
|
|
|
27
|
-
const cursor =
|
|
27
|
+
const cursor = dragging
|
|
28
|
+
? (skewing ? skewCursor : (resizing ? resizeCursor : rotateCursor))
|
|
29
|
+
: (showSkew ? skewCursor : (showResize ? resizeCursor : rotateCursor))
|
|
30
|
+
|
|
28
31
|
rotation += (EditDataHelper.getFlipDirection(point.direction, flippedX, flippedY) + 1) * 45
|
|
29
32
|
rotation = Math.round(MathHelper.formatRotation(rotation, true) / 2) * 2
|
|
30
33
|
|
|
@@ -40,7 +43,7 @@ export function updateCursor(editBox: IEditBox, e: IUIEvent): void {
|
|
|
40
43
|
|
|
41
44
|
export function updateMoveCursor(editBox: IEditBox): void {
|
|
42
45
|
const { moveCursor, moveable } = editBox.mergeConfig
|
|
43
|
-
editBox.rect.cursor = moveable ? moveCursor : undefined
|
|
46
|
+
if (editBox.canUse) editBox.rect.cursor = moveable ? moveCursor : undefined
|
|
44
47
|
}
|
|
45
48
|
|
|
46
49
|
|
package/src/editor/target.ts
CHANGED
|
@@ -16,7 +16,8 @@ export function onTarget(editor: IEditor, oldValue: IUI | IUI[]): void {
|
|
|
16
16
|
editor.leafList.reset()
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
editor.closeInnerEditor()
|
|
19
|
+
editor.closeInnerEditor(true)
|
|
20
|
+
editor.unloadEditTool()
|
|
20
21
|
|
|
21
22
|
const data = { editor, value: target, oldValue }
|
|
22
23
|
editor.emitEvent(new EditorEvent(EditorEvent.SELECT, data))
|
|
@@ -116,14 +116,18 @@ export const EditDataHelper = {
|
|
|
116
116
|
|
|
117
117
|
if (dragBounds) {
|
|
118
118
|
const allowBounds = dragBounds === 'parent' ? target.parent.boxBounds : dragBounds
|
|
119
|
-
const
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
if (
|
|
126
|
-
|
|
119
|
+
const childBounds = new Bounds(target.__localBoxBounds)
|
|
120
|
+
|
|
121
|
+
if (BoundsHelper.includes(new Bounds(allowBounds).spread(0.1), childBounds)) {
|
|
122
|
+
|
|
123
|
+
childBounds.scaleOf(target.getLocalPointByInner(origin), scaleX, scaleY)
|
|
124
|
+
|
|
125
|
+
if (!BoundsHelper.includes(allowBounds, childBounds)) {
|
|
126
|
+
const realBounds = childBounds.getIntersect(allowBounds)
|
|
127
|
+
const fitScaleX = realBounds.width / childBounds.width, fitScaleY = realBounds.height / childBounds.height
|
|
128
|
+
if (useScaleX) scaleX *= fitScaleX
|
|
129
|
+
if (useScaleY) scaleY *= fitScaleY // 后续需优化带旋转的场景
|
|
130
|
+
}
|
|
127
131
|
}
|
|
128
132
|
}
|
|
129
133
|
|
package/src/index.ts
CHANGED
|
@@ -47,7 +47,7 @@ Creator.editor = function (options?: IEditorConfig, app?: IApp): IEditor {
|
|
|
47
47
|
Box.addAttr('textBox', false, dataType)
|
|
48
48
|
|
|
49
49
|
UI.addAttr('editConfig', undefined, dataType)
|
|
50
|
-
UI.addAttr('editOuter', (ui: UI) => ui.__.__isLinePath ? 'LineEditTool' : 'EditTool', dataType)
|
|
50
|
+
UI.addAttr('editOuter', (ui: UI) => { ui.updateLayout(); return ui.__.__isLinePath ? 'LineEditTool' : 'EditTool' }, dataType) // fix: Line 需要更新布局才能精准确定
|
|
51
51
|
|
|
52
52
|
UI.addAttr('editInner', 'PathEditor', dataType)
|
|
53
53
|
Group.addAttr('editInner', '', dataType) // 必须设为空
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { IEvent, IPointData, IAlign, IAxis, IFunction, IMatrix } from '@leafer-ui/interface'
|
|
2
|
-
import { MathHelper, Matrix, LeafHelper } from '@leafer-ui/draw'
|
|
2
|
+
import { MathHelper, Matrix, LeafHelper, AroundHelper } from '@leafer-ui/draw'
|
|
3
3
|
import { DragEvent, RotateEvent, ZoomEvent, MoveEvent } from '@leafer-ui/core'
|
|
4
4
|
|
|
5
5
|
import { IEditBox, IEditPoint, IEditTool, IEditorScaleEvent, ISimulateElement, IEditorMoveEvent, IEditorRotateEvent, IEditorSkewEvent } from '@leafer-in/interface'
|
|
@@ -23,17 +23,12 @@ export class TransformTool implements ITransformTool { // Editor use
|
|
|
23
23
|
|
|
24
24
|
public onMove(e: DragEvent | MoveEvent): void {
|
|
25
25
|
|
|
26
|
-
const { target,
|
|
26
|
+
const { target, dragStartData } = this.editBox
|
|
27
27
|
|
|
28
28
|
if (e instanceof MoveEvent) {
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const move = e.getLocalMove(target)
|
|
33
|
-
|
|
34
|
-
if (moveable === 'move') e.stop(), this.move(move.x, move.y)
|
|
35
|
-
else if (resizeable === 'zoom') e.stop()
|
|
36
|
-
}
|
|
30
|
+
const move = e.getLocalMove(target)
|
|
31
|
+
this.move(move.x, move.y)
|
|
37
32
|
|
|
38
33
|
} else {
|
|
39
34
|
|
|
@@ -52,11 +47,11 @@ export class TransformTool implements ITransformTool { // Editor use
|
|
|
52
47
|
public onScale(e: DragEvent | ZoomEvent): void {
|
|
53
48
|
|
|
54
49
|
const { target, mergeConfig, single, dragStartData } = this.editBox
|
|
55
|
-
let { around, lockRatio,
|
|
50
|
+
let { around, lockRatio, flipable, editSize } = mergeConfig
|
|
56
51
|
|
|
57
52
|
if (e instanceof ZoomEvent) {
|
|
58
53
|
|
|
59
|
-
|
|
54
|
+
this.scaleOf(target.getBoxPoint(e), e.scale, e.scale)
|
|
60
55
|
|
|
61
56
|
} else {
|
|
62
57
|
|
|
@@ -78,31 +73,24 @@ export class TransformTool implements ITransformTool { // Editor use
|
|
|
78
73
|
public onRotate(e: DragEvent | RotateEvent): void {
|
|
79
74
|
|
|
80
75
|
const { target, mergeConfig, dragStartData } = this.editBox
|
|
81
|
-
const {
|
|
82
|
-
const { direction
|
|
83
|
-
|
|
84
|
-
if (skewable && name === 'resize-line') return this.onSkew(e as DragEvent)
|
|
76
|
+
const { around, rotateAround, rotateGap } = mergeConfig
|
|
77
|
+
const { direction } = e.current as IEditPoint
|
|
85
78
|
|
|
86
79
|
let origin: IPointData, rotation: number
|
|
87
80
|
|
|
88
81
|
if (e instanceof RotateEvent) {
|
|
89
82
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
if (target.scaleX * target.scaleY < 0) rotation = -rotation // flippedOne
|
|
83
|
+
rotation = e.rotation
|
|
84
|
+
origin = rotateAround ? AroundHelper.getPoint(rotateAround, target.boxBounds) : target.getBoxPoint(e)
|
|
94
85
|
|
|
95
86
|
} else {
|
|
96
87
|
|
|
97
|
-
const data = EditDataHelper.getRotateData(target, direction, e, dragStartData, e.shiftKey ? null : (target.around || target.origin || around || 'center'))
|
|
98
|
-
rotation = data.rotation
|
|
88
|
+
const data = EditDataHelper.getRotateData(target, direction, e, dragStartData, e.shiftKey ? null : (rotateAround || target.around || target.origin || around || 'center'))
|
|
89
|
+
rotation = dragStartData.rotation + data.rotation - target.rotation
|
|
99
90
|
origin = data.origin
|
|
100
91
|
|
|
101
92
|
}
|
|
102
93
|
|
|
103
|
-
if (target.scaleX * target.scaleY < 0) rotation = -rotation // flippedOne
|
|
104
|
-
if (e instanceof DragEvent) rotation = dragStartData.rotation + rotation - target.rotation
|
|
105
|
-
|
|
106
94
|
rotation = MathHelper.float(MathHelper.getGapRotation(rotation, rotateGap, target.rotation), 2)
|
|
107
95
|
if (!rotation) return
|
|
108
96
|
|