@@ -12,7 +12,8 @@ use rand::{
1212 rng,
1313} ;
1414
15- pub ( crate ) const IMAGE_EXPORT_JS_SCRIPT : & str = r#"
15+ pub ( crate ) fn image_export_js_script ( ) -> String {
16+ r#"
1617 const plot = arguments[0];
1718 const format = arguments[1];
1819 const width = arguments[2];
@@ -33,9 +34,18 @@ pub(crate) const IMAGE_EXPORT_JS_SCRIPT: &str = r#"
3334 console.error('Plotly error:', err);
3435 callback('ERROR:' + err.toString());
3536 });
36- "# ;
37+ "# . to_string ( )
38+ }
39+
40+ pub ( crate ) fn pdf_export_js_script ( ) -> String {
41+ let timeout_ms = if cfg ! ( feature = "html2pdf_export_timeout" ) {
42+ 500
43+ } else {
44+ 250
45+ } ;
3746
38- pub ( crate ) const PDF_EXPORT_JS_SCRIPT : & str = r##"
47+ format ! (
48+ r##"
3949 const plot = arguments[0];
4050 const format = arguments[1];
4151 const width = arguments[2];
@@ -50,45 +60,42 @@ pub(crate) const PDF_EXPORT_JS_SCRIPT: &str = r##"
5060 const graph_div = document.getElementById('plotly-html-element');
5161
5262 // Check if html2pdf is available
53- if (typeof html2pdf === 'undefined') {
63+ if (typeof html2pdf === 'undefined') {{
5464 console.error('html2pdf library not available');
5565 callback('ERROR:html2pdf library not loaded');
5666 return;
57- }
58-
59- console.log('html2pdf library is available');
67+ }}
6068
61- let tempDiv = null;
62- let mmWidth, mmHeight;
69+ let tempDiv = null;
6370
64- Plotly.newPlot(graph_div, plot).then(function() {
65- console.log('Plotly plot created successfully');
71+ const cleanup = () => {{
72+ if (tempDiv) {{
73+ document.body.removeChild(tempDiv);
74+ }}
75+ }};
6676
67- // Force PNG format for PDF export to test if SVG is the issue
68- return Plotly.toImage(graph_div, {
69- format: 'png' ,
77+ Plotly.newPlot(graph_div, plot).then(function() {{
78+ return Plotly.toImage(graph_div, {{
79+ format: format ,
7080 width: width,
7181 height: height,
72- });
73- }).then(function(dataUrl) {
82+ }} );
83+ }} ).then(function(dataUrl) { {
7484 console.log('Plotly image generated successfully');
7585 console.log('SVG data URL length:', dataUrl.length);
7686 console.log('SVG data URL preview:', dataUrl.substring(0, 200) + '...');
77-
78- // Convert px to mm: 1px = 0.264583 mm
79- mmWidth = width * 0.264583;
80- mmHeight = height * 0.264583;
81-
82- console.log('PDF dimensions (mm):', mmWidth, 'x', mmHeight);
87+ console.log('PDF dimensions (px):', width, 'x', height);
8388
8489 // Create a temporary div for the image
8590 tempDiv = document.createElement('div');
8691 tempDiv.style.width = width + 'px';
8792 tempDiv.style.height = height + 'px';
8893 tempDiv.style.background = 'white';
8994 tempDiv.style.position = 'fixed';
90- tempDiv.style.left = '0px';
9195 tempDiv.style.top = '0px';
96+ tempDiv.style.left = '0px';
97+ tempDiv.style.margin = '0px';
98+ tempDiv.style.padding = '0px';
9299 tempDiv.style.overflow = 'hidden';
93100 tempDiv.style.boxSizing = 'border-box';
94101 tempDiv.style.zIndex = '9999';
@@ -105,35 +112,30 @@ pub(crate) const PDF_EXPORT_JS_SCRIPT: &str = r##"
105112 img.style.objectFit = 'contain';
106113 img.style.maxWidth = '100%';
107114 img.style.maxHeight = '100%';
115+ img.style.verticalAlign = 'top';
116+ img.style.boxSizing = 'border-box';
108117 tempDiv.appendChild(img);
109118
110119 // Wait for the image to load
111- return new Promise(function(resolve) {
112- img.onload = function() {
120+ return new Promise(function(resolve) {{
121+ img.onload = function() {{
113122 console.log('SVG image loaded successfully');
114123 // Additional delay to ensure image is fully rendered
115- setTimeout(function() {
116- console.log('SVG rendering delay completed');
117- resolve();
118- }, 500);
119- };
120- img.onerror = function() {
121- console.error('Failed to load SVG image');
122- if (tempDiv) {
123- document.body.removeChild(tempDiv);
124- }
124+ // Brief delay to ensure image is fully rendered
125+ setTimeout(resolve, {timeout_ms});
126+ }};
127+ img.onerror = function() {{
128+ cleanup();
125129 callback('ERROR:Failed to load SVG image');
126- };
127- });
128- }).then(function() {
130+ }} ;
131+ }} );
132+ }} ).then(function() { {
129133 console.log('Starting PDF generation...');
130-
131- // Generate PDF with more robust configuration
132- return html2pdf().from(tempDiv).set({
134+ return html2pdf().from(tempDiv).set({{
133135 margin: 0,
134136 filename: 'plotly-plot.pdf',
135- image: { type: 'jpeg', quality: 1},
136- html2canvas: {
137+ image: {{ type: 'jpeg', quality: 1} },
138+ html2canvas: {{
137139 scale: scale,
138140 backgroundColor: '#fff',
139141 useCORS: true,
@@ -143,31 +145,27 @@ pub(crate) const PDF_EXPORT_JS_SCRIPT: &str = r##"
143145 height: height,
144146 imageTimeout: 15000,
145147 removeContainer: true,
146- foreignObjectRendering: true
147- },
148- jsPDF: {
149- unit: 'mm',
150- format: [mmWidth, mmHeight],
151- orientation: mmWidth > mmHeight ? 'landscape' : 'portrait',
148+ foreignObjectRendering: true,
149+ scrollY: 0,
150+ scrollX: 0
151+ }},
152+ jsPDF: {{
153+ unit: 'px',
154+ format: [width, height],
155+ orientation: width > height ? 'landscape' : 'portrait',
152156 compress: true
153- }
154- }).toPdf().output('datauristring');
155- }).then(function(dataUri) {
156- console.log('PDF generation completed successfully');
157- // Clean up
158- if (tempDiv) {
159- document.body.removeChild(tempDiv);
160- }
157+ }}
158+ }}).toPdf().output('datauristring');
159+ }}).then(function(dataUri) {{
160+ cleanup();
161161 callback(dataUri);
162- }).catch(function(err) {
163- console.error('PDF generation error:', err);
164- // Clean up if tempDiv exists
165- if (tempDiv) {
166- document.body.removeChild(tempDiv);
167- }
162+ }}).catch(function(err) {{
163+ cleanup();
168164 callback('ERROR:' + err.toString());
169- });
170- "## ;
165+ }});
166+ "##
167+ )
168+ }
171169
172170pub ( crate ) fn get_html_body ( offline : bool ) -> String {
173171 let offline_js = offline_js_sources ( ) ;
0 commit comments