@leafer-in/editor 1.7.0 → 1.9.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 +1279 -1036
- package/dist/editor.esm.js +1258 -1034
- package/dist/editor.esm.min.js +1 -1
- package/dist/editor.esm.min.js.map +1 -1
- package/dist/editor.js +1177 -1065
- 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 +35 -26
- package/src/decorator/data.ts +7 -5
- package/src/display/EditBox.ts +123 -54
- package/src/display/EditSelect.ts +13 -7
- package/src/display/Stroker.ts +8 -7
- package/src/editor/cursor.ts +10 -7
- package/src/editor/target.ts +2 -1
- package/src/event/EditorEvent.ts +2 -2
- package/src/helper/EditDataHelper.ts +12 -8
- package/src/index.ts +1 -1
- package/src/tool/TransformTool.ts +29 -31
- package/types/index.d.ts +43 -27
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@leafer-in/editor",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.9.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.9.0",
|
|
38
|
+
"@leafer-ui/core": "^1.9.0",
|
|
39
|
+
"@leafer-in/resize": "^1.9.0",
|
|
40
|
+
"@leafer-ui/interface": "^1.9.0",
|
|
41
|
+
"@leafer-in/interface": "^1.9.0"
|
|
42
42
|
}
|
|
43
43
|
}
|
package/src/Editor.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { IGroupInputData, IUI, IEventListenerId, IPointData, ILeafList, IEditSize, IGroup, IObject, IAlign, IAxis, IFunction, IMatrix, IApp } from '@leafer-ui/interface'
|
|
2
|
-
import { Group, DataHelper, LeafList, RenderEvent, LeafHelper, Direction9, Plugin } from '@leafer-ui/draw'
|
|
2
|
+
import { Group, DataHelper, LeafList, RenderEvent, LeafHelper, Direction9, Plugin, isString } from '@leafer-ui/draw'
|
|
3
3
|
import { DragEvent, RotateEvent, ZoomEvent, MoveEvent, useModule } from '@leafer-ui/core'
|
|
4
4
|
|
|
5
5
|
import { IEditBox, IEditPoint, IEditor, IEditorConfig, IEditTool, IEditorScaleEvent, IInnerEditor, ISimulateElement } from '@leafer-in/interface'
|
|
@@ -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
|
|
|
@@ -249,31 +259,37 @@ export class Editor extends Group implements IEditor {
|
|
|
249
259
|
|
|
250
260
|
public emitGroupEvent(type: string, group?: IGroup): void {
|
|
251
261
|
const event = new EditorGroupEvent(type, { editTarget: group })
|
|
252
|
-
this.emitEvent(event)
|
|
262
|
+
if (!group || !group.syncEventer) this.emitEvent(event) // 单选时,元素会自动将事件传递给 editor,避免重复触发
|
|
253
263
|
if (group) group.emitEvent(event)
|
|
254
264
|
}
|
|
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 (isString(nameOrSelect)) 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)
|
|
270
285
|
this.innerEditor.load()
|
|
271
286
|
this.emitInnerEvent(InnerEditorEvent.OPEN)
|
|
287
|
+
console.log('hello')
|
|
272
288
|
}
|
|
273
289
|
}
|
|
274
290
|
}
|
|
275
291
|
|
|
276
|
-
public closeInnerEditor(): void {
|
|
292
|
+
public closeInnerEditor(onlyInnerEditor?: boolean): void {
|
|
277
293
|
if (this.innerEditing) {
|
|
278
294
|
this.innerEditing = false
|
|
279
295
|
|
|
@@ -281,7 +297,7 @@ export class Editor extends Group implements IEditor {
|
|
|
281
297
|
this.innerEditor.unload()
|
|
282
298
|
this.emitInnerEvent(InnerEditorEvent.CLOSE)
|
|
283
299
|
|
|
284
|
-
this.
|
|
300
|
+
if (!onlyInnerEditor) this.updateEditTool()
|
|
285
301
|
this.innerEditor = null
|
|
286
302
|
}
|
|
287
303
|
}
|
|
@@ -289,7 +305,7 @@ export class Editor extends Group implements IEditor {
|
|
|
289
305
|
public emitInnerEvent(type: string): void {
|
|
290
306
|
const { innerEditor } = this, { editTarget } = innerEditor
|
|
291
307
|
const event = new InnerEditorEvent(type, { editTarget, innerEditor })
|
|
292
|
-
this.emitEvent(event)
|
|
308
|
+
if (!editTarget.syncEventer) this.emitEvent(event) // 单选时,元素会自动将事件传递给 editor,避免重复触发
|
|
293
309
|
editTarget.emitEvent(event)
|
|
294
310
|
}
|
|
295
311
|
|
|
@@ -337,14 +353,7 @@ export class Editor extends Group implements IEditor {
|
|
|
337
353
|
const { app, leafer, editMask } = this
|
|
338
354
|
this.targetEventIds = [
|
|
339
355
|
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
|
-
])
|
|
356
|
+
app.on_(RenderEvent.CHILD_START, this.onAppRenderStart, this)
|
|
348
357
|
]
|
|
349
358
|
if (editMask.visible) editMask.forceRender()
|
|
350
359
|
}
|
package/src/decorator/data.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { IFunction, ILeaf, IObject, IUI, } from '@leafer-ui/interface'
|
|
2
2
|
import { IEditor } from '@leafer-in/interface'
|
|
3
|
-
import { defineKey, isNull } from '@leafer-ui/draw'
|
|
3
|
+
import { defineKey, isNull, isArray, isObject } from '@leafer-ui/draw'
|
|
4
4
|
|
|
5
5
|
import { EditorEvent } from '../event/EditorEvent'
|
|
6
6
|
|
|
@@ -18,12 +18,13 @@ export function targetAttr(fn: IFunction) {
|
|
|
18
18
|
|
|
19
19
|
const isSelect = key === 'target'
|
|
20
20
|
if (isSelect) {
|
|
21
|
-
if (value
|
|
21
|
+
if (isArray(value) && 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) {
|
|
25
26
|
const check = beforeSelect({ target: value })
|
|
26
|
-
if (
|
|
27
|
+
if (isObject(check)) value = check
|
|
27
28
|
else if (check === false) return
|
|
28
29
|
}
|
|
29
30
|
}
|
|
@@ -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
|
-
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'
|
|
1
|
+
import { IRect, IEventListenerId, IBoundsData, IPointData, IKeyEvent, IGroup, IBox, IBoxInputData, IAlign, IUI, IEditorConfig, IEditorDragStartData, IEventParams, ITransformTool, IUIEvent } from '@leafer-ui/interface'
|
|
2
|
+
import { Group, Box, Text, AroundHelper, Direction9, ResizeEvent, BoundsHelper, isArray, isString, isNumber } 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 isString(moveable) || isString(resizeable) || isString(rotateable)
|
|
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
|
|
@@ -102,12 +114,14 @@ export class EditBox extends Group implements IEditBox {
|
|
|
102
114
|
const pointsStyle = this.getPointsStyle()
|
|
103
115
|
const middlePointsStyle = this.getMiddlePointsStyle()
|
|
104
116
|
|
|
117
|
+
this.visible = !target.locked
|
|
118
|
+
|
|
105
119
|
let resizeP: IRect
|
|
106
120
|
|
|
107
121
|
for (let i = 0; i < 8; i++) {
|
|
108
122
|
resizeP = resizePoints[i]
|
|
109
123
|
resizeP.set(this.getPointStyle((i % 2) ? middlePointsStyle[((i - 1) / 2) % middlePointsStyle.length] : pointsStyle[(i / 2) % pointsStyle.length]))
|
|
110
|
-
|
|
124
|
+
resizeP.rotation = ((i - (i % 2 ? 1 : 0)) / 2) * 90
|
|
111
125
|
}
|
|
112
126
|
|
|
113
127
|
// rotate
|
|
@@ -118,12 +132,12 @@ export class EditBox extends Group implements IEditBox {
|
|
|
118
132
|
|
|
119
133
|
const syncEventer = single && this.transformTool.editTool
|
|
120
134
|
|
|
135
|
+
// 编辑框作为底部虚拟元素, 在 unload() 中重置
|
|
121
136
|
rect.hittable = !syncEventer
|
|
122
137
|
rect.syncEventer = syncEventer && this.editor // 单选下 rect 的事件不会冒泡,需要手动传递给editor
|
|
123
138
|
|
|
124
|
-
// 编辑框作为底部虚拟元素, 在 onSelect 方法移除
|
|
125
139
|
if (syncEventer) {
|
|
126
|
-
target.syncEventer = rect
|
|
140
|
+
target.syncEventer = rect // 在 target 属性装饰中重置
|
|
127
141
|
this.app.interaction.bottomList = [{ target: rect, proxy: target }]
|
|
128
142
|
}
|
|
129
143
|
|
|
@@ -133,21 +147,29 @@ export class EditBox extends Group implements IEditBox {
|
|
|
133
147
|
public update(): void {
|
|
134
148
|
const { editor } = this
|
|
135
149
|
const { x, y, scaleX, scaleY, rotation, skewX, skewY, width, height } = this.target.getLayoutBounds('box', editor, true)
|
|
150
|
+
this.visible = !this.target.locked
|
|
136
151
|
this.set({ x, y, scaleX, scaleY, rotation, skewX, skewY })
|
|
137
152
|
this.updateBounds({ x: 0, y: 0, width, height })
|
|
138
153
|
}
|
|
139
154
|
|
|
155
|
+
public unload(): void {
|
|
156
|
+
this.visible = false
|
|
157
|
+
if (this.app) this.rect.syncEventer = this.app.interaction.bottomList = null
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
|
|
140
161
|
public updateBounds(bounds: IBoundsData): void {
|
|
141
162
|
const { editMask } = this.editor
|
|
142
163
|
const { mergeConfig, single, rect, circle, buttons, resizePoints, rotatePoints, resizeLines } = this
|
|
143
|
-
const { middlePoint, resizeable, rotateable, hideOnSmall, editBox, mask } = mergeConfig
|
|
164
|
+
const { middlePoint, resizeable, rotateable, hideOnSmall, editBox, mask, spread, hideRotatePoints, hideResizeLines } = mergeConfig
|
|
144
165
|
|
|
145
|
-
this.visible = !this.target.locked
|
|
146
166
|
editMask.visible = mask ? true : 0
|
|
147
167
|
|
|
168
|
+
if (spread) BoundsHelper.spread(bounds, spread)
|
|
169
|
+
|
|
148
170
|
if (this.view.worldOpacity) {
|
|
149
171
|
const { width, height } = bounds
|
|
150
|
-
const smallSize =
|
|
172
|
+
const smallSize = isNumber(hideOnSmall) ? hideOnSmall : 10
|
|
151
173
|
const showPoints = editBox && !(hideOnSmall && width < smallSize && height < smallSize)
|
|
152
174
|
|
|
153
175
|
let point = {} as IPointData, rotateP: IRect, resizeP: IRect, resizeL: IRect
|
|
@@ -157,17 +179,19 @@ export class EditBox extends Group implements IEditBox {
|
|
|
157
179
|
AroundHelper.toPoint(AroundHelper.directionData[i], bounds, point)
|
|
158
180
|
resizeP = resizePoints[i]
|
|
159
181
|
rotateP = rotatePoints[i]
|
|
160
|
-
resizeL = resizeLines[Math.floor(i / 2)]
|
|
161
182
|
resizeP.set(point)
|
|
162
183
|
rotateP.set(point)
|
|
163
|
-
resizeL.set(point)
|
|
164
184
|
|
|
165
185
|
// visible
|
|
166
|
-
resizeP.visible =
|
|
167
|
-
rotateP.visible = showPoints && rotateable && resizeable && !
|
|
186
|
+
resizeP.visible = showPoints && !!(resizeable || rotateable)
|
|
187
|
+
rotateP.visible = showPoints && rotateable && resizeable && !hideRotatePoints
|
|
168
188
|
|
|
169
189
|
if (i % 2) { // top, right, bottom, left
|
|
170
190
|
|
|
191
|
+
resizeL = resizeLines[(i - 1) / 2]
|
|
192
|
+
resizeL.set(point)
|
|
193
|
+
|
|
194
|
+
resizeL.visible = resizeP.visible && !hideResizeLines
|
|
171
195
|
resizeP.visible = rotateP.visible = showPoints && !!middlePoint
|
|
172
196
|
|
|
173
197
|
if (((i + 1) / 2) % 2) { // top, bottom
|
|
@@ -175,7 +199,6 @@ export class EditBox extends Group implements IEditBox {
|
|
|
175
199
|
if (hideOnSmall && resizeP.width * 2 > width) resizeP.visible = false
|
|
176
200
|
} else {
|
|
177
201
|
resizeL.height = height
|
|
178
|
-
resizeP.rotation = 90
|
|
179
202
|
if (hideOnSmall && resizeP.width * 2 > height) resizeP.visible = false
|
|
180
203
|
}
|
|
181
204
|
}
|
|
@@ -238,11 +261,6 @@ export class EditBox extends Group implements IEditBox {
|
|
|
238
261
|
}
|
|
239
262
|
|
|
240
263
|
|
|
241
|
-
public unload(): void {
|
|
242
|
-
this.visible = false
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
|
|
246
264
|
public getPointStyle(userStyle?: IBoxInputData): IBoxInputData {
|
|
247
265
|
const { stroke, strokeWidth, pointFill, pointSize, pointRadius } = this.mergedConfig
|
|
248
266
|
const defaultStyle = { fill: pointFill, stroke, strokeWidth, around: 'center', strokeAlign: 'center', width: pointSize, height: pointSize, cornerRadius: pointRadius, offsetX: 0, offsetY: 0, editConfig } as IBoxInputData
|
|
@@ -251,31 +269,35 @@ export class EditBox extends Group implements IEditBox {
|
|
|
251
269
|
|
|
252
270
|
public getPointsStyle(): IBoxInputData[] {
|
|
253
271
|
const { point } = this.mergedConfig
|
|
254
|
-
return point
|
|
272
|
+
return isArray(point) ? point : [point]
|
|
255
273
|
}
|
|
256
274
|
|
|
257
275
|
public getMiddlePointsStyle(): IBoxInputData[] {
|
|
258
276
|
const { middlePoint } = this.mergedConfig
|
|
259
|
-
return middlePoint
|
|
277
|
+
return isArray(middlePoint) ? middlePoint : (middlePoint ? [middlePoint] : this.getPointsStyle())
|
|
260
278
|
}
|
|
261
279
|
|
|
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
280
|
|
|
269
281
|
// drag
|
|
270
282
|
|
|
271
283
|
protected onDragStart(e: DragEvent): void {
|
|
272
284
|
this.dragging = true
|
|
273
285
|
const point = this.dragPoint = e.current as IEditPoint, { pointType } = point
|
|
274
|
-
const { editor, dragStartData } = this, { target } = this
|
|
286
|
+
const { editor, dragStartData } = this, { target } = this, { moveable, resizeable, rotateable, skewable, hideOnMove } = this.mergeConfig
|
|
287
|
+
|
|
288
|
+
// 确定模式
|
|
275
289
|
if (point.name === 'rect') {
|
|
276
|
-
this.moving = true
|
|
277
|
-
editor.opacity =
|
|
290
|
+
moveable && (this.moving = true)
|
|
291
|
+
editor.opacity = hideOnMove ? 0 : 1 // move
|
|
292
|
+
} else {
|
|
293
|
+
if (pointType.includes('rotate') || this.isHoldRotateKey(e) || !resizeable) {
|
|
294
|
+
rotateable && (this.rotating = true)
|
|
295
|
+
if (pointType === 'resize-rotate') resizeable && (this.resizing = true)
|
|
296
|
+
else if (point.name === 'resize-line') skewable && (this.skewing = true), this.rotating = false
|
|
297
|
+
} else if (pointType === 'resize') resizeable && (this.resizing = true)
|
|
298
|
+
if (pointType === 'skew') skewable && (this.skewing = true)
|
|
278
299
|
}
|
|
300
|
+
|
|
279
301
|
dragStartData.x = e.x
|
|
280
302
|
dragStartData.y = e.y
|
|
281
303
|
dragStartData.point = { x: target.x, y: target.y } // 用于移动
|
|
@@ -285,37 +307,80 @@ export class EditBox extends Group implements IEditBox {
|
|
|
285
307
|
}
|
|
286
308
|
|
|
287
309
|
protected onDragEnd(e: DragEvent): void {
|
|
288
|
-
this.
|
|
310
|
+
if (this.mergeConfig.dragLimitAnimate && this.moving) this.transformTool.onMove(e)
|
|
311
|
+
|
|
289
312
|
this.dragPoint = null
|
|
290
|
-
this.
|
|
313
|
+
this.resetDoing()
|
|
291
314
|
const { name, pointType } = e.current as IEditPoint
|
|
292
315
|
if (name === 'rect') this.editor.opacity = 1 // move
|
|
293
316
|
if (pointType && pointType.includes('resize')) ResizeEvent.resizingKeys = null
|
|
294
317
|
}
|
|
295
318
|
|
|
296
319
|
protected onDrag(e: DragEvent): void {
|
|
297
|
-
const { transformTool
|
|
298
|
-
if (
|
|
320
|
+
const { transformTool, moving, resizing, rotating, skewing } = this
|
|
321
|
+
if (moving) {
|
|
299
322
|
transformTool.onMove(e)
|
|
300
323
|
updateMoveCursor(this)
|
|
301
|
-
} else {
|
|
302
|
-
const
|
|
303
|
-
if (pointType
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
324
|
+
} else if (resizing || rotating || skewing) {
|
|
325
|
+
const point = e.current as IEditPoint
|
|
326
|
+
if (point.pointType) this.enterPoint = point// 防止变化
|
|
327
|
+
if (rotating) transformTool.onRotate(e)
|
|
328
|
+
if (resizing) transformTool.onScale(e)
|
|
329
|
+
if (skewing) transformTool.onSkew(e)
|
|
330
|
+
updatePointCursor(this, e)
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
protected resetDoing(): void {
|
|
335
|
+
if (this.canUse) this.dragging = this.gesturing = this.moving = this.resizing = this.rotating = this.skewing = false
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// 手势控制元素
|
|
339
|
+
|
|
340
|
+
public onMove(e: MoveEvent): void {
|
|
341
|
+
if (this.canGesture && e.moveType !== 'drag') {
|
|
342
|
+
e.stop()
|
|
343
|
+
if (isString(this.mergeConfig.moveable)) {
|
|
344
|
+
this.gesturing = this.moving = true
|
|
345
|
+
this.transformTool.onMove(e)
|
|
346
|
+
}
|
|
309
347
|
}
|
|
310
348
|
}
|
|
311
349
|
|
|
350
|
+
public onScale(e: ZoomEvent): void {
|
|
351
|
+
if (this.canGesture) {
|
|
352
|
+
e.stop()
|
|
353
|
+
if (isString(this.mergeConfig.resizeable)) {
|
|
354
|
+
this.gesturing = this.resizing = true
|
|
355
|
+
this.transformTool.onScale(e)
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
public onRotate(e: RotateEvent): void {
|
|
361
|
+
if (this.canGesture) {
|
|
362
|
+
e.stop()
|
|
363
|
+
if (isString(this.mergeConfig.rotateable)) {
|
|
364
|
+
this.gesturing = this.rotating = true
|
|
365
|
+
this.transformTool.onRotate(e)
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// 键盘
|
|
371
|
+
public isHoldRotateKey(e: IUIEvent): boolean { // 按住ctrl在控制点上变旋转功能
|
|
372
|
+
const { rotateKey } = this.mergedConfig
|
|
373
|
+
if (rotateKey) return e.isHoldKeys(rotateKey)
|
|
374
|
+
return e.metaKey || e.ctrlKey
|
|
375
|
+
}
|
|
376
|
+
|
|
312
377
|
protected onKey(e: KeyEvent): void {
|
|
313
|
-
|
|
378
|
+
updatePointCursor(this, e)
|
|
314
379
|
}
|
|
315
380
|
|
|
316
381
|
public onArrow(e: IKeyEvent): void {
|
|
317
|
-
const { editor } = this
|
|
318
|
-
if (editor.editing && this.mergeConfig.keyEvent) {
|
|
382
|
+
const { editor, transformTool } = this
|
|
383
|
+
if (this.canUse && editor.editing && this.mergeConfig.keyEvent) {
|
|
319
384
|
let x = 0, y = 0
|
|
320
385
|
const distance = e.shiftKey ? 10 : 1
|
|
321
386
|
switch (e.code) {
|
|
@@ -331,7 +396,7 @@ export class EditBox extends Group implements IEditBox {
|
|
|
331
396
|
case 'ArrowRight':
|
|
332
397
|
x = distance
|
|
333
398
|
}
|
|
334
|
-
if (x || y)
|
|
399
|
+
if (x || y) transformTool.move(x, y)
|
|
335
400
|
}
|
|
336
401
|
}
|
|
337
402
|
|
|
@@ -376,7 +441,7 @@ export class EditBox extends Group implements IEditBox {
|
|
|
376
441
|
[DragEvent.END, this.onDragEnd, this],
|
|
377
442
|
[PointerEvent.LEAVE, () => { this.enterPoint = null }],
|
|
378
443
|
]
|
|
379
|
-
if (point.name !== 'circle') events.push([PointerEvent.ENTER, (e: PointerEvent) => { this.enterPoint = point,
|
|
444
|
+
if (point.name !== 'circle') events.push([PointerEvent.ENTER, (e: PointerEvent) => { this.enterPoint = point, updatePointCursor(this, e) }])
|
|
380
445
|
this.__eventIds.push(point.on_(events))
|
|
381
446
|
}
|
|
382
447
|
|
|
@@ -384,8 +449,6 @@ export class EditBox extends Group implements IEditBox {
|
|
|
384
449
|
const { rect, editor, __eventIds: events } = this
|
|
385
450
|
|
|
386
451
|
events.push(
|
|
387
|
-
editor.on_(EditorEvent.SELECT, this.onSelect, this),
|
|
388
|
-
|
|
389
452
|
rect.on_([
|
|
390
453
|
[DragEvent.START, this.onDragStart, this],
|
|
391
454
|
[DragEvent.DRAG, this.onDrag, this],
|
|
@@ -401,7 +464,13 @@ export class EditBox extends Group implements IEditBox {
|
|
|
401
464
|
events.push(
|
|
402
465
|
editor.app.on_([
|
|
403
466
|
[[KeyEvent.HOLD, KeyEvent.UP], this.onKey, this],
|
|
404
|
-
[KeyEvent.DOWN, this.onArrow, this]
|
|
467
|
+
[KeyEvent.DOWN, this.onArrow, this],
|
|
468
|
+
[MoveEvent.BEFORE_MOVE, this.onMove, this, true],
|
|
469
|
+
[ZoomEvent.BEFORE_ZOOM, this.onScale, this, true],
|
|
470
|
+
[RotateEvent.BEFORE_ROTATE, this.onRotate, this, true],
|
|
471
|
+
[MoveEvent.END, this.resetDoing, this],
|
|
472
|
+
[ZoomEvent.END, this.resetDoing, this],
|
|
473
|
+
[RotateEvent.END, this.resetDoing, this],
|
|
405
474
|
])
|
|
406
475
|
)
|
|
407
476
|
})
|
|
@@ -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
|
|
@@ -125,7 +125,7 @@ export class EditSelect extends Group implements IEditSelect {
|
|
|
125
125
|
|
|
126
126
|
} else if (this.allow(e.target)) {
|
|
127
127
|
|
|
128
|
-
if (!e
|
|
128
|
+
if (!this.isHoldMultipleSelectKey(e)) editor.target = null
|
|
129
129
|
|
|
130
130
|
}
|
|
131
131
|
}
|
|
@@ -209,7 +209,7 @@ export class EditSelect extends Group implements IEditSelect {
|
|
|
209
209
|
protected allowDrag(e: DragEvent) {
|
|
210
210
|
const { boxSelect, multipleSelect } = this.editor.mergeConfig
|
|
211
211
|
if (this.running && (multipleSelect && boxSelect) && !e.target.draggable) {
|
|
212
|
-
return (!this.editor.editing && this.allow(e.target)) || (e
|
|
212
|
+
return (!this.editor.editing && this.allow(e.target)) || (this.isHoldMultipleSelectKey(e) && !findOne(e.path))
|
|
213
213
|
} else {
|
|
214
214
|
return false
|
|
215
215
|
}
|
|
@@ -230,7 +230,13 @@ export class EditSelect extends Group implements IEditSelect {
|
|
|
230
230
|
|
|
231
231
|
public isMultipleSelect(e: IPointerEvent): boolean {
|
|
232
232
|
const { multipleSelect, continuousSelect } = this.editor.mergeConfig
|
|
233
|
-
return multipleSelect && (e
|
|
233
|
+
return multipleSelect && (this.isHoldMultipleSelectKey(e) || continuousSelect)
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
public isHoldMultipleSelectKey(e: IPointerEvent): boolean {
|
|
237
|
+
const { multipleSelectKey } = this.editor.mergedConfig
|
|
238
|
+
if (multipleSelectKey) return e.isHoldKeys(multipleSelectKey)
|
|
239
|
+
return e.shiftKey
|
|
234
240
|
}
|
|
235
241
|
|
|
236
242
|
protected __listenEvents(): void {
|
package/src/display/Stroker.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { IUI, ILeaferCanvas, IRenderOptions, IRectInputData, IMatrixWithOptionHalfData } from '@leafer-ui/interface'
|
|
2
|
-
import { Paint, UI, MatrixHelper, getBoundsData, getMatrixData, BoundsHelper, LeafBoundsHelper } from '@leafer-ui/draw'
|
|
2
|
+
import { Paint, UI, MatrixHelper, getBoundsData, getMatrixData, BoundsHelper, LeafBoundsHelper, isArray, isString } from '@leafer-ui/draw'
|
|
3
3
|
|
|
4
4
|
import { IStroker } from '@leafer-in/interface'
|
|
5
5
|
|
|
@@ -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
|
|
@@ -83,8 +84,8 @@ export class Stroker extends UI implements IStroker {
|
|
|
83
84
|
|
|
84
85
|
}
|
|
85
86
|
|
|
86
|
-
if (stroke)
|
|
87
|
-
if (fill)
|
|
87
|
+
if (stroke) isString(stroke) ? Paint.stroke(stroke, this, canvas) : Paint.strokes(stroke, this, canvas)
|
|
88
|
+
if (fill) isString(fill) ? Paint.fill(fill, this, canvas) : Paint.fills(fill, this, canvas)
|
|
88
89
|
}
|
|
89
90
|
}
|
|
90
91
|
|
|
@@ -101,5 +102,5 @@ export class Stroker extends UI implements IStroker {
|
|
|
101
102
|
|
|
102
103
|
function onTarget(stroker: Stroker): void {
|
|
103
104
|
const value = stroker.target
|
|
104
|
-
stroker.list = value ? (value
|
|
105
|
+
stroker.list = value ? (isArray(value) ? value : [value]) : []
|
|
105
106
|
}
|