@leafer-in/editor 1.0.0-rc.2 → 1.0.0-rc.21

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,45 @@
1
+ import { IObject, IUIEvent } from '@leafer-ui/interface'
2
+
3
+ import { IEditor } from '@leafer-in/interface'
4
+ import { MathHelper } from '@leafer-ui/draw'
5
+
6
+ import { EditDataHelper } from '../helper/EditDataHelper'
7
+
8
+
9
+ const cacheCursors: IObject = {}
10
+
11
+ export function updateCursor(editor: IEditor, e: IUIEvent): void {
12
+ const { editBox } = editor, point = editBox.enterPoint
13
+ if (!point || !editor.hasTarget || !editBox.visible) return
14
+ if (point.name === 'circle') return // 独立旋转按钮
15
+
16
+ let { rotation } = editBox
17
+ const { resizeCursor, rotateCursor, skewCursor, resizeable, rotateable, skewable } = editor.config
18
+ const { pointType } = point, { flippedX, flippedY } = editBox
19
+
20
+ let showResize = pointType === 'resize'
21
+ if (showResize && rotateable && (e.metaKey || e.ctrlKey || !resizeable)) showResize = false
22
+ const showSkew = skewable && !showResize && point.name === 'resize-line'
23
+
24
+ const cursor = showSkew ? skewCursor : (showResize ? resizeCursor : rotateCursor)
25
+ rotation += (EditDataHelper.getFlipDirection(point.direction, flippedX, flippedY) + 1) * 45
26
+ rotation = Math.round(MathHelper.formatRotation(rotation, true) / 2) * 2
27
+
28
+ const { url, x, y } = cursor
29
+ const key = url + rotation
30
+
31
+ if (cacheCursors[key]) {
32
+ point.cursor = cacheCursors[key]
33
+ } else {
34
+ cacheCursors[key] = point.cursor = { url: toDataURL(url, rotation), x, y }
35
+ }
36
+ }
37
+
38
+ export function updateMoveCursor(editor: IEditor): void {
39
+ editor.editBox.rect.cursor = editor.config.moveCursor
40
+ }
41
+
42
+
43
+ function toDataURL(svg: string, rotation: number): string {
44
+ return '"data:image/svg+xml,' + encodeURIComponent(svg.replace('{{rotation}}', rotation.toString())) + '"'
45
+ }
@@ -0,0 +1,14 @@
1
+ import { IGroup, ILeaf } from '@leafer-ui/interface'
2
+ import { Bounds } from '@leafer-ui/draw'
3
+
4
+ import { IEditor } from '@leafer-in/interface'
5
+
6
+
7
+ export function simulate(editor: IEditor) {
8
+ const { simulateTarget, leafList: targetList } = editor
9
+ const { x, y, width, height } = new Bounds().setListWithFn(targetList.list, (leaf: ILeaf) => leaf.worldBoxBounds)
10
+
11
+ const parent = simulateTarget.parent = targetList.list[0].leafer.zoomLayer as IGroup // follow zoomLayer zoom / move
12
+ const { scaleX, scaleY, e: worldX, f: worldY } = parent.__world
13
+ simulateTarget.reset({ x: (x - worldX) / scaleX, y: (y - worldY) / scaleY, width: width / scaleX, height: height / scaleY })
14
+ }
@@ -0,0 +1,37 @@
1
+ import { LeafList } from '@leafer-ui/draw'
2
+
3
+ import { IEditor, IUI } from '@leafer-in/interface'
4
+
5
+ import { simulate } from './simulate'
6
+ import { updateMoveCursor } from './cursor'
7
+ import { EditorEvent } from '../event/EditorEvent'
8
+
9
+
10
+ export function onTarget(editor: IEditor, oldValue: IUI | IUI[]): void {
11
+ const { target } = editor
12
+ if (target) {
13
+ editor.leafList = target instanceof LeafList ? target : new LeafList(target instanceof Array ? target : target as IUI)
14
+ } else {
15
+ editor.leafList.reset()
16
+ }
17
+
18
+ editor.emitEvent(new EditorEvent(EditorEvent.SELECT, { editor, value: target, oldValue }))
19
+
20
+ if (editor.hasTarget) {
21
+ editor.waitLeafer(() => {
22
+ if (editor.multiple) simulate(editor)
23
+ updateMoveCursor(editor)
24
+ editor.updateEditTool()
25
+ editor.update()
26
+ editor.listenTargetEvents()
27
+ })
28
+ } else {
29
+ editor.removeTargetEvents()
30
+ }
31
+ }
32
+
33
+
34
+ export function onHover(editor: IEditor, oldValue: IUI): void {
35
+ editor.emitEvent(new EditorEvent(EditorEvent.HOVER, { editor, value: editor.hoverTarget, oldValue }))
36
+
37
+ }
@@ -0,0 +1,33 @@
1
+ import { IUI, IPointData } from '@leafer-ui/interface'
2
+ import { Event } from '@leafer-ui/draw'
3
+
4
+ import { IEditor, IEditorEvent } from '@leafer-in/interface'
5
+
6
+
7
+ function toList(value: IUI | IUI[]): IUI[] {
8
+ return value ? (value instanceof Array ? value : [value]) : []
9
+ }
10
+
11
+ export class EditorEvent extends Event implements IEditorEvent {
12
+
13
+ static SELECT = 'editor.select'
14
+ static HOVER = 'editor.hover'
15
+
16
+ declare readonly target: IUI
17
+ readonly editor: IEditor
18
+
19
+ readonly value: IUI | IUI[]
20
+ readonly oldValue: IUI | IUI[]
21
+
22
+ get list() { return toList(this.value) }
23
+ get oldList() { return toList(this.oldValue) }
24
+
25
+ readonly worldOrigin: IPointData
26
+ declare readonly origin: IPointData
27
+
28
+ constructor(type: string, data?: IEditorEvent) {
29
+ super(type)
30
+ if (data) Object.assign(this, data)
31
+ }
32
+
33
+ }
@@ -0,0 +1,17 @@
1
+ import { IEditorMoveEvent } from '@leafer-in/interface'
2
+
3
+ import { EditorEvent } from './EditorEvent'
4
+
5
+
6
+ export class EditorMoveEvent extends EditorEvent implements IEditorMoveEvent {
7
+
8
+ static MOVE = 'editor.move'
9
+
10
+ readonly moveX: number
11
+ readonly moveY: number
12
+
13
+ constructor(type: string, data?: IEditorMoveEvent) {
14
+ super(type, data)
15
+ }
16
+
17
+ }
@@ -1,23 +1,17 @@
1
- import { IUI, IPointData } from '@leafer-ui/interface'
2
- import { IEditor, IEditorRotateEvent } from '@leafer-in/interface'
1
+ import { IEditorRotateEvent } from '@leafer-in/interface'
3
2
 
4
- import { Event } from '@leafer-ui/core'
3
+ import { EditorEvent } from './EditorEvent'
5
4
 
6
5
 
7
- export class EditorRotateEvent extends Event implements IEditorRotateEvent {
6
+ export class EditorRotateEvent extends EditorEvent implements IEditorRotateEvent {
8
7
 
9
8
  static ROTATE = 'editor.rotate'
10
9
 
11
- declare readonly target: IUI
12
- readonly editor: IEditor
13
-
14
10
  // rotateOf(origin, rotation)
15
- readonly origin: IPointData
16
11
  readonly rotation: number
17
12
 
18
13
  constructor(type: string, data?: IEditorRotateEvent) {
19
- super(type)
20
- if (data) Object.assign(this, data)
14
+ super(type, data)
21
15
  }
22
16
 
23
17
  }
@@ -0,0 +1,27 @@
1
+ import { IAround, IDragEvent, IMatrixData } from '@leafer-ui/interface'
2
+
3
+ import { IDirection8, IEditorScaleEvent } from '@leafer-in/interface'
4
+
5
+ import { EditorEvent } from './EditorEvent'
6
+
7
+
8
+ export class EditorScaleEvent extends EditorEvent implements IEditorScaleEvent {
9
+
10
+ static SCALE = 'editor.scale'
11
+
12
+ // scaleOf(origin, scaleX, scaleY, resize)
13
+ readonly scaleX: number
14
+ readonly scaleY: number
15
+ readonly transform?: IMatrixData
16
+
17
+ readonly drag: IDragEvent
18
+
19
+ readonly direction: IDirection8
20
+ readonly lockRatio: boolean
21
+ readonly around: IAround
22
+
23
+ constructor(type: string, data?: IEditorScaleEvent) {
24
+ super(type, data)
25
+ }
26
+
27
+ }
@@ -0,0 +1,18 @@
1
+ import { IEditorSkewEvent } from '@leafer-in/interface'
2
+
3
+ import { EditorEvent } from './EditorEvent'
4
+
5
+
6
+ export class EditorSkewEvent extends EditorEvent implements IEditorSkewEvent {
7
+
8
+ static SKEW = 'editor.skew'
9
+
10
+ // skewOf(origin, skewX, skewY)
11
+ readonly skewX: number
12
+ readonly skewY: number
13
+
14
+ constructor(type: string, data?: IEditorSkewEvent) {
15
+ super(type, data)
16
+ }
17
+
18
+ }
@@ -0,0 +1,182 @@
1
+ import { IBoundsData, IPointData, IAround } from '@leafer-ui/interface'
2
+ import { AroundHelper, PointHelper } from '@leafer-ui/draw'
3
+
4
+ import { IEditorScaleEvent, IDirection8, IEditorSkewEvent, IEditorRotateEvent } from '@leafer-in/interface'
5
+
6
+
7
+ const { topLeft, top, topRight, right, bottomRight, bottom, bottomLeft, left } = IDirection8
8
+ const { toPoint } = AroundHelper
9
+
10
+ export const EditDataHelper = {
11
+
12
+ getScaleData(bounds: IBoundsData, direction: IDirection8, pointMove: IPointData, lockRatio: boolean | 'corner', around: IAround): IEditorScaleEvent {
13
+ let origin: IPointData, scaleX: number = 1, scaleY: number = 1
14
+ const { width, height } = bounds
15
+
16
+ if (around) {
17
+ pointMove.x *= 2
18
+ pointMove.y *= 2
19
+ }
20
+
21
+ // 防止变为0
22
+ if (Math.abs(pointMove.x) === width) pointMove.x += 0.1
23
+ if (Math.abs(pointMove.y) === height) pointMove.y += 0.1
24
+
25
+ const topScale = (-pointMove.y + height) / height
26
+ const rightScale = (pointMove.x + width) / width
27
+ const bottomScale = (pointMove.y + height) / height
28
+ const leftScale = (-pointMove.x + width) / width
29
+
30
+ switch (direction) {
31
+ case top:
32
+ scaleY = topScale
33
+ origin = { x: 0.5, y: 1 }
34
+ break
35
+ case right:
36
+ scaleX = rightScale
37
+ origin = { x: 0, y: 0.5 }
38
+ break
39
+ case bottom:
40
+ scaleY = bottomScale
41
+ origin = { x: 0.5, y: 0 }
42
+ break
43
+ case left:
44
+ scaleX = leftScale
45
+ origin = { x: 1, y: 0.5 }
46
+ break
47
+ case topLeft:
48
+ scaleY = topScale
49
+ scaleX = leftScale
50
+ origin = { x: 1, y: 1 }
51
+ break
52
+ case topRight:
53
+ scaleY = topScale
54
+ scaleX = rightScale
55
+ origin = { x: 0, y: 1 }
56
+ break
57
+ case bottomRight:
58
+ scaleY = bottomScale
59
+ scaleX = rightScale
60
+ origin = { x: 0, y: 0 }
61
+ break
62
+ case bottomLeft:
63
+ scaleY = bottomScale
64
+ scaleX = leftScale
65
+ origin = { x: 1, y: 0 }
66
+ }
67
+
68
+ if (lockRatio) {
69
+ const unlockSide = lockRatio === 'corner' && direction % 2
70
+ if (!unlockSide) {
71
+ if (scaleY !== 1) scaleX = scaleY
72
+ else scaleY = scaleX
73
+ }
74
+ }
75
+
76
+ toPoint(around || origin, bounds, origin)
77
+
78
+ return { origin, scaleX, scaleY, direction, lockRatio, around }
79
+ },
80
+
81
+ getRotateData(bounds: IBoundsData, direction: IDirection8, current: IPointData, last: IPointData, around: IAround): IEditorRotateEvent {
82
+ let origin: IPointData
83
+
84
+ switch (direction) {
85
+ case topLeft:
86
+ origin = { x: 1, y: 1 }
87
+ break
88
+ case topRight:
89
+ origin = { x: 0, y: 1 }
90
+ break
91
+ case bottomRight:
92
+ origin = { x: 0, y: 0 }
93
+ break
94
+ case bottomLeft:
95
+ origin = { x: 1, y: 0 }
96
+ break
97
+ default:
98
+ origin = { x: 0.5, y: 0.5 }
99
+ }
100
+
101
+ toPoint(around || origin, bounds, origin)
102
+
103
+ return { origin, rotation: PointHelper.getRotation(last, origin, current) }
104
+ },
105
+
106
+ getSkewData(bounds: IBoundsData, direction: IDirection8, move: IPointData, around: IAround): IEditorSkewEvent {
107
+ let origin: IPointData, skewX = 0, skewY = 0
108
+ let last: IPointData
109
+
110
+ switch (direction) {
111
+ case top:
112
+ last = { x: 0.5, y: 0 }
113
+ origin = { x: 0.5, y: 1 }
114
+ skewX = 1
115
+ break
116
+ case bottom:
117
+ last = { x: 0.5, y: 1 }
118
+ origin = { x: 0.5, y: 0 }
119
+ skewX = 1
120
+ break
121
+ case left:
122
+ last = { x: 0, y: 0.5 }
123
+ origin = { x: 1, y: 0.5 }
124
+ skewY = 1
125
+ break
126
+ case right:
127
+ last = { x: 1, y: 0.5 }
128
+ origin = { x: 0, y: 0.5 }
129
+ skewY = 1
130
+ }
131
+
132
+ const { x, y, width, height } = bounds
133
+
134
+ last.x = x + last.x * width
135
+ last.y = y + last.y * height
136
+
137
+ toPoint(around || origin, bounds, origin)
138
+
139
+ const rotation = PointHelper.getRotation(last, origin, { x: last.x + (skewX ? move.x : 0), y: last.y + (skewY ? move.y : 0) })
140
+ skewX ? skewX = -rotation : skewY = rotation
141
+
142
+ return { origin, skewX, skewY }
143
+ },
144
+
145
+
146
+ getAround(around: IAround, altKey: boolean): IAround {
147
+ return (altKey && !around) ? 'center' : around
148
+ },
149
+
150
+ getRotateDirection(direction: number, rotation: number, totalDirection = 8): number {
151
+ direction = (direction + Math.round(rotation / (360 / totalDirection))) % totalDirection
152
+ if (direction < 0) direction += totalDirection
153
+ return direction
154
+ },
155
+
156
+ getFlipDirection(direction: IDirection8, flipedX: boolean, flipedY: boolean): IDirection8 {
157
+ if (flipedX) {
158
+ switch (direction) {
159
+ case left: direction = right; break
160
+ case topLeft: direction = topRight; break
161
+ case bottomLeft: direction = bottomRight; break
162
+ case right: direction = left; break
163
+ case topRight: direction = topLeft; break
164
+ case bottomRight: direction = bottomLeft; break
165
+ }
166
+ }
167
+
168
+ if (flipedY) {
169
+ switch (direction) {
170
+ case top: direction = bottom; break
171
+ case topLeft: direction = bottomLeft; break
172
+ case topRight: direction = bottomRight; break
173
+ case bottom: direction = top; break
174
+ case bottomLeft: direction = topLeft; break
175
+ case bottomRight: direction = topRight; break
176
+ }
177
+ }
178
+
179
+ return direction
180
+ }
181
+
182
+ }
@@ -0,0 +1,34 @@
1
+ import { IBounds, ILeafList, IUI } from '@leafer-ui/interface'
2
+ import { Answer } from '@leafer-ui/draw'
3
+
4
+ const { No, Yes, NoAndSkip, YesAndSkip } = Answer
5
+
6
+ export const EditSelectHelper = {
7
+
8
+ findOne(path: ILeafList): IUI {
9
+ return path.list.find((leaf) => leaf.editable) as IUI
10
+ },
11
+
12
+ findBounds(leaf: IUI, bounds: IBounds): Answer {
13
+ if (leaf.__.hittable && leaf.__.visible && !leaf.__.locked && bounds.hit(leaf.__world)) {
14
+
15
+ if (leaf.__.editable) {
16
+ if (leaf.isBranch && !leaf.__.hitChildren) {
17
+ return leaf.__.hitSelf ? YesAndSkip : NoAndSkip
18
+ } else if (leaf.isFrame) {
19
+ return bounds.includes(leaf.__layout.boxBounds, leaf.__world) ? YesAndSkip : No
20
+ } else {
21
+ if (bounds.hit(leaf.__layout.boxBounds, leaf.__world) && leaf.__.hitSelf) return Yes
22
+ }
23
+ }
24
+
25
+ return No
26
+
27
+ } else {
28
+
29
+ return leaf.isBranch ? NoAndSkip : No
30
+
31
+ }
32
+ }
33
+
34
+ }
@@ -0,0 +1,73 @@
1
+ import { IGroup, IGroupInputData, ILeaf, IUI } from '@leafer-ui/interface'
2
+ import { Group, Matrix } from '@leafer-ui/draw'
3
+
4
+
5
+ const order = (a: ILeaf, b: ILeaf) => a.parent.children.indexOf(a) - b.parent.children.indexOf(b)
6
+ const reverseOrder = (a: ILeaf, b: ILeaf) => b.parent.children.indexOf(b) - a.parent.children.indexOf(a)
7
+
8
+ export const EditorHelper = {
9
+
10
+ group(list: IUI[], element?: IUI, userGroup?: IGroup | IGroupInputData): IGroup {
11
+ list.sort(reverseOrder)
12
+ const { app, parent } = list[0]
13
+
14
+ let group: IGroup
15
+ if (userGroup && (userGroup as IGroup).add) {
16
+ group = userGroup as IGroup
17
+ } else {
18
+ group = new Group(userGroup)
19
+ }
20
+
21
+ parent.addAt(group, parent.children.indexOf(list[0]))
22
+ list.sort(order)
23
+
24
+ const matrx = new Matrix(element.worldTransform)
25
+ matrx.divideParent(parent.worldTransform)
26
+ group.setTransform(matrx)
27
+ group.editable = true
28
+ group.hitChildren = false
29
+
30
+ app.lockLayout()
31
+ list.forEach(child => child.dropTo(group))
32
+ app.unlockLayout()
33
+
34
+ return group
35
+ },
36
+
37
+ ungroup(list: IUI[]): IUI[] {
38
+ const { app } = list[0]
39
+ const ungroupList: IUI[] = []
40
+
41
+ app.lockLayout()
42
+ list.forEach(leaf => {
43
+ if (leaf.isBranch) {
44
+ const { parent, children } = leaf
45
+ while (children.length) {
46
+ ungroupList.push(children[0])
47
+ children[0].dropTo(parent, parent.children.indexOf(leaf))
48
+ }
49
+ leaf.remove()
50
+ } else {
51
+ ungroupList.push(leaf)
52
+ }
53
+ })
54
+ app.unlockLayout()
55
+
56
+ return ungroupList
57
+ },
58
+
59
+ toTop(list: IUI[]): void {
60
+ list.sort(order)
61
+ list.forEach(leaf => {
62
+ if (leaf.parent) leaf.parent.add(leaf)
63
+ })
64
+ },
65
+
66
+ toBottom(list: IUI[]): void {
67
+ list.sort(reverseOrder)
68
+ list.forEach(leaf => {
69
+ if (leaf.parent) leaf.parent.addAt(leaf, 0)
70
+ })
71
+ }
72
+
73
+ }
package/src/index.ts CHANGED
@@ -1,5 +1,30 @@
1
+ export * from '@leafer-ui/scale'
2
+
1
3
  export { Editor } from './Editor'
2
- export { EditorResizeEvent } from './event/EditorResizeEvent'
4
+
5
+ export { EditBox } from './display/EditBox'
6
+ export { EditPoint } from './display/EditPoint'
7
+ export { EditSelect } from './display/EditSelect'
8
+ export { SelectArea } from './display/SelectArea'
9
+ export { Stroker } from './display/Stroker'
10
+
11
+ export { EditorEvent } from './event/EditorEvent'
12
+ export { EditorMoveEvent } from './event/EditorMoveEvent'
13
+ export { EditorScaleEvent } from './event/EditorScaleEvent'
3
14
  export { EditorRotateEvent } from './event/EditorRotateEvent'
4
- export { LineTool } from './tool/LineTool'
5
- export { RectTool } from './tool/RectTool'
15
+ export { EditorSkewEvent } from './event/EditorSkewEvent'
16
+
17
+ export { LineEditTool } from './tool/LineEditTool'
18
+ export { EditTool } from './tool/EditTool'
19
+
20
+ export { EditorHelper } from './helper/EditorHelper'
21
+ export { EditDataHelper } from './helper/EditDataHelper'
22
+ export { EditSelectHelper } from './helper/EditSelectHelper'
23
+
24
+ import { IEditor, IEditorConfig } from '@leafer-in/interface'
25
+ import { Creator } from '@leafer-ui/core'
26
+ import { Editor } from './Editor'
27
+
28
+ Creator.editor = function (options?: IEditorConfig): IEditor {
29
+ return new Editor(options)
30
+ }
package/src/svg.ts ADDED
@@ -0,0 +1,54 @@
1
+ const filterStyle = `
2
+ <feOffset dy="1"/>
3
+ <feGaussianBlur stdDeviation="1.5"/>
4
+ <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0"/>
5
+ <feBlend mode="normal" in="SourceGraphic" result="shape"/>`
6
+
7
+
8
+ export const resizeSVG = `
9
+ <svg width="24" height="24" xmlns="http://www.w3.org/2000/svg">
10
+ <g filter="url(#f)">
11
+ <g transform="rotate({{rotation}},12,12)">
12
+ <path d="M7.5 8.0H8.5V5.9L6.8 7.2L7.5 8.0ZM3 11.4L2.3 10.6L1.3 11.4L2.3 12.2L3 11.4ZM7.5 10.4H6.5V11.4H7.5V10.4ZM16.5 10.4V11.4H17.5V10.4H16.5ZM16.5 8.0L17.1 7.2L15.5 5.9V8.0H16.5ZM21 11.4L21.6 12.2L22.6 11.4L21.6 10.6L21 11.4ZM16.5 14.9H15.5V16.9L17.1 15.7L16.5 14.9ZM16.5 12.4H17.5V11.4H16.5V12.4ZM7.5 12.4V11.4H6.5V12.4H7.5ZM7.5 14.9L6.8 15.7L8.5 16.9V14.9H7.5ZM6.8 7.2L2.3 10.6L3.6 12.2L8.1 8.7L6.8 7.2ZM8.5 10.4V8.0H6.5V10.4H8.5ZM16.5 9.4H7.5V11.4H16.5V9.4ZM17.5 10.4V8.0H15.5V10.4H17.5ZM15.8 8.7L20.3 12.2L21.6 10.6L17.1 7.2L15.8 8.7ZM20.3 10.6L15.8 14.1L17.1 15.7L21.6 12.2L20.3 10.6ZM17.5 14.9V12.4H15.5V14.9H17.5ZM7.5 13.4H16.5V11.4H7.5V13.4ZM8.5 14.9V12.4H6.5V14.9H8.5ZM2.3 12.2L6.8 15.7L8.1 14.1L3.6 10.6L2.3 12.2Z" fill="white"/>
13
+ <path fill-rule="evenodd" d="M3 11.4L7.5 8.0V10.4H16.5V8.0L21 11.4L16.5 14.9V12.4H7.5V14.9L3 11.4Z" fill="black"/>
14
+ </g>
15
+ </g>
16
+ <defs>
17
+ <filter id="f" x="-1.6" y="3.9" width="27.2" height="16.9" filterUnits="userSpaceOnUse">
18
+ ${filterStyle}
19
+ </filter>
20
+ </defs>
21
+ </svg>
22
+ `
23
+
24
+ export const rotateSVG = `
25
+ <svg width="24" height="24" xmlns="http://www.w3.org/2000/svg">
26
+ <g filter="url(#f)">
27
+ <g transform="rotate(135,12,12),rotate({{rotation}},12,12)">
28
+ <path d="M20.4 8H21.4L20.8 7.1L17.3 2.6L17 2.1L16.6 2.6L13.1 7.1L12.5 8H13.5H15.4C14.9 11.8 11.8 14.9 8 15.4V13.5V12.5L7.1 13.1L2.6 16.6L2.1 17L2.6 17.3L7.1 20.8L8 21.4V20.4V18.4C13.5 17.9 17.9 13.5 18.4 8H20.4Z" stroke="white"/>
29
+ <path fill-rule="evenodd" d="M17 3L20.4 7.5H17.9C17.7 13.1 13.1 17.7 7.5 17.9V20.4L3 17L7.5 13.5V15.9C12.0 15.7 15.7 12.0 15.9 7.5H13.5L17 3Z" fill="black"/>
30
+ </g>
31
+ </g>
32
+ <defs>
33
+ <filter id="f" x="-1.6" y="-0.6" width="27.1" height="27.1" filterUnits="userSpaceOnUse">
34
+ ${filterStyle}
35
+ </filter>
36
+ </defs>
37
+ </svg>
38
+ `
39
+
40
+ export const skewSVG = `
41
+ <svg width="24" height="24" xmlns="http://www.w3.org/2000/svg">
42
+ <g filter="url(#f)">
43
+ <g transform="rotate(90,12,12),rotate({{rotation}},12,12)">
44
+ <path d="M21 10.4L21 11.4L23.8 11.4L21.6 9.6L21 10.4ZM17 10.4V11.4L17 11.4L17 10.4ZM15.5 6L16.1 5.2L14.5 3.9V6H15.5ZM15.5 8.4V9.4H16.5V8.4H15.5ZM6 8.4V7.4H5V8.4H6ZM6 10.4H5V11.4H6V10.4ZM7 14.4V13.4L7 13.4L7 14.4ZM3 14.4L3 13.4L0.1 13.4L2.3 15.2L3 14.4ZM8.5 18.9L7.8 19.7L9.5 21.0V18.9H8.5ZM8.5 16.4V15.4H7.5V16.4H8.5ZM19 16.4V17.4H20V16.4H19ZM19 14.4H20V13.4H19V14.4ZM21 9.4L17 9.4L17 11.4L21 11.4L21 9.4ZM14.8 6.7L20.3 11.2L21.6 9.6L16.1 5.2L14.8 6.7ZM16.5 8.4V6H14.5V8.4H16.5ZM6 9.4H15.5V7.4H6V9.4ZM7 10.4V8.4H5V10.4H7ZM15.5 9.4H6V11.4H15.5V9.4ZM17 9.4H15.5V11.4H17V9.4ZM7 15.4H8.5V13.4H7V15.4ZM3 15.4L7 15.4L7 13.4L3 13.4L3 15.4ZM9.1 18.1L3.6 13.6L2.3 15.2L7.8 19.7L9.1 18.1ZM7.5 16.4V18.9H9.5V16.4H7.5ZM19 15.4H8.5V17.4H19V15.4ZM18 14.4V16.4H20V14.4H18ZM8.5 15.4H19V13.4H8.5V15.4Z" fill="white"/>
45
+ <path fill-rule="evenodd" d="M17 10.4L21 10.4L15.5 6V8.4H6V10.4H15.5H17ZM8.5 14.4H7L3 14.4L8.5 18.9V16.4H19V14.4H8.5Z" fill="black"/>
46
+ </g>
47
+ </g>
48
+ <defs>
49
+ <filter x="-2.8" y="1.9" width="29.6" height="23.1" filterUnits="userSpaceOnUse" >
50
+ ${filterStyle}
51
+ </filter>
52
+ </defs>
53
+ </svg>
54
+ `
@@ -0,0 +1,75 @@
1
+ import { IEditor, IEditorScaleEvent, IEditorRotateEvent, IEditTool, IEditorSkewEvent, IEditorMoveEvent } from '@leafer-in/interface'
2
+
3
+
4
+ export class EditTool implements IEditTool {
5
+
6
+ static list: IEditTool[] = []
7
+
8
+ public tag = 'EditTool'
9
+
10
+ onMove(e: IEditorMoveEvent): void {
11
+ const { moveX, moveY, editor } = e
12
+ const { app, list } = editor
13
+ app.lockLayout()
14
+ list.forEach(target => {
15
+ target.moveWorld(moveX, moveY)
16
+ })
17
+ app.unlockLayout()
18
+ }
19
+
20
+ onScale(e: IEditorScaleEvent): void {
21
+ const { scaleX, scaleY, transform, worldOrigin, editor } = e
22
+ const { app, list } = editor
23
+ app.lockLayout()
24
+ list.forEach(target => {
25
+ const resize = editor.getEditSize(target) === 'size'
26
+ if (transform) {
27
+ target.transformWorld(transform, resize)
28
+ } else {
29
+ target.scaleOfWorld(worldOrigin, scaleX, scaleY, resize)
30
+ }
31
+ })
32
+ app.unlockLayout()
33
+ }
34
+
35
+ onRotate(e: IEditorRotateEvent): void {
36
+ const { rotation, transform, worldOrigin, editor } = e
37
+ const { app, list } = editor
38
+ app.lockLayout()
39
+ list.forEach(target => {
40
+ const resize = editor.getEditSize(target) === 'size'
41
+ if (transform) {
42
+ target.transformWorld(transform, resize)
43
+ } else {
44
+ target.rotateOfWorld(worldOrigin, rotation)
45
+ }
46
+ })
47
+ app.unlockLayout()
48
+ }
49
+
50
+ onSkew(e: IEditorSkewEvent): void {
51
+ const { skewX, skewY, transform, worldOrigin, editor } = e
52
+ const { app, list } = editor
53
+ app.lockLayout()
54
+ list.forEach(target => {
55
+ const resize = editor.getEditSize(target) === 'size'
56
+ if (transform) {
57
+ target.transformWorld(transform, resize)
58
+ } else {
59
+ target.skewOfWorld(worldOrigin, skewX, skewY, resize)
60
+ }
61
+ })
62
+ app.unlockLayout()
63
+ }
64
+
65
+ update(editor: IEditor) {
66
+ const { simulateTarget, element } = editor
67
+
68
+ if (editor.multiple) simulateTarget.parent.updateLayout()
69
+
70
+ const { x, y, scaleX, scaleY, rotation, skewX, skewY, width, height } = element.getLayoutBounds('box', editor, true)
71
+ editor.editBox.set({ x, y, scaleX, scaleY, rotation, skewX, skewY })
72
+ editor.editBox.update({ x: 0, y: 0, width, height })
73
+ }
74
+
75
+ }