@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.
Files changed (2) hide show
  1. package/package.json +10 -8
  2. 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.1",
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": ["src"],
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.1",
21
- "@leafer/math": "1.0.0-alpha.1",
22
- "@leafer/data": "1.0.0-alpha.1",
23
- "@leafer/platform": "1.0.0-alpha.1",
24
- "@leafer/debug": "1.0.0-alpha.1"
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
- "@leafer/interface": "1.0.0-alpha.1"
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, ILayoutBlockData } from '@leafer/interface'
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 layoutedBlocks: ILayoutBlockData[]
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 FPS = 60
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
- public running: boolean
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.listenEvents()
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
- private listenEvents(): void {
58
- const { target } = this
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
- target.emit(START)
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
- if (this.layoutedBlocks) this.partRender()
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
- if (this.layoutedBlocks) {
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
- protected __checkAgain(): void {
145
- if (this.changed && this.times < 3) this.target.emit(RenderEvent.AGAIN)
146
- }
147
-
105
+ public partRender(): void {
106
+ const { canvas, updateBlocks: list } = this
148
107
 
149
- protected partRender(): void {
150
- const { canvas, layoutedBlocks } = this
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
- let bounds: IBounds
156
- layoutedBlocks.forEach(block => {
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('part render')
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.clearBounds(bounds)
169
- if (Debug.showRepaint) canvas.strokeBounds(bounds, 'red')
170
- canvas.clipBounds(bounds)
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('full render')
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
- private requestRender(): void {
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.removeListenEvents()
208
- this.target = undefined
209
- this.canvas = undefined
210
- this.config = undefined
217
+ this.__removeListenEvents()
218
+ this.target = null
219
+ this.canvas = null
220
+ this.config = null
211
221
  }
212
222
  }
213
223
  }