diff --git a/public/assets/svgs/Group 25403.svg b/public/assets/svgs/Group 25403.svg new file mode 100644 index 0000000..b2d1937 --- /dev/null +++ b/public/assets/svgs/Group 25403.svg @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/assets/svgs/Group 25404.svg b/public/assets/svgs/Group 25404.svg new file mode 100644 index 0000000..c545865 --- /dev/null +++ b/public/assets/svgs/Group 25404.svg @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/components/Canvas.jsx b/src/components/Canvas.jsx index 1f6c8d0..357e35f 100644 --- a/src/components/Canvas.jsx +++ b/src/components/Canvas.jsx @@ -13,16 +13,36 @@ const Canvas = () => { const { openSetting, openObjectPanel, openPanel } = useContext(OpenContext); - const { setActiveObject } = useContext(ActiveObjectContext); + const { activeObject, setActiveObject } = useContext(ActiveObjectContext); useEffect(() => { - if (canvas) { - canvas.on('mouse:down', () => { - const activeObject = canvas?.getActiveObject(); + if (!canvas) return; // Ensure canvas is available + + // Event handler for mouse down + const handleMouseDown = (event) => { + const target = event.target; // Get the clicked target + const activeObject = canvas.getActiveObject(); // Get the active object + + if (target) { + if (target.type === 'group') { + setActiveObject(activeObject); + } else { + setActiveObject(activeObject); + } + } else { setActiveObject(activeObject); - }); - } - }, [canvas]); + } + }; + + // Attach the event listener + canvas.on('mouse:down', handleMouseDown); + + // Cleanup function to remove the event listener + return () => { + canvas.off('mouse:down', handleMouseDown); // Remove the listener on unmount + }; + }, [canvas]); // Re-run only when canvas changes + const removeSelected = useCallback(() => { const activeObject = canvas?.getActiveObject(); @@ -56,6 +76,8 @@ const Canvas = () => { }; }, [removeSelected]); + // console.log(activeObject); + return (
diff --git a/src/components/EachComponent/CustomShape/shapes.js b/src/components/EachComponent/CustomShape/shapes.js index 0b37708..7d399a5 100644 --- a/src/components/EachComponent/CustomShape/shapes.js +++ b/src/components/EachComponent/CustomShape/shapes.js @@ -35,6 +35,8 @@ export const shapes = [ { shape: 25400, source: "/assets/svgs/Group 25400.svg" }, { shape: 25401, source: "/assets/svgs/Group 25401.svg" }, { shape: 25402, source: "/assets/svgs/Group 25402.svg" }, + { shape: 25403, source: "/assets/svgs/Group 25403.svg" }, + { shape: 25404, source: "/assets/svgs/Group 25404.svg" }, ]; diff --git a/src/components/EachComponent/Customization/SelectObjectFromGroup.jsx b/src/components/EachComponent/Customization/SelectObjectFromGroup.jsx new file mode 100644 index 0000000..277cb59 --- /dev/null +++ b/src/components/EachComponent/Customization/SelectObjectFromGroup.jsx @@ -0,0 +1,96 @@ +import ActiveObjectContext from '@/components/Context/activeObject/ObjectContext'; +import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; +import { useContext, useEffect, useState } from 'react' +import { Card, } from '@/components/ui/card'; +import CanvasContext from '@/components/Context/canvasContext/CanvasContext'; +import { Separator } from '@/components/ui/separator'; + +const SelectObjectFromGroup = () => { + const [groupObjects, setGroupObjects] = useState([]); + const [selectedObject, setSelectedObject] = useState(null); + const { setActiveObject } = useContext(ActiveObjectContext); + const { canvas } = useContext(CanvasContext); + + const activeObject = canvas?.getActiveObject(); + + // Update group objects when the active object changes + useEffect(() => { + if (activeObject?.type === 'group') { + setGroupObjects(activeObject._objects || []); + setSelectedObject(null); // Reset selection when group changes + } else { + setGroupObjects([]); + setSelectedObject(null); + } + }, [activeObject]); + + // Handle object selection from dropdown + const handleSelectObject = (value) => { + const selected = groupObjects[parseInt(value)]; + setSelectedObject(selected); + setActiveObject(selected); + }; + + // Don't render if there's no active group + if (!activeObject || activeObject.type !== 'group') { + return null; + } + + console.log(selectedObject); + console.log(selectedObject?.group); + console.log(selectedObject?.fill); + + return ( +
+ +

Group Objects

+
+ +
+ + {selectedObject && ( +
+ + {selectedObject?.fill?.coords && selectedObject?.fill?.colorStops && ( + + + {selectedObject.fill.colorStops.map((stop, index) => ( + + ))} + + + )} + + +
+ )} +
+ +
+ ); +}; +export default SelectObjectFromGroup; \ No newline at end of file diff --git a/src/components/EachComponent/CustomizeShape.jsx b/src/components/EachComponent/CustomizeShape.jsx index 0e79862..3ff8d36 100644 --- a/src/components/EachComponent/CustomizeShape.jsx +++ b/src/components/EachComponent/CustomizeShape.jsx @@ -15,6 +15,7 @@ import { Card } from '../ui/card'; import PositionCustomization from './Customization/PositionCustomization'; import CollapsibleComponent from './Customization/CollapsibleComponent'; import ImageCustomization from './Customization/ImageCustomization'; +import SelectObjectFromGroup from './Customization/SelectObjectFromGroup'; const CustomizeShape = () => { const { canvas } = useContext(CanvasContext); @@ -28,16 +29,24 @@ const CustomizeShape = () => { return

No active object found

; } + console.log(activeObject?.type); + return (
+ + + {/* Apply fill and background color */} - {(!hasClipPath && activeObjectType !== 'group' && !customClipPath) && } + {(activeObjectType !== 'image' && !hasClipPath && !customClipPath) && } {/* Apply stroke and stroke color */} - {(activeObjectType !== 'group' && !customClipPath) && <>} + {(!customClipPath) && <>} - - + { + activeObject?.type !== "group" && + <> + + } {/* Controls for opacity, flip, and rotation */} @@ -60,7 +69,7 @@ const CustomizeShape = () => { {/* Shadow Customization */} - {activeObjectType !== 'group' && } + {/* Text Customization */} diff --git a/src/components/EachComponent/RoundedShapes/RoundedShape.jsx b/src/components/EachComponent/RoundedShapes/RoundedShape.jsx index bcb23ba..371b9e6 100644 --- a/src/components/EachComponent/RoundedShapes/RoundedShape.jsx +++ b/src/components/EachComponent/RoundedShapes/RoundedShape.jsx @@ -51,9 +51,7 @@ const RoundedShape = () => { scaleX: 6, scaleY: 6, strokeWidth: 0, - // rx: 0, - // x: 0, - // y: 0, + stroke: "#ffffff" }); canvas.add(iconGroup); canvas.setActiveObject(iconGroup); diff --git a/src/components/EditPanel.jsx b/src/components/EditPanel.jsx index 2cdca5f..3bc8733 100644 --- a/src/components/EditPanel.jsx +++ b/src/components/EditPanel.jsx @@ -28,9 +28,13 @@ export function EditPanel() { top: canvas?.height / 2, originX: "center", originY: "center", + selectable: true, // Allow group selection + subTargetCheck: true, // Allow individual object selection + hasControls: true, // Enable resizing/movement of the group }) canvas.remove(...activeObjects); canvas.add(group); + // canvas.setActiveObject(group); canvas.renderAll(); } else { console.log("Select at least two objects") @@ -39,33 +43,44 @@ export function EditPanel() { const ungroupSelectedObjects = () => { const activeObject = canvas.getActiveObject(); + if (activeObject && activeObject.type === "group") { - // Get the active group + // Get the group const group = activeObject; // Remove the group from the canvas canvas.remove(group); - // Iterate through each object in the group and re-add to the canvas + // Iterate through each object in the group group._objects.forEach((object) => { - // Ensure the object has a fresh state + // Calculate the absolute position based on the group's transformation + const objLeft = object.left * group.scaleX + group.left; + const objTop = object.top * group.scaleY + group.top; + + // Reset transformations and positions object.set({ - hasControls: true, // Allow resizing - selectable: true, // Make selectable - group: null, // Remove group reference - left: canvas?.width / 2, - top: canvas?.height / 2, + left: objLeft, + top: objTop, + scaleX: object.scaleX * group.scaleX, // Adjust scale based on group + scaleY: object.scaleY * group.scaleY, // Adjust scale based on group + angle: object.angle + group.angle, // Adjust rotation + hasControls: true, // Allow resizing + selectable: true, // Make selectable + group: null, // Remove group reference originX: "center", originY: "center", }); - // Set the object's coordinates and transformation matrix + // Update coordinates object.setCoords(); // Add the object back to the canvas canvas.add(object); }); + // Clear the selection + canvas.discardActiveObject(); + // Render the canvas to reflect changes canvas.renderAll(); } diff --git a/src/components/Layouts/AddShapes.jsx b/src/components/Layouts/AddShapes.jsx index a463de7..16ed3fc 100644 --- a/src/components/Layouts/AddShapes.jsx +++ b/src/components/Layouts/AddShapes.jsx @@ -3,10 +3,51 @@ import PlainShapes from '../EachComponent/Shapes/PlainShapes' import { Card } from '../ui/card' import { Separator } from '../ui/separator' import CustomShape from '../EachComponent/CustomShape/CustomShape' +import { useContext } from 'react' +import CanvasContext from '../Context/canvasContext/CanvasContext' +import ActiveObjectContext from '../Context/activeObject/ObjectContext' +import { fabric } from 'fabric' +import { Button } from '../ui/button' +import { Type } from "lucide-react"; const AddShapes = () => { + const { canvas } = useContext(CanvasContext); + const { setActiveObject } = useContext(ActiveObjectContext); + + const addText = () => { + if (canvas) { + const text = new fabric.IText('Editable Text', { + left: 100, + top: 100, + fontFamily: 'Poppins', + fontSize: 16, + }); + // Add the text to the canvas and re-render + canvas.add(text); + // canvas.clipPath = text; + canvas.setActiveObject(text); + setActiveObject(text); + canvas.renderAll(); + } + }; + return (
+ +

Add Text

+ +
+ +
+
+

Custom Shapes

diff --git a/src/components/Layouts/SheetLeftPanel.jsx b/src/components/Layouts/SheetLeftPanel.jsx index 9c9b257..3d8dadc 100644 --- a/src/components/Layouts/SheetLeftPanel.jsx +++ b/src/components/Layouts/SheetLeftPanel.jsx @@ -2,7 +2,7 @@ import { Sheet, SheetContent, SheetDescription } from '../ui/sheet'; import AddShapes from './AddShapes'; import { Separator } from '../ui/separator'; import { Button } from '../ui/button'; -import { X, Store, Shapes, Upload, Type } from "lucide-react"; +import { X, Store, Shapes, Upload } from "lucide-react"; import { Tabs, TabsContent, TabsList, TabsTrigger } from '../ui/tabs'; import AllIconsPage from '../EachComponent/Icons/AllIcons'; import UploadImage from '../EachComponent/UploadImage'; @@ -32,7 +32,7 @@ const SheetLeftPanel = () => { -

Your customizable open canvas playground.

+

Your customizable, canvas playground.

@@ -41,16 +41,19 @@ const SheetLeftPanel = () => { - - Shapes + + +

Shapes & Text

- - Icons + + +

Icons

- - Image + + +

Image

@@ -67,7 +70,6 @@ const SheetLeftPanel = () => { -