@leafer-in/editor 1.0.0 → 1.0.2
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 +209 -102
- package/dist/editor.esm.js +210 -103
- package/dist/editor.esm.min.js +1 -1
- package/dist/editor.js +209 -102
- package/dist/editor.min.cjs +1 -1
- package/dist/editor.min.js +1 -1
- package/package.json +5 -5
- package/src/Editor.ts +77 -58
- package/src/config.ts +1 -0
- package/src/display/EditBox.ts +37 -30
- package/src/display/EditMask.ts +1 -1
- package/src/display/EditSelect.ts +26 -10
- package/src/editor/cursor.ts +4 -0
- package/src/helper/EditDataHelper.ts +68 -14
- package/types/index.d.ts +15 -7
package/src/Editor.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { IGroupInputData, IUI, IEventListenerId, IPointData, ILeafList, IEditSize, IGroup, IObject, IAlign } from '@leafer-ui/interface'
|
|
2
|
-
import { Group, Rect, DataHelper, MathHelper, LeafList, Matrix, RenderEvent, LeafHelper } from '@leafer-ui/draw'
|
|
3
|
-
import { DragEvent, RotateEvent, KeyEvent, ZoomEvent } from '@leafer-ui/core'
|
|
1
|
+
import { IGroupInputData, IUI, IEventListenerId, IPointData, ILeafList, IEditSize, IGroup, IObject, IAlign, IAxis, IFunction, ILayoutBoundsData } from '@leafer-ui/interface'
|
|
2
|
+
import { Group, Rect, DataHelper, MathHelper, LeafList, Matrix, RenderEvent, LeafHelper, Direction9 } from '@leafer-ui/draw'
|
|
3
|
+
import { DragEvent, RotateEvent, KeyEvent, ZoomEvent, MoveEvent } from '@leafer-ui/core'
|
|
4
4
|
|
|
5
5
|
import { IEditBox, IEditPoint, IEditor, IEditorConfig, IEditTool, IEditorScaleEvent, IInnerEditor } from '@leafer-in/interface'
|
|
6
6
|
|
|
@@ -28,7 +28,7 @@ import { EditorGroupEvent } from './event/EditorGroupEvent'
|
|
|
28
28
|
|
|
29
29
|
export class Editor extends Group implements IEditor {
|
|
30
30
|
|
|
31
|
-
public config = config
|
|
31
|
+
public config = DataHelper.clone(config)
|
|
32
32
|
|
|
33
33
|
public get mergeConfig(): IEditorConfig {
|
|
34
34
|
const { element, config } = this
|
|
@@ -52,6 +52,7 @@ export class Editor extends Group implements IEditor {
|
|
|
52
52
|
public get editing(): boolean { return !!this.list.length }
|
|
53
53
|
public innerEditing: boolean
|
|
54
54
|
public get groupOpening(): boolean { return !!this.openedGroupList.length }
|
|
55
|
+
public resizeDirection?: Direction9
|
|
55
56
|
|
|
56
57
|
public get multiple(): boolean { return this.list.length > 1 }
|
|
57
58
|
public get single(): boolean { return this.list.length === 1 }
|
|
@@ -75,6 +76,7 @@ export class Editor extends Group implements IEditor {
|
|
|
75
76
|
public editMask: EditMask = new EditMask(this)
|
|
76
77
|
|
|
77
78
|
public dragStartPoint: IPointData
|
|
79
|
+
public dragStartBounds: ILayoutBoundsData
|
|
78
80
|
|
|
79
81
|
public targetEventIds: IEventListenerId[] = []
|
|
80
82
|
|
|
@@ -153,32 +155,47 @@ export class Editor extends Group implements IEditor {
|
|
|
153
155
|
|
|
154
156
|
// operate
|
|
155
157
|
|
|
156
|
-
public onMove(e: DragEvent): void {
|
|
157
|
-
|
|
158
|
+
public onMove(e: DragEvent | MoveEvent): void {
|
|
159
|
+
|
|
160
|
+
if (e instanceof MoveEvent) {
|
|
161
|
+
|
|
162
|
+
if (e.moveType !== 'drag') {
|
|
163
|
+
const { moveable, resizeable } = this.mergeConfig
|
|
164
|
+
const move = e.getLocalMove(this.element)
|
|
165
|
+
if (moveable === 'move') e.stop(), this.move(move.x, move.y)
|
|
166
|
+
else if (resizeable === 'zoom') e.stop()
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
} else {
|
|
170
|
+
|
|
171
|
+
const total = { x: e.totalX, y: e.totalY }
|
|
172
|
+
|
|
173
|
+
if (e.shiftKey) {
|
|
174
|
+
if (Math.abs(total.x) > Math.abs(total.y)) total.y = 0
|
|
175
|
+
else total.x = 0
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
this.move(DragEvent.getValidMove(this.element, this.dragStartPoint, total))
|
|
158
179
|
|
|
159
|
-
if (e.shiftKey) {
|
|
160
|
-
if (Math.abs(total.x) > Math.abs(total.y)) total.y = 0
|
|
161
|
-
else total.x = 0
|
|
162
180
|
}
|
|
163
181
|
|
|
164
|
-
this.move(DragEvent.getValidMove(this.element, this.dragStartPoint, total))
|
|
165
182
|
}
|
|
166
183
|
|
|
167
184
|
public onScale(e: DragEvent | ZoomEvent): void {
|
|
168
185
|
const { element } = this
|
|
186
|
+
let { around, lockRatio, resizeable, flipable, editSize } = this.mergeConfig
|
|
169
187
|
|
|
170
188
|
if (e instanceof ZoomEvent) {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
}
|
|
189
|
+
|
|
190
|
+
if (resizeable === 'zoom') e.stop(), this.scaleOf(element.getInnerPoint(e), e.scale, e.scale)
|
|
191
|
+
|
|
175
192
|
} else {
|
|
176
193
|
|
|
177
194
|
const { direction } = e.current as IEditPoint
|
|
178
|
-
|
|
195
|
+
|
|
179
196
|
if (e.shiftKey || element.lockRatio) lockRatio = true
|
|
180
197
|
|
|
181
|
-
const data = EditDataHelper.getScaleData(element.
|
|
198
|
+
const data = EditDataHelper.getScaleData(element, this.dragStartBounds, direction, e.getInnerTotal(element), lockRatio, EditDataHelper.getAround(around, e.altKey), flipable, this.multiple || editSize === 'scale')
|
|
182
199
|
|
|
183
200
|
if (this.editTool.onScaleWithDrag) {
|
|
184
201
|
data.drag = e
|
|
@@ -192,7 +209,7 @@ export class Editor extends Group implements IEditor {
|
|
|
192
209
|
}
|
|
193
210
|
|
|
194
211
|
public onRotate(e: DragEvent | RotateEvent): void {
|
|
195
|
-
const { skewable, around, rotateGap } = this.mergeConfig
|
|
212
|
+
const { skewable, rotateable, around, rotateGap } = this.mergeConfig
|
|
196
213
|
const { direction, name } = e.current as IEditPoint
|
|
197
214
|
if (skewable && name === 'resize-line') return this.onSkew(e as DragEvent)
|
|
198
215
|
|
|
@@ -200,15 +217,17 @@ export class Editor extends Group implements IEditor {
|
|
|
200
217
|
let origin: IPointData, rotation: number
|
|
201
218
|
|
|
202
219
|
if (e instanceof RotateEvent) {
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
220
|
+
|
|
221
|
+
if (rotateable === 'rotate') e.stop(), rotation = e.rotation, origin = element.getInnerPoint(e)
|
|
222
|
+
else return
|
|
223
|
+
|
|
207
224
|
} else {
|
|
225
|
+
|
|
208
226
|
const last = { x: e.x - e.moveX, y: e.y - e.moveY }
|
|
209
|
-
const data = EditDataHelper.getRotateData(element.boxBounds, direction, e.getInner(element), element.getInnerPoint(last), e.shiftKey ? null : (around || 'center'))
|
|
227
|
+
const data = EditDataHelper.getRotateData(element.boxBounds, direction, e.getInner(element), element.getInnerPoint(last), e.shiftKey ? null : (element.around || element.origin || around || 'center'))
|
|
210
228
|
rotation = data.rotation
|
|
211
229
|
origin = data.origin
|
|
230
|
+
|
|
212
231
|
}
|
|
213
232
|
|
|
214
233
|
rotation = MathHelper.getGapRotation(rotation, rotateGap, element.rotation)
|
|
@@ -250,77 +269,74 @@ export class Editor extends Group implements IEditor {
|
|
|
250
269
|
if (!this.mergeConfig.resizeable || this.element.locked) return
|
|
251
270
|
|
|
252
271
|
const { element } = this
|
|
253
|
-
const
|
|
254
|
-
const event = new EditorScaleEvent(EditorScaleEvent.SCALE, { ...data, target: element, editor: this, worldOrigin })
|
|
272
|
+
const event = new EditorScaleEvent(EditorScaleEvent.SCALE, { ...data, target: element, editor: this, worldOrigin: element.getWorldPoint(data.origin) })
|
|
255
273
|
|
|
256
274
|
this.editTool.onScaleWithDrag(event)
|
|
257
275
|
this.emitEvent(event)
|
|
258
276
|
}
|
|
259
277
|
|
|
260
278
|
|
|
261
|
-
|
|
279
|
+
override scaleOf(origin: IPointData | IAlign, scaleX: number, scaleY = scaleX, _resize?: boolean): void {
|
|
262
280
|
if (!this.mergeConfig.resizeable || this.element.locked) return
|
|
263
281
|
|
|
264
282
|
const { element } = this
|
|
265
|
-
const worldOrigin =
|
|
266
|
-
|
|
267
|
-
let transform: Matrix
|
|
268
|
-
|
|
269
|
-
if (this.multiple) {
|
|
270
|
-
const oldMatrix = new Matrix(element.worldTransform)
|
|
271
|
-
element.scaleOf(origin, scaleX, scaleY)
|
|
272
|
-
transform = new Matrix(element.worldTransform).divide(oldMatrix) // world change transform
|
|
273
|
-
}
|
|
274
|
-
|
|
283
|
+
const worldOrigin = this.getWorldOrigin(origin)
|
|
284
|
+
const transform = this.multiple && this.getChangedTransform(() => element.scaleOf(origin, scaleX, scaleY))
|
|
275
285
|
const event = new EditorScaleEvent(EditorScaleEvent.SCALE, { target: element, editor: this, worldOrigin, scaleX, scaleY, transform })
|
|
276
286
|
|
|
277
287
|
this.editTool.onScale(event)
|
|
278
288
|
this.emitEvent(event)
|
|
279
289
|
}
|
|
280
290
|
|
|
281
|
-
|
|
282
|
-
if (
|
|
291
|
+
override flip(axis: IAxis): void {
|
|
292
|
+
if (this.element.locked) return
|
|
283
293
|
|
|
284
294
|
const { element } = this
|
|
285
|
-
const worldOrigin =
|
|
286
|
-
|
|
295
|
+
const worldOrigin = this.getWorldOrigin('center')
|
|
296
|
+
const transform = this.multiple ? this.getChangedTransform(() => element.flip(axis)) : new Matrix(LeafHelper.getFlipTransform(element, axis))
|
|
297
|
+
const event = new EditorScaleEvent(EditorScaleEvent.SCALE, { target: element, editor: this, worldOrigin, scaleX: axis === 'x' ? -1 : 1, scaleY: axis === 'y' ? -1 : 1, transform })
|
|
287
298
|
|
|
288
|
-
|
|
299
|
+
this.editTool.onScale(event)
|
|
300
|
+
this.emitEvent(event)
|
|
301
|
+
}
|
|
289
302
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
element.rotateOf(origin, rotation)
|
|
293
|
-
transform = new Matrix(element.worldTransform).divide(oldMatrix) // world change transform
|
|
294
|
-
}
|
|
303
|
+
override rotateOf(origin: IPointData | IAlign, rotation: number): void {
|
|
304
|
+
if (!this.mergeConfig.rotateable || this.element.locked) return
|
|
295
305
|
|
|
306
|
+
const { element } = this
|
|
307
|
+
const worldOrigin = this.getWorldOrigin(origin)
|
|
308
|
+
const transform = this.multiple && this.getChangedTransform(() => element.rotateOf(origin, rotation))
|
|
296
309
|
const event = new EditorRotateEvent(EditorRotateEvent.ROTATE, { target: element, editor: this, worldOrigin, rotation, transform })
|
|
297
310
|
|
|
298
311
|
this.editTool.onRotate(event)
|
|
299
312
|
this.emitEvent(event)
|
|
300
313
|
}
|
|
301
314
|
|
|
302
|
-
|
|
315
|
+
override skewOf(origin: IPointData | IAlign, skewX: number, skewY = 0, _resize?: boolean): void {
|
|
303
316
|
if (!this.mergeConfig.skewable || this.element.locked) return
|
|
304
317
|
|
|
305
318
|
const { element } = this
|
|
306
|
-
const worldOrigin =
|
|
319
|
+
const worldOrigin = this.getWorldOrigin(origin)
|
|
320
|
+
const transform = this.multiple && this.getChangedTransform(() => element.skewOf(origin, skewX, skewY))
|
|
321
|
+
const event = new EditorSkewEvent(EditorSkewEvent.SKEW, { target: element, editor: this, worldOrigin, skewX, skewY, transform })
|
|
307
322
|
|
|
308
|
-
|
|
323
|
+
this.editTool.onSkew(event)
|
|
324
|
+
this.emitEvent(event)
|
|
325
|
+
}
|
|
309
326
|
|
|
310
|
-
if (this.multiple) {
|
|
311
|
-
const oldMatrix = new Matrix(element.worldTransform)
|
|
312
|
-
element.skewOf(origin, skewX, skewY)
|
|
313
|
-
transform = new Matrix(element.worldTransform).divide(oldMatrix) // world change transform
|
|
314
|
-
}
|
|
315
327
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
328
|
+
protected getWorldOrigin(origin: IPointData | IAlign): IPointData {
|
|
329
|
+
return this.element.getWorldPoint(LeafHelper.getInnerOrigin(this.element, origin))
|
|
330
|
+
}
|
|
319
331
|
|
|
320
|
-
|
|
321
|
-
this
|
|
332
|
+
protected getChangedTransform(func: IFunction): Matrix {
|
|
333
|
+
const { element } = this
|
|
334
|
+
const oldMatrix = new Matrix(element.worldTransform)
|
|
335
|
+
func()
|
|
336
|
+
return new Matrix(element.worldTransform).divide(oldMatrix) // world change transform
|
|
322
337
|
}
|
|
323
338
|
|
|
339
|
+
|
|
324
340
|
// group
|
|
325
341
|
|
|
326
342
|
public group(userGroup?: IGroup | IGroupInputData): IGroup {
|
|
@@ -455,6 +471,9 @@ export class Editor extends Group implements IEditor {
|
|
|
455
471
|
if (!this.targetEventIds.length) {
|
|
456
472
|
const { leafer } = this.list[0]
|
|
457
473
|
this.targetEventIds = [
|
|
474
|
+
this.app.on_(MoveEvent.BEFORE_MOVE, this.onMove, this, true),
|
|
475
|
+
this.app.on_(ZoomEvent.BEFORE_ZOOM, this.onScale, this, true),
|
|
476
|
+
this.app.on_(RotateEvent.BEFORE_ROTATE, this.onRotate, this, true),
|
|
458
477
|
leafer.on_(RenderEvent.START, this.update, this),
|
|
459
478
|
leafer.on_([KeyEvent.HOLD, KeyEvent.UP], (e: KeyEvent) => { updateCursor(this, e) }),
|
|
460
479
|
leafer.on_(KeyEvent.DOWN, this.editBox.onArrow, this.editBox)
|
package/src/config.ts
CHANGED
package/src/display/EditBox.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { IRect, IEventListenerId, IBoundsData, IPointData, IKeyEvent, IGroup, IBox, IBoxInputData, IAlign } from '@leafer-ui/interface'
|
|
1
|
+
import { IRect, IEventListenerId, IBoundsData, IPointData, IKeyEvent, IGroup, IBox, IBoxInputData, IAlign, IUI, IEditorConfig } from '@leafer-ui/interface'
|
|
2
2
|
import { Group, Box, AroundHelper, Direction9 } from '@leafer-ui/draw'
|
|
3
|
-
import { DragEvent, PointerEvent
|
|
3
|
+
import { DragEvent, PointerEvent } from '@leafer-ui/core'
|
|
4
4
|
|
|
5
5
|
import { IEditBox, IEditor, IEditPoint, IEditPointType } from '@leafer-in/interface'
|
|
6
6
|
|
|
@@ -22,7 +22,6 @@ export class EditBox extends Group implements IEditBox {
|
|
|
22
22
|
|
|
23
23
|
public rect: IBox = new Box({ name: 'rect', hitFill: 'all', hitStroke: 'none', strokeAlign: 'center', hitRadius: 5 }) // target rect
|
|
24
24
|
public circle: IEditPoint = new EditPoint({ name: 'circle', strokeAlign: 'center', around: 'center', cursor: 'crosshair', hitRadius: 5 }) // rotate point
|
|
25
|
-
|
|
26
25
|
public buttons: IGroup = new Group({ around: 'center', hitSelf: false })
|
|
27
26
|
|
|
28
27
|
public resizePoints: IEditPoint[] = [] // topLeft, top, topRight, right, bottomRight, bottom, bottomLeft, left
|
|
@@ -69,10 +68,9 @@ export class EditBox extends Group implements IEditBox {
|
|
|
69
68
|
this.listenPointEvents(resizePoint, 'resize', i)
|
|
70
69
|
}
|
|
71
70
|
|
|
72
|
-
buttons.add(circle)
|
|
73
71
|
this.listenPointEvents(circle, 'rotate', 2)
|
|
74
72
|
|
|
75
|
-
view.addMany(...rotatePoints, rect, buttons, ...resizeLines, ...resizePoints)
|
|
73
|
+
view.addMany(...rotatePoints, rect, circle, buttons, ...resizeLines, ...resizePoints)
|
|
76
74
|
this.add(view)
|
|
77
75
|
}
|
|
78
76
|
|
|
@@ -93,11 +91,11 @@ export class EditBox extends Group implements IEditBox {
|
|
|
93
91
|
}
|
|
94
92
|
|
|
95
93
|
// rotate
|
|
96
|
-
circle.set(this.getPointStyle(mergeConfig.rotatePoint || pointsStyle[0]))
|
|
94
|
+
circle.set(this.getPointStyle(mergeConfig.circle || mergeConfig.rotatePoint || pointsStyle[0]))
|
|
97
95
|
|
|
98
96
|
// rect
|
|
99
97
|
rect.set({ stroke, strokeWidth, ...(mergeConfig.rect || {}) })
|
|
100
|
-
rect.hittable = !single && moveable
|
|
98
|
+
rect.hittable = !single && !!moveable
|
|
101
99
|
|
|
102
100
|
// 编辑框作为底部虚拟元素, 在 onSelect 方法移除
|
|
103
101
|
element.syncEventer = (single && moveable) ? rect : null
|
|
@@ -111,7 +109,7 @@ export class EditBox extends Group implements IEditBox {
|
|
|
111
109
|
if (this.view.worldOpacity) {
|
|
112
110
|
const { mergeConfig } = this.editor
|
|
113
111
|
const { width, height } = bounds
|
|
114
|
-
const { rect, circle, resizePoints, rotatePoints, resizeLines } = this
|
|
112
|
+
const { rect, circle, buttons, resizePoints, rotatePoints, resizeLines } = this
|
|
115
113
|
const { middlePoint, resizeable, rotateable, hideOnSmall } = mergeConfig
|
|
116
114
|
|
|
117
115
|
const smallSize = typeof hideOnSmall === 'number' ? hideOnSmall : 10
|
|
@@ -150,36 +148,50 @@ export class EditBox extends Group implements IEditBox {
|
|
|
150
148
|
}
|
|
151
149
|
|
|
152
150
|
// rotate
|
|
153
|
-
circle.visible = showPoints && rotateable && !!mergeConfig.rotatePoint
|
|
151
|
+
circle.visible = showPoints && rotateable && !!(mergeConfig.circle || mergeConfig.rotatePoint)
|
|
152
|
+
if (circle.visible) this.layoutCircle(mergeConfig)
|
|
154
153
|
|
|
155
154
|
// rect
|
|
156
155
|
if (rect.path) rect.path = null // line可能会变成path优先模式
|
|
157
156
|
rect.set({ ...bounds, visible: true })
|
|
158
157
|
|
|
159
158
|
// buttons
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
if (buttonVisible) this.layoutButtons()
|
|
159
|
+
buttons.visible = showPoints && buttons.children.length > 0
|
|
160
|
+
if (buttons.visible) this.layoutButtons(mergeConfig)
|
|
163
161
|
}
|
|
164
162
|
}
|
|
165
163
|
|
|
166
|
-
protected
|
|
167
|
-
const {
|
|
168
|
-
const
|
|
164
|
+
protected layoutCircle(config: IEditorConfig): void {
|
|
165
|
+
const { circleDirection, circleMargin, buttonsMargin, buttonsDirection, middlePoint } = config
|
|
166
|
+
const direction = fourDirection.indexOf(circleDirection || ((this.buttons.children.length && buttonsDirection === 'bottom') ? 'top' : 'bottom'))
|
|
167
|
+
this.setButtonPosition(this.circle, direction, circleMargin || buttonsMargin, !!middlePoint)
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
protected layoutButtons(config: IEditorConfig): void {
|
|
171
|
+
const { buttons } = this
|
|
172
|
+
const { buttonsDirection, buttonsFixed, buttonsMargin, middlePoint } = config
|
|
169
173
|
|
|
170
174
|
const { flippedX, flippedY } = this
|
|
171
175
|
let index = fourDirection.indexOf(buttonsDirection)
|
|
172
176
|
if ((index % 2 && flippedX) || ((index + 1) % 2 && flippedY)) {
|
|
173
177
|
if (buttonsFixed) index = (index + 2) % 4 // flip x / y
|
|
174
178
|
}
|
|
179
|
+
|
|
175
180
|
const direction = buttonsFixed ? EditDataHelper.getRotateDirection(index, this.flippedOne ? this.rotation : -this.rotation, 4) : index
|
|
181
|
+
this.setButtonPosition(buttons, direction, buttonsMargin, !!middlePoint)
|
|
176
182
|
|
|
177
|
-
|
|
183
|
+
if (buttonsFixed) buttons.rotation = (direction - index) * 90
|
|
184
|
+
buttons.scaleX = flippedX ? -1 : 1
|
|
185
|
+
buttons.scaleY = flippedY ? -1 : 1
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
protected setButtonPosition(buttons: IUI, direction: number, buttonsMargin: number, useMiddlePoint: boolean): void {
|
|
189
|
+
const point = this.resizePoints[direction * 2 + 1] // 4 map 8 direction
|
|
178
190
|
const useX = direction % 2 // left / right
|
|
179
191
|
const sign = (!direction || direction === 3) ? -1 : 1 // top / left = -1
|
|
180
192
|
|
|
181
|
-
const useWidth =
|
|
182
|
-
const margin = (buttonsMargin + (useWidth ? ((
|
|
193
|
+
const useWidth = direction % 2 // left / right origin direction
|
|
194
|
+
const margin = (buttonsMargin + (useWidth ? ((useMiddlePoint ? point.width : 0) + buttons.boxBounds.width) : ((useMiddlePoint ? point.height : 0) + buttons.boxBounds.height)) / 2) * sign
|
|
183
195
|
|
|
184
196
|
if (useX) {
|
|
185
197
|
buttons.x = point.x + margin
|
|
@@ -188,15 +200,9 @@ export class EditBox extends Group implements IEditBox {
|
|
|
188
200
|
buttons.x = point.x
|
|
189
201
|
buttons.y = point.y + margin
|
|
190
202
|
}
|
|
191
|
-
|
|
192
|
-
if (buttonsFixed) {
|
|
193
|
-
buttons.rotation = (direction - index) * 90
|
|
194
|
-
buttons.scaleX = flippedX ? -1 : 1
|
|
195
|
-
buttons.scaleY = flippedY ? -1 : 1
|
|
196
|
-
}
|
|
197
|
-
|
|
198
203
|
}
|
|
199
204
|
|
|
205
|
+
|
|
200
206
|
public unload(): void {
|
|
201
207
|
this.visible = false
|
|
202
208
|
}
|
|
@@ -229,11 +235,14 @@ export class EditBox extends Group implements IEditBox {
|
|
|
229
235
|
|
|
230
236
|
protected onDragStart(e: DragEvent): void {
|
|
231
237
|
this.dragging = true
|
|
238
|
+
const { editor } = this
|
|
232
239
|
if (e.current.name === 'rect') {
|
|
233
|
-
const { editor } = this
|
|
234
240
|
this.moving = true
|
|
235
241
|
editor.dragStartPoint = { x: editor.element.x, y: editor.element.y }
|
|
236
242
|
editor.opacity = editor.mergeConfig.hideOnMove ? 0 : 1 // move
|
|
243
|
+
} else if ((e.current as IEditPoint).pointType === 'resize') {
|
|
244
|
+
editor.dragStartBounds = { ...editor.element.getLayoutBounds('box', 'local') }
|
|
245
|
+
editor.resizeDirection = (e.current as IEditPoint).direction
|
|
237
246
|
}
|
|
238
247
|
}
|
|
239
248
|
|
|
@@ -241,6 +250,7 @@ export class EditBox extends Group implements IEditBox {
|
|
|
241
250
|
this.dragging = false
|
|
242
251
|
this.moving = false
|
|
243
252
|
if (e.current.name === 'rect') this.editor.opacity = 1 // move
|
|
253
|
+
this.editor.resizeDirection = undefined
|
|
244
254
|
|
|
245
255
|
}
|
|
246
256
|
|
|
@@ -249,7 +259,7 @@ export class EditBox extends Group implements IEditBox {
|
|
|
249
259
|
const point = this.enterPoint = e.current as IEditPoint
|
|
250
260
|
if (point.pointType === 'rotate' || e.metaKey || e.ctrlKey || !editor.mergeConfig.resizeable) {
|
|
251
261
|
if (editor.mergeConfig.rotateable) editor.onRotate(e)
|
|
252
|
-
} else {
|
|
262
|
+
} else if (point.pointType === 'resize') {
|
|
253
263
|
editor.onScale(e)
|
|
254
264
|
}
|
|
255
265
|
updateCursor(editor, e)
|
|
@@ -319,9 +329,6 @@ export class EditBox extends Group implements IEditBox {
|
|
|
319
329
|
rect.on_(DragEvent.DRAG, editor.onMove, editor),
|
|
320
330
|
rect.on_(DragEvent.END, this.onDragEnd, this),
|
|
321
331
|
|
|
322
|
-
rect.on_(ZoomEvent.BEFORE_ZOOM, editor.onScale, editor, true),
|
|
323
|
-
rect.on_(RotateEvent.BEFORE_ROTATE, editor.onRotate, editor, true),
|
|
324
|
-
|
|
325
332
|
rect.on_(PointerEvent.ENTER, () => updateMoveCursor(editor)),
|
|
326
333
|
rect.on_(PointerEvent.DOUBLE_TAP, this.onDoubleTap, this),
|
|
327
334
|
rect.on_(PointerEvent.LONG_PRESS, this.onLongPress, this)
|
package/src/display/EditMask.ts
CHANGED
|
@@ -23,7 +23,7 @@ export class EditMask extends UI {
|
|
|
23
23
|
const { width, height } = rect.__
|
|
24
24
|
|
|
25
25
|
canvas.resetTransform()
|
|
26
|
-
canvas.fillWorld(canvas.bounds, mask)
|
|
26
|
+
canvas.fillWorld(canvas.bounds, mask === true ? 'rgba(0,0,0,0.8)' : mask)
|
|
27
27
|
canvas.setWorld(rect.__world, options.matrix)
|
|
28
28
|
canvas.clearRect(0, 0, width, height)
|
|
29
29
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { IBounds, ILeaf, ILeafList, IUI, IEventListenerId, IPointerEvent } from '@leafer-ui/interface'
|
|
1
|
+
import { IBounds, ILeaf, ILeafList, IUI, IEventListenerId, IPointerEvent, IFunction } from '@leafer-ui/interface'
|
|
2
2
|
import { Bounds, LeafList, Group } from '@leafer-ui/draw'
|
|
3
3
|
import { PointerEvent, DragEvent, MoveEvent, ZoomEvent } from '@leafer-ui/core'
|
|
4
4
|
|
|
@@ -29,8 +29,9 @@ export class EditSelect extends Group implements IEditSelect {
|
|
|
29
29
|
protected originList: ILeafList
|
|
30
30
|
protected needRemoveItem: IUI
|
|
31
31
|
|
|
32
|
-
protected
|
|
32
|
+
protected waitSelect: IFunction // 手机端延迟选中,防止多点触屏误选元素
|
|
33
33
|
|
|
34
|
+
protected __eventIds: IEventListenerId[] = []
|
|
34
35
|
|
|
35
36
|
constructor(editor: IEditor) {
|
|
36
37
|
super()
|
|
@@ -68,7 +69,7 @@ export class EditSelect extends Group implements IEditSelect {
|
|
|
68
69
|
|
|
69
70
|
protected onPointerMove(e: PointerEvent): void {
|
|
70
71
|
const { app, editor } = this
|
|
71
|
-
if (this.running && !this.isMoveMode && app.
|
|
72
|
+
if (this.running && !this.isMoveMode && app.interaction.canHover && !app.interaction.dragging) {
|
|
72
73
|
const find = this.findUI(e)
|
|
73
74
|
editor.hoverTarget = editor.hasItem(find) ? null : find
|
|
74
75
|
} if (this.isMoveMode) {
|
|
@@ -77,14 +78,26 @@ export class EditSelect extends Group implements IEditSelect {
|
|
|
77
78
|
}
|
|
78
79
|
|
|
79
80
|
protected onBeforeDown(e: PointerEvent): void {
|
|
81
|
+
if (e.multiTouch) return
|
|
82
|
+
|
|
80
83
|
const { select } = this.editor.mergeConfig
|
|
81
|
-
if (select === 'press')
|
|
84
|
+
if (select === 'press') {
|
|
85
|
+
if (this.app.config.mobile) {
|
|
86
|
+
this.waitSelect = () => this.checkAndSelect(e)
|
|
87
|
+
} else {
|
|
88
|
+
this.checkAndSelect(e)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
82
91
|
}
|
|
83
92
|
|
|
84
93
|
protected onTap(e: PointerEvent): void {
|
|
94
|
+
if (e.multiTouch) return
|
|
95
|
+
|
|
85
96
|
const { editor } = this
|
|
86
97
|
const { select } = editor.mergeConfig
|
|
98
|
+
|
|
87
99
|
if (select === 'tap') this.checkAndSelect(e)
|
|
100
|
+
else if (this.waitSelect) this.waitSelect()
|
|
88
101
|
|
|
89
102
|
if (this.needRemoveItem) {
|
|
90
103
|
editor.removeItem(this.needRemoveItem)
|
|
@@ -120,6 +133,9 @@ export class EditSelect extends Group implements IEditSelect {
|
|
|
120
133
|
// drag
|
|
121
134
|
|
|
122
135
|
protected onDragStart(e: DragEvent): void {
|
|
136
|
+
if (e.multiTouch) return
|
|
137
|
+
if (this.waitSelect) this.waitSelect()
|
|
138
|
+
|
|
123
139
|
if (this.allowDrag(e)) {
|
|
124
140
|
const { editor } = this
|
|
125
141
|
const { stroke, area } = editor.mergeConfig
|
|
@@ -135,10 +151,8 @@ export class EditSelect extends Group implements IEditSelect {
|
|
|
135
151
|
}
|
|
136
152
|
|
|
137
153
|
protected onDrag(e: DragEvent): void {
|
|
138
|
-
if (
|
|
139
|
-
|
|
140
|
-
return
|
|
141
|
-
}
|
|
154
|
+
if (e.multiTouch) return
|
|
155
|
+
if (this.editor.dragging) return this.onDragEnd(e)
|
|
142
156
|
|
|
143
157
|
if (this.dragging) {
|
|
144
158
|
const { editor } = this
|
|
@@ -171,7 +185,9 @@ export class EditSelect extends Group implements IEditSelect {
|
|
|
171
185
|
}
|
|
172
186
|
}
|
|
173
187
|
|
|
174
|
-
protected onDragEnd(): void {
|
|
188
|
+
protected onDragEnd(e: DragEvent): void {
|
|
189
|
+
if (e.multiTouch) return
|
|
190
|
+
|
|
175
191
|
if (this.dragging) this.originList = null, this.selectArea.visible = false
|
|
176
192
|
}
|
|
177
193
|
|
|
@@ -229,7 +245,7 @@ export class EditSelect extends Group implements IEditSelect {
|
|
|
229
245
|
app.on_(PointerEvent.BEFORE_DOWN, this.onBeforeDown, this),
|
|
230
246
|
app.on_(PointerEvent.TAP, this.onTap, this),
|
|
231
247
|
|
|
232
|
-
app.on_(DragEvent.START, this.onDragStart, this),
|
|
248
|
+
app.on_(DragEvent.START, this.onDragStart, this, true), // 采用捕获事件,需要比EditBox中的dragStart早触发
|
|
233
249
|
app.on_(DragEvent.DRAG, this.onDrag, this),
|
|
234
250
|
app.on_(DragEvent.END, this.onDragEnd, this),
|
|
235
251
|
|
package/src/editor/cursor.ts
CHANGED
|
@@ -12,6 +12,10 @@ export function updateCursor(editor: IEditor, e: IUIEvent): void {
|
|
|
12
12
|
const { editBox } = editor, point = editBox.enterPoint
|
|
13
13
|
if (!point || !editor.editing || !editBox.visible) return
|
|
14
14
|
if (point.name === 'circle') return // 独立旋转按钮
|
|
15
|
+
if (point.pointType === 'button') { // 普通按钮
|
|
16
|
+
if (!point.cursor) point.cursor = 'pointer'
|
|
17
|
+
return
|
|
18
|
+
}
|
|
15
19
|
|
|
16
20
|
let { rotation } = editBox
|
|
17
21
|
const { resizeCursor, rotateCursor, skewCursor, resizeable, rotateable, skewable } = editor.mergeConfig
|
|
@@ -1,31 +1,49 @@
|
|
|
1
|
-
import { IBoundsData, IPointData, IAround, IAlign } from '@leafer-ui/interface'
|
|
2
|
-
import { AroundHelper, PointHelper, Direction9 } from '@leafer-ui/draw'
|
|
1
|
+
import { IBoundsData, IPointData, IAround, IAlign, IUI, ILayoutBoundsData } from '@leafer-ui/interface'
|
|
2
|
+
import { AroundHelper, MathHelper, PointHelper, Direction9 } from '@leafer-ui/draw'
|
|
3
3
|
|
|
4
4
|
import { IEditorScaleEvent, IEditorSkewEvent, IEditorRotateEvent } from '@leafer-in/interface'
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
const { topLeft, top, topRight, right, bottomRight, bottom, bottomLeft, left } = Direction9
|
|
8
8
|
const { toPoint } = AroundHelper
|
|
9
|
+
const { within } = MathHelper
|
|
9
10
|
|
|
10
11
|
export const EditDataHelper = {
|
|
11
12
|
|
|
12
|
-
getScaleData(
|
|
13
|
+
getScaleData(element: IUI, startBounds: ILayoutBoundsData, direction: Direction9, totalMove: IPointData, lockRatio: boolean | 'corner', around: IAround, flipable: boolean, scaleMode: boolean): IEditorScaleEvent {
|
|
13
14
|
let align: IAlign, origin = {} as IPointData, scaleX: number = 1, scaleY: number = 1
|
|
14
|
-
|
|
15
|
+
|
|
16
|
+
const { boxBounds, widthRange, heightRange } = element
|
|
17
|
+
const { width, height } = startBounds
|
|
15
18
|
|
|
16
19
|
if (around) {
|
|
17
|
-
|
|
18
|
-
|
|
20
|
+
totalMove.x *= 2
|
|
21
|
+
totalMove.y *= 2
|
|
19
22
|
}
|
|
20
23
|
|
|
24
|
+
|
|
25
|
+
// 获取已经改变的比例
|
|
26
|
+
const originChangedScaleX = element.scaleX / startBounds.scaleX
|
|
27
|
+
const originChangedScaleY = element.scaleY / startBounds.scaleY
|
|
28
|
+
const signX = originChangedScaleX < 0 ? -1 : 1
|
|
29
|
+
const signY = originChangedScaleY < 0 ? -1 : 1
|
|
30
|
+
|
|
31
|
+
const changedScaleX = scaleMode ? originChangedScaleX : signX * boxBounds.width / width
|
|
32
|
+
const changedScaleY = scaleMode ? originChangedScaleY : signY * boxBounds.height / height
|
|
33
|
+
|
|
34
|
+
totalMove.x *= scaleMode ? originChangedScaleX : signX
|
|
35
|
+
totalMove.y *= scaleMode ? originChangedScaleY : signY
|
|
36
|
+
|
|
37
|
+
|
|
21
38
|
// 防止变为0
|
|
22
|
-
if (Math.abs(
|
|
23
|
-
if (Math.abs(
|
|
39
|
+
if (Math.abs(totalMove.x) === width) totalMove.x += 0.1
|
|
40
|
+
if (Math.abs(totalMove.y) === height) totalMove.y += 0.1
|
|
41
|
+
|
|
24
42
|
|
|
25
|
-
const topScale = (-
|
|
26
|
-
const rightScale = (
|
|
27
|
-
const bottomScale = (
|
|
28
|
-
const leftScale = (-
|
|
43
|
+
const topScale = (-totalMove.y + height) / height
|
|
44
|
+
const rightScale = (totalMove.x + width) / width
|
|
45
|
+
const bottomScale = (totalMove.y + height) / height
|
|
46
|
+
const leftScale = (-totalMove.x + width) / width
|
|
29
47
|
|
|
30
48
|
switch (direction) {
|
|
31
49
|
case top:
|
|
@@ -68,13 +86,49 @@ export const EditDataHelper = {
|
|
|
68
86
|
if (lockRatio) {
|
|
69
87
|
const unlockSide = lockRatio === 'corner' && direction % 2
|
|
70
88
|
if (!unlockSide) {
|
|
71
|
-
|
|
89
|
+
let scale: number
|
|
90
|
+
switch (direction) {
|
|
91
|
+
case top:
|
|
92
|
+
case bottom:
|
|
93
|
+
scale = scaleY
|
|
94
|
+
break
|
|
95
|
+
case left:
|
|
96
|
+
case right:
|
|
97
|
+
scale = scaleX
|
|
98
|
+
break
|
|
99
|
+
default:
|
|
100
|
+
scale = Math.sqrt(Math.abs(scaleX * scaleY))
|
|
101
|
+
|
|
102
|
+
}
|
|
72
103
|
scaleX = scaleX < 0 ? -scale : scale
|
|
73
104
|
scaleY = scaleY < 0 ? -scale : scale
|
|
74
105
|
}
|
|
75
106
|
}
|
|
76
107
|
|
|
77
|
-
|
|
108
|
+
|
|
109
|
+
scaleX /= changedScaleX
|
|
110
|
+
scaleY /= changedScaleY
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
if (!flipable) {
|
|
114
|
+
const { worldTransform } = element
|
|
115
|
+
if (scaleX < 0) scaleX = 1 / boxBounds.width / worldTransform.scaleX
|
|
116
|
+
if (scaleY < 0) scaleY = 1 / boxBounds.height / worldTransform.scaleY
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
if (widthRange) {
|
|
121
|
+
const nowWidth = boxBounds.width * element.scaleX
|
|
122
|
+
scaleX = within(nowWidth * scaleX, widthRange) / nowWidth
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (heightRange) {
|
|
126
|
+
const nowHeight = boxBounds.height * element.scaleY
|
|
127
|
+
scaleY = within(nowHeight * scaleY, heightRange) / nowHeight
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
toPoint(around || align, boxBounds, origin)
|
|
78
132
|
|
|
79
133
|
return { origin, scaleX, scaleY, direction, lockRatio, around }
|
|
80
134
|
},
|