@@ -112,6 +112,7 @@ mpl.figure.prototype._init_canvas = function () {
112112 var fig = this ;
113113
114114 var canvas_div = ( this . canvas_div = document . createElement ( 'div' ) ) ;
115+ canvas_div . setAttribute ( 'tabindex' , '0' ) ;
115116 canvas_div . setAttribute (
116117 'style' ,
117118 'border: 1px solid #ddd;' +
@@ -122,7 +123,8 @@ mpl.figure.prototype._init_canvas = function () {
122123 'outline: 0;' +
123124 'overflow: hidden;' +
124125 'position: relative;' +
125- 'resize: both;'
126+ 'resize: both;' +
127+ 'z-index: 2;'
126128 ) ;
127129
128130 function on_keyboard_event_closure ( name ) {
@@ -145,7 +147,13 @@ mpl.figure.prototype._init_canvas = function () {
145147
146148 var canvas = ( this . canvas = document . createElement ( 'canvas' ) ) ;
147149 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+ ) ;
149157
150158 this . context = canvas . getContext ( '2d' ) ;
151159
@@ -165,7 +173,12 @@ mpl.figure.prototype._init_canvas = function () {
165173 ) ) ;
166174 rubberband_canvas . setAttribute (
167175 '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;'
169182 ) ;
170183
171184 // Apply a ponyfill if ResizeObserver is not implemented by browser.
@@ -215,10 +228,10 @@ mpl.figure.prototype._init_canvas = function () {
215228 canvas . setAttribute ( 'width' , width * fig . ratio ) ;
216229 canvas . setAttribute ( 'height' , height * fig . ratio ) ;
217230 }
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' ;
222235
223236 rubberband_canvas . setAttribute ( 'width' , width ) ;
224237 rubberband_canvas . setAttribute ( 'height' , height ) ;
@@ -234,34 +247,53 @@ mpl.figure.prototype._init_canvas = function () {
234247 this . resizeObserverInstance . observe ( canvas_div ) ;
235248
236249 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+ }
240272 }
241273
242- rubberband_canvas . addEventListener (
274+ canvas_div . addEventListener (
243275 'mousedown' ,
244276 on_mouse_event_closure ( 'button_press' )
245277 ) ;
246- rubberband_canvas . addEventListener (
278+ canvas_div . addEventListener (
247279 'mouseup' ,
248280 on_mouse_event_closure ( 'button_release' )
249281 ) ;
250- rubberband_canvas . addEventListener (
282+ canvas_div . addEventListener (
251283 'dblclick' ,
252284 on_mouse_event_closure ( 'dblclick' )
253285 ) ;
254286 // Throttle sequential mouse events to 1 every 20ms.
255- rubberband_canvas . addEventListener (
287+ canvas_div . addEventListener (
256288 'mousemove' ,
257289 on_mouse_event_closure ( 'motion_notify' )
258290 ) ;
259291
260- rubberband_canvas . addEventListener (
292+ canvas_div . addEventListener (
261293 'mouseenter' ,
262294 on_mouse_event_closure ( 'figure_enter' )
263295 ) ;
264- rubberband_canvas . addEventListener (
296+ canvas_div . addEventListener (
265297 'mouseleave' ,
266298 on_mouse_event_closure ( 'figure_leave' )
267299 ) ;
@@ -289,7 +321,7 @@ mpl.figure.prototype._init_canvas = function () {
289321 } ;
290322
291323 // Disable right mouse context menu.
292- this . rubberband_canvas . addEventListener ( 'contextmenu' , function ( _e ) {
324+ canvas_div . addEventListener ( 'contextmenu' , function ( _e ) {
293325 event . preventDefault ( ) ;
294326 return false ;
295327 } ) ;
@@ -444,7 +476,7 @@ mpl.figure.prototype.handle_figure_label = function (fig, msg) {
444476} ;
445477
446478mpl . figure . prototype . handle_cursor = function ( fig , msg ) {
447- fig . rubberband_canvas . style . cursor = msg [ 'cursor' ] ;
479+ fig . canvas_div . style . cursor = msg [ 'cursor' ] ;
448480} ;
449481
450482mpl . figure . prototype . handle_message = function ( fig , msg ) {
@@ -556,30 +588,6 @@ mpl.figure.prototype._make_on_message_function = function (fig) {
556588 } ;
557589} ;
558590
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- } ;
583591
584592/*
585593 * return a copy of an object with only non-object keys
@@ -596,15 +604,15 @@ function simpleKeys(original) {
596604}
597605
598606mpl . figure . prototype . mouse_event = function ( event , name ) {
599- var canvas_pos = mpl . findpos ( event ) ;
600-
601607 if ( name === 'button_press' ) {
602608 this . canvas . focus ( ) ;
603609 this . canvas_div . focus ( ) ;
604610 }
605611
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 ;
608616
609617 this . send_message ( name , {
610618 x : x ,
@@ -614,11 +622,6 @@ mpl.figure.prototype.mouse_event = function (event, name) {
614622 guiEvent : simpleKeys ( event ) ,
615623 } ) ;
616624
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 ( ) ;
622625 return false ;
623626} ;
624627
0 commit comments