Below is my Code where the html contents (input) are downloaded into pdf
i have a page in which my html controls are present and I'm trying to download the same html file on button click. the page download but some contents get cut off at bottom of the page while converting the html to pdf. I have used jspdf and html2canvas for this implementation.
const input = document.getElementById('print');
const pdf = new jsPDF({
orientation: 'portrait',
unit: 'pt',
format: 'a4',
compress:true,
});
//check for Screen dimensions
let srcwidth = document.getElementById('print').scrollWidth;
pdf
.html(input, {
margin: [55, 0, 40, -2],
autoPaging: 'text',
html2canvas: {
scale: 595.26 / srcwidth, //595.26 is the width of A4 page
scrollY: 0,
},
})
.then(() => {
const pageCount = pdf.internal.getNumberOfPages();
const pageWidth = pdf.internal.pageSize.getWidth();
var pageHeight = pdf.internal.pageSize.getHeight();
//loop to set header/ footer, style, alignment, text style to the page
for (let i = 1; i <= pageCount; i++) {
pdf.rect(
5,
5,
pdf.internal.pageSize.width - 13,
pdf.internal.pageSize.height - 13,
'S',
);
pdf.setPage(i);
pdf.viewerPreferences({"FitWindow":true,"ViewArea":"MediaBox","ViewClip":"MediaBox" });
var header = 'CSMM 5A - Vessel Cyber Security Self Assessment';
var headerLine =
'_________________________________________________________________________________';
const footer = `Page ${i} of ${pageCount}`;
var submitedDate =
'Date Last Edited: ' +
this.formatDateTime(this.state.vesselAssesementData.editedOn);
// if (i > 1) {
pdf
.setFont('sans-serif', '', 'bold')
.setFontSize(14)
.text(header, 20, 25, { baseline: 'top' });
pdf.addImage(kline, 'PNG', 530, 12, 35, 35);
pdf.text(headerLine, 10, 38, { baseline: 'top' });
// }
pdf
.setFont('Arial, sans-serif', '', 'normal')
.setFontSize(9)
.text(
submitedDate,
pageWidth / 6.5 - pdf.getTextWidth(submitedDate) / 2,
pageHeight - 18,
{ baseline: 'bottom' },
);
pdf
.setFont('Arial, sans-serif', '', 'normal')
.setFontSize(9)
.text(
footer,
pageWidth / 1.08 - pdf.getTextWidth(footer) / 2,
pageHeight - 18,
{ baseline: 'bottom|right' },
);
}
pdf.save(
`${
'VesselCyberSecuritySelfAssessmentReport_' +
this.state.vesselAssesementData.uniqueId
}.pdf`,
);
Below is image attached where the issue occurs.
this is multiple page which is created where the content alignment issue occurs
Solution for this ASAP will be very helpful.
Related
This question already has an answer here:
React won't draw anything in the canvas in useEffect
(1 answer)
Closed 16 days ago.
I use Matter js for physics and canvas for rendering 100 items, after every change in props the app gets slower and slower. At the same time, subsequent downloads with the same props occur instantly, i.e. past images and elements remained and were not deleted, which loads the application.
enter image description here
"Top" dropdown menu changes props for bubbles component, code:
const Bubbles = ({ coins }) => {
var winwidth = window.innerWidth;
var winheight = window.innerHeight - 80;
const [physics, setPhysics] = useState({
frictionAir: 0,
friction: 0.2,
frictionStatic: 0.2,
restitution: 0.1,
inertia: Infinity,
density: 0.8,
});
useEffect(() => {
setSize(coins);
// create an engine
const engine = Engine.create();
const world = engine.world;
// create a renderer
const render = Render.create({
element: document.querySelector(".bubbles"),
engine: engine,
options: {
width: winwidth,
height: winheight,
showAngleIndicator: false,
background: "transparent",
wireframeBackground: "transparent",
wireframes: false,
showDebug: false,
},
});
const bubbles = [];
// create a canvas
const canvas = document.createElement("canvas");
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
document.querySelector(".bubbles").appendChild(canvas);
const ctx = canvas.getContext("2d");
// create 100 random bubbles
for (let i = 0; i < coins.length; i++) {
const x = Math.random() * window.innerWidth;
const y = Math.random() * window.innerHeight;
const bubble = Bodies.circle(x, y, coins[i].size / 2, {
...physics,
render: {
fillStyle: "transparent",
},
});
Composite.add(engine.world, bubble);
// store the bubble and its content data in an object
bubbles.push({
bubble,
content: {
radius: coins[i].radius,
text: `${i + 1}`,
},
});
}
// update the canvas on each engine update
Matter.Events.on(engine, "afterUpdate", function () {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (let i = 0; i < bubbles.length; i++) {
const bubble = coins[i];
const pos = bubbles[i].bubble.position;
const size = bubble.size;
const text = bubble.symbol;
const priceChange = bubble.price_change_percentage_24h.toFixed(1);
const image = new Image();
image.src = bubble.image;
if (priceChange > 0) {
ctx.fillStyle = "rgba(5, 222, 5, 0.15)";
ctx.strokeStyle = "rgba(5, 222, 5, 0.6)";
} else if (priceChange < 0) {
ctx.fillStyle = "rgba(166, 53, 53, 0.15)";
ctx.strokeStyle = "rgba(166, 53, 53, 0.8)";
} else {
ctx.fillStyle = "rgba(255, 255, 89, 0.069)";
ctx.strokeStyle = "rgba(187, 231, 11, 0.443)";
}
ctx.beginPath();
ctx.arc(pos.x, pos.y, size / 2, 0, 2 * Math.PI);
ctx.fill();
ctx.stroke();
ctx.drawImage(
image,
pos.x - size / 5,
pos.y - size / 2.5,
size / 2.5,
size / 2.5
);
ctx.font = `${size / 6}px Acme`;
ctx.fillStyle = "white";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText(text, pos.x, pos.y + size / 6.5);
ctx.font = `${size / 6.5}px Acme`;
ctx.fillStyle = "white";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillText(priceChange + "%", pos.x, pos.y + size / 3);
}
});
// fit the render viewport to the scene
window.addEventListener("onload", () => {
Render.lookAt(render, {
min: { x: 0, y: 0 },
max: { x: 100000, y: 10000 },
});
});
// run the engine
Runner.run(engine);
// run the renderer
Render.run(render);
return () => {
// stop the engine and renderer
Engine.clear(engine);
Render.stop(render);
Runner.stop(engine);
// remove the canvas from the DOM
canvas.remove();
};
}, [coins]);
return <></>;
};
export default Bubbles;
after each update of the coins props, I deleted the canvas and stopped the engine, but still the speed worsened
return () => {
// stop the engine and renderer
Engine.clear(engine);
Render.stop(render);
Runner.stop(engine);
// remove the canvas from the DOM
canvas.remove();
};
I want to either stop re-creating the engine and the matter js world, canvas with images.
Only without window.location.reload(), because I need to save props like "Top" and "Earth, Trampoline", etc.
I solved the problem. I didn't properly clear the js canvas value and also didn't set events.off when unmounting the component.
Here is the solution to my problem
return () => {
//set Matter Js events off. drawCanvas - afterUpdate event function
Events.off(engine, 'afterUpdate', drawCanvas);
Render.stop(render);
Composite.clear(engine.world);
Runner.stop(engine)
Engine.clear(engine);
render.canvas.remove();
render.canvas = null;
render.context = null;
// remove the canvas from the DOM
canvas.remove();
};
I managed to get the real time example to work:
https://jsfiddle.net/TradingView/yozeu6k1/
I tried to get a real time histogram underneath, as the usual volume indicator and the behavior is random.
A snapshot of the chart:
enter image description here
As we can see the starting point of those bars differ one from another.
Series definition:
const volumeSeries = chart.addHistogramSeries({
priceFormat: {
type: 'volume',
},
priceScaleId: '',
scaleMargins: {
top: 0.8,
bottom: 0,
}
});
Update:
volumeSeries.update({
time: data.time,
value: data.volume
});
Can anyone point me to an example in order to get a candlestick chart with a volume indicator to work? Both updating in real time.
I got it to work, basically the issue was that the histogram understands negative values as a down facing bar, so in order to show a volume indicator we have to show the absolute value of the volume and change the color.
A working example at: https://jsfiddle.net/rondolfo/0zg7u9tv/57/
//colours
var green = 'rgb(38,166,154)';
var red = 'rgb(255,82,82)';
var black = '#000000';
var white = 'rgba(255, 255, 255, 0.9)';
var grey = 'rgba(42, 46, 57, 0.5)';
// chart definition
var chart = LightweightCharts.createChart(document.body, {
width: 800,
height: 400,
layout: {
backgroundColor: black,
textColor: white,
},
grid: {
vertLines: {
visible: false,
},
horzLines: {
color: grey,
},
},
crosshair: {
mode: LightweightCharts.CrosshairMode.Normal,
}
});
chart.applyOptions({
timeScale: {
borderVisible: false,
borderColor: '#fff000',
visible: true,
timeVisible: true,
minBarSpacing: 0.0,
}
});
const candleStickSeries = chart.addCandlestickSeries({
upColor: green,
downColor: red,
wickUpColor: green,
wickDownColor: red,
borderVisible: false,
priceLineVisible: false,
});
const volumeSeries = chart.addHistogramSeries({
priceFormat: {
type: 'volume',
},
priceScaleId: '',
scaleMargins: {
top: 0.8,
bottom: 0.02,
}
});
//end chart definition
//data loading
jQuery.ajaxSetup({
async: false
});
var url = 'https://raw.githubusercontent.com/AnAlgoTrader/TradingView.LightWeightCharts.Example/main/InputData/prices.json';
var data = [];
$.get(url, function(result) {
data = JSON.parse(result);
});
//end data loading
//real time updates
var index = 0;
setInterval(function() {
if (index > data.length) return;
var item = data[index];
candleStickSeries.update({
time: item.time,
open: item.open,
high: item.high,
low: item.low,
close: item.close
});
var volumeColour = item.volume < 0 ? red : green;
volumeSeries.update({
time: item.time,
value: Math.abs(item.volume),
color: volumeColour
});
index++;
}, 1000);
I have used jspdf and jspdfAutoTable in my code to generate pdf.
It works fine on a single page, with upto 23 rows. As soon as I add 24th row (i.e the row to be present on second page), everything is distorted.
page-1 pdf screenshot
I have used below code to generate the PDF
generatePdf(){
const { jsPDF } = window.jspdf;
const { jsPDFAutotable } = window.jspdfautotable;
const doc = new jsPDF('landscape');//
var totalPagesExp = doc.internal.getNumberOfPages();// '{total_pages_count_string}' ==> the output becomes Page 1 of '{total_pages_count_string}' and page 2 of '{total_pages_count_string}'
let head = [['ID', 'Country', 'Rank', 'Capital', 'Name', 'TelephoneNumber', 'Email', 'SomeText']];
let body = [
[1, 'Denmark', 7.526, 'Cp', 'Alex', 9876543.210123456789, 'alex#example.com', 'a!£$%^&*()~#¬,.<>?asdfgQWERTY#asdfgh11222333344444'],
.
.
.
[23, 'Iceland', 7.501, 'Reykjavík', 'John', 2321, 'john#example.com', 'asdfgQWERTY'],
];
doc.autoTable({
head: head,
body: body,
tableWidth: 'auto',
styles: {
cellWidth: 'wrap',
fontSize: 8
},
columnStyles: {
ID: {cellWidth: 'auto'},
Country: {cellWidth: 'auto'},
Rank: {cellWidth: 'auto'}
},
theme: 'striped',
pageBreak: 'auto',
showHead: 'everyPage',
showFoot: 'everyPage',
margin: { top: 30 },
didDrawPage: function (data) {
doc.setFontSize(20);
doc.setTextColor(40);
//doc.setFontStyle('normal');
doc.text("Equipment Out On Jobs", 14, 22);
doc.setFontSize(20);
doc.setTextColor(40);
//doc.setFontStyle('normal');
doc.text("Job Numbers: 104319419,104319136", 14, 30);
// Footer
var str = "Page " + doc.internal.getCurrentPageInfo().pageNumber;
// Total page number plugin only available in jspdf v1.0+
if (typeof doc.putTotalPages === 'function') {
str = str + " of " + totalPagesExp;
}
doc.setFontSize(8);
doc.setTextColor(40);
//doc.setFontStyle('normal');
var pageSize = doc.internal.pageSize;
var pageHeight = pageSize.height ? pageSize.height : pageSize.getHeight();
doc.text(str, 14, pageHeight - 10);
},
});
// Total page number plugin only available in jspdf v1.0+
if (typeof doc.putTotalPages === 'function') {
doc.putTotalPages(totalPagesExp);
}
doc.save('table.pdf');
}
The entire page gets distorted.
Please help.
UPDATE codepen where it is working perfectly fine. Only in LWC, something is causing problem.
Here is documentation for Icon Layer https://deck.gl/docs/api-reference/layers/icon-layer
I want to use this IconLayer to display markers on the map.
I used this like below.
import
import { IconLayer } from "#deck.gl/layers";
Icon mapping
const ICON__MAPPING = {
marker: { x: 0, y: 0, width: 128, height: 128, mask: false }
};
Icon layer
const iconLayer = new IconLayer({
id: "icon-layer",
data: [
{
name: "Colma (COLM)",
address: "365 D Street, Colma CA 94014",
exits: 4214,
coordinates: [76.993894, 31.781929]
}
],
pickable: true,
// iconAtlas and iconMapping are required
// getIcon: return a string
iconAtlas: "https://img.icons8.com/dusk/64/000000/user-location.png",
getIcon: (d) => d.name,
iconMapping: ICON__MAPPING,
sizeScale: 15,
getPosition: (d) => d.coordinates,
getSize: (d) => 55,
getColor: (d) => [Math.sqrt(d.exits), 140, 0]
});
I used everything as documented. I am not doing any experiment. Still icon is not visible on the map.
Live Demo
https://codesandbox.io/s/reverent-framework-uepze?file=/src/App.js
The iconmapping name must match what you do in getIcon, i.e.: "Colma (COLM)" !== "marker"
I'm using some custom attributes while I'm creating my objects. For example in this case "name" and "icon":
$scope.addRoundRect = function () {
var coord = getRandomLeftTop();
var roundrect = (new fabric.Rect({
left: coord.left,
top: coord.top,
fill: '#' + getRandomColor(),
width: 250,
height: 250,
opacity: 1,
scaleX: 1,
scaleY: 1,
angle: 0,
rx: 10,
ry: 10,
strokeWidth: 0,
name: "Rounded Rectangle",
icon: "crop-square"
}));
canvas.add(roundrect).setActiveObject(roundrect);
};
This is my copy/paste function. As you can see I have already tried to paste the relevant attributes – bu I think that they are simply not cloned with the object:
function copy() {
canvas.getActiveObject().clone(function (cloned) {
_clipboard = cloned;
});
}
function paste() {
_clipboard.clone(function (clonedObj) {
canvas.discardActiveObject();
clonedObj.set({
left: clonedObj.left + 10,
top: clonedObj.top + 10,
evented: true,
name: clonedObj.name,
icon: clonedObj.icon,
});
if (clonedObj.type === 'activeSelection') {
clonedObj.canvas = canvas;
clonedObj.forEachObject(function (obj) {
canvas.add(obj);
});
clonedObj.setCoords();
} else {
canvas.add(clonedObj);
}
canvas.setActiveObject(clonedObj);
canvas.requestRenderAll();
});
To make it short: is there a way to clone and paste also this attributes without having to modify the source (ie. impleneting a full fledged custom attribute in the JSO serialization)?
var canvas = new fabric.Canvas('c');
var roundrect = new fabric.Rect({
left: 50,
top: 30,
fill: 'blue',
width: 250,
height: 250,
opacity: 1,
scaleX: 1,
scaleY: 1,
angle: 0,
rx: 10,
ry: 10,
strokeWidth: 0,
name: "Rounded Rectangle",
icon: "crop-square"
});
canvas.add(roundrect).setActiveObject(roundrect);
var customProperties = 'name icon'.split(' ');
function copy() {
canvas.getActiveObject().clone(function(cloned) {
console.log(cloned);
_clipboard = cloned;
}, customProperties);
}
function paste() {
// clone again, so you can do multiple copies.
_clipboard.clone(function(clonedObj) {
canvas.discardActiveObject();
clonedObj.set({
left: clonedObj.left + 10,
top: clonedObj.top + 10,
evented: true,
});
if (clonedObj.type === 'activeSelection') {
// active selection needs a reference to the canvas.
clonedObj.canvas = canvas;
clonedObj.forEachObject(function (obj) {
canvas.add(obj);
});
// this should solve the unselectability
clonedObj.setCoords();
} else {
canvas.add(clonedObj);
}
canvas.setActiveObject(clonedObj);
canvas.requestRenderAll();
console.log(clonedObj);
_clipboard = clonedObj;
},customProperties);
}
canvas {
border: blue dotted 2px;
}
<script src="https://rawgit.com/kangax/fabric.js/master/dist/fabric.min.js"></script>
<button onclick='copy()'>copy</button>
<button onclick='paste()'>paste</button><br>
<canvas id="c" width="400" height="400"></canvas>
object.clone accepts callback function and any additional property you want to include as another parameter. You can send your name and icon as properties to include.
And in paste you no need to clone that object if you are doing so, make sure there also send you are including your additional properties.