@@ -27,6 +27,10 @@ var MPLCanvasModel = widgets.DOMWidgetModel.extend({
27
27
_message : '' ,
28
28
_cursor : 'pointer' ,
29
29
_image_mode : 'full' ,
30
+ _rubberband_x : 0 ,
31
+ _rubberband_y : 0 ,
32
+ _rubberband_width : 0 ,
33
+ _rubberband_height : 0 ,
30
34
} ) ;
31
35
} ,
32
36
@@ -41,6 +45,8 @@ var MPLCanvasModel = widgets.DOMWidgetModel.extend({
41
45
this . offscreen_context . msBackingStorePixelRatio ||
42
46
this . offscreen_context . oBackingStorePixelRatio || 1 ;
43
47
48
+ this . requested_size = null ;
49
+ this . resize_requested = false ;
44
50
this . ratio = ( window . devicePixelRatio || 1 ) / backingStore ;
45
51
this . _init_image ( ) ;
46
52
@@ -84,18 +90,37 @@ var MPLCanvasModel = widgets.DOMWidgetModel.extend({
84
90
85
91
handle_resize : function ( msg ) {
86
92
var size = msg [ 'size' ] ;
93
+
87
94
this . resize_canvas ( size [ 0 ] , size [ 1 ] ) ;
95
+ this . offscreen_context . drawImage ( this . image , 0 , 0 ) ;
96
+
88
97
this . _for_each_view ( function ( view ) {
89
98
view . resize_canvas ( size [ 0 ] , size [ 1 ] ) ;
90
99
} ) ;
100
+
91
101
this . send_message ( 'refresh' ) ;
102
+
103
+ this . resize_requested = false ;
104
+ if ( this . requested_size !== null ) {
105
+ // Requesting saved resize
106
+ this . resize ( this . requested_size [ 0 ] , this . requested_size [ 1 ] ) ;
107
+ this . requested_size = null ;
108
+ }
109
+ } ,
110
+
111
+ resize : function ( width , height ) {
112
+ if ( this . resize_requested ) {
113
+ // If a resize was already requested, save the requested size for later
114
+ this . requested_size = [ width , height ] ;
115
+ } else {
116
+ this . resize_requested = true ;
117
+ this . send_message ( 'resize' , { 'width' : width , 'height' : height } ) ;
118
+ }
92
119
} ,
93
120
94
121
resize_canvas : function ( width , height ) {
95
122
this . offscreen_canvas . setAttribute ( 'width' , width * this . ratio ) ;
96
123
this . offscreen_canvas . setAttribute ( 'height' , height * this . ratio ) ;
97
- this . offscreen_canvas . style . width = width + 'px' ;
98
- this . offscreen_canvas . style . height = height + 'px' ;
99
124
} ,
100
125
101
126
handle_rubberband : function ( msg ) {
@@ -107,16 +132,15 @@ var MPLCanvasModel = widgets.DOMWidgetModel.extend({
107
132
y0 = Math . floor ( y0 ) + 0.5 ;
108
133
x1 = Math . floor ( x1 ) + 0.5 ;
109
134
y1 = Math . floor ( y1 ) + 0.5 ;
110
- var min_x = Math . min ( x0 , x1 ) ;
111
- var min_y = Math . min ( y0 , y1 ) ;
112
- var width = Math . abs ( x1 - x0 ) ;
113
- var height = Math . abs ( y1 - y0 ) ;
114
135
115
- this . _for_each_view ( function ( view ) {
116
- view . rubberband_context . clearRect (
117
- 0 , 0 , view . rubberband_canvas . width , view . rubberband_canvas . height ) ;
136
+ this . set ( '_rubberband_x' , Math . min ( x0 , x1 ) ) ;
137
+ this . set ( '_rubberband_y' , Math . min ( y0 , y1 ) ) ;
138
+ this . set ( '_rubberband_width' , Math . abs ( x1 - x0 ) ) ;
139
+ this . set ( '_rubberband_height' , Math . abs ( y1 - y0 ) ) ;
140
+ this . save_changes ( ) ;
118
141
119
- view . rubberband_context . strokeRect ( min_x , min_y , width , height ) ;
142
+ this . _for_each_view ( function ( view ) {
143
+ view . update_canvas ( ) ;
120
144
} ) ;
121
145
} ,
122
146
@@ -177,7 +201,7 @@ var MPLCanvasModel = widgets.DOMWidgetModel.extend({
177
201
that . offscreen_context . drawImage ( that . image , 0 , 0 ) ;
178
202
179
203
that . _for_each_view ( function ( view ) {
180
- view . context . drawImage ( that . offscreen_canvas , 0 , 0 ) ;
204
+ view . update_canvas ( ) ;
181
205
} ) ;
182
206
} ;
183
207
} ,
@@ -189,6 +213,10 @@ var MPLCanvasModel = widgets.DOMWidgetModel.extend({
189
213
} ) ;
190
214
}
191
215
} ,
216
+
217
+ remove : function ( ) {
218
+ this . send_message ( 'closing' ) ;
219
+ }
192
220
} , {
193
221
serializers : _ . extend ( {
194
222
toolbar : { deserialize : widgets . unpack_models }
@@ -199,17 +227,23 @@ var MPLCanvasView = widgets.DOMWidgetView.extend({
199
227
render : function ( ) {
200
228
this . canvas = undefined ;
201
229
this . context = undefined ;
202
- this . rubberband_canvas = undefined ;
203
- this . rubberband_context = undefined ;
230
+ this . top_canvas = undefined ;
231
+ this . top_context = undefined ;
232
+ this . resizing = false ;
233
+ this . resize_handle_size = 20 ;
204
234
205
235
this . figure = document . createElement ( 'div' ) ;
206
- this . figure . addEventListener ( 'remove' , this . close . bind ( this ) ) ;
207
236
this . figure . classList = 'jupyter-matplotlib-figure jupyter-widgets widget-container widget-box widget-vbox' ;
208
237
209
238
this . _init_header ( ) ;
210
239
this . _init_canvas ( ) ;
211
240
this . _init_footer ( ) ;
212
241
242
+ this . _resize_event = this . resize_event . bind ( this ) ;
243
+ this . _stop_resize_event = this . stop_resize_event . bind ( this ) ;
244
+ window . addEventListener ( 'mousemove' , this . _resize_event ) ;
245
+ window . addEventListener ( 'mouseup' , this . _stop_resize_event ) ;
246
+
213
247
this . waiting = false ;
214
248
215
249
var that = this ;
@@ -320,41 +354,82 @@ var MPLCanvasView = widgets.DOMWidgetView.extend({
320
354
321
355
this . context = canvas . getContext ( '2d' ) ;
322
356
323
- var rubberband_canvas = this . rubberband_canvas = document . createElement ( 'canvas' ) ;
324
- rubberband_canvas . style . display = 'block' ;
325
- rubberband_canvas . style . position = 'absolute' ;
326
- rubberband_canvas . style . left = 0 ;
327
- rubberband_canvas . style . top = 0 ;
328
- rubberband_canvas . style . zIndex = 1 ;
357
+ var top_canvas = this . top_canvas = document . createElement ( 'canvas' ) ;
358
+ top_canvas . style . display = 'block' ;
359
+ top_canvas . style . position = 'absolute' ;
360
+ top_canvas . style . left = 0 ;
361
+ top_canvas . style . top = 0 ;
362
+ top_canvas . style . zIndex = 1 ;
329
363
330
- rubberband_canvas . addEventListener ( 'mousedown' , this . mouse_event ( 'button_press' ) ) ;
331
- rubberband_canvas . addEventListener ( 'mouseup' , this . mouse_event ( 'button_release' ) ) ;
332
- rubberband_canvas . addEventListener ( 'mousemove' , this . mouse_event ( 'motion_notify' ) ) ;
364
+ top_canvas . addEventListener ( 'mousedown' , this . mouse_event ( 'button_press' ) ) ;
365
+ top_canvas . addEventListener ( 'mouseup' , this . mouse_event ( 'button_release' ) ) ;
366
+ top_canvas . addEventListener ( 'mousemove' , this . mouse_event ( 'motion_notify' ) ) ;
333
367
334
- rubberband_canvas . addEventListener ( 'mouseenter' , this . mouse_event ( 'figure_enter' ) ) ;
335
- rubberband_canvas . addEventListener ( 'mouseleave' , this . mouse_event ( 'figure_leave' ) ) ;
368
+ top_canvas . addEventListener ( 'mouseenter' , this . mouse_event ( 'figure_enter' ) ) ;
369
+ top_canvas . addEventListener ( 'mouseleave' , this . mouse_event ( 'figure_leave' ) ) ;
336
370
337
- rubberband_canvas . addEventListener ( 'wheel' , this . mouse_event ( 'scroll' ) ) ;
371
+ top_canvas . addEventListener ( 'wheel' , this . mouse_event ( 'scroll' ) ) ;
338
372
339
373
canvas_div . appendChild ( canvas ) ;
340
- canvas_div . appendChild ( rubberband_canvas ) ;
374
+ canvas_div . appendChild ( top_canvas ) ;
341
375
342
- this . rubberband_context = rubberband_canvas . getContext ( '2d' ) ;
343
- this . rubberband_context . strokeStyle = '#000000 ' ;
376
+ this . top_context = top_canvas . getContext ( '2d' ) ;
377
+ this . top_context . strokeStyle = 'rgba(0, 0, 0, 255) ' ;
344
378
345
379
// Disable right mouse context menu.
346
- this . rubberband_canvas . addEventListener ( 'contextmenu' , function ( e ) {
380
+ this . top_canvas . addEventListener ( 'contextmenu' , function ( e ) {
347
381
event . preventDefault ( ) ;
348
382
event . stopPropagation ( ) ;
349
383
return false ;
350
384
} ) ;
351
385
352
386
this . resize_canvas ( this . model . get ( '_width' ) , this . model . get ( '_height' ) ) ;
387
+ this . update_canvas ( ) ;
388
+ } ,
389
+
390
+ update_canvas : function ( ) {
391
+ if ( this . canvas . width == 0 || this . canvas . height == 0 ) {
392
+ return ;
393
+ }
394
+
395
+ this . context . clearRect ( 0 , 0 , this . canvas . width , this . canvas . height ) ;
353
396
this . context . drawImage ( this . model . offscreen_canvas , 0 , 0 ) ;
397
+
398
+ this . top_context . clearRect ( 0 , 0 , this . top_canvas . width , this . top_canvas . height ) ;
399
+
400
+ // Draw rubberband
401
+ if ( this . model . get ( '_rubberband_width' ) != 0 && this . model . get ( '_rubberband_height' ) != 0 ) {
402
+ this . top_context . strokeRect (
403
+ this . model . get ( '_rubberband_x' ) , this . model . get ( '_rubberband_y' ) ,
404
+ this . model . get ( '_rubberband_width' ) , this . model . get ( '_rubberband_height' )
405
+ ) ;
406
+ }
407
+
408
+ // Draw resize handle
409
+ this . top_context . save ( ) ;
410
+
411
+ var gradient = this . top_context . createLinearGradient (
412
+ this . top_canvas . width - this . resize_handle_size / 3 , this . top_canvas . height - this . resize_handle_size / 3 ,
413
+ this . top_canvas . width - this . resize_handle_size / 4 , this . top_canvas . height - this . resize_handle_size / 4
414
+ ) ;
415
+ gradient . addColorStop ( 0 , 'rgba(0, 0, 0, 0)' ) ;
416
+ gradient . addColorStop ( 1 , 'rgba(0, 0, 0, 255)' ) ;
417
+
418
+ this . top_context . fillStyle = gradient ;
419
+
420
+ this . top_context . globalAlpha = 0.3 ;
421
+ this . top_context . beginPath ( ) ;
422
+ this . top_context . moveTo ( this . top_canvas . width , this . top_canvas . height ) ;
423
+ this . top_context . lineTo ( this . top_canvas . width , this . top_canvas . height - this . resize_handle_size ) ;
424
+ this . top_context . lineTo ( this . top_canvas . width - this . resize_handle_size , this . top_canvas . height ) ;
425
+ this . top_context . closePath ( ) ;
426
+ this . top_context . fill ( ) ;
427
+
428
+ this . top_context . restore ( ) ;
354
429
} ,
355
430
356
431
_update_cursor : function ( ) {
357
- this . rubberband_canvas . style . cursor = this . model . get ( '_cursor' ) ;
432
+ this . top_canvas . style . cursor = this . model . get ( '_cursor' ) ;
358
433
} ,
359
434
360
435
_init_footer : function ( ) {
@@ -376,11 +451,13 @@ var MPLCanvasView = widgets.DOMWidgetView.extend({
376
451
this . canvas . style . width = width + 'px' ;
377
452
this . canvas . style . height = height + 'px' ;
378
453
379
- this . rubberband_canvas . setAttribute ( 'width' , width ) ;
380
- this . rubberband_canvas . setAttribute ( 'height' , height ) ;
454
+ this . top_canvas . setAttribute ( 'width' , width ) ;
455
+ this . top_canvas . setAttribute ( 'height' , height ) ;
381
456
382
457
this . canvas_div . style . width = width + 'px' ;
383
458
this . canvas_div . style . height = height + 'px' ;
459
+
460
+ this . update_canvas ( ) ;
384
461
} ,
385
462
386
463
mouse_event : function ( name ) {
@@ -399,8 +476,25 @@ var MPLCanvasView = widgets.DOMWidgetView.extend({
399
476
}
400
477
401
478
if ( name === 'button_press' ) {
402
- that . canvas . focus ( ) ;
403
- that . canvas_div . focus ( ) ;
479
+ // If clicking on the resize handle
480
+ if ( canvas_pos . x >= that . top_canvas . width - that . resize_handle_size &&
481
+ canvas_pos . y >= that . top_canvas . height - that . resize_handle_size ) {
482
+ that . resizing = true ;
483
+ return ;
484
+ } else {
485
+ that . canvas . focus ( ) ;
486
+ that . canvas_div . focus ( ) ;
487
+ }
488
+ }
489
+
490
+ if ( name === 'motion_notify' ) {
491
+ // If the mouse is on the handle, change the cursor style
492
+ if ( canvas_pos . x >= that . top_canvas . width - that . resize_handle_size &&
493
+ canvas_pos . y >= that . top_canvas . height - that . resize_handle_size ) {
494
+ that . top_canvas . style . cursor = 'nw-resize' ;
495
+ } else {
496
+ that . top_canvas . style . cursor = that . model . get ( '_cursor' ) ;
497
+ }
404
498
}
405
499
406
500
// Rate-limit the position text updates so that we don't overwhelm the
@@ -421,10 +515,21 @@ var MPLCanvasView = widgets.DOMWidgetView.extend({
421
515
* to control all of the cursor setting manually through the
422
516
* 'cursor' event from matplotlib */
423
517
event . preventDefault ( ) ;
424
- return false ;
425
518
} ;
426
519
} ,
427
520
521
+ resize_event : function ( event ) {
522
+ if ( this . resizing ) {
523
+ var new_size = utils . get_mouse_position ( event , this . top_canvas ) ;
524
+
525
+ this . model . resize ( new_size . x , new_size . y ) ;
526
+ }
527
+ } ,
528
+
529
+ stop_resize_event : function ( ) {
530
+ this . resizing = false ;
531
+ } ,
532
+
428
533
key_event : function ( name ) {
429
534
var that = this ;
430
535
return function ( event ) {
@@ -458,9 +563,9 @@ var MPLCanvasView = widgets.DOMWidgetView.extend({
458
563
} ;
459
564
} ,
460
565
461
- close : function ( ) {
462
- this . send_message ( 'closing' ) ;
463
- this . trigger ( 'close' ) ;
566
+ remove : function ( ) {
567
+ window . removeEventListener ( 'mousemove' , this . _resize_event ) ;
568
+ window . removeEventListener ( 'mouseup' , this . _stop_resize_event ) ;
464
569
}
465
570
} ) ;
466
571
0 commit comments