@leafer-in/editor 1.5.2 → 1.6.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leafer-in/editor",
3
- "version": "1.5.2",
3
+ "version": "1.6.0",
4
4
  "description": "@leafer-in/editor",
5
5
  "author": "Chao (Leafer) Wan",
6
6
  "license": "MIT",
@@ -34,9 +34,9 @@
34
34
  "leaferjs"
35
35
  ],
36
36
  "peerDependencies": {
37
- "@leafer-ui/core": "^1.5.2",
38
- "@leafer-in/resize": "^1.5.2",
39
- "@leafer-ui/interface": "^1.5.2",
40
- "@leafer-in/interface": "^1.5.2"
37
+ "@leafer-ui/core": "^1.6.0",
38
+ "@leafer-in/resize": "^1.6.0",
39
+ "@leafer-ui/interface": "^1.6.0",
40
+ "@leafer-in/interface": "^1.6.0"
41
41
  }
42
42
  }
package/src/Editor.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { IGroupInputData, IUI, IEventListenerId, IPointData, ILeafList, IEditSize, IGroup, IObject, IAlign, IAxis, IFunction, IMatrix } from '@leafer-ui/interface'
2
- import { Group, DataHelper, MathHelper, LeafList, Matrix, RenderEvent, LeafHelper, Direction9, isNull } from '@leafer-ui/draw'
1
+ import { IGroupInputData, IUI, IEventListenerId, IPointData, ILeafList, IEditSize, IGroup, IObject, IAlign, IAxis, IFunction, IMatrix, IApp } from '@leafer-ui/interface'
2
+ import { Group, DataHelper, MathHelper, LeafList, Matrix, RenderEvent, LeafHelper, Direction9 } from '@leafer-ui/draw'
3
3
  import { DragEvent, RotateEvent, KeyEvent, ZoomEvent, MoveEvent, Plugin } from '@leafer-ui/core'
4
4
 
5
5
  import { IEditBox, IEditPoint, IEditor, IEditorConfig, IEditTool, IEditorScaleEvent, IInnerEditor, ISimulateElement, IEditorMoveEvent, IEditorRotateEvent, IEditorSkewEvent } from '@leafer-in/interface'
@@ -16,7 +16,7 @@ import { EditMask } from './display/EditMask'
16
16
  import { config } from './config'
17
17
 
18
18
  import { onTarget, onHover } from './editor/target'
19
- import { targetAttr } from './decorator/data'
19
+ import { targetAttr, mergeConfigAttr } from './decorator/data'
20
20
  import { EditorHelper } from './helper/EditorHelper'
21
21
  import { EditDataHelper } from './helper/EditDataHelper'
22
22
  import { simulate } from './editor/simulate'
@@ -29,21 +29,11 @@ import { SimulateElement } from './display/SimulateElement'
29
29
 
30
30
  export class Editor extends Group implements IEditor {
31
31
 
32
- public config = DataHelper.clone(config) as IEditorConfig
33
-
34
- public get mergeConfig(): IEditorConfig {
35
- const { config, element, dragPoint } = this, mergeConfig = { ...config } // 实时合并,后期可优化
36
- if (element && element.editConfig) Object.assign(mergeConfig, element.editConfig)
37
- if (dragPoint) {
38
- if (dragPoint.editConfig) Object.assign(mergeConfig, dragPoint.editConfig)
39
- if (mergeConfig.editSize === 'font-size') mergeConfig.lockRatio = true // 强制锁定比例
40
- if (dragPoint.pointType === 'resize-rotate') {
41
- mergeConfig.around || (mergeConfig.around = 'center')
42
- isNull(mergeConfig.lockRatio) && (mergeConfig.lockRatio = true)
43
- }
44
- }
45
- return mergeConfig
46
- }
32
+ public config: IEditorConfig
33
+
34
+ @mergeConfigAttr()
35
+ readonly mergeConfig: IEditorConfig
36
+ readonly mergedConfig: IEditorConfig
47
37
 
48
38
  @targetAttr(onHover)
49
39
  public hoverTarget?: IUI
@@ -88,12 +78,16 @@ export class Editor extends Group implements IEditor {
88
78
  public selector: EditSelect = new EditSelect(this)
89
79
  public editMask: EditMask = new EditMask(this)
90
80
 
81
+ public targetChanged: boolean
91
82
  public targetEventIds: IEventListenerId[] = []
92
83
 
93
84
 
94
85
  constructor(userConfig?: IEditorConfig, data?: IGroupInputData) {
95
86
  super(data)
96
- if (userConfig) this.config = DataHelper.default(userConfig, this.config)
87
+ let mergedConfig: IEditorConfig = DataHelper.clone(config)
88
+ if (userConfig) mergedConfig = DataHelper.default(userConfig, mergedConfig)
89
+ this.mergedConfig = this.config = mergedConfig
90
+
97
91
  this.addMany(this.editMask, this.selector, this.editBox)
98
92
  if (!Plugin.has('resize')) this.config.editSize = 'scale'
99
93
  }
@@ -489,8 +483,7 @@ export class Editor extends Group implements IEditor {
489
483
  }
490
484
 
491
485
  public emitInnerEvent(type: string): void {
492
- const { innerEditor } = this
493
- const { editTarget } = innerEditor
486
+ const { innerEditor } = this, { editTarget } = innerEditor
494
487
  const event = new InnerEditorEvent(type, { editTarget, innerEditor })
495
488
  this.emitEvent(event)
496
489
  editTarget.emitEvent(event)
@@ -524,28 +517,42 @@ export class Editor extends Group implements IEditor {
524
517
  }
525
518
  }
526
519
 
520
+ protected onAppRenderStart(app: IApp): void {
521
+ if (this.targetChanged = app.children.some(leafer => leafer !== this.leafer && leafer.renderer.changed)) this.editBox.forceRender()
522
+ }
523
+
524
+ protected onRenderStart(): void {
525
+ if (this.targetChanged) this.update()
526
+ }
527
+
528
+ protected onKey(e: KeyEvent): void {
529
+ updateCursor(this, e)
530
+ }
531
+
527
532
  // event
528
533
 
529
534
  public listenTargetEvents(): void {
530
535
  if (!this.targetEventIds.length) {
531
- const { app, leafer } = this
536
+ const { app, leafer, editBox, editMask } = this
532
537
  this.targetEventIds = [
533
- leafer.on_(RenderEvent.START, this.update, this),
534
- app.on_(RenderEvent.CHILD_START, this.forceRender, this),
538
+ leafer.on_(RenderEvent.START, this.onRenderStart, this),
539
+ app.on_(RenderEvent.CHILD_START, this.onAppRenderStart, this),
535
540
  app.on_(MoveEvent.BEFORE_MOVE, this.onMove, this, true),
536
541
  app.on_(ZoomEvent.BEFORE_ZOOM, this.onScale, this, true),
537
542
  app.on_(RotateEvent.BEFORE_ROTATE, this.onRotate, this, true),
538
- app.on_([KeyEvent.HOLD, KeyEvent.UP], (e: KeyEvent) => { updateCursor(this, e) }),
539
- app.on_(KeyEvent.DOWN, this.editBox.onArrow, this.editBox)
543
+ app.on_([KeyEvent.HOLD, KeyEvent.UP], this.onKey, this),
544
+ app.on_(KeyEvent.DOWN, editBox.onArrow, editBox)
540
545
  ]
546
+ if (editMask.visible) editMask.forceRender()
541
547
  }
542
548
  }
543
549
 
544
550
  public removeTargetEvents(): void {
545
- const { targetEventIds } = this
551
+ const { targetEventIds, editMask } = this
546
552
  if (targetEventIds.length) {
547
553
  this.off_(targetEventIds)
548
554
  targetEventIds.length = 0
555
+ if (editMask.visible) editMask.forceRender()
549
556
  }
550
557
  }
551
558
 
@@ -1,24 +1,63 @@
1
1
  import { IFunction, ILeaf, IObject, IUI, } from '@leafer-ui/interface'
2
2
  import { IEditor } from '@leafer-in/interface'
3
- import { defineKey } from '@leafer-ui/draw'
3
+ import { defineKey, isNull } from '@leafer-ui/draw'
4
4
 
5
5
  import { EditorEvent } from '../event/EditorEvent'
6
6
 
7
7
 
8
-
9
8
  export function targetAttr(fn: IFunction) {
10
9
  return (target: ILeaf, key: string) => {
11
10
  const privateKey = '_' + key
12
11
  defineKey(target, key, {
13
12
  get() { return (this as IObject)[privateKey] },
14
- set(value: unknown) {
13
+ set(value: IUI | IUI[]) {
15
14
  const old = (this as IObject)[privateKey]
16
15
  if (old !== value) {
17
- const type = key === 'target' ? EditorEvent.BEFORE_SELECT : EditorEvent.BEFORE_HOVER
18
- if (this.hasEvent(type)) this.emitEvent(new EditorEvent(type, { editor: this as IEditor, value: value as IUI, oldValue: old }));
16
+
17
+ if ((this as IEditor).config) { // Editor
18
+
19
+ const isSelect = key === 'target'
20
+ if (isSelect) {
21
+ if (value instanceof Array && value.length > 1 && value[0].locked) value.splice(0, 1) // fix: 单个锁定 + shift多选
22
+
23
+ const { beforeSelect } = (this as IEditor).config
24
+ if (beforeSelect) {
25
+ const check = beforeSelect({ target: value })
26
+ if (typeof check === 'object') value = check
27
+ else if (check === false) return
28
+ }
29
+ }
30
+
31
+ const type = isSelect ? EditorEvent.BEFORE_SELECT : EditorEvent.BEFORE_HOVER
32
+ if (this.hasEvent(type)) this.emitEvent(new EditorEvent(type, { editor: this as IEditor, value: value as IUI, oldValue: old }))
33
+ }
34
+
19
35
  (this as IObject)[privateKey] = value, fn(this, old)
20
36
  }
21
37
  }
22
38
  } as ThisType<ILeaf>)
23
39
  }
24
- }
40
+ }
41
+
42
+
43
+ export function mergeConfigAttr() {
44
+ return (target: IEditor, key: string) => {
45
+ defineKey(target, key, {
46
+ get() {
47
+ const { config, element, dragPoint } = this, mergeConfig = { ...config } // 实时合并,后期可优化
48
+ if (element && element.editConfig) Object.assign(mergeConfig, element.editConfig)
49
+ if (dragPoint) {
50
+ if (dragPoint.editConfig) Object.assign(mergeConfig, dragPoint.editConfig)
51
+ if (mergeConfig.editSize === 'font-size') mergeConfig.lockRatio = true // 强制锁定比例
52
+ if (dragPoint.pointType === 'resize-rotate') {
53
+ mergeConfig.around || (mergeConfig.around = 'center')
54
+ isNull(mergeConfig.lockRatio) && (mergeConfig.lockRatio = true)
55
+ }
56
+ }
57
+ return (this as IObject).mergedConfig = mergeConfig
58
+ }
59
+ } as ThisType<IEditor>)
60
+ }
61
+ }
62
+
63
+
@@ -1,5 +1,5 @@
1
1
  import { IRect, IEventListenerId, IBoundsData, IPointData, IKeyEvent, IGroup, IBox, IBoxInputData, IAlign, IUI, IEditorConfig, IEditorDragStartData } from '@leafer-ui/interface'
2
- import { Group, Box, Text, AroundHelper, Direction9 } from '@leafer-ui/draw'
2
+ import { Group, Box, Text, AroundHelper, Direction9, ResizeEvent } from '@leafer-ui/draw'
3
3
  import { DragEvent, PointerEvent } from '@leafer-ui/core'
4
4
 
5
5
  import { IEditBox, IEditor, IEditPoint, IEditPointType } from '@leafer-in/interface'
@@ -22,7 +22,7 @@ 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
- public buttons: IGroup = new Group({ around: 'center', hitSelf: false })
25
+ public buttons: IGroup = new Group({ around: 'center', hitSelf: false, visible: 0 })
26
26
 
27
27
  public resizePoints: IEditPoint[] = [] // topLeft, top, topRight, right, bottomRight, bottom, bottomLeft, left
28
28
  public rotatePoints: IEditPoint[] = [] // topLeft, top, topRight, right, bottomRight, bottom, bottomLeft, left
@@ -108,14 +108,15 @@ export class EditBox extends Group implements IEditBox {
108
108
  }
109
109
 
110
110
  public update(bounds: IBoundsData): void {
111
- const { mergeConfig, element, multiple } = this.editor
112
- const { middlePoint, resizeable, rotateable, hideOnSmall, editBox } = mergeConfig
111
+ const { rect, circle, buttons, resizePoints, rotatePoints, resizeLines, editor } = this
112
+ const { mergeConfig, element, multiple, editMask } = editor
113
+ const { middlePoint, resizeable, rotateable, hideOnSmall, editBox, mask } = mergeConfig
114
+
113
115
  this.visible = !element.locked
116
+ editMask.visible = mask ? true : 0
114
117
 
115
118
  if (this.view.worldOpacity) {
116
119
  const { width, height } = bounds
117
- const { rect, circle, buttons, resizePoints, rotatePoints, resizeLines } = this
118
-
119
120
  const smallSize = typeof hideOnSmall === 'number' ? hideOnSmall : 10
120
121
  const showPoints = editBox && !(hideOnSmall && width < smallSize && height < smallSize)
121
122
 
@@ -160,9 +161,9 @@ export class EditBox extends Group implements IEditBox {
160
161
  rect.set({ ...bounds, visible: multiple ? true : editBox })
161
162
 
162
163
  // buttons
163
- buttons.visible = showPoints && buttons.children.length > 0
164
+ buttons.visible = showPoints && buttons.children.length > 0 || 0
164
165
  if (buttons.visible) this.layoutButtons(mergeConfig)
165
- }
166
+ } else rect.set(bounds) // 需要更新大小
166
167
  }
167
168
 
168
169
  protected layoutCircle(config: IEditorConfig): void {
@@ -239,7 +240,7 @@ export class EditBox extends Group implements IEditBox {
239
240
 
240
241
  protected onDragStart(e: DragEvent): void {
241
242
  this.dragging = true
242
- const point = this.dragPoint = e.current as IEditPoint
243
+ const point = this.dragPoint = e.current as IEditPoint, { pointType } = point
243
244
  const { editor, dragStartData } = this, { element } = editor
244
245
  if (point.name === 'rect') {
245
246
  this.moving = true
@@ -250,42 +251,48 @@ export class EditBox extends Group implements IEditBox {
250
251
  dragStartData.point = { x: element.x, y: element.y } // 用于移动
251
252
  dragStartData.bounds = { ...element.getLayoutBounds('box', 'local') } // 用于resize
252
253
  dragStartData.rotation = element.rotation // 用于旋转
254
+ if (pointType && pointType.includes('resize')) ResizeEvent.resizingKeys = editor.leafList.keys // 记录正在resize中的元素列表
253
255
  }
254
256
 
255
257
  protected onDragEnd(e: DragEvent): void {
256
258
  this.dragging = false
257
259
  this.dragPoint = null
258
260
  this.moving = false
259
- if (e.current.name === 'rect') this.editor.opacity = 1 // move
261
+ const { name, pointType } = e.current as IEditPoint
262
+ if (name === 'rect') this.editor.opacity = 1 // move
263
+ if (pointType && pointType.includes('resize')) ResizeEvent.resizingKeys = null
260
264
  }
261
265
 
262
266
  protected onDrag(e: DragEvent): void {
263
267
  const { editor } = this
264
268
  const { pointType } = this.enterPoint = e.current as IEditPoint
265
- if (pointType.includes('rotate') || e.metaKey || e.ctrlKey || !editor.mergeConfig.resizeable) editor.onRotate(e)
266
- if (pointType.includes('resize')) editor.onScale(e)
269
+ if (pointType.includes('rotate') || e.metaKey || e.ctrlKey || !editor.mergeConfig.resizeable) {
270
+ editor.onRotate(e)
271
+ if (pointType === 'resize-rotate') editor.onScale(e)
272
+ } else if (pointType === 'resize') editor.onScale(e)
267
273
  if (pointType === 'skew') editor.onSkew(e)
268
274
  updateCursor(editor, e)
269
275
  }
270
276
 
271
277
  public onArrow(e: IKeyEvent): void {
272
- if (this.editor.editing && this.editor.mergeConfig.keyEvent) {
273
- const move = { x: 0, y: 0 }
278
+ const { editor } = this
279
+ if (editor.editing && editor.mergeConfig.keyEvent) {
280
+ let x = 0, y = 0
274
281
  const distance = e.shiftKey ? 10 : 1
275
282
  switch (e.code) {
276
283
  case 'ArrowDown':
277
- move.y = distance
284
+ y = distance
278
285
  break
279
286
  case 'ArrowUp':
280
- move.y = -distance
287
+ y = -distance
281
288
  break
282
289
  case 'ArrowLeft':
283
- move.x = -distance
290
+ x = -distance
284
291
  break
285
292
  case 'ArrowRight':
286
- move.x = distance
293
+ x = distance
287
294
  }
288
- this.editor.move(move)
295
+ if (x || y) editor.move(x, y)
289
296
  }
290
297
  }
291
298
 
@@ -1,8 +1,9 @@
1
- import { ILeaferCanvas, IRenderOptions } from '@leafer-ui/interface'
1
+ import { IBox, ILeaferCanvas, IRenderOptions } from '@leafer-ui/interface'
2
2
  import { UI } from '@leafer-ui/draw'
3
3
 
4
4
  import { IEditor } from '@leafer-in/interface'
5
5
 
6
+ const bigBounds = { x: 0, y: 0, width: 100000, height: 100000 }
6
7
 
7
8
  export class EditMask extends UI {
8
9
 
@@ -12,20 +13,28 @@ export class EditMask extends UI {
12
13
  super()
13
14
  this.editor = editor
14
15
  this.hittable = false
16
+ this.visible = 0
15
17
  }
16
18
 
17
- public __draw(canvas: ILeaferCanvas, options: IRenderOptions): void {
18
- const { editor } = this
19
- const { mask } = editor.mergeConfig
19
+ override __updateWorldBounds(): void {
20
+ Object.assign(this.__local, bigBounds) // 强制修改渲染包围盒
21
+ Object.assign(this.__world, bigBounds)
22
+ }
20
23
 
21
- if (mask && editor.list.length) {
22
- const { rect } = editor.editBox
23
- const { width, height } = rect.__
24
+ public __draw(canvas: ILeaferCanvas, options: IRenderOptions): void {
24
25
 
25
- canvas.resetTransform()
26
+ const { editor } = this, { mask } = editor.mergedConfig
27
+ if (mask && editor.editing) {
26
28
  canvas.fillWorld(canvas.bounds, mask === true ? 'rgba(0,0,0,0.8)' : mask)
27
- canvas.setWorld(rect.__world, options.matrix)
28
- canvas.clearRect(0, 0, width, height)
29
+ if (options.bounds && !options.bounds.hit(editor.editBox.rect.__world, options.matrix)) return
30
+
31
+ canvas.saveBlendMode('destination-out')
32
+ 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) // 文本框
36
+ })
37
+ canvas.restoreBlendMode()
29
38
  }
30
39
  }
31
40
 
@@ -189,7 +189,7 @@ export class EditSelect extends Group implements IEditSelect {
189
189
  protected onDragEnd(e: DragEvent): void {
190
190
  if (e.multiTouch) return
191
191
 
192
- if (this.dragging) this.originList = null, this.selectArea.visible = false
192
+ if (this.dragging) this.originList = null, this.selectArea.visible = 0
193
193
  }
194
194
 
195
195
  protected onAutoMove(e: MoveEvent): void {
@@ -11,7 +11,8 @@ export class SelectArea extends Group implements ISelectArea {
11
11
 
12
12
  constructor(data?: IGroupInputData) {
13
13
  super(data)
14
- this.visible = this.hittable = false
14
+ this.visible = 0
15
+ this.hittable = false
15
16
  this.addMany(this.fillArea, this.strokeArea)
16
17
  }
17
18
 
@@ -1,4 +1,4 @@
1
- import { IUI, ILeaferCanvas, IRenderOptions, IRectInputData } from '@leafer-ui/interface'
1
+ import { IUI, ILeaferCanvas, IRenderOptions, IRectInputData, IMatrixWithOptionHalfData } from '@leafer-ui/interface'
2
2
  import { Paint, UI, MatrixHelper, getBoundsData, getMatrixData, BoundsHelper, LeafBoundsHelper } from '@leafer-ui/draw'
3
3
 
4
4
  import { IStroker } from '@leafer-in/interface'
@@ -10,7 +10,7 @@ const { abs } = Math
10
10
  const { copy, scale } = MatrixHelper
11
11
  const { setListWithFn } = BoundsHelper
12
12
  const { worldBounds } = LeafBoundsHelper
13
- const matrix = getMatrixData()
13
+ const matrix = getMatrixData() as IMatrixWithOptionHalfData
14
14
  const bounds = getBoundsData()
15
15
 
16
16
  export class Stroker extends UI implements IStroker {
@@ -22,6 +22,7 @@ export class Stroker extends UI implements IStroker {
22
22
 
23
23
  constructor() {
24
24
  super()
25
+ this.visible = 0
25
26
  this.hittable = false
26
27
  this.strokeAlign = 'center'
27
28
  }
@@ -37,9 +38,8 @@ export class Stroker extends UI implements IStroker {
37
38
  if (list.length) {
38
39
  setListWithFn(bounds, list, worldBounds)
39
40
  this.set(bounds)
40
- } else {
41
- this.width = this.height = 1
42
- }
41
+ this.visible = true
42
+ } else this.visible = 0
43
43
  }
44
44
 
45
45
  public __draw(canvas: ILeaferCanvas, options: IRenderOptions): void {
@@ -58,11 +58,12 @@ export class Stroker extends UI implements IStroker {
58
58
 
59
59
  const aScaleX = abs(worldTransform.scaleX), aScaleY = abs(worldTransform.scaleY)
60
60
 
61
+ copy(matrix, worldTransform)
62
+ matrix.half = strokeWidth % 2
63
+
61
64
  if (aScaleX !== aScaleY) { // need no scale stroke, use rect path
62
65
 
63
- copy(matrix, worldTransform)
64
66
  scale(matrix, 1 / aScaleX, 1 / aScaleY)
65
-
66
67
  canvas.setWorld(matrix, options.matrix)
67
68
  canvas.beginPath()
68
69
  data.strokeWidth = strokeWidth
@@ -72,7 +73,7 @@ export class Stroker extends UI implements IStroker {
72
73
 
73
74
  } else {
74
75
 
75
- canvas.setWorld(worldTransform, options.matrix)
76
+ canvas.setWorld(matrix, options.matrix)
76
77
  canvas.beginPath()
77
78
 
78
79
  if (leaf.__.__useArrow) leaf.__drawPath(canvas)
@@ -1,6 +1,6 @@
1
1
  import { LeafList } from '@leafer-ui/draw'
2
2
 
3
- import { IEditor, ILeaf, IUI } from '@leafer-in/interface'
3
+ import { IEditor, IUI } from '@leafer-in/interface'
4
4
 
5
5
  import { simulate } from './simulate'
6
6
  import { updateMoveCursor } from './cursor'
@@ -10,11 +10,7 @@ import { EditorEvent } from '../event/EditorEvent'
10
10
  export function onTarget(editor: IEditor, oldValue: IUI | IUI[]): void {
11
11
  const { target } = editor
12
12
  if (target) {
13
- const { list } = editor.leafList = target instanceof LeafList ? target : new LeafList(target instanceof Array ? target : target as IUI)
14
- if (!list.every(checkEditable)) { // 过滤不合格的元素
15
- editor.target = list.filter(checkEditable) as IUI[]
16
- return
17
- }
13
+ editor.leafList = target instanceof LeafList ? target : new LeafList(target)
18
14
  if (editor.multiple) simulate(editor) // 更新模拟元素
19
15
  } else {
20
16
  editor.simulateTarget.remove()
@@ -41,9 +37,4 @@ export function onTarget(editor: IEditor, oldValue: IUI | IUI[]): void {
41
37
 
42
38
  export function onHover(editor: IEditor, oldValue: IUI): void {
43
39
  editor.emitEvent(new EditorEvent(EditorEvent.HOVER, { editor, value: editor.hoverTarget, oldValue }))
44
- }
45
-
46
-
47
- function checkEditable(item: ILeaf): boolean {
48
- return item.editable && !item.locked
49
40
  }
@@ -99,10 +99,10 @@ export const EditDataHelper = {
99
99
  }
100
100
  }
101
101
 
102
+ const useScaleX = scaleX !== 1, useScaleY = scaleY !== 1
102
103
 
103
- scaleX /= changedScaleX
104
- scaleY /= changedScaleY
105
-
104
+ if (useScaleX) scaleX /= changedScaleX
105
+ if (useScaleY) scaleY /= changedScaleY
106
106
 
107
107
  if (!flipable) {
108
108
  const { worldTransform } = element
@@ -121,24 +121,27 @@ export const EditDataHelper = {
121
121
 
122
122
  if (!BoundsHelper.includes(allowBounds, localBounds)) {
123
123
  const realBounds = localBounds.getIntersect(allowBounds)
124
- scaleX *= realBounds.width / localBounds.width
125
- scaleY *= realBounds.height / localBounds.height // 后续需优化带旋转的场景
124
+ const fitScaleX = realBounds.width / localBounds.width, fitScaleY = realBounds.height / localBounds.height
125
+ if (useScaleX) scaleX *= fitScaleX
126
+ if (useScaleY) scaleY *= fitScaleY // 后续需优化带旋转的场景
126
127
  }
127
128
  }
128
129
 
129
- if (widthRange) {
130
+ if (useScaleX && widthRange) {
130
131
  const nowWidth = boxBounds.width * element.scaleX
131
132
  scaleX = within(nowWidth * scaleX, widthRange) / nowWidth
132
133
  }
133
134
 
134
- if (heightRange) {
135
+ if (useScaleY && heightRange) {
135
136
  const nowHeight = boxBounds.height * element.scaleY
136
137
  scaleY = within(nowHeight * scaleY, heightRange) / nowHeight
137
138
  }
138
139
 
139
140
  // 防止小于1px
140
- if (Math.abs(scaleX * worldBoxBounds.width) < 1) scaleX = (scaleX < 0 ? -1 : 1) / worldBoxBounds.width
141
- if (Math.abs(scaleY * worldBoxBounds.height) < 1) scaleY = (scaleY < 0 ? -1 : 1) / worldBoxBounds.height
141
+ if (useScaleX && Math.abs(scaleX * worldBoxBounds.width) < 1) scaleX = (scaleX < 0 ? -1 : 1) / worldBoxBounds.width
142
+ if (useScaleY && Math.abs(scaleY * worldBoxBounds.height) < 1) scaleY = (scaleY < 0 ? -1 : 1) / worldBoxBounds.height
143
+
144
+ if (lockRatio && scaleX !== scaleY) scaleY = scaleX = Math.min(scaleX, scaleY)
142
145
 
143
146
  return { origin, scaleX, scaleY, direction, lockRatio, around }
144
147
  },
@@ -21,9 +21,7 @@ export class EditTool extends InnerEditor implements IEditTool {
21
21
  const { moveX, moveY, editor } = e
22
22
  const { app, list } = editor
23
23
  app.lockLayout()
24
- list.forEach(target => {
25
- target.moveWorld(moveX, moveY)
26
- })
24
+ list.forEach(target => { target.moveWorld(moveX, moveY) })
27
25
  app.unlockLayout()
28
26
  }
29
27
 
@@ -33,11 +31,8 @@ export class EditTool extends InnerEditor implements IEditTool {
33
31
  app.lockLayout()
34
32
  list.forEach(target => {
35
33
  const resize = editor.getEditSize(target) !== 'scale'
36
- if (transform) {
37
- target.transformWorld(transform, resize)
38
- } else {
39
- target.scaleOfWorld(worldOrigin, scaleX, scaleY, resize)
40
- }
34
+ if (transform) target.transformWorld(transform, resize)
35
+ else target.scaleOfWorld(worldOrigin, scaleX, scaleY, resize)
41
36
  })
42
37
  app.unlockLayout()
43
38
  }
@@ -48,11 +43,8 @@ export class EditTool extends InnerEditor implements IEditTool {
48
43
  app.lockLayout()
49
44
  list.forEach(target => {
50
45
  const resize = editor.getEditSize(target) !== 'scale'
51
- if (transform) {
52
- target.transformWorld(transform, resize)
53
- } else {
54
- target.rotateOfWorld(worldOrigin, rotation)
55
- }
46
+ if (transform) target.transformWorld(transform, resize)
47
+ else target.rotateOfWorld(worldOrigin, rotation)
56
48
  })
57
49
  app.unlockLayout()
58
50
  }
@@ -63,11 +55,8 @@ export class EditTool extends InnerEditor implements IEditTool {
63
55
  app.lockLayout()
64
56
  list.forEach(target => {
65
57
  const resize = editor.getEditSize(target) !== 'scale'
66
- if (transform) {
67
- target.transformWorld(transform, resize)
68
- } else {
69
- target.skewOfWorld(worldOrigin, skewX, skewY, resize)
70
- }
58
+ if (transform) target.transformWorld(transform, resize)
59
+ else target.skewOfWorld(worldOrigin, skewX, skewY, resize)
71
60
  })
72
61
  app.unlockLayout()
73
62
  }
package/types/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { IBounds, ILeafList, IUI, IFunction, IEventListenerId, ILeaf, IPointerEvent, ILeaferCanvas, IRenderOptions, IGroup, IObject, IGroupInputData, IEditSize, IPointData, IAlign, IAxis, IMatrix, IBox, IEditorDragStartData, IBoundsData, IEditorConfig as IEditorConfig$1, IBoxInputData, IKeyEvent, IRect, IRectInputData, IMatrixData, IDragEvent, IAround, ILayoutBoundsData } from '@leafer-ui/interface';
1
+ import { IBounds, ILeafList, IUI, IFunction, IEventListenerId, ILeaf, IPointerEvent, ILeaferCanvas, IRenderOptions, IGroup, IObject, IGroupInputData, IEditSize, IPointData, IAlign, IAxis, IMatrix, IApp, IBox, IEditorDragStartData, IBoundsData, IEditorConfig as IEditorConfig$1, IBoxInputData, IKeyEvent, IRect, IRectInputData, IMatrixData, IDragEvent, IAround, ILayoutBoundsData } from '@leafer-ui/interface';
2
2
  import { Group, UI, Direction9, Event, Box } from '@leafer-ui/draw';
3
- import { PointerEvent, DragEvent, MoveEvent, ZoomEvent, RotateEvent } from '@leafer-ui/core';
3
+ import { PointerEvent, DragEvent, MoveEvent, ZoomEvent, RotateEvent, KeyEvent } from '@leafer-ui/core';
4
4
  import { IEditSelect, IEditor, IStroker, ISelectArea, IEditorConfig, IEditPoint, ISimulateElement, IEditBox, IEditTool, IInnerEditor, IEditorScaleEvent, IEditorEvent, IEditPointType, IEditorMoveEvent, IEditorRotateEvent, IEditorSkewEvent, IEditorGroupEvent, IInnerEditorEvent, IUI as IUI$1, IDragEvent as IDragEvent$1, IPointData as IPointData$1, IPathCommandData, IFromToData, IAround as IAround$1 } from '@leafer-in/interface';
5
5
 
6
6
  declare class EditSelect extends Group implements IEditSelect {
@@ -42,13 +42,15 @@ declare class EditSelect extends Group implements IEditSelect {
42
42
  declare class EditMask extends UI {
43
43
  editor: IEditor;
44
44
  constructor(editor: IEditor);
45
+ __updateWorldBounds(): void;
45
46
  __draw(canvas: ILeaferCanvas, options: IRenderOptions): void;
46
47
  destroy(): void;
47
48
  }
48
49
 
49
50
  declare class Editor extends Group implements IEditor {
50
51
  config: IEditorConfig;
51
- get mergeConfig(): IEditorConfig;
52
+ readonly mergeConfig: IEditorConfig;
53
+ readonly mergedConfig: IEditorConfig;
52
54
  hoverTarget?: IUI;
53
55
  target?: IUI | IUI[];
54
56
  leafList: ILeafList;
@@ -73,6 +75,7 @@ declare class Editor extends Group implements IEditor {
73
75
  editToolList: IObject;
74
76
  selector: EditSelect;
75
77
  editMask: EditMask;
78
+ targetChanged: boolean;
76
79
  targetEventIds: IEventListenerId[];
77
80
  constructor(userConfig?: IEditorConfig, data?: IGroupInputData);
78
81
  select(target: IUI | IUI[]): void;
@@ -112,6 +115,9 @@ declare class Editor extends Group implements IEditor {
112
115
  unlock(): void;
113
116
  toTop(): void;
114
117
  toBottom(): void;
118
+ protected onAppRenderStart(app: IApp): void;
119
+ protected onRenderStart(): void;
120
+ protected onKey(e: KeyEvent): void;
115
121
  listenTargetEvents(): void;
116
122
  removeTargetEvents(): void;
117
123
  destroy(): void;