@@ -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,19 @@ pub(crate) const IMAGE_EXPORT_JS_SCRIPT: &str = r#"
3334 console.error('Plotly error:', err);
3435 callback('ERROR:' + err.toString());
3536 });
36- "# ;
37+ "#
38+ . to_string ( )
39+ }
40+
41+ pub ( crate ) fn pdf_export_js_script ( ) -> String {
42+ let timeout_ms = if cfg ! ( feature = "html2pdf_export_timeout" ) {
43+ 500
44+ } else {
45+ 250
46+ } ;
3747
38- pub ( crate ) const PDF_EXPORT_JS_SCRIPT : & str = r##"
48+ format ! (
49+ r##"
3950 const plot = arguments[0];
4051 const format = arguments[1];
4152 const width = arguments[2];
@@ -50,45 +61,42 @@ pub(crate) const PDF_EXPORT_JS_SCRIPT: &str = r##"
5061 const graph_div = document.getElementById('plotly-html-element');
5162
5263 // Check if html2pdf is available
53- if (typeof html2pdf === 'undefined') {
64+ if (typeof html2pdf === 'undefined') {{
5465 console.error('html2pdf library not available');
5566 callback('ERROR:html2pdf library not loaded');
5667 return;
57- }
58-
59- console.log('html2pdf library is available');
68+ }}
6069
61- let tempDiv = null;
62- let mmWidth, mmHeight;
70+ let tempDiv = null;
6371
64- Plotly.newPlot(graph_div, plot).then(function() {
65- console.log('Plotly plot created successfully');
72+ const cleanup = () => {{
73+ if (tempDiv) {{
74+ document.body.removeChild(tempDiv);
75+ }}
76+ }};
6677
67- // Force PNG format for PDF export to test if SVG is the issue
68- return Plotly.toImage(graph_div, {
69- format: 'png' ,
78+ Plotly.newPlot(graph_div, plot).then(function() {{
79+ return Plotly.toImage(graph_div, {{
80+ format: format ,
7081 width: width,
7182 height: height,
72- });
73- }).then(function(dataUrl) {
83+ }} );
84+ }} ).then(function(dataUrl) { {
7485 console.log('Plotly image generated successfully');
7586 console.log('SVG data URL length:', dataUrl.length);
7687 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);
88+ console.log('PDF dimensions (px):', width, 'x', height);
8389
8490 // Create a temporary div for the image
8591 tempDiv = document.createElement('div');
8692 tempDiv.style.width = width + 'px';
8793 tempDiv.style.height = height + 'px';
8894 tempDiv.style.background = 'white';
8995 tempDiv.style.position = 'fixed';
90- tempDiv.style.left = '0px';
9196 tempDiv.style.top = '0px';
97+ tempDiv.style.left = '0px';
98+ tempDiv.style.margin = '0px';
99+ tempDiv.style.padding = '0px';
92100 tempDiv.style.overflow = 'hidden';
93101 tempDiv.style.boxSizing = 'border-box';
94102 tempDiv.style.zIndex = '9999';
@@ -105,35 +113,30 @@ pub(crate) const PDF_EXPORT_JS_SCRIPT: &str = r##"
105113 img.style.objectFit = 'contain';
106114 img.style.maxWidth = '100%';
107115 img.style.maxHeight = '100%';
116+ img.style.verticalAlign = 'top';
117+ img.style.boxSizing = 'border-box';
108118 tempDiv.appendChild(img);
109119
110120 // Wait for the image to load
111- return new Promise(function(resolve) {
112- img.onload = function() {
121+ return new Promise(function(resolve) {{
122+ img.onload = function() {{
113123 console.log('SVG image loaded successfully');
114124 // 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- }
125+ // Brief delay to ensure image is fully rendered
126+ setTimeout(resolve, {timeout_ms});
127+ }};
128+ img.onerror = function() {{
129+ cleanup();
125130 callback('ERROR:Failed to load SVG image');
126- };
127- });
128- }).then(function() {
131+ }} ;
132+ }} );
133+ }} ).then(function() { {
129134 console.log('Starting PDF generation...');
130-
131- // Generate PDF with more robust configuration
132- return html2pdf().from(tempDiv).set({
135+ return html2pdf().from(tempDiv).set({{
133136 margin: 0,
134137 filename: 'plotly-plot.pdf',
135- image: { type: 'jpeg', quality: 1},
136- html2canvas: {
138+ image: {{ type: 'jpeg', quality: 1} },
139+ html2canvas: {{
137140 scale: scale,
138141 backgroundColor: '#fff',
139142 useCORS: true,
@@ -143,31 +146,27 @@ pub(crate) const PDF_EXPORT_JS_SCRIPT: &str = r##"
143146 height: height,
144147 imageTimeout: 15000,
145148 removeContainer: true,
146- foreignObjectRendering: true
147- },
148- jsPDF: {
149- unit: 'mm',
150- format: [mmWidth, mmHeight],
151- orientation: mmWidth > mmHeight ? 'landscape' : 'portrait',
149+ foreignObjectRendering: true,
150+ scrollY: 0,
151+ scrollX: 0
152+ }},
153+ jsPDF: {{
154+ unit: 'px',
155+ format: [width, height],
156+ orientation: width > height ? 'landscape' : 'portrait',
152157 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- }
158+ }}
159+ }}).toPdf().output('datauristring');
160+ }}).then(function(dataUri) {{
161+ cleanup();
161162 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- }
163+ }}).catch(function(err) {{
164+ cleanup();
168165 callback('ERROR:' + err.toString());
169- });
170- "## ;
166+ }});
167+ "##
168+ )
169+ }
171170
172171pub ( crate ) fn get_html_body ( offline : bool ) -> String {
173172 let offline_js = offline_js_sources ( ) ;
0 commit comments