@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/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
- const total = { x: e.totalX, y: e.totalY }
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
- if (this.mergeConfig.resizeable === 'zoom') {
172
- e.stop()
173
- this.scaleOf(element.getInnerPoint(e), e.scale, e.scale)
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
- let { around, lockRatio } = this.mergeConfig
195
+
179
196
  if (e.shiftKey || element.lockRatio) lockRatio = true
180
197
 
181
- const data = EditDataHelper.getScaleData(element.boxBounds, direction, e.getInnerMove(element), lockRatio, EditDataHelper.getAround(around, e.altKey))
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
- if (this.mergeConfig.rotateable === 'rotate') {
204
- e.stop()
205
- rotation = e.rotation, origin = element.getInnerPoint(e)
206
- } else return
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 worldOrigin = element.getWorldPoint(data.origin)
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
- public scaleOf(origin: IPointData | IAlign, scaleX: number, scaleY = scaleX, _resize?: boolean): void {
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 = element.getWorldPoint(LeafHelper.getInnerOrigin(element, origin))
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
- public rotateOf(origin: IPointData | IAlign, rotation: number): void {
282
- if (!this.mergeConfig.rotateable || this.element.locked) return
291
+ override flip(axis: IAxis): void {
292
+ if (this.element.locked) return
283
293
 
284
294
  const { element } = this
285
- const worldOrigin = element.getWorldPoint(LeafHelper.getInnerOrigin(element, origin))
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
- let transform: Matrix
299
+ this.editTool.onScale(event)
300
+ this.emitEvent(event)
301
+ }
289
302
 
290
- if (this.multiple) {
291
- const oldMatrix = new Matrix(element.worldTransform)
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
- public skewOf(origin: IPointData | IAlign, skewX: number, skewY = 0, _resize?: boolean): void {
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 = element.getWorldPoint(LeafHelper.getInnerOrigin(element, origin))
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
- let transform: Matrix
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
- const event = new EditorSkewEvent(EditorSkewEvent.SKEW, {
317
- target: element, editor: this, skewX, skewY, transform, worldOrigin
318
- })
328
+ protected getWorldOrigin(origin: IPointData | IAlign): IPointData {
329
+ return this.element.getWorldPoint(LeafHelper.getInnerOrigin(this.element, origin))
330
+ }
319
331
 
320
- this.editTool.onSkew(event)
321
- this.emitEvent(event)
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
@@ -33,6 +33,7 @@ export const config: IEditorConfig = {
33
33
 
34
34
  moveable: true,
35
35
  resizeable: true,
36
+ flipable: true,
36
37
  rotateable: true,
37
38
  skewable: true
38
39
  }
@@ -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, RotateEvent, ZoomEvent } from '@leafer-ui/core'
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
- const buttonVisible = showPoints && (circle.visible || this.buttons.children.length > 1)
161
- this.buttons.visible = buttonVisible
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 layoutButtons(): void {
167
- const { buttons, resizePoints } = this
168
- const { buttonsDirection, buttonsFixed, buttonsMargin, middlePoint } = this.editor.mergeConfig
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
- const point = resizePoints[direction * 2 + 1] // 4 map 8 direction
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 = index % 2 // left / right origin direction
182
- const margin = (buttonsMargin + (useWidth ? ((middlePoint ? point.width : 0) + buttons.boxBounds.width) : ((middlePoint ? point.height : 0) + buttons.boxBounds.height)) / 2) * sign
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)
@@ -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 __eventIds: IEventListenerId[] = []
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.config.pointer.hover && !app.interaction.dragging) {
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') this.checkAndSelect(e)
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 (this.editor.dragging) {
139
- this.onDragEnd()
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
 
@@ -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(bounds: IBoundsData, direction: Direction9, pointMove: IPointData, lockRatio: boolean | 'corner', around: IAround): IEditorScaleEvent {
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
- const { width, height } = bounds
15
+
16
+ const { boxBounds, widthRange, heightRange } = element
17
+ const { width, height } = startBounds
15
18
 
16
19
  if (around) {
17
- pointMove.x *= 2
18
- pointMove.y *= 2
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(pointMove.x) === width) pointMove.x += 0.1
23
- if (Math.abs(pointMove.y) === height) pointMove.y += 0.1
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 = (-pointMove.y + height) / height
26
- const rightScale = (pointMove.x + width) / width
27
- const bottomScale = (pointMove.y + height) / height
28
- const leftScale = (-pointMove.x + width) / width
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
- const scale = Math.sqrt(Math.abs(scaleX * scaleY))
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
- toPoint(around || align, bounds, origin)
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
  },