@@ -112,6 +112,7 @@ mpl.figure.prototype._init_canvas = function () {
112
112
var fig = this ;
113
113
114
114
var canvas_div = ( this . canvas_div = document . createElement ( 'div' ) ) ;
115
+ canvas_div . setAttribute ( 'tabindex' , '0' ) ;
115
116
canvas_div . setAttribute (
116
117
'style' ,
117
118
'border: 1px solid #ddd;' +
@@ -122,7 +123,8 @@ mpl.figure.prototype._init_canvas = function () {
122
123
'outline: 0;' +
123
124
'overflow: hidden;' +
124
125
'position: relative;' +
125
- 'resize: both;'
126
+ 'resize: both;' +
127
+ 'z-index: 2;'
126
128
) ;
127
129
128
130
function on_keyboard_event_closure ( name ) {
@@ -145,7 +147,13 @@ mpl.figure.prototype._init_canvas = function () {
145
147
146
148
var canvas = ( this . canvas = document . createElement ( 'canvas' ) ) ;
147
149
canvas . classList . add ( 'mpl-canvas' ) ;
148
- canvas . setAttribute ( 'style' , 'box-sizing: content-box;' ) ;
150
+ canvas . setAttribute (
151
+ 'style' ,
152
+ 'box-sizing: content-box;' +
153
+ 'pointer-events: none;' +
154
+ 'position: relative;' +
155
+ 'z-index: 0;'
156
+ ) ;
149
157
150
158
this . context = canvas . getContext ( '2d' ) ;
151
159
@@ -165,7 +173,12 @@ mpl.figure.prototype._init_canvas = function () {
165
173
) ) ;
166
174
rubberband_canvas . setAttribute (
167
175
'style' ,
168
- 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'
176
+ 'box-sizing: content-box;' +
177
+ 'left: 0;' +
178
+ 'pointer-events: none;' +
179
+ 'position: absolute;' +
180
+ 'top: 0;' +
181
+ 'z-index: 1;'
169
182
) ;
170
183
171
184
// Apply a ponyfill if ResizeObserver is not implemented by browser.
@@ -215,10 +228,10 @@ mpl.figure.prototype._init_canvas = function () {
215
228
canvas . setAttribute ( 'width' , width * fig . ratio ) ;
216
229
canvas . setAttribute ( 'height' , height * fig . ratio ) ;
217
230
}
218
- canvas . setAttribute (
219
- 'style' ,
220
- ' width: ' + width + 'px; height: ' + height + 'px;'
221
- ) ;
231
+ /* This rescales the canvas back to display pixels, so that it
232
+ * appears correct on HiDPI screens. */
233
+ canvas . style . width = width + 'px' ;
234
+ canvas . style . height = height + 'px' ;
222
235
223
236
rubberband_canvas . setAttribute ( 'width' , width ) ;
224
237
rubberband_canvas . setAttribute ( 'height' , height ) ;
@@ -234,34 +247,53 @@ mpl.figure.prototype._init_canvas = function () {
234
247
this . resizeObserverInstance . observe ( canvas_div ) ;
235
248
236
249
function on_mouse_event_closure ( name ) {
237
- return function ( event ) {
238
- return fig . mouse_event ( event , name ) ;
239
- } ;
250
+ /* User Agent sniffing is bad, but WebKit is busted:
251
+ * https://bugs.webkit.org/show_bug.cgi?id=144526
252
+ * https://bugs.webkit.org/show_bug.cgi?id=181818
253
+ * The worst that happens here is that they get an extra browser
254
+ * selection when dragging, if this check fails to catch them.
255
+ */
256
+ var UA = navigator . userAgent ;
257
+ var isWebKit = / A p p l e W e b K i t / . test ( UA ) && ! / C h r o m e / . test ( UA ) ;
258
+ if ( isWebKit ) {
259
+ return function ( event ) {
260
+ /* This prevents the web browser from automatically changing to
261
+ * the text insertion cursor when the button is pressed. We
262
+ * want to control all of the cursor setting manually through
263
+ * the 'cursor' event from matplotlib */
264
+ event . preventDefault ( )
265
+ return fig . mouse_event ( event , name ) ;
266
+ } ;
267
+ } else {
268
+ return function ( event ) {
269
+ return fig . mouse_event ( event , name ) ;
270
+ } ;
271
+ }
240
272
}
241
273
242
- rubberband_canvas . addEventListener (
274
+ canvas_div . addEventListener (
243
275
'mousedown' ,
244
276
on_mouse_event_closure ( 'button_press' )
245
277
) ;
246
- rubberband_canvas . addEventListener (
278
+ canvas_div . addEventListener (
247
279
'mouseup' ,
248
280
on_mouse_event_closure ( 'button_release' )
249
281
) ;
250
- rubberband_canvas . addEventListener (
282
+ canvas_div . addEventListener (
251
283
'dblclick' ,
252
284
on_mouse_event_closure ( 'dblclick' )
253
285
) ;
254
286
// Throttle sequential mouse events to 1 every 20ms.
255
- rubberband_canvas . addEventListener (
287
+ canvas_div . addEventListener (
256
288
'mousemove' ,
257
289
on_mouse_event_closure ( 'motion_notify' )
258
290
) ;
259
291
260
- rubberband_canvas . addEventListener (
292
+ canvas_div . addEventListener (
261
293
'mouseenter' ,
262
294
on_mouse_event_closure ( 'figure_enter' )
263
295
) ;
264
- rubberband_canvas . addEventListener (
296
+ canvas_div . addEventListener (
265
297
'mouseleave' ,
266
298
on_mouse_event_closure ( 'figure_leave' )
267
299
) ;
@@ -289,7 +321,7 @@ mpl.figure.prototype._init_canvas = function () {
289
321
} ;
290
322
291
323
// Disable right mouse context menu.
292
- this . rubberband_canvas . addEventListener ( 'contextmenu' , function ( _e ) {
324
+ canvas_div . addEventListener ( 'contextmenu' , function ( _e ) {
293
325
event . preventDefault ( ) ;
294
326
return false ;
295
327
} ) ;
@@ -444,7 +476,7 @@ mpl.figure.prototype.handle_figure_label = function (fig, msg) {
444
476
} ;
445
477
446
478
mpl . figure . prototype . handle_cursor = function ( fig , msg ) {
447
- fig . rubberband_canvas . style . cursor = msg [ 'cursor' ] ;
479
+ fig . canvas_div . style . cursor = msg [ 'cursor' ] ;
448
480
} ;
449
481
450
482
mpl . figure . prototype . handle_message = function ( fig , msg ) {
@@ -556,30 +588,6 @@ mpl.figure.prototype._make_on_message_function = function (fig) {
556
588
} ;
557
589
} ;
558
590
559
- // from https://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas
560
- mpl . findpos = function ( e ) {
561
- //this section is from http://www.quirksmode.org/js/events_properties.html
562
- var targ ;
563
- if ( ! e ) {
564
- e = window . event ;
565
- }
566
- if ( e . target ) {
567
- targ = e . target ;
568
- } else if ( e . srcElement ) {
569
- targ = e . srcElement ;
570
- }
571
- if ( targ . nodeType === 3 ) {
572
- // defeat Safari bug
573
- targ = targ . parentNode ;
574
- }
575
-
576
- // pageX,Y are the mouse positions relative to the document
577
- var boundingRect = targ . getBoundingClientRect ( ) ;
578
- var x = e . pageX - ( boundingRect . left + document . body . scrollLeft ) ;
579
- var y = e . pageY - ( boundingRect . top + document . body . scrollTop ) ;
580
-
581
- return { x : x , y : y } ;
582
- } ;
583
591
584
592
/*
585
593
* return a copy of an object with only non-object keys
@@ -596,15 +604,15 @@ function simpleKeys(original) {
596
604
}
597
605
598
606
mpl . figure . prototype . mouse_event = function ( event , name ) {
599
- var canvas_pos = mpl . findpos ( event ) ;
600
-
601
607
if ( name === 'button_press' ) {
602
608
this . canvas . focus ( ) ;
603
609
this . canvas_div . focus ( ) ;
604
610
}
605
611
606
- var x = canvas_pos . x * this . ratio ;
607
- var y = canvas_pos . y * this . ratio ;
612
+ // from https://stackoverflow.com/q/1114465
613
+ var boundingRect = this . canvas . getBoundingClientRect ( ) ;
614
+ var x = ( event . clientX - boundingRect . left ) * this . ratio ;
615
+ var y = ( event . clientY - boundingRect . top ) * this . ratio ;
608
616
609
617
this . send_message ( name , {
610
618
x : x ,
@@ -614,11 +622,6 @@ mpl.figure.prototype.mouse_event = function (event, name) {
614
622
guiEvent : simpleKeys ( event ) ,
615
623
} ) ;
616
624
617
- /* This prevents the web browser from automatically changing to
618
- * the text insertion cursor when the button is pressed. We want
619
- * to control all of the cursor setting manually through the
620
- * 'cursor' event from matplotlib */
621
- event . preventDefault ( ) ;
622
625
return false ;
623
626
} ;
624
627
0 commit comments