@leafer-in/editor 1.0.0-beta.15

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 ADDED
@@ -0,0 +1,232 @@
1
+ import { IGroupInputData, IPolygon, IUI, IEventListenerId } from '@leafer-ui/interface'
2
+ import { IEditor, IEditorConfig, IEditorTool, IDirection8 } from '@leafer-in/interface'
3
+
4
+ import { Group, Rect, Polygon, DragEvent, PointHelper, PointerEvent, KeyEvent, RotateEvent, DataHelper, MathHelper, RenderEvent } from '@leafer-ui/core'
5
+
6
+ import { getResizeData } from './resize'
7
+ import { updateCursor } from './cursor'
8
+
9
+ import { LineTool } from './tool/LineTool'
10
+ import { RectTool } from './tool/RectTool'
11
+
12
+ import { EditorResizeEvent } from './event/EditorResizeEvent'
13
+ import { EditorRotateEvent } from './event/EditorRotateEvent'
14
+
15
+
16
+ export class Editor extends Group implements IEditor {
17
+
18
+ public config: IEditorConfig = {
19
+ type: 'pc',
20
+ stroke: '#836DFF',
21
+ pointFill: '#FFFFFF',
22
+ pointSize: 10,
23
+ pointRadius: 10,
24
+ rotateGap: 90,
25
+ hideOnMove: false,
26
+ moveCursor: 'move',
27
+ resizeType: 'auto',
28
+ resizeCursor: ['nwse-resize', 'ns-resize', 'nesw-resize', 'ew-resize', 'nwse-resize', 'ns-resize', 'nesw-resize', 'ew-resize'],
29
+ rotateCursor: ['ne-resize', 'e-resize', 'se-resize', 's-resize', 'sw-resize', 'w-resize', 'nw-resize', 'n-resize'],
30
+ resizeable: true,
31
+ rotateable: true
32
+ }
33
+
34
+ public resizePoints: IUI[] = [] // topLeft, top, topRight, right, bottomRight, bottom, bottomLeft, left
35
+ public rotatePoints: IUI[] = [] // topLeft, top, topRight, right, bottomRight, bottom, bottomLeft, left
36
+ public resizeLines: IUI[] = [] // top, right, bottom, left
37
+
38
+ public targetRect: IUI = new Rect({ hitFill: 'all', hitRadius: 5 })
39
+ public rect: IPolygon = new Polygon({ hittable: false, strokeAlign: 'center' })
40
+ public circle: IUI = new Rect({ around: 'center', hitRadius: 10 }) // rotate point
41
+
42
+ public tool: IEditorTool
43
+
44
+ private _target: IUI
45
+ public get target(): IUI { return this._target }
46
+ public set target(value: IUI) {
47
+ this.__removeTargetEvents()
48
+ this.visible = !!value
49
+
50
+ this._target = value
51
+ if (value) this.onTarget()
52
+ }
53
+
54
+ public enterPoint: IUI
55
+
56
+ protected __eventIds: IEventListenerId[] = []
57
+ protected __targetEventIds: IEventListenerId[] = []
58
+
59
+ constructor(userConfig?: IEditorConfig, data?: IGroupInputData) {
60
+ super(data)
61
+ if (userConfig) this.config = DataHelper.default(userConfig, this.config)
62
+ this.init()
63
+ }
64
+
65
+ protected init() {
66
+ let rotatePoint: IUI, resizeLine: IUI, resizePoint: IUI
67
+ const { resizePoints, rotatePoints, resizeLines } = this
68
+
69
+ for (let i = 0; i < 8; i++) {
70
+ rotatePoint = new Rect({ around: 'center', width: 30, height: 30, hitRadius: 10, hitFill: "all" })
71
+ rotatePoints.push(rotatePoint)
72
+ this.__listenPointEvents(rotatePoint, 'rotate', i)
73
+
74
+ if (i % 2) {
75
+ resizeLine = new Rect({ around: 'center', width: 10, height: 10, hitFill: "all" })
76
+ resizeLines.push(resizeLine)
77
+ this.__listenPointEvents(resizeLine, 'resize', i)
78
+ }
79
+
80
+ resizePoint = new Rect({ around: 'center', hitRadius: 5 })
81
+ resizePoints.push(resizePoint)
82
+ this.__listenPointEvents(resizePoint, 'resize', i)
83
+ }
84
+
85
+ this.__listenPointEvents(this.circle, 'rotate', 1)
86
+ this.addMany(...rotatePoints, this.targetRect, this.rect, this.circle, ...resizeLines, ...resizePoints)
87
+
88
+ this.__listenEvents()
89
+ }
90
+
91
+
92
+ protected onTarget(): void {
93
+ this.tool = this.getTool(this.target)
94
+ this.waitLeafer(() => {
95
+ this.update()
96
+ this.updateMoveCursor()
97
+ this.__listenTargetEvents()
98
+ })
99
+ }
100
+
101
+ public getTool(value: IUI): IEditorTool {
102
+ return (value.tag === 'Line' && value.resizeable) ? LineTool : RectTool
103
+ }
104
+
105
+ public update(): void {
106
+ if (!this.target) return
107
+ this.tool.update(this)
108
+ }
109
+
110
+
111
+ protected onDrag(e: DragEvent): void {
112
+ const { resizeable, rotateable } = this.config
113
+ if (e.metaKey || e.ctrlKey || !resizeable) {
114
+ if (rotateable) this.onRotate(e)
115
+ } else {
116
+ this.onResize(e)
117
+ }
118
+ }
119
+
120
+ protected onMove(e: DragEvent): void {
121
+ const { target } = this
122
+ const { x, y } = e.getLocalMove(target)
123
+ if (e.shiftKey) {
124
+ if (Math.abs(x) > Math.abs(y)) {
125
+ target.x += x
126
+ } else {
127
+ target.y += y
128
+ }
129
+ } else {
130
+ target.x += x
131
+ target.y += y
132
+ }
133
+ }
134
+
135
+ protected onRotate(e: DragEvent | RotateEvent): void {
136
+ const { target } = this
137
+ const { rotateGap } = this.config
138
+ const { x, y, width, height } = target.boxBounds
139
+ const origin = { x: x + width / 2, y: y + height / 2 }
140
+
141
+ let rotation: number
142
+
143
+ if (e instanceof RotateEvent) {
144
+ rotation = e.rotation
145
+ } else {
146
+ const point = e
147
+ const last = { x: point.x - e.moveX, y: point.y - e.moveY }
148
+ rotation = PointHelper.getChangeAngle(last, target.getWorldPoint(origin), point)
149
+ }
150
+
151
+ rotation = MathHelper.getGapRotation(target.rotation + rotation, rotateGap) - target.rotation
152
+
153
+ const event = new EditorRotateEvent(EditorRotateEvent.ROTATE, { editor: this, target, origin, rotation })
154
+
155
+ this.tool.rotate(event)
156
+ target.emitEvent(event)
157
+ }
158
+
159
+ public onResize(e: DragEvent): void {
160
+ const { target } = this
161
+ const { __direction } = e.current.__
162
+
163
+ let { resizeType, around, lockRatio } = this.config
164
+
165
+ if (e.shiftKey) lockRatio = true
166
+ if (e.altKey && !around) around = 'center'
167
+
168
+ if (resizeType === 'auto') resizeType = target.resizeable ? 'size' : 'scale'
169
+ const data = getResizeData(target.boxBounds, __direction, e.getInnerMove(this.targetRect), lockRatio, around)
170
+
171
+ const event = new EditorResizeEvent(EditorResizeEvent.RESIZE, { ...data, target, editor: this, dragEvent: e, resizeType })
172
+
173
+ this.tool.resize(event)
174
+ target.emitEvent(event)
175
+ }
176
+
177
+
178
+ public updateMoveCursor(): void {
179
+ this.targetRect.cursor = this.config.moveCursor
180
+ }
181
+
182
+
183
+ protected __listenEvents(): void {
184
+ this.__eventIds = [
185
+ this.targetRect.on_(DragEvent.START, () => { this.opacity = this.config.hideOnMove ? 0 : 1 }),
186
+ this.targetRect.on_(DragEvent.DRAG, this.onMove, this),
187
+ this.targetRect.on_(DragEvent.END, () => { this.opacity = 1 }),
188
+ this.targetRect.on_(PointerEvent.ENTER, this.updateMoveCursor, this)
189
+ ]
190
+ }
191
+
192
+ protected __removeListenEvents(): void {
193
+ this.targetRect.off_(this.__eventIds)
194
+ this.__eventIds.length = 0
195
+ }
196
+
197
+
198
+ protected __listenPointEvents(point: IUI, type: 'rotate' | 'resize', direction: IDirection8): void {
199
+ point.__.__direction = direction
200
+ const resize = point.__.__isResizePoint = type === 'resize'
201
+ point.on_(DragEvent.DRAG, resize ? this.onDrag : this.onRotate, this) // i % 2 ? this.onSkew :
202
+ point.on_(PointerEvent.LEAVE, () => this.enterPoint = null)
203
+ point.on_(PointerEvent.ENTER, (e) => { this.enterPoint = point; updateCursor(this, e) })
204
+ }
205
+
206
+
207
+ protected __listenTargetEvents(): void {
208
+ if (this.target) {
209
+ const { leafer } = this.target
210
+ this.__targetEventIds = [
211
+ leafer.on_(RenderEvent.START, this.update, this),
212
+ leafer.on_([KeyEvent.HOLD, KeyEvent.UP], (e) => { updateCursor(this, e) })
213
+ ]
214
+ }
215
+ }
216
+
217
+ protected __removeTargetEvents(): void {
218
+ if (this.__targetEventIds.length) {
219
+ const { leafer } = this.target
220
+ if (leafer) leafer.off_(this.__targetEventIds)
221
+ this.__targetEventIds.length = 0
222
+ }
223
+ }
224
+
225
+
226
+ public destroy(): void {
227
+ this.__removeListenEvents()
228
+ this._target = null
229
+ super.destroy()
230
+ }
231
+
232
+ }
package/src/cursor.ts ADDED
@@ -0,0 +1,57 @@
1
+ import { ICursorType, IUIEvent } from '@leafer-ui/interface'
2
+ import { IDirection8, IEditor } from '@leafer-in/interface'
3
+
4
+
5
+ const { topLeft, top, topRight, right, bottomRight, bottom, bottomLeft, left } = IDirection8
6
+
7
+ export function updateCursor(editor: IEditor, e: IUIEvent): void {
8
+
9
+ const point = editor.enterPoint
10
+ if (!point || !editor.target || !editor.visible) return
11
+
12
+ let { rotation } = editor
13
+ let { resizeCursor, rotateCursor, resizeable } = editor.config
14
+ const mirror = editor.tool.getMirrorData(editor)
15
+ const { __direction, __isResizePoint } = point.__
16
+
17
+ editor.enterPoint = point
18
+
19
+ if (__isResizePoint && (e.metaKey || e.ctrlKey || !resizeable)) resizeCursor = rotateCursor
20
+
21
+ if (mirror.x || mirror.y) {
22
+ mirrorCursors(resizeCursor = [...resizeCursor], mirror.x, mirror.y)
23
+ mirrorCursors(rotateCursor = [...rotateCursor], mirror.y, mirror.x)
24
+ if (mirror.x + mirror.y === 1) rotation = -rotation
25
+ }
26
+
27
+ let index = (__direction + Math.round(rotation / 45)) % 8
28
+ if (index < 0) index += 8
29
+
30
+ point.cursor = __isResizePoint ? resizeCursor[index] : rotateCursor[index]
31
+
32
+ }
33
+
34
+
35
+ export function mirrorCursors(mirror: ICursorType[], mirrorX: number, mirrorY: number): void {
36
+
37
+ if (mirrorX) {
38
+ const topCursor = mirror[top], topLeftCursor = mirror[topLeft], topRightCursor = mirror[topRight]
39
+ mirror[top] = mirror[bottom]
40
+ mirror[topLeft] = mirror[bottomLeft]
41
+ mirror[topRight] = mirror[bottomRight]
42
+ mirror[bottom] = topCursor
43
+ mirror[bottomLeft] = topLeftCursor
44
+ mirror[bottomRight] = topRightCursor
45
+ }
46
+
47
+ if (mirrorY) {
48
+ const leftCursor = mirror[left], topLeftCursor = mirror[topLeft], bottomLeftCursor = mirror[bottomLeft]
49
+ mirror[left] = mirror[right]
50
+ mirror[topLeft] = mirror[topRight]
51
+ mirror[bottomLeft] = mirror[bottomRight]
52
+ mirror[right] = leftCursor
53
+ mirror[topRight] = topLeftCursor
54
+ mirror[bottomRight] = bottomLeftCursor
55
+ }
56
+
57
+ }
@@ -0,0 +1,34 @@
1
+ import { IUI, IResizeType, IBoundsData, IPointData, IAround, IDragEvent } from '@leafer-ui/interface'
2
+ import { IEditor, IDirection8, IEditorResizeEvent } from '@leafer-in/interface'
3
+
4
+ import { Event } from '@leafer-ui/core'
5
+
6
+ export class EditorResizeEvent extends Event implements IEditorResizeEvent {
7
+
8
+ static RESIZE = 'editor.resize'
9
+
10
+ declare readonly target: IUI
11
+ readonly editor: IEditor
12
+
13
+ readonly resizeType: IResizeType
14
+ readonly lockRatio: boolean
15
+ readonly around: IAround
16
+
17
+ readonly dragEvent: IDragEvent
18
+ readonly direction: IDirection8
19
+
20
+ // from old to bounds
21
+ readonly bounds: IBoundsData
22
+ readonly old: IBoundsData
23
+
24
+ // scaleOf(origin, scaleX, scaleY)
25
+ readonly origin: IPointData
26
+ readonly scaleX: number
27
+ readonly scaleY: number
28
+
29
+ constructor(type: string, data?: IEditorResizeEvent) {
30
+ super(type)
31
+ if (data) Object.assign(this, data)
32
+ }
33
+
34
+ }
@@ -0,0 +1,23 @@
1
+ import { IUI, IPointData } from '@leafer-ui/interface'
2
+ import { IEditor, IEditorRotateEvent } from '@leafer-in/interface'
3
+
4
+ import { Event } from '@leafer-ui/core'
5
+
6
+
7
+ export class EditorRotateEvent extends Event implements IEditorRotateEvent {
8
+
9
+ static ROTATE = 'editor.rotate'
10
+
11
+ declare readonly target: IUI
12
+ readonly editor: IEditor
13
+
14
+ // rotateOf(origin, rotation)
15
+ readonly origin: IPointData
16
+ readonly rotation: number
17
+
18
+ constructor(type: string, data?: IEditorRotateEvent) {
19
+ super(type)
20
+ if (data) Object.assign(this, data)
21
+ }
22
+
23
+ }
package/src/index.ts ADDED
@@ -0,0 +1,5 @@
1
+ export { Editor } from './Editor'
2
+ export { EditorResizeEvent } from './event/EditorResizeEvent'
3
+ export { EditorRotateEvent } from './event/EditorRotateEvent'
4
+ export { LineTool } from './tool/LineTool'
5
+ export { RectTool } from './tool/RectTool'
package/src/resize.ts ADDED
@@ -0,0 +1,87 @@
1
+ import { IBoundsData, IPointData, IMatrixData, IAround } from '@leafer-ui/interface'
2
+ import { IEditorResizeEvent, IDirection8 } from '@leafer-in/interface'
3
+
4
+ import { MatrixHelper } from '@leafer-ui/core'
5
+
6
+
7
+ const { scaleOfOuter, reset } = MatrixHelper
8
+ const { topLeft, top, topRight, right, bottomRight, bottom, bottomLeft, left } = IDirection8
9
+ const matrix = {} as IMatrixData
10
+
11
+ export function getResizeData(old: IBoundsData, direction: IDirection8, move: IPointData, lockRatio: boolean, around: IAround): IEditorResizeEvent {
12
+
13
+ if (around) {
14
+ move.x *= 2
15
+ move.y *= 2
16
+ }
17
+
18
+ let origin: IPointData, scaleX: number = 1, scaleY: number = 1
19
+ const { x, y, width, height } = old
20
+
21
+ const topScale = (-move.y + height) / height
22
+ const rightScale = (move.x + width) / width
23
+ const bottomScale = (move.y + height) / height
24
+ const leftScale = (-move.x + width) / width
25
+
26
+ switch (direction) {
27
+ case top:
28
+ scaleY = topScale
29
+ if (lockRatio) scaleX = scaleY
30
+ origin = { x: x + width / 2, y: y + height }
31
+ break
32
+ case right:
33
+ scaleX = rightScale
34
+ if (lockRatio) scaleY = scaleX
35
+ origin = { x, y: y + height / 2 }
36
+ break
37
+ case bottom:
38
+ scaleY = bottomScale
39
+ if (lockRatio) scaleX = scaleY
40
+ origin = { x: x + width / 2, y }
41
+ break
42
+ case left:
43
+ scaleX = leftScale
44
+ if (lockRatio) scaleY = scaleX
45
+ origin = { x: x + width, y: y + height / 2 }
46
+ break
47
+ case topLeft:
48
+ scaleY = topScale
49
+ scaleX = leftScale
50
+ if (lockRatio) scaleX = scaleY
51
+ origin = { x: x + width, y: y + height }
52
+ break
53
+ case topRight:
54
+ scaleY = topScale
55
+ scaleX = rightScale
56
+ if (lockRatio) scaleX = scaleY
57
+ origin = { x, y: y + height }
58
+ break
59
+ case bottomRight:
60
+ scaleY = bottomScale
61
+ scaleX = rightScale
62
+ if (lockRatio) scaleX = scaleY
63
+ origin = { x, y }
64
+ break
65
+ case bottomLeft:
66
+ scaleY = bottomScale
67
+ scaleX = leftScale
68
+ if (lockRatio) scaleX = scaleY
69
+ origin = { x: x + width, y }
70
+ break
71
+ }
72
+
73
+ if (around) {
74
+ if (typeof around === 'object') {
75
+ origin = { x: x + width / around.x, y: y + height / around.y }
76
+ } else {
77
+ origin = { x: x + width / 2, y: y + height / 2 }
78
+ }
79
+ }
80
+
81
+ reset(matrix)
82
+ scaleOfOuter(matrix, origin, scaleX, scaleY)
83
+ const bounds = { x: old.x + matrix.e, y: old.y + matrix.f, width: width * scaleX, height: height * scaleY }
84
+ return { bounds, old, origin, scaleX, scaleY, direction, lockRatio, around, }
85
+
86
+ }
87
+
@@ -0,0 +1,88 @@
1
+ import { IDirection8, IEditor, IEditorTool, IEditorResizeEvent, IEditorRotateEvent, ILine, IPointData } from '@leafer-in/interface'
2
+
3
+ import { RectTool } from './RectTool'
4
+
5
+
6
+ const { left, right } = IDirection8
7
+
8
+ export const LineTool: IEditorTool = {
9
+
10
+ name: 'LineTool',
11
+
12
+ getMirrorData(_editor: IEditor): IPointData {
13
+ return {
14
+ x: 0,
15
+ y: 0
16
+ }
17
+ },
18
+
19
+ resize(e: IEditorResizeEvent): void {
20
+ const { direction, dragEvent, lockRatio, around } = e
21
+ const target = e.target as ILine
22
+
23
+ const fromPoint = { x: 0, y: 0 }
24
+ const { toPoint } = target
25
+
26
+ target.rotation = 0
27
+
28
+ let { x, y } = dragEvent.getInnerMove(target)
29
+
30
+ if (lockRatio) {
31
+ if (Math.abs(x) > Math.abs(y)) {
32
+ y = 0
33
+ } else {
34
+ x = 0
35
+ }
36
+ }
37
+
38
+ if (direction === left) {
39
+
40
+ fromPoint.x += x
41
+ fromPoint.y += y
42
+
43
+ if (around) {
44
+ toPoint.x -= x
45
+ toPoint.y -= y
46
+ }
47
+
48
+ } else {
49
+
50
+ if (around) {
51
+ fromPoint.x -= x
52
+ fromPoint.y -= y
53
+ }
54
+
55
+ toPoint.x += x
56
+ toPoint.y += y
57
+
58
+ }
59
+
60
+ target.getLocalPointByInner(fromPoint, null, null, true)
61
+ target.getLocalPointByInner(toPoint, null, null, true)
62
+ target.x = fromPoint.x
63
+ target.y = fromPoint.y
64
+
65
+ target.getInnerPointByLocal(toPoint, null, null, true)
66
+ target.toPoint = toPoint
67
+
68
+ },
69
+
70
+ rotate(e: IEditorRotateEvent): void {
71
+ RectTool.rotate(e)
72
+ },
73
+
74
+ update(editor: IEditor) {
75
+
76
+ const { rotatePoints, circle, resizeLines, resizePoints } = editor
77
+ RectTool.update(editor)
78
+
79
+ for (let i = 0; i < 8; i++) {
80
+ if (i < 4) resizeLines[i].visible = false
81
+ resizePoints[i].visible = rotatePoints[i].visible = i === left || i === right
82
+ }
83
+
84
+ circle.visible = false
85
+
86
+ }
87
+
88
+ }
@@ -0,0 +1,139 @@
1
+ import { IUI, IUIInputData, IPointData } from '@leafer-ui/interface'
2
+ import { IEditor, IEditorResizeEvent, IEditorRotateEvent, IEditorTool } from '@leafer-in/interface'
3
+
4
+ import { Bounds, Matrix } from '@leafer-ui/core'
5
+
6
+
7
+ export const RectTool: IEditorTool = {
8
+
9
+ name: 'RectTool',
10
+
11
+ getMirrorData(editor: IEditor): IPointData {
12
+ const { scaleX, scaleY } = editor.target
13
+ return {
14
+ x: scaleX < 0 ? 1 : 0, // 1 = mirrorX
15
+ y: scaleY < 0 ? 1 : 0
16
+ }
17
+ },
18
+
19
+ resize(e: IEditorResizeEvent): void {
20
+ const { target, bounds, resizeType, old } = e
21
+ const { x, y, width, height } = bounds
22
+ const point = { x: x - old.x, y: y - old.y }
23
+
24
+ target.innerToWorld(point, null, true, target.parent)
25
+ target.x += point.x
26
+ target.y += point.y
27
+
28
+ if (resizeType === 'scale') {
29
+ target.scaleX *= width / old.width
30
+ target.scaleY *= height / old.height
31
+ } else {
32
+ if (width < 0) {
33
+ target.width = -width
34
+ target.scaleX *= -1
35
+ } else {
36
+ if (target.width !== width) target.width = width
37
+ }
38
+
39
+ if (height < 0) {
40
+ target.height = -height
41
+ target.scaleY *= -1
42
+ } else {
43
+ if (target.height !== height) target.height = height // Text auto height
44
+ }
45
+
46
+
47
+ }
48
+ },
49
+
50
+ rotate(e: IEditorRotateEvent): void {
51
+ const { target, rotation, origin } = e
52
+ target.rotateOf(origin, rotation)
53
+ },
54
+
55
+ update(editor: IEditor) {
56
+ const { target, config, rotatePoints, targetRect, rect, circle, resizeLines, resizePoints } = editor
57
+ const { type, resizeable, rotateable, stroke, pointFill, pointSize, pointRadius } = config
58
+
59
+ const defaultStyle = { fill: pointFill, stroke, width: pointSize, height: pointSize, cornerRadius: pointRadius }
60
+ const pointStyles = config.point instanceof Array ? config.point : [config.point || defaultStyle]
61
+
62
+ const box = new Bounds(target.boxBounds)
63
+ const w = target.worldTransform, pw = editor.parent.worldTransform
64
+
65
+ const matrix = new Matrix(w)
66
+ matrix.divide(pw)
67
+ const worldX = matrix.e, worldY = matrix.f
68
+
69
+
70
+ let { scaleX, scaleY, rotation, skewX, skewY } = w
71
+ scaleX /= pw.scaleX, scaleY /= pw.scaleY, rotation -= pw.rotation, skewX -= pw.skewX, skewY -= pw.skewY
72
+
73
+ const { x, y, width, height } = box.scale(scaleX, scaleY) // maybe width / height < 0
74
+
75
+ editor.set({ x: worldX, y: worldY, rotation, skewX, skewY })
76
+ targetRect.set({ x, y, width: box.width / scaleX, height: box.height / scaleY, scaleX, scaleY, visible: true })
77
+
78
+
79
+ const points: IPointData[] = [ // topLeft, top, topRight, right, bottomRight, bottom, bottomLeft, left
80
+ { x, y },
81
+ { x: x + width / 2, y },
82
+ { x: x + width, y },
83
+ { x: x + width, y: y + height / 2 },
84
+ { x: x + width, y: y + height },
85
+ { x: x + width / 2, y: y + height },
86
+ { x, y: y + height },
87
+ { x, y: y + height / 2 }
88
+ ]
89
+
90
+ const rectPoints: number[] = []
91
+ let point: IPointData, style: IUIInputData, rotateP: IUI, resizeP: IUI, resizeL: IUI
92
+
93
+ for (let i = 0; i < 8; i++) {
94
+ point = points[i]
95
+ style = pointStyles[i % pointStyles.length]
96
+
97
+ resizeP = resizePoints[i]
98
+ resizeL = resizeLines[Math.floor(i / 2)]
99
+ rotateP = rotatePoints[i]
100
+
101
+ resizeP.set(style)
102
+ resizeP.x = rotateP.x = resizeL.x = point.x
103
+ resizeP.y = rotateP.y = resizeL.y = point.y
104
+
105
+ resizeP.visible = resizeL.visible = resizeable || rotateable
106
+ rotateP.visible = rotateable && resizeable
107
+
108
+ if (i % 2) { // top, right, bottom, left
109
+ if (((i + 1) / 2) % 2) { // top, bottom
110
+ resizeL.width = Math.abs(width)
111
+ rotateP.width = Math.max(10, Math.abs(width) - 30) // skew
112
+ } else {
113
+ resizeL.height = Math.abs(height)
114
+ rotateP.height = Math.max(10, Math.abs(height) - 30) // skew
115
+ }
116
+
117
+ resizeP.rotation = 90
118
+ resizeP.visible = type === 'mobile'
119
+
120
+ } else {
121
+ rectPoints.push(point.x, point.y)
122
+ }
123
+ }
124
+
125
+
126
+
127
+ style = config.rotatePoint || style
128
+
129
+ circle.set(style)
130
+ circle.x = x + width / 2
131
+ if (!style.y) circle.y = y - (10 + (resizeP.height + circle.height) / 2) * (this.getMirrorData(editor).y ? -1 : 1)
132
+ circle.visible = rotateable && type === 'mobile'
133
+
134
+ rect.set(config.rect || { stroke })
135
+ rect.points = rectPoints
136
+ rect.visible = true
137
+ }
138
+
139
+ }