@leafer-in/editor 1.0.0-rc.6 → 1.0.0-rc.8

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.
@@ -0,0 +1,264 @@
1
+ import { IRect, IAround, IEventListenerId, IBoundsData, IRectInputData, IPointData, IKeyEvent, IGroup, IBox } from '@leafer-ui/interface'
2
+ import { Group, DragEvent, PointerEvent, Box, AroundHelper } from '@leafer-ui/core'
3
+
4
+ import { IEditBox, IEditor, IDirection8, IEditPoint, IEditPointType } from '@leafer-in/interface'
5
+
6
+ import { updateCursor, updateMoveCursor } from '../editor/cursor'
7
+ import { EditorEvent } from '../event/EditorEvent'
8
+ import { EditPoint } from './EditPoint'
9
+ import { EditDataHelper } from '../helper/EditDataHelper'
10
+
11
+
12
+ const fourDirection = ['top', 'right', 'bottom', 'left']
13
+
14
+ export class EditBox extends Group implements IEditBox {
15
+
16
+ public editor: IEditor
17
+ public dragging: boolean
18
+
19
+ public rect: IBox = new Box({ name: 'rect', hitFill: 'all', hitStroke: 'none', strokeAlign: 'center', hitRadius: 5 }) // target rect
20
+ public circle: IEditPoint = new EditPoint({ name: 'circle', strokeAlign: 'outside', around: 'center', cursor: 'crosshair', hitRadius: 5 }) // rotate point
21
+
22
+ public buttons: IGroup = new Group({ around: 'center', hitSelf: false })
23
+
24
+ public resizePoints: IEditPoint[] = [] // topLeft, top, topRight, right, bottomRight, bottom, bottomLeft, left
25
+ public rotatePoints: IEditPoint[] = [] // topLeft, top, topRight, right, bottomRight, bottom, bottomLeft, left
26
+ public resizeLines: IEditPoint[] = [] // top, right, bottom, left
27
+
28
+ // fliped
29
+ public get flipped(): boolean { return this.flippedX || this.flippedY }
30
+ public get flippedX(): boolean { return this.scaleX < 0 }
31
+ public get flippedY(): boolean { return this.scaleY < 0 }
32
+ public get flippedOne(): boolean { return this.scaleX * this.scaleY < 0 }
33
+
34
+ public enterPoint: IEditPoint
35
+
36
+ protected __eventIds: IEventListenerId[] = []
37
+
38
+ constructor(editor: IEditor) {
39
+ super()
40
+ this.editor = editor
41
+ this.visible = false
42
+ this.create()
43
+ this.__listenEvents()
44
+ }
45
+
46
+ public create() {
47
+ let rotatePoint: IEditPoint, resizeLine: IEditPoint, resizePoint: IEditPoint
48
+ const { resizePoints, rotatePoints, resizeLines, rect, circle, buttons } = this
49
+ const arounds: IAround[] = [{ x: 1, y: 1 }, { x: 0.5, y: 1 }, { x: 0, y: 1 }, { x: 0, y: 0.5 }, { x: 0, y: 0 }, { x: 0.5, y: 0 }, { x: 1, y: 0 }, { x: 1, y: 0.5 }]
50
+
51
+ for (let i = 0; i < 8; i++) {
52
+ rotatePoint = new EditPoint({ around: arounds[i], width: 15, height: 15, hitFill: "all" })
53
+ rotatePoints.push(rotatePoint)
54
+ this.listenPointEvents(rotatePoint, 'rotate', i)
55
+
56
+ if (i % 2) {
57
+ resizeLine = new EditPoint({ name: 'resize-line', around: 'center', width: 10, height: 10, hitFill: "all" })
58
+ resizeLines.push(resizeLine)
59
+ this.listenPointEvents(resizeLine, 'resize', i)
60
+ }
61
+
62
+ resizePoint = new EditPoint({ name: 'resize-point', around: 'center', strokeAlign: 'outside', hitRadius: 5 })
63
+ resizePoints.push(resizePoint)
64
+ this.listenPointEvents(resizePoint, 'resize', i)
65
+ }
66
+
67
+ buttons.add(circle)
68
+ this.listenPointEvents(circle, 'rotate', 2)
69
+
70
+ this.addMany(...rotatePoints, rect, buttons, ...resizeLines, ...resizePoints)
71
+ }
72
+
73
+ // update
74
+
75
+ public update(bounds: IBoundsData): void {
76
+ const { config, list } = this.editor
77
+ const { width, height } = bounds
78
+ const { rect, circle, resizePoints, rotatePoints, resizeLines } = this
79
+ const { middlePoint, resizeable, rotateable, stroke, strokeWidth } = config
80
+
81
+ const pointsStyle = this.getPointsStyle()
82
+ const middlePointsStyle = this.getMiddlePointsStyle()
83
+
84
+ this.visible = list[0] && !list[0].locked // check locked
85
+
86
+ let point = {} as IPointData, style: IRectInputData, rotateP: IRect, resizeP: IRect, resizeL: IRect
87
+
88
+ for (let i = 0; i < 8; i++) {
89
+
90
+ AroundHelper.toPoint(AroundHelper.directionData[i], bounds, point)
91
+ style = this.getPointStyle((i % 2) ? middlePointsStyle[((i - 1) / 2) % middlePointsStyle.length] : pointsStyle[(i / 2) % pointsStyle.length])
92
+ resizeP = resizePoints[i], rotateP = rotatePoints[i], resizeL = resizeLines[Math.floor(i / 2)]
93
+ resizeP.set(style)
94
+ resizeP.set(point), rotateP.set(point), resizeL.set(point)
95
+
96
+ // visible
97
+ resizeP.visible = resizeL.visible = resizeable || rotateable
98
+ rotateP.visible = rotateable && resizeable
99
+
100
+ if (i % 2) { // top, right, bottom, left
101
+
102
+ resizeP.visible = rotateP.visible = !!middlePoint
103
+
104
+ if (((i + 1) / 2) % 2) { // top, bottom
105
+ resizeL.width = width
106
+ if (resizeP.width > width - 30) resizeP.visible = false
107
+ } else {
108
+ resizeL.height = height
109
+ resizeP.rotation = 90
110
+ if (resizeP.width > height - 30) resizeP.visible = false
111
+ }
112
+ } else {
113
+ resizeP.rotation = (i / 2) * 90
114
+ }
115
+
116
+ }
117
+
118
+ // rotate
119
+ circle.visible = rotateable && !!config.rotatePoint
120
+ circle.set(this.getPointStyle(config.rotatePoint || pointsStyle[0]))
121
+
122
+ // rect
123
+ rect.set({ stroke, strokeWidth, ...(config.rect || {}) })
124
+ rect.set({ ...bounds, visible: true })
125
+
126
+ // buttons
127
+ this.layoutButtons()
128
+ }
129
+
130
+ protected layoutButtons(): void {
131
+ const { buttons, resizePoints } = this
132
+ const { buttonsDirection, buttonsFixed, buttonsMargin, middlePoint } = this.editor.config
133
+
134
+ const { flippedX, flippedY } = this
135
+ let index = fourDirection.indexOf(buttonsDirection)
136
+ if ((index % 2 && flippedX) || ((index + 1) % 2 && flippedY)) {
137
+ if (buttonsFixed) index = (index + 2) % 4 // flip x / y
138
+ }
139
+ const direction = buttonsFixed ? EditDataHelper.getRotateDirection(index, this.flippedOne ? this.rotation : -this.rotation, 4) : index
140
+
141
+ const point = resizePoints[direction * 2 + 1] // 4 map 8 direction
142
+ const useX = direction % 2 // left / right
143
+ const sign = (!direction || direction === 3) ? -1 : 1 // top / left = -1
144
+
145
+ const useWidth = index % 2 // left / right origin direction
146
+ const margin = (buttonsMargin + (useWidth ? ((middlePoint ? point.width : 0) + buttons.boxBounds.width) : ((middlePoint ? point.height : 0) + buttons.boxBounds.height)) / 2) * sign
147
+
148
+ if (useX) {
149
+ buttons.x = point.x + margin
150
+ buttons.y = point.y
151
+ } else {
152
+ buttons.x = point.x
153
+ buttons.y = point.y + margin
154
+ }
155
+
156
+ if (buttonsFixed) {
157
+ buttons.rotation = (direction - index) * 90
158
+ buttons.scaleX = flippedX ? -1 : 1
159
+ buttons.scaleY = flippedY ? -1 : 1
160
+ }
161
+
162
+ }
163
+
164
+ public getPointStyle(userStyle?: IRectInputData): IRectInputData {
165
+ const { stroke, strokeWidth, pointFill, pointSize, pointRadius } = this.editor.config
166
+ const defaultStyle = { fill: pointFill, stroke, strokeWidth, width: pointSize, height: pointSize, cornerRadius: pointRadius }
167
+ return userStyle ? Object.assign(defaultStyle, userStyle) : defaultStyle
168
+ }
169
+
170
+ public getPointsStyle(): IRectInputData[] {
171
+ const { point } = this.editor.config
172
+ return point instanceof Array ? point : [point]
173
+ }
174
+
175
+ public getMiddlePointsStyle(): IRectInputData[] {
176
+ const { middlePoint } = this.editor.config
177
+ return middlePoint instanceof Array ? middlePoint : (middlePoint ? [middlePoint] : this.getPointsStyle())
178
+ }
179
+
180
+ // drag
181
+
182
+ protected onDragStart(e: DragEvent): void {
183
+ this.dragging = true
184
+ if (e.target.name === 'rect') this.editor.opacity = this.editor.config.hideOnMove ? 0 : 1 // move
185
+ }
186
+
187
+ protected onDragEnd(e: DragEvent): void {
188
+ this.dragging = false
189
+ if (e.target.name === 'rect') this.editor.opacity = 1 // move
190
+ }
191
+
192
+ protected onDrag(e: DragEvent): void {
193
+ const { editor } = this
194
+ const point = e.current as IEditPoint
195
+ if (point.pointType === 'rotate' || e.metaKey || e.ctrlKey || !editor.config.resizeable) {
196
+ if (editor.config.rotateable) editor.onRotate(e)
197
+ } else {
198
+ editor.onScale(e)
199
+ }
200
+ }
201
+
202
+ public onArrow(e: IKeyEvent): void {
203
+ if (this.editor.hasTarget) {
204
+ const move = { x: 0, y: 0 }
205
+ const distance = e.shiftKey ? 10 : 1
206
+ switch (e.code) {
207
+ case 'ArrowDown':
208
+ move.y = distance
209
+ break
210
+ case 'ArrowUp':
211
+ move.y = -distance
212
+ break
213
+ case 'ArrowLeft':
214
+ move.x = -distance
215
+ break
216
+ case 'ArrowRight':
217
+ move.x = distance
218
+ }
219
+ if (move.x || move.y) this.editor.move(move.x, move.y)
220
+ }
221
+ }
222
+
223
+ protected onDoubleClick(): void {
224
+ const { editor } = this
225
+ if (editor.single && editor.element.isBranch) {
226
+ //list[0].hitChildren = true
227
+ }
228
+ }
229
+
230
+ public listenPointEvents(point: IEditPoint, type: IEditPointType, direction: IDirection8): void {
231
+ const { editor } = this
232
+ point.direction = direction
233
+ point.pointType = type
234
+ point.on_(DragEvent.START, this.onDragStart, this)
235
+ point.on_(DragEvent.DRAG, this.onDrag, this)
236
+ point.on_(DragEvent.END, this.onDragEnd, this)
237
+ point.on_(PointerEvent.LEAVE, () => this.enterPoint = null)
238
+ if (point.name !== 'circle') point.on_(PointerEvent.ENTER, (e) => { this.enterPoint = point, updateCursor(editor, e) })
239
+ }
240
+
241
+ protected __listenEvents(): void {
242
+ const { rect, editor } = this
243
+ this.__eventIds = [
244
+ editor.on_(EditorEvent.SELECT, () => { this.visible = editor.hasTarget }),
245
+ rect.on_(DragEvent.START, this.onDragStart, this),
246
+ rect.on_(DragEvent.DRAG, editor.onMove, editor),
247
+ rect.on_(DragEvent.END, this.onDragEnd, this),
248
+ rect.on_(PointerEvent.ENTER, () => updateMoveCursor(editor)),
249
+ rect.on_(PointerEvent.DOUBLE_CLICK, this.onDoubleClick, this)
250
+ ]
251
+ }
252
+
253
+ protected __removeListenEvents(): void {
254
+ this.off_(this.__eventIds)
255
+ this.__eventIds.length = 0
256
+ }
257
+
258
+ public destroy(): void {
259
+ this.editor = null
260
+ this.__removeListenEvents()
261
+ super.destroy()
262
+ }
263
+
264
+ }
@@ -0,0 +1,9 @@
1
+ import { Box } from '@leafer-ui/core'
2
+
3
+ import { IDirection8, IEditPoint, IEditPointType } from '@leafer-in/interface'
4
+
5
+
6
+ export class EditPoint extends Box implements IEditPoint {
7
+ public direction: IDirection8
8
+ public pointType: IEditPointType
9
+ }
@@ -0,0 +1,236 @@
1
+ import { IBounds, ILeaf, ILeafList, IUI, IEventListenerId } from '@leafer-ui/interface'
2
+ import { Bounds, PointerEvent, DragEvent, MoveEvent, LeafList, Group, ZoomEvent } from '@leafer-ui/core'
3
+
4
+ import { IEditSelect, IEditor, ISelectArea, IStroker } from '@leafer-in/interface'
5
+
6
+ import { Stroker } from './Stroker'
7
+ import { SelectArea } from './SelectArea'
8
+ import { EditSelectHelper } from '../helper/EditSelectHelper'
9
+ import { EditorEvent } from '../event/EditorEvent'
10
+
11
+
12
+ const { findOne } = EditSelectHelper
13
+
14
+ export class EditSelect extends Group implements IEditSelect {
15
+
16
+ public editor: IEditor
17
+
18
+ public get dragging(): boolean { return !!this.originList }
19
+ public get running(): boolean { return this.editor.hittable && this.editor.config.selector }
20
+ public get isMoveMode(): boolean { return this.app && this.app.interaction.moveMode }
21
+
22
+ public hoverStroker: IStroker = new Stroker()
23
+ public targetStroker: IStroker = new Stroker()
24
+
25
+ public bounds: IBounds = new Bounds()
26
+ public selectArea: ISelectArea = new SelectArea()
27
+
28
+ protected originList: ILeafList
29
+ protected lastDownLeaf: IUI
30
+
31
+ protected __eventIds: IEventListenerId[] = []
32
+
33
+
34
+ constructor(editor: IEditor) {
35
+ super()
36
+ this.editor = editor
37
+ this.addMany(this.targetStroker, this.hoverStroker, this.selectArea)
38
+ this.__listenEvents()
39
+ }
40
+
41
+ // hover / select
42
+
43
+ protected onHover(): void {
44
+ const { editor } = this
45
+ if (this.running && !this.dragging && !editor.dragging) {
46
+ const { stroke, strokeWidth, hover } = editor.config
47
+ this.hoverStroker.setTarget(hover ? this.editor.hoverTarget : null, { stroke, strokeWidth })
48
+ } else {
49
+ this.hoverStroker.target = null
50
+ }
51
+ }
52
+
53
+ protected onSelect(): void {
54
+ if (this.running) {
55
+ const { config, list } = this.editor
56
+ const { stroke, strokeWidth } = config
57
+ this.targetStroker.setTarget(list, { stroke, strokeWidth: Math.max(1, strokeWidth / 2) })
58
+ this.hoverStroker.target = null
59
+ }
60
+ }
61
+
62
+ public update(): void {
63
+ if (this.running) this.targetStroker.forceUpdate()
64
+ }
65
+
66
+ // move / down
67
+
68
+ protected onPointerMove(e: PointerEvent): void {
69
+ if (this.running && !this.isMoveMode) {
70
+ const find = e.shiftKey ? this.findDeepOne(e) : findOne(e.path)
71
+ this.editor.hoverTarget = this.editor.hasItem(find) ? null : find
72
+ } if (this.isMoveMode) {
73
+ this.editor.hoverTarget = null // move.dragEmpty
74
+ }
75
+ }
76
+
77
+ protected onBeforeDown(e: PointerEvent): void {
78
+ if (this.running && !this.isMoveMode && !e.middle) {
79
+ const find = this.lastDownLeaf = findOne(e.path)
80
+
81
+ if (find) {
82
+
83
+ if (e.shiftKey) {
84
+ this.editor.shiftItem(find)
85
+ } else {
86
+ this.editor.target = find
87
+ }
88
+
89
+ // change down data
90
+ this.editor.updateLayout()
91
+ find.leafer.interaction.updateDownData()
92
+
93
+ } else if (this.allow(e.target)) {
94
+
95
+ if (!e.shiftKey) this.editor.target = null
96
+
97
+ }
98
+ }
99
+ }
100
+
101
+ protected onTap(e: PointerEvent): void {
102
+ if (this.running && e.shiftKey && !e.middle && !this.lastDownLeaf) {
103
+ const find = this.findDeepOne(e)
104
+ if (find) this.editor.shiftItem(find)
105
+ } else if (this.isMoveMode) {
106
+ this.editor.target = null // move.dragEmpty
107
+ }
108
+
109
+ this.lastDownLeaf = null
110
+ }
111
+
112
+ // drag
113
+
114
+ protected onDragStart(e: DragEvent): void {
115
+ if (this.running && this.allowDrag(e)) {
116
+ const { editor } = this
117
+ const { stroke, strokeWidth, area } = editor.config
118
+ const { x, y } = e.getInner(this)
119
+
120
+ this.bounds.set(x, y)
121
+
122
+ this.selectArea.setStyle({ visible: true, stroke, strokeWidth, x, y }, area)
123
+ this.selectArea.setBounds(this.bounds.get())
124
+
125
+ this.originList = editor.leafList.clone()
126
+ }
127
+ }
128
+
129
+ protected onDrag(e: DragEvent): void {
130
+ if (this.editor.dragging) {
131
+ this.onDragEnd()
132
+ return
133
+ }
134
+
135
+ if (this.dragging) {
136
+ const { editor } = this
137
+ const total = e.getInnerTotal(this)
138
+
139
+ const dragBounds = this.bounds.clone().unsign()
140
+ const list = new LeafList(editor.app.find(EditSelectHelper.findBounds, dragBounds))
141
+
142
+ this.bounds.width = total.x
143
+ this.bounds.height = total.y
144
+
145
+ this.selectArea.setBounds(dragBounds.get())
146
+
147
+ if (list.length) {
148
+
149
+ const selectList: ILeaf[] = []
150
+
151
+ this.originList.forEach(item => { if (!list.has(item)) selectList.push(item) })
152
+ list.forEach(item => { if (!this.originList.has(item)) selectList.push(item) })
153
+
154
+ if (selectList.length !== editor.list.length || editor.list.some((child, index) => child !== selectList[index])) {
155
+ editor.target = selectList as IUI[]
156
+ }
157
+
158
+ } else {
159
+
160
+ editor.target = this.originList.list as IUI[]
161
+ if (editor.leafList.length) editor.update()
162
+
163
+ }
164
+ }
165
+ }
166
+
167
+ protected onDragEnd(): void {
168
+ if (this.dragging) this.originList = null, this.selectArea.visible = false
169
+ }
170
+
171
+ protected onAutoMove(e: MoveEvent): void {
172
+ if (this.dragging) {
173
+ const { x, y } = e.getLocalMove(this)
174
+ this.bounds.x += x
175
+ this.bounds.y += y
176
+ }
177
+ }
178
+
179
+ // helper
180
+
181
+ protected allow(target: ILeaf): boolean {
182
+ return target.leafer !== this.editor.leafer
183
+ }
184
+
185
+ protected allowDrag(e: DragEvent) {
186
+ if (this.editor.config.boxSelect && !e.target.draggable) {
187
+ return (!this.editor.hasTarget && this.allow(e.target)) || (e.shiftKey && !findOne(e.path))
188
+ } else {
189
+ return false
190
+ }
191
+ }
192
+
193
+ protected findDeepOne(e: PointerEvent): IUI {
194
+ const options = { exclude: new LeafList(this.editor.editBox.rect) }
195
+ return findOne(e.target.leafer.interaction.findPath(e, options)) as IUI
196
+ }
197
+
198
+ protected __listenEvents(): void {
199
+ const { editor } = this
200
+ editor.waitLeafer(() => {
201
+
202
+ const { app } = editor
203
+ app.selector.proxy = editor
204
+
205
+ this.__eventIds = [
206
+ editor.on_(EditorEvent.HOVER, this.onHover, this),
207
+ editor.on_(EditorEvent.SELECT, this.onSelect, this),
208
+
209
+ app.on_(PointerEvent.MOVE, this.onPointerMove, this),
210
+ app.on_(PointerEvent.BEFORE_DOWN, this.onBeforeDown, this),
211
+ app.on_(PointerEvent.TAP, this.onTap, this),
212
+
213
+ app.on_(DragEvent.START, this.onDragStart, this),
214
+ app.on_(DragEvent.DRAG, this.onDrag, this),
215
+ app.on_(DragEvent.END, this.onDragEnd, this),
216
+
217
+ app.on_(MoveEvent.MOVE, this.onAutoMove, this),
218
+ app.on_([ZoomEvent.ZOOM, MoveEvent.MOVE], () => { this.editor.hoverTarget = null }),
219
+ ]
220
+
221
+ })
222
+ }
223
+
224
+ protected __removeListenEvents(): void {
225
+ if (this.__eventIds) {
226
+ this.off_(this.__eventIds)
227
+ this.__eventIds.length = 0
228
+ }
229
+ }
230
+
231
+ public destroy(): void {
232
+ this.editor = this.originList = this.lastDownLeaf = null
233
+ this.__removeListenEvents()
234
+ super.destroy()
235
+ }
236
+ }
@@ -0,0 +1,30 @@
1
+ import { IBoundsData, IGroupInputData, IRect, IRectInputData } from '@leafer-ui/interface'
2
+ import { Group, Rect } from '@leafer-ui/core'
3
+
4
+ import { ISelectArea } from '@leafer-in/interface'
5
+
6
+
7
+ export class SelectArea extends Group implements ISelectArea {
8
+
9
+ protected strokeArea: IRect = new Rect({ strokeAlign: 'center' })
10
+ protected fillArea: IRect = new Rect()
11
+
12
+ constructor(data?: IGroupInputData) {
13
+ super(data)
14
+ this.visible = this.hittable = false
15
+ this.addMany(this.fillArea, this.strokeArea)
16
+ }
17
+
18
+ public setStyle(style: IRectInputData, userStyle?: IRectInputData): void {
19
+ const { visible, stroke, strokeWidth } = style
20
+ this.visible = visible
21
+ this.strokeArea.reset({ stroke, strokeWidth, ...(userStyle || {}) })
22
+ this.fillArea.reset({ visible: userStyle ? false : true, fill: stroke, opacity: 0.2 })
23
+ }
24
+
25
+ public setBounds(bounds: IBoundsData): void {
26
+ this.strokeArea.set(bounds)
27
+ this.fillArea.set(bounds)
28
+ }
29
+
30
+ }
@@ -0,0 +1,89 @@
1
+ import { IUI, ILeaferCanvas, IRenderOptions, IRectInputData } from '@leafer-ui/interface'
2
+ import { Paint, UI, MatrixHelper } from '@leafer-ui/core'
3
+
4
+ import { IStroker } from '@leafer-in/interface'
5
+
6
+ import { targetAttr } from '../decorator/data'
7
+
8
+
9
+ const matrix = MatrixHelper.get()
10
+ const { abs } = Math
11
+ const { copy, scale } = MatrixHelper
12
+
13
+ export class Stroker extends UI implements IStroker {
14
+
15
+ @targetAttr(onTarget)
16
+ public target: IUI | IUI[]
17
+
18
+ public list: IUI[] = []
19
+
20
+ constructor() {
21
+ super()
22
+ this.hittable = false
23
+ this.strokeAlign = 'center'
24
+ }
25
+
26
+ public setTarget(target: IUI | IUI[], style: IRectInputData): void {
27
+ const { stroke, strokeWidth } = style
28
+ this.set({ stroke, strokeWidth })
29
+ this.target = target
30
+ }
31
+
32
+ public __draw(canvas: ILeaferCanvas, options: IRenderOptions): void {
33
+ const { list } = this
34
+ if (list.length) {
35
+
36
+ let leaf: IUI
37
+ const { stroke, strokeWidth } = this.__
38
+ const { bounds } = options
39
+
40
+ for (let i = 0; i < list.length; i++) {
41
+ leaf = list[i]
42
+ if (bounds && bounds.hit(leaf.__world, options.matrix)) {
43
+
44
+ let drewPath: boolean
45
+
46
+ if (leaf.__.editSize === 'scale') {
47
+ const aScaleX = abs(leaf.__world.scaleX), aScaleY = abs(leaf.__world.scaleY)
48
+ if (aScaleX !== aScaleY) { // need no scale stroke
49
+ copy(matrix, leaf.__world)
50
+ scale(matrix, 1 / aScaleX, 1 / aScaleY)
51
+
52
+ canvas.setWorld(matrix, options.matrix)
53
+ canvas.beginPath()
54
+ this.__.strokeWidth = strokeWidth
55
+
56
+ const { x, y, width, height } = leaf.__layout.boxBounds
57
+ canvas.rect(x * aScaleX, y * aScaleY, width * aScaleX, height * aScaleY)
58
+
59
+ drewPath = true
60
+ }
61
+ }
62
+
63
+ if (!drewPath) {
64
+ canvas.setWorld(leaf.__world, options.matrix)
65
+ canvas.beginPath()
66
+ leaf.__.__pathForRender ? leaf.__drawRenderPath(canvas) : leaf.__drawPathByBox(canvas)
67
+ this.__.strokeWidth = strokeWidth / abs(leaf.__world.scaleX)
68
+ }
69
+
70
+ typeof stroke === 'string' ? Paint.stroke(stroke, this, canvas, options) : Paint.strokes(stroke, this, canvas, options)
71
+ }
72
+ }
73
+
74
+ this.__.strokeWidth = strokeWidth
75
+ }
76
+ }
77
+
78
+ public destroy(): void {
79
+ this.target = null
80
+ super.destroy()
81
+ }
82
+
83
+ }
84
+
85
+ function onTarget(stroker: Stroker): void {
86
+ const value = stroker.target
87
+ stroker.list = value ? (value instanceof Array ? value : [value]) : []
88
+ stroker.forceUpdate()
89
+ }
@@ -0,0 +1,58 @@
1
+ import { ICursorType, IUIEvent } from '@leafer-ui/interface'
2
+ import { IDirection8, IEditor } from '@leafer-in/interface'
3
+
4
+ import { EditDataHelper } from '../helper/EditDataHelper'
5
+
6
+
7
+ const { topLeft, top, topRight, right, bottomRight, bottom, bottomLeft, left } = IDirection8
8
+
9
+ export function updateCursor(editor: IEditor, e: IUIEvent): void {
10
+ const { editBox } = editor, point = editBox.enterPoint
11
+ if (!point || !editor.hasTarget || !editBox.visible) return
12
+
13
+ let { rotation } = editBox
14
+ let { resizeCursor, rotateCursor, resizeable, rotateable } = editor.config
15
+ const { direction, pointType } = point
16
+
17
+ editBox.enterPoint = point
18
+ const isResizePoint = pointType === 'resize'
19
+
20
+ if (isResizePoint && rotateable && (e.metaKey || e.ctrlKey || !resizeable)) resizeCursor = rotateCursor
21
+
22
+ if (editBox.flipped) {
23
+ const { flippedX, flippedY } = editBox
24
+ mirrorCursors(resizeCursor = [...resizeCursor], flippedX, flippedY)
25
+ mirrorCursors(rotateCursor = [...rotateCursor], flippedY, flippedX)
26
+ if (editBox.flippedOne) rotation = -rotation
27
+ }
28
+
29
+ const index = EditDataHelper.getRotateDirection(direction, rotation)
30
+ point.cursor = isResizePoint ? resizeCursor[index] : rotateCursor[index]
31
+ }
32
+
33
+ export function updateMoveCursor(editor: IEditor): void {
34
+ editor.editBox.rect.cursor = editor.config.moveCursor
35
+ }
36
+
37
+
38
+ export function mirrorCursors(mirror: ICursorType[], mirrorX: boolean, mirrorY: boolean): void {
39
+ if (mirrorX) {
40
+ const topCursor = mirror[top], topLeftCursor = mirror[topLeft], topRightCursor = mirror[topRight]
41
+ mirror[top] = mirror[bottom]
42
+ mirror[topLeft] = mirror[bottomLeft]
43
+ mirror[topRight] = mirror[bottomRight]
44
+ mirror[bottom] = topCursor
45
+ mirror[bottomLeft] = topLeftCursor
46
+ mirror[bottomRight] = topRightCursor
47
+ }
48
+
49
+ if (mirrorY) {
50
+ const leftCursor = mirror[left], topLeftCursor = mirror[topLeft], bottomLeftCursor = mirror[bottomLeft]
51
+ mirror[left] = mirror[right]
52
+ mirror[topLeft] = mirror[topRight]
53
+ mirror[bottomLeft] = mirror[bottomRight]
54
+ mirror[right] = leftCursor
55
+ mirror[topRight] = topLeftCursor
56
+ mirror[bottomRight] = bottomLeftCursor
57
+ }
58
+ }