@leafer/renderer 1.0.0-alpha.21 → 1.0.0-alpha.30
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 +7 -7
- package/src/Renderer.ts +114 -63
- package/src/renderHitView.ts +49 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@leafer/renderer",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.30",
|
|
4
4
|
"description": "@leafer/renderer",
|
|
5
5
|
"author": "Chao (Leafer) Wan",
|
|
6
6
|
"license": "MIT",
|
|
@@ -19,13 +19,13 @@
|
|
|
19
19
|
"leaferjs"
|
|
20
20
|
],
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@leafer/event": "1.0.0-alpha.
|
|
23
|
-
"@leafer/math": "1.0.0-alpha.
|
|
24
|
-
"@leafer/data": "1.0.0-alpha.
|
|
25
|
-
"@leafer/platform": "1.0.0-alpha.
|
|
26
|
-
"@leafer/debug": "1.0.0-alpha.
|
|
22
|
+
"@leafer/event": "1.0.0-alpha.30",
|
|
23
|
+
"@leafer/math": "1.0.0-alpha.30",
|
|
24
|
+
"@leafer/data": "1.0.0-alpha.30",
|
|
25
|
+
"@leafer/platform": "1.0.0-alpha.30",
|
|
26
|
+
"@leafer/debug": "1.0.0-alpha.30"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
|
-
"@leafer/interface": "1.0.0-alpha.
|
|
29
|
+
"@leafer/interface": "1.0.0-alpha.30"
|
|
30
30
|
}
|
|
31
31
|
}
|
package/src/Renderer.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ILeaf, ILeaferCanvas, IRenderer, IRendererConfig, IEventListenerId, IBounds, IFunction } from '@leafer/interface'
|
|
1
|
+
import { ILeaf, ILeaferCanvas, IRenderer, IRendererConfig, IEventListenerId, IBounds, IFunction, IRenderOptions } 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'
|
|
@@ -19,6 +19,9 @@ export class Renderer implements IRenderer {
|
|
|
19
19
|
public times: number = 0
|
|
20
20
|
|
|
21
21
|
public running: boolean
|
|
22
|
+
public rendering: boolean
|
|
23
|
+
|
|
24
|
+
public waitAgain: boolean
|
|
22
25
|
public changed: boolean
|
|
23
26
|
|
|
24
27
|
public config: IRendererConfig = {
|
|
@@ -26,9 +29,15 @@ export class Renderer implements IRenderer {
|
|
|
26
29
|
maxFPS: 60
|
|
27
30
|
}
|
|
28
31
|
|
|
32
|
+
protected renderBounds: IBounds
|
|
33
|
+
protected renderOptions: IRenderOptions
|
|
34
|
+
protected totalBounds: IBounds
|
|
35
|
+
|
|
29
36
|
protected __eventIds: IEventListenerId[]
|
|
30
37
|
|
|
31
|
-
|
|
38
|
+
protected get needFill(): boolean { return !!(!this.canvas.allowBackgroundColor && this.config.fill) }
|
|
39
|
+
|
|
40
|
+
constructor(target: ILeaf, canvas: ILeaferCanvas, userConfig?: IRendererConfig) {
|
|
32
41
|
this.target = target
|
|
33
42
|
this.canvas = canvas
|
|
34
43
|
if (userConfig) this.config = DataHelper.default(userConfig, this.config)
|
|
@@ -53,126 +62,151 @@ export class Renderer implements IRenderer {
|
|
|
53
62
|
}
|
|
54
63
|
|
|
55
64
|
public render(callback?: IFunction): void {
|
|
65
|
+
if (!(this.running)) return
|
|
66
|
+
|
|
56
67
|
const { target } = this
|
|
57
68
|
this.times = 0
|
|
69
|
+
this.totalBounds = new Bounds()
|
|
58
70
|
|
|
59
|
-
debug.log(target.
|
|
71
|
+
debug.log(target.innerName, '--->')
|
|
60
72
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
73
|
+
try {
|
|
74
|
+
this.emitRender(RenderEvent.START)
|
|
75
|
+
this.renderOnce(callback)
|
|
76
|
+
this.emitRender(RenderEvent.END, this.totalBounds)
|
|
77
|
+
} catch (e) {
|
|
78
|
+
debug.error(e)
|
|
79
|
+
}
|
|
65
80
|
|
|
66
|
-
debug.log(
|
|
81
|
+
debug.log('-------------|')
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
public renderAgain(): void {
|
|
85
|
+
if (this.rendering) {
|
|
86
|
+
this.waitAgain = true
|
|
87
|
+
} else {
|
|
88
|
+
this.renderOnce()
|
|
89
|
+
}
|
|
67
90
|
}
|
|
68
91
|
|
|
69
92
|
public renderOnce(callback?: IFunction): void {
|
|
70
|
-
|
|
93
|
+
if (this.rendering) return debug.warn('rendering')
|
|
94
|
+
if (this.times > 3) return debug.warn('render max times')
|
|
71
95
|
|
|
72
96
|
this.times++
|
|
73
97
|
this.totalTimes++
|
|
98
|
+
|
|
99
|
+
this.rendering = true
|
|
74
100
|
this.changed = false
|
|
101
|
+
this.renderBounds = new Bounds()
|
|
102
|
+
this.renderOptions = {}
|
|
75
103
|
|
|
76
104
|
if (callback) {
|
|
77
|
-
|
|
78
|
-
target.emit(RenderEvent.BEFORE_ONCE)
|
|
79
|
-
|
|
105
|
+
this.emitRender(RenderEvent.BEFORE)
|
|
80
106
|
callback()
|
|
81
|
-
|
|
82
107
|
} else {
|
|
83
|
-
|
|
84
108
|
this.requestLayout()
|
|
85
109
|
|
|
86
|
-
|
|
110
|
+
this.emitRender(RenderEvent.BEFORE)
|
|
87
111
|
|
|
88
112
|
if (this.config.usePartRender && this.totalTimes > 1) {
|
|
89
113
|
this.partRender()
|
|
90
114
|
} else {
|
|
91
115
|
this.fullRender()
|
|
92
116
|
}
|
|
93
|
-
|
|
94
117
|
}
|
|
95
118
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
119
|
+
this.emitRender(RenderEvent.RENDER, this.renderBounds, this.renderOptions)
|
|
120
|
+
this.emitRender(RenderEvent.AFTER, this.renderBounds, this.renderOptions)
|
|
99
121
|
|
|
100
122
|
this.updateBlocks = null
|
|
123
|
+
this.rendering = false
|
|
101
124
|
|
|
102
|
-
this.
|
|
125
|
+
if (this.waitAgain) {
|
|
126
|
+
this.waitAgain = false
|
|
127
|
+
this.renderOnce()
|
|
128
|
+
}
|
|
103
129
|
}
|
|
104
130
|
|
|
105
131
|
public partRender(): void {
|
|
106
132
|
const { canvas, updateBlocks: list } = this
|
|
133
|
+
if (!list) return debug.warn('PartRender: need update attr')
|
|
107
134
|
|
|
108
|
-
if (
|
|
109
|
-
|
|
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)
|
|
117
|
-
} else {
|
|
118
|
-
list.forEach(block => {
|
|
119
|
-
if (canvas.bounds.hit(block) && !block.isEmpty()) this.clipRender(block.getIntersect(canvas.bounds))
|
|
120
|
-
})
|
|
121
|
-
}
|
|
135
|
+
if (list.some(block => block.includes(this.target.__world))) this.mergeBlocks()
|
|
136
|
+
list.forEach(block => { if (canvas.bounds.hit(block) && !block.isEmpty()) this.clipRender(block) })
|
|
122
137
|
}
|
|
123
138
|
|
|
124
|
-
public clipRender(
|
|
139
|
+
public clipRender(block: IBounds): void {
|
|
125
140
|
const t = Run.start('PartRender')
|
|
126
|
-
const { canvas
|
|
141
|
+
const { canvas } = this
|
|
127
142
|
|
|
128
|
-
bounds
|
|
129
|
-
|
|
143
|
+
const bounds = block.getIntersect(canvas.bounds)
|
|
144
|
+
const includes = block.includes(this.target.__world)
|
|
145
|
+
const realBounds = new Bounds().copy(bounds)
|
|
130
146
|
|
|
131
147
|
canvas.save()
|
|
132
|
-
|
|
133
|
-
if (Debug.showRepaint)
|
|
134
|
-
|
|
135
|
-
|
|
148
|
+
|
|
149
|
+
if (includes && !Debug.showRepaint) {
|
|
150
|
+
canvas.clear()
|
|
151
|
+
} else {
|
|
152
|
+
bounds.spread(1 + 1 / this.canvas.pixelRatio).ceil()
|
|
153
|
+
canvas.clearWorld(bounds, true)
|
|
154
|
+
canvas.clipWorld(bounds, true)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
this.__render(bounds, realBounds)
|
|
136
158
|
canvas.restore()
|
|
137
159
|
|
|
138
160
|
Run.end(t)
|
|
139
161
|
}
|
|
140
162
|
|
|
141
|
-
public fullRender(
|
|
142
|
-
const { canvas, target } = this
|
|
143
|
-
Renderer.fullRender(target, canvas, bounds)
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
static fullRender(target: ILeaf, canvas: ILeaferCanvas, bounds?: IBounds): void {
|
|
163
|
+
public fullRender(): void {
|
|
147
164
|
const t = Run.start('FullRender')
|
|
148
|
-
|
|
165
|
+
const { canvas } = this
|
|
149
166
|
|
|
150
167
|
canvas.save()
|
|
151
168
|
canvas.clear()
|
|
152
|
-
|
|
169
|
+
this.__render(canvas.bounds)
|
|
153
170
|
canvas.restore()
|
|
154
171
|
|
|
155
172
|
Run.end(t)
|
|
156
173
|
}
|
|
157
174
|
|
|
175
|
+
protected __render(bounds: IBounds, realBounds?: IBounds): void {
|
|
176
|
+
const options: IRenderOptions = bounds?.includes(this.target.__world) ? {} : { bounds }
|
|
177
|
+
|
|
178
|
+
if (this.needFill) this.canvas.fillWorld(bounds, this.config.fill)
|
|
179
|
+
if (Debug.showRepaint) this.canvas.strokeWorld(bounds, 'red')
|
|
180
|
+
|
|
181
|
+
this.target.__render(this.canvas, options)
|
|
182
|
+
|
|
183
|
+
this.renderBounds = realBounds || bounds
|
|
184
|
+
this.renderOptions = options
|
|
185
|
+
this.totalBounds.isEmpty() ? this.totalBounds = this.renderBounds : this.totalBounds.add(this.renderBounds)
|
|
186
|
+
|
|
187
|
+
if (Debug.showHitView) this.renderHitView(options)
|
|
188
|
+
if (Debug.showBoundsView) this.renderBoundsView(options)
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
public renderHitView(_options: IRenderOptions): void { }
|
|
192
|
+
|
|
193
|
+
public renderBoundsView(_options: IRenderOptions): void { }
|
|
194
|
+
|
|
158
195
|
public addBlock(block: IBounds): void {
|
|
159
196
|
if (!this.updateBlocks) this.updateBlocks = []
|
|
160
197
|
this.updateBlocks.push(block)
|
|
161
198
|
}
|
|
162
199
|
|
|
163
200
|
public mergeBlocks(): void {
|
|
164
|
-
const { updateBlocks } = this
|
|
165
|
-
if (
|
|
201
|
+
const { updateBlocks: list } = this
|
|
202
|
+
if (list) {
|
|
166
203
|
const bounds = new Bounds()
|
|
167
|
-
bounds.setByList(
|
|
168
|
-
|
|
204
|
+
bounds.setByList(list)
|
|
205
|
+
list.length = 0
|
|
206
|
+
list.push(bounds)
|
|
169
207
|
}
|
|
170
208
|
}
|
|
171
209
|
|
|
172
|
-
protected __checkAgain(): void {
|
|
173
|
-
if (this.changed && this.times < 3) this.target.emit(RenderEvent.AGAIN)
|
|
174
|
-
}
|
|
175
|
-
|
|
176
210
|
protected __requestRender(): void {
|
|
177
211
|
const startTime = Date.now()
|
|
178
212
|
Platform.requestRender(() => {
|
|
@@ -184,18 +218,34 @@ export class Renderer implements IRenderer {
|
|
|
184
218
|
}
|
|
185
219
|
|
|
186
220
|
protected __onResize(e: ResizeEvent): void {
|
|
221
|
+
if (this.canvas.unreal) return
|
|
187
222
|
if (e.bigger || !e.samePixelRatio) {
|
|
188
223
|
const { width, height } = e.old
|
|
189
224
|
const bounds = new Bounds(0, 0, width, height)
|
|
190
|
-
if (!bounds.includes(this.target.__world)) {
|
|
191
|
-
this.
|
|
192
|
-
this.
|
|
225
|
+
if (!bounds.includes(this.target.__world) || this.needFill || !e.samePixelRatio) {
|
|
226
|
+
this.addBlock(this.canvas.bounds)
|
|
227
|
+
this.target.forceUpdate('blendMode')
|
|
193
228
|
}
|
|
194
229
|
}
|
|
195
230
|
}
|
|
196
231
|
|
|
197
232
|
protected __onLayoutEnd(event: LayoutEvent): void {
|
|
198
|
-
event.data.map(item =>
|
|
233
|
+
if (event.data) event.data.map(item => {
|
|
234
|
+
let empty: boolean
|
|
235
|
+
if (item.updatedList) item.updatedList.list.some(leaf => {
|
|
236
|
+
empty = (!leaf.__world.width || !leaf.__world.height)
|
|
237
|
+
if (empty) {
|
|
238
|
+
debug.warn(leaf.innerName, ': none bounds')
|
|
239
|
+
empty = (!leaf.isBranch || leaf.isBranchLeaf) // render object
|
|
240
|
+
}
|
|
241
|
+
return empty
|
|
242
|
+
})
|
|
243
|
+
this.addBlock(empty ? this.canvas.bounds : item.updatedBounds)
|
|
244
|
+
})
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
protected emitRender(type: string, bounds?: IBounds, options?: IRenderOptions): void {
|
|
248
|
+
this.target.emitEvent(new RenderEvent(type, this.times, bounds, options))
|
|
199
249
|
}
|
|
200
250
|
|
|
201
251
|
protected __listenEvents(): void {
|
|
@@ -203,7 +253,7 @@ export class Renderer implements IRenderer {
|
|
|
203
253
|
this.__eventIds = [
|
|
204
254
|
target.on__(RenderEvent.REQUEST, this.update, this),
|
|
205
255
|
target.on__(LayoutEvent.END, this.__onLayoutEnd, this),
|
|
206
|
-
target.on__(RenderEvent.AGAIN, this.
|
|
256
|
+
target.on__(RenderEvent.AGAIN, this.renderAgain, this),
|
|
207
257
|
target.on__(ResizeEvent.RESIZE, this.__onResize, this)
|
|
208
258
|
]
|
|
209
259
|
}
|
|
@@ -214,6 +264,7 @@ export class Renderer implements IRenderer {
|
|
|
214
264
|
|
|
215
265
|
public destroy(): void {
|
|
216
266
|
if (this.target) {
|
|
267
|
+
this.stop()
|
|
217
268
|
this.__removeListenEvents()
|
|
218
269
|
this.target = null
|
|
219
270
|
this.canvas = null
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { ILeaf, ILeaferCanvas, IRenderOptions } from '@leafer/interface'
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
const colorList: string[] = []
|
|
5
|
+
for (let i = 0; i < 360; i++) {
|
|
6
|
+
colorList.push(Math.round(Math.random() * 360) + '')
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function renderHitView(target: ILeaf, canvas: ILeaferCanvas, options: IRenderOptions, hasMask?: boolean): void {
|
|
10
|
+
if (target.hittable) {
|
|
11
|
+
if (target.isBranch) {
|
|
12
|
+
renderBranchHitView(target, canvas, options)
|
|
13
|
+
} else {
|
|
14
|
+
renderLeafHitView(target, canvas, options, hasMask)
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function renderBranchHitView(branch: ILeaf, canvas: ILeaferCanvas, options: IRenderOptions): void {
|
|
20
|
+
const { children } = branch
|
|
21
|
+
let target: ILeaf
|
|
22
|
+
for (let i = 0, len = children.length; i < len; i++) {
|
|
23
|
+
target = children[i]
|
|
24
|
+
if (target.hittable) {
|
|
25
|
+
if (target.isBranch) {
|
|
26
|
+
renderBranchHitView(target, canvas, options)
|
|
27
|
+
} else {
|
|
28
|
+
renderLeafHitView(target, canvas, options, target.__hasMask)
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function renderLeafHitView(leaf: ILeaf, canvas: ILeaferCanvas, options: IRenderOptions, hasMask: boolean): void {
|
|
35
|
+
if (leaf.__worldOpacity) {
|
|
36
|
+
const { isMask, __strokeOuterWidth: strokeWidth } = leaf.__
|
|
37
|
+
if (hasMask && !isMask) return
|
|
38
|
+
|
|
39
|
+
canvas.setWorld(leaf.__world, options.matrix)
|
|
40
|
+
canvas.opacity = 0.5
|
|
41
|
+
|
|
42
|
+
leaf.__drawHitPath(canvas)
|
|
43
|
+
|
|
44
|
+
canvas.fillStyle = canvas.strokeStyle = 'hsl(' + colorList[leaf.innerId % 360] + ',50%, 50%)'
|
|
45
|
+
canvas.fill(leaf.__.windingRule)
|
|
46
|
+
canvas.strokeWidth = strokeWidth ? strokeWidth * 2 : 1
|
|
47
|
+
canvas.stroke()
|
|
48
|
+
}
|
|
49
|
+
}
|