import { useEffect, useContext, useState, useRef, useCallback } from "react"; import { AspectRatio } from "@/components/ui/aspect-ratio"; import OpenContext from "../Context/openContext/OpenContext"; import CanvasContext from "../Context/canvasContext/CanvasContext"; import { Card, CardContent } from "../ui/card"; import ActiveObjectContext from "../Context/activeObject/ObjectContext"; import { Slider } from "@/components/ui/slider"; export default function Canvas() { const { setLeftPanelOpen, setRightPanelOpen, setOpenSetting, setOpenObjectPanel, rightPanelOpen, } = useContext(OpenContext); const { canvasRef, canvas, setCanvas, fabricCanvasRef, canvasRatio, setCanvasHeight, setCanvasWidth, setScreenWidth, } = useContext(CanvasContext); const { setActiveObject } = useContext(ActiveObjectContext); const [zoomLevel, setZoomLevel] = useState(100); const containerRef = useRef(null); const handleZoom = useCallback( (newZoom) => { const zoom = Math.min(Math.max(newZoom, 0), 100); setZoomLevel(zoom); if (canvasRef.current && canvas) { const scale = zoom / 100; // Update canvas dimensions const newWidth = canvasRef.current.offsetWidth * scale; const newHeight = canvasRef.current.offsetHeight * scale; canvas.setWidth(newWidth); canvas.setHeight(newHeight); setCanvasWidth(newWidth); setCanvasHeight(newHeight); canvas.renderAll(); } }, [canvas, canvasRef, setCanvasHeight, setCanvasWidth] ); useEffect(() => { if (!canvas) return; const handleMouseDown = (event) => { const target = event.target; const activeObject = canvas.getActiveObject(); if (target) { if (target.type === "group") { setActiveObject(activeObject); } else { setActiveObject(activeObject); } } else { setActiveObject(activeObject); } }; const handleWheel = (event) => { if (event.ctrlKey || event.metaKey) { event.preventDefault(); const delta = event.deltaY > 0 ? -1 : 1; handleZoom(zoomLevel + delta); event.stopPropagation(); } }; const handleKeyboard = (event) => { if ( (event.ctrlKey || event.metaKey) && (event.key === "=" || event.key === "-") ) { event.preventDefault(); const delta = event.key === "=" ? 1 : -1; handleZoom(zoomLevel + delta); } }; let lastDistance = 0; const handleTouchStart = (event) => { if (event.touches.length === 2) { const touch1 = event.touches[0]; const touch2 = event.touches[1]; lastDistance = Math.hypot( touch2.clientX - touch1.clientX, touch2.clientY - touch1.clientY ); } }; const handleTouchMove = (event) => { if (event.touches.length === 2) { event.preventDefault(); const touch1 = event.touches[0]; const touch2 = event.touches[1]; const distance = Math.hypot( touch2.clientX - touch1.clientX, touch2.clientY - touch1.clientY ); if (lastDistance > 0) { const delta = distance - lastDistance; const zoomDelta = delta > 0 ? 1 : -1; handleZoom(zoomLevel + zoomDelta); } lastDistance = distance; } }; const handleTouchEnd = () => { lastDistance = 0; }; const handleResize = () => { handleZoom(zoomLevel); }; canvas.on("mouse:down", handleMouseDown); const canvasContainer = document.getElementById("canvas-ref"); if (canvasContainer) { canvasContainer.addEventListener("wheel", handleWheel, { passive: false, }); canvasContainer.addEventListener("touchstart", handleTouchStart); canvasContainer.addEventListener("touchmove", handleTouchMove, { passive: false, }); canvasContainer.addEventListener("touchend", handleTouchEnd); window.addEventListener("keydown", handleKeyboard); window.addEventListener("resize", handleResize); } return () => { canvas.off("mouse:down", handleMouseDown); if (canvasContainer) { canvasContainer.removeEventListener("wheel", handleWheel); canvasContainer.removeEventListener("touchstart", handleTouchStart); canvasContainer.removeEventListener("touchmove", handleTouchMove); canvasContainer.removeEventListener("touchend", handleTouchEnd); window.removeEventListener("keydown", handleKeyboard); window.removeEventListener("resize", handleResize); } }; }, [canvas, setActiveObject, zoomLevel, handleZoom]); useEffect(() => { import("fabric").then((fabricModule) => { window.fabric = fabricModule.fabric; }); }, [canvasRef, fabricCanvasRef, setCanvas]); const getRatioValue = (ratio) => { const [width, height] = ratio.split(":").map(Number); return width / height; }; useEffect(() => { const updateCanvasSize = () => { if (canvasRef.current && canvas) { const newWidth = canvasRef.current.offsetWidth; const newHeight = canvasRef.current.offsetHeight; canvas.setWidth(newWidth); canvas.setHeight(newHeight); setCanvasWidth(newWidth); setCanvasHeight(newHeight); const bgImage = canvas.backgroundImage; if (bgImage) { const scaleX = newWidth / bgImage.width; const scaleY = newHeight / bgImage.height; const scale = Math.max(scaleX, scaleY); bgImage.scaleX = scale; bgImage.scaleY = scale; bgImage.left = 0; bgImage.top = 0; canvas.setBackgroundImage(bgImage, canvas.renderAll.bind(canvas)); } else { canvas.renderAll(); } } setScreenWidth(document.getElementById("root").offsetWidth); if (document.getElementById("root").offsetWidth <= 640) { setLeftPanelOpen(false); setRightPanelOpen(false); } if (document.getElementById("root").offsetWidth > 640) { setOpenObjectPanel(false); setOpenSetting(false); } }; updateCanvasSize(); window.addEventListener("resize", updateCanvasSize); return () => window.removeEventListener("resize", updateCanvasSize); }, [ setCanvasWidth, setCanvasHeight, canvasRatio, canvasRef, canvas, setLeftPanelOpen, setOpenObjectPanel, setRightPanelOpen, rightPanelOpen, setScreenWidth, setOpenSetting, ]); useEffect(() => { if (window.fabric) { if (fabricCanvasRef?.current) { fabricCanvasRef.current.dispose(); } const canvasElement = document.getElementById("fabric-canvas"); if (canvasElement) { canvasElement.classList.add("fabric-canvas-container"); } fabricCanvasRef.current = new window.fabric.Canvas("fabric-canvas", { width: canvasRef?.current?.offsetWidth, height: canvasRef?.current?.offsetWidth, backgroundColor: "#ffffff", allowTouchScrolling: true, selection: true, preserveObjectStacking: true, }); setCanvas(fabricCanvasRef.current); } }, [canvasRef, fabricCanvasRef, setCanvas]); return ( <> {/* Zoom Controls */}