@@ -44,15 +44,14 @@ function render_pipeline_graph() {
44
44
const units = UNIT_DATA . filter ( unit => unit . duration >= min_time ) ;
45
45
46
46
const graph_height = Y_TICK_DIST * units . length ;
47
- const { ctx, width , height } = draw_graph_axes ( 'pipeline-graph' , graph_height ) ;
47
+ const { ctx, graph_width , canvas_width , canvas_height , px_per_sec } = draw_graph_axes ( 'pipeline-graph' , graph_height ) ;
48
48
const container = document . getElementById ( 'pipeline-container' ) ;
49
- container . style . width = width ;
50
- container . style . height = height ;
51
- const PX_PER_SEC = document . getElementById ( 'scale' ) . valueAsNumber ;
49
+ container . style . width = canvas_width ;
50
+ container . style . height = canvas_height ;
52
51
53
52
// Canvas for hover highlights. This is a separate layer to improve performance.
54
- const linectx = setup_canvas ( 'pipeline-graph-lines' , width , height ) ;
55
- linectx . clearRect ( 0 , 0 , width , height ) ;
53
+ const linectx = setup_canvas ( 'pipeline-graph-lines' , canvas_width , canvas_height ) ;
54
+ linectx . clearRect ( 0 , 0 , canvas_width , canvas_height ) ;
56
55
57
56
// Draw Y tick marks.
58
57
for ( let n = 1 ; n < units . length ; n ++ ) {
@@ -79,12 +78,12 @@ function render_pipeline_graph() {
79
78
for ( i = 0 ; i < units . length ; i ++ ) {
80
79
let unit = units [ i ] ;
81
80
let y = i * Y_TICK_DIST + 1 ;
82
- let x = PX_PER_SEC * unit . start ;
81
+ let x = px_per_sec * unit . start ;
83
82
let rmeta_x = null ;
84
83
if ( unit . rmeta_time != null ) {
85
- rmeta_x = x + PX_PER_SEC * unit . rmeta_time ;
84
+ rmeta_x = x + px_per_sec * unit . rmeta_time ;
86
85
}
87
- let width = Math . max ( PX_PER_SEC * unit . duration , 1.0 ) ;
86
+ let width = Math . max ( px_per_sec * unit . duration , 1.0 ) ;
88
87
UNIT_COORDS [ unit . i ] = { x, y, width, rmeta_x} ;
89
88
}
90
89
@@ -104,14 +103,17 @@ function render_pipeline_graph() {
104
103
ctx . beginPath ( ) ;
105
104
ctx . fillStyle = '#aa95e8' ;
106
105
let ctime = unit . duration - unit . rmeta_time ;
107
- roundedRect ( ctx , rmeta_x , y , PX_PER_SEC * ctime , BOX_HEIGHT , RADIUS ) ;
106
+ roundedRect ( ctx , rmeta_x , y , px_per_sec * ctime , BOX_HEIGHT , RADIUS ) ;
108
107
ctx . fill ( ) ;
109
108
}
110
109
ctx . fillStyle = "#000" ;
111
110
ctx . textAlign = 'start' ;
112
111
ctx . textBaseline = 'hanging' ;
113
112
ctx . font = '14px sans-serif' ;
114
- ctx . fillText ( `${ unit . name } ${ unit . target } ${ unit . duration } s` , x + 5.0 , y + BOX_HEIGHT / 2 - 6 ) ;
113
+ const label = `${ unit . name } ${ unit . target } ${ unit . duration } s` ;
114
+ const text_info = ctx . measureText ( label ) ;
115
+ const label_x = Math . min ( x + 5.0 , canvas_width - text_info . width - X_LINE ) ;
116
+ ctx . fillText ( label , label_x , y + BOX_HEIGHT / 2 - 6 ) ;
115
117
draw_dep_lines ( ctx , unit . i , false ) ;
116
118
}
117
119
ctx . restore ( ) ;
@@ -154,7 +156,7 @@ function render_timing_graph() {
154
156
const TOP_MARGIN = 10 ;
155
157
const GRAPH_HEIGHT = AXIS_HEIGHT - TOP_MARGIN ;
156
158
157
- const { graph_width, ctx} = draw_graph_axes ( 'timing-graph' , AXIS_HEIGHT ) ;
159
+ const { canvas_width , graph_width, ctx} = draw_graph_axes ( 'timing-graph' , AXIS_HEIGHT ) ;
158
160
159
161
// Draw Y tick marks and labels.
160
162
let max_v = 0 ;
@@ -195,18 +197,20 @@ function render_timing_graph() {
195
197
}
196
198
197
199
const cpuFillStyle = 'rgba(250, 119, 0, 0.2)' ;
198
- ctx . beginPath ( ) ;
199
- ctx . fillStyle = cpuFillStyle ;
200
- let bottomLeft = coord ( CPU_USAGE [ 0 ] [ 0 ] , 0 ) ;
201
- ctx . moveTo ( bottomLeft . x , bottomLeft . y ) ;
202
- for ( let i = 0 ; i < CPU_USAGE . length ; i ++ ) {
203
- let [ time , usage ] = CPU_USAGE [ i ] ;
204
- let { x, y} = coord ( time , usage / 100.0 * max_v ) ;
205
- ctx . lineTo ( x , y ) ;
200
+ if ( CPU_USAGE . length > 1 ) {
201
+ ctx . beginPath ( ) ;
202
+ ctx . fillStyle = cpuFillStyle ;
203
+ let bottomLeft = coord ( CPU_USAGE [ 0 ] [ 0 ] , 0 ) ;
204
+ ctx . moveTo ( bottomLeft . x , bottomLeft . y ) ;
205
+ for ( let i = 0 ; i < CPU_USAGE . length ; i ++ ) {
206
+ let [ time , usage ] = CPU_USAGE [ i ] ;
207
+ let { x, y} = coord ( time , usage / 100.0 * max_v ) ;
208
+ ctx . lineTo ( x , y ) ;
209
+ }
210
+ let bottomRight = coord ( CPU_USAGE [ CPU_USAGE . length - 1 ] [ 0 ] , 0 ) ;
211
+ ctx . lineTo ( bottomRight . x , bottomRight . y ) ;
212
+ ctx . fill ( ) ;
206
213
}
207
- let bottomRight = coord ( CPU_USAGE [ CPU_USAGE . length - 1 ] [ 0 ] , 0 ) ;
208
- ctx . lineTo ( bottomRight . x , bottomRight . y ) ;
209
- ctx . fill ( ) ;
210
214
211
215
function draw_line ( style , key ) {
212
216
let first = CONCURRENCY_DATA [ 0 ] ;
@@ -231,7 +235,7 @@ function render_timing_graph() {
231
235
// Draw a legend.
232
236
ctx . restore ( ) ;
233
237
ctx . save ( ) ;
234
- ctx . translate ( graph_width - 150 , MARGIN ) ;
238
+ ctx . translate ( canvas_width - 200 , MARGIN ) ;
235
239
// background
236
240
ctx . fillStyle = '#fff' ;
237
241
ctx . strokeStyle = '#000' ;
@@ -289,13 +293,18 @@ function setup_canvas(id, width, height) {
289
293
}
290
294
291
295
function draw_graph_axes ( id , graph_height ) {
292
- const PX_PER_SEC = document . getElementById ( 'scale' ) . valueAsNumber ;
293
- const graph_width = PX_PER_SEC * DURATION ;
294
- const width = graph_width + X_LINE + 30 ;
295
- const height = graph_height + MARGIN + Y_LINE ;
296
- let ctx = setup_canvas ( id , width , height ) ;
296
+ const scale = document . getElementById ( 'scale' ) . valueAsNumber ;
297
+ // Cap the size of the graph. It is hard to view if it is too large, and
298
+ // browsers may not render a large graph because it takes too much memory.
299
+ // 4096 is still ridiculously large, and probably won't render on mobile
300
+ // browsers, but should be ok for many desktop environments.
301
+ const graph_width = Math . min ( scale * DURATION , 4096 ) ;
302
+ const px_per_sec = Math . floor ( graph_width / DURATION ) ;
303
+ const canvas_width = Math . max ( graph_width + X_LINE + 30 , X_LINE + 250 ) ;
304
+ const canvas_height = graph_height + MARGIN + Y_LINE ;
305
+ let ctx = setup_canvas ( id , canvas_width , canvas_height ) ;
297
306
ctx . fillStyle = '#f7f7f7' ;
298
- ctx . fillRect ( 0 , 0 , width , height ) ;
307
+ ctx . fillRect ( 0 , 0 , canvas_width , canvas_height ) ;
299
308
300
309
ctx . lineWidth = 2 ;
301
310
ctx . font = '16px sans-serif' ;
@@ -309,19 +318,18 @@ function draw_graph_axes(id, graph_height) {
309
318
ctx . stroke ( ) ;
310
319
311
320
// Draw X tick marks.
312
- const tick_width = graph_width - 10 ;
313
- const [ step , top ] = split_ticks ( DURATION , tick_width / MIN_TICK_DIST ) ;
321
+ const [ step , top ] = split_ticks ( DURATION , graph_width / MIN_TICK_DIST ) ;
314
322
const num_ticks = top / step ;
315
- const tick_dist = tick_width / num_ticks ;
323
+ const tick_dist = graph_width / num_ticks ;
316
324
ctx . fillStyle = '#303030' ;
317
325
for ( let n = 0 ; n < num_ticks ; n ++ ) {
318
326
const x = X_LINE + ( ( n + 1 ) * tick_dist ) ;
319
327
ctx . beginPath ( ) ;
320
- ctx . moveTo ( x , height - Y_LINE ) ;
321
- ctx . lineTo ( x , height - Y_LINE + 5 ) ;
328
+ ctx . moveTo ( x , canvas_height - Y_LINE ) ;
329
+ ctx . lineTo ( x , canvas_height - Y_LINE + 5 ) ;
322
330
ctx . stroke ( ) ;
323
331
324
- ctx . fillText ( `${ ( n + 1 ) * step } s` , x , height - Y_LINE + 20 ) ;
332
+ ctx . fillText ( `${ ( n + 1 ) * step } s` , x , canvas_height - Y_LINE + 20 ) ;
325
333
}
326
334
327
335
// Draw vertical lines.
@@ -336,7 +344,7 @@ function draw_graph_axes(id, graph_height) {
336
344
}
337
345
ctx . strokeStyle = '#000' ;
338
346
ctx . setLineDash ( [ ] ) ;
339
- return { width , height , graph_width, graph_height, ctx} ;
347
+ return { canvas_width , canvas_height , graph_width, graph_height, ctx, px_per_sec } ;
340
348
}
341
349
342
350
function round_up ( n , step ) {
@@ -349,6 +357,7 @@ function round_up(n, step) {
349
357
350
358
// Determine the `(step, max_value)` of the number of ticks along an axis.
351
359
function split_ticks ( n , max_ticks ) {
360
+ max_ticks = Math . ceil ( max_ticks ) ;
352
361
if ( n <= max_ticks ) {
353
362
return [ 1 , n ] ;
354
363
} else if ( n <= max_ticks * 2 ) {
@@ -359,7 +368,12 @@ function split_ticks(n, max_ticks) {
359
368
return [ 5 , round_up ( n , 5 ) ] ;
360
369
} else {
361
370
let step = 10 ;
371
+ let count = 0 ;
362
372
while ( true ) {
373
+ if ( count > 100 ) {
374
+ throw Error ( "tick loop too long" ) ;
375
+ }
376
+ count += 1 ;
363
377
let top = round_up ( n , step ) ;
364
378
if ( top <= max_ticks * step ) {
365
379
return [ step , top ] ;
0 commit comments