-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfigure_download.js
More file actions
132 lines (116 loc) · 5.33 KB
/
Copy pathfigure_download.js
File metadata and controls
132 lines (116 loc) · 5.33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// Routes Plotly's modebar "Download plot as image" button through
// pywebview's native save dialog. Intercepts the camera button click in
// the document-level capture phase. Shows a format picker (SVG / PNG)
// before opening the native save dialog so the choice is always explicit.
(function () {
function figureName(gd) {
var title = gd && gd.layout && gd.layout.title;
if (title && typeof title === 'string') return title;
if (title && title.text) return title.text;
return 'figure';
}
function isDownloadButton(btn) {
if (btn.hasAttribute('data-pywv-download')) return true;
var title = (btn.getAttribute('data-title') || '').toLowerCase();
return title.indexOf('download') !== -1 ||
title.indexOf('save plot') !== -1 ||
title.indexOf('image') !== -1;
}
function showFormatPicker(svgUrl, pngUrl, name) {
var existing = document.getElementById('pywv-fmt-picker');
if (existing) existing.remove();
var overlay = document.createElement('div');
overlay.id = 'pywv-fmt-overlay';
overlay.style.cssText =
'position:fixed;inset:0;z-index:9998;background:rgba(0,0,0,0.3)';
var picker = document.createElement('div');
picker.id = 'pywv-fmt-picker';
picker.style.cssText =
'position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);' +
'background:#fff;border-radius:8px;padding:20px 24px;' +
'box-shadow:0 8px 32px rgba(0,0,0,0.2);z-index:9999;' +
'font-family:system-ui,sans-serif;text-align:center;min-width:220px';
picker.innerHTML =
'<p style="margin:0 0 16px;font-size:15px;font-weight:600;color:#212529">' +
'Save figure as…</p>' +
'<div style="display:flex;gap:10px;justify-content:center">' +
'<button id="pywv-save-svg" style="' +
'flex:1;padding:9px 0;cursor:pointer;border:1.5px solid #228be6;' +
'color:#228be6;background:#fff;border-radius:6px;font-size:14px;' +
'font-weight:600">SVG</button>' +
'<button id="pywv-save-png" style="' +
'flex:1;padding:9px 0;cursor:pointer;border:1.5px solid #868e96;' +
'color:#495057;background:#fff;border-radius:6px;font-size:14px">' +
'PNG</button>' +
'</div>';
function dismiss() {
overlay.remove();
picker.remove();
document.removeEventListener('keydown', onKey, true);
}
function onKey(e) {
if (e.key === 'Escape') dismiss();
}
overlay.addEventListener('click', dismiss);
document.addEventListener('keydown', onKey, true);
picker.querySelector('#pywv-save-svg').addEventListener('click', function (e) {
e.stopPropagation();
dismiss();
fetch('/save-figure', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({data_url: svgUrl, suggested_name: name, fmt: 'svg'})
});
});
picker.querySelector('#pywv-save-png').addEventListener('click', function (e) {
e.stopPropagation();
dismiss();
fetch('/save-figure', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({data_url: pngUrl, suggested_name: name, fmt: 'png'})
});
});
document.body.appendChild(overlay);
document.body.appendChild(picker);
}
function handle(e) {
var t = e.target;
if (!t || !t.closest) return;
var btn = t.closest('.modebar-btn');
if (!btn || !isDownloadButton(btn)) return;
var gd = btn.closest('.js-plotly-plot') || btn.closest('.plot-container');
if (!gd || !window.Plotly) return;
if (!window.DEERANALYSIS_PYWEBVIEW) {
window.alert('Figure download unavailable: not running in pywebview.');
return;
}
e.preventDefault();
e.stopImmediatePropagation();
var layout = gd._fullLayout || {};
var width = layout.width || 800;
var height = layout.height || 600;
var name = figureName(gd);
Promise.all([
window.Plotly.toImage(gd, {format: 'svg', width: width, height: height}),
window.Plotly.toImage(gd, {format: 'png', width: width, height: height, scale: 2})
]).then(function (urls) {
showFormatPicker(urls[0], urls[1], name);
}).catch(function (err) {
console.error('[figure_download] toImage failed:', err);
window.alert('Could not render figure: ' + (err && err.message ? err.message : err));
});
}
function patchDownloadTooltips(root) {
(root || document).querySelectorAll('.modebar-btn').forEach(function (btn) {
if (isDownloadButton(btn)) {
btn.setAttribute('data-title', 'Save as SVG or PNG');
btn.setAttribute('data-pywv-download', '1');
}
});
}
new MutationObserver(function () {
patchDownloadTooltips();
}).observe(document.body, {childList: true, subtree: true});
document.addEventListener('click', handle, true);
})();