Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit cb77e0d

Browse files
committed
Add a ponyfill for ResizeObserver on older browsers.
This fixes nbagg on Firefox ESR. Fixes #18481.
1 parent 7d0cb13 commit cb77e0d

File tree

4 files changed

+93
-2
lines changed

4 files changed

+93
-2
lines changed

lib/matplotlib/backends/web_backend/js/mpl.js

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,17 @@ mpl.figure.prototype._init_canvas = function () {
169169
'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'
170170
);
171171

172-
var resizeObserver = new ResizeObserver(function (entries) {
172+
// Apply a ponyfill if ResizeObserver is not implemented by browser.
173+
if (this.ResizeObserver === undefined) {
174+
if (window.ResizeObserver !== undefined) {
175+
this.ResizeObserver = window.ResizeObserver;
176+
} else {
177+
var obs = _JSXTOOLS_RESIZE_OBSERVER({});
178+
this.ResizeObserver = obs.ResizeObserver;
179+
}
180+
}
181+
182+
this.resizeObserverInstance = new this.ResizeObserver(function (entries) {
173183
var nentries = entries.length;
174184
for (var i = 0; i < nentries; i++) {
175185
var entry = entries[i];
@@ -222,7 +232,7 @@ mpl.figure.prototype._init_canvas = function () {
222232
}
223233
}
224234
});
225-
resizeObserver.observe(canvas_div);
235+
this.resizeObserverInstance.observe(canvas_div);
226236

227237
function on_mouse_event_closure(name) {
228238
return function (event) {
@@ -673,3 +683,7 @@ mpl.figure.prototype.toolbar_button_onclick = function (name) {
673683
mpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {
674684
this.message.textContent = tooltip;
675685
};
686+
687+
///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////
688+
// prettier-ignore
689+
var _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError("Constructor requires 'new' operator");i.set(this,e)}function h(){throw new TypeError("Function is not a constructor")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A};

lib/matplotlib/backends/web_backend/js/nbagg_mpl.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ mpl.figure.prototype.handle_close = function (fig, msg) {
6161
'cleared',
6262
fig._remove_fig_handler
6363
);
64+
fig.resizeObserverInstance.unobserve(fig.canvas_div);
6465

6566
// Update the output cell to use the data from the current canvas.
6667
fig.push_to_output();

lib/matplotlib/backends/web_backend/package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,8 @@
1111
"lint:check": "npm run prettier:check && npm run eslint:check",
1212
"prettier": "prettier --write \"**/*{.ts,.tsx,.js,.jsx,.css,.json}\"",
1313
"prettier:check": "prettier --check \"**/*{.ts,.tsx,.js,.jsx,.css,.json}\""
14+
},
15+
"dependencies": {
16+
"@jsxtools/resize-observer": "^1.0.4"
1417
}
1518
}

tools/embed_js.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
"""
2+
Script to embed JavaScript dependencies in mpl.js.
3+
"""
4+
5+
from pathlib import Path
6+
import re
7+
import subprocess
8+
import sys
9+
10+
11+
# The list of packages to embed, in some form that `npm install` can use.
12+
JAVASCRIPT_PACKAGES = [
13+
# Polyfill/ponyfill for ResizeObserver.
14+
'@jsxtools/resize-observer',
15+
]
16+
# This is the magic line that must exist in mpl.js, after which the embedded
17+
# JavaScript will be appended.
18+
MPLJS_MAGIC_HEADER = (
19+
"///////////////// REMAINING CONTENT GENERATED BY embed_js.py "
20+
"/////////////////\n")
21+
22+
23+
def safe_name(name):
24+
"""
25+
Make *name* safe to use as a JavaScript variable name.
26+
"""
27+
return '_'.join(re.split(r'[@/-]', name)).upper()
28+
29+
30+
def gen_embedded_lines(web_backend_path):
31+
for pkg in JAVASCRIPT_PACKAGES:
32+
index = web_backend_path / 'node_modules' / pkg / 'index.js'
33+
if not index.exists():
34+
# Exact version should already be saved in package.json, so we use
35+
# --no-save here.
36+
try:
37+
subprocess.run(['npm', 'install', '--no-save', pkg],
38+
cwd=web_backend_path)
39+
except FileNotFoundError as err:
40+
raise ValueError(
41+
f'npm must be installed to fetch {pkg}') from err
42+
name = safe_name(pkg)
43+
print('Embedding', index, 'as', name)
44+
yield '// prettier-ignore\n'
45+
for line in index.read_text().splitlines(keepends=True):
46+
line = line.replace('module.exports=function',
47+
f'var {name}=function')
48+
yield line
49+
50+
51+
def build_mpljs(web_backend_path):
52+
mpljs_path = web_backend_path / "js/mpl.js"
53+
mpljs_orig = mpljs_path.read_text().splitlines(keepends=True)
54+
try:
55+
mpljs_orig = mpljs_orig[:mpljs_orig.index(MPLJS_MAGIC_HEADER) + 1]
56+
except IndexError as err:
57+
raise ValueError(
58+
f'The mpl.js file *must* have the exact line: {MPLJS_MAGIC_HEADER}'
59+
) from err
60+
61+
with mpljs_path.open('w') as mpljs:
62+
mpljs.writelines(mpljs_orig)
63+
mpljs.writelines(gen_embedded_lines(web_backend_path))
64+
65+
66+
if __name__ == '__main__':
67+
# Write the mpl.js file.
68+
if len(sys.argv) > 1:
69+
web_backend_path = Path(sys.argv[1])
70+
else:
71+
web_backend_path = (Path(__file__).parent.parent /
72+
"lib/matplotlib/backends/web_backend")
73+
build_mpljs(web_backend_path)

0 commit comments

Comments
 (0)