@leafer/display-module 1.0.0-beta.15 → 1.0.0-beta.17
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 +5 -4
- package/src/BranchRender.ts +90 -0
- package/src/LeafBounds.ts +140 -0
- package/src/LeafDataProxy.ts +25 -0
- package/src/LeafEventer.ts +125 -0
- package/src/LeafHit.ts +29 -0
- package/src/LeafMask.ts +38 -0
- package/src/LeafMatrix.ts +123 -0
- package/src/LeafRender.ts +34 -0
package/package.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@leafer/display-module",
|
|
3
|
-
"version": "1.0.0-beta.
|
|
3
|
+
"version": "1.0.0-beta.17",
|
|
4
4
|
"description": "@leafer/display-module",
|
|
5
5
|
"author": "Chao (Leafer) Wan",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"main": "src/index.ts",
|
|
8
8
|
"types": "types/index.d.ts",
|
|
9
9
|
"files": [
|
|
10
|
+
"src",
|
|
10
11
|
"types",
|
|
11
12
|
"dist"
|
|
12
13
|
],
|
|
@@ -21,10 +22,10 @@
|
|
|
21
22
|
"leaferjs"
|
|
22
23
|
],
|
|
23
24
|
"dependencies": {
|
|
24
|
-
"@leafer/event": "1.0.0-beta.
|
|
25
|
-
"@leafer/math": "1.0.0-beta.
|
|
25
|
+
"@leafer/event": "1.0.0-beta.17",
|
|
26
|
+
"@leafer/math": "1.0.0-beta.17"
|
|
26
27
|
},
|
|
27
28
|
"devDependencies": {
|
|
28
|
-
"@leafer/interface": "1.0.0-beta.
|
|
29
|
+
"@leafer/interface": "1.0.0-beta.17"
|
|
29
30
|
}
|
|
30
31
|
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { ILeaf, ILeaferCanvas, IRenderOptions, IBranchRenderModule } from '@leafer/interface'
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
export const BranchRender: IBranchRenderModule = {
|
|
5
|
+
|
|
6
|
+
__updateChange(): void {
|
|
7
|
+
const { __layout: layout } = this
|
|
8
|
+
if (layout.childrenSortChanged) {
|
|
9
|
+
this.__updateSortChildren()
|
|
10
|
+
layout.childrenSortChanged = false
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
this.__.__checkSingle()
|
|
14
|
+
},
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
__render(canvas: ILeaferCanvas, options: IRenderOptions): void {
|
|
18
|
+
if (this.__worldOpacity) {
|
|
19
|
+
|
|
20
|
+
if (this.__.__single) {
|
|
21
|
+
canvas.resetTransform()
|
|
22
|
+
const tempCanvas = canvas.getSameCanvas()
|
|
23
|
+
|
|
24
|
+
this.__renderBranch(tempCanvas, options)
|
|
25
|
+
|
|
26
|
+
canvas.opacity = this.__worldOpacity
|
|
27
|
+
|
|
28
|
+
const blendMode = this.__.isEraser ? 'destination-out' : this.__.blendMode
|
|
29
|
+
options.matrix ? canvas.copyWorld(tempCanvas, null, null, blendMode) : canvas.copyWorld(tempCanvas, this.__world, this.__world, blendMode)
|
|
30
|
+
|
|
31
|
+
tempCanvas.recycle()
|
|
32
|
+
} else {
|
|
33
|
+
this.__renderBranch(canvas, options)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
__renderBranch(canvas: ILeaferCanvas, options: IRenderOptions): void {
|
|
40
|
+
|
|
41
|
+
let child: ILeaf
|
|
42
|
+
const { children } = this
|
|
43
|
+
|
|
44
|
+
if (this.__hasMask && children.length > 1) {
|
|
45
|
+
|
|
46
|
+
let mask: boolean
|
|
47
|
+
let maskCanvas = canvas.getSameCanvas()
|
|
48
|
+
let contentCanvas = canvas.getSameCanvas()
|
|
49
|
+
|
|
50
|
+
for (let i = 0, len = children.length; i < len; i++) {
|
|
51
|
+
child = children[i]
|
|
52
|
+
|
|
53
|
+
if (child.isMask) {
|
|
54
|
+
if (mask) {
|
|
55
|
+
this.__renderMask(canvas, contentCanvas, maskCanvas)
|
|
56
|
+
maskCanvas.clear()
|
|
57
|
+
contentCanvas.clear()
|
|
58
|
+
} else {
|
|
59
|
+
mask = true
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
child.__render(maskCanvas, options)
|
|
63
|
+
continue
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
child.__render(contentCanvas, options)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
this.__renderMask(canvas, contentCanvas, maskCanvas)
|
|
70
|
+
maskCanvas.recycle()
|
|
71
|
+
contentCanvas.recycle()
|
|
72
|
+
|
|
73
|
+
} else {
|
|
74
|
+
|
|
75
|
+
const { bounds, hideBounds } = options
|
|
76
|
+
|
|
77
|
+
for (let i = 0, len = children.length; i < len; i++) {
|
|
78
|
+
child = children[i]
|
|
79
|
+
|
|
80
|
+
if (bounds && !bounds.hit(child.__world, options.matrix)) continue
|
|
81
|
+
if (hideBounds && hideBounds.includes(child.__world, options.matrix)) continue
|
|
82
|
+
|
|
83
|
+
child.__render(canvas, options)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { ILeafBoundsModule } from '@leafer/interface'
|
|
2
|
+
import { BoundsHelper } from '@leafer/math'
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
const { toOuterOf, copyAndSpread } = BoundsHelper
|
|
6
|
+
|
|
7
|
+
export const LeafBounds: ILeafBoundsModule = {
|
|
8
|
+
|
|
9
|
+
__updateWorldBounds(): void {
|
|
10
|
+
|
|
11
|
+
if (this.__layout.boundsChanged) {
|
|
12
|
+
|
|
13
|
+
let resize: boolean
|
|
14
|
+
const layout = this.__layout
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
if (layout.boxChanged) {
|
|
18
|
+
|
|
19
|
+
this.__updatePath()
|
|
20
|
+
this.__updateRenderPath()
|
|
21
|
+
|
|
22
|
+
this.__updateBoxBounds()
|
|
23
|
+
layout.boxChanged = false
|
|
24
|
+
resize = true
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
if (layout.localBoxChanged) { // position change
|
|
29
|
+
|
|
30
|
+
this.__updateLocalBoxBounds()
|
|
31
|
+
layout.localBoxChanged = false
|
|
32
|
+
|
|
33
|
+
if (layout.strokeSpread) layout.strokeChanged = true
|
|
34
|
+
if (layout.renderSpread) layout.renderChanged = true
|
|
35
|
+
this.parent?.__layout.boxChange()
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
if (layout.strokeChanged) {
|
|
40
|
+
|
|
41
|
+
layout.strokeSpread = this.__updateStrokeSpread()
|
|
42
|
+
|
|
43
|
+
if (layout.strokeSpread) {
|
|
44
|
+
|
|
45
|
+
if (layout.strokeBounds === layout.boxBounds) {
|
|
46
|
+
layout.spreadStroke()
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
this.__updateStrokeBounds()
|
|
50
|
+
this.__updateLocalStrokeBounds()
|
|
51
|
+
|
|
52
|
+
} else {
|
|
53
|
+
layout.spreadStrokeCancel()
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
layout.strokeChanged = false
|
|
57
|
+
if (layout.renderSpread) layout.renderChanged = true
|
|
58
|
+
|
|
59
|
+
if (this.parent) this.parent.__layout.strokeChange()
|
|
60
|
+
resize || (resize = true)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
if (layout.renderChanged) {
|
|
65
|
+
|
|
66
|
+
layout.renderSpread = this.__updateRenderSpread()
|
|
67
|
+
|
|
68
|
+
if (layout.renderSpread) {
|
|
69
|
+
|
|
70
|
+
if (layout.renderBounds === layout.boxBounds || layout.renderBounds === layout.strokeBounds) {
|
|
71
|
+
layout.spreadRender()
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
this.__updateRenderBounds()
|
|
75
|
+
this.__updateLocalRenderBounds()
|
|
76
|
+
|
|
77
|
+
} else {
|
|
78
|
+
layout.spreadRenderCancel()
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
layout.renderChanged = false
|
|
82
|
+
|
|
83
|
+
if (this.parent) this.parent.__layout.renderChange()
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
layout.boundsChanged = false
|
|
88
|
+
|
|
89
|
+
toOuterOf(this.__layout.renderBounds, this.__world, this.__world)
|
|
90
|
+
|
|
91
|
+
if (resize) this.__onUpdateSize()
|
|
92
|
+
|
|
93
|
+
} else {
|
|
94
|
+
toOuterOf(this.__layout.renderBounds, this.__world, this.__world)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
},
|
|
98
|
+
|
|
99
|
+
__updateLocalBoxBounds(): void {
|
|
100
|
+
toOuterOf(this.__layout.boxBounds, this.__local, this.__local)
|
|
101
|
+
},
|
|
102
|
+
|
|
103
|
+
__updateLocalStrokeBounds(): void {
|
|
104
|
+
toOuterOf(this.__layout.strokeBounds, this.__local, this.__layout.localStrokeBounds)
|
|
105
|
+
},
|
|
106
|
+
|
|
107
|
+
__updateLocalRenderBounds(): void {
|
|
108
|
+
toOuterOf(this.__layout.renderBounds, this.__local, this.__layout.localRenderBounds)
|
|
109
|
+
},
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
__updateBoxBounds(): void {
|
|
113
|
+
const b = this.__layout.boxBounds
|
|
114
|
+
const { width, height } = this.__
|
|
115
|
+
b.x = 0
|
|
116
|
+
b.y = 0
|
|
117
|
+
b.width = width
|
|
118
|
+
b.height = height
|
|
119
|
+
},
|
|
120
|
+
|
|
121
|
+
__updateNaturalSize(): void {
|
|
122
|
+
const { __: data, __layout: layout } = this
|
|
123
|
+
data.__naturalWidth = layout.boxBounds.width
|
|
124
|
+
data.__naturalHeight = layout.boxBounds.height
|
|
125
|
+
|
|
126
|
+
if (this.around) {
|
|
127
|
+
layout.positionChanged = layout.matrixChanged = true
|
|
128
|
+
this.__updateWorldMatrix()
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
|
|
132
|
+
__updateStrokeBounds(): void {
|
|
133
|
+
copyAndSpread(this.__layout.strokeBounds, this.__layout.boxBounds, this.__layout.strokeSpread)
|
|
134
|
+
},
|
|
135
|
+
|
|
136
|
+
__updateRenderBounds(): void {
|
|
137
|
+
copyAndSpread(this.__layout.renderBounds, this.__layout.strokeBounds, this.__layout.renderSpread)
|
|
138
|
+
},
|
|
139
|
+
|
|
140
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { ILeafDataProxyModule } from '@leafer/interface'
|
|
2
|
+
import { PropertyEvent } from '@leafer/event'
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
export const LeafDataProxy: ILeafDataProxyModule = {
|
|
6
|
+
|
|
7
|
+
__setAttr(name: string, newValue: unknown): void {
|
|
8
|
+
if (this.leafer && this.leafer.created) {
|
|
9
|
+
if (typeof newValue === 'object' || this.__.__getInput(name) !== newValue) {
|
|
10
|
+
this.__[name] = newValue
|
|
11
|
+
const { CHANGE } = PropertyEvent
|
|
12
|
+
const event = new PropertyEvent(CHANGE, this, name, this.__.__get(name), newValue)
|
|
13
|
+
if (this.hasEvent(CHANGE) && !this.isLeafer) this.emitEvent(event)
|
|
14
|
+
this.leafer.emitEvent(event)
|
|
15
|
+
}
|
|
16
|
+
} else {
|
|
17
|
+
this.__[name] = newValue
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
|
|
21
|
+
__getAttr(name: string): unknown {
|
|
22
|
+
return this.__.__get(name)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { IEventListener, IEventListenerOptions, IEventListenerMap, IEventListenerItem, IEventListenerId, IEvent, IObject, IEventTarget, ILeafEventerModule } from '@leafer/interface'
|
|
2
|
+
|
|
3
|
+
const empty = {}
|
|
4
|
+
|
|
5
|
+
export const LeafEventer: ILeafEventerModule = {
|
|
6
|
+
|
|
7
|
+
on(type: string | string[], listener: IEventListener, options?: IEventListenerOptions | boolean): void {
|
|
8
|
+
let capture: boolean, once: boolean
|
|
9
|
+
if (options) {
|
|
10
|
+
if (typeof options === 'boolean') {
|
|
11
|
+
capture = options
|
|
12
|
+
} else {
|
|
13
|
+
capture = options.capture
|
|
14
|
+
once = options.once
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
let events: IEventListenerItem[]
|
|
19
|
+
const map = __getListenerMap(this, capture, true)
|
|
20
|
+
const typeList = typeof type === 'string' ? type.split(' ') : type
|
|
21
|
+
const item = once ? { listener, once } : { listener }
|
|
22
|
+
|
|
23
|
+
typeList.forEach(type => {
|
|
24
|
+
if (type) {
|
|
25
|
+
events = map[type]
|
|
26
|
+
if (events) {
|
|
27
|
+
if (events.findIndex(item => item.listener === listener) === -1) events.push(item)
|
|
28
|
+
} else {
|
|
29
|
+
map[type] = [item]
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
})
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
off(type: string | string[], listener: IEventListener, options?: IEventListenerOptions | boolean): void {
|
|
36
|
+
let capture: boolean
|
|
37
|
+
if (options) capture = typeof options === 'boolean' ? options : options.capture
|
|
38
|
+
|
|
39
|
+
let events: IEventListenerItem[], index: number
|
|
40
|
+
const map = __getListenerMap(this, capture)
|
|
41
|
+
const typeList = typeof type === 'string' ? type.split(' ') : type
|
|
42
|
+
|
|
43
|
+
typeList.forEach(type => {
|
|
44
|
+
if (type) {
|
|
45
|
+
events = map[type]
|
|
46
|
+
if (events) {
|
|
47
|
+
index = events.findIndex(item => item.listener === listener)
|
|
48
|
+
if (index > -1) events.splice(index, 1)
|
|
49
|
+
if (!events.length) delete map[type]
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
})
|
|
53
|
+
},
|
|
54
|
+
|
|
55
|
+
on_(type: string | string[], listener: IEventListener, bind?: IObject, options?: IEventListenerOptions | boolean): IEventListenerId {
|
|
56
|
+
if (bind) listener = listener.bind(bind)
|
|
57
|
+
this.on(type, listener, options)
|
|
58
|
+
return { type, listener, options }
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
off_(id: IEventListenerId | IEventListenerId[]): void {
|
|
62
|
+
if (!id) return
|
|
63
|
+
const list = id instanceof Array ? id : [id]
|
|
64
|
+
list.forEach(item => this.off(item.type, item.listener, item.options))
|
|
65
|
+
list.length = 0
|
|
66
|
+
},
|
|
67
|
+
|
|
68
|
+
once(type: string | string[], listener: IEventListener, capture?: boolean): void {
|
|
69
|
+
this.on(type, listener, { once: true, capture })
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
emit(type: string, event?: IEvent | IObject, capture?: boolean): void {
|
|
73
|
+
const map = __getListenerMap(this, capture)
|
|
74
|
+
const list = map[type]
|
|
75
|
+
if (list) {
|
|
76
|
+
let item: IEventListenerItem
|
|
77
|
+
for (let i = 0, len = list.length; i < len; i++) {
|
|
78
|
+
item = list[i]
|
|
79
|
+
item.listener(event)
|
|
80
|
+
if (item.once) {
|
|
81
|
+
this.off(type, item.listener, capture)
|
|
82
|
+
i--, len--
|
|
83
|
+
}
|
|
84
|
+
if (event && (event as IEvent).isStopNow) break
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
|
|
89
|
+
emitEvent(event: IEvent, capture?: boolean): void {
|
|
90
|
+
event.current = this
|
|
91
|
+
this.emit(event.type, event, capture)
|
|
92
|
+
},
|
|
93
|
+
|
|
94
|
+
hasEvent(type: string, capture?: boolean): boolean {
|
|
95
|
+
const { __bubbleMap: b, __captureMap: c } = this
|
|
96
|
+
if (capture === undefined) {
|
|
97
|
+
return !!((c && c[type]) || (b && b[type]))
|
|
98
|
+
} else {
|
|
99
|
+
return !!(capture ? (c && c[type]) : (b && b[type]))
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function __getListenerMap(eventer: IEventTarget, capture?: boolean, create?: boolean): IEventListenerMap {
|
|
106
|
+
if (capture) {
|
|
107
|
+
|
|
108
|
+
const { __captureMap: c } = eventer
|
|
109
|
+
if (c) {
|
|
110
|
+
return c
|
|
111
|
+
} else {
|
|
112
|
+
return create ? eventer.__captureMap = {} : empty
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
} else {
|
|
116
|
+
|
|
117
|
+
const { __bubbleMap: b } = eventer
|
|
118
|
+
if (b) {
|
|
119
|
+
return b
|
|
120
|
+
} else {
|
|
121
|
+
return create ? eventer.__bubbleMap = {} : empty
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
}
|
|
125
|
+
}
|
package/src/LeafHit.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { ILeafHitModule, IRadiusPointData, ILeaferCanvas } from '@leafer/interface'
|
|
2
|
+
import { PointHelper } from '@leafer/math'
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
const { toInnerRadiusPointOf, copy, setRadius } = PointHelper
|
|
6
|
+
const inner = {} as IRadiusPointData
|
|
7
|
+
|
|
8
|
+
export const LeafHit: ILeafHitModule = {
|
|
9
|
+
|
|
10
|
+
__hitWorld(point: IRadiusPointData): boolean {
|
|
11
|
+
if (this.__layout.hitCanvasChanged || !this.__hitCanvas) {
|
|
12
|
+
this.__updateHitCanvas()
|
|
13
|
+
this.__layout.hitCanvasChanged = false
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (this.__.hitRadius) {
|
|
17
|
+
copy(inner, point), point = inner
|
|
18
|
+
setRadius(point, this.__.hitRadius)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
toInnerRadiusPointOf(point, this.__world, inner)
|
|
22
|
+
return this.__hit(inner)
|
|
23
|
+
},
|
|
24
|
+
|
|
25
|
+
__drawHitPath(canvas: ILeaferCanvas): void {
|
|
26
|
+
this.__drawRenderPath(canvas)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
}
|
package/src/LeafMask.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { ILeaf, ILeaferCanvas, ILeafMaskModule } from '@leafer/interface'
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
export const LeafMask: ILeafMaskModule = {
|
|
5
|
+
|
|
6
|
+
__updateEraser(value?: boolean): void {
|
|
7
|
+
this.__hasEraser = value ? true : this.children.some(item => item.__.isEraser)
|
|
8
|
+
},
|
|
9
|
+
|
|
10
|
+
__updateMask(value?: boolean): void {
|
|
11
|
+
this.__hasMask = value ? true : this.children.some(item => item.__.isMask)
|
|
12
|
+
},
|
|
13
|
+
|
|
14
|
+
__renderMask(canvas: ILeaferCanvas, content: ILeaferCanvas, mask: ILeaferCanvas): void {
|
|
15
|
+
content.resetTransform()
|
|
16
|
+
content.useMask(mask)
|
|
17
|
+
canvas.resetTransform()
|
|
18
|
+
canvas.opacity = this.__worldOpacity
|
|
19
|
+
canvas.copyWorld(content)
|
|
20
|
+
},
|
|
21
|
+
|
|
22
|
+
__removeMask(child?: ILeaf): void {
|
|
23
|
+
if (child) {
|
|
24
|
+
child.isMask = false
|
|
25
|
+
this.remove(child)
|
|
26
|
+
} else {
|
|
27
|
+
const { children } = this
|
|
28
|
+
for (let i = 0, len = children.length; i < len; i++) {
|
|
29
|
+
child = children[i]
|
|
30
|
+
if (child.isMask) {
|
|
31
|
+
this.__removeMask(child)
|
|
32
|
+
len--, i--
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { ILeafMatrixModule, IPointData } from '@leafer/interface'
|
|
2
|
+
import { OneRadian, MatrixHelper } from '@leafer/math'
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
const { sin, cos } = Math
|
|
6
|
+
const defaultWorld = { ...MatrixHelper.defaultMatrix, scaleX: 1, scaleY: 1, rotation: 0, skewX: 0, skewY: 0 }
|
|
7
|
+
const defaultCenter: IPointData = { x: 0.5, y: 0.5 }
|
|
8
|
+
|
|
9
|
+
export const LeafMatrix: ILeafMatrixModule = {
|
|
10
|
+
|
|
11
|
+
__updateWorldMatrix(): void {
|
|
12
|
+
|
|
13
|
+
const pw = this.parent ? this.parent.__world : defaultWorld
|
|
14
|
+
const r = this.__local
|
|
15
|
+
const w = this.__world
|
|
16
|
+
|
|
17
|
+
if (this.__layout.matrixChanged) this.__updateLocalMatrix()
|
|
18
|
+
|
|
19
|
+
if (this.__layout.affectScaleOrRotation) {
|
|
20
|
+
w.a = r.a * pw.a + r.b * pw.c
|
|
21
|
+
w.b = r.a * pw.b + r.b * pw.d
|
|
22
|
+
w.c = r.c * pw.a + r.d * pw.c
|
|
23
|
+
w.d = r.c * pw.b + r.d * pw.d
|
|
24
|
+
w.e = r.e * pw.a + r.f * pw.c + pw.e
|
|
25
|
+
w.f = r.e * pw.b + r.f * pw.d + pw.f
|
|
26
|
+
|
|
27
|
+
const data = this.__
|
|
28
|
+
w.scaleX = pw.scaleX * data.scaleX
|
|
29
|
+
w.scaleY = pw.scaleY * data.scaleY
|
|
30
|
+
|
|
31
|
+
w.rotation = pw.rotation + data.rotation
|
|
32
|
+
w.skewX = pw.skewX + data.skewX
|
|
33
|
+
w.skewY = pw.skewY + data.skewY
|
|
34
|
+
} else {
|
|
35
|
+
w.a = pw.a
|
|
36
|
+
w.b = pw.b
|
|
37
|
+
w.c = pw.c
|
|
38
|
+
w.d = pw.d
|
|
39
|
+
w.e = r.e * pw.a + r.f * pw.c + pw.e
|
|
40
|
+
w.f = r.e * pw.b + r.f * pw.d + pw.f
|
|
41
|
+
|
|
42
|
+
w.scaleX = pw.scaleX
|
|
43
|
+
w.scaleY = pw.scaleY
|
|
44
|
+
|
|
45
|
+
w.rotation = pw.rotation
|
|
46
|
+
w.skewX = pw.skewX
|
|
47
|
+
w.skewY = pw.skewY
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
__updateLocalMatrix(): void {
|
|
52
|
+
|
|
53
|
+
const r = this.__local
|
|
54
|
+
const layout = this.__layout
|
|
55
|
+
|
|
56
|
+
if (layout.affectScaleOrRotation) {
|
|
57
|
+
|
|
58
|
+
const { scaleX, scaleY } = this.__
|
|
59
|
+
|
|
60
|
+
if (layout.affectRotation) {
|
|
61
|
+
|
|
62
|
+
if (layout.scaleChanged || layout.rotationChanged) {
|
|
63
|
+
|
|
64
|
+
let { rotation, skewX, skewY } = this.__
|
|
65
|
+
|
|
66
|
+
if (rotation || skewX || skewY) {
|
|
67
|
+
|
|
68
|
+
rotation *= OneRadian
|
|
69
|
+
if (skewX) skewX *= OneRadian
|
|
70
|
+
if (skewY) skewY *= OneRadian
|
|
71
|
+
|
|
72
|
+
r.a = scaleX * cos(rotation + skewY)
|
|
73
|
+
r.b = scaleX * sin(rotation + skewY)
|
|
74
|
+
r.c = scaleY * -sin(rotation - skewX)
|
|
75
|
+
r.d = scaleY * cos(rotation - skewX)
|
|
76
|
+
|
|
77
|
+
} else {
|
|
78
|
+
|
|
79
|
+
r.a = scaleX
|
|
80
|
+
r.b = 0
|
|
81
|
+
r.c = 0
|
|
82
|
+
r.d = scaleY
|
|
83
|
+
|
|
84
|
+
layout.affectRotation = false
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
layout.scaleChanged = false
|
|
88
|
+
layout.rotationChanged = false
|
|
89
|
+
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
} else {
|
|
93
|
+
|
|
94
|
+
if (layout.scaleChanged) {
|
|
95
|
+
r.a = scaleX
|
|
96
|
+
r.d = scaleY
|
|
97
|
+
layout.scaleChanged = false
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (layout.positionChanged) {
|
|
105
|
+
r.e = this.__.x
|
|
106
|
+
r.f = this.__.y
|
|
107
|
+
const { width, height, around } = this.__
|
|
108
|
+
if (around && width && height) {
|
|
109
|
+
const origin = (around === 'center') ? defaultCenter : around
|
|
110
|
+
const offsetX = width * origin.x, offsetY = height * origin.y
|
|
111
|
+
r.e -= offsetX * r.a + offsetY * r.c
|
|
112
|
+
r.f -= offsetX * r.b + offsetY * r.d
|
|
113
|
+
}
|
|
114
|
+
layout.positionChanged = false
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
this.__layout.matrixChanged = false
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { ILeaferCanvas, IRenderOptions, ILeafRenderModule } from '@leafer/interface'
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
export const LeafRender: ILeafRenderModule = {
|
|
5
|
+
|
|
6
|
+
__render(canvas: ILeaferCanvas, options: IRenderOptions): void {
|
|
7
|
+
if (this.__worldOpacity) {
|
|
8
|
+
canvas.setWorld(this.__world, options.matrix)
|
|
9
|
+
canvas.opacity = this.__worldOpacity
|
|
10
|
+
|
|
11
|
+
if (this.__.__single) {
|
|
12
|
+
const tempCanvas = canvas.getSameCanvas(true)
|
|
13
|
+
|
|
14
|
+
this.__draw(tempCanvas, options)
|
|
15
|
+
|
|
16
|
+
const blendMode = this.__.isEraser ? 'destination-out' : this.__.blendMode
|
|
17
|
+
if (options.matrix || this.__hasMirror) {
|
|
18
|
+
canvas.copyWorldByReset(tempCanvas, null, null, blendMode)
|
|
19
|
+
} else {
|
|
20
|
+
canvas.copyWorldToInner(tempCanvas, this.__world, this.__layout.renderBounds, blendMode)
|
|
21
|
+
}
|
|
22
|
+
tempCanvas.recycle()
|
|
23
|
+
} else {
|
|
24
|
+
this.__draw(canvas, options)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
__updateWorldOpacity(): void {
|
|
30
|
+
this.__worldOpacity = this.__.visible ? (this.parent ? this.parent.__worldOpacity * this.__.opacity : this.__.opacity) : 0
|
|
31
|
+
if (this.__layout.opacityChanged) this.__layout.opacityChanged = false
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
}
|