@leafer-in/editor 1.6.7 → 1.7.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.
@@ -29,10 +29,11 @@ export class EditMask extends UI {
29
29
  if (options.bounds && !options.bounds.hit(editor.editBox.rect.__world, options.matrix)) return
30
30
 
31
31
  canvas.saveBlendMode('destination-out')
32
+ options = { ...options, shape: true }
32
33
  editor.list.forEach(item => {
33
- item.__renderShape(canvas, options)
34
- const { __box, parent } = item
35
- if ((item = __box) || ((item = parent) && (parent as IBox).textBox)) item.__renderShape(canvas, options) // 文本框
34
+ item.__render(canvas, options)
35
+ const { parent } = item
36
+ if (parent && (parent as IBox).textBox) parent.__renderShape(canvas, options) // 文本框
36
37
  })
37
38
  canvas.restoreBlendMode()
38
39
  }
@@ -1,6 +1,6 @@
1
1
  import { IObject, IUIEvent } from '@leafer-ui/interface'
2
2
 
3
- import { IEditor } from '@leafer-in/interface'
3
+ import { IEditBox } from '@leafer-in/interface'
4
4
  import { MathHelper } from '@leafer-ui/draw'
5
5
 
6
6
  import { EditDataHelper } from '../helper/EditDataHelper'
@@ -8,18 +8,17 @@ import { EditDataHelper } from '../helper/EditDataHelper'
8
8
 
9
9
  const cacheCursors: IObject = {}
10
10
 
11
- export function updateCursor(editor: IEditor, e: IUIEvent): void {
12
- const { editBox } = editor, point = editBox.enterPoint
13
- if (!point || !editor.editing || !editBox.visible) return
11
+ export function updateCursor(editBox: IEditBox, e: IUIEvent): void {
12
+ const { enterPoint: point } = editBox
13
+ if (!point || !editBox.editor.editing || !editBox.visible) return
14
14
  if (point.name === 'circle') return // 独立旋转按钮
15
15
  if (point.pointType === 'button') { // 普通按钮
16
16
  if (!point.cursor) point.cursor = 'pointer'
17
17
  return
18
18
  }
19
19
 
20
- let { rotation } = editBox
21
- const { resizeCursor, rotateCursor, skewCursor, resizeable, rotateable, skewable } = editor.mergeConfig
22
- const { pointType } = point, { flippedX, flippedY } = editBox
20
+ let { rotation, flippedX, flippedY } = editBox
21
+ const { pointType } = point, { resizeCursor, rotateCursor, skewCursor, resizeable, rotateable, skewable } = editBox.mergeConfig
23
22
 
24
23
  let showResize = pointType.includes('resize')
25
24
  if (showResize && rotateable && (e.metaKey || e.ctrlKey || !resizeable)) showResize = false
@@ -39,9 +38,9 @@ export function updateCursor(editor: IEditor, e: IUIEvent): void {
39
38
  }
40
39
  }
41
40
 
42
- export function updateMoveCursor(editor: IEditor): void {
43
- const { moveCursor, moveable } = editor.mergeConfig
44
- editor.editBox.rect.cursor = moveable ? moveCursor : undefined
41
+ export function updateMoveCursor(editBox: IEditBox): void {
42
+ const { moveCursor, moveable } = editBox.mergeConfig
43
+ editBox.rect.cursor = moveable ? moveCursor : undefined
45
44
  }
46
45
 
47
46
 
@@ -1,4 +1,4 @@
1
- import { IGroup, ILeaf } from '@leafer-ui/interface'
1
+ import { ILeaf } from '@leafer-ui/interface'
2
2
  import { Bounds } from '@leafer-ui/draw'
3
3
 
4
4
  import { IEditor } from '@leafer-in/interface'
@@ -8,7 +8,7 @@ const bounds = new Bounds()
8
8
 
9
9
  export function simulate(editor: IEditor) {
10
10
  const { simulateTarget, list } = editor
11
- const { zoomLayer } = list[0].leafer.zoomLayer as IGroup // follow zoomLayer zoom / move
11
+ const { zoomLayer } = list[0].leafer // follow zoomLayer zoom / move
12
12
  simulateTarget.safeChange(() => {
13
13
  bounds.setListWithFn(list, (leaf: ILeaf) => leaf.getBounds('box', 'page'))
14
14
  if (bounds.width === 0) bounds.width = 0.1 // fix
@@ -3,7 +3,6 @@ import { LeafList } from '@leafer-ui/draw'
3
3
  import { IEditor, IUI } from '@leafer-in/interface'
4
4
 
5
5
  import { simulate } from './simulate'
6
- import { updateMoveCursor } from './cursor'
7
6
  import { EditorEvent } from '../event/EditorEvent'
8
7
 
9
8
 
@@ -15,23 +14,25 @@ export function onTarget(editor: IEditor, oldValue: IUI | IUI[]): void {
15
14
  } else {
16
15
  editor.simulateTarget.remove()
17
16
  editor.leafList.reset()
18
- editor.closeInnerEditor()
19
17
  }
20
18
 
21
- editor.emitEvent(new EditorEvent(EditorEvent.SELECT, { editor, value: target, oldValue }))
19
+ editor.closeInnerEditor()
20
+
21
+ const data = { editor, value: target, oldValue }
22
+ editor.emitEvent(new EditorEvent(EditorEvent.SELECT, data))
22
23
  editor.checkOpenedGroups()
23
24
 
24
25
  if (editor.editing) {
25
26
  editor.waitLeafer(() => {
26
- updateMoveCursor(editor)
27
27
  editor.updateEditTool()
28
- editor.update()
29
28
  editor.listenTargetEvents()
30
29
  })
31
30
  } else {
32
31
  editor.updateEditTool()
33
32
  editor.removeTargetEvents()
34
33
  }
34
+
35
+ editor.emitEvent(new EditorEvent(EditorEvent.AFTER_SELECT, data))
35
36
  }
36
37
 
37
38
 
@@ -12,6 +12,7 @@ export class EditorEvent extends Event implements IEditorEvent {
12
12
 
13
13
  static BEFORE_SELECT = 'editor.before_select'
14
14
  static SELECT = 'editor.select'
15
+ static AFTER_SELECT = 'editor.after_select'
15
16
 
16
17
  static BEFORE_HOVER = 'editor.before_hover'
17
18
  static HOVER = 'editor.hover'
@@ -10,10 +10,10 @@ const { within } = MathHelper
10
10
 
11
11
  export const EditDataHelper = {
12
12
 
13
- getScaleData(element: IUI, startBounds: ILayoutBoundsData, direction: Direction9, totalMove: IPointData, lockRatio: boolean | 'corner', around: IAround, flipable: boolean, scaleMode: boolean): IEditorScaleEvent {
13
+ getScaleData(target: IUI, startBounds: ILayoutBoundsData, direction: Direction9, totalMove: IPointData, lockRatio: boolean | 'corner', around: IAround, flipable: boolean, scaleMode: boolean): IEditorScaleEvent {
14
14
  let align: IAlign, origin = {} as IPointData, scaleX: number = 1, scaleY: number = 1
15
15
 
16
- const { boxBounds, widthRange, heightRange, dragBounds, worldBoxBounds } = element
16
+ const { boxBounds, widthRange, heightRange, dragBounds, worldBoxBounds } = target
17
17
  const { width, height } = startBounds
18
18
 
19
19
  if (around) {
@@ -23,8 +23,8 @@ export const EditDataHelper = {
23
23
 
24
24
 
25
25
  // 获取已经改变的比例
26
- const originChangedScaleX = element.scaleX / startBounds.scaleX
27
- const originChangedScaleY = element.scaleY / startBounds.scaleY
26
+ const originChangedScaleX = target.scaleX / startBounds.scaleX
27
+ const originChangedScaleY = target.scaleY / startBounds.scaleY
28
28
  const signX = originChangedScaleX < 0 ? -1 : 1
29
29
  const signY = originChangedScaleY < 0 ? -1 : 1
30
30
 
@@ -105,7 +105,7 @@ export const EditDataHelper = {
105
105
  if (useScaleY) scaleY /= changedScaleY
106
106
 
107
107
  if (!flipable) {
108
- const { worldTransform } = element
108
+ const { worldTransform } = target
109
109
  if (scaleX < 0) scaleX = 1 / boxBounds.width / worldTransform.scaleX
110
110
  if (scaleY < 0) scaleY = 1 / boxBounds.height / worldTransform.scaleY
111
111
  }
@@ -115,9 +115,9 @@ export const EditDataHelper = {
115
115
  toPoint(around || align, boxBounds, origin, true)
116
116
 
117
117
  if (dragBounds) {
118
- const allowBounds = dragBounds === 'parent' ? element.parent.boxBounds : dragBounds
119
- const localBounds = new Bounds(element.__localBoxBounds)
120
- localBounds.scaleOf(element.getLocalPointByInner(origin), scaleX, scaleY)
118
+ const allowBounds = dragBounds === 'parent' ? target.parent.boxBounds : dragBounds
119
+ const localBounds = new Bounds(target.__localBoxBounds)
120
+ localBounds.scaleOf(target.getLocalPointByInner(origin), scaleX, scaleY)
121
121
 
122
122
  if (!BoundsHelper.includes(allowBounds, localBounds)) {
123
123
  const realBounds = localBounds.getIntersect(allowBounds)
@@ -128,12 +128,12 @@ export const EditDataHelper = {
128
128
  }
129
129
 
130
130
  if (useScaleX && widthRange) {
131
- const nowWidth = boxBounds.width * element.scaleX
131
+ const nowWidth = boxBounds.width * target.scaleX
132
132
  scaleX = within(nowWidth * scaleX, widthRange) / nowWidth
133
133
  }
134
134
 
135
135
  if (useScaleY && heightRange) {
136
- const nowHeight = boxBounds.height * element.scaleY
136
+ const nowHeight = boxBounds.height * target.scaleY
137
137
  scaleY = within(nowHeight * scaleY, heightRange) / nowHeight
138
138
  }
139
139
 
@@ -146,7 +146,7 @@ export const EditDataHelper = {
146
146
  return { origin, scaleX, scaleY, direction, lockRatio, around }
147
147
  },
148
148
 
149
- getRotateData(bounds: IBoundsData, direction: Direction9, current: IPointData, last: IPointData, around: IAround): IEditorRotateEvent {
149
+ getRotateData(target: IUI, direction: Direction9, current: IPointData, last: IPointData, around: IAround): IEditorRotateEvent {
150
150
  let align: IAlign, origin = {} as IPointData
151
151
 
152
152
  switch (direction) {
@@ -166,9 +166,9 @@ export const EditDataHelper = {
166
166
  align = 'center'
167
167
  }
168
168
 
169
- toPoint(around || align, bounds, origin, true)
169
+ toPoint(around || align, target.boxBounds, origin, true)
170
170
 
171
- return { origin, rotation: PointHelper.getRotation(last, origin, current) }
171
+ return { origin, rotation: PointHelper.getRotation(last, target.getWorldPointByBox(origin), current) }
172
172
  },
173
173
 
174
174
  getSkewData(bounds: IBoundsData, direction: Direction9, move: IPointData, around: IAround): IEditorSkewEvent {
package/src/index.ts CHANGED
@@ -19,6 +19,8 @@ export { EditToolCreator, registerEditTool, registerInnerEditor } from './tool/E
19
19
  export { InnerEditor } from './tool/InnerEditor'
20
20
  export { EditTool } from './tool/EditTool'
21
21
  export { LineEditTool } from './tool/LineEditTool'
22
+ export { TransformTool } from './tool/TransformTool'
23
+
22
24
 
23
25
  export { EditorHelper } from './helper/EditorHelper'
24
26
  export { EditDataHelper } from './helper/EditDataHelper'
@@ -69,10 +69,7 @@ export class EditTool extends InnerEditor implements IEditTool {
69
69
  }
70
70
 
71
71
  public update(): void {
72
- const { editor, editBox } = this
73
- const { x, y, scaleX, scaleY, rotation, skewX, skewY, width, height } = editor.element.getLayoutBounds('box', editor, true)
74
- editBox.set({ x, y, scaleX, scaleY, rotation, skewX, skewY })
75
- editBox.update({ x: 0, y: 0, width, height })
72
+ this.editBox.update()
76
73
  this.onUpdate()
77
74
  }
78
75
 
@@ -1,5 +1,5 @@
1
1
  import { IGroup, IEventListenerId, IUI, IObject } from '@leafer-ui/interface'
2
- import { IInnerEditor, IEditor, IEditBox } from '@leafer-in/interface'
2
+ import { IInnerEditor, IEditor, IEditBox, IInnerEditorMode } from '@leafer-in/interface'
3
3
 
4
4
  import { Group } from '@leafer-ui/draw'
5
5
  import { EditToolCreator } from './EditToolCreator'
@@ -13,6 +13,8 @@ export class InnerEditor implements IInnerEditor {
13
13
 
14
14
  public get tag() { return 'InnerEditor' }
15
15
 
16
+ public get mode(): IInnerEditorMode { return 'focus' } // 专注模式
17
+
16
18
  public editTarget: IUI
17
19
 
18
20
  public config: IObject
@@ -22,7 +24,7 @@ export class InnerEditor implements IInnerEditor {
22
24
 
23
25
  public view: IGroup
24
26
 
25
- public eventIds: IEventListenerId[]
27
+ public eventIds: IEventListenerId[] = []
26
28
 
27
29
 
28
30
  constructor(editor: IEditor) {
@@ -44,7 +46,7 @@ export class InnerEditor implements IInnerEditor {
44
46
  public load(): void {
45
47
  const { editor } = this
46
48
  if (editor) {
47
- if (editor.app) editor.selector.hittable = editor.app.tree.hitChildren = false
49
+ if (editor.app && this.mode === 'focus') editor.selector.hittable = editor.app.tree.hitChildren = false
48
50
  this.onLoad()
49
51
  }
50
52
  }
@@ -56,7 +58,7 @@ export class InnerEditor implements IInnerEditor {
56
58
  public unload(): void {
57
59
  const { editor } = this
58
60
  if (editor) {
59
- if (editor.app) editor.selector.hittable = editor.app.tree.hitChildren = true
61
+ if (editor.app && this.mode === 'focus') editor.selector.hittable = editor.app.tree.hitChildren = true
60
62
  this.onUnload()
61
63
  }
62
64
  }
@@ -0,0 +1,294 @@
1
+ import { IEvent, IPointData, IAlign, IAxis, IFunction, IMatrix } from '@leafer-ui/interface'
2
+ import { MathHelper, Matrix, LeafHelper } from '@leafer-ui/draw'
3
+ import { DragEvent, RotateEvent, ZoomEvent, MoveEvent } from '@leafer-ui/core'
4
+
5
+ import { IEditBox, IEditPoint, IEditTool, IEditorScaleEvent, ISimulateElement, IEditorMoveEvent, IEditorRotateEvent, IEditorSkewEvent } from '@leafer-in/interface'
6
+
7
+ import { EditorMoveEvent } from '../event/EditorMoveEvent'
8
+ import { EditorScaleEvent } from '../event/EditorScaleEvent'
9
+ import { EditorRotateEvent } from '../event/EditorRotateEvent'
10
+ import { EditorSkewEvent } from '../event/EditorSkewEvent'
11
+
12
+ import { EditDataHelper } from '../helper/EditDataHelper'
13
+ import { ITransformTool } from '@leafer-ui/interface'
14
+
15
+ export class TransformTool implements ITransformTool { // Editor use
16
+
17
+ public editBox: IEditBox
18
+
19
+ public editTool?: IEditTool // 可能不存在值
20
+
21
+
22
+ // operate
23
+
24
+ public onMove(e: DragEvent | MoveEvent): void {
25
+
26
+ const { target, mergeConfig, dragStartData } = this.editBox
27
+
28
+ if (e instanceof MoveEvent) {
29
+
30
+ if (e.moveType !== 'drag') {
31
+ const { moveable, resizeable } = mergeConfig
32
+ const move = e.getLocalMove(target)
33
+
34
+ if (moveable === 'move') e.stop(), this.move(move.x, move.y)
35
+ else if (resizeable === 'zoom') e.stop()
36
+ }
37
+
38
+ } else {
39
+
40
+ const total = { x: e.totalX, y: e.totalY }
41
+
42
+ if (e.shiftKey) {
43
+ if (Math.abs(total.x) > Math.abs(total.y)) total.y = 0
44
+ else total.x = 0
45
+ }
46
+
47
+ this.move(DragEvent.getValidMove(target, dragStartData.point, total))
48
+
49
+ }
50
+ }
51
+
52
+ public onScale(e: DragEvent | ZoomEvent): void {
53
+
54
+ const { target, mergeConfig, single, dragStartData } = this.editBox
55
+ let { around, lockRatio, resizeable, flipable, editSize } = mergeConfig
56
+
57
+ if (e instanceof ZoomEvent) {
58
+
59
+ if (resizeable === 'zoom') e.stop(), this.scaleOf(target.getBoxPoint(e), e.scale, e.scale)
60
+
61
+ } else {
62
+
63
+ const { direction } = e.current as IEditPoint
64
+ if (e.shiftKey || target.lockRatio) lockRatio = true
65
+
66
+ const data = EditDataHelper.getScaleData(target, dragStartData.bounds, direction, e.getInnerTotal(target), lockRatio, EditDataHelper.getAround(around, e.altKey), flipable, !single || editSize === 'scale')
67
+
68
+ if (this.editTool && this.editTool.onScaleWithDrag) {
69
+ data.drag = e
70
+ this.scaleWithDrag(data)
71
+ } else {
72
+ this.scaleOf(data.origin, data.scaleX, data.scaleY)
73
+ }
74
+
75
+ }
76
+ }
77
+
78
+ public onRotate(e: DragEvent | RotateEvent): void {
79
+
80
+ const { target, mergeConfig, dragStartData } = this.editBox
81
+ const { skewable, rotateable, around, rotateGap } = mergeConfig
82
+ const { direction, name } = e.current as IEditPoint
83
+
84
+ if (skewable && name === 'resize-line') return this.onSkew(e as DragEvent)
85
+
86
+ let origin: IPointData, rotation: number
87
+
88
+ if (e instanceof RotateEvent) {
89
+
90
+ if (rotateable === 'rotate') e.stop(), rotation = e.rotation, origin = target.getBoxPoint(e)
91
+ else return
92
+
93
+ if (target.scaleX * target.scaleY < 0) rotation = -rotation // flippedOne
94
+
95
+ } else {
96
+
97
+ const data = EditDataHelper.getRotateData(target, direction, e, dragStartData, e.shiftKey ? null : (target.around || target.origin || around || 'center'))
98
+ rotation = data.rotation
99
+ origin = data.origin
100
+
101
+ }
102
+
103
+ if (target.scaleX * target.scaleY < 0) rotation = -rotation // flippedOne
104
+ if (e instanceof DragEvent) rotation = dragStartData.rotation + rotation - target.rotation
105
+
106
+ rotation = MathHelper.float(MathHelper.getGapRotation(rotation, rotateGap, target.rotation), 2)
107
+ if (!rotation) return
108
+
109
+ this.rotateOf(origin, rotation)
110
+ }
111
+
112
+ public onSkew(e: DragEvent): void {
113
+
114
+ const { target, mergeConfig } = this.editBox
115
+ const { around } = mergeConfig
116
+
117
+ const { origin, skewX, skewY } = EditDataHelper.getSkewData(target.boxBounds, (e.current as IEditPoint).direction, e.getInnerMove(target), EditDataHelper.getAround(around, e.altKey))
118
+ if (!skewX && !skewY) return
119
+
120
+ this.skewOf(origin, skewX, skewY)
121
+ }
122
+
123
+
124
+ // transform
125
+
126
+ public move(x: number | IPointData, y = 0): void {
127
+ if (!this.checkTransform('moveable')) return
128
+ if (typeof x === 'object') y = x.y, x = x.x
129
+
130
+ const { target, mergeConfig, single, editor } = this.editBox
131
+ const { beforeMove } = mergeConfig
132
+ if (beforeMove) {
133
+ const check = beforeMove({ target, x, y })
134
+ if (typeof check === 'object') x = check.x, y = check.y
135
+ else if (check === false) return
136
+ }
137
+
138
+ const world = target.getWorldPointByLocal({ x, y }, null, true)
139
+ if (!single) (target as ISimulateElement).safeChange(() => target.move(x, y))
140
+ const data: IEditorMoveEvent = { target, editor, moveX: world.x, moveY: world.y }
141
+
142
+ this.emitEvent(new EditorMoveEvent(EditorMoveEvent.BEFORE_MOVE, data))
143
+ const event = new EditorMoveEvent(EditorMoveEvent.MOVE, data)
144
+ this.doMove(event)
145
+ this.emitEvent(event)
146
+ }
147
+
148
+ public scaleWithDrag(data: IEditorScaleEvent): void {
149
+ if (!this.checkTransform('resizeable')) return
150
+
151
+ const { target, mergeConfig, editor } = this.editBox
152
+ const { beforeScale } = mergeConfig
153
+ if (beforeScale) {
154
+ const { origin, scaleX, scaleY, drag } = data
155
+ const check = beforeScale({ target, drag, origin, scaleX, scaleY })
156
+ if (check === false) return
157
+ }
158
+
159
+ data = { ...data, target, editor, worldOrigin: target.getWorldPoint(data.origin) }
160
+
161
+ this.emitEvent(new EditorScaleEvent(EditorScaleEvent.BEFORE_SCALE, data))
162
+ const event = new EditorScaleEvent(EditorScaleEvent.SCALE, data)
163
+ this.editTool.onScaleWithDrag(event)
164
+ this.emitEvent(event)
165
+ }
166
+
167
+ public scaleOf(origin: IPointData | IAlign, scaleX: number, scaleY = scaleX, _resize?: boolean): void {
168
+ if (!this.checkTransform('resizeable')) return
169
+
170
+ const { target, mergeConfig, single, editor } = this.editBox
171
+
172
+ const { beforeScale } = mergeConfig
173
+ if (beforeScale) {
174
+ const check = beforeScale({ target, origin, scaleX, scaleY })
175
+ if (typeof check === 'object') scaleX = check.scaleX, scaleY = check.scaleY
176
+ else if (check === false) return
177
+ }
178
+
179
+ const worldOrigin = this.getWorldOrigin(origin)
180
+ const transform = !single && this.getChangedTransform(() => (target as ISimulateElement).safeChange(() => target.scaleOf(origin, scaleX, scaleY)))
181
+ const data: IEditorScaleEvent = { target, editor, worldOrigin, scaleX, scaleY, transform }
182
+
183
+ this.emitEvent(new EditorScaleEvent(EditorScaleEvent.BEFORE_SCALE, data))
184
+ const event = new EditorScaleEvent(EditorScaleEvent.SCALE, data)
185
+ this.doScale(event)
186
+ this.emitEvent(event)
187
+ }
188
+
189
+ public flip(axis: IAxis): void {
190
+ if (!this.checkTransform('resizeable')) return
191
+
192
+ const { target, single, editor } = this.editBox
193
+
194
+ const worldOrigin = this.getWorldOrigin('center')
195
+ const transform = !single ? this.getChangedTransform(() => (target as ISimulateElement).safeChange(() => target.flip(axis))) : new Matrix(LeafHelper.getFlipTransform(target, axis))
196
+ const data: IEditorScaleEvent = { target, editor, worldOrigin, scaleX: axis === 'x' ? -1 : 1, scaleY: axis === 'y' ? -1 : 1, transform }
197
+
198
+ this.emitEvent(new EditorScaleEvent(EditorScaleEvent.BEFORE_SCALE, data))
199
+ const event = new EditorScaleEvent(EditorScaleEvent.SCALE, data)
200
+ this.doScale(event)
201
+ this.emitEvent(event)
202
+ }
203
+
204
+ public rotateOf(origin: IPointData | IAlign, rotation: number): void {
205
+ if (!this.checkTransform('rotateable')) return
206
+
207
+ const { target, mergeConfig, single, editor } = this.editBox
208
+
209
+ const { beforeRotate } = mergeConfig
210
+ if (beforeRotate) {
211
+ const check = beforeRotate({ target, origin, rotation })
212
+ if (typeof check === 'number') rotation = check
213
+ else if (check === false) return
214
+ }
215
+
216
+ const worldOrigin = this.getWorldOrigin(origin)
217
+ const transform = !single && this.getChangedTransform(() => (target as ISimulateElement).safeChange(() => target.rotateOf(origin, rotation)))
218
+ const data: IEditorRotateEvent = { target, editor, worldOrigin, rotation, transform }
219
+
220
+ this.emitEvent(new EditorRotateEvent(EditorRotateEvent.BEFORE_ROTATE, data))
221
+ const event = new EditorRotateEvent(EditorRotateEvent.ROTATE, data)
222
+ this.doRotate(event)
223
+ this.emitEvent(event)
224
+ }
225
+
226
+ public skewOf(origin: IPointData | IAlign, skewX: number, skewY = 0, _resize?: boolean): void {
227
+ if (!this.checkTransform('skewable')) return
228
+
229
+ const { target, mergeConfig, single, editor } = this.editBox
230
+
231
+ const { beforeSkew } = mergeConfig
232
+ if (beforeSkew) {
233
+ const check = beforeSkew({ target, origin, skewX, skewY })
234
+ if (typeof check === 'object') skewX = check.skewX, skewY = check.skewY
235
+ else if (check === false) return
236
+ }
237
+
238
+ const worldOrigin = this.getWorldOrigin(origin)
239
+ const transform = !single && this.getChangedTransform(() => (target as ISimulateElement).safeChange(() => target.skewOf(origin, skewX, skewY)))
240
+ const data: IEditorSkewEvent = { target, editor, worldOrigin, skewX, skewY, transform }
241
+
242
+ this.emitEvent(new EditorSkewEvent(EditorSkewEvent.BEFORE_SKEW, data))
243
+ const event = new EditorSkewEvent(EditorSkewEvent.SKEW, data)
244
+ this.doSkew(event)
245
+ this.emitEvent(event)
246
+ }
247
+
248
+
249
+ // do
250
+
251
+ protected doMove(event: IEditorMoveEvent) {
252
+ this.editTool.onMove(event)
253
+ }
254
+
255
+ protected doScale(event: IEditorScaleEvent): void {
256
+ this.editTool.onScale(event)
257
+ }
258
+
259
+ protected doRotate(event: IEditorRotateEvent): void {
260
+ this.editTool.onRotate(event)
261
+ }
262
+
263
+ protected doSkew(event: IEditorSkewEvent): void {
264
+ this.editTool.onSkew(event)
265
+ }
266
+
267
+ // helper
268
+
269
+ public checkTransform(type: 'moveable' | 'resizeable' | 'rotateable' | 'skewable'): boolean {
270
+ const { target, mergeConfig } = this.editBox
271
+ return target && !target.locked && mergeConfig[type] as boolean
272
+ }
273
+
274
+ protected getWorldOrigin(origin: IPointData | IAlign): IPointData {
275
+ const { target } = this.editBox
276
+ return target.getWorldPoint(LeafHelper.getInnerOrigin(target, origin))
277
+ }
278
+
279
+ protected getChangedTransform(func: IFunction): IMatrix {
280
+
281
+ const { target, single } = this.editBox
282
+ if (!single && !(target as ISimulateElement).canChange) return (target as ISimulateElement).changedTransform
283
+
284
+ const oldMatrix = new Matrix(target.worldTransform)
285
+ func()
286
+ return new Matrix(target.worldTransform).divide(oldMatrix) // world change transform
287
+ }
288
+
289
+ // need rewrite
290
+ public emitEvent(event?: IEvent, capture?: boolean): void {
291
+ this.editBox.editor.emitEvent(event, capture)
292
+ }
293
+
294
+ }