@@ -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,25 @@ 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+ let foreign_object_rendering = if cfg ! ( feature = "chromedriver" ) {
49+ "true"
50+ } else {
51+ "false"
52+ } ;
53+
54+ format ! (
55+ r##"
3956 const plot = arguments[0];
4057 const format = arguments[1];
4158 const width = arguments[2];
@@ -50,45 +67,42 @@ pub(crate) const PDF_EXPORT_JS_SCRIPT: &str = r##"
5067 const graph_div = document.getElementById('plotly-html-element');
5168
5269 // Check if html2pdf is available
53- if (typeof html2pdf === 'undefined') {
70+ if (typeof html2pdf === 'undefined') {{
5471 console.error('html2pdf library not available');
5572 callback('ERROR:html2pdf library not loaded');
5673 return;
57- }
58-
59- console.log('html2pdf library is available');
74+ }}
6075
61- let tempDiv = null;
62- let mmWidth, mmHeight;
76+ let tempDiv = null;
6377
64- Plotly.newPlot(graph_div, plot).then(function() {
65- console.log('Plotly plot created successfully');
78+ const cleanup = () => {{
79+ if (tempDiv) {{
80+ document.body.removeChild(tempDiv);
81+ }}
82+ }};
6683
67- // Force PNG format for PDF export to test if SVG is the issue
68- return Plotly.toImage(graph_div, {
69- format: 'png' ,
84+ Plotly.newPlot(graph_div, plot).then(function() {{
85+ return Plotly.toImage(graph_div, {{
86+ format: format ,
7087 width: width,
7188 height: height,
72- });
73- }).then(function(dataUrl) {
89+ }} );
90+ }} ).then(function(dataUrl) { {
7491 console.log('Plotly image generated successfully');
7592 console.log('SVG data URL length:', dataUrl.length);
7693 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);
94+ console.log('PDF dimensions (px):', width, 'x', height);
8395
8496 // Create a temporary div for the image
8597 tempDiv = document.createElement('div');
8698 tempDiv.style.width = width + 'px';
8799 tempDiv.style.height = height + 'px';
88100 tempDiv.style.background = 'white';
89101 tempDiv.style.position = 'fixed';
90- tempDiv.style.left = '0px';
91102 tempDiv.style.top = '0px';
103+ tempDiv.style.left = '0px';
104+ tempDiv.style.margin = '0px';
105+ tempDiv.style.padding = '0px';
92106 tempDiv.style.overflow = 'hidden';
93107 tempDiv.style.boxSizing = 'border-box';
94108 tempDiv.style.zIndex = '9999';
@@ -105,35 +119,30 @@ pub(crate) const PDF_EXPORT_JS_SCRIPT: &str = r##"
105119 img.style.objectFit = 'contain';
106120 img.style.maxWidth = '100%';
107121 img.style.maxHeight = '100%';
122+ img.style.verticalAlign = 'top';
123+ img.style.boxSizing = 'border-box';
108124 tempDiv.appendChild(img);
109125
110126 // Wait for the image to load
111- return new Promise(function(resolve) {
112- img.onload = function() {
127+ return new Promise(function(resolve) {{
128+ img.onload = function() {{
113129 console.log('SVG image loaded successfully');
114130 // 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- }
131+ // Brief delay to ensure image is fully rendered
132+ setTimeout(resolve, {timeout_ms});
133+ }};
134+ img.onerror = function() {{
135+ cleanup();
125136 callback('ERROR:Failed to load SVG image');
126- };
127- });
128- }).then(function() {
137+ }} ;
138+ }} );
139+ }} ).then(function() { {
129140 console.log('Starting PDF generation...');
130-
131- // Generate PDF with more robust configuration
132- return html2pdf().from(tempDiv).set({
141+ return html2pdf().from(tempDiv).set({{
133142 margin: 0,
134143 filename: 'plotly-plot.pdf',
135- image: { type: 'jpeg', quality: 1},
136- html2canvas: {
144+ image: {{ type: 'jpeg', quality: 1} },
145+ html2canvas: {{
137146 scale: scale,
138147 backgroundColor: '#fff',
139148 useCORS: true,
@@ -143,31 +152,27 @@ pub(crate) const PDF_EXPORT_JS_SCRIPT: &str = r##"
143152 height: height,
144153 imageTimeout: 15000,
145154 removeContainer: true,
146- foreignObjectRendering: true
147- },
148- jsPDF: {
149- unit: 'mm',
150- format: [mmWidth, mmHeight],
151- orientation: mmWidth > mmHeight ? 'landscape' : 'portrait',
155+ foreignObjectRendering: {foreign_object_rendering},
156+ scrollY: 0,
157+ scrollX: 0
158+ }},
159+ jsPDF: {{
160+ unit: 'px',
161+ format: [width, height],
162+ orientation: width > height ? 'landscape' : 'portrait',
152163 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- }
164+ }}
165+ }}).toPdf().output('datauristring');
166+ }}).then(function(dataUri) {{
167+ cleanup();
161168 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- }
169+ }}).catch(function(err) {{
170+ cleanup();
168171 callback('ERROR:' + err.toString());
169- });
170- "## ;
172+ }});
173+ "##
174+ )
175+ }
171176
172177pub ( crate ) fn get_html_body ( offline : bool ) -> String {
173178 let offline_js = offline_js_sources ( ) ;
0 commit comments