Skip to content

Commit

Permalink
Merge pull request #368 from chitraa-cj/pdffix
Browse files Browse the repository at this point in the history
fixed the pdf flowchart issue
  • Loading branch information
subhadeeproy3902 authored Jun 26, 2024
2 parents 56dfd90 + 428f811 commit d1fa0af
Showing 1 changed file with 65 additions and 95 deletions.
160 changes: 65 additions & 95 deletions src/app/workspace/[fileId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,12 @@ import { useConvex } from "convex/react";
import { api } from "../../../../convex/_generated/api";
import { FILE } from "../../dashboard/_components/FileList";
import Canvas from "../_components/Canvas";
import dynamic from 'next/dynamic';
import EditorJS, { OutputData } from "@editorjs/editorjs";
import { useKindeBrowserClient } from "@kinde-oss/kinde-auth-nextjs";
import { useRouter } from "next/navigation";

// Dynamic imports for server-side libraries
const jsPDFPromise = import("jspdf");
const excalidrawPromise = import("@excalidraw/excalidraw");
const jsPDFPromise = import('jspdf');
const excalidrawPromise = import('@excalidraw/excalidraw');

function Workspace({ params }: any) {
const [triggerSave, setTriggerSave] = useState(false);
Expand All @@ -22,49 +21,29 @@ function Workspace({ params }: any) {
const editorRef = useRef<EditorJS | null>(null);
const canvasRef = useRef<any>(null);

const { user, isAuthenticated, isLoading } = useKindeBrowserClient();
const router = useRouter();

console.log(user, isAuthenticated, isLoading);

useEffect(() => {
if (params.fileId && !isLoading) {
if (params.fileId) {
getFileData();
}
}, [params.fileId, isLoading]);
}, [params.fileId]);

const getFileData = async () => {
const result = await convex.query(api.files.getFileById, {
_id: params.fileId,
});

const teamInfo = await convex.query(api.teams.getTeamById, {
_id: result.teamId,
});

if (result.private) {
if (user) {
if (!teamInfo.teamMembers.includes(user.email)) {
router.push("/");
}
console.log(user);
} else {
router.push("/");
}
}
setFileData(result);
};

const saveAsPdf = async () => {
const { default: jsPDF } = await jsPDFPromise;
const { exportToSvg } = await excalidrawPromise;

const editorInstance = editorRef.current;
const canvasInstance = canvasRef.current;

if (editorInstance && canvasInstance) {
const pdf = new jsPDF("p", "mm", "a4");

// Extract text content from the editor
editorInstance.save().then((editorContent: OutputData) => {
const pageWidth = pdf.internal.pageSize.getWidth();
Expand All @@ -73,57 +52,50 @@ function Workspace({ params }: any) {
const textWidth = pageWidth - margin * 2;
const textHeight = pageHeight - margin * 2;
let y = margin;

editorContent.blocks.forEach((block: any) => {
let lines: any[] = [];

switch (block.type) {
case "paragraph":
lines = parseText(block.data.text);
break;
case "header":
pdf.setFontSize(16); // Set font size for header
lines = [{ text: block.data.text, style: "header" }];
lines = [{ text: block.data.text, style: 'header' }];
pdf.setFontSize(12); // Reset font size
break;
case "list":
lines = block.data.items.map((item: string) => ({
text: `• ${item}`,
style: "normal",
}));
lines = block.data.items.map((item: string) => ({ text: `• ${item}`, style: 'normal' }));
break;
// Add more cases if needed for different block types
default:
lines = [{ text: block.data.text, style: "normal" }];
lines = [{ text: block.data.text, style: 'normal' }];
}

lines.forEach((line: any) => {
if (y + 10 > textHeight) {
pdf.addPage();
y = margin;
}

switch (line.style) {
case "bold":
case 'bold':
pdf.setFont("helvetica", "bold");
break;
case "italic":
case 'italic':
pdf.setFont("helvetica", "italic");
break;
case "header":
case 'header':
pdf.setFont("helvetica", "bold");
const headerWidth =
(pdf.getStringUnitWidth(line.text) * 16) /
pdf.internal.scaleFactor;
const headerWidth = pdf.getStringUnitWidth(line.text) * 16 / pdf.internal.scaleFactor;
pdf.text(line.text, (pageWidth - headerWidth) / 2, y);
y += 10;
break;
default:
pdf.setFont("helvetica", "normal");
}

if (line.style !== "header") {
// Split text if it's too wide and handle separately

if (line.style !== 'header') {
const wrappedLines = pdf.splitTextToSize(line.text, textWidth);
wrappedLines.forEach((wrappedLine: string) => {
if (y + 10 > textHeight) {
Expand All @@ -135,87 +107,87 @@ function Workspace({ params }: any) {
});
}
});

// Reset font style and size after each block

pdf.setFont("helvetica", "normal");
pdf.setFontSize(12);
});

// Export flowchart as SVG from Excalidraw
const elements = canvasInstance.getSceneElements();
const appState = canvasInstance.getAppState();
const files = canvasInstance.getFiles();

exportToSvg({
elements: elements,
appState: { ...appState, exportBackground: false }, // No background
appState: { ...appState, exportBackground: false },
files: files,
}).then((svg: SVGSVGElement) => {
// Add heading for the flowchart
pdf.setFont("helvetica", "bold");
pdf.setFontSize(16); // Set font size for the heading
const headingText = "Flowchart";
const headingWidth =
pdf.getStringUnitWidth(headingText) * pdf.internal.scaleFactor;
const headingX = (pageWidth - headingWidth) / 2;
pdf.text(headingText, headingX, y + 10);
pdf.setFontSize(12); // Reset font size
pdf.setFont("helvetica", "normal");
y += 20; // Adjust y position to avoid overlap with the heading

// Convert SVG to PNG using the Canvas API
const svgData = new XMLSerializer().serializeToString(svg);
const canvas = document.createElement("canvas");
const context = canvas.getContext("2d");
const img = new Image();

img.onload = () => {
if (context) {
canvas.width = img.width;
canvas.height = img.height;
context.drawImage(img, 0, 0);

const imgData = canvas.toDataURL("image/png");
const imgProps = pdf.getImageProperties(imgData);
const imgHeight = (imgProps.height * pageWidth) / imgProps.width;

// Add canvas image just below the heading
pdf.addImage(
imgData,
"PNG",
margin,
y,
pageWidth - margin * 2,
imgHeight
);
y += imgHeight;

// Save the PDF
let imgWidth = pageWidth - margin * 2;
let imgHeight = (imgProps.height * imgWidth) / imgProps.width;

// Check if the image height exceeds the remaining page height
if (y + imgHeight + 20 > pageHeight - margin) { // 20 for the heading space
pdf.addPage();
y = margin;
}

// Add heading for the flowchart
pdf.setFont("helvetica", "bold");
pdf.setFontSize(16); // Set font size for the heading
const headingText = "Flowchart";
const headingWidth = pdf.getStringUnitWidth(headingText) * 16 / pdf.internal.scaleFactor;
pdf.text(headingText, (pageWidth - headingWidth) / 2, y);
pdf.setFontSize(12); // Reset font size
pdf.setFont("helvetica", "normal");
y += 20; // Adjust y position to avoid overlap with the heading

// Check if the image height exceeds the page height and scale it down if necessary
if (imgHeight > pageHeight - margin * 2) {
const scaleFactor = (pageHeight - margin * 2) / imgHeight;
imgHeight *= scaleFactor;
imgWidth *= scaleFactor;
}

pdf.addImage(imgData, "PNG", margin, y, imgWidth, imgHeight, undefined, "FAST");

pdf.save("document.pdf");
} else {
console.error("Failed to get canvas context");
}
};

img.src = `data:image/svg+xml;base64,${btoa(svgData)}`;
});
});
} else {
console.error("Unable to find the content to save as PDF");
}
};
};

const parseText = (text: string) => {
const lines: any[] = [];
const parser = new DOMParser();
const parsedHtml = parser.parseFromString(text, "text/html");
const parsedHtml = parser.parseFromString(text, 'text/html');
parsedHtml.body.childNodes.forEach((node: ChildNode) => {
if (node.nodeType === Node.TEXT_NODE) {
lines.push({ text: node.textContent, style: "normal" });
} else if (node.nodeName === "B") {
lines.push({ text: node.textContent, style: "bold" });
} else if (node.nodeName === "I") {
lines.push({ text: node.textContent, style: "italic" });
lines.push({ text: node.textContent, style: 'normal' });
} else if (node.nodeName === 'B') {
lines.push({ text: node.textContent, style: 'bold' });
} else if (node.nodeName === 'I') {
lines.push({ text: node.textContent, style: 'italic' });
}
});
return lines;
Expand All @@ -231,9 +203,7 @@ function Workspace({ params }: any) {
onSaveAsPdf={saveAsPdf}
/>

{!isLoading && <div
className={`grid grid-cols-1 ${fullScreen ? "" : "md:grid-cols-2"} overflow-x-none`}
>
<div className={`grid grid-cols-1 ${fullScreen ? "" : "md:grid-cols-2"} overflow-x-none`}>
<div className={`${fullScreen ? "hidden" : "block"}`}>
<Editor
ref={editorRef as MutableRefObject<EditorJS | null>}
Expand All @@ -250,7 +220,7 @@ function Workspace({ params }: any) {
fileData={fileData}
/>
</div>
</div>}
</div>
</div>
);
}
Expand Down

0 comments on commit d1fa0af

Please sign in to comment.