I have an external html file that I would like to print as a PDF but I'm having trouble getting the example code to work as intended and I'm obviously missing something trivial when implementing it.
This is my code so far:
function savePDF(data) {
var parser = new DOMParser();
var htmlDoc = parser.parseFromString(data, 'text/html');
let pdf = new jsPDF('p','pt','a4');
pdf.addHTML(
htmlDoc.body, // HTML DOM element.
);
pdf.save("test.pdf");
}
Where data is a string containing the html of the external webpage I wish to convert to a pdf.
Chrome is generating a TypeError: Cannot read property 'innerWidth' of null
This for example works perfectly (using fromHTML instead of addHTML) but the css/styling is missing:
function savePDF(data) {
var parser = new DOMParser();
var htmlDoc = parser.parseFromString(data, 'text/html');
let pdf = new jsPDF('p','pt','a4');
pdf.fromHTML(htmlDoc.body.innerHTML, 0, 0, {},
function(){pdf.save('test.pdf');
});
}
Sample html that I'm using:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>PDF Test</title>
</head>
<body>
<div id="capture" style="padding: 10px; background: #f5da55">
<h4 style="color: #000; ">Hello world!</h4>
</div>
</body>
</html>
As the documentation says the addHtml method is deprecated ( http://raw.githack.com/MrRio/jsPDF/master/docs/global.html#addHTML), so i played a bit with your example and if you updated your code like this it works. You still have to work a bit to fix the width of div in the pdf.
<!DOCTYPE html>
<html>
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.5.3/jspdf.debug.js" integrity="sha384-NaWTHo/8YCBYJ59830LTz/P4aQZK1sS0SneOgAvhsIl3zBu8r9RevNg5lHCHAuQ/" crossorigin="anonymous"></script>
<script src="https://html2canvas.hertzen.com/dist/html2canvas.js"></script>
</head>
<body>
<div id="capture" style="padding: 10px; background: #f5da55;">
<h4 style="color: #000; ">Hello world!</h4>
</div>
</body>
<script type="text/javascript">
function savePDF(data) {
let pdf = new jsPDF('p','pt','a4');
pdf.html(data, {
callback: function (doc) {
doc.save("test.pdf");
}
});
}
savePDF(document.body.innerHTML)
</script>
</html>
Related
I would like the Google Sheets sidebar to open with a color set in cell Sheet1:A1. My current code works (I suspect there may be a more efficient way to do this), but the CSS steps through each theme in root until it lands on the correct theme.
For example, if A1 is set to 'Orange', calling the sidebar will load with the body first as 'Default' and then switch to 'Orange'. Is there a way to load the correct root theme on the initial page load instead of stepping through the themes in root?
Google Apps Script
function onOpen(e) {
SpreadsheetApp.getUi()
.createMenu("Sidebar")
.addItem("Show sidebar", "showSidebar")
.addToUi();
}
function showSidebar() {
var htmlWidget = HtmlService.createTemplateFromFile('Test').evaluate()
.setTitle("Theme Test");
SpreadsheetApp.getUi().showSidebar(htmlWidget);
}
function getColorTheme() {
colorTheme = SpreadsheetApp.getActive().getRange("Sheet1!A1").getDisplayValue();
return colorTheme;
}
HTML for Sidebar
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<style>
:root,
:root.Default {
--bg-color: #45818e;
}
:root.Orange {
--bg-color: #e69138;
}
body {
background-color: var(--bg-color);
}
</style>
<script>
function setTheme(colorTheme) {
document.documentElement.className = colorTheme;
}
</script>
</head>
<body>
<p>Hello world</p>
<script>
google.script.run.withSuccessHandler(setTheme).getColorTheme();
</script>
</body>
</html>
From your situation, how about the following patterns?
Pattern 1:
In this pattern, HTML is modified using Google Apps Script and the modified HTML is used with HtmlService.createHtmlOutput().
Google Apps Script side:
function showSidebar() {
var colorTheme = SpreadsheetApp.getActive().getRange("Sheet1!A1").getDisplayValue();
var html = HtmlService.createHtmlOutputFromFile('Test').getContent().replace("{{colorTheme}}", colorTheme);
var htmlWidget = HtmlService.createHtmlOutput(html).setTitle("Theme Test");
SpreadsheetApp.getUi().showSidebar(htmlWidget);
}
HTML side:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<style>
:root,
:root.Default {
--bg-color: #45818e;
}
:root.Orange {
--bg-color: #e69138;
}
body {
background-color: var(--bg-color);
}
</style>
<script>
document.documentElement.className = "{{colorTheme}}";
</script>
</head>
<body>
<p>Hello world</p>
</body>
</html>
Pattern 2:
In this pattern, HTML is modified using HTMl template and the modified HTML is used with HtmlService.createHtmlOutput().
Google Apps Script side:
function ashowSidebar() {
var colorTheme = SpreadsheetApp.getActive().getRange("Sheet1!A1").getDisplayValue();
var htmlWidget = HtmlService.createTemplateFromFile('Test')
htmlWidget.colorTheme = colorTheme;
SpreadsheetApp.getUi().showSidebar(htmlWidget.evaluate().setTitle("Theme Test"));
}
HTML side:
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<style>
:root,
:root.Default {
--bg-color: #45818e;
}
:root.Orange {
--bg-color: #e69138;
}
body {
background-color: var(--bg-color);
}
</style>
<script>
document.documentElement.className = "<?= colorTheme ?>";
</script>
</head>
<body>
<p>Hello world</p>
</body>
</html>
Note:
From the recent benchmark of the HTML template, it seems that in the current stage, the process cost of evaluate() is a bit high. Ref So, I proposed the above 2 patterns with and without an HTML template.
In this case, <html class="{{colorTheme}}"> and <html class="<?= colorTheme ?>"> might be able to be used instead of Javascript. But, I'm not sure about your actual situation. So, in this answer, Javascript is used as a sample modification.
References:
createHtmlOutput(html)
HTML Service: Templated HTML
createTemplateFromFile(filename)
here is my code while i download pdf images attributes of html are missing.
suppose in cases like generating invoices we should print tables containing details along with logo.
but images are not displaying in downloaded pdf using this code.Provide me with possible resolution and reason for this.thanks in advance
$(document).on('click', '#btn', function() {
let pdf = new jsPDF();
let section = $('body');
let page = function() {
pdf.save('pagename.pdf');
};
pdf.addHTML(section, page);
})
html,
body {
overflow-x: hidden;
}
#btn {
padding: 10px;
border: 0px;
margin: 50px;
cursor: pointer;
}
<!DOCTYPE html>
<html>
<head>
<title>HTML with Image</title>
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
<style type="text/css">
</style>
</head>
<body>
<button id="btn">Convert to PDF</button>
<div id="text">
<h2>HTML Page with Image to PDF</h2>
<img src="http://photojournal.jpl.nasa.gov/jpeg/PIA17555.jpg" width="300px">
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/0.4.1/html2canvas.js">
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.0.272/jspdf.debug.js"></script>
<script src="custom.js"></script>
<script type="text/javascript">
</script>
</body>
</html>
all the html elements are working fine except images . kindly help me with resolving this.
jsPdf does not support adding images the way you are trying to add them, because addtHtml function uses the html2canvas module, to convert your Html to canvas, so jsPdf can render it into pdf. Please check this link below.
https://weihui-guo.medium.com/save-html-page-and-online-images-as-a-pdf-attachment-with-one-click-from-client-side-21d65656e764
I am making a HTML5 widget for a SCADA.
The widget generates a custom_widget.js, witch I have modified to this.
// Subscribes to receive property changes
cwidget.on("Data", function() {
var Data = document.getElementsByName("Data")
var Data.scr = cwidget.Data;
});
The custom_widget.js is called in my HTML.
And I would like to use the Data tag inside a Script, in the HTML.
What is the syntax for importing the tag in the HTML?
From the technical manual for the SCADA program, I have this example.
HTML
<!DOCTYPE html>
<html style="overflow: hidden;">
<head>
<script src="../Resources/Apis/Proxy.js" cwidget="MyWidget"></script>
<script src="./custom_widget.js"></script>
<title>MyWidget</title>
</head>
<body>
<iframe id="myFrame" style="width: 100vw; height: 100vh;"></iframe>
</body>
</html>
custom_widget.js
cwidget.on("URL", function() {
var myFrame = document.getElementById("myFrame");
myFrame.onload = cwidget.dispatchEvent("PageLoaded");
myFrame.src = cwidget.URL;
});
I am working with jsPDF to create a PDF from my HTML. However, it always generates an empty page doesn't matter which HTML content I enter as the source.
Here is my code:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Save HTML TO PDF</title>
</head>
<body>
<div><button id="cmd">download as PDF</button></div>
<div id="content">Hello</div>
<script src="https://unpkg.com/jspdf#latest/dist/jspdf.min.js"></script>
<script src="https://html2canvas.hertzen.com/dist/html2canvas.min.js"></script>
<script type="text/javascript">
document.getElementById("cmd").addEventListener("click", function () {
window.html2canvas = html2canvas;
var doc = new jsPDF("p", "pt", "a4");
doc.html(document.getElementById("content"), {
callback: function(pdf) {
pdf.save("cv-a4.pdf");
}
});
});
</script>
</body>
</html>
What am I doing wrong? In my opinion that matches exactly the documentation. However, as stated above, the pdf generated does not show any content and not the "Hello". ( I took some of the code from this StackOverflow question)
#threxx
Try this code :
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Save HTML TO PDF</title>
</head>
<body>
<div><button id="cmd">download as PDF</button></div>
<div id="content">
<h1 style="color: brown;">Hello, He/She..</h1>
<p style="color: green;">How Are you ??</p>
Thank you.
</div>
<script src="https://unpkg.com/jspdf#latest/dist/jspdf.min.js"></script>
<script src="https://html2canvas.hertzen.com/dist/html2canvas.min.js"></script>
<script type="text/javascript">
document.getElementById("cmd").addEventListener("click", function () {
var doc = new jsPDF("p", "pt", "a4");
var source = window.document.getElementById('content').innerHTML;
doc.fromHTML(source, 30, 30);
doc.save("cv-a4.pdf");
});
</script>
</body>
</html>
I hope above code will be useful for you.
Thank you.
So after doing some more research I found this answer which will return a PDF from the HTML. Small problem: still only very poor CSS styles but afaik jspdf doesn't support custom CSS.
<script src="https://unpkg.com/jspdf#latest/dist/jspdf.min.js"></script>
<script src="https://html2canvas.hertzen.com/dist/html2canvas.min.js"></script>
<script type="text/javascript">
document.getElementById("cmd").addEventListener("click", function () {
var doc = new jsPDF("p", "pt", "a4");
var source = document.body;
var margin = {
top: 20,
left: 20,
right: 20,
bottom: 20
};
doc.fromHTML(source, 30, 30, {
'width': 80, // max width of content on PDF
},
function(pdf){doc.save('saveInCallback.pdf');},
margin
);
});
</script>
I want to use HTML import so I created two files.
File1:
<!DOCTYPE html>
<html>
<head>
<style>
div {
height: 300px;
width: 300px;
background-color: yellow;
}
</style>
</head>
<body>
<div></div>
</body>
</html>
File2:
<!DOCTYPE html>
<html>
<head>
<link rel='import' href='test.html' id='LINK'>
<script>
var LINK = document.getElementById('LINK');
var test = LINK.import;
var content = document.importNode(test.content, true);
document.body.appendChild(content);
</script>
</head>
<body>
</body>
</html>
I should see a yellow square when I execute File2 but instead I'm getting this error:
Uncaught TypeError: Failed to execute 'importNode' on 'Document': parameter 1 is not of type 'Node'.
at Import.html:8
When I log the "test" variable to the console, I am getting the document that contains File1 so it's fine there. I just don't get what the error is supposed to mean and why it's not working.
When you write:
var content = document.importNode(test.content, true);
...you suppose that test is a <template> element.
So in the document you import, you should have a <template> element.
test.html:
<html>
<head>
<style>
div {
height: 300px;
width: 300px;
background-color: yellow;
}
</style>
</head>
<body>
<template><div></div></template>
</body>
</html>
In the main file, use querySelector() (or another selector function) to get the template:
var LINK = document.getElementById('LINK');
var test = LINK.import.querySelector('template');
var content = document.importNode(test.content, true);
...