@leafer/renderer 1.0.0-alpha.1 → 1.0.0-alpha.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.
- package/package.json +10 -8
- package/src/Renderer.ts +101 -91
package/package.json
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@leafer/renderer",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.21",
|
|
4
4
|
"description": "@leafer/renderer",
|
|
5
5
|
"author": "Chao (Leafer) Wan",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"main": "src/index.ts",
|
|
8
|
-
"files": [
|
|
8
|
+
"files": [
|
|
9
|
+
"src"
|
|
10
|
+
],
|
|
9
11
|
"repository": {
|
|
10
12
|
"type": "git",
|
|
11
13
|
"url": "https://github.com/leaferjs/leafer.git"
|
|
@@ -17,13 +19,13 @@
|
|
|
17
19
|
"leaferjs"
|
|
18
20
|
],
|
|
19
21
|
"dependencies": {
|
|
20
|
-
"@leafer/event": "1.0.0-alpha.
|
|
21
|
-
"@leafer/math": "1.0.0-alpha.
|
|
22
|
-
"@leafer/data": "1.0.0-alpha.
|
|
23
|
-
"@leafer/platform": "1.0.0-alpha.
|
|
24
|
-
"@leafer/debug": "1.0.0-alpha.
|
|
22
|
+
"@leafer/event": "1.0.0-alpha.21",
|
|
23
|
+
"@leafer/math": "1.0.0-alpha.21",
|
|
24
|
+
"@leafer/data": "1.0.0-alpha.21",
|
|
25
|
+
"@leafer/platform": "1.0.0-alpha.21",
|
|
26
|
+
"@leafer/debug": "1.0.0-alpha.21"
|
|
25
27
|
},
|
|
26
28
|
"devDependencies": {
|
|
27
|
-
|
|
29
|
+
"@leafer/interface": "1.0.0-alpha.21"
|
|
28
30
|
}
|
|
29
31
|
}
|
package/src/Renderer.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ILeaf, ILeaferCanvas, IRenderer, IRendererConfig, IEventListenerId, IBounds, IFunction
|
|
1
|
+
import { ILeaf, ILeaferCanvas, IRenderer, IRendererConfig, IEventListenerId, IBounds, IFunction } from '@leafer/interface'
|
|
2
2
|
import { LayoutEvent, RenderEvent, ResizeEvent } from '@leafer/event'
|
|
3
3
|
import { Bounds } from '@leafer/math'
|
|
4
4
|
import { DataHelper } from '@leafer/data'
|
|
@@ -6,80 +6,45 @@ import { Platform } from '@leafer/platform'
|
|
|
6
6
|
import { Debug, Run } from '@leafer/debug'
|
|
7
7
|
|
|
8
8
|
|
|
9
|
+
const debug = Debug.get('Renderer')
|
|
10
|
+
|
|
9
11
|
export class Renderer implements IRenderer {
|
|
10
12
|
|
|
11
13
|
public target: ILeaf
|
|
12
14
|
public canvas: ILeaferCanvas
|
|
13
|
-
public
|
|
15
|
+
public updateBlocks: IBounds[]
|
|
14
16
|
|
|
17
|
+
public FPS = 60
|
|
15
18
|
public totalTimes = 0
|
|
16
19
|
public times: number = 0
|
|
17
20
|
|
|
18
|
-
public
|
|
21
|
+
public running: boolean
|
|
22
|
+
public changed: boolean
|
|
19
23
|
|
|
20
24
|
public config: IRendererConfig = {
|
|
25
|
+
usePartRender: true,
|
|
21
26
|
maxFPS: 60
|
|
22
27
|
}
|
|
23
28
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
private _changed = false
|
|
27
|
-
set changed(value: boolean) {
|
|
28
|
-
if (value) {
|
|
29
|
-
if (!this._changed) {
|
|
30
|
-
this._changed = true
|
|
31
|
-
this.requestRender()
|
|
32
|
-
}
|
|
33
|
-
} else {
|
|
34
|
-
this._changed = false
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
get changed(): boolean { return this._changed }
|
|
38
|
-
|
|
39
|
-
protected eventIds: IEventListenerId[]
|
|
29
|
+
protected __eventIds: IEventListenerId[]
|
|
40
30
|
|
|
41
31
|
constructor(target: ILeaf, canvas: ILeaferCanvas, userConfig: IRendererConfig) {
|
|
42
32
|
this.target = target
|
|
43
33
|
this.canvas = canvas
|
|
44
34
|
if (userConfig) this.config = DataHelper.default(userConfig, this.config)
|
|
45
|
-
this.
|
|
35
|
+
this.__listenEvents()
|
|
46
36
|
}
|
|
47
37
|
|
|
48
38
|
public start(): void {
|
|
49
39
|
this.running = true
|
|
50
|
-
this.changed = true
|
|
51
40
|
}
|
|
52
41
|
|
|
53
42
|
public stop(): void {
|
|
54
43
|
this.running = false
|
|
55
44
|
}
|
|
56
45
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
this.eventIds = [
|
|
60
|
-
target.on__(RenderEvent.REQUEST, this.onRequest, this),
|
|
61
|
-
target.on__(LayoutEvent.END, this.onLayoutEnd, this),
|
|
62
|
-
target.on__(RenderEvent.AGAIN, this.renderOnce, this),
|
|
63
|
-
target.on__(ResizeEvent.RESIZE, this.onResize, this)
|
|
64
|
-
]
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
private removeListenEvents(): void {
|
|
68
|
-
this.target.off__(this.eventIds)
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
protected onResize(e: ResizeEvent): void {
|
|
72
|
-
if (e.bigger || !e.samePixelRatio) {
|
|
73
|
-
const { width, height } = e.old
|
|
74
|
-
const bounds = new Bounds(0, 0, width, height)
|
|
75
|
-
if (!bounds.includes(this.target.__world)) {
|
|
76
|
-
this.target.__updateAttr('fill')
|
|
77
|
-
this.changed = true
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
protected onRequest(): void {
|
|
46
|
+
public update(): void {
|
|
47
|
+
if (!this.changed) this.__requestRender()
|
|
83
48
|
this.changed = true
|
|
84
49
|
}
|
|
85
50
|
|
|
@@ -87,23 +52,22 @@ export class Renderer implements IRenderer {
|
|
|
87
52
|
this.target.emit(LayoutEvent.REQUEST)
|
|
88
53
|
}
|
|
89
54
|
|
|
90
|
-
public onLayoutEnd(event: LayoutEvent): void {
|
|
91
|
-
this.layoutedBlocks = event.data
|
|
92
|
-
}
|
|
93
|
-
|
|
94
55
|
public render(callback?: IFunction): void {
|
|
95
56
|
const { target } = this
|
|
96
|
-
const { START, RENDER, END } = RenderEvent
|
|
97
57
|
this.times = 0
|
|
98
|
-
|
|
58
|
+
|
|
59
|
+
debug.log(target.innerId, '--->')
|
|
60
|
+
|
|
61
|
+
target.emit(RenderEvent.START)
|
|
99
62
|
this.renderOnce(callback)
|
|
100
|
-
target.emit(RENDER)
|
|
101
|
-
target.emit(END)
|
|
63
|
+
target.emit(RenderEvent.RENDER)
|
|
64
|
+
target.emit(RenderEvent.END)
|
|
65
|
+
|
|
66
|
+
debug.log(target.innerId, '---|')
|
|
102
67
|
}
|
|
103
68
|
|
|
104
69
|
public renderOnce(callback?: IFunction): void {
|
|
105
70
|
const { target } = this
|
|
106
|
-
const { BEFORE_ONCE, ONCE, AFTER_ONCE } = RenderEvent
|
|
107
71
|
|
|
108
72
|
this.times++
|
|
109
73
|
this.totalTimes++
|
|
@@ -111,7 +75,7 @@ export class Renderer implements IRenderer {
|
|
|
111
75
|
|
|
112
76
|
if (callback) {
|
|
113
77
|
|
|
114
|
-
target.emit(BEFORE_ONCE)
|
|
78
|
+
target.emit(RenderEvent.BEFORE_ONCE)
|
|
115
79
|
|
|
116
80
|
callback()
|
|
117
81
|
|
|
@@ -119,56 +83,56 @@ export class Renderer implements IRenderer {
|
|
|
119
83
|
|
|
120
84
|
this.requestLayout()
|
|
121
85
|
|
|
122
|
-
target.emit(BEFORE_ONCE)
|
|
86
|
+
target.emit(RenderEvent.BEFORE_ONCE)
|
|
123
87
|
|
|
124
|
-
if (this.totalTimes > 1) {
|
|
125
|
-
|
|
88
|
+
if (this.config.usePartRender && this.totalTimes > 1) {
|
|
89
|
+
this.partRender()
|
|
126
90
|
} else {
|
|
127
91
|
this.fullRender()
|
|
128
92
|
}
|
|
129
93
|
|
|
130
94
|
}
|
|
131
95
|
|
|
132
|
-
target.emit(ONCE)
|
|
133
|
-
target.emit(AFTER_ONCE)
|
|
96
|
+
target.emit(RenderEvent.ONCE)
|
|
97
|
+
target.emit(RenderEvent.AFTER_ONCE)
|
|
134
98
|
|
|
135
99
|
|
|
136
|
-
|
|
137
|
-
this.layoutedBlocks.forEach(item => { item.destroy() })
|
|
138
|
-
this.layoutedBlocks = undefined
|
|
139
|
-
}
|
|
100
|
+
this.updateBlocks = null
|
|
140
101
|
|
|
141
102
|
this.__checkAgain()
|
|
142
103
|
}
|
|
143
104
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
}
|
|
147
|
-
|
|
105
|
+
public partRender(): void {
|
|
106
|
+
const { canvas, updateBlocks: list } = this
|
|
148
107
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
if (layoutedBlocks.some(block => block.updatedBounds.includes(this.target.__world))) {
|
|
108
|
+
if (!list) {
|
|
109
|
+
debug.warn('PartRender: layoutedBlocks is empty')
|
|
153
110
|
this.fullRender(canvas.bounds)
|
|
111
|
+
return
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (list.some(block => block.includes(this.target.__world))) {
|
|
115
|
+
this.mergeBlocks()
|
|
116
|
+
this.clipRender(this.updateBlocks[0], true)
|
|
154
117
|
} else {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
bounds = block.updatedBounds
|
|
158
|
-
if (canvas.bounds.hit(bounds) && !bounds.isEmpty()) this.clipRender(bounds.getIntersect(canvas.bounds))
|
|
118
|
+
list.forEach(block => {
|
|
119
|
+
if (canvas.bounds.hit(block) && !block.isEmpty()) this.clipRender(block.getIntersect(canvas.bounds))
|
|
159
120
|
})
|
|
160
121
|
}
|
|
161
122
|
}
|
|
162
123
|
|
|
163
|
-
public clipRender(bounds: IBounds): void {
|
|
164
|
-
const t = Run.start('
|
|
124
|
+
public clipRender(bounds: IBounds, fullMode?: boolean): void {
|
|
125
|
+
const t = Run.start('PartRender')
|
|
165
126
|
const { canvas, target } = this
|
|
166
127
|
|
|
128
|
+
bounds.spread(1 + 1 / this.canvas.pixelRatio)
|
|
129
|
+
bounds.ceil()
|
|
130
|
+
|
|
167
131
|
canvas.save()
|
|
168
|
-
canvas.
|
|
169
|
-
if (Debug.showRepaint) canvas.
|
|
170
|
-
canvas.
|
|
171
|
-
target.__render(canvas, { bounds })
|
|
132
|
+
canvas.clearWorld(bounds, true)
|
|
133
|
+
if (Debug.showRepaint) canvas.strokeWorld(bounds, 'red')
|
|
134
|
+
canvas.clipWorld(bounds, true)
|
|
135
|
+
target.__render(canvas, fullMode ? {} : { bounds })
|
|
172
136
|
canvas.restore()
|
|
173
137
|
|
|
174
138
|
Run.end(t)
|
|
@@ -177,11 +141,10 @@ export class Renderer implements IRenderer {
|
|
|
177
141
|
public fullRender(bounds?: IBounds): void {
|
|
178
142
|
const { canvas, target } = this
|
|
179
143
|
Renderer.fullRender(target, canvas, bounds)
|
|
180
|
-
if (Debug.showRepaint) canvas.strokeBounds(bounds || canvas.bounds, 'red')
|
|
181
144
|
}
|
|
182
145
|
|
|
183
146
|
static fullRender(target: ILeaf, canvas: ILeaferCanvas, bounds?: IBounds): void {
|
|
184
|
-
const t = Run.start('
|
|
147
|
+
const t = Run.start('FullRender')
|
|
185
148
|
if (!bounds) bounds = canvas.bounds
|
|
186
149
|
|
|
187
150
|
canvas.save()
|
|
@@ -192,7 +155,25 @@ export class Renderer implements IRenderer {
|
|
|
192
155
|
Run.end(t)
|
|
193
156
|
}
|
|
194
157
|
|
|
195
|
-
|
|
158
|
+
public addBlock(block: IBounds): void {
|
|
159
|
+
if (!this.updateBlocks) this.updateBlocks = []
|
|
160
|
+
this.updateBlocks.push(block)
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
public mergeBlocks(): void {
|
|
164
|
+
const { updateBlocks } = this
|
|
165
|
+
if (updateBlocks) {
|
|
166
|
+
const bounds = new Bounds()
|
|
167
|
+
bounds.setByList(updateBlocks)
|
|
168
|
+
this.updateBlocks = [bounds]
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
protected __checkAgain(): void {
|
|
173
|
+
if (this.changed && this.times < 3) this.target.emit(RenderEvent.AGAIN)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
protected __requestRender(): void {
|
|
196
177
|
const startTime = Date.now()
|
|
197
178
|
Platform.requestRender(() => {
|
|
198
179
|
if (this.changed) {
|
|
@@ -202,12 +183,41 @@ export class Renderer implements IRenderer {
|
|
|
202
183
|
})
|
|
203
184
|
}
|
|
204
185
|
|
|
186
|
+
protected __onResize(e: ResizeEvent): void {
|
|
187
|
+
if (e.bigger || !e.samePixelRatio) {
|
|
188
|
+
const { width, height } = e.old
|
|
189
|
+
const bounds = new Bounds(0, 0, width, height)
|
|
190
|
+
if (!bounds.includes(this.target.__world)) {
|
|
191
|
+
this.target.__updateAttr('fill')
|
|
192
|
+
this.update()
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
protected __onLayoutEnd(event: LayoutEvent): void {
|
|
198
|
+
event.data.map(item => this.addBlock(item.updatedBounds))
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
protected __listenEvents(): void {
|
|
202
|
+
const { target } = this
|
|
203
|
+
this.__eventIds = [
|
|
204
|
+
target.on__(RenderEvent.REQUEST, this.update, this),
|
|
205
|
+
target.on__(LayoutEvent.END, this.__onLayoutEnd, this),
|
|
206
|
+
target.on__(RenderEvent.AGAIN, this.renderOnce, this),
|
|
207
|
+
target.on__(ResizeEvent.RESIZE, this.__onResize, this)
|
|
208
|
+
]
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
protected __removeListenEvents(): void {
|
|
212
|
+
this.target.off__(this.__eventIds)
|
|
213
|
+
}
|
|
214
|
+
|
|
205
215
|
public destroy(): void {
|
|
206
216
|
if (this.target) {
|
|
207
|
-
this.
|
|
208
|
-
this.target =
|
|
209
|
-
this.canvas =
|
|
210
|
-
this.config =
|
|
217
|
+
this.__removeListenEvents()
|
|
218
|
+
this.target = null
|
|
219
|
+
this.canvas = null
|
|
220
|
+
this.config = null
|
|
211
221
|
}
|
|
212
222
|
}
|
|
213
223
|
}
|