Skip to content

Commit 1ac29ce

Browse files
authored
Merge pull request #47 from Shreyanshi210205/export
Export
2 parents fccebb7 + efbc382 commit 1ac29ce

File tree

4 files changed

+61
-4
lines changed

4 files changed

+61
-4
lines changed

client/package-lock.json

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

client/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
"@radix-ui/react-slider": "^1.3.6",
1515
"@tailwindcss/vite": "^4.1.14",
1616
"axios": "^1.12.2",
17+
"canvas2svg": "^1.0.16",
1718
"class-variance-authority": "^0.7.1",
1819
"clsx": "^2.1.1",
1920
"jspdf": "^3.0.3",

client/src/components/Canvas.jsx

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import { StrokeControl } from "./StrokeControl";
55
import { toast } from "sonner";
66
import { io } from "socket.io-client";
77
import tinycolor from "tinycolor2";
8+
import { jsPDF } from "jspdf";
9+
import C2S from "canvas2svg";
810

911
export const Canvas = () => {
1012
const canvasRef = useRef(null);
@@ -554,6 +556,48 @@ export const Canvas = () => {
554556
return "cursor-crosshair";
555557
};
556558

559+
const handleExport = (format) => {
560+
const canvas = canvasRef.current;
561+
if (!canvas) return;
562+
563+
switch (format) {
564+
case "png": {
565+
const link = document.createElement("a");
566+
link.download = "canvas.png";
567+
link.href = canvas.toDataURL("image/png");
568+
link.click();
569+
break;
570+
}
571+
572+
case "pdf": {
573+
const pdf = new jsPDF({
574+
orientation: "landscape",
575+
unit: "px",
576+
format: [canvas.width, canvas.height],
577+
});
578+
const imgData = canvas.toDataURL("image/png");
579+
pdf.addImage(imgData, "PNG", 0, 0, canvas.width, canvas.height);
580+
pdf.save("canvas.pdf");
581+
break;
582+
}
583+
584+
case "svg": {
585+
const svgCtx = new C2S(canvas.width, canvas.height);
586+
const svgData = svgCtx.getSerializedSvg();
587+
const blob = new Blob([svgData], { type: "image/svg+xml" });
588+
const link = document.createElement("a");
589+
link.download = "canvas.svg";
590+
link.href = URL.createObjectURL(blob);
591+
link.click();
592+
break;
593+
}
594+
595+
default:
596+
console.warn("Unsupported format:", format);
597+
}
598+
};
599+
600+
557601
return (
558602
<div className="relative w-full h-screen overflow-hidden bg-canvas">
559603
{/* 🔹 Login / Logout buttons (Unchanged) */}
@@ -612,6 +656,7 @@ export const Canvas = () => {
612656
activeTool={activeTool}
613657
onToolChange={handleToolChange}
614658
onClear={handleClear}
659+
onExport={handleExport}
615660
/>
616661
{joined ? (
617662
<button

client/src/components/Toolbar.jsx

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ export const Toolbar = ({ activeTool, onToolChange, onClear, onExport }) => {
2727

2828
];
2929

30+
const handleExport = (format) => {
31+
onExport(format);
32+
}
33+
3034
const brushTypes = [
3135
{
3236
id: "solid",
@@ -142,20 +146,20 @@ export const Toolbar = ({ activeTool, onToolChange, onClear, onExport }) => {
142146
</Button>
143147
}
144148
>
145-
<DropdownMenuItem onClick={() => onExport("png")}>
149+
<DropdownMenuItem onClick={() => handleExport("png")}>
146150
<FileImage className="h-4 w-4" />
147151
Export as PNG
148152
</DropdownMenuItem>
149-
<DropdownMenuItem onClick={() => onExport("svg")}>
153+
<DropdownMenuItem onClick={() => handleExport("svg")}>
150154
<FileType className="h-4 w-4" />
151155
Export as SVG
152156
</DropdownMenuItem>
153-
<DropdownMenuItem onClick={() => onExport("pdf")}>
157+
<DropdownMenuItem onClick={() => handleExport("pdf")}>
154158
<FileType className="h-4 w-4" />
155159
Export as PDF
156160
</DropdownMenuItem>
157161
</DropdownMenu>
158162
</div>
159163
</div>
160164
);
161-
};
165+
};

0 commit comments

Comments
 (0)