187 lines
6.4 KiB
JavaScript
187 lines
6.4 KiB
JavaScript
import * as XLSX from "xlsx";
|
|
import { PDFDocument, rgb, StandardFonts } from 'pdf-lib';
|
|
|
|
/**
|
|
* Export JSON data to CSV
|
|
* @param {Array} data - Array of objects to export
|
|
* @param {string} fileName - File name without extension
|
|
*/
|
|
export const exportToCSV = (data, fileName = "data") => {
|
|
const headers = Object.keys(data[0] || {});
|
|
const csvContent = [
|
|
headers.join(","), // header row
|
|
...data.map(row => headers.map(field => `"${row[field] ?? ""}"`).join(",")),
|
|
].join("\n");
|
|
|
|
const blob = new Blob([csvContent], { type: "text/csv;charset=utf-8;" });
|
|
const url = URL.createObjectURL(blob);
|
|
const link = document.createElement("a");
|
|
link.href = url;
|
|
link.setAttribute("download", `${fileName}.csv`);
|
|
document.body.appendChild(link);
|
|
link.click();
|
|
document.body.removeChild(link);
|
|
};
|
|
|
|
/**
|
|
* Export JSON data to Excel
|
|
* @param {Array} data - Array of objects to export
|
|
* @param {string} fileName - File name without extension
|
|
*/
|
|
export const exportToExcel = (data, fileName = "data") => {
|
|
const ws = XLSX.utils.json_to_sheet(data);
|
|
const wb = XLSX.utils.book_new();
|
|
XLSX.utils.book_append_sheet(wb, ws, "Sheet1");
|
|
XLSX.writeFile(wb, `${fileName}.xlsx`);
|
|
};
|
|
|
|
/**
|
|
* Export JSON data to PDF using pdf-lib
|
|
* @param {Array} data - Array of objects to export
|
|
* @param {string} fileName - File name for the PDF (optional)
|
|
*/
|
|
export const exportToPDF = async (data, fileName = "data") => {
|
|
if (!data || data.length === 0) return;
|
|
|
|
// Create a new PDF document
|
|
const pdfDoc = await PDFDocument.create();
|
|
|
|
// Set up the font
|
|
const font = await pdfDoc.embedFont(StandardFonts.Helvetica); // Use Helvetica font
|
|
|
|
// Calculate column widths dynamically based on data content
|
|
const headers = Object.keys(data[0]);
|
|
const rows = data.map(item => headers.map(header => item[header] || ''));
|
|
|
|
const getMaxColumnWidth = (columnIndex) => {
|
|
let maxWidth = font.widthOfTextAtSize(headers[columnIndex], 12);
|
|
rows.forEach(row => {
|
|
const cellText = row[columnIndex].toString();
|
|
maxWidth = Math.max(maxWidth, font.widthOfTextAtSize(cellText, 10));
|
|
});
|
|
return maxWidth + 10; // Padding for better spacing
|
|
};
|
|
|
|
const columnWidths = headers.map((_, index) => getMaxColumnWidth(index));
|
|
const tableX = 30; // X-coordinate for the table start
|
|
const rowHeight = 20; // Height of each row (can be adjusted)
|
|
const maxPageHeight = 750; // Max available height for content (before a new page is added)
|
|
const pageMargin = 30; // Margin from the top of the page
|
|
|
|
let tableY = maxPageHeight; // Start Y position for the table
|
|
const maxPageWidth = 600; // Max available width for content (before a new page is added)
|
|
|
|
// Add the headers and rows to the page
|
|
const addHeadersToPage = (page, scaleFactor) => {
|
|
let xPosition = tableX;
|
|
headers.forEach((header, index) => {
|
|
page.drawText(header, {
|
|
x: xPosition,
|
|
y: tableY,
|
|
font,
|
|
size: 12 * scaleFactor, // Scale the header font size
|
|
color: rgb(0, 0, 0),
|
|
});
|
|
xPosition += columnWidths[index] * scaleFactor; // Adjust X position based on scaling
|
|
});
|
|
tableY -= rowHeight; // Move down after adding headers
|
|
};
|
|
|
|
// Add a new page and reset the table position
|
|
const addNewPage = (scaleFactor) => {
|
|
const page = pdfDoc.addPage([600, 800]);
|
|
tableY = maxPageHeight; // Reset Y position for the new page
|
|
addHeadersToPage(page, scaleFactor); // Re-add headers to the new page
|
|
return page;
|
|
};
|
|
|
|
// Create the first page and add headers
|
|
let page = pdfDoc.addPage([600, 800]);
|
|
|
|
// Check if the content fits within the page width, scale if necessary
|
|
const checkPageWidth = (row) => {
|
|
let totalWidth = columnWidths.reduce((acc, width) => acc + width, 0);
|
|
let scaleFactor = 1;
|
|
if (totalWidth > maxPageWidth) {
|
|
scaleFactor = maxPageWidth / totalWidth; // Scale down if necessary
|
|
}
|
|
|
|
return scaleFactor;
|
|
};
|
|
|
|
// Function to check for page breaks when adding a new row
|
|
const checkPageBreak = () => {
|
|
if (tableY - rowHeight < pageMargin) {
|
|
page = addNewPage(scaleFactor); // Add a new page if there is no space for the next row
|
|
}
|
|
};
|
|
|
|
// Add rows to the PDF with pagination and horizontal scaling
|
|
rows.forEach(row => {
|
|
checkPageBreak(); // Check for page break before adding each row
|
|
|
|
const scaleFactor = checkPageWidth(row); // Get the scaling factor for the row
|
|
|
|
// Add headers to the first page and each new page with the same scale factor
|
|
if (tableY === maxPageHeight) {
|
|
addHeadersToPage(page, scaleFactor); // Add headers only on the first page
|
|
}
|
|
|
|
let xPosition = tableX;
|
|
row.forEach((value, index) => {
|
|
page.drawText(value.toString(), {
|
|
x: xPosition,
|
|
y: tableY,
|
|
font,
|
|
size: 10 * scaleFactor, // Scale the font size
|
|
color: rgb(0, 0, 0),
|
|
});
|
|
xPosition += columnWidths[index] * scaleFactor; // Adjust X position based on scaling
|
|
});
|
|
|
|
tableY -= rowHeight; // Move down to the next row position
|
|
});
|
|
|
|
// Serialize the document to bytes
|
|
const pdfBytes = await pdfDoc.save();
|
|
|
|
// Trigger a download of the PDF
|
|
const blob = new Blob([pdfBytes], { type: 'application/pdf' });
|
|
const link = document.createElement('a');
|
|
link.href = URL.createObjectURL(blob);
|
|
link.download = `${fileName}.pdf`;
|
|
link.click();
|
|
};
|
|
|
|
/**
|
|
* Print the HTML table by accepting the table element or a reference.
|
|
* @param {HTMLElement} table - The table element (or ref) to print
|
|
*/
|
|
export const printTable = (table) => {
|
|
if (table) {
|
|
const newWindow = window.open("", "", "width=600,height=600"); // Open a new window
|
|
|
|
// Inject styles for the table and body
|
|
newWindow.document.write("<html><head><title>Print Table</title>");
|
|
const style = document.createElement('style');
|
|
style.innerHTML = `
|
|
body { font-family: Arial, sans-serif; }
|
|
table { border-collapse: collapse; width: 100%; }
|
|
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
|
|
th { background-color: #f2f2f2; }
|
|
`;
|
|
newWindow.document.head.appendChild(style);
|
|
|
|
newWindow.document.write("</head><body>");
|
|
newWindow.document.write(table.outerHTML); // Write the table HTML to the new window
|
|
newWindow.document.write("</body></html>");
|
|
|
|
newWindow.document.close(); // Close the document stream
|
|
|
|
// Wait for the document to load before triggering print
|
|
newWindow.onload = () => {
|
|
newWindow.print(); // Trigger the print dialog after the content is loaded
|
|
};
|
|
}
|
|
};
|